Tile map file

From Boktai Hacking Wiki
Revision as of 14:36, 26 September 2024 by Raphi (talk | contribs)

Tile maps store visual data for the GBA's background layers. Each tile map file contains:

  • The tile set used by this tile map file, as an array of standard 8x8 px 4 bpp tiles. Optional, if the tile map file does not contain tile set data, then they must be loaded by an external mechanism (generally a script). Tile maps for menus are usually storing the tile sets themselves, while normal overworld/dungeon maps depend on a global tile set.
  • An array of metatiles: Each metatile is 2x2 tiles in size. This serves as a compression mechanism.
  • An array of layers: Each tile map file may one or multiple different "layers". tile map files only contain a single layer, but menus can have one layer per page in the menu for example. All layers in a tile map file share the same tile set and metatile set.

Compression

Most tile map files are stored LZ77 (swi 0x11) compressed. When loading a tile map file, the game checks if the file starts with the ASCII characters "MP" (hex: 0x4d, 0x50). If it does, then the file is not compressed, and used by the game as-is. If it does not start with these characters, the game will LZ77 decompress it to EWRAM. Note that the first 4 bytes after decompression must be discarded (they will contain the uncompressed length of the file).

File format

struct TilemapHeader {
  /* offset 0x00 */ char magic[2];  // Always the two ASCII characters "MP"
  /* offset 0x02 */ u16 unknown_0x02;
  /* offset 0x04 */ u16 layerCount; // Number of layers in this file
  /* offset 0x06 */ u16 tileCount;  // Number of tiles in this file's tileset (if it exists)
  /* offset 0x08 */ u32 unknown_0x08;

  // Byte offset from start of this struct to the layerDefinitions[] array
  /* offset 0x0c */ u32 offsetToLayerDefinitions;

  // Byte offset from start of this struct to the tileset[] array
  // If it's zero, then this file does not contain a tileset.
  /* offset 0x10 */ u32 offsetToTileset;

  // Byte offset from start of this struct to the metatiles[] array
  /* offset 0x14 */ u32 offsetToMetatiles;

  // TODO: how are these ordered?

  TilemapLayer layerDefintions[layerCount];

  // Each metatile contains four GBA BG screen entries:
  // https://problemkaputt.de/gbatek-lcd-vram-bg-screen-data-format-bg-map.htm
  // This includes the tile number and the palette bits (TODO: Does it include the flip bits?).
  // For each metatile, element 0=top left, 1=top right, 2=bottom left, 3=bottom right.
  u16 metatiles[][4];

  // Only if offsetToTiles != 0. Array of 8x8 px 4 bpp GBA tiles to use.
  u8 tileset[][32];

  // Each layer is an array of TilemapLayer.width * TilemapLayer.height metatile numbers,
  // in row-major order.
  // Each individual u16 in this array references a metatile, which is 16x16 px in size.
  u16 layerData[][];
};

struct TilemapLayer {
  /* offset 0x00 */ u16 width;  // Width of layer in metatiles
  /* offset 0x02 */ u16 height; // Height of layer in metatiles
  /* offset 0x04 */ u32 unknown_0x4;

  // Byte offset from start of **the TilemapHeader struct** to the layer data
  /* offset 0x08 */ u32 offsetToTilemap;
};