Own every borrowed PartArray frame across callbacks, version presentation state across appearance rebinding, reject recursive phase consumption, and preserve static MotionDone when only a stale visual pose is discarded.
89 lines
3.4 KiB
C#
89 lines
3.4 KiB
C#
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();
|
|
public readonly List<PartTransform> SequenceFramesScratch = new();
|
|
public readonly List<PartTransform> ScheduleFramesScratch = 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 ulong PresentationRevision { get; private set; } = 1UL;
|
|
|
|
public double LastSequenceDiagnosticTime;
|
|
public double LastPartDiagnosticTime;
|
|
|
|
public void InvalidatePresentationPoses()
|
|
{
|
|
PresentationRevision++;
|
|
if (PresentationRevision == 0UL)
|
|
PresentationRevision++;
|
|
PresentationPosesInitialized = false;
|
|
VisualPartPosesScratch.Clear();
|
|
EffectPartPosesScratch.Clear();
|
|
}
|
|
|
|
public IReadOnlyList<PartTransform> CaptureSequenceFrames(
|
|
IReadOnlyList<PartTransform> source)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(source);
|
|
SequenceFramesScratch.Clear();
|
|
for (int i = 0; i < source.Count; i++)
|
|
SequenceFramesScratch.Add(source[i]);
|
|
return SequenceFramesScratch;
|
|
}
|
|
|
|
public IReadOnlyList<PartTransform> CaptureScheduleFrames(
|
|
IReadOnlyList<PartTransform> source)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(source);
|
|
ScheduleFramesScratch.Clear();
|
|
for (int i = 0; i < source.Count; i++)
|
|
ScheduleFramesScratch.Add(source[i]);
|
|
return ScheduleFramesScratch;
|
|
}
|
|
}
|
|
|
|
internal readonly record struct LiveAnimationPartTemplate(
|
|
uint GfxObjId,
|
|
IReadOnlyDictionary<uint, uint>? SurfaceOverrides,
|
|
bool IsDrawable);
|