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 Displaying

#168409 - semihce - Mon Apr 27, 2009 10:02 pm

Hi guys,

I am trying to display a sprite on GBA screen. I've done the things that are said in this link

http://home.no/neogeo/HOVEDSIDE_INDEX/GBA_HOVEDSIDE_INDEX_ENGELSK/GBA%20HTML%20LEKSJONER%201-5/GBA_Lek4_english.htm

But I cant see the sprite on the screen. When I look at "Tools/Tile Viewer", I see my sprite stands there at the address 0x6010000. Why I see my sprite at that address but I cant see it on screen? I merely get a black screen!! Why? Please help me..

#168413 - semihce - Tue Apr 28, 2009 2:40 pm

I couldnt get answer to my question and I am trying to describe my problem little bit more..

Code:
int main()
{
   u16 loop;
   s16 x = 10;
   s16 y = 50;
   
   //set mode 1, switch on sprites, set storing of sprite tiles as 1D
   SetMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);
   
   InitializeSprites();   //set all sprites outside the screen (removes unwanted sprites)
   
   sprites[0].attribute0 = COLOR_256 | TALL | y;  //set 256 colors, shape and y-coordinate
   sprites[0].attribute1 = SIZE_64 | x;  //set shape and x-coordinate
   sprites[0].attribute2 = 0;   //points to where in VRAM we get the tile data from

   for(loop = 0; loop < 256; loop++)          //transfer palette data into memory (256 colors)
   {
      OBJ_PaletteMem[loop] = myPaletteData[loop];
   }
   
   for(loop = 0; loop < 1024; loop++)   //transfer sprite tile data into memory (32x64)
   {
      OAM_Data[loop] = myTileData[loop];
   }
   
   while(1)  //main loop
   {
      vsync();  //wait for screen to finish drawing.
      CopyOAM();  //copy sprite info (OAM) into OAM memory
   }
}


I've written nearly the same code above. I am trying to display a sprite on GBA screen. But I cant see the sprite on the screen altough I see my sprite on "Tools/Tile Viewer" with an address of 0x6010000. I see only a black screen. What can be the reason?

#168430 - Ruben - Wed Apr 29, 2009 3:33 am

Hm, what's vsync defined as? And also, use a #define for the sprite's displacement (negative x/y will overflow into the other bits messing everything up)

And make u16 loop into a u32/int!!! That's probably one of the most common-yet horrible code issues ever on the GBA.

EDIT: Also, can you link a binary?

#168438 - semihce - Wed Apr 29, 2009 12:05 pm

Actually, the code I've pasted and the one I used is different. I am using a ready library to display a sprite. For example, to display a sprite I just call the "Lypson_SimpleSpriteObject" class from the library. The code I've used is completely like this:

Code:
void init()
{
   Lypson_VblankCopier::init();
   Lypson_Interrupt::enableInterrupts();
   
   //set all sprites outside the screen (removes unwanted sprites)
   Lypson_Sprite::initializeSprites();
   
   // Set graphics mode
   #define SCREENMODE_1    0x1     ///< Enable screen mode 1
   #define OBJMAP_1D       0x40    ///< 1D object(sprite) mapping
   #define OBJ_ENABLE      0x1000   //Enables sprites
   
   //set mode 1, switch on sprites, set storing of sprite tiles as 1D
   Lypson_Graphics::setMode( SCREENMODE_1 | OBJ_ENABLE | OBJMAP_1D );
}

int main(void)
{
   init();
   
   Lypson_SimpleSpriteObject *simpleSprite = new Lypson_SimpleSpriteObject(character_alouette_Bitmap,
                                                         character_alouette_Palette,
                                                         Lypson_Sprite::Size_32x64,
                                                         true);
   
   while(true)
   {
      Lypson_Graphics::waitForVblank();
      Lypson_Sprite::updateOAMattributes();
   }
   
   Lypson_Error::halt();
   return(0);
}


If you look at the code carefully, you'll understand that there is no difference between this code and the code that I gave before.

Here is a link to the output GBA file.
http://ktuce.ktu.edu.tr/~baysemi/GameRevolution.gba

#168439 - Ruben - Wed Apr 29, 2009 12:09 pm

From what I see in the binary, your sprite ends up at (192,128), index 127, in 16 colours and every other sprite is actually not disabled nor placed outside the screen. Are you sure you've got the structures set up correctly?

