font_zh.ttf becomes font_cn.ttf (cn, tw, jp, en, kr) and gains siblings built the same way: font_tw (tw, jp, cn, en, kr), font_en (en, jp, tw, cn, kr), font_kr (kr, jp, en, tw, cn). font.ttf (jp first) is unchanged and stays the fallback. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
4.5 KiB
Graphics/font.ttf — how it is made, and how the cabinet actually uses its fonts
What the cabinet ships
The cabinet has no vector font. Data\x64\font\ holds pre-rasterised BC7 glyph atlases,
one family per language and one atlas per size/weight bucket, each with an XML sidecar
(codepoint → rect; no bearings, no kerning):
| language | buckets on disk | distinct codepoints | face (as drawn in the atlas) |
|---|---|---|---|
jp |
30, 32_B, 32_DB, 32_EB, 64 |
7 532 | 30/32: rounded gothic in three weights; 64: brush/勘亭流-style display face |
tw |
30, 32, 64 |
17 678 | same split |
cn |
30, 32, 64 |
7 608 | same split (the 64 face is a heavier brush) |
kr |
30, 32, 64 |
8 407 | same split |
en |
30, 32, 64 |
299 | same split |
(The JP 39.06 dump has the same files minus cn_*; the CN 05 dump adds cn_*. The
jp/tw/kr/en XMLs are byte-identical between the two.)
How a text record picks its atlas
- Language comes from the cabinet language setting: wordlist rows are looked up in the
language's column and rendered from that language's atlas family. Rows flagged
fontType 0(untranslated) always render fromjp. - Size/weight bucket is authored per text record in the
.nulm(DefineFontentry symbol"0".."4"→64,30,32_EB,32_B,32_DB). It is not language dependent. Foren/tw/kr/cnthe three weighted32_*buckets are registered onto the plain32atlas, so a record that asks for32_EBon acncabinet is drawn fromcn_32. - The only fallback is
jp_64when the language itself is unknown; a codepoint missing from the chosen atlas is simply not drawn. Of the 692 text records in the shipped movies, 449 use the 30/32 (rounded gothic) buckets and 168 use the 64 (brush) bucket.
YataiDON draws every string through a single .ttf, so one face has to serve all of it.
This skin's font.ttf is built from the _64 (brush) atlases, which is the face used for
headings, song titles and most of the large text.
Building font.ttf
tools/font/build_font.py merges the five _64 atlases into one TrueType font:
- Decode each
<lang>_64.nutexbto a DDS (BC7,nutexb_dump -o) next to its XML. - For each language in priority order
jp, tw, cn, kr, en, every codepoint that does not yet have an inked glyph takes its bitmap from that atlas (blank placeholder cells are skipped so a later atlas can supply the character). - Each bitmap is upscaled 4× (bicubic), thresholded at alpha ≥ 128, traced with potrace
and converted to quadratic outlines (
cu2qu). - Metrics:
unitsPerEm 1024,scale = 1024 / fontPointof the atlas (16 units per pixel forjp_64),advance = cell width × scale, baseline = the atlas's median bottom ink row of its Han/Hangul glyphs, so the five families sit on one baseline with equal Han height.ascender 880 / descender −144, as the earlier build.
pip install potracer fonttools pillow numpy
python build_font.py <dir with *_64.dds + *_64.xml> font.ttf --order jp,tw,cn,kr,en
Result (version 3.000): 22 382 glyphs — 7 499 from jp, 10 107 from tw, 1 956 from cn,
2 737 from kr, 82 from en. Coverage of each atlas's repertoire: jp 7521/7532,
tw 17651/17678, cn 7589/7608, kr 8070/8407, en 268/295 (the remainder are blank cells in
the atlases themselves). Version 2.000 had no cn or kr glyphs, which is why Simplified
Chinese and Korean text showed ?.
Per-language fonts (Graphics/font_<family>.ttf)
The engine loads Graphics/font_<language code>.ttf if present, else Graphics/font_<cabinet family>.ttf
(zh → cn, ko → kr, ja → jp), else font.ttf. The settings screen reloads the skin, so switching
language switches the font. This mirrors the cabinet, which draws everything from the language's own
atlas family and only lacks what that family does not have.
| file | atlas priority | used for |
|---|---|---|
font.ttf |
jp, tw, cn, kr, en |
Japanese, and any language without its own file (unchanged 3.000) |
font_cn.ttf |
cn, tw, jp, en, kr |
Simplified Chinese (zh) |
font_tw.ttf |
tw, jp, cn, en, kr |
Traditional Chinese (zh_tw / tw) |
font_en.ttf |
en, jp, tw, cn, kr |
English |
font_kr.ttf |
kr, jp, en, tw, cn |
Korean (ko) |
python build_font.py <dir> font_cn.ttf --order cn,tw,jp,en,kr
python build_font.py <dir> font_tw.ttf --order tw,jp,cn,en,kr
python build_font.py <dir> font_en.ttf --order en,jp,tw,cn,kr
python build_font.py <dir> font_kr.ttf --order kr,jp,en,tw,cn