Fix GameFontHandle.Text position not counting in scrolls, and add support for font gamma changing

This commit is contained in:
Soreepeong 2022-03-03 11:36:32 +09:00
parent 940fbb0a2f
commit b72bfa9d19
6 changed files with 108 additions and 17 deletions

View file

@ -134,6 +134,15 @@ namespace Dalamud.Configuration.Internal
/// </summary> /// </summary>
public bool UseAxisFontsFromGame { get; set; } = false; public bool UseAxisFontsFromGame { get; set; } = false;
/// <summary>
/// Gets or sets the gamma value to apply for Dalamud fonts. Effects text thickness.
///
/// Before gamma is applied...
/// * ...TTF fonts loaded with stb or FreeType are in linear space.
/// * ...the game's prebaked AXIS fonts are in gamma space with gamma value of 1.4.
/// </summary>
public float FontGamma { get; set; } = 1.0f;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether or not plugin UI should be hidden. /// Gets or sets a value indicating whether or not plugin UI should be hidden.
/// </summary> /// </summary>

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
namespace Dalamud.Interface.GameFonts namespace Dalamud.Interface.GameFonts
@ -31,7 +32,16 @@ namespace Dalamud.Interface.GameFonts
/// <summary> /// <summary>
/// Gets a value indicating whether this font is ready for use. /// Gets a value indicating whether this font is ready for use.
/// </summary> /// </summary>
public bool Available => this.manager.GetFont(this.fontStyle) != null; public bool Available
{
get
{
unsafe
{
return this.manager.GetFont(this.fontStyle).GetValueOrDefault(null).NativePtr != null;
}
}
}
/// <summary> /// <summary>
/// Gets the font. /// Gets the font.
@ -68,9 +78,13 @@ namespace Dalamud.Interface.GameFonts
} }
else else
{ {
this.LayoutBuilder(text) var pos = ImGui.GetWindowPos() + ImGui.GetCursorPos();
.Build() pos.X -= ImGui.GetScrollX();
.Draw(ImGui.GetWindowDrawList(), ImGui.GetWindowPos() + ImGui.GetCursorPos(), ImGui.GetColorU32(ImGuiCol.Text)); pos.Y -= ImGui.GetScrollY();
var layout = this.LayoutBuilder(text).Build();
layout.Draw(ImGui.GetWindowDrawList(), pos, ImGui.GetColorU32(ImGuiCol.Text));
ImGui.Dummy(new Vector2(layout.Width, layout.Height));
} }
} }

View file

@ -73,7 +73,6 @@ namespace Dalamud.Interface.GameFonts
/// <param name="col">Color.</param> /// <param name="col">Color.</param>
public void Draw(ImDrawListPtr drawListPtr, Vector2 pos, uint col) public void Draw(ImDrawListPtr drawListPtr, Vector2 pos, uint col)
{ {
ImGui.Dummy(new Vector2(this.Width, this.Height));
foreach (var element in this.Elements) foreach (var element in this.Elements)
{ {
if (element.IsControl) if (element.IsControl)

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
using Dalamud.Configuration.Internal;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Interface.Internal; using Dalamud.Interface.Internal;
using ImGuiNET; using ImGuiNET;
@ -288,9 +289,10 @@ namespace Dalamud.Interface.GameFonts
/// </summary> /// </summary>
public unsafe void AfterBuildFonts() public unsafe void AfterBuildFonts()
{ {
var io = ImGui.GetIO(); var ioFonts = ImGui.GetIO().Fonts;
io.Fonts.GetTexDataAsRGBA32(out byte* pixels8, out var width, out var height); ioFonts.GetTexDataAsRGBA32(out byte* pixels8, out var width, out var height);
var pixels32 = (uint*)pixels8; var pixels32 = (uint*)pixels8;
var fontGamma = this.interfaceManager.FontGamma;
foreach (var (style, font) in this.fonts) foreach (var (style, font) in this.fonts)
{ {
@ -319,7 +321,7 @@ namespace Dalamud.Interface.GameFonts
foreach (var (c, (rectId, glyph)) in this.glyphRectIds[style]) foreach (var (c, (rectId, glyph)) in this.glyphRectIds[style])
{ {
var rc = io.Fonts.GetCustomRectByIndex(rectId); var rc = ioFonts.GetCustomRectByIndex(rectId);
var sourceBuffer = this.texturePixels[glyph.TextureFileIndex]; var sourceBuffer = this.texturePixels[glyph.TextureFileIndex];
var sourceBufferDelta = glyph.TextureChannelByteIndex; var sourceBufferDelta = glyph.TextureChannelByteIndex;
var widthAdjustment = style.CalculateWidthAdjustment(fdt, glyph); var widthAdjustment = style.CalculateWidthAdjustment(fdt, glyph);
@ -366,6 +368,19 @@ namespace Dalamud.Interface.GameFonts
} }
} }
} }
if (Math.Abs(fontGamma - 1.4f) >= 0.001)
{
// Gamma correction (stbtt/FreeType would output in linear space whereas most real world usages will apply 1.4 or 1.8 gamma; Windows/XIV prebaked uses 1.4)
for (int y = rc.Y, y_ = rc.Y + rc.Height; y < y_; y++)
{
for (int x = rc.X, x_ = rc.X + rc.Width; x < x_; x++)
{
var i = (((y * width) + x) * 4) + 3;
pixels8[i] = (byte)(Math.Pow(pixels8[i] / 255.0f, 1.4f / fontGamma) * 255.0f);
}
}
}
} }
} }

