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 > Loading And Accessing Multiple Sprites & Bgs.

#27535 - Celeryface - Thu Oct 14, 2004 9:45 pm

Hello,

I've put together a small sprite/character animation and background scrolling demo, but I have run into problems trying to properly load multiple backgrounds using different tiles and palettes. How do I load them, and how do I access the backgrounds certain tiles/palette later on? My demo currently only has one scrolling background, but I want to do parallax scrolling using at least 1 more background (I'm using Mode 0 for my demo).

Same goes for sprites. I have multiple framed animations for a player character and have got it to play the different animations depending on the state the character is in, but I haven't been able to figure out how to load another set of sprites for different characters and access them properly (palettes and sprite data).

If anyone can give some tips that would be awesome.

Thanks! :)

#27537 - sajiimori - Thu Oct 14, 2004 10:14 pm

Since there's only one hardward BG palette of 256 colors, you have to either divide it up so each of your 2 BGs get half of the palette, or share the whole thing (which is generally better unless they need to vary independently).

It's a little different with tiles because there's more VRAM available than can be accessed by a single BG, so you have the option of filling up VRAM with two totally seperate tilesets.

As far as how to load tiles and palettes into VRAM, the various tutorials will tell you how to do that. Let us know if you need extra help with a particular topic.

I personally find it very helpful to draw a diagram of VRAM and mark out the areas I want to allocate for different purposes (e.g. screen maps and tile data for each background).

I'm not sure what the problem is regarding sprites. If you know how to load one set of graphics, what's the difficulty in loading more?

#27550 - Celeryface - Fri Oct 15, 2004 11:44 am

sajiimori wrote:
Since there's only one hardward BG palette of 256 colors, you have to either divide it up so each of your 2 BGs get half of the palette, or share the whole thing (which is generally better unless they need to vary independently).

It's a little different with tiles because there's more VRAM available than can be accessed by a single BG, so you have the option of filling up VRAM with two totally seperate tilesets.

As far as how to load tiles and palettes into VRAM, the various tutorials will tell you how to do that. Let us know if you need extra help with a particular topic.

I personally find it very helpful to draw a diagram of VRAM and mark out the areas I want to allocate for different purposes (e.g. screen maps and tile data for each background).

I'm not sure what the problem is regarding sprites. If you know how to load one set of graphics, what's the difficulty in loading more?


Thanks for the reply :)

Backgrounds: How do the backgrounds know which part of memory it uses to draw its tiles? Is that taken care of when you load the background?

Sprites: For sprites, I'm having trouble understanding how know you load multiple sprites into memory (especially animated sprites) and know where to access them later on. Do I need to keep track of the OAM index for each sprite?

Also, for sprite palettes when I load multiple sprites, should I only use one palette for all sprites? I've read that you can use 16 16-colour palettes, but how do you access the individual palettes when drawing the different sprites and how do you know which palette to use?

Thanks again for the help :)

#27551 - keldon - Fri Oct 15, 2004 11:51 am

for this, you would be better off with the GbaTec manual; get it from the docs section of gbadev.org

#27563 - sajiimori - Fri Oct 15, 2004 6:07 pm

GBATek is definitely a great reference. The Pern tutorials are easier to follow when you're just starting out.

Let us know if you don't understand something in those. =)

#27565 - Celeryface - Fri Oct 15, 2004 6:22 pm

sajiimori wrote:
GBATek is definitely a great reference. The Pern tutorials are easier to follow when you're just starting out.

Let us know if you don't understand something in those. =)


I'll check out the Pern tutorials and the reference page.

I finished reading the GBA Programming Book by J. Harbour. It was a good read and I learned a lot of cool stuff. The only things that I haven't been able to do yet is the above questions (storing multiple palettes and knowing how to access them when drawing different sprites/backgrounds).

Thanks for the help. :)

#27567 - poslundc - Fri Oct 15, 2004 6:44 pm

http://www.thepernproject.com

Read the tutorials on sprites and backgrounds and tell us what you don't understand.

Dan.

#27571 - Celeryface - Fri Oct 15, 2004 10:21 pm

poslundc wrote:
http://www.thepernproject.com

Read the tutorials on sprites and backgrounds and tell us what you don't understand.

