Jump to content

Sprite set file: Difference between revisions

no edit summary
No edit summary
Line 7: Line 7:
<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
struct spriteset_header {
struct spriteset_header {
   u16 unknown_0x00;
   u16 palStart;   // palette start index in the sprite palettes file
   u16 spriteCount; // number of sprites in this sprite set
   u16 spriteCount; // number of sprites in this sprite set
   u16 unknown_0x04;
   u16 unknown_0x04;
Line 36: Line 36:


struct spriteset_obj {
struct spriteset_obj {
   u8 flip; // bitmask; 4 = horizontal, 8 = vertical
   u8 flip; // bitmask; 4 = horizontal, 8 = vertical. TODO: other bits?


   // 00=8x8,  01=16x8,  02=8x16
   // 00=8x8,  01=16x8,  02=8x16
Line 48: Line 48:


   // Bottom 12 bits: Start index for this OBJ in the raw tile data array
   // Bottom 12 bits: Start index for this OBJ in the raw tile data array
   // Top 4 bits: Palette index
   // Top 4 bits: Palette index, add to spriteset_header.palStart
   u16 tileAndPalette;
   u16 tileAndPalette;
};
};


struct spriteset_tile {
struct spriteset_tile {
   u8[32] data; // Raw GBA tile data
   u8 data[32]; // Raw GBA tile data (8x8 px, 4bpp)
}
};
</syntaxhighlight>
</syntaxhighlight>


The OBJ palette must be loaded manually first. There is no link between a sprite set file and its matching palette file.
= Palettes =
 
Each OBJ is linked to the palette it should use using the information in spriteset_obj.tileAndPalette and spriteset_header.palStart. However, the game engine can override this (used e.g. to animate menu cursors etc.).
 
Each game's master file table contains a single file that defines ''all'' palettes for each spriteset_sprite. This file is stored in the MFT directory with id_low = 0x4679 and id_high = 0x9a65. This directory will only contain a single file with the ID 0xc5e9 in every game.
 
The structure of this file is simple: A 4 byte header, containing the number of palettes in this file, followed by an array of that many palettes. Each palette is 0x20 bytes in size (16 entries per palette, 2 bytes per entry, see [https://problemkaputt.de/gbatek-lcd-color-palettes.htm GBATEK]). The game engine will automatically copy palettes from this file into palette RAM as neccessary.
 
To get the palette index for a spriteset_obj, add <code>(spriteset_obj.tileAndPalette >> 12) + spriteset_header.palStart</code>.


= Usage example =
= Usage example =


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
void load_sprite(spriteset_header* spriteset, int spriteId)
void load_sprite(spriteset_header* spriteset, void* spritePalettes, int spriteId)
{
{
  // spriteset should point to the start of a spriteset file
  // spritePalettes should point to the start of the sprite palettes file (there is only one per game)
   spriteset_sprite* sprites = (u8*)spriteset + spriteset->offsetToSprites;
   spriteset_sprite* sprites = (u8*)spriteset + spriteset->offsetToSprites;
  u8* objs = (u8*)spriteset + spriteset->offsetToOBJs;
   spriteset_tile* tiles = (u8*)spriteset + spriteset->offsetToTiles;
   spriteset_tile* tiles = (u8*)spriteset + spriteset->offsetToTiles;


   spriteset_sprite* sprite = &sprites[spriteId];
   spriteset_sprite* sprite = &sprites[spriteId];
   // do something with sprite
   // do something with sprite
  spriteset_obj* objs = (u8*)spriteset + spriteset->offsetToOBJs + sprite->objOffset;


   for (int objIndex=0; objIndex < sprite->objCount; objIndex++) {
   for (int objIndex=0; objIndex < sprite->objCount; objIndex++) {
     spriteset_obj* obj = objs + sprite->objStart;
     spriteset_obj* obj = &objs[objIndex];
     // do something with obj
     // do something with obj


     int tileIndex = obj->tileAndPalette & 0xfff;
     int firstTileIndex = obj->tileAndPalette & 0xfff;
     spriteset_tile* firstTile = &tiles[tileIndex];
     spriteset_tile* firstTile = &tiles[firstTileIndex];
    // do something with the tiles
     // number of tiles is implied by sprite->shape
     // number of tiles is implied by sprite->shape
     // do something with the tiles
     // for OBJs with a height of more than 1 tile, successive rows of tiles are stored 16 tiles apart.
    // example: assuming startTileIndex = 4 and shape = 8x16: tile indices are 4 and 20.
 
    // color lookup example:
    int pixelColor = firstTile->data[0] & 0xf; // extract color of 1st pixel in the tile
    int paletteIndex = spriteset->palStart + (obj->tileAndPalette >> 12);
    // First 4 bytes are an ignoreable header, and each palette is 0x20 bytes in size (16 colors * 2 bytes per color)
    u16* palettePtr = (u8*)spritePalettes + 4 + 0x20*paletteIndex;
    u16 paletteEntry = palettePtr[pixelColor];
   }
   }
}
}