This commit is contained in:
Soreepeong 2022-06-30 23:16:17 +09:00
parent 40f20687be
commit 28ff6d9f00
6 changed files with 163 additions and 36 deletions

View file

@ -10,6 +10,7 @@ using Dalamud.Configuration.Internal;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using Dalamud.Support; using Dalamud.Support;
using Dalamud.Utility; using Dalamud.Utility;
using ImGuiNET;
using Newtonsoft.Json; using Newtonsoft.Json;
using PInvoke; using PInvoke;
using Serilog; using Serilog;

View file

@ -11,6 +11,7 @@ using Dalamud.Utility.Timing;
using ImGuiNET; using ImGuiNET;
using Lumina.Data.Files; using Lumina.Data.Files;
using Serilog; using Serilog;
using static Dalamud.Interface.ImGuiHelpers;
namespace Dalamud.Interface.GameFonts namespace Dalamud.Interface.GameFonts
{ {
@ -134,15 +135,18 @@ namespace Dalamud.Interface.GameFonts
unsafe unsafe
{ {
var font = fontPtr.NativePtr; var font = fontPtr.NativePtr;
for (int i = 0, i_ = font->IndexAdvanceX.Size; i < i_; ++i) for (int i = 0, i_ = font->IndexedHotData.Size; i < i_; ++i)
((float*)font->IndexAdvanceX.Data)[i] /= fontScale; {
font->FallbackAdvanceX /= fontScale; font->IndexedHotData.Ref<ImFontGlyphHotDataReal>(i).AdvanceX /= fontScale;
font->IndexedHotData.Ref<ImFontGlyphHotDataReal>(i).OccupiedWidth /= fontScale;
}
font->FontSize /= fontScale; font->FontSize /= fontScale;
font->Ascent /= fontScale; font->Ascent /= fontScale;
font->Descent /= fontScale; font->Descent /= fontScale;
if (font->ConfigData != null) if (font->ConfigData != null)
font->ConfigData->SizePixels /= fontScale; font->ConfigData->SizePixels /= fontScale;
var glyphs = (ImGuiHelpers.ImFontGlyphReal*)font->Glyphs.Data; var glyphs = (ImFontGlyphReal*)font->Glyphs.Data;
for (int i = 0, i_ = font->Glyphs.Size; i < i_; i++) for (int i = 0, i_ = font->Glyphs.Size; i < i_; i++)
{ {
var glyph = &glyphs[i]; var glyph = &glyphs[i];
@ -152,6 +156,11 @@ namespace Dalamud.Interface.GameFonts
glyph->Y1 /= fontScale; glyph->Y1 /= fontScale;
glyph->AdvanceX /= fontScale; glyph->AdvanceX /= fontScale;
} }
for (int i = 0, i_ = font->KerningPairs.Size; i < i_; i++)
font->KerningPairs.Ref<ImFontKerningPair>(i).AdvanceXAdjustment /= fontScale;
for (int i = 0, i_ = font->FrequentKerningPairs.Size; i < i_; i++)
font->FrequentKerningPairs.Ref<float>(i) /= fontScale;
} }
if (rebuildLookupTable) if (rebuildLookupTable)
@ -253,8 +262,11 @@ namespace Dalamud.Interface.GameFonts
this.glyphRectIds.Clear(); this.glyphRectIds.Clear();
this.fonts.Clear(); this.fonts.Clear();
foreach (var style in this.fontUseCounter.Keys) lock (this.syncRoot)
this.EnsureFont(style); {
foreach (var style in this.fontUseCounter.Keys)
this.EnsureFont(style);
}
} }
/// <summary> /// <summary>
@ -279,10 +291,18 @@ namespace Dalamud.Interface.GameFonts
{ {
var interfaceManager = Service<InterfaceManager>.Get(); var interfaceManager = Service<InterfaceManager>.Get();
var ioFonts = ImGui.GetIO().Fonts; var ioFonts = ImGui.GetIO().Fonts;
ioFonts.GetTexDataAsRGBA32(0, out byte* pixels8, out var width, out var height);
var pixels32 = (uint*)pixels8;
var fontGamma = interfaceManager.FontGamma; var fontGamma = interfaceManager.FontGamma;
var pixels8s = new byte*[ioFonts.Textures.Size];
var pixels32s = new uint*[ioFonts.Textures.Size];
var widths = new int[ioFonts.Textures.Size];
var heights = new int[ioFonts.Textures.Size];
for (var i = 0; i < pixels8s.Length; i++)
{
ioFonts.GetTexDataAsRGBA32(i, out pixels8s[i], out widths[i], out heights[i]);
pixels32s[i] = (uint*)pixels8s[i];
}
foreach (var (style, font) in this.fonts) foreach (var (style, font) in this.fonts)
{ {
var fdt = this.fdts[(int)(this.isBuildingAsFallbackFontMode ? style.FamilyWithMinimumSize : style.FamilyAndSize)]; var fdt = this.fdts[(int)(this.isBuildingAsFallbackFontMode ? style.FamilyWithMinimumSize : style.FamilyAndSize)];
@ -302,7 +322,10 @@ namespace Dalamud.Interface.GameFonts
var glyph = font.FindGlyphNoFallback(fallbackCharCandidate); var glyph = font.FindGlyphNoFallback(fallbackCharCandidate);
if ((IntPtr)glyph.NativePtr != IntPtr.Zero) if ((IntPtr)glyph.NativePtr != IntPtr.Zero)
{ {
font.SetFallbackChar(fallbackCharCandidate); var ptr = font.NativePtr;
ptr->FallbackChar = fallbackCharCandidate;
ptr->FallbackGlyph = glyph.NativePtr;
ptr->FallbackHotData = (ImFontGlyphHotData*)ptr->IndexedHotData.Address<ImFontGlyphHotDataReal>(fallbackCharCandidate);
break; break;
} }
} }
@ -323,7 +346,11 @@ namespace Dalamud.Interface.GameFonts
foreach (var (c, (rectId, glyph)) in this.glyphRectIds[style]) foreach (var (c, (rectId, glyph)) in this.glyphRectIds[style])
{ {
var rc = ioFonts.GetCustomRectByIndex(rectId); var rc = (ImFontAtlasCustomRectReal*)ioFonts.GetCustomRectByIndex(rectId).NativePtr;
var pixels8 = pixels8s[rc->TextureIndex];
var pixels32 = pixels32s[rc->TextureIndex];
var width = widths[rc->TextureIndex];
var height = heights[rc->TextureIndex];
var sourceBuffer = this.texturePixels[glyph.TextureFileIndex]; var sourceBuffer = this.texturePixels[glyph.TextureFileIndex];
var sourceBufferDelta = glyph.TextureChannelByteIndex; var sourceBufferDelta = glyph.TextureChannelByteIndex;
var widthAdjustment = style.CalculateBaseWidthAdjustment(fdt, glyph); var widthAdjustment = style.CalculateBaseWidthAdjustment(fdt, glyph);
@ -334,7 +361,7 @@ namespace Dalamud.Interface.GameFonts
for (var x = 0; x < glyph.BoundingWidth; x++) for (var x = 0; x < glyph.BoundingWidth; x++)
{ {
var a = sourceBuffer[sourceBufferDelta + (4 * (((glyph.TextureOffsetY + y) * fdt.FontHeader.TextureWidth) + glyph.TextureOffsetX + x))]; var a = sourceBuffer[sourceBufferDelta + (4 * (((glyph.TextureOffsetY + y) * fdt.FontHeader.TextureWidth) + glyph.TextureOffsetX + x))];
pixels32[((rc.Y + y) * width) + rc.X + x] = (uint)(a << 24) | 0xFFFFFFu; pixels32[((rc->Y + y) * width) + rc->X + x] = (uint)(a << 24) | 0xFFFFFFu;
} }
} }
} }
@ -343,7 +370,7 @@ namespace Dalamud.Interface.GameFonts
for (var y = 0; y < glyph.BoundingHeight; y++) for (var y = 0; y < glyph.BoundingHeight; y++)
{ {
for (var x = 0; x < glyph.BoundingWidth + widthAdjustment; x++) for (var x = 0; x < glyph.BoundingWidth + widthAdjustment; x++)
pixels32[((rc.Y + y) * width) + rc.X + x] = 0xFFFFFFu; pixels32[((rc->Y + y) * width) + rc->X + x] = 0xFFFFFFu;
} }
for (int xbold = 0, xbold_ = Math.Max(1, (int)Math.Ceiling(style.Weight + 1)); xbold < xbold_; xbold++) for (int xbold = 0, xbold_ = Math.Max(1, (int)Math.Ceiling(style.Weight + 1)); xbold < xbold_; xbold++)
@ -364,7 +391,7 @@ namespace Dalamud.Interface.GameFonts
var a1 = sourceBuffer[sourceBufferDelta + (4 * sourcePixelIndex)]; var a1 = sourceBuffer[sourceBufferDelta + (4 * sourcePixelIndex)];
var a2 = x == glyph.BoundingWidth - 1 ? 0 : sourceBuffer[sourceBufferDelta + (4 * (sourcePixelIndex + 1))]; var a2 = x == glyph.BoundingWidth - 1 ? 0 : sourceBuffer[sourceBufferDelta + (4 * (sourcePixelIndex + 1))];
var n = (a1 * xness) + (a2 * (1 - xness)); var n = (a1 * xness) + (a2 * (1 - xness));
var targetOffset = ((rc.Y + y) * width) + rc.X + x + xDeltaInt; var targetOffset = ((rc->Y + y) * width) + rc->X + x + xDeltaInt;
pixels8[(targetOffset * 4) + 3] = Math.Max(pixels8[(targetOffset * 4) + 3], (byte)(boldStrength * n)); pixels8[(targetOffset * 4) + 3] = Math.Max(pixels8[(targetOffset * 4) + 3], (byte)(boldStrength * n));
} }
} }
@ -374,9 +401,9 @@ namespace Dalamud.Interface.GameFonts
if (Math.Abs(fontGamma - 1.4f) >= 0.001) 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) // 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 y = rc->Y, y_ = rc->Y + rc->Height; y < y_; y++)
{ {
for (int x = rc.X, x_ = rc.X + rc.Width; x < x_; x++) for (int x = rc->X, x_ = rc->X + rc->Width; x < x_; x++)
{ {
var i = (((y * width) + x) * 4) + 3; var i = (((y * width) + x) * 4) + 3;
pixels8[i] = (byte)(Math.Pow(pixels8[i] / 255.0f, 1.4f / fontGamma) * 255.0f); pixels8[i] = (byte)(Math.Pow(pixels8[i] / 255.0f, 1.4f / fontGamma) * 255.0f);
@ -435,12 +462,15 @@ namespace Dalamud.Interface.GameFonts
io.Fonts.AddCustomRectFontGlyph( io.Fonts.AddCustomRectFontGlyph(
font, font,
c, c,
glyph.BoundingWidth + widthAdjustment + 1, glyph.BoundingWidth + widthAdjustment,
glyph.BoundingHeight + 1, glyph.BoundingHeight,
glyph.AdvanceWidth, glyph.AdvanceWidth,
new Vector2(0, glyph.CurrentOffsetY)), new Vector2(0, glyph.CurrentOffsetY)),
glyph); glyph);
} }
foreach (var kernPair in fdt.Distances)
font.AddKerningPair(kernPair.Left, kernPair.Right, kernPair.RightOffset);
} }
} }
} }

