diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index f58f8d56..563c3b27 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -79,7 +79,7 @@ public partial class MainWindow #if DEBUG await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.Extract( - "Engine/Content/BasicShapes/Cube.uasset")); + "FortniteGame/Content/Environments/Props/Winter/Meshes/SM_ChristmasTree_Llama.uasset")); #endif } diff --git a/FModel/Views/Snooper/Model.cs b/FModel/Views/Snooper/Model.cs index 9d75b635..22c939ca 100644 --- a/FModel/Views/Snooper/Model.cs +++ b/FModel/Views/Snooper/Model.cs @@ -1,8 +1,6 @@ using System; using System.Linq; -using System.Numerics; using CUE4Parse_Conversion.Meshes.PSK; -using ImGuiNET; using Silk.NET.OpenGL; namespace FModel.Views.Snooper; @@ -28,13 +26,13 @@ public class Model : IDisposable public readonly float[] Vertices; public readonly Section[] Sections; - private string[] _transforms = { + public Transform Transforms = Transform.Identity; + public readonly string[] TransformsLabels = { "X Location", "Y", "Z", "X Rotation", "Y", "Z", "X Scale", "Y", "Z" }; - private bool _display_vertex_colors; - private Transform _transform = Transform.Identity; + public bool DisplayVertexColors; public Model(string name, CBaseMeshLod lod, CMeshVertex[] vertices) { @@ -113,7 +111,7 @@ public class Model : IDisposable _shader.Use(); - _shader.SetUniform("uModel", _transform.Matrix); + _shader.SetUniform("uModel", Transforms.Matrix); _shader.SetUniform("uView", camera.GetViewMatrix()); _shader.SetUniform("uProjection", camera.GetProjectionMatrix()); _shader.SetUniform("viewPos", camera.Position); @@ -125,59 +123,7 @@ public class Model : IDisposable _shader.SetUniform("light.position", camera.Position); - _shader.SetUniform("display_vertex_colors", _display_vertex_colors); - - ImGui.Text($"Entity: {Name}"); - if (ImGui.TreeNode("Transform")) - { - const int width = 100; - var speed = camera.Speed / 100; - var index = 0; - - ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Position.X, speed, 0f, 0f, "%.2f m"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Position.Z, speed, 0f, 0f, "%.2f m"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Position.Y, speed, 0f, 0f, "%.2f m"); - ImGui.PopID(); - - ImGui.Spacing(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Rotation.X, 1f, 0f, 0f, "%.1f°"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Rotation.Z, 1f, 0f, 0f, "%.1f°"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Rotation.Y, 1f, 0f, 0f, "%.1f°"); - ImGui.PopID(); - - ImGui.Spacing(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Scale.X, speed, 0f, 0f, "%.3f"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Scale.Z, speed, 0f, 0f, "%.3f"); - ImGui.PopID(); - - index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); - ImGui.DragFloat(_transforms[index], ref _transform.Scale.Y, speed, 0f, 0f, "%.3f"); - ImGui.PopID(); - - ImGui.TreePop(); - } - if (HasVertexColors) ImGui.Checkbox("Display Vertex Colors", ref _display_vertex_colors); - ImGui.Separator(); + _shader.SetUniform("display_vertex_colors", DisplayVertexColors); for (int section = 0; section < Sections.Length; section++) { diff --git a/FModel/Views/Snooper/Section.cs b/FModel/Views/Snooper/Section.cs index f11e2a29..d1bdd2da 100644 --- a/FModel/Views/Snooper/Section.cs +++ b/FModel/Views/Snooper/Section.cs @@ -250,7 +250,7 @@ public class Section : IDisposable // ImGui.EndTooltip(); // } - DrawImGui(index); + // DrawImGui(index); _diffuseMap?.Bind(TextureUnit.Texture0); _normalMap?.Bind(TextureUnit.Texture1); diff --git a/FModel/Extensions/ImGuiExtensions.cs b/FModel/Views/Snooper/SnimGui.cs similarity index 56% rename from FModel/Extensions/ImGuiExtensions.cs rename to FModel/Views/Snooper/SnimGui.cs index f49c63cf..21168d02 100644 --- a/FModel/Extensions/ImGuiExtensions.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -1,18 +1,66 @@ -using System.Numerics; -using FModel.Views.Snooper; +using System; +using System.Collections.Generic; +using System.Numerics; using ImGuiNET; using Silk.NET.Input; using Silk.NET.Maths; +using Silk.NET.OpenGL; +using Silk.NET.OpenGL.Extensions.ImGui; +using Silk.NET.Windowing; -namespace FModel.Extensions; +namespace FModel.Views.Snooper; -public static class ImGuiExtensions +public class SnimGui : IDisposable { - public const uint DockspaceId = 1337; + private readonly ImGuiController _controller; - private static bool _viewportFocus; + private readonly Vector2 _outlinerSize; + private readonly Vector2 _outlinerPosition; + private readonly Vector2 _propertiesSize; + private readonly Vector2 _propertiesPosition; + private readonly Vector2 _viewportSize; + private readonly Vector2 _viewportPosition; + private bool _viewportFocus; + private int _selectedModel; - public static void DrawDockSpace(Vector2D size) + private const ImGuiWindowFlags _noResize = ImGuiWindowFlags.NoResize; // 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... + private const uint _dockspaceId = 1337; + + public SnimGui(GL gl, IWindow window, IInputContext input) + { + var fontConfig = new ImGuiFontConfig("C:\\Windows\\Fonts\\segoeui.ttf", 16); + _controller = new ImGuiController(gl, window, input, fontConfig); + + var style = ImGui.GetStyle(); + var viewport = ImGui.GetMainViewport(); + var titleBarHeight = ImGui.GetFontSize() + style.FramePadding.Y * 2; + + _outlinerSize = new Vector2(300, 350); + _outlinerPosition = new Vector2(viewport.WorkSize.X - _outlinerSize.X, titleBarHeight); + _propertiesSize = _outlinerSize with { Y = viewport.WorkSize.Y - _outlinerSize.Y - titleBarHeight }; + _propertiesPosition = new Vector2(viewport.WorkSize.X - _propertiesSize.X, _outlinerPosition.Y + _outlinerSize.Y); + _viewportSize = _outlinerPosition with { Y = viewport.WorkSize.Y - titleBarHeight }; + _viewportPosition = new Vector2(0, titleBarHeight); + _selectedModel = 0; + + Theme(style); + } + + public void Construct(Vector2D size, FramebufferObject framebuffer, Camera camera, IMouse mouse, IList models) + { + DrawDockSpace(size); + DrawNavbar(); + + DrawOuliner(camera, models); + DrawProperties(camera, models); + Draw3DViewport(framebuffer, camera, mouse); + } + + /// + /// absolutely useless at the moment since ImGui.NET lacks DockerBuilder bindinds + /// + private void DrawDockSpace(Vector2D size) { const ImGuiWindowFlags flags = ImGuiWindowFlags.MenuBar | ImGuiWindowFlags.NoDocking | @@ -23,10 +71,10 @@ public static class ImGuiExtensions ImGui.SetNextWindowPos(new Vector2(0, 0)); ImGui.SetNextWindowSize(new Vector2(size.X, size.Y)); ImGui.Begin("Snooper", flags); - ImGui.DockSpace(DockspaceId); + ImGui.DockSpace(_dockspaceId); } - public static void DrawNavbar() + private void DrawNavbar() { if (!ImGui.BeginMainMenuBar()) return; @@ -54,14 +102,118 @@ public static class ImGuiExtensions ImGui.EndMainMenuBar(); } - public static void DrawViewport(FramebufferObject framebuffer, Camera camera, IMouse mouse) + private void DrawOuliner(Camera camera, IList models) + { + ImGui.SetNextWindowSize(_outlinerSize, _firstUse); + ImGui.SetNextWindowPos(_outlinerPosition, _firstUse); + ImGui.Begin("Scene", _noResize | ImGuiWindowFlags.NoCollapse); + + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Collection")) + { + for (var i = 0; i < models.Count; i++) + { + var model = models[i]; + if (ImGui.Selectable(model.Name, _selectedModel == i)) + _selectedModel = i; + } + ImGui.TreePop(); + } + + if (ImGui.TreeNode("Camera")) + { + ImGui.Text($"Position: {camera.Position}"); + ImGui.Text($"Direction: {camera.Direction}"); + ImGui.Text($"Speed: {camera.Speed}"); + ImGui.Text($"Far: {camera.Far}"); + ImGui.Text($"Near: {camera.Near}"); + ImGui.Text($"Zoom: {camera.Zoom}"); + ImGui.TreePop(); + } + + ImGui.Text($"Position: {_viewportPosition}"); + ImGui.Text($"Size: {_viewportSize}"); + + ImGui.End(); + } + + private void DrawProperties(Camera camera, IList models) + { + ImGui.SetNextWindowSize(_propertiesSize, _firstUse); + ImGui.SetNextWindowPos(_propertiesPosition, _firstUse); + ImGui.Begin("Properties", _noResize | ImGuiWindowFlags.NoCollapse); + + var model = models[_selectedModel]; + ImGui.Text($"Entity: {model.Name}"); + ImGui.BeginDisabled(!model.HasVertexColors); + ImGui.Checkbox("Vertex Colors", ref model.DisplayVertexColors); + ImGui.EndDisabled(); + + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Transform")) + { + const int width = 100; + var speed = camera.Speed / 100; + var index = 0; + + ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Position.X, speed, 0f, 0f, "%.2f m"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Position.Z, speed, 0f, 0f, "%.2f m"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Position.Y, speed, 0f, 0f, "%.2f m"); + ImGui.PopID(); + + ImGui.Spacing(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Rotation.X, 1f, 0f, 0f, "%.1f°"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Rotation.Z, 1f, 0f, 0f, "%.1f°"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Rotation.Y, 1f, 0f, 0f, "%.1f°"); + ImGui.PopID(); + + ImGui.Spacing(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Scale.X, speed, 0f, 0f, "%.3f"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Scale.Z, speed, 0f, 0f, "%.3f"); + ImGui.PopID(); + + index++; ImGui.SetNextItemWidth(width); ImGui.PushID(index); + ImGui.DragFloat(model.TransformsLabels[index], ref model.Transforms.Scale.Y, speed, 0f, 0f, "%.3f"); + ImGui.PopID(); + + ImGui.TreePop(); + } + + ImGui.End(); + } + + private void Draw3DViewport(FramebufferObject framebuffer, Camera camera, IMouse mouse) { const float lookSensitivity = 0.1f; const ImGuiWindowFlags flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysUseWindowPadding; - ImGui.Begin("Viewport", flags); + ImGui.SetNextWindowSize(_viewportSize, _firstUse); + ImGui.SetNextWindowPos(_viewportPosition, _firstUse); + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); + ImGui.Begin("Viewport", _noResize | flags); + ImGui.PopStyleVar(); var largest = ImGui.GetContentRegionAvail(); largest.X -= ImGui.GetScrollX(); @@ -120,7 +272,7 @@ public static class ImGuiExtensions ImGui.End(); } - public static void Theme() + private void Theme(ImGuiStylePtr style) { var io = ImGui.GetIO(); io.ConfigFlags |= ImGuiConfigFlags.DockingEnable; @@ -128,8 +280,7 @@ public static class ImGuiExtensions io.ConfigWindowsMoveFromTitleBarOnly = true; io.ConfigDockingWithShift = true; - var style = ImGui.GetStyle(); - style.WindowPadding = Vector2.Zero; + // style.WindowPadding = Vector2.Zero; // style.Colors[(int) ImGuiCol.Text] = new Vector4(0.95f, 0.96f, 0.98f, 1.00f); // style.Colors[(int) ImGuiCol.TextDisabled] = new Vector4(0.36f, 0.42f, 0.47f, 1.00f); // style.Colors[(int) ImGuiCol.WindowBg] = new Vector4(0.149f, 0.149f, 0.188f, 0.35f); @@ -179,4 +330,8 @@ public static class ImGuiExtensions // style.Colors[(int) ImGuiCol.NavWindowingDimBg] = new Vector4(0.80f, 0.80f, 0.80f, 0.20f); // style.Colors[(int) ImGuiCol.ModalWindowDimBg] = new Vector4(0.80f, 0.80f, 0.80f, 0.35f); } + + public void Update(float deltaTime) => _controller.Update(deltaTime); + public void Render() => _controller.Render(); + public void Dispose() => _controller.Dispose(); } diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index 71de4f94..8cf9b7ba 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -8,13 +8,11 @@ using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Assets.Exports.StaticMesh; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse_Conversion.Meshes; -using FModel.Extensions; using ImGuiNET; using Silk.NET.Core; using Silk.NET.Input; using Silk.NET.Maths; using Silk.NET.OpenGL; -using Silk.NET.OpenGL.Extensions.ImGui; using Silk.NET.Windowing; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Advanced; @@ -25,8 +23,8 @@ namespace FModel.Views.Snooper; public class Snooper { private readonly IWindow _window; - private ImGuiController _controller; private GL _gl; + private SnimGui _imGui; private Camera _camera; private IKeyboard _keyboard; private IMouse _mouse; @@ -125,12 +123,7 @@ public class Snooper _gl = GL.GetApi(_window); _gl.Enable(EnableCap.Multisample); - // we don't need to bother with file check - // but keep an eye on font size for different monitors - var fontConfig = new ImGuiFontConfig("C:\\Windows\\Fonts\\segoeui.ttf", 16); - _controller = new ImGuiController(_gl, _window, input, fontConfig); - - ImGuiExtensions.Theme(); + _imGui = new SnimGui(_gl, _window, input); _framebuffer.Setup(_gl); _skybox.Setup(_gl); @@ -148,44 +141,28 @@ public class Snooper /// private void OnRender(double deltaTime) { - _controller.Update((float) deltaTime); + _imGui.Update((float) deltaTime); ClearWhatHasBeenDrawn(); // in main window _framebuffer.Bind(); // switch to dedicated window ClearWhatHasBeenDrawn(); // in dedicated window - ImGuiExtensions.DrawDockSpace(_size); - ImGuiExtensions.DrawNavbar(); - ImGui.ShowDemoWindow(); - _skybox.Bind(_camera); _grid.Bind(_camera); - ImGui.Begin("Properties", ImGuiWindowFlags.NoFocusOnAppearing); - if (ImGui.TreeNode("Camera")) - { - ImGui.Text($"Position: {_camera.Position}"); - ImGui.Text($"Direction: {_camera.Direction}"); - ImGui.Text($"Speed: {_camera.Speed}"); - ImGui.Text($"Far: {_camera.Far}"); - ImGui.Text($"Near: {_camera.Near}"); - ImGui.Text($"Zoom: {_camera.Zoom}"); - ImGui.TreePop(); - } foreach (var model in _models) { model.Bind(_camera); } - ImGui.End(); - ImGuiExtensions.DrawViewport(_framebuffer, _camera, _mouse); + _imGui.Construct(_size, _framebuffer, _camera, _mouse, _models); _framebuffer.BindMsaa(); _framebuffer.Bind(0); // switch back to main window _framebuffer.BindStuff(); - _controller.Render(); // render ImGui in main window + _imGui.Render(); // render ImGui in main window } private void ClearWhatHasBeenDrawn() @@ -229,7 +206,7 @@ public class Snooper model.Dispose(); } _models.Clear(); - _controller.Dispose(); + _imGui.Dispose(); _window.Dispose(); _gl.Dispose(); }