Skip to main content

OpenGLDevice.ixx File

OpenGL-specific RenderingDevice implementation. More...

Included Headers

Namespaces Index

namespacehelios
namespaceext

Platform-specific extensions and backend implementations. More...

namespaceopengl

OpenGL-specific implementations. More...

namespacerendering

OpenGL rendering implementations. More...

Classes Index

classOpenGLDevice

OpenGL implementation of `RenderingDevice`. More...

Description

OpenGL-specific RenderingDevice implementation.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file OpenGLDevice.ixx
3 * @brief OpenGL-specific RenderingDevice implementation.
4 */
5module;
6
7#include <glad/gl.h>
8#include <GLFW/glfw3.h>
9#include <format>
10#include <stdexcept>
11#include <utility>
12#include <cassert>
13
14export module helios.ext.opengl.rendering.OpenGLDevice;
15
16import helios.math.types;
17import helios.rendering.RenderingDevice;
18import helios.rendering.RenderQueue;
19import helios.rendering.RenderPass;
20import helios.rendering.mesh.PrimitiveType;
21import helios.rendering.mesh.MeshConfig;
22import helios.rendering.ClearFlags;
23import helios.rendering.RenderTarget;
24import helios.rendering.Viewport;
25
26import helios.rendering.text.TextRenderer;
27import helios.rendering.text.FontResourceProvider;
28
29import helios.ext.opengl.rendering.model.OpenGLMesh;
30import helios.ext.opengl.rendering.shader.OpenGLShader;
31import helios.ext.opengl.rendering.OpenGLGlyphTextRenderer;
32import helios.ext.opengl.rendering.OpenGLMeshRenderer;
33
34export namespace helios::ext::opengl::rendering {
35
36 /**
37 * @brief OpenGL implementation of `RenderingDevice`.
38 *
39 * `OpenGLDevice` is the concrete OpenGL backend for the helios rendering system.
40 * It handles all OpenGL-specific operations including mesh rendering, shader management,
41 * and text rendering via `OpenGLGlyphTextRenderer`.
42 *
43 * ## Responsibilities
44 *
45 * - **Initialization:** Load OpenGL function pointers via GLAD.
46 * - **Render Pass Execution:** Configure viewport, clear buffers, and process render commands.
47 * - **Mesh Rendering:** Bind VAOs and issue draw calls for geometry.
48 * - **Text Rendering:** Delegate text commands to `OpenGLGlyphTextRenderer`.
49 *
50 * ## Usage
51 *
52 * ```cpp
53 * auto textRenderer = std::make_unique<OpenGLGlyphTextRenderer>();
54 * auto device = std::make_unique<OpenGLDevice>(std::move(textRenderer));
55 *
56 * // After creating OpenGL context
57 * device->init();
58 *
59 * // Load fonts via the text renderer
60 * device->textRenderer().addFontFamily(FontId{1}, "fonts/arial.ttf");
61 * ```
62 *
63 * @see RenderingDevice
64 * @see OpenGLGlyphTextRenderer
65 */
67
68
69 /**
70 * @brief Text renderer for FreeType-based glyph rendering.
71 */
72 std::unique_ptr<helios::ext::opengl::rendering::OpenGLGlyphTextRenderer> textRenderer_;
73
74 /**
75 * @brief Mesh renderer for geometry rendering.
76 */
77 std::unique_ptr<helios::ext::opengl::rendering::OpenGLMeshRenderer> meshRenderer_;
78
79 /**
80 * @brief Font resource provider for loading fonts and retrieving glyph data.
81 */
82 std::unique_ptr<helios::rendering::text::FontResourceProvider> fontResourceProvider_;
83
84
85 public:
86 ~OpenGLDevice() override = default;
87
88 /**
89 * @brief Constructs an OpenGLDevice with the given renderers and font provider.
90 *
91 * @param meshRenderer The mesh renderer for geometry rendering.
92 * @param textRenderer The text renderer for glyph-based text rendering.
93 * @param fontResourceProvider The font resource provider for loading fonts.
94 */
95 explicit OpenGLDevice(
96 std::unique_ptr<helios::ext::opengl::rendering::OpenGLMeshRenderer> meshRenderer,
97 std::unique_ptr<helios::ext::opengl::rendering::OpenGLGlyphTextRenderer> textRenderer,
98 std::unique_ptr<helios::rendering::text::FontResourceProvider> fontResourceProvider
99 ) :
100 meshRenderer_(std::move(meshRenderer)),
101 textRenderer_(std::move(textRenderer)),
102 fontResourceProvider_(std::move(fontResourceProvider)){}
103
104 /**
105 * @brief Initializes the OpenGL device to access modern OpenGL.
106 *
107 * This method must be called **after** the helios application's `setCurrent()` was called
108 * for creating a current context. This OpenGL device will then load from this context.
109 *
110 * This method uses the `gladLoadGL` method in conjunction with `glfwGetProcAddress`,
111 * which returns the address of the specific OpenGL core.
112 *
113 * @see https://www.glfw.org/docs/latest/group__context.html#ga35f1837e6f666781842483937612f163
114 *
115 * @todo Provide abstraction for glfwGetProcAddress.
116 */
117 void init() override {
118 if (initialized_) {
119 return;
120 }
121 const GLADloadfunc procAddressLoader = glfwGetProcAddress;
122 const int gl_ver = gladLoadGL(procAddressLoader);
123
124 if (gl_ver == 0) {
125 logger_.error("Failed to load OpenGL");
126 throw std::runtime_error("Failed to load OpenGL");
127 }
128
129 textRenderer_->init();
130
131 logger_.info(std::format("OpenGL {0}.{1} loaded", GLAD_VERSION_MAJOR(gl_ver), GLAD_VERSION_MINOR(gl_ver)));
132
133 initialized_ = true;
134 }
135
136 /**
137 * @brief Begins a new render pass.
138 *
139 * This implementation makes sure that the rendering surface is cleared
140 * with the current clear color, which can be configured via `clearColor()`.
141 *
142 * @param renderPass The render pass to begin.
143 *
144 * @see clear()
145 * @see clearColor()
146 */
147 void beginRenderPass(helios::rendering::RenderPass& renderPass) const noexcept override {
148 meshRenderer_->beginRenderPass(renderPass);
149 textRenderer_->beginRenderPass(renderPass);
150
151 const auto& viewport = renderPass.viewport();
152
153 assert(viewport.renderTarget() && "Unexpected missing render target for viewport");
154
155 const helios::rendering::RenderTarget& renderTarget = *(viewport.renderTarget());
156 const auto viewportBounds = viewport.bounds();
157 const auto col = viewport.clearColor();
158 glViewport(static_cast<int>(renderTarget.width() * viewportBounds[0]),
159 static_cast<int>(renderTarget.height() * viewportBounds[1]),
160 static_cast<int>(renderTarget.width() * viewportBounds[2]),
161 static_cast<int>(renderTarget.height() * viewportBounds[3]));
162
163
164 // this is equally important for the GlpyhTextRenderer
165 // enable blending since the font's fragment shader uses the alpha channel
166 glEnable(GL_BLEND);
167 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
168
169
170 glClearColor(col[0], col[1], col[2], col[3]);
171
172 const int clearFlags = viewport.clearFlags();
173 glClear(((clearFlags & std::to_underlying(helios::rendering::ClearFlags::Color)) ? GL_COLOR_BUFFER_BIT : 0) |
174 ((clearFlags & std::to_underlying(helios::rendering::ClearFlags::Depth)) ? GL_DEPTH_BUFFER_BIT : 0) |
175 ((clearFlags & std::to_underlying(helios::rendering::ClearFlags::Stencil)) ? GL_STENCIL_BUFFER_BIT
176 : 0));
177 }
178
179 /**
180 * @brief Processes render commands and draws geometry and text.
181 *
182 * Iterates through all render commands in the render queue, binds the appropriate
183 * shaders and VAOs, applies uniform values, and issues draw calls. After processing
184 * geometry, delegates any text render commands to `renderTextCommands()`.
185 *
186 * @param renderPass The render pass containing the render queue to be processed.
187 *
188 * @see renderTextCommands()
189 */
190 void doRender(helios::rendering::RenderPass& renderPass) const noexcept override {
191 const auto& renderQueue = renderPass.renderQueue();
192
193 if (renderQueue.meshRenderCommandsSize() > 0) {
194 renderMeshCommands(renderPass);
195 }
196
197 if (renderQueue.textRenderCommandsSize() > 0) {
198 renderTextCommands(renderPass);
199 }
200 }
201
202 /**
203 * @brief Renders all mesh commands in the render pass.
204 *
205 * Iterates through the mesh render commands in the render queue and delegates
206 * each command to the `OpenGLMeshRenderer` for rendering.
207 *
208 * @param renderPass The render pass containing mesh render commands.
209 */
210 void renderMeshCommands(const helios::rendering::RenderPass& renderPass) const noexcept {
211
212 const auto& renderQueue = renderPass.renderQueue();
213
214 for (auto& rc: renderQueue.meshRenderCommands()) {
215 meshRenderer_->render(rc, renderPass.frameUniformValues());
216 }
217
218 }
219
220 /**
221 * @brief Renders all text commands in the render pass.
222 *
223 * Iterates through the text render commands in the render queue and delegates
224 * each command to the `OpenGLGlyphTextRenderer` for rendering.
225 *
226 * @param renderPass The render pass containing text render commands.
227 */
228 void renderTextCommands(const helios::rendering::RenderPass& renderPass) const noexcept {
229 const auto& renderQueue = renderPass.renderQueue();
230
231 for (auto& rc: renderQueue.textRenderCommands()) {
232 textRenderer_->render(rc, renderPass.frameUniformValues());
233 }
234 }
235
236 /**
237 * @brief Ends the specified render pass.
238 *
239 * The current implementation does nothing.
240 *
241 * @param renderPass The render pass to end.
242 */
243 void endRenderPass(helios::rendering::RenderPass& renderPass) const noexcept override {
244 glBindVertexArray(0);
245 }
246
247 /**
248 * @brief Returns a reference to the text renderer.
249 *
250 * Use this to register font families before rendering text.
251 *
252 * @return Reference to the `TextRenderer` interface.
253 *
254 * @see OpenGLGlyphTextRenderer::addFontFamily()
255 */
256 [[nodiscard]] helios::rendering::text::TextRenderer& textRenderer() const noexcept {
257 return *textRenderer_;
258 }
259
260 /**
261 * @brief Returns a reference to the font resource provider.
262 *
263 * Use this to load fonts before creating `TextRenderPrototype` instances.
264 *
265 * @return Reference to the `FontResourceProvider` implementation.
266 */
268 return *fontResourceProvider_;
269 }
270
271
272 };
273} // namespace helios::ext::opengl::rendering

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.