Dan.


Cool. Here might be an answer to one of my questions:

Quote:
Attribute 2: ...
Bits 12-15 are the palette number. If your sprite is a 16-color sprite then this value will determine which of the 16 16-color palettes are used. If it is a 256-color sprite then these bits are ignored.

and

#define PALETTE(n) ((n) << 12)


For PALETTE(n), is the used for when you're assigning the palette when initializing the sprites?


For initializing 16x16 sprites:
Code:
sprites[i].gfxID = i * 4;
sprites[i].oam->attribute[0] = COLOR_16 | SQUARE;

//copy the sprite graphics in obj graphics mem
for(i = 0; i < 16 * 16 * 128 / 4; i++)

//copy in the palette
   for(i = 0; i < 16; i++)


For the above code it's only if all of the sprites you're loading are 16x16, what if you're using multiple sizes?

Thanks again for the help! :)

#27574 - poslundc - Fri Oct 15, 2004 10:54 pm

Celeryface wrote:
For PALETTE(n), is the used for when you're assigning the palette when initializing the sprites?


It refers to the top 4 bits of an entry in OAM. There are 128 entries in OAM, one for each of the (up to 128) sprites you can display simultaneously on the screen.

You would set these bits (as well as the other OAM bits) once you have your sprite's data and palette loaded into VRAM and are ready to display them at some location on the screen.

Quote:
For initializing 16x16 sprites:
Code:
sprites[i].gfxID = i * 4;
sprites[i].oam->attribute[0] = COLOR_16 | SQUARE;

//copy the sprite graphics in obj graphics mem
for(i = 0; i < 16 * 16 * 128 / 4; i++)

//copy in the palette
   for(i = 0; i < 16; i++)


For the above code it's only if all of the sprites you're loading are 16x16, what if you're using multiple sizes?


Then for the OAM entries of your other sprites, use different values. OAM stands for object attribute memory: it contains the attributes (data such as shape, size, palette, location, etc.) for each object on the screen.

Dan.

#27578 - Celeryface - Sat Oct 16, 2004 12:12 am

poslundc wrote:
Celeryface wrote:
For PALETTE(n), is the used for when you're assigning the palette when initializing the sprites?


It refers to the top 4 bits of an entry in OAM. There are 128 entries in OAM, one for each of the (up to 128) sprites you can display simultaneously on the screen.

You would set these bits (as well as the other OAM bits) once you have your sprite's data and palette loaded into VRAM and are ready to display them at some location on the screen.

Quote:
For initializing 16x16 sprites:
Code:
sprites[i].gfxID = i * 4;
sprites[i].oam->attribute[0] = COLOR_16 | SQUARE;

//copy the sprite graphics in obj graphics mem
for(i = 0; i < 16 * 16 * 128 / 4; i++)

//copy in the palette
   for(i = 0; i < 16; i++)


For the above code it's only if all of the sprites you're loading are 16x16, what if you're using multiple sizes?


Then for the OAM entries of your other sprites, use different values. OAM stands for object attribute memory: it contains the attributes (data such as shape, size, palette, location, etc.) for each object on the screen.

Dan.


Thanks for your reply. :)

When loading in multiple palettes, I should load in the palettes in seperate 16 blocks, THEN I should assign the palette in the attribute for the sprites?

Like so:

Code:
for(i = 0; i < 16; i++)
      OBJPaletteMem[i] = spritePalette[i];

for(i = 16; i < 32; i++)
      OBJPaletteMem[i] = spritePalette2[i];


What does the code looking like for assigning a new palette entry?

#27579 - sajiimori - Sat Oct 16, 2004 12:26 am

This is what you need to know to set a sprite's palette index:

- Where OAM is
- How OAM is arranged
- Which attribute the palette index is in
- Which bits the palette index is at in that attribute
- How to work with bits in C

Which part don't you understand? (If it is working with bits in C, you'll need a good C book.)

#27580 - Celeryface - Sat Oct 16, 2004 12:47 am

sajiimori wrote:
This is what you need to know to set a sprite's palette index:

- Where OAM is
- How OAM is arranged
- Which attribute the palette index is in
- Which bits the palette index is at in that attribute
- How to work with bits in C