#168441 - semihce - Wed Apr 29, 2009 12:23 pm

What did you mean with "your sprite ends up at (192,128), index 127, in 16 colours".

I also want to give a link to the header files:

http://ktuce.ktu.edu.tr/~baysemi/character_alouette.pal.h
http://ktuce.ktu.edu.tr/~baysemi/character_alouette.raw.h

In other sprite displaying examples I see that they use 16bit in each pixel of tileData and paletteData.
But I used 16bit paletteData and 8bit tileData, as you can understand from here my tileDatas are indexes to the paletteData.

#168442 - Ruben - Wed Apr 29, 2009 12:29 pm

In short, it's similar to doing this...

Code:
for(int i = 0 ; i < 128 ; i++) {
    OAM_Buffer[i].attr0 = 0;
    OAM_Buffer[i].attr1 = 0;
    OAM_Buffer[i].attr2 = 0;
}

OAM_Buffer[127].attr0 = OBJ_TALL + 128;
OAM_Buffer[127].attr1 = OBJ_SIZE_32 + 192;


And that wasn't the declarations I was talking about. I meant the declarations where you define the OAM object structure, the shadow buffer, etc.

EDIT: Fixed a typo >>'

#168443 - semihce - Wed Apr 29, 2009 12:41 pm

I am giving the function "Lypson_Sprite::initializeSprites();" which sets all sprites outside the screen..

Code:
for( int i = 0; i < 128; i++)
{
   Lypson_Sprite::sprites[i].attribute0 = 160;  //y to > 159 (outside screen -> invisible)
   Lypson_Sprite::sprites[i].attribute1 = 240;  //x to > 239 (outside screen -> invisible)
   Lypson_Sprite::sprites[i].attribute2 = 0;
}


I hope this is what you want to see..

#168444 - Ruben - Wed Apr 29, 2009 12:44 pm

Not exactly >>'

I needed to see the "GBA.h" file or whatever you called it, that defines something like

Code:
typedef struct __OAM_t {
    u16 attr[4];
} OAM_t;

#168445 - Ruben - Wed Apr 29, 2009 12:48 pm

Actually, on further inspection...

The data in IWRAM is fine.. it's just that you're not copying it to OAM correctly.

What exactly does Lypson_Sprite::updateOAMattributes() do?

#168446 - semihce - Wed Apr 29, 2009 12:51 pm

Code:
//This is the way attributes are defined
struct Lypson_Sprite_structure {
   u16 attribute0;
   u16 attribute1;
   u16 attribute2;
   u16 filler;
};

//This is a struct instance
static Lypson_Sprite_structure sprites[128];

//And this is how it is used
Lypson_Sprite::sprites[index].attribute0 = 160;  //y to > 159 (outside screen -> invisible)
Lypson_Sprite::sprites[index].attribute1 = 240;  //x to > 239 (outside screen -> invisible)
Lypson_Sprite::sprites[index].attribute2 = 0;

#168447 - Ruben - Wed Apr 29, 2009 12:59 pm

Code:
//This is a struct instance
static Lypson_Sprite_structure sprites[128];


I'm not sure since I don't see your full code, but I get the feeling you wouldn't want to name that static. And also, can you please tell me what Lypson_Sprite::updateOAMattributes() does? As in, the code?

#168448 - semihce - Wed Apr 29, 2009 1:02 pm

Code:
bool Lypson_Sprite::updateOAMattributes()
{
   Lypson_Sprite_structure *OAM_memory = (Lypson_Sprite_structure *)OAMmem;
   for(int i=0; i<128; i++)
      OAM_memory[i] = sprites[i];
   return true; // Needed to use this method as an interrupt handler function.
}

#168449 - Ruben - Wed Apr 29, 2009 1:05 pm

Hm, what's OAMmem defined as?

(Also, I noticed 8-bit copies to palette.. my guess is that you're using memcpy. Please don't use it when copying to the palette memory, as it can only be written to in 16-bit chunks, and memcpy tends to like using 8-bit chunks)

#168450 - semihce - Wed Apr 29, 2009 1:14 pm

Very annoying....

My code works in VisualHam but it doesnt work when i compile it outside of VisualHam.


Last edited by semihce on Wed Apr 29, 2009 3:03 pm; edited 1 time in total

