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/ImGuiClipboardFunctionProvider.cs b/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs index 1746fb1c4..bbf665405 100644 --- a/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs +++ b/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs @@ -52,7 +52,6 @@ internal sealed unsafe class ImGuiClipboardFunctionProvider : IServiceType, IDis private ImGuiClipboardFunctionProvider(InterfaceManager.InterfaceManagerWithScene imws) { // Effectively waiting for ImGui to become available. - _ = imws; Debug.Assert(ImGuiHelpers.IsImGuiInitialized, "IMWS initialized but IsImGuiInitialized is false?"); var io = ImGui.GetIO(); 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; }