fix #124: interior-root building look-ins as a landscape-stage sub-pass

From inside a building, looking out at ANOTHER building with an opening
showed its back walls missing (see-through to the world): per-building
look-in floods only ran for outdoor roots; under an interior root the
far building's interior never flooded.

Decomp anchor (named-retail, this session's read): retail runs the
look-in INSIDE the landscape stage for ANY root - LScape::draw is the
FIRST call of PView::DrawCells' outside-view branch (pc:432719),
strictly BEFORE the depth clear (pc:432732) and the exit-portal seals
(pc:432785). ConstructView(CBldPortal) (0x005a59a0) clips each aperture
via GetClip against the INSTALLED view - the accumulated doorway region
when looked into from inside - and build_draw_portals_only pass 1
far-Z punches ALL apertures before pass 2 floods + draws any interior
cell. The nested DrawCells has an empty outside view (PView ctor
draw_landscape=0): no recursive landscape/clear/seal.

Port:
- GameWindow's per-building gather (frustum pre-gate on
  Building.PortalBounds) now runs for interior roots too; the root's
  own doorway self-excludes via the seed eye-side test (the eye is on
  its interior side).
- PortalVisibilityBuilder.BuildFromExterior/ConstructViewBuilding gain
  seedRegion - the installed-view clip: interior-root look-ins seed
  against the OutsideView polygons (a building not visible through the
  doorway never floods); null = full screen (outdoor roots unchanged).
- RetailPViewRenderer.DrawBuildingLookIns: a landscape-stage sub-pass
  (before ClearDepthForInterior + seals) - per building, punch ALL
  apertures (new DrawLookInPortalPunch callback, always forceFarZ=true,
  closing the ISSUES "forceFarZ keys on root kind, under-punches" gap),
  then draw the flooded cells' shells + statics far->near. Look-in
  frames are NEVER merged into the main frame: a merged cell would draw
  post-clear and z-fail against the root's seal (the old ledger
  portShape sketch was wrong on this point).
- Look-in cells join the Prepare + partition set so shells have batches
  and statics route to ByCell (consumed only by the sub-pass; the main
  cell-object pass iterates the main flood's cells).

Register: AP-33 added in the same commit - look-in statics draw WHOLE
(no per-part viewcone; over-include is the safe direction) and look-in
DYNAMICS are deferred (an NPC inside a far building stays invisible -
retail draws objects per overlapped cell in the landscape stage).

Pins: Issue124LookInSeedRegionTests on the real corner-building door -
a seed region containing the aperture floods (and never more than the
full-screen seed), a disjoint region floods NOTHING, and an
interior-side eye never seeds its own exit portal.

Suites: App 259+1skip / Core 1439+2skip / UI 420 / Net 294 green.
Awaiting the user gate: far-building interiors visible through their
apertures from inside; #130 re-gate (top-edge strip) rides the same
launch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-12 15:59:29 +02:00
parent 5135066733
commit 77cef4cd86
6 changed files with 379 additions and 32 deletions

View file

@ -4304,28 +4304,48 @@ of which draw list the building's shell left.
## #124 — Looking out through an opening: far buildings with openings show missing/transparent back walls
**Status:** OPEN
**Status:** FIX SHIPPED — awaiting user visual gate
**Severity:** MEDIUM
**Filed:** 2026-06-11 (re-gate; pre-existing — "still have that issue")
**Filed:** 2026-06-11 (re-gate; pre-existing — "still have that issue";
user 2026-06-12: "especially visible when I look out through a door
opening when inside a building")
**Component:** render — per-building look-in floods under INTERIOR roots
From inside a building, looking out through a door/window at ANOTHER
building that has an opening: the far building's back walls are
missing/transparent (see the world through it). **Lead (by read):** the
per-building look-in floods (`MergeNearbyBuildingFloods`) run ONLY for
outdoor roots — `RetailPViewDrawContext.NearbyBuildingCells` is
documented "Null for interior roots." So under an interior root the far
building's INTERIOR never floods: through its window you see the shell
only, and a shell has no interior back-wall faces → transparent.
Retail runs the building look-in inside `LScape::draw` (DrawBlock →
DrawPortal → ConstructView(CBldPortal)), which executes for ANY root
whose outside view is non-empty — including interior roots looking out
a doorway. Fix shape: provide the nearby-building gather + per-building
floods for interior roots too, with look-in apertures getting PUNCH
semantics (the `forceFarZ` selector currently keys on
`clipRoot.IsOutdoorNode`, which under-punches this case). Needs its own
focused pass — touches the gather, the merge, and the depth-mask
selector.
missing/transparent. The lead confirmed by decomp: retail runs the
look-in INSIDE the landscape stage for ANY root — `LScape::draw` is the
FIRST call of `PView::DrawCells`' outside-view branch (pc:432719),
strictly BEFORE the depth clear (pc:432732) and the seals (pc:432785);
`ConstructView(CBldPortal)`'s GetClip runs under the INSTALLED view
(the doorway region), and all apertures far-Z punch (pass 1) before any
interior cell draws (pass 2).
**Fix (2026-06-12):**
- The per-building gather (frustum pre-gate on `Building.PortalBounds`)
now runs for interior roots too; the root's own doorway self-excludes
via the seed eye-side test.
- `BuildFromExterior` gained `seedRegion` — the port of retail's
installed-view clip: interior-root look-ins seed clipped against the
OutsideView (doorway) polygons, so a building not visible through the
doorway never floods. Outdoor roots keep the full-screen default.
- NEW `DrawBuildingLookIns` sub-pass inside the LANDSCAPE stage (before
the depth clear + seals): per building, punch ALL apertures
(`DrawLookInPortalPunch`, always far-Z), then draw the flooded cells'
shells + statics far→near. NOT merged into the main frame — a merged
cell would draw post-clear and z-fail against the root's seal.
- Look-in cells join the Prepare/partition set (shells get batches,
statics route to ByCell, consumed only by the sub-pass).
Pins: `Issue124LookInSeedRegionTests` (containing region floods ⊆
full-screen flood; disjoint region floods nothing; interior-side eye
never seeds its own exit door). Register: AP-33 (look-in statics drawn
whole — no per-part viewcone; look-in DYNAMICS deferred — an NPC inside
a far building stays invisible; both documented).
**Gate:** from inside a building, look out the door at another building
with an open door/window — its interior/back walls render through its
aperture instead of see-through to the world behind.
---