diff --git a/FModel/Views/Snooper/Animations/Skeleton.cs b/FModel/Views/Snooper/Animations/Skeleton.cs index 5d328c4f..5489ca04 100644 --- a/FModel/Views/Snooper/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Animations/Skeleton.cs @@ -188,10 +188,10 @@ public class Skeleton : IDisposable boneIndices.TrackIndex = trackIndex; var parentTrackIndex = info.ParentIndex; - if (parentTrackIndex < 0) continue; do { + if (parentTrackIndex < 0) break; info = anim.TrackBonesInfo[parentTrackIndex]; if (BonesIndicesByLoweredName.TryGetValue(info.Name.Text.ToLower(), out var parentBoneIndices) && parentBoneIndices.HasTrack) boneIndices.ParentTrackIndex = parentBoneIndices.BoneIndex; diff --git a/FModel/Views/Snooper/Models/Model.cs b/FModel/Views/Snooper/Models/Model.cs index 63d6ad2a..907e6bab 100644 --- a/FModel/Views/Snooper/Models/Model.cs +++ b/FModel/Views/Snooper/Models/Model.cs @@ -137,7 +137,7 @@ public class Model : IDisposable } public Model(USkeletalMesh export, FGuid guid, CSkeletalMesh skeletalMesh) : this(export, guid, skeletalMesh, Transform.Identity) {} - private Model(USkeletalMesh export, FGuid guid, CSkeletalMesh skeletalMesh, Transform transform) : this(export, guid, export.Materials, skeletalMesh.LODs, transform) + public Model(USkeletalMesh export, FGuid guid, CSkeletalMesh skeletalMesh, Transform transform) : this(export, guid, export.Materials, skeletalMesh.LODs, transform) { Box = skeletalMesh.BoundingBox * Constants.SCALE_DOWN_RATIO; Skeleton = new Skeleton(export.ReferenceSkeleton); @@ -275,17 +275,14 @@ public class Model : IDisposable } private Matrix4x4 UpdateMatrices() { + _matrixVbo.Bind(); for (int instance = 0; instance < TransformsCount; instance++) { var matrix = Transforms[instance].Matrix; - if (matrix == _previousMatrix) return matrix; - - _matrixVbo.Bind(); _matrixVbo.Update(instance, matrix); - _matrixVbo.Unbind(); - _previousMatrix = matrix; } + _matrixVbo.Unbind(); return _previousMatrix; } diff --git a/FModel/Views/Snooper/Models/Socket.cs b/FModel/Views/Snooper/Models/Socket.cs index e0ede3e5..8c37b422 100644 --- a/FModel/Views/Snooper/Models/Socket.cs +++ b/FModel/Views/Snooper/Models/Socket.cs @@ -18,6 +18,7 @@ public class Socket : IDisposable public readonly string Name; public readonly FName BoneName; public readonly Transform Transform; + public readonly bool IsVirtual; public readonly List AttachedModels; @@ -27,11 +28,12 @@ public class Socket : IDisposable AttachedModels = new List(); } - public Socket(string name, FName boneName, Transform transform) : this() + public Socket(string name, FName boneName, Transform transform, bool isVirtual) : this() { Name = name; BoneName = boneName; Transform = transform; + IsVirtual = isVirtual; } public Socket(UStaticMeshSocket socket) : this() diff --git a/FModel/Views/Snooper/Options.cs b/FModel/Views/Snooper/Options.cs index 3083eda2..3b7fa599 100644 --- a/FModel/Views/Snooper/Options.cs +++ b/FModel/Views/Snooper/Options.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using System.Linq; using CUE4Parse_Conversion.Textures; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Misc; @@ -105,7 +106,7 @@ public class Options private void DetachAndRemoveModels(Model model) { - foreach (var socket in model.Sockets) + foreach (var socket in model.Sockets.ToList()) { foreach (var info in socket.AttachedModels) { @@ -114,7 +115,12 @@ public class Options attachedModel.SafeDetachModel(model); RemoveModel(info.Guid); } - socket.Dispose(); + + if (socket.IsVirtual) + { + socket.Dispose(); + model.Sockets.Remove(socket); + } } } diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 2bc9f87a..e07ec006 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -128,22 +128,46 @@ public class Renderer : IDisposable !notifyClass.TryGetValue(out FPackageIndex meshProp, "SkeletalMeshProp", "StaticMeshProp", "Mesh") || !meshProp.TryLoad(out UObject export)) continue; - FGuid guid = export switch + var t = Transform.Identity; + if (notifyClass.TryGetValue(out FTransform offset, "Offset")) { - UStaticMesh st => LoadStaticMesh(st, false), - USkeletalMesh sk => LoadSkeletalMesh(sk, false), - _ => throw new ArgumentException() - }; + t.Rotation = offset.Rotation; + t.Position = offset.Translation * Constants.SCALE_DOWN_RATIO; + t.Scale = offset.Scale3D; + } + + FGuid guid; + switch (export) + { + case UStaticMesh st: + { + guid = st.LightingGuid; + if (Options.TryGetModel(guid, out var instancedModel)) + instancedModel.AddInstance(t); + else if (st.TryConvert(out var mesh)) + Options.Models[guid] = new Model(st, guid, mesh, t); + break; + } + case USkeletalMesh sk: + { + guid = new FGuid((uint) sk.GetFullName().GetHashCode()); + if (!Options.Models.ContainsKey(guid) && sk.TryConvert(out var mesh)) + Options.Models[guid] = new Model(sk, guid, mesh, t); + break; + } + default: + throw new ArgumentException(); + } if (!Options.TryGetModel(guid, out var addedModel)) continue; addedModel.IsAnimatedProp = true; - if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation")) + if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation", "Animation")) Animate(skeletalMeshPropAnimation, addedModel); if (notifyClass.TryGetValue(out FName socketName, "SocketName")) { - var t = Transform.Identity; + t = Transform.Identity; if (notifyClass.TryGetValue(out FVector location, "LocationOffset", "Location")) t.Position = location * Constants.SCALE_DOWN_RATIO; if (notifyClass.TryGetValue(out FRotator rotation, "RotationOffset", "Rotation")) @@ -151,7 +175,7 @@ public class Renderer : IDisposable if (notifyClass.TryGetValue(out FVector scale, "Scale")) t.Scale = scale; - var s = new Socket($"TL_{addedModel.Name}", socketName, t); + var s = new Socket($"TL_{addedModel.Name}", socketName, t, true); model.Sockets.Add(s); addedModel.AttachModel(model, s); } @@ -243,40 +267,32 @@ public class Renderer : IDisposable Picking.Render(viewMatrix, projMatrix, Options.Models); } - private FGuid LoadStaticMesh(UStaticMesh original, bool select = true) + private void LoadStaticMesh(UStaticMesh original) { var guid = original.LightingGuid; if (Options.TryGetModel(guid, out var model)) { model.AddInstance(Transform.Identity); - if (select) Application.Current.Dispatcher.Invoke(() => model.SetupInstances()); - return guid; + Application.Current.Dispatcher.Invoke(() => model.SetupInstances()); + return; } if (!original.TryConvert(out var mesh)) - return guid; + return; Options.Models[guid] = new Model(original, guid, mesh); - if (select) - { - Options.SelectModel(guid); - SetupCamera(Options.Models[guid].Box); - } - return guid; + Options.SelectModel(guid); + SetupCamera(Options.Models[guid].Box); } - private FGuid LoadSkeletalMesh(USkeletalMesh original, bool select = true) + private void LoadSkeletalMesh(USkeletalMesh original) { var guid = new FGuid((uint) original.GetFullName().GetHashCode()); - if (Options.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return guid; + if (Options.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return; Options.Models[guid] = new Model(original, guid, mesh); - if (select) - { - Options.SelectModel(guid); - SetupCamera(Options.Models[guid].Box); - } - return guid; + Options.SelectModel(guid); + SetupCamera(Options.Models[guid].Box); } private void LoadMaterialInstance(UMaterialInstance original) diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index a182e9fe..5910e886 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -155,7 +155,7 @@ public class Snooper : GameWindow Renderer.CameraOp.Modify(KeyboardState, (float) e.Time); if (KeyboardState.IsKeyPressed(Keys.Delete)) - Renderer.Options.Models.Remove(Renderer.Options.SelectedModel); + Renderer.Options.RemoveModel(Renderer.Options.SelectedModel); if (KeyboardState.IsKeyPressed(Keys.H)) WindowShouldClose(true, false); if (KeyboardState.IsKeyPressed(Keys.Escape))