From fd709d08b7d35e30cbd2b6c47bd06a13aacec358 Mon Sep 17 00:00:00 2001 From: 4sval Date: Fri, 16 Dec 2022 01:14:15 +0100 Subject: [PATCH] texture viewer --- CUE4Parse | 2 +- FModel/Views/Snooper/Material.cs | 44 +++++++++++++++++++++++++------- FModel/Views/Snooper/Options.cs | 5 +++- FModel/Views/Snooper/SnimGui.cs | 39 ++++++++++++++++++++++++---- FModel/Views/Snooper/Texture.cs | 9 ++++--- 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 19559b2e..75cf4d4e 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 19559b2ec9a84ba47f57245f26cf861b8f00f8b0 +Subproject commit 75cf4d4e0ddcc3742121e9990c6aad9220ab938a diff --git a/FModel/Views/Snooper/Material.cs b/FModel/Views/Snooper/Material.cs index 9b63ed39..37972ff8 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 CUE4Parse.UE4.Objects.Core.Misc; using ImGuiNET; using OpenTK.Graphics.OpenGL4; @@ -282,7 +283,7 @@ public class Material : IDisposable } } - public void ImGuiTextures(Dictionary icons, Model model) + public bool ImGuiTextures(Dictionary icons, Model model) { if (ImGui.BeginTable("material_textures", 2)) { @@ -309,21 +310,46 @@ public class Material : IDisposable ImGui.EndTable(); } - ImGui.Image(GetSelectedTexture() ?? icons["noimage"].GetPointer(), + var texture = GetSelectedTexture() ?? icons["noimage"]; + ImGui.Image(texture.GetPointer(), new Vector2(ImGui.GetContentRegionAvail().X - ImGui.GetScrollX()), Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1.0f, 1.0f, 1.0f, 0.25f)); - ImGui.Spacing(); + return ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left); } - private IntPtr? GetSelectedTexture() + public Vector2[] ImGuiTextureViewer(Dictionary icons, Model model) + { + var texture = GetSelectedTexture() ?? icons["noimage"]; + if (ImGui.BeginTable("texture_viewer_table", 2, ImGuiTableFlags.SizingStretchProp)) + { + SnimGui.Layout("Type");ImGui.Text($" : ({texture.Format}) {texture.Name}"); + SnimGui.TooltipCopy("(?) Click to Copy Path", texture.Path); + SnimGui.Layout("Guid");ImGui.Text($" : {texture.Guid.ToString(EGuidFormats.UniqueObjectGuid)}"); + SnimGui.Layout("Import");ImGui.Text($" : {texture.ImportedWidth}x{texture.ImportedHeight}"); + SnimGui.Layout("Export");ImGui.Text($" : {texture.Width}x{texture.Height}"); + ImGui.EndTable(); + } + + var largest = ImGui.GetContentRegionAvail(); + largest.X -= ImGui.GetScrollX(); + largest.Y -= ImGui.GetScrollY(); + + var ratio = Math.Min(largest.X / texture.Width, largest.Y / texture.Height); + var size = new Vector2(texture.Width * ratio, texture.Height * ratio); + var pos = ImGui.GetCursorPos(); + ImGui.Image(texture.GetPointer(),size, Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1.0f, 1.0f, 1.0f, 0.25f)); + return new[] { size, pos }; + } + + private Texture GetSelectedTexture() { return SelectedTexture switch { - 0 => Diffuse[SelectedChannel]?.GetPointer(), - 1 => Normals[SelectedChannel]?.GetPointer(), - 2 => SpecularMasks[SelectedChannel]?.GetPointer(), - 3 => Ao.Texture?.GetPointer(), - 4 => Emissive[SelectedChannel]?.GetPointer(), + 0 => Diffuse[SelectedChannel], + 1 => Normals[SelectedChannel], + 2 => SpecularMasks[SelectedChannel], + 3 => Ao.Texture, + 4 => Emissive[SelectedChannel], _ => null }; } diff --git a/FModel/Views/Snooper/Options.cs b/FModel/Views/Snooper/Options.cs index 10c73195..dbc1edfb 100644 --- a/FModel/Views/Snooper/Options.cs +++ b/FModel/Views/Snooper/Options.cs @@ -102,7 +102,7 @@ public class Options } /// - /// Red : Specular + /// Red : Specular (if possible) /// Blue : Roughness /// Green : Metallic /// @@ -129,6 +129,9 @@ public class Options } break; } + // R: Roughness + // G: Metallic + // B: Whatever (AO / S / E / ...) case "ccff7r": { unsafe diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 9449ef6b..02b89c18 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -44,6 +44,8 @@ public class SnimGui private readonly Save _saver = new (); private readonly string _renderer; private readonly string _version; + private bool _openTextureViewer; + private bool _overlayUvOverTexture; private bool _viewportFocus; private readonly Vector4 _accentColor = new (0.125f, 0.42f, 0.831f, 1.0f); @@ -76,6 +78,7 @@ public class SnimGui Draw3DViewport(s); DrawNavbar(); + if (_openTextureViewer) DrawTextureViewer(s); Controller.Render(); } @@ -581,9 +584,9 @@ hello world! } ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); - if (ImGui.CollapsingHeader("Textures")) + if (ImGui.CollapsingHeader("Textures") && material.ImGuiTextures(icons, model)) { - material.ImGuiTextures(icons, model); + _openTextureViewer = true; } ImGui.SetNextItemOpen(true, ImGuiCond.Appearing); @@ -615,6 +618,32 @@ hello world! } } + private void DrawTextureViewer(Snooper s) + { + if (ImGui.Begin("Texture Viewer", ref _openTextureViewer, ImGuiWindowFlags.NoScrollbar) && + s.Renderer.Options.TryGetModel(out var model) && + s.Renderer.Options.TryGetSection(model, out var section)) + { + var vectors = model.Materials[section.MaterialIndex].ImGuiTextureViewer(s.Renderer.Options.Icons, model); + if (_overlayUvOverTexture) + { + var size = vectors[0]; + var drawList = ImGui.GetWindowDrawList(); + drawList.PushClipRect(size, size, true); + ImGui.SetCursorPos(vectors[1]); + ImGui.InvisibleButton("canvas", size, ImGuiButtonFlags.MouseButtonLeft | ImGuiButtonFlags.MouseButtonRight); + drawList.AddLine(new Vector2(0, 0), size, 255, 2f); + drawList.PopClipRect(); + } + Popup(() => + { + if (ImGui.MenuItem("Overlay UVs", null, _overlayUvOverTexture)) + _overlayUvOverTexture = !_overlayUvOverTexture; + }); + } + ImGui.End(); // if window is collapsed + } + private void Draw3DViewport(Snooper s) { ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); @@ -752,15 +781,15 @@ hello world! ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); } - public static void TooltipCopy(string name) + public static void TooltipCopy(string label, string text = null) { if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); - ImGui.Text(name); + ImGui.Text(label); ImGui.EndTooltip(); } - if (ImGui.IsItemClicked()) ImGui.SetClipboardText(name); + if (ImGui.IsItemClicked()) ImGui.SetClipboardText(text ?? label); } private void Theme() diff --git a/FModel/Views/Snooper/Texture.cs b/FModel/Views/Snooper/Texture.cs index 1ddf7ea8..21ece32f 100644 --- a/FModel/Views/Snooper/Texture.cs +++ b/FModel/Views/Snooper/Texture.cs @@ -2,6 +2,7 @@ using System; using System.Windows; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.UE4.Objects.Core.Misc; using OpenTK.Graphics.OpenGL4; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -15,6 +16,7 @@ public class Texture : IDisposable private readonly TextureTarget _target; public readonly string Type; + public readonly FGuid Guid; public readonly string Name; public readonly string Path; public readonly EPixelFormat Format; @@ -22,7 +24,6 @@ public class Texture : IDisposable public readonly uint ImportedHeight; public int Width; public int Height; - public string Label; public Texture(TextureType type) { @@ -34,7 +35,8 @@ public class Texture : IDisposable TextureType.MsaaFramebuffer => TextureTarget.Texture2DMultisample, _ => TextureTarget.Texture2D }; - Label = "(?) Click to Copy Path"; + + Guid = new FGuid(); } public Texture(uint width, uint height) : this(TextureType.MsaaFramebuffer) @@ -72,8 +74,9 @@ public class Texture : IDisposable public Texture(byte[] data, int width, int height, UTexture2D texture2D) : this(TextureType.Normal) { Type = texture2D.ExportType; + Guid = texture2D.LightingGuid; Name = texture2D.Name; - Path = texture2D.Owner?.Name; + Path = texture2D.GetPathName(); Format = texture2D.Format; ImportedWidth = texture2D.ImportedSize.X; ImportedHeight = texture2D.ImportedSize.Y;