feat(render): implement Campaign AR and terrain fidelity

This commit is contained in:
Erik 2026-08-22 13:13:29 +02:00
parent 99cf26e00c
commit 7a5f96ede5
368 changed files with 50611 additions and 950 deletions

View file

@ -35,6 +35,32 @@ public sealed class HostInputCameraCompositionTests
Assert.Equal((1280, 720), fixture.Factory.Viewport.Size);
}
[Fact]
public void DiagnosticOrbitOverridesReachOnlyTheInitialOrbitCamera()
{
using var fixture = new Fixture();
HostInputCameraResult result = fixture
.Phase(180f, -135f, 7.5f)
.Compose(fixture.Platform);
Assert.Equal(180f, result.CameraController.Orbit.Distance);
Assert.Equal(-135f * MathF.PI / 180f, result.CameraController.Orbit.Yaw);
Assert.Equal(7.5f * MathF.PI / 180f, result.CameraController.Orbit.Pitch);
}
[Fact]
public void VulkanFactoryConvertsDiagnosticOrbitAnglesFromDegrees()
{
var factory = new VulkanHostInputCameraCompositionFactory();
CameraController camera = factory.CreateCameraController(200f, 180f, -12f);
Assert.Equal(200f, camera.Orbit.Distance);
Assert.Equal(MathF.PI, camera.Orbit.Yaw, precision: 6);
Assert.Equal(-12f * MathF.PI / 180f, camera.Orbit.Pitch, precision: 6);
}
[Theory]
[MemberData(nameof(FaultPointValues))]
public void FailureAtEveryProductionBoundaryStopsTheExactSuffix(
@ -138,7 +164,10 @@ public sealed class HostInputCameraCompositionTests
public Factory Factory { get; }
public Publication Publication { get; }
public HostInputCameraCompositionPhase Phase() => new(
public HostInputCameraCompositionPhase Phase(
float? initialOrbitDistanceMeters = null,
float? initialOrbitYawDegrees = null,
float? initialOrbitPitchDegrees = null) => new(
new HostInputCameraDependencies(
Framebuffer,
new Vector2D<int>(1280, 720),
@ -150,7 +179,10 @@ public sealed class HostInputCameraCompositionTests
PlayerMode,
Chase,
Pointer,
new DiagnosticLog()),
new DiagnosticLog(),
initialOrbitDistanceMeters,
initialOrbitYawDegrees,
initialOrbitPitchDegrees),
Publication,
Factory,
point =>
@ -318,8 +350,20 @@ public sealed class HostInputCameraCompositionTests
KeyBindings bindings) =>
InputDispatcher.CreateDetached(keyboard, mouse, bindings);
public CameraController CreateCameraController() =>
new(new OrbitCamera(), new FlyCamera());
public CameraController CreateCameraController(
float? initialOrbitDistanceMeters,
float? initialOrbitYawDegrees,
float? initialOrbitPitchDegrees)
{
var orbit = new OrbitCamera();
if (initialOrbitDistanceMeters is { } distance)
orbit.Distance = distance;
if (initialOrbitYawDegrees is { } yaw)
orbit.Yaw = yaw * (MathF.PI / 180f);
if (initialOrbitPitchDegrees is { } pitch)
orbit.Pitch = pitch * (MathF.PI / 180f);
return new CameraController(orbit, new FlyCamera());
}
public IFramebufferCameraTarget CreateCameraTarget(CameraController camera) =>
new CameraTarget(camera);

View file

@ -181,9 +181,25 @@ public sealed class InteractionUiRuntimeSourcesTests
Assert.True(source.IsWorldReady);
Assert.True(source.TryRequestCheckpoint("ready", out _, out _));
Assert.Equal("ready", target.LastCheckpoint);
Assert.Equal(target.RenderPackStatus, source.RenderPackStatus);
Assert.Equal(1280, source.FramebufferWidth);
Assert.Equal(720, source.FramebufferHeight);
Assert.True(source.TrySelectRenderPack("high", out _));
Assert.Equal("high", target.LastRenderPackPreset);
Assert.True(source.TryDisableRenderPack(out _));
Assert.True(target.RenderPackDisabled);
Assert.True(source.TryReenableRenderPack(out _));
Assert.True(target.RenderPackReenabled);
Assert.True(source.TryResizeFramebuffer(1024, 768, out _));
Assert.Equal((1024, 768), target.LastFramebufferSize);
binding.Dispose();
Assert.False(source.IsWorldReady);
Assert.Equal(
AcDream.App.UI.Testing.RetailUiAutomationRenderPackStatus.Retail,
source.RenderPackStatus);
Assert.False(source.TrySelectRenderPack("high", out string unboundError));
Assert.Contains("not bound", unboundError);
source.Deactivate();
Assert.Throws<ObjectDisposedException>(() => source.Bind(target));
}
@ -454,7 +470,48 @@ public sealed class InteractionUiRuntimeSourcesTests
public bool IsWorldReady => true;
public bool IsWorldViewportVisible => true;
public int PortalMaterializationCount => 2;
public AcDream.App.UI.Testing.RetailUiAutomationRenderPackStatus
RenderPackStatus { get; } = new(
AcDream.App.UI.Testing.RetailUiAutomationRenderPackState.Active,
"acdream.atmospheric",
"high",
7,
null);
public int FramebufferWidth => 1280;
public int FramebufferHeight => 720;
public string? LastCheckpoint { get; private set; }
public string? LastRenderPackPreset { get; private set; }
public bool RenderPackDisabled { get; private set; }
public bool RenderPackReenabled { get; private set; }
public (int Width, int Height)? LastFramebufferSize { get; private set; }
public bool TrySelectRenderPack(string presetId, out string error)
{
LastRenderPackPreset = presetId;
error = string.Empty;
return true;
}
public bool TryDisableRenderPack(out string error)
{
RenderPackDisabled = true;
error = string.Empty;
return true;
}
public bool TryReenableRenderPack(out string error)
{
RenderPackReenabled = true;
error = string.Empty;
return true;
}
public bool TryResizeFramebuffer(int width, int height, out string error)
{
LastFramebufferSize = (width, height);
error = string.Empty;
return true;
}
public bool TryRequestCheckpoint(
string name,

View file

@ -223,7 +223,8 @@ public sealed class WorldRenderCompositionTests
public void InitializeEnvironment(
WorldEnvironmentController environment,
Region region) { }
Region region,
IDatReaderWriter dats) { }
/// <summary>
/// Campaign V slice V6i-2: the arm a backend with no GL context takes.