Jump to content

Sprite set file: Difference between revisions

No edit summary
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
Sprite sets are stored in directory id_low = 0x5f29, id_high = 0xc8e5 in the [[master file table]]. Each sprite set contains multiple distinct sprites, and each sprite may be made of multiple [https://problemkaputt.de/gbatek-lcd-obj-overview.htm GBA OBJs].
Sprite sets are stored in directory id_low = 0x5f29, id_high = 0xc8e5 in the [[master file table]]. Each sprite set contains multiple distinct sprites, and each sprite may be made of multiple [https://problemkaputt.de/gbatek-lcd-obj-overview.htm GBA OBJs]. Not ''all'' sprites are stored in these sprite sets (example: Boks, bats, etc. are stored elsewhere).


= File format =
= File format =
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 30: Line 30:
   u16 unknown_0x0c;
   u16 unknown_0x0c;
   u16 unknown_0x0e;
   u16 unknown_0x0e;
   u32 objStart; // Start index for this sprite in the spriteset_obj[] array
 
   // BYTE OFFSET from start of sprite_obj[] array to the 1st OBJ of this sprite
  u32 objOffset;
};
};


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 46: 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;
  spriteset_obj* 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 + objIndex];
     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];
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>
= Sprite set list =
== Boktai 1 ==
{| class="wikitable exportable"
! File ID || Description
|-
| 1bc7 || Flamethrowers
|-
| 2117 || Muspell
|-
| 2137 || Carmilla
|-
| 31ce || Hel 2
|-
| 41a8 || Multiplayer menus
|-
| 4e23 || Garmr
|-
| 575d || Count (with coat)
|-
| 576d || Count (without coat)
|-
| 66a8 || Solar sensor help screens
|-
| 746a || Armors (shield only)
|-
| 766a || Armors (sword and shield)
|-
| 769a || Armors (hammer and shield)
|-
| 786a || Armors (sword only)
|-
| 789a || Armors (hammer only)
|-
| 7a6a || Armors (no weapon)
|-
| 8ab4 || Select menu – items & weapon
|-
| a1f7 || Solar tree
|-
| a3ae || Splash screens, settings, new game, etc.
|-
| a493 || Bank/Loans
|-
| a6aa || Select menu – map
|-
| a9c5 || Markers (Immortal, Undead, Arrows, Trap) & Yes/No
|-
| aac7 || Main menu
|-
| b11e || Hel 1
|-
| e894 || Gun parts 1
|-
| edbe || Unknown – maybe link battle?
|-
| fa48 || Gun parts 2 (Dark gun, star lens, astro/infinite battery)
|-
| ff88 || Dungeon titles (shown when entering a dungeon)
|}
== Boktai 2 ==
{| class="wikitable exportable"
! File ID || Description
|-
| 0c23 || Big ray of sun (end of Jormy?)
|-
| 0f54 || Main menu
|-
| 1774 || Big picture of Django with the Sol de Vice
|-
| 18c2 || Multiplayer (contains unused JOYSPOT image)
|-
| 1b12 || Solar sensor help screens
|-
| 1bc7 || Flamethrowers
|-
| 24a0 || “boktai2” and Dream Avenue xF screens
|-
| 3f12 || World map screen
|-
| 5d04 || Inventory icons (and MegaMan and ShadeMan icons)
|-
| 5d36 || ShadeMan
|-
| 6893 || Bank/Loans (contains unused JP art)
|-
| 7ee2 || Splash screens and region select
|-
| 82f1 || Markers (Undead, Immortal, Trap, arrows), mission completed/failed, purification completed
|-
| 9524 || Jormy
|-
| 9abf || Library
|-
| ae52 || Skeletons and Liches
|-
| af82 || MegaMan
|-
| b991 || Candle on a box (where is this used?)
|-
| c153 || Mall (e.g. solar forging, shops, …)
|-
| cef0 || Bank/Loans (and “Restart”?)
|-
| d27a || Dialog box portraits
|-
| d3ca || Duneyrr
|-
| d3da || Ringo/Dainn
|-
| d3ea || Cheyenne
|-
| d3fa || Durathror
|-
| d40a || Dvalinn
|-
| de23 || Django/Sabata
|-
| dfce || Smith and Marcello
|-
| dfde || Lita
|-
| dfee || Zazie
|-
| dffe || Violet and her doll
|-
| e00e || Nero
|-
| e01e || Kid
|-
| e02e || Librarian
|-
| e03e || ??? and the coffin seller
|-
| e04e || Clocktower guy and old guy
|-
| e2de || Carmilla
|-
| e349 || Dainn
|-
| ef43 || In-game menu
|-
| f099 || Chandelier
|}
== Boktai 3 ==
{| class="wikitable exportable"
! File ID || Description
|-
| 0658 || MegaMan
|-
| 1289 || Multiplayer
|-
| 158a || Ringo/Dainn
|-
| 1778 || Cheyenne
|-
| 1bc7 || Flamethrowers
|-
| 2bec || Gun parts
|-
| 32ba || Bank/Loans
|-
| 35e3 || Trinity
|-
| 3d99 || Bike
|-
| 3db6 || Critter that steals your solar nut in the tutorial
|-
| 530d || Select menu, San Miguel, maybe unused stuff?
|-
| 546b || Cannons
|-
| 5d04 || Inventory icons (and Count/MegaMan/Django icons)
|-
| 731d || Main menu
|-
| 7516 || Chair
|-
| 761e || Armors
|-
| 7c8b || Multiplayer (wireless)
|-
| 82f1 || Markers (Undead, Immortal, Trap, arrows), mission completed/failed, purification completed
|-
| 999b || Torch
|-
| a2db || World map
|-
| ae52 || Skeletons
|-
| af82 || MegaMan
|-
| b3de || Vanargand
|-
| b991 || Candle on a box (where is this used?)
|-
| de23 || Django/Sabata
|-
| df11 || Solar sensor help screens
|-
| dfce || Smith/Marcello
|-
| dfde || Lita
|-
| dfee || Zazie
|-
| dffe || Violet and her doll
|-
| e00e || Nero
|-
| e01e || Kid
|-
| e02e || Librarian
|-
| e03e || ??? and the bike shop guy
|-
| e04e || Clocktower guy and old guy
|-
| e2ab || Splash screens and region select
|-
| e2de || Carmilla
|-
| e2ee || Townspeople
|-
| e2fe || Gari
|-
| e349 || Dainn
|-
| e89f || Dungeon titles (shown when entering a dungeon)
|-
| f099 || Chandelier
|-
| f761 || Count
|-
| f771 || Bird and lots of “No”?
|-
| f7d2 || Trance
|-
| fb81 || Ratatosk
|}


[[Category:Documentation]] [[Category:File formats]]
[[Category:Documentation]] [[Category:File formats]]
[[Category:Boktai 1]] [[Category:Boktai 2]] [[Category:Boktai 3]]
[[Category:Boktai 1]] [[Category:Boktai 2]] [[Category:Boktai 3]]