diff --git a/Dalamud/Interface/GameFonts/GameFontManager.cs b/Dalamud/Interface/GameFonts/GameFontManager.cs index b7e208af1..6b00be2e7 100644 --- a/Dalamud/Interface/GameFonts/GameFontManager.cs +++ b/Dalamud/Interface/GameFonts/GameFontManager.cs @@ -284,39 +284,49 @@ namespace Dalamud.Interface.GameFonts /// public void BuildFonts() { - var io = ImGui.GetIO(); - io.Fonts.TexDesiredWidth = 4096; - - this.glyphRectIds.Clear(); - this.fonts.Clear(); - - foreach (var style in this.fontUseCounter.Keys) + unsafe { - var rectIds = this.glyphRectIds[style] = new(); + ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig(); + fontConfig.OversampleH = 1; + fontConfig.OversampleV = 1; + fontConfig.PixelSnapH = true; - var fdt = this.fdts[(int)style.FamilyAndSize]; - if (fdt == null) - continue; + var io = ImGui.GetIO(); + io.Fonts.TexDesiredWidth = 4096; - var font = io.Fonts.AddFontDefault(); - this.fonts[style] = font; - foreach (var glyph in fdt.Glyphs) + this.glyphRectIds.Clear(); + this.fonts.Clear(); + + foreach (var style in this.fontUseCounter.Keys) { - var c = glyph.Char; - if (c < 32 || c >= 0xFFFF) + var rectIds = this.glyphRectIds[style] = new(); + + var fdt = this.fdts[(int)style.FamilyAndSize]; + if (fdt == null) continue; - var widthAdjustment = style.CalculateWidthAdjustment(fdt, glyph); - rectIds[c] = Tuple.Create( - io.Fonts.AddCustomRectFontGlyph( - font, - c, - glyph.BoundingWidth + widthAdjustment + 1, - glyph.BoundingHeight + 1, - glyph.AdvanceWidth, - new Vector2(0, glyph.CurrentOffsetY)), - glyph); + var font = io.Fonts.AddFontDefault(fontConfig); + this.fonts[style] = font; + foreach (var glyph in fdt.Glyphs) + { + var c = glyph.Char; + if (c < 32 || c >= 0xFFFF) + continue; + + var widthAdjustment = style.CalculateWidthAdjustment(fdt, glyph); + rectIds[c] = Tuple.Create( + io.Fonts.AddCustomRectFontGlyph( + font, + c, + glyph.BoundingWidth + widthAdjustment + 1, + glyph.BoundingHeight + 1, + glyph.AdvanceWidth, + new Vector2(0, glyph.CurrentOffsetY)), + glyph); + } } + + fontConfig.Destroy(); } } diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 6f5477463..9c7d5b151 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -49,6 +49,8 @@ namespace Dalamud.Interface.Internal { private const float DefaultFontSizePt = 12.0f; private const float DefaultFontSizePx = DefaultFontSizePt * 4.0f / 3.0f; + private const ushort Fallback1Codepoint = 0x3013; // Geta mark; FFXIV uses this to indicate that a glyph is missing. + private const ushort Fallback2Codepoint = '-'; // FFXIV uses dash if Geta mark is unavailable. private readonly string rtssPath; @@ -603,6 +605,11 @@ namespace Dalamud.Interface.Internal this.fontBuildSignal.Reset(); ioFonts.Clear(); + ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig(); + fontConfig.OversampleH = 1; + fontConfig.OversampleV = 1; + fontConfig.PixelSnapH = true; + var fontPathJp = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "NotoSansCJKjp-Medium.otf"); if (!File.Exists(fontPathJp)) ShowFontError(fontPathJp); @@ -610,7 +617,7 @@ namespace Dalamud.Interface.Internal // Default font { var japaneseRangeHandle = GCHandle.Alloc(GlyphRangesJapanese.GlyphRanges, GCHandleType.Pinned); - DefaultFont = ioFonts.AddFontFromFileTTF(fontPathJp, (DefaultFontSizePx + 1) * fontScale, null, japaneseRangeHandle.AddrOfPinnedObject()); + DefaultFont = ioFonts.AddFontFromFileTTF(fontPathJp, (DefaultFontSizePx + 1) * fontScale, fontConfig, japaneseRangeHandle.AddrOfPinnedObject()); japaneseRangeHandle.Free(); fontsToUnscale.Add(DefaultFont); } @@ -622,7 +629,7 @@ namespace Dalamud.Interface.Internal ShowFontError(fontPathIcon); var iconRangeHandle = GCHandle.Alloc(new ushort[] { 0xE000, 0xF8FF, 0, }, GCHandleType.Pinned); - IconFont = ioFonts.AddFontFromFileTTF(fontPathIcon, DefaultFontSizePx * fontScale, null, iconRangeHandle.AddrOfPinnedObject()); + IconFont = ioFonts.AddFontFromFileTTF(fontPathIcon, DefaultFontSizePx * fontScale, fontConfig, iconRangeHandle.AddrOfPinnedObject()); iconRangeHandle.Free(); fontsToUnscale.Add(IconFont); } @@ -632,7 +639,7 @@ namespace Dalamud.Interface.Internal var fontPathMono = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "Inconsolata-Regular.ttf"); if (!File.Exists(fontPathMono)) ShowFontError(fontPathMono); - MonoFont = ioFonts.AddFontFromFileTTF(fontPathMono, DefaultFontSizePx * fontScale); + MonoFont = ioFonts.AddFontFromFileTTF(fontPathMono, DefaultFontSizePx * fontScale, fontConfig); fontsToUnscale.Add(MonoFont); } @@ -649,6 +656,9 @@ namespace Dalamud.Interface.Internal foreach (var (fontSize, requests) in extraFontRequests) { List> codepointRanges = new(); + codepointRanges.Add(Tuple.Create(Fallback1Codepoint, Fallback1Codepoint)); + codepointRanges.Add(Tuple.Create(Fallback2Codepoint, Fallback2Codepoint)); + foreach (var request in requests) { foreach (var range in request.CodepointRanges) @@ -674,7 +684,7 @@ namespace Dalamud.Interface.Internal flattenedRanges.Add(0); var rangeHandle = GCHandle.Alloc(flattenedRanges.ToArray(), GCHandleType.Pinned); - var sizedFont = ioFonts.AddFontFromFileTTF(fontPathJp, fontSize * fontScale, null, rangeHandle.AddrOfPinnedObject()); + var sizedFont = ioFonts.AddFontFromFileTTF(fontPathJp, fontSize * fontScale, fontConfig, rangeHandle.AddrOfPinnedObject()); rangeHandle.Free(); fontsToUnscale.Add(sizedFont); @@ -713,7 +723,12 @@ namespace Dalamud.Interface.Internal foreach (var font in fontsToUnscale) { - if (font.NativePtr == MonoFont.NativePtr || font.NativePtr == IconFont.NativePtr) + // Leave IconFont alone. + if (font.NativePtr == IconFont.NativePtr) + continue; + + // MonoFont will be filled later from DefaultFont. + if (font.NativePtr == MonoFont.NativePtr) continue; if (this.overwriteAllNotoGlyphsWithAxis) @@ -722,11 +737,17 @@ namespace Dalamud.Interface.Internal GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, font, false, false, 0xE020, 0xE0DB); } + // Fill missing glyphs in DefaultFont from Axis + GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, DefaultFont, true, false); + // Fill missing glyphs in MonoFont from DefaultFont GameFontManager.CopyGlyphsAcrossFonts(DefaultFont, MonoFont, true, false); foreach (var font in fontsToUnscale) + { + font.FallbackChar = Fallback1Codepoint; font.BuildLookupTable(); + } Log.Verbose("[FONT] Invoke OnAfterBuildFonts"); this.AfterBuildFonts?.Invoke(); @@ -734,6 +755,7 @@ namespace Dalamud.Interface.Internal Log.Verbose("[FONT] Fonts built!"); + fontConfig.Destroy(); this.fontBuildSignal.Set(); this.FontsReady = true;