Magnum::Text::RendererCore class new in Git master

Text renderer core.

Implements essential logic for rendering text formed from multiple runs, lines and fonts, providing access to glyph positions, glyph IDs and glyph cluster information that can be subsequently used to show the text on the screen and perform cursor or selection placement.

See the higher-level Renderer subclass for full usage documentation — the input interface is mostly the same between the two, with just the output being something else. The rest of this documentation thus only highlights the differences between the two. For lowest-level functionality see the AbstractShaper class, which exposes text shaping capabilities implemented directly by particular font plugins.

Usage

A RendererCore instance is created and populated the same way as a Renderer or RendererGL, with add() and render() behaving exactly the same:

Text::RendererCore renderer{cache};

renderer.render(shaper, size, "Hello, world!");

Once rendered, the glyphPositions() and glyphIds() views provide access to rendered glyph data, and runScales() with runEnds() describe which scale is applied to particular glyph ranges in order to place the glyphs at given positions apprpriately scaled. You can then use the low-level renderGlyphQuadsInto() utility to create textured quads, or feed the data to some entirely different system that renders the text without needing textured quads at all.

Range1Dui runs = renderer.render().second();

struct Vertex {
    Vector2 position;
    Vector2 textureCoordinates; /* or Vector3 for an array glyph cache */
};
Containers::Array<Vertex> vertices;
for(UnsignedInt run = runs.min(); run != runs.max(); ++run) {
    Range1Dui glyphs = renderer.glyphsForRuns({run, run + 1});
    Containers::StridedArrayView1D<Vertex> runVertices =
        arrayAppend(vertices, NoInit, glyphs.size());
    Text::renderGlyphQuadsInto(renderer.glyphCache(),
        renderer.runScales()[run],
        renderer.glyphPositions().slice(glyphs.min(), glyphs.max()),
        renderer.glyphIds().slice(glyphs.min(), glyphs.max()),
        runVertices.slice(&Vertex::position),
        runVertices.slice(&Vertex::textureCoordinates));
}

Mapping between input text and shaped glyphs

For implementing text selection or editing, if RendererCoreFlag::GlyphClusters is enabled on RendererCore construction, the renderer exposes also the glyph cluster information for each run via glyphClusters(). See the relevant Renderer documentation for a detailed explanation of how the data get used.

Providing custom glyph and run data allocators

For more control over memory allocations or for very customized use, it's possible to hook up custom allocators for glyph and run data. For example, if you always use the RendererCore to render only up to a fixed amount of glyphs, you can direct it to statically sized arrays:

struct Glyph {
    Vector2 position;
    UnsignedInt id;
    Vector2 advance;
} glyphs[256];
struct Run {
    Float scale;
    UnsignedInt end;
} runs[16];

Text::RendererCore renderer{cache,
    [](void* state, UnsignedInt glyphCount,
       Containers::StridedArrayView1D<Vector2>& glyphPositions,
       Containers::StridedArrayView1D<UnsignedInt>& glyphIds,
       Containers::StridedArrayView1D<UnsignedInt>*,
       Containers::StridedArrayView1D<Vector2>& glyphAdvances
    ) {
        Containers::ArrayView<Glyph> glyphs = *static_cast<Glyph(*)[256]>(state);
        CORRADE_INTERNAL_ASSERT(glyphCount <= glyphs.size());;
        glyphPositions = stridedArrayView(glyphs).slice(&Glyph::position);
        glyphIds = stridedArrayView(glyphs).slice(&Glyph::id);
        glyphAdvances = stridedArrayView(glyphs).slice(&Glyph::advance);
    }, glyphs,
    [](void* state, UnsignedInt runCount,
       Containers::StridedArrayView1D<Float>& runScales,
       Containers::StridedArrayView1D<UnsignedInt>& runEnds
    ) {
        Containers::ArrayView<Run> runs = *static_cast<Run(*)[16]>(state);
        CORRADE_INTERNAL_ASSERT(runCount <= runs.size());;
        runScales = Containers::stridedArrayView(runs).slice(&Run::scale);
        runEnds = Containers::stridedArrayView(runs).slice(&Run::end);
    }, runs
};

A behavior worth mentioning is that on clear() or reset() the allocators get called with the count being 0, which can be used to "redirect" the allocation to some entirely different memory. That allows you to use a single renderer instance to independently render and replace several different text blocks, instead of having a dedicated renderer instance for each or having to copy the rendered data out every time:

