diff --git a/docs/plan/level-assets.md b/docs/plan/level-assets.md index 23b679c..28673e0 100644 --- a/docs/plan/level-assets.md +++ b/docs/plan/level-assets.md @@ -730,3 +730,71 @@ A tfrag can now be turned into positioned, UV-mapped, textured, lit triangles, told which LOD to draw, and morphed toward its parents at the right rate. Everything needed for a first frame is parsed, and the frame is verified by screenshot rather than by assertion. + +## Core index field order (2026-10-11) + +Repeatedly re-deriving these by hand wasted real time this session, so the +order is written out. It matches `LevelCoreHeader::parse` in +`crates/gc-formats/src/level_core.rs`: + +| offset | field | +|--------|-------| +| 0x00 | gs_ram count | +| 0x04 | gs_ram offset | +| 0x08 | tfrags | +| 0x0c | occlusion | +| 0x10 | sky | +| 0x14 | collision | +| 0x18 | moby_classes count | +| 0x1c | moby_classes offset | +| 0x20 | tie_classes count | +| 0x24 | tie_classes offset | +| 0x28 | shrub_classes count | +| 0x2c | shrub_classes offset | + +Note `gs_ram` and the three class tables are **count/offset pairs**, so every +one of them is two words. The region offsets (`tfrags` through `collision`) are +single words. Counting the class tables as one word each shifts every field +after them, which is how `collision` got read as `sky` and produced a page of +implausible collision headers on all 27 levels. + +## Sky (2026-10-11) + +Region is `[sky, collision)` and is well defined, but the header is **not** +yet decoded and the layout is not uniform. + +Reading `u16` at the head, most levels give: + +``` ++0x00 0 ++0x02 0 ++0x04 4 or 6 varies per level ++0x06 0 ++0x08 0 level 2 is the exception ++0x0a 3..6 looks like a layer count ++0x0c 0 ++0x0e 64 (0x40) ++0x10 128 or 192 varies ++0x12 64 (0x40) +``` + +Level 2 breaks the pattern: `+0x08` is 0x0109 and the three words after the +apparent count are shifted and different (`80 00 00 00 00 01 00 00 40 00`). +So a single fixed header does not fit every level, and the count at `+0x0a` +cannot be trusted to be one. + +A table of offsets follows at `+0x20` for the layers. The offsets ascend and +sit in the last 8-15% of the region, but the count of *non-zero* offsets is +sometimes less than the declared count (level 26 declares 6, has 4 real +offsets and 2 zero slots). Unresolved. + +## Moby geometry (2026-10-11) + +Class entries are 0x20 bytes in `core_index.bin`, fields +`geom_offset, o_class, unknown_8, unknown_c, textures[16]`; all 238 level-0 +moby classes carry `textures == ffff..ff`, i.e. no texture slots. + +`geom_offset` points into `core_data`, and the spans tile without overlap. The +data at that offset does not start with a recognisable header -- it opens with +zero words and then packed half-float VIF data (`55 55 15 3e` shows up 4 bytes +in). Not decoded.