Monday 15 July 2013

SPRITES

All of the functions relating to sprites, including those of the Object Attribute Memory (OAM) can be found in C:\devkitPro\libnds\include\nds\arm9\sprite.h 

Sprites are primarily all about the Object Attribute Memory (OAM) functions: of which there are many necessary to complete, before you can achieve the desired results. We start with oamInit():

void oamInit(OamState* oam, SpriteMapping mapping, bool extPalette);

  • OamState can only be either &oamMain or &oamSub depending on which screen you are rendering the sprite to. This is a small (1kb) data bank with direct 32bit access to the ARM 9 processor. In every instance of it's usage it is entered into the parameters of a function as a pointer, since it is updated by each function.
  • SpriteMapping is an enumerator with one of 9 possible options. I always enter SpriteMapping_1D_128 since I don't really understand any of the explanations: “1D tile mapping 128 byte boundary between offset”...Yeah.
  • Extended palettes are only for 8bpp sprites.
  • (Very) typical example:

oamInit(&oamMain, SpriteMapping_1D_128, false);

Much less standardized, and with a very important return output, is the function oamAllocateGfx():

u16* oamAllocateGfx(OamState *oam, SpriteSize size, SpriteColorFormat colorFormat);

  • OamState, is the same as in the previous function.
  • SpriteSize is an enumerator which goes up to 64x64 pixel sprites (though, as with the maps, later, it is possible to combine several sprites together to make something larger, if necessary)
  • SpriteColorFormat is typically 256 colors, but can use, both, 16 color format and 16bit bitmaps.
  • The function returns a half-word pointer. This is crucial. It describes the address in VRAM of the allocated and bound sprite and should therefore be assigned to a pointer variable for easy recall in later functions:

sprite->sprite_gfx_mem = oamAllocateGfx(&oamMain, SpriteSize_64x64, SpriteColorFormat_256Color);

If you are using the (GRIT) GBA Raster Image Transmogrifier (which you should be), importing your image as a .h file at the top of your code will result in your importing, both, tile and palette data, of the form: filenameTiles and filenamePal.

Your palette, you merely need to bind directly to the SPRITE_PALETTE using dmaCopy, e.g.:

dmaCopy(manPal, SPRITE_PALETTE, 512)

  • dmaCopy is explained in further detail, below, but is basically in the form of dmaCopy(from, to, size-in-bytes)
  • the size, in this instance, is 512 since each color is a half-word or 2 bytes (16bit colours of the form aBBBBBGGGGGRRRRR – alpha, blue, green, red – each 0 to 32) and there are a maximum of 256 colours in any one palette.
  • It should be noted that it is perfectly possible to, otherwise, save the address of the start of the imported palette to a pointer variable, copy the address of this pointer to the SPRITE_PALETTE using dmaCopy(), and therefore, switch between several palettes by setting that variable to point at different sets when needed.

Your tiles, alternatively, you need to have a pointer variable reference their address, e.g.:

u8* frame_gfx = (u8*) manTiles;

such that you can bring in the tiles as an array and merely add the required amount of bytes to the end of the address in order to advance it to the next frame of animation:

u8* offset = sprite->frame_gfx + frame * 64*64;

then, it is entered into dmaCopy():

dmaCopy(offset, sprite->sprite_gfx_mem, 64*64);

  • Remember that sprite_gfx_mem variable? Yeah, this is the pointer variable which references the address of the allocated and bound sprite, and that is why it was so important to receive it from oamAllocateGfx().

There are a couple more OAM functions which contain information about the sprite – usually relating to special functionality, such as scaling and rotating – but which otherwise have to be completed each time, even if you do not use such aspects. These are:

void oamSet(OamState* oam, int id, int x, int y, int priority, int palette_alpha, SpriteSize size, SpriteColorFormat format, const void* gfxOffset, int affineIndex, bool sizeDouble, bool hide, bool hflip, bool vflip, bool mosaic);

Yep, that's a big one. This is pretty much all of your attributes.

  • Id is the number of this set, increasing from 0 to 127, for each new sprite.
  • x and y are positions on the screen, for animation purposes.
  • Priority is between 0 and 3. Never used it: always 0.
  • palette alpha is used in extended Palette mode and with bitmaps. Set to 0.
  • SpriteSize and ColorFormat are the same as used previously in oamAllocateGfx.
  • *gfxOffset is our favourite pointer again – the pointer variable which references the address of the allocated and bound sprite.
  • AffineIndex is used for transformations between 0 and 32. Set to -1.
  • finally we end with five bool transformations, which are fairly obvious from the names, and are typically all set to false, (except for hflip – which is very useful for turning your character around) thus:

oamSet(&oamMain, 0, sprite.x, sprite.y, 0, 0, SpriteSize_64x64, SpriteColorFormat_256Color, sprite->sprite_gfx_mem, -1, false, false,
manFlip, false, false);

Finally, we have oamUpdate():

void oamUpdate(OamState* oam);

A nice easy one to end with.


  • This needs to be called after each Vblank.   

No comments:

Post a Comment