# Cockpit cage, glances, and the "black rear view" (2026-07-11) > **SUPERSEDED IN PART -- see "2026-07-12: the BT411 cross-check" at the > bottom.** The geometry forensics below stand; the identities and the fix > plan were revised after reading the BT411 port's reconstruction. Operator report: hat-down (rear glance) = black display; sliding the seat cam back showed "a large black cube-ish". Full forensics from a live-session fifodump snapshot (offline renders + wire scans). Resolution shipped in `live_bridge.py` (cage twist + unframed glances). ## What the geometry actually is Two cockpit fixtures ride the player mech (own-chain, `gated`): | inst | dcs | mount (wire) | shape | |---|---|---|---| | `9fd` **cockpit CAGE** | `9fe` | `dcs_link` DIRECTLY under the vehicle root (`7 9fc 9fe`) | 45 verts / 40 tris, 21x21x42, **all faces inward** -- open framed panes forward, SOLID textured wall aft; invisible from outside (backface-culled) | | `a11` canopy trim | `a10` | linked into the head rig (`7 a12 a10`, `7 a10 a3e`) | 5 geoms, r=3.4, at head height; the near-cull (<10 units) hides it in first person | Both DCS create-records carry **zone `9fb`** (type-2 node, created at mission staging alongside the two boot zones). The three ER-laser beam instances are own-chain + gated too (r=2000; the fixture filter excludes them by radius). - **The black rear view = the cage's solid rear wall**, verified by rendering the snapshot offline: forward through the panes is a perfect canopy view, rear is wall-to-wall black. Seat-cam slid back = the same shell seen from its edge (plus the canopy un-culling past 10 units). - The mech has NO real model instance of itself in the scene -- from outside (chase cam) the player mech IS a small black box. Other mechs are full models; your own is cage + canopy + beams only. ## What the wire does NOT do Scanned the whole session dump (~43k records): - The game **never updates** the cage/canopy nodes after staging -- no arm/disarm, no DCS re-pose, nothing per-glance. - **No view switching** during glances: ONE type-3 view node (handle 3); its 36 flushes are projection/fog only (incl. the mission-start fog sweep and the screen dims -- the game itself programs **832x512**, w12/w13). - Zone masks (`ffffffff` -> `0fffffff`) are set once at boot/staging for all zones uniformly -- not per-glance. - Texture alpha-cutout is NOT the rear-wall mechanism: zero of the 15 texmap nodes carry the alpha flag, and the wall texels (17,17,17 sum=51) wouldn't pass the <=24 discard threshold anyway. - Glances arrive as ordinary head-DCS chain motion (nothing else flushes). ## Ground truth (operator, ran the real pods) Tank-turret model: **torso twist = turning the turret; the cockpit cage tracks the twist.** The hat moves the PILOT'S HEAD on top of that (twist 90 right + hat right = looking back down your path). And **glance views are UNFRAMED** -- the real pods showed a clean world view with no cockpit framing on hat glances. (So hat-rear was never "through the cage's rear wall" -- the real views simply didn't render the cockpit fixtures.) ## Fix shipped (live_bridge.py -- bridge policy, Dave's core untouched) 1. **Cage twist**: `hook_chain_matrix` wraps `Renderer.chain_matrix`; chains rooted at the cage DCS get the camera's composed torso-twist yaw pre-multiplied in model space (`v @ Y @ M`; cage chain is [cage_dcs, root] with identity local, so Y lands exactly as a yaw about the mech axis). `CAGE_TWIST_SIGN` flips (default follows the camera's twist). 2. **Unframed glances**: `fp_cam` now reports `.glance` = look direction deviating > `GLANCE_DEG` (45) HORIZONTALLY from the twisted hull heading (stick-Y pitch can't trip it; TORSO.SUB vertical limits are +10/-30). While glancing, `render()` draws with the cockpit fixtures filtered out. `GLANCE_HIDE=0` disables. 3. Fixture identification (`cockpit_refresh`, after every SceneCache rebuild): own-chain + gated + not billboard + radius < 100; the cage = the one hanging directly under the root (chain length 2, radius > 5). Verified on the snapshot: picks exactly {9fd, a11}, cage dcs 9fe. ## Open / related - **Laser aim vs torso** (operator): beams render/aim along the hull heading, missiles track the torso. The beam chains ride the DCS rig, and the rig's flushed values EXCLUDE joint angles (the torso joint arrives only as 0x1f (sin,cos) entries) -- composing joint rotations into instance chains at the right chain position is the proper fix (would move the beams' origin AND direction with the twist). The pick ray (CAM backchannel) already follows the twisted look -- likely why missiles track. - Canopy trim (`a11`) twist: same joint-composition gap; currently masked by the near-cull in first person. - Whether the ORIGINAL board treated zone-9fb instances specially (camera-space / per-view zone enables) is still undetermined -- our fix implements the operator-specified behavior at the bridge level instead. - The pod crashed at session end with a guest "Illegal Unhandled Interrupt 6" storm (game-side; unrelated to the bridge -- device untouched today). ## 2026-07-12: the BT411 cross-check (C:\VWE\BT411, fresh pull) -- REVISED PICTURE The concurrent BT411 port hit the SAME black-enclosure cockpit problem, and their reconstruction settles the identities and the authentic mechanism: 1. **Instance `a11` = `MAX_COP.BGF`, the REAL cockpit shell** -- byte-proven: 272 verts / extent 2.5x2.3x3.3 / Y 0.4..2.7 matches a11's five geoms exactly (every mech has one: `*_COP.BGF`, measured with scratchpad cop_bounds.py). Per BT411 (open-questions.md): it is **the TORSO segment's inside-skeleton mesh** -- so it rotates with the torso on the real rig (operator's turret model confirmed) -- and **its window panes are PUNCH texels**: "with punch live the black pane texels become holes and the world shows through the frame". THE PUNCH CUTOUT is why real glances read as (nearly) unframed world -- the shell is never hidden. The operator's memory of seeing "the cage or the mech's arm" on left/right glances fits: thin frame lines + arm through the punched side panes. (BT411's interim policy is ours too: they hide `_cop` by name filter until their punch/skeleton branch works, `BT_INSIDE_COCKPIT=1` reveals.) 2. **Instance `9fd` (the 21x21x42 inward box, root-linked, hidden-until- armed) = the mission fade shroud** (`BTPOVStartEndRenderable`, armed for MissionStartingState=3 / MissionEndingState=4 with dplMainZone+ dplDeathZone). Session 1's "black rear wall" happened because THAT mission had ENDED (egg timer expired) and the shroud was armed; session 2 (fresh mission) never armed it -- which is why the twist hook "did nothing": the visible frame was a11 all along. 3. **Glances = `EyepointRotation`** (mech attribute; mapper look states LookLeft/Right/Behind/Down; LookBehind = yaw pi + pitch), composed into the view every frame by DPLEyeRenderable. The look commit ALSO walks the weapon roster setting the weapon+0x3e0 gate per look state -- **glancing inhibits FIRE, it does NOT hide cockpit fixtures** (my "camera children" read was wrong; those offsets are the weapon fields from the fire-gate disasm). BT411 has the whole commit block deferred (offset conflicts) -- their port has no glances yet either. 4. **On our wire, glances/twist ride the 0x1f articulation batches only** (cam-chain DCS bodies flush exactly once at creation -- verified across the whole session dump). The "hats click but nothing renders" at session end: the final 10% of the dump has ZERO 0x1f batches -- the game had stopped articulating entirely (wedged/ended state, pre-crash), not a bridge regression. ### GLANCES SOLVED + LIVE-CONFIRMED 2026-07-14 -- it was a KeyError crash **Operator confirmed hat glances now render correctly.** The whole saga resolved to a one-line bug of my own making, found via the operator's key symptom: "when the hat is held the screen STOPS rendering and snaps to the current view on release." That = render() was THROWING during glances. Root cause: render()'s glance-hide guard referenced `_ckpt['fix']`, but I had renamed that key to `'fixh'` days earlier (cockpit_refresh) and never updated this line -> **KeyError EVERY frame where fp_cam.glance was true** (i.e. every glance frame). The exception was swallowed by render()'s try/except, so NO frame drew during a hold (screen froze), and on release fp_cam.glance went false, the guard short-circuited before the bad key, and the draw resumed ("snaps to current"). fp_cam was computing the glance camera correctly the WHOLE time (out_yaw provably swung with the hat) -- the crash was downstream of it, in the draw dispatch. Fix: REMOVED the glance-hide block entirely (always `r.draw(board)`). This both kills the crash AND implements the already-decided descope (pilots confirm the canopy stays visible during glances -- a11/MAX_COP has no rear geometry so rear reads unframed naturally). The glance rides the camera via fp_cam, which reads the eye-DCS 0x1f absolute pose -- exactly the authentic game->board wire op the operator insisted it was. **The operator was right at every turn:** it was a wire operation (action 0x1f eye-DCS reflush), NOT input/transport/binding; do NOT tee from vRIO. My successive "game-side / fix_degenerate / not-emitted" theories were all wrong; the persistence on "find where we drop it in the data path" was correct -- we were crashing on it. ### REAR VIEW (hat-down) 2026-07-14 -- canopy drop, LIVE-CONFIRMED Right after glances started rendering, the rear glance (hat-down / LookBehind) came up BLACK, and sliding the seat back showed a black box. Chased it: - NOT the 9fd shroud: in gameplay 9fd is inst_visible=0 (unarmed, not drawn); hiding it was a no-op. The live probe's "own drawn" list showed the ONLY own-mech instance drawn is a11 (the canopy, MAX_COP, r3). - The canopy is a shell around the head: open front, dark solid BACK. Looking forward = through the open front (world + strut framing); looking behind = the canopy's dark interior back = black. GL render confirmed: rear WITH a11 = black, rear WITHOUT a11 = full arena (geometry is all there behind). OPERATOR (ran the real pods): **hat-down on original hardware gave a CLEAR rear view, NO canopy framing** (left/right glances DO keep the canopy). So the authentic rule is direction-dependent. Fix: fp_cam computes glance_dev (look deviation from twisted hull heading); render() drops the canopy fixtures when glance_dev > REAR_DEG (110 deg default -- left/right ~50 deg keep it, rear ~180 deg drops it). Operator confirmed "acceptable behaviour." COCKPIT CAMERA COMPLETE + ALL LIVE-CONFIRMED: twist (turret-true, zero parallax) + lasers follow torso + hat glances left/right (canopy framed) + hat-down clean rear view + the pipe transport (vRIO/vPLASMA). Remaining is cosmetic (IR/thermal palette on action 0x1b, texture interpolation, per-mech seat trim). Diagnostic scaffolding (glance_probe, fp_cam.out_yaw telemetry, own-drawn list, BRIDGE_AUTOSAVE) left in, harmless; trim in a cleanup pass. ### GLANCE: THE forensics trail 2026-07-14 (era A/B -- superseded by the fix above) **There is no glance regression -- the wire NEVER carried a hat glance, in any era.** Prompted by the operator's challenge ("engine unchanged, only the transport changed com0com->pipe -- so why did it break?"), diffed a 7/07 working-era capture vs 7/13: - Cam-chain DCSs flush ONCE at construction in BOTH eras; no per-glance reflush ever (era_diff.py). - `fix_degenerate` provably changes the look yaw by ZERO (bisect_glance.py: raw == fixd at every checkpoint) -- EXONERATED as the culprit. - Decomposing the look into hull + twist + residual (find_glance.py): the residual is FLAT across both 7/07 captures (only the +-180 chain- construction artifact). No independent glance rotation in the wire. **What actually happened (from our own memory + these forensics):** the game never emitted a chain-independent glance through our HLE device. The single time hat glances "worked" (2026-07-07) was a BRIDGE fp_cam hack (recover the glance from the degenerate chain, swap yaw<->pitch) that the operator confirmed "momentarily" -- and it was REVERTED the same day because it corrupted stick-Y vertical aim into yaw. The "source fix" that replaced it (`fix_degenerate`) is inert for glances (proven above). So there is NOTHING to bisect: glances were a reverted experiment, not a lost feature; the com0com->pipe transport change coincided with "stopped working" purely by timing. This RETIRES the prior "game-side binding / keyboard-dead" and "fix_degenerate ate it" theories -- both wrong. **Path forward (operator principle 2026-07-14: DO NOT tee from vRIO -- the glance is an authentic game->board WIRE op; find where we drop/misdecode it).** This is CORRECT and cracked open the key protocol fact: **RUNTIME DCS UPDATES TRANSMIT AS ACTION 0x1f, NOT 3.** BT411 FUN_0048ffa4 (flush dirty-DCS list) + FUN_0048e440 -> FUN_00492580(**0x1f**, ...): a runtime DCS matrix update -- INCLUDING the eyepoint reflush -- packs per DCS either 12 floats (type-0, full matrix) or 2 words (type 1-3) and sends on **action 0x1f**, the same action as the articulation batch. So every earlier "no reflush" scan (which looked at action 3) was blind to it. The glance lives in the 0x1f stream. **Where our render stands vs that:** the eye DCS = the node the game list-adds to the view (6df in glance_snap); it IS a 12-float 0x1f node and IS in our cam_chain -> chain_matrix already applies it, so a real glance reflush WOULD render for free. BUT: our fp_cam only composes 0x1f *joints* (2-float sin/cos) for cam_chain members (the twist sum); a glance carried as a 2-word entry on a DCS OUTSIDE our heuristic chain would be parsed and DISCARDED -- a concrete renderer gap if that's the form. **What the captures show (glance_snap, plateau.py):** NO 0x1f handle shows a sustained hold-then-return matching the 5s hat holds -- the eye DCS (6df) moves only with hull/drive, walk joints just oscillate (runs 15-45), static mounts sit at 180. So in OUR broken-setup capture the game isn't emitting a glance reflush. But this capture is from the NON-working setup, so it can't distinguish "renderer drops it" from "game doesn't emit it" -- need a capture that contains a real glance. **DECISIVE next step (probe rewritten -- glance_probe now watches the RIGHT signal: eye/leaf 0x1f yaw + out-of-chain 0x1f movers, per 4s report):** a NARRATED 5s hold next session settles it -- leaf yaw plateaus with the hold = game emits, we must render it (bridge application bug, find it); out-of-chain mover plateaus = we parse-and-drop it (apply that handle); both flat = game not emitting (then it's upstream, the hat->look-state binding). NO vRIO tee. ### GLANCE MECHANISM DECODED 2026-07-14 (disasm) + eyepoint pipeline (reference) Chased the hat glance through the shipped BTL4OPT binary (BT411 decomp). The camera path, end to end: - The piloted mech builds as **insideEntity** (btl4vid.cpp:300-304) -> the **eyepoint camera is a board DCS** created by **DPLEyeRenderable** (ctor @004579a8): eye DCS handle at [this+0x10], and a pointer to the mech's **EyepointRotation** attribute at [this+0x48]. - Per frame, **DPLEyeRenderable update @00457b48**: if EyepointRotation changed (vs cached [this+0x4c]), recompose the eye DCS matrix from the euler and mark it dirty (@0045fbf4 appends to the renderer's dirty-DCS list @+0x2c8) -> the eye DCS gets **reflushed to the board**. - EyepointRotation (mech+0x360) is written by the **mapper look-commit** (mechmppr.cpp KeypressMessageHandler / InterpretControls, part_013.c:418): when look-state (0x198, derived from lookLeft/Right/Behind/Down at param+0x134..0x140) changes, it writes the euler (LookBehind = yaw pi = 0x40490fdb, pitch from torso+0x570) and re-slaves the camera children. **So a glance = an eye-DCS reflush, and that DCS is IN our cam chain -- we'd render it for FREE if it happened.** It doesn't: the glance-probe premise (validated on glance_snap: all 11 cam-DCS reflushes are at staging 22.6%, ZERO during the 80-98% holds) proves the game never moves the eye during our glances. **Root cause (narrowed):** EyepointRotation never changes => the mapper look-commit never fires => the look-state fields never change. Those fields are set by the ARROW keys via KeypressMessageHandler (keyboard is DEAD in the pod, see above) -- and the HAT button reaches an audio-mapped action (hence the glance SOUND) but, in this build/config, does not set the look-state fields. Both glance routes are therefore blocked in the current -egg trim; "worked on 7/07" was a different session config. Overturns two earlier claims: NOT a view/zone re-parent (the only view list-ops are at staging) and NOT a wire-parse blind spot (zero 0x1f parse failures). **Decisive next step (telemetry SHIPPED, live_bridge glance_probe):** a NARRATED hat hold ("holding left NOW") vs the `GLANCE-PROBE: cam DCS .. REFLUSHED` line settles it: a reflush during a hold = camera IS moving (bridge bug, unlikely per forensics); silence = game-side gate confirmed, and the fix moves to the input binding (make the hat set the look-state fields -- CTL binding / the same fields the dead arrow keys drive), OR a bridge-synthetic glance (compose glance yaw in fp_cam like twist -- but the bridge needs a hat-state feed it doesn't currently have; the game's per-hat instance-visibility blip on inst-701-family + zone is the only wire-observable candidate and needs the narrated capture to decode). The in-game keyboard being dead is now ON the glance critical path -- fixing it (or binding the hat to look) may be the whole fix. ### PUNCH-CUTOUT DESCOPED 2026-07-13 (pilot testimony) Operators who flew the pods report **seeing canopy geometry when hat-glancing left/right** -- the shell structure was VISIBLE in glance views. This matches a11/MAX_COP's measured geometry exactly: all five geoms sit FORWARD of the head (bbox z -3.4..-0.7, NO rear geometry), so rear glance = naturally unframed world and side glances = sweeping past the struts. NO punch cutout is needed for glance correctness; the 7/12 "black rear wall" was the 9fd fade shroud (mission-end state), not the canopy. Consequences: - The punch-cutout work item is DROPPED for the canopy (BT411's D3D port still needs it for their blx_cop texture; and the punch texel semantics may still matter for OTHER textures someday -- footnote only). - **The GLANCE-HIDE policy must RETIRE once glances render**: authentic glances show the canopy sweeping past, so hiding fixtures during glances is anti-authentic. Keep GLANCE_HIDE only until the eyepoint pipeline works, then default it OFF. ### Revised fix plan - **The authentic fix for the shell = implement the PUNCH texel cutout** for `_cop` textures in the renderer (their windows render as holes). Our wire carries NO texmap alpha-flag words (all 15 = 0), and the shell's dark texels (17,17,17, sum 51) exceed vrview_gl's alpha-cut threshold (<=24) -- so BT punch is a DIFFERENT flag/semantic than the FLYK-era cutout: find where the punch attribute travels on the VPX wire (texture upload header? b2z tag?) or key it on the `_cop` texture content. With punch live, the glance-hide policy for a11 RETIRES (authentic = shell always on, windows see through); keep hiding 9fd behavior as-is (it is a fade shroud -- its blackness is the point). - **Twist**: a11 is torso-mounted per BT411, and the operator watched it stay chassis-locked -- so our chains genuinely lack the torso joint rotation (confirmed joint-composition gap). Bridge yaw hook targets fixture DCS a10; first live test DOUBLED (sign inverted in model space); `CAGE_TWIST_SIGN=-1` is loaded but UNTESTED (sim was retired for the night). The proper engine-level fix stays: compose the 0x1f joint (sin,cos) rotations into instance chains at the joint DCS -- BT411's gyro/eye-joint reconstruction (IntegrateEyeJoint @004b2ec0, currently a NaN-stub for them) is the reference for WHERE the joints sit. - **Lasers vs missiles**: BT411 confirms the crosshair = torso boresight (stick twists the torso to aim; no free-aim on twist mechs). Their open item (b): "on a TWIST-CAPABLE mech the crosshair should deflect with the torso twist AND the torso should visibly lead the legs". Our beam render + aim ride the joint-less chain = hull heading; the pick ray (CAM backchannel) is twist-aware = missiles track. Same joint-composition fix covers the beams (origin AND direction). - 9fd arming = mission state; a mission-review/production run will show the start blackout + end blackout arming on the wire (watch instance body word4 flushes on 9fd). ## 2026-07-13: twist SOLVED (root-pivot + mirrored basis); glances = wire-silent First full pipe-transport session (namedpipe vRIO/vPLASMA: controls + plasma confirmed good). Offline forensics on the glance/twist capture (scratchpad glance_snap.fifodump, torso held to +68deg at 92.2%): **LIVE-CONFIRMED 2026-07-13 night (operator): the canopy tracks the torso twist (turret-true), and the LASER BEAMS follow the torso too.** Final recipe: root-pivot yaw conjugation (M inv(Mr) Y Mr) at CAGE_TWIST_SIGN=+1 applied to ALL own gated instances (canopy + shroud + the three gun-mount beam instances -- twist_dcs; beams excluded from the glance-hide set), plus the camera EYE swung along the same turret arc in fp_cam (operator: the head is rigid with the torso -- zero shell/view parallax; the eye-position arc is the authentic world-view motion). Closes both "cage locked to chassis" and "lasers fire where the chassis faces". ALSO FOUND 2026-07-13 night: **in-game PC keyboard input is DEAD in the pod** ('l' searchlight dev key, '+'/'-' zoom, arrows: nothing; DOS-prompt typing fine). Never historically validated -- may have been broken forever. Suspects for a cold test: the shipped binary's L4CONTROLS parse (setenv echoes RIO,KEYBOARD so policy is right), or the VPX device's extra SDL head windows eating keystrokes. Consequence: the arrow-key glance experiment is VOID -- keyboard nulls prove nothing about the look pipeline. Glance regression suspect narrowed to vRIO hold semantics (old COM build glanced fine yesterday; glances are the hat's only HOLD-driven function; ask vRIO's log: 88 on deflect, 89 only on release?). **Twist sign CORRECTED 2026-07-13 late (rendered A/B, ab2_*.png): default CAGE_TWIST_SIGN=+1.** The -1 default came from a numeric calibration that mixed yaw-sign conventions; the rendered A/B at the held +68deg twist shows +1 brings the shell around WITH the twist (turret behavior; the small parallax = head-off-axis, authentic) while -1 rotates it OUT of view (the "canopy does not rotate" live report -- it was leaving the frustum). Also learned: handle namespaces alternate between missions (9fc/a10 vs 69c/6b0 rigs) -- never hardcode; the fixture detection handles it. One live confirm pending. **BT411 new-pull digest (2026-07-13 evening, renderer-relevant):** - FOG restored (task #63): authored per-map/time/WEATHER in BTDPL.INI (weather = an EGG field: clear/fog/soup); the arcade fog = dpl_fog_type_pixel_lin (per-pixel linear) -- Dave's GL shader is already per-pixel linear, so our fog is authentic; useful for checking per-egg fog VALUES. - Gait (task #59): piloted mech plays INTERIOR 'i'-suffix clips -- NO hip lean (level cockpit) + jointshakey cockpit rattle; exterior mechs lean -8/-11 deg into walk/run. Our wire carries whatever the game plays => the bridge inherits level+rattle natively; other mechs SHOULD visibly lean (check live). - Torso twist live (task #57/58) w/ centered boresight crosshair -- reference for our laser-aim/joint-composition item. - Missile splash/damage-economy fixes + DAFC muzzle flash (task #60-62) and the i860 specialfx forensics (065c114) -- board-side effect engine decode, groundwork for rendering detonations/impact FX in the bridge. **Twist -- measured and closed.** Yaw ledger: the camera = hull yaw (chain Z-row, contains NO twist) + JOINTS twist sum; the canopy is HULL-LOCKED natively (its world yaw tracks the hull exactly through twists). The three confusing live observations all came from ONE bug: the hook's model-space pre-multiply yawed the canopy about its own local origin, swinging it sideways in an arc. Fix: compose the yaw ABOUT THE VEHICLE-ROOT AXIS (M' = M inv(Mr) Y Mr, Mr = root pose from anim_abs) -- distance-from-axis preserved exactly (pivot_check.py). One subtlety: the rig's root basis is MIRRORED (det -1, same family as FP_RIGHT_SIGN/fliplr), which inverts the yaw sense under conjugation -- hence default CAGE_TWIST_SIGN=-1, calibrated offline (canopy lands exactly on native+twist). AWAITING one live confirm. **Glances -- the game never puts them on the wire (in the test egg).** Around-the-clock 5s holds captured; exhaustive scans of the tail: NO pose node rotates, NO joint pulses match holds (the 12-joint flurry = the legs WALKING; the +-64deg sweeps = the twist test itself; the zero-translation anim nodes = STATIC rear-facing mounts at yaw 180 always -- NOT eyepoints; my 6b3 identification was wrong). Meanwhile the game DOES react internally (range-bar jumps on hats). Best hypothesis, matching BT411: the glance renders via the GYROSCOPE's eye-joint integrators (IntegrateEyeJoint @004b2ec0 -- incomplete/NaN-stubbed in their port too), and that subsystem never emits in our -egg trim -- OR earlier "working glances" (7/07) came through a path that today's state doesn't drive. The 7/07 sessions DID render glances, so the signal exists under some conditions -- find what differs (egg? mission state? control mode BAS/MID/ADV? gyro power?). ## 2026-07-13: vision modes (IR/thermal) + the shipped keyboard map Looked up the rumored CTRL-W / CTRL-T vision keys in BTL4OPT.EXE (BT411 decomp + reconstruction). Verdict: **no such bindings exist in the shipped binary.** Plain `w`/`t` are pilot-target select (slots 0/3). The RP-era engine SOURCE had ALT-W = wireframe and ALT-V = "predator vision" debug keys (L4APP.cpp), but in the shipped BT binary the wireframe toggle (@0045fdd8, prints "wireframe ON/OFF") is DEAD CODE -- no caller, no pointer-table reference -- and no app-level ALT-key switch exists at all. The tip most likely drifted from ALT-W/ALT-V or a different build. **The REAL IR/thermal mode -- and how to render it:** - `ThermalSight` subsystem (BT411 thermalsight.hpp, classID 0x0BDE, a PowerWatcher): driven by the cockpit IR BUTTON (`requestedOn`), gated by generator power + heat + being the locally-viewed mech. - Its sim calls the global pvision toggle @0045fe44 (prints "pvision ON"/"pvision OFF") which issues **`dpl_Effect`(type 0, handle 0, {c,c,c}, mode) with mode = -1 (ON) / -2 (OFF)** -- a special view-effect = the Division board's thermal palette flip. THAT is the wire signature our renderer must honor: watch for the effect/fog-mode carrying -1/-2 on the view and swap the output palette (the "IR button = thermal render mode, nothing to render it" note from 7/06 closes here). - dpl_Effect type map (from callers): 0 = view color effect/fog-family (color + mode), 1 = per-handle effect, 2 = clear/reset. The pvision call is type 0 on handle 0 (the main view). - **Wire encoding (host stub @0048e168): type-0 effects transmit ACTION 0x1b, payload = [mode:u32][node:u32][0x40-byte color struct]** -- fog uses the same action with ordinary modes (0x1b already appears in our session histograms); **pvision = mode 0xFFFFFFFF (ON) / 0xFFFFFFFE (OFF)**. Bridge implementation = watch action 0x1b word0 for -1/-2, flip a thermal palette in the present pass. (Type-1 effects = action 0x1d, 0x108 bytes; type-2 = action 0x23, 8 bytes.) **"Some mechs use IR, some use another vision mode" (operator) -- tracked down 2026-07-13, game-side verdict: there is exactly ONE vision mode.** Every mech roster in BTL4.RES carries the SAME ThermalSight subsystem (BT411 weapsub audit, all chains), it has no per-mech model fields, the IR button gate at record+0x25c is the electrical-short event flag (not a capability switch), and the pvision toggle takes no parameters. Candidate explanations for the memory, for the old pilots to arbitrate: (a) the OTHER vision aid on every roster is the SEARCHLIGHT (night illumination cone) -- "IR mech vs searchlight mech" habits; (b) ThermalSight SHUTS OFF at heat alarm level >= 2 -- hot energy-boat mechs lose IR constantly, reading as "this mech doesn't have IR"; (c) a different build ('96 BTLIVE vs 4.10) or the sensor-MFD display modes. Ask: WHICH mechs had which mode, and what did it look like (white-hot vs green)? Archaeology bonus: sda4/DPL3/VRENDER/VWE.DOC = Division musing on a Pixel-Planes 5 / DEC Alpha board for VWE (the PXPL5SUP dir) -- pvision's official name in the engine is "predator vision". **Shipped keyboard map (PC keyboard, KeypressMessageHandler @004d1bf0)**, useful for dev testing from the DOSBox window: `+`/`-` target-range zoom; `1-5` + `a b c d f g s v x z` weapon/preset modes; `w e r t y u i o` pilot-target select; `j`/`l` fake LRM10 / Searchlight buttons; F1/F2 joystick align begin/end; 0x13d/0x13e cycle control/display mode; **ARROW KEYS = the eyepoint look keys** (UP=forward, LEFT/RIGHT=glance left/right, DOWN=look BEHIND, CTRL-UP=look down); Ctrl-F1..F10 = fake subsystem buttons (GeneratorA-D, Condenser1, LRM15 fire/ammo/load, Avionics, Hud); `\` = mech message 0x19; `&` = stop mission. NOTE for the glance hunt: the arrow keys drive the SAME lookLeft/lookRight/lookBehind/lookDown fields as the hat -- a keyboard glance test needs no vRIO and isolates the eyepoint->board question. **Renderer backlog (operator, 2026-07-13): the Division card did TEXTURE INTERPOLATION (bilinear filtering)** -- check vrview_gl's texture sampler (likely NEAREST) and implement/verify linear filtering for authenticity. **Bridge state:** the eyepoint camera compose is EXPLICIT OPT-IN only (GLANCE_DCS=) -- auto-detection would have latched the static 180 mounts and flipped the camera permanently. New telemetry for the narrated hunt: the 4s report prints `wire: NEW anim/joints=[...]` whenever handles first appear in the 0x1f stream -- next session, have the pilot narrate ("holding hat-left NOW") and read the log; if nothing appears during holds, compare against a 7/07-style run (gauge_arena_sound.conf, no net stack) to isolate what enables the eyepoint emission. --- ## 2026-07-14: Where the IR / thermal palette actually lives (source hunt) Operator question: does the game tell the Division card *which* palette to use for IR/predator vision, or is the card's firmware around to decompile? Answer: **the game specifies no palette at all -- it just flips a switch; the palette is baked into the i860 board firmware.** Chain of evidence (all from THIS project's primary sources -- OUR dump is the authority; BT411 is a downstream reconstruction *of* this and is NOT cited): 1. **Our own game source: `CODE/RP/MUNGA_L4/L4VIDEO.CPP:5535`, `DPLRenderer::DPLTogglePVision()`** -- the real, shipped, non-stubbed implementation (the engine `DPLRenderer` is shared by BT and RP). Comment reads `toggles the state of dpl "predator" vision`. Verbatim: ```cpp static Logical pvision_on = 0; dpl_EXPLOSION_EFFECT_INFO sfx_info; sfx_info.x = sfx_info.y = sfx_info.z = 0; if ((pvision_on ^= 1) != 0) { ... sfx_info.type = -1; } // pvision ON else { ... sfx_info.type = -2; } // pvision OFF dpl_Effect(dpl_effect_type_explosion, NULL, &sfx_info); ``` Pvision is sent as a **special "explosion" effect at the origin with `type = -1 / -2`**. The struct (`CODE/RP/MUNGA_L4/libDPL/dpl/DPLTYPES.H:278`, `{float x,y,z; int32 type; dpl_TEXTURE *tex;}`) has **no colour field** -- so the game hands the board zero palette information. (This also corrects an earlier disasm misread that thought an RGB triple + matrix was being sent; there is none.) 2. **DPL3 SDK source (`sda4/DPL3`, `sda4/DPL3RLS`).** The board effect dispatcher `PAZsfx()` (`VRENDER/SFX.C:751`) only handles explosion codes `0/1/2`; there is **no `-1/-2` branch and no DAC/palette flip anywhere in this source**. This VRENDER source is the 1994-95 vintage (DPL3RLS build dirs `VR_40826`..`VR_50329`) -- it **predates the pvision feature**. 3. **The exe itself.** Same as (1): the on/off flag is all that crosses the wire. Nothing selects a colour. So the palette is the **board's built-in response to explosion type -1/-2**, i.e. it lives in the i860 firmware, not in the game, the SDK, or the exe. ### Is the firmware around / decompilable? Yes. The board-load images are in the dump as `VRENDMON.BTL` (plus the `VREND2..9` overlays per game). Dated build tree `sda4/VREND/` runs **Oct 1995 -> Jun 1996** (`51019` ... `60623EDO`), newer than the source we have; the production images are `sda4/BTLIVE/` and `sda4/RPLIVE/`. The newest (`VREND/60623EDO/ VRENDMON.BTL`, 13 Jun 1996, 85 KB) is **raw i860 machine code** -- opens `f0 b4 d1 d1 ...`, no COFF/ELF wrapper, no symbol/string table (grep for vision/pred/therm/heat/palette = nothing; strings are stripped/packed). Bottom line for the crew: - The **exact** IR palette can only come from **reversing the i860 `VRENDMON.BTL`** (Ghidra has an i860 module; same workflow the BT411 team already runs). Target: the colour/DAC transform gated by the effect `type == -1`. It's a real RE effort (stripped code) but the binary is here. - Until then our `heat` palette is an educated interim; the IR-vision-options sheet (heat/green/amber/mono) is the fast path if a crew member simply *recognises* the original look. - Empirical cross-check: hitting the cockpit IR button in the live sim already drives `board.pvision` through action `0x1b` mode `-1/-2` -- exactly the explosion-type encoding above -- so the mechanism is confirmed end to end; only the colour LUT is unknown. ### Revised model (operator, 2026-07-14): grayscale squash + fog off, not a palette Operator's read: predator vision is probably **not** a false-colour palette swap -- it's a **per-pixel squash to grayscale plus fog turned OFF** (so targets read through night/weather). This fits everything: the game sends no colour, and "see through the murk" is the same family of trick as the searchlight (which turned out to be a view-fog push-back, not a light cone). `heat`/`green`/`amber` were only ever an interim guess at the *name* "predator". Renderer changed to match (`dpl3-revive/patha/vrview_gl.py`): - default `VRVIEW_PVISION_PALETTE` flipped `heat` -> `mono` (grayscale squash). - when pvision is active, the **scene pass forces `fog_on = 0`** (a present- pass recolour alone cannot undo fog already baked into the pixels). - green/amber/heat ramps retained purely as opt-in crew A/B (`VRVIEW_ PVISION_PALETTE=green|amber|heat`). Still a hypothesis pending a live look + crew memory; the ground-truth remains recoverable by reversing the i860 `VRENDMON.BTL` (colour/DAC transform gated by effect `type == -1`).