# FW0 — the retail frame walk, port-ready pseudocode model (2026-08-30) The distilled model FW1 ports from. Sources: the five decomp reads in [`2026-08-30-fw-walk-pseudocode-appendix.md`](2026-08-30-fw-walk-pseudocode-appendix.md) (BN pseudo-C cross-checked against the Ghidra patchmem decomp wherever x87-flag mush demanded it), reconciled against the live traces in [`2026-08-30-fw-walk-oracle/`](2026-08-30-fw-walk-oracle/README.md). Every function below carries its named symbol + address; the appendix has the full extractions with per-function gotchas. ## 1. The frame root — `SmartBox::RenderNormalMode` @0x00453aa0 Per frame (via `SmartBox::Draw` → `DrawNoBlit` @0x00454c20, which first runs `update_viewer` and skips rendering entirely when `viewer_cell` is null): ``` if ((viewer.objcell_id & 0xFFFF) < 0x100) { // CAMERA cell is outdoor LScape::update_viewpoint(lscape, viewer.objcell_id); Render::update_viewpoint(&viewer); Render::set_default_view(); // full-screen view Render::useSunlightSet(1); LScape::draw(lscape); // → §3 } else { // camera in an EnvCell if (viewer_cell->seen_outside) LScape::update_viewpoint(lscape, Position::get_outside_cell_id(&viewer)); Render::update_viewpoint(&viewer); render_device->DrawInside(viewer_cell); // → PView::DrawInside, §5 } D3DPolyRender::FlushAlphaList(0f); ``` `SmartBox::update_viewer` @0x00453ce0 resolves the camera pose and cell: a `CTransition` sphere sweep (the global `viewer_sphere`) from a pivot on the player (CameraManager pivot part + offset) toward the camera's sought position; `t->sphere_path.curr_cell` becomes `viewer_cell`. Fallbacks: `AdjustPosition` on the raw sought position, else camera at the player with `viewer_cell = null` (frame skipped). **The frame roots at the CAMERA's cell** — proven live by the porch-cam trace. ## 2. The invisible-panel primitive — `D3DPolyRender::DrawPortalPolyInternal` @0x0059bc90 The single primitive behind both "punch" and "seal": draws one portal polygon as an untextured CULL_NONE triangle fan, **depth-test ALWAYS, z-write ON, color alpha 0** (invisible under SRCALPHA/INVSRCALPHA). Byte-verified in the raw pseudo-C: `SetDepthBufferMode(DEPTHTEST_ALWAYS, (mode>>2)&1)` @0059be02; forced Z `0.999998987f` @0059bf4b. - `flag=1` (mode global `maxZ1`=7): every vertex Z forced to **0.999998987 (far plane)** — the **PUNCH**: re-opens the aperture's depth so look-in content can draw into it. - `flag=0` (mode `maxZ2`=6): real projected Z — the **SEAL**: writes the portal surface's own depth at the aperture. Only seals increment `portalsDrawnCount` (the deferred z-clear trigger). - Trivial reject: polygon wholly outside a ±12.0 local-XY box (the 24 m cell); the reject-loop polarity is an FP-status idiom (`test ah,0x44`) BN could not lift — **re-verify polarity at FW1 against the binary bytes** before porting. - Debug: raising the mode's alpha bit (via the maxZ1/maxZ2 globals, .data @0x820e18/0x820e14) renders the panels visibly in cycling colors. - Goes through `DrawPrimitiveUP`, gated by the registry bool `s_bAllowDrawPrimitiveUP` (default 1). - Restores NO state — callers rely on backup/restore_curr_state. **This resolves the campaign's panel question:** the "seal panels" are not mesh subsets (those authored Translucency-1.0 subsets stay never-drawn); they are the buildings'/cells' PORTAL POLYGONS drawn depth-only by this primitive. AD-117's stamps unknowingly re-invented a real retail mechanism at the wrong site with the wrong geometry. ## 3. The outdoor walk — `LScape::draw` @0x00506330 ``` GameSky::Draw(sky, 0) // dome LScape::draw_check_blocks(this) // per-view visibility union (below) for i = mid_width² - 1 .. 0: // block_draw_list built near-to-far → blk = block_draw_list[i] // backwards walk = FAR-TO-NEAR if (blk && blk->in_view) render_device->DrawBlock(blk) if (weather) GameSky::Draw(sky, 1) ``` - Grid: `mid_width`=11 × 11 blocks (`mid_radius`=5); block side 192 m (FPU-elided in BN — pinned by the explicit 24 m cell pitch). - `get_block_order` @0x00504c50: viewer's block first, then concentric rings (8 quadrant-symmetric slots per step from static coefficient tables); rebuild only when the viewer crosses a LANDBLOCK boundary. - Block frames are **viewer-relative**: origin `((row−viewer_b_xoff)·192, (col−viewer_b_yoff)·192, 0)` — the landscape renders in viewer-block-local space for float precision. - `draw_check_blocks` @0x00505f80: clears every block/cell `in_view`, then FOR EACH VIEW of `Render::PortalList` (outdoor: the default view; interior: the exit views) unions visibility via clip-height interval grids (`get_clip_height` corners → `block_check` vs max/min_zval); `landcell_check` @0x005050a0 refines per-cell (non-8×8 far blocks: all cells PARTIAL; ENTIRELY_INSIDE blocks: all cells 2; else per-cell corner grids at 24 m pitch). A cell marked by an earlier view is never downgraded. - `CLandBlock::calc_sq_draw_order` @0x0052f4a0: per-block cell order, closest cell (picked by the 9-case compass direction switch) written LAST, rings filled backwards → forward iteration = far-to-near. Early-out compares only `closest.x/y`, not `dir` (keep this quirk). Per block, `RenderDeviceD3D::DrawBlock` @0x005a17c0: pass 1 updates in-view cells' shadow objects + insertion-sorts shadow parts by depth; pass 2 per cell (far-to-near): terrain (`DrawLandCell` — detail texture only on full 8×8 blocks) then `DrawSortCell` @0x0059f140: ``` if (cell->building) render_device->DrawBuilding(cell->building) // §4 render_device->DrawObjCell(cell) // scenery/statics/dynamics via sorted shadow parts → CPhysicsPart::Draw(part, 0) ``` Mid-walk alpha pressure valve: `FlushAlphaList(flush)` with the global `flush`=0.75 (flushes only above ~2250 queued alpha meshes). ## 4. Buildings — `RenderDeviceD3D::DrawBuilding` @0x0059f2a0 ``` outdoor_pview->outdoor_portal_list = b->portals; // ALWAYS CPhysicsPart::UpdateViewerDistance(part0); // degrade level if (part0->gfxobj[deg_level] == 0) return; // degraded out → whole building skipped CBuildingObj::curr_pos = &b->m_position; // frame-restore anchor for the portal pass set building detail-surface state; FlushAlphaList(0f); CPhysicsPart::Draw(part0, 1); // PORTAL pass ObjBuildingOrBuildingPart = 1; CPhysicsPart::Draw(part0, 0); // SHELL pass (normal mesh; per-frame dedupe applies) ObjBuildingOrBuildingPart = 0; ``` The portal pass, through `DrawMesh` @0x005a0860 (per portal view, `building_view`-gated; portal-flagged draws run even when viewconeCheck says OUTSIDE) → `DrawMeshInternal` @0x0059f360, walks the building's drawing-BSP **twice** (`BSPTREE::build_draw_portals_only` — portal nodes visited far-to-near, plane epsilon 0.0002): - **Pass 1 — punch.** Each in_portal → `PView::DrawPortal` @0x005a5ab0 → `ConstructView(CBldPortal)` @0x005a59a0: viewer sidedness must match the authored `portal_side` (IN_PLANE within ±0.0002 fails BOTH gates); `GetClip` must leave ≥3 points; the destination EnvCell must be currently Visible (`CEnvCell::GetVisible` — not loaded ⇒ silently no punch, no fallback). On success: `DrawPortalPolyInternal(poly, 1)` — the far-Z punch — and the clipped view is pushed onto the destination cell's top `portal_view` via `Render::copy_view`. - **Pass 2 — look-in.** Same walk/gates; on success recurses `ConstructView(CEnvCell)` (the §5 flood seeded through `other_portal_id`) and calls `PView::DrawCells` — the trace's `DC ov=0` punches: interior cells + objects drawn into the punched aperture (no landscape, no clear, no sealing on this path). - Push/pop asymmetry (MUST preserve): `ConstructView(CBldPortal)` pops the building frame only on SUCCESS (before recursing); on failure the frame stays pushed and `DrawPortal` compensates by re-pushing `CBuildingObj::curr_pos` only on success. - `DrawCells` bumps `m_nFrameStamp`, re-arming the per-frame part dedupe so objects already drawn outdoors can draw again inside a look-in. - DEAD in 2013 (do not port): `DrawBuildingLeaf` + `curr_leaf_cells` (pre-EnvCell interior model); `PView::DrawPortal`'s pass==3 seal-on-fail branch (pass only ever ∈ {1,2}). ## 5. Interior frames — `PView::DrawInside` @0x005a5860 ``` CEnvCell::curr_view_push(cell); // num_view++ (0x48-byte lazy slot, counters reset) PView::add_views(this, cell->num_stabs, cell->stab_list); // push a view slot on every visible stab cell Render::positionPush(3, identity Position stamped with cell DID); Render::copy_view(cell->top_view, null, 4); // root view = full viewport quad PView::ConstructView(this, cell, 0xffff); // the flood (below) PView::DrawCells(this, 0); // dead arg Render::positionPop(); remove_views(...); cell->num_view -= 1; ``` `ConstructView(CEnvCell)` @0x005a57b0 — the flood: zero `outside_view.view_count`, bump `master_timestamp`, reset todo/draw lists; seed `InitCell(cell, 0xffff)` + `InsCellTodoList(cell, 0)`; then pop-from-END: append cell to `cell_draw_list` (grow +30), mark top view `cell_view_done`, `ClipPortals` → `AddViewToPortals` (clips each portal against the cell's current view and enqueues neighbors with their clipped views; portals leading outdoors raise `outside_view`). `PView::DrawCells` @0x005a4840 — the draw, all passes far-to-near (`cell_draw_list` walked from the end): ``` if (outside_view.view_count > 0) { // 'ov' in the traces (field, not the dead arg) Render::PortalList = &outside_view; LScape::draw(lscape); // landscape THROUGH the exit views (§3) FlushAlphaList(0f); m_nFrameStamp += 1; if (forceClear || portalsDrawnCount != 0) // count reset only on the !forceClear arm Clear(flag 4 /*z-buffer*/, black, z=1.0); // deferred clear triggered by earlier SEALS for cells far-to-near, per view of the cell's top portal_view: for each portal with other_cell_id == 0xFFFFFFFF: // exits to the landscape DrawPortalPolyInternal(portal.poly, 0); // SEAL @ own depth (verified @0059a49b7) } useSunlightSet(0); restore_all_lighting(); for cells far-to-near, per view: setup_view; DrawEnvCell(cell); // BSP geometry for cells far-to-near: PortalList = cell top view; DrawObjCellForDummies(cell); // objects ``` Degenerate guard NOT to port: `num_view==0` would loop 65535 views — unreachable (every listed cell was `curr_view_push`ed). ## 6. View machinery - `Render::set_view` @0x0054d0e0 — pure CPU global install: the active view's edge count, in-mask (`npnts+1` bits: edges + the CY plane), vertex/plane base, screen bounds. No GPU state. - `Render::copy_view` @0x0054dfc0 — appends ONE view: perspective-divided screen points (drop near-duplicates/collinear within ~1 px; <3 survivors ⇒ reject; cap 31), bounds, and per-edge WORLD-space planes (`N = normalize(cross(ray[k+1], ray[k]))` — NEXT × CURRENT, corrected 2026-08-30 by the flood-read appendix against Ghidra; an earlier revision of this line had the operands reversed — `d = −dot(N, viewpoint)`). `copy_view(dest, null, n)` = the full-viewport root quad (count ignored). Full extraction: `2026-08-30-fw-flood-pseudocode-appendix.md`. - `PView::GetClip` @0x005a4320 — projects the portal polygon (`xformStart`), reverses winding for NEGATIVE side, and (do_clip) clips via `ACRender::polyClipFinish` against the installed view. ≤32 verts assumed. The only CPU polygon clip in the frame. - `Render::viewconeCheck` @0x0054c250 — sphere vs the CY plane + the active view's edge planes, in viewer-block space. Cull strict (`d < −r`); partial inclusive (`d ≤ r`); publishes `local_object_center/radius` ALWAYS (even when OUTSIDE). BN's version of this body is unusable (inverted flags) — the model here is Ghidra-verified. ## 7. Constants and anchors | Item | Value | |---|---| | Outdoor cell test | `(objcell_id & 0xFFFF) < 0x100` | | Plane/side epsilon `F_EPSILON` | 0.000199999995f (0x3951B717) | | Punch far-Z | 0.999998987f | | Panel depth mode | test ALWAYS, write ON (mode bit2), alpha 0 | | Panel local-XY reject box | ±12.0 | | Landscape grid | mid_width 11, mid_radius 5, block 192 m, cell 24 m | | Alpha pressure valve | global `flush` = 0.75 (~2250 meshes) | | copy_view vertex cap | 31 (0x1F) | | Flood list growth | +30 (0x1E) | | BoundingType | 0 OUTSIDE, 1 PARTIALLY_INSIDE, 2 ENTIRELY_INSIDE | | Sidedness | 0 POSITIVE, 1 NEGATIVE, 2 IN_PLANE (always rejects) | | Exit-portal sentinel | `other_cell_id == 0xFFFFFFFF` (cell), `0xFFFF` (no-through seed) | Struct anchors (acclient.h): `PView` {outside_view@0 (view_count@+0x38), draw_landscape, outdoor_portal_list, cell_draw_list@+0x50, cell_draw_num@+0x60, cell_todo_list, cell_todo_num, lscape@+0x78}; `CEnvCell.m_DID`@+0x28, `num_view`@+0x134, `portal_view`@+0x138; `CCellPortal` stride 0x18 {other_cell_id, other_cell_ptr, portal@+8, portal_side, other_portal_id, exact_match}; `CBldPortal` {portal_side, other_cell_id, other_portal_id, exact_match, num_stabs, stab_list}; `CLandBlock.in_view`@+0xFC, `CLandCell` stride 0x108 (in_view@+0x104). ## 8. What the traces + code jointly prove about #456 Outdoor frames draw EVERYTHING distance-eligible — the far building first (far-to-near) — and correctness is pure depth: nearer terrain, shells, punches, and look-in cell geometry bury the vista. Interior frames never roster the far building (exit-view cone culls it) and SEAL their exit apertures at own depth after drawing the landscape through them, so nothing drawn later can leak into the aperture. There is no hiding mechanism to invent; FW3/FW4 reproducing this walk resolves #456 wholesale. ## 9. Verification status Byte-verified against the raw pseudo-C by hand: the seal loop (`other_cell_id==0xffffffff → DrawPortalPolyInternal(poly,0)` @0059a49af), the deferred z-clear (@005a48a9), `DEPTHTEST_ALWAYS` + z-write-from-mode (@0059be02), punch Z 0.999998987f (@0059bf4b), the fan submit (@0059bf84). Ghidra-arbitrated where BN mush was flagged: the rooting condition, the `viewconeCheck` comparisons, the ConstructView sidedness decode, the DrawCells dead argument. **Re-verify at FW1 before relying on:** the ±12 reject polarity in `DrawPortalPolyInternal` (FP-status idiom), the `DrawBlock` alpha-flush comparison polarity, and `InsCellTodoList`'s insert position (LIFO pop order depends on it — port it from its body @0x005a4f50, not from assumption). Resolved non-issue: the trace's `ov` is the FIELD `outside_view.view_count` (probe read PView+0x38), not `DrawCells`' dead argument — reports 2 and 5 agree once combined.