struct Allocation {
    UnsignedInt current = 0;
    /* Using just a fixed set of texts for brevity */
    Containers::Array<Glyph> texts[5];
} allocation;

Text::RendererCore renderer{cache,
    [](void* state, UnsignedInt glyphCount,
       Containers::StridedArrayView1D<Vector2>& glyphPositions,
       Containers::StridedArrayView1D<UnsignedInt>& glyphIds,
       Containers::StridedArrayView1D<UnsignedInt>*,
       Containers::StridedArrayView1D<Vector2>& glyphAdvances
    ) {
        auto& allocation = *static_cast<Allocation*>(state);
        Containers::Array<Glyph>& glyphs = allocation.texts[allocation.current];
        if(glyphCount > glyphs.size())
            arrayResize(glyphs, glyphCount);

        glyphPositions = stridedArrayView(glyphs).slice(&Glyph::position);
        glyphIds = stridedArrayView(glyphs).slice(&Glyph::id);
        glyphAdvances = stridedArrayView(glyphs).slice(&Glyph::advance);
    }, &allocation,
    /* Text runs use the renderer's default allocator */
    nullptr, nullptr
};



/* Updating text 3 */
allocation.current = 3;
renderer
    .clear()
    .render(shaper, size, "Hello, world!");

/* Updating text 1 */
allocation.current = 1;
renderer
    .clear()
    .render(shaper, size, "This doesn't replace text 3!");

Expected allocator behavior is fully documented in the RendererCore() constructor, note especially the special casing for glyph advances. The Renderer subclass then provides two additional allocator hooks for index and vertex data.

Derived classes

class Renderer new in Git master
Text renderer.

Constructors, destructors, conversion operators

RendererCore(const AbstractGlyphCache& glyphCache, RendererCoreFlags flags = {}) explicit
Construct.
RendererCore(const AbstractGlyphCache& glyphCache, void(*)(void*state, UnsignedInt glyphCount, Containers::StridedArrayView1D<Vector2>&glyphPositions, Containers::StridedArrayView1D<UnsignedInt>&glyphIds, Containers::StridedArrayView1D<UnsignedInt>*glyphClusters, Containers::StridedArrayView1D<Vector2>&glyphAdvances) glyphAllocator, void* glyphAllocatorState, void(*)(void*state, UnsignedInt runCount, Containers::StridedArrayView1D<Float>&runScales, Containers::StridedArrayView1D<UnsignedInt>&runEnds) runAllocator, void* runAllocatorState, RendererCoreFlags flags = {}) explicit
Construct with external allocators.
RendererCore(NoCreateT) explicit noexcept new in Git master
Construct without creating the internal state.
RendererCore(RendererCore&) deleted
Copying is not allowed.
RendererCore(RendererCore&&) noexcept
Move constructor.

Public functions

