tecs.gfx.fonts
Font identity, glyph metrics, and the atlas that carries glyphs to the backend.
A game names a font once and every text that selects it shares the atlas that font fills. newTTF opens the file and reads its metrics; a glyph is rasterized and packed the first time something asks for it, and the atlas crosses to the backend as one ordinary tecs.gfx.images upload.
const font, reason = tecs.gfx.fonts.newTTF({source = "assets/fonts/JetBrainsMono-ExtraBold.ttf"})
assert(font, reason)
const glyph = tecs.gfx.fonts.glyph(font, 0x41)
const image = tecs.gfx.fonts.imageOf(font)Every metric this module returns is in em units, so multiplying one by a text's em size gives world units. That keeps one atlas usable at every displayed size and keeps the layout in tecs.gfx.text free of the raster's own resolution.
The default "sdf" raster stores a signed distance field, which scales without regenerating glyphs. Choose a size near the largest ordinary on-screen size. An "alpha" raster stores direct coverage instead and draws correctly through a plain textured quad; a distance field needs a shader that recovers coverage by smoothstepping around the half-way value, so a backend without one draws an "sdf" font as a soft gradient rather than as text.
Residency is observed rather than waited on, exactly as an image's is. imageOf queues whatever the atlas gained since the last call and answers with the id; tecs.gfx.images.stateOf on that id then reports where the upload stands.
Module contents
Constructors
| Constructor | Description |
|---|---|
newTTF | Reads a font's bytes and its metrics. |
Types
| Type | Kind | Description |
|---|---|---|
Font | record | A loaded font and the atlas its glyphs live in. |
Glyph | record | One glyph's place in the atlas and its box relative to the pen. |
Raster | type | Selects how a font's glyph images are stored. |
TTFOptions | type | The options newTTF accepts. |
Functions
| Function | Kind | Description |
|---|---|---|
advanceOf | function | Returns one codepoint's horizontal advance in em units. |
atlasNameOf | function | The name the atlas is uploaded under. |
atlasSize | function | Returns the atlas dimensions in texels. |
epoch | function | Returns how many times any atlas has been laid out again. |
find | function | Returns the font one name resolves to. |
glyph | function | Returns the glyph one codepoint selects, making it resident on first use. |
glyphIndexOf | function | Returns the glyph index one codepoint selects. |
hasGlyph | function | Reports whether the font carries a glyph for one codepoint. |
imageOf | function | Returns the atlas image id, queuing whatever the atlas gained. |
kerningOf | function | Returns the kerning between two codepoints in em units. |
release | function | Drops the atlas from the backend. |
residentGlyphs | function | Returns how many glyphs the atlas holds. |
Values
| Value | Kind | Description |
|---|---|---|
DEFAULT_SIZE | variable | The point size a font rasterizes at when the caller names none. |
SDF_SPREAD | variable | The texels a distance field reaches on each side of an outline. |
Constructors#
newTTFconstructor#
function newTTF(options: TTFOptions): Font?, string?Reads a font's bytes and its metrics.
Loading a name a font already holds replaces what that name resolves to. A Text already carrying the earlier font keeps it, so a reload changes what new text picks up rather than what old text draws.
Arguments
| Name | Type | Description |
|---|---|---|
options | TTFOptions | the source path or |
Returns
| Type | Description |
|---|---|
Font? | the font, or nil when the file could not be read or parsed |
string? | why the font could not be loaded, when unsuccessful |
Raises
when neither
sourcenorbytesis given, when the size is not greater than zero, or when the raster is not one of its declared values
Types#
Fontrecord#
record Font
name: string
source: string
size: number
raster: Raster
ascent: number
descent: number
lineGap: number
lineHeight: number
endA loaded font and the atlas its glyphs live in.
Immutable in everything a game reads. The atlas behind it grows as glyphs are asked for, which is why imageOf rather than a stored id is what extraction reads.
Fields
source#
source: stringRead-only. Reports the path the bytes were read from, or the empty string for a font handed over as bytes.
size#
size: numberRead-only. Reports the point size glyphs are rasterized at. It is not the size text is drawn at.
raster#
raster: RasterRead-only. Reports whether the atlas holds a distance field or direct coverage.
ascent#
ascent: numberRead-only. Reports the distance from the baseline to the top of the typographic ascent, in em units.
descent#
descent: numberRead-only. Reports the distance from the baseline to the bottom of the typographic descent, in em units. It is negative in every ordinary font.
lineHeight#
lineHeight: numberRead-only. Reports the baseline-to-baseline distance in em units, which is the ascent less the descent plus the leading.
Glyphrecord#
record Glyph
index: integer
advance: number
left: number
top: number
right: number
bottom: number
u0: number
v0: number
u1: number
v1: number
width: integer
height: integer
endOne glyph's place in the atlas and its box relative to the pen.
The four plane edges are in em units with y increasing downward from the baseline, so a glyph drawn at em size s with its pen at x, y covers x + left * s to x + right * s horizontally. A glyph with no ink, which is what a space is, reports four zeroes and no atlas region.
Fields
index#
index: integerRead-only. Reports the face's glyph index, which is zero for the .notdef glyph a font draws for a character it does not carry.
top#
top: numberRead-only. Reports the top edge of the drawn box in em units, above the baseline and so usually negative.
width#
width: integerRead-only. Reports the region width in atlas texels, which is zero for a glyph with no ink.
Rastertype#
type Raster = "sdf" | "alpha"Selects how a font's glyph images are stored.
These identifiers reach a game's font configuration and are a compatibility surface.
TTFOptionstype#
type TTFOptions = {
source: string?,
bytes: string?,
name: string?,
size: number?,
raster: Raster?
}The options newTTF accepts.
Functions#
advanceOffunction#
function advanceOf(font: Font, codepoint: integer): numberReturns one codepoint's horizontal advance in em units.
Reads the horizontal metrics directly, so it costs nothing and makes no glyph resident. Measuring a string that will never be drawn goes through here rather than through glyph.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
codepoint | integer | the Unicode scalar to measure |
Returns
| Type | Description |
|---|---|
number | the advance in em units |
atlasNameOffunction#
function atlasNameOf(name: string): stringThe name the atlas is uploaded under.
A glyph entity stores this through its Sprite, and a snapshot stores a sprite's image by name, so the prefix is a compatibility surface.
Arguments
| Name | Type | Description |
|---|---|---|
name | string | the font identity |
Returns
| Type | Description |
|---|---|
string | the image name, which is stable for the life of the font |
atlasSizefunction#
function atlasSize(font: Font): integer, integerReturns the atlas dimensions in texels.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
Returns
| Type | Description |
|---|---|
integer | the width, then the height, both powers of two |
integer |
epochfunction#
function epoch(): integerReturns how many times any atlas has been laid out again.
Growing an atlas moves every region in it, so anything holding a texture coordinate read from a Glyph compares this against what it last saw and reads the regions again when the two differ.
Returns
| Type | Description |
|---|---|
integer | a count that only increases, shared by every loaded font |
findfunction#
Returns the font one name resolves to.
Arguments
| Name | Type | Description |
|---|---|---|
name | string | the font identity |
Returns
| Type | Description |
|---|---|
Font? | the font, or nil when nothing has been loaded under that name |
glyphfunction#
Returns the glyph one codepoint selects, making it resident on first use.
A codepoint the font does not carry answers with the face's .notdef glyph, which is the box a font draws for a missing character, rather than with nil. A codepoint with no ink, which is what a space is, answers with a glyph whose advance is set and whose region is empty.
The returned record is the font's own and is updated in place when the atlas grows. Read what you need from it rather than keeping it across frames.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
codepoint | integer | the Unicode scalar to draw |
Returns
| Type | Description |
|---|---|
Glyph | the glyph, whose plane box and advance are in em units |
glyphIndexOffunction#
function glyphIndexOf(font: Font, codepoint: integer): integerReturns the glyph index one codepoint selects.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
codepoint | integer | the Unicode scalar to look up |
Returns
| Type | Description |
|---|---|
integer | the face's glyph index, which is zero for a codepoint the font does not carry |
hasGlyphfunction#
function hasGlyph(font: Font, codepoint: integer): booleanReports whether the font carries a glyph for one codepoint.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
codepoint | integer | the Unicode scalar to look up |
Returns
| Type | Description |
|---|---|
boolean | whether the font maps it to anything but |
imageOffunction#
function imageOf(font: Font): integerReturns the atlas image id, queuing whatever the atlas gained.
The id is permanent, so a caller may store it. Residency is not: call this once per frame that might have added a glyph and let tecs.gfx.images.stateOf report where the upload stands.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
Returns
| Type | Description |
|---|---|
integer | the process-wide image id the atlas uploads under |
kerningOffunction#
function kerningOf(font: Font, left: integer, right: integer): numberReturns the kerning between two codepoints in em units.
Only a format-zero kern table is read. A font that carries its kerning in GPOS alone reports zero for every pair, which lays the text out on its advance widths.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
left | integer | the Unicode scalar on the left |
right | integer | the Unicode scalar on the right |
Returns
| Type | Description |
|---|---|
number | the adjustment to add after the left glyph's advance, in em units |
releasefunction#
function release(font: Font): boolean, string?Drops the atlas from the backend.
The glyphs stay packed and the id survives, so the next imageOf makes the same atlas resident again under the same id. Text drawn in between samples the backend's white fallback.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
Returns
| Type | Description |
|---|---|
boolean | whether a release was queued, which is false before the first upload |
string? | why nothing was queued, when unsuccessful |
residentGlyphsfunction#
function residentGlyphs(font: Font): integerReturns how many glyphs the atlas holds.
Counts every glyph asked for, including the inkless ones that occupy no region, because each of those cost a lookup and a metric.
Arguments
| Name | Type | Description |
|---|---|---|
font | Font | the loaded font |
Returns
| Type | Description |
|---|---|
integer | the resident glyph count |
Values#
DEFAULT_SIZEvariable#
const DEFAULT_SIZE: numberThe point size a font rasterizes at when the caller names none.
SDF_SPREADvariable#
const SDF_SPREAD: integerThe texels a distance field reaches on each side of an outline.
The same number is the padding around every glyph, because the field has to have somewhere to run before the region ends. A wider spread costs atlas room and buys a thicker outline or glow; four texels carry an ordinary antialiased edge at any size the atlas is used at.