mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
switch to ImTool
This commit is contained in:
parent
ac124e8f08
commit
eabf6d9bcf
496
FModel/Extensions/ImGuiControllerExtensions.cs
Normal file
496
FModel/Extensions/ImGuiControllerExtensions.cs
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using FModel.Framework;
|
||||
using ImGuiNET;
|
||||
using Silk.NET.Input;
|
||||
using Silk.NET.Input.Extensions;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.OpenGL;
|
||||
using Silk.NET.Windowing;
|
||||
using Shader = FModel.Views.Snooper.Shader;
|
||||
using Texture = FModel.Views.Snooper.Texture;
|
||||
|
||||
namespace FModel.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// because we use ImTool for docking purposes we pasted
|
||||
/// https://github.com/dotnet/Silk.NET/blob/main/src/OpenGL/Extensions/Silk.NET.OpenGL.Extensions.ImGui/ImGuiController.cs
|
||||
/// </summary>
|
||||
public class ImGuiControllerExtensions : IDisposable
|
||||
{
|
||||
private GL _gl;
|
||||
private IView _view;
|
||||
private IInputContext _input;
|
||||
private bool _frameBegun;
|
||||
private readonly List<char> _pressedChars = new ();
|
||||
private IKeyboard _keyboard;
|
||||
|
||||
private int _attribLocationTex;
|
||||
private int _attribLocationProjMtx;
|
||||
private int _attribLocationVtxPos;
|
||||
private int _attribLocationVtxUV;
|
||||
private int _attribLocationVtxColor;
|
||||
private uint _vboHandle;
|
||||
private uint _elementsHandle;
|
||||
private uint _vertexArrayObject;
|
||||
|
||||
private Texture _fontTexture;
|
||||
private Shader _shader;
|
||||
|
||||
private int _windowWidth;
|
||||
private int _windowHeight;
|
||||
|
||||
public IntPtr Context;
|
||||
|
||||
public ImGuiControllerExtensions(GL gl, IView view, IInputContext input, ImGuiFontConfig? imGuiFontConfig = null)
|
||||
{
|
||||
Init(gl, view, input);
|
||||
|
||||
var io = ImGui.GetIO();
|
||||
if (imGuiFontConfig is not null)
|
||||
{
|
||||
io.Fonts.AddFontFromFileTTF(imGuiFontConfig.Value.FontPath, imGuiFontConfig.Value.FontSize);
|
||||
}
|
||||
|
||||
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
|
||||
|
||||
CreateDeviceResources();
|
||||
SetKeyMappings();
|
||||
|
||||
SetPerFrameImGuiData(1f / 60f);
|
||||
|
||||
BeginFrame();
|
||||
}
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
ImGui.SetCurrentContext(Context);
|
||||
}
|
||||
|
||||
private void Init(GL gl, IView view, IInputContext input)
|
||||
{
|
||||
_gl = gl;
|
||||
_view = view;
|
||||
_input = input;
|
||||
_windowWidth = view.Size.X;
|
||||
_windowHeight = view.Size.Y;
|
||||
|
||||
Context = ImGui.CreateContext();
|
||||
ImGui.SetCurrentContext(Context);
|
||||
ImGui.StyleColorsDark();
|
||||
}
|
||||
|
||||
private void BeginFrame()
|
||||
{
|
||||
ImGui.NewFrame();
|
||||
_frameBegun = true;
|
||||
_keyboard = _input.Keyboards[0];
|
||||
_view.Resize += WindowResized;
|
||||
_keyboard.KeyChar += OnKeyChar;
|
||||
}
|
||||
|
||||
private void OnKeyChar(IKeyboard arg1, char arg2)
|
||||
{
|
||||
_pressedChars.Add(arg2);
|
||||
}
|
||||
|
||||
private void WindowResized(Vector2D<int> size)
|
||||
{
|
||||
_windowWidth = size.X;
|
||||
_windowHeight = size.Y;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
if (!_frameBegun) return;
|
||||
|
||||
var oldCtx = ImGui.GetCurrentContext();
|
||||
if (oldCtx != Context)
|
||||
ImGui.SetCurrentContext(Context);
|
||||
|
||||
_frameBegun = false;
|
||||
ImGui.Render();
|
||||
RenderImDrawData(ImGui.GetDrawData());
|
||||
|
||||
if (oldCtx != Context)
|
||||
ImGui.SetCurrentContext(oldCtx);
|
||||
}
|
||||
|
||||
public void Update(float deltaSeconds)
|
||||
{
|
||||
var oldCtx = ImGui.GetCurrentContext();
|
||||
if (oldCtx != Context)
|
||||
ImGui.SetCurrentContext(Context);
|
||||
|
||||
if (_frameBegun)
|
||||
ImGui.Render();
|
||||
|
||||
SetPerFrameImGuiData(deltaSeconds);
|
||||
UpdateImGuiInput();
|
||||
|
||||
_frameBegun = true;
|
||||
ImGui.NewFrame();
|
||||
|
||||
if (oldCtx != Context)
|
||||
ImGui.SetCurrentContext(oldCtx);
|
||||
}
|
||||
|
||||
private void SetPerFrameImGuiData(float deltaSeconds)
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.DisplaySize = new Vector2(_windowWidth, _windowHeight);
|
||||
|
||||
if (_windowWidth > 0 && _windowHeight > 0)
|
||||
{
|
||||
io.DisplayFramebufferScale = new Vector2(_view.FramebufferSize.X / _windowWidth,
|
||||
_view.FramebufferSize.Y / _windowHeight);
|
||||
}
|
||||
|
||||
io.DeltaTime = deltaSeconds; // DeltaTime is in seconds.
|
||||
}
|
||||
|
||||
private static Key[] keyEnumArr = (Key[]) Enum.GetValues(typeof(Key));
|
||||
private void UpdateImGuiInput()
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
|
||||
var mouseState = _input.Mice[0].CaptureState();
|
||||
var keyboardState = _input.Keyboards[0];
|
||||
|
||||
io.MouseDown[0] = mouseState.IsButtonPressed(MouseButton.Left);
|
||||
io.MouseDown[1] = mouseState.IsButtonPressed(MouseButton.Right);
|
||||
io.MouseDown[2] = mouseState.IsButtonPressed(MouseButton.Middle);
|
||||
|
||||
var point = new Point((int) mouseState.Position.X, (int) mouseState.Position.Y);
|
||||
io.MousePos = new Vector2(point.X, point.Y);
|
||||
|
||||
var wheel = mouseState.GetScrollWheels()[0];
|
||||
io.MouseWheel = wheel.Y;
|
||||
io.MouseWheelH = wheel.X;
|
||||
|
||||
foreach (var key in keyEnumArr)
|
||||
{
|
||||
if (key == Key.Unknown)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
io.KeysDown[(int) key] = keyboardState.IsKeyPressed(key);
|
||||
}
|
||||
|
||||
foreach (var c in _pressedChars)
|
||||
{
|
||||
io.AddInputCharacter(c);
|
||||
}
|
||||
|
||||
_pressedChars.Clear();
|
||||
|
||||
io.KeyCtrl = keyboardState.IsKeyPressed(Key.ControlLeft) || keyboardState.IsKeyPressed(Key.ControlRight);
|
||||
io.KeyAlt = keyboardState.IsKeyPressed(Key.AltLeft) || keyboardState.IsKeyPressed(Key.AltRight);
|
||||
io.KeyShift = keyboardState.IsKeyPressed(Key.ShiftLeft) || keyboardState.IsKeyPressed(Key.ShiftRight);
|
||||
io.KeySuper = keyboardState.IsKeyPressed(Key.SuperLeft) || keyboardState.IsKeyPressed(Key.SuperRight);
|
||||
}
|
||||
|
||||
private void PressChar(char keyChar)
|
||||
{
|
||||
_pressedChars.Add(keyChar);
|
||||
}
|
||||
|
||||
private static void SetKeyMappings()
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.KeyMap[(int) ImGuiKey.Tab] = (int) Key.Tab;
|
||||
io.KeyMap[(int) ImGuiKey.LeftArrow] = (int) Key.Left;
|
||||
io.KeyMap[(int) ImGuiKey.RightArrow] = (int) Key.Right;
|
||||
io.KeyMap[(int) ImGuiKey.UpArrow] = (int) Key.Up;
|
||||
io.KeyMap[(int) ImGuiKey.DownArrow] = (int) Key.Down;
|
||||
io.KeyMap[(int) ImGuiKey.PageUp] = (int) Key.PageUp;
|
||||
io.KeyMap[(int) ImGuiKey.PageDown] = (int) Key.PageDown;
|
||||
io.KeyMap[(int) ImGuiKey.Home] = (int) Key.Home;
|
||||
io.KeyMap[(int) ImGuiKey.End] = (int) Key.End;
|
||||
io.KeyMap[(int) ImGuiKey.Delete] = (int) Key.Delete;
|
||||
io.KeyMap[(int) ImGuiKey.Backspace] = (int) Key.Backspace;
|
||||
io.KeyMap[(int) ImGuiKey.Enter] = (int) Key.Enter;
|
||||
io.KeyMap[(int) ImGuiKey.Escape] = (int) Key.Escape;
|
||||
io.KeyMap[(int) ImGuiKey.A] = (int) Key.A;
|
||||
io.KeyMap[(int) ImGuiKey.C] = (int) Key.C;
|
||||
io.KeyMap[(int) ImGuiKey.V] = (int) Key.V;
|
||||
io.KeyMap[(int) ImGuiKey.X] = (int) Key.X;
|
||||
io.KeyMap[(int) ImGuiKey.Y] = (int) Key.Y;
|
||||
io.KeyMap[(int) ImGuiKey.Z] = (int) Key.Z;
|
||||
}
|
||||
|
||||
private unsafe void SetupRenderState(ImDrawDataPtr drawDataPtr, int framebufferWidth, int framebufferHeight)
|
||||
{
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
_gl.Enable(GLEnum.Blend);
|
||||
_gl.BlendEquation(GLEnum.FuncAdd);
|
||||
_gl.BlendFuncSeparate(GLEnum.SrcAlpha, GLEnum.OneMinusSrcAlpha, GLEnum.One, GLEnum.OneMinusSrcAlpha);
|
||||
_gl.Disable(GLEnum.CullFace);
|
||||
_gl.Disable(GLEnum.DepthTest);
|
||||
_gl.Disable(GLEnum.StencilTest);
|
||||
_gl.Enable(GLEnum.ScissorTest);
|
||||
_gl.Disable(GLEnum.PrimitiveRestart);
|
||||
_gl.PolygonMode(GLEnum.FrontAndBack, GLEnum.Fill);
|
||||
|
||||
float L = drawDataPtr.DisplayPos.X;
|
||||
float R = drawDataPtr.DisplayPos.X + drawDataPtr.DisplaySize.X;
|
||||
float T = drawDataPtr.DisplayPos.Y;
|
||||
float B = drawDataPtr.DisplayPos.Y + drawDataPtr.DisplaySize.Y;
|
||||
|
||||
Span<float> orthoProjection = stackalloc float[] {
|
||||
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
|
||||
0.0f, 0.0f, -1.0f, 0.0f,
|
||||
(R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
_shader.Use();
|
||||
_gl.Uniform1(_attribLocationTex, 0);
|
||||
_gl.UniformMatrix4(_attribLocationProjMtx, 1, false, orthoProjection);
|
||||
|
||||
_gl.BindSampler(0, 0);
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
_vertexArrayObject = _gl.GenVertexArray();
|
||||
_gl.BindVertexArray(_vertexArrayObject);
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
_gl.BindBuffer(GLEnum.ArrayBuffer, _vboHandle);
|
||||
_gl.BindBuffer(GLEnum.ElementArrayBuffer, _elementsHandle);
|
||||
_gl.EnableVertexAttribArray((uint) _attribLocationVtxPos);
|
||||
_gl.EnableVertexAttribArray((uint) _attribLocationVtxUV);
|
||||
_gl.EnableVertexAttribArray((uint) _attribLocationVtxColor);
|
||||
_gl.VertexAttribPointer((uint) _attribLocationVtxPos, 2, GLEnum.Float, false, (uint) sizeof(ImDrawVert), (void*) 0);
|
||||
_gl.VertexAttribPointer((uint) _attribLocationVtxUV, 2, GLEnum.Float, false, (uint) sizeof(ImDrawVert), (void*) 8);
|
||||
_gl.VertexAttribPointer((uint) _attribLocationVtxColor, 4, GLEnum.UnsignedByte, true, (uint) sizeof(ImDrawVert), (void*) 16);
|
||||
}
|
||||
|
||||
private unsafe void RenderImDrawData(ImDrawDataPtr drawDataPtr)
|
||||
{
|
||||
int framebufferWidth = (int) (drawDataPtr.DisplaySize.X * drawDataPtr.FramebufferScale.X);
|
||||
int framebufferHeight = (int) (drawDataPtr.DisplaySize.Y * drawDataPtr.FramebufferScale.Y);
|
||||
if (framebufferWidth <= 0 || framebufferHeight <= 0)
|
||||
return;
|
||||
|
||||
// Backup GL state
|
||||
_gl.GetInteger(GLEnum.ActiveTexture, out int lastActiveTexture);
|
||||
_gl.ActiveTexture(GLEnum.Texture0);
|
||||
|
||||
_gl.GetInteger(GLEnum.CurrentProgram, out int lastProgram);
|
||||
_gl.GetInteger(GLEnum.TextureBinding2D, out int lastTexture);
|
||||
|
||||
_gl.GetInteger(GLEnum.SamplerBinding, out int lastSampler);
|
||||
|
||||
_gl.GetInteger(GLEnum.ArrayBufferBinding, out int lastArrayBuffer);
|
||||
_gl.GetInteger(GLEnum.VertexArrayBinding, out int lastVertexArrayObject);
|
||||
|
||||
Span<int> lastPolygonMode = stackalloc int[2];
|
||||
_gl.GetInteger(GLEnum.PolygonMode, lastPolygonMode);
|
||||
|
||||
Span<int> lastScissorBox = stackalloc int[4];
|
||||
_gl.GetInteger(GLEnum.ScissorBox, lastScissorBox);
|
||||
|
||||
_gl.GetInteger(GLEnum.BlendSrcRgb, out int lastBlendSrcRgb);
|
||||
_gl.GetInteger(GLEnum.BlendDstRgb, out int lastBlendDstRgb);
|
||||
|
||||
_gl.GetInteger(GLEnum.BlendSrcAlpha, out int lastBlendSrcAlpha);
|
||||
_gl.GetInteger(GLEnum.BlendDstAlpha, out int lastBlendDstAlpha);
|
||||
|
||||
_gl.GetInteger(GLEnum.BlendEquationRgb, out int lastBlendEquationRgb);
|
||||
_gl.GetInteger(GLEnum.BlendEquationAlpha, out int lastBlendEquationAlpha);
|
||||
|
||||
bool lastEnableBlend = _gl.IsEnabled(GLEnum.Blend);
|
||||
bool lastEnableCullFace = _gl.IsEnabled(GLEnum.CullFace);
|
||||
bool lastEnableDepthTest = _gl.IsEnabled(GLEnum.DepthTest);
|
||||
bool lastEnableStencilTest = _gl.IsEnabled(GLEnum.StencilTest);
|
||||
bool lastEnableScissorTest = _gl.IsEnabled(GLEnum.ScissorTest);
|
||||
bool lastEnablePrimitiveRestart = _gl.IsEnabled(GLEnum.PrimitiveRestart);
|
||||
|
||||
SetupRenderState(drawDataPtr, framebufferWidth, framebufferHeight);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
Vector2 clipOff = drawDataPtr.DisplayPos; // (0,0) unless using multi-viewports
|
||||
Vector2 clipScale = drawDataPtr.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < drawDataPtr.CmdListsCount; n++)
|
||||
{
|
||||
ImDrawListPtr cmdListPtr = drawDataPtr.CmdListsRange[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
|
||||
_gl.BufferData(GLEnum.ArrayBuffer, (nuint) (cmdListPtr.VtxBuffer.Size * sizeof(ImDrawVert)), (void*) cmdListPtr.VtxBuffer.Data, GLEnum.StreamDraw);
|
||||
_gl.BufferData(GLEnum.ElementArrayBuffer, (nuint) (cmdListPtr.IdxBuffer.Size * sizeof(ushort)), (void*) cmdListPtr.IdxBuffer.Data, GLEnum.StreamDraw);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmdListPtr.CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
ImDrawCmdPtr cmdPtr = cmdListPtr.CmdBuffer[cmd_i];
|
||||
|
||||
if (cmdPtr.UserCallback != IntPtr.Zero)
|
||||
throw new NotImplementedException();
|
||||
|
||||
Vector4 clipRect;
|
||||
clipRect.X = (cmdPtr.ClipRect.X - clipOff.X) * clipScale.X;
|
||||
clipRect.Y = (cmdPtr.ClipRect.Y - clipOff.Y) * clipScale.Y;
|
||||
clipRect.Z = (cmdPtr.ClipRect.Z - clipOff.X) * clipScale.X;
|
||||
clipRect.W = (cmdPtr.ClipRect.W - clipOff.Y) * clipScale.Y;
|
||||
|
||||
if (clipRect.X < framebufferWidth && clipRect.Y < framebufferHeight && clipRect.Z >= 0.0f && clipRect.W >= 0.0f)
|
||||
{
|
||||
// Apply scissor/clipping rectangle
|
||||
_gl.Scissor((int) clipRect.X, (int) (framebufferHeight - clipRect.W), (uint) (clipRect.Z - clipRect.X), (uint) (clipRect.W - clipRect.Y));
|
||||
|
||||
// Bind texture, Draw
|
||||
_gl.BindTexture(GLEnum.Texture2D, (uint) cmdPtr.TextureId);
|
||||
|
||||
_gl.DrawElementsBaseVertex(GLEnum.Triangles, cmdPtr.ElemCount, GLEnum.UnsignedShort, (void*) (cmdPtr.IdxOffset * sizeof(ushort)), (int) cmdPtr.VtxOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
_gl.DeleteVertexArray(_vertexArrayObject);
|
||||
_vertexArrayObject = 0;
|
||||
|
||||
// Restore modified GL state
|
||||
_gl.UseProgram((uint) lastProgram);
|
||||
_gl.BindTexture(GLEnum.Texture2D, (uint) lastTexture);
|
||||
|
||||
_gl.BindSampler(0, (uint) lastSampler);
|
||||
|
||||
_gl.ActiveTexture((GLEnum) lastActiveTexture);
|
||||
|
||||
_gl.BindVertexArray((uint) lastVertexArrayObject);
|
||||
|
||||
_gl.BindBuffer(GLEnum.ArrayBuffer, (uint) lastArrayBuffer);
|
||||
_gl.BlendEquationSeparate((GLEnum) lastBlendEquationRgb, (GLEnum) lastBlendEquationAlpha);
|
||||
_gl.BlendFuncSeparate((GLEnum) lastBlendSrcRgb, (GLEnum) lastBlendDstRgb, (GLEnum) lastBlendSrcAlpha, (GLEnum) lastBlendDstAlpha);
|
||||
|
||||
if (lastEnableBlend)
|
||||
{
|
||||
_gl.Enable(GLEnum.Blend);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.Blend);
|
||||
}
|
||||
|
||||
if (lastEnableCullFace)
|
||||
{
|
||||
_gl.Enable(GLEnum.CullFace);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.CullFace);
|
||||
}
|
||||
|
||||
if (lastEnableDepthTest)
|
||||
{
|
||||
_gl.Enable(GLEnum.DepthTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.DepthTest);
|
||||
}
|
||||
if (lastEnableStencilTest)
|
||||
{
|
||||
_gl.Enable(GLEnum.StencilTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.StencilTest);
|
||||
}
|
||||
|
||||
if (lastEnableScissorTest)
|
||||
{
|
||||
_gl.Enable(GLEnum.ScissorTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.ScissorTest);
|
||||
}
|
||||
|
||||
if (lastEnablePrimitiveRestart)
|
||||
{
|
||||
_gl.Enable(GLEnum.PrimitiveRestart);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gl.Disable(GLEnum.PrimitiveRestart);
|
||||
}
|
||||
|
||||
_gl.PolygonMode(GLEnum.FrontAndBack, (GLEnum) lastPolygonMode[0]);
|
||||
_gl.Scissor(lastScissorBox[0], lastScissorBox[1], (uint) lastScissorBox[2], (uint) lastScissorBox[3]);
|
||||
}
|
||||
|
||||
private void CreateDeviceResources()
|
||||
{
|
||||
// Backup GL state
|
||||
|
||||
_gl.GetInteger(GLEnum.TextureBinding2D, out int lastTexture);
|
||||
_gl.GetInteger(GLEnum.ArrayBufferBinding, out int lastArrayBuffer);
|
||||
_gl.GetInteger(GLEnum.VertexArrayBinding, out int lastVertexArray);
|
||||
|
||||
_shader = new Shader(_gl, "imgui");
|
||||
|
||||
_attribLocationTex = _shader.GetUniformLocation("Texture");
|
||||
_attribLocationProjMtx = _shader.GetUniformLocation("ProjMtx");
|
||||
_attribLocationVtxPos = _shader.GetAttribLocation("Position");
|
||||
_attribLocationVtxUV = _shader.GetAttribLocation("UV");
|
||||
_attribLocationVtxColor = _shader.GetAttribLocation("Color");
|
||||
|
||||
_vboHandle = _gl.GenBuffer();
|
||||
_elementsHandle = _gl.GenBuffer();
|
||||
|
||||
RecreateFontDeviceTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
_gl.BindTexture(GLEnum.Texture2D, (uint) lastTexture);
|
||||
_gl.BindBuffer(GLEnum.ArrayBuffer, (uint) lastArrayBuffer);
|
||||
|
||||
_gl.BindVertexArray((uint) lastVertexArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the texture used to render text.
|
||||
/// </summary>
|
||||
private unsafe void RecreateFontDeviceTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
var io = ImGui.GetIO();
|
||||
io.Fonts.GetTexDataAsRGBA32(out IntPtr pixels, out int width, out int height, out int bytesPerPixel); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
_gl.GetInteger(GLEnum.TextureBinding2D, out int lastTexture);
|
||||
|
||||
_fontTexture = new Texture(_gl, (uint) width, (uint) height, pixels);
|
||||
_fontTexture.Bind(TextureTarget.Texture2D);
|
||||
_fontTexture.SetMagFilter(TextureMagFilter.Linear);
|
||||
_fontTexture.SetMinFilter(TextureMinFilter.Linear);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts.SetTexID(_fontTexture.GetPointer());
|
||||
|
||||
// Restore state
|
||||
_gl.BindTexture(GLEnum.Texture2D, (uint) lastTexture);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_view.Resize -= WindowResized;
|
||||
_keyboard.KeyChar -= OnKeyChar;
|
||||
|
||||
_gl.DeleteBuffer(_vboHandle);
|
||||
_gl.DeleteBuffer(_elementsHandle);
|
||||
_gl.DeleteVertexArray(_vertexArrayObject);
|
||||
|
||||
_fontTexture.Dispose();
|
||||
_shader.Dispose();
|
||||
|
||||
ImGui.DestroyContext(Context);
|
||||
}
|
||||
}
|
||||
|
|
@ -101,6 +101,8 @@
|
|||
<None Remove="Resources\skybox.vert" />
|
||||
<None Remove="Resources\framebuffer.frag" />
|
||||
<None Remove="Resources\framebuffer.vert" />
|
||||
<None Remove="Resources\imgui.frag" />
|
||||
<None Remove="Resources\imgui.vert" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -118,6 +120,8 @@
|
|||
<EmbeddedResource Include="Resources\skybox.vert" />
|
||||
<EmbeddedResource Include="Resources\framebuffer.frag" />
|
||||
<EmbeddedResource Include="Resources\framebuffer.vert" />
|
||||
<EmbeddedResource Include="Resources\imgui.frag" />
|
||||
<EmbeddedResource Include="Resources\imgui.vert" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -129,6 +133,7 @@
|
|||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||
<PackageReference Include="EpicManifestParser" Version="1.2.70-temp" />
|
||||
<PackageReference Include="HelixToolkit.SharpDX.Core.Wpf" Version="2.21.0" />
|
||||
<PackageReference Include="ImTool" Version="1.3.6" />
|
||||
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.16" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.4" />
|
||||
|
|
@ -138,8 +143,8 @@
|
|||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Silk.NET.Input" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.Input.Extensions" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.OpenGL" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.16.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
|
||||
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.0" />
|
||||
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
|
||||
|
|
|
|||
16
FModel/Framework/ImGuiFontConfig.cs
Normal file
16
FModel/Framework/ImGuiFontConfig.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace FModel.Framework;
|
||||
|
||||
public readonly struct ImGuiFontConfig
|
||||
{
|
||||
public ImGuiFontConfig(string fontPath, int fontSize)
|
||||
{
|
||||
if (fontSize <= 0) throw new ArgumentOutOfRangeException(nameof(fontSize));
|
||||
FontPath = fontPath ?? throw new ArgumentNullException(nameof(fontPath));
|
||||
FontSize = fontSize;
|
||||
}
|
||||
|
||||
public string FontPath { get; }
|
||||
public int FontSize { get; }
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
await _threadWorkerView.Begin(_ =>
|
||||
_applicationView.CUE4Parse.Extract(
|
||||
"FortniteGame/Content/Environments/Props/Winter/Meshes/SM_ChristmasTree_Llama.uasset"));
|
||||
"FortniteGame/Content/Characters/Player/Male/Medium/Bodies/M_MED_StaminaCat/Meshes/M_MED_StaminaCat.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
13
FModel/Resources/imgui.frag
Normal file
13
FModel/Resources/imgui.frag
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#version 330
|
||||
|
||||
layout (location = 0) out vec4 Out_Color;
|
||||
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
|
||||
uniform sampler2D Texture;
|
||||
|
||||
void main()
|
||||
{
|
||||
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
||||
}
|
||||
17
FModel/Resources/imgui.vert
Normal file
17
FModel/Resources/imgui.vert
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#version 330
|
||||
|
||||
layout (location = 0) in vec2 Position;
|
||||
layout (location = 1) in vec2 UV;
|
||||
layout (location = 2) in vec4 Color;
|
||||
|
||||
uniform mat4 ProjMtx;
|
||||
|
||||
out vec2 Frag_UV;
|
||||
out vec4 Frag_Color;
|
||||
|
||||
void main()
|
||||
{
|
||||
Frag_UV = UV;
|
||||
Frag_Color = Color;
|
||||
gl_Position = ProjMtx * vec4(Position.xy,0,1);
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ public class Model : IDisposable
|
|||
public readonly float[] Vertices;
|
||||
public readonly Section[] Sections;
|
||||
|
||||
public Transform Transforms = Transform.Identity;
|
||||
public readonly Transform Transforms = Transform.Identity;
|
||||
public readonly string[] TransformsLabels = {
|
||||
"X Location", "Y", "Z",
|
||||
"X Rotation", "Y", "Z",
|
||||
|
|
@ -127,7 +127,7 @@ public class Model : IDisposable
|
|||
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
Sections[section].Bind(section, _shader);
|
||||
Sections[section].Bind(_shader);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using CUE4Parse_Conversion.Meshes.PSK;
|
|||
using CUE4Parse_Conversion.Textures;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using ImGuiNET;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
|
@ -16,16 +15,6 @@ public class Section : IDisposable
|
|||
private uint _handle;
|
||||
private GL _gl;
|
||||
|
||||
private Texture _diffuseMap;
|
||||
private Texture _normalMap;
|
||||
private Texture _specularMap;
|
||||
private Texture _emissionMap;
|
||||
|
||||
private bool _hasSpecularMap;
|
||||
private bool _hasDiffuseColor;
|
||||
private Vector4 _diffuseColor = Vector4.Zero;
|
||||
private Vector4 _emissionColor = Vector4.Zero;
|
||||
|
||||
private Vector3 _ambientLight;
|
||||
private Vector3 _diffuseLight;
|
||||
private Vector3 _specularLight;
|
||||
|
|
@ -38,9 +27,14 @@ public class Section : IDisposable
|
|||
public readonly int FirstFaceIndex;
|
||||
public readonly CMaterialParams Parameters;
|
||||
|
||||
private bool _show = true;
|
||||
private bool _wireframe;
|
||||
private bool _selected;
|
||||
public bool Show;
|
||||
public bool Wireframe;
|
||||
public readonly Texture[] Textures;
|
||||
public readonly string[] TexturesLabels;
|
||||
public Vector4 DiffuseColor;
|
||||
public Vector4 EmissionColor;
|
||||
public bool HasSpecularMap;
|
||||
public bool HasDiffuseColor;
|
||||
|
||||
public Section(string name, int index, uint facesCount, int firstFaceIndex, CMeshSection section)
|
||||
{
|
||||
|
|
@ -55,6 +49,12 @@ public class Section : IDisposable
|
|||
unrealMaterial.GetParams(Parameters);
|
||||
}
|
||||
|
||||
Show = true;
|
||||
Textures = new Texture[4];
|
||||
TexturesLabels = new[] { "Diffuse", "Normal", "Specular", "Emissive" };
|
||||
DiffuseColor = Vector4.Zero;
|
||||
EmissionColor = Vector4.Zero;
|
||||
|
||||
_game = ApplicationService.ApplicationView.CUE4Parse.Game;
|
||||
}
|
||||
|
||||
|
|
@ -66,34 +66,34 @@ public class Section : IDisposable
|
|||
|
||||
if (Parameters.IsNull)
|
||||
{
|
||||
_diffuseColor = new Vector4(1, 0, 0, 1);
|
||||
DiffuseColor = new Vector4(1, 0, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var platform = UserSettings.Default.OverridedPlatform;
|
||||
if (!Parameters.HasTopDiffuseTexture && Parameters.DiffuseColor is { A: > 0 } diffuseColor)
|
||||
{
|
||||
_diffuseColor = new Vector4(diffuseColor.R, diffuseColor.G, diffuseColor.B, diffuseColor.A);
|
||||
DiffuseColor = new Vector4(diffuseColor.R, diffuseColor.G, diffuseColor.B, diffuseColor.A);
|
||||
}
|
||||
else if (Parameters.Diffuse is UTexture2D { IsVirtual: false } diffuse)
|
||||
{
|
||||
var mip = diffuse.GetFirstMip();
|
||||
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, platform, out var data, out _);
|
||||
_diffuseMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
Textures[0] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
}
|
||||
|
||||
if (Parameters.Normal is UTexture2D { IsVirtual: false } normal)
|
||||
{
|
||||
var mip = normal.GetFirstMip();
|
||||
TextureDecoder.DecodeTexture(mip, normal.Format, normal.isNormalMap, platform, out var data, out _);
|
||||
_normalMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
Textures[1] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
}
|
||||
|
||||
if (Parameters.Specular is UTexture2D { IsVirtual: false } specular)
|
||||
{
|
||||
var mip = specular.GetFirstMip();
|
||||
SwapSpecular(specular, mip, platform, out var data);
|
||||
_specularMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
Textures[2] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
}
|
||||
|
||||
if (Parameters.HasTopEmissiveTexture &&
|
||||
|
|
@ -102,18 +102,18 @@ public class Section : IDisposable
|
|||
{
|
||||
var mip = emissive.GetFirstMip();
|
||||
TextureDecoder.DecodeTexture(mip, emissive.Format, emissive.isNormalMap, platform, out var data, out _);
|
||||
_emissionMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
_emissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A);
|
||||
Textures[3] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
|
||||
EmissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A);
|
||||
}
|
||||
}
|
||||
|
||||
// diffuse light is based on normal map, so increase ambient if no normal map
|
||||
_ambientLight = new Vector3(_normalMap == null ? 1.0f : 0.2f);
|
||||
_ambientLight = new Vector3(Textures[1] == null ? 1.0f : 0.2f);
|
||||
_diffuseLight = new Vector3(0.75f);
|
||||
_specularLight = new Vector3(0.5f);
|
||||
_hasSpecularMap = _specularMap != null;
|
||||
_hasDiffuseColor = _diffuseColor != Vector4.Zero;
|
||||
_show = !Parameters.IsNull && !Parameters.IsTransparent;
|
||||
HasSpecularMap = Textures[2] != null;
|
||||
HasDiffuseColor = DiffuseColor != Vector4.Zero;
|
||||
Show = !Parameters.IsNull && !Parameters.IsTransparent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -220,49 +220,19 @@ public class Section : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void Bind(int index, Shader shader)
|
||||
public void Bind(Shader shader)
|
||||
{
|
||||
// ImGui.TableNextRow();
|
||||
//
|
||||
// ImGui.TableSetColumnIndex(0);
|
||||
// ImGui.Text(Index.ToString());
|
||||
// ImGui.TableSetColumnIndex(1);
|
||||
// ImGui.Text(Name);
|
||||
// if (ImGui.IsItemHovered())
|
||||
// {
|
||||
// ImGui.BeginTooltip();
|
||||
// ImGui.Text($"Faces: {FacesCount} ({Math.Round(FacesCount / indices * 100f, 2)}%%)");
|
||||
// ImGui.Text($"First Face: {FirstFaceIndex}");
|
||||
// ImGui.Separator();
|
||||
// if (_hasDiffuseColor)
|
||||
// {
|
||||
// ImGui.ColorEdit4("Diffuse Color", ref _diffuseColor, ImGuiColorEditFlags.NoInputs);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ImGui.Text($"Diffuse: ({Parameters.Diffuse?.ExportType}) {Parameters.Diffuse?.Name}");
|
||||
// ImGui.Text($"Normal: ({Parameters.Normal?.ExportType}) {Parameters.Normal?.Name}");
|
||||
// ImGui.Text($"Specular: ({Parameters.Specular?.ExportType}) {Parameters.Specular?.Name}");
|
||||
// if (Parameters.HasTopEmissiveTexture)
|
||||
// ImGui.Text($"Emissive: ({Parameters.Emissive?.ExportType}) {Parameters.Emissive?.Name}");
|
||||
// ImGui.Separator();
|
||||
// }
|
||||
// ImGui.EndTooltip();
|
||||
// }
|
||||
for (var i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
Textures[i]?.Bind(TextureUnit.Texture0 + i);
|
||||
}
|
||||
|
||||
// DrawImGui(index);
|
||||
shader.SetUniform("material.useSpecularMap", HasSpecularMap);
|
||||
|
||||
_diffuseMap?.Bind(TextureUnit.Texture0);
|
||||
_normalMap?.Bind(TextureUnit.Texture1);
|
||||
_specularMap?.Bind(TextureUnit.Texture2);
|
||||
_emissionMap?.Bind(TextureUnit.Texture3);
|
||||
shader.SetUniform("material.hasDiffuseColor", HasDiffuseColor);
|
||||
shader.SetUniform("material.diffuseColor", DiffuseColor);
|
||||
|
||||
shader.SetUniform("material.useSpecularMap", _hasSpecularMap);
|
||||
|
||||
shader.SetUniform("material.hasDiffuseColor", _hasDiffuseColor);
|
||||
shader.SetUniform("material.diffuseColor", _diffuseColor);
|
||||
|
||||
shader.SetUniform("material.emissionColor", _emissionColor);
|
||||
shader.SetUniform("material.emissionColor", EmissionColor);
|
||||
|
||||
shader.SetUniform("material.shininess", Parameters.MetallicValue);
|
||||
|
||||
|
|
@ -270,27 +240,16 @@ public class Section : IDisposable
|
|||
shader.SetUniform("light.diffuse", _diffuseLight);
|
||||
shader.SetUniform("light.specular", _specularLight);
|
||||
|
||||
_gl.PolygonMode(MaterialFace.Front, _wireframe ? PolygonMode.Line : PolygonMode.Fill);
|
||||
if (_show) _gl.DrawArrays(PrimitiveType.Triangles, FirstFaceIndex, FacesCount);
|
||||
_gl.PolygonMode(MaterialFace.Front, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
|
||||
if (Show) _gl.DrawArrays(PrimitiveType.Triangles, FirstFaceIndex, FacesCount);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_diffuseMap?.Dispose();
|
||||
_normalMap?.Dispose();
|
||||
_specularMap?.Dispose();
|
||||
_emissionMap?.Dispose();
|
||||
for (var i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
Textures[i]?.Dispose();
|
||||
}
|
||||
_gl.DeleteProgram(_handle);
|
||||
}
|
||||
|
||||
private void DrawImGui(int index)
|
||||
{
|
||||
ImGui.PushID(index);
|
||||
ImGui.Selectable(Name, ref _selected);
|
||||
if (_selected)
|
||||
{
|
||||
|
||||
}
|
||||
ImGui.PopID();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
|
|
@ -8,8 +9,10 @@ namespace FModel.Views.Snooper;
|
|||
|
||||
public class Shader : IDisposable
|
||||
{
|
||||
private uint _handle;
|
||||
private GL _gl;
|
||||
private readonly uint _handle;
|
||||
private readonly GL _gl;
|
||||
private readonly Dictionary<string, int> _uniformToLocation = new ();
|
||||
private readonly Dictionary<string, int> _attribLocation = new ();
|
||||
|
||||
public Shader(GL gl) : this(gl, "default") {}
|
||||
|
||||
|
|
@ -103,6 +106,34 @@ public class Shader : IDisposable
|
|||
_gl.Uniform4(location, value.X, value.Y, value.Z, value.W);
|
||||
}
|
||||
|
||||
public int GetUniformLocation(string uniform)
|
||||
{
|
||||
if (!_uniformToLocation.TryGetValue(uniform, out int location))
|
||||
{
|
||||
location = _gl.GetUniformLocation(_handle, uniform);
|
||||
_uniformToLocation.Add(uniform, location);
|
||||
if (location == -1)
|
||||
{
|
||||
Serilog.Log.Debug($"The uniform '{uniform}' does not exist in the shader!");
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
public int GetAttribLocation(string attrib)
|
||||
{
|
||||
if (!_attribLocation.TryGetValue(attrib, out int location))
|
||||
{
|
||||
location = _gl.GetAttribLocation(_handle, attrib);
|
||||
_attribLocation.Add(attrib, location);
|
||||
if (location == -1)
|
||||
{
|
||||
Serilog.Log.Debug($"The attrib '{attrib}' does not exist in the shader!");
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_gl.DeleteProgram(_handle);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using ImGuiNET;
|
||||
using Silk.NET.Input;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.OpenGL;
|
||||
using Silk.NET.OpenGL.Extensions.ImGui;
|
||||
using Silk.NET.Windowing;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class SnimGui : IDisposable
|
||||
{
|
||||
private readonly ImGuiController _controller;
|
||||
private readonly ImGuiControllerExtensions _controller;
|
||||
private readonly GraphicsAPI _api;
|
||||
|
||||
private readonly Vector2 _outlinerSize;
|
||||
private readonly Vector2 _outlinerPosition;
|
||||
|
|
@ -20,29 +22,36 @@ public class SnimGui : IDisposable
|
|||
private readonly Vector2 _propertiesPosition;
|
||||
private readonly Vector2 _viewportSize;
|
||||
private readonly Vector2 _viewportPosition;
|
||||
private readonly Vector2 _textureSize;
|
||||
private readonly Vector2 _texturePosition;
|
||||
private bool _viewportFocus;
|
||||
private int _selectedModel;
|
||||
private int _selectedSection;
|
||||
|
||||
private const ImGuiWindowFlags _noResize = ImGuiWindowFlags.NoResize; // delete once we have a proper docking branch
|
||||
private const ImGuiWindowFlags _noResize = ImGuiWindowFlags.NoResize| ImGuiWindowFlags.NoMove; // delete once we have a proper docking branch
|
||||
private const ImGuiCond _firstUse = ImGuiCond.Appearing; // switch to FirstUseEver once the docking branch will not be useful anymore...
|
||||
private const uint _dockspaceId = 1337;
|
||||
|
||||
public SnimGui(GL gl, IWindow window, IInputContext input)
|
||||
{
|
||||
var fontConfig = new ImGuiFontConfig("C:\\Windows\\Fonts\\segoeui.ttf", 16);
|
||||
_controller = new ImGuiController(gl, window, input, fontConfig);
|
||||
_controller = new ImGuiControllerExtensions(gl, window, input, fontConfig);
|
||||
_api = window.API;
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
var viewport = ImGui.GetMainViewport();
|
||||
var titleBarHeight = ImGui.GetFontSize() + style.FramePadding.Y * 2;
|
||||
|
||||
_outlinerSize = new Vector2(300, 350);
|
||||
_outlinerSize = new Vector2(400, 250);
|
||||
_outlinerPosition = new Vector2(viewport.WorkSize.X - _outlinerSize.X, titleBarHeight);
|
||||
_propertiesSize = _outlinerSize with { Y = viewport.WorkSize.Y - _outlinerSize.Y - titleBarHeight };
|
||||
_propertiesPosition = new Vector2(viewport.WorkSize.X - _propertiesSize.X, _outlinerPosition.Y + _outlinerSize.Y);
|
||||
_viewportSize = _outlinerPosition with { Y = viewport.WorkSize.Y - titleBarHeight };
|
||||
_viewportSize = _outlinerPosition with { Y = viewport.WorkSize.Y - titleBarHeight - 150 };
|
||||
_viewportPosition = new Vector2(0, titleBarHeight);
|
||||
_textureSize = _viewportSize with { Y = viewport.WorkSize.Y - _viewportSize.Y - titleBarHeight };
|
||||
_texturePosition = new Vector2(0, _viewportPosition.Y + _viewportSize.Y);
|
||||
_selectedModel = 0;
|
||||
_selectedSection = 0;
|
||||
|
||||
Theme(style);
|
||||
}
|
||||
|
|
@ -54,6 +63,7 @@ public class SnimGui : IDisposable
|
|||
|
||||
DrawOuliner(camera, models);
|
||||
DrawProperties(camera, models);
|
||||
DrawTextures(models);
|
||||
Draw3DViewport(framebuffer, camera, mouse);
|
||||
}
|
||||
|
||||
|
|
@ -108,12 +118,19 @@ public class SnimGui : IDisposable
|
|||
ImGui.SetNextWindowPos(_outlinerPosition, _firstUse);
|
||||
ImGui.Begin("Scene", _noResize | ImGuiWindowFlags.NoCollapse);
|
||||
|
||||
ImGui.Text($"{_api.API} {_api.Profile} {_api.Version.MajorVersion}.{_api.Version.MinorVersion}");
|
||||
|
||||
var vertices = 0;
|
||||
var indices = 0;
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Collection"))
|
||||
{
|
||||
for (var i = 0; i < models.Count; i++)
|
||||
{
|
||||
var model = models[i];
|
||||
vertices += model.Vertices.Length;
|
||||
indices += model.Indices.Length;
|
||||
if (ImGui.Selectable(model.Name, _selectedModel == i))
|
||||
_selectedModel = i;
|
||||
}
|
||||
|
|
@ -131,8 +148,8 @@ public class SnimGui : IDisposable
|
|||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.Text($"Position: {_viewportPosition}");
|
||||
ImGui.Text($"Size: {_viewportSize}");
|
||||
ImGui.Text($"Vertices: {vertices}");
|
||||
ImGui.Text($"Indices: {indices}");
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
|
@ -149,7 +166,6 @@ public class SnimGui : IDisposable
|
|||
ImGui.Checkbox("Vertex Colors", ref model.DisplayVertexColors);
|
||||
ImGui.EndDisabled();
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Transform"))
|
||||
{
|
||||
const int width = 100;
|
||||
|
|
@ -199,6 +215,90 @@ public class SnimGui : IDisposable
|
|||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
if (ImGui.TreeNode("Materials"))
|
||||
{
|
||||
ImGui.BeginTable("Sections", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable);
|
||||
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Name");
|
||||
ImGui.TableHeadersRow();
|
||||
for (var i = 0; i < model.Sections.Length; i++)
|
||||
{
|
||||
var section = model.Sections[i];
|
||||
|
||||
ImGui.PushID(i);
|
||||
ImGui.TableNextRow();
|
||||
if (!section.Show)
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f)));
|
||||
ImGui.TableSetColumnIndex(0);
|
||||
ImGui.Text(section.Index.ToString("D"));
|
||||
ImGui.TableSetColumnIndex(1);
|
||||
if (ImGui.Selectable(section.Name, _selectedSection == i, ImGuiSelectableFlags.SpanAllColumns))
|
||||
_selectedSection = i;
|
||||
ImGui.PopID();
|
||||
}
|
||||
ImGui.EndTable();
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
private void DrawTextures(IList<Model> models)
|
||||
{
|
||||
ImGui.SetNextWindowSize(_textureSize, _firstUse);
|
||||
ImGui.SetNextWindowPos(_texturePosition, _firstUse);
|
||||
ImGui.Begin("Textures", _noResize | ImGuiWindowFlags.NoCollapse);
|
||||
|
||||
var section = models[_selectedModel].Sections[_selectedSection];
|
||||
ImGui.BeginGroup();
|
||||
ImGui.Checkbox("Show", ref section.Show);
|
||||
ImGui.Checkbox("Wireframe", ref section.Wireframe);
|
||||
ImGui.Checkbox("3", ref section.Wireframe);
|
||||
ImGui.Checkbox("4", ref section.Wireframe);
|
||||
ImGui.EndGroup();
|
||||
ImGui.SameLine();
|
||||
ImGui.BeginGroup();
|
||||
if (section.HasDiffuseColor)
|
||||
{
|
||||
ImGui.ColorEdit4(section.TexturesLabels[0], ref section.DiffuseColor, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < section.Textures.Length; i++)
|
||||
{
|
||||
if (section.Textures[i] is not {} texture)
|
||||
continue;
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.BeginGroup();
|
||||
ImGui.Image(texture.GetPointer(), new Vector2(88), Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1, 1, 1, .5f));
|
||||
var text = section.TexturesLabels[i];
|
||||
var width = ImGui.GetCursorPos().X;
|
||||
ImGui.SetCursorPosX(width + ImGui.CalcTextSize(text).X * 0.5f);
|
||||
ImGui.Text(text);
|
||||
ImGui.EndGroup();
|
||||
}
|
||||
}
|
||||
ImGui.EndGroup();
|
||||
|
||||
// ImGui.Text($"Faces: {FacesCount} ({Math.Round(FacesCount / indices * 100f, 2)}%%)");
|
||||
// ImGui.Text($"First Face: {FirstFaceIndex}");
|
||||
// ImGui.Separator();
|
||||
// if (_hasDiffuseColor)
|
||||
// {
|
||||
// ImGui.ColorEdit4("Diffuse Color", ref _diffuseColor, ImGuiColorEditFlags.NoInputs);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ImGui.Text($"Diffuse: ({Parameters.Diffuse?.ExportType}) {Parameters.Diffuse?.Name}");
|
||||
// ImGui.Text($"Normal: ({Parameters.Normal?.ExportType}) {Parameters.Normal?.Name}");
|
||||
// ImGui.Text($"Specular: ({Parameters.Specular?.ExportType}) {Parameters.Specular?.Name}");
|
||||
// if (Parameters.HasTopEmissiveTexture)
|
||||
// ImGui.Text($"Emissive: ({Parameters.Emissive?.ExportType}) {Parameters.Emissive?.Name}");
|
||||
// ImGui.Separator();
|
||||
// }
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +378,7 @@ public class SnimGui : IDisposable
|
|||
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable;
|
||||
io.ConfigWindowsMoveFromTitleBarOnly = true;
|
||||
io.ConfigDockingWithShift = true;
|
||||
// io.ConfigDockingWithShift = true;
|
||||
|
||||
// style.WindowPadding = Vector2.Zero;
|
||||
// style.Colors[(int) ImGuiCol.Text] = new Vector4(0.95f, 0.96f, 0.98f, 1.00f);
|
||||
|
|
|
|||
|
|
@ -8,22 +8,21 @@ namespace FModel.Views.Snooper;
|
|||
|
||||
public class Texture : IDisposable
|
||||
{
|
||||
private uint _handle;
|
||||
private GL _gl;
|
||||
|
||||
private TextureType _type;
|
||||
private readonly uint _handle;
|
||||
private readonly GL _gl;
|
||||
private readonly TextureType _type;
|
||||
|
||||
public Texture(GL gl, TextureType type)
|
||||
{
|
||||
_gl = gl;
|
||||
_handle = _gl.GenTexture();
|
||||
_type = type;
|
||||
|
||||
Bind(TextureUnit.Texture0);
|
||||
}
|
||||
|
||||
public Texture(GL gl, uint width, uint height) : this(gl, TextureType.MsaaFramebuffer)
|
||||
{
|
||||
Bind(TextureUnit.Texture0);
|
||||
|
||||
_gl.TexImage2DMultisample(TextureTarget.Texture2DMultisample, Constants.SAMPLES_COUNT, InternalFormat.Rgb, width, height, Silk.NET.OpenGL.Boolean.True);
|
||||
|
||||
_gl.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMinFilter, (int) GLEnum.Nearest);
|
||||
|
|
@ -36,6 +35,8 @@ public class Texture : IDisposable
|
|||
|
||||
public unsafe Texture(GL gl, int width, int height) : this(gl, TextureType.Framebuffer)
|
||||
{
|
||||
Bind(TextureUnit.Texture0);
|
||||
|
||||
_gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgb, (uint) width, (uint) height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, null);
|
||||
|
||||
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
|
||||
|
|
@ -48,6 +49,8 @@ public class Texture : IDisposable
|
|||
|
||||
public unsafe Texture(GL gl, byte[] data, uint width, uint height) : this(gl, TextureType.Normal)
|
||||
{
|
||||
Bind(TextureUnit.Texture0);
|
||||
|
||||
fixed (void* d = &data[0])
|
||||
{
|
||||
_gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d);
|
||||
|
|
@ -63,6 +66,8 @@ public class Texture : IDisposable
|
|||
|
||||
public unsafe Texture(GL gl, string[] textures) : this(gl, TextureType.Cubemap)
|
||||
{
|
||||
Bind(TextureUnit.Texture0);
|
||||
|
||||
for (int t = 0; t < textures.Length; t++)
|
||||
{
|
||||
var info = Application.GetResourceStream(new Uri($"/FModel;component/Resources/{textures[t]}.png", UriKind.Relative));
|
||||
|
|
@ -88,18 +93,45 @@ public class Texture : IDisposable
|
|||
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
|
||||
}
|
||||
|
||||
public unsafe Texture(GL gl, uint width, uint height, IntPtr data) : this(gl, TextureType.Normal)
|
||||
{
|
||||
Bind(TextureTarget.Texture2D);
|
||||
|
||||
_gl.TexStorage2D(GLEnum.Texture2D, 1, SizedInternalFormat.Rgba8, width, height);
|
||||
_gl.TexSubImage2D(GLEnum.Texture2D, 0, 0, 0, width, height, PixelFormat.Bgra, PixelType.UnsignedByte, (void*) data);
|
||||
|
||||
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
|
||||
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMaxLevel, 1 - 1);
|
||||
}
|
||||
|
||||
public void Bind(TextureUnit textureSlot)
|
||||
{
|
||||
_gl.ActiveTexture(textureSlot);
|
||||
var target = _type switch
|
||||
Bind(_type switch
|
||||
{
|
||||
TextureType.Cubemap => TextureTarget.TextureCubeMap,
|
||||
TextureType.MsaaFramebuffer => TextureTarget.Texture2DMultisample,
|
||||
_ => TextureTarget.Texture2D
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public void Bind(TextureTarget target)
|
||||
{
|
||||
_gl.BindTexture(target, _handle);
|
||||
}
|
||||
|
||||
public void SetMinFilter(TextureMinFilter filter)
|
||||
{
|
||||
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMinFilter, (int)filter);
|
||||
}
|
||||
|
||||
public void SetMagFilter(TextureMagFilter filter)
|
||||
{
|
||||
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMagFilter, (int)filter);
|
||||
}
|
||||
|
||||
public IntPtr GetPointer() => (IntPtr) _handle;
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user