checkpoint: preserve user-gated FW closeout fixes

This commit is contained in:
Erik 2026-08-31 08:27:37 +02:00
parent a2f2eb7d78
commit b8befded8b
22 changed files with 1005 additions and 198 deletions

View file

@ -25,8 +25,9 @@ namespace AcDream.App.Rendering.Walk;
/// true eye ray (near/far unprojection) are observably equivalent to
/// retail's exact construction for this contract.
///
/// One instance is a per-frame value (like <c>WalkTraceReplayContext</c>):
/// construct fresh each frame with that frame's camera pose.
/// Production retains one instance per renderer and rebinds its frame-local
/// camera values through <see cref="Reset"/>. The registries and grow-only
/// active-view scratch remain renderer-lifetime owners.
/// </summary>
public sealed class WalkProductionFrameContext : IWalkFrameContext, IRetailFrameWalkContext
{
@ -35,19 +36,28 @@ public sealed class WalkProductionFrameContext : IWalkFrameContext, IRetailFrame
private sealed class InverseViewProjectionRayCaster : IWalkRayCaster
{
private readonly Matrix4x4 _inverseViewProjection;
private readonly float _viewportWidth;
private readonly float _viewportHeight;
private Matrix4x4 _inverseViewProjection;
private float _viewportWidth;
private float _viewportHeight;
public InverseViewProjectionRayCaster(
Matrix4x4 viewProjection, float viewportWidth, float viewportHeight)
=> Reset(viewProjection, viewportWidth, viewportHeight);
internal void Reset(
Matrix4x4 viewProjection, float viewportWidth, float viewportHeight)
{
if (!Matrix4x4.Invert(viewProjection, out _inverseViewProjection))
if (!Matrix4x4.Invert(viewProjection, out Matrix4x4 inverseViewProjection))
{
throw new ArgumentException(
"The walk's view-projection matrix must be invertible.",
nameof(viewProjection));
}
// Publish only after validation succeeds. Matrix4x4.Invert writes
// its out value even on failure; assigning the field directly
// would silently corrupt the retained ray caster for the next
// report-and-continue frame.
_inverseViewProjection = inverseViewProjection;
_viewportWidth = viewportWidth;
_viewportHeight = viewportHeight;
}
@ -72,8 +82,8 @@ public sealed class WalkProductionFrameContext : IWalkFrameContext, IRetailFrame
private readonly CellVisibility _cells;
private readonly WalkBuildingRegistry _buildings;
private readonly Matrix4x4 _viewProjection;
private readonly IWalkRayCaster _rays;
private Matrix4x4 _viewProjection;
private readonly InverseViewProjectionRayCaster _rays;
private Vector2[] _activeViewVerts = new Vector2[32];
private int _activeViewVertCount;
@ -89,19 +99,39 @@ public sealed class WalkProductionFrameContext : IWalkFrameContext, IRetailFrame
{
_cells = cells ?? throw new ArgumentNullException(nameof(cells));
_buildings = buildings ?? throw new ArgumentNullException(nameof(buildings));
_rays = new InverseViewProjectionRayCaster(
viewProjection, viewportWidth, viewportHeight);
Reset(worldViewpoint, forward, viewProjection, viewportWidth, viewportHeight);
}
/// <summary>
/// FW6 allocation closeout: rebind this retained context to one frame's
/// camera values while preserving its active-view scratch. The cell and
/// building registries are lifetime owners and therefore never change.
/// </summary>
internal void Reset(
Vector3 worldViewpoint,
Vector3 forward,
Matrix4x4 viewProjection,
float viewportWidth,
float viewportHeight)
{
// Validate/invert before publishing any new frame value so a bad
// camera matrix leaves the previous usable binding intact.
_rays.Reset(viewProjection, viewportWidth, viewportHeight);
WorldViewpoint = worldViewpoint;
_viewProjection = viewProjection;
ViewportWidth = viewportWidth;
ViewportHeight = viewportHeight;
_rays = new InverseViewProjectionRayCaster(viewProjection, viewportWidth, viewportHeight);
_activeViewVertCount = 0;
// The retail CY near plane: N = forward, d = -dot(eye, forward) - znear.
CyPlane = new WalkPlane(forward, -Vector3.Dot(worldViewpoint, forward) - ZNear);
}
public Vector3 WorldViewpoint { get; }
public float ViewportWidth { get; }
public float ViewportHeight { get; }
public WalkPlane CyPlane { get; }
public Vector3 WorldViewpoint { get; private set; }
public float ViewportWidth { get; private set; }
public float ViewportHeight { get; private set; }
public WalkPlane CyPlane { get; private set; }
public IWalkRayCaster Rays => _rays;
public IWalkFrameContext CellContext => this;