View file

@ -189,6 +189,16 @@ namespace Dalamud.Interface.Internal
/// </summary> /// </summary>
public bool IsReady => this.scene != null; public bool IsReady => this.scene != null;
/// <summary>
/// Gets or sets the overrided font gamma value, instead of using the value from configuration.
/// </summary>
public float? FontGammaOverride { get; set; } = null;
/// <summary>
/// Gets the font gamma value to use.
/// </summary>
public float FontGamma => Math.Max(0.1f, this.FontGammaOverride.GetValueOrDefault(Service<DalamudConfiguration>.Get().FontGamma));
/// <summary> /// <summary>
/// Enable this module. /// Enable this module.
/// </summary> /// </summary>
@ -521,10 +531,12 @@ namespace Dalamud.Interface.Internal
private unsafe void SetupFonts() private unsafe void SetupFonts()
{ {
var dalamud = Service<Dalamud>.Get(); var dalamud = Service<Dalamud>.Get();
var ioFonts = ImGui.GetIO().Fonts;
var fontGamma = this.FontGamma;
this.fontBuildSignal.Reset(); this.fontBuildSignal.Reset();
ImGui.GetIO().Fonts.Clear(); ioFonts.Clear();
ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig(); ImFontConfigPtr fontConfig = ImGuiNative.ImFontConfig_ImFontConfig();
fontConfig.PixelSnapH = true; fontConfig.PixelSnapH = true;
@ -536,7 +548,7 @@ namespace Dalamud.Interface.Internal
var japaneseRangeHandle = GCHandle.Alloc(GlyphRangesJapanese.GlyphRanges, GCHandleType.Pinned); var japaneseRangeHandle = GCHandle.Alloc(GlyphRangesJapanese.GlyphRanges, GCHandleType.Pinned);
DefaultFont = ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, japaneseRangeHandle.AddrOfPinnedObject()); DefaultFont = ioFonts.AddFontFromFileTTF(fontPathJp, 17.0f, null, japaneseRangeHandle.AddrOfPinnedObject());
var fontPathGame = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "gamesym.ttf"); var fontPathGame = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "gamesym.ttf");
@ -553,7 +565,7 @@ namespace Dalamud.Interface.Internal
GCHandleType.Pinned); GCHandleType.Pinned);
fontConfig.MergeMode = false; fontConfig.MergeMode = false;
ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, gameRangeHandle.AddrOfPinnedObject()); ioFonts.AddFontFromFileTTF(fontPathGame, 17.0f, fontConfig, gameRangeHandle.AddrOfPinnedObject());
fontConfig.MergeMode = true; fontConfig.MergeMode = true;
var fontPathIcon = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "FontAwesome5FreeSolid.otf"); var fontPathIcon = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "FontAwesome5FreeSolid.otf");
@ -569,14 +581,14 @@ namespace Dalamud.Interface.Internal
0, 0,
}, },
GCHandleType.Pinned); GCHandleType.Pinned);
IconFont = ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathIcon, 17.0f, null, iconRangeHandle.AddrOfPinnedObject()); IconFont = ioFonts.AddFontFromFileTTF(fontPathIcon, 17.0f, null, iconRangeHandle.AddrOfPinnedObject());
var fontPathMono = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "Inconsolata-Regular.ttf"); var fontPathMono = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "Inconsolata-Regular.ttf");
if (!File.Exists(fontPathMono)) if (!File.Exists(fontPathMono))
ShowFontError(fontPathMono); ShowFontError(fontPathMono);
MonoFont = ImGui.GetIO().Fonts.AddFontFromFileTTF(fontPathMono, 16.0f); MonoFont = ioFonts.AddFontFromFileTTF(fontPathMono, 16.0f);
var gameFontManager = Service<GameFontManager>.Get(); var gameFontManager = Service<GameFontManager>.Get();
gameFontManager.BuildFonts(); gameFontManager.BuildFonts();
@ -590,7 +602,15 @@ namespace Dalamud.Interface.Internal
Log.Verbose("{0} - {1}", i, ImGui.GetIO().Fonts.Fonts[i].GetDebugName()); Log.Verbose("{0} - {1}", i, ImGui.GetIO().Fonts.Fonts[i].GetDebugName());
} }
ImGui.GetIO().Fonts.Build(); ioFonts.Build();
if (Math.Abs(fontGamma - 1.0f) >= 0.001)
{
// Gamma correction (stbtt/FreeType would output in linear space whereas most real world usages will apply 1.4 or 1.8 gamma; Windows/XIV prebaked uses 1.4)
ioFonts.GetTexDataAsRGBA32(out byte* texPixels, out var texWidth, out var texHeight);
for (int i = 3, i_ = texWidth * texHeight * 4; i < i_; i += 4)
texPixels[i] = (byte)(Math.Pow(texPixels[i] / 255.0f, 1.0f / fontGamma) * 255.0f);
}
gameFontManager.AfterBuildFonts(); gameFontManager.AfterBuildFonts();
GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, DefaultFont, false, true); GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, DefaultFont, false, true);