auto operator=(RendererCore&) -> RendererCore& deleted
Copying is not allowed.
auto operator=(RendererCore&&) -> RendererCore& noexcept
Move assignment.
auto glyphCache() const -> const AbstractGlyphCache&
Glyph cache associated with the renderer.
auto flags() const -> RendererCoreFlags
Flags.
auto glyphCount() const -> UnsignedInt
Total count of rendered glyphs.
auto glyphCapacity() const -> UnsignedInt
Glyph capacity.
auto runCount() const -> UnsignedInt
Total count of rendered runs.
auto runCapacity() const -> UnsignedInt
Run capacity.
auto isRendering() const -> bool
Whether text rendering is currently in progress.
auto renderingGlyphCount() const -> UnsignedInt
Total count of glyphs including current in-progress rendering.
auto renderingRunCount() const -> UnsignedInt
Total count of runs including current in-progress rendering.
auto cursor() const -> Vector2
Cursor position.
auto setCursor(const Vector2& cursor) -> RendererCore&
Set cursor position for the next rendered text.
auto alignment() const -> Alignment
Text alignment.
auto setAlignment(Alignment alignment) -> RendererCore&
Set alignment for the next rendered text.
auto lineAdvance() const -> Float
Line advance.
auto setLineAdvance(Float advance) -> RendererCore&
Set line advance for the next rendered text.
auto layoutDirection() const -> LayoutDirection
Layout direction.
auto setLayoutDirection(LayoutDirection direction) -> RendererCore&
Set layout direction.
auto glyphPositions() const -> Containers::StridedArrayView1D<const Vector2>
Glyph positions.
auto glyphIds() const -> Containers::StridedArrayView1D<const UnsignedInt>
Glyph IDs.
auto glyphClusters() const -> Containers::StridedArrayView1D<const UnsignedInt>
Glyph cluster IDs.
auto runScales() const -> Containers::StridedArrayView1D<const Float>
Text run scales.
auto runEnds() const -> Containers::StridedArrayView1D<const UnsignedInt>
Text run end glyph offsets.
auto glyphsForRuns(const Range1Dui& runRange) const -> Range1Dui
Range of glyphs corresponding to a range of runs.
auto reserve(UnsignedInt glyphCapacity, UnsignedInt runCapacity) -> RendererCore&
Reserve capacity for given glyph and run count.
auto clear() -> RendererCore&
Clear rendered glyphs and runs.
auto reset() -> RendererCore&
Reset internal renderer state.
auto add(AbstractShaper& shaper, Float size, Containers::StringView text, UnsignedInt begin, UnsignedInt end, Containers::ArrayView<const FeatureRange> features = {}) -> RendererCore&
Add to the currently rendered text.
auto add(AbstractShaper& shaper, Float size, Containers::StringView text, UnsignedInt begin, UnsignedInt end, std::initializer_list<FeatureRange> features) -> RendererCore&
auto add(AbstractShaper& shaper, Float size, Containers::StringView text, Containers::ArrayView<const FeatureRange> features = {}) -> RendererCore&
Add a whole string to the currently rendered text.
auto add(AbstractShaper& shaper, Float size, Containers::StringView text, std::initializer_list<FeatureRange> features) -> RendererCore&
auto render() -> Containers::Pair<Range2D, Range1Dui>
Wrap up rendering of all text added so far.
auto render(AbstractShaper& shaper, Float size, Containers::StringView text, Containers::ArrayView<const FeatureRange> features = {}) -> Containers::Pair<Range2D, Range1Dui>
Render a whole text at once.
auto render(AbstractShaper& shaper, Float size, Containers::StringView text, std::initializer_list<FeatureRange> features) -> Containers::Pair<Range2D, Range1Dui>

Function documentation

Magnum::Text::RendererCore::RendererCore(const AbstractGlyphCache& glyphCache, RendererCoreFlags flags = {}) explicit

Construct.

Parameters
glyphCache Glyph cache to use for glyph ID mapping
flags Opt-in feature flags

By default, the renderer allocates the memory for glyph and run data internally. Use the overload below to supply external allocators.

Magnum::Text::RendererCore::RendererCore(const AbstractGlyphCache& glyphCache, void(*)(void*state, UnsignedInt glyphCount, Containers::StridedArrayView1D<Vector2>&glyphPositions, Containers::StridedArrayView1D<UnsignedInt>&glyphIds, Containers::StridedArrayView1D<UnsignedInt>*glyphClusters, Containers::StridedArrayView1D<Vector2>&glyphAdvances) glyphAllocator, void* glyphAllocatorState, void(*)(void*state, UnsignedInt runCount, Containers::StridedArrayView1D<Float>&runScales, Containers::StridedArrayView1D<UnsignedInt>&runEnds) runAllocator, void* runAllocatorState, RendererCoreFlags flags = {}) explicit

Construct with external allocators.

Parameters
glyphCache Glyph cache to use for glyph ID mapping
glyphAllocator Glyph allocator function or nullptr
glyphAllocatorState State pointer to pass to glyphAllocator
runAllocator Run allocator function or nullptr
runAllocatorState State pointer to pass to runAllocator
flags Opt-in feature flags

The glyphAllocator gets called with desired glyphCount every time glyphCount() reaches glyphCapacity(). Size of passed-in glyphPositions, glyphIds and glyphClusters views matches glyphCount(). The glyphAdvances view is a temporary storage with contents that don't need to be preserved on reallocation and is thus passed in empty. If the renderer wasn't constructed with RendererCoreFlag::GlyphClusters, the glyphClusters is nullptr to indicate it's not meant to be allocated. The allocator is expected to replace all passed views with new views that are larger by at least glyphCount, pointing to a reallocated memory with contents from the original view preserved. Initially glyphCount() is 0 and the views are all passed in empty, every subsequent time the views match a prefix of views previously returned by the allocator. To save memory, the renderer guarantees that glyphIds and glyphClusters are only filled once glyphAdvances were merged into glyphPositions. In other words, the glyphAdvances can alias a suffix of glyphIds and glyphClusters.

