imgui icons + material inspector v.final +/-

This commit is contained in:
4sval 2022-11-16 01:35:30 +01:00
parent 9d7e491bf3
commit d0963bd018
9 changed files with 453 additions and 314 deletions

@ -1 +1 @@
Subproject commit 7a13a4e1c46e8a084f681e1a1a8702de695da3fa
Subproject commit 2e3274d96eb02b4b376f9f44942da81593130d28

View File

@ -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;

View File

@ -1,4 +1,4 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using EpicManifestParser.Objects;

View File

@ -13,6 +13,7 @@ public class Cache : IDisposable
{
public readonly Dictionary<FGuid, Model> Models;
public readonly Dictionary<FGuid, Texture> Textures;
public readonly Dictionary<string, Texture> Icons;
private ETexturePlatform _platform;
private readonly FGame _game;
@ -21,8 +22,11 @@ public class Cache : IDisposable
{
Models = new Dictionary<FGuid, Model>();
Textures = new Dictionary<FGuid, Texture>();
Icons = new Dictionary<string, Texture>();
_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();
}
}

View File

@ -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<T>(string id, Dictionary<string, T> 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++)

View File

@ -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);
}

View File

@ -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<string, Texture> 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<string, Texture> 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<Model> content, bool styled = true)
private void MeshWindow(string name, Renderer renderer, Action<Dictionary<string, Texture>, 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<Model, Section> content, bool styled = true)
private void SectionWindow(string name, Renderer renderer, Action<Dictionary<string, Texture>, 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);

View File

@ -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()

View File

@ -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<Rgba32>(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<Rgba32>(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)