acdream/tests/AcDream.App.Tests/Rendering/RetailSelectionSceneTests.cs
Erik 28e1cf8029 refactor(render): extract world scene frame owner
Move fallback and PView world drawing, shared alpha, particles, visibility, selection, and diagnostics behind focused frame owners. Make exceptional frames failure-atomic by restoring the shared GL baseline and preserving primary alpha failures through cleanup.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 07:22:09 +02:00

137 lines
4.2 KiB
C#

using System.Numerics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Selection;
using AcDream.Core.Selection;
using AcDream.Core.World;
namespace AcDream.App.Tests.Rendering;
public sealed class RetailSelectionSceneTests
{
private sealed class GeometrySource(RetailSelectionMesh mesh)
: IRetailSelectionGeometrySource
{
public RetailSelectionMesh? Resolve(uint gfxObjId)
=> gfxObjId == 0x0100_0001u ? mesh : null;
}
[Fact]
public void PublishedHitCarriesLogicalEntityIdentity()
{
var scene = CreateScene();
var entity = Entity(localId: 44u, serverGuid: 0x5000_0044u);
Publish(scene, entity);
RetailSelectionHit? hit = PickCenter(scene);
Assert.NotNull(hit);
Assert.Equal(entity.ServerGuid, hit.Value.ServerGuid);
Assert.Equal(entity.Id, hit.Value.LocalEntityId);
}
[Fact]
public void ResetClearsPublishedFrameAndLightingPulse()
{
double now = 1d;
var pulse = new RetailSelectionLightingPulse(() => now);
var scene = CreateScene(pulse);
var entity = Entity(localId: 45u, serverGuid: 0x5000_0045u);
Publish(scene, entity);
scene.BeginLightingPulse(entity.ServerGuid, entity.Id);
scene.Reset();
Assert.Null(PickCenter(scene));
Assert.False(scene.TryGetLighting(entity.ServerGuid, entity.Id, out _));
}
[Fact]
public void AbortFrame_DiscardsBuildingSelectionAndPreservesPublishedFrame()
{
var scene = CreateScene();
var published = Entity(localId: 46u, serverGuid: 0x5000_0046u);
Publish(scene, published);
var rejected = Entity(localId: 47u, serverGuid: 0x5000_0047u);
scene.BeginFrame();
(Matrix4x4 view, Matrix4x4 projection) = Camera();
scene.SetViewFrustum(FrustumPlanes.FromViewProjection(view * projection));
scene.AddVisiblePart(
rejected,
partIndex: 0,
gfxObjId: 0x0100_0001u,
Matrix4x4.CreateTranslation(0f, 0f, -5f));
scene.AbortFrame();
RetailSelectionHit? hit = PickCenter(scene);
Assert.NotNull(hit);
Assert.Equal(published.Id, hit.Value.LocalEntityId);
}
private static RetailSelectionScene CreateScene(
RetailSelectionLightingPulse? pulse = null)
{
var mesh = new RetailSelectionMesh(
Vector3.Zero,
2f,
[new RetailSelectionPolygon(
[
new(-1f, -1f, 0f),
new( 1f, -1f, 0f),
new( 1f, 1f, 0f),
new(-1f, 1f, 0f),
],
SingleSided: false)]);
return new RetailSelectionScene(new GeometrySource(mesh), pulse);
}
private static WorldEntity Entity(uint localId, uint serverGuid)
=> new()
{
Id = localId,
ServerGuid = serverGuid,
SourceGfxObjOrSetupId = 0x0200_0001u,
Position = Vector3.Zero,
Rotation = Quaternion.Identity,
MeshRefs = [],
};
private static void Publish(RetailSelectionScene scene, WorldEntity entity)
{
scene.BeginFrame();
(Matrix4x4 view, Matrix4x4 projection) = Camera();
scene.SetViewFrustum(FrustumPlanes.FromViewProjection(view * projection));
scene.AddVisiblePart(
entity,
partIndex: 0,
gfxObjId: 0x0100_0001u,
Matrix4x4.CreateTranslation(0f, 0f, -5f));
scene.CompleteFrame();
}
private static RetailSelectionHit? PickCenter(RetailSelectionScene scene)
{
(Matrix4x4 view, Matrix4x4 projection) = Camera();
return scene.Pick(
400f,
300f,
new Vector2(800f, 600f),
view,
projection,
skipServerGuid: 0u);
}
private static (Matrix4x4 View, Matrix4x4 Projection) Camera()
{
Matrix4x4 view = Matrix4x4.CreateLookAt(
Vector3.Zero,
-Vector3.UnitZ,
Vector3.UnitY);
Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView(
MathF.PI / 3f,
4f / 3f,
0.1f,
100f);
return (view, projection);
}
}