Use ImGuiWindow from gen, support AddCallback

This commit is contained in:
Soreepeong 2025-08-02 20:21:11 +09:00
parent f7749237ee
commit 1a15600a8f
9 changed files with 91 additions and 87 deletions

View file

@ -1,3 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Cfontawesome/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Cfontawesome/@EntryIndexedValue">True</s:Boolean>
<s:Int64 x:Key="/Default/PerformanceThreshold/AnalysisFileSizeThreshold/=CSHARP/@EntryIndexedValue">300000</s:Int64> <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Ctextures_005Ctexturewraps_005Cinternal_005Cdrawlisttexturewrap/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -343,10 +343,16 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
var vertexOffset = 0; var vertexOffset = 0;
var indexOffset = 0; var indexOffset = 0;
var clipOff = new Vector4(drawData.DisplayPos, drawData.DisplayPos.X, drawData.DisplayPos.Y); 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) foreach (ref var cmdList in cmdLists)
{ {
var cmds = new ImVectorWrapper<ImDrawCmd>(cmdList.Handle->CmdBuffer.ToUntyped()); var cmds = new ImVectorWrapper<ImDrawCmd>(cmdList.Handle->CmdBuffer.ToUntyped());
foreach (ref var cmd in cmds.DataSpan) foreach (ref var cmd in cmds.DataSpan)
{
switch ((ImDrawCallbackEnum)(nint)cmd.UserCallback)
{
case ImDrawCallbackEnum.Empty:
{ {
var clipV4 = cmd.ClipRect - clipOff; var clipV4 = cmd.ClipRect - clipOff;
var clipRect = new RECT((int)clipV4.X, (int)clipV4.Y, (int)clipV4.Z, (int)clipV4.W); var clipRect = new RECT((int)clipV4.X, (int)clipV4.Y, (int)clipV4.Z, (int)clipV4.W);
@ -357,17 +363,30 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer
this.context.Get()->RSSetScissorRects(1, &clipRect); this.context.Get()->RSSetScissorRects(1, &clipRect);
if (cmd.UserCallback == null)
{
// Bind texture and draw // Bind texture and draw
var srv = (ID3D11ShaderResourceView*)cmd.TextureId.Handle; 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()->PSSetShaderResources(0, 1, &srv);
this.context.Get()->DrawIndexed( this.context.Get()->DrawIndexed(
cmd.ElemCount, cmd.ElemCount,
(uint)(cmd.IdxOffset + indexOffset), (uint)(cmd.IdxOffset + indexOffset),
(int)(cmd.VtxOffset + vertexOffset)); (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*<ImDrawListPtr, ref ImDrawCmd, void>)cmd.UserCallback;
cb(cmdList, ref cmd);
break;
}
} }
} }

View file

@ -71,7 +71,7 @@ internal class TexWidget : IDataWindowWidget
private enum DrawBlameTableColumnUserId private enum DrawBlameTableColumnUserId
{ {
NativeAddress, NativeAddress = 1,
Actions, Actions,
Name, Name,
Width, Width,
@ -231,7 +231,7 @@ internal class TexWidget : IDataWindowWidget
ImGui.PopID(); ImGui.PopID();
} }
if (ImGui.CollapsingHeader($"CropCopy##{this.DrawExistingTextureModificationArgs}")) if (ImGui.CollapsingHeader($"CropCopy##{nameof(this.DrawExistingTextureModificationArgs)}"))
{ {
ImGui.PushID(nameof(this.DrawExistingTextureModificationArgs)); ImGui.PushID(nameof(this.DrawExistingTextureModificationArgs));
this.DrawExistingTextureModificationArgs(); this.DrawExistingTextureModificationArgs();

View file

@ -1,9 +1,4 @@
using System.Diagnostics;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGui;
@ -15,13 +10,13 @@ internal sealed unsafe partial class DrawListTextureWrap
/// <inheritdoc/> /// <inheritdoc/>
public void ResizeAndDrawWindow(ReadOnlySpan<char> windowName, Vector2 scale) public void ResizeAndDrawWindow(ReadOnlySpan<char> windowName, Vector2 scale)
{ {
ref var window = ref ImGuiWindow.FindWindowByName(windowName); var window = ImGuiP.FindWindowByName(windowName);
if (Unsafe.IsNullRef(ref window)) if (window.IsNull)
throw new ArgumentException("Window not found", nameof(windowName)); throw new ArgumentException("Window not found", nameof(windowName));
this.Size = window.Size; this.Size = window.Size;
var numDrawList = CountDrawList(ref window); var numDrawList = CountDrawList(window);
var drawLists = stackalloc ImDrawList*[numDrawList]; var drawLists = stackalloc ImDrawList*[numDrawList];
var drawData = new ImDrawData var drawData = new ImDrawData
{ {
@ -34,7 +29,7 @@ internal sealed unsafe partial class DrawListTextureWrap
DisplaySize = window.Size, DisplaySize = window.Size,
FramebufferScale = scale, FramebufferScale = scale,
}; };
AddWindowToDrawData(ref window, ref drawLists); AddWindowToDrawData(window, ref drawLists);
for (var i = 0; i < numDrawList; i++) for (var i = 0; i < numDrawList; i++)
{ {
drawData.TotalVtxCount += drawData.CmdLists[i]->VtxBuffer.Size; drawData.TotalVtxCount += drawData.CmdLists[i]->VtxBuffer.Size;
@ -45,10 +40,9 @@ internal sealed unsafe partial class DrawListTextureWrap
return; return;
static bool IsWindowActiveAndVisible(scoped in ImGuiWindow window) => static bool IsWindowActiveAndVisible(ImGuiWindowPtr window) => window is { Active: true, Hidden: false };
window.Active != 0 && window.Hidden == 0;
static void AddWindowToDrawData(scoped ref ImGuiWindow window, ref ImDrawList** wptr) static void AddWindowToDrawData(ImGuiWindowPtr window, ref ImDrawList** wptr)
{ {
switch (window.DrawList.CmdBuffer.Size) 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++) for (var i = 0; i < window.DC.ChildWindows.Size; i++)
{ {
ref var child = ref *(ImGuiWindow*)window.DC.ChildWindows[i]; var child = window.DC.ChildWindows[i];
if (IsWindowActiveAndVisible(in child)) // Clipped children may have been marked not active if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
AddWindowToDrawData(ref child, ref wptr); AddWindowToDrawData(child, ref wptr);
} }
} }
static int CountDrawList(scoped ref ImGuiWindow window) static int CountDrawList(ImGuiWindowPtr window)
{ {
var res = window.DrawList.CmdBuffer.Size switch var res = window.DrawList.CmdBuffer.Size switch
{ {
@ -79,51 +73,8 @@ internal sealed unsafe partial class DrawListTextureWrap
_ => 1, _ => 1,
}; };
for (var i = 0; i < window.DC.ChildWindows.Size; i++) 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; 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<char> 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<nint> ChildWindows;
}
}
} }

View file

@ -0,0 +1,15 @@
namespace Dalamud.Bindings.ImGui;
public enum ImDrawCallbackEnum
{
Empty,
/// <summary>
/// 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).
/// </summary>
ResetRenderState = -1,
}

View file

@ -1,6 +1,3 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Dalamud.Bindings.ImGui; namespace Dalamud.Bindings.ImGui;
public unsafe partial class ImGui public unsafe partial class ImGui

View file

@ -6,6 +6,26 @@ namespace Dalamud.Bindings.ImGui;
[SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "InconsistentNaming")]
public static unsafe partial class ImGui public static unsafe partial class ImGui
{ {
public static void AddCallback(
ImDrawListPtr self, delegate*<ImDrawList*, ImDrawCmd*, void> callback, void* callbackData = null) =>
((delegate* unmanaged[Cdecl]<ImDrawList*, delegate*<ImDrawList*, ImDrawCmd*, void>, void*, void>)funcTable
[540])(self, callback, callbackData);
public static void AddCallback(
ImDrawListPtr self, delegate*<ImDrawListPtr, ImDrawCmdPtr, void> callback, void* callbackData = null) =>
AddCallback(self, (delegate*<ImDrawList*, ImDrawCmd*, void>)callback, callbackData);
public static void AddCallback(
ImDrawListPtr self, delegate*<ref ImDrawList, ref ImDrawCmd, void> callback, void* callbackData = null) =>
AddCallback(self, (delegate*<ImDrawList*, ImDrawCmd*, void>)callback, callbackData);
public static void AddCallback(ImDrawListPtr self, ImDrawCallbackEnum presetCallback)
{
if (!Enum.IsDefined(presetCallback))
throw new ArgumentOutOfRangeException(nameof(presetCallback), presetCallback, null);
AddCallback(self, (delegate*<ImDrawList*, ImDrawCmd*, void>)(nint)presetCallback);
}
public static ImGuiPayloadPtr AcceptDragDropPayload( public static ImGuiPayloadPtr AcceptDragDropPayload(
ImU8String type, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None) ImU8String type, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
{ {

View file

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=custom/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -28,7 +28,7 @@ namespace Dalamud.Bindings.ImGui
public ImTextureID(void* handle) { Handle = (ulong)handle; } public ImTextureID(void* handle) { Handle = (ulong)handle; }
public ulong Handle { get; } public ulong Handle { get; }
public bool IsNull => Handle == 0; 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 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;
public static bool operator !=(ImTextureID left, ImTextureID right) => left.Handle != right.Handle; public static bool operator !=(ImTextureID left, ImTextureID right) => left.Handle != right.Handle;