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">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Cfontawesome/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Int64 x:Key="/Default/PerformanceThreshold/AnalysisFileSizeThreshold/=CSHARP/@EntryIndexedValue">300000</s:Int64>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Cfontawesome/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interface_005Ctextures_005Ctexturewraps_005Cinternal_005Cdrawlisttexturewrap/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -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<ImDrawCmd>(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*<ImDrawListPtr, ref ImDrawCmd, void>)cmd.UserCallback;
cb(cmdList, ref cmd);
break;
}
}
}

View file

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

View file

@ -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
/// <inheritdoc/>
public void ResizeAndDrawWindow(ReadOnlySpan<char> 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<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;
public unsafe partial class ImGui

View file

@ -6,6 +6,26 @@ namespace Dalamud.Bindings.ImGui;
[SuppressMessage("ReSharper", "InconsistentNaming")]
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(
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 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;