mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Merge pull request #766 from Soreepeong/feature/game-fonts
This commit is contained in:
commit
2ab9cbeda9
11 changed files with 1065 additions and 263 deletions
|
|
@ -130,9 +130,9 @@ namespace Dalamud.Configuration.Internal
|
|||
public float GlobalUiScale { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the game font to use for Dalamud UI.
|
||||
/// Gets or sets a value indicating whether to use AXIS fonts from the game.
|
||||
/// </summary>
|
||||
public GameFont DefaultFontFromGame { get; set; } = GameFont.Undefined;
|
||||
public bool UseAxisFontsFromGame { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not plugin UI should be hidden.
|
||||
|
|
|
|||
49
Dalamud/Interface/GameFonts/GameFontFamily.cs
Normal file
49
Dalamud/Interface/GameFonts/GameFontFamily.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.Interface.GameFonts
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum of available game font families.
|
||||
/// </summary>
|
||||
public enum GameFontFamily
|
||||
{
|
||||
/// <summary>
|
||||
/// Placeholder meaning unused.
|
||||
/// </summary>
|
||||
Undefined,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif fonts used for the whole UI. Contains Japanese characters in addition to Latin characters.
|
||||
/// </summary>
|
||||
Axis,
|
||||
|
||||
/// <summary>
|
||||
/// Serif fonts used for job names. Contains Latin characters.
|
||||
/// </summary>
|
||||
Jupiter,
|
||||
|
||||
/// <summary>
|
||||
/// Digit-only serif fonts used for flying texts. Contains numbers.
|
||||
/// </summary>
|
||||
JupiterNumeric,
|
||||
|
||||
/// <summary>
|
||||
/// Digit-only sans-serif horizontally wide fonts used for HP/MP/IL numbers.
|
||||
/// </summary>
|
||||
Meidinger,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif horizontally wide font used for names of gauges. Contains Latin characters.
|
||||
/// </summary>
|
||||
MiedingerMid,
|
||||
|
||||
/// <summary>
|
||||
/// Sans-serif horizontally narrow font used for addon titles. Contains Latin characters.
|
||||
/// </summary>
|
||||
TrumpGothic,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
namespace Dalamud.Interface.GameFonts
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum of available game fonts.
|
||||
/// Enum of available game fonts in specific sizes.
|
||||
/// </summary>
|
||||
public enum GameFont : int
|
||||
public enum GameFontFamilyAndSize : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Placeholder meaning unused.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
|
||||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.GameFonts
|
||||
|
|
@ -10,26 +10,92 @@ namespace Dalamud.Interface.GameFonts
|
|||
public class GameFontHandle : IDisposable
|
||||
{
|
||||
private readonly GameFontManager manager;
|
||||
private readonly GameFont font;
|
||||
private readonly GameFontStyle fontStyle;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameFontHandle"/> class.
|
||||
/// </summary>
|
||||
/// <param name="manager">GameFontManager instance.</param>
|
||||
/// <param name="font">Font to use.</param>
|
||||
internal GameFontHandle(GameFontManager manager, GameFont font)
|
||||
internal GameFontHandle(GameFontManager manager, GameFontStyle font)
|
||||
{
|
||||
this.manager = manager;
|
||||
this.font = font;
|
||||
this.fontStyle = font;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the font style.
|
||||
/// </summary>
|
||||
public GameFontStyle Style => this.fontStyle;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this font is ready for use.
|
||||
/// </summary>
|
||||
public bool Available => this.manager.GetFont(this.fontStyle) != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the font.
|
||||
/// </summary>
|
||||
/// <returns>Corresponding font or null.</returns>
|
||||
public ImFontPtr? Get() => this.manager.GetFont(this.font);
|
||||
public ImFontPtr ImFont => this.manager.GetFont(this.fontStyle).Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FdtReader.
|
||||
/// </summary>
|
||||
public FdtReader FdtReader => this.manager.GetFdtReader(this.fontStyle.FamilyAndSize);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GameFontLayoutPlan.Builder.
|
||||
/// </summary>
|
||||
/// <param name="text">Text.</param>
|
||||
/// <returns>A new builder for GameFontLayoutPlan.</returns>
|
||||
public GameFontLayoutPlan.Builder LayoutBuilder(string text)
|
||||
{
|
||||
return new GameFontLayoutPlan.Builder(this.ImFont, this.FdtReader, text);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose() => this.manager.DecreaseFontRef(this.font);
|
||||
public void Dispose() => this.manager.DecreaseFontRef(this.fontStyle);
|
||||
|
||||
/// <summary>
|
||||
/// Draws text.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to draw.</param>
|
||||
public void Text(string text)
|
||||
{
|
||||
if (!this.Available)
|
||||
{
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LayoutBuilder(text)
|
||||
.Build()
|
||||
.Draw(ImGui.GetWindowDrawList(), ImGui.GetWindowPos() + ImGui.GetCursorPos(), ImGui.GetColorU32(ImGuiCol.Text));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws text in given color.
|
||||
/// </summary>
|
||||
/// <param name="col">Color.</param>
|
||||
/// <param name="text">Text to draw.</param>
|
||||
public void TextColored(Vector4 col, string text)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, col);
|
||||
this.Text(text);
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws disabled text.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to draw.</param>
|
||||
public void TextDisabled(string text)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
this.TextColored(*ImGui.GetStyleColorVec4(ImGuiCol.TextDisabled), text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
414
Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs
Normal file
414
Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.GameFonts
|
||||
{
|
||||
/// <summary>
|
||||
/// Plan on how glyphs will be rendered.
|
||||
/// </summary>
|
||||
public class GameFontLayoutPlan
|
||||
{
|
||||
/// <summary>
|
||||
/// Horizontal alignment.
|
||||
/// </summary>
|
||||
public enum HorizontalAlignment
|
||||
{
|
||||
/// <summary>
|
||||
/// Align to left.
|
||||
/// </summary>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// Align to center.
|
||||
/// </summary>
|
||||
Center,
|
||||
|
||||
/// <summary>
|
||||
/// Align to right.
|
||||
/// </summary>
|
||||
Right,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the associated ImFontPtr.
|
||||
/// </summary>
|
||||
public ImFontPtr ImFontPtr { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size in points of the text.
|
||||
/// </summary>
|
||||
public float Size { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the x offset of the leftmost glyph.
|
||||
/// </summary>
|
||||
public float X { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the text.
|
||||
/// </summary>
|
||||
public float Width { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the text.
|
||||
/// </summary>
|
||||
public float Height { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of plannen elements.
|
||||
/// </summary>
|
||||
public IList<Element> Elements { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Draws font to ImGui.
|
||||
/// </summary>
|
||||
/// <param name="drawListPtr">Target ImDrawList.</param>
|
||||
/// <param name="pos">Position.</param>
|
||||
/// <param name="col">Color.</param>
|
||||
public void Draw(ImDrawListPtr drawListPtr, Vector2 pos, uint col)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(this.Width, this.Height));
|
||||
foreach (var element in this.Elements)
|
||||
{
|
||||
if (element.IsControl)
|
||||
continue;
|
||||
|
||||
this.ImFontPtr.RenderChar(
|
||||
drawListPtr,
|
||||
this.Size,
|
||||
new Vector2(
|
||||
this.X + pos.X + element.X,
|
||||
pos.Y + element.Y),
|
||||
col,
|
||||
element.Glyph.Char);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plan on how each glyph will be rendered.
|
||||
/// </summary>
|
||||
public class Element
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the original codepoint.
|
||||
/// </summary>
|
||||
public int Codepoint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the corresponding or fallback glyph.
|
||||
/// </summary>
|
||||
public FdtReader.FontTableEntry Glyph { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X offset of this glyph.
|
||||
/// </summary>
|
||||
public float X { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y offset of this glyph.
|
||||
/// </summary>
|
||||
public float Y { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether whether this codepoint is a control character.
|
||||
/// </summary>
|
||||
public bool IsControl
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Codepoint < 0x10000 && char.IsControl((char)this.Codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether whether this codepoint is a space.
|
||||
/// </summary>
|
||||
public bool IsSpace
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Codepoint < 0x10000 && char.IsWhiteSpace((char)this.Codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether whether this codepoint is a line break character.
|
||||
/// </summary>
|
||||
public bool IsLineBreak
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Codepoint == '\n' || this.Codepoint == '\r';
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether whether this codepoint is a chinese character.
|
||||
/// </summary>
|
||||
public bool IsChineseCharacter
|
||||
{
|
||||
get
|
||||
{
|
||||
// CJK Symbols and Punctuation(〇)
|
||||
if (this.Codepoint >= 0x3007 && this.Codepoint <= 0x3007)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension A
|
||||
if (this.Codepoint >= 0x3400 && this.Codepoint <= 0x4DBF)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs
|
||||
if (this.Codepoint >= 0x4E00 && this.Codepoint <= 0x9FFF)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension B
|
||||
if (this.Codepoint >= 0x20000 && this.Codepoint <= 0x2A6DF)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension C
|
||||
if (this.Codepoint >= 0x2A700 && this.Codepoint <= 0x2B73F)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension D
|
||||
if (this.Codepoint >= 0x2B740 && this.Codepoint <= 0x2B81F)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension E
|
||||
if (this.Codepoint >= 0x2B820 && this.Codepoint <= 0x2CEAF)
|
||||
return true;
|
||||
|
||||
// CJK Unified Ideographs Extension F
|
||||
if (this.Codepoint >= 0x2CEB0 && this.Codepoint <= 0x2EBEF)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether whether this codepoint is a good position to break word after.
|
||||
/// </summary>
|
||||
public bool IsWordBreakPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.IsChineseCharacter)
|
||||
return true;
|
||||
|
||||
if (this.Codepoint >= 0x10000)
|
||||
return false;
|
||||
|
||||
// TODO: Whatever
|
||||
switch (char.GetUnicodeCategory((char)this.Codepoint))
|
||||
{
|
||||
case System.Globalization.UnicodeCategory.SpaceSeparator:
|
||||
case System.Globalization.UnicodeCategory.LineSeparator:
|
||||
case System.Globalization.UnicodeCategory.ParagraphSeparator:
|
||||
case System.Globalization.UnicodeCategory.Control:
|
||||
case System.Globalization.UnicodeCategory.Format:
|
||||
case System.Globalization.UnicodeCategory.Surrogate:
|
||||
case System.Globalization.UnicodeCategory.PrivateUse:
|
||||
case System.Globalization.UnicodeCategory.ConnectorPunctuation:
|
||||
case System.Globalization.UnicodeCategory.DashPunctuation:
|
||||
case System.Globalization.UnicodeCategory.OpenPunctuation:
|
||||
case System.Globalization.UnicodeCategory.ClosePunctuation:
|
||||
case System.Globalization.UnicodeCategory.InitialQuotePunctuation:
|
||||
case System.Globalization.UnicodeCategory.FinalQuotePunctuation:
|
||||
case System.Globalization.UnicodeCategory.OtherPunctuation:
|
||||
case System.Globalization.UnicodeCategory.MathSymbol:
|
||||
case System.Globalization.UnicodeCategory.ModifierSymbol:
|
||||
case System.Globalization.UnicodeCategory.OtherSymbol:
|
||||
case System.Globalization.UnicodeCategory.OtherNotAssigned:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build a GameFontLayoutPlan.
|
||||
/// </summary>
|
||||
public class Builder
|
||||
{
|
||||
private readonly ImFontPtr fontPtr;
|
||||
private readonly FdtReader fdt;
|
||||
private readonly string text;
|
||||
private int maxWidth = int.MaxValue;
|
||||
private float size;
|
||||
private HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Builder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="fontPtr">Corresponding ImFontPtr.</param>
|
||||
/// <param name="fdt">FDT file to base on.</param>
|
||||
/// <param name="text">Text.</param>
|
||||
public Builder(ImFontPtr fontPtr, FdtReader fdt, string text)
|
||||
{
|
||||
this.fontPtr = fontPtr;
|
||||
this.fdt = fdt;
|
||||
this.text = text;
|
||||
this.size = fdt.FontHeader.LineHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the size of resulting text.
|
||||
/// </summary>
|
||||
/// <param name="size">Size in pixels.</param>
|
||||
/// <returns>This.</returns>
|
||||
public Builder WithSize(float size)
|
||||
{
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum width of the text.
|
||||
/// </summary>
|
||||
/// <param name="maxWidth">Maximum width in pixels.</param>
|
||||
/// <returns>This.</returns>
|
||||
public Builder WithMaxWidth(int maxWidth)
|
||||
{
|
||||
this.maxWidth = maxWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the horizontal alignment of the text.
|
||||
/// </summary>
|
||||
/// <param name="horizontalAlignment">Horizontal alignment.</param>
|
||||
/// <returns>This.</returns>
|
||||
public Builder WithHorizontalAlignment(HorizontalAlignment horizontalAlignment)
|
||||
{
|
||||
this.horizontalAlignment = horizontalAlignment;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the layout plan.
|
||||
/// </summary>
|
||||
/// <returns>Newly created layout plan.</returns>
|
||||
public GameFontLayoutPlan Build()
|
||||
{
|
||||
var scale = this.size / this.fdt.FontHeader.LineHeight;
|
||||
var unscaledMaxWidth = (float)Math.Ceiling(this.maxWidth / scale);
|
||||
var elements = new List<Element>();
|
||||
foreach (var c in this.text)
|
||||
elements.Add(new() { Codepoint = c, Glyph = this.fdt.GetGlyph(c), });
|
||||
|
||||
var lastBreakIndex = 0;
|
||||
List<int> lineBreakIndices = new() { 0 };
|
||||
for (var i = 1; i < elements.Count; i++)
|
||||
{
|
||||
var prev = elements[i - 1];
|
||||
var curr = elements[i];
|
||||
|
||||
if (prev.IsLineBreak)
|
||||
{
|
||||
curr.X = 0;
|
||||
curr.Y = prev.Y + this.fdt.FontHeader.LineHeight;
|
||||
lineBreakIndices.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
curr.X = prev.X + prev.Glyph.NextOffsetX + prev.Glyph.BoundingWidth + this.fdt.GetDistance(prev.Codepoint, curr.Codepoint);
|
||||
curr.Y = prev.Y;
|
||||
}
|
||||
|
||||
if (prev.IsWordBreakPoint)
|
||||
lastBreakIndex = i;
|
||||
|
||||
if (curr.IsSpace)
|
||||
continue;
|
||||
|
||||
if (curr.X + curr.Glyph.BoundingWidth < unscaledMaxWidth)
|
||||
continue;
|
||||
|
||||
if (!prev.IsSpace && elements[lastBreakIndex].X > 0)
|
||||
{
|
||||
prev = elements[lastBreakIndex - 1];
|
||||
curr = elements[lastBreakIndex];
|
||||
i = lastBreakIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastBreakIndex = i;
|
||||
}
|
||||
|
||||
curr.X = 0;
|
||||
curr.Y = prev.Y + this.fdt.FontHeader.LineHeight;
|
||||
lineBreakIndices.Add(i);
|
||||
}
|
||||
|
||||
lineBreakIndices.Add(elements.Count);
|
||||
|
||||
var targetX = 0f;
|
||||
var targetWidth = 0f;
|
||||
var targetHeight = 0f;
|
||||
for (var i = 1; i < lineBreakIndices.Count; i++)
|
||||
{
|
||||
var from = lineBreakIndices[i - 1];
|
||||
var to = lineBreakIndices[i];
|
||||
while (to > from && elements[to - 1].IsSpace)
|
||||
{
|
||||
to--;
|
||||
}
|
||||
|
||||
if (from >= to)
|
||||
continue;
|
||||
|
||||
var right = 0f;
|
||||
for (var j = from; j < to; j++)
|
||||
{
|
||||
var e = elements[j];
|
||||
right = Math.Max(right, e.X + Math.Max(e.Glyph.BoundingWidth, e.Glyph.AdvanceWidth));
|
||||
targetHeight = Math.Max(targetHeight, e.Y + e.Glyph.BoundingHeight);
|
||||
}
|
||||
|
||||
targetWidth = Math.Max(targetWidth, right - elements[from].X);
|
||||
float offsetX;
|
||||
if (this.horizontalAlignment == HorizontalAlignment.Center)
|
||||
offsetX = (unscaledMaxWidth - right) / 2;
|
||||
else if (this.horizontalAlignment == HorizontalAlignment.Right)
|
||||
offsetX = unscaledMaxWidth - right;
|
||||
else if (this.horizontalAlignment == HorizontalAlignment.Left)
|
||||
offsetX = 0;
|
||||
else
|
||||
throw new ArgumentException("Invalid horizontal alignment");
|
||||
for (var j = from; j < to; j++)
|
||||
elements[j].X += offsetX;
|
||||
targetX = i == 1 ? elements[from].X : Math.Min(targetX, elements[from].X);
|
||||
}
|
||||
|
||||
targetHeight = Math.Max(targetHeight, this.fdt.FontHeader.LineHeight * (lineBreakIndices.Count - 1));
|
||||
|
||||
targetWidth *= scale;
|
||||
targetHeight *= scale;
|
||||
targetX *= scale;
|
||||
foreach (var e in elements)
|
||||
{
|
||||
e.X *= scale;
|
||||
e.Y *= scale;
|
||||
}
|
||||
|
||||
return new GameFontLayoutPlan()
|
||||
{
|
||||
ImFontPtr = this.fontPtr,
|
||||
Size = this.size,
|
||||
X = targetX,
|
||||
Width = targetWidth,
|
||||
Height = targetHeight,
|
||||
Elements = elements,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,10 +33,9 @@ namespace Dalamud.Interface.GameFonts
|
|||
|
||||
private readonly FdtReader?[] fdts;
|
||||
private readonly List<byte[]> texturePixels;
|
||||
private readonly ImFontPtr?[] fonts = new ImFontPtr?[FontNames.Length];
|
||||
|
||||
private readonly int[] fontUseCounter = new int[FontNames.Length];
|
||||
private readonly List<Dictionary<char, Tuple<int, FdtReader.FontTableEntry>>> glyphRectIds = new();
|
||||
private readonly Dictionary<GameFontStyle, ImFontPtr> fonts = new();
|
||||
private readonly Dictionary<GameFontStyle, int> fontUseCounter = new();
|
||||
private readonly Dictionary<GameFontStyle, Dictionary<char, Tuple<int, FdtReader.FontTableEntry>>> glyphRectIds = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameFontManager"/> class.
|
||||
|
|
@ -60,34 +59,34 @@ namespace Dalamud.Interface.GameFonts
|
|||
/// </summary>
|
||||
/// <param name="font">Font to describe.</param>
|
||||
/// <returns>A string in a form of "FontName (NNNpt)".</returns>
|
||||
public static string DescribeFont(GameFont font)
|
||||
public static string DescribeFont(GameFontFamilyAndSize font)
|
||||
{
|
||||
return font switch
|
||||
{
|
||||
GameFont.Undefined => "-",
|
||||
GameFont.Axis96 => "AXIS (9.6pt)",
|
||||
GameFont.Axis12 => "AXIS (12pt)",
|
||||
GameFont.Axis14 => "AXIS (14pt)",
|
||||
GameFont.Axis18 => "AXIS (18pt)",
|
||||
GameFont.Axis36 => "AXIS (36pt)",
|
||||
GameFont.Jupiter16 => "Jupiter (16pt)",
|
||||
GameFont.Jupiter20 => "Jupiter (20pt)",
|
||||
GameFont.Jupiter23 => "Jupiter (23pt)",
|
||||
GameFont.Jupiter45 => "Jupiter Numeric (45pt)",
|
||||
GameFont.Jupiter46 => "Jupiter (46pt)",
|
||||
GameFont.Jupiter90 => "Jupiter Numeric (90pt)",
|
||||
GameFont.Meidinger16 => "Meidinger Numeric (16pt)",
|
||||
GameFont.Meidinger20 => "Meidinger Numeric (20pt)",
|
||||
GameFont.Meidinger40 => "Meidinger Numeric (40pt)",
|
||||
GameFont.MiedingerMid10 => "MiedingerMid (10pt)",
|
||||
GameFont.MiedingerMid12 => "MiedingerMid (12pt)",
|
||||
GameFont.MiedingerMid14 => "MiedingerMid (14pt)",
|
||||
GameFont.MiedingerMid18 => "MiedingerMid (18pt)",
|
||||
GameFont.MiedingerMid36 => "MiedingerMid (36pt)",
|
||||
GameFont.TrumpGothic184 => "Trump Gothic (18.4pt)",
|
||||
GameFont.TrumpGothic23 => "Trump Gothic (23pt)",
|
||||
GameFont.TrumpGothic34 => "Trump Gothic (34pt)",
|
||||
GameFont.TrumpGothic68 => "Trump Gothic (68pt)",
|
||||
GameFontFamilyAndSize.Undefined => "-",
|
||||
GameFontFamilyAndSize.Axis96 => "AXIS (9.6pt)",
|
||||
GameFontFamilyAndSize.Axis12 => "AXIS (12pt)",
|
||||
GameFontFamilyAndSize.Axis14 => "AXIS (14pt)",
|
||||
GameFontFamilyAndSize.Axis18 => "AXIS (18pt)",
|
||||
GameFontFamilyAndSize.Axis36 => "AXIS (36pt)",
|
||||
GameFontFamilyAndSize.Jupiter16 => "Jupiter (16pt)",
|
||||
GameFontFamilyAndSize.Jupiter20 => "Jupiter (20pt)",
|
||||
GameFontFamilyAndSize.Jupiter23 => "Jupiter (23pt)",
|
||||
GameFontFamilyAndSize.Jupiter45 => "Jupiter Numeric (45pt)",
|
||||
GameFontFamilyAndSize.Jupiter46 => "Jupiter (46pt)",
|
||||
GameFontFamilyAndSize.Jupiter90 => "Jupiter Numeric (90pt)",
|
||||
GameFontFamilyAndSize.Meidinger16 => "Meidinger Numeric (16pt)",
|
||||
GameFontFamilyAndSize.Meidinger20 => "Meidinger Numeric (20pt)",
|
||||
GameFontFamilyAndSize.Meidinger40 => "Meidinger Numeric (40pt)",
|
||||
GameFontFamilyAndSize.MiedingerMid10 => "MiedingerMid (10pt)",
|
||||
GameFontFamilyAndSize.MiedingerMid12 => "MiedingerMid (12pt)",
|
||||
GameFontFamilyAndSize.MiedingerMid14 => "MiedingerMid (14pt)",
|
||||
GameFontFamilyAndSize.MiedingerMid18 => "MiedingerMid (18pt)",
|
||||
GameFontFamilyAndSize.MiedingerMid36 => "MiedingerMid (36pt)",
|
||||
GameFontFamilyAndSize.TrumpGothic184 => "Trump Gothic (18.4pt)",
|
||||
GameFontFamilyAndSize.TrumpGothic23 => "Trump Gothic (23pt)",
|
||||
GameFontFamilyAndSize.TrumpGothic34 => "Trump Gothic (34pt)",
|
||||
GameFontFamilyAndSize.TrumpGothic68 => "Trump Gothic (68pt)",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(font), font, "Invalid argument"),
|
||||
};
|
||||
}
|
||||
|
|
@ -97,15 +96,15 @@ namespace Dalamud.Interface.GameFonts
|
|||
/// </summary>
|
||||
/// <param name="font">Font to check.</param>
|
||||
/// <returns>True if it can.</returns>
|
||||
public static bool IsGenericPurposeFont(GameFont font)
|
||||
public static bool IsGenericPurposeFont(GameFontFamilyAndSize font)
|
||||
{
|
||||
return font switch
|
||||
{
|
||||
GameFont.Axis96 => true,
|
||||
GameFont.Axis12 => true,
|
||||
GameFont.Axis14 => true,
|
||||
GameFont.Axis18 => true,
|
||||
GameFont.Axis36 => true,
|
||||
GameFontFamilyAndSize.Axis96 => true,
|
||||
GameFontFamilyAndSize.Axis12 => true,
|
||||
GameFontFamilyAndSize.Axis14 => true,
|
||||
GameFontFamilyAndSize.Axis18 => true,
|
||||
GameFontFamilyAndSize.Axis36 => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
|
@ -174,32 +173,38 @@ namespace Dalamud.Interface.GameFonts
|
|||
/// <summary>
|
||||
/// Creates a new GameFontHandle, and increases internal font reference counter, and if it's first time use, then the font will be loaded on next font building process.
|
||||
/// </summary>
|
||||
/// <param name="gameFont">Font to use.</param>
|
||||
/// <param name="style">Font to use.</param>
|
||||
/// <returns>Handle to game font that may or may not be ready yet.</returns>
|
||||
public GameFontHandle NewFontRef(GameFont gameFont)
|
||||
public GameFontHandle NewFontRef(GameFontStyle style)
|
||||
{
|
||||
var fontIndex = (int)gameFont;
|
||||
var needRebuild = false;
|
||||
|
||||
lock (this.syncRoot)
|
||||
{
|
||||
var prev = this.fontUseCounter[fontIndex] == 0;
|
||||
this.fontUseCounter[fontIndex] += 1;
|
||||
needRebuild = prev != (this.fontUseCounter[fontIndex] == 0);
|
||||
var prevValue = this.fontUseCounter.GetValueOrDefault(style, 0);
|
||||
var newValue = this.fontUseCounter[style] = prevValue + 1;
|
||||
needRebuild = (prevValue == 0) != (newValue == 0) && !this.fonts.ContainsKey(style);
|
||||
}
|
||||
|
||||
if (needRebuild)
|
||||
this.interfaceManager.RebuildFonts();
|
||||
|
||||
return new(this, gameFont);
|
||||
return new(this, style);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the font.
|
||||
/// </summary>
|
||||
/// <param name="gameFont">Font to get.</param>
|
||||
/// <param name="style">Font to get.</param>
|
||||
/// <returns>Corresponding font or null.</returns>
|
||||
public ImFontPtr? GetFont(GameFont gameFont) => this.fonts[(int)gameFont];
|
||||
public ImFontPtr? GetFont(GameFontStyle style) => this.fonts.GetValueOrDefault(style, null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the corresponding FdtReader.
|
||||
/// </summary>
|
||||
/// <param name="family">Font to get.</param>
|
||||
/// <returns>Corresponding FdtReader or null.</returns>
|
||||
public FdtReader? GetFdtReader(GameFontFamilyAndSize family) => this.fdts[(int)family];
|
||||
|
||||
/// <summary>
|
||||
/// Fills missing glyphs in target font from source font, if both are not null.
|
||||
|
|
@ -208,9 +213,9 @@ 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 void CopyGlyphsAcrossFonts(ImFontPtr? source, GameFont target, bool missingOnly, bool rebuildLookupTable)
|
||||
public void CopyGlyphsAcrossFonts(ImFontPtr? source, GameFontStyle target, bool missingOnly, bool rebuildLookupTable)
|
||||
{
|
||||
GameFontManager.CopyGlyphsAcrossFonts(source, this.fonts[(int)target], missingOnly, rebuildLookupTable);
|
||||
GameFontManager.CopyGlyphsAcrossFonts(source, this.fonts[target], missingOnly, rebuildLookupTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -220,9 +225,9 @@ 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 void CopyGlyphsAcrossFonts(GameFont source, ImFontPtr? target, bool missingOnly, bool rebuildLookupTable)
|
||||
public void CopyGlyphsAcrossFonts(GameFontStyle source, ImFontPtr? target, bool missingOnly, bool rebuildLookupTable)
|
||||
{
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.fonts[(int)source], target, missingOnly, rebuildLookupTable);
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.fonts[source], target, missingOnly, rebuildLookupTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -232,9 +237,9 @@ 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 void CopyGlyphsAcrossFonts(GameFont source, GameFont target, bool missingOnly, bool rebuildLookupTable)
|
||||
public void CopyGlyphsAcrossFonts(GameFontStyle source, GameFontStyle target, bool missingOnly, bool rebuildLookupTable)
|
||||
{
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.fonts[(int)source], this.fonts[(int)target], missingOnly, rebuildLookupTable);
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.fonts[source], this.fonts[target], missingOnly, rebuildLookupTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -242,30 +247,38 @@ namespace Dalamud.Interface.GameFonts
|
|||
/// </summary>
|
||||
public void BuildFonts()
|
||||
{
|
||||
this.glyphRectIds.Clear();
|
||||
var io = ImGui.GetIO();
|
||||
io.Fonts.TexDesiredWidth = 4096;
|
||||
|
||||
for (var i = 0; i < FontNames.Length; i++)
|
||||
{
|
||||
this.fonts[i] = null;
|
||||
this.glyphRectIds.Add(new());
|
||||
this.glyphRectIds.Clear();
|
||||
this.fonts.Clear();
|
||||
|
||||
var fdt = this.fdts[i];
|
||||
if (this.fontUseCounter[i] == 0 || fdt == null)
|
||||
foreach (var style in this.fontUseCounter.Keys)
|
||||
{
|
||||
var rectIds = this.glyphRectIds[style] = new();
|
||||
|
||||
var fdt = this.fdts[(int)style.FamilyAndSize];
|
||||
if (fdt == null)
|
||||
continue;
|
||||
|
||||
Log.Information($"GameFontManager BuildFont: {FontNames[i]}");
|
||||
|
||||
var font = io.Fonts.AddFontDefault();
|
||||
this.fonts[i] = font;
|
||||
this.fonts[style] = font;
|
||||
foreach (var glyph in fdt.Glyphs)
|
||||
{
|
||||
var c = glyph.Char;
|
||||
if (c < 32 || c >= 0xFFFF)
|
||||
continue;
|
||||
|
||||
this.glyphRectIds[i][c] = Tuple.Create(io.Fonts.AddCustomRectFontGlyph(font, c, glyph.BoundingWidth + 1, glyph.BoundingHeight + 1, glyph.BoundingWidth + glyph.NextOffsetX, new Vector2(0, glyph.CurrentOffsetY)), glyph);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -279,13 +292,9 @@ namespace Dalamud.Interface.GameFonts
|
|||
io.Fonts.GetTexDataAsRGBA32(out byte* pixels8, out var width, out var height);
|
||||
var pixels32 = (uint*)pixels8;
|
||||
|
||||
for (var i = 0; i < this.fonts.Length; i++)
|
||||
foreach (var (style, font) in this.fonts)
|
||||
{
|
||||
if (!this.fonts[i].HasValue)
|
||||
continue;
|
||||
|
||||
var font = this.fonts[i]!.Value;
|
||||
var fdt = this.fdts[i];
|
||||
var fdt = this.fdts[(int)style.FamilyAndSize];
|
||||
var fontPtr = font.NativePtr;
|
||||
fontPtr->ConfigData->SizePixels = fontPtr->FontSize = fdt.FontHeader.LineHeight;
|
||||
fontPtr->Ascent = fdt.FontHeader.Ascent;
|
||||
|
|
@ -301,75 +310,83 @@ namespace Dalamud.Interface.GameFonts
|
|||
}
|
||||
}
|
||||
|
||||
fixed (char* c = FontNames[i])
|
||||
fixed (char* c = FontNames[(int)style.FamilyAndSize])
|
||||
{
|
||||
for (var j = 0; j < 40; j++)
|
||||
fontPtr->ConfigData->Name[j] = 0;
|
||||
Encoding.UTF8.GetBytes(c, FontNames[i].Length, fontPtr->ConfigData->Name, 40);
|
||||
Encoding.UTF8.GetBytes(c, FontNames[(int)style.FamilyAndSize].Length, fontPtr->ConfigData->Name, 40);
|
||||
}
|
||||
|
||||
foreach (var (c, (rectId, glyph)) in this.glyphRectIds[i])
|
||||
foreach (var (c, (rectId, glyph)) in this.glyphRectIds[style])
|
||||
{
|
||||
var rc = io.Fonts.GetCustomRectByIndex(rectId);
|
||||
var sourceBuffer = this.texturePixels[glyph.TextureFileIndex];
|
||||
var sourceBufferDelta = glyph.TextureChannelByteIndex;
|
||||
for (var y = 0; y < glyph.BoundingHeight; y++)
|
||||
var widthAdjustment = style.CalculateWidthAdjustment(fdt, glyph);
|
||||
if (widthAdjustment == 0)
|
||||
{
|
||||
for (var x = 0; x < glyph.BoundingWidth; x++)
|
||||
for (var y = 0; y < glyph.BoundingHeight; y++)
|
||||
{
|
||||
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;
|
||||
for (var x = 0; x < glyph.BoundingWidth; 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var y = 0; y < glyph.BoundingHeight; y++)
|
||||
{
|
||||
for (var x = 0; x < glyph.BoundingWidth + widthAdjustment; x++)
|
||||
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++)
|
||||
{
|
||||
var boldStrength = Math.Min(1f, style.Weight + 1 - xbold);
|
||||
for (var y = 0; y < glyph.BoundingHeight; y++)
|
||||
{
|
||||
float xDelta = xbold;
|
||||
if (style.SkewStrength > 0)
|
||||
xDelta += style.SkewStrength * (fdt.FontHeader.LineHeight - glyph.CurrentOffsetY - y) / fdt.FontHeader.LineHeight;
|
||||
else if (style.SkewStrength < 0)
|
||||
xDelta -= style.SkewStrength * (glyph.CurrentOffsetY + y) / fdt.FontHeader.LineHeight;
|
||||
var xDeltaInt = (int)Math.Floor(xDelta);
|
||||
var xness = xDelta - xDeltaInt;
|
||||
for (var x = 0; x < glyph.BoundingWidth; x++)
|
||||
{
|
||||
var sourcePixelIndex = ((glyph.TextureOffsetY + y) * fdt.FontHeader.TextureWidth) + glyph.TextureOffsetX + x;
|
||||
var a1 = sourceBuffer[sourceBufferDelta + (4 * sourcePixelIndex)];
|
||||
var a2 = x == glyph.BoundingWidth - 1 ? 0 : sourceBuffer[sourceBufferDelta + (4 * (sourcePixelIndex + 1))];
|
||||
var n = (a1 * xness) + (a2 * (1 - xness));
|
||||
var targetOffset = ((rc.Y + y) * width) + rc.X + x + xDeltaInt;
|
||||
pixels8[(targetOffset * 4) + 3] = Math.Max(pixels8[(targetOffset * 4) + 3], (byte)(boldStrength * n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, GameFont.Axis96, true, false);
|
||||
this.CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, GameFont.Axis12, true, false);
|
||||
this.CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, GameFont.Axis14, true, false);
|
||||
this.CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, GameFont.Axis18, true, false);
|
||||
this.CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, GameFont.Axis36, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis18, GameFont.Jupiter16, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Jupiter20, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Jupiter23, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Jupiter45, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Jupiter46, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Jupiter90, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis18, GameFont.Meidinger16, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Meidinger20, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.Meidinger40, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis96, GameFont.MiedingerMid10, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis12, GameFont.MiedingerMid12, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis14, GameFont.MiedingerMid14, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis18, GameFont.MiedingerMid18, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.MiedingerMid36, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis18, GameFont.TrumpGothic184, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.TrumpGothic23, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.TrumpGothic34, true, false);
|
||||
this.CopyGlyphsAcrossFonts(GameFont.Axis36, GameFont.TrumpGothic68, true, false);
|
||||
|
||||
foreach (var font in this.fonts)
|
||||
font?.BuildLookupTable();
|
||||
foreach (var font in this.fonts.Values)
|
||||
{
|
||||
CopyGlyphsAcrossFonts(InterfaceManager.DefaultFont, font, true, false);
|
||||
font.BuildLookupTable();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrease font reference counter and release if nobody is using it.
|
||||
/// Decrease font reference counter.
|
||||
/// </summary>
|
||||
/// <param name="gameFont">Font to release.</param>
|
||||
internal void DecreaseFontRef(GameFont gameFont)
|
||||
/// <param name="style">Font to release.</param>
|
||||
internal void DecreaseFontRef(GameFontStyle style)
|
||||
{
|
||||
var fontIndex = (int)gameFont;
|
||||
var needRebuild = false;
|
||||
|
||||
lock (this.syncRoot)
|
||||
{
|
||||
var prev = this.fontUseCounter[fontIndex] == 0;
|
||||
this.fontUseCounter[fontIndex] -= 1;
|
||||
needRebuild = prev != (this.fontUseCounter[fontIndex] == 0);
|
||||
if ((this.fontUseCounter[style] -= 1) == 0)
|
||||
this.fontUseCounter.Remove(style);
|
||||
}
|
||||
|
||||
if (needRebuild)
|
||||
this.interfaceManager.RebuildFonts();
|
||||
}
|
||||
|
||||
private struct ImFontGlyphReal
|
||||
|
|
|
|||
235
Dalamud/Interface/GameFonts/GameFontStyle.cs
Normal file
235
Dalamud/Interface/GameFonts/GameFontStyle.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.Interface.GameFonts
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a font based on game resource file.
|
||||
/// </summary>
|
||||
public struct GameFontStyle
|
||||
{
|
||||
/// <summary>
|
||||
/// Font family of the font.
|
||||
/// </summary>
|
||||
public GameFontFamilyAndSize FamilyAndSize;
|
||||
|
||||
/// <summary>
|
||||
/// Weight of the font.
|
||||
///
|
||||
/// 0 is unaltered.
|
||||
/// Any value greater than 0 will make it bolder.
|
||||
/// </summary>
|
||||
public float Weight;
|
||||
|
||||
/// <summary>
|
||||
/// Skewedness of the font.
|
||||
///
|
||||
/// 0 is unaltered.
|
||||
/// Greater than 1 will make upper part go rightwards.
|
||||
/// Less than 1 will make lower part go rightwards.
|
||||
/// </summary>
|
||||
public float SkewStrength;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameFontStyle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="family">Font family.</param>
|
||||
/// <param name="size">Size in points.</param>
|
||||
public GameFontStyle(GameFontFamily family, float size)
|
||||
{
|
||||
this.FamilyAndSize = GetRecommendedFamilyAndSize(family, size);
|
||||
this.Weight = this.SkewStrength = 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameFontStyle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="familyAndSize">Font family and size.</param>
|
||||
public GameFontStyle(GameFontFamilyAndSize familyAndSize)
|
||||
{
|
||||
this.FamilyAndSize = familyAndSize;
|
||||
this.Weight = this.SkewStrength = 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the font family.
|
||||
/// </summary>
|
||||
public GameFontFamily Family => this.FamilyAndSize switch
|
||||
{
|
||||
GameFontFamilyAndSize.Undefined => GameFontFamily.Undefined,
|
||||
GameFontFamilyAndSize.Axis96 => GameFontFamily.Axis,
|
||||
GameFontFamilyAndSize.Axis12 => GameFontFamily.Axis,
|
||||
GameFontFamilyAndSize.Axis14 => GameFontFamily.Axis,
|
||||
GameFontFamilyAndSize.Axis18 => GameFontFamily.Axis,
|
||||
GameFontFamilyAndSize.Axis36 => GameFontFamily.Axis,
|
||||
GameFontFamilyAndSize.Jupiter16 => GameFontFamily.Jupiter,
|
||||
GameFontFamilyAndSize.Jupiter20 => GameFontFamily.Jupiter,
|
||||
GameFontFamilyAndSize.Jupiter23 => GameFontFamily.Jupiter,
|
||||
GameFontFamilyAndSize.Jupiter45 => GameFontFamily.JupiterNumeric,
|
||||
GameFontFamilyAndSize.Jupiter46 => GameFontFamily.Jupiter,
|
||||
GameFontFamilyAndSize.Jupiter90 => GameFontFamily.JupiterNumeric,
|
||||
GameFontFamilyAndSize.Meidinger16 => GameFontFamily.Meidinger,
|
||||
GameFontFamilyAndSize.Meidinger20 => GameFontFamily.Meidinger,
|
||||
GameFontFamilyAndSize.Meidinger40 => GameFontFamily.Meidinger,
|
||||
GameFontFamilyAndSize.MiedingerMid10 => GameFontFamily.MiedingerMid,
|
||||
GameFontFamilyAndSize.MiedingerMid12 => GameFontFamily.MiedingerMid,
|
||||
GameFontFamilyAndSize.MiedingerMid14 => GameFontFamily.MiedingerMid,
|
||||
GameFontFamilyAndSize.MiedingerMid18 => GameFontFamily.MiedingerMid,
|
||||
GameFontFamilyAndSize.MiedingerMid36 => GameFontFamily.MiedingerMid,
|
||||
GameFontFamilyAndSize.TrumpGothic184 => GameFontFamily.TrumpGothic,
|
||||
GameFontFamilyAndSize.TrumpGothic23 => GameFontFamily.TrumpGothic,
|
||||
GameFontFamilyAndSize.TrumpGothic34 => GameFontFamily.TrumpGothic,
|
||||
GameFontFamilyAndSize.TrumpGothic68 => GameFontFamily.TrumpGothic,
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the font size.
|
||||
/// </summary>
|
||||
public float Size => this.FamilyAndSize switch
|
||||
{
|
||||
GameFontFamilyAndSize.Undefined => 0,
|
||||
GameFontFamilyAndSize.Axis96 => 9.6f,
|
||||
GameFontFamilyAndSize.Axis12 => 12,
|
||||
GameFontFamilyAndSize.Axis14 => 14,
|
||||
GameFontFamilyAndSize.Axis18 => 18,
|
||||
GameFontFamilyAndSize.Axis36 => 36,
|
||||
GameFontFamilyAndSize.Jupiter16 => 16,
|
||||
GameFontFamilyAndSize.Jupiter20 => 20,
|
||||
GameFontFamilyAndSize.Jupiter23 => 23,
|
||||
GameFontFamilyAndSize.Jupiter45 => 45,
|
||||
GameFontFamilyAndSize.Jupiter46 => 46,
|
||||
GameFontFamilyAndSize.Jupiter90 => 90,
|
||||
GameFontFamilyAndSize.Meidinger16 => 16,
|
||||
GameFontFamilyAndSize.Meidinger20 => 20,
|
||||
GameFontFamilyAndSize.Meidinger40 => 40,
|
||||
GameFontFamilyAndSize.MiedingerMid10 => 10,
|
||||
GameFontFamilyAndSize.MiedingerMid12 => 12,
|
||||
GameFontFamilyAndSize.MiedingerMid14 => 14,
|
||||
GameFontFamilyAndSize.MiedingerMid18 => 18,
|
||||
GameFontFamilyAndSize.MiedingerMid36 => 36,
|
||||
GameFontFamilyAndSize.TrumpGothic184 => 18.4f,
|
||||
GameFontFamilyAndSize.TrumpGothic23 => 23,
|
||||
GameFontFamilyAndSize.TrumpGothic34 => 34,
|
||||
GameFontFamilyAndSize.TrumpGothic68 => 8,
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this font is bold.
|
||||
/// </summary>
|
||||
public bool Bold
|
||||
{
|
||||
get => this.Weight > 0f;
|
||||
set => this.Weight = value ? 1f : 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this font is italic.
|
||||
/// </summary>
|
||||
public bool Italic
|
||||
{
|
||||
get => this.SkewStrength != 0;
|
||||
set => this.SkewStrength = value ? 4 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recommend GameFontFamilyAndSize given family and size.
|
||||
/// </summary>
|
||||
/// <param name="family">Font family.</param>
|
||||
/// <param name="size">Font size in points.</param>
|
||||
/// <returns>Recommended GameFontFamilyAndSize.</returns>
|
||||
public static GameFontFamilyAndSize GetRecommendedFamilyAndSize(GameFontFamily family, float size)
|
||||
{
|
||||
if (size <= 0)
|
||||
return GameFontFamilyAndSize.Undefined;
|
||||
|
||||
switch (family)
|
||||
{
|
||||
case GameFontFamily.Undefined:
|
||||
return GameFontFamilyAndSize.Undefined;
|
||||
|
||||
case GameFontFamily.Axis:
|
||||
if (size <= 9.6)
|
||||
return GameFontFamilyAndSize.Axis96;
|
||||
else if (size <= 12)
|
||||
return GameFontFamilyAndSize.Axis12;
|
||||
else if (size <= 14)
|
||||
return GameFontFamilyAndSize.Axis14;
|
||||
else if (size <= 18)
|
||||
return GameFontFamilyAndSize.Axis18;
|
||||
else
|
||||
return GameFontFamilyAndSize.Axis36;
|
||||
|
||||
case GameFontFamily.Jupiter:
|
||||
if (size <= 16)
|
||||
return GameFontFamilyAndSize.Jupiter16;
|
||||
else if (size <= 20)
|
||||
return GameFontFamilyAndSize.Jupiter20;
|
||||
else if (size <= 23)
|
||||
return GameFontFamilyAndSize.Jupiter23;
|
||||
else
|
||||
return GameFontFamilyAndSize.Jupiter46;
|
||||
|
||||
case GameFontFamily.JupiterNumeric:
|
||||
if (size <= 45)
|
||||
return GameFontFamilyAndSize.Jupiter45;
|
||||
else
|
||||
return GameFontFamilyAndSize.Jupiter90;
|
||||
|
||||
case GameFontFamily.Meidinger:
|
||||
if (size <= 16)
|
||||
return GameFontFamilyAndSize.Meidinger16;
|
||||
else if (size <= 20)
|
||||
return GameFontFamilyAndSize.Meidinger20;
|
||||
else
|
||||
return GameFontFamilyAndSize.Meidinger40;
|
||||
|
||||
case GameFontFamily.MiedingerMid:
|
||||
if (size <= 10)
|
||||
return GameFontFamilyAndSize.MiedingerMid10;
|
||||
else if (size <= 12)
|
||||
return GameFontFamilyAndSize.MiedingerMid12;
|
||||
else if (size <= 14)
|
||||
return GameFontFamilyAndSize.MiedingerMid14;
|
||||
else if (size <= 18)
|
||||
return GameFontFamilyAndSize.MiedingerMid18;
|
||||
else
|
||||
return GameFontFamilyAndSize.MiedingerMid36;
|
||||
|
||||
case GameFontFamily.TrumpGothic:
|
||||
if (size <= 18.4)
|
||||
return GameFontFamilyAndSize.TrumpGothic184;
|
||||
else if (size <= 23)
|
||||
return GameFontFamilyAndSize.TrumpGothic23;
|
||||
else if (size <= 34)
|
||||
return GameFontFamilyAndSize.TrumpGothic34;
|
||||
else
|
||||
return GameFontFamilyAndSize.TrumpGothic68;
|
||||
|
||||
default:
|
||||
return GameFontFamilyAndSize.Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the adjustment to width resulting fron Weight and SkewStrength.
|
||||
/// </summary>
|
||||
/// <param name="reader">Font information.</param>
|
||||
/// <param name="glyph">Glyph.</param>
|
||||
/// <returns>Width adjustment in pixel unit.</returns>
|
||||
public int CalculateWidthAdjustment(FdtReader reader, FdtReader.FontTableEntry glyph)
|
||||
{
|
||||
var widthDelta = this.Weight;
|
||||
if (this.SkewStrength > 0)
|
||||
widthDelta += 1f * this.SkewStrength * (reader.FontHeader.LineHeight - glyph.CurrentOffsetY) / reader.FontHeader.LineHeight;
|
||||
else if (this.SkewStrength < 0)
|
||||
widthDelta -= 1f * this.SkewStrength * (glyph.CurrentOffsetY + glyph.BoundingHeight) / reader.FontHeader.LineHeight;
|
||||
|
||||
return (int)Math.Ceiling(widthDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,8 +57,7 @@ namespace Dalamud.Interface.Internal
|
|||
private readonly SwapChainVtableResolver address;
|
||||
private RawDX11Scene? scene;
|
||||
|
||||
private GameFont overwriteDefaultFontFromGameFont = GameFont.Undefined;
|
||||
private GameFontHandle? overwriteDefaultFontFromGameFontHandle;
|
||||
private GameFontHandle? axisFontHandle;
|
||||
|
||||
// can't access imgui IO before first present call
|
||||
private bool lastWantCapture = false;
|
||||
|
|
@ -313,16 +312,7 @@ namespace Dalamud.Interface.Internal
|
|||
if (!this.isRebuildingFonts)
|
||||
{
|
||||
Log.Verbose("[FONT] RebuildFonts() trigger");
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
if (this.overwriteDefaultFontFromGameFont != configuration.DefaultFontFromGame)
|
||||
{
|
||||
this.overwriteDefaultFontFromGameFont = configuration.DefaultFontFromGame;
|
||||
this.overwriteDefaultFontFromGameFontHandle?.Dispose();
|
||||
if (configuration.DefaultFontFromGame == GameFont.Undefined)
|
||||
this.overwriteDefaultFontFromGameFontHandle = null;
|
||||
else
|
||||
this.overwriteDefaultFontFromGameFontHandle = Service<GameFontManager>.Get().NewFontRef(configuration.DefaultFontFromGame);
|
||||
}
|
||||
this.SetAxisFonts();
|
||||
|
||||
this.isRebuildingFonts = true;
|
||||
this.scene.OnNewRenderFrame += this.RebuildFontsInternal;
|
||||
|
|
@ -342,6 +332,26 @@ namespace Dalamud.Interface.Internal
|
|||
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");
|
||||
}
|
||||
|
||||
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.axisFontHandle?.Dispose();
|
||||
this.axisFontHandle = Service<GameFontManager>.Get().NewFontRef(new(expectedFamilyAndSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.axisFontHandle?.Dispose();
|
||||
this.axisFontHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE(goat): When hooking ReShade DXGISwapChain::runtime_present, this is missing the syncInterval arg.
|
||||
* Seems to work fine regardless, I guess, so whatever.
|
||||
|
|
@ -403,15 +413,7 @@ namespace Dalamud.Interface.Internal
|
|||
this.scene.OnBuildUI += this.Display;
|
||||
this.scene.OnNewInputFrame += this.OnNewInputFrame;
|
||||
|
||||
if (this.overwriteDefaultFontFromGameFont != configuration.DefaultFontFromGame)
|
||||
{
|
||||
this.overwriteDefaultFontFromGameFont = configuration.DefaultFontFromGame;
|
||||
this.overwriteDefaultFontFromGameFontHandle?.Dispose();
|
||||
if (configuration.DefaultFontFromGame == GameFont.Undefined)
|
||||
this.overwriteDefaultFontFromGameFontHandle = null;
|
||||
else
|
||||
this.overwriteDefaultFontFromGameFontHandle = Service<GameFontManager>.Get().NewFontRef(configuration.DefaultFontFromGame);
|
||||
}
|
||||
this.SetAxisFonts();
|
||||
|
||||
this.SetupFonts();
|
||||
|
||||
|
|
@ -591,7 +593,7 @@ namespace Dalamud.Interface.Internal
|
|||
ImGui.GetIO().Fonts.Build();
|
||||
|
||||
gameFontManager.AfterBuildFonts();
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.overwriteDefaultFontFromGameFontHandle?.Get(), DefaultFont, false, true);
|
||||
GameFontManager.CopyGlyphsAcrossFonts(this.axisFontHandle?.ImFont, DefaultFont, false, true);
|
||||
|
||||
Log.Verbose("[FONT] Invoke OnAfterBuildFonts");
|
||||
this.AfterBuildFonts?.Invoke();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
private const float MinScale = 0.3f;
|
||||
private const float MaxScale = 2.0f;
|
||||
|
||||
private readonly List<GameFont> validFontChoices;
|
||||
private readonly string[] validFontNames;
|
||||
private readonly string[] languages;
|
||||
private readonly string[] locLanguages;
|
||||
private int langIndex;
|
||||
|
|
@ -40,6 +38,7 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
private bool doCfChatMessage;
|
||||
|
||||
private float globalUiScale;
|
||||
private bool doUseAxisFontsFromGame;
|
||||
private bool doToggleUiHide;
|
||||
private bool doToggleUiHideDuringCutscenes;
|
||||
private bool doToggleUiHideDuringGpose;
|
||||
|
|
@ -69,8 +68,6 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
private bool doButtonsSystemMenu;
|
||||
private bool disableRmtFiltering;
|
||||
|
||||
private int validFontIndex;
|
||||
|
||||
#region Experimental
|
||||
|
||||
private bool doPluginTest;
|
||||
|
|
@ -94,6 +91,7 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
this.doCfChatMessage = configuration.DutyFinderChatMessage;
|
||||
|
||||
this.globalUiScale = configuration.GlobalUiScale;
|
||||
this.doUseAxisFontsFromGame = configuration.UseAxisFontsFromGame;
|
||||
this.doToggleUiHide = configuration.ToggleUiHide;
|
||||
this.doToggleUiHideDuringCutscenes = configuration.ToggleUiHideDuringCutscenes;
|
||||
this.doToggleUiHideDuringGpose = configuration.ToggleUiHideDuringGpose;
|
||||
|
|
@ -116,10 +114,6 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu;
|
||||
this.disableRmtFiltering = configuration.DisableRmtFiltering;
|
||||
|
||||
this.validFontChoices = Enum.GetValues<GameFont>().Where(x => x == GameFont.Undefined || GameFontManager.IsGenericPurposeFont(x)).ToList();
|
||||
this.validFontNames = this.validFontChoices.Select(x => GameFontManager.DescribeFont(x)).ToArray();
|
||||
this.validFontIndex = Math.Max(0, this.validFontChoices.IndexOf(configuration.DefaultFontFromGame));
|
||||
|
||||
this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray();
|
||||
try
|
||||
{
|
||||
|
|
@ -286,20 +280,19 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
{
|
||||
this.globalUiScale = 1.0f;
|
||||
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
|
||||
Service<InterfaceManager>.Get().RebuildFonts();
|
||||
}
|
||||
|
||||
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref this.globalUiScale, 0.005f, MinScale, MaxScale, "%.2f"))
|
||||
{
|
||||
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
|
||||
Service<InterfaceManager>.Get().RebuildFonts();
|
||||
}
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale all XIVLauncher UI elements - useful for 4K displays."));
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10, 16);
|
||||
|
||||
ImGui.Text(Loc.Localize("DalamudSettingsGlobalFont", "Global Font"));
|
||||
ImGui.Combo("##DalamudSettingsGlobalFontDrag", ref this.validFontIndex, this.validFontNames, this.validFontNames.Length);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10, 16);
|
||||
|
||||
if (ImGui.Button(Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor")))
|
||||
{
|
||||
Service<DalamudInterface>.Get().OpenStyleEditor();
|
||||
|
|
@ -311,6 +304,9 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below."));
|
||||
|
||||
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"), ref this.doUseAxisFontsFromGame);
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font."));
|
||||
|
||||
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"), ref this.doToggleUiHide);
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideHint", "Hide any open windows by plugins when toggling the game overlay."));
|
||||
|
||||
|
|
@ -814,7 +810,7 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
configuration.IsFocusManagementEnabled = this.doFocus;
|
||||
configuration.ShowTsm = this.doTsm;
|
||||
|
||||
configuration.DefaultFontFromGame = this.validFontChoices[this.validFontIndex];
|
||||
configuration.UseAxisFontsFromGame = this.doUseAxisFontsFromGame;
|
||||
|
||||
// This is applied every frame in InterfaceManager::CheckViewportState()
|
||||
configuration.IsDisableViewport = !this.doViewport;
|
||||
|
|
@ -858,9 +854,8 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
|
||||
configuration.Save();
|
||||
|
||||
Service<InterfaceManager>.Get().RebuildFonts();
|
||||
|
||||
_ = Service<PluginManager>.Get().ReloadPluginMastersAsync();
|
||||
Service<InterfaceManager>.Get().RebuildFonts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
|
@ -8,6 +8,7 @@ using Dalamud.Game;
|
|||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Interface.Animation.EasingFunctions;
|
||||
using Dalamud.Interface.GameFonts;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
using ImGuiScene;
|
||||
|
|
@ -19,6 +20,7 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
/// </summary>
|
||||
internal class TitleScreenMenuWindow : Window, IDisposable
|
||||
{
|
||||
private const float TargetFontSize = 16.2f;
|
||||
private readonly TextureWrap shadeTexture;
|
||||
|
||||
private readonly Dictionary<Guid, InOutCubic> shadeEasings = new();
|
||||
|
|
@ -27,6 +29,8 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
|
||||
private InOutCubic? fadeOutEasing;
|
||||
|
||||
private GameFontHandle? axisFontHandle;
|
||||
|
||||
private State state = State.Hide;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -67,14 +71,19 @@ 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();
|
||||
}
|
||||
|
|
@ -90,128 +99,143 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.SetWindowFontScale(1.3f);
|
||||
ImGui.SetWindowFontScale(TargetFontSize / ImGui.GetFont().FontSize * 4 / 3);
|
||||
|
||||
var tsm = Service<TitleScreenMenu>.Get();
|
||||
|
||||
switch (this.state)
|
||||
{
|
||||
case State.Show:
|
||||
{
|
||||
for (var i = 0; i < tsm.Entries.Count; i++)
|
||||
{
|
||||
var entry = tsm.Entries[i];
|
||||
|
||||
if (!this.moveEasings.TryGetValue(entry.Id, out var moveEasing))
|
||||
for (var i = 0; i < tsm.Entries.Count; i++)
|
||||
{
|
||||
moveEasing = new InOutQuint(TimeSpan.FromMilliseconds(400));
|
||||
this.moveEasings.Add(entry.Id, moveEasing);
|
||||
var entry = tsm.Entries[i];
|
||||
|
||||
if (!this.moveEasings.TryGetValue(entry.Id, out var moveEasing))
|
||||
{
|
||||
moveEasing = new InOutQuint(TimeSpan.FromMilliseconds(400));
|
||||
this.moveEasings.Add(entry.Id, moveEasing);
|
||||
}
|
||||
|
||||
if (!moveEasing.IsRunning && !moveEasing.IsDone)
|
||||
{
|
||||
moveEasing.Restart();
|
||||
}
|
||||
|
||||
if (moveEasing.IsDone)
|
||||
{
|
||||
moveEasing.Stop();
|
||||
}
|
||||
|
||||
moveEasing.Update();
|
||||
|
||||
var finalPos = (i + 1) * this.shadeTexture.Height;
|
||||
var pos = moveEasing.Value * finalPos;
|
||||
|
||||
// FIXME(goat): Sometimes, easings can overshoot and bring things out of alignment.
|
||||
if (moveEasing.IsDone)
|
||||
{
|
||||
pos = finalPos;
|
||||
}
|
||||
|
||||
this.DrawEntry(entry, moveEasing.IsRunning && i != 0, true, i == 0, true);
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
cursor.Y = (float)pos;
|
||||
ImGui.SetCursorPos(cursor);
|
||||
}
|
||||
|
||||
if (!moveEasing.IsRunning && !moveEasing.IsDone)
|
||||
if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
|
||||
ImGuiHoveredFlags.AllowWhenOverlapped |
|
||||
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem))
|
||||
{
|
||||
moveEasing.Restart();
|
||||
this.state = State.FadeOut;
|
||||
}
|
||||
|
||||
if (moveEasing.IsDone)
|
||||
{
|
||||
moveEasing.Stop();
|
||||
}
|
||||
|
||||
moveEasing.Update();
|
||||
|
||||
var finalPos = (i + 1) * this.shadeTexture.Height;
|
||||
var pos = moveEasing.Value * finalPos;
|
||||
|
||||
// FIXME(goat): Sometimes, easings can overshoot and bring things out of alignment.
|
||||
if (moveEasing.IsDone)
|
||||
{
|
||||
pos = finalPos;
|
||||
}
|
||||
|
||||
this.DrawEntry(entry, moveEasing.IsRunning && i != 0, true, i == 0, true);
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
cursor.Y = (float)pos;
|
||||
ImGui.SetCursorPos(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
|
||||
ImGuiHoveredFlags.AllowWhenOverlapped |
|
||||
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem))
|
||||
{
|
||||
this.state = State.FadeOut;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State.FadeOut:
|
||||
{
|
||||
this.fadeOutEasing ??= new InOutCubic(TimeSpan.FromMilliseconds(400))
|
||||
{
|
||||
IsInverse = true,
|
||||
};
|
||||
this.fadeOutEasing ??= new InOutCubic(TimeSpan.FromMilliseconds(400))
|
||||
{
|
||||
IsInverse = true,
|
||||
};
|
||||
|
||||
if (!this.fadeOutEasing.IsRunning && !this.fadeOutEasing.IsDone)
|
||||
{
|
||||
this.fadeOutEasing.Restart();
|
||||
if (!this.fadeOutEasing.IsRunning && !this.fadeOutEasing.IsDone)
|
||||
{
|
||||
this.fadeOutEasing.Restart();
|
||||
}
|
||||
|
||||
if (this.fadeOutEasing.IsDone)
|
||||
{
|
||||
this.fadeOutEasing.Stop();
|
||||
}
|
||||
|
||||
this.fadeOutEasing.Update();
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value);
|
||||
|
||||
for (var i = 0; i < tsm.Entries.Count; i++)
|
||||
{
|
||||
var entry = tsm.Entries[i];
|
||||
|
||||
var finalPos = (i + 1) * this.shadeTexture.Height;
|
||||
|
||||
this.DrawEntry(entry, i != 0, true, i == 0, false);
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
cursor.Y = finalPos;
|
||||
ImGui.SetCursorPos(cursor);
|
||||
}
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
|
||||
ImGuiHoveredFlags.AllowWhenOverlapped |
|
||||
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
|
||||
|
||||
if (!isHover && this.fadeOutEasing!.IsDone)
|
||||
{
|
||||
this.state = State.Hide;
|
||||
this.fadeOutEasing = null;
|
||||
}
|
||||
else if (isHover)
|
||||
{
|
||||
this.state = State.Show;
|
||||
this.fadeOutEasing = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.fadeOutEasing.IsDone)
|
||||
{
|
||||
this.fadeOutEasing.Stop();
|
||||
}
|
||||
|
||||
this.fadeOutEasing.Update();
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value);
|
||||
|
||||
for (var i = 0; i < tsm.Entries.Count; i++)
|
||||
{
|
||||
var entry = tsm.Entries[i];
|
||||
|
||||
var finalPos = (i + 1) * this.shadeTexture.Height;
|
||||
|
||||
this.DrawEntry(entry, i != 0, true, i == 0, false);
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
cursor.Y = finalPos;
|
||||
ImGui.SetCursorPos(cursor);
|
||||
}
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
var isHover = ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows |
|
||||
ImGuiHoveredFlags.AllowWhenOverlapped |
|
||||
ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
|
||||
|
||||
if (!isHover && this.fadeOutEasing!.IsDone)
|
||||
{
|
||||
this.state = State.Hide;
|
||||
this.fadeOutEasing = null;
|
||||
}
|
||||
else if (isHover)
|
||||
{
|
||||
this.state = State.Show;
|
||||
this.fadeOutEasing = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case State.Hide:
|
||||
{
|
||||
if (this.DrawEntry(tsm.Entries[0], true, false, true, true))
|
||||
{
|
||||
this.state = State.Show;
|
||||
}
|
||||
if (this.DrawEntry(tsm.Entries[0], true, false, true, true))
|
||||
{
|
||||
this.state = State.Show;
|
||||
}
|
||||
|
||||
this.moveEasings.Clear();
|
||||
this.logoEasings.Clear();
|
||||
this.shadeEasings.Clear();
|
||||
break;
|
||||
}
|
||||
this.moveEasings.Clear();
|
||||
this.logoEasings.Clear();
|
||||
this.shadeEasings.Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAxisFonts()
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
if (configuration.UseAxisFontsFromGame)
|
||||
{
|
||||
if (this.axisFontHandle == null)
|
||||
this.axisFontHandle = Service<GameFontManager>.Get().NewFontRef(new(GameFontFamily.Axis, TargetFontSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.axisFontHandle?.Dispose();
|
||||
this.axisFontHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -215,9 +215,9 @@ namespace Dalamud.Interface
|
|||
/// <summary>
|
||||
/// Gets a game font.
|
||||
/// </summary>
|
||||
/// <param name="gameFont">Font to get.</param>
|
||||
/// <param name="style">Font to get.</param>
|
||||
/// <returns>Handle to the game font which may or may not be available for use yet.</returns>
|
||||
public GameFontHandle GetGameFontHandle(GameFont gameFont) => Service<GameFontManager>.Get().NewFontRef(gameFont);
|
||||
public GameFontHandle GetGameFontHandle(GameFontStyle style) => Service<GameFontManager>.Get().NewFontRef(style);
|
||||
|
||||
/// <summary>
|
||||
/// Call this to queue a rebuild of the font atlas.<br/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue