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 | 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; | ||
// 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] | u8 data[32]; // Raw GBA tile data (8x8 px, 4bpp) | ||
} | }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
= 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_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[ | spriteset_obj* obj = &objs[objIndex]; | ||
// do something with obj | // do something with obj | ||
int | int firstTileIndex = obj->tileAndPalette & 0xfff; | ||
spriteset_tile* firstTile = &tiles[ | 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 | ||
// | // 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]] |
Latest revision as of 16:22, 18 September 2024
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 GBA OBJs. Not all sprites are stored in these sprite sets (example: Boks, bats, etc. are stored elsewhere).
File format
TODO: very incomplete
struct spriteset_header {
u16 palStart; // palette start index in the sprite palettes file
u16 spriteCount; // number of sprites in this sprite set
u16 unknown_0x04;
u16 unknown_0x06;
u16 unknown_0x08;
u16 unknown_0x0a;
u32 offsetToSprites; // byte offset from start of this struct to the spriteset_sprite[spriteCount] array
u32 offsetToUnknown_0x10;
u32 offsetToOBJs; // byte offset from start of this struct to the spriteset_obj[] array
u32 offsetToUnknown_0x18;
u32 offsetToTiles; // byte offset from start of this struct to the spriteset_tile[] array
};
struct spriteset_sprite {
u16 unknown_0x00;
u16 objCount; // Sprite is made up of this many OBJs
u16 unknown_0x04;
u16 unknown_0x06;
u16 unknown_0x08;
u16 unknown_0x0a;
u16 unknown_0x0c;
u16 unknown_0x0e;
// BYTE OFFSET from start of sprite_obj[] array to the 1st OBJ of this sprite
u32 objOffset;
};
struct spriteset_obj {
u8 flip; // bitmask; 4 = horizontal, 8 = vertical. TODO: other bits?
// 00=8x8, 01=16x8, 02=8x16
// 04=16x16, 05=32x8, 06=8x32
// 08=32x32, 09=32x16, 10=16x32
// 12=64x64, 13=64x32, 14=32x64
u8 shape;
i16 xOffset;
i16 yOffset;
// Bottom 12 bits: Start index for this OBJ in the raw tile data array
// Top 4 bits: Palette index, add to spriteset_header.palStart
u16 tileAndPalette;
};
struct spriteset_tile {
u8 data[32]; // Raw GBA tile data (8x8 px, 4bpp)
};
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 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 (spriteset_obj.tileAndPalette >> 12) + spriteset_header.palStart
.
Usage example
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_tile* tiles = (u8*)spriteset + spriteset->offsetToTiles;
spriteset_sprite* sprite = &sprites[spriteId];
// do something with sprite
spriteset_obj* objs = (u8*)spriteset + spriteset->offsetToOBJs + sprite->objOffset;
for (int objIndex=0; objIndex < sprite->objCount; objIndex++) {
spriteset_obj* obj = &objs[objIndex];
// do something with obj
int firstTileIndex = obj->tileAndPalette & 0xfff;
spriteset_tile* firstTile = &tiles[firstTileIndex];
// do something with the tiles
// number of tiles is implied by sprite->shape
// 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];
}
}
Sprite set list
Boktai 1
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
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
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 |