refactor(animation): extract live PartArray presenter

Move final live part composition, exact-incarnation schedule handoff, MotionDone binding, and presentation diagnostics out of GameWindow while preserving the retail frame order. Reject stale schedule and completion ABA at the new owner boundary.

Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-21 09:37:02 +02:00
parent 9760ff5a8d
commit f004ac5562
14 changed files with 963 additions and 438 deletions

View file

@ -0,0 +1,63 @@
using System.Numerics;
using AcDream.App.World;
using AcDream.Core.Physics;
using AcDream.Core.Physics.Motion;
using AcDream.Core.World;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Types;
namespace AcDream.App.Rendering;
/// <summary>
/// Incarnation-owned live <c>CPartArray</c> presentation state. Time, root
/// motion, and hooks remain owned by <see cref="LiveEntityAnimationScheduler"/>;
/// this component retains the final part-presentation channels only.
/// </summary>
internal sealed class LiveEntityAnimationState : ILiveEntityAnimationRuntime
{
public required WorldEntity Entity;
WorldEntity ILiveEntityAnimationRuntime.Entity => Entity;
uint ILiveEntityAnimationRuntime.CurrentMotion => Sequencer?.CurrentMotion ?? 0u;
public required Setup Setup;
public required Animation Animation;
public required int LowFrame;
public required int HighFrame;
public required float Framerate;
public required float Scale;
public required IReadOnlyList<LiveAnimationPartTemplate> PartTemplate;
public required IReadOnlyList<bool> PartAvailability;
public float CurrFrame;
public AnimationSequencer? Sequencer;
public IReadOnlyList<PartTransform>? PreparedSequenceFrames;
public bool SequenceAdvancedBeforeAnimationPass;
public readonly Frame RootMotionScratch = new();
public readonly MotionDeltaFrame RootMotionDeltaScratch = new();
/// <summary>Reusable compact drawable channel, consumed before draw.</summary>
public readonly List<MeshRef> MeshRefsScratch = new();
/// <summary>Reusable indexed rigid/effect channel.</summary>
public readonly List<Matrix4x4> EffectPartPosesScratch = new();
/// <summary>
/// Indexed visible transforms retained separately from the rigid channel
/// because Setup DefaultScale affects geometry but not attachments.
/// </summary>
public readonly List<Matrix4x4> VisualPartPosesScratch = new();
public bool PresentationPosesInitialized;
public double LastSequenceDiagnosticTime;
public double LastPartDiagnosticTime;
public void InvalidatePresentationPoses()
{
PresentationPosesInitialized = false;
VisualPartPosesScratch.Clear();
EffectPartPosesScratch.Clear();
}
}
internal readonly record struct LiveAnimationPartTemplate(
uint GfxObjId,
IReadOnlyDictionary<uint, uint>? SurfaceOverrides,
bool IsDrawable);