The runAllocator gets called with desired runCount every time runCount() reaches runCapacity(). Size of passed-in runScales and runEnds views matches runCount(). The allocator is expected to replace the views with new views that are larger by at least runCount, pointing to a reallocated memory with contents from the original views preserved. Initially runCount() is 0 and the views are passed in empty, every subsequent time the views match a prefix of views previously returned by the allocator.

The renderer always requests only exactly the desired size and the growth strategy is up to the allocators themselves — the returned views can be larger than requested and aren't all required to all have the same size. The minimum of size increases across all views is then treated as the new glyphCapacity() / runCapacity().

As a special case, when clear() or reset() is called, the allocators are called with empty views and glyphCount / runCount being 0. This is to allow the allocators to perform any needed reset as well.

If glyphAllocator or runAllocator is nullptr, glyphAllocatorState or runAllocatorState is ignored and default builtin allocator get used for either. Passing nullptr for both is equivalent to calling the RendererCore(const AbstractGlyphCache&, RendererCoreFlags) constructor.

Magnum::Text::RendererCore::RendererCore(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::RendererCore::RendererCore(RendererCore&&) noexcept

Move constructor.

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

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

Total count of rendered glyphs.

Does not include glyphs from the current in-progress rendering, if any, as their contents are not finalized yet. Use renderingGlyphCount() to query the count including the in-progress glyphs.

UnsignedInt Magnum::Text::RendererCore::glyphCapacity() const

Glyph capacity.

UnsignedInt Magnum::Text::RendererCore::runCount() const

Total count of rendered runs.

Does not include runs from the current in-progress rendering, if any, as their contents are not finalized yet. Use renderingRunCount() to query the count including the in-progress runs.

UnsignedInt Magnum::Text::RendererCore::runCapacity() const

Run capacity.

bool Magnum::Text::RendererCore::isRendering() const

Whether text rendering is currently in progress.

Returns true if there are any add() calls not yet followed by a render(), false otherwise. If rendering is in progress, setCursor(), setAlignment() and setLayoutDirection() cannot be called. The glyphCount(), runCount() and all data accessors don't include the yet-to-be-finalized contents.

UnsignedInt Magnum::Text::RendererCore::renderingGlyphCount() const

Total count of glyphs including current in-progress rendering.

Can be used for example to query which glyphs correspond to the last add() call. If isRendering() is false, the returned value is the same as glyphCount().

UnsignedInt Magnum::Text::RendererCore::renderingRunCount() const

Total count of runs including current in-progress rendering.

Can be used for example to query which runs correspond to the last add() call. If isRendering() is false, the returned value is the same as runCount().

Vector2 Magnum::Text::RendererCore::cursor() const

Cursor position.

Note that this does not return the current position at which an in-progress rendering is happening — the way the glyphs get placed before they're aligned to their final position is internal to the implementation and querying such in-progress state would be of little use.

RendererCore& Magnum::Text::RendererCore::setCursor(const Vector2& cursor)

Set cursor position for the next rendered text.

Returns Reference to self (for method chaining)

The next rendered text is placed according to specified cursor, alignment() and lineAdvance(). Expects that rendering is currently not in progress, meaning that the cursor can be only specified before rendering a particular piece of text. Initial value is {0.0f, 0.0f}.

RendererCore& Magnum::Text::RendererCore::setAlignment(Alignment alignment)

Set alignment for the next rendered text.

Returns Reference to self (for method chaining)

The next rendered text is placed according to specified cursor(), alignment and lineAdvance(). Expects that rendering is currently not in progress, meaning that the alignment can be only specified before rendering a particular piece of text. Initial value is Alignment::MiddleCenter.

RendererCore& Magnum::Text::RendererCore::setLineAdvance(Float advance)

Set line advance for the next rendered text.

Returns Reference to self (for method chaining)

The next rendered text is placed according to specified cursor(), alignment and advance. The advance value is used according to layoutDirection() and in a coordinate system matching AbstractFont::ascent() and descent(), so for example causes the next line to be shifted in a negative Y direction for LayoutDirection::HorizontalTopToBottom. Expects that rendering is currently not in progress, meaning that the line advance can be only specified before rendering a particular piece of text. If set to 0.0f, the line advance is picked metrics of the first font a corresponding size passed to add().

RendererCore& Magnum::Text::RendererCore::setLayoutDirection(LayoutDirection direction)

Set layout direction.

Returns Reference to self (for method chaining)

Expects that rendering is currently not in progress. Currently expected to always be LayoutDirection::HorizontalTopToBottom. Initial value is LayoutDirection::HorizontalTopToBottom.

Containers::StridedArrayView1D<const Vector2> Magnum::Text::RendererCore::glyphPositions() const

Glyph positions.

The returned view has a size of glyphCount(). Note that the contents are not guaranteed to be meaningful if custom glyph allocator is used, as the user code is free to perform subsequent operations on those.

Containers::StridedArrayView1D<const UnsignedInt> Magnum::Text::RendererCore::glyphIds() const

Glyph IDs.

The returned view has a size of glyphCount(). Note that the contents are not guaranteed to be meaningful if custom glyph allocator is used, as the user code is free to perform subsequent operations on those.

Containers::StridedArrayView1D<const UnsignedInt> Magnum::Text::RendererCore::glyphClusters() const

Glyph cluster IDs.

Expects that the renderer was constructed with RendererCoreFlag::GlyphClusters. The returned view has a size of glyphCount(). Note that the contents are not guaranteed to be meaningful if custom glyph allocator is used, as the user code is free to perform subsequent operations on those.

Containers::StridedArrayView1D<const Float> Magnum::Text::RendererCore::runScales() const

Text run scales.

The returned view has a size of runCount(). Note that the contents are not guaranteed to be meaningful if custom run allocator is used, as the user code is free to perform subsequent operations on those.

Containers::StridedArrayView1D<const UnsignedInt> Magnum::Text::RendererCore::runEnds() const

Text run end glyph offsets.

The returned view has a size of runCount(), the last value is equal to glyphCount(), and the values index the glyphPositions(), glyphIds() and glyphClusters() views. The first text run glyphs start at offset 0 and end at runEnds()[0], the second text run glyphs start at offset runEnds()[0] and end at runEnds()[1], etc. See also the glyphsForRuns() function which provides a convenient way to get a range of glyphs corresponding to a range of runs without having to deal with edge cases.

Note that the contents of the returned view are not guaranteed to be meaningful if custom run allocator is used, as the user code is free to perform subsequent operations on those.

Range1Dui Magnum::Text::RendererCore::glyphsForRuns(const Range1Dui& runRange) const

Range of glyphs corresponding to a range of runs.

With runRange being for example the second value returned by render(), returns a begin and end glyph offset for given run range, which can then be used to index the glyphPositions(), glyphIds() and glyphClusters() views; when multipled by 6 to index the Renderer::indices() view and when multiplied by 4 to index the Renderer::vertexPositions() and vertexTextureCoordinates() / vertexTextureArrayCoordinates() views. Expects that both the min and max runRange value are less than or equal to renderingRunCount().

Note that the returned value is not guaranteed to be meaningful if custom run allocator is used, as the user code is free to perform subsequent operations on the run data.

RendererCore& Magnum::Text::RendererCore::reserve(UnsignedInt glyphCapacity, UnsignedInt runCapacity)

Reserve capacity for given glyph and run count.

Returns Reference to self (for method chaining)

RendererCore& Magnum::Text::RendererCore::clear()

Clear rendered glyphs and runs.

Returns Reference to self (for method chaining)

The glyphCount() and runCount() becomes 0 after this call and any in-progress rendering is discarded, making isRendering() return false. If custom glyph or run allocators are used, they get called with empty views and zero sizes.

Depending on allocator used, glyphCapacity() and runCapacity() may stay non-zero. The cursor(), alignment(), lineAdvance() and layoutDirection() are left untouched, use reset() to reset those to their default values as well.

RendererCore& Magnum::Text::RendererCore::reset()

Reset internal renderer state.

Returns Reference to self (for method chaining)

Calls clear(), and additionally cursor(), alignment(), lineAdvance() and layoutDirection() are reset to their default values. Apart from glyphCapacity() and runCapacity(), which may stay non-zero depending on allocator used, the instance is equivalent to a default-constructed state.

RendererCore& Magnum::Text::RendererCore::add(AbstractShaper& shaper, Float size, Containers::StringView text, UnsignedInt begin, UnsignedInt end, Containers::ArrayView<const FeatureRange> features = {})

Add to the currently rendered text.

Parameters
shaper Shaper instance to render with
size Font size
text Text in UTF-8
begin Beginning byte in the input text
end (One byte after) the end byte in the input text
features Typographic features to apply for the whole text or its subranges
Returns Reference to self (for method chaining)

Splits text into individual lines and shapes each with given shaper. Places and aligns the text according to cursor(), alignment() and layoutDirection(), continuing from the state left after the previous add(), if any.

After calling this function, isRendering() returns true, renderingGlyphCount() and renderingRunCount() are updated with the count of newly added glyphs and runs, and setCursor(), setAlignment() or setLayoutDirection() cannot be called anymore. Call add() more times and wrap up with render() to perform the final alignment and other steps necessary to finalize the rendering. If you only need to render the whole text at once, you can use render(AbstractShaper&, Float, Containers::StringView, Containers::ArrayView<const FeatureRange>) instead.

The function assumes that the shaper has either appropriate script, language and shape direction set, or has them left at defaults in order let them be autodetected. In order to allow the implementation to perform shaping aware of surrounding context, such as picking correct glyphs for beginning, middle or end of a word or a paragraph, the individual add() calls should ideally be made with the same text view and the slices defined by begin and end. Use the add(AbstractShaper&, Float, Containers::StringView, Containers::ArrayView<const FeatureRange>) overload to pass a string as a whole.

The function uses AbstractShaper::shape(), renderLineGlyphPositionsInto(), alignRenderedLine() and glyphQuadBounds() internally, see their documentation for more information.

RendererCore& Magnum::Text::RendererCore::add(AbstractShaper& shaper, Float size, Containers::StringView text, UnsignedInt begin, UnsignedInt end, std::initializer_list<FeatureRange> features)

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

RendererCore& Magnum::Text::RendererCore::add(AbstractShaper& shaper, Float size, Containers::StringView text, Containers::ArrayView<const FeatureRange> features = {})

Add a whole string to the currently rendered text.

Equivalent to add(AbstractShaper&, Float, Containers::StringView, UnsignedInt, UnsignedInt, Containers::ArrayView<const FeatureRange>) with begin set to 0 and end to size of text.

RendererCore& Magnum::Text::RendererCore::add(AbstractShaper& shaper, Float size, Containers::StringView text, std::initializer_list<FeatureRange> features)

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

Containers::Pair<Range2D, Range1Dui> Magnum::Text::RendererCore::render()

Wrap up rendering of all text added so far.

Performs a final alignment of the text block added by preceding add() calls and wraps up the rendering. After calling this function, isRendering() returns false, glyphCount() and runCount() are updated with the count of all rendered glyphs and runs, and setCursor(), setAlignment() or setLayoutDirection() can be called again for the next text to be rendered.

The function returns a bounding box and a range of runs of the currently rendered text, the run range can then be used to index the runScales() and runEnds() views. Note that it's possible for the render to produce an empty range, such as when an empty text was passed or when it was just newlines. You can use glyphsForRuns() to convert the returned run range to a begin and end glyph offset, which can be then used to index the glyphPositions(), glyphIds() and glyphClusters() views; when multipled by 6 to index the Renderer::indices() view and when multiplied by 4 to index the Renderer::vertexPositions() and vertexTextureCoordinates() / vertexTextureArrayCoordinates() views.

The rendered glyph range is not touched or used by the renderer in any way afterwards. If the renderer was created with custom allocators, the caller can thus perform further operations on the allocated data.

Use clear() or reset() to discard all text rendered so far. The function uses alignRenderedBlock() internally, see its documentation for more information.

Containers::Pair<Range2D, Range1Dui> Magnum::Text::RendererCore::render(AbstractShaper& shaper, Float size, Containers::StringView text, Containers::ArrayView<const FeatureRange> features = {})

Render a whole text at once.

A convenience shortcut for rendering a single piece of text that's equivalent to calling add(AbstractShaper&, Float, Containers::StringView, Containers::ArrayView<const FeatureRange>) followed by render(). See their documentation for more information.

After calling this function, isRendering() returns false. If this function is called while rendering is in progress, the glyphs rendered so far are included in the result as well.

Containers::Pair<Range2D, Range1Dui> Magnum::Text::RendererCore::render(AbstractShaper& shaper, Float size, Containers::StringView text, std::initializer_list<FeatureRange> features)

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