Magnum::Text::AbstractGlyphCache class new in 2019.10

Base for glyph caches.

A GPU-API-agnostic base for glyph caches, supporting multiple fonts and both 2D and 2D array textures. See the GlyphCache and DistanceFieldGlyphCache subclasses for concrete OpenGL implementations. The base class provides a common interface for adding fonts, glyph properties, uploading glyph data and retrieving glyph properties back.

Filling the glyph cache

A glyph cache is constructed through the concrete GPU-API-specific subclasses, namely the GlyphCache and DistanceFieldGlyphCache classes mentioned above. Depending on the use case and platform capabilities it's also possible to create glyph caches with 2D texture arrays, for example when large alphabets are used or when the cache may get filled on-demand with many additional glyphs.

A glyph cache is created in an appropriate PixelFormat and a size. PixelFormat::R8Unorm is the usual choice, PixelFormat::RGBA8Unorm is useful for emoji fonts or when arbitrary icon data are put into the cache.

Text::GlyphCacheGL cache{PixelFormat::R8Unorm, Vector2i{512}};

The rest of this section describes low level usage of the glyph cache filling APIs, which are useful mainly when implementing an AbstractFont itself or when adding arbitrary other image data to the cache. When using the glyph cache with an existing AbstractFont instance, often the high level use involves just calling AbstractFont::fillGlyphCache(), which does all of the following on its own.

Let's say we want to fill the glyph cache with a custom set of images that don't necessarily need to be a font per se. Assuming the input images are stored in a simple array, and the goal is to put them all together into the cache and reference them later simply by their array indices.

Containers::ArrayView<const ImageView2D> images = ;

Adding a font

As the cache supports multiple fonts, each glyph added to it needs to be associated with a particular font. The addFont() function takes an upper bound on glyph IDs used in the font and optionally an identifier to associate it with a concrete AbstractFont instance to look it up later with findFont(). It returns a font ID that's subsequently used for adding and querying glyphs. In our case the glyph IDs are simply indices into the array, so the upper bound is the array size:

UnsignedInt fontId = cache.addFont(images.size());

Reserving space in the glyph atlas

Each glyph cache contains an instance of TextureTools::AtlasLandfill packer, which is used to layout glyph data into the cache texture as well as maintain the remaining free space when more glyphs get added. In this case we'll ask it for best offsets corresponding to the input image sizes, and as we created the cache as 2D, we can get 2D offsets back. To keep the example simple, rotations are disabled as well, see the atlas packer class docs for information about how to deal with them and achieve potentially better packing efficiency.

Containers::Array<Vector2i> offsets{NoInit, images.size()};

cache.atlas().clearFlags(
    TextureTools::AtlasLandfillFlag::RotatePortrait|
    TextureTools::AtlasLandfillFlag::RotateLandscape);
CORRADE_INTERNAL_ASSERT(cache.atlas().add(
    stridedArrayView(images).slice(&ImageView2D::size),
    offsets));

In case the layouting fails, triggering the assertion, the cache size was picked too small or there was already enough glyphs added that the new ones didn't fit. The solution is then to either increase the cache size, turn the cache into an array, or create a second cache for the new data. Depending on the input sizes it's also possible to achieve a better packing efficiency by toggling various TextureTools::AtlasLandfillFlag values — you can for example create temporary instances aside, attempt packing with them, and then for filling the glyph cache itself pick the set of flags that resulted in the smallest TextureTools::AtlasLandfill::filledSize().

Adding glyphs

With the offsets array filled, everything is ready for adding images into the cache with addGlyph() and copying their data to respective locations in the cache image(). Together with input image sizes, the offsets are used to form Range2Di instances. What is left at zeros in this case is the third glyph offset argument, which describes how the glyph image is positioned relative to the text layouting cursor (used for example for letters j or q that reach below the baseline).

/* The glyph cache is just 2D, so copying to the first slice */
Containers::StridedArrayView3D<char> dst = cache.image().pixels()[0];
Range2Di updated;
for(UnsignedInt i = 0; i != images.size(); ++i) {
    Range2Di rectangle = Range2Di::fromSize(offsets[i], images[i].size());
    cache.addGlyph(fontId, i, {}, rectangle);

    /* Copy assuming all input images have the same pixel format */
    Containers::StridedArrayView3D<const char> src = images[i].pixels();
    Utility::copy(src, dst.sliceSize({
        std::size_t(offsets[i].y()),
        std::size_t(offsets[i].x()),
        0}, src.size()));

    /* Maintain a range that was updated in the glyph cache */
    updated = Math::join(updated, rectangle);
}

/* Reflect the image data update to the actual GPU-side texture */
cache.flushImage(updated);

