This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
banjo_kazooie:sprites [2025/04/12 12:10] snowboundmage2 created |
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 a sprite file used in the Banjo Kazooie game (based on the n64 rom) . All multi-byte values are stored in **big endian**. | + | 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. |
- | ===== Sprite File Binary Layout ===== | + | All integers are **big-endian** unless stated otherwise. |
- | The sprite file begins with a 16-byte header, followed by a frame offset table, and then the actual frame data. | + | ---- |
- | ==== Header Section (First 0x10 bytes) ==== | + | ===== 🢩 Overview ===== |
- | ^ Offset ^ Bytes ^ Big Endian Value ^ Description ^ | + | 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. |
- | | 0x00 | 00 01 | 0x0001 | Frame count = 1 | | + | |
- | | 0x02 | 01 00 | 0x0100 | Format ID = 0x100 | | + | |
- | | 0x04 | FF FF FF FF | 0xFFFFFFFF | Likely unused or sentinel | | + | |
- | | 0x08 | 00 BE | 0x00BE = 190 | Possibly a default width? | | + | |
- | | 0x0A | 00 BE | 0x00BE = 190 | Possibly a default height? | | + | |
- | | 0x0C | 00 00 00 00 | 0x00000000 | Padding or flags | | + | |
- | At offset `0x10`, the **frame offset table** begins. | + | ---- |
- | ==== Frame Offset Table (0x10–0x14) ==== | + | ===== 📘 Reference Table ===== |
- | ^ Offset ^ Bytes ^ Big Endian Value ^ Description ^ | + | ==== 🥇 File Header (offsets 0x00–0x03) ==== |
- | | 0x10 | 00 00 00 04 | 0x00000004 | Offset to Frame 0: `0x04 + 0x14 = 0x18` | | + | |
- | The frame offset table contains a single `uint32_t`, pointing to the first frame header. Since there's only one frame, the table is 4 bytes long. | + | ^ Field ^ Offset ^ Type ^ Description ^ |
+ | | Frame Count | 0x00 | `uint16_t` | Number of frames | | ||
+ | | Format ID | 0x02 | `uint16_t` | Format identifier | | ||
- | ==== Frame 0 Header (starts at 0x18) ==== | + | ==== 🎨 Format ID Mappings ==== |
+ | |||
+ | ^ 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 | | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== 🖼 Single Chunk Sprite Layout ===== | ||
+ | |||
+ | Used if `frameCount > 256` (`0x0100`). | ||
+ | |||
+ | ==== Structure ==== | ||
+ | |||
+ | ^ 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 | | ||
+ | |||
+ | ==== Notes ==== | ||
+ | * No frame table or chunk headers are present. | ||
+ | * Pixel data begins after a 16-byte header, aligned to the next 8-byte boundary. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== 🎞 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 | ||
+ | |||
+ | ---- | ||
- | ^ Offset ^ Bytes ^ Big Endian Value ^ Description ^ | + | ===== 📌 Notes ===== |
- | | 0x18 | 00 00 | 0 | X position | | + | |
- | | 0x1A | 00 00 | 0 | Y position | | + | |
- | | 0x1C | 03 91 | 0x0391 = 913 | Width in pixels | | + | |
- | | 0x1E | 00 13 | 0x0013 = 19 | Height in pixels | | + | |
- | | 0x20 | 00 3E | 0x003E = 62 | Chunk count | | + | |
- | | 0x22 | 00 00 | — | Unknown or padding | | + | |
- | More details on **chunk data** may follow after offset `0x24`. | + | * 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!'' | ||