visible() documented its argument as `byte << 8 | 1 << bit` -- high byte
selects the mask byte, low byte is already the shifted bit -- then shifted
the low byte a second time as though it were a bit index.
That is wrong twice over. It inverts the meaning of every bit argument,
and for any low byte above 8 it panics in debug, because `1u8 << 32` is
an overflow. Real data reaches it: the folded bits for the upper bytes of
a mask are exactly the values that trip it.
Treat the low byte as the bit mask, which is what the doc says and what
the renderer needs. Added an assertion for a mask index that does not
exist, since that was the case that exposed the mismatch.
A z -> y -> x tree of u16 node offsets over 4x4x4-unit cells, each
populated cell naming one 128-byte mask of 1024 visibility bits that the
renderer fills from the camera's cell each frame.
Two sentinels carry meaning and one of them is easy to miss: a z or y
slot of 0 means "no subtree", and an x slot of 0xffff means "no cell".
Reading the latter as a mask index gives a grid whose highest mask is
65535 on every single level, which is the tell.
The check that makes this real is the mask array. It starts at
masks_offset and runs to (highest_mask + 1) * 0x80, and on every level
with a grid that ends at the block boundary exactly -- widest
unexplained tail across the disc is 0 bytes. A wrong tree shape or cell
size would leave the highest mask index elsewhere entirely.
412,521 populated cells over 140,939 masks, across the 24 levels that
have one.
An offset of 0 means the level has no occlusion data at all, which is
not the same as "at the start of the file" -- that is where the tfrags
block lives, and parsing it as a grid produces a mask array that fits
anyway, with 1600 bytes to spare. That is what made level 10 look
plausible on the first pass; three levels (10, 24, 25) carry none.