Important is to call flushImage() at the end, which makes the glyph cache update its actual GPU-side texture based on what area of the image was updated. In case of DistanceFieldGlyphCache for example it also triggers distance field generation for given area.

If the images put into the cache are meant to be used with general meshes, the TextureTools::atlasTextureCoordinateTransformation() function can be used to create an appropriate texture coordinate transformation matrix. See its documentation for an example of calculating and applying the matrix to either the mesh directly or to a material / shader.

Incremental population

As long as the cache size allows, it's possible to add more fonts with additional glyphs. It's also possible to call addGlyph() for any font that was added previously, as long as the added glyph ID is within corresponding fontGlyphCount() bounds and given glyph ID wasn't added yet. That allows for example a use case where the glyph cache is initially empty and glyphs are rasterized to it only as needed by actually rendered text, which is especially useful with large alphabets or when the set of used fonts is large.

However, note that packing the atlas with all glyphs from all fonts just once will always result in a more optimal layout of the glyph data than adding the glyphs incrementally.

Setting a custom invalid glyph

By default, to denote an invalid glyph, i.e. a glyph that isn't present in the cache, a zero-area rectangle is used. This can be overriden with setInvalidGlyph(). Its usage is similar to addGlyph(), in particular you may want to reserve its space together with other glyphs to achieve best packing.

Additionally, glyph ID 0 in fonts is usually reserved for invalid font-specific glyphs as well. The cache-global invalid glyph can thus be either a special one or you can make it alias some other font-specific invalid glyph, by calling setInvalidGlyph() with the same arguments as addGlyph() for a font-specific glyph ID 0.

Querying glyph properties and glyph data

A glyph cache can be queried for ID of a particular font with findFont(), passing the AbstractFont pointer to it. If no font with such pointer was added, the function returns Containers::NullOpt. Then, for a particular font ID a font-specific glyph ID can be queried with glyphId(). If no such glyph was added yet, the function returns 0, i.e. the invalid glyph. The glyph() function then directly returns data for given glyph, or the invalid glyph data in case the glyph wasn't found.

Containers::Pointer<Text::AbstractFont> font = ;
Text::AbstractGlyphCache& cache = ;

Containers::ArrayView<const UnsignedInt> fontGlyphIds = ;

Containers::Optional<UnsignedInt> fontId = cache.findFont(*font);

for(std::size_t i = 0; i != fontGlyphIds.size(); ++i) {
    Containers::Triple<Vector2i, Int, Range2Di> glyph =
        cache.glyph(*fontId, fontGlyphIds[i]);
    
}

As text rendering is potentially happening very often, batch glyphIdsInto(), glyphOffsets(), glyphLayers() and glyphRectangles() APIs are provided as well to trim down the amount of function calls and redundant lookups:

Containers::Array<UnsignedInt> glyphIds{NoInit, fontGlyphIds.size()};
cache.glyphIdsInto(*fontId, fontGlyphIds, glyphIds);

Containers::StridedArrayView1D<const Vector2i> offsets = cache.glyphOffsets();
Containers::StridedArrayView1D<const Range2Di> rects = cache.glyphRectangles();
for(std::size_t i = 0; i != fontGlyphIds.size(); ++i) {
    Vector2i offset = offsets[glyphIds[i]];
    Range2Di rectangle = rects[glyphIds[i]];
    
}

For invalid glyphs it's the caller choice to either use the invalid glyph as-is (as done above), leading to blank spaces in the text, or remember the font-specific glyph IDs that resolved to 0 with glyphId(), rasterize them to the cache in the next round, and then update the rendered text again.

Glyph padding

Fonts commonly shape the glyphs to sub-pixel positions, the GPU rasterizer then rounds the actual quads to nearest pixels, which then can lead to neighboring pixels to leak into the rendered glyph or, conversely, the rendered glyph having an edge cut. Because of that, by default the glyphs are padded with one pixel on each side, which should prevent such artifacts even if rendering the glyphs 2x supersampled.

If you have a pixel-perfect font that gets always shaped to whole pixel positions, you can set it back to zero in the constructor. Or for example if you can ensure that at least lines get placed on whole pixel positions and the line advance is whole pixels as well, you can se it to zero in one dimension at least, assuming neither TextureTools::AtlasLandfillFlag::RotatePortrait nor RotateLandscape is enabled in atlas().

On the other hand, if you're rendering more than 2x supersampled or for example using the cache for generating a distance field, you may want to increase the padding even further.

Subclassing

A subclass needs to implement the doFeatures() and doSetImage() functions. If the subclass does additional processing of the glyph cache image, it should advertise that with GlyphCacheFeature::ImageProcessing and implement doSetProcessedImage() as well. If it's desirable and possible to download the processed image as well, it should advertise GlyphCacheFeature::ProcessedImageDownload and implement doProcessedImage().

