GVM textures and how a landtable binds them
Textures are GVM archives: a GVMH header and a series of GVRT textures (the GameCube format), PRS-compressed on disc (landtxNN.prs, bgtexNN.prs, …). The only pixel formats the stage
archives use are CMPR (DXT1-like) and RGB5A3. Sourced · SA Tools
Counts are from a recorded census of the USA disc GSNE8P; they cannot be re-checked now. Observed
GVMH header
Section titled “GVMH header”The header size is little-endian, the other fields big-endian. After the header come the GVRT textures.
| Offset | Size | Type | Field | Confidence | Notes |
|---|---|---|---|---|---|
| 0x0 | 4 | char[4] = GVMH | magic | Observed | |
| 0x4 | 4 | u32 | header size | Observed | little-endian |
| 0x8 | 2 | u16 | flags | Observed | big-endian: 1 global index, 2 dimensions, 4 format, 8 name |
| 0xA | 2 | u16 | entry count | Observed | big-endian |
| 0xC | variable | entry[] | entries | Observed | per entry u16 id, then (flags & 8) char[28] name, (flags & 4) u16 format, (flags & 2) u16 dimensions, (flags & 1) u32 global index |
The texture list
Section titled “The texture list”A landtable has two texture fields: a texture-archive name at +0x18 and an NJS_TEXLIST* at +0x1C; material texture ids index the list. A texlist is NJS_TEXLIST { NJS_TEXNAME* textures; u32 nbTexture }
with NJS_TEXNAME { char* filename; u32 attr; u32 texaddr }. Observed
| Evidence | Count |
|---|---|
| Landtables whose archive field names a file on the disc, and whose texlist names equal the archive’s GVM entry names at every index | 84 of 86 |
The two exceptions (stg29 and stg56 both use landtx29): the GVM has 25 entries, the texlist 26, and 18 names match at the same index |
2 |
| Landtables with no archive field: stg03, stg15, stg52, stg53, stg55, stg58 | 6 |
Archive field names a file that is not on the disc (landtx22_uv, _x, _poison, _light, _ani, _tani) |
9 |
All Observed. These sub-landtables find all their texlist names in the bgtexNN archive; each bgtexNN name appears as a string in that stage’s REL. stg03’s texlist is exactly landtx03 (24
names) followed by landtx03_suimen (14 names), and both names appear as strings in stg03’s REL. Observed
Binding by name
Section titled “Binding by name”The following rule binds every case on the disc (the game’s own loader was not read): a texlist name is looked up by exact, case-insensitive name in this order. Observed
- Pointer: the archive named by the landtable’s own field. 2,831 of 3,121 texlist entries. Observed
- Identity (only when there is no archive field): a GVM whose name list equals the texlist, or two GVMs whose lists concatenated equal it. 211 entries; this resolves stg52, 53 and 55 uniquely.
For stg15,
landtx15.prsandlandtx20.prsare byte-identical. Observed - Module string: GVMs whose file name occurs as a NUL-terminated string in the stage module. 76 entries; a name found in several with different pixel data stays unresolved. Observed
3,118 of 3,121 texlist entries are bound this way. The 3 that are not are miu256_cg001 in stg29 and stg56, and miu64_ig008 in stg58, which exists with different data in two archives. Observed
How the game’s loader binds a texlist to loaded textures was not read from code. Unknown
The rule above is consistent with every case on the disc but was not read from the engine’s code.