Decompress the gameplay extent: the level light bank now parses

gameplay is a WAD stream, exactly like core_data. The extractor was
writing it compressed, so the light bank framing read the WAD header's
stream length as a light count: level 0's offset at +0x04 was 0xa0d
and the "count" there was 698810368.

The file says so in its first six bytes: 57 41 44 79 0d 0a -- "WADy".

Decompressed, level 0's gameplay extent is 1,872,256 bytes, the offset at
+0x04 is 0xc2b20, and the count there is 5. Five directional light sets.

All 80,274 vertices of level 0 now go through LightTfrags, and the
renderer's fallback line no longer appears. The frame's colour
distribution goes from 295 to 737 distinct sampled colours and takes on
the level's warm cast.

This corrects a recorded negative result that was simply wrong.
docs/roadmap.md carried "gameplay does not decode with the WAD LZ77
decoder, all 27 levels fail identically, so the input is wrong rather
than the decoder", with bit order and header length also ruled out.
That was true of the data being parsed and wrong about the cause: the
decoder was never the problem, it was being handed a file that had not
been through it.

Same lesson as the origin bug, from the other direction. A recorded
failure without a positive control is easy to record and easy to leave;
the control here is trivial and should have been run first -- decompress
and look.

The renderer keeps counting and reporting how many vertices it lit,
because a silent fallback to stored colours looks plausible and is wrong.
Lighting magnitudes remain unverified: that needs comparison against
reference frames via the PCSX2 loop, which is still to come.
This commit is contained in:
2026-10-10 03:27:52 +02:00
parent 65b5d366de
commit bcf0d1f0cc
3 changed files with 70 additions and 41 deletions
+15 -11
View File
@@ -14,7 +14,7 @@ early, while they are still cheap to retire.
- [x] Repository hygiene in place (pre-commit guard, `.gitignore`, licence
record)
- [x] **Phase 1 complete.** The disc pipeline runs end to end and is verified
against a committed hash table: 5,213 files, 5,762,497,559 bytes, every
against a committed hash table: 5,213 files, 5,795,847,447 bytes, every
one of the 92 asset containers parsing.
- [x] **Phase 2 in progress.** Level containers are parsed through their typed
header, and the `data` extent is parsed as a container of byte ranges. The
@@ -50,12 +50,14 @@ early, while they are still cheap to retire.
- [x] **The `LightTfrags` pass** is written and unit-tested against the PS2
model: PEXT5 base colour, `select` set blending, re-normalised blended
directions, and `base + A*max(dA, dA*wA) + B*max(dB, dB*wB)`.
- [ ] **The level light bank does not parse on RAC2.** The reference's framing
(u32 offset at +0x04, i32 count there) yields offset `0xa0d` and a
nonsense count on level 0. The renderer now reports how many vertices it
actually lit, which is currently 0 of 80,274 -- so the frame falls back
to the stored colours and says so rather than looking plausibly lit.
Detail in `plan/level-assets.md`.
- [x] **The level light bank parses and level 0 is fully lit.** `gameplay` is a
WAD stream; the extractor had been writing it compressed, which is why
the bank framing found garbage. All 80,274 vertices of level 0 now go
through `LightTfrags`. The renderer still counts and reports how many
vertices it lit, because a silent fallback to stored colours would look
plausible and be wrong.
- [ ] Lighting *magnitudes* are unverified: they need comparison against
reference frames, which needs the PCSX2 comparison loop.
- [ ] Then the GS register set and the guard-band clip test.
The disc being the exact build the reference projects pin is the single
@@ -189,10 +191,12 @@ Phase 1 hands over the extents; this phase works out what each one contains.
`unk_06`/`unk_0a` suppressing absent tiers, all 370,349 LOD entries
across the 27 levels resolve: 29,043 LOD-01 and 341,306 LOD-0, zero
failures. See `plan/level-assets.md` for the two corrections.
- [ ] `gameplay` — begins `WAD` + a per-level byte, and does *not* decode with
the WAD LZ77 decoder. All 27 levels fail identically, so the input is
wrong rather than the decoder. Ruled out: bit order, header length, the
LZ77 framing. Hypotheses queued in `plan/level-assets.md`.
- [x] `gameplay` — **it is a WAD stream**, exactly like `core_data`; the
extractor was writing it compressed. Decompressed, level 0 is 1,872,256
bytes and holds 5 directional light sets. The earlier "does not decode
with the WAD LZ77 decoder, bit order and header length ruled out" note
was wrong about the cause: the decoder was right and the input was not
what it looked like. Corrected in `plan/level-assets.md`.
- [ ] `occlusion` — 2 to 25 sectors, small enough to read whole.
- [ ] `sound_bank` — `SBlk` and `DAW` signatures found in all 27.
- [ ] `data` — the large one: 4.2 to 21.9 MB of geometry per level.