The [flap] line now reports, per root portal, the actual projected NDC vertices and
the Intersect-against-FullScreen result count (clip=N), so a portal that PROJECTS
(proj>=3) but still fails to ADD its neighbour (vis stays low) shows WHY: clip=0 with
ndc inside [-1,1] = winding/self-intersection degeneracy; clip=0 with ndc outside
[-1,1] = genuinely off-screen; the ndc coords expose a near-plane bowtie. Pins the
exact clip-region failure before the root-cause fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-frame (not cell-change-throttled, so it catches the flicker at a stable root):
[flap] line from the builder — root cell's per-portal side-test D + traverse/cull +
NDC projection, plus OutsideView poly count + visible-cell count; localEye exposes
when the eye has crossed an interior portal plane. Paired [flap-cam] line from the
draw site — FindCameraCell resolution branch (CameraCellResolution enum, new),
eyeInRoot AABB flag (stale-root signal), eye + player worldpos, and the frame's
TerrainMode/OutdoorVisible outcome. Disambiguates side-cull vs empty-projection vs
stale-root. Inert when off (gated). Throwaway apparatus to converge the flap fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code review caught a CRITICAL under-inclusion: ApplyReciprocalClip scanned for the
first OtherCellId match, so a cell with two portals to the same neighbour clipped both
near-side openings against the FIRST reciprocal polygon — hiding geometry through the
second opening (real on Holtburg cellar cells 0x148<->0x149). Plumb the dat's
OtherPortalId back-link through CellPortalInfo + BuildLoadedCell and index the reciprocal
directly (retail arg2->other_portal_id, 433557). Skip (degrade to over-include) when the
index is unresolvable — never clip against a guessed polygon. Adds a disjoint two-back-
portal regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clip the portal opening against the neighbour's matching back-portal polygon
before propagating, so a cell's clip region is the intersection of the opening
seen from both sides. Closes the M-4 stub in ISSUES #102. Can only tighten,
never under-include; degrades to prior behavior when no back-portal is found.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code-review minor follow-ups: correct the CellTodoList comments (ties are LIFO,
not FIFO — an equal-distance newcomer lands at the tail and pops first, matching
retail's break-on-first-not-greater + pop-from-tail). Update ISSUES #102 to record
that U.2a closes I-1/I-2 (under-count + duplicate accumulation) via the enqueue-once
gate, narrowing the residual to diamond-topology clip-completeness (AddToCell onward
re-propagation, tracked under U.6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PortalVisibilityFrame gains OrderedVisibleCells (closest-first). Replace the FIFO +
MaxReprocessPerCell cap with a distance-priority queue and a grow-watermark fixpoint
(retail InsCellTodoList 433183 / AddViewToPortals 433446) so cyclic dungeon graphs
converge without duplicate-cell blow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First-fix from the visual-gate-failure handoff: an empty OutsideView means
"no outdoors visible from here," not "all outdoors." When inside a building
with an empty clipped mask, Step 4 now draws NO terrain/scenery instead of
disabling the stencil and flooding ungated terrain over the cell interior
(the Step-3 walls already occupy the framebuffer). Visual-confirmed: Holtburg
cottage cellar walls are solid now, no terrain bleed-through.
Also adds portal diagnostics that root-caused so-called "Bug B":
- PortalVisibilityBuilder: per-camera-cell CAMPORTAL census (polyLen +
side-test result) emitted BEFORE the BFS guards, so an empty OUTSIDEVIEW
can be traced to the exact gate.
- A8CellAudit `portals`: replicate BuildLoadedCell's polygon-vertex
resolution so PortalPolygons[i] validity is checkable offline.
Finding: the builder is largely CORRECT — it produces narrowed clipped
OutsideView regions for most cells (0172/0173/0162/015E/0165/016F). The
empty cases are mostly legitimate (windowless cellar can't see out; the
3rd-person camera eye on the outdoor side of a front-door plane culls that
exit). The handoff's Finding 2 ("under-produces, never narrows") is
substantially not real. Remaining wall-missing regressions in OTHER
buildings live in the cross-building Step-5 enforcement, escalated separately.
All gated behind ACDREAM_A8_INDOOR_BRANCH=1; default play unaffected.
App tests 108/108.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Env-gated diagnostics (off by default; do not affect the default game):
- ACDREAM_A8_DUMP_PV=1: PortalVisibilityBuilder dumps local→NDC→clipped portal
geometry + OutsideView poly count for the first 2 Build calls per camera cell.
- ACDREAM_PROBE_ENVCELL=1: [opaque] line dumps the opaque cell-render stats
(cells/tris) BEFORE the per-cell transparent loop overwrites _envCellRenderer.Stats.
Used to diagnose the A8.F visual-gate failure (see handoff doc). Gated behind
ACDREAM_A8_INDOOR_BRANCH=1 like the rest of the indoor branch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>