mirror of
https://github.com/4sval/FModel.git
synced 2026-03-28 20:55:38 -05:00
added a guizmo for model transformation
This commit is contained in:
parent
0e4d0431a3
commit
e8b061f018
|
|
@ -1 +1 @@
|
|||
Subproject commit 24c816dfd462a95e087344419486a8f8008f77f5
|
||||
Subproject commit 4514f1acd51c9d3458eb0eda0abf37bb77453d2b
|
||||
|
|
@ -156,7 +156,6 @@
|
|||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageReference Include="EpicManifestParser" Version="2.4.1" />
|
||||
<PackageReference Include="EpicManifestParser.ZlibngDotNetDecompressor" Version="1.0.1" />
|
||||
<PackageReference Include="ImGui.NET" Version="1.91.0.1" />
|
||||
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.5" />
|
||||
|
|
@ -168,6 +167,7 @@
|
|||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
|
||||
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.9" />
|
||||
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
|
||||
<PackageReference Include="Twizzle.ImGui-Bundle.NET" Version="1.91.5.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using FModel.Settings;
|
||||
using ImGuiNET;
|
||||
using ImGuizmoNET;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
|
|
@ -54,11 +54,12 @@ public class ImGuiController : IDisposable
|
|||
|
||||
int major = GL.GetInteger(GetPName.MajorVersion);
|
||||
int minor = GL.GetInteger(GetPName.MinorVersion);
|
||||
|
||||
KHRDebugAvailable = (major == 4 && minor >= 3) || IsExtensionSupported("KHR_debug");
|
||||
|
||||
IntPtr context = ImGui.CreateContext();
|
||||
ImGui.SetCurrentContext(context);
|
||||
IntPtr imguiCtx = ImGui.CreateContext();
|
||||
ImGui.SetCurrentContext(imguiCtx);
|
||||
|
||||
var io = ImGui.GetIO();
|
||||
unsafe
|
||||
|
|
@ -69,32 +70,24 @@ public class ImGuiController : IDisposable
|
|||
FontNormal = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 16 * DpiScale);
|
||||
FontBold = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeuib.ttf", 16 * DpiScale);
|
||||
FontSemiBold = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\seguisb.ttf", 16 * DpiScale);
|
||||
io.Fonts.AddFontDefault();
|
||||
io.Fonts.Build(); // Build font atlas
|
||||
|
||||
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
|
||||
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
|
||||
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable;
|
||||
io.Fonts.Flags |= ImFontAtlasFlags.NoBakedLines;
|
||||
// io.ConfigDockingWithShift = true;
|
||||
io.ConfigDockingWithShift = true;
|
||||
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
||||
io.BackendRendererUserData = 0;
|
||||
|
||||
CreateDeviceResources();
|
||||
|
||||
SetPerFrameImGuiData(1f / 60f);
|
||||
|
||||
ImGui.NewFrame();
|
||||
_frameBegun = true;
|
||||
}
|
||||
|
||||
public void Normal() => PushFont(FontNormal);
|
||||
public void Bold() => PushFont(FontBold);
|
||||
public void SemiBold() => PushFont(FontSemiBold);
|
||||
|
||||
public void PopFont()
|
||||
{
|
||||
ImGui.PopFont();
|
||||
PushFont(FontNormal);
|
||||
}
|
||||
|
||||
private void PushFont(ImFontPtr ptr) => ImGui.PushFont(ptr);
|
||||
|
||||
public void WindowResized(int width, int height)
|
||||
|
|
@ -132,34 +125,42 @@ public class ImGuiController : IDisposable
|
|||
|
||||
RecreateFontDeviceTexture();
|
||||
|
||||
string VertexSource = @"#version 460 core
|
||||
string VertexSource = @"#version 330 core
|
||||
|
||||
uniform mat4 projection_matrix;
|
||||
|
||||
layout(location = 0) in vec2 in_position;
|
||||
layout(location = 1) in vec2 in_texCoord;
|
||||
layout(location = 2) in vec4 in_color;
|
||||
|
||||
out vec4 color;
|
||||
out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection_matrix * vec4(in_position, 0, 1);
|
||||
color = in_color;
|
||||
texCoord = in_texCoord;
|
||||
gl_Position = projection_matrix * vec4(in_position, 0, 1);
|
||||
color = in_color;
|
||||
texCoord = in_texCoord;
|
||||
}";
|
||||
string FragmentSource = @"#version 460 core
|
||||
string FragmentSource = @"#version 330 core
|
||||
|
||||
uniform sampler2D in_fontTexture;
|
||||
|
||||
in vec4 color;
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
outputColor = color * texture(in_fontTexture, texCoord);
|
||||
outputColor = color * texture(in_fontTexture, texCoord);
|
||||
}";
|
||||
|
||||
_shader = CreateProgram("ImGui", VertexSource, FragmentSource);
|
||||
_shaderProjectionMatrixLocation = GL.GetUniformLocation(_shader, "projection_matrix");
|
||||
_shaderFontTextureLocation = GL.GetUniformLocation(_shader, "in_fontTexture");
|
||||
|
||||
int stride = Unsafe.SizeOf<ImDrawVert>();
|
||||
int stride = Marshal.SizeOf<ImDrawVert>();
|
||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, stride, 0);
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 8);
|
||||
GL.VertexAttribPointer(2, 4, VertexAttribPointerType.UnsignedByte, true, stride, 16);
|
||||
|
|
@ -225,7 +226,6 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
ImGui.Render();
|
||||
RenderImDrawData(ImGui.GetDrawData());
|
||||
}
|
||||
CheckGLError("End of frame");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -243,6 +243,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
|
||||
_frameBegun = true;
|
||||
ImGui.NewFrame();
|
||||
ImGuizmo.BeginFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -252,7 +253,6 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
private void SetPerFrameImGuiData(float deltaSeconds)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
// if (io.WantSaveIniSettings) ImGui.SaveIniSettingsToDisk(_iniPath);
|
||||
io.DisplaySize = new Vector2(
|
||||
_windowWidth / _scaleFactor.X,
|
||||
_windowHeight / _scaleFactor.Y);
|
||||
|
|
@ -265,6 +265,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
private void UpdateImGuiInput(GameWindow wnd)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
|
||||
var mState = wnd.MouseState;
|
||||
var kState = wnd.KeyboardState;
|
||||
|
||||
|
|
@ -276,7 +277,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
io.AddMouseButtonEvent(4, mState[MouseButton.Button2]);
|
||||
io.AddMouseWheelEvent(mState.ScrollDelta.X, mState.ScrollDelta.Y);
|
||||
|
||||
foreach (Keys key in Enum.GetValues(typeof(Keys)))
|
||||
foreach (Keys key in Enum.GetValues<Keys>())
|
||||
{
|
||||
if (key == Keys.Unknown) continue;
|
||||
io.AddKeyEvent(TranslateKey(key), kState.IsKeyDown(key));
|
||||
|
|
@ -294,7 +295,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
io.KeySuper = kState.IsKeyDown(Keys.LeftSuper) || kState.IsKeyDown(Keys.RightSuper);
|
||||
}
|
||||
|
||||
public void PressChar(char keyChar)
|
||||
internal void PressChar(char keyChar)
|
||||
{
|
||||
PressedChars.Add(keyChar);
|
||||
}
|
||||
|
|
@ -340,7 +341,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
{
|
||||
ImDrawListPtr cmd_list = draw_data.CmdLists[i];
|
||||
|
||||
int vertexSize = cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>();
|
||||
int vertexSize = cmd_list.VtxBuffer.Size * Marshal.SizeOf<ImDrawVert>();
|
||||
if (vertexSize > _vertexBufferSize)
|
||||
{
|
||||
int newSize = (int)Math.Max(_vertexBufferSize * 1.5f, vertexSize);
|
||||
|
|
@ -390,7 +391,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
{
|
||||
ImDrawListPtr cmd_list = draw_data.CmdLists[n];
|
||||
|
||||
GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>(), cmd_list.VtxBuffer.Data);
|
||||
GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, cmd_list.VtxBuffer.Size * Marshal.SizeOf<ImDrawVert>(), cmd_list.VtxBuffer.Data);
|
||||
CheckGLError($"Data Vert {n}");
|
||||
|
||||
GL.BufferSubData(BufferTarget.ElementArrayBuffer, IntPtr.Zero, cmd_list.IdxBuffer.Size * sizeof(ushort), cmd_list.IdxBuffer.Data);
|
||||
|
|
@ -544,16 +545,16 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
|
||||
public static ImGuiKey TranslateKey(Keys key)
|
||||
{
|
||||
if (key is >= Keys.D0 and <= Keys.D9)
|
||||
if (key >= Keys.D0 && key <= Keys.D9)
|
||||
return key - Keys.D0 + ImGuiKey._0;
|
||||
|
||||
if (key is >= Keys.A and <= Keys.Z)
|
||||
if (key >= Keys.A && key <= Keys.Z)
|
||||
return key - Keys.A + ImGuiKey.A;
|
||||
|
||||
if (key is >= Keys.KeyPad0 and <= Keys.KeyPad9)
|
||||
if (key >= Keys.KeyPad0 && key <= Keys.KeyPad9)
|
||||
return key - Keys.KeyPad0 + ImGuiKey.Keypad0;
|
||||
|
||||
if (key is >= Keys.F1 and <= Keys.F24)
|
||||
if (key >= Keys.F1 && key <= Keys.F24)
|
||||
return key - Keys.F1 + ImGuiKey.F24;
|
||||
|
||||
return key switch
|
||||
|
|
@ -596,7 +597,7 @@ outputColor = color * texture(in_fontTexture, texCoord);
|
|||
Keys.KeyPadAdd => ImGuiKey.KeypadAdd,
|
||||
Keys.KeyPadEnter => ImGuiKey.KeypadEnter,
|
||||
Keys.KeyPadEqual => ImGuiKey.KeypadEqual,
|
||||
Keys.LeftShift => ImGuiKey.LeftShift,
|
||||
Keys.LeftShift => ImGuiKey.ModShift,
|
||||
Keys.LeftControl => ImGuiKey.LeftCtrl,
|
||||
Keys.LeftAlt => ImGuiKey.LeftAlt,
|
||||
Keys.LeftSuper => ImGuiKey.LeftSuper,
|
||||
|
|
|
|||
|
|
@ -390,6 +390,12 @@ public class CUE4ParseViewModel : ViewModel
|
|||
FLogger.Text("Additive animations have their reference pose stripped, which will lead to inaccurate preview and export", Constants.WHITE, true));
|
||||
}
|
||||
|
||||
if (Provider.Versions.Game is EGame.GAME_UE4_LATEST or EGame.GAME_UE5_LATEST && !Provider.ProjectName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase)) // ignore fortnite globally
|
||||
{
|
||||
FLogger.Append(ELog.Warning, () =>
|
||||
FLogger.Text($"Experimental UE version selected, likely unsuitable for '{Provider.GameDisplayName ?? Provider.ProjectName}'", Constants.WHITE, true));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
@ -578,7 +584,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "manifest":
|
||||
case "uplugin":
|
||||
case "archive":
|
||||
case "vmodule":
|
||||
case "vmodule":
|
||||
case "uparam": // Steel Hunters
|
||||
case "verse":
|
||||
case "html":
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ public class SkeletalModel : UModel
|
|||
public void Render(Shader shader)
|
||||
{
|
||||
shader.SetUniform("uMorphTime", MorphTime);
|
||||
shader.SetUniform("uIsSpline", false);
|
||||
Skeleton.Render(shader);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -373,6 +373,7 @@ public abstract class UModel : IRenderableModel
|
|||
MatrixVbo = new BufferObject<Matrix4x4>(TransformsCount, BufferTarget.ArrayBuffer);
|
||||
for (int instance = 0; instance < TransformsCount; instance++)
|
||||
{
|
||||
Transforms[instance].Save();
|
||||
MatrixVbo.Update(instance, Transforms[instance].Matrix);
|
||||
}
|
||||
Vao.BindInstancing(); // VertexAttributePointer
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ public class Material : IDisposable
|
|||
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));
|
||||
Vector2.Zero, Vector2.One);
|
||||
return ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using FModel.Settings;
|
|||
using FModel.Views.Snooper.Animations;
|
||||
using FModel.Views.Snooper.Models;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
using ImGuizmoNET;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
|
@ -67,7 +68,9 @@ public class SnimGui
|
|||
|
||||
private Vector2 _outlinerSize;
|
||||
private bool _tiOpen;
|
||||
private bool _transformOpen;
|
||||
private bool _viewportFocus;
|
||||
private OPERATION _guizmoOperation;
|
||||
|
||||
private readonly Vector4 _accentColor = new (0.125f, 0.42f, 0.831f, 1.0f);
|
||||
private readonly Vector4 _alertColor = new (0.831f, 0.573f, 0.125f, 1.0f);
|
||||
|
|
@ -82,14 +85,14 @@ public class SnimGui
|
|||
_renderer = GL.GetString(StringName.Renderer);
|
||||
_version = "OpenGL " + GL.GetString(StringName.Version);
|
||||
_tableWidth = 17 * Controller.DpiScale;
|
||||
_guizmoOperation = OPERATION.TRANSLATE;
|
||||
|
||||
Theme();
|
||||
}
|
||||
|
||||
public void Render(Snooper s)
|
||||
{
|
||||
Controller.SemiBold();
|
||||
DrawDockSpace(s.ClientSize);
|
||||
ImGui.DockSpaceOverViewport(_dockspaceId, ImGui.GetMainViewport(), ImGuiDockNodeFlags.PassthruCentralNode);
|
||||
|
||||
SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false);
|
||||
AnimationWindow("Timeline", s.Renderer, (icons, tracker, animations) =>
|
||||
|
|
@ -249,22 +252,6 @@ public class SnimGui
|
|||
}
|
||||
}
|
||||
|
||||
private void DrawDockSpace(OpenTK.Mathematics.Vector2i size)
|
||||
{
|
||||
const ImGuiWindowFlags flags =
|
||||
ImGuiWindowFlags.MenuBar | ImGuiWindowFlags.NoDocking |
|
||||
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize |
|
||||
ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoMove |
|
||||
ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoNavFocus;
|
||||
|
||||
ImGui.SetNextWindowPos(new Vector2(0, 0));
|
||||
ImGui.SetNextWindowSize(new Vector2(size.X, size.Y));
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
ImGui.Begin("Oui oui", flags);
|
||||
ImGui.PopStyleVar();
|
||||
ImGui.DockSpace(_dockspaceId);
|
||||
}
|
||||
|
||||
private void DrawNavbar()
|
||||
{
|
||||
if (!ImGui.BeginMainMenuBar()) return;
|
||||
|
|
@ -604,14 +591,43 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Transform"))
|
||||
_transformOpen = ImGui.BeginTabItem("Transform");
|
||||
if (_transformOpen)
|
||||
{
|
||||
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();
|
||||
|
||||
model.Transforms[model.SelectedInstance].ImGuiTransform(s.Renderer.CameraOp.Speed / 100f);
|
||||
if (ImGui.BeginTable("guizmo_controls", 2, ImGuiTableFlags.SizingStretchProp))
|
||||
{
|
||||
var t = model.Transforms[model.SelectedInstance];
|
||||
var c = _guizmoOperation switch
|
||||
{
|
||||
OPERATION.TRANSLATE => 0,
|
||||
OPERATION.ROTATE => 1,
|
||||
OPERATION.SCALE => 2,
|
||||
_ => 3
|
||||
};
|
||||
|
||||
Layout("Operation ");
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X * 0.6f);
|
||||
ImGui.PushID(1);ImGui.Combo("", ref c, "Translate\0Rotate\0Scale\0");
|
||||
ImGui.PopID();ImGui.SameLine();if (ImGui.Button("Reset All")) t.Reset();
|
||||
Layout("Position");ImGui.Text(t.Position.ToString());
|
||||
Layout("Rotation");ImGui.Text(t.Rotation.ToString());
|
||||
Layout("Scale");ImGui.Text(t.Scale.ToString());
|
||||
|
||||
_guizmoOperation = c switch
|
||||
{
|
||||
0 => OPERATION.TRANSLATE,
|
||||
1 => OPERATION.ROTATE,
|
||||
2 => OPERATION.SCALE,
|
||||
_ => OPERATION.UNIVERSAL
|
||||
};
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
|
@ -719,8 +735,8 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
{
|
||||
(model.Materials[section.MaterialIndex].GetSelectedTexture() ?? s.Renderer.Options.Icons["noimage"]).ImGuiTextureInspector();
|
||||
}
|
||||
ImGui.End(); // if window is collapsed
|
||||
}
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
private void DrawSkeletonTree(Snooper s)
|
||||
|
|
@ -741,8 +757,8 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.EndTable();
|
||||
}
|
||||
}
|
||||
ImGui.End(); // if window is collapsed
|
||||
}
|
||||
ImGui.End();
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
|
|
@ -756,41 +772,54 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
largest.Y -= ImGui.GetScrollY();
|
||||
|
||||
var size = new Vector2(largest.X, largest.Y);
|
||||
var pos = ImGui.GetWindowPos();
|
||||
var fHeight = ImGui.GetFrameHeight();
|
||||
|
||||
s.Renderer.CameraOp.AspectRatio = size.X / size.Y;
|
||||
ImGui.Image(s.Framebuffer.GetPointer(), size, new Vector2(0, 1), new Vector2(1, 0), Vector4.One);
|
||||
ImGui.Image(s.Framebuffer.GetPointer(), size, new Vector2(0, 1), new Vector2(1, 0));
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
if (_transformOpen)
|
||||
{
|
||||
// if left button down while mouse is hover viewport
|
||||
if (ImGui.IsMouseDown(ImGuiMouseButton.Left) && !_viewportFocus)
|
||||
{
|
||||
_viewportFocus = true;
|
||||
s.CursorState = CursorState.Grabbed;
|
||||
}
|
||||
if (ImGui.IsMouseClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
var guid = s.Renderer.Picking.ReadPixel(ImGui.GetMousePos(), ImGui.GetCursorScreenPos(), size);
|
||||
s.Renderer.Options.SelectModel(guid);
|
||||
ImGui.SetWindowFocus("Outliner");
|
||||
ImGui.SetWindowFocus("Details");
|
||||
}
|
||||
ImGuizmo.SetDrawlist(ImGui.GetWindowDrawList());
|
||||
ImGuizmo.SetRect(pos.X, pos.Y + fHeight, size.X, size.Y);
|
||||
DrawGuizmo(s);
|
||||
}
|
||||
|
||||
if (ImGui.IsMouseDragging(ImGuiMouseButton.Left) && _viewportFocus)
|
||||
if (!ImGuizmo.IsUsing())
|
||||
{
|
||||
s.Renderer.CameraOp.Modify(ImGui.GetIO().MouseDelta);
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
// if left button down while mouse is hover viewport
|
||||
if (ImGui.IsMouseDown(ImGuiMouseButton.Left) && !_viewportFocus)
|
||||
{
|
||||
_viewportFocus = true;
|
||||
s.CursorState = CursorState.Grabbed;
|
||||
}
|
||||
if (ImGui.IsMouseClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
var guid = s.Renderer.Picking.ReadPixel(ImGui.GetMousePos(), ImGui.GetCursorScreenPos(), size);
|
||||
s.Renderer.Options.SelectModel(guid);
|
||||
ImGui.SetWindowFocus("Outliner");
|
||||
ImGui.SetWindowFocus("Details");
|
||||
}
|
||||
}
|
||||
|
||||
// if left button up and mouse was in viewport
|
||||
if (ImGui.IsMouseReleased(ImGuiMouseButton.Left) && _viewportFocus)
|
||||
{
|
||||
_viewportFocus = false;
|
||||
s.CursorState = CursorState.Normal;
|
||||
if (_viewportFocus && ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||
{
|
||||
s.Renderer.CameraOp.Modify(ImGui.GetIO().MouseDelta);
|
||||
}
|
||||
|
||||
// if left button up and mouse was in viewport
|
||||
if (_viewportFocus && ImGui.IsMouseReleased(ImGuiMouseButton.Left))
|
||||
{
|
||||
_viewportFocus = false;
|
||||
s.CursorState = CursorState.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
const float margin = 7.5f;
|
||||
var buttonWidth = 14.0f * ImGui.GetWindowDpiScale();
|
||||
var basePos = new Vector2( size.X - buttonWidth - margin * 2, ImGui.GetFrameHeight() + margin);
|
||||
var basePos = new Vector2( size.X - buttonWidth - margin * 2, fHeight + margin);
|
||||
ImGui.SetCursorPos(basePos);
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f));
|
||||
|
|
@ -821,6 +850,26 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
private void DrawGuizmo(Snooper s)
|
||||
{
|
||||
var enableGuizmo = s.Renderer.Options.TryGetModel(out var selected) && selected.IsVisible;
|
||||
if (enableGuizmo)
|
||||
{
|
||||
var view = s.Renderer.CameraOp.GetViewMatrix();
|
||||
var proj = s.Renderer.CameraOp.GetProjectionMatrix();
|
||||
var transform = selected.Transforms[selected.SelectedInstance];
|
||||
var matrix = transform.Matrix;
|
||||
|
||||
if (ImGuizmo.Manipulate(ref view.M11, ref proj.M11, _guizmoOperation, MODE.LOCAL, ref matrix.M11) &&
|
||||
Matrix4x4.Invert(transform.Relation, out var invRelation)) // matrix * invRelation = local matrix
|
||||
{
|
||||
// ^ long story short: there was issues with other transformation methods
|
||||
// that's one way of modifying root elements without breaking the world matrix
|
||||
transform.ModifyLocal(matrix * invRelation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Popup(Action content)
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(4f));
|
||||
|
|
@ -850,12 +899,13 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
{
|
||||
if (ImGui.Begin(name, ImGuiWindowFlags.NoScrollbar))
|
||||
{
|
||||
Controller.PopFont();
|
||||
Controller.Normal();
|
||||
if (styled) PushStyleCompact();
|
||||
content();
|
||||
if (styled) PopStyleCompact();
|
||||
ImGui.End();
|
||||
ImGui.PopFont();
|
||||
}
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
private void MeshWindow(string name, Renderer renderer, Action<Dictionary<string, Texture>, UModel> content, bool styled = true)
|
||||
|
|
@ -908,7 +958,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.GetCursorPosY() + (region.Y - size.Y) / 2));
|
||||
Controller.Bold();
|
||||
ImGui.TextColored(color, text);
|
||||
Controller.PopFont();
|
||||
ImGui.PopFont();
|
||||
}
|
||||
|
||||
public static void Layout(string name, bool tooltip = false)
|
||||
|
|
@ -1027,7 +1077,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
style.Colors[(int) ImGuiCol.TableRowBgAlt] = new Vector4(1.00f, 1.00f, 1.00f, 0.06f);
|
||||
style.Colors[(int) ImGuiCol.TextSelectedBg] = new Vector4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||
style.Colors[(int) ImGuiCol.DragDropTarget] = new Vector4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||
style.Colors[(int) ImGuiCol.NavHighlight] = new Vector4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||
style.Colors[(int) ImGuiCol.NavCursor] = new Vector4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||
style.Colors[(int) ImGuiCol.NavWindowingHighlight] = new Vector4(1.00f, 1.00f, 1.00f, 0.70f);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -16,63 +15,37 @@ public class Transform
|
|||
public FQuat Rotation = FQuat.Identity;
|
||||
public FVector Scale = FVector.OneVector;
|
||||
|
||||
public Matrix4x4 LocalMatrix =>
|
||||
Matrix4x4.CreateScale(Scale.X, Scale.Z, Scale.Y) *
|
||||
Matrix4x4.CreateFromQuaternion(Quaternion.Normalize(new Quaternion(Rotation.X, Rotation.Z, Rotation.Y, -Rotation.W))) *
|
||||
Matrix4x4.CreateTranslation(Position.X, Position.Z, Position.Y);
|
||||
private Matrix4x4? _saved;
|
||||
public Matrix4x4 LocalMatrix => Matrix4x4.CreateScale(Scale.X, Scale.Z, Scale.Y) *
|
||||
Matrix4x4.CreateFromQuaternion(Quaternion.Normalize(new Quaternion(Rotation.X, Rotation.Z, Rotation.Y, -Rotation.W))) *
|
||||
Matrix4x4.CreateTranslation(Position.X, Position.Z, Position.Y);
|
||||
public Matrix4x4 Matrix => LocalMatrix * Relation;
|
||||
|
||||
public void ImGuiTransform(float speed)
|
||||
public void Save()
|
||||
{
|
||||
const float width = 100f;
|
||||
_saved = LocalMatrix;
|
||||
}
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Location"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Position.X, speed, 0f, 0f, "%.2f m");
|
||||
public void ModifyLocal(Matrix4x4 matrix)
|
||||
{
|
||||
Matrix4x4.Decompose(matrix, out var scale, out var rotation, out var position);
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Position.Z, speed, 0f, 0f, "%.2f m");
|
||||
Scale.X = scale.X;
|
||||
Scale.Y = scale.Z;
|
||||
Scale.Z = scale.Y;
|
||||
Rotation.X = rotation.X;
|
||||
Rotation.Y = rotation.Z;
|
||||
Rotation.Z = rotation.Y;
|
||||
Rotation.W = -rotation.W;
|
||||
Position.X = position.X;
|
||||
Position.Z = position.Y;
|
||||
Position.Y = position.Z;
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Position.Y, speed, 0f, 0f, "%.2f m");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Rotation"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("W", ref Rotation.W, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Rotation.X, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Rotation.Z, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Rotation.Y, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Scale"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Scale.X, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Scale.Z, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Scale.Y, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
if (!_saved.HasValue) return;
|
||||
ModifyLocal(_saved.Value);
|
||||
}
|
||||
|
||||
public override string ToString() => Matrix.Translation.ToString();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user