using System.Numerics;
using AcDream.App.Rendering;
using AcDream.Core.World;
using Xunit;
namespace AcDream.App.Tests.Rendering;
///
/// Campaign CC gate round 1, Batch D (GF-7/GF-14): pins
/// , the pure
/// helper that decides which entities
/// submits to WbDrawDispatcher. Exercised directly (no GPU device, no
/// constructed WbDrawDispatcher) — the same interface-fake-first
/// testing shape CreatureAppraisalPresentationTests already uses for
/// this renderer family, since PrivateEntityViewportRenderer itself
/// pulls in a live mesh-pipeline object graph too heavy to construct in a
/// unit test.
///
///
/// This is the paperdoll/creature-appraisal REGRESSION PIN the batch's test
/// plan calls for: both renderers never configure a backdrop slot (see
/// PaperdollViewportRenderer/CreatureAppraisalPresentation.cs —
/// neither passes a backdropRenderId nor exposes SetBackdrop),
/// so every one of their draws calls this helper with backdrop: null —
/// exactly the first case below.
///
///
public sealed class PrivateEntityViewportRendererDrawOrderTests
{
private static WorldEntity Entity(uint id, IReadOnlyList meshRefs) => new()
{
Id = id,
ServerGuid = id,
SourceGfxObjOrSetupId = 0x0200_0001u,
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
MeshRefs = meshRefs,
};
private static readonly MeshRef[] OneMesh = [new MeshRef(0x0100_0001u, Matrix4x4.Identity)];
[Fact]
public void NoBackdrop_ReturnsExactlyTheMainEntity()
{
WorldEntity main = Entity(1u, OneMesh);
IReadOnlyList entities =
PrivateEntityViewportRenderer.BuildDrawEntities(backdrop: null, main);
Assert.Same(main, Assert.Single(entities));
}
[Fact]
public void BackdropPresent_ReturnsBackdropFirstThenMain()
{
// Decomp-cited: gmCG3DView::Update adds the backdrop object to
// creature_mode_objects BEFORE the player object is re-added
// (~0x004eed44 vs ~0x004ef199) — this ordering is retail-faithful,
// not an arbitrary choice.
WorldEntity backdrop = Entity(ChargenPreviewEntityBuilder.PreviewBackdropRenderId, OneMesh);
WorldEntity main = Entity(ChargenPreviewEntityBuilder.PreviewRenderId, OneMesh);
IReadOnlyList entities =
PrivateEntityViewportRenderer.BuildDrawEntities(backdrop, main);
Assert.Equal(2, entities.Count);
Assert.Same(backdrop, entities[0]);
Assert.Same(main, entities[1]);
}
[Fact]
public void BackdropWithNoDrawableMeshes_DegradesToExactlyTheMainEntity()
{
WorldEntity emptyBackdrop = Entity(
ChargenPreviewEntityBuilder.PreviewBackdropRenderId, []);
WorldEntity main = Entity(ChargenPreviewEntityBuilder.PreviewRenderId, OneMesh);
IReadOnlyList entities =
PrivateEntityViewportRenderer.BuildDrawEntities(emptyBackdrop, main);
Assert.Same(main, Assert.Single(entities));
}
}