Which part don't you understand? (If it is working with bits in C, you'll need a good C book.)


The part I didn't understand was where/when you actually set the palette for each sprite?

I see attribute 2 is assigned the gfxID when you initialize a sprite. Is the palette assigned during initialization?

Also, is it done this way?

Code:
sprites[i].oam->attribute[2] = sprites[i].gfxID;

or

sprites[i].oam->attribute[2] = PALETTE(0);

#27582 - sajiimori - Sat Oct 16, 2004 1:15 am

Since attribute 2 contains more than one piece of information, you need to OR the different components of it together. If you just assign over the old contents, you'll overwrite them.

You can set the palette index at any time.

#27583 - DekuTree64 - Sat Oct 16, 2004 1:18 am

The attributes are split up into several fields, so you normally don't just set the entire attribute to a single value (unless you're just initializing it, and mean to zap all the other fields).

Attribute 2 contains 3 fields, starting character, priority, and palette. TO set the char and palette, you OR them together. The PALETTE(x) define is just to hide the shift to make things more understandable, but really all you're doing is setting different bits in the same variable. So, your code would be like this:
Code:
sprites[i].oam->attribute[2] = sprites[i].gfxID | PALETTE(0);


When you load the palette is entirely up to you. I would suggest doing it during initialization for now, because that's the easiest and most of the time a good way to handle them.
It's perfectly fine to load in new palettes every frame if you want to though, or even during HBlank to do some nice gradient effects and stuff.

EDIT: Curses, beaten to the punch.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#27611 - Celeryface - Sat Oct 16, 2004 11:29 pm

These topics seem much clearer now. I'll implement the solutions in my next set of tests to see how it goes.

Thanks for the help :)

#27747 - Celeryface - Wed Oct 20, 2004 12:12 pm

Last night I discovered a formula for calculating the area to fill the sprite data.

for( i = 0; i < (size*size/2); i++ )


The amount of space certain size sprites take up are:

32x32 256-colour sprite takes up 32 tiles.
64x64 256-colour sprite takes up 128 tiles.

16x16 256-colour sprite takes up ?????

It seems to work now for accessing and loading sprites. Is there a better or more general formula I can use to to load and keep track of where sprite data is stored? Also you can only store 1024 tiles in sprite memory, correct?

Thanks again.

#27750 - poslundc - Wed Oct 20, 2004 2:18 pm

Even though OAM refers to the "tile number" I find it more practical to think in terms of memory consumption.

You have 32,768 bytes of sprite VRAM.

One tile is 8 pixels by 8 pixels = 64 pixels.

One pixel is 4 bits (half a byte, aka a nibble) in 16-colour mode, 8 bits (one byte) in 256-colour mode.

So one tile is 32 bytes in 16-colour mode, or 64 bytes in 256-colour mode.

So sprite VRAM can store 1024 16-colour tiles, or 512 256-colour tiles.

A 32x32 sprite is 1024 pixels. Divide by 64 pixels/tile and you'll see it's composed of 16 "tiles", not 32. The reason you have to advance your tile number by 32 is because you are using 256-colour mode, and when the OAM refers to "tile number" it really means 32-byte increments, not 64-byte increments.

A 64x64 sprite is 4096 pixels, or 64 "tiles"... again, if you're in 256-colour mode you need to advance 128 tiles because the tiles take up twice as much space.

A 16x16 sprite is 256 pixels... you can do the math yourself from here.

If you want to know how many sprites can fit into memory, divide the amount of memory (32,768 bytes) by the number of tiles your sprite consumes (physical tiles, not the "logical" tiles you need to advance in OAM) multiplied by the number of bytes consumed per tile (either 32 or 64).

Dan.

Dan.

#27751 - Celeryface - Wed Oct 20, 2004 3:53 pm

Thank you that was very helpful :)

I have another question:

When working in 256-colour mode for( i = 0; i < (size*size/2); i++ ) works good for loading in the sprite tile data. Is the (size*size/2) formula different for 16-colour mode?

#27752 - poslundc - Wed Oct 20, 2004 4:08 pm

A good way to figure out the answer to that question would be to calculate how many bytes of data you are copying with your for-loop, then compare that number with how many bytes of data you need to copy if you are in 16 colour mode.

Dan.