Merge pull request #770 from Soreepeong/feature/nicer-fonts

Show size appropriate fonts
This commit is contained in:
goaaats 2022-03-07 09:47:13 +01:00 committed by GitHub
commit e2ddc29e98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 397 additions and 122 deletions

View file

@ -117,18 +117,21 @@ namespace Dalamud.Interface.GameFonts
/// <param name="target">Target font.</param>
/// <param name="missingOnly">Whether to copy missing glyphs only.</param>
/// <param name="rebuildLookupTable">Whether to call target.BuildLookupTable().</param>
public static void CopyGlyphsAcrossFonts(ImFontPtr? source, ImFontPtr? target, bool missingOnly, bool rebuildLookupTable)
/// <param name="rangeLow">Low codepoint range to copy.</param>
/// <param name="rangeHigh">High codepoing range to copy.</param>
public static void CopyGlyphsAcrossFonts(ImFontPtr? source, ImFontPtr? target, bool missingOnly, bool rebuildLookupTable, int rangeLow = 32, int rangeHigh = 0xFFFE)
{
if (!source.HasValue || !target.HasValue)
return;
var scale = target.Value!.FontSize / source.Value!.FontSize;
unsafe
{
var glyphs = (ImFontGlyphReal*)source.Value!.Glyphs.Data;
for (int j = 0, j_ = source.Value!.Glyphs.Size; j < j_; j++)
{
var glyph = &glyphs[j];
if (glyph->Codepoint < 32 || glyph->Codepoint >= 0xFFFF)
if (glyph->Codepoint < rangeLow || glyph->Codepoint > rangeHigh)
continue;
var prevGlyphPtr = (ImFontGlyphReal*)target.Value!.FindGlyphNoFallback((ushort)glyph->Codepoint).NativePtr;
@ -137,27 +140,27 @@ namespace Dalamud.Interface.GameFonts
target.Value!.AddGlyph(
target.Value!.ConfigData,
(ushort)glyph->Codepoint,
glyph->X0,
glyph->Y0,
glyph->X0 + ((glyph->X1 - glyph->X0) * target.Value!.FontSize / source.Value!.FontSize),
glyph->Y0 + ((glyph->Y1 - glyph->Y0) * target.Value!.FontSize / source.Value!.FontSize),
glyph->X0 * scale,
glyph->Y0 * scale,
glyph->X1 * scale,
glyph->Y1 * scale,
glyph->U0,
glyph->V0,
glyph->U1,
glyph->V1,
glyph->AdvanceX * target.Value!.FontSize / source.Value!.FontSize);
glyph->AdvanceX * scale);
}
else if (!missingOnly)
{
prevGlyphPtr->X0 = glyph->X0;
prevGlyphPtr->Y0 = glyph->Y0;
prevGlyphPtr->X1 = glyph->X0 + ((glyph->X1 - glyph->X0) * target.Value!.FontSize / source.Value!.FontSize);
prevGlyphPtr->Y1 = glyph->Y0 + ((glyph->Y1 - glyph->Y0) * target.Value!.FontSize / source.Value!.FontSize);
prevGlyphPtr->X0 = glyph->X0 * scale;
prevGlyphPtr->Y0 = glyph->Y0 * scale;
prevGlyphPtr->X1 = glyph->X1 * scale;
prevGlyphPtr->Y1 = glyph->Y1 * scale;
prevGlyphPtr->U0 = glyph->U0;
prevGlyphPtr->V0 = glyph->V0;
prevGlyphPtr->U1 = glyph->U1;
prevGlyphPtr->V1 = glyph->V1;
prevGlyphPtr->AdvanceX = glyph->AdvanceX * target.Value!.FontSize / source.Value!.FontSize;
prevGlyphPtr->AdvanceX = glyph->AdvanceX * scale;
}
}
}
@ -166,6 +169,39 @@ namespace Dalamud.Interface.GameFonts
target.Value!.BuildLookupTable();
}
/// <summary>
/// Unscales fonts after they have been rendered onto atlas.
/// </summary>
/// <param name="fontPtr">Font to unscale.</param>
/// <param name="fontScale">Scale factor.</param>
/// <param name="rebuildLookupTable">Whether to call target.BuildLookupTable().</param>
public static void UnscaleFont(ImFontPtr fontPtr, float fontScale, bool rebuildLookupTable = true)
{
unsafe
{
var font = fontPtr.NativePtr;
for (int i = 0, i_ = font->IndexAdvanceX.Size; i < i_; ++i)
((float*)font->IndexAdvanceX.Data)[i] /= fontScale;
font->FallbackAdvanceX /= fontScale;
font->FontSize /= fontScale;
font->Ascent /= fontScale;
font->Descent /= fontScale;
var glyphs = (ImFontGlyphReal*)font->Glyphs.Data;
for (int i = 0, i_ = font->Glyphs.Size; i < i_; i++)
{
var glyph = &glyphs[i];
glyph->X0 /= fontScale;
glyph->X1 /= fontScale;
glyph->Y0 /= fontScale;
glyph->Y1 /= fontScale;
glyph->AdvanceX /= fontScale;
}
}
if (rebuildLookupTable)
fontPtr.BuildLookupTable();
}
/// <inheritdoc/>
public void Dispose()
{
@ -248,39 +284,48 @@ namespace Dalamud.Interface.GameFonts
/// </summary>
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();
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();
}
}

