acdream/tests/AcDream.App.Tests/Rendering/Walk/WalkPortalGateDumpTests.cs
Erik bf53e2ad6e refactor(rendering): delete superseded visibility probes
Delete the callerless portal-BFS research graph and spent renderer probe families while retaining the production RetailFrameWalk path, terrain diagnostics, membership invariant, and walk transcript.

Mutation evidence (all restored):

1. Restored PortalVisibilityBuilder type -> AppAssembly_ContainsNoSupersededPortalGraphTypes first failed Assert.Empty with AcDream.App.Rendering.PortalVisibilityBuilder.

2. Restored ACDREAM_PROBE_FACILITY_STAIRS -> ProductionSource_ContainsNoDeletedRendererProbe_AndRetainsWalkTranscriptProof first failed Assert.Empty on RenderingDiagnostics.cs.

3. Added a second RetailFrameWalk field -> WalkFrameOwners_AreUnique first failed Assert.Single with _frameWalk and _mutatedSecondFrameWalk.

4. Added OrderBy to OrderedStream -> OrderedWalkStream_HasNoCrossStreamReorder first failed Assert.DoesNotContain on OrderBy(.

5. Added IDatReaderWriter parameter -> FrameTimeWalkOwners_HaveNoRawDatDependency first failed Assert.Empty on RetailFrameWalk.MutatedRawDatParameter.
2026-09-05 05:18:17 +02:00

303 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AcDream.App.Tests.Rendering;
using AcDream.App.Rendering.Walk;
using DatReaderWriter;
using DatReaderWriter.Options;
using System.Numerics;
using System.Text;
namespace AcDream.App.Tests.Rendering.Walk;
/// <summary>
/// FW1 look-in gate microscope: for the street fixture pose, dump every
/// gate input for building a9b4001a (retail punches it) vs a9b4001e
/// (retail does not): raw portal flags, the BSP-emitted polygon's plane,
/// the eye's signed distance and side, and the active-view clip count.
/// Writes the dump to the scratch directory; always passes.
/// </summary>
[Trait("Lane", "InstalledDat")]
public sealed class WalkPortalGateDumpTests
{
[Fact]
public void Dump_the_gate_inputs_for_a_punching_and_a_silent_building()
{
string? datDir = InstalledDatTestPath.Resolve();
if (datDir is null)
{
Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory.");
}
IReadOnlyList<WalkOracleFrame> frames =
WalkOracleTrace.Load("posed/holtburg-street-outdoor");
WalkOracleFrame frame = frames[1];
Assert.NotNull(frame.Pose);
using var dats = new DatCollection(datDir!, DatAccessType.Read);
WalkLandscapeDatBuilder.BuiltWorld world =
WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId, frame.Pose.Origin);
var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells)
{
Buildings = world.Buildings,
};
// Install the outdoor default view as the active clip context.
var defaultView = new WalkPortalView();
WalkCopyView.AppendFullViewportQuad(
defaultView, ctx.Rays, ctx.WorldViewpoint,
ctx.ViewportWidth, ctx.ViewportHeight);
ctx.SetActiveView(defaultView, 0);
var dump = new StringBuilder();
Span<WalkScreenPoint> clipped = stackalloc WalkScreenPoint[64];
dump.AppendLine($"pose cell={frame.Pose.CellId:x8} origin={frame.Pose.Origin}");
foreach (uint id in new[] { 0xA9B4001Au, 0xA9B4001Eu, 0xA9B40022u, 0xA9B40026u })
{
WalkBuilding building = world.Buildings.Keys.Single(b => b.PositionCellId == id);
float dist = ctx.ViewerDistanceTo(building);
Vector3 eyeInBuilding = ctx.ViewpointInBuilding(building);
dump.AppendLine(
$"building {id:x8}: dist={dist:f1} eff={MathF.Max(0f, dist - 50f):f1} "
+ $"eyeLocal={eyeInBuilding} portals={building.Portals.Length}");
WalkBspNode? bsp = building.Select(dist, 50f, 0f).DrawingBsp;
var refs = new List<WalkPortalRef>();
Collect(bsp, refs);
dump.AppendLine($" level BSP portal refs: {refs.Count}");
foreach (WalkPortalRef portalRef in refs)
{
ref WalkBldPortal bp = ref building.Portals[portalRef.PortalIndex];
float d = Vector3.Dot(portalRef.Polygon.Plane.Normal, eyeInBuilding)
+ portalRef.Polygon.Plane.D;
int side = d > WalkVisibilityMath.Epsilon ? 0
: d < -WalkVisibilityMath.Epsilon ? 1 : 2;
int n = ctx.ClipBuildingPolygon(building, portalRef.Polygon, side, clipped);
dump.AppendLine(
$" ref idx={portalRef.PortalIndex} other={bp.OtherCellId:x8} "
+ $"rawSide={bp.PortalSide} exact={bp.ExactMatch} "
+ $"planeD@eye={d:f2} eyeSide={side} clipN={n} "
+ $"gate(side==rawSide)={(side == bp.PortalSide ? "PASS" : "reject")}");
}
}
string path = Path.Combine(Path.GetTempPath(), "fw1-portal-gate-dump.txt");
File.WriteAllText(path, dump.ToString());
Assert.True(true);
}
private static void Collect(WalkBspNode? node, List<WalkPortalRef> into)
{
if (node is null) return;
if (node.InPortals is not null) into.AddRange(node.InPortals);
Collect(node.PosNode, into);
Collect(node.NegNode, into);
}
private sealed class NullSink : IWalkEventSink
{
public void Emit(in WalkEvent walkEvent) { }
}
/// <summary>
/// Walkout-F2 microscope: retail floods buildings a9b4001e (×4) and
/// a9b40026 (×1) through the cottage's exit views; the replay floods
/// neither, while the SAME machinery against the root view passes the
/// street fixture. Differential per portal: clip count against the
/// full-viewport window vs each exit-view window, plus each window's
/// vertices and signed area (winding).
/// </summary>
[Fact]
public void Dump_the_exit_view_look_in_inputs_for_walkout_f2()
{
string? datDir = InstalledDatTestPath.Resolve();
if (datDir is null)
{
Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory.");
}
var dump = new StringBuilder();
using var dats = new DatCollection(datDir!, DatAccessType.Read);
// walkout F2 (retail FLOODS 001e/0026) vs doorway-still F2 (retail
// floods NOTHING) — the poses differ by ~1 m and ~5° of yaw.
WalkOraclePose[] poses =
[
WalkOracleTrace.Load("posed/holtburg-walkout")[2].Pose!,
WalkOracleTrace.Load("posed/holtburg-doorway-still")[1].Pose!,
];
foreach (WalkOraclePose pose in poses)
{
WalkLandscapeDatBuilder.BuiltWorld world =
WalkLandscapeDatBuilder.Build(dats, pose.CellId, pose.Origin);
var ctx = new WalkTraceReplayContext(pose, world.Cells)
{
Buildings = world.Buildings,
};
WalkCell camera = world.Cells[pose.CellId];
var walk = new RetailFrameWalk();
walk.WalkFrame(pose.CellId, camera, world.Landscape, ctx, new NullSink());
WalkPortalView outside = walk.InteriorPView.OutsideView;
dump.AppendLine(
$"pose cell={pose.CellId:x8} origin={pose.Origin} ov={outside.ViewCount}");
for (int v = 0; v < outside.ViewCount; v++)
{
WalkViewPoly poly = outside.View.Polys[v];
var verts = new Vector2[poly.VertexCount];
for (int k = 0; k < poly.VertexCount; k++)
verts[k] = outside.View.Vertices[poly.VertexIndex + k].Point;
dump.AppendLine(
$" exit view {v}: n={poly.VertexCount} area={SignedArea(verts):f1} "
+ $"verts={string.Join(' ', verts.Select(p => $"({p.X:f1},{p.Y:f1})"))}");
}
var defaultView = new WalkPortalView();
WalkCopyView.AppendFullViewportQuad(
defaultView, ctx.Rays, ctx.WorldViewpoint,
ctx.ViewportWidth, ctx.ViewportHeight);
{
WalkViewPoly rootPoly = defaultView.View.Polys[0];
var rootVerts = new Vector2[rootPoly.VertexCount];
for (int k = 0; k < rootPoly.VertexCount; k++)
rootVerts[k] = defaultView.View.Vertices[rootPoly.VertexIndex + k].Point;
dump.AppendLine(
$" root view: n={rootPoly.VertexCount} area={SignedArea(rootVerts):f1} "
+ $"verts={string.Join(' ', rootVerts.Select(p => $"({p.X:f1},{p.Y:f1})"))}");
}
foreach (uint id in new[] { 0xA9B4001Eu, 0xA9B40026u, 0xA9B4002Fu })
{
WalkBuilding building =
world.Buildings.Keys.Single(b => b.PositionCellId == id);
float dist = ctx.ViewerDistanceTo(building);
Vector3 eyeInBuilding = ctx.ViewpointInBuilding(building);
WalkBspNode? bsp = building.Select(dist, 50f, 0f).DrawingBsp;
dump.AppendLine(
$" building {id:x8}: dist={dist:f1} eff={MathF.Max(0f, dist - 50f):f1} "
+ $"bsp={(bsp is null ? "NULL" : "selected")} ports={CountPorts(bsp)}");
for (int li = 0; li < building.DegradeLevels.Length; li++)
{
WalkBuildingDegradeLevel lv = building.DegradeLevels[li];
dump.AppendLine(
$" level {li}: min={lv.MinDist:f1} ideal={lv.IdealDist:f1} "
+ $"max={lv.MaxDist:f1} ports={CountPorts(lv.DrawingBsp)} "
+ $"idealArmThr={lv.IdealDist:f1} "
+ $"negMulThr={lv.IdealDist - (lv.IdealDist - lv.MaxDist) * -0.99f:f1}");
}
if (bsp is null) continue;
var refs = new List<WalkPortalRef>();
WalkBuildingPortals.BuildDrawPortalsOnly(
bsp, 1, eyeInBuilding, (portalRef, _) => refs.Add(portalRef));
var clipped = new WalkScreenPoint[64];
foreach (WalkPortalRef portalRef in refs)
{
ref WalkBldPortal bp = ref building.Portals[portalRef.PortalIndex];
float d = Vector3.Dot(portalRef.Polygon.Plane.Normal, eyeInBuilding)
+ portalRef.Polygon.Plane.D;
int side = d > WalkVisibilityMath.Epsilon ? 0
: d < -WalkVisibilityMath.Epsilon ? 1 : 2;
ctx.SetActiveView(defaultView, 0);
int rootN = ctx.ClipBuildingPolygon(
building, portalRef.Polygon, side, clipped);
string rootVerts = string.Join(
' ',
clipped.Take(rootN).Select(p => $"({p.X:f1},{p.Y:f1},w={p.W:f3})"));
var perView = new StringBuilder();
for (int v = 0; v < outside.ViewCount; v++)
{
ctx.SetActiveView(outside, v);
int n = ctx.ClipBuildingPolygon(
building, portalRef.Polygon, side, clipped);
float area = 0f;
for (int k = 0; k < n; k++)
{
WalkScreenPoint a = clipped[k];
WalkScreenPoint b = clipped[(k + 1) % n];
area += a.X * b.Y - b.X * a.Y;
}
perView.Append($" view{v}N={n}(area={0.5f * area:f1})");
}
dump.AppendLine(
$" ref idx={portalRef.PortalIndex} other={bp.OtherCellId:x8} "
+ $"rawSide={bp.PortalSide} eyeSide={side} "
+ $"gate={(side == bp.PortalSide ? "PASS" : "REJECT")} "
+ $"rootN={rootN}{perView}");
if (rootN > 0)
dump.AppendLine($" root-clipped: {rootVerts}");
}
}
}
string path = Path.Combine(Path.GetTempPath(), "fw1-walkout-f2-lookin-dump.txt");
File.WriteAllText(path, dump.ToString());
Assert.True(true);
}
/// <summary>
/// Foundry-entry F67 microscope: retail (F67+F68, same camera P(F68))
/// orders building a9b40036's floods 116,118,11d; the replay orders
/// 11d,116,118. Dump the full BSP traversal at that camera — every
/// node's plane, d, arm choice, and emissions — to find the
/// order-controlling node and its |d|.
/// </summary>
[Fact]
public void Dump_the_foundry_f67_bsp_traversal_for_0036()
{
string? datDir = InstalledDatTestPath.Resolve();
if (datDir is null)
{
Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory.");
}
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("posed/foundry-entry");
WalkOraclePose pose = frames[67].Pose!; // P(F68) = camera of F67
using var dats = new DatCollection(datDir!, DatAccessType.Read);
WalkLandscapeDatBuilder.BuiltWorld world =
WalkLandscapeDatBuilder.Build(dats, pose.CellId, pose.Origin);
var ctx = new WalkTraceReplayContext(pose, world.Cells)
{
Buildings = world.Buildings,
};
WalkBuilding building =
world.Buildings.Keys.Single(b => b.PositionCellId == 0xA9B40036u);
Vector3 eye = ctx.ViewpointInBuilding(building);
WalkBspNode? bsp = building.Select(
ctx.ViewerDistanceTo(building), 50f, 0f).DrawingBsp;
var dump = new StringBuilder();
dump.AppendLine($"camera cell={pose.CellId:x8} origin={pose.Origin}");
dump.AppendLine($"eyeInBuilding={eye} dist={ctx.ViewerDistanceTo(building):f2}");
DumpNode(bsp, eye, building, 0, dump);
string path = Path.Combine(Path.GetTempPath(), "fw1-foundry-f67-bsp-dump.txt");
File.WriteAllText(path, dump.ToString());
Assert.True(true);
}
private static void DumpNode(
WalkBspNode? node, Vector3 eye, WalkBuilding building, int depth, StringBuilder dump)
{
if (node is null) return;
string pad = new(' ', depth * 2);
if (node.IsFail)
{
dump.AppendLine($"{pad}FAIL");
return;
}
float d = Vector3.Dot(node.SplittingPlane.Normal, eye) + node.SplittingPlane.D;
int side = d > WalkVisibilityMath.Epsilon ? 0
: d < -WalkVisibilityMath.Epsilon ? 1 : 2;
string ports = node.InPortals is null
? ""
: " PORT[" + string.Join(',', node.InPortals.Select(
p => $"idx{p.PortalIndex}->{building.Portals[p.PortalIndex].OtherCellId:x8}")) + "]";
dump.AppendLine(
$"{pad}N=({node.SplittingPlane.Normal.X:f4},{node.SplittingPlane.Normal.Y:f4},"
+ $"{node.SplittingPlane.Normal.Z:f4}) D={node.SplittingPlane.D:f4} "
+ $"d={d:f6} side={side}{ports}");
DumpNode(node.PosNode, eye, building, depth + 1, dump);
DumpNode(node.NegNode, eye, building, depth + 1, dump);
}
private static int CountPorts(WalkBspNode? node)
=> node is null ? 0
: (node.IsPortal ? 1 : 0) + CountPorts(node.PosNode) + CountPorts(node.NegNode);
private static float SignedArea(Vector2[] verts)
{
float sum = 0f;
for (int i = 0; i < verts.Length; i++)
{
Vector2 a = verts[i];
Vector2 b = verts[(i + 1) % verts.Length];
sum += a.X * b.Y - b.X * a.Y;
}
return 0.5f * sum;
}
}