• Please review our updated Terms and Rules here

8 Bit Twice Shy aka Size Does Matter

neilobremski

Experienced Member
Joined
Oct 9, 2016
Messages
55
Location
Seattle, USA
I've been working with 8-bit fixed point for pre-calculated SINE and COSINE values. One compromise of this is that the maximum positive value is only 127 which means I can only represent 127/128 (0.9921875) and not a whole ONE.

Recently I encountered an odd bug where viewing my tile map from a 270° facing caused the Z coordinates of all objects to be reversed. My test map and player position looked like so:

Code:
P
 P <

And thus I expected to see the following:


But instead it was blank. I decided the view (position) rotation algorithm must be bogus and reworked it from scratch. I tested it with the following JScript on my Windows computer:

Code:
function cos(degrees)
{
	return Math.round(Math.cos(Math.PI * degrees / 180.0) * 100) / 100;
}

function sin(degrees)
{
	return Math.round(Math.sin(Math.PI * degrees / 180.0) * 100) / 100;
}

function turn(x,y, degrees)
{
	var xr = (x * cos(degrees)) - (y * sin(degrees));
	var yr = (y * cos(degrees)) + (x * sin(degrees));
	WScript.Echo("TURN: " + xr + " , " + yr);
}

function view(x,y, degrees)
{
	var xr = (x * cos(degrees)) - (y * -sin(degrees));
	var yr = -((y * cos(degrees)) + (x * -sin(degrees)));
	WScript.Echo("VIEW: " + xr + " , " + yr);
}

var x = parseFloat(WScript.Arguments.Item(0).toString());
var y = parseFloat(WScript.Arguments.Item(1).toString());
var degrees = parseFloat(WScript.Arguments.Item(2).toString());

turn(x,y,degrees);

view(x,y,degrees);

NOTE that Y is negated for use as Z since positive Z is "in front" and negative is "in back" of the camera. Redoing the algorithm only caused me more alarm because it looked suspiciously like what I had had before:

Code:
;	Zt = ((Yr * cos(dir)) + (Xr * -sin(dir))) * -128
;	Xt = ((Xr * cos(dir)) - (Yr * -sin(dir))) * 128

So why then wasn't it working? I stepped through the code and found the answer in the 8-bit fixed point. See if you can spot it ...

Code:
MOV	AX, BP	; 5EA 
MOV	AL, AH	; 5EC  AL = cos(dir)
IMUL	BL	; 5EE Yr * cos(dir)
MOV	DX, AX	; 5F0 
MOV	AX, BP	; 5F2 
NEG	AL	; 5F4 AL = -sin(dir)
IMUL	BH	; 5F6 Xr * -sin(dir)
ADD	AX, DX	; 5F8 
NEG	AX	; 5FA * -128
STOSW		; 5FC write [  Zt  ]

The SINE value of 270 degrees is -1 which in 8-bit fixed point is 0x80 or -128. This cannot be negated because there is no +128! And since the two's complement does nothing the value remains the same. Remember I am truncating positive values to +127 or 0x7F and doing that logically would incur a lot of extra instructions ... or I could simply negate the 16-bit value resulting from IMUL ...

Code:
MOV	AX, BP	; 5EA 
MOV	AL, AH	; 5EC 
IMUL	BL	; 5EE Yr * cos(dir)
MOV	DX, AX	; 5F0 
MOV	AX, BP	; 5F2 
IMUL	BH	; 5F4 Xr * -sin(dir)
NEG	AX	; 5F6 
ADD	AX, DX	; 5F8 
NEG	AX	; 5FA * -128
STOSW		; 5FC write [  Zt  ]

That works but there are two NEG's surrounding an ADD which is redundant. I finally reduced this code to the following which works beautifully ...

Code:
MOV	AX, BP	; 5EA 
MOV	AL, AH	; 5EC 
IMUL	BL	; 5EE Yr * cos(dir)
MOV	DX, AX	; 5F0 
MOV	AX, BP	; 5F2 
IMUL	BH	; 5F4 Xr * -sin(dir)
NEG	DX	; 5F6
ADD	AX, DX	; 5F8 
STOSW		; 5FA write [  Zt  ]

Voila! Whenever dealing with fixed point, size does matter!
 
Back
Top