Decode tfrag texture bindings, vertex colours and light records
Adds level_core.rs (the uncompressed core index header and texture table) and extends tfrag.rs with the data a draw call needs beyond geometry. An ad-gif is five A+D quadwords holding packed fields rather than GS registers; the level load rewrites them in place before drawing. On disc TEX0_1.data_lo indexes the level's texture table, TEX1_1.data_lo is the LOD bias K and data_hi the minification filter, and CLAMP_1 holds both wrap modes. Three things are easy to get wrong here: * K is a signed 12-bit value in 1/16 units, sign-extended by shifting the field up 4 and back down. Retail values are -137..-89 mip-scaled; reading it unsigned gives 1911 instead of -137. * TEX1_1.data_hi is MMIN, and 4 decodes as LinearMipmapNearest, not LinearMipmapLinear as the raw bit layout suggests. * RGBA and the light/normal records are not in the VIF lists at all. They sit at fixed offsets in the patch data block: rgba_size*4 colours at rgba_ofs, vert_count light records at light_ofs+0x10. The tfrag origin lives there too -- if no STROW row supplied one, the quadword at light_ofs is it. The texture table checks out on its own terms: 93 entries at index offset 0x2900 on level 0, and 0x2900 + 93*16 lands exactly on the next range. Verification: an ad-gif index outside the level's table would mean the geometry and the textures were misread independently, so every one is range-checked against real entries. All 27 levels: 47,950 ad-gifs over 18,102 patches, all in range, referencing 1429 of 1595 level texture entries (90%). Each patch's light array is exactly vert_count records and its RGBA array exactly rgba_size*4. Still open: LOD selection and morphing, and the texel data itself.
This commit is contained in:
@@ -357,8 +357,45 @@ element size from the immediate, 2-byte payload padding, ignoring non-unpack
|
||||
payloads, and banking strips by arrival order. Every one produced parseable,
|
||||
plausible geometry; only the header's own triangle count caught them.
|
||||
|
||||
### Texture bindings, colours and lights
|
||||
|
||||
Also settled. Adds `level_core.rs` for the index header and the texture table,
|
||||
which is the join between tfrags and texel data.
|
||||
|
||||
A tfrag's **ad-gifs** are five A+D quadwords (0x50 bytes) holding packed
|
||||
fields rather than GS registers; the level load rewrites them in place before
|
||||
drawing. On disc `TEX0_1.data_lo` indexes the level's texture table,
|
||||
`TEX1_1.data_lo` is the LOD bias K and `data_hi` the minification filter, and
|
||||
`CLAMP_1` holds the two wrap modes. The texture table is a count/offset pair at
|
||||
index offset 0x30, entries of 16 bytes.
|
||||
|
||||
The table checks out on its own terms: on level 0 it is 93 entries at 0x2900,
|
||||
and 0x2900 + 93 x 16 lands exactly on the next range at 0x38.
|
||||
|
||||
Three details worth writing down:
|
||||
|
||||
* **K is a signed 12-bit value in 1/16 units**, sign-extended by shifting the
|
||||
field up 4 and back down. Retail values are -137..-89, which is -8.56..-5.56
|
||||
mip levels. Reading the field as unsigned gives 1911 instead of -137.
|
||||
* **`data_hi` of TEX1_1 is MMIN, and 4 is `LinearMipmapNearest`**, not
|
||||
`LinearMipmapLinear` as the bit layout alone suggests.
|
||||
* **RGBA and the light/normal records are not in the VIF lists.** They sit at
|
||||
fixed offsets in the patch's data block: `rgba_size * 4` four-byte colours at
|
||||
`rgba_ofs`, and `vert_count` eight-byte records at `light_ofs + 0x10`. The
|
||||
origin also lives there — if no STROW row supplied one, the quadword at
|
||||
`light_ofs` is the origin.
|
||||
|
||||
### Verification
|
||||
|
||||
Every ad-gif must index a texture that exists, or the geometry and the texture
|
||||
data have been misread independently of each other. Across all 27 levels:
|
||||
**47,950 ad-gifs over 18,102 patches, all indices in range**, referencing
|
||||
1429 of the 1595 level texture entries (90%). Each patch's light array is
|
||||
exactly `vert_count` records and its RGBA array exactly `rgba_size * 4`.
|
||||
|
||||
### Still open
|
||||
|
||||
The ad-gif texture bindings (which texture each primitive samples), the RGBA
|
||||
per-vertex colours and light records, and the LOD switch and morph rules in
|
||||
`TfragProc`. Positions and topology are drawable but not yet textured.
|
||||
The LOD switch and morph rules in `TfragProc`, the texel data itself, and the
|
||||
GS register values the level load builds from the texture entry. A tfrag can
|
||||
now be turned into positioned, UV-mapped, textured triangles; what is missing
|
||||
is choosing which LOD to draw and decoding pixels.
|
||||
|
||||
Reference in New Issue
Block a user