The public flushImage() function already does checking for rectangle bounds so it's not needed to do it again inside doSetImage(), similarly the bounds checking is done for doSetProcessedImage().

Derived classes

class GlyphCacheGL new in Git master
OpenGL glyph cache.

Constructors, destructors, conversion operators

AbstractGlyphCache(PixelFormat format, const Vector3i& size, const Vector2i& padding = Vector2i{1}) explicit new in Git master
Construct a 2D array glyph cache.
AbstractGlyphCache(PixelFormat format, const Vector2i& size, const Vector2i& padding = Vector2i{1}) explicit new in Git master
Construct a 2D glyph cache.
AbstractGlyphCache(PixelFormat format, const Vector3i& size, PixelFormat processedFormat, const Vector2i& processedSize, const Vector2i& padding = Vector2i{1}) explicit new in Git master
Construct a 2D array glyph cache with a specific processed format and size.
AbstractGlyphCache(PixelFormat format, const Vector2i& size, PixelFormat processedFormat, const Vector2i& processedSize, const Vector2i& padding = Vector2i{1}) explicit new in Git master
Construct a 2D glyph cache with a specific processed format and size.
AbstractGlyphCache(const Vector2i& size, const Vector2i& padding = Vector2i{1}) deprecated in Git master explicit
Construct a 2D glyph cache.
AbstractGlyphCache(NoCreateT) explicit noexcept new in Git master
Construct without creating the internal state.
AbstractGlyphCache(const AbstractGlyphCache&) deleted
Copying is not allowed.
AbstractGlyphCache(AbstractGlyphCache&&) noexcept new in Git master
Move constructor.

Public functions

auto operator=(const AbstractGlyphCache&) -> AbstractGlyphCache& deleted
Copying is not allowed.
auto operator=(AbstractGlyphCache&&) -> AbstractGlyphCache& noexcept new in Git master
Move assignment.
auto features() const -> GlyphCacheFeatures
Features supported by this glyph cache implementation.
auto format() const -> PixelFormat new in Git master
Glyph cache format.
auto processedFormat() const -> PixelFormat new in Git master
Processed glyph cache format.
auto size() const -> Vector3i new in Git master
Glyph cache size.
auto processedSize() const -> Vector3i new in Git master
Processed glyph cache size.
auto textureSize() const -> Vector2i deprecated in Git master
2D glyph cache texture size
auto padding() const -> Vector2i
Glyph padding.
auto fontCount() const -> UnsignedInt new in Git master
Count of fonts in the cache.
auto glyphCount() const -> UnsignedInt
Count of all glyphs added to the cache.
auto atlas() -> TextureTools::AtlasLandfill& new in Git master
Atlas packer instance.
auto atlas() const -> const TextureTools::AtlasLandfill& new in Git master
void setInvalidGlyph(const Vector2i& offset, Int layer, const Range2Di& rectangle) new in Git master
Set a cache-global invalid glyph.
void setInvalidGlyph(const Vector2i& offset, const Range2Di& rectangle) new in Git master
Set a cache-global invalid glyph in a 2D glyph cache.
auto addFont(UnsignedInt glyphCount, const AbstractFont* pointer = nullptr) -> UnsignedInt new in Git master
Add a font.
auto fontGlyphCount(UnsignedInt fontId) const -> UnsignedInt new in Git master
Upper bound on glyph IDs present in given font.
auto fontPointer(UnsignedInt fontId) const -> const AbstractFont* new in Git master
Unique font identifier.
auto findFont(const AbstractFont& font) const -> Containers::Optional<UnsignedInt> new in Git master
Find a font ID for a font instance.
auto reserve(const std::vector<Vector2i>& sizes) -> std::vector<Range2Di> deprecated in Git master
Reserve space for given glyph sizes in the cache.
auto addGlyph(UnsignedInt fontId, UnsignedInt fontGlyphId, const Vector2i& offset, Int layer, const Range2Di& rectangle) -> UnsignedInt new in Git master
Add a glyph.
auto addGlyph(UnsignedInt fontId, UnsignedInt fontGlyphId, const Vector2i& offset, const Range2Di& rectangle) -> UnsignedInt
Add a glyph to a 2D glyph cache.
void insert(UnsignedInt glyph, const Vector2i& offset, const Range2Di& rectangle) deprecated in Git master
Add a glyph.
auto image() -> MutableImageView3D new in Git master
Glyph cache image.
auto image() const -> ImageView3D new in Git master
void flushImage(const Range3Di& range) new in Git master
Flush glyph cache image updates.
void flushImage(Int layer, const Range2Di& range) new in Git master
void flushImage(const Range2Di& range) new in Git master
Flush 2D glyph cache image updates.
void setImage(const Vector2i& offset, const ImageView2D& image) deprecated in Git master
Set cache image.
auto processedImage() -> Image3D new in Git master
Download processed cache image.
void setProcessedImage(const Vector3i& offset, const ImageView3D& image) new in Git master
Set processed cache image.
void setProcessedImage(const Vector2i& offset, const ImageView2D& image) new in Git master
Set 2D processed cache image.
auto glyphId(UnsignedInt fontId, UnsignedInt fontGlyphId) const -> UnsignedInt new in Git master
Query a cache-global glyph ID from a font-local glyph ID.
void glyphIdsInto(UnsignedInt fontId, const Containers::StridedArrayView1D<const UnsignedInt>& fontGlyphIds, const Containers::StridedArrayView1D<UnsignedInt>& glyphIds) const
Query cache-global glyph IDs from font-local glyph IDs.
void glyphIdsInto(UnsignedInt fontId, std::initializer_list<UnsignedInt> fontGlyphIds, const Containers::StridedArrayView1D<UnsignedInt>& glyphIds) const new in Git master
auto glyphOffsets() const -> Containers::StridedArrayView1D<const Vector2i> new in Git master
Positions of all glyphs in the cache relative to a point on the baseline.
auto glyphLayers() const -> Containers::StridedArrayView1D<const Int> new in Git master
Layers of all glyphs in the cache atlas.
auto glyphRectangles() const -> Containers::StridedArrayView1D<const Range2Di> new in Git master
Rectangles of all glyphs in the cache atlas.
auto glyph(UnsignedInt fontId, UnsignedInt fontGlyphId) const -> Containers::Triple<Vector2i, Int, Range2Di> new in Git master
Properties of given glyph ID in given font.
auto glyph(UnsignedInt glyphId) const -> Containers::Triple<Vector2i, Int, Range2Di> new in Git master
Properties of given cache-global glyph ID.
auto operator[](UnsignedInt glyphId) const -> std::pair<Vector2i, Range2Di> deprecated in Git master
Properties of given glyph.

