12 KiB
S3 — Walk: exact PView views, leaf admission, and interleave — ownership map and chunk plan
Status: DRAFT packet written 2026-09-03 at the S2 closeout, BEFORE the owner's §7 capture session. Every retail claim below is decomp-verified (named pseudo-C + Ghidra bridge, cited by address); the capture session adds the per-frame TRANSCRIPT the automated gate needs and may amend §3 (marked "capture-owned"). Nothing in this packet is implemented yet.
Plan: docs/plans/2026-09-01-campaign-overhaul-world-solidity.md §9 S3.
Binding inputs: oh1-retail-world-contract.md §4–§5 (view/frame order),
oh1-built-mesh-view-contract.md (caller order, stamps, direct answers,
binding constraints), 2026-08-30-fw-flood-pseudocode-appendix.md, the FW
plan's verified seam map (docs/plans/2026-08-30-campaign-fw-frame-walk.md
§"Verified seam map"), and S2's ownership truth
(s2-membership-ownership-map.md §9: the registry is the only membership
source; the walk reads GetRetailPartEntriesInCell).
1. What S3 changes (behavior)
WalkPView owns retail's exact per-frame state — the portal-view lists, the
view/update counts, the todo order, the draw list, and the stamps — and each
content category follows its retail leaf rule. Terrain is emitted as ordered
landcell events interleaved with buildings and object lists in retail
far-to-near order. DrawBuilding is one semantic sequence. The "all terrain
first" simplification and every generic GPU clip rule that retail does not
have are deleted. S3 ships no evidence infrastructure beyond the one
print-only transcript emitter its own gate consumes (rule §5).
2. Retail truth (decomp-verified; addresses are the Sept 2013 build)
| Retail function | Address | What it decides | Verified in |
|---|---|---|---|
PView::InitCell / InsCellTodoList |
(walk root; see flood appendix) | seeds the flood from the viewer cell, orders the todo list | flood appendix |
PView::ClipPortals / AddViewToPortals / ConstructView |
PView::GetClip → polyClipFinish @0x006B6D00 |
builds CHILD VIEWS by polygon-clipping PORTAL polygons — the only polygon clip in the walk | built-mesh contract §"What polygon-clips?" |
Render::copy_view |
0x0054dfc0 |
copies the view polygon, derives edge planes (0x48 semantic fields, prune, cap 31) | built-mesh contract ledger |
Render::set_view |
0x0054d0e0 |
installs the view in render globals; NO scissor, NO general mesh clip | idem |
Render::obj_view_set |
0x0054b9b0 |
transforms the active planes/sphere through FrameCurrent, publishes local_object_center/radius |
idem (side effects unrepresented — Medium row) |
Render::viewconeCheck |
0x0054c250 |
the ordinary sphere admission: strict-outside / inclusive-partial | WalkVisibilityMath pins |
CPhysicsPart::Draw |
0x0050d7a0 |
outer part-stamp skip (+0xdc vs device +0xb0); force bypasses; local player bypasses the inner stamp |
idem |
RenderDeviceD3D::DrawMeshInternal |
0x0059f360 |
first admitted view stamps the non-player part and submits the WHOLE eligible mesh once; later views return | idem |
RenderDeviceD3D::DrawEnvCell |
0x0059f170 |
no sphere admission; cell stamp (+0x130) gate; whole shell once per stamp |
idem |
RenderDeviceD3D::DrawBuilding |
0x0059f2a0 |
detail state → FlushAlphaList(0) → CPhysicsPart::Draw(part,1) portal-only BSP pass → flag → Draw(part,0) ordinary shell |
idem |
PView::DrawCells |
0x005a4840 |
outside-view branch (sunlight, LScape::draw, alpha flush, device-stamp advance @0x005a4886, counter consume/clear, exit seals) then reverse shells (CEnvCell::setup_view @0x0052c430 per live view + DrawEnvCell) then reverse object lists (DrawObjCellForDummies) |
retail-world contract §5.2 |
LScape::draw_check_blocks / landcell_check / grab_visible_cells / draw / calc_draw_order |
(landscape walk) | admitted land cells in retail FAR-TO-NEAR order; per admitted cell DrawLandCell THEN DrawSortCell (building pass / look-in / shell / object turn) |
retail-world contract §5.2; capture-owned: the exact calc_draw_order sequence at the four poses |
DrawObjCellForDummies |
(object-list path) | installs the cell's top portal_view_type as PortalList, walks the cell's shadow part list (CShadowPart::insertion_sort by CYpt) and draws each part through the view loop |
built-mesh contract §"object-list path" |
Facts already PROVED and binding (do not re-derive, do not weaken):
- the built cell shell is stamped and submitted whole once after Boolean admission;
- portal polygons, not built meshes, are polygon-clipped;
DrawCellsdraws all shells then all object lists, both in reverse draw-list order, views ascending;- device, cell-shell and part stamps persist with the local-player bypass;
- the "first view clips the shell" hypothesis is RETIRED.
3. Current acdream owners (functions, not line numbers — re-locate at chunk time)
| Retail mechanism | Current owner | Assessment (from the built-mesh comparison at eaea8776, re-checked against c94a1a40 file list) |
S3 action |
|---|---|---|---|
| view polygon / planes | WalkViews |
strong match | keep; pin |
| viewcone sense | WalkVisibilityMath |
exact | keep |
| flood + todo order | WalkFrameDriver (flood turns, VisitedCells, OnLandscape) |
order proven for shells/objects; _skyDrawnThisFrame is a PROXY for retail's outside_view.view_count != 0 |
chunk 2 replaces the proxy with the real outside-view count |
| whole-mesh admission at slot 0 | WbDrawDispatcher.WalkClassify (ResolveWalkLightSet, part stamps, RetailWholeMeshSlot) |
correct | keep; chunk 4 deletes the still-translated clip slots per category |
| part stamp identity | (RenderProjectionId, PartIndex) |
retail identity is the CPhysicsPart*; S2 made per-cell membership registry-borrowed, so one logical part now reaches the classifier from EVERY cell it is in with the SAME projection id — the identity audit the contract asked for is now structurally answered; pin it |
chunk 2 pin |
| cell shell once per stamp + mid-frame re-arm | WalkFrameDriver shell loop, RetailPViewPassExecutor.WalkLeaf |
correct | keep; re-arm gate moves to the real outside-view count |
| building sequence | WalkFrameDriver building turn, RetailFrameWalk |
matches alpha barrier → portal pass → shell | keep; pin as ONE sequence |
| terrain emission | RetailPViewPassExecutor landscape stage (whole-stage terrain event before building/object turns) |
DIVERGES: retail is DrawLandCell then DrawSortCell PER admitted land cell, far-to-near |
chunk 3 |
| landscape leaf's use of the installed outside-view list | TerrainModernRenderer visible cells + WalkFrameDriver.VisitedLandscapeCellIds |
top-level ownership proven; per-leaf pixel use is an S3 audit item | chunk 3 audit (bounded: one pose) |
| generic GPU clip rules for categories retail never clips | Vulkan clip slots on look-in / straddling / building categories (RetailPViewPassExecutor, UseIndoorMembershipOnlyRouting) |
retail clips only portal polygons | chunk 4 delete, with a CPU/GPU equivalence pin for any category that must keep a translated clip |
obj_view_set side effects |
not represented (world-space sphere vs captured planes) | mathematically aligned for affine transforms | out of S3 unless the capture shows a consumer |
missing SelectionSphere fallback |
"any view → whole mesh" | not a retail branch | keep as a corruption fallback, outside parity claims (register row if it survives S5) |
4. Chunks (bounded; one Sonnet agent each; stop on a third round)
Chunk 1 — transcript emitter + parser + fixture import (needs §7 captures).
One print-only flag (documented in docs/launch-options.md in the same
commit) emits the OH line kinds the capture templates produce
(tools/walk-oracle/oh/*.template: walk / parts / alpha-depth) from the
production walk; the existing FW0-style test-side parser is extended for the
new kinds; the four captured pose logs are imported as fixtures. Gate: the
emitter's lines parse with the same parser as the retail logs; NO validator,
NO canonical JSONL (rule §5, feedback-evidence-infrastructure-sink).
BLOCKED until the owner runs the capture session.
Chunk 2 — exact PView state. WalkPView (new, App/Rendering/Walk) owns:
the live view list per cell (retail portal_view_type lists), the
outside-view count, the view/update counts, the todo order, the draw list and
the two stamps. _skyDrawnThisFrame and every other proxy for
outside_view.view_count != 0 is replaced by the real count. Per-category
leaf contract pinned: whole-once (built shell), Boolean sphere (ordinary
part), actual polygon clip (portal polygons only), repeated submission (local
player). Part identity pin: the same logical part reached from two cells
classifies once per stamp. Can start before the capture (decomp oracle);
the capture confirms.
Chunk 3 — interleave. Terrain becomes ordered landcell events: for each
admitted land cell in retail far-to-near order, DrawLandCell (that cell's
terrain range) then DrawSortCell (building pass 1 / look-in work / building
shell / land-cell object turn). Per-landcell terrain ranges come from the
existing terrain mesh layout (index ranges per landcell — verify
TerrainModernRenderer exposes them; if not, the chunk adds the range table
at bake/upload time, not a per-frame rebuild). The whole-stage terrain event
is deleted in chunk 4, not here (two-step so the pixel gate can bisect).
Gate: terrain pixels/mesh counts unchanged when no interleave is present;
dense-outdoor p50/p99 recorded before/after.
Chunk 4 — deletions. The whole-stage terrain event; the generic clip rules on categories retail never clips (Vulkan clip slots removed from those categories); any residual "first view clips the shell" code path. Gate: no duplicate draw of a stamped part across a pan/zoom replay; membership/draw count changes only at a retail view boundary.
5. Review (one Opus retail lens + one shader/perf lens at the S3 boundary)
- retail lens on every stamp/view loop branch and on the call order against the capture transcript and the decomp;
- shader review of clip-space sign, y inversion, W plane, plane count and scissor for the categories that KEEP a translated clip;
- performance review: the command-count increase from interleaving is
measured (dense outdoor p50/p99), not hidden by reordering.
Lead verifies every finding against the source before an edit (S2 precedent:
19 findings, 4 blocking, all real; see
s2-membership-ownership-map.md§9).
6. Automated gate (S3 has no standalone owner gate; folds into G3)
- transcript equality with the §7 captures at the captured depth for all four poses plus the FW0 still fixtures;
- tests distinguish whole-shell-once, Boolean part admission and actual polygon clipping;
- pan/zoom replay changes membership/draw count only at a retail view boundary;
- no duplicate draw of a stamped part;
- terrain pixels/mesh counts unchanged when no interleave is present;
- self-gate route (
tools/overhaul-selfgate/) at the three owner poses + the four capture poses, pixel-diffed against the G2 candidate runlogs/selfgate-20260903-010022-s2-review-fixes-3— the per-region diff, not the eye, is the verdict (feedback-deleted-fallback-carried-population).
7. Open questions for the capture session (ask for exactly these two)
LScape::calc_draw_ordersequence at each of the four poses (far-to-near land cell order) — chunk 3's oracle. Captured by the walk template'sLC/SClines (added 2026-09-03:RenderDeviceD3D::DrawLandCell0x0059f120 /DrawSortCell0x0059f140, one line per call with the cell'sm_DID).- Per-frame
outside_view.view_countand the device-stamp advance count at each pose — chunk 2's oracle for the re-arm gate.