diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index 46d37fe90..d252321db 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -699,35 +699,38 @@ internal class InterfaceManager : IDisposable, IServiceType
{
this.dalamudAtlas = fontAtlasFactory
.CreateFontAtlas(nameof(InterfaceManager), FontAtlasAutoRebuildMode.Disable);
- this.defaultFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
- e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(DefaultFontSizePx)));
- this.iconFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
- e => e.OnPreBuild(
- tk => tk.AddFontAwesomeIconFont(
- new()
- {
- SizePx = DefaultFontSizePx,
- GlyphMinAdvanceX = DefaultFontSizePx,
- GlyphMaxAdvanceX = DefaultFontSizePx,
- })));
- this.monoFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
- e => e.OnPreBuild(
- tk => tk.AddDalamudAssetFont(
- DalamudAsset.InconsolataRegular,
- new() { SizePx = DefaultFontSizePx })));
- this.dalamudAtlas.BuildStepChange += e => e.OnPostPromotion(
- tk =>
- {
- // Note: the first call of this function is done outside the main thread; this is expected.
- // Do not use DefaultFont, IconFont, and MonoFont.
- // Use font handles directly.
+ using (this.dalamudAtlas.SuppressAutoRebuild())
+ {
+ this.defaultFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
+ e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(DefaultFontSizePx)));
+ this.iconFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
+ e => e.OnPreBuild(
+ tk => tk.AddFontAwesomeIconFont(
+ new()
+ {
+ SizePx = DefaultFontSizePx,
+ GlyphMinAdvanceX = DefaultFontSizePx,
+ GlyphMaxAdvanceX = DefaultFontSizePx,
+ })));
+ this.monoFontHandle = (IFontHandle.IInternal)this.dalamudAtlas.NewDelegateFontHandle(
+ e => e.OnPreBuild(
+ tk => tk.AddDalamudAssetFont(
+ DalamudAsset.InconsolataRegular,
+ new() { SizePx = DefaultFontSizePx })));
+ this.dalamudAtlas.BuildStepChange += e => e.OnPostPromotion(
+ tk =>
+ {
+ // Note: the first call of this function is done outside the main thread; this is expected.
+ // Do not use DefaultFont, IconFont, and MonoFont.
+ // Use font handles directly.
- // Fill missing glyphs in MonoFont from DefaultFont
- tk.CopyGlyphsAcrossFonts(this.defaultFontHandle.ImFont, this.monoFontHandle.ImFont, true);
+ // Fill missing glyphs in MonoFont from DefaultFont
+ tk.CopyGlyphsAcrossFonts(this.defaultFontHandle.ImFont, this.monoFontHandle.ImFont, true);
- // Broadcast to auto-rebuilding instances
- this.AfterBuildFonts?.Invoke();
- });
+ // Broadcast to auto-rebuilding instances
+ this.AfterBuildFonts?.Invoke();
+ });
+ }
// This will wait for scene on its own. We just wait for this.dalamudAtlas.BuildTask in this.InitScene.
_ = this.dalamudAtlas.BuildFontsAsync(false);
diff --git a/Dalamud/Interface/ManagedFontAtlas/IFontAtlas.cs b/Dalamud/Interface/ManagedFontAtlas/IFontAtlas.cs
index 0a50d6070..d32adc1eb 100644
--- a/Dalamud/Interface/ManagedFontAtlas/IFontAtlas.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/IFontAtlas.cs
@@ -1,7 +1,6 @@
using System.Threading.Tasks;
using Dalamud.Interface.GameFonts;
-using Dalamud.Interface.ManagedFontAtlas.Internals;
using ImGuiNET;
@@ -54,25 +53,73 @@ public interface IFontAtlas : IDisposable
///
bool IsGlobalScaled { get; }
- ///
+ ///
+ /// Suppresses automatically rebuilding fonts for the scope.
+ ///
+ /// An instance of that will release the suppression.
+ ///
+ /// Use when you will be creating multiple new handles, and want rebuild to trigger only when you're done doing so.
+ /// This function will effectively do nothing, if is set to
+ /// .
+ ///
+ ///
+ ///
+ /// using (atlas.SuppressBuild()) {
+ /// this.font1 = atlas.NewGameFontHandle(...);
+ /// this.font2 = atlas.NewDelegateFontHandle(...);
+ /// }
+ ///
+ ///
+ public IDisposable SuppressAutoRebuild();
+
+ ///
+ /// Creates a new from game's built-in fonts.
+ ///
+ /// Font to use.
+ /// Handle to a font that may or may not be ready yet.
public IFontHandle NewGameFontHandle(GameFontStyle style);
- ///
+ ///
+ /// Creates a new IFontHandle using your own callbacks.
+ ///
+ /// Callback for .
+ /// Handle to a font that may or may not be ready yet.
+ ///
+ /// On initialization:
+ ///
+ /// this.fontHandle = atlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => {
+ /// var config = new SafeFontConfig { SizePx = 16 };
+ /// config.MergeFont = tk.AddFontFromFile(@"C:\Windows\Fonts\comic.ttf", config);
+ /// tk.AddGameSymbol(config);
+ /// tk.AddExtraGlyphsForDalamudLanguage(config);
+ /// // optionally do the following if you have to add more than one font here,
+ /// // to specify which font added during this delegate is the final font to use.
+ /// tk.Font = config.MergeFont;
+ /// }));
+ /// // or
+ /// this.fontHandle = atlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(36)));
+ ///
+ ///
+ /// On use:
+ ///
+ /// using (this.fontHandle.Push())
+ /// ImGui.TextUnformatted("Example");
+ ///
+ ///
public IFontHandle NewDelegateFontHandle(FontAtlasBuildStepDelegate buildStepDelegate);
- ///
- public void FreeFontHandle(IFontHandle handle);
-
///
/// Queues rebuilding fonts, on the main thread.
/// Note that would not necessarily get changed from calling this function.
///
+ /// If is .
void BuildFontsOnNextFrame();
///
/// Rebuilds fonts immediately, on the current thread.
/// Even the callback for will be called on the same thread.
///
+ /// If is .
void BuildFontsImmediately();
///
@@ -80,5 +127,6 @@ public interface IFontAtlas : IDisposable
///
/// Call on the main thread.
/// The task.
+ /// If is .
Task BuildFontsAsync(bool callPostPromotionOnMainThread = true);
}
diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs
index f9f2c0ef1..b6ec720dc 100644
--- a/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs
@@ -88,11 +88,7 @@ internal class DelegateFontHandle : IFontHandle.IInternal
}
}
- ///
- /// Creates a new IFontHandle using your own callbacks.
- ///
- /// Callback for .
- /// Handle to a font that may or may not be ready yet.
+ ///
public IFontHandle NewFontHandle(FontAtlasBuildStepDelegate buildStepDelegate)
{
var key = new DelegateFontHandle(this, buildStepDelegate);
diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs
index 52d77b963..5656fc673 100644
--- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
@@ -203,6 +204,9 @@ internal sealed partial class FontAtlasFactory
private Task buildTask = EmptyTask;
private FontAtlasBuiltData builtData;
+ private int buildSuppressionCounter;
+ private bool buildSuppressionSuppressed;
+
private int buildIndex;
private bool buildQueued;
private bool disposed = false;
@@ -356,6 +360,19 @@ internal sealed partial class FontAtlasFactory
GC.SuppressFinalize(this);
}
+ ///
+ public IDisposable SuppressAutoRebuild()
+ {
+ this.buildSuppressionCounter++;
+ return Disposable.Create(
+ () =>
+ {
+ this.buildSuppressionCounter--;
+ if (this.buildSuppressionSuppressed)
+ this.OnRebuildRecommend();
+ });
+ }
+
///
public IFontHandle NewGameFontHandle(GameFontStyle style) => this.gameFontHandleManager.NewFontHandle(style);
@@ -363,15 +380,6 @@ internal sealed partial class FontAtlasFactory
public IFontHandle NewDelegateFontHandle(FontAtlasBuildStepDelegate buildStepDelegate) =>
this.delegateFontHandleManager.NewFontHandle(buildStepDelegate);
- ///
- public void FreeFontHandle(IFontHandle handle)
- {
- foreach (var manager in this.fontHandleManagers)
- {
- manager.FreeFontHandle(handle);
- }
- }
-
///
public void BuildFontsOnNextFrame()
{
@@ -688,6 +696,13 @@ internal sealed partial class FontAtlasFactory
if (this.disposed)
return;
+ if (this.buildSuppressionCounter > 0)
+ {
+ this.buildSuppressionSuppressed = true;
+ return;
+ }
+
+ this.buildSuppressionSuppressed = false;
this.factory.Framework.RunOnFrameworkThread(
() =>
{
diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs
index c40302f6c..2739ed2da 100644
--- a/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs
@@ -157,11 +157,7 @@ internal class GamePrebakedFontHandle : IFontHandle.IInternal
this.Substance = null;
}
- ///
- /// Creates a new from game's built-in fonts.
- ///
- /// Font to use.
- /// Handle to a font that may or may not be ready yet.
+ ///
public IFontHandle NewFontHandle(GameFontStyle style)
{
var handle = new GamePrebakedFontHandle(this, style);
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index 5d0810009..a477ec09e 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -37,7 +37,6 @@ public sealed class UiBuilder : IDisposable
private readonly DalamudConfiguration configuration = Service.Get();
private readonly DisposeSafety.ScopedFinalizer scopedFinalizer = new();
- private readonly IFontAtlas privateAtlas;
private bool hasErrorWindow = false;
private bool lastFrameUiHideState = false;
@@ -61,14 +60,14 @@ public sealed class UiBuilder : IDisposable
this.interfaceManager.ResizeBuffers += this.OnResizeBuffers;
this.scopedFinalizer.Add(() => this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers);
- this.privateAtlas =
+ this.FontAtlas =
this.scopedFinalizer
.Add(
Service
.Get()
.CreateFontAtlas(namespaceName, FontAtlasAutoRebuildMode.Disable));
- this.privateAtlas.BuildStepChange += this.PrivateAtlasOnBuildStepChange;
- this.privateAtlas.RebuildRecommend += this.RebuildFonts;
+ this.FontAtlas.BuildStepChange += this.PrivateAtlasOnBuildStepChange;
+ this.FontAtlas.RebuildRecommend += this.RebuildFonts;
}
catch
{
@@ -104,7 +103,7 @@ public sealed class UiBuilder : IDisposable
/// (at any time), so you should both reload your custom fonts and restore those
/// pointers inside this handler.
///
- [Obsolete($"Use {nameof(NewDelegateFontHandle)} instead.", false)]
+ [Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
public event Action? BuildFonts;
///
@@ -113,7 +112,7 @@ public sealed class UiBuilder : IDisposable
/// (at any time), so you should both reload your custom fonts and restore those
/// pointers inside this handler.
///
- [Obsolete($"Use {nameof(NewDelegateFontHandle)} instead.", false)]
+ [Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
public event Action? AfterBuildFonts;
///
@@ -145,7 +144,7 @@ public sealed class UiBuilder : IDisposable
///
/// A font handle corresponding to this font can be obtained with:
///
- /// uiBuilderOrFontAtlas.NewDelegateFontHandle(
+ /// fontAtlas.NewDelegateFontHandle(
/// e => e.OnPreBuild(
/// tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePt)));
///
@@ -159,7 +158,7 @@ public sealed class UiBuilder : IDisposable
///
/// A font handle corresponding to this font can be obtained with:
///
- /// uiBuilderOrFontAtlas.NewDelegateFontHandle(
+ /// fontAtlas.NewDelegateFontHandle(
/// e => e.OnPreBuild(
/// tk => tk.AddFontAwesomeIconFont(new() { SizePt = UiBuilder.DefaultFontSizePt })));
///
@@ -173,7 +172,7 @@ public sealed class UiBuilder : IDisposable
///
/// A font handle corresponding to this font can be obtained with:
///
- /// uiBuilderOrFontAtlas.NewDelegateFontHandle(
+ /// fontAtlas.NewDelegateFontHandle(
/// e => e.OnPreBuild(
/// tk => tk.AddDalamudAssetFont(
/// DalamudAsset.InconsolataRegular,
@@ -251,6 +250,11 @@ public sealed class UiBuilder : IDisposable
///
public bool UiPrepared => Service.GetNullable() != null;
+ ///
+ /// Gets the plugin-private font atlas.
+ ///
+ public IFontAtlas FontAtlas { get; }
+
///
/// Gets or sets a value indicating whether statistics about UI draw time should be collected.
///
@@ -418,40 +422,11 @@ public sealed class UiBuilder : IDisposable
///
/// Font to get.
/// Handle to the game font which may or may not be available for use yet.
- [Obsolete($"Use {nameof(NewGameFontHandle)} instead.", false)]
+ [Obsolete($"Use {nameof(this.FontAtlas)}.{nameof(IFontAtlas.NewGameFontHandle)} instead.", false)]
public GameFontHandle GetGameFontHandle(GameFontStyle style) => new(
- (IFontHandle.IInternal)this.NewGameFontHandle(style),
+ (IFontHandle.IInternal)this.FontAtlas.NewGameFontHandle(style),
Service.Get());
- ///
- public IFontHandle NewGameFontHandle(GameFontStyle style) => this.privateAtlas.NewGameFontHandle(style);
-
- ///
- ///
- /// On initialization:
- ///
- /// this.fontHandle = uiBuilder.NewDelegateFontHandle(e => e.OnPreBuild(tk => {
- /// var config = new SafeFontConfig { SizePx = 16 };
- /// config.MergeFont = tk.AddFontFromFile(@"C:\Windows\Fonts\comic.ttf", config);
- /// tk.AddGameSymbol(config);
- /// tk.AddExtraGlyphsForDalamudLanguage(config);
- /// // optionally do the following if you have to add more than one font here,
- /// // to specify which font added during this delegate is the final font to use.
- /// tk.Font = config.MergeFont;
- /// }));
- /// // or
- /// this.fontHandle = uiBuilder.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(36)));
- ///
- ///
- /// On use:
- ///
- /// using (this.fontHandle.Push())
- /// ImGui.TextUnformatted("Example");
- ///
- ///
- public IFontHandle NewDelegateFontHandle(FontAtlasBuildStepDelegate buildStepDelegate) =>
- this.privateAtlas.NewDelegateFontHandle(buildStepDelegate);
-
///
/// Call this to queue a rebuild of the font atlas.
/// This will invoke any and handlers and ensure that any
@@ -461,9 +436,9 @@ public sealed class UiBuilder : IDisposable
{
Log.Verbose("[FONT] {0} plugin is initiating FONT REBUILD", this.namespaceName);
if (this.AfterBuildFonts is null && this.BuildFonts is null)
- this.privateAtlas.BuildFontsAsync();
+ this.FontAtlas.BuildFontsAsync();
else
- this.privateAtlas.BuildFontsOnNextFrame();
+ this.FontAtlas.BuildFontsOnNextFrame();
}
///
@@ -579,7 +554,7 @@ public sealed class UiBuilder : IDisposable
}
// just in case, if something goes wrong, prevent drawing; otherwise it probably will crash.
- if (!this.privateAtlas.BuildTask.IsCompletedSuccessfully
+ if (!this.FontAtlas.BuildTask.IsCompletedSuccessfully
&& (this.BuildFonts is not null || this.AfterBuildFonts is not null))
{
return;