View file

@ -154,6 +154,7 @@ namespace Dalamud.Interface
return; return;
var scale = target.Value!.FontSize / source.Value!.FontSize; var scale = target.Value!.FontSize / source.Value!.FontSize;
var addedCodepoints = new HashSet<int>();
unsafe unsafe
{ {
var glyphs = (ImFontGlyphReal*)source.Value!.Glyphs.Data; var glyphs = (ImFontGlyphReal*)source.Value!.Glyphs.Data;
@ -168,10 +169,11 @@ namespace Dalamud.Interface
var prevGlyphPtr = (ImFontGlyphReal*)target.Value!.FindGlyphNoFallback((ushort)glyph->Codepoint).NativePtr; var prevGlyphPtr = (ImFontGlyphReal*)target.Value!.FindGlyphNoFallback((ushort)glyph->Codepoint).NativePtr;
if ((IntPtr)prevGlyphPtr == IntPtr.Zero) if ((IntPtr)prevGlyphPtr == IntPtr.Zero)
{ {
addedCodepoints.Add(glyph->Codepoint);
target.Value!.AddGlyph( target.Value!.AddGlyph(
target.Value!.ConfigData, target.Value!.ConfigData,
(ushort)glyph->Codepoint, (ushort)glyph->Codepoint,
0, glyph->TextureIndex,
glyph->X0 * scale, glyph->X0 * scale,
((glyph->Y0 - source.Value!.Ascent) * scale) + target.Value!.Ascent, ((glyph->Y0 - source.Value!.Ascent) * scale) + target.Value!.Ascent,
glyph->X1 * scale, glyph->X1 * scale,
@ -184,6 +186,7 @@ namespace Dalamud.Interface
} }
else if (!missingOnly) else if (!missingOnly)
{ {
addedCodepoints.Add(glyph->Codepoint);
prevGlyphPtr->X0 = glyph->X0 * scale; prevGlyphPtr->X0 = glyph->X0 * scale;
prevGlyphPtr->Y0 = ((glyph->Y0 - source.Value!.Ascent) * scale) + target.Value!.Ascent; prevGlyphPtr->Y0 = ((glyph->Y0 - source.Value!.Ascent) * scale) + target.Value!.Ascent;
prevGlyphPtr->X1 = glyph->X1 * scale; prevGlyphPtr->X1 = glyph->X1 * scale;
@ -195,6 +198,16 @@ namespace Dalamud.Interface
prevGlyphPtr->AdvanceX = glyph->AdvanceX * scale; prevGlyphPtr->AdvanceX = glyph->AdvanceX * scale;
} }
} }
var kernPairs = source.Value!.KerningPairs;
for (int j = 0, k = kernPairs.Size; j < k; j++)
{
if (!addedCodepoints.Contains(kernPairs[j].Left))
continue;
if (!addedCodepoints.Contains(kernPairs[j].Right))
continue;
target.Value.AddKerningPair(kernPairs[j].Left, kernPairs[j].Right, kernPairs[j].AdvanceXAdjustment);
}
} }
if (rebuildLookupTable) if (rebuildLookupTable)
@ -215,7 +228,7 @@ namespace Dalamud.Interface
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "ImGui internals")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "ImGui internals")]
public struct ImFontGlyphReal public struct ImFontGlyphReal
{ {
public uint ColoredVisibleCodepoint; public uint ColoredVisibleTextureIndexCodepoint;
public float AdvanceX; public float AdvanceX;
public float X0; public float X0;
public float Y0; public float Y0;
@ -226,23 +239,110 @@ namespace Dalamud.Interface
public float U1; public float U1;
public float V1; public float V1;
private const uint ColoredMask /*****/ = 0b_00000000_00000000_00000000_00000001u;
private const uint VisibleMask /*****/ = 0b_00000000_00000000_00000000_00000010u;
private const uint TextureMask /*****/ = 0b_00000000_00000000_00000111_11111100u;
private const uint CodepointMask /***/ = 0b_11111111_11111111_11111000_00000000u;
private const int ColoredShift = 0;
private const int VisibleShift = 1;
private const int TextureShift = 2;
private const int CodepointShift = 11;
public bool Colored public bool Colored
{ {
get => ((this.ColoredVisibleCodepoint >> 0) & 1) != 0; get => (int)((this.ColoredVisibleTextureIndexCodepoint & ColoredMask) >> ColoredShift) != 0;
set => this.ColoredVisibleCodepoint = (this.ColoredVisibleCodepoint & 0xFFFFFFFEu) | (value ? 1u : 0u); set => this.ColoredVisibleTextureIndexCodepoint = (this.ColoredVisibleTextureIndexCodepoint & ~ColoredMask) | (value ? 1u << ColoredShift : 0u);
} }
public bool Visible public bool Visible
{ {
get => ((this.ColoredVisibleCodepoint >> 1) & 1) != 0; get => (int)((this.ColoredVisibleTextureIndexCodepoint & VisibleMask) >> VisibleShift) != 0;
set => this.ColoredVisibleCodepoint = (this.ColoredVisibleCodepoint & 0xFFFFFFFDu) | (value ? 2u : 0u); set => this.ColoredVisibleTextureIndexCodepoint = (this.ColoredVisibleTextureIndexCodepoint & ~VisibleMask) | (value ? 1u << VisibleShift : 0u);
}
public int TextureIndex
{
get => (int)(this.ColoredVisibleTextureIndexCodepoint & TextureMask) >> TextureShift;
set => this.ColoredVisibleTextureIndexCodepoint = (this.ColoredVisibleTextureIndexCodepoint & ~TextureMask) | ((uint)value << TextureShift);
} }
public int Codepoint public int Codepoint
{ {
get => (int)(this.ColoredVisibleCodepoint >> 2); get => (int)(this.ColoredVisibleTextureIndexCodepoint & CodepointMask) >> CodepointShift;
set => this.ColoredVisibleCodepoint = (this.ColoredVisibleCodepoint & 3u) | ((uint)value << 2); set => this.ColoredVisibleTextureIndexCodepoint = (this.ColoredVisibleTextureIndexCodepoint & ~CodepointMask) | ((uint)value << CodepointShift);
} }
} }
/// <summary>
/// ImFontGlyphHotData the correct version.
/// </summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "ImGui internals")]
public struct ImFontGlyphHotDataReal
{
public float AdvanceX;
public float OccupiedWidth;
public uint KerningPairInfo;
private const uint UseBisectMask /***/ = 0b_00000000_00000000_00000000_00000001u;
private const uint OffsetMask /******/ = 0b_00000000_00001111_11111111_11111110u;
private const uint CountMask /*******/ = 0b_11111111_11110000_00000111_11111100u;
private const int UseBisectShift = 0;
private const int OffsetShift = 1;
private const int CountShift = 20;
public bool UseBisect
{
get => (int)((this.KerningPairInfo & UseBisectMask) >> UseBisectShift) != 0;
set => this.KerningPairInfo = (this.KerningPairInfo & ~UseBisectMask) | (value ? 1u << UseBisectShift : 0u);
}
public bool Offset
{
get => (int)((this.KerningPairInfo & OffsetMask) >> OffsetShift) != 0;
set => this.KerningPairInfo = (this.KerningPairInfo & ~OffsetMask) | (value ? 1u << OffsetShift : 0u);
}
public int Count
{
get => (int)(this.KerningPairInfo & CountMask) >> CountShift;
set => this.KerningPairInfo = (this.KerningPairInfo & ~CountMask) | ((uint)value << CountShift);
}
}
/// <summary>
/// ImFontAtlasCustomRect the correct version.
/// </summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "ImGui internals")]
public unsafe struct ImFontAtlasCustomRectReal
{
public ushort Width;
public ushort Height;
public ushort X;
public ushort Y;
public uint TextureIndexAndGlyphID;
public float GlyphAdvanceX;
public Vector2 GlyphOffset;
public ImFont* Font;
private const uint TextureIndexMask /***/ = 0b_00000000_00000000_00000111_11111100u;
private const uint GlyphIDMask /********/ = 0b_11111111_11111111_11111000_00000000u;
private const int TextureIndexShift = 2;
private const int GlyphIDShift = 11;
public int TextureIndex
{
get => (int)(this.TextureIndexAndGlyphID & TextureIndexMask) >> TextureIndexShift;
set => this.TextureIndexAndGlyphID = (this.TextureIndexAndGlyphID & ~TextureIndexMask) | ((uint)value << TextureIndexShift);
}
public int GlyphID
{
get => (int)(this.TextureIndexAndGlyphID & GlyphIDMask) >> GlyphIDShift;
set => this.TextureIndexAndGlyphID = (this.TextureIndexAndGlyphID & ~GlyphIDMask) | ((uint)value << GlyphIDShift);
}
};
} }
} }

