Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions FontManagement/FontManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Globalization;
using System.IO;
using FontStashSharp;
using FontStashSharp.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
Expand Down Expand Up @@ -61,7 +62,7 @@ public static void Initialize()
/// <summary>
/// Creates a new FontSystem with current text shaping settings.
/// </summary>
private static FontSystem CreateFontSystem()
private static FontSystem CreateFontSystem(IFontLoader fontLoader = null)
{
var settings = new FontSystemSettings
{
Expand All @@ -71,7 +72,8 @@ private static FontSystem CreateFontSystem()
TextureWidth = fontRenderingSettings.TextureWidth,
TextureHeight = fontRenderingSettings.TextureHeight,
GlyphRenderResult = fontRenderingSettings.GlyphRenderResult,
UseEmToPixelsScale = true
UseEmToPixelsScale = true,
FontLoader = fontLoader,
};

if (textShapingSettings.Enabled)
Expand All @@ -84,7 +86,7 @@ private static FontSystem CreateFontSystem()
settings.ShapedTextCacheSize = textShapingSettings.CacheSize;
}

return new FontSystem(settings);
return new FontSystem(settings) { DefaultCharacter = '?' };
}

public static Vector2 MeasureString(string text, int fontIndex)
Expand Down Expand Up @@ -265,12 +267,16 @@ private static void CreateFontIndexesFromIni(IniFile iniFile, ContentManager con
string fontPath = iniFile.GetStringValue(section, "Path", "");
int size = iniFile.GetIntValue(section, "Size", 16);
string fontTypeStr = iniFile.GetStringValue(section, "Type", nameof(FontType.SpriteFont));
string fontLoaderStr = iniFile.GetStringValue(section, "Loader", nameof(TTFFontLoader.StbTrueType));
int fallback = iniFile.GetIntValue(section, "Fallback", -1);

if (!Enum.TryParse<FontType>(fontTypeStr, true, out var fontType))
throw new Exception($"Invalid font type for {section}: {fontTypeStr}");

fontConfigs.Add(new FontConfig(fontPath, size, fontType, fallback));
if (!Enum.TryParse<TTFFontLoader>(fontLoaderStr, true, out var fontLoader))
throw new Exception($"Invalid font loader for {section}: {fontLoaderStr}");

fontConfigs.Add(new FontConfig(fontPath, size, fontType, fontLoader, fallback));
}

for (int i = 0; i < fontCount; i++)
Expand Down Expand Up @@ -299,7 +305,17 @@ private static void CreateFontIndexesFromIni(IniFile iniFile, ContentManager con
/// </summary>
private static void CreateTrueTypeFontIndex(int fontIndex, FontConfig config, List<FontConfig> allConfigs, string searchPath)
{
FontSystem fontSystem = CreateFontSystem();
IFontLoader fontLoader = config.FontLoader switch
{
// Note: FontStashSharp automatically uses StbTrueType with parameters specified in FontSystemSettings, so we return null here to use the default loader.
TTFFontLoader.StbTrueType => null,
TTFFontLoader.FreeType => new FreeTypeFontLoader(FreeTypeRenderMode.Normal),
TTFFontLoader.FreeTypeMono => new FreeTypeFontLoader(FreeTypeRenderMode.Mono),
TTFFontLoader.Forme => throw new NotImplementedException("Forme font loader is not implemented yet"),
_ => throw new Exception($"Unsupported font loader for Font{fontIndex}: {config.FontLoader}")
};

FontSystem fontSystem = CreateFontSystem(fontLoader);
fontSystem.DefaultCharacter = '?';
fontSystems.Add(fontSystem);

Expand Down Expand Up @@ -395,13 +411,15 @@ private readonly struct FontConfig
public string Path { get; }
public int Size { get; }
public FontType FontType { get; }
public TTFFontLoader FontLoader { get; }
public int Fallback { get; }

public FontConfig(string path, int size, FontType fontType, int fallback)
public FontConfig(string path, int size, FontType fontType, TTFFontLoader fontLoader, int fallback)
{
Path = path;
Size = size;
FontType = fontType;
FontLoader = fontLoader;
Fallback = fallback;
}
}
Expand Down
22 changes: 22 additions & 0 deletions FontManagement/FreeTypeFontLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using FontStashSharp.Interfaces;

namespace Rampastring.XNAUI.FontManagement;

/// <summary>
/// FreeType-based font loader that correctly handles embedded bitmap fonts in TTF files.
/// Replaces FontStashSharp.Rasterizers.FreeType which has broken struct layouts on Windows x64
/// (FreeTypeSharp maps C 'long' to IntPtr instead of int, causing struct field misalignment).
/// </summary>
public sealed class FreeTypeFontLoader : IFontLoader
{
public FreeTypeRenderMode RenderMode { get; } = FreeTypeRenderMode.Normal;

public FreeTypeFontLoader() { }

public FreeTypeFontLoader(FreeTypeRenderMode renderMode)
{
RenderMode = renderMode;
}

public IFontSource Load(byte[] data) => new FreeTypeFontSource(data) { RenderMode = RenderMode };
}
Loading