Skip to content

Commit 0e36597

Browse files
authored
Prep work for KernSmith runtime support (#2438)
1 parent fb30b23 commit 0e36597

7 files changed

Lines changed: 145 additions & 135 deletions

File tree

Gum/Wireframe/CustomSetPropertyOnRenderable.cs

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ public class CustomSetPropertyOnRenderable
5858
public static IRuntimeFontService? FontService { get; set; }
5959
#endif
6060

61+
/// <summary>
62+
/// Optional in-memory font creator. When set, font generation bypasses disk entirely —
63+
/// the creator produces a <see cref="BitmapFont"/> directly from raw pixel data and
64+
/// .fnt metadata. If null or if creation fails, falls back to the disk-based
65+
/// <see cref="FontService"/> path.
66+
/// </summary>
67+
public static IInMemoryFontCreator? InMemoryFontCreator { get; set; }
68+
6169
public static event Action<string>? PropertyAssignmentError;
6270

6371
/// <summary>
@@ -1086,23 +1094,9 @@ BitmapFont GetAndCreateFontIfNecessary()
10861094
// no cache, does it need to be created?
10871095
if (font == null)
10881096
{
1089-
// this could be a custom font, so let's see if it exists:
1090-
1091-
string fileName = String.Empty;
1092-
if (ToolsUtilities.FileManager.FileExists(fontFileName))
1093-
{
1094-
fileName = fontFileName;
1095-
}
1096-
#if !FRB
1097-
else if (FontService != null)
1098-
{
1099-
fileName = FontService.AbsoluteFontCacheFolder +
1100-
ToolsUtilities.FileManager.RemovePath(fontFileName);
1101-
}
1102-
1103-
if (FontService != null && !ToolsUtilities.FileManager.FileExists(fileName))
1097+
// Try in-memory font creation first (no disk I/O)
1098+
if (InMemoryFontCreator != null)
11041099
{
1105-
// user could have typed anything in there, so who knows if this will succeed. Therefore, try/catch:
11061100
try
11071101
{
11081102
BmfcSave bmfcSave = new BmfcSave();
@@ -1112,35 +1106,83 @@ BitmapFont GetAndCreateFontIfNecessary()
11121106
bmfcSave.UseSmoothing = useFontSmoothingStack.Peek();
11131107
bmfcSave.IsItalic = isItalicStack.Peek();
11141108
bmfcSave.IsBold = isBoldStack.Peek();
1115-
#if !FRB
1116-
// BBCode inline font creation: when BBCode tags like [FontSize=24] reference a font
1117-
// that doesn't exist, create it on demand. This parallels the font creation in
1118-
// UpdateToFontValues — both use FontService.CreateFontIfNecessary with the same pattern.
1109+
11191110
var gumProject = ObjectFinder.Self.GumProjectSave;
11201111
bmfcSave.Ranges = gumProject?.FontRanges ?? BmfcSave.DefaultRanges;
11211112
bmfcSave.SpacingHorizontal = gumProject?.FontSpacingHorizontal ?? 1;
11221113
bmfcSave.SpacingVertical = gumProject?.FontSpacingVertical ?? 1;
1123-
#endif
11241114

1125-
FontService.CreateFontIfNecessary(bmfcSave);
1115+
font = InMemoryFontCreator.TryCreateFont(bmfcSave);
1116+
if (font != null)
1117+
{
1118+
global::RenderingLibrary.Content.LoaderManager.Self.AddDisposable(fontFileName, font);
1119+
}
11261120
}
11271121
catch
11281122
{
1129-
// do nothing?
1123+
// Fall through to disk-based path
11301124
}
11311125
}
1132-
#endif
11331126

1134-
if (ToolsUtilities.FileManager.FileExists(fileName))
1135-
{
1136-
font = new BitmapFont(fileName);
1137-
}
1138-
else
1127+
// Fall back to disk-based font creation
1128+
if (font == null)
11391129
{
1140-
// This can happen when closing tags are encountered at the end of a font. If no font exists, we can just go to the default
1141-
font = Text.DefaultBitmapFont;
1130+
// this could be a custom font, so let's see if it exists:
1131+
1132+
string fileName = String.Empty;
1133+
if (ToolsUtilities.FileManager.FileExists(fontFileName))
1134+
{
1135+
fileName = fontFileName;
1136+
}
1137+
#if !FRB
1138+
else if (FontService != null)
1139+
{
1140+
fileName = FontService.AbsoluteFontCacheFolder +
1141+
ToolsUtilities.FileManager.RemovePath(fontFileName);
1142+
}
1143+
1144+
if (FontService != null && !ToolsUtilities.FileManager.FileExists(fileName))
1145+
{
1146+
// user could have typed anything in there, so who knows if this will succeed. Therefore, try/catch:
1147+
try
1148+
{
1149+
BmfcSave bmfcSave = new BmfcSave();
1150+
bmfcSave.FontSize = fontSizeStack.Peek();
1151+
bmfcSave.FontName = fontNameStack.Peek();
1152+
bmfcSave.OutlineThickness = outlineThicknessStack.Peek();
1153+
bmfcSave.UseSmoothing = useFontSmoothingStack.Peek();
1154+
bmfcSave.IsItalic = isItalicStack.Peek();
1155+
bmfcSave.IsBold = isBoldStack.Peek();
1156+
#if !FRB
1157+
// BBCode inline font creation: when BBCode tags like [FontSize=24] reference a font
1158+
// that doesn't exist, create it on demand. This parallels the font creation in
1159+
// UpdateToFontValues — both use FontService.CreateFontIfNecessary with the same pattern.
1160+
var gumProject = ObjectFinder.Self.GumProjectSave;
1161+
bmfcSave.Ranges = gumProject?.FontRanges ?? BmfcSave.DefaultRanges;
1162+
bmfcSave.SpacingHorizontal = gumProject?.FontSpacingHorizontal ?? 1;
1163+
bmfcSave.SpacingVertical = gumProject?.FontSpacingVertical ?? 1;
1164+
#endif
1165+
1166+
FontService.CreateFontIfNecessary(bmfcSave);
1167+
}
1168+
catch
1169+
{
1170+
// do nothing?
1171+
}
1172+
}
1173+
#endif
1174+
1175+
if (ToolsUtilities.FileManager.FileExists(fileName))
1176+
{
1177+
font = new BitmapFont(fileName);
1178+
}
1179+
else
1180+
{
1181+
// This can happen when closing tags are encountered at the end of a font. If no font exists, we can just go to the default
1182+
font = Text.DefaultBitmapFont;
1183+
}
1184+
global::RenderingLibrary.Content.LoaderManager.Self.AddDisposable(fontFileName, font);
11421185
}
1143-
global::RenderingLibrary.Content.LoaderManager.Self.AddDisposable(fontFileName, font);
11441186
}
11451187

11461188
return font;
@@ -1303,15 +1345,40 @@ public static void UpdateToFontValues(IText text, GraphicalUiElement graphicalUi
13031345
font = GetFontDisposable(fontName);
13041346
}
13051347

1348+
// Try in-memory font creation first (no disk I/O)
1349+
if (font == null && InMemoryFontCreator != null)
1350+
{
1351+
try
1352+
{
1353+
BmfcSave bmfcSave = new BmfcSave();
1354+
bmfcSave.FontSize = textRuntime.FontSize;
1355+
bmfcSave.FontName = textRuntime.Font;
1356+
bmfcSave.OutlineThickness = textRuntime.OutlineThickness;
1357+
bmfcSave.UseSmoothing = textRuntime.UseFontSmoothing;
1358+
bmfcSave.IsItalic = textRuntime.IsItalic;
1359+
bmfcSave.IsBold = textRuntime.IsBold;
1360+
1361+
var gumProject = ObjectFinder.Self.GumProjectSave;
1362+
bmfcSave.Ranges = gumProject?.FontRanges ?? BmfcSave.DefaultRanges;
1363+
bmfcSave.SpacingHorizontal = gumProject?.FontSpacingHorizontal ?? 1;
1364+
bmfcSave.SpacingVertical = gumProject?.FontSpacingVertical ?? 1;
1365+
1366+
font = InMemoryFontCreator.TryCreateFont(bmfcSave);
1367+
if (font != null)
1368+
{
1369+
loaderManager.AddDisposable(fullFileName, font);
1370+
}
1371+
}
1372+
catch
1373+
{
1374+
// Fall through to disk-based path
1375+
}
1376+
}
1377+
13061378
#if !FRB
1307-
// On-demand font creation: if no cached or embedded font was found, ask the FontService
1308-
// to generate the .fnt/.png files. This is the primary font creation path for both the
1309-
// Gum tool and game runtimes. The Gum tool wires FontService to its FontManager (which
1310-
// delegates to HeadlessFontGenerationService / bmfont.exe). Game runtimes can provide
1311-
// their own IRuntimeFontService implementation.
1312-
//
1313-
// Bulk font generation (e.g., recreating the entire font cache on project load) is handled
1314-
// separately by IFontManager.CreateAllMissingFontFiles, which is tool-only.
1379+
// Disk-based font creation: ask FontService to generate .fnt/.png files,
1380+
// then load from disk. This is the fallback when no InMemoryFontCreator
1381+
// is available or when in-memory creation fails.
13151382
if (font == null && FontService != null)
13161383
{
13171384
try

MonoGameGum/FnaGum/FnaGum.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
<Compile Include="..\..\RenderingLibrary\Graphics\AtlasedTexture.cs" Link="Renderables\AtlasedTexture.cs" />
5555
<Compile Include="..\..\RenderingLibrary\Graphics\BitmapCharacterInfo.cs" Link="Renderables\Fonts\BitmapCharacterInfo.cs" />
5656
<Compile Include="..\..\RenderingLibrary\Graphics\Fonts\BitmapFont.cs" Link="Renderables\Fonts\BitmapFont.cs" />
57+
<Compile Include="..\..\RenderingLibrary\Graphics\Fonts\IInMemoryFontCreator.cs" Link="Renderables\Fonts\IInMemoryFontCreator.cs" />
5758
<Compile Include="..\..\RenderingLibrary\Graphics\IAnimation.cs" Link="Renderables\IAnimation.cs" />
5859
<Compile Include="..\..\RenderingLibrary\Graphics\ImageData.cs" Link="RenderingLibrary\ImageData.cs" />
5960
<Compile Include="..\..\RenderingLibrary\Graphics\NineSlice.cs" Link="Renderables\NineSlice.cs" />

MonoGameGum/KniGum/KniGum.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<Compile Include="..\..\RenderingLibrary\Graphics\AtlasedTexture.cs" Link="Renderables\AtlasedTexture.cs" />
6161
<Compile Include="..\..\RenderingLibrary\Graphics\BitmapCharacterInfo.cs" Link="Renderables\Fonts\BitmapCharacterInfo.cs" />
6262
<Compile Include="..\..\RenderingLibrary\Graphics\Fonts\BitmapFont.cs" Link="Renderables\Fonts\BitmapFont.cs" />
63+
<Compile Include="..\..\RenderingLibrary\Graphics\Fonts\IInMemoryFontCreator.cs" Link="Renderables\Fonts\IInMemoryFontCreator.cs" />
6364
<Compile Include="..\..\RenderingLibrary\Graphics\IAnimation.cs" Link="Renderables\IAnimation.cs" />
6465
<Compile Include="..\..\RenderingLibrary\Graphics\ImageData.cs" Link="RenderingLibrary\ImageData.cs" />
6566
<Compile Include="..\..\RenderingLibrary\Graphics\NineSlice.cs" Link="Renderables\NineSlice.cs" />

MonoGameGum/MonoGameGum.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<Compile Include="..\RenderingLibrary\Graphics\AtlasedTexture.cs" Link="Renderables\AtlasedTexture.cs" />
108108
<Compile Include="..\RenderingLibrary\Graphics\BitmapCharacterInfo.cs" Link="Renderables\Fonts\BitmapCharacterInfo.cs" />
109109
<Compile Include="..\RenderingLibrary\Graphics\Fonts\BitmapFont.cs" Link="Renderables\Fonts\BitmapFont.cs" />
110+
<Compile Include="..\RenderingLibrary\Graphics\Fonts\IInMemoryFontCreator.cs" Link="Renderables\Fonts\IInMemoryFontCreator.cs" />
110111
<Compile Include="..\RenderingLibrary\Graphics\IAnimation.cs" Link="Renderables\IAnimation.cs" />
111112
<Compile Include="..\RenderingLibrary\Graphics\ImageData.cs" Link="RenderingLibrary\ImageData.cs" />
112113
<Compile Include="..\RenderingLibrary\Graphics\NineSlice.cs" Link="Renderables\NineSlice.cs" />

RenderingLibrary/Graphics/Fonts/BitmapFont.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,26 @@ public BitmapFont(Texture2D fontTextureGraphic, string fontPattern)
235235
SetFontPattern();
236236
}
237237

238+
/// <summary>
239+
/// Creates a <see cref="BitmapFont"/> entirely in memory from pre-built texture pages
240+
/// and .fnt content. No disk I/O is performed. This is intended for runtime font
241+
/// generation where a library like KernSmith produces textures and metadata directly.
242+
/// </summary>
243+
public BitmapFont(Texture2D[] textures, string fntContent)
244+
{
245+
mTextures = textures;
246+
247+
mTextureNames = new string[textures.Length];
248+
for (int i = 0; i < textures.Length; i++)
249+
{
250+
mTextureNames[i] = textures[i]?.Name;
251+
}
252+
253+
_ParsedFontFile = new ParsedFontFile(fntContent);
254+
255+
SetFontPattern();
256+
}
257+
238258

239259

240260
public void AssignCharacterTextureCoordinates(int asciiNumber, out float tVTop, out float tVBottom,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace RenderingLibrary.Graphics.Fonts;
2+
3+
/// <summary>
4+
/// Creates <see cref="BitmapFont"/> instances entirely in memory, without writing or reading
5+
/// font files from disk. Platform-specific implementations produce texture objects from
6+
/// raw pixel data and construct the <see cref="BitmapFont"/> directly.
7+
/// </summary>
8+
public interface IInMemoryFontCreator
9+
{
10+
/// <summary>
11+
/// Attempts to create a <see cref="BitmapFont"/> from the given font description.
12+
/// Returns <c>null</c> if creation fails or is not supported for the given parameters.
13+
/// </summary>
14+
BitmapFont? TryCreateFont(BmfcSave bmfcSave);
15+
}

RenderingLibrary/RenderingLibrary.csproj

Lines changed: 0 additions & 95 deletions
This file was deleted.

0 commit comments

Comments
 (0)