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)); } }