View file

@ -47,8 +47,15 @@ namespace Dalamud.Interface.Internal
/// </summary>
internal class InterfaceManager : IDisposable
{
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;
private readonly HashSet<SpecialGlyphRequest> glyphRequests = new();
private readonly Hook<PresentDelegate> presentHook;
private readonly Hook<ResizeBuffersDelegate> resizeBuffersHook;
private readonly Hook<SetCursorDelegate> setCursorHook;
@ -57,7 +64,8 @@ namespace Dalamud.Interface.Internal
private readonly SwapChainVtableResolver address;
private RawDX11Scene? scene;
private GameFontHandle? axisFontHandle;
private GameFontHandle[] axisFontHandles;
private bool overwriteAllNotoGlyphsWithAxis;
// can't access imgui IO before first present call
private bool lastWantCapture = false;
@ -337,6 +345,70 @@ namespace Dalamud.Interface.Internal
this.fontBuildSignal.WaitOne();
}
/// <summary>
/// Requests a default font of specified size to exist.
/// </summary>
/// <param name="size">Font size in pixels.</param>
/// <param name="ranges">Ranges of glyphs.</param>
/// <returns>Requets handle.</returns>
public SpecialGlyphRequest NewFontSizeRef(float size, List<Tuple<ushort, ushort>> ranges)
{
var allContained = false;
var fonts = ImGui.GetIO().Fonts.Fonts;
ImFontPtr foundFont = null;
unsafe
{
for (int i = 0, i_ = fonts.Size; i < i_; i++)
{
if (!this.glyphRequests.Any(x => x.FontInternal.NativePtr == fonts[i].NativePtr))
continue;
allContained = true;
foreach (var range in ranges)
{
if (!allContained)
break;
for (var j = range.Item1; j <= range.Item2 && allContained; j++)
allContained &= fonts[i].FindGlyphNoFallback(j).NativePtr != null;
}
if (allContained)
foundFont = fonts[i];
break;
}
}
var req = new SpecialGlyphRequest(this, size, ranges);
req.FontInternal = foundFont;
if (!allContained)
this.RebuildFonts();
return req;
}
/// <summary>
/// Requests a default font of specified size to exist.
/// </summary>
/// <param name="size">Font size in pixels.</param>
/// <param name="text">Text to calculate glyph ranges from.</param>
/// <returns>Requets handle.</returns>
public SpecialGlyphRequest NewFontSizeRef(float size, string text)
{
List<Tuple<ushort, ushort>> ranges = new();
foreach (var c in new SortedSet<char>(text.ToHashSet()))
{
if (ranges.Any() && ranges[^1].Item2 + 1 == c)
ranges[^1] = Tuple.Create<ushort, ushort>(ranges[^1].Item1, c);
else
ranges.Add(Tuple.Create<ushort, ushort>(c, c));
}
return this.NewFontSizeRef(size, ranges);
}
private static void ShowFontError(string path)
{
Util.Fatal($"One or more files required by XIVLauncher were not found.\nPlease restart and report this error if it occurs again.\n\n{path}", "Error");
@ -345,20 +417,18 @@ namespace Dalamud.Interface.Internal
private void SetAxisFonts()
{
var configuration = Service<DalamudConfiguration>.Get();
if (configuration.UseAxisFontsFromGame)
{
var currentFamilyAndSize = GameFontStyle.GetRecommendedFamilyAndSize(GameFontFamily.Axis, this.axisFontHandle?.Style.Size ?? 0f);
var expectedFamilyAndSize = GameFontStyle.GetRecommendedFamilyAndSize(GameFontFamily.Axis, 12 * ImGui.GetIO().FontGlobalScale);
if (currentFamilyAndSize == expectedFamilyAndSize)
return;
this.overwriteAllNotoGlyphsWithAxis = configuration.UseAxisFontsFromGame;
this.axisFontHandle?.Dispose();
this.axisFontHandle = Service<GameFontManager>.Get().NewFontRef(new(expectedFamilyAndSize));
}
else
if (this.axisFontHandles == null)
{
this.axisFontHandle?.Dispose();
this.axisFontHandle = null;
this.axisFontHandles = new GameFontHandle[]
{
Service<GameFontManager>.Get().NewFontRef(new(GameFontFamilyAndSize.Axis96)),
Service<GameFontManager>.Get().NewFontRef(new(GameFontFamilyAndSize.Axis12)),
Service<GameFontManager>.Get().NewFontRef(new(GameFontFamilyAndSize.Axis14)),
Service<GameFontManager>.Get().NewFontRef(new(GameFontFamilyAndSize.Axis18)),
Service<GameFontManager>.Get().NewFontRef(new(GameFontFamilyAndSize.Axis36)),
};
}
}
@ -531,64 +601,108 @@ namespace Dalamud.Interface.Internal
private unsafe void SetupFonts()
{
var dalamud = Service<Dalamud>.Get();
var ioFonts = ImGui.GetIO().Fonts;
var io = ImGui.GetIO();
var ioFonts = io.Fonts;
var fontScale = io.FontGlobalScale;
var fontGamma = this.FontGamma;
List<ImFontPtr> fontsToUnscale = new();
this.fontBuildSignal.Reset();
ioFonts.Clear();
ioFonts.TexDesiredWidth = 4096;
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);
var japaneseRangeHandle = GCHandle.Alloc(GlyphRangesJapanese.GlyphRanges, GCHandleType.Pinned);
// Default font
{
var japaneseRangeHandle = GCHandle.Alloc(GlyphRangesJapanese.GlyphRanges, GCHandleType.Pinned);
DefaultFont = ioFonts.AddFontFromFileTTF(fontPathJp, (DefaultFontSizePx + 1) * fontScale, fontConfig, japaneseRangeHandle.AddrOfPinnedObject());
japaneseRangeHandle.Free();
fontsToUnscale.Add(DefaultFont);
}
DefaultFont = ioFonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, japaneseRangeHandle.AddrOfPinnedObject());
// FontAwesome icon font
{
var fontPathIcon = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "FontAwesome5FreeSolid.otf");
if (!File.Exists(fontPathIcon))
ShowFontError(fontPathIcon);
var fontPathGame = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "gamesym.ttf");
var iconRangeHandle = GCHandle.Alloc(new ushort[] { 0xE000, 0xF8FF, 0, }, GCHandleType.Pinned);
IconFont = ioFonts.AddFontFromFileTTF(fontPathIcon, DefaultFontSizePx * fontScale, fontConfig, iconRangeHandle.AddrOfPinnedObject());
iconRangeHandle.Free();
fontsToUnscale.Add(IconFont);
}
if (!File.Exists(fontPathGame))
ShowFontError(fontPathGame);
// Monospace font
{
var fontPathMono = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "Inconsolata-Regular.ttf");
if (!File.Exists(fontPathMono))
ShowFontError(fontPathMono);
MonoFont = ioFonts.AddFontFromFileTTF(fontPathMono, DefaultFontSizePx * fontScale, fontConfig);
fontsToUnscale.Add(MonoFont);
}
var gameRangeHandle = GCHandle.Alloc(
new ushort[]
// Default font but in requested size for requested glyphs
{
Dictionary<float, List<SpecialGlyphRequest>> extraFontRequests = new();
foreach (var extraFontRequest in this.glyphRequests)
{
0xE020,
0xE0DB,
0,
},
GCHandleType.Pinned);
if (!extraFontRequests.ContainsKey(extraFontRequest.Size))
extraFontRequests[extraFontRequest.Size] = new();
extraFontRequests[extraFontRequest.Size].Add(extraFontRequest);
}
fontConfig.MergeMode = false;
ioFonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, gameRangeHandle.AddrOfPinnedObject());
fontConfig.MergeMode = true;
var fontPathIcon = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "FontAwesome5FreeSolid.otf");
if (!File.Exists(fontPathIcon))
ShowFontError(fontPathIcon);
var iconRangeHandle = GCHandle.Alloc(
new ushort[]
foreach (var (fontSize, requests) in extraFontRequests)
{
0xE000,
0xF8FF,
0,
},
GCHandleType.Pinned);
IconFont = ioFonts.AddFontFromFileTTF(fontPathIcon, 17.0f, null, iconRangeHandle.AddrOfPinnedObject());
List<Tuple<ushort, ushort>> codepointRanges = new();
codepointRanges.Add(Tuple.Create(Fallback1Codepoint, Fallback1Codepoint));
codepointRanges.Add(Tuple.Create(Fallback2Codepoint, Fallback2Codepoint));
var fontPathMono = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "Inconsolata-Regular.ttf");
// ImGui default ellipsis characters
codepointRanges.Add(Tuple.Create<ushort, ushort>(0x2026, 0x2026));
codepointRanges.Add(Tuple.Create<ushort, ushort>(0x0085, 0x0085));
if (!File.Exists(fontPathMono))
ShowFontError(fontPathMono);
foreach (var request in requests)
{
foreach (var range in request.CodepointRanges)
codepointRanges.Add(range);
}
MonoFont = ioFonts.AddFontFromFileTTF(fontPathMono, 16.0f);
codepointRanges.Sort((x, y) => (x.Item1 == y.Item1 ? (x.Item2 < y.Item2 ? -1 : (x.Item2 == y.Item2 ? 0 : 1)) : (x.Item1 < y.Item1 ? -1 : 1)));
List<ushort> flattenedRanges = new();
foreach (var range in codepointRanges)
{
if (flattenedRanges.Any() && flattenedRanges[^1] >= range.Item1 - 1)
{
flattenedRanges[^1] = Math.Max(flattenedRanges[^1], range.Item2);
}
else
{
flattenedRanges.Add(range.Item1);
flattenedRanges.Add(range.Item2);
}
}
flattenedRanges.Add(0);
var rangeHandle = GCHandle.Alloc(flattenedRanges.ToArray(), GCHandleType.Pinned);
var sizedFont = ioFonts.AddFontFromFileTTF(fontPathJp, fontSize * fontScale, fontConfig, rangeHandle.AddrOfPinnedObject());
rangeHandle.Free();
fontsToUnscale.Add(sizedFont);
foreach (var request in requests)
request.FontInternal = sizedFont;
}
}
var gameFontManager = Service<GameFontManager>.Get();
gameFontManager.BuildFonts();
@ -612,8 +726,48 @@ namespace Dalamud.Interface.Internal
texPixels[i] = (byte)(Math.Pow(texPixels[i] / 255.0f, 1.0f / fontGamma) * 255.0f);
}
foreach (var font in fontsToUnscale)
GameFontManager.UnscaleFont(font, fontScale, false);
gameFontManager.AfterBuildFonts();
GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, DefaultFont, false, true);
foreach (var font in fontsToUnscale)
{
// Leave IconFont alone.
if (font.NativePtr == IconFont.NativePtr)
continue;
// MonoFont will be filled later from DefaultFont.
if (font.NativePtr == MonoFont.NativePtr)
continue;
var axisFont = this.axisFontHandles[^1];
for (var i = this.axisFontHandles.Length - 2; i >= 0; i--)
{
if (this.axisFontHandles[i].Style.Size >= (font.FontSize - 1) * fontScale * 3 / 4)
axisFont = this.axisFontHandles[i];
else
break;
}
if (this.overwriteAllNotoGlyphsWithAxis)
GameFontManager.CopyGlyphsAcrossFonts(axisFont.ImFont, font, false, false);
else
GameFontManager.CopyGlyphsAcrossFonts(axisFont.ImFont, font, false, false, 0xE020, 0xE0DB);
// Fill missing glyphs in DefaultFont from Axis
if (font.NativePtr == DefaultFont.NativePtr)
GameFontManager.CopyGlyphsAcrossFonts(axisFont.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();
@ -621,12 +775,8 @@ namespace Dalamud.Interface.Internal
Log.Verbose("[FONT] Fonts built!");
this.fontBuildSignal.Set();
fontConfig.Destroy();
japaneseRangeHandle.Free();
gameRangeHandle.Free();
iconRangeHandle.Free();
this.fontBuildSignal.Set();
this.FontsReady = true;
}
@ -765,5 +915,65 @@ namespace Dalamud.Interface.Internal
Service<NotificationManager>.Get().Draw();
}
/// <summary>
/// Represents a glyph request.
/// </summary>
public class SpecialGlyphRequest : IDisposable
{
/// <summary>
/// Initializes a new instance of the <see cref="SpecialGlyphRequest"/> class.
/// </summary>
/// <param name="manager">InterfaceManager to associate.</param>
/// <param name="size">Font size in pixels.</param>
/// <param name="ranges">Codepoint ranges.</param>
internal SpecialGlyphRequest(InterfaceManager manager, float size, List<Tuple<ushort, ushort>> ranges)
{
this.Manager = manager;
this.Size = size;
this.CodepointRanges = ranges;
this.Manager.glyphRequests.Add(this);
}
/// <summary>
/// Gets the font of specified size, or DefaultFont if it's not ready yet.
/// </summary>
public ImFontPtr Font
{
get
{
unsafe
{
return this.FontInternal.NativePtr == null ? DefaultFont : this.FontInternal;
}
}
}
/// <summary>
/// Gets or sets the associated ImFont.
/// </summary>
internal ImFontPtr FontInternal { get; set; }
/// <summary>
/// Gets associated InterfaceManager.
/// </summary>
internal InterfaceManager Manager { get; init; }
/// <summary>
/// Gets font size.
/// </summary>
internal float Size { get; init; }
/// <summary>
/// Gets codepoint ranges.
/// </summary>
internal List<Tuple<ushort, ushort>> CodepointRanges { get; init; }
/// <inheritdoc/>
public void Dispose()
{
this.Manager.glyphRequests.Remove(this);
}
}
}
}

