From d0963bd018fdec2463650232d76a54aac4643c0f Mon Sep 17 00:00:00 2001 From: 4sval Date: Wed, 16 Nov 2022 01:35:30 +0100 Subject: [PATCH] imgui icons + material inspector v.final +/- --- CUE4Parse | 2 +- FModel/Framework/ImGuiController.cs | 13 +- .../ApiEndpoints/EpicApiEndpoint.cs | 2 +- FModel/Views/Snooper/Cache.cs | 10 + FModel/Views/Snooper/Material.cs | 73 ++- FModel/Views/Snooper/Skeleton.cs | 18 +- FModel/Views/Snooper/SnimGui.cs | 596 ++++++++++-------- FModel/Views/Snooper/Socket.cs | 5 +- FModel/Views/Snooper/Texture.cs | 48 +- 9 files changed, 453 insertions(+), 314 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 7a13a4e1..2e3274d9 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 7a13a4e1c46e8a084f681e1a1a8702de695da3fa +Subproject commit 2e3274d96eb02b4b376f9f44942da81593130d28 diff --git a/FModel/Framework/ImGuiController.cs b/FModel/Framework/ImGuiController.cs index 117da66c..5237b1f1 100644 --- a/FModel/Framework/ImGuiController.cs +++ b/FModel/Framework/ImGuiController.cs @@ -32,6 +32,9 @@ public class ImGuiController : IDisposable private int _windowWidth; private int _windowHeight; + private ImFontPtr _normal; + private ImFontPtr _semiBold; + private readonly System.Numerics.Vector2 _scaleFactor = System.Numerics.Vector2.One; private static bool KHRDebugAvailable = false; @@ -49,8 +52,8 @@ public class ImGuiController : IDisposable IntPtr context = ImGui.CreateContext(); ImGui.SetCurrentContext(context); var io = ImGui.GetIO(); - // io.Fonts.AddFontDefault(); - io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 16); + _normal = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 16); + _semiBold = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\seguisb.ttf", 16); io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset; io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard; @@ -66,6 +69,12 @@ public class ImGuiController : IDisposable _frameBegun = true; } + public void SemiBold() => PushFont(_semiBold); + public void Normal() => PushFont(_normal); + public void PopFont() => ImGui.PopFont(); + + private void PushFont(ImFontPtr ptr) => ImGui.PushFont(ptr); + public void WindowResized(int width, int height) { _windowWidth = width; diff --git a/FModel/ViewModels/ApiEndpoints/EpicApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/EpicApiEndpoint.cs index 65ab9f1d..218adb94 100644 --- a/FModel/ViewModels/ApiEndpoints/EpicApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/EpicApiEndpoint.cs @@ -1,4 +1,4 @@ -using System; +using System.Net; using System.Threading; using System.Threading.Tasks; using EpicManifestParser.Objects; diff --git a/FModel/Views/Snooper/Cache.cs b/FModel/Views/Snooper/Cache.cs index 27386f74..efdf4a18 100644 --- a/FModel/Views/Snooper/Cache.cs +++ b/FModel/Views/Snooper/Cache.cs @@ -13,6 +13,7 @@ public class Cache : IDisposable { public readonly Dictionary Models; public readonly Dictionary Textures; + public readonly Dictionary Icons; private ETexturePlatform _platform; private readonly FGame _game; @@ -21,8 +22,11 @@ public class Cache : IDisposable { Models = new Dictionary(); Textures = new Dictionary(); + Icons = new Dictionary(); _platform = UserSettings.Default.OverridedPlatform; _game = Services.ApplicationService.ApplicationView.CUE4Parse.Game; + + Icons["material"] = new Texture("materialicon"); } public bool TryGetCachedModel(UStaticMesh o, out Model model) @@ -82,6 +86,11 @@ public class Cache : IDisposable { texture.Dispose(); } + + foreach (var texture in Icons.Values) + { + texture.Dispose(); + } } public void Dispose() @@ -91,5 +100,6 @@ public class Cache : IDisposable DisposeTextures(); Textures.Clear(); + Icons.Clear(); } } diff --git a/FModel/Views/Snooper/Material.cs b/FModel/Views/Snooper/Material.cs index 56bf177f..fcabe597 100644 --- a/FModel/Views/Snooper/Material.cs +++ b/FModel/Views/Snooper/Material.cs @@ -5,6 +5,7 @@ using System.Numerics; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Math; +using ImGuiNET; using OpenTK.Graphics.OpenGL4; namespace FModel.Views.Snooper; @@ -30,7 +31,6 @@ public class Material : IDisposable public bool HasM; public float EmissiveMult = 1f; - public float UVScale = 1f; public Material() @@ -202,6 +202,77 @@ public class Material : IDisposable shader.SetUniform("uParameters.UVScale", UVScale); } + private const string _mult = "x %.2f"; + private const float _step = 0.01f; + private const float _zero = 0.000001f; // doesn't actually work if _infinite is used as max value /shrug + private const float _infinite = 0.0f; + private const ImGuiSliderFlags _clamp = ImGuiSliderFlags.AlwaysClamp; + public void ImGuiParameters() + { + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 3)); + ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 1)); + if (ImGui.BeginTable("parameters", 2)) + { + Layout("Emissive Multiplier");ImGui.PushID(1); + ImGui.DragFloat("", ref EmissiveMult, _step, _zero, _infinite, _mult, _clamp); + ImGui.PopID();Layout("UV Scale");ImGui.PushID(2); + ImGui.DragFloat("", ref UVScale, _step, _zero, _infinite, _mult, _clamp); + ImGui.PopID(); + + if (HasM) + { + Layout("Ambient Occlusion");ImGui.PushID(3); + ImGui.DragFloat("", ref M.AmbientOcclusion, _step, _zero, 1.0f, _mult, _clamp); + ImGui.PopID();Layout("Cavity");ImGui.PushID(4); + ImGui.DragFloat("", ref M.Cavity, _step, _zero, 1.0f, _mult, _clamp); + ImGui.PopID();Layout("Skin Boost Exponent");ImGui.PushID(5); + ImGui.DragFloat("", ref M.SkinBoost.Exponent, _step, _zero, _infinite, _mult, _clamp); + ImGui.PopID();Layout("Skin Boost Color");ImGui.PushID(6); + ImGui.ColorEdit3("", ref M.SkinBoost.Color); + ImGui.PopID(); + } + ImGui.EndTable(); + } + ImGui.PopStyleVar(2); + } + + public void ImGuiDictionaries(string id, Dictionary dictionary, bool center = false, bool wrap = false) + { + if (ImGui.BeginTable(id, 2)) + { + foreach ((string key, T value) in dictionary.Reverse()) + { + Layout(key, true); + var text = $"{value:N}"; + if (center) ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() - ImGui.CalcTextSize(text).X) / 2); + if (wrap) ImGui.TextWrapped(text); else ImGui.Text(text); + TooltipCopy(text); + } + ImGui.EndTable(); + } + } + + private void Layout(string name, bool tooltip = false) + { + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + ImGui.Spacing();ImGui.SameLine();ImGui.Text(name); + if (tooltip) TooltipCopy(name); + ImGui.TableSetColumnIndex(1); + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); + } + + private void TooltipCopy(string name) + { + if (ImGui.IsItemHovered()) + { + ImGui.BeginTooltip(); + ImGui.Text(name); + ImGui.EndTooltip(); + } + if (ImGui.IsItemClicked()) ImGui.SetClipboardText(name); + } + public void Dispose() { for (int i = 0; i < Diffuse.Length; i++) diff --git a/FModel/Views/Snooper/Skeleton.cs b/FModel/Views/Snooper/Skeleton.cs index d0241b9f..57c23577 100644 --- a/FModel/Views/Snooper/Skeleton.cs +++ b/FModel/Views/Snooper/Skeleton.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; +using System.Numerics; using CUE4Parse.UE4.Assets.Exports.Animation; using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; +using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.UObject; namespace FModel.Views.Snooper; @@ -26,11 +29,18 @@ public class Skeleton : IDisposable !RefSkel.ReferenceSkeleton.FinalNameToIndexMap.TryGetValue(socket.BoneName.Text, out var boneIndex)) continue; - var t = RefSkel.ReferenceSkeleton.FinalRefBonePose[boneIndex]; var transform = Transform.Identity; - transform.Position = t.Translation.ToMapVector() * Constants.SCALE_DOWN_RATIO; - transform.Rotation = t.Rotator(); - transform.Scale = t.Scale3D.ToMapVector(); + for (int j = 0; j <= boneIndex; j++) + { + var t = RefSkel.ReferenceSkeleton.FinalRefBonePose[j].Inverse(); + (t.Translation.X, t.Translation.Z, t.Translation.Y) = (-t.Translation.Z, -t.Translation.Y, -t.Translation.X); + var matrix = Matrix4x4.CreateScale(t.Scale3D.ToMapVector()); + // matrix *= Matrix4x4.CreateFromQuaternion(t.Rotation); + matrix *= Matrix4x4.CreateTranslation(t.Translation * Constants.SCALE_DOWN_RATIO); + + // Console.WriteLine($@"{t.Translation}"); + transform.Relation *= matrix; + } Sockets[i] = new Socket(socket, transform); } diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 892d2575..b72e366c 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.Core.Misc; @@ -27,19 +28,16 @@ public class SnimGui public SnimGui(int width, int height) { Controller = new ImGuiController(width, height); - - var style = ImGui.GetStyle(); - Theme(style); + Theme(); } public void Render(Snooper s) { + Controller.SemiBold(); DrawDockSpace(s.Size); DrawNavbar(); - SectionWindow("Materials", s.Renderer, DrawMaterials); - SectionWindow("Textures", s.Renderer, DrawTextures); - SectionWindow("Parameters", s.Renderer, DrawParameters); + SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false); SectionWindow("UV Channels", s.Renderer, DrawUvChannels); Window("Timeline", () => {}); @@ -49,14 +47,14 @@ public class SnimGui ImGui.DragFloat("Far Plane", ref s.Camera.Far, 0.1f, 5f, s.Camera.Far * 2f, "%.2f m", ImGuiSliderFlags.AlwaysClamp); }); Window("World", () => ImGui.Checkbox("Diffuse Only", ref s.Renderer.bDiffuseOnly)); - Window("Outliner", () => DrawOuliner(s)); Window("Sockets", () => DrawSockets(s)); - MeshWindow("Transform", s.Renderer, model => DrawTransform(model, s.Camera.Speed / 100f)); - MeshWindow("Details", s.Renderer, model => DrawDetails(model, s)); - + DrawOuliner(s); + DrawDetails(s); Draw3DViewport(s); + // ImGui.ShowDemoWindow(); + Controller.Render(); } @@ -106,70 +104,82 @@ public class SnimGui private void DrawOuliner(Snooper s) { - if (ImGui.BeginTable("Items", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable)) + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); + Window("Outliner", () => { - ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed); - ImGui.TableSetupColumn("Channels", ImGuiTableColumnFlags.WidthFixed); - ImGui.TableSetupColumn("Name"); - ImGui.TableHeadersRow(); - - var i = 0; - foreach ((FGuid guid, Model model) in s.Renderer.Cache.Models) + if (ImGui.BeginTable("Items", 3, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV, ImGui.GetContentRegionAvail())) { - ImGui.PushID(i); - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - if (!model.Show) - { - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f))); - } + ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed); + ImGui.TableSetupColumn("Channels", ImGuiTableColumnFlags.WidthFixed); + ImGui.TableSetupColumn("Name"); + ImGui.TableHeadersRow(); - ImGui.Text(model.TransformsCount.ToString("D")); - ImGui.TableNextColumn(); - ImGui.Text(model.NumTexCoords.ToString("D")); - ImGui.TableNextColumn(); - model.IsSelected = s.Renderer.Settings.SelectedModel == guid; - if (ImGui.Selectable(model.Name, model.IsSelected, ImGuiSelectableFlags.SpanAllColumns)) + var i = 0; + foreach ((FGuid guid, Model model) in s.Renderer.Cache.Models) { - s.Renderer.Settings.SelectModel(guid); - } - if (ImGui.BeginPopupContextItem()) - { - s.Renderer.Settings.SelectModel(guid); - ImGui.BeginDisabled(!model.HasSkeleton); - if (ImGui.Selectable("Animate")) + ImGui.PushID(i); + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + if (!model.Show) { - s.Renderer.Settings.AnimateMesh(true); - s.WindowShouldClose(true, false); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f))); } - ImGui.Separator(); - ImGui.EndDisabled(); - if (ImGui.Selectable("Delete")) s.Renderer.Cache.Models.Remove(guid); - if (ImGui.Selectable("Deselect")) s.Renderer.Settings.SelectModel(Guid.Empty); - if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(model.Name); - ImGui.EndPopup(); - } - ImGui.PopID(); - i++; - } - ImGui.EndTable(); - } + ImGui.Text(model.TransformsCount.ToString("D")); + ImGui.TableNextColumn(); + ImGui.Text(model.NumTexCoords.ToString("D")); + ImGui.TableNextColumn(); + model.IsSelected = s.Renderer.Settings.SelectedModel == guid; + if (ImGui.Selectable(model.Name, model.IsSelected, ImGuiSelectableFlags.SpanAllColumns)) + { + s.Renderer.Settings.SelectModel(guid); + } + if (ImGui.BeginPopupContextItem()) + { + s.Renderer.Settings.SelectModel(guid); + if (ImGui.Selectable("Save")) + { + + } + ImGui.BeginDisabled(!model.HasSkeleton); + if (ImGui.Selectable("Animate")) + { + s.Renderer.Settings.AnimateMesh(true); + s.WindowShouldClose(true, false); + } + ImGui.EndDisabled(); + ImGui.Separator(); + if (ImGui.Selectable("Delete")) s.Renderer.Cache.Models.Remove(guid); + if (ImGui.Selectable("Deselect")) s.Renderer.Settings.SelectModel(Guid.Empty); + ImGui.Separator(); + if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(model.Name); + ImGui.EndPopup(); + } + ImGui.PopID(); + i++; + } + + ImGui.EndTable(); + } + }); + ImGui.PopStyleVar(); } private void DrawSockets(Snooper s) { foreach (var model in s.Renderer.Cache.Models.Values) { - if (!model.HasSkeleton) return; + if (!model.HasSkeleton || model.IsSelected) return; if (ImGui.TreeNode($"{model.Name} [{model.Skeleton.Sockets.Length}]")) { + var i = 0; foreach (var socket in model.Skeleton.Sockets) { + ImGui.PushID(i); ImGui.Text($"{socket.Name} attached to {socket.Bone}"); - ImGui.Text($"P: {socket.Transform.Position}"); - ImGui.Text($"R: {socket.Transform.Rotation}"); - ImGui.Text($"S: {socket.Transform.Scale}"); + ImGui.Text($"P: {socket.Transform.Matrix.M41} | {socket.Transform.Matrix.M42} | {socket.Transform.Matrix.M43}"); + // ImGui.Text($"R: {socket.Transform.Rotation}"); + // ImGui.Text($"S: {socket.Transform.Scale}"); if (ImGui.Button("Attach")) { var guid = s.Renderer.Settings.SelectedModel; @@ -179,222 +189,220 @@ public class SnimGui selected.UpdateMatrix(selected.SelectedInstance); } } + ImGui.PopID(); + i++; } ImGui.TreePop(); } } } - private void DrawDetails(Model model, Snooper s) + private void DrawDetails(Snooper s) { - ImGui.Text($"Entity: ({model.Type}) {model.Name}"); - ImGui.Text($"Guid: {s.Renderer.Settings.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); - // if (model.Skeleton.Anim != null) - // { - // ImGui.DragFloat("Time", ref model.Skeleton.Anim.CurrentTime, 1.0f, 0.0f, 115.0f, "%.1f s"); - // model.Skeleton.Anim.CalculateBoneTransform(); - // } - - ImGui.Columns(3, "Actions", false); - if (ImGui.Button("Go To")) + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); + MeshWindow("Details", s.Renderer, (icons, model) => { - var instancePos = model.Transforms[model.SelectedInstance].Position; - s.Camera.Position = new Vector3(instancePos.X, instancePos.Y, instancePos.Z); - } - ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show); - ImGui.NextColumn(); ImGui.BeginDisabled(!model.Show); ImGui.Checkbox("Wire", ref model.Wireframe); ImGui.EndDisabled(); - ImGui.Columns(4); - ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.bVertexColors); ImGui.EndDisabled(); - ImGui.NextColumn(); ImGui.Checkbox("Normals", ref model.bVertexNormals); - ImGui.NextColumn(); ImGui.Checkbox("Tangent", ref model.bVertexTangent); - ImGui.NextColumn(); ImGui.Checkbox("Coords", ref model.bVertexTexCoords); - ImGui.Columns(1); - - ImGui.Separator(); - - if (ImGui.BeginTabBar("tabbar_details", ImGuiTabBarFlags.None)) - { - if (ImGui.BeginTabItem("Sections") && ImGui.BeginTable("table_sections", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable)) + ImGui.Text($"Entity: ({model.Type}) {model.Name}"); + ImGui.Text($"Guid: {s.Renderer.Settings.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); + ImGui.Spacing(); + ImGui.Columns(3, "Actions", false); + if (ImGui.Button("Go To")) { - ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed); - ImGui.TableSetupColumn("Material"); - ImGui.TableHeadersRow(); - - var swap = false; - for (var i = 0; i < model.Sections.Length; i++) + var instancePos = model.Transforms[model.SelectedInstance].Position; + s.Camera.Position = new Vector3(instancePos.X, instancePos.Y, instancePos.Z); + } + ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show); + ImGui.NextColumn(); ImGui.BeginDisabled(!model.Show); ImGui.Checkbox("Wire", ref model.Wireframe); ImGui.EndDisabled(); + ImGui.Columns(4); + ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.bVertexColors); ImGui.EndDisabled(); + ImGui.NextColumn(); ImGui.Checkbox("Normals", ref model.bVertexNormals); + ImGui.NextColumn(); ImGui.Checkbox("Tangent", ref model.bVertexTangent); + ImGui.NextColumn(); ImGui.Checkbox("Coords", ref model.bVertexTexCoords); + ImGui.Columns(1); + ImGui.Spacing(); + if (ImGui.BeginTabBar("tabbar_details", ImGuiTabBarFlags.None)) + { + if (ImGui.BeginTabItem("Sections") && ImGui.BeginTable("table_sections", 2, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV, ImGui.GetContentRegionAvail())) { - var section = model.Sections[i]; - var material = model.Materials[section.MaterialIndex]; + ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed); + ImGui.TableSetupColumn("Material"); + ImGui.TableHeadersRow(); - ImGui.PushID(i); - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - if (!section.Show) + var swap = false; + for (var i = 0; i < model.Sections.Length; i++) { - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f))); - } + var section = model.Sections[i]; + var material = model.Materials[section.MaterialIndex]; - ImGui.Text(section.MaterialIndex.ToString("D")); - ImGui.TableNextColumn(); - if (ImGui.Selectable(material.Name, s.Renderer.Settings.SelectedSection == i, ImGuiSelectableFlags.SpanAllColumns)) - { - s.Renderer.Settings.SelectSection(i); - } - if (ImGui.BeginPopupContextItem()) - { - s.Renderer.Settings.SelectSection(i); - if (ImGui.Selectable("Swap")) + ImGui.PushID(i); + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + if (!section.Show) { - if (_swapAwareness) - { - s.Renderer.Settings.SwapMaterial(true); - s.WindowShouldClose(true, false); - } - else swap = true; + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f))); } - if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(material.Name); + + ImGui.Text(section.MaterialIndex.ToString("D")); + ImGui.TableNextColumn(); + if (ImGui.Selectable(material.Name, s.Renderer.Settings.SelectedSection == i, ImGuiSelectableFlags.SpanAllColumns)) + { + s.Renderer.Settings.SelectSection(i); + } + if (ImGui.BeginPopupContextItem()) + { + s.Renderer.Settings.SelectSection(i); + if (ImGui.MenuItem("Show", null, section.Show)) section.Show = !section.Show; + if (ImGui.Selectable("Swap")) + { + if (_swapAwareness) + { + s.Renderer.Settings.SwapMaterial(true); + s.WindowShouldClose(true, false); + } + else swap = true; + } + ImGui.Separator(); + if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(material.Name); + ImGui.EndPopup(); + } + ImGui.PopID(); + } + ImGui.EndTable(); + + var p_open = true; + if (swap) ImGui.OpenPopup("Swap?"); + ImGui.SetNextWindowPos(ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, new Vector2(.5f)); + if (ImGui.BeginPopupModal("Swap?", ref p_open, ImGuiWindowFlags.AlwaysAutoResize)) + { + ImGui.TextWrapped("You're about to swap a material.\nThe window will close for you to extract a material!\n\n"); + ImGui.Separator(); + + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); + ImGui.Checkbox("Got it! Don't show me again", ref _swapAwareness); + ImGui.PopStyleVar(); + + var size = new Vector2(120, 0); + if (ImGui.Button("OK", size)) + { + ImGui.CloseCurrentPopup(); + s.Renderer.Settings.SwapMaterial(true); + s.WindowShouldClose(true, false); + } + + ImGui.SetItemDefaultFocus(); + ImGui.SameLine(); + + if (ImGui.Button("Cancel", size)) + { + ImGui.CloseCurrentPopup(); + } + ImGui.EndPopup(); } - ImGui.PopID(); + + ImGui.EndTabItem(); } - ImGui.EndTable(); - - var p_open = true; - if (swap) ImGui.OpenPopup("Swap?"); - ImGui.SetNextWindowPos(ImGui.GetMainViewport().GetCenter(), ImGuiCond.Appearing, new Vector2(.5f)); - if (ImGui.BeginPopupModal("Swap?", ref p_open, ImGuiWindowFlags.AlwaysAutoResize)) + if (ImGui.BeginTabItem("Transform")) { - ImGui.TextWrapped("You're about to swap a material.\nThe window will close for you to extract a material!\n\n"); - ImGui.Separator(); + const int width = 100; + var speed = s.Camera.Speed / 100f; - ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); - ImGui.Checkbox("Got it! Don't show me again", ref _swapAwareness); - ImGui.PopStyleVar(); + ImGui.PushID(0); ImGui.BeginDisabled(model.TransformsCount < 2); + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); + ImGui.SliderInt("", ref model.SelectedInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp); + ImGui.EndDisabled(); ImGui.PopID(); - var size = new Vector2(120, 0); - if (ImGui.Button("OK", size)) + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Location")) { - ImGui.CloseCurrentPopup(); - s.Renderer.Settings.SwapMaterial(true); - s.WindowShouldClose(true, false); + ImGui.PushID(1); + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Position.X, speed, 0f, 0f, "%.2f m"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Position.Z, speed, 0f, 0f, "%.2f m"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Position.Y, speed, 0f, 0f, "%.2f m"); + + ImGui.PopID(); + ImGui.TreePop(); } - ImGui.SetItemDefaultFocus(); - ImGui.SameLine(); - - if (ImGui.Button("Cancel", size)) + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Rotation")) { - ImGui.CloseCurrentPopup(); + ImGui.PushID(2); + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°"); + + ImGui.PopID(); + ImGui.TreePop(); } - ImGui.EndPopup(); - } - - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem("Morph Targets")) - { - if (model.HasMorphTargets) - { - const float width = 10; - var region = ImGui.GetContentRegionAvail(); - var box = new Vector2(region.X - width, region.Y / 1.5f); - - if (ImGui.BeginListBox("", box)) + if (ImGui.TreeNode("Scale")) { - for (int i = 0; i < model.Morphs.Length; i++) + ImGui.PushID(3); + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Scale.X, speed, 0f, 0f, "%.3f"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Scale.Z, speed, 0f, 0f, "%.3f"); + + ImGui.SetNextItemWidth(width); + ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Scale.Y, speed, 0f, 0f, "%.3f"); + + ImGui.PopID(); + ImGui.TreePop(); + } + + model.UpdateMatrix(model.SelectedInstance); + ImGui.EndTabItem(); + } + if (ImGui.BeginTabItem("Morph Targets")) + { + if (model.HasMorphTargets) + { + const float width = 10; + var region = ImGui.GetContentRegionAvail(); + var box = new Vector2(region.X - width, region.Y / 1.5f); + + if (ImGui.BeginListBox("", box)) { - ImGui.PushID(i); - if (ImGui.Selectable(model.Morphs[i].Name, s.Renderer.Settings.SelectedMorph == i)) + for (int i = 0; i < model.Morphs.Length; i++) { - s.Renderer.Settings.SelectMorph(i, model); + ImGui.PushID(i); + if (ImGui.Selectable(model.Morphs[i].Name, s.Renderer.Settings.SelectedMorph == i)) + { + s.Renderer.Settings.SelectMorph(i, model); + } + ImGui.PopID(); } - ImGui.PopID(); + ImGui.EndListBox(); + + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(2f, 0f)); + ImGui.SameLine(); ImGui.PushID(99); + ImGui.VSliderFloat("", box with { X = width }, ref model.MorphTime, 0.0f, 1.0f, "", ImGuiSliderFlags.AlwaysClamp); + ImGui.PopID(); ImGui.PopStyleVar(); + ImGui.Spacing(); + ImGui.Text($"Time: {model.MorphTime:P}%"); } - ImGui.EndListBox(); - - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(2f, 0f)); - ImGui.SameLine(); ImGui.PushID(99); - ImGui.VSliderFloat("", box with { X = width }, ref model.MorphTime, 0.0f, 1.0f, "", ImGuiSliderFlags.AlwaysClamp); - ImGui.PopID(); ImGui.PopStyleVar(); - ImGui.Spacing(); - ImGui.Text($"Time: {model.MorphTime:P}%"); } + else ImGui.TextColored(_errorColor, "mesh has no morph targets"); + ImGui.EndTabItem(); } - else - { - ImGui.TextColored(_errorColor, "mesh has no morph targets"); - } - - ImGui.EndTabItem(); } - } + }); + ImGui.PopStyleVar(); } - private void DrawTransform(Model model, float speed) - { - const int width = 100; - - ImGui.PushID(0); ImGui.BeginDisabled(model.TransformsCount < 2); - ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - ImGui.SliderInt("", ref model.SelectedInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp); - ImGui.EndDisabled(); ImGui.PopID(); - - ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); - if (ImGui.TreeNode("Location")) - { - ImGui.PushID(1); - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Position.X, speed, 0f, 0f, "%.2f m"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Position.Z, speed, 0f, 0f, "%.2f m"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Position.Y, speed, 0f, 0f, "%.2f m"); - - ImGui.PopID(); - ImGui.TreePop(); - } - - ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); - if (ImGui.TreeNode("Rotation")) - { - ImGui.PushID(2); - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°"); - - ImGui.PopID(); - ImGui.TreePop(); - } - - if (ImGui.TreeNode("Scale")) - { - ImGui.PushID(3); - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Scale.X, speed, 0f, 0f, "%.3f"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Scale.Z, speed, 0f, 0f, "%.3f"); - - ImGui.SetNextItemWidth(width); - ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Scale.Y, speed, 0f, 0f, "%.3f"); - - ImGui.PopID(); - ImGui.TreePop(); - } - - model.UpdateMatrix(model.SelectedInstance); - } - - private void DrawUvChannels(Model model, Section section) + private void DrawUvChannels(Dictionary icons, Model model, Section section) { var width = ImGui.GetContentRegionAvail().X; var material = model.Materials[section.MaterialIndex]; @@ -416,47 +424,45 @@ public class SnimGui DrawSquareTexture(material.M.Texture, size); ImGui.SameLine(); DrawSquareTexture(material.Emissive[material.SelectedChannel], size); ImGui.SameLine(); } - else TextColored(_errorColor, "no texture in material section"); + else CenteredTextColored(_errorColor, "no texture in material section"); } } - private void DrawMaterials(Model model, Section section) + private void DrawMaterialInspector(Dictionary icons, Model model, Section section) { var material = model.Materials[section.MaterialIndex]; - foreach ((string key, float value) in material.Parameters.Scalars) - { - ImGui.Text($"{key}: {value}"); - } - ImGui.Spacing(); ImGui.Separator(); ImGui.Spacing(); - foreach ((string key, FLinearColor value) in material.Parameters.Colors) - { - ImGui.Text(key); ImGui.SameLine(); - ImGui.ColorButton(key, new Vector4(value.R, value.G, value.B, value.A)); - } - } - private void DrawTextures(Model model, Section section) - { - var material = model.Materials[section.MaterialIndex]; - foreach ((string key, UUnrealMaterial value) in material.Parameters.Textures) - { - ImGui.Text($"{key}: {value.Name}"); - } - } + ImGui.Spacing(); + ImGui.Image(icons["material"].GetPointer(), new Vector2(24)); + ImGui.SameLine(); ImGui.AlignTextToFramePadding(); ImGui.Text(material.Name); + ImGui.Spacing(); - private void DrawParameters(Model model, Section section) - { - const int width = 50; - var material = model.Materials[section.MaterialIndex]; - ImGui.Checkbox("Show Section", ref section.Show); - ImGui.SetNextItemWidth(width); ImGui.DragFloat("Emissive Multiplier", ref material.EmissiveMult, .01f, 0f); - ImGui.SetNextItemWidth(width); ImGui.DragFloat("UV Scale", ref material.UVScale, .01f, 0f); - if (material.HasM) + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.CollapsingHeader("Parameters")) { - ImGui.ColorEdit3("Skin Boost Color", ref material.M.SkinBoost.Color, ImGuiColorEditFlags.NoInputs); - ImGui.SetNextItemWidth(width); ImGui.DragFloat("Skin Boost Exponent", ref material.M.SkinBoost.Exponent, .01f, 0f); - ImGui.SetNextItemWidth(width); ImGui.DragFloat("AmbientOcclusion", ref material.M.AmbientOcclusion, .01f, 0f, 1f); - ImGui.SetNextItemWidth(width); ImGui.DragFloat("Cavity", ref material.M.Cavity, .01f, 0f, 1f); + material.ImGuiParameters(); + } + + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.CollapsingHeader("Properties")) + { + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Scalars")) + { + material.ImGuiDictionaries("scalars", material.Parameters.Scalars, true); + ImGui.TreePop(); + } + ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); + if (ImGui.TreeNode("Colors")) + { + material.ImGuiDictionaries("colors", material.Parameters.Colors, true); + ImGui.TreePop(); + } + if (ImGui.TreeNode("Textures")) + { + material.ImGuiDictionaries("textures", material.Parameters.Textures); + ImGui.TreePop(); + } } } @@ -515,6 +521,7 @@ public class SnimGui { if (ImGui.Begin(name)) { + Controller.Normal(); if (styled) PushStyleCompact(); content(); if (styled) PopStyleCompact(); @@ -522,20 +529,20 @@ public class SnimGui } } - private void MeshWindow(string name, Renderer renderer, Action content, bool styled = true) + private void MeshWindow(string name, Renderer renderer, Action, Model> content, bool styled = true) { Window(name, () => { - if (renderer.Cache.Models.TryGetValue(renderer.Settings.SelectedModel, out var model)) content(model); + if (renderer.Cache.Models.TryGetValue(renderer.Settings.SelectedModel, out var model)) content(renderer.Cache.Icons, model); else NoMeshSelected(); }, styled); } - private void SectionWindow(string name, Renderer renderer, Action content, bool styled = true) + private void SectionWindow(string name, Renderer renderer, Action, Model, Section> content, bool styled = true) { - MeshWindow(name, renderer, model => + MeshWindow(name, renderer, (icons, model) => { - if (renderer.Settings.TryGetSection(model, out var section)) content(model, section); + if (renderer.Settings.TryGetSection(model, out var section)) content(icons, model, section); else NoSectionSelected(); }, styled); } @@ -548,10 +555,15 @@ public class SnimGui ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, style.ItemSpacing with { Y = style.ItemSpacing.Y * 0.6f }); } - private void NoMeshSelected() => TextColored(_errorColor, "no mesh selected"); - private void NoSectionSelected() => TextColored(_errorColor, "no section selected"); - private void TextColored(Vector4 color, string text) + private void NoMeshSelected() => CenteredTextColored(_errorColor, "no mesh selected"); + private void NoSectionSelected() => CenteredTextColored(_errorColor, "no section selected"); + private void CenteredTextColored(Vector4 color, string text) { + var region = ImGui.GetContentRegionAvail(); + var size = ImGui.CalcTextSize(text); + ImGui.SetCursorPos(new Vector2( + ImGui.GetCursorPosX() + (region.X - size.X) / 2, + ImGui.GetCursorPosY() + (region.Y - size.Y) / 2)); ImGui.TextColored(color, text); } @@ -578,17 +590,43 @@ public class SnimGui } } - private void Theme(ImGuiStylePtr style) + private void Theme() { + var style = ImGui.GetStyle(); var io = ImGui.GetIO(); io.ConfigFlags |= ImGuiConfigFlags.DockingEnable; io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable; io.ConfigWindowsMoveFromTitleBarOnly = true; io.ConfigDockingWithShift = true; - style.WindowMenuButtonPosition = ImGuiDir.Right; + style.WindowPadding = new Vector2(4f); + style.FramePadding = new Vector2(3f); + style.CellPadding = new Vector2(3f, 2f); + style.ItemSpacing = new Vector2(6f, 3f); + style.ItemInnerSpacing = new Vector2(3f); + style.TouchExtraPadding = new Vector2(0f); + style.IndentSpacing = 20f; style.ScrollbarSize = 10f; - style.FrameRounding = 3.0f; + style.GrabMinSize = 8f; + style.WindowBorderSize = 0f; + style.ChildBorderSize = 0f; + style.PopupBorderSize = 0f; + style.FrameBorderSize = 0f; + style.TabBorderSize = 0f; + style.WindowRounding = 0f; + style.ChildRounding = 0f; + style.FrameRounding = 0f; + style.PopupRounding = 0f; + style.ScrollbarRounding = 0f; + style.GrabRounding = 0f; + style.LogSliderDeadzone = 0f; + style.TabRounding = 0f; + style.WindowTitleAlign = new Vector2(0.5f); + style.WindowMenuButtonPosition = ImGuiDir.Right; + style.ColorButtonPosition = ImGuiDir.Right; + style.ButtonTextAlign = new Vector2(0.5f); + style.SelectableTextAlign = new Vector2(0f); + style.DisplaySafeAreaPadding = new Vector2(3f); style.Colors[(int) ImGuiCol.Text] = new Vector4(1.00f, 1.00f, 1.00f, 1.00f); style.Colors[(int) ImGuiCol.TextDisabled] = new Vector4(0.50f, 0.50f, 0.50f, 1.00f); diff --git a/FModel/Views/Snooper/Socket.cs b/FModel/Views/Snooper/Socket.cs index 62cc8f69..a9c1c6b2 100644 --- a/FModel/Views/Snooper/Socket.cs +++ b/FModel/Views/Snooper/Socket.cs @@ -9,14 +9,15 @@ public class Socket : IDisposable public readonly string Bone; public readonly Transform Transform; - public Socket(USkeletalMeshSocket socket, Transform relation) + public Socket(USkeletalMeshSocket socket, Transform transform) { Name = socket.SocketName.Text; Bone = socket.BoneName.Text; Transform = Transform.Identity; - Transform.Relation = relation.Matrix; + Transform.Relation = transform.Matrix; Transform.Position = socket.RelativeLocation.ToMapVector() * Constants.SCALE_DOWN_RATIO; Transform.Rotation = socket.RelativeRotation; + Transform.Scale = socket.RelativeScale.ToMapVector(); } public void Dispose() diff --git a/FModel/Views/Snooper/Texture.cs b/FModel/Views/Snooper/Texture.cs index 33b41d35..1ddf7ea8 100644 --- a/FModel/Views/Snooper/Texture.cs +++ b/FModel/Views/Snooper/Texture.cs @@ -113,19 +113,7 @@ public class Texture : IDisposable for (int t = 0; t < textures.Length; t++) { - var info = Application.GetResourceStream(new Uri($"/FModel;component/Resources/{textures[t]}.png", UriKind.Relative)); - using var img = Image.Load(info.Stream); - Width = img.Width; // we don't care anyway - Height = img.Height; // we don't care anyway - GL.TexImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, PixelInternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); - - img.ProcessPixelRows(accessor => - { - for (int y = 0; y < accessor.Height; y++) - { - GL.TexSubImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, 0, y, accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, accessor.GetRowSpan(y).ToArray()); - } - }); + ProcessPixels(textures[t], TextureTarget.TextureCubeMapPositiveX + t); } GL.TexParameter(_target, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear); @@ -135,21 +123,33 @@ public class Texture : IDisposable GL.TexParameter(_target, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge); } - public Texture(uint width, uint height, IntPtr data) : this(TextureType.Normal) + public Texture(string texture) : this(TextureType.Normal) { - Width = (int) width; - Height = (int) height; - Bind(_target); + Bind(TextureUnit.Texture0); - GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba8, Width, Height); - GL.TexSubImage2D(_target, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, data); + ProcessPixels(texture, _target); - var repeat = (int) TextureWrapMode.Repeat; - GL.TexParameterI(_target, TextureParameterName.TextureWrapS, ref repeat); - GL.TexParameterI(_target, TextureParameterName.TextureWrapT, ref repeat); + GL.TexParameter(_target, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear); + GL.TexParameter(_target, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Linear); + GL.TexParameter(_target, TextureParameterName.TextureWrapR, (int) TextureWrapMode.ClampToEdge); + GL.TexParameter(_target, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge); + GL.TexParameter(_target, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge); + } - var zero = 1 - 1; - GL.TexParameterI(_target, TextureParameterName.TextureMaxLevel, ref zero); + private void ProcessPixels(string texture, TextureTarget target) + { + var info = Application.GetResourceStream(new Uri($"/FModel;component/Resources/{texture}.png", UriKind.Relative)); + using var img = Image.Load(info.Stream); + Width = img.Width; + Height = img.Height; + GL.TexImage2D(target, 0, PixelInternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero); + img.ProcessPixelRows(accessor => + { + for (int y = 0; y < accessor.Height; y++) + { + GL.TexSubImage2D(target, 0, 0, y, accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, accessor.GetRowSpan(y).ToArray()); + } + }); } public void Bind(TextureUnit textureSlot)