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 > sprite question

#40595 - wally - Wed Apr 20, 2005 7:40 pm

I was trying to use the smantouch program to learn how to program for the DS. So the first thing I tried was to change the pictures. So I tried to change the pacman from a 8x8 to a 64x64. However the graphics come up corrupted. When changing the sprite size what would I have to change in the main program? I don't understand the OAM changes.

#41247 - wally - Tue Apr 26, 2005 11:13 pm

OK I got the code to give me 5 sprites, however all five have the same image. What am I doing wrong? The code is below.
Thanks for all your help.


//Custom defines
#define REG_VCOUNT *(vu16*)0x4000006 //Our good old vblank counter

//System includes
#include <NDS/NDS.h>
#include <NDS/ARM9/rand.h>

//Artwork includes
#include "resources/pal.h"
#include "resources/pac0.h"
#include "resources/gh0.h"
#include "resources/bg.h"

//-------------------------------------------------------------------

//OAM globals
sSpriteEntry OAMCopy[128];
sSpriteEntry OAMCopySub[128];

//Sprite structure
typedef struct
{
int x,y; //location
int xSpeed, ySpeed; //speed
sSpriteEntry* oam;
}Sprite;

//-------------------------------------------------------------------

//Moves a sprite in OAM memory
void MoveSprite(Sprite* sp)
{
int x = sp->x >> 8;
int y = sp->y >> 8;

sp->oam->attribute[1] &= 0xFE00;
sp->oam->attribute[1] |= x;

sp->oam->attribute[0] &= 0xFF00;
sp->oam->attribute[0] |= y;

}
//-------------------------------------------------------------------

//Initializes the sprites
void NextSprite(Sprite* sp, int number)
{

sp->x += sp->xSpeed;
sp->y += sp->ySpeed;
if(sp->x < 256 || sp->x > 61440) { sp->xSpeed=-sp->xSpeed; }
if(sp->y < 256 || sp->y > 45056) { sp->ySpeed=-sp->ySpeed; }


}

//-------------------------------------------------------------------

//Initializes the sprites
void CreateSprite(Sprite* sp, int number)
{
sp->x = (rand() & (100<<8))+((number+number)<<8);
sp->y = (rand() & (100<<8))+((number+number)<<8);
sp->xSpeed = (rand() & (3<<6))+(1<<6);
sp->ySpeed = (rand() & (3<<6))+(1<<6);
sp->oam = &OAMCopy[number];

sp->oam->attribute[0] = ATTR0_COLOR_256 | ATTR0_SQUARE;
sp->oam->attribute[1] = ATTR1_SIZE_64;
sp->oam->attribute[2] = 0;


}

//-------------------------------------------------------------------

//Initialises OAM, moving all sprites offscreen
void initOAM(void)
{
int i;

for(i = 0; i < 128; i++)
{
OAMCopy[i].attribute[0] = ATTR0_DISABLED;
OAMCopySub[i].attribute[0] = ATTR0_DISABLED;
}
}

//-------------------------------------------------------------------

//Copies OAM buffer to actual OAM memory space
void updateOAM(void)
{
int i;

for(i = 0; i < 128 * sizeof(sSpriteEntry) / 4 ; i++)
{
((uint32*)OAM)[i] = ((uint32*)OAMCopy)[i];
((uint32*)OAM_SUB)[i] = ((uint32*)OAMCopySub)[i];
}
}

//-------------------------------------------------------------------

//Entry point- this is where we start!
int main(int argc, char ** argv) {

int i=0, colourComponent=0;

//turn on the power to the system
powerON(POWER_ALL);
videoSetMode( MODE_0_2D | DISPLAY_SPR_1D_LAYOUT | DISPLAY_SPR_ACTIVE | DISPLAY_BG0_ACTIVE );
videoSetModeSub( MODE_0_2D | DISPLAY_SPR_1D_LAYOUT | DISPLAY_SPR_ACTIVE | DISPLAY_BG0_ACTIVE );

/*
VRAM_A_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_A;
VRAM_B_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_A;
VRAM_C_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_B;
VRAM_D_CR = VRAM_ENABLE | VRAM_ARM9 | VRAM_CORE_B;
vramSetMainBanks(VRAM_A_MAIN_BG,VRAM_B_MAIN_SPRITE,VRAM_C_SUB_BG,VRAM_D_SUB_SPRITE);
*/

//Set screens to black initially
BG_PALETTE[0] = RGB15(0, 0, 0); //Main screen
BG_PALETTE[512] = RGB15(0, 0, 0); //Sub screen


Sprite sprites[128];
Sprite sprites_sub[128];
initOAM();

//Setup heads
CreateSprite(&sprites[0],0);
CreateSprite(&sprites[1],1);
CreateSprite(&sprites[2],2);
CreateSprite(&sprites[3],3);
CreateSprite(&sprites[4],4);


//Load palette and sprite data (main screen)
for(i=0; i<512; i++) { SPRITE_PALETTE[i] = palPalette[i]; }
for(i=0; i<8192; i++) { SPRITE_GFX[i] = pac0Data[i]; }
for(i=8193; i<16384; i++) { SPRITE_GFX[i] = pac1Data[i-8193]; }
for(i=16385; i<24576; i++) { SPRITE_GFX[i] = pac2Data[i-16385]; }
for(i=24577; i<32768; i++) { SPRITE_GFX[i] = pac3Data[i-24577]; }
for(i=32769; i<40960; i++) { SPRITE_GFX[i] = pac4Data[i-32769]; }

//Setup top screen
sprites_sub[0].x = 8;
sprites_sub[0].y = 8;
sprites_sub[0].xSpeed = (8<<8);
sprites_sub[0].ySpeed = (1<<8);
sprites_sub[0].oam = &OAMCopySub[0];

sprites_sub[0].oam->attribute[0] = ATTR0_COLOR_256 | ATTR0_SQUARE;
sprites_sub[0].oam->attribute[1] = ATTR1_SIZE_64;
sprites_sub[0].oam->attribute[2] = 0;

//Load palette and sprite data (sub screen)
for(i=0; i<512; i++) { SPRITE_PALETTE_SUB[i] = palPalette[i]; }
for(i=0; i<8192; i++) { SPRITE_GFX_SUB[i] = gh0Data[i]; }


//-------------------------------------------------------------------

//Main game loop
bool exitFlag = false;
while (!exitFlag)
{
//Pulse screen colours (disco time!)
if (colourComponent < 31) { colourComponent++; }
else { colourComponent = 0; }
PALETTE[0] = RGB15(colourComponent, 0, 0);
PALETTE[512] = RGB15(0, 0, 31-colourComponent);



//Move heads

NextSprite(&sprites[0],0);
NextSprite(&sprites[1],1);
NextSprite(&sprites[2],2);
NextSprite(&sprites[3],3);
NextSprite(&sprites[4],4);

MoveSprite(&sprites[0]);
MoveSprite(&sprites[1]);
MoveSprite(&sprites[2]);
MoveSprite(&sprites[3]);
MoveSprite(&sprites[4]);




//swiWaitForVBlank();
while(REG_VCOUNT != 190) {;}

updateOAM();
}

return 0;
}

