This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
banjo_kazooie:sprites [2025/04/12 12:15] snowboundmage2 |
banjo_kazooie:sprites [2025/04/12 13:01] (current) snowboundmage2 [Sprite Asset] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Sprite Data ====== | ====== Sprite Data ====== | ||
- | This page documents the binary layout of sprite files found in the Banjo-Kazooie ROM (Nintendo 64). These files contain image data composed of one or more frames, each composed of a series of image chunks. | + | This page documents the binary sprite format derived from Banjo-Kazooie’s N64 rom. It supports both single-chunk and multi-frame layouts, with support for various pixel formats and chunk-based rendering. |
- | All multi-byte values are stored in **big endian**. | + | All integers are **big-endian** unless stated otherwise. |
- | Unless otherwise stated, all examples use sprite ID `06EB`. | + | |
- | ===== File Structure ===== | + | ---- |
- | A sprite file is divided into the following sections: | + | ===== 🢩 Overview ===== |
- | * [[#header|Header (0x00–0x10)]] | + | This format is used for static or animated sprite graphics in the ROM. Depending on frame count, it can store a simple image or a complex animation. |
- | * [[#frame_offset_table|Frame Offset Table (0x10–...)]] | + | |
- | * [[#frame_data|Frame Data]] | + | |
- | ===== Header ===== | + | ---- |
- | The header occupies the first 0x10 bytes of the file and contains basic metadata about the sprite. | + | |
- | ^ Offset ^ Size ^ Description ^ | + | ===== 📘 Reference Table ===== |
- | | 0x00 | 2 bytes | Frame count (`0x0001`) | | + | |
- | | 0x02 | 2 bytes | Format ID (`0x0100`) | | + | |
- | | 0x04 | 4 bytes | Unknown or sentinel (`0xFFFFFFFF`) | | + | |
- | | 0x08 | 2 bytes | Default width? (`0x00BE` = 190) | | + | |
- | | 0x0A | 2 bytes | Default height? (`0x00BE` = 190) | | + | |
- | | 0x0C | 4 bytes | Padding or flags (`0x00000000`) | | + | |
- | ===== Frame Offset Table ===== | + | ==== 🥇 File Header (offsets 0x00–0x03) ==== |
- | Immediately following the header is the frame offset table. This table contains 32-bit pointers to each frame's data section, relative to the start of the offset table. | + | |
- | For a file with 1 frame: | + | ^ Field ^ Offset ^ Type ^ Description ^ |
- | ^ Offset ^ Size ^ Description ^ | + | | Frame Count | 0x00 | `uint16_t` | Number of frames | |
- | | 0x10 | 4 bytes | Frame 0 offset: `0x00000004` (points to 0x18 from file start) | | + | | Format ID | 0x02 | `uint16_t` | Format identifier | |
- | Total size of this section = `4 × frame_count` | + | ==== 🎨 Format ID Mappings ==== |
- | ===== Frame Data ===== | + | ^ Format ID ^ Enum ^ Description ^ Bits per Pixel ^ |
+ | | 0x0001 | CI4 | 4-bit color indexed | 4 | | ||
+ | | 0x0004 | CI8 | 8-bit color indexed | 8 | | ||
+ | | 0x0020 | I4 | 4-bit intensity | 4 | | ||
+ | | 0x0040 | I8 | 8-bit intensity | 8 | | ||
+ | | 0x0400 | RGBA16 | 16-bit RGBA (5-5-5-1 format) | 16 | | ||
+ | | 0x0800 | RGBA32 | 32-bit RGBA | 32 | | ||
- | Each frame starts with a 12-byte header. | + | ---- |
- | ==== Frame 0 Header (at 0x18) ==== | + | ===== 🖼 Single Chunk Sprite Layout ===== |
- | ^ Offset ^ Size ^ Description ^ | + | Used if `frameCount > 256` (`0x0100`). |
- | | 0x00 | 2 bytes | X position (`0x0000`) | | + | |
- | | 0x02 | 2 bytes | Y position (`0x0000`) | | + | |
- | | 0x04 | 2 bytes | Width in pixels (`0x0391` = 913) | | + | |
- | | 0x06 | 2 bytes | Height in pixels (`0x0013` = 19) | | + | |
- | | 0x08 | 2 bytes | Chunk count (`0x003E` = 62) | | + | |
- | | 0x0A | 2 bytes | Unknown or padding (`0x0000`) | | + | |
- | Following the frame header, chunk data begins at offset `0x24`. | + | ==== Structure ==== |
- | ===== Notes ===== | + | ^ Field ^ Offset ^ Type ^ Description ^ |
+ | | X | 0x08 | `int16_t` | X position | | ||
+ | | Y | 0x0A | `int16_t` | Y position | | ||
+ | | Width | 0x0C | `uint16_t` | Width in pixels | | ||
+ | | Height | 0x0E | `uint16_t` | Height in pixels | | ||
+ | | Data Offset | ~0x10+ | — | 8-byte aligned after header | | ||
+ | | Data Size | — | computed | Width × Height × bpp ÷ 8 | | ||
- | * The format ID `0x0100` appears to be standard for most (if not all) sprite files. | + | ==== Notes ==== |
- | * Chunk data is not yet fully documented, but it follows immediately after the frame header. | + | * No frame table or chunk headers are present. |
- | * Width and height fields may override the default width/height stored in the main header. | + | * Pixel data begins after a 16-byte header, aligned to the next 8-byte boundary. |
---- | ---- | ||
- | ''This format is still under investigation. If you have additional samples or insights, please contribute.'' | + | |
+ | ===== 🎞 Multi-Frame Sprite Layout ===== | ||
+ | |||
+ | Used if `frameCount ≤ 256` (`0x0100`). | ||
+ | |||
+ | ==== 📂 Frame Table ==== | ||
+ | |||
+ | * Offset: `0x10` | ||
+ | * Entry size: 4 bytes per frame | ||
+ | * Each entry contains a **relative** 32-bit offset from the start of the frame data block. | ||
+ | |||
+ | ==== 🧱 Frame Data Block ==== | ||
+ | |||
+ | Starts at: `0x10 + (frameCount × 4)` | ||
+ | |||
+ | === Frame Header === | ||
+ | |||
+ | ^ Field ^ Offset ^ Type ^ Description ^ | ||
+ | | X | 0x00 | `int16_t` | Frame X offset | | ||
+ | | Y | 0x02 | `int16_t` | Frame Y offset | | ||
+ | | Width | 0x04 | `uint16_t` | Frame width | | ||
+ | | Height | 0x06 | `uint16_t` | Frame height | | ||
+ | | Chunk Count | 0x08 | `uint16_t` | Number of chunks | | ||
+ | |||
+ | === Palette Data (for CI4 / CI8 only) === | ||
+ | |||
+ | ^ Field ^ Offset ^ Size ^ Description ^ | ||
+ | | Palette Data | aligned after 0x14 | 32 or 512B | 16×2 or 256×2 bytes, depending on format | | ||
+ | |||
+ | === Chunk Table === | ||
+ | |||
+ | Each chunk entry is 8 bytes: | ||
+ | |||
+ | ^ Field ^ Offset ^ Type ^ Description ^ | ||
+ | | Chunk X | 0x00 | `int16_t` | Chunk X position | | ||
+ | | Chunk Y | 0x02 | `int16_t` | Chunk Y position | | ||
+ | | Chunk Width | 0x04 | `uint16_t` | Width of chunk | | ||
+ | | Chunk Height | 0x06 | `uint16_t` | Height of chunk | | ||
+ | |||
+ | * Pixel data for each chunk follows the chunk table. | ||
+ | * All data is aligned to the next 8-byte boundary. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== 🧠 Design Rationale ===== | ||
+ | |||
+ | === Format ID and Versatility === | ||
+ | * 16-bit format ID allows for clean extensibility. | ||
+ | * Decoding behavior is format-specific (e.g. CI formats require palettes). | ||
+ | |||
+ | === Single vs Multi-frame Decision === | ||
+ | * A `frameCount > 0x0100` indicates the file is a simple image without a frame table. | ||
+ | * Keeps parsing logic simpler for single-use graphics. | ||
+ | |||
+ | === Frame Table Abstraction === | ||
+ | * Offsets are relative to the frame data block, not absolute. | ||
+ | * Allows reorganization and stream-friendly parsing. | ||
+ | |||
+ | === 8-byte Alignment === | ||
+ | * Ensures data structures are aligned in memory. | ||
+ | * Improves DMA or cache line performance on N64. | ||
+ | |||
+ | === Chunk-Based Rendering === | ||
+ | * Chunks allow tile reuse or sub-rectangles. | ||
+ | * Efficient layout, supports tilemaps or partial redraws. | ||
+ | |||
+ | === Optional Palette === | ||
+ | * CI4 and CI8 include palettes automatically. | ||
+ | * Size and format are inferred based on format ID. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== ✅ Validation Checklist ===== | ||
+ | |||
+ | Use the following to verify whether a file matches this format: | ||
+ | |||
+ | - [ ] File size ≥ 4 bytes | ||
+ | - [ ] Read and parse frame count and format ID | ||
+ | - [ ] If frameCount > 0x0100 → parse as single-chunk | ||
+ | - [ ] If ≤ 0x0100 → validate frame table offsets | ||
+ | - [ ] Parse each frame header and chunk table | ||
+ | - [ ] Validate alignment and total chunk data sizes | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== 📌 Notes ===== | ||
+ | |||
+ | * All integers are stored in **big-endian** format. | ||
+ | * Offsets in the frame table are **relative** to the frame data section. | ||
+ | * Data structures and pixel data must be aligned to 8-byte boundaries. | ||
+ | * CI4/CI8 formats require an internal palette directly after the frame header. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ''This documentation is a work in progress based on reverse engineering efforts. Contributions welcome!'' | ||