Port POV tools to Windows

the script (this gets called in the win .bat file)

#!/bin/bash

cd "$(dirname "$0")"
clear
echo ""
files=$(ls 2>/dev/null -Ubad1 -- *.png | wc -l)
find . -type f -name "* *" | while read file; do mv "$file" ${file// /_}; done

if [ "$files" -lt 1 ]; then
	echo "OOPS, no .png files found!"
	echo ""
	echo "Let's download an example for you to try :)"
	echo "DOWNLOADING: Star Wars Logo example image.........."
	echo ""
	wget https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1024px-Star_Wars_Logo.svg.png&>/dev/null &
	echo "Hit ENTER to process the image, or type q to exit."
	read delay
	if [ "$delay" = "q" ]; then exit
	fi
	echo ""
	make HEIGHT=144
	exit
fi
if [ "$files" -ge 2 ]; then
	echo "OOPS, too many .png files found!"
	echo ""
	echo "There needs to be only ONE source .png image in the pov_tools folder."
	echo "Please fix that then press ENTER to try again"
	echo "or type 'q' to quit for now."
	read fix
	if [ "$fix" = "q" ]; then exit
	else
		exec "./create_POV_data_files"
	fi
fi
echo""
echo "Hi! Is the source for POV image smaller than 800x144? (y/n)"
# or
echo "What height do you want the resulting image to be?"
# or
echo "What is your blade length in pixels?"
echo "  minimum 30 pixels - max 144 Full blade "
read choice
if [[ "$choice" = "y" || "$choice" = "Y" ]]; then
	echo "Source image file HEIGHT? :"
	read HEIGHT
	make HEIGHT=$HEIGHT
else
	make HEIGHT=144
fi
# echo "Hi! Is the source for POV image smaller than 800x144? (y/n)"
# read choice
# if [[ "$choice" = "y" || "$choice" = "Y" ]]; then
# 	echo "Source image file WIDTH? :"
# 	read WIDTH
# 	echo "Source image file HEIGHT? :"
# 	read HEIGHT
# 	make WIDTH=$WIDTH HEIGHT=$HEIGHT
# else
# 	make
# fi

fi```

Not sure I get this question part. I believe Q1 is irrelevant. My guess is that the correct question to ask would be either Q2 or Q3.

Crucible Logo (it reads on windows as 952x128):

With height 144 it transforms into this (800x144):

So my guess is smaller images than blade length is okay, it will just be placed inside the optimized image (aligned top).

The reason for the crashes is that unless you update pov.h, it tries to extract 144 pixels from the data. If the data doesn’t contain 144 pixels per line, then the result will either be garbage or a crash. Basically, the code relies on having the data have the right number of pixels in it.

Once the code has extracted 144 pixels, it does a very simple nearest-neighbor scaling to the length of the blade. That means that the output will always cover the blade, but nearest-neighbor is not a great scaling algorithm. Of course, that detail might get lost when you wave the blade around and take long exposure pictures… :slight_smile:

In addition to adjusting the height, I think we might also wan to adjust the “width”, as I think we might have more angles than we need. I should take a look and see what happens when we do, because we might need to adjust the code to do that. Reducing the height and width will use less memory, which for one thing might mean that we can use more complex pictures.

Finally, I’m thinking that we might want to make an 8-bit mode. Basically we would quantize the pictures to 256 colors, then RLE-encode that. It should give a good balance between allowing color pictures and not taking very much memory.

1 Like

Do we need less angles because on a shorter blade - though it describes the same arc - the different angles are not as distinguishable from another because they are closer together due to them being closer to the center point?

But even without adjusting width/angles and only the height, the FC-data file is less than 50% of the fullsize variant (72 - 44.5kB vs 144 - 93.9kB) at least of my 2 colors test image. That is why I didn’t even check in the script files if there was anything going on with the 144 height value. The way it worked right of the bat suggested to me, everything was fine.

8-bit mode sounds like a great compromise, maybe as a third option between FC and SC as “8B”? Is there currently anything happening to the colors when I try using - I don’t know an image with a metallic sheen to it, so different types of grey?

Edit:
@profezzorn How did you land on 800 for the corresponding width to the 144 (neo)pixels.
If we take U = 2 * Pi * r for example, r being our pixels, that would conclude halfing our pixels would need halfing that width. At least I don’t see why the formula for the circumference should not apply to a piece of a circle.
So for a 100 pixel blade this would translate to

800 / 144  = X / 100
(800 * 100) / 144 = X
X = 555.5555555

Rounding up to 556?

Hi @NoSloppy, what about something like this:

echo""
echo "Hi! Do you want to optimize the POV image for a specific blade length? (y/n)"
echo "This can increase performance and safe flash memory. Default is 144 pixels."
read choice
#kaQnub: there was a ";" between "]]" and "then". bug or feature?
if [[ "$choice" = "y" || "$choice" = "Y" ]] then
	echo "What is your blade length in pixels?"
	echo "(minimum 30 pixels - max 144 pixels for full blade)"
	read HEIGHT
	if [[ "$HEIGHT" >= "30" && "$HEIGHT" <= "144" ]] then
		make HEIGHT=$HEIGHT
	elif [[ "$HEIGHT" < "30" ]] then
		make HEIGHT=30
	else
		make HEIGHT=144
	fi
else
	make HEIGHT=144
fi

I had pov.h using the variable we defined at the bottom of pgm/pnmtorle. It seems actually when that is fed what was the default before of 144, when the crashing happened.

I got this working as well by feeding wiper the command line arguments for width and height:

int main(int argc, char** argv) {
  read_pnm(stdin, &image);
  // output.resize(800*10, 144*10);
  if (argc == 1) {
    output.resize(800*10, 144*10);
  } else {
    int pov_w = atoi(argv[1]);
    int pov_h = atoi(argv[2]);
    output.resize(pov_w * 10, pov_h * 10);
  }

And then in makefile, it got

..........
./pnmwindshieldwiper $(WIDTH) $(HEIGHT) | pnmscale -reduce 10.........

But the beauty of maintaining the scale ratio automatically gets lost this way.

Are you manually inputting the width?
Have you tried my approach of calculating pov_w with the ratio in mind?
Maybe sth like this

int main(int argc, char** argv) {
  read_pnm(stdin, &image);
  // output.resize(800*10, 144*10);
  if (argc == 1) { // maybe we can also or pov_h == 144  in here, but therefore the order has to change
    output.resize(800*10, 144*10);
  } else {
    int default_h = 144; //edit changed _w and _h, because h = 144
    int default_w = 800;
    int pov_h = atoi(argv[2]); //probably needs to change because we would only need 1 arg
    int pov_w = round((float)default_h * (float)pov_h / (float)default_w); //Edit added (float) to each int variable
    output.resize(pov_w * 10, pov_h * 10);
  }

That of course depends on how Fredrik came up with the 800 in the first place, and if we can just keep the ratio like that. Maybe there has to be an offset factor to be woven in there.

argc (argument count) is the total number of arguments. The command itself counts as one and is (argument value) argv[0] then whatever arguments you add increase from there. So width was a second argument as argv[1], height is 3 arguments as argv[2].
So if we do just height, there’s still two total arguments, but height would be argv[1]. Make sense?
Yeah that calculation of the ratio for width would be real nice to let some math handle it instead of manually having to enter it.
Which, again, seems to all be just fine if we just go back to defining height, having pov.h use that. Pnmwindshieldwiper does the initial scaling in ratio, then pnmscale just brings it down to be equivalent rows of what we enter for height.
The whole question of adjusting width seems to be a non-issue because it DOES adjust the width, in ratio, and done…no?

Let’s wait for Fredrik to enlighten us.
In the meantime, like so?:

if (argc == 1 || atoi(argv[1])) {
    output.resize(800*10, 144*10);
  } else {
    int default_h = 144;
    int default_w = 800;
    int pov_h = atoi(argv[1]); 
    int pov_w = round((float)default_h * (float)pov_h / (float)default_w); 
    output.resize(pov_w * 10, pov_h * 10);
  }

Edit: If i do that, my files are exactly the same as if I would not have bothered making these changes.

Then I would need to see the code to figure out why.

It’s not exactly how I would write the code, but yes, that is a good way to do it.
We could also allow the width to be 0 and calculate it from the height maybe.

I think we should only do this if the width specified on the command line is zero.

Don’t remember.
It sort of makes sense to try to make the pixels square-ish.
Since the sweep covers 45 °, the length of the outside arc would be \pi * R / 2. It should be noted that in addition to the number of pixels in the hilt, there is a “base”, of pixels underneath the sweep. It looks like the code currently assumes that the “base” is 50% of the length of the blade. This base includes the hilt itself, and whatever part of your arm you’re using to do the swing. (in the windshield-wiper analogy, this would be the area below the windshield-wiper that doesn’t get wiped…)

Based on this, the number of angles for an 144-pixel blade should be \pi * 144 * 1.5 / 2 = 339. However, it should be noted that having more angles will make the quality better, so we might want to scale that up a bit. How much is a matter of experimentation. Maybe we do height * 4 or something?

For a 72-pixel blade, we could still have 800 angles if we want to, but the above math would suggest that something like 170 might be enough.

As far as I can tell, the pov.h automatically adjusts to the number of angles, so changing the 800 to something else shouldn’t cause any crashes, it just changes the quality of the output. Basically, more angles will always give better results, but the difference between 700 and 800 is probably extremely small. Once the number of angles go below height * \pi * 1.5/2 I expect the drop in quality to be a lot more noticeable.

Also, a question: I know you guys have spent a bunch of time on this, but it’s also been a bit of a headache. Do you want me to go fix it, or do you want to keep at it?

For an image like this, it might make more sense to just feed it into pnmtorle without pushing it through pnmwindshieldwiper first. It would get distorted when you swing the saber, but that might be fine…

Should be pi ∗ r/4, shouldn’t it? 2 ∗ pi ∗ r being full circle.

Of course you are correct, that the center point is not at 0 pixels. but rather than being 50% of blade length, it should always be 50% of 144. Well, at least it should be constant independent of pixel amount.

Correct, it would be, but I meant 90 °, not 45 ° :slight_smile:

We could fix it so that the “base” can also be specified on the command line.

Tomehto, Tomahto :slight_smile:

But how would we measure this?
again with a question to specify this? if not base = 72 (why math this round(144 / 2))
Maybe:

Do you want to specify a base length? (Y/N) (add explanation for base here)
N -> base = 72
Y ->
How long is your hilt compared to your blade (in %)?
// For me that would be 15cm hilt vs 50cm blade which is 30%
base = round((float)height * 30 / 100)

Right now, pnmwindshieldwiper just have two values, one is the length of the blade and the other is the length of the base. The unit is unimportant, only the fraction between them matters. However, it would be easy to allow them to be placed on the command line, like:

pnmwindshieldwiper 0 72 50 35

The four numbers would be width, height, blade length, hilt + arm length.
The zero width means “calculate a reasonable width for me”.
I don’t know how you guys do the long exposure, but I do the swing with my elbow, so the length of the “base” counts from my elbow to the first pixel in the blade.

Well I had to figure it out to achieve the best possible image.
I first tried the emitter being my center point. those images were horrible.
The slight arc i made while swinging, i couldn’t really describe what i was doing.
For me personally I would want something that I can easily reproduce.
Pommel being the center point could work for me as well as ellbow, but while sitting down, not sure if there is enough room.

Also: what happens if someone has eg. a pixel strip and a 16pixel connector in series with the blade?
My guess he might lose some image information.

Is this 72 there 144 / 2 or assuming my exampel of the 72px blade?
hilt length: Is 50 in percent to the blade? or a pixel value?
arm length: in percent to the blade?

So for my 72px blade would the numbers be:

pnmwindshieldwiper 0 36 30 0 (assuming i want a spin around the pommel) ?

The 72 is the number of pixels.
The 50 and 35 can be in any unit you like, but I was thinking centimeters.
So I think in your case it would be:

pnmwindshieldwiper 0 72 50 0

In your case the “50” can technically be any number since 0 / 50 = 0 / 100 = 0 /100000000