diff --git a/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs index f698b0b0..78420fa2 100644 --- a/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs +++ b/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs @@ -181,6 +181,56 @@ public sealed class Issue113DoorVanishDiagnosticTests return n.LengthSquared() < 1e-10f ? Vector3.Zero : Vector3.Normalize(n); } + /// + /// Phase A confirmation: retail's building/cell mesh pass skips surface + /// batches whose CSurface type has neither Base1Image (0x2) nor + /// Base1ClipMap (0x4) — the skipNoTexture rule (D3DPolyRender inner draw + /// 0x0059d4a0; default skipNoTexture=1). Prediction: the hall's phantom + /// stair-ramp portal-fill polys {0,1} reference SOLID (untextured) + /// surfaces while cottage door/window fills reference TEXTURED surfaces — + /// which is exactly why retail shows doors but not the ramp. + /// + [Fact] + public void DumpPortalFillSurfaceTypes() + { + var datDir = ConformanceDats.ResolveDatDir(); + if (datDir is null) { _out.WriteLine("dats unavailable — skipped"); return; } + using var dats = new DatCollection(datDir, DatAccessType.Read); + + foreach (uint mid in new uint[] { 0x010014C3u, 0x01000827u, 0x0100082Eu, 0x01000C17u }) + { + var gfx = dats.Get(mid); + if (gfx?.DrawingBSP?.Root is null) continue; + + var walked = new HashSet(); + void Walk(DatReaderWriter.Types.DrawingBSPNode? n) + { + if (n is null) return; + if (n.Polygons is not null) foreach (var pid in n.Polygons) walked.Add((ushort)pid); + Walk(n.PosNode); Walk(n.NegNode); + } + Walk(gfx.DrawingBSP.Root); + var portalFills = gfx.Polygons.Keys.Where(k => !walked.Contains(k)).OrderBy(k => k).ToList(); + + _out.WriteLine($"=== model 0x{mid:X8}: {portalFills.Count} portal-fill polys; Surfaces list has {gfx.Surfaces.Count} entries ==="); + foreach (var pid in portalFills) + { + var poly = gfx.Polygons[pid]; + string Describe(short surfIdx) + { + if (surfIdx < 0 || surfIdx >= gfx.Surfaces.Count) return $"idx{surfIdx}=OOB"; + uint sid = gfx.Surfaces[surfIdx]; + var surf = dats.Get(sid); + if (surf is null) return $"0x{sid:X8}=MISSING"; + bool textured = surf.Type.HasFlag(DatReaderWriter.Enums.SurfaceType.Base1Image) + || surf.Type.HasFlag(DatReaderWriter.Enums.SurfaceType.Base1ClipMap); + return $"0x{sid:X8} type={surf.Type} -> {(textured ? "TEXTURED (drawn)" : "SOLID (skipNoTexture SKIPS on building/cell pass)")}"; + } + _out.WriteLine($" poly {pid,3}: sides={poly.SidesType} stip={poly.Stippling} pos[{Describe(poly.PosSurface)}] neg[{Describe(poly.NegSurface)}]"); + } + } + } + /// /// Control group: the two #113 models (hall + cottage) whose orphans ARE /// the phantom geometry, for type-model comparison against the door.