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.

Coding > sprites in mode 4

#15449 - slboytoy - Thu Jan 22, 2004 9:23 pm

hi there

i'm working on a program that draws a background in mode 4. i'm trying to modify this so that a sprite is displayed over top of the background. the code compiles ok but when i run it on Visual Boy Advance the sprite does not show up. i checked the map view and the OAM viewer and everything seems to be working. i can push a key and control the sprite animation on the OAM viewer but, like i said, i does not show up on the game screen.

anybody have any ideas/suggestions about how to fix this?

thanks

#15452 - sajiimori - Thu Jan 22, 2004 9:39 pm

Did you enable sprites in REG_DISPCNT?

Can you see the sprite if you don't turn on the background?

#15453 - slboytoy - Thu Jan 22, 2004 9:42 pm

yeah. here's the code for that in case i buggered it up some how

SetMode(MODE_4 |BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D);

i can't see the sprite in mode 4 with the backgound off...only mode 2

#15454 - johnny_north - Thu Jan 22, 2004 9:51 pm

Half the memory for sprites is available in mode 4 than for mode 2. Check one of the available tech refs to be sure you're selecting them correctly (GBATEK or PERN).

#15455 - slboytoy - Thu Jan 22, 2004 9:57 pm

i've read a couple of places about the OAM memory being halved in mode 4 but i haven't seen anything on how to actually fix the problem. do i just change the starting address of the OAM in my program?

#15456 - johnny_north - Thu Jan 22, 2004 10:05 pm

Seriously, read one of those two docs. The pern project will tell you exactly what to do. The key is that you will have fewer sprite tiles to work with not fewer sprite objects.

#15458 - slboytoy - Thu Jan 22, 2004 10:17 pm

i don't see where it makes mention to using sprites in mode 4 on the pern project site. can you possibly point me in the right direction? it's not in the sprite tutorial (day 3). is it somewhere else or am i just an idiot?

#15459 - johnny_north - Thu Jan 22, 2004 10:25 pm

From pern day 3:

Quote:
Character data starts at 0x6010000 and extends for 32KB. It consists of 1024 8x8 16 color tiles (256 color tiles actually take two 8x8 slots). The character name bits in attribute 2 refer to one of these tiles. The problem with this set up is that bit map modes (mode 3,4, and 5) actually extend into the character data area of memory cutting it in half. This means that only character names greater than 511 are allowed in the bitmap modes.

#15463 - slboytoy - Thu Jan 22, 2004 10:38 pm

so......what does that mean?????????

what do i actually need to change? the loop for copying the array into the OAM? or is it the one for copying the sprite to the screen? or is it the frame markers that need to be reset??

i tried changing each of these separtely to no avail. the closest i came was changing the loop for copying the sprite array into the OAM. this allowed me to see the first frame of the sprite (on the OAM viewer only) but i can't cycle it up and down like i was previously

#15467 - sajiimori - Thu Jan 22, 2004 10:56 pm

Don't confuse OAM with character (tile) memory.

There are normally 1024 sprite characters available (when using 16 color sprites). In modes 3-5, only the second 512 of them are available.
Code:

#define CHAR_MEMORY (u8*)0x6010000
#define CHAR_LOCATION(n) (CHAR_MEMORY+32*(n))

You should load your sprites starting at CHAR_LOCATION(512).

Understand now?

#15476 - slboytoy - Thu Jan 22, 2004 11:18 pm

i didn't work. the "CHAR_MEMORY" definition in the previous example is handled by a value called "OAMData" however this is defined as an u16 instead of just an u8. do i not have to shift sprite frames for my active frame up? i did this and it didn't work.

any extra help would be appreciated

#15481 - sajiimori - Fri Jan 23, 2004 12:14 am

I can't tell what you're doing unless you post some code.

#15488 - tepples - Fri Jan 23, 2004 3:23 am

In modes 3 through 5, you need to copy your sprite cel data into some location between 0x06014000 and 0x06017FFF. These correspond to attribute 2 tile numbers 512 through 1024. Quickest way to test for this is to run your program in VisualBoyAdvance, open the Map Viewer, switch to frame 1, and look for some corruption in the bottom half.