Private functions

auto doFeatures() const -> GlyphCacheFeatures pure virtual
Implementation for features()
void doSetImage(const Vector3i& offset, const ImageView3D& image) virtual new in Git master
Set a 3D glyph cache image.
void doSetImage(const Vector2i& offset, const ImageView2D& image) virtual
Set a 2D glyph cache image.
auto doProcessedImage() -> Image3D virtual new in Git master
Implementation for processedImage()
void doSetProcessedImage(const Vector3i& offset, const ImageView3D& image) virtual new in Git master
Implementation for setProcessedImage()
void doSetProcessedImage(const Vector2i& offset, const ImageView2D& image) virtual new in Git master
Implementation for setProcessedImage()

Function documentation

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(PixelFormat format, const Vector3i& size, const Vector2i& padding = Vector2i{1}) explicit new in Git master

Construct a 2D array glyph cache.

Parameters
format Source image format
size Source image size in pixels
padding Padding around every glyph in pixelss. See Glyph padding for more information about the default.

The size is expected to be non-zero. If the implementation advertises GlyphCacheFeature::ImageProcessing, the processedFormat() and processedSize() is the same as format and size, use AbstractGlyphCache(PixelFormat, const Vector3i&, PixelFormat, const Vector2i&, const Vector2i&) to specify different values.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(PixelFormat format, const Vector2i& size, const Vector2i& padding = Vector2i{1}) explicit new in Git master

Construct a 2D glyph cache.

Parameters
format Source image format
size Source image size in pixels
padding Padding around every glyph in pixels. See Glyph padding for more information about the default.

Equivalent to calling AbstractGlyphCache(PixelFormat, const Vector3i&, const Vector2i&) with depth set to 1.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(PixelFormat format, const Vector3i& size, PixelFormat processedFormat, const Vector2i& processedSize, const Vector2i& padding = Vector2i{1}) explicit new in Git master

Construct a 2D array glyph cache with a specific processed format and size.

Parameters
format Source image format
size Source image size in pixels
processedFormat Processed image format
processedSize Processed image size in pixels
padding Padding around every glyph in pixelss. See Glyph padding for more information about the default.

The size and processedSize is expected to be non-zero, depth of processed size is implicitly the same as in size. If the implementation doesn't advertise GlyphCacheFeature::ImageProcessing, the processedFormat and processedSize are unused.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(PixelFormat format, const Vector2i& size, PixelFormat processedFormat, const Vector2i& processedSize, const Vector2i& padding = Vector2i{1}) explicit new in Git master

