diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index 55e921b5..8306f23c 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -159,6 +159,15 @@ + + + + + + + + + diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index d7eb2fba..ea7304c5 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -635,6 +635,13 @@ namespace FModel.Settings set => SetProperty(ref _showGrid, value); } + private bool _previewWorlds = true; + public bool PreviewWorlds + { + get => _previewWorlds; + set => SetProperty(ref _previewWorlds, value); + } + private bool _previewStaticMeshes = true; public bool PreviewStaticMeshes { diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 46dffc96..4f425308 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -94,6 +94,8 @@ public class CUE4ParseViewModel : ViewModel Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenHeight * .85)), NumberOfSamples = Constants.SAMPLES_COUNT, WindowBorder = WindowBorder.Resizable, + Flags = ContextFlags.ForwardCompatible, + Profile = ContextProfile.Core, StartVisible = false, StartFocused = false, Title = "3D Viewer" @@ -779,7 +781,7 @@ public class CUE4ParseViewModel : ViewModel SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Directory, TabControl.SelectedTab.Header.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data); return false; } - case UWorld: + case UWorld when UserSettings.Default.PreviewWorlds: case UStaticMesh when UserSettings.Default.PreviewStaticMeshes: case USkeletalMesh when UserSettings.Default.PreviewSkeletalMeshes: case UMaterialInstance when UserSettings.Default.PreviewMaterials && !ModelIsOverwritingMaterial && @@ -787,8 +789,8 @@ public class CUE4ParseViewModel : ViewModel export.Owner.Name.EndsWith($"/RenderSwitch_Materials/{export.Name}", StringComparison.OrdinalIgnoreCase) || export.Owner.Name.EndsWith($"/MI_BPTile/{export.Name}", StringComparison.OrdinalIgnoreCase))): { - SnooperViewer.LoadExport(cancellationToken, export); - SnooperViewer.Run(); + if (SnooperViewer.TryLoadExport(cancellationToken, export)) + SnooperViewer.Run(); return true; } case UMaterialInstance m when ModelIsOverwritingMaterial: diff --git a/FModel/ViewModels/Commands/MenuCommand.cs b/FModel/ViewModels/Commands/MenuCommand.cs index 4fd88eac..b4263886 100644 --- a/FModel/ViewModels/Commands/MenuCommand.cs +++ b/FModel/ViewModels/Commands/MenuCommand.cs @@ -35,6 +35,9 @@ public class MenuCommand : ViewModelCommand contextViewModel.CUE4Parse.TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("json"); contextViewModel.CUE4Parse.TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(contextViewModel.CUE4Parse.GameDirectory.DirectoryFiles, Formatting.Indented), false); break; + case "Views_3dViewer": + contextViewModel.CUE4Parse.SnooperViewer.Run(); + break; case "Views_AudioPlayer": Helper.OpenWindow("Audio Player", () => new AudioPlayer().Show()); break; @@ -109,4 +112,4 @@ public class MenuCommand : ViewModelCommand cancellationToken.ThrowIfCancellationRequested(); foreach (var f in parent.Folders) LoopFolders(cancellationToken, f, isExpanded); } -} \ No newline at end of file +} diff --git a/FModel/ViewModels/GameSelectorViewModel.cs b/FModel/ViewModels/GameSelectorViewModel.cs index d765630d..43b39e23 100644 --- a/FModel/ViewModels/GameSelectorViewModel.cs +++ b/FModel/ViewModels/GameSelectorViewModel.cs @@ -337,22 +337,14 @@ public class GameSelectorViewModel : ViewModel dic[key] = val; } - if (dic.Keys.Count <= 0) return null; - AppInfo appInfo = new(); - var appId = dic["appid"]; - var name = dic["name"]; - var installDir = dic["installDir"]; + if (!dic.TryGetValue("appid", out var appId) || + !dic.TryGetValue("name", out var name) || + !dic.TryGetValue("installDir", out var installDir)) return null; var path = Path.GetDirectoryName(appMetaFile); var libGameRoot = Path.Combine(path, "common", installDir); - if (!Directory.Exists(libGameRoot)) return null; - - appInfo.Id = appId; - appInfo.Name = name; - appInfo.GameRoot = libGameRoot; - - return appInfo; + return !Directory.Exists(libGameRoot) ? null : new AppInfo { Id = appId, Name = name, GameRoot = libGameRoot }; } private static List GetSteamLibs() diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index 3dd838e2..a08001b4 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -64,7 +64,7 @@ M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z - M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm8 7h-5v12c0 .55-.45 1-1 1s-1-.45-1-1v-5h-2v5c0 .55-.45 1-1 1s-1-.45-1-1V9H4c-.55 0-1-.45-1-1s.45-1 1-1h16c.55 0 1 .45 1 1s-.45 1-1 1z + M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z M11 9h2v2h-2V9zm-2 2h2v2H9v-2zm4 0h2v2h-2v-2zm2-2h2v2h-2V9zM7 9h2v2H7V9zm12-6H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 18H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm2-7h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v5z M12 4C7 4 2.73 7.11 1 11.5 2.73 15.89 7 19 12 19s9.27-3.11 11-7.5C21.27 7.11 17 4 12 4zm0 12.5c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z M12 6.5c2.76 0 5 2.24 5 5 0 .51-.1 1-.24 1.46l3.06 3.06c1.39-1.23 2.49-2.77 3.18-4.53C21.27 7.11 17 4 12 4c-1.27 0-2.49.2-3.64.57l2.17 2.17c.47-.14.96-.24 1.47-.24zM2.71 3.16c-.39.39-.39 1.02 0 1.41l1.97 1.97C3.06 7.83 1.77 9.53 1 11.5 2.73 15.89 7 19 12 19c1.52 0 2.97-.3 4.31-.82l2.72 2.72c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L4.13 3.16c-.39-.39-1.03-.39-1.42 0zM12 16.5c-2.76 0-5-2.24-5-5 0-.77.18-1.5.49-2.14l1.57 1.57c-.03.18-.06.37-.06.57 0 1.66 1.34 3 3 3 .2 0 .38-.03.57-.07L14.14 16c-.65.32-1.37.5-2.14.5zm2.97-5.33c-.15-1.4-1.25-2.49-2.64-2.64l2.64 2.64z diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index b8e1cc48..dd224932 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -307,6 +307,7 @@ + @@ -371,25 +372,30 @@ IsChecked="{Binding SaveMaterials, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/> - + + + + - - + - - + - + - - + diff --git a/FModel/Views/Snooper/Camera.cs b/FModel/Views/Snooper/Camera.cs index a6ec5016..0afd2de4 100644 --- a/FModel/Views/Snooper/Camera.cs +++ b/FModel/Views/Snooper/Camera.cs @@ -18,6 +18,14 @@ public class Camera public float Far = 100f; public float AspectRatio = 16f / 9f; + public Camera() + { + Position = new Vector3(0, 1, 1); + Direction = Vector3.Zero; + + InitDirection(); + } + public Camera(Vector3 position, Vector3 direction, float near, float far, float speed) { Position = position; @@ -26,6 +34,11 @@ public class Camera Far = far; Speed = speed; + InitDirection(); + } + + private void InitDirection() + { // trigonometric math to calculate the cam's yaw/pitch based on position and direction to look var yaw = MathF.Atan((-Position.X - Direction.X) / (Position.Z - Direction.Z)); var pitch = MathF.Atan((Position.Y - Direction.Y) / (Position.Z - Direction.Z)); diff --git a/FModel/Views/Snooper/FramebufferObject.cs b/FModel/Views/Snooper/FramebufferObject.cs index 5d06f5b2..1d239ec2 100644 --- a/FModel/Views/Snooper/FramebufferObject.cs +++ b/FModel/Views/Snooper/FramebufferObject.cs @@ -115,11 +115,11 @@ public class FramebufferObject : IDisposable public void Dispose() { - _vao.Dispose(); - _shader.Dispose(); - _framebufferTexture.Dispose(); - _postProcessingTexture.Dispose(); - _renderbuffer.Dispose(); + _vao?.Dispose(); + _shader?.Dispose(); + _framebufferTexture?.Dispose(); + _postProcessingTexture?.Dispose(); + _renderbuffer?.Dispose(); GL.DeleteFramebuffer(_framebufferHandle); GL.DeleteFramebuffer(_postProcessingHandle); } diff --git a/FModel/Views/Snooper/Grid.cs b/FModel/Views/Snooper/Grid.cs index e839a239..0190c7bf 100644 --- a/FModel/Views/Snooper/Grid.cs +++ b/FModel/Views/Snooper/Grid.cs @@ -57,10 +57,10 @@ public class Grid : IDisposable public void Dispose() { - _ebo.Dispose(); - _vbo.Dispose(); - _vao.Dispose(); - _shader.Dispose(); + _ebo?.Dispose(); + _vbo?.Dispose(); + _vao?.Dispose(); + _shader?.Dispose(); GL.DeleteProgram(_handle); } } diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index c69949c7..5c66ca55 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -296,16 +296,19 @@ public class Renderer : IDisposable LoadWorld(cancellationToken, w, transform); } - public void Dispose() + public void Save() { UserSettings.Default.ShowSkybox = ShowSkybox; UserSettings.Default.ShowGrid = ShowGrid; + } + public void Dispose() + { _skybox?.Dispose(); _grid?.Dispose(); - _shader.Dispose(); - _outline.Dispose(); - Picking.Dispose(); - Cache.Dispose(); + _shader?.Dispose(); + _outline?.Dispose(); + Picking?.Dispose(); + Cache?.Dispose(); } } diff --git a/FModel/Views/Snooper/Skybox.cs b/FModel/Views/Snooper/Skybox.cs index 89529921..424c593b 100644 --- a/FModel/Views/Snooper/Skybox.cs +++ b/FModel/Views/Snooper/Skybox.cs @@ -103,10 +103,10 @@ public class Skybox : IDisposable public void Dispose() { - _ebo.Dispose(); - _vbo.Dispose(); - _vao.Dispose(); - _shader.Dispose(); + _ebo?.Dispose(); + _vbo?.Dispose(); + _vao?.Dispose(); + _shader?.Dispose(); GL.DeleteProgram(_handle); } } diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 77dcbf88..b32eafa1 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -108,7 +108,7 @@ public class SnimGui if (ImGui.BeginMenu("Window")) { - ImGui.MenuItem("Append", "R"); + ImGui.MenuItem("Hide", "H"); ImGui.MenuItem("Close", "ESC"); ImGui.EndMenu(); } @@ -449,7 +449,7 @@ public class SnimGui ImGui.DragInt("", ref material.SelectedChannel, 1, 0, model.NumTexCoords - 1, "UV %i", ImGuiSliderFlags.AlwaysClamp); ImGui.EndDisabled();ImGui.PopID();Layout("Type");ImGui.PushID(2); ImGui.Combo("texture_type", ref material.SelectedTexture, - "Diffuse\0Normals\0Specular\0Mask\0Emissive\0"); + "Diffuse\0Normals\0Specular\0Ambient Occlusion\0Emissive\0"); ImGui.PopID(); ImGui.EndTable(); } @@ -606,29 +606,6 @@ public class SnimGui if (ImGui.IsItemClicked()) ImGui.SetClipboardText(name); } - private void DrawSquareTexture(Texture texture, Vector2 size) - { - ImGui.Image(texture?.GetPointer() ?? IntPtr.Zero, size, Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1, 1, 1, .5f)); - if (texture == null) return; - - if (ImGui.IsItemHovered()) - { - ImGui.BeginTooltip(); - ImGui.Text($"Type: ({texture.Format}) {texture.Type}:{texture.Name}"); - ImGui.Text($"Texture: {texture.Path}"); - ImGui.Text($"Imported: {texture.ImportedWidth}x{texture.ImportedHeight}"); - ImGui.Text($"Mip Used: {texture.Width}x{texture.Height}"); - ImGui.Spacing(); - ImGui.TextDisabled(texture.Label); - ImGui.EndTooltip(); - } - if (ImGui.IsItemClicked()) - { - ImGui.SetClipboardText(Creator.Utils.FixPath(texture.Path)); - texture.Label = "(?) Path Copied to Clipboard"; - } - } - private void Theme() { var style = ImGui.GetStyle(); diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index 423a27d7..9d72b865 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Threading; using System.Windows; using CUE4Parse.UE4.Assets.Exports; @@ -24,6 +25,7 @@ public class Snooper : GameWindow public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings) { + Camera = new Camera(); Framebuffer = new FramebufferObject(ClientSize); Renderer = new Renderer(ClientSize.X, ClientSize.Y); @@ -31,23 +33,26 @@ public class Snooper : GameWindow _init = false; } - public void LoadExport(CancellationToken cancellationToken, UObject export) + public bool TryLoadExport(CancellationToken cancellationToken, UObject export) { - var newCamera = Renderer.Load(cancellationToken, export); - if (newCamera == null || !(newCamera.Speed > _previousSpeed)) return; - - Camera = newCamera; - _previousSpeed = Camera.Speed; + var newCamera = Renderer.Load(cancellationToken, export) ?? new Camera(); + if (newCamera.Speed > _previousSpeed) + { + Camera = newCamera; + _previousSpeed = Camera.Speed; + } + return Renderer.Cache.Models.Count > 0; } public unsafe void WindowShouldClose(bool value, bool clear) { if (clear) { + _previousSpeed = 0f; Renderer.Cache.DisposeModels(); Renderer.Cache.Models.Clear(); Renderer.Settings.Reset(); - _previousSpeed = 0f; + Renderer.Save(); } GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop @@ -147,7 +152,7 @@ public class Snooper : GameWindow if (KeyboardState.IsKeyDown(Keys.C)) Camera.ModifyZoom(+.5f); - if (KeyboardState.IsKeyPressed(Keys.R)) + if (KeyboardState.IsKeyPressed(Keys.H)) WindowShouldClose(true, false); if (KeyboardState.IsKeyPressed(Keys.Escape)) WindowShouldClose(true, true); @@ -166,13 +171,9 @@ public class Snooper : GameWindow _gui.Controller.WindowResized(e.Width, e.Height); } - protected override void Dispose(bool disposing) + protected override void OnClosing(CancelEventArgs e) { - base.Dispose(disposing); - - Framebuffer?.Dispose(); - Renderer?.Dispose(); - - _gui?.Controller.Dispose(); + base.OnClosing(e); + WindowShouldClose(true, true); } }