Posting all source code that writes to OAM or to VRAM (or writes to structures that are copied directly to OAM) would help the most. If you can't do that, even uploading your program's binary might help, as some readers of this forum have mad ski11z with VBA's viewers and, after having analyzed the program, will tell you exactly what you're doing wrong and what he or she did to find it.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#15634 - slboytoy - Mon Jan 26, 2004 7:48 pm

thanks everyone for your help. i'm pretty close to getting it to work but it's still not quite there. here's my code. if anybody sees anything that i did wrong let me know.

thanks again

Code:
 
#include "gba.h"       //GBA register definitions
#include "keypad.h"     //button registers
#include "dispcnt.h"    //REG_DISPCNT register #defines
#include "sprit.h"      //my generic sprite header file
#include "numbers.h"   //sprite info
#include "palette.h"   //palette info
#include "backgroundpic.h"   //holds the image information in an array

//*****OAMData = 0x6014000 <==this was done in gba.h*****


#define MULTIBOOT const int __gba_multiboot
MULTIBOOT = 1;

//create an OAM variable and make it point to the address of OAM
u16* OAM = (u16*)0x7000000;

//create the array of sprites (128 is the maximum)
OAMEntry sprites[128];

//create the rotation and scaling array (overlaps the OAMEntry array memory)
pRotData rotData = (pRotData)sprites;

//animated sprite structure required
typedef struct
{
   u16 x;         //x and y position on screen
   u16 y;
   u16 spriteFrame[10];     //animation frame
   int activeFrame;        //which frame is active
}Sprite;

Sprite numSprite;      //create instance

//Copy our sprite array to OAM
void CopyOAM()
{
   u16 loop;
   u16* temp;
   temp = (u16*)sprites;
   for(loop = 0; loop < 128*4; loop++)
   {
      OAM[loop] = temp[loop];
   }
}

//Set sprites to off screen
void InitializeSprites()
{
   u16 loop;
   for(loop = 0; loop < 128; loop++)
   {
      sprites[loop].attribute0 = 160;  //y to > 159
      sprites[loop].attribute1 = 240;  //x to > 239
   }
}

//move the background image into memory
void PlotPixel(int x,int y, unsigned short int c)
{
   VideoBuffer[(y) * 120 + (x)] = (c);
}

//wait for the screen to stop drawing
void WaitForVsync()
{
   while((volatile u16)REG_VCOUNT != 160){}
}

void GetInput()
{
   if(!(*KEYS & KEY_UP))      //if the up key is pressed
   {
      if (numSprite.activeFrame > 0)
      {
         numSprite.activeFrame = numSprite.activeFrame - 1;
         sprites[0].attribute2 = numSprite.spriteFrame[numSprite.activeFrame];
      }
   }
   if(!(*KEYS & KEY_DOWN))         //if the up down is pressed
   {
       if (numSprite.activeFrame < 9)
       {
          numSprite.activeFrame = numSprite.activeFrame + 1;
         sprites[0].attribute2 = numSprite.spriteFrame[numSprite.activeFrame];
      }
   }
}


