What ttir Does
ttir runs on the host machine. It reads one or more font
files, imports the font tables it needs, selects a subset of
Unicode codepoints, builds alpha atlas data, validates the
result, and writes a C++ header that can be included by FALL
applications.
The runtime type declarations live in src/a_font.hpp. The
parser, validator, subset planner, atlas builder, and generated
header writer live in tools/ttir.cpp.
This page does not describe text rendering. Rendering is
being moved toward level g, which is intended to become
the cross-platform graphics abstraction for all FALL
targets, including embedded targets.
Committed Fonts
The repository already has Noto font inputs under assets/:
assets/NotoSans-Regular.ttf
assets/NotoSansJP-Regular.ttf
assets/NotoSansKR-Regular.ttf
assets/NotoSansSC-Regular.ttf
assets/NotoSansTC-Regular.ttf
assets/NotoSansHK-Regular.ttf
The generated headers currently used by the tree are:
assets/noto-regular.hpp
assets/noto.hpp
Build ttir
Build only the host-side font compiler:
make ttir
The Makefile configures the Linux build directory and builds the
ttir target. The resulting binary is:
build-relbare/ttir
Print the current command help:
./build-relbare/ttir --help
Print version information:
./build-relbare/ttir --version
Inspect A Font
If no -o output path is passed, ttir does not generate a
header. It prints information about the input font instead.
./build-relbare/ttir assets/NotoSans-Regular.ttf
The info output reports the inferred face, cmap codepoint count, glyph count, non-empty glyph count, kerning availability, and curated script coverage.
Generate A Small Header
Generate a regular Noto header with ASCII, Latin Extended, and Cyrillic coverage:
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o assets/noto-regular.hpp \
--namespace assets \
--symbol noto_regular \
--scripts ascii,latinext,cyrillic \
--pixel-height 20 \
--supersample 1
The same command is already wrapped by the Makefile:
make noto-regular
Use make noto-regular when you do not want to remember the
ttir arguments for the lightweight single-font asset.
Generate The Noto Collection
Generate the larger collection from all committed Noto fonts:
./build-relbare/ttir \
assets/NotoSans-Regular.ttf \
assets/NotoSansJP-Regular.ttf \
assets/NotoSansSC-Regular.ttf \
assets/NotoSansTC-Regular.ttf \
assets/NotoSansHK-Regular.ttf \
assets/NotoSansKR-Regular.ttf \
-o assets/noto.hpp \
--namespace assets \
--symbol noto \
--scripts ascii,latinext,greek,cyrillic,jp,kr,sc,tc,hk \
--pixel-height 8 \
--supersample 1
The same collection command is wrapped by:
make noto
Multi-font generation requires --scripts. That prevents
accidental full CJK atlas generation.
Help Commands
ttir --help lists four usage forms:
ttir <input.ttf|input.otf> [more.ttf|more.otf ...]inspects fonts and prints information.ttir <input.ttf|input.otf> [more.ttf|more.otf ...] -o <output.hpp> [options]generates a header.ttir --helpprints command help.ttir --versionprints the tool version.
Options
-o <path> selects the generated header path. Without it,
ttir is in information mode.
./build-relbare/ttir assets/NotoSans-Regular.ttf -o /tmp/noto_ascii.hpp --ascii
--namespace <name> selects the C++ namespace for generated
symbols. The default is assets.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/ui_font.hpp \
--namespace ui_assets \
--symbol ui \
--ascii
--symbol <prefix> selects the generated symbol prefix. For
example, --symbol ui produces names such as ui_glyphs,
ui_cmap, ui_atlases, and ui_asset.
--face <JP|KR|SC|TC|HK> assigns a CJK face tag to a
generated single-font asset. The regular face is used when no
CJK face is selected.
./build-relbare/ttir assets/NotoSansJP-Regular.ttf \
-o /tmp/noto_jp.hpp \
--symbol noto_jp \
--face JP \
--scripts jp
--scripts <list> selects named script coverage. The current
names are ascii, latinext, greek,
cyrillic, jp, kr,
sc, tc, and hk.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/noto_text.hpp \
--scripts ascii,latinext,cyrillic
--literal <utf8> builds a subset closed over the exact UTF-8
text you pass. It is useful for tiny firmware labels.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/boot_label.hpp \
--symbol boot_label \
--literal "Boot OK"
--ascii is shorthand for printable ASCII, U+0020 through
U+007E.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/noto_ascii.hpp \
--ascii
--full emits the chosen cmap. It is the default when no subset
option is set. Be careful with large CJK fonts because this can
produce very large headers.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/noto_regular_full.hpp \
--full
--pixel-height <n> selects the alpha atlas pixel height.
Valid values are 1 through 512. The default is 32.
--padding <n> selects atlas glyph padding in pixels. Valid
values are 0 through 64. The default is 1.
--supersample <n> selects alpha raster supersampling. Valid
values are 1, 2, 4, and 8. The default is 4.
./build-relbare/ttir assets/NotoSans-Regular.ttf \
-o /tmp/noto_24px.hpp \
--ascii \
--pixel-height 24 \
--padding 1 \
--supersample 2
Generated Header Shape
A generated header starts with #pragma once, includes
a_font.hpp, and opens the selected namespace.
#pragma once
#include "a_font.hpp"
namespace assets {
// generated symbols live here
}
The header then defines static data tables. The exact symbol
names use the selected --symbol prefix.
*_glyphsstores onea::font::glyph_metricentry per baked glyph.*_cmapmaps Unicode codepoints to baked glyph indexes.*_kerningstores sorted kerning pairs when the source provides supported pairs.*_atlas_glyphsmaps baked glyphs to rectangles inside the atlas.*_atlas_pixelsstores alpha8 atlas bytes.*_atlasesdescribes atlas dimensions, stride, pixel height, rectangles, and pixel data.
After the tables, the header defines names and a manifest:
static constexpr char noto_regular_family_name[] = "noto_regular";
static constexpr char noto_regular_style_name[] = "regular";
static constexpr a::font::asset_manifest noto_regular_manifest{
a::font::ttir_schema_version,
/* generator_version */ 1u,
/* hashes */ ...,
a::view<const char>{noto_regular_family_name},
a::view<const char>{noto_regular_style_name},
a::font::face_kind::regular
};
The main public value for a single generated font is the asset
view. For --symbol noto_regular, the symbol is
noto_regular_asset.
static constexpr a::font::asset_view noto_regular_asset{
a::font::metrics{...},
a::font::cmap_storage::sorted_array,
a::view<const a::font::glyph_metric>{noto_regular_glyphs, ...},
a::view<const a::font::cmap_entry>{noto_regular_cmap, ...},
a::view<const a::font::kern_entry>{noto_regular_kerning, ...},
a::view<const a::font::atlas_view>{noto_regular_atlases, ...},
¬o_regular_manifest
};
The generated header validates itself at compile time:
static_assert(a::font::validate_asset(noto_regular_asset) == a::font::error::ok,
"generated font asset failed validation");
Generated Bundle Metadata
The header also emits tag types and an a::bundle specification
that describes the generated static data as deterministic
storage.
struct noto_regular_glyphs_tag final {};
struct noto_regular_cmap_tag final {};
struct noto_regular_atlas_pixels_tag final {};
struct noto_regular_asset_tag final {};
struct noto_regular_bundle_spec final {
using permanent = a::resources<
a::array<a::font::glyph_metric, ..., noto_regular_glyphs_tag>,
a::array<a::font::cmap_entry, ..., noto_regular_cmap_tag>,
a::buffer<noto_regular_atlas_pixels_tag, ...>,
a::object<a::font::asset_view, noto_regular_asset_tag>
>;
};
using noto_regular_bundle = a::bundle<noto_regular_bundle_spec>;
The generated size constants let firmware code inspect the amount of read-only data and the equivalent bundle footprint.
static constexpr a::usize noto_regular_rodata_bytes = ...;
static constexpr a::usize noto_regular_bundle_bytes = noto_regular_bundle::size_bytes();
static constexpr a::usize noto_regular_bundle_alignment = noto_regular_bundle::alignment_bytes();
Collections
When multiple font files are passed, the generated header emits
one asset per face and then a collection view. make noto
currently produces faces for regular, JP, SC, TC, HK, and KR.
static constexpr a::font::font_collection_face noto_faces[] = {
a::font::font_collection_face{a::font::face_kind::regular, ¬o_regular_asset},
a::font::font_collection_face{a::font::face_kind::jp, ¬o_jp_asset},
a::font::font_collection_face{a::font::face_kind::sc, ¬o_sc_asset},
a::font::font_collection_face{a::font::face_kind::tc, ¬o_tc_asset},
a::font::font_collection_face{a::font::face_kind::hk, ¬o_hk_asset},
a::font::font_collection_face{a::font::face_kind::kr, ¬o_kr_asset}
};
static constexpr a::font::font_collection_view noto_collection{
a::view<const a::font::font_collection_face>{noto_faces, 6u}
};
Collections are also validated at compile time:
static_assert(a::font::validate_collection(noto_collection) == a::font::error::ok,
"generated font collection failed validation");