tiny-atlas
v1.2.1
Published
Index glyphs of a label into a single SDF texture for rendering.
Downloads
7
Readme
tiny-atlas
Utility to produce data for drawing labels using signed distance fields in a webgl context. Internally uses tiny-sdf
and potpack
to create label props that glyphs index into a single texture. Made to be paired with regl
.
See example/atlas.cjs
for a complete example with regl
based rendering. example/atlas-instances.cjs
is the same example but done with instancing, properties are all attached to a single object.
API Interface Example
const { Atlas } = require('tiny-atlas')
// The arguments object is sent directly to `tiny-sdf`
const atlas = new Atlas({
fontSize: 48,
buffer: 3,
radius: 8,
cutoff: 0.25,
fontFamily: 'Arial',
})
// Make as many labels as you want. `text` is string that is processed
// any other keys are passed to the final object in the `glyphs`
const labels = [{ text: 'coquí' }]
// `texture` is passed into `regl.texture` to produce a `sampler2D`
// compatible object.
// `glyphs` are in the shape described below, they hold all the properties
// to render with a reference to the `texture`.
const { texture, glyphs } = atlas.prepare({ labels })
const glyphsTexture = regl.texture(texture)
API
Atlas
is the exported class. Its constructor takes an object passed along to tiny-sdf
. This class is used to manage label's, which are in turn made up of glyphs.
atlas.prepare({ labels: [{ text }] })
method accepts an array of labels. The objects in this array only required a string value at the text
key, any other keys will be spread across the glyphs
object that corresponds to that particular label. The texture
return value can be passed directly into regl.texture
. The baselineOffsets
key is a two element array with the first value being the max top distance from the baseline across all labels, and the second value being the max bottom distance from the baseline.
If drawing labels using instancing is desired, a truthy value at the instances
key of the options object of atlas.prepare
can be used. Additional label props can be spread in the return value by setting the instances
value to an object with the shape { create, onGlyph}
. create
& onGlyph
are expected to be functions. create
gets passed an object with keys { props, size }
where props
is the return value that we are spreading across, and size is the total number of glyphs that are being accounted for with the output props
. This allows for determining the type and length of array that will be returned. onGlyph
is a function that is called with keys { props, labelIndex, charIndex, glyphIndex }
. Again, props
is the return value. labelIndex
is the index of the current label that is being processed from the labels
array. charIndex
is the character index within that label. glyphIndex
is the position in the array with the same length as the size
that was used in the create
function.
Instanced and object preperation will return a labels
key that is the original label data that includes a glyphIndicies
array. For instanced preperation the indicies will map into the individual arrays available on the glyphs
arrays. For example, getting the labelDim
for a label would look like:
const prepared = atlas.prepare({ labels, instances: true })
for (let i = 0; i < prepared.labels.length; i++) {
const label = prepare.labels[i]
const { glyphIndicies } = label
const gi = glyphIndicies[0]
const labelDim = [
prepared.glyphs.labelDim[gi * 2 + 0],
prepared.glyphs.labelDim[gi * 2 + 1],
]
}
Where as object preperation (non-instanced) data will be accessible indexing into glyphs
, as follows:
const prepared = atlas.prepare({ labels })
for (let i = 0; i < prepared.labels.length; i++) {
const label = prepare.labels[i]
const { glyphIndicies } = label
const gi = glyphIndicies[0]
const { labelDim } = prepared.glyphs[gi]
}
If requesting instanced props, there will be an additional label
key on the return value whose value will be an array of the original input labels, with the additional glyphIndicies
array. glyphIndicies
carries the integer index values that can be used to pull data from the various props
arrays for the any input label.
atlas.prepare({
labels : [{ text, ... }],
}) => {
texture: {
data,
width,
height,
format,
type,
mag,
min,
},
glyphs: [{
// 0-1 value of the position of the glyph in the label
glyphInLabelStringIndex: Float,
// accumulated glyph widths preceding this glyph in the label
glyphInLabelStringOffset: vec2<Float>,
// glyph offset in the texture
glyphTexOffset: vec2<Float>,
// glyph dimensions in the texture
glyphTexDim: vec2<Float>,
// glyph's dimensions in SDF space
// (tinySDFResult.{glyphWidth,glyphHeight})
glyphRasterDim: vec2<Float>,
// glyphs rasterized max distance from the baseline in SDF space
glyphRasterTop: Float,
// dimensions of the label in SDF space
labelDim: vec2<Float>,
}],
// offsets from the baseline, describing the max distance above
// and below the baseline: [top, bottom]
baselineOffset: vec2<Float>,
labels: {
// includes all original label props
...label,
// glyphIndicies are the indicies of glyphs of this label
glyphIndicies: [Integer]
}
}
atlas.prepare({
labels : [{ text, ... }],
instances? : {
init?: ({ props, size }) => void,
onGlyph?: ({ props, labelIndex, charIndex, glyphIndex }) => void,
},
}) => {
texture: {
data,
width,
height,
format,
type,
mag,
min,
},
glyphs: {
// 0-1 value of the position of the glyph in the label
// length = size * 1
glyphInLabelStringIndex: Float32Array,
// accumulated glyph widths preceding this glyph in the label
// length = size * 2
glyphInLabelStringOffset: Float32Array,
// glyph offset in the texture
// length = size * 2
glyphTexOffset: Float32Array,
// glyph dimensions in the texture
// length = size * 2
glyphTexDim: Float32Array,
// glyph's dimensions in SDF space
// (tinySDFResult.{glyphWidth,glyphHeight})
// length = size * 2
glyphRasterDim: Float32Array,
// glyphs rasterized max distance from the baseline in SDF space
// length = size * 1
glyphRasterTop: Float32Array,
// dimensions of the label in SDF space
// length = size * 2
labelDim: Float32Array,
},
// offsets from the baseline, describing the max distance above
// and below the baseline: [top, bottom]
baselineOffset: vec2<Float>,
labels: {
// includes all original label props
...label,
// glyphIndicies are the indicies of glyphs of this label
glyphIndicies: [Integer]
}
}
atlas.clear({ cache: boolean })
method accepts an object that can include a cache
key with a boolean value. If this is set to true, the tiny-sdf
results that are stored internally will be cleared. If cache
is falsy, only the label
level data will be removed, but glyph
level data will be maintained.