#168451 - Ruben - Wed Apr 29, 2009 1:16 pm

No, I don't think this is the reason of the problem, otherwise it'd be a colour error, not a memory error. Also, I noticed horribly un-optimized code. Are you using -O2?

#168454 - Cearn - Wed Apr 29, 2009 2:51 pm

semihce wrote:
Code:
struct Lypson_Sprite_structure {
   u16 attribute0;
   u16 attribute1;
   u16 attribute2;
   u16 filler;
};

bool Lypson_Sprite::updateOAMattributes()
{
   Lypson_Sprite_structure *OAM_memory = (Lypson_Sprite_structure *)OAMmem;
   for(int i=0; i<128; i++)
      OAM_memory[i] = sprites[i];
   return true; // Needed to use this method as an interrupt handler function.
}
This unfortunately doesn't work anymore with devkitARMs after r19 due to a change in how structs are aligned in memory and some internal details of memcpy. For details, see tonc:data alignment. Either force 32-bit alignment on the struct, or use a dedicated copier like memcpy (or DMA). Preferably both.

Code:
struct Lypson_Sprite_structure {
   u16 attribute0;
   u16 attribute1;
   u16 attribute2;
   u16 filler;
} __attribute__ ((aligned (4)));

bool Lypson_Sprite::updateOAMattributes()
{
   memcpy(OAMmem, sprites, 128*sizeof(Lypson_Sprite_structure));
   return true;
}

The GBA's palette, VRAM and OAM regions only allow 16-bit or 32-bit writes to them; byte-writes corrupt data. memcpy will copy in 32-bit chunks if both the source and destination are 32-bit aligned and there's more than 16 bytes to copy. If not, it'll do byte-writes, which would be bad.

#168455 - Ruben - Wed Apr 29, 2009 3:01 pm

Ah, Cearn, always making me look like a noobie (which I probably am). :P

#168462 - sverx - Wed Apr 29, 2009 4:33 pm

Cearn wrote:
This unfortunately doesn't work anymore with devkitARMs after r19 due to a change in how structs are aligned in memory and some internal details of memcpy.


Do you mean structs won't be "automatically" word aligned? :| I really didn't know that... good to know!

#168466 - semihce - Wed Apr 29, 2009 6:13 pm

Cearn wrote:
semihce wrote:
Code:
struct Lypson_Sprite_structure {
   u16 attribute0;
   u16 attribute1;
   u16 attribute2;
   u16 filler;
};

bool Lypson_Sprite::updateOAMattributes()
{
   Lypson_Sprite_structure *OAM_memory = (Lypson_Sprite_structure *)OAMmem;
   for(int i=0; i<128; i++)
      OAM_memory[i] = sprites[i];
   return true; // Needed to use this method as an interrupt handler function.
}
This unfortunately doesn't work anymore with devkitARMs after r19 due to a change in how structs are aligned in memory and some internal details of memcpy. For details, see tonc:data alignment. Either force 32-bit alignment on the struct, or use a dedicated copier like memcpy (or DMA). Preferably both.

Code:
struct Lypson_Sprite_structure {
   u16 attribute0;
   u16 attribute1;
   u16 attribute2;
   u16 filler;
} __attribute__ ((aligned (4)));

bool Lypson_Sprite::updateOAMattributes()
{
   memcpy(OAMmem, sprites, 128*sizeof(Lypson_Sprite_structure));
   return true;
}

The GBA's palette, VRAM and OAM regions only allow 16-bit or 32-bit writes to them; byte-writes corrupt data. memcpy will copy in 32-bit chunks if both the source and destination are 32-bit aligned and there's more than 16 bytes to copy. If not, it'll do byte-writes, which would be bad.


How can I use memcpy() ?..
I got this error: "memcopy() is not declared in this scope?".. Should i include any header file?

#168467 - semihce - Wed Apr 29, 2009 6:18 pm

HEYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY..

ADDING THIS CODE "__attribute__ ((aligned (4)))" is enough.

THANK YOU VERY MUCH.. I LOVE GBA FORUM :D:D:D

#168468 - elhobbs - Wed Apr 29, 2009 6:19 pm

semihce wrote:
How can I use memcpy() ?..
I got this error: "memcopy() is not declared in this scope?".. Should i include any header file?

memcpy != memcopy ;)