View file

@ -26,7 +26,7 @@ namespace Dalamud.Interface.Internal.Windows
internal class SettingsWindow : Window
{
private const float MinScale = 0.3f;
private const float MaxScale = 2.0f;
private const float MaxScale = 3.0f;
private readonly string[] languages;
private readonly string[] locLanguages;

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Dalamud.Configuration.Internal;
@ -20,17 +21,18 @@ namespace Dalamud.Interface.Internal.Windows
/// </summary>
internal class TitleScreenMenuWindow : Window, IDisposable
{
private const float TargetFontSize = 16.2f;
private const float TargetFontSizePt = 18f;
private const float TargetFontSizePx = TargetFontSizePt * 4 / 3;
private readonly TextureWrap shadeTexture;
private readonly Dictionary<Guid, InOutCubic> shadeEasings = new();
private readonly Dictionary<Guid, InOutQuint> moveEasings = new();
private readonly Dictionary<Guid, InOutCubic> logoEasings = new();
private readonly Dictionary<string, InterfaceManager.SpecialGlyphRequest> specialGlyphRequests = new();
private InOutCubic? fadeOutEasing;
private GameFontHandle? axisFontHandle;
private State state = State.Hide;
/// <summary>
@ -71,19 +73,14 @@ namespace Dalamud.Interface.Internal.Windows
/// <inheritdoc/>
public override void PreDraw()
{
this.SetAxisFonts();
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(0, 0));
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0));
if (this.axisFontHandle?.Available ?? false)
ImGui.PushFont(this.axisFontHandle.ImFont);
base.PreDraw();
}
/// <inheritdoc/>
public override void PostDraw()
{
if (this.axisFontHandle?.Available ?? false)
ImGui.PopFont();
ImGui.PopStyleVar(2);
base.PostDraw();
}
@ -99,7 +96,7 @@ namespace Dalamud.Interface.Internal.Windows
/// <inheritdoc/>
public override void Draw()
{
ImGui.SetWindowFontScale(TargetFontSize / ImGui.GetFont().FontSize * 4 / 3);
var scale = ImGui.GetIO().FontGlobalScale;
var tsm = Service<TitleScreenMenu>.Get();
@ -129,7 +126,7 @@ namespace Dalamud.Interface.Internal.Windows
moveEasing.Update();
var finalPos = (i + 1) * this.shadeTexture.Height;
var finalPos = (i + 1) * this.shadeTexture.Height * scale;
var pos = moveEasing.Value * finalPos;
// FIXME(goat): Sometimes, easings can overshoot and bring things out of alignment.
@ -180,7 +177,7 @@ namespace Dalamud.Interface.Internal.Windows
{
var entry = tsm.Entries[i];
var finalPos = (i + 1) * this.shadeTexture.Height;
var finalPos = (i + 1) * this.shadeTexture.Height * scale;
this.DrawEntry(entry, i != 0, true, i == 0, false);
@ -222,26 +219,36 @@ namespace Dalamud.Interface.Internal.Windows
break;
}
}
}
private void SetAxisFonts()
{
var configuration = Service<DalamudConfiguration>.Get();
if (configuration.UseAxisFontsFromGame)
var srcText = tsm.Entries.Select(e => e.Name).ToHashSet();
var keys = this.specialGlyphRequests.Keys.ToHashSet();
keys.RemoveWhere(x => srcText.Contains(x));
foreach (var key in keys)
{
if (this.axisFontHandle == null)
this.axisFontHandle = Service<GameFontManager>.Get().NewFontRef(new(GameFontFamily.Axis, TargetFontSize));
}
else
{
this.axisFontHandle?.Dispose();
this.axisFontHandle = null;
this.specialGlyphRequests[key].Dispose();
this.specialGlyphRequests.Remove(key);
}
}
private bool DrawEntry(
TitleScreenMenu.TitleScreenMenuEntry entry, bool inhibitFadeout, bool showText, bool isFirst, bool overrideAlpha)
{
InterfaceManager.SpecialGlyphRequest fontHandle;
if (this.specialGlyphRequests.TryGetValue(entry.Name, out fontHandle) && fontHandle.Size != TargetFontSizePx)
{
fontHandle.Dispose();
this.specialGlyphRequests.Remove(entry.Name);
fontHandle = null;
}
if (fontHandle == null)
this.specialGlyphRequests[entry.Name] = fontHandle = Service<InterfaceManager>.Get().NewFontSizeRef(TargetFontSizePx, entry.Name);
ImGui.PushFont(fontHandle.Font);
ImGui.SetWindowFontScale(TargetFontSizePx / fontHandle.Size);
var scale = ImGui.GetIO().FontGlobalScale;
if (!this.shadeEasings.TryGetValue(entry.Id, out var shadeEasing))
{
shadeEasing = new InOutCubic(TimeSpan.FromMilliseconds(350));
@ -251,7 +258,7 @@ namespace Dalamud.Interface.Internal.Windows
var initialCursor = ImGui.GetCursorPos();
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)shadeEasing.Value);
ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width, this.shadeTexture.Height));
ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width * scale, this.shadeTexture.Height * scale));
ImGui.PopStyleVar();
var isHover = ImGui.IsItemHovered();
@ -305,7 +312,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 1f);
}
ImGui.Image(entry.Texture.ImGuiHandle, new Vector2(TitleScreenMenu.TextureSize));
ImGui.Image(entry.Texture.ImGuiHandle, new Vector2(TitleScreenMenu.TextureSize * scale));
if (overrideAlpha || isFirst)
{
ImGui.PopStyleVar();
@ -319,23 +326,36 @@ namespace Dalamud.Interface.Internal.Windows
var textHeight = ImGui.GetTextLineHeightWithSpacing();
var cursor = ImGui.GetCursorPos();
cursor.Y += (entry.Texture.Height / 2) - (textHeight / 2);
ImGui.SetCursorPos(cursor);
cursor.Y += (entry.Texture.Height * scale / 2) - (textHeight / 2);
if (overrideAlpha)
{
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, showText ? (float)logoEasing.Value : 0f);
}
// Drop shadow
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF000000);
for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++)
{
ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i));
ImGui.Text(entry.Name);
}
ImGui.PopStyleColor();
ImGui.SetCursorPos(cursor);
ImGui.Text(entry.Name);
if (overrideAlpha)
{
ImGui.PopStyleVar();
}
initialCursor.Y += entry.Texture.Height;
initialCursor.Y += entry.Texture.Height * scale;
ImGui.SetCursorPos(initialCursor);
ImGui.PopFont();
return isHover;
}