acdream/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs
Erik 0f01fb4430 feat(render) Campaign FW1: FIRST TRACE CONFORMANCE GREEN (foundry-deep)
The replay harness reconstructs the camera from a pose-stamped oracle
frame (Frame quaternion w,x,y,z storage order; +Y forward / +Z up;
landblock-local origin) and drives the ported walk over adapter-built
cells (cell transforms from EnvCell.Position now populated). The
foundry-deep fixture - the pure-interior frame shape - reproduces
retail EXACTLY on every complete frame: DI + DC(ov=0, [cell]) with no
landscape, 39/39. Conventions are now pinned by live retail output; the
remaining nine fixtures need the outdoor world build-out (landscape
blocks, terrain z-slabs, building transforms + active-view clip) and
join the same gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 10:23:39 +02:00

110 lines
4.7 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 System.Numerics;
using AcDream.App.Rendering.Walk;
namespace AcDream.App.Tests.Rendering.Walk;
/// <summary>
/// The FW1 conformance replay harness: reconstructs the camera state from a
/// pose-stamped oracle frame and drives the ported walk over
/// adapter-built world data. Convention notes (adjudicate against the
/// fixtures, loudly, on any mismatch):
/// <list type="bullet">
/// <item>The dumped quaternion is retail Frame storage order w,x,y,z
/// (q0=w) — unit-norm verified on the captures.</item>
/// <item>Retail's frame axes: +Y forward, +Z up (the camera looks along
/// the rotated +Y).</item>
/// <item>Pose origin is landblock-local, the same space the adapter's
/// cell transforms produce.</item>
/// </list>
/// </summary>
public sealed class WalkTraceReplayContext : IWalkFrameContext, IRetailFrameWalkContext
{
private sealed class BasisRayCaster(
Vector3 right, Vector3 forward, Vector3 up,
float halfWidth, float halfHeight, float focal) : IWalkRayCaster
{
public Vector3 RayThrough(float screenX, float screenY)
{
// Screen origin top-left, y down (the xformStart convention).
float nx = (screenX - halfWidth) / halfWidth;
float ny = (halfHeight - screenY) / halfHeight;
return right * (nx / focal) + forward + up * (ny / focal);
}
}
private readonly Dictionary<uint, WalkCell> _cells;
private readonly Matrix4x4 _viewProjection;
private readonly IWalkRayCaster _rays;
public WalkTraceReplayContext(
WalkOraclePose pose, Dictionary<uint, WalkCell> cells,
float viewportWidth = 800f, float viewportHeight = 600f,
float verticalFovRadians = 1.0f)
{
_cells = cells;
WorldViewpoint = pose.Origin;
var rotation = new Quaternion(pose.Q1, pose.Q2, pose.Q3, pose.Q0);
Vector3 forward = Vector3.Transform(Vector3.UnitY, rotation);
Vector3 up = Vector3.Transform(Vector3.UnitZ, rotation);
Vector3 right = Vector3.Transform(Vector3.UnitX, rotation);
Matrix4x4 view = Matrix4x4.CreateLookAt(pose.Origin, pose.Origin + forward, up);
Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView(
verticalFovRadians, viewportWidth / viewportHeight, 0.1f, 5000f);
_viewProjection = view * projection;
ViewportWidth = viewportWidth;
ViewportHeight = viewportHeight;
float focal = MathF.Tan(verticalFovRadians / 2f);
_rays = new BasisRayCaster(
right, forward, up, viewportWidth / 2f, viewportHeight / 2f, focal);
// The retail CY near plane: N = forward, d = dot(eye, forward) znear.
CyPlane = new WalkPlane(forward, -Vector3.Dot(pose.Origin, forward) - 0.1f);
}
public Vector3 ViewpointIn(WalkCell cell)
=> Vector3.Transform(WorldViewpoint, cell.InverseWorldTransform);
public Matrix4x4 ObjectToClip(WalkCell cell)
=> cell.WorldTransform * _viewProjection;
public WalkCell? GetVisible(uint cellId) => _cells.GetValueOrDefault(cellId);
public IWalkRayCaster Rays => _rays;
public Vector3 WorldViewpoint { get; }
public float ViewportWidth { get; }
public float ViewportHeight { get; }
public WalkPlane CyPlane { get; }
public IWalkFrameContext CellContext => this;
public void SetActiveView(WalkPortalView views, int index) { }
public Vector3 ViewpointInBuilding(WalkBuilding building) => WorldViewpoint;
public int ClipBuildingPolygon(
WalkBuilding building, WalkPolygon polygon, int side, Span<WalkScreenPoint> output)
=> 0; // building look-ins join the conformance surface with the landscape fixtures
// ---- signatures for comparing walk output to oracle frames ----
public static string Signature(IEnumerable<WalkEvent> events)
=> string.Join("|", events.Select(e => e.Kind switch
{
WalkEventKind.Landscape => "LS",
WalkEventKind.Building => $"BLD:{e.CellId:x8}",
WalkEventKind.DrawInside => $"DI:{e.CellId:x8}",
WalkEventKind.DrawCells =>
$"DC:ov={e.OutsideViewCount}:{string.Join(',', e.Cells.Select(c => c.ToString("x8")))}",
_ => "?",
}));
public static string Signature(WalkOracleFrame frame)
=> string.Join("|", frame.Events.Select(e => e.Kind switch
{
WalkOracleEventKind.Landscape => "LS",
WalkOracleEventKind.Building => $"BLD:{e.CellId!.Value:x8}",
WalkOracleEventKind.DrawInside => $"DI:{e.CellId!.Value:x8}",
WalkOracleEventKind.DrawCells =>
$"DC:ov={e.OutsideViewCount}:{string.Join(',', e.Cells.Select(c => c.ToString("x8")))}",
_ => "?",
}));
}