Commit graph

1 commit

Author SHA1 Message Date
Erik
dac8f6ad1f fix(render): §4 flood strobe — homogeneous reciprocal clip + collinear-aware region dedup
THE BUG (pinned deterministically by the new CornerFloodReplayTests harness — real
Holtburg cells, captured corner-press scenario): a smooth 2 cm/step monotonic eye
sweep across the 0172↔0173↔0171 doorway produced a NON-monotonic flood — on ~10 of
61 steps the player's room (0172) vanished from the flood entirely or collapsed to
a sub-pixel sliver, taking its downstream chain (016F, the outside view) with it.
Live, those isolated frames are the §4 background strobe: openings/passages flash
the clear color during transitions, and the corner press shows background at the
angles that park the eye near the doorway plane.

TWO root causes, both fixed:

1. ApplyReciprocalClip ran the reciprocal portal polygon through the legacy
   divide-first ProjectToNdc + 2D Intersect path, justified by "the reciprocal is
   never near the eye." That assumption is exactly false at doorways/corners: the
   reciprocal IS the same opening whose plane the eye presses against (2-60 cm).
   ProjectToNdc's MinW=0.05 eye-clip + side-plane clip + divide is knife-edge
   there — 2 cm eye moves flipped its output between a no-op and a duplicated-
   vertex hairline that ground the healthy region down to <3 distinct vertices.
   FIX: route the reciprocal through the SAME homogeneous pipeline as the forward
   clip (ProjectToClip + ClipToRegion) — which is what retail does:
   PView::OtherPortalClip (decomp:433524-433563) runs the reciprocal through the
   very same GetClip(finish=1) → ACRender::polyClipFinish homogeneous clipper.
   Also ported retail's skip: exact_match portals (CCellPortal.exact_match,
   acclient.h:32300; PView::ClipPortals :433689) bypass the reciprocal clip —
   both sides share the same polygon, so re-clipping is redundant.

2. CellView.CanonicalKey missed COLLINEAR re-emissions: the homogeneous region
   clipper legitimately inserts intersection vertices ON a subject edge when a
   region edge grazes it, so BFS re-clip rounds re-emit the SAME geometric region
   with 1-2 extra collinear edge vertices — keyed as distinct, defeating the
   dedup and accumulating duplicate polygons (this was the real mechanism behind
   the historical "float drift defeats the dedup" rationale that had parked the
   reciprocal on the unstable path). FIX: canonicalize away collinear snapped
   points (exact integer cross-products on the 1e-3 NDC grid) so the key is
   purely a function of the region's corners.

Conformance: CornerSweep_FloodIsCompleteAndMonotone pins the fixed behavior —
61-step monotonic eye sweep ⇒ full flood every step, outside view always reached,
player-room region monotone (was: clean shrink 4.000→2.879 with zero drops, vs
~10 glitch steps before). Diagnostic facts (trace diff, hop microscope, primitive
scratch) retained as the apparatus.

Suites: App 223 green (incl. Build_AppliesReciprocalOtherPortalClip, now passing
with proper tightening AND dedup), Core 1377 green + the 4 pre-existing #99-era
failures + 1 skip, UI 420, Net 294. Visual gate pending: corner press, room↔room,
cellar↔floor, indoor↔outdoor transitions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:26:01 +02:00