using AcDream.App.Rendering.Wb; using AcDream.App.Rendering.Gpu; using AcDream.Core.Meshing; using System.Numerics; namespace AcDream.App.Tests.Rendering.Wb; public sealed class PackedDispatcherOracleTests { /// /// Campaign VM VM6 review fix round 2 (F1 BLOCKER): the production /// packed classifier (WbDrawDispatcher.PackedOracle.cs's /// ClassifyPackedBatches/GetOrCreatePackedGroup) is a private instance /// pipeline reached only through the full RetailPViewPassExecutor → /// DrawPackedProductionRoute route, which needs a real IGpuDevice, /// world-pass scope, mesh manager, and compiled pipelines to construct — /// no test in this suite (or anywhere in the App test project) stands /// one up, so driving ClassifyPackedBatches/GetOrCreatePackedGroup /// directly is not a "cheap test." This proves the two halves of the /// fix that ARE cheaply testable and, chained together, prove the exact /// claim the review asked for: (1) FoliageWindClassification.Classify — /// called with the SAME argument shape ClassifyPackedBatches now uses /// (entity.LocalEntityId, exclusion membership, batch.Translucency, /// entity-scoped HasCutoutSubset) — resolves a real procedural-scenery /// entity id (0x8…) to CutoutFoliageFlag (0x2); (2) that flags value, /// carried on an IndirectGroupInput exactly like GetOrCreatePackedGroup /// now carries it on InstanceGroup.FoliageFlags, reaches the literal /// BatchData.flags word through BuildIndirectArrays — the same shared, /// already-tested production step both the classic and packed group /// lists feed into (WbDrawDispatcherIndirectBuilderTests pins bit 0; /// this pins bits 1/2 landing alongside it for a real scenery id). /// [Fact] public void SceneryCutoutEntityClassificationReachesTheBatchDataFlagsWordAsBit0x2() { const uint proceduralSceneryTreeId = 0x80010203u; // top nibble 0x8 uint foliageFlags = FoliageWindClassification.Classify( proceduralSceneryTreeId, isExcluded: false, TranslucencyKind.ClipMap, meshHasCutoutSubset: true); Assert.Equal(FoliageWindClassification.CutoutFoliageFlag, foliageFlags); Assert.Equal(0x2u, foliageFlags); var groups = new List { new( IndexCount: 12, FirstIndex: 0, BaseVertex: 0, InstanceCount: 1, FirstInstance: 0, TextureIndex: 0x5, TextureLayer: 0, Translucency: TranslucencyKind.ClipMap, FoliageFlags: foliageFlags), }; var indirect = new DrawElementsIndirectCommand[4]; var batches = new WbDrawDispatcher.BatchDataPublic[4]; WbDrawDispatcher.BuildIndirectArrays(groups, indirect, batches); // Bit 0 (the #226 built-mesh marker) | bit 1 (cutout foliage) = 0x3; // isolating bit 1 with a mask proves the foliage classification // specifically reached the word, not merely that SOME nonzero value // did. Assert.Equal(0x2u, batches[0].Flags & 0x2u); } [Theory] [InlineData(false, 0u)] [InlineData(true, 1u)] public void PackedInstanceWriter_AppendsDetailCategoryInParallel( bool buildingDetail, uint expectedCategory) { var group = new WbDrawDispatcher.InstanceGroup(); WbDrawDispatcher.AppendPackedInstance( group, Matrix4x4.Identity, Vector3.One, submissionOrder: 7, slot: 3u, lights: WbDrawDispatcher.InstanceLightSet.Disabled, indoor: true, buildingDetail: buildingDetail, opacity: 0.5f, selectionLighting: new Vector2(0.25f, 0.75f)); Assert.Single(group.Matrices); Assert.Single(group.LocalSortCenters); Assert.Single(group.SubmissionOrders); Assert.Single(group.Slots); Assert.Single(group.LightSets); Assert.Single(group.IndoorFlags); Assert.Equal(expectedCategory, Assert.Single(group.DetailCategories)); Assert.Single(group.Opacities); Assert.Single(group.SelectionLighting); } [Theory] [InlineData(0u, false, false)] [InlineData(0u, true, false)] [InlineData(7u, false, false)] [InlineData(7u, true, true)] public void TransparentDeferral_MatchesProductionNoVaoEarlyReturn( uint anyVao, bool alphaQueueCollecting, bool expected) { Assert.Equal( expected, WbDrawDispatcher.ShouldDeferPackedTransparent( anyVao, alphaQueueCollecting)); } }