#include <Magnum/Text/Renderer.h>
template<UnsignedInt dimensions>
Renderer class
Text renderer.
Lays out the text into mesh using given font. Use of ligatures, kerning etc. depends on features supported by particular font and its layouter.
Usage
Immutable text (e.g. menu items, credits) can be simply rendered using static methods, returning result either as data arrays or as fully configured mesh. The text can be then drawn as usual by configuring the shader and drawing the mesh:
/* Font instance, received from a plugin manager */ Containers::Pointer<Text::AbstractFont> font = …; /* Open a 12 pt font */ font->openFile("font.ttf", 12.0f); /* Populate a glyph cache */ Text::GlyphCacheGL cache{PixelFormat::R8Unorm, Vector2i{128}}; font->fillGlyphCache(cache, "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789?!:;,. "); Shaders::VectorGL2D shader; GL::Buffer vertexBuffer, indexBuffer; GL::Mesh mesh; /* Render a 12 pt text, centered */ std::tie(mesh, std::ignore) = Text::Renderer2D::render(*font, cache, 12.0f, "Hello World!", vertexBuffer, indexBuffer, GL::BufferUsage::StaticDraw, Text::Alignment::LineCenter); /* Projection matrix is matching application window size to have the size match 12 pt in other applications, assuming a 96 DPI display and no UI scaling. */ Matrix3 projectionMatrix = Matrix3::projection(Vector2{windowSize()}); /* Draw the text on the screen */ shader .setTransformationProjectionMatrix(projectionMatrix) .setColor(0xffffff_rgbf) .bindVectorTexture(cache.texture()) .draw(mesh);
See render(AbstractFont&, const AbstractGlyphCache&, Float, const std::
While this method is sufficient for one-shot rendering of static texts, for mutable texts (e.g. FPS counters, chat messages) there is another approach that doesn't recreate everything on each text change:
/* Initialize the renderer and reserve memory for enough glyphs */ Text::Renderer2D renderer{*font, cache, 12.0f, Text::Alignment::LineCenter}; renderer.reserve(32, GL::BufferUsage::DynamicDraw, GL::BufferUsage::StaticDraw); /* Update the text occasionally */ renderer.render("Hello World Countdown: 10"); /* Draw the text on the screen */ shader.setTransformationProjectionMatrix(projectionMatrix) .setColor(0xffffff_rgbf) .bindVectorTexture(cache.texture()) .draw(renderer.mesh());
Font size
As mentioned in AbstractFont class documentation, the size at which the font is loaded is decoupled from the size at which a concrete text is rendered. In particular, with a concrete projection matrix, the size you pass to either render() or to the Renderer() constructor will always result in the same size of the rendered text, independently of the size the font was loaded in. Size of the loaded font is the size at which the glyphs get prerendered into the glyph cache, affecting visual quality.
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 results in e.g. a 12 pt font matching a 12 pt font in other applications, and is what's shown in the above snippets. The most straightforward way to achieve that is to set up the projection matrix size to match actual window pixels, such as Platform::
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 DistanceFieldGlyphCache is the better match, as it can provide text at different sizes with minimal quality loss. 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 used by the Renderer 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 GlyphCache 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 GlyphCache font size like this. The Renderer keeps using the size without this multiplier.
Float sizeMultiplier = (Vector2{framebufferSize()}*dpiScaling()/Vector2{windowSize()}).max();
Required OpenGL functionality
Mutable text rendering requires ARB_
Base classes
- class AbstractRenderer
- Base for text renderers.
Public static functions
-
static auto render(AbstractFont& font,
const AbstractGlyphCache& cache,
Float size,
const std::
string& text, GL:: Buffer& vertexBuffer, GL:: Buffer& indexBuffer, GL:: BufferUsage usage, Alignment alignment = Alignment:: LineLeft) -> std:: tuple<GL:: Mesh, Range2D> - Render text.
Constructors, destructors, conversion operators
-
Renderer(AbstractFont& font,
const AbstractGlyphCache& cache,
Float size,
Alignment alignment = Alignment::
LineLeft) explicit - Constructor.
-
Renderer(AbstractFont&,
AbstractGlyphCache&&,
Float,
Alignment alignment = Alignment::
LineLeft) deleted
Function documentation
template<UnsignedInt dimensions>
static std:: tuple<GL:: Mesh, Range2D> Magnum:: Text:: Renderer<dimensions>:: render(AbstractFont& font,
const AbstractGlyphCache& cache,
Float size,
const std:: string& text,
GL:: Buffer& vertexBuffer,
GL:: Buffer& indexBuffer,
GL:: BufferUsage usage,
Alignment alignment = Alignment:: LineLeft)
Render text.
Parameters | |
---|---|
font | Font |
cache | Glyph cache |
size | Font size |
text | Text to render |
vertexBuffer | Buffer where to store vertices |
indexBuffer | Buffer where to store indices |
usage | Usage of vertex and index buffer |
alignment | Text alignment |
Returns a mesh prepared for use with Shaders::font
is present in cache
and that cache
isn't an array.
template<UnsignedInt dimensions>
Magnum:: Text:: Renderer<dimensions>:: Renderer(AbstractFont& font,
const AbstractGlyphCache& cache,
Float size,
Alignment alignment = Alignment:: LineLeft) explicit
Constructor.
Parameters | |
---|---|
font | Font |
cache | Glyph cache |
size | Font size |
alignment | Text alignment |
template<UnsignedInt dimensions>
Magnum:: Text:: Renderer<dimensions>:: Renderer(AbstractFont&,
AbstractGlyphCache&&,
Float,
Alignment alignment = Alignment:: LineLeft) deleted
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.