Any way to do fast trig operations without FPU?

A place for people with an interest in developing new shmups.
Post Reply
User avatar
iatneH
Posts: 3202
Joined: Tue Jan 25, 2005 11:09 pm
Location: Vancouver, BC, Canada

Any way to do fast trig operations without FPU?

Post by iatneH »

Just throwing this out there out of curiosity, I probably won't have time to work on anything that can use this...

Anyway, if say programming for something like GP2X with only simulated (software) floating point in SDL and the compiler, what's a fast way to aim bullets from a source to a destination?

I would like to be able to represent a (straight) bullet path as an angle and a speed, reason being there may be patterns which aim at multiple positions. E.g. aim one stream directly at the player, aim a second stream 5 degrees clockwise from the original, and aim a third stream 5 degrees CCW from the original - then the pattern will behave the same way regardless of where the player is in relation to bullet source.
If there's processing time to spare, then maybe also add in a 2nd derivative function to change bullet trajectories.

The same sort of thing can also be used to retrieve the animation frame of enemies that orient/rotate themselves to face the player ship.

Of course it's easy to do sloppily with trig and calc on a PC, but how to do it efficiently on a weaker hardware? There's gotta be a way since I've seen it on Megadrive and SFC games.. Especially the changing bullet speed/direction, since I saw it on Gynoug (and maybe even earlier games had it as well).

Thanks in advance, although I hardly read the dev forum...
User avatar
mrkotfw
Posts: 170
Joined: Sun Nov 26, 2006 3:15 am
Location: California

Post by mrkotfw »

I think what you want is fixed-point math. There is information out there (Google for "tonc tutorial").
Yaul: An awesome open source SEGA Saturn software development kit
User avatar
iatneH
Posts: 3202
Joined: Tue Jan 25, 2005 11:09 pm
Location: Vancouver, BC, Canada

Post by iatneH »

Fack. I was hoping it wouldn't come to that. Thanks though! One of these days I'll get around to wrapping my head around it...
hmn
Posts: 3
Joined: Tue Mar 06, 2007 3:35 pm
Contact:

Post by hmn »

Oldskool programs use lookup tables:

Code: Select all

const int SINTABLE[360] = { ... };
User avatar
ED-057
Posts: 1560
Joined: Fri Jan 28, 2005 7:21 am
Location: USH

Post by ED-057 »

yes, lookup tables AND fixed-point math... Having floats in a table would still be relatively slow if you have no FPU (although it might not be a problem on the GP2x)

Fixed-point math isn't hard at all though. For example, let's go with six fraction bits (means all your numbers that would be floats are multiplied by 64 and stored as integers). If you have a bullet at position 50,100 on the screen and you want to move 5.25 pixels left every frame then normally you just subtract 50-5.25... With fixed-point you use integers instead, so call the position 3200,6400 and the speed 336 and then subtract 3200-336=2864. When the calculation is done you convert the scaled values back to the real position 2864/64=44 6400/64=100
User avatar
mrkotfw
Posts: 170
Joined: Sun Nov 26, 2006 3:15 am
Location: California

Post by mrkotfw »

ED-057 wrote:yes, lookup tables AND fixed-point math... Having floats in a table would still be relatively slow if you have no FPU (although it might not be a problem on the GP2x)

Fixed-point math isn't hard at all though. For example, let's go with six fraction bits (means all your numbers that would be floats are multiplied by 64 and stored as integers). If you have a bullet at position 50,100 on the screen and you want to move 5.25 pixels left every frame then normally you just subtract 50-5.25... With fixed-point you use integers instead, so call the position 3200,6400 and the speed 336 and then subtract 3200-336=2864. When the calculation is done you convert the scaled values back to the real position 2864/64=44 6400/64=100
Thank you for that explanation. :P
Yaul: An awesome open source SEGA Saturn software development kit
User avatar
iatneH
Posts: 3202
Joined: Tue Jan 25, 2005 11:09 pm
Location: Vancouver, BC, Canada

Post by iatneH »

Thanks, I don't know why it seemed so complicated last time I tried to read about it. Possibly because it was written by a mathematician rather than a programmer?

Anyway, sounds like everything should be done in the expanded space and only scaled back when drawing to the screen? Else there would be accumulation of rounding error..?

But aren't divisions also inefficient?... or is /64 chosen so that we can do bitwise shifts?
User avatar
ED-057
Posts: 1560
Joined: Fri Jan 28, 2005 7:21 am
Location: USH

Post by ED-057 »

yes, exactly right...
User avatar
serge
Posts: 55
Joined: Wed Mar 30, 2005 1:06 am
Location: Odessa, Ukraine

Post by serge »

I have some code for you:
Fixed-point sine, cosine and sincos functions.
Functions to calculate angle to target.

This code is specifically optimized for ARM architecture (CPU of this type is used in GP2X) and was used on several projects.

I kind of cut'n'pasted it together, to remove some project specific code and to make it runnable under Ch Interpreter for easy testing(http://www.softintegration.com/products ... /download/) so it's a bit messy - will try to find some time to clean it up later.
It's straight C code, in its original form was compiled under many different compilers, but it's possible I messed it up while combining the pieces into these .ch files.

It needs some explanation, will try to write more about this later, but several notes:

In fxtrg.ch FX_TBLSIZE controls the size of the lookup table, so it can be selected at compile time, might want to try different sizes, bigger tables will give you more precision, but generally ARM-based machines have small caches and slow memory interface, so using big memory tables can be bad.
In general you're more interested in function behaviour, not its precision.

trgToNum() can be eliminated, making code faster. You can assume FX_PRECISION of the table is always bigger than the number of fractional bits you'd need in a real game.

Angles calculated by fxCalcTargetAngle() are 10-bit values, 0x100 being one quarter (90 degrees). There are macros in the code to convert this to radians etc. 0 degrees is at 3 o'clock, angle values increasing counter-clockwise.

ARM CPUs lack integer division, fxUdiv32_16() in heading.ch implements division with some optimizations, can be made faster by handling special cases. There is CLZ routine to Calc Leading Zeroes, on some ARMs there is a special machine instruction to do this, not sure if it exist on GP2X though.

Attached a MIT style license to the code, so it can be used by anyone, basically without any restrictions.
Post Reply