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 > sprite rotation issue

#20506 - tethered - Wed May 12, 2004 8:51 am

hello everyone,

i'm attempting to do a little hardware sprite rotation, and i'm running into some difficulty. for some reason, when i set the rotation bit in attribute 0, my sprite turns into a single colored box. i've spent hours reading everything i can find on the subject and nothing is very clear about how this works. i think i've done everything i need to do... here's the source, its pretty straight-forward, all in the same function...

Code:
#include "math.h"
#include "includes\gba.h"
#include "graphics\sprites.pal.c"
#include "graphics\ship.raw.c"


OAMEntry sprites[128];
pRotData rotData = (pRotData)sprites;


#define PI 3.14159265


int main(void)
{
    u16 i;
    u16* temp;
    float f_x = 104, f_y = 64;
    float f_thrust = 0.05;
    float f_xDisplacement = 0, f_yDisplacement = 0;
    float f_angle = 0, f_radian = 0;
    float f_sin_array[256], f_cos_array[256];
    int pa, pb, pc, pd; // used for sprite rotation
   
    SetMode(MODE_0 | OBJ_ENABLE | OBJ_MAP_1D);
   
    // generate SIN array
    f_angle = 0;
    for (i = 0; i < 256; i++)
    {
        f_radian = f_angle * (PI / 180);
        f_sin_array[i] = sin(f_radian);
        f_angle+=1.40625;
    }

    // generate COS array
    f_angle = 0;
    for (i = 0; i < 256; i++)
    {
        f_radian = f_angle * (PI / 180);
        f_cos_array[i] = cos(f_radian);
        f_angle+=1.40625;
    }
    f_angle = 0;
   
    // clear any sprite data from the screen
    for (i = 0; i < 128; i++)
    {
        sprites[i].attribute0 = 160;
        sprites[i].attribute1 = 240;
        sprites[i].attribute2 = 0;
    }
   
    // load palette
    for (i = 0; i < 256; i++)
        OBJ_PaletteMem[i] = sprite_Palette[i];
       
    // load sprite data
    for (i = 0; i < 512; i++)
        OBJ_Data[i] = ((u16*)ship_Bitmap)[i];
       
    // set ship sprite oam data
    sprites[0].attribute0 = COLOR_256 | SQUARE | ROTATION_FLAG | 64;
    sprites[0].attribute1 = SIZE_32 | 0 | 104;
    sprites[0].attribute2 = 0;
       
    // game loop
    while(1)
    {
       
        if(keyDown(KEY_LEFT))
        {
            f_angle = f_angle - 1;
            if (f_angle < 0)
                f_angle = 255;
        }
       
        if(keyDown(KEY_RIGHT))
        {
            f_angle = f_angle + 1;
            if (f_angle > 255)
                f_angle = 0;
        }
       
        if(keyDown(KEY_UP))
        {
            f_xDisplacement = f_xDisplacement + f_sin_array[((int)f_angle)] * f_thrust;
            f_yDisplacement = f_yDisplacement + f_cos_array[((int)f_angle)] * f_thrust;
        }

        if(keyDown(KEY_DOWN))
        {
            // drag = .95
            f_xDisplacement = f_xDisplacement * .95;
            f_yDisplacement = f_yDisplacement * .95;
        }
       
        // update x and y coords
        f_x += f_xDisplacement;
        f_y -= f_yDisplacement;
        if (f_x > 240 - 32) f_x = 0;
        if (f_x < 0) f_x = 240 - 32;
        if (f_y > 160 - 32) f_y = 0;
        if (f_y < 0) f_y = 160 - 32;
       
        // update sprite attribs
        sprites[0].attribute0 = COLOR_256 | SQUARE | ROTATION_FLAG | ((int)f_y);
        sprites[0].attribute1 = SIZE_32 | ((int)f_x);
       
        // rotate sprite
        pa = ((s16)((32) * f_cos_array[((int)f_angle)])) >> 8;
        pb = ((s16)((32) * f_sin_array[((int)f_angle)])) >> 8;
        pc = ((s16)((32) * -f_sin_array[((int)f_angle)])) >> 8;
        pd = ((s16)((32) * f_cos_array[((int)f_angle)])) >> 8;
        rotData[0].pa = pa;
        rotData[0].pb = pb;
        rotData[0].pc = pc;
        rotData[0].pd = pd;
       
        // vdraw . . .
        while (REG_VCOUNT < 160);
       
        // update oam memory
        temp = (u16*)sprites;
        for (i = 0; i < 512; i++)
            OAM_Mem[i] = temp[i];
       
        // vblank . . .
        while (REG_VCOUNT >= 160);

    }
   
    return 0;
}


