using System; using System.Numerics; using AcDream.App.Rendering; using Xunit; namespace AcDream.App.Tests.Rendering; public class UnifiedFloodTests { // Shared building fixture: a building cell whose interior is at Y >= 5. // The exit portal faces -Y (Normal=(0,-1,0)); interior is where dot<=0 -> Y>=5 (InsideSide=1). // The outdoor camera is at Y=-3, which is the OUTDOOR side (Y<5). // OutdoorCellNode.Build flips InsideSide to 0 so the outdoor camera (dot>=0 i.e. Y<5) passes // the side test and the flood reaches the building. private static LoadedCell MakeBuildingCell(uint cellId) { var building = new LoadedCell { CellId = cellId, SeenOutside = true }; building.WorldTransform = Matrix4x4.Identity; building.InverseWorldTransform = Matrix4x4.Identity; building.Portals.Add(new CellPortalInfo(0xFFFF, 0, 0, 0)); // InsideSide=1: interior where (0,-1,0)·p+5 <= 0 -> Y>=5 (the building body is at Y>=5). building.ClipPlanes.Add(new PortalClipPlane { Normal = new Vector3(0, -1, 0), D = 5f, InsideSide = 1 }); building.PortalPolygons.Add(new[] { new Vector3(-1, 5, 0), new Vector3(1, 5, 0), new Vector3(1, 5, 2), new Vector3(-1, 5, 2) }); return building; } [Fact] public void Build_RootedAtOutdoorNode_FloodsIntoBuilding() { var building = MakeBuildingCell(0xA9B40170); var node = OutdoorCellNode.Build(0xA9B40031, new[] { building }); LoadedCell? Lookup(uint id) => (id & 0xFFFFu) == 0x0170 ? building : null; var eye = new Vector3(0, -3, 1); var view = Matrix4x4.CreateLookAt(eye, new Vector3(0, 5, 1), Vector3.UnitZ); var proj = Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 3f, 16f / 9f, 1f, 5000f); var frame = PortalVisibilityBuilder.Build(node, eye, Lookup, view * proj); Assert.Contains(0xA9B40031u, frame.OrderedVisibleCells); // the outdoor node itself Assert.Contains(0xA9B40170u, frame.OrderedVisibleCells); // flooded into the building } [Fact] public void Build_OutdoorBuildingCycle_Terminates() { // Building's exit portal reciprocally points back near the node; assert Build // returns (does not hang) and the visible set is bounded/small. var building = MakeBuildingCell(0xA9B40170); var node = OutdoorCellNode.Build(0xA9B40031, new[] { building }); LoadedCell? Lookup(uint id) => (id & 0xFFFFu) == 0x0170 ? building : (id & 0xFFFFu) == 0x0031 ? node : null; var eye = new Vector3(0, -3, 1); var view = Matrix4x4.CreateLookAt(eye, new Vector3(0, 5, 1), Vector3.UnitZ); var proj = Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 3f, 16f / 9f, 1f, 5000f); var frame = PortalVisibilityBuilder.Build(node, eye, Lookup, view * proj); Assert.True(frame.OrderedVisibleCells.Count < 10); // bounded, no runaway } }