Text Rendering Demo
This example demonstrates how to render dynamic text using the helios text rendering system. It showcases FreeType-based glyph rendering with OpenGL, including font loading, text positioning, and real-time text updates.
What You'll Learn
- Setting up the text rendering pipeline
- Loading fonts via
FontResourceProvider - Creating
TextRenderPrototypefor shared shader configuration - Using
TextRenderablefor dynamic text display - Integrating text into the scene graph
- Configuring orthographic projection for 2D UI text
Prerequisites
- helios framework properly built and installed
- Basic understanding of C++ and OpenGL
- FreeType library (automatically included via helios)
Project Structure
render_text_demo/
├── main.cpp # Main application code
├── resources/
│ ├── font_shader.vert # Vertex shader for text
│ ├── font_shader.frag # Fragment shader for text
│ ├── Roboto-SemiBoldItalic.ttf # Font file
│ ├── OFL.txt # Font license
│ └── README.txt # Font attribution
└── README.md # This file
Step-by-Step Tutorial
1. Application and Window Setup
Create an OpenGL application with a configured viewport:
constexpr int SCREEN_WIDTH = 1920;
constexpr int SCREEN_HEIGHT = 1080;
const auto app = helios::ext::glfw::app::GLFWFactory::makeOpenGLApp(
"helios - Text Rendering Demo",
SCREEN_WIDTH, SCREEN_HEIGHT,
16.0f, 9.0f // Aspect ratio
);
auto* win = dynamic_cast<helios::ext::glfw::window::GLFWWindow*>(app->current());
auto mainViewport = std::make_shared<helios::rendering::Viewport>(0.0f, 0.0f, 1.0f, 1.0f);
mainViewport->setClearFlags(std::to_underlying(helios::rendering::ClearFlags::Color))
.setClearColor(helios::math::vec4f(0.051f, 0.051f, 0.153f, 1.0f));
win->addViewport(mainViewport);
2. UI Scene and Orthographic Camera
Text rendering uses a dedicated scene with orthographic projection:
// Create UI scene with no culling (all text is always visible).
auto uiScene = std::make_unique<helios::scene::Scene>(
std::make_unique<helios::scene::CullNoneStrategy>()
);
// Create UI viewport.
auto uiViewport = std::make_shared<helios::rendering::Viewport>(0.0f, 0.0f, 1.0f, 1.0f);
win->addViewport(uiViewport);
// Configure orthographic camera.
// Origin (0,0) is at the bottom-left corner of the screen.
auto uiCamera = std::make_unique<helios::scene::Camera>();
auto uiCameraSceneNode = std::make_unique<helios::scene::CameraSceneNode>(std::move(uiCamera));
auto* uiCameraSceneNode_ptr = uiCameraSceneNode.get();
uiViewport->setCameraSceneNode(uiCameraSceneNode_ptr);
uiCameraSceneNode_ptr->camera().setOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT);
uiCameraSceneNode_ptr->setTranslation(helios::math::vec3f(0.0f, 0.0f, -100.0f));
uiCameraSceneNode_ptr->lookAtLocal(
helios::math::vec3f(0.0f, 0.0f, 0.0f),
helios::math::vec3f(0.0f, 1.0f, 0.0f)
);
std::ignore = uiScene->addNode(std::move(uiCameraSceneNode));
3. Text Shader Setup
The text shader requires specific uniform locations:
auto glyphUniformLocationMap = std::make_unique<
helios::ext::opengl::rendering::shader::OpenGLUniformLocationMap
>();
glyphUniformLocationMap->set(helios::rendering::shader::UniformSemantics::ProjectionMatrix, 1);
glyphUniformLocationMap->set(helios::rendering::shader::UniformSemantics::TextTexture, 3);
glyphUniformLocationMap->set(helios::rendering::shader::UniformSemantics::TextColor, 4);
glyphUniformLocationMap->set(helios::rendering::shader::UniformSemantics::ModelMatrix, 8);
glyphUniformLocationMap->set(helios::rendering::shader::UniformSemantics::ViewMatrix, 9);
auto glyphShader = std::make_shared<helios::ext::opengl::rendering::shader::OpenGLShader>(
"resources/font_shader.vert",
"resources/font_shader.frag",
helios::util::io::BasicStringFileReader()
);
glyphShader->setUniformLocationMap(std::move(glyphUniformLocationMap));
4. Font Loading
Load fonts via the rendering device's font resource provider:
auto fontId = helios::engine::core::data::FontId{"roboto"};
auto& fontResourceProvider = app->renderingDevice().fontResourceProvider();
fontResourceProvider.loadFont(fontId, "resources/Roboto-SemiBoldItalic.ttf");
5. Text Prototype and Renderable
Create a reusable prototype and text instance:
// Shared prototype with shader and font configuration.
auto uiTextPrototype = std::make_shared<helios::rendering::text::TextRenderPrototype>(
glyphShader,
std::make_shared<helios::rendering::text::TextShaderProperties>(),
&fontResourceProvider
);
// Create a TextRenderable for dynamic text display.
auto textRenderable = std::make_shared<helios::rendering::text::TextRenderable>(
std::make_unique<helios::rendering::text::TextMesh>("Hello World!", fontId),
uiTextPrototype
);
// Add to the scene graph.
auto textSceneNode = std::make_unique<helios::scene::SceneNode>(textRenderable);
auto* textNode = uiScene->addNode(std::move(textSceneNode));
textNode->setScale({1.0f, 1.0f, 1.0f});
textNode->setTranslation({100.0f, 100.0f, 0.0f});
6. Render Loop
Update and render text each frame:
float deltaTime = 0.0f;
while (!win->shouldClose()) {
framePacer.beginFrame();
app->eventManager().dispatchAll();
inputManager.poll(0.0f);
if (inputManager.isKeyPressed(helios::input::types::Key::ESC)) {
win->setShouldClose(true);
}
// Update text content dynamically.
textRenderable->setText(std::format("Frame Time: {:.4f} ms", deltaTime * 1000.0f));
// Render the UI scene.
const auto& uiSnapshot = uiScene->createSnapshot(*uiViewport);
if (uiSnapshot.has_value()) {
auto uiRenderPass = helios::rendering::RenderPassFactory::getInstance()
.buildRenderPass(*uiSnapshot);
app->renderingDevice().render(uiRenderPass);
}
win->swapBuffers();
frameStats = framePacer.sync();
deltaTime = frameStats.totalFrameTime;
}
Key Concepts
Text Rendering Pipeline
TextRenderable (high-level, scene graph)
│
▼
TextRenderCommand (low-level, per-frame)
│
▼
RenderQueue
│
▼
OpenGLGlyphTextRenderer (FreeType + OpenGL)
Coordinate System
Text uses screen-space coordinates with orthographic projection:
(0, 1080) ─────────────────── (1920, 1080)
│ │
│ Text appears here │
│ at (100, 100) │
│ ● │
│ │
(0, 0) ─────────────────────── (1920, 0)
Controls
- ESC - Exit application
Running the Example
cd build/bin
./render_text_demo
Expected Output
A window displaying "Frame Time: X.XXXX ms" where X updates each frame, rendered in white text on a dark blue background.
See Also
- Simple Cube Rendering - Basic 3D rendering
- Spaceship Control - Complete game loop example
- Spaceship Shooting - Advanced gameplay mechanics