Files
TheriapolisV3/Theriapolis.Game/CodexUI/Core/CodexFonts.cs
T
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

83 lines
4.0 KiB
C#

using FontStashSharp;
using Microsoft.Xna.Framework.Graphics;
namespace Theriapolis.Game.CodexUI.Core;
/// <summary>
/// Static font registry for CodexUI. Loaded once at game startup via
/// <see cref="LoadAll"/>; widgets read from these fields. The slots map to
/// the design's typographic ladder:
/// - DisplayLarge / Medium / Small → Cinzel-Bold (fallback: Georgia Bold) — all-caps headings
/// - SerifBody / SerifItalic → Cormorant Garamond (fallback: Georgia / Georgia Italic)
/// - MonoTag / MonoTagSmall → JetBrains Mono (fallback: Consolas)
///
/// FontStashSharp loads TTF files into a runtime atlas. We try
/// <c>Content/Fonts/</c> first (project-supplied fonts), then fall back to
/// Windows system fonts so the game runs without bundling Cinzel/Cormorant.
/// </summary>
public static class CodexFonts
{
public static SpriteFontBase DisplayLarge = null!; // ~32 px, codex header
public static SpriteFontBase DisplayMedium = null!; // ~22 px, h2
public static SpriteFontBase DisplaySmall = null!; // ~16 px, h3
public static SpriteFontBase SerifBody = null!; // ~16 px, body text
public static SpriteFontBase SerifItalic = null!; // ~14 px, italic body / trait names
public static SpriteFontBase MonoTag = null!; // ~10 px, eyebrow + tag text
public static SpriteFontBase MonoTagSmall = null!; // ~9 px, sub-tags
private static FontSystem? _serif;
private static FontSystem? _italic;
private static FontSystem? _mono;
/// <summary>
/// Load every font slot. Throws on failure — fonts are required for the
/// codex screen to render anything legible.
/// </summary>
public static void LoadAll(GraphicsDevice gd, string contentRoot)
{
_serif = LoadFontSystem(contentRoot, new[] { "Fonts/Cinzel-Bold.ttf", "Fonts/CormorantGaramond-Bold.ttf" },
new[] { @"C:\Windows\Fonts\georgiab.ttf", @"C:\Windows\Fonts\timesbd.ttf" });
_italic = LoadFontSystem(contentRoot, new[] { "Fonts/CormorantGaramond-Italic.ttf", "Fonts/CormorantGaramond-Regular.ttf" },
new[] { @"C:\Windows\Fonts\georgiai.ttf", @"C:\Windows\Fonts\timesi.ttf", @"C:\Windows\Fonts\georgia.ttf" });
_mono = LoadFontSystem(contentRoot, new[] { "Fonts/JetBrainsMono-Medium.ttf" },
new[] { @"C:\Windows\Fonts\consola.ttf", @"C:\Windows\Fonts\consolab.ttf", @"C:\Windows\Fonts\cour.ttf" });
DisplayLarge = _serif.GetFont(32f);
DisplayMedium = _serif.GetFont(22f);
DisplaySmall = _serif.GetFont(16f);
SerifBody = _italic.GetFont(15f);
SerifItalic = _italic.GetFont(14f);
MonoTag = _mono.GetFont(11f);
MonoTagSmall = _mono.GetFont(9f);
}
private static FontSystem LoadFontSystem(string contentRoot, string[] preferred, string[] fallbacks)
{
var fs = new FontSystem();
// Try project-supplied fonts first (Content/Fonts/*).
foreach (var rel in preferred)
{
string path = System.IO.Path.Combine(contentRoot, rel);
if (System.IO.File.Exists(path))
{
fs.AddFont(System.IO.File.ReadAllBytes(path));
return fs;
}
}
// Fall back to a system font — guaranteed available on the target
// platforms (Windows Georgia/Times/Consolas; future: macOS / Linux
// would need their own fallback list).
foreach (var path in fallbacks)
{
if (System.IO.File.Exists(path))
{
fs.AddFont(System.IO.File.ReadAllBytes(path));
return fs;
}
}
throw new System.IO.FileNotFoundException(
"CodexFonts: no font found in either project Content/Fonts/ or system fallback locations. " +
$"Preferred: {string.Join(", ", preferred)}; fallbacks: {string.Join(", ", fallbacks)}");
}
}