int main()
{
   u16 loop;       //generic loop variable
        numSprite.x = 25;   //variables to hold position of number sprite on screen
   numSprite.y = 25;
   int x, y;

          SetMode(MODE_4 |BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D); //set mode 4, enable sprites, 1d mapping and enable background 2

   for(loop = 0; loop < 256; loop++)          //load the palette into memory
      OBJPaletteMem[loop] = numberPalette[loop];

   for(loop = 0; loop < 256; loop++)                 //256 entries allowed
      BGPaletteMem[loop] = backgroundpicPalette[loop]; //load the palette into palette memory
   
   InitializeSprites();

   sprites[0].attribute0 = COLOR_256 | SQUARE | numSprite.y;   //setup sprite info, 256 colour, shape and y-coord
   sprites[0].attribute1 = SIZE_16 | numSprite.x;             //size 16x16 and x-coord
   sprites[0].attribute2 = 512;                              //pointer to tile where sprite starts

       for(loop = 0; loop < 1280; loop++)                      //load sprite image data
   {
      OAMData[loop] = numData[loop];
   }

   numSprite.activeFrame = 512;                    //set the initial active frame markers
   numSprite.spriteFrame[0] = 512;                 //set the frame markers
   numSprite.spriteFrame[1] = 520;
   numSprite.spriteFrame[2] = 528;
   numSprite.spriteFrame[3] = 536;
   numSprite.spriteFrame[4] = 544;
   numSprite.spriteFrame[5] = 552;
   numSprite.spriteFrame[6] = 560;
   numSprite.spriteFrame[7] = 568;
   numSprite.spriteFrame[8] = 576;
   numSprite.spriteFrame[9] = 584;


   while(1)                                //main loop
        {
      //plot the background
      for(y = 0; y < 160; y++)                  //screen height
      {
         for(x = 0; x < 120; x++)          //screen width
         {
            PlotPixel(x,y, backgroundpicData[y*120+x]);   //load image data into
         }                  //memory pixel by pixel
      }
   
      //control the sprite
      GetInput();
      WaitForVsync();         //waits for the screen to stop drawing
      CopyOAM();         //Copies sprite array into OAM.
   }
}

#15641 - sajiimori - Mon Jan 26, 2004 11:33 pm

What does it do wrong?

#15644 - dagamer34 - Tue Jan 27, 2004 12:25 am

Try plotting your pixels AFTER VSync. That might help. Other than that, all I can say is to look at the demos on this site, one of them deals with sprites in mode 4.

Try doing the simple stuff and build up from that. Remove code as needed. Its easier to fix a car engine after you have opened the hood, right?
_________________
Little kids and Playstation 2's don't mix. :(

#15648 - sajiimori - Tue Jan 27, 2004 12:33 am

Quote:

Try plotting your pixels AFTER VSync. That might help.

It doesn't really matter. In fact, the plotting really only needs to be done once, before the main loop. All the redundant copying will slow things down quite a bit.

#15734 - slboytoy - Wed Jan 28, 2004 6:43 pm

well i got the initial loading figured out. thanks everyone for helping with that. now i was just wondering how many frames i can load into memory for each sprite.

the idea is i have one sprite containing the data for 16 seperate frames. i want to be able to scroll through the frames using the keypad.

do i need to split these frames into different sprites? if so, how many frames will each be able to hold?

#15741 - tepples - Wed Jan 28, 2004 9:09 pm

Either you can keep all your sprite cels in sprite cel VRAM (0x06014000-0x06017fff) and switch among them in OAM, or you can keep your sprite cels in EWRAM or ROM and copy one into VRAM at a time.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#15743 - sajiimori - Wed Jan 28, 2004 9:42 pm

I'll elaborate on what tepples said a bit.
Quote:

do i need to split these frames into different sprites? if so, how many frames will each be able to hold?

It sounds like you have the wrong idea about how the sprite hardware works. Sprites don't "hold" frames, and frames aren't made of sprites.

The GBA has 2 blocks of memory that are relevant to sprite management.

There's what I call character RAM (sometimes called tile memory or character base blocks), which is where you store sprite pixel information in 8x8 tiles. It has room for 1024 16-color tiles, or 512 256-color tiles.

Some gba headers #define character RAM as OAMData, but that's a really misleading name because there's a totally seperate area of memory called Object Attribute Memory (OAM) that is used for a completely different purpose. OAM stores information for up to 128 sprites that are currently on-screen. Each entry stores things like size, x and y position, and also a number referring to a tile in character RAM. That tile will be the top-left tile of the on-screen sprite.

So you could say that you use OAM to tell the GBA what sprites you want on-screen, and you use character RAM to tell the GBA what pixel data to use for them.

#15769 - slboytoy - Thu Jan 29, 2004 7:41 pm

got everything working. thanks for all the help