Skip to content

Commit 4d84335

Browse files
committed
Updated documentation for runtime fonts / text layout
1 parent 55f0f9f commit 4d84335

File tree

2 files changed

+67
-42
lines changed

2 files changed

+67
-42
lines changed

docs/en/en.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,10 +1121,6 @@
11211121
"path": "/manuals/font",
11221122
"name": "Font"
11231123
},
1124-
{
1125-
"path": "/extension-fontgen",
1126-
"name": "Runtime TTF Font"
1127-
},
11281124
{
11291125
"path": "/manuals/resource",
11301126
"name": "Resource management"

docs/en/manuals/font.md

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ Fonts added to your project are automatically converted into a texture format th
1616
- Bitmap
1717
- Distance field
1818

19+
## Offline or Runtime fonts
20+
21+
By default, the conversion to rasterized glyph images happens at build time (offline). This has the drawback that each font needs to rasterize all possible glyphs in the build stage, producing potentially very large textures that consume memory and also increase the bundle size.
22+
23+
By using "runtime fonts", the .ttf fonts will be bundled as-is, and the rasterization will happen on-demand at runtime. This minimizes both runtime memory usage and the bundle size.
24+
25+
## Text layout support (e.g. Right-to-left)
26+
27+
The runtime fonts also have the benefit of supporting full text layout, e.g. right-to-left.
28+
We currently use the libraries [HarfBuzz](https://github.com/harfbuzz/harfbuzz), [SheenBidi](https://github.com/Tehreer/SheenBidi), [libunibreak](https://github.com/adah1972/libunibreak) and [SkriBidi](https://github.com/memononen/Skribidi).
29+
30+
See [Enabling Runtime Fonts](/manuals/font#enabling-runtime-fonts)
31+
32+
## Font collection
33+
34+
The `.fontc` file format is also known as a font collection. In offline mode, only one font is associated with it.
35+
When using runtime fonts, you can associate more than one font file (.ttf) with the font collection.
36+
37+
This allows for using the a font collection when rendering multiple texts in different languages, while also keeping the memory foot print low.
38+
E.g. loading a collection with the japanese font, then associate that font with the current main font, followed by unloading the japanese font collection.
39+
1940
## Creating a font
2041

2142
To create a font for use in Defold, create a new Font file by selecting <kbd>File ▸ New...</kbd> from the menu, then select <kbd>Font</kbd>. You can also <kbd>right click</kbd> a location in the *Assets* browser and select <kbd>New... ▸ Font</kbd>.
@@ -81,6 +102,8 @@ Shadow support is enabled by the built-in font material shaders and handles both
81102
*Characters*
82103
: Which characters to include in the font. By default this field include the ASCII printable characters (character codes 32-126). You can add or remove characters from this field to include more or less characters in the font..
83104

105+
For runtime fonts, this text acts as a cache prewarming with the correct glyphs. This happens during load time. See `font.prewarm_text()`.
106+
84107
::: sidenote
85108
The ASCII printable characters are:
86109
space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ \` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
@@ -163,23 +186,29 @@ For example - to generate a gradient in a shader fragment, simply write:
163186

164187
For more information about shader uniforms, see the [Shader manual](/manuals/shader).
165188

166-
## Runtime generation
189+
## Enabling Runtime Fonts
167190

168191
It is possible to use runtime generation for SDF type fonts, when using TrueType (.ttf) fonts.
169192
This approach can greatly reduce the download size and runtime memory consumption of a Defold game.
170-
The small downside is a very small delay for each glyph generated at runtime.
193+
The small downside is the asynchronous nature of generating each glyph.
194+
195+
* Enable the feature by setting `font.runtime_generation` in game.project.
171196

172-
Enable the feature by setting `font.runtime_generation` in game.project.
197+
* Add an [App Manifest](/manuals/app-manifest) and enable the `Use full text layout system` option.
198+
This builds a custom engine that has this feature enabled.
173199

174200
::: sidenote
175201
This feature is currently experimental, but with the intention to be used as the default workflow in the future.
176202
:::
177203

178204
::: important
179-
This setting affects all .ttf fonts in the project.
205+
The `font.runtime_generation` setting affects all .ttf fonts in the project.
180206
:::
181207

182-
### Prewarming glyph cache
208+
209+
### Font Scripting
210+
211+
#### Prewarming glyph cache
183212

184213
In order to make the runtime fonts easier to use, they support prewarming of the glyph cache.
185214
This means the font will generate the glyphs listed in *Characters* in the font.
@@ -188,53 +217,53 @@ This means the font will generate the glyphs listed in *Characters* in the font.
188217
If `All Chars` is selected, there will be no prewarming as it defeats the purpose of not having to generate all glyphs at the same time.
189218
:::
190219

191-
### Font Scripting
220+
If the `Characters` field of the `.fontc` file is set, this is used as a text, to figure out which glyphs needs to be updated in the glyph cache.
221+
222+
It is also possible to manually update the glyph cache by calling `font.prewarm_text(font_collection, text, callback)`. It provides a callback to let you know when all the missing glyphs have been added to the glyph cache, and it's safe to present the text on screen.
223+
224+
### Adding/removing fonts to a font collection
192225

193-
For runtime fonts, it's possible to add or removed sub fonts.
226+
For runtime fonts, it's possible to add or remove fonts (.ttf) to a font collection.
194227
This is useful when a large font has been split up into multiple files for different character sets (e.g. CJK)
195228

196229
::: important
197-
Adding a subfont doesn't automatically load or render all the glyphs.
230+
Adding a font to a font collection doesn't automatically load or render all the glyphs.
198231
:::
199232

200233
```lua
201-
-- Add the range A-Z to the .fontc
202-
local font_hash = hash("/assets/fonts/roboto.fontc")
203-
local ttf_hash = hash("/assets/fonts/Roboto/Roboto-Bold.ttf")
204-
local codepoint_min = 0x00000041 -- A
205-
local codepoint_max = 0x0000005A -- Z
206-
font.add_source(font_hash, ttf_hash, codepoint_min, codepoint_max)
234+
-- get the main font
235+
local font_collection = go.get("#label", "font")
236+
font.add_font(font_collection, self.language_ttf_hash)
237+
238+
-- get the selected language font
239+
local font_collection_language = go.get("localization_japanese#label", "font")
240+
local font_info = font.get_info(font_collection_language)
241+
self.language_ttf_hash = font_info.fonts[1].path_hash -- get the first font (the one specified in the editor)
242+
font.add_font(self.font_collection, self.language_ttf_hash) -- increases the reference count to the font
207243
```
208244

209245
```lua
210-
-- Remove the associated ttf resource
211-
local font_hash = hash("/assets/fonts/roboto.fontc")
212-
local ttf_hash = hash("/assets/fonts/Roboto/Roboto-Bold.ttf")
213-
font.remove_source(font_hash, ttf_hash)
246+
-- remove the font reference
247+
font.add_font(self.font_collection, self.language_ttf_hash)
214248
```
215249

216-
To load the glyphs to the font, you will need to call the `font.add_glyphs()`.
217-
It is an asynchronous operation, and once it's done, it's safe to progress to show any message containing the glyphs.
250+
### Prewarming glyphs
218251

219-
```lua
220-
local function add_glyph_callback(self, id, result, errmsg)
221-
if not result then
222-
print("Request " .. id .." finished with error:", errmsg)
223-
else
224-
msg.post(some_url, "show_dialog")
225-
end
226-
end
227-
228-
-- Load glyphs into the font
229-
local font_hash = hash("/assets/fonts/roboto.fontc")
230-
local glyphs = "Some text to be shown!" -- for optimal performance, make this a list of unique glyphs
231-
local request_id = font.add_glyphs(font_hash, ttf_hash, add_glyph_callback)
232-
```
252+
To properly show a text with a runtime font, the glyphs need to be resolved. The `font.prewarm_text()` does this for you.
253+
It is an asynchronous operation, and once it's done and you get the callback, it's safe to progress to show any message containing the glyphs.
254+
255+
::: important
256+
If the glyph cache gets full, the oldest glyph in the cache will be evicted.
257+
:::
233258

234-
And, once the characters aren't needed anymore, you can discard that memory:
235259
```lua
236-
-- Remove the associated ttf resource
237-
local font_hash = hash("/assets/fonts/roboto.fontc")
238-
font.remove_glyphs(font_hash, "All the characters in the set")
260+
font.prewarm_text(self.font_collection, info.text, function (self, request_id, result, err)
261+
if result then
262+
print("PREWARMING OK!")
263+
label.set_text(self.label, info.text)
264+
else
265+
print("Error prewarming text:", err)
266+
end
267+
end)
239268
```
240269

0 commit comments

Comments
 (0)