working mess

This commit is contained in:
4sval 2023-02-21 12:38:26 +01:00
parent cdb52d096f
commit d78df4a953
9 changed files with 97 additions and 70 deletions

@ -1 +1 @@
Subproject commit 2623c0baa171d05f6f6d3922a1a6ea3ae675fb25
Subproject commit 4ac22af1ff164287f936730bec57261f997ce734

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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)

View File

@ -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);
}

View File

@ -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())

View File

@ -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))