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 > Converting (and understanding) float -> fixed point code

#162862 - ZeroSum - Sun Sep 14, 2008 11:32 pm

I've been using floats for my calculations so far and I got to the point where a certain amount of geometry would cause to framerate to dive. I thought I needed to add some culling so I added a simple check to see if vertexs were out of camera view. Of course, I also did this in floats and it has made my framerate even worse with fewer polys drawn!

I understand now that I should be working in fixed point, and I understand it up to a point (no pun intended). What I don't understand is how to perform the operations in the code below with fixed point numbers. At first I tried to change all floats to v16 and (obviously :p) this failed, but I'm not sure what I should be doing.

Do I need to be shifting everywhere to make everything the right format? Or am I completly wrong? It that would make the code quite ugly and hard to follow. What are the correct ways to perform add/sub/multiply/divide on fixed point numbers using libnds? I have some of my code below to give an idea of what I am trying to do.

Thanks for reading.

This is what I'm using to cull:
Code:
bool DmRenderer::CullCheck( float curX, float curZ )
{
   // Divide by 10.0 to match the camera and world coords because
   // the world is scaled by 10.0 when drawn to fit larger maps.
   float camX = m_Interface.Graphics->GetCamX() / 10.0;
   float camZ = m_Interface.Graphics->GetCamZ() / 10.0;


   // Check the coords passed in are in range of visible X.
   if( curX < (camX - 0.6 ) ) return false;
   if( curX > (camX + 0.6 ) ) return false;

   // Check the coords passed in are in range of visible Z.
   if( curZ < (camZ - 0.5 ) ) return false;
   if( curZ > (camZ + 0.5 ) ) return false;

   // Passed cull check.
   return true;
}

And this is one of my main drawing functions:
Code:

void Renderer::DrawFloors( Level* level, std::string texture)
{
   // Get the size of the level.
   int TotalX = level->GetCellsX();
   int TotalY = level->GetCellsY();

   float CellWidth = 0.1;
   float CellHeight = 0.1;

   // Calculate where to start the grid so it is centered on cam 0,0,0.
   float StartPointX = 0.0 - (CellWidth * (TotalX / 2 )) ;
   float StartPointZ = 0.0 - (CellHeight * (TotalY / 2) ) ;

   // Current position to drawn. Incremented in loops.
   float currentX = StartPointX ;
   float currentZ = StartPointZ ;

   // Bind the passed in texture.
   TexturePool->BindTexture( texture );

   // Tell the graphics class we're going to draw.
   Graphics->Begin();

   // Loop through the grid of cells.
   for( int y = 0; y < TotalY; y++ )
   {
      for( int x = 0; x < TotalX; x++ )
      {
         // If this cell is a passageway...
         if( level->GetCellType(x, y) == Passage )
         {
            // and passes the cull check...
            if( CullCheck( currentX, currentZ ) )
            {
               // Draw it..
               Graphics->DrawPlaneFloor( floattov16( currentX ), floattov16( 0.2 ),
                                                     floattov16( CellWidth ), floattov16( CellHeight ),
                                            floattov16( currentZ ) );               
            }
         }
         // Every X move along one cell width.
         currentX += CellWidth;
      }

      // Move back to the first X pos and increment Z to drawn next row.
      currentX = StartPointX ;
      currentZ += CellHeight;
   }

   Graphics->End();
}

#162863 - silent_code - Mon Sep 15, 2008 12:02 am

FYI: The hardware already offers an asynchronous frustum culling test (a.k.a. box test).
_________________
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.

#162865 - DensitY - Mon Sep 15, 2008 12:45 am

I did a post many moons ago on fixed point math

http://forum.gbadev.org/viewtopic.php?p=153700&highlight=#153700


I also give an example of using fixed point math todo some jobs that we normally use float point

ie

number * 0.5 in fixed point.

#162869 - sgeos - Mon Sep 15, 2008 4:30 am

http://forum.gbadev.org/viewtopic.php?t=15976

#162873 - a128 - Mon Sep 15, 2008 11:10 am

use the search function luke!

#162910 - Lazy1 - Tue Sep 16, 2008 6:05 am

So, if we were to make a fixed point class would it still be more beneficial than floating-point?
What about double? Is a 64bit integer used instead or what?

#162912 - DensitY - Tue Sep 16, 2008 7:29 am

the benefits is purely in the speed department. precision is what suffers. Ideally I personally avoid fixed point numbers overflowing 32bits on the ds.

#162956 - sgeos - Wed Sep 17, 2008 3:04 am

Lazy1 wrote:
What about double?

Last I heard, doubles are not used in games because they are "too slow", but this may be changing on higher end platforms (ie, 64 bit systems).

#163180 - mreaves - Wed Sep 24, 2008 7:37 pm

doubles aren't so slow nowadays, especially on new vectorised processors...

Fixed point precision on the DS should be fine, a 19:12 format gives you a very decent fraction range (enough for what is needed anyway).

I also wouldn't wrap fixed point stuff in a class. Lots to overload plus you'll lose a little bit of speed because of class overhead. It is fairly trivial to set up a bunch of Macros for all your needs.

#163187 - tepples - Wed Sep 24, 2008 8:43 pm

mreaves wrote:
you'll lose a little bit of speed because of class overhead.

What class overhead? In C++, you pay for what you use. I don't know of any necessary space or time overhead that methods in a class have over equivalent functions outside of a class. I'd imagine that a good C++ compiler would optimize inline methods of a class with one field, no virtual methods, no explicit destructor, etc. to be as fast as inline functions or even macros. Have you implemented it both ways and profiled the result?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#163189 - DensitY - Wed Sep 24, 2008 9:13 pm

as tepples says, unless you do a polymorphic design of your classes the compiler generally does a good job.

doubles are still avoided on PC even when usage of SIMD, simply because its alot quicker todo 4 parallel operations vs 2. GPUs, not entirely sure.

#163198 - Lazy1 - Thu Sep 25, 2008 3:16 am

Well, I just asked about double since it was being used in some code I was converting to fixed point.
I have no idea why they would use that over float since everything seems to work great even using fixed point.

Right now I have the YM3812 emulator from MAME 99% converted to fixed point, thanks for all the helpful information you all posted.
In the end I chose not to make a full fixed point class since I got bored part way through.

Now I have to hope it will run acceptably on the ARM9/ARM7 :D

#163203 - mreaves - Thu Sep 25, 2008 6:32 am

tepples wrote:
mreaves wrote:
you'll lose a little bit of speed because of class overhead.

What class overhead? In C++, you pay for what you use. I don't know of any necessary space or time overhead that methods in a class have over equivalent functions outside of a class. I'd imagine that a good C++ compiler would optimize inline methods of a class with one field, no virtual methods, no explicit destructor, etc. to be as fast as inline functions or even macros. Have you implemented it both ways and profiled the result?

In my experience a class version will just never be as efficient as using specific code or macros. Lets be honest, it isn't like it is super hard to NOT have a class wrapper and just used fixed point macros. But hey, what do I know.

#163204 - a128 - Thu Sep 25, 2008 8:04 am

I put my fixpoint C++ class online...a few weeks ago

http://a128.blogspot.com/2008/09/fixed-point-class-nds-2008.html