View file

@ -39,6 +39,7 @@ namespace Dalamud.Interface.Internal.Windows
private float globalUiScale; private float globalUiScale;
private bool doUseAxisFontsFromGame; private bool doUseAxisFontsFromGame;
private float fontGamma;
private bool doToggleUiHide; private bool doToggleUiHide;
private bool doToggleUiHideDuringCutscenes; private bool doToggleUiHideDuringCutscenes;
private bool doToggleUiHideDuringGpose; private bool doToggleUiHideDuringGpose;
@ -91,6 +92,7 @@ namespace Dalamud.Interface.Internal.Windows
this.doCfChatMessage = configuration.DutyFinderChatMessage; this.doCfChatMessage = configuration.DutyFinderChatMessage;
this.globalUiScale = configuration.GlobalUiScale; this.globalUiScale = configuration.GlobalUiScale;
this.fontGamma = configuration.FontGamma;
this.doUseAxisFontsFromGame = configuration.UseAxisFontsFromGame; this.doUseAxisFontsFromGame = configuration.UseAxisFontsFromGame;
this.doToggleUiHide = configuration.ToggleUiHide; this.doToggleUiHide = configuration.ToggleUiHide;
this.doToggleUiHideDuringCutscenes = configuration.ToggleUiHideDuringCutscenes; this.doToggleUiHideDuringCutscenes = configuration.ToggleUiHideDuringCutscenes;
@ -176,13 +178,20 @@ namespace Dalamud.Interface.Internal.Windows
public override void OnClose() public override void OnClose()
{ {
var configuration = Service<DalamudConfiguration>.Get(); var configuration = Service<DalamudConfiguration>.Get();
var interfaceManager = Service<InterfaceManager>.Get();
var rebuildFont = interfaceManager.FontGamma != configuration.FontGamma;
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale; ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
interfaceManager.FontGammaOverride = null;
this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList(); this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList();
this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList(); this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList();
configuration.DtrOrder = this.dtrOrder; configuration.DtrOrder = this.dtrOrder;
configuration.DtrIgnore = this.dtrIgnore; configuration.DtrIgnore = this.dtrIgnore;
if (rebuildFont)
interfaceManager.RebuildFonts();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -272,21 +281,23 @@ namespace Dalamud.Interface.Internal.Windows
private void DrawLookAndFeelTab() private void DrawLookAndFeelTab()
{ {
var interfaceManager = Service<InterfaceManager>.Get();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global UI Scale")); ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global UI Scale"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button("Reset")) if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsGlobalUiScaleReset"))
{ {
this.globalUiScale = 1.0f; this.globalUiScale = 1.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale; ImGui.GetIO().FontGlobalScale = this.globalUiScale;
Service<InterfaceManager>.Get().RebuildFonts(); interfaceManager.RebuildFonts();
} }
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref this.globalUiScale, 0.005f, MinScale, MaxScale, "%.2f")) if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref this.globalUiScale, 0.005f, MinScale, MaxScale, "%.2f"))
{ {
ImGui.GetIO().FontGlobalScale = this.globalUiScale; ImGui.GetIO().FontGlobalScale = this.globalUiScale;
Service<InterfaceManager>.Get().RebuildFonts(); interfaceManager.RebuildFonts();
} }
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale all XIVLauncher UI elements - useful for 4K displays.")); ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale all XIVLauncher UI elements - useful for 4K displays."));
@ -332,6 +343,28 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"), ref this.doTsm); ImGui.Checkbox(Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"), ref this.doTsm);
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen.")); ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen."));
ImGuiHelpers.ScaledDummy(10, 16);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsFontGamma", "Font Gamma"));
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsFontGammaReset"))
{
this.fontGamma = 1.4f;
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
if (ImGui.DragFloat("##DalamudSettingsFontGammaDrag", ref this.fontGamma, 0.005f, MinScale, MaxScale, "%.2f"))
{
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFontGammaHint", "Changes the thickness of text."));
ImGuiHelpers.ScaledDummy(10, 16);
} }
private void DrawServerInfoBarTab() private void DrawServerInfoBarTab()
@ -811,6 +844,7 @@ namespace Dalamud.Interface.Internal.Windows
configuration.ShowTsm = this.doTsm; configuration.ShowTsm = this.doTsm;
configuration.UseAxisFontsFromGame = this.doUseAxisFontsFromGame; configuration.UseAxisFontsFromGame = this.doUseAxisFontsFromGame;
configuration.FontGamma = this.fontGamma;
// This is applied every frame in InterfaceManager::CheckViewportState() // This is applied every frame in InterfaceManager::CheckViewportState()
configuration.IsDisableViewport = !this.doViewport; configuration.IsDisableViewport = !this.doViewport;