Parse the collision container framing

Collision sits inside core_data at the offset the core index gives, behind
a 0x40-byte header that self-describes: it carries its own size and the
payload size. That pairing is the invariant -- the declared header size is
exactly 0x40 on all 27 levels and header + payload stays inside the lump.

41,481,520 payload bytes across the 19 levels that have any; 8 declare
zero length, which is present-but-empty rather than absent, so the two are
counted separately.

The cells inside the payload are not decoded. They do not walk as
fixed-stride cells, and treating faces as variable-length records stops
partway into the first cell on level 0 rather than tiling the payload. The
first cell reads as 11 verts and 33 faces under every hypothesis tried,
which is exactly the kind of agreement that looks like a result and is
not one -- three different strides all produce the same first cell and all
of them are wrong. Left open rather than committed as a guess.
This commit is contained in:
2026-10-11 02:21:10 +02:00
parent 2dcc6e9710
commit dc941a8eec
4 changed files with 221 additions and 2 deletions
+7 -2
View File
@@ -206,7 +206,12 @@ Phase 1 hands over the extents; this phase works out what each one contains.
- [ ] `tie` — instanced environment geometry, fat vertices
- [ ] `shrub` — foliage and decorative meshes
- [ ] `moby` — dynamic actors; `moby_anim` — skeletal animation
- [ ] `collision` — cells, packed vertices, faces
- [x] `collision` — container framing. A 0x40-byte header self-describes: it
carries its own size and the payload size, and `header + payload` stays
inside `core_data` on all 27 levels. 41,481,520 payload bytes across 19
levels; 8 levels declare zero length. The cell layout is **not** decoded
-- the payload does not walk as fixed-stride cells, and variable-length
faces stop partway into the first cell rather than tiling it.
- [x] `occlusion` — the PVS grid. A z/y/x tree of u16 node offsets over 4x4x4-unit
cells, populated cells naming 128-byte masks. **412,521 cells over
140,939 masks** across the 24 levels that have one; the mask array ends
@@ -214,7 +219,7 @@ Phase 1 hands over the extents; this phase works out what each one contains.
data, and an offset of 0 means *absent* rather than "at the start" — the
latter parses as a grid whose mask array happens to fit, which is how it
nearly went wrong.
- [ ] `sky`, `volumes`, `textures` (CSM1 CLUT + PS2 alpha)
- [ ] `sky`, `volumes`; textures are done (CSM1 CLUT + PS2 alpha)
- [ ] `level_overlay` — the seven-section parser and relocation from Phase 3
**Gate:** every parser has a golden test against bytes from the real disc, and