// EntityClipTests.cs // // Phase W Stage 4/5: unit-test WbDrawDispatcher.EntityPassesVisibleCellGate. // The gate is internal static (AcDream.App is InternalsVisibleTo AcDream.App.Tests) // and pure — tests it without a GL context. Covers: ParentCellId in the visible // set → included; ParentCellId NOT in the set → excluded; null visibleCellIds → // everything included (outdoor / unconstrained root). using System.Collections.Generic; using System.Numerics; using AcDream.App.Rendering.Wb; using AcDream.Core.World; using Xunit; namespace AcDream.App.Tests.Rendering; public sealed class EntityClipTests { // Minimal WorldEntity factory. EntityPassesVisibleCellGate only reads // ParentCellId and IsBuildingShell/BuildingShellAnchorCellId from the entity; // the other required fields are set to safe sentinel values. private static WorldEntity Entity(uint? parentCellId, bool isShell = false, uint? shellAnchor = null) => new WorldEntity { Id = 1u, SourceGfxObjOrSetupId = 0u, Position = Vector3.Zero, Rotation = Quaternion.Identity, MeshRefs = System.Array.Empty(), ParentCellId = parentCellId, IsBuildingShell = isShell, BuildingShellAnchorCellId = shellAnchor, }; [Fact] public void EntityClip_ParentInVisibleSet_Included() { // Entity whose ParentCellId is in the visible set must pass the gate. const uint cellId = 0xA9B40170u; var visibleCellIds = new HashSet { cellId }; var entity = Entity(parentCellId: cellId); bool result = WbDrawDispatcher.EntityPassesVisibleCellGate( entity, visibleCellIds, WbDrawDispatcher.EntitySet.All); Assert.True(result); } [Fact] public void EntityClip_ParentNotInVisibleSet_Excluded() { // Entity whose ParentCellId is NOT in the visible set must fail the gate. const uint visibleCell = 0xA9B40170u; const uint entityCell = 0xA9B40172u; var visibleCellIds = new HashSet { visibleCell }; var entity = Entity(parentCellId: entityCell); bool result = WbDrawDispatcher.EntityPassesVisibleCellGate( entity, visibleCellIds, WbDrawDispatcher.EntitySet.All); Assert.False(result); } [Fact] public void EntityClip_NullVisibleSet_IncludesAll() { // Null visibleCellIds means the outdoor root — no culling, all entities pass. var entity = Entity(parentCellId: 0xA9B40172u); bool result = WbDrawDispatcher.EntityPassesVisibleCellGate( entity, visibleCellIds: null, WbDrawDispatcher.EntitySet.All); Assert.True(result); } [Fact] public void EntityClip_NullParentCell_NullVisibleSet_Included() { // An outdoor entity (ParentCellId == null) with null visibleCellIds passes. var entity = Entity(parentCellId: null); bool result = WbDrawDispatcher.EntityPassesVisibleCellGate( entity, visibleCellIds: null, WbDrawDispatcher.EntitySet.All); Assert.True(result); } [Fact] public void EntityClip_NullParentCell_NonNullVisibleSet_Included() { // An outdoor entity (ParentCellId == null) with a non-null visibleCellIds // falls through to the final return-true (not a shell, not shell-scoped); // outdoor scenery is not gated by the indoor cell filter. var visibleCellIds = new HashSet { 0xA9B40170u }; var entity = Entity(parentCellId: null); bool result = WbDrawDispatcher.EntityPassesVisibleCellGate( entity, visibleCellIds, WbDrawDispatcher.EntitySet.All); Assert.True(result); } }