using System.Numerics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Walk;
namespace AcDream.App.Tests.Rendering.Walk;
/// Campaign FW3.1 — hermetic (no DAT) coverage of the production
/// frame context: cell resolution through ,
/// building resolution through , and the
/// CyPlane/ray-cast wiring. This proves the SEAM (does the context read the
/// right registries the right way); the ten-fixture conformance gate proves
/// the WORLD DATA those registries are fed is correct.
public sealed class WalkProductionFrameContextTests
{
private static Matrix4x4 SimpleViewProjection() =>
Matrix4x4.CreateLookAt(Vector3.Zero, Vector3.UnitY, Vector3.UnitZ)
* Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 3f, 4f / 3f, 0.1f, 1000f);
[Fact]
public void GetVisible_ResolvesThroughTheCommittedCellVisibilityRegistry()
{
var cellVisibility = new CellVisibility();
var walkCell = new WalkCell { CellId = 0xA9B40100u };
var loaded = new LoadedCell { CellId = 0xA9B40100u, Walk = walkCell };
cellVisibility.CommitLandblock(0xA9B4FFFFu, new[] { loaded });
var ctx = new WalkProductionFrameContext(
cellVisibility, new WalkBuildingRegistry(), Vector3.Zero, Vector3.UnitY,
SimpleViewProjection(), 1024f, 768f);
Assert.Same(walkCell, ctx.GetVisible(0xA9B40100u));
Assert.Null(ctx.GetVisible(0xA9B40101u));
}
[Fact]
public void GetVisible_ReturnsNullWhenTheCommittedCellHasNoWalkModel()
{
// A hand-built LoadedCell that never went through
// EnvCellLandblockBuildBuilder.BuildVisibilityCell (test-only
// shortcut some existing fixtures take) — Walk stays null.
var cellVisibility = new CellVisibility();
var loaded = new LoadedCell { CellId = 0xA9B40100u };
cellVisibility.CommitLandblock(0xA9B4FFFFu, new[] { loaded });
var ctx = new WalkProductionFrameContext(
cellVisibility, new WalkBuildingRegistry(), Vector3.Zero, Vector3.UnitY,
SimpleViewProjection(), 1024f, 768f);
Assert.Null(ctx.GetVisible(0xA9B40100u));
}
[Fact]
public void ObjectToClipAndViewpointIn_UseTheCellsOwnTransforms()
{
var cell = new WalkCell
{
CellId = 1,
WorldTransform = Matrix4x4.CreateTranslation(10f, 0f, 0f),
InverseWorldTransform = Matrix4x4.CreateTranslation(-10f, 0f, 0f),
};
Matrix4x4 vp = SimpleViewProjection();
var ctx = new WalkProductionFrameContext(
new CellVisibility(), new WalkBuildingRegistry(), new Vector3(10f, 0f, 0f), Vector3.UnitY,
vp, 1024f, 768f);
Assert.Equal(cell.WorldTransform * vp, ctx.ObjectToClip(cell));
Assert.Equal(Vector3.Zero, ctx.ViewpointIn(cell));
}
[Fact]
public void ViewpointInBuilding_ResolvesThroughWalkBuildingRegistry()
{
var registry = new WalkBuildingRegistry();
var building = new WalkBuilding { PositionCellId = 1 };
Matrix4x4 world = Matrix4x4.CreateTranslation(5f, 0f, 0f);
Matrix4x4.Invert(world, out Matrix4x4 inverse);
registry.Publish(0xA9B4FFFFu, new[] { new WalkBuildingFactory.Entry(building, world, inverse) });
var ctx = new WalkProductionFrameContext(
new CellVisibility(), registry, new Vector3(5f, 0f, 0f), Vector3.UnitY,
SimpleViewProjection(), 1024f, 768f);
Assert.Equal(Vector3.Zero, ctx.ViewpointInBuilding(building));
}
[Fact]
public void ViewpointInBuilding_ThrowsWhenTheBuildingIsNotCommitted()
{
// Fail loud (the PV3 post-mortem rule): a walk/registry desync must
// never resolve to a silently-skipped building.
var ctx = new WalkProductionFrameContext(
new CellVisibility(), new WalkBuildingRegistry(), Vector3.Zero, Vector3.UnitY,
SimpleViewProjection(), 1024f, 768f);
var unregistered = new WalkBuilding { PositionCellId = 1 };
Assert.Throws(() => ctx.ViewpointInBuilding(unregistered));
}
[Fact]
public void ViewerDistanceTo_MeasuresToTheBuildingsTransformedSortCenter()
{
var registry = new WalkBuildingRegistry();
var building = new WalkBuilding { PositionCellId = 1, SortCenter = new Vector3(0f, 3f, 0f) };
Matrix4x4 world = Matrix4x4.CreateTranslation(0f, 10f, 0f);
Matrix4x4.Invert(world, out Matrix4x4 inverse);
registry.Publish(0xA9B4FFFFu, new[] { new WalkBuildingFactory.Entry(building, world, inverse) });
var ctx = new WalkProductionFrameContext(
new CellVisibility(), registry, Vector3.Zero, Vector3.UnitY,
SimpleViewProjection(), 1024f, 768f);
Assert.Equal(13f, ctx.ViewerDistanceTo(building));
}
[Fact]
public void CyPlane_MatchesTheRetailNearPlaneFormula()
{
Vector3 forward = Vector3.UnitY;
var eye = new Vector3(0f, 5f, 0f);
var ctx = new WalkProductionFrameContext(
new CellVisibility(), new WalkBuildingRegistry(), eye, forward,
SimpleViewProjection(), 1024f, 768f);
Assert.Equal(forward, ctx.CyPlane.Normal);
Assert.Equal(-Vector3.Dot(eye, forward) - WalkProductionFrameContext.ZNear, ctx.CyPlane.D);
}
[Fact]
public void Constructor_RejectsANonInvertibleViewProjection()
{
Assert.Throws(() => new WalkProductionFrameContext(
new CellVisibility(), new WalkBuildingRegistry(), Vector3.Zero, Vector3.UnitY,
default, 1024f, 768f));
}
}