diff --git a/CUE4Parse b/CUE4Parse index cce937b3..d589f6ca 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit cce937b3a2cfb64af60d4a9b601c1cff2d430632 +Subproject commit d589f6ca0d8f8dbebfbff2a05e010c24cc55b68e diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index d4cb503d..01418ff1 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -360,7 +360,7 @@ namespace FModel.Settings set => SetProperty(ref _nextAudio, value); } - private EMeshFormat _meshExportFormat = EMeshFormat.ActorX; + private EMeshFormat _meshExportFormat = EMeshFormat.UEFormat; public EMeshFormat MeshExportFormat { get => _meshExportFormat; @@ -451,6 +451,13 @@ namespace FModel.Settings set => SetProperty(ref _previewSkeletalMeshes, value); } + private bool _previewAnimations = true; + public bool PreviewAnimations + { + get => _previewAnimations; + set => SetProperty(ref _previewAnimations, value); + } + private bool _previewMaterials = true; public bool PreviewMaterials { diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index f748edfe..3855b04a 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -77,13 +77,6 @@ public class CUE4ParseViewModel : ViewModel set => SetProperty(ref _modelIsOverwritingMaterial, value); } - private bool _modelIsWaitingAnimation; - public bool ModelIsWaitingAnimation - { - get => _modelIsWaitingAnimation; - set => SetProperty(ref _modelIsWaitingAnimation, value); - } - public bool IsSnooperOpen => _snooper is { Exists: true, IsVisible: true }; private Snooper _snooper; public Snooper SnooperViewer @@ -868,9 +861,10 @@ public class CUE4ParseViewModel : ViewModel SnooperViewer.Run(); return true; } - case UAnimSequenceBase when isNone && ModelIsWaitingAnimation: + case UAnimSequenceBase when isNone && UserSettings.Default.PreviewAnimations || SnooperViewer.Renderer.Options.ModelIsWaitingAnimation: { - SnooperViewer.Renderer.Animate(pointer.Object); + // animate all animations using their specified skeleton or when we explicitly asked for a loaded model to be animated (ignoring whether we wanted to preview animations) + SnooperViewer.Renderer.Animate(pointer.Object.Value); SnooperViewer.Run(); return true; } diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index 9c023e14..7ff12b81 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -2,6 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:FModel" + xmlns:c4pMeshes="clr-namespace:CUE4Parse_Conversion.Meshes;assembly=CUE4Parse-Conversion" xmlns:controls="clr-namespace:FModel.Views.Resources.Controls" xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" @@ -9,7 +10,7 @@ xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" IconVisibility="Collapsed" SizeToContent="Height" MinHeight="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.10'}" - Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.35'}"> + Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.45'}"> + + + + + @@ -347,8 +390,8 @@ - - + @@ -357,8 +400,8 @@ - - + @@ -367,52 +410,57 @@ - + - - + - - + - - + - - + + + + - - + - - + - - + - - + - + - - + @@ -421,8 +469,8 @@ - - + diff --git a/FModel/Views/Snooper/Animations/Skeleton.cs b/FModel/Views/Snooper/Animations/Skeleton.cs index ff01318d..2abc98c9 100644 --- a/FModel/Views/Snooper/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Animations/Skeleton.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Numerics; using CUE4Parse_Conversion.Animations.PSA; using CUE4Parse.UE4.Assets.Exports.Animation; +using CUE4Parse.UE4.Objects.Core.Misc; using FModel.Views.Snooper.Buffers; using FModel.Views.Snooper.Shading; using ImGuiNET; @@ -21,6 +22,7 @@ public class Skeleton : IDisposable private readonly List _breadcrumb; public string Name; + public FGuid Guid; public readonly Dictionary BonesByLoweredName; public readonly int BoneCount; diff --git a/FModel/Views/Snooper/Models/SkeletalModel.cs b/FModel/Views/Snooper/Models/SkeletalModel.cs index 17592492..8804bb93 100644 --- a/FModel/Views/Snooper/Models/SkeletalModel.cs +++ b/FModel/Views/Snooper/Models/SkeletalModel.cs @@ -36,6 +36,7 @@ public class SkeletalModel : UModel if (export.Skeleton.TryLoad(out USkeleton skeleton)) { Skeleton.Name = skeleton.Name; + Skeleton.Guid = skeleton.Guid; // Skeleton.Merge(skeleton.ReferenceSkeleton); sockets.AddRange(skeleton.Sockets); } @@ -116,15 +117,18 @@ public class SkeletalModel : UModel AddInstance(Transform.Identity); Box = box * Constants.SCALE_DOWN_RATIO; - Morphs = new List(); + Morphs = []; Skeleton = new Skeleton(export.ReferenceSkeleton); Skeleton.Name = export.Name; + Skeleton.Guid = export.Guid; for (int i = 0; i < export.Sockets.Length; i++) { if (export.Sockets[i].Load() is not { } socket) continue; Sockets.Add(new Socket(socket)); } + + IsVisible = true; } public override void Setup(Options options) diff --git a/FModel/Views/Snooper/Options.cs b/FModel/Views/Snooper/Options.cs index d4201392..e597259f 100644 --- a/FModel/Views/Snooper/Options.cs +++ b/FModel/Views/Snooper/Options.cs @@ -16,6 +16,7 @@ namespace FModel.Views.Snooper; public class Options { public FGuid SelectedModel { get; private set; } + public bool ModelIsWaitingAnimation { get; private set; } public int SelectedSection { get; private set; } public int SelectedMorph { get; private set; } public int SelectedAnimation{ get; private set; } @@ -238,7 +239,7 @@ public class Options public void AnimateMesh(bool value) { - Services.ApplicationService.ApplicationView.CUE4Parse.ModelIsWaitingAnimation = value; + ModelIsWaitingAnimation = value; } public void ResetModelsLightsAnimations() diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index f067336e..3a7b811a 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -119,7 +119,28 @@ public class Renderer : IDisposable Application.Current.Dispatcher.Invoke(() => model.Materials[section.MaterialIndex].Setup(Options, model.UvCount)); } - public void Animate(Lazy anim) => Animate(anim.Value, Options.SelectedModel); + public void Animate(UObject anim) + { + if (!Options.ModelIsWaitingAnimation) + { + if (anim is UAnimSequenceBase animBase) + { + /*if (Options.TryGetModel(out var selected) && + selected is SkeletalModel { IsVisible: true } skeletalModel && + skeletalModel.Skeleton.Guid == animBase.SkeletonGuid) + { + // do nothing, selected model has the correct skeleton for this animation + } + else */if (animBase.Skeleton.TryLoad(out USkeleton skeleton)) + { + LoadSkeleton(skeleton); + } + } + else return; // should never end here + } + + Animate(anim, Options.SelectedModel); + } private void Animate(UObject anim, FGuid guid) { if (anim is not UAnimSequenceBase animBase || !animBase.Skeleton.TryLoad(out USkeleton skeleton) || @@ -285,7 +306,7 @@ public class Renderer : IDisposable animation.TimeCalculation(Options.Tracker.ElapsedTime); foreach (var guid in animation.AttachedModels) { - if (Options.Models[guid] is not SkeletalModel skeletalModel) continue; + if (!Options.TryGetModel(guid, out var m) || m is not SkeletalModel skeletalModel) continue; skeletalModel.Skeleton.UpdateAnimationMatrices(animation, AnimateWithRotationOnly); } } diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index dc3165f5..5784e51c 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -44,7 +44,7 @@ public class Snooper : GameWindow { if (clear) { - Renderer.CameraOp.Speed = 0; + Renderer.CameraOp.Speed = 1f; Renderer.Save(); }