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 3 (N1): this test does NOT guard /// the packed classifier itself — CreateGroupFromKey's own test /// (InstanceGroupClearTests.CreateGroupFromKey_CopiesFoliageFlagsFromTheKey) /// plus GroupKey.FoliageFlags being a required constructor argument are /// what actually make F1 (the round-2 blocker: the packed classifier's /// InstanceGroup silently carried FoliageFlags == 0) impossible to /// reintroduce. What THIS test proves is the SHARED production step /// downstream of classification: FoliageWindClassification.Classify, /// called with the same argument shape ClassifyPackedBatches uses /// (entity.LocalEntityId, exclusion membership, batch.Translucency, /// entity-scoped HasCutoutSubset), resolves a real procedural-scenery /// entity id (0x8…) to CutoutFoliageFlag (0x2); and a group carrying /// that flags value reaches the literal BatchData.flags word through /// BuildIndirectArrays — the same 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)); } }