mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
working mess
This commit is contained in:
parent
cdb52d096f
commit
d78df4a953
|
|
@ -1 +1 @@
|
|||
Subproject commit 2623c0baa171d05f6f6d3922a1a6ea3ae675fb25
|
||||
Subproject commit 4ac22af1ff164287f936730bec57261f997ce734
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using CUE4Parse_Conversion.Animations;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.Utils;
|
||||
using ImGuiNET;
|
||||
|
|
@ -10,6 +11,8 @@ namespace FModel.Views.Snooper.Animations;
|
|||
|
||||
public class Animation : IDisposable
|
||||
{
|
||||
public readonly UObject Export;
|
||||
public readonly string Path;
|
||||
public readonly string Name;
|
||||
public readonly Sequence[] Sequences;
|
||||
public readonly float StartTime; // Animation Start Time
|
||||
|
|
@ -25,15 +28,17 @@ public class Animation : IDisposable
|
|||
|
||||
public readonly List<FGuid> AttachedModels;
|
||||
|
||||
public Animation()
|
||||
public Animation(UObject export)
|
||||
{
|
||||
Export = export;
|
||||
Path = Export.GetPathName();
|
||||
Name = Export.Name;
|
||||
Sequences = Array.Empty<Sequence>();
|
||||
AttachedModels = new List<FGuid>();
|
||||
}
|
||||
|
||||
public Animation(string name, CAnimSet animSet) : this()
|
||||
public Animation(UObject export, CAnimSet animSet) : this(export)
|
||||
{
|
||||
Name = name;
|
||||
TargetSkeleton = animSet.OriginalAnim.Name;
|
||||
|
||||
Sequences = new Sequence[animSet.Sequences.Count];
|
||||
|
|
@ -49,7 +54,7 @@ public class Animation : IDisposable
|
|||
StartTime = Sequences[0].StartTime;
|
||||
}
|
||||
|
||||
public Animation(string name, CAnimSet animSet, params FGuid[] animatedModels) : this(name, animSet)
|
||||
public Animation(UObject export, CAnimSet animSet, params FGuid[] animatedModels) : this(export, animSet)
|
||||
{
|
||||
AttachedModels.AddRange(animatedModels);
|
||||
}
|
||||
|
|
@ -84,7 +89,7 @@ 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)
|
||||
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 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);
|
||||
|
|
@ -92,6 +97,23 @@ public class Animation : IDisposable
|
|||
ImGui.SetCursorScreenPos(p1);
|
||||
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;
|
||||
}
|
||||
SnimGui.Popup(() =>
|
||||
{
|
||||
s.Renderer.Options.SelectedAnimation = i;
|
||||
if (ImGui.Selectable("Save"))
|
||||
{
|
||||
s.WindowShouldFreeze(true);
|
||||
saver.Value = s.Renderer.Options.TrySave(Export, out saver.Label, out saver.Path);
|
||||
s.WindowShouldFreeze(false);
|
||||
}
|
||||
ImGui.Separator();
|
||||
if (ImGui.Selectable("Copy Path to Clipboard")) ImGui.SetClipboardText(Path);
|
||||
});
|
||||
|
||||
drawList.AddRectFilled(p1, p2, IsSelected ? 0xFF48B048 : 0xFF175F17, 5.0f, ImDrawFlags.RoundCornersTop);
|
||||
drawList.PushClipRect(p1, p2, true);
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ public class Skeleton : IDisposable
|
|||
do
|
||||
{
|
||||
var parentBoneIndices = BonesIndicesByLoweredName[loweredParentBoneName];
|
||||
if (parentBoneIndices.HasTrack || parentBoneIndices.HasParentTrack) boneIndices.ParentTrackIndex = parentBoneIndices.BoneIndex;
|
||||
if (parentBoneIndices.HasParentTrack || parentBoneIndices.IsRoot) boneIndices.ParentTrackIndex = parentBoneIndices.BoneIndex;
|
||||
else loweredParentBoneName = parentBoneIndices.LoweredParentBoneName;
|
||||
} while (!boneIndices.HasParentTrack);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class TimeTracker : IDisposable
|
|||
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, ref int activeAnimation, ImFontPtr fontPtr)
|
||||
public void ImGuiTimeline(Snooper s, Save saver, Dictionary<string, Texture> icons, List<Animation> animations, Vector2 outliner, ImFontPtr fontPtr)
|
||||
{
|
||||
var treeP0 = ImGui.GetCursorScreenPos();
|
||||
var canvasSize = ImGui.GetContentRegionAvail();
|
||||
|
|
@ -94,7 +94,7 @@ public class TimeTracker : IDisposable
|
|||
{
|
||||
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))
|
||||
if (ImGui.ImageButton($"timeline_actions_{_icons[i]}", icons[i == 1 ? IsPaused ? "tl_play" : "tl_pause" : _icons[i]].GetPointer(), _buttonSize))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
|
|
@ -103,7 +103,6 @@ public class TimeTracker : IDisposable
|
|||
break;
|
||||
case 1:
|
||||
IsPaused = !IsPaused;
|
||||
_icons[1] = IsPaused ? "tl_play" : "tl_pause";
|
||||
break;
|
||||
case 2:
|
||||
SafeSetElapsedTime(ElapsedTime - _timeStep.X / timeRatio.X);
|
||||
|
|
@ -112,6 +111,8 @@ public class TimeTracker : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
drawList.AddText(treeP0 with { Y = treeP0.Y + _thickness }, 0xA0FFFFFF, $"{ElapsedTime:F1}/{MaxElapsedTime:F1} seconds");
|
||||
|
||||
ImGui.SetCursorScreenPos(timelineP0);
|
||||
ImGui.InvisibleButton("timeline_timetracker_canvas", timelineSize with { Y = _timeBarHeight }, ImGuiButtonFlags.MouseButtonLeft);
|
||||
IsActive = ImGui.IsItemActive();
|
||||
|
|
@ -143,12 +144,7 @@ public class TimeTracker : IDisposable
|
|||
for (int i = 0; i < animations.Count; i++)
|
||||
{
|
||||
var y = timelineP0.Y + _timeBarHeight + _timeStep.Y * i;
|
||||
|
||||
animations[i].ImGuiAnimation(drawList, timelineP0, treeP0, treeP1, _timeStep, timeRatio, y, _thickness);
|
||||
animations[i].IsSelected = activeAnimation == i;
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
activeAnimation = 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse_Conversion;
|
||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
|
|
@ -14,7 +12,6 @@ using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
|||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using FModel.Extensions;
|
||||
using FModel.Settings;
|
||||
using FModel.Views.Snooper.Animations;
|
||||
using FModel.Views.Snooper.Buffers;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
|
|
@ -68,7 +65,7 @@ public class Model : IDisposable
|
|||
public bool HasVertexColors => _vertexAttributes[(int) EAttribute.Colors].Enabled;
|
||||
private const int _faceSize = 3;
|
||||
|
||||
private readonly UObject _export;
|
||||
public readonly UObject Export;
|
||||
public readonly string Path;
|
||||
public readonly string Name;
|
||||
public readonly string Type;
|
||||
|
|
@ -110,8 +107,8 @@ public class Model : IDisposable
|
|||
|
||||
protected Model(UObject export)
|
||||
{
|
||||
_export = export;
|
||||
Path = _export.GetPathName();
|
||||
Export = export;
|
||||
Path = Export.GetPathName();
|
||||
Name = Path.SubstringAfterLast('/').SubstringBefore('.');
|
||||
Type = export.ExportType;
|
||||
UvCount = 1;
|
||||
|
|
@ -433,22 +430,6 @@ public class Model : IDisposable
|
|||
if (TwoSided) GL.Enable(EnableCap.CullFace);
|
||||
}
|
||||
|
||||
public bool TrySave(out string label, out string savedFilePath)
|
||||
{
|
||||
var exportOptions = new ExporterOptions
|
||||
{
|
||||
LodFormat = UserSettings.Default.LodExportFormat,
|
||||
MeshFormat = UserSettings.Default.MeshExportFormat,
|
||||
MaterialFormat = UserSettings.Default.MaterialExportFormat,
|
||||
TextureFormat = UserSettings.Default.TextureExportFormat,
|
||||
SocketFormat = UserSettings.Default.SocketExportFormat,
|
||||
Platform = UserSettings.Default.OverridedPlatform,
|
||||
ExportMorphTargets = UserSettings.Default.SaveMorphTargets
|
||||
};
|
||||
var toSave = new Exporter(_export, exportOptions);
|
||||
return toSave.TryWriteToDir(new DirectoryInfo(UserSettings.Default.ModelDirectory), out label, out savedFilePath);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ebo.Dispose();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CUE4Parse_Conversion;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Settings;
|
||||
|
|
@ -17,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;
|
||||
public int SelectedAnimation{ get; set; }
|
||||
|
||||
public readonly Dictionary<FGuid, Model> Models;
|
||||
public readonly Dictionary<FGuid, Texture> Textures;
|
||||
|
|
@ -136,6 +139,8 @@ public class Options
|
|||
public void RemoveAnimations()
|
||||
{
|
||||
Tracker.Reset();
|
||||
SelectedAnimation = 0;
|
||||
|
||||
foreach (var animation in Animations)
|
||||
{
|
||||
foreach (var guid in animation.AttachedModels)
|
||||
|
|
@ -147,6 +152,10 @@ public class Options
|
|||
}
|
||||
animation.Dispose();
|
||||
}
|
||||
foreach (var kvp in Models.ToList().Where(kvp => kvp.Value.IsAnimatedProp))
|
||||
{
|
||||
RemoveModel(kvp.Key);
|
||||
}
|
||||
Animations.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +215,22 @@ public class Options
|
|||
Services.ApplicationService.ApplicationView.CUE4Parse.ModelIsWaitingAnimation = value;
|
||||
}
|
||||
|
||||
public bool TrySave(UObject export, out string label, out string savedFilePath)
|
||||
{
|
||||
var exportOptions = new ExporterOptions
|
||||
{
|
||||
LodFormat = UserSettings.Default.LodExportFormat,
|
||||
MeshFormat = UserSettings.Default.MeshExportFormat,
|
||||
MaterialFormat = UserSettings.Default.MaterialExportFormat,
|
||||
TextureFormat = UserSettings.Default.TextureExportFormat,
|
||||
SocketFormat = UserSettings.Default.SocketExportFormat,
|
||||
Platform = UserSettings.Default.OverridedPlatform,
|
||||
ExportMorphTargets = UserSettings.Default.SaveMorphTargets
|
||||
};
|
||||
var toSave = new Exporter(export, exportOptions);
|
||||
return toSave.TryWriteToDir(new DirectoryInfo(UserSettings.Default.ModelDirectory), out label, out savedFilePath);
|
||||
}
|
||||
|
||||
public void ResetModelsLightsAnimations()
|
||||
{
|
||||
foreach (var model in Models.Values)
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public class Renderer : IDisposable
|
|||
case UAnimSequence animSequence when animSequence.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animSequence);
|
||||
var animation = new Animation(animSequence.Name, animSet, guid);
|
||||
var animation = new Animation(animSequence, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -113,7 +113,7 @@ public class Renderer : IDisposable
|
|||
case UAnimMontage animMontage when animMontage.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animMontage);
|
||||
var animation = new Animation(animMontage.Name, animSet, guid);
|
||||
var animation = new Animation(animMontage, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -180,7 +180,7 @@ public class Renderer : IDisposable
|
|||
case UAnimComposite animComposite when animComposite.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animComposite);
|
||||
var animation = new Animation(animComposite.Name, animSet, guid);
|
||||
var animation = new Animation(animComposite, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -190,6 +190,7 @@ public class Renderer : IDisposable
|
|||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
Options.Tracker.IsPaused = false;
|
||||
Options.Tracker.SafeSetMaxElapsedTime(maxElapsedTime);
|
||||
Options.AnimateMesh(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class SnimGui
|
|||
|
||||
SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false);
|
||||
AnimationWindow("Timeline", s.Renderer, (icons, tracker, animations) =>
|
||||
tracker.ImGuiTimeline(icons, animations, _outlinerSize, ref s.Renderer.Options.SelectedAnimation, Controller.FontSemiBold));
|
||||
tracker.ImGuiTimeline(s, _saver, icons, animations, _outlinerSize, Controller.FontSemiBold));
|
||||
|
||||
Window("World", () => DrawWorld(s), false);
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ public class SnimGui
|
|||
{
|
||||
foreach (var model in s.Renderer.Options.Models.Values)
|
||||
{
|
||||
b |= model.TrySave(out _, out _);
|
||||
b |= s.Renderer.Options.TrySave(model.Export, out _, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
if (ImGui.Selectable("Save"))
|
||||
{
|
||||
s.WindowShouldFreeze(true);
|
||||
_saver.Value = model.TrySave(out _saver.Label, out _saver.Path);
|
||||
_saver.Value = s.Renderer.Options.TrySave(model.Export, out _saver.Label, out _saver.Path);
|
||||
s.WindowShouldFreeze(false);
|
||||
}
|
||||
ImGui.BeginDisabled(!model.HasSkeleton);
|
||||
|
|
@ -378,34 +378,34 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
i++;
|
||||
}
|
||||
|
||||
Modal("Saved", _saver.Value, () =>
|
||||
{
|
||||
ImGui.TextWrapped($"Successfully saved {_saver.Label}");
|
||||
ImGui.Separator();
|
||||
|
||||
var size = new Vector2(120, 0);
|
||||
if (ImGui.Button("OK", size))
|
||||
{
|
||||
_saver.Reset();
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui.SetItemDefaultFocus();
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button("Show In Explorer", size))
|
||||
{
|
||||
Process.Start("explorer.exe", $"/select, \"{_saver.Path.Replace('/', '\\')}\"");
|
||||
|
||||
_saver.Reset();
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
});
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
});
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
Modal("Saved", _saver.Value, () =>
|
||||
{
|
||||
ImGui.TextWrapped($"Successfully saved {_saver.Label}");
|
||||
ImGui.Separator();
|
||||
|
||||
var size = new Vector2(120, 0);
|
||||
if (ImGui.Button("OK", size))
|
||||
{
|
||||
_saver.Reset();
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui.SetItemDefaultFocus();
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button("Show In Explorer", size))
|
||||
{
|
||||
Process.Start("explorer.exe", $"/select, \"{_saver.Path.Replace('/', '\\')}\"");
|
||||
|
||||
_saver.Reset();
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawSockets(Snooper s)
|
||||
|
|
@ -716,7 +716,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
private void Popup(Action content)
|
||||
public static void Popup(Action content)
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(4f));
|
||||
if (ImGui.BeginPopupContextItem())
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ public class Snooper : GameWindow
|
|||
|
||||
Renderer.CameraOp.Modify(KeyboardState, (float) e.Time);
|
||||
|
||||
if (KeyboardState.IsKeyPressed(Keys.Space))
|
||||
Renderer.Options.Tracker.IsPaused = !Renderer.Options.Tracker.IsPaused;
|
||||
if (KeyboardState.IsKeyPressed(Keys.Delete))
|
||||
Renderer.Options.RemoveModel(Renderer.Options.SelectedModel);
|
||||
if (KeyboardState.IsKeyPressed(Keys.H))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user