Construct a 2D glyph cache with a specific processed format and size.

Parameters
format Source image format
size Source image size in pixels
processedFormat Processed image format
processedSize Processed image size in pixels
padding Padding around every glyph in pixels. See Glyph padding for more information about the default.

Equivalent to calling AbstractGlyphCache(PixelFormat, const Vector3i&, PixelFormat, const Vector2i&, const Vector2i&) with size depth set to 1.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(const Vector2i& size, const Vector2i& padding = Vector2i{1}) explicit

Construct a 2D glyph cache.

Parameters
size Source image size in pixels
padding Padding around every glyph in pixelss. See Glyph padding for more information about the default.

Calls AbstractGlyphCache(PixelFormat, const Vector2i&, const Vector2i&) with format set to PixelFormat::R8Unorm.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(NoCreateT) explicit noexcept new in Git master

Construct without creating the internal state.

The constructed instance is equivalent to moved-from state, i.e. no APIs can be safely called on the object. Useful in cases where you will overwrite the instance later anyway. Move another object over it to make it useful.

Note that this is a low-level and a potentially dangerous API, see the documentation of NoCreate for alternatives.

Magnum::Text::AbstractGlyphCache::AbstractGlyphCache(AbstractGlyphCache&&) noexcept new in Git master

Move constructor.

Performs a destructive move, i.e. the original object isn't usable afterwards anymore.

PixelFormat Magnum::Text::AbstractGlyphCache::format() const new in Git master

Glyph cache format.

Corresponds to the format of the image view returned from image(). Note that if the implementation advertises GlyphCacheFeature::ImageProcessing, the format actually used for rendering exposed in processedFormat() may be different from the input format.

PixelFormat Magnum::Text::AbstractGlyphCache::processedFormat() const new in Git master

Processed glyph cache format.

Corresponds to the format of the image view returned from processedImage(), if GlyphCacheFeature::ImageProcessing is supported.

Vector3i Magnum::Text::AbstractGlyphCache::size() const new in Git master

Glyph cache size.

Corresponds to the size of the image view returned from image(). Note that if the implementation advertises GlyphCacheFeature::ImageProcessing, the size actually used for rendering exposed in processedSize() may be different from the input size.

Vector3i Magnum::Text::AbstractGlyphCache::processedSize() const new in Git master

Processed glyph cache size.

Corresponds to the size of the image view returned from processedImage(), if GlyphCacheFeature::ImageProcessing is supported. The depth is always the same as in size().

Vector2i Magnum::Text::AbstractGlyphCache::textureSize() const

2D glyph cache texture size

Can be called only if size() depth is 1.

Vector2i Magnum::Text::AbstractGlyphCache::padding() const

Glyph padding.

UnsignedInt Magnum::Text::AbstractGlyphCache::fontCount() const new in Git master

Count of fonts in the cache.

UnsignedInt Magnum::Text::AbstractGlyphCache::glyphCount() const

Count of all glyphs added to the cache.

The returned count is a sum across all fonts present in the cache. It's not possible to query count of added glyphs for a just single font, the fontGlyphCount() query returns an upper bound for a font-specific glyph ID.

TextureTools::AtlasLandfill& Magnum::Text::AbstractGlyphCache::atlas() new in Git master

Atlas packer instance.

Meant to be used to reserve space in the atlas texture for to-be-added glyphs. After that call addGlyph() to associate the reserved space with actual glyph properties, copy the corresponding glyph data to appropriate sub-ranges in image() and reflect the updates to the GPU-side data with flushImage().

The atlas packer is initially configured to match size() and padding() and the TextureTools::AtlasLandfillFlag::RotatePortrait and RotateLandscape flags are cleared. Everything else is left at defaults. See the class documentation for more information.

const TextureTools::AtlasLandfill& Magnum::Text::AbstractGlyphCache::atlas() const new in Git master

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void Magnum::Text::AbstractGlyphCache::setInvalidGlyph(const Vector2i& offset, Int layer, const Range2Di& rectangle) new in Git master

Set a cache-global invalid glyph.

Parameters
offset Offset of the rendered glyph relative to a point on the baseline
layer Layer in the atlas
rectangle Rectangle in the atlas without padding applied
Returns Cache-global glyph ID

Defines properties of glyph with ID 0, i.e. a cache-global invalid glyph. By default the glyph is empty.

The layer and rectangle is expected to be in bounds for size(). Usually the rectangle would match an offset + size reserved earlier in the atlas() packer, but doesn't have to. If not, it's the caller responsibility to ensure the atlas packer has up-to-date information about used area in the atlas in case incremental filling of the cache is desired.

Copy the corresponding glyph data to appropriate sub-ranges in image(). After the glyphs are copied, call flushImage() to reflect the updates to the GPU-side data.

