From 1a15600a8fe6c8c3282b6cca84d1927c3c2b1d4e Mon Sep 17 00:00:00 2001 From: Soreepeong <3614868+Soreepeong@users.noreply.github.com> Date: Sat, 2 Aug 2025 20:21:11 +0900 Subject: [PATCH] Use ImGuiWindow from gen, support AddCallback --- Dalamud/Dalamud.csproj.DotSettings | 4 +- .../ImGuiBackend/Renderers/Dx11Renderer.cs | 57 ++++++++++----- .../Windows/Data/Widgets/TexWidget.cs | 4 +- .../DrawListTextureWrap/WindowPrinter.cs | 71 +++---------------- .../Custom/ImDrawCallbackEnum.cs | 15 ++++ .../Custom/ImGui.Custom.cs | 3 - .../Custom/ImGui.Misc.cs | 20 ++++++ .../Dalamud.Bindings.ImGui.csproj.DotSettings | 2 + imgui/Dalamud.Bindings.ImGui/ImTextureID.cs | 2 +- 9 files changed, 91 insertions(+), 87 deletions(-) create mode 100644 imgui/Dalamud.Bindings.ImGui/Custom/ImDrawCallbackEnum.cs create mode 100644 imgui/Dalamud.Bindings.ImGui/Dalamud.Bindings.ImGui.csproj.DotSettings diff --git a/Dalamud/Dalamud.csproj.DotSettings b/Dalamud/Dalamud.csproj.DotSettings index 9089754a3..e723e4da1 100644 --- a/Dalamud/Dalamud.csproj.DotSettings +++ b/Dalamud/Dalamud.csproj.DotSettings @@ -1,3 +1,3 @@  -True -300000 +True + True diff --git a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs index 080b52427..9e97a11b8 100644 --- a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs +++ b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs @@ -343,31 +343,50 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer var vertexOffset = 0; var indexOffset = 0; var clipOff = new Vector4(drawData.DisplayPos, drawData.DisplayPos.X, drawData.DisplayPos.Y); + this.context.Get()->PSSetShader(this.pixelShader, null, 0); + this.context.Get()->PSSetSamplers(0, 1, this.sampler.GetAddressOf()); foreach (ref var cmdList in cmdLists) { var cmds = new ImVectorWrapper(cmdList.Handle->CmdBuffer.ToUntyped()); foreach (ref var cmd in cmds.DataSpan) { - var clipV4 = cmd.ClipRect - clipOff; - var clipRect = new RECT((int)clipV4.X, (int)clipV4.Y, (int)clipV4.Z, (int)clipV4.W); - - // Skip the draw if nothing would be visible - if (clipRect.left >= clipRect.right || clipRect.top >= clipRect.bottom) - continue; - - this.context.Get()->RSSetScissorRects(1, &clipRect); - - if (cmd.UserCallback == null) + switch ((ImDrawCallbackEnum)(nint)cmd.UserCallback) { - // Bind texture and draw - var srv = (ID3D11ShaderResourceView*)cmd.TextureId.Handle; - this.context.Get()->PSSetShader(this.pixelShader, null, 0); - this.context.Get()->PSSetSamplers(0, 1, this.sampler.GetAddressOf()); - this.context.Get()->PSSetShaderResources(0, 1, &srv); - this.context.Get()->DrawIndexed( - cmd.ElemCount, - (uint)(cmd.IdxOffset + indexOffset), - (int)(cmd.VtxOffset + vertexOffset)); + case ImDrawCallbackEnum.Empty: + { + var clipV4 = cmd.ClipRect - clipOff; + var clipRect = new RECT((int)clipV4.X, (int)clipV4.Y, (int)clipV4.Z, (int)clipV4.W); + + // Skip the draw if nothing would be visible + if (clipRect.left >= clipRect.right || clipRect.top >= clipRect.bottom) + continue; + + this.context.Get()->RSSetScissorRects(1, &clipRect); + + // Bind texture and draw + var srv = (ID3D11ShaderResourceView*)cmd.TextureId.Handle; + this.context.Get()->PSSetShaderResources(0, 1, &srv); + this.context.Get()->DrawIndexed( + cmd.ElemCount, + (uint)(cmd.IdxOffset + indexOffset), + (int)(cmd.VtxOffset + vertexOffset)); + break; + } + + case ImDrawCallbackEnum.ResetRenderState: + { + // Special callback value used by the user to request the renderer to reset render state. + this.SetupRenderState(drawData); + break; + } + + default: + { + // User callback, registered via ImDrawList::AddCallback() + var cb = (delegate*)cmd.UserCallback; + cb(cmdList, ref cmd); + break; + } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs index 34403fd16..1ebd681d9 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs @@ -71,7 +71,7 @@ internal class TexWidget : IDataWindowWidget private enum DrawBlameTableColumnUserId { - NativeAddress, + NativeAddress = 1, Actions, Name, Width, @@ -231,7 +231,7 @@ internal class TexWidget : IDataWindowWidget ImGui.PopID(); } - if (ImGui.CollapsingHeader($"CropCopy##{this.DrawExistingTextureModificationArgs}")) + if (ImGui.CollapsingHeader($"CropCopy##{nameof(this.DrawExistingTextureModificationArgs)}")) { ImGui.PushID(nameof(this.DrawExistingTextureModificationArgs)); this.DrawExistingTextureModificationArgs(); diff --git a/Dalamud/Interface/Textures/TextureWraps/Internal/DrawListTextureWrap/WindowPrinter.cs b/Dalamud/Interface/Textures/TextureWraps/Internal/DrawListTextureWrap/WindowPrinter.cs index e9a786a8c..18eaab37c 100644 --- a/Dalamud/Interface/Textures/TextureWraps/Internal/DrawListTextureWrap/WindowPrinter.cs +++ b/Dalamud/Interface/Textures/TextureWraps/Internal/DrawListTextureWrap/WindowPrinter.cs @@ -1,9 +1,4 @@ -using System.Diagnostics; -using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; using Dalamud.Bindings.ImGui; @@ -15,13 +10,13 @@ internal sealed unsafe partial class DrawListTextureWrap /// public void ResizeAndDrawWindow(ReadOnlySpan windowName, Vector2 scale) { - ref var window = ref ImGuiWindow.FindWindowByName(windowName); - if (Unsafe.IsNullRef(ref window)) + var window = ImGuiP.FindWindowByName(windowName); + if (window.IsNull) throw new ArgumentException("Window not found", nameof(windowName)); this.Size = window.Size; - var numDrawList = CountDrawList(ref window); + var numDrawList = CountDrawList(window); var drawLists = stackalloc ImDrawList*[numDrawList]; var drawData = new ImDrawData { @@ -34,7 +29,7 @@ internal sealed unsafe partial class DrawListTextureWrap DisplaySize = window.Size, FramebufferScale = scale, }; - AddWindowToDrawData(ref window, ref drawLists); + AddWindowToDrawData(window, ref drawLists); for (var i = 0; i < numDrawList; i++) { drawData.TotalVtxCount += drawData.CmdLists[i]->VtxBuffer.Size; @@ -45,10 +40,9 @@ internal sealed unsafe partial class DrawListTextureWrap return; - static bool IsWindowActiveAndVisible(scoped in ImGuiWindow window) => - window.Active != 0 && window.Hidden == 0; + static bool IsWindowActiveAndVisible(ImGuiWindowPtr window) => window is { Active: true, Hidden: false }; - static void AddWindowToDrawData(scoped ref ImGuiWindow window, ref ImDrawList** wptr) + static void AddWindowToDrawData(ImGuiWindowPtr window, ref ImDrawList** wptr) { switch (window.DrawList.CmdBuffer.Size) { @@ -63,13 +57,13 @@ internal sealed unsafe partial class DrawListTextureWrap for (var i = 0; i < window.DC.ChildWindows.Size; i++) { - ref var child = ref *(ImGuiWindow*)window.DC.ChildWindows[i]; - if (IsWindowActiveAndVisible(in child)) // Clipped children may have been marked not active - AddWindowToDrawData(ref child, ref wptr); + var child = window.DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, ref wptr); } } - static int CountDrawList(scoped ref ImGuiWindow window) + static int CountDrawList(ImGuiWindowPtr window) { var res = window.DrawList.CmdBuffer.Size switch { @@ -79,51 +73,8 @@ internal sealed unsafe partial class DrawListTextureWrap _ => 1, }; for (var i = 0; i < window.DC.ChildWindows.Size; i++) - res += CountDrawList(ref *(ImGuiWindow*)window.DC.ChildWindows[i]); + res += CountDrawList(window.DC.ChildWindows[i]); return res; } } - - [StructLayout(LayoutKind.Explicit, Size = 0x448)] - private struct ImGuiWindow - { - [FieldOffset(0x048)] - public Vector2 Pos; - - [FieldOffset(0x050)] - public Vector2 Size; - - [FieldOffset(0x0CB)] - public byte Active; - - [FieldOffset(0x0D2)] - public byte Hidden; - - [FieldOffset(0x118)] - public ImGuiWindowTempData DC; - - [FieldOffset(0x2C0)] - public ImDrawListPtr DrawList; - - [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] -#pragma warning disable SA1300 - public static extern ImGuiWindow* igCustom_FindWindowByName(byte* inherit); -#pragma warning restore SA1300 - - public static ref ImGuiWindow FindWindowByName(ReadOnlySpan name) - { - var nb = Encoding.UTF8.GetByteCount(name); - var buf = stackalloc byte[nb + 1]; - buf[Encoding.UTF8.GetBytes(name, new(buf, nb))] = 0; - - return ref *igCustom_FindWindowByName(buf); - } - - [StructLayout(LayoutKind.Explicit, Size = 0xF0)] - public struct ImGuiWindowTempData - { - [FieldOffset(0x98)] - public ImVector ChildWindows; - } - } } diff --git a/imgui/Dalamud.Bindings.ImGui/Custom/ImDrawCallbackEnum.cs b/imgui/Dalamud.Bindings.ImGui/Custom/ImDrawCallbackEnum.cs new file mode 100644 index 000000000..4865d903c --- /dev/null +++ b/imgui/Dalamud.Bindings.ImGui/Custom/ImDrawCallbackEnum.cs @@ -0,0 +1,15 @@ +namespace Dalamud.Bindings.ImGui; + +public enum ImDrawCallbackEnum +{ + Empty, + + /// + /// Special Draw callback value to request renderer backend to reset the graphics/render state. + /// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at + /// this address. This is useful for example if you submitted callbacks which you know have altered the render + /// state, and you want it to be restored. It is not done by default because they are many perfectly useful way of + /// altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). + /// + ResetRenderState = -1, +} diff --git a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Custom.cs b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Custom.cs index faf6859a3..6e3420f49 100644 --- a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Custom.cs +++ b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Custom.cs @@ -1,6 +1,3 @@ -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - namespace Dalamud.Bindings.ImGui; public unsafe partial class ImGui diff --git a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Misc.cs b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Misc.cs index a2a138626..64629ccfc 100644 --- a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Misc.cs +++ b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Misc.cs @@ -6,6 +6,26 @@ namespace Dalamud.Bindings.ImGui; [SuppressMessage("ReSharper", "InconsistentNaming")] public static unsafe partial class ImGui { + public static void AddCallback( + ImDrawListPtr self, delegate* callback, void* callbackData = null) => + ((delegate* unmanaged[Cdecl], void*, void>)funcTable + [540])(self, callback, callbackData); + + public static void AddCallback( + ImDrawListPtr self, delegate* callback, void* callbackData = null) => + AddCallback(self, (delegate*)callback, callbackData); + + public static void AddCallback( + ImDrawListPtr self, delegate* callback, void* callbackData = null) => + AddCallback(self, (delegate*)callback, callbackData); + + public static void AddCallback(ImDrawListPtr self, ImDrawCallbackEnum presetCallback) + { + if (!Enum.IsDefined(presetCallback)) + throw new ArgumentOutOfRangeException(nameof(presetCallback), presetCallback, null); + AddCallback(self, (delegate*)(nint)presetCallback); + } + public static ImGuiPayloadPtr AcceptDragDropPayload( ImU8String type, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None) { diff --git a/imgui/Dalamud.Bindings.ImGui/Dalamud.Bindings.ImGui.csproj.DotSettings b/imgui/Dalamud.Bindings.ImGui/Dalamud.Bindings.ImGui.csproj.DotSettings new file mode 100644 index 000000000..06f483845 --- /dev/null +++ b/imgui/Dalamud.Bindings.ImGui/Dalamud.Bindings.ImGui.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/imgui/Dalamud.Bindings.ImGui/ImTextureID.cs b/imgui/Dalamud.Bindings.ImGui/ImTextureID.cs index 53643ab9f..7be18f2dc 100644 --- a/imgui/Dalamud.Bindings.ImGui/ImTextureID.cs +++ b/imgui/Dalamud.Bindings.ImGui/ImTextureID.cs @@ -28,7 +28,7 @@ namespace Dalamud.Bindings.ImGui public ImTextureID(void* handle) { Handle = (ulong)handle; } public ulong Handle { get; } public bool IsNull => Handle == 0; - public static ImTextureID Null => new ImTextureID(0); + public static ImTextureID Null => default; public static implicit operator ImTextureID(ulong handle) => new ImTextureID(handle); public static bool operator ==(ImTextureID left, ImTextureID right) => left.Handle == right.Handle; public static bool operator !=(ImTextureID left, ImTextureID right) => left.Handle != right.Handle;