Author: hobbitdur

The menu module describes its UI sprites (icons, portraits, card animations, magazine pictures) with two small quad-list formats. Both map sprite ids to lists of textured quads; they differ in directory layout and quad size. The texture itself lives elsewhere (a TIM already uploaded to VRAM) — these files only carry UV/CLUT rectangles and draw offsets.

.sp1 format (icon.sp1)

Offset Size Description
0x00 4 UInt32 icon count (329 in icon.sp1)
0x04 4×N Directory, one UInt32 per icon id: {UInt16 offset from file start, UInt16 quad count}
… - Quads (8 bytes each)

Each quad is 8 bytes, two packed UInt32:

  • DWord 0: bits 0-15 = texture UV (byte U, byte V) · bits 16-26 = CLUT selector (the primitive CLUT is 0x3810 + these bits) · bit 27 = semi-transparency (ABE) · bits 30-31 = texture page (E1 bits 5-6).
  • DWord 1: byte 0 = width · byte 1 = signed X offset · byte 2 = height · byte 3 = signed Y offset.

Icon ids 128-139 are not read from the file: they are the confirm/cancel/etc. button icons, redirected to a dedicated renderer that remaps them through the controller key configuration.

The text engine draws icons with control code 0x05 NN (see MenuModuleRuntime), but NN is not the icon id directly. Text_RenderGlyphs resolves it as:

NN Icon id drawn
0x20–0x2F controller button icon, through the key configuration
0x30–0x3F NN + 80
0x40–0x7E TEXT_ICON_CODE_TO_SPRITE[NN], a table of 16-bit ids at 0xB86D84 (EN 2013)

The table’s entries include the status icons (0x53–0x59, 0x65–0x71 → ids 0x110–0x11C) and the eight element icons (0x5D–0x64 → ids 0x120–0x127, the “names” kernel misc text 101–108 hold). It ends at 0x7E; see Element System for the full list.

Two different renderers read this file, and only one is bounds-checked. Menu_DrawSp1SpriteById (0x4B7210, used by the menu pages) returns without drawing when the id is at or past the file’s icon count. The text path — Menu_DrawSp1Icon (0x4B75B0) and Menu_GetSp1IconSize (0x4B73F0) — does not check, so a text icon code that resolves past the end of the file reads beyond the directory.

icon.sp1 is loaded by Menu_LoadFile into an allocation of the file’s own size, so sprites can be appended: add a directory entry, move every existing offset by 4, and put the new quads at the end.

.sp2 format (face.sp2, cardanm.sp2, mngrp Pos 4)

Offset Size Description
0x00 4 UInt32 sprite count
0x04 4×N UInt32 offsets from file start, one per sprite id (0 = unused id)
… - Sprite records

Each sprite record is a UInt32 quad count followed by 12 bytes per quad:

Offset Size Description
0x00 1 Texture U
0x01 1 Texture V
0x02 2 CLUT id
0x04 2 Width
0x06 2 Height
0x08 1 Signed X offset from the sprite draw position
0x09 1 Signed Y offset
0x0A 2 Texture page (PS1 GPU E1 bits, masked with 0x9FF)

Known files

File Sprites Content
icon.sp1 329 UI icons (element/status symbols, cursors, button icons…)
face.sp2 64 Character and GF portraits (32×48)
cardanm.sp2 12 Triple Triad card flip animation frames (64×64)
mngrp.bin Pos 4 79 (39 used) Magazine and Chocobo World screen pictures

Addresses (FF8 PC 2000 EN)

Address Name Description
0x4B75B0 Menu_DrawSp1Icon SP1 icon renderer
0x4B73F0 Menu_GetSp1IconSize Bounding box (max width/height incl. offsets)
0x4FDCA0 Menu_DrawSp2Sprite Generic SP2 sprite renderer