class new in Git master
#include <Magnum/Text/Renderer.h>
Renderer Text renderer.
Implements logic for rendering text formed from multiple runs, lines and fonts, resulting in a textured quad mesh, optionally with glyph cluster information that can be used to perform cursor and selection placement. You'll likely use the renderer through the RendererGL subclass, which directly populates a GL::
The RendererCore base implements just glyph positioning and layout, to be used in scenarios where forming textured quads is deferred to later or not needed at all. For lowest-level functionality see the AbstractShaper class, which exposes text shaping capabilities implemented directly by particular font plugins.
Usage
Assuming you'll want to subsequently render the text with OpenGL, construct the renderer using the RendererGL subclass and an OpenGL glyph cache implementation, such as a GlyphCacheGL.
Text::GlyphCacheGL cache{PixelFormat::R8Unorm, {256, 256}}; … Text::RendererGL renderer{cache};
Before rendering with a particular AbstractFont, the glyph cache has to be filled with desired glyphs from it, if not done already, as shown below. The AbstractFont class documentation shows additional ways how to fill the glyph cache.
Containers::Pointer<Text::AbstractFont> font = …; if(!font->fillGlyphCache(cache, "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789?!:;,. ")) Fatal{} << "Glyph cache too small to fit all characters";
To render a text, pass an AbstractShaper instance created from the font together with desired font size and actual text to render():
renderer.render(*font->createShaper(), font->size(), "Hello, world!");
Once rendered, the RendererGL::
GL::Renderer::enable(GL::Renderer::Feature::Blending); GL::Renderer::setBlendFunction( GL::Renderer::BlendFunction::One, GL::Renderer::BlendFunction::OneMinusSourceAlpha); Shaders::VectorGL2D shader; shader .setTransformationProjectionMatrix(Matrix3::projection(Vector2{windowSize()})) .bindVectorTexture(cache.texture()) .draw(renderer.mesh());
If you use just the base Renderer, the rendered index and vertex data are exposed through indices(), vertexPositions() and vertexTextureCoordinates() / vertexTextureArrayCoordinates(), which you can pass to a custom renderer, for example. Likewise, the glyph cache can be a custom AbstractGlyphCache subclass that uploads the rasterized glyph data to a texture in a custom renderer. For more control over data layout in custom use cases see the Providing custom index and vertex data allocators section down below.
Cursor, alignment and other layouting options
Internally, the renderer splits the passed text to individual lines and shapes each separately, placing them together at a concrete cursor position with specific alignment and line advance. The initial cursor position is at {0.0f, 0.0f}
with a Text::
renderer .setCursor({+windowSize().x()*0.5f - 10.0f, -windowSize().y()*0.5f + 10.0f}) .setAlignment(Text::Alignment::BottomRight) .render(*font->createShaper(), font->size(), "Hello,\nworld!");
The renderer supports only horizontal text layout right now. The setLayoutDirection() API is currently just a placeholder for when vertical layout is supported in the future as well.
Font script, language and shaping direction
The AbstractShaper instance contains internal font-specific state used for actual text shaping. If you create an instance and reuse it multiple times instead of creating it on the fly, it allows the implementation to reuse allocated resources. It's also possible to call AbstractShaper::
Containers::Pointer<Text::AbstractShaper> shaper = font->createShaper(); shaper->setScript(Text::Script::Latin); shaper->setLanguage("en"); shaper->setDirection(Text::ShapeDirection::LeftToRight); renderer.render(*shaper, shaper->font().size(), "Hello, world!");
The AbstractShaper documentation has additional info about how the shaping properties are handled and how to check what's supported by a particular font plugin.
Font features
The last argument to render() allows enabling and disabling typographic features. For example, assuming the font would support small capitals (and the particular AbstractFont plugin would recognize and use the feature), we could render the "world" part with small caps, resulting in "Hello, ᴡᴏʀʟᴅ!":
renderer.render(*shaper, shaper->font().size(), "Hello, world!", { {Text::Feature::SmallCapitals, 7, 12} });
The behavior is equivalent to font features passed to AbstractShaper::
Rendering multiple text blocks
Each call to render() doesn't replace the previously rendered but appends to it, starting again from the position specified with setCursor(). Ultimately that means you can render multiple blocks of text into the same mesh. The following snippet places the two parts of the text to bottom left and bottom right window corners:
renderer .setCursor({-windowSize().x()*0.5f + 10.0f, -windowSize().y()*0.5f + 10.0f}) .setAlignment(Text::Alignment::BottomLeft) .render(*shaper, shaper->font().size(), "Hello,"); renderer .setCursor({+windowSize().x()*0.5f - 10.0f, -windowSize().y()*0.5f + 10.0f}) .setAlignment(Text::Alignment::BottomRight) .render(*shaper, shaper->font().size(), "world!");
Then you can either draw everything at once, with the same shader setup as listed above, or draw particular parts with different settings. For that, the render() function returns two values — a bounding box that can be used for various placement and alignment purposes, and a range of text runs the rendered text spans. A run is a range of glyphs together with an associated scale, and the run offsets can be converted to glyph offsets using glyphsForRuns(). Glyph offsets then directly correspond to vertex and index offsets, as each glyph is a quad consisting of four vertices and six indices. The following code draws each of the two pieces with a different color by making temporary GL::
Range1Dui helloRuns = renderer … .render(*shaper, shaper->font().size(), "Hello,").second(); Range1Dui helloGlyphs = renderer.glyphsForRuns(helloRuns); Range1Dui worldRuns = renderer … .render(*shaper, shaper->font().size(), "world!").second(); Range1Dui worldGlyphs = renderer.glyphsForRuns(worldRuns); shader .setTransformationProjectionMatrix(Matrix3::projection(Vector2{windowSize()})) .bindVectorTexture(cache.texture()) .setColor(0x3bd267_rgbf) .draw(GL::MeshView{renderer.mesh()} .setIndexOffset(helloGlyphs.min()*6) .setCount(helloGlyphs.size()*6)) .setColor(0x2f83cc_rgbf) .draw(GL::MeshView{renderer.mesh()} .setIndexOffset(worldGlyphs.min()*6) .setCount(worldGlyphs.size()*6));
Finally, clear() discards all text rendered so far, meaning that the next render() will start from an empty state. The reset() function additionally resets also all other state like cursor position and alignment to default values.
Rendering multiple text runs together
Besides rendering the whole text at once with a single font, it's possible to render different parts of the text with different fonts, sizes or even just differently configured shaper instances. This is done by using add(), which, compared to render(), continues shaping where the previous add() ended instead of going back to the cursor specified with setCursor(). When done, a call to the parameter-less render() performs final alignment and wraps up the rendering. In the following snippet, a bold font is used to render the "world" part:
Containers::Pointer<Text::AbstractShaper> shaper = font->createShaper(); Containers::Pointer<Text::AbstractShaper> boldShaper = boldFont->createShaper(); … renderer .add(*shaper, shaper->font().size(), "Hello, ") .add(*boldShaper, boldShaper->font().size(), "world") .add(*shaper, shaper->font().size(), "!") .render();
Fonts can be switched anywhere, not just at word boundaries. However, to make use of the full shaping capabilities of a certain font implementation, it's recommended to supply the text with additional context so the shaper can perform kerning, glyph substitution and other operations even across the individual pieces. This is done by passing the whole text every time and specifying the range to shape by a begin and end byte offset into it, allowing the shaper to peek outside of the actually shaped piece of text:
Containers::StringView text = "Hello, world!"; renderer .add(*shaper, shaper->font().size(), text, 0, 7) .add(*boldShaper, boldShaper->font().size(), text, 7, 12) .add(*shaper, shaper->font().size(), text, 12, 13) .render();
Font size
So far, for simplicity, the snippets above passed AbstractFont::
When rendering the text, there are two common approaches — either setting up the size to match a global user interface scale, or having the text size proportional to the window size. The first approach is what's shown in the above snippets, with a projection that matches Platform::
Containers::Pointer<Text::AbstractFont> font = …; if(!font->openFile("font.ttf", size*2.0f)) /* Supersample 2x */ … … renderer.render(*font->createShaper(), size, …);
The second approach, with text size being relative to the window size, is for cases where the text is meant to match surrounding art, such as in a game menu. In this case the projection size is usually something arbitrary that doesn't match window pixels, and the text point size then has to be relative to that. For this use case a DistanceFieldGlyphCacheGL is the better match, as it can provide text at different sizes without the scaling causing blurriness or aliased edges. See its documentation for details about picking the right font size and other parameters for best results.
DPI awareness
To achieve crisp rendering and/or text size matching other applications on HiDPI displays, additional steps need to be taken. There are two separate concepts for DPI-aware rendering:
- Interface size — size at which the interface elements are positioned on the screen. Often, for simplicity, the interface is using some "virtual units", so a 12 pt font is still a 12 pt font independently of how the interface is scaled compared to actual display properties (for example by setting a global 150% scale in the desktop environment, or by zooming a browser window). The size passed to render() or add() should match these virtual units.
- Framebuffer size — how many pixels is actually there. If a 192 DPI display has a 200% interface scale, a 12 pt font would be 32 pixels. But if it only has a 150% scale, all interface elements will be smaller, and a 12 pt font would be only 24 pixels. The size used by the AbstractFont and GlyphCacheGL should be chosen with respect to the actual physical pixels.
When using for example Platform::*Application
implementations, you usually have three values at your disposal — windowSize(), framebufferSize() and dpiScaling(). Their relation is documented thoroughly in DPI awareness, for this particular case a scaled interface size, used instead of window size for the projection, would be calculated like this:
Vector2 interfaceSize = Vector2{windowSize()}/dpiScaling();
And a multiplier for the AbstractFont and GlyphCacheGL font size like this. The render() or add() keeps using the size without this multiplier.
Float sizeMultiplier = (Vector2{framebufferSize()}*dpiScaling()/Vector2{windowSize()}).max();
Rendering and mesh drawing performance
To avoid repeated reallocations when rendering a larger chunk of text, when the text is combined of many small runs or when rendering many separate text blocks together, call reserve() with expected glyph and run count.
For the mesh the Renderer by default uses MeshIndexType::
Mapping between input text and shaped glyphs
For implementing text selection or editing, if RendererFlag::
Text::Renderer renderer{cache, Text::RendererFlag::GlyphPositionsClusters}; Range1Dui runs = renderer.render(…, text).second(); Range1Dui glyphs = renderer.glyphsForRuns(runs); Containers::StridedArrayView1D<const UnsignedInt> clusters = renderer.glyphClusters().slice(glyphs.min(), glyphs.max()); /* Input text corresponding to glyphs 2 to 5 */ Containers::StringView selection = text.slice(clusters[2], clusters[5]); /* Or glyphs corresponding to a concrete text selection */ Containers::Pair<UnsignedInt, UnsignedInt> selectionGlyphs = Text::glyphRangeForBytes(clusters, selection.begin() - text.begin(), selection.end() - text.begin());
When using RendererGL, the flag is RendererGLFlag::
Providing custom index and vertex data allocators
If you're using Renderer directly and not the RendererGL subclass, it's possible to hook up custom allocators for index and vertex data. Let's say that you want to have per-vertex colors in addition to positions and texture coordinates. The text renderer produces position and texture coordinate data inside render() and colors get filled in after, by querying the vertex range corresponding to the produced glyph run produced using glyphsForRuns():
struct Vertex { Vector2 position; Vector2 textureCoordinates; Color4 color; }; Containers::Array<Vertex> vertices; Text::Renderer renderer{cache, /* Glyphs, runs and indices use renderer's default allocators */ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, [](void* state, UnsignedInt vertexCount, Containers::StridedArrayView1D<Vector2>& vertexPositions, Containers::StridedArrayView1D<Vector2>& vertexTextureCoordinates ) { auto& vertices = *static_cast<Containers::Array<Vertex>*>(state); if(vertexCount > vertices.size()) arrayResize(vertices, vertexCount); vertexPositions = stridedArrayView(vertices).slice(&Vertex::position); vertexTextureCoordinates = stridedArrayView(vertices).slice(&Vertex::textureCoordinates); }, &vertices }; /* Render a text and fill vertex colors. Each glyph quad is four vertices. */ Range1Dui runs = renderer.render(…).second(); Range1Dui glyphs = renderer.glyphsForRuns(runs); for(Vertex& vertex: vertices.slice(glyphs.min()*4, glyphs.max()*4)) vertex.color = 0x3bd267_rgbf;
In case of indices you can for example use a single statically-allocated memory across all renderers, to avoid each allocating its own copy:
/* A 2-byte index type can index at most 65k vertices, which is enough for 16k glyph quads, and each glyph quad needs six indices */ char indices[2*16384*6]; Text::Renderer renderer{cache, nullptr, nullptr, nullptr, nullptr, [](void* state, UnsignedInt size, Containers::ArrayView<char>& indices) { indices = *static_cast<char(*)[2*16384*6]>(state); CORRADE_INTERNAL_ASSERT(size <= indices.size());; }, indices, nullptr, nullptr };
Expected allocator behavior is fully documented in the Renderer() constructor, note especially the differences when array glyph caches are used. The Providing custom glyph and run data allocators section in the RendererCore documentation shows more use cases with examples for the remaining two allocators.
Base classes
- class RendererCore new in Git master
- Text renderer core.
Derived classes
- class RendererGL new in Git master
- OpenGL text renderer.
Constructors, destructors, conversion operators
- Renderer(const AbstractGlyphCache& glyphCache, RendererFlags flags = {}) explicit
- Construct.
-
Renderer(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, void(*)(void*state, UnsignedInt size, Containers:: ArrayView<char>&indices) indexAllocator, void* indexAllocatorState, void(*)(void*state, UnsignedInt vertexCount, Containers:: StridedArrayView1D<Vector2>&vertexPositions, Containers:: StridedArrayView1D<Vector2>&vertexTextureCoordinates) vertexAllocator, void* vertexAllocatorState, RendererFlags flags = {}) explicit - Construct with external allocators.
- Renderer(NoCreateT) explicit noexcept new in Git master
- Construct without creating the internal state.
- Renderer(Renderer&) deleted
- Copying is not allowed.
- Renderer(Renderer&&) noexcept
- Move constructor.
Public functions
- auto operator=(Renderer&) -> Renderer& deleted
- Copying is not allowed.
- auto operator=(Renderer&&) -> Renderer& noexcept
- Move assignment.
- auto flags() const -> RendererFlags
- Flags.
- auto glyphIndexCapacity() const -> UnsignedInt
- Glyph index capacity.
- auto glyphVertexCapacity() const -> UnsignedInt
- Glyph vertex capacity.
- auto indexType() const -> MeshIndexType
- Index type.
- auto setIndexType(MeshIndexType atLeast) -> Renderer&
- Set index type.
-
auto glyphPositions() const -> Containers::
StridedArrayView1D<const Vector2> - Glyph positions.
-
auto glyphIds() const -> Containers::
StridedArrayView1D<const UnsignedInt> deleted - Glyph IDs are not accessible.
-
auto glyphClusters() const -> Containers::
StridedArrayView1D<const UnsignedInt> - Glyph cluster IDs.
-
auto indices() const -> Containers::
StridedArrayView2D<const char> - Type-erased glyph quad indices.
-
template<class T>auto indices() const -> Containers::
ArrayView<const T> - Glyph quad indices.
-
auto vertexPositions() const -> Containers::
StridedArrayView1D<const Vector2> - Vertex positions.
-
auto vertexTextureCoordinates() const -> Containers::
StridedArrayView1D<const Vector2> - Vertex texture coordinates.
-
auto vertexTextureArrayCoordinates() const -> Containers::
StridedArrayView1D<const Vector3> - Vertex texture array coordinates.
- auto reserve(UnsignedInt glyphCapacity, UnsignedInt runCapacity) -> Renderer&
- Reserve capacity for given glyph count.
- auto clear() -> Renderer&
- Clear rendered glyphs, runs and vertices.
- auto reset() -> Renderer&
- Reset internal renderer state.
-
auto render() -> Containers::
Pair<Range2D, Range1Dui> - Wrap up rendering of all text added so far.
Function documentation
Magnum:: Text:: Renderer:: Renderer(const AbstractGlyphCache& glyphCache,
RendererFlags flags = {}) explicit
Construct.
Parameters | |
---|---|
glyphCache | Glyph cache to use |
flags | Opt-in feature flags |
By default, the renderer allocates the memory for glyph, run, index and vertex data internally. Use the overload below to supply external allocators.
Magnum:: Text:: Renderer:: Renderer(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,
void(*)(void*state, UnsignedInt size, Containers:: ArrayView<char>&indices) indexAllocator,
void* indexAllocatorState,
void(*)(void*state, UnsignedInt vertexCount, Containers:: StridedArrayView1D<Vector2>&vertexPositions, Containers:: StridedArrayView1D<Vector2>&vertexTextureCoordinates) vertexAllocator,
void* vertexAllocatorState,
RendererFlags 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 |
indexAllocator | Index allocator function or nullptr |
indexAllocatorState | State pointer to pass to indexAllocator |
vertexAllocator | Vertex allocator function or nullptr |
vertexAllocatorState | State pointer to pass to vertexAllocator |
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 RendererFlag::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 indexAllocator
gets called with desired size
every time glyphCapacity() increases. Size of passed-in indices
array either matches glyphCapacity() times 6
times size of indexType() if the index type stays the same, or is empty if the index type changes (and the whole index array is going to get rebuilt with a different type, thus no contents need to be preserved). The allocator is expected to replace the passed view with a new view that's larger by at least size
, pointing to a reallocated memory with contents from the original view preserved. Initially glyphCapacity() is 0
and the view is passed in empty, every subsequent time the view matches a prefix of the view previously returned by the allocator.
The vertexAllocator
gets called with vertexCount
every time glyphCount() reaches glyphCapacity(). Size of passed-in vertexPositions
and vertexTextureCoordinates
views matches glyphCount() times 4
. The allocator is expected to replace the views with new views that are larger by at least vertexCount
, pointing to a reallocated memory with contents from the original views preserved. Initially glyphCount() is 0
and the views are passed in empty, every subsequent time the views match a prefix of views previously returned by the allocator. If the glyphCache
is an array, the allocator is expected to (re)allocate vertexTextureCoordinates
for a Vector3 type even though the view points to just the first two components of each texture coordinates.
The renderer always requests only exactly the desired size and the growth strategy is up to the allocators themselves — the returned glyph and run 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(), glyphIndexCapacity(), glyphVertexCapacity() and runCapacity().
As a special case, when clear() or reset() is called, the allocators are called with empty views and glyphCount
/ runCount
/ size
/ vertexCount
being 0
. This is to allow the allocators to perform any needed reset as well.
If glyphAllocator
, runAllocator
, indexAllocator
or vertexAllocator
is nullptr
, glyphAllocatorState
, runAllocatorState
, indexAllocatorState
or vertexAllocatorState
is ignored and default builtin allocator get used for either. Passing nullptr
for all is equivalent to calling the Renderer(const AbstractGlyphCache&, RendererFlags) constructor.
Magnum:: Text:: Renderer:: Renderer(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.
UnsignedInt Magnum:: Text:: Renderer:: glyphIndexCapacity() const
Glyph index capacity.
Describes how many glyphs can be rendered into the index buffer. The actual index count is six times the capacity.
UnsignedInt Magnum:: Text:: Renderer:: glyphVertexCapacity() const
Glyph vertex capacity.
Describes how many glyphs can be rendered into the vertex buffer. The actual vertex count is four times the capacity.
MeshIndexType Magnum:: Text:: Renderer:: indexType() const
Index type.
The smallest type that can describe vertices for all glyphCapacity() glyphs and isn't smaller than what was set in setIndexType(). Initially set to MeshIndexType::64
and 16384
glyphs.
Renderer& Magnum:: Text:: Renderer:: setIndexType(MeshIndexType atLeast)
Set index type.
Returns | Reference to self (for method chaining) |
---|
Sets the smallest possible index type to be used. Initially MeshIndexType::64
and 16384
glyphs. Set to a larger type if you want it to be used even if the glyph capacity is smaller. Setting it back to a smaller type afterwards uses the type only if the glyph capacity allows it.
Containers:: StridedArrayView1D<const Vector2> Magnum:: Text:: Renderer:: glyphPositions() const
Glyph positions.
Expects that the renderer was constructed with RendererFlag::
Containers:: StridedArrayView1D<const UnsignedInt> Magnum:: Text:: Renderer:: glyphIds() const deleted
Glyph IDs are not accessible.
Unlike with RendererCore, to save memory, glyph IDs are retrieved only to a temporary location to produce glyph quads and are subsequently overwritten by vertex data.
Containers:: StridedArrayView1D<const UnsignedInt> Magnum:: Text:: Renderer:: glyphClusters() const
Glyph cluster IDs.
Expects that the renderer was constructed with RendererFlag::
Containers:: StridedArrayView2D<const char> Magnum:: Text:: Renderer:: indices() const
Type-erased glyph quad indices.
The returned view is contiguous with a size of glyphCount() times 6
, the second dimension having a size of indexType(). The values index the vertexPositions() and vertexTextureCoordinates() / vertexTextureArrayCoordinates() arrays. Note that the contents are not guaranteed to be meaningful if custom index allocator is used, as the user code is free to perform subsequent operations on those.
Use the templated overload below to get the indices in a concrete type.
template<class T>
Containers:: ArrayView<const T> Magnum:: Text:: Renderer:: indices() const
Glyph quad indices.
Expects that T
is either UnsignedByte, UnsignedShort or UnsignedInt and matches indexType(). The returned view has a size of glyphCount() times 6
. Note that the contents are not guaranteed to be meaningful if custom index allocator is used, as the user code is free to perform subsequent operations on those.
Use the non-templated overload above to get a type-erased view on the indices.
Containers:: StridedArrayView1D<const Vector2> Magnum:: Text:: Renderer:: vertexPositions() const
Vertex positions.
The returned view has a size of glyphCount() times 4
. Note that the contents are not guaranteed to be meaningful if custom vertex allocator is used, as the user code is free to perform subsequent operations on those.
Containers:: StridedArrayView1D<const Vector2> Magnum:: Text:: Renderer:: vertexTextureCoordinates() const
Vertex texture coordinates.
Expects that the renderer was constructed with a non-array AbstractGlyphCache, i.e. with a depth equal to 1
. The returned view has a size of glyphCount() times 4
. Note that the contents are not guaranteed to be meaningful if custom vertex allocator is used, as the user code is free to perform subsequent operations on those.
Containers:: StridedArrayView1D<const Vector3> Magnum:: Text:: Renderer:: vertexTextureArrayCoordinates() const
Vertex texture array coordinates.
Expects that the renderer was constructed with an array AbstractGlyphCache, i.e. with a depth larger than 1
. The returned view has a size of glyphCount() times 4
. Note that the contents are not guaranteed to be meaningful if custom vertex allocator is used, as the user code is free to perform subsequent operations on those.
Renderer& Magnum:: Text:: Renderer:: reserve(UnsignedInt glyphCapacity,
UnsignedInt runCapacity)
Reserve capacity for given glyph count.
Returns | Reference to self (for method chaining) |
---|
Calls RendererCore::glyphCapacity
and indexType(), their actually allocated capacity doesn't need to match glyphCapacity() and is exposed through glyphIndexCapacity() and glyphVertexCapacity().
Renderer& Magnum:: Text:: Renderer:: clear()
Clear rendered glyphs, runs and vertices.
Returns | Reference to self (for method chaining) |
---|
Calls RendererCore::0
after this call and any in-progress rendering is discarded, making isRendering() return false
. If custom glyph, run or vertex allocators are used, they get called with empty views and zero sizes. Custom index allocator isn't called however, as the index buffer only needs updating when its capacity isn't large enough.
Depending on allocator used, glyphCapacity(), glyphVertexCapacity() 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.
Renderer& Magnum:: Text:: Renderer:: 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(), glyphVertexCapacity() and runCapacity() which may stay non-zero depending on allocator used, and glyphIndexCapacity() plus indexType() which are left untouched, the instance is equivalent to a default-constructed state.
Containers:: Pair<Range2D, Range1Dui> Magnum:: Text:: Renderer:: render()
Wrap up rendering of all text added so far.
Calls RendererCore::
The function uses renderGlyphQuadsInto() and renderGlyphQuadIndicesInto() internally, see their documentation for more information.