mirror of
https://github.com/4sval/FModel.git
synced 2026-04-03 07:36:11 -05:00
timeline
This commit is contained in:
parent
591a2d2336
commit
4247dec633
|
|
@ -78,10 +78,10 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"fortnitegame/Content/Characters/Player/Male/Medium/Bodies/M_Med_Soldier_04/Meshes/SK_M_Med_Soldier_04.uasset"));
|
||||
"fortnitegame/Content/Characters/Player/Male/Medium/Bodies/M_MED_BlueGlaze/Meshes/M_MED_BlueGlaze.uasset"));
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"fortnitegame/Content/Animation/Game/MainPlayer/Emotes/Basketball_Tricks/Basketball_Tricks_Loop_CMM_M.uasset"));
|
||||
"fortnitegame/Content/Animation/Game/MainPlayer/Emotes/Troops/Emote_Troops_CMM_M.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ namespace FModel.Views.Snooper.Animations;
|
|||
|
||||
public class Animation : IDisposable
|
||||
{
|
||||
public readonly UObject Export;
|
||||
public readonly CAnimSet AnimSet;
|
||||
private readonly UObject _export;
|
||||
private readonly CAnimSet _animSet;
|
||||
|
||||
public readonly string Path;
|
||||
public readonly string Name;
|
||||
public readonly Sequence[] Sequences;
|
||||
|
|
@ -33,25 +34,25 @@ public class Animation : IDisposable
|
|||
|
||||
public Animation(UObject export)
|
||||
{
|
||||
Export = export;
|
||||
Path = Export.GetPathName();
|
||||
Name = Export.Name;
|
||||
_export = export;
|
||||
Path = _export.GetPathName();
|
||||
Name = _export.Name;
|
||||
Sequences = Array.Empty<Sequence>();
|
||||
AttachedModels = new List<FGuid>();
|
||||
}
|
||||
|
||||
public Animation(UObject export, CAnimSet animSet) : this(export)
|
||||
{
|
||||
AnimSet = animSet;
|
||||
TargetSkeleton = AnimSet.OriginalAnim.Name;
|
||||
_animSet = animSet;
|
||||
TargetSkeleton = _animSet.OriginalAnim.Name;
|
||||
|
||||
Sequences = new Sequence[AnimSet.Sequences.Count];
|
||||
Sequences = new Sequence[_animSet.Sequences.Count];
|
||||
for (int i = 0; i < Sequences.Length; i++)
|
||||
{
|
||||
Sequences[i] = new Sequence(AnimSet.Sequences[i]);
|
||||
Sequences[i] = new Sequence(_animSet.Sequences[i]);
|
||||
|
||||
EndTime = Sequences[i].EndTime;
|
||||
TotalElapsedTime += AnimSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame;
|
||||
TotalElapsedTime += _animSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame;
|
||||
}
|
||||
|
||||
if (Sequences.Length > 0)
|
||||
|
|
@ -95,29 +96,31 @@ public class Animation : IDisposable
|
|||
|
||||
public void ImGuiAnimation(Snooper s, Save saver, ImDrawListPtr drawList, Vector2 timelineP0, Vector2 treeP0, Vector2 treeP1, Vector2 timeStep, Vector2 timeRatio, float y, float t, int i)
|
||||
{
|
||||
var name = $"{Name}##{i}";
|
||||
var p1 = new Vector2(timelineP0.X + StartTime * timeRatio.X + t, y + t);
|
||||
var p2 = new Vector2(timelineP0.X + EndTime * timeRatio.X - t, y + timeStep.Y - t);
|
||||
|
||||
ImGui.SetCursorScreenPos(p1);
|
||||
ImGui.InvisibleButton($"timeline_sequencetracker_{Name}##{i}", new Vector2(EndTime * timeRatio.X - t, timeStep.Y - t), ImGuiButtonFlags.MouseButtonLeft);
|
||||
ImGui.InvisibleButton($"timeline_sequencetracker_{name}", new Vector2(EndTime * timeRatio.X - t, timeStep.Y - t), ImGuiButtonFlags.MouseButtonLeft);
|
||||
IsActive = ImGui.IsItemActive();
|
||||
IsSelected = s.Renderer.Options.SelectedAnimation == i;
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
{
|
||||
s.Renderer.Options.SelectedAnimation = i;
|
||||
s.Renderer.Options.SelectAnimation(i);
|
||||
}
|
||||
SnimGui.Popup(() =>
|
||||
{
|
||||
s.Renderer.Options.SelectedAnimation = i;
|
||||
s.Renderer.Options.SelectAnimation(i);
|
||||
if (ImGui.BeginMenu("Animate"))
|
||||
{
|
||||
foreach ((var guid, var model) in s.Renderer.Options.Models)
|
||||
{
|
||||
if (ImGui.MenuItem(model.Name, model.HasSkeleton && !AttachedModels.Contains(guid)))
|
||||
var selected = AttachedModels.Contains(guid);
|
||||
if (ImGui.MenuItem(model.Name, null, selected, (model.HasSkeleton && !model.Skeleton.IsAnimated) || selected))
|
||||
{
|
||||
AttachedModels.Add(guid);
|
||||
if (selected) AttachedModels.Remove(guid); else AttachedModels.Add(guid);
|
||||
model.Skeleton.ResetAnimatedData(true);
|
||||
model.Skeleton.Animate(AnimSet, s.Renderer.AnimateWithRotationOnly);
|
||||
if (!selected) model.Skeleton.Animate(_animSet, s.Renderer.AnimateWithRotationOnly);
|
||||
}
|
||||
}
|
||||
ImGui.EndMenu();
|
||||
|
|
@ -125,7 +128,7 @@ public class Animation : IDisposable
|
|||
if (ImGui.Selectable("Save"))
|
||||
{
|
||||
s.WindowShouldFreeze(true);
|
||||
saver.Value = s.Renderer.Options.TrySave(Export, out saver.Label, out saver.Path);
|
||||
saver.Value = s.Renderer.Options.TrySave(_export, out saver.Label, out saver.Path);
|
||||
s.WindowShouldFreeze(false);
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
|
@ -138,8 +141,10 @@ public class Animation : IDisposable
|
|||
Sequences[j].DrawSequence(drawList, timelineP0.X, p2, timeStep, timeRatio, t);
|
||||
}
|
||||
|
||||
drawList.PushClipRect(treeP0 with { Y = p1.Y }, treeP1 with { Y = p2.Y }, true);
|
||||
drawList.AddText(treeP0 with { Y = y + timeStep.Y / 4.0f }, 0xFFFFFFFF, Name);
|
||||
drawList.PopClipRect();
|
||||
ImGui.SetCursorScreenPos(treeP0 with { Y = p1.Y });
|
||||
if (ImGui.Selectable(name, s.Renderer.Options.SelectedAnimation == i, ImGuiSelectableFlags.SpanAllColumns, new Vector2(p1.X - treeP0.X, timeStep.Y - t - t)))
|
||||
{
|
||||
s.Renderer.Options.SelectAnimation(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,12 +141,14 @@ public class TimeTracker : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.SelectableTextAlign, new Vector2(0.0f, 0.5f));
|
||||
for (int i = 0; i < animations.Count; i++)
|
||||
{
|
||||
var y = timelineP0.Y + _timeBarHeight + _timeStep.Y * i;
|
||||
animations[i].ImGuiAnimation(s, saver, drawList, timelineP0, treeP0, treeP1, _timeStep, timeRatio, y, _thickness, i);
|
||||
DrawSeparator(drawList, timelineP0, y + _timeStep.Y, animations[i].EndTime * timeRatio.X, ETrackerType.End);
|
||||
}
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
for (int i = 0; i < animations.Count; i++)
|
||||
{
|
||||
|
|
@ -165,7 +167,13 @@ public class TimeTracker : IDisposable
|
|||
|
||||
private void DrawSeparator(ImDrawListPtr drawList, Vector2 origin, float y, float time, ETrackerType separatorType)
|
||||
{
|
||||
const int size = 5;
|
||||
float size = separatorType switch
|
||||
{
|
||||
ETrackerType.Frame => 5,
|
||||
ETrackerType.End => 5,
|
||||
ETrackerType.InBetween => 7.5f,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null)
|
||||
};
|
||||
|
||||
Vector2 p1 = separatorType switch
|
||||
{
|
||||
|
|
@ -180,11 +188,10 @@ public class TimeTracker : IDisposable
|
|||
{
|
||||
ETrackerType.Frame => 0xFF6F6F6F,
|
||||
ETrackerType.End => 0xFF2E3E82,
|
||||
ETrackerType.InBetween => 0x50FFFFFF,
|
||||
ETrackerType.InBetween => 0xA0FFFFFF,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null)
|
||||
};
|
||||
|
||||
drawList.AddLine(p1, p2, color, 1f);
|
||||
switch (separatorType)
|
||||
{
|
||||
case ETrackerType.Frame:
|
||||
|
|
@ -193,13 +200,19 @@ public class TimeTracker : IDisposable
|
|||
var xr = p1.X + size;
|
||||
var yb = origin.Y + _timeBarHeight - _timeHeight / 2.0f;
|
||||
|
||||
drawList.AddLine(p1, p2, color, 1f);
|
||||
drawList.AddQuadFilled(origin with { X = xl }, origin with { X = xr }, new Vector2(xr, yb), new Vector2(xl, yb), color);
|
||||
drawList.AddTriangleFilled(new Vector2(xl, yb), new Vector2(xr, yb), p1, color);
|
||||
break;
|
||||
case ETrackerType.End:
|
||||
case ETrackerType.InBetween:
|
||||
drawList.AddLine(p1, p2, color, 1f);
|
||||
drawList.AddTriangleFilled(p1, p1 with { X = p1.X - size }, p1 with { Y = p1.Y + size }, color);
|
||||
break;
|
||||
case ETrackerType.InBetween:
|
||||
p1.Y += _timeBarHeight;
|
||||
drawList.AddLine(p1, p2, color, 1f);
|
||||
drawList.AddTriangleFilled(p1, new Vector2(p1.X - size / 2.0f, p1.Y - size), new Vector2(p1.X + size / 2.0f, p1.Y - size), color);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class Options
|
|||
public FGuid SelectedModel { get; private set; }
|
||||
public int SelectedSection { get; private set; }
|
||||
public int SelectedMorph { get; private set; }
|
||||
public int SelectedAnimation{ get; set; }
|
||||
public int SelectedAnimation{ get; private set; }
|
||||
|
||||
public readonly Dictionary<FGuid, Model> Models;
|
||||
public readonly Dictionary<FGuid, Texture> Textures;
|
||||
|
|
@ -98,6 +98,11 @@ public class Options
|
|||
SelectedMorph = 0;
|
||||
}
|
||||
|
||||
public void SelectAnimation(int animation)
|
||||
{
|
||||
SelectedAnimation = animation;
|
||||
}
|
||||
|
||||
public void RemoveModel(FGuid guid)
|
||||
{
|
||||
if (!TryGetModel(guid, out var model)) return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user