void Magnum::Text::AbstractGlyphCache::setInvalidGlyph(const Vector2i& offset, const Range2Di& rectangle) new in Git master

Set a cache-global invalid glyph in a 2D glyph cache.

Equivalent to calling setInvalidGlyph(const Vector2i&, Int, const Range2Di&) with layer set to 0. Can be called only if size() depth is 1.

UnsignedInt Magnum::Text::AbstractGlyphCache::addFont(UnsignedInt glyphCount, const AbstractFont* pointer = nullptr) new in Git master

Add a font.

Parameters
glyphCount Upper bound on glyph IDs present in the font, or the value of AbstractFont::glyphCount()
pointer Font instance for later lookup via findFont(). Use nullptr if not associated with any particular font instance.

Returns font ID that's subsequently used to identify the font in addGlyph() and glyph(). The pointer is expected to be either nullptr or unique across all added fonts but apart from that isn't accessed in any way.

UnsignedInt Magnum::Text::AbstractGlyphCache::fontGlyphCount(UnsignedInt fontId) const new in Git master

Upper bound on glyph IDs present in given font.

Parameters
fontId Font ID returned by addFont()

The fontId is expected to be less than fontCount(). Note that this query doesn't return an actual number of glyphs added for given font but an upper bound on their IDs.

const AbstractFont* Magnum::Text::AbstractGlyphCache::fontPointer(UnsignedInt fontId) const new in Git master

Unique font identifier.

Parameters
fontId Font ID returned by addFont()

The fontId is expected to be less than fontCount(). The returned pointer isn't guaranteed to point to anything meaningful.

Containers::Optional<UnsignedInt> Magnum::Text::AbstractGlyphCache::findFont(const AbstractFont& font) const new in Git master

Find a font ID for a font instance.

Returns a font ID if a pointer matching font was used in an earlier addFont() call, Containers::NullOpt otherwise. The lookup is done with an $ \mathcal{O}(n) $ complexity with $ n $ being fontCount().

std::vector<Range2Di> Magnum::Text::AbstractGlyphCache::reserve(const std::vector<Vector2i>& sizes)

Reserve space for given glyph sizes in the cache.

Calls addFont() with glyph count set to size of the sizes vector and then TextureTools::AtlasLandfill::add() to reserve the sizes. For backwards compatibility only, can be called just once.

UnsignedInt Magnum::Text::AbstractGlyphCache::addGlyph(UnsignedInt fontId, UnsignedInt fontGlyphId, const Vector2i& offset, Int layer, const Range2Di& rectangle) new in Git master

Add a glyph.

Parameters
fontId Font ID returned by addFont()
fontGlyphId Glyph ID in given font
offset Offset of the rendered glyph relative to a point on the baseline
layer Layer in the atlas
rectangle Rectangle in the atlas without padding applied
Returns Cache-global glyph ID

The fontId is expected to be less than fontCount(), fontGlyphId then less than the glyph count passed in the addFont() call and an ID that haven't been added yet, and layer and rectangle in bounds for size(). Usually the rectangle would match an offset + size reserved earlier in the atlas() packer, but doesn't have to. If not, it's the caller responsibility to ensure the atlas packer has up-to-date information about used area in the atlas in case incremental filling of the cache is desired.

Copy the corresponding glyph data to appropriate sub-ranges in image(). After the glyphs are copied, call flushImage() to reflect the updates to the GPU-side data.

The returned glyph ID can be passed directly to glyph() to retrieve its properties, the same ID can be also queried by passing the fontId and fontGlyphId to glyphId(). Due to how the internal glyph ID mapping is implemented, there can be at most 65536 glyphs added including the implicit invalid one.

UnsignedInt Magnum::Text::AbstractGlyphCache::addGlyph(UnsignedInt fontId, UnsignedInt fontGlyphId, const Vector2i& offset, const Range2Di& rectangle)

Add a glyph to a 2D glyph cache.

Equivalent to calling addGlyph(UnsignedInt, UnsignedInt, const Vector2i&, Int, const Range2Di&) with layer set to 0. Can be called only if size() depth is 1.

void Magnum::Text::AbstractGlyphCache::insert(UnsignedInt glyph, const Vector2i& offset, const Range2Di& rectangle)

Add a glyph.

Parameters
glyph Glyph ID
offset Offset relative to point on baseline
rectangle Region in texture atlas

Calls either setInvalidGlyph() or addGlyph() with fontId set to 0. If no font is added yet, adds it, if it's added expands its glyph count as necessary. Cannot be called if there's more than one font.

MutableImageView3D Magnum::Text::AbstractGlyphCache::image() new in Git master

