acdream/src/AcDream.App
Erik 0940d7961a fix(render): Phase A8 — cell-mesh Landblock CullMode → None + cull state restore
The cull A/B diagnostic (prior commit's ACDREAM_A8_DISABLE_CULL=1) in
visual-gate-#3 confirmed: cell-mesh polys are being culled by back-face
culling, which is why floors disappear when looking down from inside a
room. Per-cell audit data showed every cell-mesh batch has
CullMode.Landblock — assigned because AC's CellStruct polys carry
SidesType=Landblock in the dat. Our SetCullMode maps Landblock to
glCullFace(Back), matching WB.

Root cause:
WB sets `glFrontFace(GLEnum.CW)` globally at GameScene.cs:843. Our
WbDrawDispatcher.cs:1056 sets `glFrontFace(CCW)` — the GL default,
opposite of WB. With our flipped-from-natural fan triangulation in
BuildCellStructPolygonIndices (which emits (i, i-1, 0) for each fan
triangle, reversing the input vertex order), the resulting effective
winding from the camera's perspective is OPPOSITE WB's. Cull-back then
removes the OPPOSITE face from what WB does — hiding the floor side
that should be visible from inside the room.

Within a single cell-mesh batch, the polys face every direction (walls
outward, floor up, ceiling down) but all share CullMode.Landblock. No
single cull setting can be correct for all three orientations
simultaneously — the retail-faithful approach is to render cell polys
double-sided (cull off).

Two changes scoped to EnvCellRenderer.RenderModernMDIInternal so other
renderers aren't affected:
  1. Remap CullMode.Landblock → None when iterating per-cull-mode
     batch groups. Cell polys render with cull disabled, all faces
     visible. CullMode.Landblock is only assigned by
     PrepareCellStructMeshData (cell polys) in this codebase — terrain
     uses a different render path. Scope is exactly right.
  2. Explicitly Enable(CullFace) + CullFace(Back) at Render exit so the
     dispatcher's subsequent IndoorPass + LiveDynamic Draws don't
     inherit the cull-disabled state. The see-through-head symptom in
     visual-gate-#3 was caused by exactly this state leak from the
     ACDREAM_A8_DISABLE_CULL=1 diagnostic; the proper fix needs the
     explicit restore. Also updates the static `_currentCullMode` cache
     so the next Render call's first SetCullMode comparison is correct.

Removed the ACDREAM_A8_DISABLE_CULL diagnostic env var — its role as
A/B test is complete. 14/14 EnvCellRenderer tests pass. Build green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:12:20 +02:00
..
Audio feat(audio): Phase E.2 OpenAL engine + SoundTable cookbook + hook wiring 2026-04-18 16:38:26 +02:00
Input fix(physics): close #77 — auto-walk honors ACE CanCharge bit; zero velocity in turn-in-place 2026-05-18 09:33:33 +02:00
Net refactor(app): extract LiveSessionController for network-side session lifecycle (Step 2) 2026-05-17 16:15:57 +02:00
Plugins feat(core): add IGameState, IEvents, WorldEvents with replay-on-subscribe 2026-04-10 20:29:29 +02:00
Rendering fix(render): Phase A8 — cell-mesh Landblock CullMode → None + cull state restore 2026-05-27 20:12:20 +02:00
Streaming refactor: #100 — remove hiddenTerrainCells / BuildingTerrainCells plumbing 2026-05-25 21:37:53 +02:00
UI feat(retail): Commit B — retail-faithful AP cadence + screen-rect picker 2026-05-16 13:56:08 +02:00
AcDream.App.csproj feat(O-T7): drop WB project references; complete extraction 2026-05-21 17:17:33 +02:00
Program.cs refactor(app): extract typed RuntimeOptions for startup env vars (Step 1) 2026-05-17 09:16:55 +02:00
RuntimeOptions.cs refactor(app): extract typed RuntimeOptions for startup env vars (Step 1) 2026-05-17 09:16:55 +02:00