what am i doing wrong? its almost 4am and i'm about to cash out for the night, so i'll let this thread marinate overnight...

o, also, i know its not the most efficient code in the world right now... like i've said before in other threads, i'm just experimenting now to get a better understanding of the platform... otpimization comes later...

thanks,


chuck

#20527 - poslundc - Wed May 12, 2004 2:41 pm

First of all, stop using floats! This is more than a simple optimization; it is a fundamental design issue.

Meanwhile, all of your rotation paramters are coming out as zero. You can see this from a simple numerical analysis. Take your calculation of pa for example:

Code:
   pa = ((s16)((32) * f_cos_array[((int)f_angle)])) >> 8;


You know that f_cos_array will return a value between zero and one. For the moment, lets assume you pass in zero as your angle and get one (the function's maximum) as your cosine.

You multiply 1 * 32, which yields 32. You now shift right by 8, which is the same as dividing by 256... suddenly you're left with a number less than one (which is zero in integral terms).

This means no matter what your angle is, you will always get zero as your rotation parameter.

The rotation attributes are 8.8 fixed-point numbers. If you are at all unsure of what this means, please read up on fixed-point math, because you will absolutely need it for GBA programming.

As for making your code work, try the following line instead:

Code:
   pa = (s16)(256.0 * f_cos_array[(int)f_angle]);


Dan.

#20540 - tethered - Wed May 12, 2004 8:24 pm

Point noted about floats and fixed point math. I'm aware of fixed point math but don't have a solid understanding of it as of yet. For the time being, I'm just tryin to feel out the console and gain a better understanding for where things need to be stored in memory, etc. I intend on reading more into some of the fundamental stuff as the need for them arises.

I see what you're saying regarding my rotation parameters all coming out as 0.

Code:
pa = (s16)(256.0 * f_cos_array[(int)f_angle]);
pa = (s16)(256.0 * f_sin_array[(int)f_angle]);
pa = (s16)(256.0 * -f_sin_array[(int)f_angle]);
pa = (s16)(256.0 * f_cos_array[(int)f_angle]);


Using this block of code, however, I get similar results: my ship turns into a single colored box, but now as you change the angles, the colors inside the box change in vertical bands.

I guess my real problem at this point is that I don't fully understand what data needs to be put where (in registers and memory), and I'm still solidifying my understanding of the more complex areas of C as I go along. And at the same time, the tutorials all seem to be pretty poorly written. For example, The Pern Project... its good if you just need a quick review or to use as a reference, but for someone that has no experience with the console its hard to make any sense out of it... it's all over the place!

So any advice is welcome. Explanations, links to documentation, anything that will help me continue to move in the right direction.


- Chuck

#20543 - Cearn - Wed May 12, 2004 9:19 pm

erm, that should be
Code:

pa = (s16)(256.0 * f_cos_array[(int)f_angle]);
pb = (s16)(256.0 * f_sin_array[(int)f_angle]);
pc = (s16)(256.0 * -f_sin_array[(int)f_angle]);
pd = (s16)(256.0 * f_cos_array[(int)f_angle]);

, not a four times over.

Some additional info about pa-pd. These form a matrix that describes the affine transformation between the screen and texture (=tiles) space. The only thing is that the transformation goes from screen to texture space, and not the other way round. The matrix you can find at Pern is the other way round. For a full story, see http://user.chem.tue.nl/jakvijn/tonc/affine.htm

#20545 - tethered - Wed May 12, 2004 9:29 pm

doh!

#20547 - poslundc - Wed May 12, 2004 10:29 pm

Cearn wrote:
For a full story, see http://user.chem.tue.nl/jakvijn/tonc/affine.htm


Cearn, that tutorial is awesome! When did you create it? It ought to be FAQ'd!

Dan.

#20549 - Cearn - Wed May 12, 2004 11:51 pm

Praise from a master, that's always nice :)
I've been working on it for a while now, but kept delaying any formal announcement because there's always one more thing to add. Should be soon now that I finally have a way to test on hardware. Or maybe until I finally get a nice mode7 demo with variable pitch. Or fully switch to devkitARM, dang, there I go again. See what I mean about constant delaying? :P

#20568 - poslundc - Thu May 13, 2004 4:42 am

Well, it's some good stuff you've got going there. I keep waiting for someone to develop a viable alternative to Pern and gbajunkie that doesn't teach the normal bad habits they do.

Oh, and I'm hardly a master, I just post a lot. :P

Dan.

#20592 - tepples - Thu May 13, 2004 3:43 pm

I could probably write part of a tutorial. I'll bring up another topic about this.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#20645 - NoMis - Fri May 14, 2004 8:29 am

Great tutorial! I never knew how this thing realy work, i just copied the code but now its clear :)