neilobremski
Experienced Member
It's time to take the time to make a post to mark my progress. Previously I had mentioned doing sine and cosine multiplications using fixed-point, specifically 10-bit so that the whole unsigned fraction could fit in a single byte. I thought this would be sufficient and it was but it also turned out to still be more than necessary. On top of that, using word multiplications ties up a lot more registers.
So I did two things: first I dropped down to using a single byte to store the entire fixed point value. This usually leaves only 6 bits for the unsigned fraction portion but the second thing I did was to dare to use 7. The result is fixed point numbers which can express -1 but not a pure +1, because zero counts on the positive side and so the range is always -N^2 to N^2 - 1. Thus with 7 bits, the range is -128 to +127 and my fixed point range is -1.00 to +0.99.
Obviously I was worried that this would not be enough precision but on paper it looked okay and when I finally got it all coded and visually demonstrated, I was pleased to see it worked fine. I added some rounding code to so that the positive sine/cosine multiplications come out correct for the angles I need them to. [SUP][1][/SUP]
The following assembly multiplies a whole signed integer in AL by one of the sine/cosine fixed point values in AH (or the opposite order since multiplication is commutative).
This won't work properly for negative rounding but that hasn't stopped me from using it successfully to rotate stuff. Check it out:
Some other cool things about using a 128 denominator is that the fractions it represents are at least two decimal points so it's a bit easier to do on paper. And also, my 3D tile sizes are 128 as well which means that rotating a tile from it's 2D 8-bit coordinates will result in a proper 3D 16-bit coordinate with a single multiplication. More on this in my next post about the square raycast ...
Footnotes:
[SUP][1][/SUP]. I'm working with angles in multiples of 10 degrees.
So I did two things: first I dropped down to using a single byte to store the entire fixed point value. This usually leaves only 6 bits for the unsigned fraction portion but the second thing I did was to dare to use 7. The result is fixed point numbers which can express -1 but not a pure +1, because zero counts on the positive side and so the range is always -N^2 to N^2 - 1. Thus with 7 bits, the range is -128 to +127 and my fixed point range is -1.00 to +0.99.
Obviously I was worried that this would not be enough precision but on paper it looked okay and when I finally got it all coded and visually demonstrated, I was pleased to see it worked fine. I added some rounding code to so that the positive sine/cosine multiplications come out correct for the angles I need them to. [SUP][1][/SUP]
The following assembly multiplies a whole signed integer in AL by one of the sine/cosine fixed point values in AH (or the opposite order since multiplication is commutative).
Code:
IMUL AH ;
SAL AX, 1 ; afterwards AH = truncated whole result
ROL AL, 1 ;
AND AL, 1 ; AL is now a rounding carry
ADD AL, AH ; add carry to round up
This won't work properly for negative rounding but that hasn't stopped me from using it successfully to rotate stuff. Check it out:
Some other cool things about using a 128 denominator is that the fractions it represents are at least two decimal points so it's a bit easier to do on paper. And also, my 3D tile sizes are 128 as well which means that rotating a tile from it's 2D 8-bit coordinates will result in a proper 3D 16-bit coordinate with a single multiplication. More on this in my next post about the square raycast ...
Footnotes:
[SUP][1][/SUP]. I'm working with angles in multiples of 10 degrees.