diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs
index 28a9075bd..1ee248b17 100644
--- a/Dalamud/Interface/Internal/DalamudIme.cs
+++ b/Dalamud/Interface/Internal/DalamudIme.cs
@@ -11,6 +11,7 @@ using System.Text.Unicode;
using Dalamud.Game.Text;
using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.GameFonts;
+using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility;
@@ -28,7 +29,6 @@ namespace Dalamud.Interface.Internal;
[ServiceManager.BlockingEarlyLoadedService]
internal sealed unsafe class DalamudIme : IDisposable, IServiceType
{
- private const int ImGuiContextTextStateOffset = 0x4588;
private const int CImGuiStbTextCreateUndoOffset = 0xB57A0;
private const int CImGuiStbTextUndoOffset = 0xB59C0;
@@ -178,7 +178,7 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
internal char InputModeIcon { get; private set; }
private static ImGuiInputTextState* TextState =>
- (ImGuiInputTextState*)(ImGui.GetCurrentContext() + ImGuiContextTextStateOffset);
+ (ImGuiInputTextState*)(ImGui.GetCurrentContext() + ImGuiContextOffsets.TextStateOffset);
///
public void Dispose()
diff --git a/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs b/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
new file mode 100644
index 000000000..cdf7ab23e
--- /dev/null
+++ b/Dalamud/Interface/Internal/ImGuiDrawListFixProvider.cs
@@ -0,0 +1,124 @@
+using System.Diagnostics;
+using System.Linq;
+using System.Numerics;
+
+using Dalamud.Hooking;
+
+using ImGuiNET;
+
+namespace Dalamud.Interface.Internal;
+
+///
+/// Fixes ImDrawList not correctly dealing with the current texture for that draw list not in tune with the global
+/// state. Currently, ImDrawList::AddPolyLine and ImDrawList::AddRectFilled are affected.
+///
+/// * The implementation for AddRectFilled is entirely replaced with the hook below.
+/// * The implementation for AddPolyLine is wrapped with Push/PopTextureID.
+///
+/// TODO:
+/// * imgui_draw.cpp:1433 ImDrawList::AddRectFilled
+/// The if block needs a PushTextureID(_Data->TexIdCommon)/PopTextureID() block,
+/// if _Data->TexIdCommon != _CmdHeader.TextureId.
+/// * imgui_draw.cpp:729 ImDrawList::AddPolyLine
+/// The if block always needs to call PushTextureID if the abovementioned condition is not met.
+/// Change push_texture_id to only have one condition.
+///
+[ServiceManager.EarlyLoadedService]
+internal sealed unsafe class ImGuiDrawListFixProvider : IServiceType, IDisposable
+{
+ private const int CImGuiImDrawListAddPolyLineOffset = 0x589B0;
+ private const int CImGuiImDrawListAddRectFilled = 0x59FD0;
+ private const int CImGuiImDrawListSharedDataTexIdCommonOffset = 0;
+
+ private readonly Hook hookImDrawListAddPolyline;
+ private readonly Hook hookImDrawListAddRectFilled;
+
+ [ServiceManager.ServiceConstructor]
+ private ImGuiDrawListFixProvider(InterfaceManager.InterfaceManagerWithScene imws)
+ {
+ // Force cimgui.dll to be loaded.
+ _ = ImGui.GetCurrentContext();
+ var cimgui = Process.GetCurrentProcess().Modules.Cast()
+ .First(x => x.ModuleName == "cimgui.dll")
+ .BaseAddress;
+
+ this.hookImDrawListAddPolyline = Hook.FromAddress(
+ cimgui + CImGuiImDrawListAddPolyLineOffset,
+ this.ImDrawListAddPolylineDetour);
+ this.hookImDrawListAddRectFilled = Hook.FromAddress(
+ cimgui + CImGuiImDrawListAddRectFilled,
+ this.ImDrawListAddRectFilledDetour);
+ this.hookImDrawListAddPolyline.Enable();
+ this.hookImDrawListAddRectFilled.Enable();
+ }
+
+ private delegate void ImDrawListAddPolyLine(
+ ImDrawListPtr drawListPtr,
+ ref Vector2 points,
+ int pointsCount,
+ uint color,
+ ImDrawFlags flags,
+ float thickness);
+
+ private delegate void ImDrawListAddRectFilled(
+ ImDrawListPtr drawListPtr,
+ ref Vector2 min,
+ ref Vector2 max,
+ uint col,
+ float rounding,
+ ImDrawFlags flags);
+
+ ///
+ public void Dispose()
+ {
+ this.hookImDrawListAddPolyline.Dispose();
+ this.hookImDrawListAddRectFilled.Dispose();
+ }
+
+ private void ImDrawListAddRectFilledDetour(
+ ImDrawListPtr drawListPtr,
+ ref Vector2 min,
+ ref Vector2 max,
+ uint col,
+ float rounding,
+ ImDrawFlags flags)
+ {
+ if (rounding < 0 || (flags & ImDrawFlags.RoundCornersMask) == ImDrawFlags.RoundCornersMask)
+ {
+ var texIdCommon = *(nint*)(drawListPtr._Data + CImGuiImDrawListSharedDataTexIdCommonOffset);
+ var pushTextureId = texIdCommon != drawListPtr._CmdHeader.TextureId;
+ if (pushTextureId)
+ drawListPtr.PushTextureID(texIdCommon);
+
+ drawListPtr.PrimReserve(6, 4);
+ drawListPtr.PrimRect(min, max, col);
+
+ if (pushTextureId)
+ drawListPtr.PopTextureID();
+ }
+ else
+ {
+ drawListPtr.PathRect(min, max, rounding, flags);
+ drawListPtr.PathFillConvex(col);
+ }
+ }
+
+ private void ImDrawListAddPolylineDetour(
+ ImDrawListPtr drawListPtr,
+ ref Vector2 points,
+ int pointsCount,
+ uint color,
+ ImDrawFlags flags,
+ float thickness)
+ {
+ var texIdCommon = *(nint*)(drawListPtr._Data + CImGuiImDrawListSharedDataTexIdCommonOffset);
+ var pushTextureId = texIdCommon != drawListPtr._CmdHeader.TextureId;
+ if (pushTextureId)
+ drawListPtr.PushTextureID(texIdCommon);
+
+ this.hookImDrawListAddPolyline.Original(drawListPtr, ref points, pointsCount, color, flags, thickness);
+
+ if (pushTextureId)
+ drawListPtr.PopTextureID();
+ }
+}
diff --git a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs b/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
index fd203192f..89e23ab78 100644
--- a/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
+++ b/Dalamud/Interface/Internal/ManagedAsserts/ImGuiContextOffsets.cs
@@ -18,4 +18,6 @@ internal static class ImGuiContextOffsets
public const int FontStackOffset = 0x7A4;
public const int BeginPopupStackOffset = 0x7B8;
+
+ public const int TextStateOffset = 0x4588;
}
diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/ImGuiDockNodeUpdateForceFont.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/ImGuiDockNodeUpdateForceFont.cs
deleted file mode 100644
index a2a30429a..000000000
--- a/Dalamud/Interface/ManagedFontAtlas/Internals/ImGuiDockNodeUpdateForceFont.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System.Diagnostics;
-using System.Linq;
-
-using Dalamud.Hooking;
-using Dalamud.Interface.Internal;
-using Dalamud.Interface.Utility;
-
-namespace Dalamud.Interface.ManagedFontAtlas.Internals;
-
-///
-/// Forces ImGui::RenderWindowDecorations to use the default font.
-/// Fixes dock node draw using shared data across different draw lists.
-/// TODO: figure out how to synchronize ImDrawList::_Data and ImDrawList::Push/PopTextureID across different instances.
-/// It might be better to just special-case that particular function,
-/// as no other code touches ImDrawList that is irrelevant to the global shared state,
-/// with the exception of Dock... functions which are called from ImGui::NewFrame,
-/// which are guaranteed to use the global default font.
-///
-[ServiceManager.EarlyLoadedService]
-internal class ImGuiRenderWindowDecorationsForceFont : IServiceType, IDisposable
-{
- private const int CImGuiRenderWindowDecorationsOffset = 0x461B0;
- private const int CImGuiWindowDockIsActiveOffset = 0x401;
-
- private readonly Hook hook;
-
- [ServiceManager.ServiceConstructor]
- private ImGuiRenderWindowDecorationsForceFont(InterfaceManager.InterfaceManagerWithScene imws)
- {
- // Effectively waiting for ImGui to become available.
- Debug.Assert(ImGuiHelpers.IsImGuiInitialized, "IMWS initialized but IsImGuiInitialized is false?");
-
- var cimgui = Process.GetCurrentProcess().Modules.Cast()
- .First(x => x.ModuleName == "cimgui.dll")
- .BaseAddress;
- this.hook = Hook.FromAddress(
- cimgui + CImGuiRenderWindowDecorationsOffset,
- this.ImGuiRenderWindowDecorationsDetour);
- this.hook.Enable();
- }
-
- private delegate void ImGuiRenderWindowDecorationsDelegate(
- nint window,
- nint titleBarRectPtr,
- byte titleBarIsHighlight,
- byte handleBordersAndResizeGrips,
- int resizeGripCount,
- nint resizeGripColPtr,
- float resizeGripDrawSize);
-
- ///
- public void Dispose() => this.hook.Dispose();
-
- private unsafe void ImGuiRenderWindowDecorationsDetour(
- nint window,
- nint titleBarRectPtr,
- byte titleBarIsHighlight,
- byte handleBordersAndResizeGrips,
- int resizeGripCount,
- nint resizeGripColPtr,
- float resizeGripDrawSize)
- {
- using (
- ((byte*)window)![CImGuiWindowDockIsActiveOffset] != 0
- ? Service.Get().DefaultFontHandle?.Push()
- : null)
- {
- this.hook.Original(
- window,
- titleBarRectPtr,
- titleBarIsHighlight,
- handleBordersAndResizeGrips,
- resizeGripCount,
- resizeGripColPtr,
- resizeGripDrawSize);
- }
- }
-}