Glyph cache image.

The view is of format() and size(), and is initially zero-filled. For every addGlyph() copy the corresponding glyph data to appropriate sub-ranges of the image. After the glyphs are copied, call flushImage() to reflect the updates to the GPU-side data.

If the glyph cache has GlyphCacheFeature::ImageProcessing set, the actual image used for rendering is different. Use processedImage() to download it.

ImageView3D Magnum::Text::AbstractGlyphCache::image() const new in Git master

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void Magnum::Text::AbstractGlyphCache::flushImage(const Range3Di& range) new in Git master

Flush glyph cache image updates.

Call after copying glyph data to image() in order to reflect the updates to the GPU-side data. The range is expected to be in bounds for size(). You can use Math::join() on rectangles passed to addGlyph() to calculate the area that spans all glyphs that were added.

The function assumes the range excludes padding(). The image data get copied to the GPU including the padding to make sure the padded glyph area doesn't contain leftovers of uninitialized GPU memory.

void Magnum::Text::AbstractGlyphCache::flushImage(Int layer, const Range2Di& range) new in Git master

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void Magnum::Text::AbstractGlyphCache::flushImage(const Range2Di& range) new in Git master

Flush 2D glyph cache image updates.

Equivalent to calling flushImage(const Range3Di&) with depth offset 0 and depth size 1. Can be called only if size() depth is 1.

void Magnum::Text::AbstractGlyphCache::setImage(const Vector2i& offset, const ImageView2D& image)

Set cache image.

Uploads image for one or more glyphs to given offset in cache texture and calls flushImage(). The offset and ImageView::size() are expected to be in bounds for size(). Can be called only if size() depth is 1.

Image3D Magnum::Text::AbstractGlyphCache::processedImage() new in Git master

Download processed cache image.

If the glyph cache has GlyphCacheFeature::ImageProcessing set, the actual image used for rendering is different from image() and has potentially a different size or format. Expects that GlyphCacheFeature::ProcessedImageDownload is supported. For a glyph cache without GlyphCacheFeature::ImageProcessing you can get the image directly through image().

void Magnum::Text::AbstractGlyphCache::setProcessedImage(const Vector3i& offset, const ImageView3D& image) new in Git master

Set processed cache image.

Expects that the implementation supports GlyphCacheFeature::ImageProcessing. The ImageView::format() is expected to match processedFormat(), the offset and ImageView::size() are expected to be in bounds for processedSize().

void Magnum::Text::AbstractGlyphCache::setProcessedImage(const Vector2i& offset, const ImageView2D& image) new in Git master

Set 2D processed cache image.

Equivalent to calling setProcessedImage(const Vector3i&, const ImageView3D&) with offset depth 0 and image depth 1. Can be called only if size() depth (and thus also processedSize() depth) is 1.

UnsignedInt Magnum::Text::AbstractGlyphCache::glyphId(UnsignedInt fontId, UnsignedInt fontGlyphId) const new in Git master

Query a cache-global glyph ID from a font-local glyph ID.

Parameters
fontId Font ID returned by addFont()
fontGlyphId Glyph ID in given font

The fontId is expected to be less than fontCount(), fontGlyphId then less than the glyph count passed in the addFont() call. The returned ID can be then used to index the glyphOffsets() const, glyphLayers() const and glyphRectangles() const views, alternatively you can use glyph(UnsignedInt, UnsignedInt) const to get properties of a single glyph directly.

If addGlyph() wasn't called for given fontId and fontGlyphId yet, returns 0, i.e. the cache-global invalid glyph index.

The lookup is done with an $ \mathcal{O}(1) $ complexity.

void Magnum::Text::AbstractGlyphCache::glyphIdsInto(UnsignedInt fontId, const Containers::StridedArrayView1D<const UnsignedInt>& fontGlyphIds, const Containers::StridedArrayView1D<UnsignedInt>& glyphIds) const

Query cache-global glyph IDs from font-local glyph IDs.

Parameters
fontId in Font ID returned by addFont()
fontGlyphIds in Glyph IDs in given font
glyphIds out Resulting cache-global glyph IDs

A batch variant of glyphId(), mainly meant to be used to index the glyphOffsets() const, glyphLayers() const and glyphRectangles() const views.

The fontId is expected to be less than fontCount(), all fontGlyphIds items then less than the glyph count passed in the addFont() call. The fontGlyphIds and glyphIds views are expected to have the same size. Glyphs for which addGlyph() wasn't called yet have the corresponding glyphIds item set to 0.

The lookup is done with an $ \mathcal{O}(n) $ complexity with $ n $ being size of the fontGlyphIds array.