View file

@ -848,6 +848,12 @@ namespace Dalamud.Interface.Internal
} }
} }
for (int i = 0, i_ = ioFonts.ConfigData.Size; i < i_; i++)
{
var config = ioFonts.ConfigData[i];
config.RasterizerGamma = config.RasterizerGamma * fontGamma;
}
Log.Verbose("[FONT] ImGui.IO.Build will be called."); Log.Verbose("[FONT] ImGui.IO.Build will be called.");
ioFonts.Build(); ioFonts.Build();
gameFontManager.AfterIoFontsBuild(); gameFontManager.AfterIoFontsBuild();
@ -881,14 +887,6 @@ namespace Dalamud.Interface.Internal
if (!disableBigFonts) if (!disableBigFonts)
this.IsFallbackFontMode = false; this.IsFallbackFontMode = false;
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(0, 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();
foreach (var (font, mod) in this.loadedFontInfo) foreach (var (font, mod) in this.loadedFontInfo)

View file

@ -142,7 +142,6 @@ namespace Dalamud.Interface.Internal.Windows
} }
if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows | if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
ImGuiHoveredFlags.AllowWhenOverlapped |
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem)) ImGuiHoveredFlags.AllowWhenBlockedByActiveItem))
{ {
this.state = State.FadeOut; this.state = State.FadeOut;
@ -188,7 +187,6 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.PopStyleVar(); ImGui.PopStyleVar();
var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows | var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
ImGuiHoveredFlags.AllowWhenOverlapped |
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem); ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
if (!isHover && this.fadeOutEasing!.IsDone) if (!isHover && this.fadeOutEasing!.IsDone)

@ -1 +1 @@
Subproject commit 4a58aef6683b12685ed064df286a6aa77fd04521 Subproject commit cd6300cd7944b24643ed7381fbe5ae15efc10448