#41249 - Ethos - Tue Apr 26, 2005 11:19 pm

attribute[2] = 0;

That is why

#41251 - wally - Tue Apr 26, 2005 11:22 pm

what exactly is attribute 2? I thought it was the order the images were placed.

#41253 - Ethos - Tue Apr 26, 2005 11:28 pm

I don't know DS 2D (no time, its all about the 3D).
But in GBA attribute 2 (bits 0-9) are the tile in memory you are trying to reference

#41550 - Pacifist - Fri Apr 29, 2005 4:25 pm

It's the memory offset between where Sprite memory starts and where the sprite you want to draw is.

0 is the first sprite. If your drawing 8x8 sprites then the second on is at 2x1 and the third is at 2x2. 2 is the number of bytes the sprite takes up (right?). An 8x8 sprites has 8*8 pixels = 64 bits / 32 bits per byte = 2 bytes.

16x16 sprites take up 8 bytes and your 64x64 sprites take up a whopping 128.

Therefore your sprites should be at

0*128, 1*128, 2*128 etc...

however it looks like you've loaded them into specific chunks of sprite memory instead of loading them sequentially. In this case the offset will be where you loaded them.

for(i=0; i<8192; i++) { SPRITE_GFX[i] = pac0Data[i]; }
for(i=8193; i<16384; i++) { SPRITE_GFX[i] = pac1Data[i-8193]; }
for(i=16385; i<24576; i++) { SPRITE_GFX[i] = pac2Data[i-16385]; }
for(i=24577; i<32768; i++) { SPRITE_GFX[i] = pac3Data[i-24577]; }
for(i=32769; i<40960; i++) { SPRITE_GFX[i] = pac4Data[i-32769]; }

so sprite one is at
sprites_sub[0].oam->attribute[2] = 0;
two is at
sprites_sub[1].oam->attribute[2] = 8193;
three is at
sprites_sub[2].oam->attribute[2] = 16385;
etc...

at least thats what *I* think is going on but I'm still pretty new to all this.
[/quote]

#41552 - wally - Fri Apr 29, 2005 4:43 pm

how would you load them sequentially?

#41555 - Pacifist - Fri Apr 29, 2005 5:04 pm

oho I am wrong about some of this.

I have the memory addessing all wrong. A notable sign of this is that I expect one bit to represent the colour of a 256 colour pixel...

dovoto has a good tutorial on sprites here:

http://www.thepernproject.com/tutorials/GBA/day_3.html

He says that a 64*64 sprite takes up 64*64/2 bytes. Which makes way more sense than what I was saying.

So where your using 8192 as the size of your sprites you should use 64*64/2.

so if you just want to modify your existing code:
int spriteSize = 64*64/2;
for(i=0; i<spriteSize; i++) { SPRITE_GFX[i] = pac0Data[i]; }
for(i=0; i<spriteSize; i++) { SPRITE_GFX[i+spriteSize] = pac1Data[i];
for(i=0; i<spriteSize; i++) { SPRITE_GFX[i+spriteSize*2] = pac2Data[i]; }
for(i=0; i<spriteSize; i++) { SPRITE_GFX[i+spriteSize*3] = pac3Data[i];
for(i=0; i<spriteSize; i++) { SPRITE_GFX[i+spriteSize*4] = pac4Data[i]; }

You should really read the tutorial. I may have the size wrong and I obviously haven't tested the code I just wrote.

#41558 - Ethos - Fri Apr 29, 2005 5:58 pm

Pacifist wrote:
He says that a 64*64 sprite takes up 64*64/2 bytes. Which makes way more sense than what I was saying.


Nope, wrong. He is copying, 64x64*2 bytes, but he is doing 64*64/2 copies of 4 bytes.

Two threads....same dicussion.