diff --git a/FModel/Views/Snooper/Models/Animations/Animation.cs b/FModel/Views/Snooper/Models/Animations/Animation.cs index a778140d..1059365d 100644 --- a/FModel/Views/Snooper/Models/Animations/Animation.cs +++ b/FModel/Views/Snooper/Models/Animations/Animation.cs @@ -15,9 +15,13 @@ public enum AnimSeparatorType public class Animation : IDisposable { public float ElapsedTime; + public int Frame; + public int FrameInSequence; + public bool IsPaused; public readonly int TotalFrames; - public readonly float TotalDuration; + public readonly int EndFrame; + public readonly float MaxElapsedTime; public int CurrentSequence; public readonly Sequence[] Sequences; @@ -29,7 +33,8 @@ public class Animation : IDisposable IsPaused = false; TotalFrames = 0; - TotalDuration = 0.0f; + EndFrame = 0; + MaxElapsedTime = 0.0f; Sequences = Array.Empty(); } @@ -41,7 +46,8 @@ public class Animation : IDisposable Sequences[i] = new Sequence(anim.Sequences[i], skeleton, rotationOnly); TotalFrames += Sequences[i].MaxFrame; - TotalDuration += Sequences[i].Duration; + MaxElapsedTime += anim.Sequences[i].NumFrames * Sequences[i].TimePerFrame; + EndFrame += (Sequences[i].Duration / Sequences[i].TimePerFrame).FloorToInt(); } if (Sequences.Length > 0) @@ -51,27 +57,48 @@ public class Animation : IDisposable public void Update(float deltaSeconds) { if (IsPaused) return; - if (Sequences[CurrentSequence].IsComplete) + + ElapsedTime += deltaSeconds; + TimeCalculation(); + } + + private void TimeCalculation() + { + CurrentSequence = SequencesCount; + for (int i = 0; i < Sequences.Length; i++) { - Sequences[CurrentSequence].Reset(); - CurrentSequence++; + if (ElapsedTime < Sequences[i].EndTime) + { + CurrentSequence = i; + break; + } } if (CurrentSequence >= SequencesCount) Reset(); - ElapsedTime += Sequences[CurrentSequence].Update(deltaSeconds); + Frame = Math.Min((ElapsedTime / Sequences[CurrentSequence].TimePerFrame).FloorToInt(), TotalFrames); + + var baseFrame = 0; + for (int s = 0; s < CurrentSequence; s++) + { + baseFrame += Sequences[s].MaxFrame; + } + FrameInSequence = Math.Min(Frame - baseFrame, Sequences[CurrentSequence].MaxFrame); } public Matrix4x4 InterpolateBoneTransform(int boneIndex) { // interpolate here - return Sequences[CurrentSequence].BonesTransform[boneIndex][Sequences[CurrentSequence].Frame].Matrix; + return Sequences[CurrentSequence].BonesTransform[boneIndex][FrameInSequence].Matrix; } private void Reset() { ElapsedTime = 0.0f; + Frame = 0; + FrameInSequence = 0; + CurrentSequence = 0; } @@ -92,7 +119,8 @@ public class Animation : IDisposable if (IsPaused && ImGui.IsMouseDragging(ImGuiMouseButton.Left)) { var mousePosCanvas = io.MousePos - canvasP0; - ElapsedTime = Math.Clamp(mousePosCanvas.X / canvasSize.X * TotalDuration, 0, TotalDuration); + ElapsedTime = Math.Clamp(mousePosCanvas.X / canvasSize.X * MaxElapsedTime, 0, MaxElapsedTime); + TimeCalculation(); } drawList.AddRectFilled(canvasP0, canvasP1 with { Y = canvasP0.Y + _timeBarHeight }, 0xFF181818); @@ -108,11 +136,11 @@ public class Animation : IDisposable for (int i = 0; i < Sequences.Length; i++) { - Sequences[i].DrawSequence(drawList, canvasP0, ratio, i); + Sequences[i].DrawSequence(drawList, canvasP0.X, canvasP0.Y + _timeBarHeight, ratio, i); } - DrawSeparator(drawList, canvasP0, canvasP1, ElapsedTime * ratio.X, AnimSeparatorType.InBetween); - DrawSeparator(drawList, canvasP0, canvasP1, TotalDuration * ratio.X, AnimSeparatorType.End); + DrawSeparator(drawList, canvasP0, canvasP1, Frame * ratio.X, AnimSeparatorType.InBetween); + DrawSeparator(drawList, canvasP0, canvasP1, EndFrame * ratio.X, AnimSeparatorType.End); // ImGui.Text($"{Sequences[CurrentSequence].Name} > {(CurrentSequence < SequencesCount - 1 ? Sequences[CurrentSequence + 1].Name : Sequences[0].Name)}"); // ImGui.Text($"Frame: {Sequences[CurrentSequence].Frame}/{Sequences[CurrentSequence].MaxFrame}"); diff --git a/FModel/Views/Snooper/Models/Animations/Sequence.cs b/FModel/Views/Snooper/Models/Animations/Sequence.cs index ee0c6380..25c948a9 100644 --- a/FModel/Views/Snooper/Models/Animations/Sequence.cs +++ b/FModel/Views/Snooper/Models/Animations/Sequence.cs @@ -1,15 +1,12 @@ using System; using System.Numerics; using CUE4Parse_Conversion.Animations; -using CUE4Parse.Utils; using ImGuiNET; namespace FModel.Views.Snooper.Models.Animations; public class Sequence : IDisposable { - public int Frame; - public float ElapsedTime; public readonly string Name; public readonly int MaxFrame; public readonly float TimePerFrame; @@ -18,23 +15,24 @@ public class Sequence : IDisposable public readonly float EndTime; public readonly int LoopingCount; - public readonly Transform[][] BonesTransform; + private readonly float _start; + private readonly float _end; - public bool IsComplete => ElapsedTime > Duration; - // public bool IsComplete => Frame >= MaxFrame; + public readonly Transform[][] BonesTransform; public Sequence(CAnimSequence sequence, Skeleton skeleton, bool rotationOnly) { - Reset(); - Name = sequence.Name; MaxFrame = sequence.NumFrames - 1; TimePerFrame = 1.0f / sequence.Rate; - StartTime = sequence.StartPos / TimePerFrame; - Duration = sequence.AnimEndTime / TimePerFrame; + StartTime = sequence.StartPos; + Duration = sequence.AnimEndTime; EndTime = StartTime + Duration; LoopingCount = sequence.LoopingCount; + _start = StartTime / TimePerFrame; + _end = EndTime / TimePerFrame; + BonesTransform = new Transform[skeleton.BonesTransformByIndex.Count][]; for (int trackIndex = 0; trackIndex < skeleton.UnrealSkeleton.ReferenceSkeleton.FinalRefBoneInfo.Length; trackIndex++) { @@ -83,27 +81,13 @@ public class Sequence : IDisposable } } - public float Update(float deltaSeconds) - { - var delta = deltaSeconds / TimePerFrame; - ElapsedTime += delta; - Frame = Math.Min(ElapsedTime.FloorToInt(), MaxFrame); - return delta; - } - - public void Reset() - { - ElapsedTime = 0.0f; - Frame = 0; - } - private readonly float _height = 20.0f; - public void DrawSequence(ImDrawListPtr drawList, Vector2 origin, Vector2 ratio, int index) + public void DrawSequence(ImDrawListPtr drawList, float x, float y, Vector2 ratio, int index) { - var height = _height * (index % 2) + _height; - var p1 = new Vector2(origin.X + StartTime * ratio.X, origin.Y + height); - var p2 = new Vector2(origin.X + EndTime * ratio.X, origin.Y + height + _height); + var height = _height * (index % 2); + var p1 = new Vector2(x + _start * ratio.X, y + height); + var p2 = new Vector2(x + _end * ratio.X, y + height + _height); drawList.AddRectFilled(p1, p2, 0xFF175F17); drawList.AddText(p1 with { X = p1.X + 2.5f }, 0xFF000000, Name); }