D307: investigate CCTV facing-backwards — no port-side bug found; GE_D307 diagnostic in-tree

setupCctv orientation path traced end-to-end and every input verified
N64-faithful against the ROM for Bunker1: PcctvZ (not GcameraZ) switch
data bit-for-bit, boundpads match the pccg sidecar once the legitimate
load-time room-scale (pad->pos *= get_room_data_float2(), ~1.8542) is
applied, record config words incl. unkCC match; all matrix/atan2 helpers
are byte-identical src/game code. PC orientation values are what the N64
computes; if the symptom genuinely differs from N64 the remaining suspect
is fast3d's handling of the non-orthonormal lens matrix (unk84 row 0
scaled 0.1x). Blocked on user repro detail.

Also: plan/README/findings refreshed for M-197 (D75 fixed, user-confirmed)
and M-198 (D236 closed); D252 retired; findings index regenerated.
This commit is contained in:
James Dansereau committed 2026-09-21 23:26:18 -04:00
1 parent 0503d33564
commit 61766e8aef
5 files changed
+92 -33

No files matched your search

+40 -17
View File
@@ -14,9 +14,11 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
commits ahead. Branch `release/v0.4.0` off `main` when Phase 1 starts.
- All 20 solo missions (plus the ending-credits sequence) load/render/crash-free; campaign completable end-to-end
(Agent, playtested). Steady 60 fps. Audio done. Saves done.
- Known-issue list = README "Known issues" section (D252, D303, D245, D308/
D306, D307, D311, D318 disclosure, D75, D236, widescreen-stretch, D249,
D240/D241, D257/D259/D281 AllUnlocked caveat).
- Known-issue list = README "Known issues" section (D303, D245, D308/
D306, D307, D311, D318 disclosure, widescreen-stretch, D249,
D240/D241, D257/D259/D281 AllUnlocked caveat). ~~D252~~ retired (M-188),
~~D75~~ fixed (M-197, user-confirmed), ~~D236~~ fixed (M-198, pass 26 —
awaiting play-test sign-off).
## Triage of every open item (as of this triage)
@@ -29,8 +31,8 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
| D245 | Water seam between two patterns, moves with view (REOPENED) | M-142 probe: tc-shift k flips during ordinary rotation; opt-in `GE_D245_FIXEDSHIFT` candidate build-verified, needs A/B vs N64 reference before making it default. |
| D303 | Wrong extra long muzzle flash (M16 + others) | Reported only, not investigated. |
| D306/D308 | Z-fighting: Dam intro/truck wheels + general/broader instances | Two reports, likely one family; investigate together. |
| D307 | In-level security camera props face backwards on some levels (Bunker) | Reported only. |
| D236 | Surface 1 billboard trees render as a solid wall of texture | Longest-running graphics bug (16+ passes). IA4 I2:A2 decode + AC-edge fixes are **in-tree uncommitted** and owe a game-wide IA4 regression sweep — commit or shelve decision first. Second-pass suspects: fog range > TEXTLOD/mip > density/culling > palette; D276 reframed oml=0xc81049d8/fmt=3 as primary suspect. |
| D307 | In-level security camera props face backwards on some levels (Bunker) | **Investigated 2026-09-21 — no port-side bug found.** Full orientation path traced (`setupCctv` → per-frame `RotY(unkC8)×unk84`); every input verified N64-faithful against the ROM (PcctvZ switch data, boundpads incl. the legitimate load-time room-scale ×1.8542, record config words); all math helpers are byte-identical `src/game` code. Remaining suspect if it genuinely differs from N64: fast3d handling of the non-orthonormal lens matrix. **Blocked on user repro detail** (which camera/level + screenshot + ideally N64 compare). `GE_D307=1` diagnostic kept in-tree. |
| D236 | Surface 1 billboard trees render as a solid wall of texture | **FIXED (M-198, pass 26, `425237f9`):** root cause was a texture-BINDING bug — `TEXTURETYPE_DETAIL` cards drawn from the detail tile (opaque IA8 noise) instead of the base image; `gfx_lod_tile_offset` now samples tile 1 when the pair differs (`Video.DetailBaseTile`, default on). Live-verified Surface 1/2 + Depot; other levels provably untouched. Awaiting user play-test sign-off; probes stripped (`0503d335`). |
| D235 | Wrong textures after death/restart (level reload), multiple levels | State-leak on re-entry: texture pool / CI-cache not fully reset. Needs fresh-boot-vs-reload confirmation + surfaces + screenshot, then instrument `texInitPool`/CI-cache clear. |
| D288 | Silo intro: huge flat untextured triangle sweeps the frame (frames ~562–741 of bare `-level_20`) | Visually confirmed + precisely bounded; root cause unknown. |
| D294 | Statue: CCCP monument ground renders solid black, self-recovers in 10–30 s | Not investigated. |
@@ -40,7 +42,7 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
| D197 | Character face textures wrap around the head instead of clamping (Silo, intermittent) | `G_TX_CLAMP` → GL mapping + non-PoT shifts (D167 family). Try `Video.WrapFix=1` on a repro first. |
| D182(2)/D176(b) | File-select background degrades after round-trip (comb/interlacing); Surface tree-line static — shared "texture pitch/shear" defect | M-36 Family A; `import_texture_*` line-size assumption. Distinct from the disproven D183 hypothesis. |
| D176(a) | Sky: RDPHALF tri-raster decode; horizon-band coverage (Defect 2) still open | Path B draft in `scratchpad/sky.patch`, phase-fold fix applied, **never visually verified** — one `-level_22` screenshot owed. Branch `land/d176a-sky-perspective-scroll` exists (forgejo remote) — audit + port to main. |
| D75 | Front-end logos: Nintendo logo degenerate (tiny orbiting fragment); Rareware filtering wrong | **M-195 progress (2026-09-21):** emission + transform both proven correct (D63/D75V probes; zero unknown-opcode warnings; GDLs byte-faithful). Leading hypothesis: all `G_VTX` batches encode v0=0 → multi-batch nodes overwrite shared vertex slots 0..n−1, only the last batch survives. Next: cross-reference one node's G_TRI4 index ranges against per-batch counts (ROM dump) to confirm; fix is port-layer fast3d slot management if so. |
| D75 | Front-end logos: Nintendo logo degenerate (tiny orbiting fragment); Rareware filtering wrong | **M-195 progress (2026-09-21):** emission + transform both proven correct (D63/D75V probes; zero unknown-opcode warnings; GDLs byte-faithful). Leading hypothesis: all `G_VTX` batches encode v0=0 → multi-batch nodes overwrite shared vertex slots 0..n−1, only the last batch survives. Next: cross-reference one node's G_TRI4 index ranges against per-batch counts (ROM dump) to confirm; **SUPERSEDED by M-197 (same day): FIXED.** The D50 sidecar converter (`d43_emit.py`) reserved + remapped the models' embedded texture-blob spans but never copied the pixel bytes → TEXEL0 sampled a zeroed buffer → black-on-black. Tooling-only fix (blob raw-copy + round-trip validation); sidecars regenerated; **user-confirmed live** ("the images and legal page and Nintendo logo are good now"). Three files affected: `PnintendologoZ`, `PgoldeneyelogoZ`, `PlegalpageZ`. **Remaining:** pal/jpn sidecar regen on machines holding those ROMs. |
| D290 | Watch in-game "controller" section shows no control-pad graphic | Not investigated (front-end). |
| D174/D172 | Blood: decals never interactively verified (D120 needs sidecar regen); spray color fixed but owed an eyeball | BUNKER1 firefight with regenerated sidecars (`d43 && d69 && d88 --regen`). |
| D240/D241 | Gunshot SFX cadence drifts; PP7/AK47 goes silent under heavy fire near looping sounds | D241 high-confidence = D207 reproduced (check D207 entry status first — index row is stale/ambiguous). Fold into the D207 voice-cap family. |
@@ -130,11 +132,13 @@ verification (headless where possible, human eyeball/ear as merge gate):
fireball-rainbow re-report.
5. **D245 water seam** — candidate fix exists; A/B against N64 reference,
then flip default (A1-class fidelity call).
6. **D303 + D306/D308 z-fighting family + D307 camera flip** — small visual
parity items; batch per commit cadence.
7. **D236 tree wall** — commit/shelve the in-tree decode fixes first, then
continue from D276's oml/fmt=3 lead. Longest pole; consider dispatching as
a subagent investigation while 4–6 land.
6. **D303 + D306/D308 z-fighting family** — small visual parity items; batch
per commit cadence. (~~D307 camera flip~~ investigated 2026-09-21: no
port-side bug found, all inputs verified N64-faithful — blocked on user
repro detail; see Bucket A row.)
7. ~~**D236 tree wall**~~ — **done (M-198, pass 26):** `TEXTURETYPE_DETAIL`
tile-binding fix in fast3d (`Video.DetailBaseTile`); live-verified,
probes stripped. Only the user play-test sign-off remains.
8. ~~**D235 texture reload leak**~~ — **done (M-193):** port-side
`TextureCacheMap` now cleared on every stage transition via
`videoResetTextureCache()` in boss.c; 21/21 sweep pixel-identical; live
@@ -146,10 +150,10 @@ verification (headless where possible, human eyeball/ear as merge gate):
shipped, get the campaign capture, then apply the decision rules in the
finding), **then D240/D241** (fold into D207 family) + verify D230's bass
fix by ear on the elevator track.
11. **Front-end fidelity batch: D75 logos, D290 watch pad graphic, D182(2)/
11. **Front-end fidelity batch: D290 watch pad graphic, D182(2)/
D176(b) pitch-shear defect, D176(a) sky Defect 2** (verify the patch
visually first — it's been unverified for weeks), D195 Control alpha,
D197 face wrap.
D197 face wrap. (~~D75 logos~~ fixed M-197.)
12. **D174/D172 blood verification** (regen sidecars, BUNKER1 firefight).
13. **D258 PAL/JP asset conversion repair** — apply the verified repair path;
re-run the region sweep. Decide scope: ship JP/PAL-accurate or document
@@ -285,6 +289,21 @@ Order by user-visible value:
against per-batch counts; fix would be port-layer fast3d slot management.
Probe code (`gfx_pc.cpp`, `videoGetFrameCount()` in video.c/h) uncommitted
at end of session — commit with the doc updates.
- **D307 (CCTV facing backwards) investigated — no port-side bug found.**
Env-gated `GE_D307=1` probe in `setupCctv` dumps every input + derived
orientation per record. Bunker1 (`UsetupsevbunkerZ`) decode vs live: model
switch offset = `PcctvZ` (NOT `GcameraZ`, that's the gun) sw[0]
bit-for-bit; boundpads match the pccg sidecar once the legitimate load-time
room-scale (`pad->pos *= get_room_data_float2()`, ≈1.8542 here) is applied;
record config words (incl. `unkCC`) match; all matrix/atan2 helpers are
byte-identical `src/game` code. Conclusion: PC orientation values == what
the N64 computes; if the symptom is real vs N64, the remaining suspect is
fast3d's handling of the non-orthonormal lens matrix (`unk84` row 0 scaled
0.1×). Blocked on user repro detail (which camera/level + screenshot).
Findings entry updated; probe kept in-tree (D60/D88 pattern).
- **Plan/doc refresh:** D75 (M-197) and D236 (M-198) marked fixed throughout
(Bucket A rows, Phase 1 items 6/7/11, playtest brief); findings index
regenerated; README Known Issues to match.
### Big playtest brief (for the user, when the tree is final)
@@ -327,10 +346,14 @@ Checklist beyond the normal play:
13. **D207 (alarm klaxon)**: if gunfire goes quiet during an alarm, note the
level + weapon + situation; ideally re-run that spot with
`GE_AUDIOTRACE=1` and share the log (or a short clip).
14. **D75 (front-end logos)**: screenshot the Nintendo logo screen (still
expected-broken: only a tiny fragment renders — M-195 suspects vertex-slot
overwrite in fast3d) and the Rareware logo — confirms whether the v0.4.0
tree changed anything there.
14. **D75 (front-end logos)**: confirm the Nintendo/Rareware logos + legal
page still render correctly (fixed M-197; user-confirmed once already).
15. **D236 (Surface trees)**: Surface 1/2 — confirm the treeline renders as
discrete tree sprites, not a wall (fixed M-198; probes stripped).
16. **D307 (security cameras)**: if any in-level CCTV camera looks like it's
facing backwards, note which level + which camera (screenshot) — the
orientation math is verified N64-faithful, so a concrete repro is what's
needed to keep chasing it.
## Conventions reminder
- One findings entry per investigation; next labels after **D322**.
+3 -3
View File
@@ -7,7 +7,7 @@ D43-D50,RESOLVED,"model-file loading → offline sidecar ""Plan B"" (d43_emit.py
D51-D58,RESOLVED,"font pixeldata, osGetCount tick rate, model RW pools, cseq BE header, synth slots, RLE menu bg, watch raw offsets, gun-barrel DL",resolved
D59-D68,RESOLVED,"intro render: blood-RLE clobber, DMA validate, OSMesgQueue, HEADS/BODIES sentinels, romCopy width, image_entry, Globalimagetable BE→LE",resolved
D70-D74,RESOLVED,"intro-logo pixels: C-array bswap, UV path, sinf/cosf DVAL(), texture-import truncation",resolved
D75,OPEN,front-end 3D model transforms (D77 audio split out below —,"OPEN (parked). M-32 triage (see §F ""D75 ADDENDUM""):"
D75,FIXED,front-end 3D model transforms (D77 audio split out below —,"FIXED (M-197, 2026-09-21; user-confirmed live):"
D76 · D164,FIXED,Legal screen only draws line 1 —,"FIXED — this row and the ## D164 entry below were stale; the proposed one-line #ifdef PORT fix was actually committed 8dfc578f4 (2026-08-31), well before this correction (2026-09-18)."
D159,FIXED,"front-end wallet-Bond photo ""interlaced""/combed (RC1 / D149) —",FIXED (#ifdef PORT no-op the swap in image.c)
D161,FIXED,Depot (-level_30) ceiling = bright-blue speckle + radial rays (B2).,FIXED (port/fast3d/gfx_pc.cpp)
@@ -132,7 +132,7 @@ D164,FIXED,"Disclaimer / legal screen only draws the first line (D76 root cause,
D165,FIXED,"Front-end menu cursor doesn't feel like a mouse pointer (M-31, user bug B5 follow-up).","FIXED (port/src/input.c; Input.MenuPointerMode, Input.HipfirePitchSpeed added)."
D166,FIXED,Hipfire mouse pitch is digital while yaw is analog —,FIXED (port/src/input.c).…
D235,OPEN,Wrong textures load after dying/restarting a level —,OPEN — needs: does it repro on a *fresh* level boot (rules out reload-state) vs only after death/restart (confirms it); which surfaces; a screenshot.…
D236,OPEN,"Surface 1: 2D billboard trees render as a wall/sheet of tree texture instead of discrete camera-facing tree sprites (M-106, user QA report).","OPEN — pass 24 (2026-09-21, static) DECODED THE TREE TEXTURE (new tools_pc/texdecode.py ports image.c's LOOKUP/HUFFLOOKUP/RLELOOKUP codecs)."
D236,CLOSED,"Surface 1: 2D billboard trees render as a wall/sheet of tree texture instead of discrete camera-facing tree sprites (M-106, user QA report).","CLOSED (M-198, pass 26, 425237f9; probes stripped 0503d335):"
D237,OPEN,"QoL ask (M-106, user QA):",OPEN — not designed; port-only
D238,OPEN,"QoL ask (M-106, user QA):",OPEN — not designed; port-only (port/src/input.c + config.c)
D239,CLOSED,"QoL ask (M-106, user QA):",CLOSED — executed in the v0.2.0 prep pass (port-only)…
@@ -184,7 +184,7 @@ D303,OPEN,"Some muzzle flashes (M16 named specifically, ""and some others"") dra
D304,FIXED,"Mouse sensitivity menu overhaul (user request, 2026-09-18):","FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single Input.MouseSensitivity menu row + fixed overlayUpdateScroll()'s unconditional bottom-anchor, th…"
D305,FIXED,"Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, Game.AllUnlocked previously enabled on the session/save) —",FIXED (defensive guard) —
D306,OPEN,"Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).","OPEN — reported only, not investigated."
D307,OPEN,"In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g.","OPEN — reported only, not investigated."
D307,OPEN,"In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g.",OPEN (investigated 2026-09-21) —
D308,OPEN,"Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).","OPEN — reported/confirmed by the user, not investigated."
D309,FIXED,Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen —,FIXED via D310 — user-playtest-confirmed 2026-09-18 (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log).
D310,FIXED,"RULE-2-SIGNOFF: chraiitemsize() mis-sizes 1-byte AI_PRINT records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT —",FIXED — user-playtest-confirmed 2026-09-18 (v2:
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
7 D51-D58
8 D59-D68
9 D70-D74
10 D75
11 D76 · D164
12 D159
13 D161
132 D165
133 D166
134 D235
135 D236
136 D237
137 D238
138 D239
184 D304
185 D305
186 D306
187 D307
188 D308
189 D309
190 D310
+12 -4
View File
@@ -391,7 +391,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D59–D68 | intro render: blood-RLE clobber, DMA validate, OSMesgQueue, HEADS/BODIES sentinels, romCopy width, image_entry, Globalimagetable BE→LE | resolved |
| D69 · D78–D84 | stage load (`load_bg_file`): bg/stan offline sidecar (`d69_emit.py`) + StandTile/bg_room_data ABI | resolved |
| D70–D74 | intro-logo pixels: C-array bswap, UV path, sinf/cosf `DVAL()`, texture-import truncation | resolved |
| D75 | front-end 3D model transforms (D77 audio split out below — resolved, unrelated cause) | OPEN (parked). **M-32 triage (see §F "D75 ADDENDUM"): (a) D73-scope-gap RULED OUT (gu tree fully endian-clean). Splits in two: Bug 1 = logo/photo transform = the parked D114/D116 fast3d viewport mirror (not game code). Bug 2 = absent animated models = category (b). M-32b runtime probe (`GE_D75=1`): `render_pos`/`dynAllocate`-arena hypothesis RULED OUT (render_pos valid + fresh each frame), model instances valid (nMtx 21/1), zero fast3d DL warnings — failure is downstream in `drawjointlist`/`dotube` vtx/node-DL resolution or an off-screen `basemtx`. Needs a drawjointlist-level probe. M-33 (upright captures, D168 fixed): "Bug 1 = D114/D116 mirror" retracted; **gun-barrel Bond RENDERS fine** (walk + fire, upright) — the "absent" reports were the flipped capture; **Nintendo logo genuinely broken** (renders as 2 white blobs, shifted left — a real `logoinst` transform/geometry bug, not a flip); cast roll not re-captured. See §F "D75 Bug 2 — M-33 UPDATE". **v0.2.0-pre playtest (user):** Nintendo logo still broken; Rareware logo nearly right but its texture filtering looks off; MISSION COMPLETE / mode-select screens have no 3D models at all, so the earlier "absent mode-select model" framing was inaccurate.** |
| D75 | front-end 3D model transforms (D77 audio split out below — resolved, unrelated cause) | **FIXED (M-197, 2026-09-21; user-confirmed live): the D50 sidecar converter dropped the models' embedded texture blobs (`PnintendologoZ`/`PgoldeneyelogoZ`/`PlegalpageZ`) — `d43_emit.py` now raw-copies + round-trip-validates them; NTSC sidecars regenerated. Remaining: pal/jpn regen on ROM-holding machines.** Historical trail — M-32 triage (see §F "D75 ADDENDUM"): (a) D73-scope-gap RULED OUT (gu tree fully endian-clean). Splits in two: Bug 1 = logo/photo transform = the parked D114/D116 fast3d viewport mirror (not game code). Bug 2 = absent animated models = category (b). M-32b runtime probe (`GE_D75=1`): `render_pos`/`dynAllocate`-arena hypothesis RULED OUT (render_pos valid + fresh each frame), model instances valid (nMtx 21/1), zero fast3d DL warnings — failure is downstream in `drawjointlist`/`dotube` vtx/node-DL resolution or an off-screen `basemtx`. Needs a drawjointlist-level probe. M-33 (upright captures, D168 fixed): "Bug 1 = D114/D116 mirror" retracted; **gun-barrel Bond RENDERS fine** (walk + fire, upright) — the "absent" reports were the flipped capture; **Nintendo logo genuinely broken** (renders as 2 white blobs, shifted left — a real `logoinst` transform/geometry bug, not a flip); cast roll not re-captured. See §F "D75 Bug 2 — M-33 UPDATE". **v0.2.0-pre playtest (user):** Nintendo logo still broken; Rareware logo nearly right but its texture filtering looks off; MISSION COMPLETE / mode-select screens have no 3D models at all, so the earlier "absent mode-select model" framing was inaccurate.** |
| D76 · D164 | **Legal screen only draws line 1 — root-caused (M-31)**: linker-adjacency assumption broken by mingw. — full `## D164` entry at file tail | **FIXED** — this row and the `## D164` entry below were stale; the proposed one-line `#ifdef PORT` fix was actually committed `8dfc578f4` (2026-08-31), well before this correction (2026-09-18). Docs simply never caught up to the merge. |
| D159 | front-end wallet-Bond photo "interlaced"/combed (RC1 / D149) — `texSwapAltRowBytes` odd-row 8-byte pre-swap (N64 RDP odd-line TMEM XOR compensation) not reversed by fast3d | FIXED (`#ifdef PORT` no-op the swap in `image.c`) |
| D161 | Depot (`-level_30`) ceiling = bright-blue speckle + radial rays (B2). A CI8 tile drawn with `gsDPSetTextureLUT(G_TT_NONE)` was decoded against the stale `rdp.palette` → garbage. Fix: `#ifdef`-free narrow route CI→I when `palette_fmt == G_TT_NONE` in `gfx_pc.cpp import_texture()`. | FIXED (`port/fast3d/gfx_pc.cpp`) |
@@ -539,7 +539,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D233 | **All levels (intermittent): indoor level geometry invisible near doors — you can see through walls/floors into rooms you can't see into, while world objects…** — full `## D233` entry at file tail | **FIXED + VISUALLY VERIFIED (M-107 fix, M-108 verify).** See the other D233 row for full detail. |
| D234 | **Dam: guard towers along the dam structure invisible except the first one (M-106, user QA report).** — full `## D234` entry at file tail | **VISUALLY VERIFIED FIXED (M-108), mechanism unexplained.** See the other D234 row for detail. |
| D235 | **Wrong textures load after dying/restarting a level — not Facility-specific, seen on multiple levels (M-106, user QA report; clarified same session).** — full `## D235` entry at file tail | OPEN — needs: does it repro on a *fresh* level boot (rules out reload-state) vs only after death/restart (confirms it); which surfaces; a screenshot.… |
| D236 | **Surface 1: 2D billboard trees render as a wall/sheet of tree texture instead of discrete camera-facing tree sprites (M-106, user QA report).** — full `## D236` entry at file tail | OPEN — **pass 24 (2026-09-21, static) DECODED THE TREE TEXTURE** (new `tools_pc/texdecode.py` ports image.c's LOOKUP/HUFFLOOKUP/RLELOOKUP codecs). **`tex1198` LOD 0 = 64×17 RGBA5551, 44.2% opaque, and its 1-bit alpha renders as an unmistakable treeline silhouette** — pass 23's identification confirmed by decode, not inference. **Rare authored a six-level LOD pyramid that PRESERVES the silhouette and its alpha coverage (44.2% → 43.1% → 38.8%), each level a separately-authored image with its own compmethod.** Since `XLU_SURF` has no alpha test (pass 22), averaging that 0/1 alpha into fractional mip alpha would smear the minified treeline into exactly the reported band — so 'authored LOD chain replaced by driver-generated mips' is now the leading mechanism, with hard ground truth behind it. Corrects pass 23: only `tex1198` is a treeline (`tex1199` 89.4% opaque denser foliage; `tex1200`/`tex1201` 100% opaque detail textures sharing the class). Two decoder bugs found while porting (missing per-image byte-align, `image.c:1096`; a GUESSED rather than ported RLE fudge) — both produced confident wrong pictures. **Pass 25 (live) answered all three questions: (1) YES 64×17 RGBA16 intact, pool ≡ offline decode; (2) YES alpha survives (44.2% opaque); (3) NO — no code path uploads authored chains as GL mips.** New: `tex1198`–`1201` are **never drawn from an idle spawn** (zero RGBA16 imports in 4800 frames) — the spawn wall is painted by other classes (cf D276/D280); the drawn tree-class card is **`tex149` IA8 32×64 hard cutout, byte-exact import, no authored chain**. Mip mechanism located: `texGetDepthAndSize` sizes LOADBLOCKs from the header `lods` field even for single-image textures (live A/B: 2808 B vs 2048 B real data), and the port's RC2 clip + `glGenerateMipmap`/trilinear (observed live) box-filters hard 0/F alpha into fractional mips → XLU smear. Pass 26 fix directions in entry (cheapest: no mip gen for no-chain textures). |
| D236 | **Surface 1: 2D billboard trees render as a wall/sheet of tree texture instead of discrete camera-facing tree sprites (M-106, user QA report).** — full `## D236` entry at file tail | **CLOSED (M-198, pass 26, `425237f9`; probes stripped `0503d335`): root cause = `TEXTURETYPE_DETAIL` tile binding — fast3d drew the detail tile (opaque IA8 noise) instead of the base image; `gfx_lod_tile_offset` now samples tile 1 when the pair differs (`Video.DetailBaseTile`, default on). Live-verified Surface 1/2 + Depot; awaiting user play-test sign-off.** Historical trail — pass 24 (2026-09-21, static) DECODED THE TREE TEXTURE** (new `tools_pc/texdecode.py` ports image.c's LOOKUP/HUFFLOOKUP/RLELOOKUP codecs). **`tex1198` LOD 0 = 64×17 RGBA5551, 44.2% opaque, and its 1-bit alpha renders as an unmistakable treeline silhouette** — pass 23's identification confirmed by decode, not inference. **Rare authored a six-level LOD pyramid that PRESERVES the silhouette and its alpha coverage (44.2% → 43.1% → 38.8%), each level a separately-authored image with its own compmethod.** Since `XLU_SURF` has no alpha test (pass 22), averaging that 0/1 alpha into fractional mip alpha would smear the minified treeline into exactly the reported band — so 'authored LOD chain replaced by driver-generated mips' is now the leading mechanism, with hard ground truth behind it. Corrects pass 23: only `tex1198` is a treeline (`tex1199` 89.4% opaque denser foliage; `tex1200`/`tex1201` 100% opaque detail textures sharing the class). Two decoder bugs found while porting (missing per-image byte-align, `image.c:1096`; a GUESSED rather than ported RLE fudge) — both produced confident wrong pictures. **Pass 25 (live) answered all three questions: (1) YES 64×17 RGBA16 intact, pool ≡ offline decode; (2) YES alpha survives (44.2% opaque); (3) NO — no code path uploads authored chains as GL mips.** New: `tex1198`–`1201` are **never drawn from an idle spawn** (zero RGBA16 imports in 4800 frames) — the spawn wall is painted by other classes (cf D276/D280); the drawn tree-class card is **`tex149` IA8 32×64 hard cutout, byte-exact import, no authored chain**. Mip mechanism located: `texGetDepthAndSize` sizes LOADBLOCKs from the header `lods` field even for single-image textures (live A/B: 2808 B vs 2048 B real data), and the port's RC2 clip + `glGenerateMipmap`/trilinear (observed live) box-filters hard 0/F alpha into fractional mips → XLU smear. Pass 26 fix directions in entry (cheapest: no mip gen for no-chain textures). |
| D237 | **QoL ask (M-106, user QA): F10 options overlay — make it scrollable with the mouse wheel, expose more settings into it (e.g. screen-flash / no-hit-flash…** — full `## D237` entry at file tail | OPEN — not designed; port-only |
| D238 | **QoL ask (M-106, user QA): mouse sensitivity rework toward normal PC-shooter feel.** — full `## D238` entry at file tail | OPEN — not designed; port-only (`port/src/input.c` + `config.c`) |
| D239 | **QoL ask (M-106, user QA): click-to-lock vs always-grab parity.** — full `## D239` entry at file tail | CLOSED — executed in the v0.2.0 prep pass (port-only)… |
@@ -592,7 +592,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D304 | **Mouse sensitivity menu overhaul (user request, 2026-09-18): aim speed/turn speed sliders weren't "1:1", had too little range, and (follow-up) risked decoupling into a bad state; F10 menu also had a click-jump bug.** — full `## D304` entry at file tail | FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single `Input.MouseSensitivity` menu row + fixed `overlayUpdateScroll()`'s unconditional bottom-anchor, the actual cause of the reported "menu jumps to the setting below on click"). Build-verified (Windows) both passes; headless overlay smoke test clean after each. **Live F10 playtest done (2026-09-18): user confirmed the collapsed single-sensitivity menu works, the click-jump is gone, and the D251 bottom-row duplication no longer occurs.** |
| D305 | **Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, `Game.AllUnlocked` previously enabled on the session/save) — same exact FAULT ADDR 0x62 / `sndHandleEvent` signature as D285, reproduced AFTER D285's own lock fix was already live-verified crash-free on real hardware.** — full `## D305` entry at file tail | FIXED (defensive guard) — `sndHandleEvent`'s preempt-scan (`src/snd.c`) dereferenced its list-walk pointer before ever checking it for NULL (a do-while always runs its body once); D285's `osSetIntMask` lock only prevents another thread from emptying the list mid-scan, not a scan that starts with an already-empty list, so the crash could still happen even with that fix in place. Added the missing `iterState != NULL` guard before the loop, matching D255's established skip-instead-of-dereference precedent. Root desync mechanism (why pool-exhaustion accounting and the list can disagree) still not identified; `Game.AllUnlocked` correlation not proven, only reported. **Live-verified on the Deck (2026-09-18):** user ran two test sessions on Cavern with the updated build, plus toggled `Game.AllUnlocked` off then back on and relaunched — no crash in any of them. |
| D306 | **Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).** — full `## D306` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
| D307 | **In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g. Bunker (user QA, 2026-09-18) — NOT the player's view camera.** — full `## D307` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
| D307 | **In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g. Bunker (user QA, 2026-09-18) — NOT the player's view camera.** — full `## D307` entry at file tail | OPEN (investigated 2026-09-21) — no port-side bug found: orientation path traced, every input verified N64-faithful vs ROM (`PcctvZ` switch data, room-scaled boundpads, config words), all math byte-identical `src/game`. Blocked on user repro detail; `GE_D307=1` diagnostic in-tree. |
| D308 | **Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).** — full `## D308` entry at file tail | OPEN — reported/confirmed by the user, not investigated. Explicitly not for v0.3.0; D306 may be one instance of this. |
| D309 | **Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` created by `chraiitemsize`'s `AI_PRINT` NUL-scan mis-sizing a stringless PRINT record (user report + live GDB diagnosis, 2026-09-18).** — full `## D309` entry at file tail | **FIXED via D310 — user-playtest-confirmed 2026-09-18** (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log). The teardown-ordering open question (why PC presents the unreachable-Bond state) remains documented but is now harmless. |
| D310 | **RULE-2-SIGNOFF: `chraiitemsize()` mis-sizes 1-byte `AI_PRINT` records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT — fixes D309's freeze mechanism and the Caverns standing-still guards (`Stop`+`PRINT("wait")` mis-lands on EndList, re-executed every tick; user report 2026-09-18).** — full `## D310` entry at file tail | **FIXED — user-playtest-confirmed 2026-09-18** (v2: global-list-only sizing via `d310ItemSize`; guards resume, Trevelyan pathing intact, Caverns→intro clean; probe log verified both list classes). PD precedent: PRINT removed, slot 0xAD reassigned. |
@@ -12227,7 +12227,15 @@ do {
**Reported only, not investigated, explicitly not for v0.3.0.** User playtest: on some levels (Bunker named specifically), the in-level **security camera props/entities** — the gameplay objects that spot the player and alert guards, not the player's own view camera — can end up facing backwards (the wrong direction) "for some reason." No further repro detail given (trigger condition, whether it self-corrects, whether it's tied to a specific spawn/setup path). No code read done. **Correction (same day): initially misread as the player's view camera — clarified by the user to mean the in-level security camera entities specifically.**
**Status:** OPEN — logged, no investigation started. Deferred past v0.3.0 by user instruction.
**Investigation (v0.4.0 prep, 2026-09-21):** the full orientation path was traced and every input verified N64-faithful; **no port-side divergence found**.
- Orientation is computed once at load in `setupCctv()` (`src/game/prop.c`): watchpoint = `obj->mtx · Switches[0]->Data + prop->pos`; look basis = `set_basis_and_position_target(watch − padpos, up=(0,1,0))` with row 0 scaled by model scale (0.1); yaw `unkC4 = atan2f(tx, tz)`; initial turret angle `unkCC` from record config word (N64 w51). Per-frame render: `mtxs[1] = RotY(unkC8) × unk84` (`propobj.c` ~5964). All matrix/atan2 helpers are byte-identical `src/game` code (`matrixmath.c`, `math_atan2f.c`) — none are port forks.
- Data verified against the ROM for Bunker1 (`UsetupsevbunkerZ`, level_09, 4 CCTV records): model switch offset `(0, 70.3664, 31.9837)` matches `PcctvZ` (NOT `GcameraZ` — that's the gun; PitemZ idx 24 = `assets/obseg/prop/cctv`) node sw[0] bit-for-bit; boundpad positions match the pccg sidecar exactly once the legitimate load-time room-scale is applied (`pad->pos *= get_room_data_float2()`, 1/level-scale ≈ 1.8542 for Bunker1 — initially looked like a mismatch because raw file values are pre-scale); `unkCC` raw angles match record config words; prop placement derives from pad + bbox via the standard `moveToPad` path.
- An env-gated diagnostic (`GE_D307=1`, TEMP, load-time only) dumps every input and derived value per CCTV record for offline ROM comparison — kept in-tree like D60/D88.
**Conclusion so far:** given byte-identical code + verified-identical inputs, the PC orientation values are what the N64 computes. If the cameras genuinely differ from N64 hardware, the remaining suspect is fast3d's handling of the non-orthonormal lens matrix (`unk84` row 0 scaled 0.1×) in the per-frame render path — but that is unproven. **Blocked on user repro detail:** which camera/level, a screenshot, and ideally an N64 comparison (the symptom may be faithful N64 level-design behavior).
**Status:** OPEN (investigated — no port-side bug found; awaiting repro detail).
## D308 — Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).