Awesome
gl-sprite-text
A solution for bitmap and SDF text rendering in stack.gl. This uses gl-sprite-batch and fontpath under the hood.
The BMFont spec is used for glyph and font data. You also need to pass an array of gl-texture2d items matching the paths
specified by the font file. (Multi-page fonts are supported.)
The font
object can also include an images
array (ndarray/HTMLImage), which will get piped into gl-texture2d
. You can use bmfont-lato for testing; it includes Lato Regular in a few sizes and the base64-inlined images
ndarray.
var createText = require('gl-sprite-text')
var Lato = require('bmfont-lato')
//build the text
text = createText(gl, {
font: Lato,
text: 'Hello, World!'
})
//optionally word-wrap it to a specific width
text.layout(500)
function render() {
//draws the text with lower-left origin
text.draw(shader)
}
See demo/simple.js for an example. After npm install
, you can run it with:
npm run demo-simple
Tools
After you've exported the BMFont with your favourite tool, you can run it through bmfont2json to produce valid output:
# if you haven't already, install the tool globally
npm install bmfont2json -g
# then you can use it like so..
bmfont2json Lato32.fnt > Lato32.json
Signed Distance Fields
Bitmap fonts are great for fixed-size text, but if you need large fonts, or fonts that scale smoothly (i.e. if it's being 3D transformed), it's better to use alpha testing to avoid aliasing artifacts. To generate SDF font atlases, you can use Hiero and LibGDX. Then, you need to render it with a signed distance field shader. See the demo/sdf.js example:
npm run demo-sdf
As you can see from the demo, you can also achieve drop shadows, outlines, glows and other effects with independent colors.
Static Text
By default, the text is pushed to dynamic buffers every frame. This allows it to animate (e.g. changing position, start/end indices, text content), and also ensures that underlines and multi-page textures will work.
Basic static text is supported with the cache()
method. Static text only supports a single texture page, and no underlines.
var text = createText(gl, {
font: myFont,
textures: textures,
text: str,
//hint to buffers that they will be static
dynamic: false
})
//cache the current text state
text.cache(x, y, start, end)
function render() {
text.draw(shader)
}
Usage
Inherits from fontpath-simple-renderer
so the API should work, but this module may diverge from it in the future. Here is the current public API:
text = createText(opts)
The following options can be provided:
font
the bitmap font object, requiredtextures
an array of gl textures to matchfont.paths
. If this is not specified, it will look for animages
array in thefont
object, which can be ndarrays, HTMLImage objects, or anything that gets piped tocreateTexture
.text
the string of text we will be rendering, default to empty stringalign
a string 'left', 'center', 'right', default leftunderline
boolean, whether to underline the text, default falseunderlinePosition
the position of underline in pixels, defaults to a fraction of font sizeunderlineThickness
the underline thickness in pixels, defaults to a fraction of font sizelineHeight
a line height in pixels, otherwise defaults to an automatic gapletterSpacing
the letter spacing in pixels, default 0wrapMode
can benormal
,pre
, ornowrap
, defaultnormal
wrapWidth
an initial number in pixels which is passed tolayout()
after the other options have been set. Otherwise, defaults to no layout (a single line, no breaks)capacity
an initial capacity to use for gl-sprite-batchdynamic
whether the WebGL buffers should useDYNAMIC_DRAW
, default true
All options except for font
, wrapMode
and wrapWidth
are fields which be changed at runtime, before calling draw()
.
Note: Changing the text
currently calls clearLayout()
. You will need to call layout()
again.
text.draw(shader[, x, y, start, end])
Draws the text with the given shader, at the specified pixel position (lower-left origin).
The start
(inclusive) and end
(exclusive) indices will draw the laid out glyphs within those bounds. This can be used to style and colour different pieces of text. If not specified, they will default to 0 and the text length, respectively.
If text is cached, the x, y, start, end
parameters are ignored.
text.layout([wrapWidth])
Word-wraps the text with the current wrap mode to the optional given width. You can change the wrap mode like so:
text.wordwrap.mode = 'pre'
text.layout(250)
If no width is specified, it will only break on explicit newline characters \n
.
This creates some new objects in memory, so you may not want to do it every frame.
text.clearLayout()
Clears the current word-wrapping. This leads to a single line of text, no line-breaks.
text.getBounds()
Returns an object with the computed bounds of the text box:
{ x, y, width height }
This can be used to draw the text at an upper-left origin instead.
text.cache([x, y, start, end])
Caches the current text parameters into a static buffer. Underlines are not supported; and this only works with one texture page (e.g. all glyphs in a single sprite sheet).
The parameters replace those in draw()
. When cached, draw()
will ignore the x, y, start, end
parameters.
text.uncache()
Disables caching, allowing it to be animated dynamically again.
text.dispose([textures])
If no batch
was provided during the constructor, this will dispose of the default (internally created) batch.
Specifying true for textures
(default false) will also dispose of the texture array associated with this text object.
License
MIT, see LICENSE.md for details.