mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
new timeline part 1
This commit is contained in:
parent
e49216a844
commit
4eb220168e
|
|
@ -230,6 +230,12 @@
|
|||
<Resource Include="Resources\link_on.png" />
|
||||
<Resource Include="Resources\link_off.png" />
|
||||
<Resource Include="Resources\link_has.png" />
|
||||
<Resource Include="Resources\tl_play.png" />
|
||||
<Resource Include="Resources\tl_pause.png" />
|
||||
<Resource Include="Resources\tl_rewind.png" />
|
||||
<Resource Include="Resources\tl_forward.png" />
|
||||
<Resource Include="Resources\tl_previous.png" />
|
||||
<Resource Include="Resources\tl_next.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public partial class MainWindow
|
|||
|
||||
private async void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var newOrUpdated = UserSettings.Default.ShowChangelog;
|
||||
#if !DEBUG
|
||||
ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(UserSettings.Default.UpdateMode);
|
||||
#endif
|
||||
|
|
@ -67,7 +68,7 @@ public partial class MainWindow
|
|||
await _applicationView.CUE4Parse.InitInformation();
|
||||
#endif
|
||||
await _applicationView.CUE4Parse.InitMappings();
|
||||
await _applicationView.InitImGuiSettings();
|
||||
await _applicationView.InitImGuiSettings(newOrUpdated);
|
||||
await _applicationView.InitVgmStream();
|
||||
await _applicationView.InitOodle();
|
||||
|
||||
|
|
|
|||
BIN
FModel/Resources/tl_forward.png
Normal file
BIN
FModel/Resources/tl_forward.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 210 B |
BIN
FModel/Resources/tl_next.png
Normal file
BIN
FModel/Resources/tl_next.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 221 B |
BIN
FModel/Resources/tl_pause.png
Normal file
BIN
FModel/Resources/tl_pause.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 B |
BIN
FModel/Resources/tl_play.png
Normal file
BIN
FModel/Resources/tl_play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 183 B |
BIN
FModel/Resources/tl_previous.png
Normal file
BIN
FModel/Resources/tl_previous.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 219 B |
BIN
FModel/Resources/tl_rewind.png
Normal file
BIN
FModel/Resources/tl_rewind.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 B |
|
|
@ -1,14 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using CUE4Parse_Conversion.Animations;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.Utils;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace FModel.Views.Snooper.Animations;
|
||||
|
||||
public class Animation : IDisposable
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly Sequence[] Sequences;
|
||||
public readonly float StartTime; // Animation Start Time
|
||||
public readonly float EndTime; // Animation End Time
|
||||
public readonly float TotalElapsedTime; // Animation Max Time
|
||||
|
||||
|
|
@ -23,8 +27,9 @@ public class Animation : IDisposable
|
|||
AttachedModels = new List<FGuid>();
|
||||
}
|
||||
|
||||
public Animation(CAnimSet animSet) : this()
|
||||
public Animation(string name, CAnimSet animSet) : this()
|
||||
{
|
||||
Name = name;
|
||||
Sequences = new Sequence[animSet.Sequences.Count];
|
||||
for (int i = 0; i < Sequences.Length; i++)
|
||||
{
|
||||
|
|
@ -34,11 +39,11 @@ public class Animation : IDisposable
|
|||
EndTime = Sequences[i].EndTime;
|
||||
}
|
||||
|
||||
// if (Sequences.Length > 0)
|
||||
// Tracker.ElapsedTime = Sequences[0].StartTime;
|
||||
if (Sequences.Length > 0)
|
||||
StartTime = Sequences[0].StartTime;
|
||||
}
|
||||
|
||||
public Animation(CAnimSet animSet, params FGuid[] animatedModels) : this(animSet)
|
||||
public Animation(string name, CAnimSet animSet, params FGuid[] animatedModels) : this(name, animSet)
|
||||
{
|
||||
AttachedModels.AddRange(animatedModels);
|
||||
}
|
||||
|
|
@ -72,4 +77,16 @@ public class Animation : IDisposable
|
|||
{
|
||||
AttachedModels.Clear();
|
||||
}
|
||||
|
||||
public void ImGuiAnimation(ImDrawListPtr drawList, Vector2 timelineP0, Vector2 treeP0, Vector2 treeP1, Vector2 timeStep, Vector2 timeRatio, float y, float 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);
|
||||
|
||||
drawList.AddRectFilled(p1, p2, 0xFF175F17, 5.0f, ImDrawFlags.RoundCornersTop);
|
||||
|
||||
drawList.PushClipRect(treeP0, treeP1);
|
||||
drawList.AddText(treeP0 with { Y = y + timeStep.Y / 4.0f }, 0xFFFFFFFF, Name);
|
||||
drawList.PopClipRect();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,12 +177,7 @@ public class Skeleton : IDisposable
|
|||
|
||||
private void TrackSkeleton(CAnimSet anim)
|
||||
{
|
||||
// reset
|
||||
foreach (var boneIndices in BonesIndicesByLoweredName.Values)
|
||||
{
|
||||
boneIndices.TrackIndex = -1;
|
||||
boneIndices.ParentTrackIndex = -1;
|
||||
}
|
||||
ResetAnimatedData();
|
||||
|
||||
// tracked bones
|
||||
for (int trackIndex = 0; trackIndex < anim.TrackBonesInfo.Length; trackIndex++)
|
||||
|
|
@ -211,7 +206,7 @@ public class Skeleton : IDisposable
|
|||
continue;
|
||||
|
||||
#if DEBUG
|
||||
Log.Warning($"Bone Mismatch: {boneName} ({boneIndices.BoneIndex}) was not present in the anim's target skeleton");
|
||||
Log.Warning($"{Name} Bone Mismatch: {boneName} ({boneIndices.BoneIndex}) was not present in the anim's target skeleton");
|
||||
#endif
|
||||
|
||||
var loweredParentBoneName = boneIndices.LoweredParentBoneName;
|
||||
|
|
@ -224,13 +219,25 @@ public class Skeleton : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void ResetAnimatedData(bool full = false)
|
||||
{
|
||||
foreach (var boneIndices in BonesIndicesByLoweredName.Values)
|
||||
{
|
||||
boneIndices.TrackIndex = -1;
|
||||
boneIndices.ParentTrackIndex = -1;
|
||||
}
|
||||
|
||||
if (!full) return;
|
||||
_animatedBonesTransform = Array.Empty<Transform[][]>();
|
||||
_ssbo.UpdateRange(BoneCount, Matrix4x4.Identity);
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
_handle = GL.CreateProgram();
|
||||
|
||||
_ssbo = new BufferObject<Matrix4x4>(BoneCount, BufferTarget.ShaderStorageBuffer);
|
||||
for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++)
|
||||
_ssbo.Update(boneIndex, Matrix4x4.Identity);
|
||||
_ssbo.UpdateRange(BoneCount, Matrix4x4.Identity);
|
||||
}
|
||||
|
||||
public void UpdateAnimationMatrices(int currentSequence, int frameInSequence)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace FModel.Views.Snooper.Animations;
|
||||
|
|
@ -16,34 +17,37 @@ public enum ETrackerType
|
|||
public class TimeTracker : IDisposable
|
||||
{
|
||||
public bool IsPaused;
|
||||
public bool IsActive;
|
||||
public float ElapsedTime;
|
||||
public float MaxElapsedTime { get; private set; }
|
||||
|
||||
private float _timeHeight = 10.0f;
|
||||
private float _timeBarHeight => _timeHeight * 2.0f;
|
||||
public float MaxElapsedTime;
|
||||
|
||||
public TimeTracker()
|
||||
{
|
||||
Reset();
|
||||
SetMaxElapsedTime(0.01f);
|
||||
}
|
||||
|
||||
public void Update(float deltaSeconds)
|
||||
{
|
||||
if (IsPaused) return;
|
||||
if (IsPaused || IsActive) return;
|
||||
ElapsedTime += deltaSeconds;
|
||||
if (ElapsedTime >= MaxElapsedTime) Reset();
|
||||
if (ElapsedTime >= MaxElapsedTime) Reset(false);
|
||||
}
|
||||
|
||||
public void SetMaxElapsedTime(float maxElapsedTime)
|
||||
public void SafeSetElapsedTime(float elapsedTime)
|
||||
{
|
||||
ElapsedTime = Math.Clamp(elapsedTime, 0.0f, MaxElapsedTime);
|
||||
}
|
||||
|
||||
public void SafeSetMaxElapsedTime(float maxElapsedTime)
|
||||
{
|
||||
MaxElapsedTime = MathF.Max(maxElapsedTime, MaxElapsedTime);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
public void Reset(bool doMet = true)
|
||||
{
|
||||
IsPaused = false;
|
||||
ElapsedTime = 0.0f;
|
||||
if (doMet) MaxElapsedTime = 0.01f;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -51,52 +55,100 @@ public class TimeTracker : IDisposable
|
|||
Reset();
|
||||
}
|
||||
|
||||
public void ImGuiTimeline(ImFontPtr fontPtr, List<Animation> animations)
|
||||
private const float _margin = 5.0f;
|
||||
private const float _thickness = 2.0f;
|
||||
private const float _timeHeight = 10.0f;
|
||||
private float _timeBarHeight => _timeHeight * 2.0f;
|
||||
private readonly Vector2 _buttonSize = new (14.0f);
|
||||
private readonly string[] _icons = { "tl_forward", "tl_pause", "tl_rewind" };
|
||||
|
||||
public void ImGuiTimeline(Dictionary<string, Texture> icons, List<Animation> animations, Vector2 outliner, int activeAnimation, ImFontPtr fontPtr)
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
var canvasP0 = ImGui.GetCursorScreenPos();
|
||||
var treeP0 = ImGui.GetCursorScreenPos();
|
||||
var canvasSize = ImGui.GetContentRegionAvail();
|
||||
var canvasP1 = new Vector2(canvasP0.X + canvasSize.X, canvasP0.Y + canvasSize.Y);
|
||||
var timeRatio = canvasSize / MaxElapsedTime;
|
||||
var timelineP1 = new Vector2(treeP0.X + canvasSize.X, treeP0.Y + canvasSize.Y);
|
||||
|
||||
var treeP1 = timelineP1 with { X = treeP0.X + outliner.X };
|
||||
|
||||
var timelineP0 = treeP0 with { X = treeP1.X + _thickness };
|
||||
var timelineSize = timelineP1 - timelineP0;
|
||||
var timeRatio = timelineSize / MaxElapsedTime;
|
||||
var timeStep = timeRatio * MaxElapsedTime / timelineSize * 50.0f;
|
||||
timeStep.Y /= 2.0f;
|
||||
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
drawList.AddRectFilled(treeP0, treeP1, 0xFF1F1C1C);
|
||||
drawList.AddRectFilled(timelineP0, timelineP1 with { Y = timelineP0.Y + _timeBarHeight }, 0xFF141414);
|
||||
drawList.AddRectFilled(timelineP0 with { Y = timelineP0.Y + _timeBarHeight }, timelineP1, 0xFF242424);
|
||||
drawList.AddLine(new Vector2(treeP1.X, treeP0.Y), treeP1, 0xFF504545, _thickness);
|
||||
drawList.AddLine(treeP0 with { Y = timelineP0.Y + _timeBarHeight }, timelineP1 with { Y = timelineP0.Y + _timeBarHeight }, 0x50504545, _thickness);
|
||||
|
||||
ImGui.InvisibleButton("timeline_canvas", canvasP1 with { Y = _timeBarHeight }, ImGuiButtonFlags.MouseButtonLeft);
|
||||
IsPaused = ImGui.IsItemActive();
|
||||
if (IsPaused && ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||
// adding margin
|
||||
treeP0.X += _margin;
|
||||
treeP1.X -= _margin;
|
||||
|
||||
// control buttons
|
||||
for (int i = 0; i < _icons.Length; i++)
|
||||
{
|
||||
var mousePosCanvas = io.MousePos - canvasP0;
|
||||
ElapsedTime = Math.Clamp(mousePosCanvas.X / canvasSize.X * MaxElapsedTime, 0.01f, MaxElapsedTime);
|
||||
var x = _buttonSize.X * 2.0f * i;
|
||||
ImGui.SetCursorScreenPos(treeP0 with { X = treeP1.X - x - _buttonSize.X * 2.0f + _thickness });
|
||||
if (ImGui.ImageButton($"timeline_actions_{_icons[i]}", icons[_icons[i]].GetPointer(), _buttonSize))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
SafeSetElapsedTime(ElapsedTime + timeStep.X / timeRatio.X);
|
||||
break;
|
||||
case 1:
|
||||
IsPaused = !IsPaused;
|
||||
_icons[1] = IsPaused ? "tl_play" : "tl_pause";
|
||||
break;
|
||||
case 2:
|
||||
SafeSetElapsedTime(ElapsedTime - timeStep.X / timeRatio.X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetCursorScreenPos(timelineP0);
|
||||
ImGui.InvisibleButton("timeline_timetracker_canvas", timelineSize with { Y = _timeBarHeight }, ImGuiButtonFlags.MouseButtonLeft);
|
||||
IsActive = ImGui.IsItemActive();
|
||||
if (IsActive && ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||
{
|
||||
var mousePosCanvas = ImGui.GetIO().MousePos - timelineP0;
|
||||
SafeSetElapsedTime(mousePosCanvas.X / timelineSize.X * MaxElapsedTime);
|
||||
foreach (var animation in animations)
|
||||
{
|
||||
animation.TimeCalculation(ElapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
drawList.AddRectFilled(canvasP0, canvasP1 with { Y = canvasP0.Y + _timeBarHeight }, 0xFF181818);
|
||||
drawList.PushClipRect(canvasP0, canvasP1 with { Y = canvasP0.Y + _timeBarHeight }, true);
|
||||
{
|
||||
for (float x = 0; x < canvasSize.X; x += timeRatio.X * MaxElapsedTime / canvasSize.X * 50.0f)
|
||||
{ // draw time + time grid
|
||||
for (float x = 0; x < timelineSize.X; x += timeStep.X)
|
||||
{
|
||||
drawList.AddLine(new Vector2(canvasP0.X + x, canvasP0.Y + _timeHeight + 2.5f), canvasP1 with { X = canvasP0.X + x }, 0xA0FFFFFF);
|
||||
drawList.AddText(fontPtr, 14, new Vector2(canvasP0.X + x + 4, canvasP0.Y + 7.5f), 0x50FFFFFF, $"{x / timeRatio.X:F1}s");
|
||||
var cursor = timelineP0.X + x;
|
||||
drawList.AddLine(new Vector2(cursor, timelineP0.Y + _timeHeight + 2.5f), new Vector2(cursor, timelineP0.Y + _timeBarHeight), 0xA0FFFFFF);
|
||||
drawList.AddLine(new Vector2(cursor, timelineP0.Y + _timeBarHeight), timelineP1 with { X = cursor }, 0x28C8C8C8);
|
||||
drawList.AddText(fontPtr, 14, new Vector2(cursor + 4, timelineP0.Y + 7.5f), 0x50FFFFFF, $"{x / timeRatio.X:F1}s");
|
||||
}
|
||||
|
||||
for (float y = _timeBarHeight; y < timelineSize.Y; y += timeStep.Y)
|
||||
{
|
||||
drawList.AddLine(timelineP0 with { Y = timelineP0.Y + y }, timelineP1 with { Y = timelineP0.Y + y }, 0x28C8C8C8);
|
||||
}
|
||||
}
|
||||
drawList.PopClipRect();
|
||||
|
||||
foreach (var animation in animations)
|
||||
for (int i = 0; i < animations.Count; i++)
|
||||
{
|
||||
for (int i = 0; i < animation.Sequences.Length; i++)
|
||||
{
|
||||
animation.Sequences[i].DrawSequence(drawList, canvasP0.X, canvasP0.Y + _timeBarHeight, timeRatio, i, i == animation.CurrentSequence ? 0xFF0000FF : 0xFF175F17);
|
||||
}
|
||||
DrawSeparator(drawList, canvasP0, canvasP1, animation.EndTime * timeRatio.X, ETrackerType.End);
|
||||
var y = timelineP0.Y + _timeBarHeight + timeStep.Y * (i % 2);
|
||||
animations[i].ImGuiAnimation(drawList, timelineP0, treeP0, treeP1, timeStep, timeRatio, y, _thickness);
|
||||
DrawSeparator(drawList, timelineP0, y + timeStep.Y, animations[i].EndTime * timeRatio.X, ETrackerType.End);
|
||||
}
|
||||
|
||||
DrawSeparator(drawList, canvasP0, canvasP1, ElapsedTime * timeRatio.X, ETrackerType.Frame);
|
||||
DrawSeparator(drawList, timelineP0, timelineP1.Y, ElapsedTime * timeRatio.X, ETrackerType.Frame);
|
||||
}
|
||||
|
||||
private void DrawSeparator(ImDrawListPtr drawList, Vector2 origin, Vector2 destination, float time, ETrackerType separatorType)
|
||||
private void DrawSeparator(ImDrawListPtr drawList, Vector2 origin, float y, float time, ETrackerType separatorType)
|
||||
{
|
||||
const int size = 5;
|
||||
|
||||
|
|
@ -106,7 +158,7 @@ public class TimeTracker : IDisposable
|
|||
ETrackerType.End => origin with { X = origin.X + time },
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(separatorType), separatorType, null)
|
||||
};
|
||||
var p2 = new Vector2(p1.X, destination.Y);
|
||||
var p2 = p1 with { Y = y };
|
||||
|
||||
uint color = separatorType switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ public class BufferObject<TDataType> : IDisposable where TDataType : unmanaged
|
|||
GL.BufferData(bufferTarget, length * sizeof(TDataType), IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
||||
}
|
||||
|
||||
public void UpdateRange(int count, TDataType data)
|
||||
{
|
||||
Bind();
|
||||
for (int i = 0; i < count; i++) Update(i, data);
|
||||
Unbind();
|
||||
}
|
||||
|
||||
public unsafe void Update(int offset, TDataType data)
|
||||
{
|
||||
GL.BufferSubData(_bufferTarget, (IntPtr) (offset * sizeof(TDataType)), sizeof(TDataType), ref data);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ public class Model : IDisposable
|
|||
public Section[] Sections;
|
||||
public Material[] Materials;
|
||||
public bool TwoSided;
|
||||
public bool IsAnimatedProp;
|
||||
|
||||
public bool HasSkeleton => Skeleton != null;
|
||||
public readonly Skeleton Skeleton;
|
||||
|
|
@ -306,7 +307,11 @@ public class Model : IDisposable
|
|||
public void DetachModel(Model attachedTo, Socket socket)
|
||||
{
|
||||
socket.AttachedModels.Remove(Guid);
|
||||
SafeDetachModel(attachedTo);
|
||||
}
|
||||
|
||||
public void SafeDetachModel(Model attachedTo)
|
||||
{
|
||||
_attachedTo = string.Empty;
|
||||
attachedTo._attachedFor.Remove($"'{Name}'");
|
||||
Transforms[SelectedInstance].Relation = _previousMatrix;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ public class Options
|
|||
["link_on"] = new ("link_on"),
|
||||
["link_off"] = new ("link_off"),
|
||||
["link_has"] = new ("link_has"),
|
||||
["tl_play"] = new ("tl_play"),
|
||||
["tl_pause"] = new ("tl_pause"),
|
||||
["tl_rewind"] = new ("tl_rewind"),
|
||||
["tl_forward"] = new ("tl_forward"),
|
||||
["tl_previous"] = new ("tl_previous"),
|
||||
["tl_next"] = new ("tl_next"),
|
||||
};
|
||||
|
||||
_platform = UserSettings.Default.OverridedPlatform;
|
||||
|
|
@ -88,9 +94,50 @@ public class Options
|
|||
SelectedMorph = 0;
|
||||
}
|
||||
|
||||
public void SelectAnimation()
|
||||
public void RemoveModel(FGuid guid)
|
||||
{
|
||||
if (!TryGetModel(guid, out var model)) return;
|
||||
|
||||
DetachAndRemoveModels(model);
|
||||
model.Dispose();
|
||||
Models.Remove(guid);
|
||||
}
|
||||
|
||||
private void DetachAndRemoveModels(Model model)
|
||||
{
|
||||
foreach (var socket in model.Sockets)
|
||||
{
|
||||
foreach (var guid in socket.AttachedModels)
|
||||
{
|
||||
if (!TryGetModel(guid, out var attachedModel)) continue;
|
||||
|
||||
attachedModel.SafeDetachModel(model);
|
||||
RemoveModel(guid);
|
||||
}
|
||||
socket.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAnimation(Animation animation)
|
||||
{
|
||||
Animations.Add(animation);
|
||||
}
|
||||
|
||||
public void RemoveAnimations()
|
||||
{
|
||||
Tracker.Reset();
|
||||
foreach (var animation in Animations)
|
||||
{
|
||||
foreach (var guid in animation.AttachedModels)
|
||||
{
|
||||
if (!TryGetModel(guid, out var animatedModel)) continue;
|
||||
|
||||
animatedModel.Skeleton.ResetAnimatedData(true);
|
||||
DetachAndRemoveModels(animatedModel);
|
||||
}
|
||||
animation.Dispose();
|
||||
}
|
||||
Animations.Clear();
|
||||
}
|
||||
|
||||
public void SelectSection(int index)
|
||||
|
|
|
|||
|
|
@ -108,19 +108,19 @@ public class Renderer : IDisposable
|
|||
case UAnimSequence animSequence when animSequence.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animSequence);
|
||||
var animation = new Animation(animSet, model.Guid);
|
||||
var animation = new Animation(animSequence.Name, animSet, model.Guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.Animations.Add(animation);
|
||||
Options.AddAnimation(animation);
|
||||
break;
|
||||
}
|
||||
case UAnimMontage animMontage when animMontage.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animMontage);
|
||||
var animation = new Animation(animSet, model.Guid);
|
||||
var animation = new Animation(animMontage.Name, animSet, model.Guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.Animations.Add(animation);
|
||||
Options.AddAnimation(animation);
|
||||
|
||||
foreach (var notifyEvent in animMontage.Notifies)
|
||||
{
|
||||
|
|
@ -138,6 +138,7 @@ public class Renderer : IDisposable
|
|||
if (!Options.TryGetModel(guid, out var addedModel))
|
||||
continue;
|
||||
|
||||
addedModel.IsAnimatedProp = true;
|
||||
if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation"))
|
||||
Animate(skeletalMeshPropAnimation, addedModel);
|
||||
if (notifyClass.TryGetValue(out FName socketName, "SocketName"))
|
||||
|
|
@ -150,7 +151,7 @@ public class Renderer : IDisposable
|
|||
if (notifyClass.TryGetValue(out FVector scale, "Scale"))
|
||||
t.Scale = scale;
|
||||
|
||||
var s = new Socket("hello", socketName, t);
|
||||
var s = new Socket($"TL_{addedModel.Name}", socketName, t);
|
||||
model.Sockets.Add(s);
|
||||
addedModel.AttachModel(model, s);
|
||||
}
|
||||
|
|
@ -160,17 +161,17 @@ public class Renderer : IDisposable
|
|||
case UAnimComposite animComposite when animComposite.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animComposite);
|
||||
var animation = new Animation(animSet, model.Guid);
|
||||
var animation = new Animation(animComposite.Name, animSet, model.Guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.Animations.Add(animation);
|
||||
Options.AddAnimation(animation);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
Options.Tracker.SetMaxElapsedTime(maxElapsedTime);
|
||||
Options.Tracker.SafeSetMaxElapsedTime(maxElapsedTime);
|
||||
Options.AnimateMesh(false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public class SnimGui
|
|||
private readonly Save _saver = new ();
|
||||
private readonly string _renderer;
|
||||
private readonly string _version;
|
||||
|
||||
private Vector2 _outlinerSize;
|
||||
private bool _ti_open;
|
||||
private bool _viewportFocus;
|
||||
|
||||
|
|
@ -71,7 +73,8 @@ public class SnimGui
|
|||
DrawDockSpace(s.Size);
|
||||
|
||||
SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false);
|
||||
AnimationWindow("Timeline", s.Renderer, (icons, tracker, animations) => tracker.ImGuiTimeline(Controller.FontSemiBold, animations));
|
||||
AnimationWindow("Timeline", s.Renderer, (icons, tracker, animations) =>
|
||||
tracker.ImGuiTimeline(icons, animations, _outlinerSize, s.Renderer.Options.SelectedAnimation, Controller.FontSemiBold));
|
||||
|
||||
Window("World", () => DrawWorld(s), false);
|
||||
|
||||
|
|
@ -305,6 +308,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
Window("Outliner", () =>
|
||||
{
|
||||
_outlinerSize = ImGui.GetWindowSize();
|
||||
if (ImGui.BeginTable("Items", 4, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV | ImGuiTableFlags.NoSavedSettings, ImGui.GetContentRegionAvail()))
|
||||
{
|
||||
ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed, _tableWidth);
|
||||
|
|
@ -349,6 +353,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.BeginDisabled(!model.HasSkeleton);
|
||||
if (ImGui.Selectable("Animate"))
|
||||
{
|
||||
s.Renderer.Options.RemoveAnimations();
|
||||
s.Renderer.Options.AnimateMesh(true);
|
||||
s.WindowShouldClose(true, false);
|
||||
}
|
||||
|
|
@ -359,7 +364,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
s.Renderer.CameraOp.Teleport(instancePos, model.Box);
|
||||
}
|
||||
|
||||
if (ImGui.Selectable("Delete")) s.Renderer.Options.Models.Remove(guid);
|
||||
if (ImGui.Selectable("Delete")) s.Renderer.Options.RemoveModel(guid);
|
||||
if (ImGui.Selectable("Deselect")) s.Renderer.Options.SelectModel(Guid.Empty);
|
||||
ImGui.Separator();
|
||||
if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(model.Name);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user