gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Need help with converting float to fixed

#161316 - 3dfx - Fri Aug 01, 2008 2:05 am

I'm trying to port my 3d game-ish/engine to the DS. At first I used floats because it made more sense to me but my frame rate started taking a nose dive so I converted everything to fixed point. Everything seems to work all right except my models. The interpolation between keyframes with them are screwed up big time using fixed point but are fine with floats. Here's how I have the interpolation:
Code:

//model->timeStep is how far from 0.0f to 1.0f the model has been animated
//model->end and model->begin are int values of what frame our current animation begins and ends at

//old way
float fraction =  (model->timeStep - (float)(start - model->begin) / (float)(model->end - model->begin + 1)) * (model->end - model->begin + 1);
VERTEX3 one, two, pt;
one.x = model->frames[start].vertices[vertex].position.x;
one.y = model->frames[start].vertices[vertex].position.y;
one.z = model->frames[start].vertices[vertex].position.z;
 
two.x = model->frames[end].vertices[vertex].position.x;
two.y = model->frames[end].vertices[vertex].position.y;
two.z = model->frames[end].vertices[vertex].position.z;

//my new vertex
pt.x = one.x * (1 - fraction) + two.x * fraction;
pt.y = one.y * (1 - fraction) + two.y * fraction;
pt.z = one.z * (1 - fraction)    + two.z * fraction;


^^ Works fine. Using fixed points,

Code:

float fraction =  (model->timeStep - (float)(start - model->begin) / (float)(model->end - model->begin + 1)) *  (model->end - model->begin + 1);
v16 cFrac = floattov16(fraction);

VERTEX3F one, two, pt;
one.x = model->frames[start].vertices[vertex].position.x;
one.y = model->frames[start].vertices[vertex].position.y;
one.z = model->frames[start].vertices[vertex].position.z;
 
two.x = model->frames[end].vertices[vertex].position.x;
two.y = model->frames[end].vertices[vertex].position.y;
two.z = model->frames[end].vertices[vertex].position.z;

//my new vertex
pt.x = one.x * (floattov16(1.0f) - cFrac) + two.x * cFrac;
pt.y = one.y * (floattov16(1.0f) - cFrac) + two.y * cFrac;
pt.z = one.z * (floattov16(1.0f) - cFrac) + two.z * cFrac;

The model animates fine when I don't interpolate (albeit jerkily as it should).
Can anyone see what I'm doing wrong?

#161317 - Sausage Boy - Fri Aug 01, 2008 2:38 am

I'm a bit tired, but I think your problem lies with the fixed point multiplication. Basically, you need to right-shift your answer by 12 (I think). Think about what would happen if you tried to calculate 1*1 in fixed point. You might need to cast to bigger containers to keep from overflowing as well.

You probably won't be able to use my advice right away, but I hope it can be a starting point for information-searching and experimenting.
_________________
"no offense, but this is the gayest game ever"

#161318 - 3dfx - Fri Aug 01, 2008 2:52 am

Well your advice worked perfectly! :D
The bitshift worked, and now I'll remember to it. :)
I shoulda known 1*1 = (1<<12)*(1<<12) in 4.12 fixed point, just not used to dealing with fixed points I guess.

#161319 - DensitY - Fri Aug 01, 2008 2:56 am

easiest way to think of it is this

say you have
16.16 fixed point number and an interger

multiplying a fixed number by a standard number results in a fixed point result, multipling a fixed number by another fixed number gives you a fixed point result but with double the precision range.

for example

16.16 = 16.16 * int
16.32 = 16.16 * 16.16

if you want the fixed * int to be back to int you do
int = (16. 16 * int) >> 16

if you want the fixed * fixed to be 16.16 you do
16.16 = (16.16 * 16.16) >> 16

follow?

#161323 - silent_code - Fri Aug 01, 2008 9:57 am

You might also want to use the hardware divider.
IIrc, the function was "divf32()" or atleast something along the lines.
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#161334 - naleksiev - Fri Aug 01, 2008 6:23 pm

silent_code wrote:
You might also want to use the hardware divider.
IIrc, the function was "divf32()" or atleast something along the lines.


From what I remember when I profiled it, hardware division was about 5-10 times faster than normal division

#161335 - Maxxie - Fri Aug 01, 2008 6:47 pm

There is no need for a division here, if you divide by (semi) constant data:

Quote:

float fraction = (model->timeStep - (float)(start - model->begin) / (float)(model->end - model->begin + 1)) * (model->end - model->begin + 1);


Just precalculate the inverse of the divisor (Either in your code when model->end/begin changes or even when creating the model itself), and store it with the model data. Every time you need to do the division, you can just multiply with that value, which is much faster on the arm.
_________________
Trying to bring more detail into understanding the wireless hardware

#161360 - 3dfx - Fri Aug 01, 2008 11:00 pm

naleksiev wrote:
silent_code wrote:
You might also want to use the hardware divider.
IIrc, the function was "divf32()" or atleast something along the lines.


From what I remember when I profiled it, hardware division was about 5-10 times faster than normal division

The f32 is fixed 32 right? Just wanna make sure.

Maxxie wrote:

ust precalculate the inverse of the divisor (Either in your code when model->end/begin changes or even when creating the model itself), and store it with the model data. Every time you need to do the division, you can just multiply with that value, which is much faster on the arm.

I'm actually doing that right now but posted it so for clarity's sake.