From fcd98ee2bb557c8048c91749e03b8defed593b32 Mon Sep 17 00:00:00 2001
From: meli <57847713+ff-meli@users.noreply.github.com>
Date: Wed, 29 Apr 2020 17:13:05 -0700
Subject: [PATCH] Add ability for plugins to add ImGui fonts at runtime, though
we should discourage this as much as possible. Also sneak in an api-matching
update to part of ImGuiScene, to make more things useable in SamplePlugin
---
Dalamud/Interface/InterfaceManager.cs | 85 +++++++++++++++++++--------
Dalamud/Interface/UiBuilder.cs | 20 +++++++
lib/ImGuiScene | 2 +-
3 files changed, 81 insertions(+), 26 deletions(-)
diff --git a/Dalamud/Interface/InterfaceManager.cs b/Dalamud/Interface/InterfaceManager.cs
index 3d66d24d8..5fde5a051 100644
--- a/Dalamud/Interface/InterfaceManager.cs
+++ b/Dalamud/Interface/InterfaceManager.cs
@@ -54,11 +54,15 @@ namespace Dalamud.Interface
public ImGuiIOPtr LastImGuiIoPtr;
+ public Action OnBuildFonts;
+ private bool isRebuildingFonts = false;
+
///
/// This event gets called by a plugin UiBuilder when read
///
public event RawDX11Scene.BuildUIDelegate OnDraw;
+
public InterfaceManager(Dalamud dalamud, SigScanner scanner)
{
this.dalamud = dalamud;
@@ -200,7 +204,18 @@ namespace Dalamud.Interface
return null;
}
- private unsafe IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
+ // Sets up a deferred invocation of font rebuilding, before the next render frame
+ public void RebuildFonts()
+ {
+ // don't invoke this multiple times per frame, in case multiple plugins call it
+ if (!this.isRebuildingFonts)
+ {
+ this.isRebuildingFonts = true;
+ this.scene.OnNewRenderFrame += RebuildFontsInternal;
+ }
+ }
+
+ private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
{
if (this.scene == null)
{
@@ -209,30 +224,7 @@ namespace Dalamud.Interface
this.scene.OnBuildUI += Display;
this.scene.OnNewInputFrame += OnNewInputFrame;
- ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig();
- fontConfig.MergeMode = true;
- fontConfig.PixelSnapH = true;
-
- var fontPathJp = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "NotoSansCJKjp-Medium.otf");
- ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, ImGui.GetIO().Fonts.GetGlyphRangesJapanese());
-
- var fontPathGame = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "gamesym.ttf");
- Log.Verbose(fontPathGame);
-
- var rangeHandle = GCHandle.Alloc(new ushort[]
- {
- 0xE020,
- 0xE0DB,
- 0
- }, GCHandleType.Pinned);
-
-
- ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, rangeHandle.AddrOfPinnedObject());
-
- ImGui.GetIO().Fonts.Build();
-
- fontConfig.Destroy();
- rangeHandle.Free();
+ SetupFonts();
ImGui.GetStyle().GrabRounding = 3f;
ImGui.GetStyle().FrameRounding = 4f;
@@ -268,6 +260,49 @@ namespace Dalamud.Interface
return this.presentHook.Original(swapChain, syncInterval, presentFlags);
}
+ private unsafe void SetupFonts()
+ {
+ ImGui.GetIO().Fonts.Clear();
+
+ ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig();
+ fontConfig.MergeMode = true;
+ fontConfig.PixelSnapH = true;
+
+ var fontPathJp = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "NotoSansCJKjp-Medium.otf");
+ ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, ImGui.GetIO().Fonts.GetGlyphRangesJapanese());
+
+ var fontPathGame = Path.Combine(this.dalamud.StartInfo.WorkingDirectory, "UIRes", "gamesym.ttf");
+ Log.Verbose(fontPathGame);
+
+ var rangeHandle = GCHandle.Alloc(new ushort[]
+ {
+ 0xE020,
+ 0xE0DB,
+ 0
+ }, GCHandleType.Pinned);
+
+
+ ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, rangeHandle.AddrOfPinnedObject());
+
+ OnBuildFonts?.Invoke();
+
+ ImGui.GetIO().Fonts.Build();
+
+ fontConfig.Destroy();
+ rangeHandle.Free();
+ }
+
+ // This is intended to only be called as a handler attached to scene.OnNewRenderFrame
+ private void RebuildFontsInternal()
+ {
+ SetupFonts();
+
+ this.scene.OnNewRenderFrame -= RebuildFontsInternal;
+ this.scene.InvalidateFonts();
+
+ this.isRebuildingFonts = false;
+ }
+
private IntPtr ResizeBuffersDetour(IntPtr swapChain, uint bufferCount, uint width, uint height, uint newFormat, uint swapChainFlags)
{
Log.Verbose($"Calling resizebuffers {bufferCount} {width} {height} {newFormat} {swapChainFlags}");
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index 31468e302..8b2d3f30a 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -70,6 +70,26 @@ namespace Dalamud.Interface
public TextureWrap LoadImageRaw(byte[] imageData, int width, int height, int numChannels) =>
this.interfaceManager.LoadImageRaw(imageData, width, height, numChannels);
+ ///
+ /// An event that is called any time ImGui fonts need to be rebuilt.
+ /// Any ImFontPtr objects that you store can be invalidated when fonts are rebuilt
+ /// (at any time), so you should both reload your custom fonts and restore those
+ /// pointers inside this handler.
+ ///
+ public Action OnBuildFonts
+ {
+ get { return this.interfaceManager.OnBuildFonts; }
+ set { this.interfaceManager.OnBuildFonts = value; }
+ }
+
+ ///
+ /// Call this to queue a rebuild of the font atlas.
+ /// This will invoke any handlers and ensure that any loaded fonts are
+ /// ready to be used on the next UI frame.
+ ///
+ public void RebuildFonts() =>
+ this.interfaceManager.RebuildFonts();
+
///
/// Event that is fired when the plugin should open its configuration interface.
///
diff --git a/lib/ImGuiScene b/lib/ImGuiScene
index aaa037938..d5b9345dc 160000
--- a/lib/ImGuiScene
+++ b/lib/ImGuiScene
@@ -1 +1 @@
-Subproject commit aaa037938d6fe835a15542a3451d12108e3f83b6
+Subproject commit d5b9345dc1463d746b832843bd7c81b753d4e5b0