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.

Beginners > Points on a circle

#164342 - crazakp - Wed Oct 29, 2008 1:41 am

I looked through a couple threads about trig functions and bit shifting and fixed point numbers before deciding to post. I don't think this is an issue with any of those, but I could be wrong.

What I'd like to do is move a sprite in a circle. Starting at 0 degrees, if the user presses up, it moves up a degree, if they press down, down a degree.

So to accomplish this, I would just need to figure out the (x,y) coordinate based on the angle, radius, and center.

Since I just started learning about fixed point numbers and LUTs, I tried to make a simple example in mode 3, where I would just draw a circle.

My problem is that it draws the circle at (0,0) no matter what. Could someone help me figure out what's wrong with my code? I'm using tonc.

Code:

#define MEM_VRAM   0x06000000
#define vid_mem      ((COLOR*)MEM_VRAM)
#define CLR_RED      0x001F

int main()
{
   COLOR clr = CLR_RED;
   int i,x,y,radius,cx,cy,angle;
   
   radius = 25<<8;
   cx = 75<<8;
   cy = 75<<8;
   
   REG_DISPCNT= DCNT_BG2 | DCNT_MODE3;
   
   vid_mem[(cy>>8)*M3_WIDTH+(cx>>8)]= clr;
   
   for(i=0; i<360; i++)
   {
      angle = (i * 182);
      
      x = cx + radius * lu_cos(angle)>>12;
      y = cy + radius * lu_sin(angle)>>12;
      
      vid_mem[(y>>8)*M3_WIDTH+(x>>8)]= clr;
   }
   
   while(1);

   return 0;
}


Since lu_cos has a range of [0,FFFFh], I divided that by 360 to come up with the multiplier for each degree (182).


EDIT:
I got around this problem by just using bresenham's circle algorithm, but I'd still like to know what I did wrong because I'm also trying to calculate projectile motion, which uses trig functions.

#164346 - Cearn - Wed Oct 29, 2008 8:26 am

The creators of C, pranksters that they are, made it so that the precedence of bit-shifts rank lower than additions (and the other bitwise operators lower than == and !=). This code:
Code:
y = a + b*c>>d;
is parsed as
Code:
y = (a + b*c)>>d;
, which is not what you're after.

Change this:
Code:
      x = cx + radius * lu_cos(angle)>>12;
      y = cy + radius * lu_sin(angle)>>12;
to this:
Code:
      x = cx + (radius * lu_cos(angle)>>12);
      y = cy + (radius * lu_sin(angle)>>12);

#164368 - crazakp - Wed Oct 29, 2008 9:27 pm

Your changes worked. But I'm still confused about something.

Code:

      x = cx + (radius * lu_cos(angle)>>12);
      y = cy + (radius * lu_sin(angle)>>12);


So in the parenthesis, the multiplication would happen before the bit shift. Wouldn't that be (8.8Q * .12Q) and according to my understanding the resulting fixed point number would be 8.96Q (8 * 12). I had thought about order of precedence earlier, and did this:

Code:

    y = a + b * (c>>12)


And I don't think it worked. I'm pretty sure my understanding is wrong so any clarification would be appreciated. Thanks for your help.

#164377 - Cearn - Wed Oct 29, 2008 11:13 pm

crazakp wrote:
Your changes worked. But I'm still confused about something.

Code:

      x = cx + (radius * lu_cos(angle)>>12);
      y = cy + (radius * lu_sin(angle)>>12);


So in the parenthesis, the multiplication would happen before the bit shift. Wouldn't that be (8.8Q * .12Q) ...

Yes, and that's what you want to happen. For accuracy, you'll want to have as many bits behind the 'decimal' point as possible.

crazakp wrote:
... and according to my understanding the resulting fixed point number would be 8.96Q (8 * 12).

The numerical values of the numbers multiply, but the fixed-point bits add. It may help to compare it to a regular decimal case: (a*10^8) * (b*10^12) = a*b * 10^20. Analogously, 8.8Q*.12Q = 8.20Q. Of course you can't simply add that to the cx (which is 8.8Q), just like 1 meter + 1 cm is not 2 meters (or 2 cm). For addition, you have to convert to the same units again -- in this case the 8.20Q number is converted to 8.8Q by dividing by the 1<<12 (the .12Q equivalent of one).

Fixed-point math in hex is a lot like fixed-point math in decimal. If it helps, try to see what it would look like in decimal (where you should be able to find many examples in schoolwork) and once you have that down apply it to hex/binary.

crazakp wrote:
I had thought about order of precedence earlier, and did this:

Code:

    y = a + b * (c>>12)


And I don't think it worked. I'm pretty sure my understanding is wrong so any clarification would be appreciated. Thanks for your help.

In this case, c is the sine or cosine with 12 fractional bits. The sine and cosine functions are all fractional bits, so removing all those bits by the early right-shift is not a good idea.

#164382 - crazakp - Thu Oct 30, 2008 2:56 am

I think I have a better understanding now. Thanks for the thorough explanation.