diff --git a/CUE4Parse b/CUE4Parse index 46d45fbf..de9589bc 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 46d45fbfbfe427358b84139c8bfd85d03355a8f3 +Subproject commit de9589bc3ff5302208a5a5b01f009310a50376a8 diff --git a/FModel/Views/Snooper/Camera.cs b/FModel/Views/Snooper/Camera.cs index 4bdc3335..66f68dd0 100644 --- a/FModel/Views/Snooper/Camera.cs +++ b/FModel/Views/Snooper/Camera.cs @@ -34,7 +34,7 @@ public class Camera public void ModifyZoom(float zoomAmount) { //We don't want to be able to zoom in too close or too far away so clamp to these values - Zoom = Math.Clamp(Zoom - zoomAmount, 1.0f, 60f); + Zoom = Math.Clamp(Zoom - zoomAmount, 1.0f, 89f); } public void ModifyDirection(float xOffset, float yOffset) diff --git a/FModel/Views/Snooper/Model.cs b/FModel/Views/Snooper/Model.cs index 2a783419..8b47a5f0 100644 --- a/FModel/Views/Snooper/Model.cs +++ b/FModel/Views/Snooper/Model.cs @@ -46,7 +46,6 @@ public class Model : IDisposable public bool IsSavable; public bool DisplayVertexColors; public bool DisplayBones; - public int SelectedMorph; public float MorphTime; protected Model(UObject owner, string name, string type) @@ -149,10 +148,10 @@ public class Model : IDisposable _matrixVbo.Unbind(); } - public void UpdateMorph() + public void UpdateMorph(int index) { _morphVbo.Bind(); - _morphVbo.Update(Morphs[SelectedMorph].Vertices); + _morphVbo.Update(Morphs[index].Vertices); _morphVbo.Unbind(); } @@ -188,7 +187,7 @@ public class Model : IDisposable for (uint morph = 0; morph < Morphs.Length; morph++) { Morphs[morph].Setup(gl); - if (morph == SelectedMorph) + if (morph == 0) _morphVbo = new BufferObject(_gl, Morphs[morph].Vertices, BufferTargetARB.ArrayBuffer); } _vao.Bind(); diff --git a/FModel/Views/Snooper/Options.cs b/FModel/Views/Snooper/Options.cs new file mode 100644 index 00000000..19ab5a59 --- /dev/null +++ b/FModel/Views/Snooper/Options.cs @@ -0,0 +1,52 @@ +using System; +using CUE4Parse.UE4.Objects.Core.Misc; + +namespace FModel.Views.Snooper; + +public class Options +{ + public FGuid SelectedModel { get; private set; } + public int SelectedModelInstance; + + public int SelectedSection { get; private set; } + public int SelectedMorph { get; private set; } + + public Options() + { + Reset(); + } + + public void Reset() + { + SelectedModel = Guid.Empty; + SelectedModelInstance = 0; + SelectedSection = 0; + SelectedMorph = 0; + } + + public void SelectModel(FGuid guid) + { + SelectedModel = guid; + SelectedModelInstance = 0; + SelectedSection = 0; + SelectedMorph = 0; + } + + public void SelectSection(int index) + { + SelectedSection = index; + } + + public void SelectMorph(int index, Model model) + { + SelectedMorph = index; + model.UpdateMorph(SelectedMorph); + } + + public bool TryGetSection(Model model, out Section section) + { + if (SelectedSection >= 0 && SelectedSection < model.Sections.Length) + section = model.Sections[SelectedSection]; else section = null; + return section != null; + } +} diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 83ec1e34..f40c7e6b 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -32,9 +32,6 @@ public class SnimGui : IDisposable private readonly Vector2 _textureSize; private readonly Vector2 _texturePosition; private bool _viewportFocus; - private FGuid _selectedModel; - private int _selectedInstance; - private int _selectedSection; private const ImGuiWindowFlags _noResize = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove; // delete once we have a proper docking branch private const ImGuiCond _firstUse = ImGuiCond.Appearing; // switch to FirstUseEver once the docking branch will not be useful anymore... @@ -59,23 +56,18 @@ public class SnimGui : IDisposable _viewportPosition = new Vector2(0, titleBarHeight); _textureSize = _viewportSize with { Y = viewport.WorkSize.Y - _viewportSize.Y - titleBarHeight }; _texturePosition = new Vector2(0, _viewportPosition.Y + _viewportSize.Y); - _selectedModel = new FGuid(); - _selectedInstance = 0; - _selectedSection = 0; Theme(style); } - public void Increment(FGuid guid) => _selectedModel = guid; - - public void Construct(Vector2D size, FramebufferObject framebuffer, Camera camera, IMouse mouse, IDictionary models) + public void Construct(ref Options options, Vector2D size, FramebufferObject framebuffer, Camera camera, IMouse mouse, IDictionary models) { DrawDockSpace(size); DrawNavbar(); - DrawOuliner(camera, models); - DrawProperties(camera, models); - DrawTextures(models); + DrawOuliner(ref options, camera, models); + DrawProperties(ref options, camera, models); + DrawTextures(ref options, models); Draw3DViewport(framebuffer, camera, mouse); } @@ -126,7 +118,7 @@ public class SnimGui : IDisposable ImGui.EndMainMenuBar(); } - private void DrawOuliner(Camera camera, IDictionary models) + private void DrawOuliner(ref Options options, Camera camera, IDictionary models) { ImGui.SetNextWindowSize(_outlinerSize, _firstUse); ImGui.SetNextWindowPos(_outlinerPosition, _firstUse); @@ -144,20 +136,19 @@ public class SnimGui : IDisposable foreach (var (guid, model) in models) { ImGui.PushID(i); - model.IsSelected = _selectedModel == guid; + model.IsSelected = options.SelectedModel == guid; if (ImGui.Selectable(model.Name, model.IsSelected)) { - _selectedModel = guid; - _selectedInstance = 0; - _selectedSection = 0; + options.SelectModel(guid); } if (ImGui.BeginPopupContextItem()) { + options.SelectModel(guid); if (ImGui.Selectable("Deselect")) - _selectedModel = Guid.Empty; + options.SelectModel(Guid.Empty); if (ImGui.Selectable("Delete")) models.Remove(guid); - if (ImGui.Selectable("Copy to Clipboard")) + if (ImGui.Selectable("Copy Name to Clipboard")) Application.Current.Dispatcher.Invoke(delegate { Clipboard.SetText(model.Name); @@ -187,19 +178,19 @@ public class SnimGui : IDisposable ImGui.End(); } - private void DrawProperties(Camera camera, IDictionary models) + private void DrawProperties(ref Options options, Camera camera, IDictionary models) { ImGui.SetNextWindowSize(_propertiesSize, _firstUse); ImGui.SetNextWindowPos(_propertiesPosition, _firstUse); ImGui.Begin("Properties", _noResize | ImGuiWindowFlags.NoCollapse); - if (!models.TryGetValue(_selectedModel, out var model)) + if (!models.TryGetValue(options.SelectedModel, out var model)) return; ImGui.Text($"Entity: ({model.Type}) {model.Name}"); - ImGui.Text($"Guid: {_selectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); + ImGui.Text($"Guid: {options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); PushStyleCompact(); ImGui.Columns(4, "Actions", false); - if (ImGui.Button("Go To")) camera.Position = model.Transforms[_selectedInstance].Position; + if (ImGui.Button("Go To")) camera.Position = model.Transforms[options.SelectedModelInstance].Position; ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show); ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.DisplayVertexColors); ImGui.EndDisabled(); ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasBones); ImGui.Checkbox("Bones", ref model.DisplayBones); ImGui.EndDisabled(); @@ -219,7 +210,7 @@ public class SnimGui : IDisposable PushStyleCompact(); ImGui.PushID(0); ImGui.BeginDisabled(model.TransformsCount < 2); ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - ImGui.SliderInt("", ref _selectedInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp); + ImGui.SliderInt("", ref options.SelectedModelInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp); ImGui.EndDisabled(); ImGui.PopID(); ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); @@ -227,13 +218,13 @@ public class SnimGui : IDisposable { ImGui.PushID(1); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[_selectedInstance].Position.X, speed, 0f, 0f, "%.2f m"); + ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Position.X, speed, 0f, 0f, "%.2f m"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[_selectedInstance].Position.Y, speed, 0f, 0f, "%.2f m"); + ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Position.Y, speed, 0f, 0f, "%.2f m"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[_selectedInstance].Position.Z, speed, 0f, 0f, "%.2f m"); + ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Position.Z, speed, 0f, 0f, "%.2f m"); ImGui.PopID(); ImGui.TreePop(); @@ -244,13 +235,13 @@ public class SnimGui : IDisposable { ImGui.PushID(2); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[_selectedInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°"); + ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[_selectedInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°"); + ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[_selectedInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°"); + ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°"); ImGui.PopID(); ImGui.TreePop(); @@ -261,19 +252,19 @@ public class SnimGui : IDisposable { ImGui.PushID(3); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[_selectedInstance].Scale.X, speed, 0f, 0f, "%.3f"); + ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Scale.X, speed, 0f, 0f, "%.3f"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[_selectedInstance].Scale.Y, speed, 0f, 0f, "%.3f"); + ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Scale.Y, speed, 0f, 0f, "%.3f"); ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[_selectedInstance].Scale.Z, speed, 0f, 0f, "%.3f"); + ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Scale.Z, speed, 0f, 0f, "%.3f"); ImGui.PopID(); ImGui.TreePop(); } - model.UpdateMatrix(_selectedInstance); + model.UpdateMatrix(options.SelectedModelInstance); PopStyleCompact(); ImGui.EndTabItem(); } @@ -296,14 +287,20 @@ public class SnimGui : IDisposable ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f))); ImGui.Text(section.Index.ToString("D")); ImGui.TableNextColumn(); - if (ImGui.Selectable(section.Name, _selectedSection == i, ImGuiSelectableFlags.SpanAllColumns)) - _selectedSection = i; + if (ImGui.Selectable(section.Name, options.SelectedSection == i, ImGuiSelectableFlags.SpanAllColumns)) + options.SelectSection(i); if (ImGui.BeginPopupContextItem()) { + options.SelectSection(i); if (ImGui.Selectable("Swap")) { } + if (ImGui.Selectable("Copy Name to Clipboard")) + Application.Current.Dispatcher.Invoke(delegate + { + Clipboard.SetText(section.Name); + }); ImGui.EndPopup(); } ImGui.PopID(); @@ -321,11 +318,8 @@ public class SnimGui : IDisposable for (int i = 0; i < model.Morphs.Length; i++) { ImGui.PushID(i); - if (ImGui.Selectable(model.Morphs[i].Name, model.SelectedMorph == i)) - { - model.SelectedMorph = i; - model.UpdateMorph(); - } + if (ImGui.Selectable(model.Morphs[i].Name, options.SelectedMorph == i)) + options.SelectMorph(i, model); ImGui.PopID(); } ImGui.EndListBox(); @@ -340,15 +334,15 @@ public class SnimGui : IDisposable ImGui.End(); } - private void DrawTextures(IDictionary models) + private void DrawTextures(ref Options options, IDictionary models) { ImGui.SetNextWindowSize(_textureSize, _firstUse); ImGui.SetNextWindowPos(_texturePosition, _firstUse); ImGui.Begin("Textures", _noResize | ImGuiWindowFlags.NoCollapse); - if (!models.TryGetValue(_selectedModel, out var model)) + if (!models.TryGetValue(options.SelectedModel, out var model) || + !options.TryGetSection(model, out var section)) return; - var section = model.Sections[_selectedSection]; PushStyleCompact(); ImGui.BeginGroup(); ImGui.Checkbox("Show", ref section.Show); ImGui.Checkbox("Wireframe", ref section.Wireframe); @@ -405,7 +399,7 @@ public class SnimGui : IDisposable Application.Current.Dispatcher.Invoke(delegate { Clipboard.SetText(Utils.FixPath(texture.Path)); - texture.Label = "(?) Copied to Clipboard"; + texture.Label = "(?) Path Copied to Clipboard"; }); } @@ -451,18 +445,16 @@ public class SnimGui : IDisposable var io = ImGui.GetIO(); if (ImGui.IsItemHovered()) { - camera.ModifyZoom(io.MouseWheel); - - // if left button down while mouse is hover viewport - if (ImGui.IsMouseDown(ImGuiMouseButton.Left) && !_viewportFocus) + // if right button down while mouse is hover viewport + if (ImGui.IsMouseDown(ImGuiMouseButton.Right) && !_viewportFocus) _viewportFocus = true; } // this can't be inside IsItemHovered! read it as - // if left mouse button was pressed while hovering the viewport - // move camera until left mouse button is released + // if right mouse button was pressed while hovering the viewport + // move camera until right mouse button is released // no matter where mouse position end up - if (ImGui.IsMouseDragging(ImGuiMouseButton.Left, lookSensitivity) && _viewportFocus) + if (ImGui.IsMouseDragging(ImGuiMouseButton.Right, lookSensitivity) && _viewportFocus) { var delta = io.MouseDelta * lookSensitivity; camera.ModifyDirection(delta.X, delta.Y); @@ -470,7 +462,7 @@ public class SnimGui : IDisposable } // if left button up and mouse was in viewport - if (ImGui.IsMouseReleased(ImGuiMouseButton.Left) && _viewportFocus) + if (ImGui.IsMouseReleased(ImGuiMouseButton.Right) && _viewportFocus) { _viewportFocus = false; mouse.Cursor.CursorMode = CursorMode.Normal; diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index 8c4fc019..b29064b0 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -35,6 +35,7 @@ public class Snooper private IKeyboard _keyboard; private IMouse _mouse; private RawImage _icon; + private Options _options; private readonly FramebufferObject _framebuffer; private readonly Skybox _skybox; @@ -87,6 +88,7 @@ public class Snooper _size = vector2D; }; + _options = new Options(); _framebuffer = new FramebufferObject(_size); _skybox = new Skybox(); _grid = new Grid(); @@ -104,6 +106,7 @@ public class Snooper { _models[guid] = new Model(export, st.Name, st.ExportType, mesh.LODs[0], mesh.LODs[0].Verts); SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO); + _options.SelectModel(guid); } break; } @@ -114,6 +117,7 @@ public class Snooper { _models[guid] = new Model(export, sk.Name, sk.ExportType, mesh.LODs[0], mesh.LODs[0].Verts, sk.MorphTargets, mesh.RefSkeleton); SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO); + _options.SelectModel(guid); } break; } @@ -328,7 +332,7 @@ public class Snooper model.Outline(_outline); } - _imGui.Construct(_size, _framebuffer, _camera, _mouse, _models); + _imGui.Construct(ref _options, _size, _framebuffer, _camera, _mouse, _models); _framebuffer.BindMsaa(); _framebuffer.Bind(0); // switch back to main window @@ -361,6 +365,10 @@ public class Snooper _camera.Position += moveSpeed * _camera.Up; if (_keyboard.IsKeyPressed(Key.Q)) _camera.Position -= moveSpeed * _camera.Up; + if (_keyboard.IsKeyPressed(Key.X)) + _camera.ModifyZoom(-.5f); + if (_keyboard.IsKeyPressed(Key.C)) + _camera.ModifyZoom(+.5f); if (_keyboard.IsKeyPressed(Key.H)) { @@ -390,6 +398,7 @@ public class Snooper if (!_append) { _models.Clear(); + _options.Reset(); _previousSpeed = 0f; } _imGui.Dispose(); diff --git a/FModel/Views/Snooper/Texture.cs b/FModel/Views/Snooper/Texture.cs index dbcfe477..f2ca7f39 100644 --- a/FModel/Views/Snooper/Texture.cs +++ b/FModel/Views/Snooper/Texture.cs @@ -30,7 +30,7 @@ public class Texture : IDisposable _handle = _gl.GenTexture(); _type = type; - Label = "(?) Click to Copy"; + Label = "(?) Click to Copy Path"; } public Texture(GL gl, uint width, uint height) : this(gl, TextureType.MsaaFramebuffer)