# `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.
```nupp
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.
## Constructors
### `newTTF` _constructor_
```nupp
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 `bytes`, the identity, the raster point size, and the raster mode; `name` defaults to `source`, `size` to `DEFAULT_SIZE`, and `raster` to `"sdf"` |
#### 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 `source` nor `bytes` is given, when the size is not greater than zero, or when the raster is not one of its declared values
## Types
### `Font` _record_
```nupp
record Font
name: string
source: string
size: number
raster: Raster
ascent: number
descent: number
lineGap: number
lineHeight: number
end
```
A 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
##### `name`
```nupp
name: string
```
Read-only. Reports the identity a snapshot stores and `find` resolves.
##### `source`
```nupp
source: string
```
Read-only. Reports the path the bytes were read from, or the empty
string for a font handed over as bytes.
##### `size`
```nupp
size: number
```
Read-only. Reports the point size glyphs are rasterized at. It is not
the size text is drawn at.
##### `raster`
```nupp
raster: Raster
```
Read-only. Reports whether the atlas holds a distance field or direct
coverage.
##### `ascent`
```nupp
ascent: number
```
Read-only. Reports the distance from the baseline to the top of the
typographic ascent, in em units.
##### `descent`
```nupp
descent: number
```
Read-only. Reports the distance from the baseline to the bottom of the
typographic descent, in em units. It is negative in every ordinary font.
##### `lineGap`
```nupp
lineGap: number
```
Read-only. Reports the extra leading between two lines, in em units.
##### `lineHeight`
```nupp
lineHeight: number
```
Read-only. Reports the baseline-to-baseline distance in em units, which
is the ascent less the descent plus the leading.
### `Glyph` _record_
```nupp
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
end
```
One 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`
```nupp
index: integer
```
Read-only. Reports the face's glyph index, which is zero for the
`.notdef` glyph a font draws for a character it does not carry.
##### `advance`
```nupp
advance: number
```
Read-only. Reports the horizontal advance in em units.
##### `left`
```nupp
left: number
```
Read-only. Reports the left edge of the drawn box in em units.
##### `top`
```nupp
top: number
```
Read-only. Reports the top edge of the drawn box in em units, above the
baseline and so usually negative.
##### `right`
```nupp
right: number
```
Read-only. Reports the right edge of the drawn box in em units.
##### `bottom`
```nupp
bottom: number
```
Read-only. Reports the bottom edge of the drawn box in em units.
##### `u0`
```nupp
u0: number
```
Read-only. Reports the left edge of the atlas region, from zero to one.
##### `v0`
```nupp
v0: number
```
Read-only. Reports the top edge of the atlas region, from zero to one.
##### `u1`
```nupp
u1: number
```
Read-only. Reports the right edge of the atlas region, from zero to one.
##### `v1`
```nupp
v1: number
```
Read-only. Reports the bottom edge of the atlas region, from zero to one.
##### `width`
```nupp
width: integer
```
Read-only. Reports the region width in atlas texels, which is zero for
a glyph with no ink.
##### `height`
```nupp
height: integer
```
Read-only. Reports the region height in atlas texels.
### `Raster` _type_
```nupp
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.
### `TTFOptions` _type_
```nupp
type TTFOptions = {
source: string?,
bytes: string?,
name: string?,
size: number?,
raster: Raster?
}
```
The options `newTTF` accepts.
## Functions
### `advanceOf` _function_
```nupp
function advanceOf(font: Font, codepoint: integer): number
```
Returns 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 |
### `atlasNameOf` _function_
```nupp
function atlasNameOf(name: string): string
```
The 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 |
### `atlasSize` _function_
```nupp
function atlasSize(font: Font): integer, integer
```
Returns 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` | |
### `epoch` _function_
```nupp
function epoch(): integer
```
Returns 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 |
### `find` _function_
```nupp
function find(name: string): Font?
```
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 |
### `glyph` _function_
```nupp
function glyph(font: Font, codepoint: integer): Glyph
```
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 |
### `glyphIndexOf` _function_
```nupp
function glyphIndexOf(font: Font, codepoint: integer): integer
```
Returns 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 |
### `hasGlyph` _function_
```nupp
function hasGlyph(font: Font, codepoint: integer): boolean
```
Reports 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 `.notdef` |
### `imageOf` _function_
```nupp
function imageOf(font: Font): integer
```
Returns 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 |
### `kerningOf` _function_
```nupp
function kerningOf(font: Font, left: integer, right: integer): number
```
Returns 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 |
### `release` _function_
```nupp
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 |
### `residentGlyphs` _function_
```nupp
function residentGlyphs(font: Font): integer
```
Returns 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_SIZE` _variable_
```nupp
const DEFAULT_SIZE: number
```
The point size a font rasterizes at when the caller names none.
### `SDF_SPREAD` _variable_
```nupp
const SDF_SPREAD: integer
```
The 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.