This commit is contained in:
4sval 2023-02-21 23:21:14 +01:00
parent 591a2d2336
commit 4247dec633
4 changed files with 50 additions and 27 deletions

View File

@ -78,10 +78,10 @@ public partial class MainWindow
#if DEBUG #if DEBUG
await _threadWorkerView.Begin(cancellationToken => await _threadWorkerView.Begin(cancellationToken =>
_applicationView.CUE4Parse.Extract(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 => await _threadWorkerView.Begin(cancellationToken =>
_applicationView.CUE4Parse.Extract(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 #endif
} }

View File

@ -11,8 +11,9 @@ namespace FModel.Views.Snooper.Animations;
public class Animation : IDisposable public class Animation : IDisposable
{ {
public readonly UObject Export; private readonly UObject _export;
public readonly CAnimSet AnimSet; private readonly CAnimSet _animSet;
public readonly string Path; public readonly string Path;
public readonly string Name; public readonly string Name;
public readonly Sequence[] Sequences; public readonly Sequence[] Sequences;
@ -33,25 +34,25 @@ public class Animation : IDisposable
public Animation(UObject export) public Animation(UObject export)
{ {
Export = export; _export = export;
Path = Export.GetPathName(); Path = _export.GetPathName();
Name = Export.Name; Name = _export.Name;
Sequences = Array.Empty<Sequence>(); Sequences = Array.Empty<Sequence>();
AttachedModels = new List<FGuid>(); AttachedModels = new List<FGuid>();
} }
public Animation(UObject export, CAnimSet animSet) : this(export) public Animation(UObject export, CAnimSet animSet) : this(export)
{ {
AnimSet = animSet; _animSet = animSet;
TargetSkeleton = AnimSet.OriginalAnim.Name; TargetSkeleton = _animSet.OriginalAnim.Name;
Sequences = new Sequence[AnimSet.Sequences.Count]; Sequences = new Sequence[_animSet.Sequences.Count];
for (int i = 0; i < Sequences.Length; i++) 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; EndTime = Sequences[i].EndTime;
TotalElapsedTime += AnimSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame; TotalElapsedTime += _animSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame;
} }
if (Sequences.Length > 0) 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) 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 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); var p2 = new Vector2(timelineP0.X + EndTime * timeRatio.X - t, y + timeStep.Y - t);
ImGui.SetCursorScreenPos(p1); 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(); IsActive = ImGui.IsItemActive();
IsSelected = s.Renderer.Options.SelectedAnimation == i; IsSelected = s.Renderer.Options.SelectedAnimation == i;
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{ {
s.Renderer.Options.SelectedAnimation = i; s.Renderer.Options.SelectAnimation(i);
} }
SnimGui.Popup(() => SnimGui.Popup(() =>
{ {
s.Renderer.Options.SelectedAnimation = i; s.Renderer.Options.SelectAnimation(i);
if (ImGui.BeginMenu("Animate")) if (ImGui.BeginMenu("Animate"))
{ {
foreach ((var guid, var model) in s.Renderer.Options.Models) 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.ResetAnimatedData(true);
model.Skeleton.Animate(AnimSet, s.Renderer.AnimateWithRotationOnly); if (!selected) model.Skeleton.Animate(_animSet, s.Renderer.AnimateWithRotationOnly);
} }
} }
ImGui.EndMenu(); ImGui.EndMenu();
@ -125,7 +128,7 @@ public class Animation : IDisposable
if (ImGui.Selectable("Save")) if (ImGui.Selectable("Save"))
{ {
s.WindowShouldFreeze(true); 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); s.WindowShouldFreeze(false);
} }
ImGui.Separator(); ImGui.Separator();
@ -138,8 +141,10 @@ public class Animation : IDisposable
Sequences[j].DrawSequence(drawList, timelineP0.X, p2, timeStep, timeRatio, t); Sequences[j].DrawSequence(drawList, timelineP0.X, p2, timeStep, timeRatio, t);
} }
drawList.PushClipRect(treeP0 with { Y = p1.Y }, treeP1 with { Y = p2.Y }, true); ImGui.SetCursorScreenPos(treeP0 with { Y = p1.Y });
drawList.AddText(treeP0 with { Y = y + timeStep.Y / 4.0f }, 0xFFFFFFFF, Name); if (ImGui.Selectable(name, s.Renderer.Options.SelectedAnimation == i, ImGuiSelectableFlags.SpanAllColumns, new Vector2(p1.X - treeP0.X, timeStep.Y - t - t)))
drawList.PopClipRect(); {
s.Renderer.Options.SelectAnimation(i);
}
} }
} }

View File

@ -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++) for (int i = 0; i < animations.Count; i++)
{ {
var y = timelineP0.Y + _timeBarHeight + _timeStep.Y * i; var y = timelineP0.Y + _timeBarHeight + _timeStep.Y * i;
animations[i].ImGuiAnimation(s, saver, drawList, timelineP0, treeP0, treeP1, _timeStep, timeRatio, y, _thickness, 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); DrawSeparator(drawList, timelineP0, y + _timeStep.Y, animations[i].EndTime * timeRatio.X, ETrackerType.End);
} }
ImGui.PopStyleVar();
for (int i = 0; i < animations.Count; i++) 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) 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 Vector2 p1 = separatorType switch
{ {
@ -180,11 +188,10 @@ public class TimeTracker : IDisposable
{ {
ETrackerType.Frame => 0xFF6F6F6F, ETrackerType.Frame => 0xFF6F6F6F,
ETrackerType.End => 0xFF2E3E82, ETrackerType.End => 0xFF2E3E82,
ETrackerType.InBetween => 0x50FFFFFF, ETrackerType.InBetween => 0xA0FFFFFF,
_ => throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null) _ => throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null)
}; };
drawList.AddLine(p1, p2, color, 1f);
switch (separatorType) switch (separatorType)
{ {
case ETrackerType.Frame: case ETrackerType.Frame:
@ -193,13 +200,19 @@ public class TimeTracker : IDisposable
var xr = p1.X + size; var xr = p1.X + size;
var yb = origin.Y + _timeBarHeight - _timeHeight / 2.0f; 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.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); drawList.AddTriangleFilled(new Vector2(xl, yb), new Vector2(xr, yb), p1, color);
break; break;
case ETrackerType.End: 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); drawList.AddTriangleFilled(p1, p1 with { X = p1.X - size }, p1 with { Y = p1.Y + size }, color);
break; 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: default:
throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null); throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null);
} }

View File

@ -20,7 +20,7 @@ public class Options
public FGuid SelectedModel { get; private set; } public FGuid SelectedModel { get; private set; }
public int SelectedSection { get; private set; } public int SelectedSection { get; private set; }
public int SelectedMorph { 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, Model> Models;
public readonly Dictionary<FGuid, Texture> Textures; public readonly Dictionary<FGuid, Texture> Textures;
@ -98,6 +98,11 @@ public class Options
SelectedMorph = 0; SelectedMorph = 0;
} }
public void SelectAnimation(int animation)
{
SelectedAnimation = animation;
}
public void RemoveModel(FGuid guid) public void RemoveModel(FGuid guid)
{ {
if (!TryGetModel(guid, out var model)) return; if (!TryGetModel(guid, out var model)) return;