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