void Magnum::Text::AbstractGlyphCache::glyphIdsInto(UnsignedInt fontId, std::initializer_list<UnsignedInt> fontGlyphIds, const Containers::StridedArrayView1D<UnsignedInt>& glyphIds) const new in Git master

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Containers::StridedArrayView1D<const Vector2i> Magnum::Text::AbstractGlyphCache::glyphOffsets() const new in Git master

Positions of all glyphs in the cache relative to a point on the baseline.

The offsets are including padding(). Size of the returned view is the same as glyphCount(). Use glyphId() or glyphIdsInto() to map from per-font glyph IDs to indices in this array. The first item is the position of the cache-global invalid glyph.

The returned view is only guaranteed to be valid until the next addGlyph() call.

Containers::StridedArrayView1D<const Int> Magnum::Text::AbstractGlyphCache::glyphLayers() const new in Git master

Layers of all glyphs in the cache atlas.

Size of the returned view is the same as glyphCount(). Use glyphId() or glyphIdsInto() to map from per-font glyph IDs to indices in this array. The first item is the layer of the cache-global invalid glyph. All values are guaranteed to be less than size() depth.

The returned view is only guaranteed to be valid until the next addGlyph() call.

Containers::StridedArrayView1D<const Range2Di> Magnum::Text::AbstractGlyphCache::glyphRectangles() const new in Git master

Rectangles of all glyphs in the cache atlas.

The rectangles are including padding(). Size of the returned view is the same as glyphCount(). Use glyphId() or glyphIdsInto() to map from per-font glyph IDs to indices in this array. The first item is the layer of the cache-global invalid glyph. All values are guaranteed to fit into size() width and height.

The returned view is only guaranteed to be valid until the next addGlyph() call.

Containers::Triple<Vector2i, Int, Range2Di> Magnum::Text::AbstractGlyphCache::glyph(UnsignedInt fontId, UnsignedInt fontGlyphId) const new in Git master

Properties of given glyph ID in given font.

Parameters
fontId Font ID returned by addFont()
fontGlyphId Glyph ID in given font

Returns offset of the rendered glyph relative to a point on the baseline, layer and rectangle in the atlas. The offset and rectangle are including padding(). The fontId is expected to be less than fontCount(), fontGlyphId then less than the glyph count passed in the addFont() call.

The lookup is done with an $ \mathcal{O}(1) $ complexity.

Containers::Triple<Vector2i, Int, Range2Di> Magnum::Text::AbstractGlyphCache::glyph(UnsignedInt glyphId) const new in Git master

Properties of given cache-global glyph ID.

Parameters
glyphId Cache-global glyph ID

Returns offset of the rendered glyph relative to a point on the baseline, layer and rectangle in the atlas. The offset and rectangle are including padding(). The glyphId is expected to be less than glyphCount().

std::pair<Vector2i, Range2Di> Magnum::Text::AbstractGlyphCache::operator[](UnsignedInt glyphId) const

Properties of given glyph.

Parameters
glyphId Glyph ID

Calls glyph() with fontId set to 0, returns its output with the layer index ignored.

void Magnum::Text::AbstractGlyphCache::doSetImage(const Vector3i& offset, const ImageView3D& image) virtual private new in Git master

Set a 3D glyph cache image.

Called from flushImage() with a slice of image(). The offset and ImageView::size() are guaranteed to be in bounds for size(). For a glyph cache with size() depth being 1 default implementation delegates to doSetImage(const Vector2i&, const ImageView2D&). Implement either this or the other overload.

void Magnum::Text::AbstractGlyphCache::doSetImage(const Vector2i& offset, const ImageView2D& image) virtual private

Set a 2D glyph cache image.

Delegated to from the default implementation of doSetImage(const Vector3i&, const ImageView3D&) if size() depth is 1. The offset and ImageView::size() are guaranteed to be in bounds for size(). Implement either this or the other overload.

void Magnum::Text::AbstractGlyphCache::doSetProcessedImage(const Vector3i& offset, const ImageView3D& image) virtual private new in Git master

Implementation for setProcessedImage()

The offset and ImageView::size() are guaranteed to be in bounds for processedSize(). For a glyph cache with size() depth (and thus also processedSize() depth) being 1 default implementation delegates to doSetProcessedImage(const Vector2i&, const ImageView2D&). Implement either this or the other overload.

void Magnum::Text::AbstractGlyphCache::doSetProcessedImage(const Vector2i& offset, const ImageView2D& image) virtual private new in Git master

Implementation for setProcessedImage()

Delegated to from the default implementation of doSetProcessedImage(const Vector3i&, const ImageView3D&) if size() depth (and thus also processedSize() depth) is 1. The offset and ImageView::size() are guaranteed to be in bounds for processedSize(). Implement either this or the other overload.