Skip to main content

OpenGLBackend.ixx File

OpenGL backend for render-pass execution and indexed draw submission. More...

Included Headers

#include <glad/gl.h> #include <GLFW/glfw3.h> #include <memory> #include <cassert> #include <utility> #include <type_traits> #include <span> #include "helios-opengl-config.h" #include <optional> #include <helios.engine.runtime.world.EngineWorld> #include <helios.opengl.types> #include <helios.engine.scene.components> #include <helios.engine.util.Colors> #include <helios.math> #include <helios.engine.rendering.common.types> #include <helios.engine.rendering.viewport> #include <helios.engine.rendering.material> #include <helios.engine.util.log> #include <helios.engine.rendering.viewport.ViewportEntity> #include <helios.opengl.OpenGLUniformWriter> #include <helios.opengl.components> #include <helios.engine.rendering.mesh> #include <helios.engine.rendering.renderTarget.RenderTargetEntity> #include <helios.engine.rendering.common.components> #include <helios.engine.rendering.renderTarget> #include <helios.engine.spatial.components> #include <helios.engine.core.components> #include <helios.engine.scene.types> #include <helios.engine.rendering.shader>

Namespaces Index

namespacehelios
namespaceopengl
namespacerendering
namespacecomponents
namespaceshader
namespacecomponents
namespacetypes
namespacetypes
namespacecomponents
namespacerenderTarget
namespacetypes
namespaceviewport
namespacetypes
namespacecomponents
namespacetypes
namespaceworld
namespacelog

Classes Index

classOpenGLBackend

Applies render-pass state and executes OpenGL draw calls. More...

structViewProjection

Per-viewport camera matrices used for a render pass. More...

Macro Definitions Index

#defineHELIOS_LOG_SCOPE   "helios::opengl"

Description

OpenGL backend for render-pass execution and indexed draw submission.

Macro Definitions

HELIOS_LOG_SCOPE

#define HELIOS_LOG_SCOPE   "helios::opengl"

Definition at line 74 of file OpenGLBackend.ixx.

74#define HELIOS_LOG_SCOPE "helios::opengl"

File Listing

The file content with the documentation metadata removed is:

1
5module;
6
7#include <glad/gl.h>
8#include <GLFW/glfw3.h>
9#include <memory>
10#include <cassert>
11#include <utility>
12#include <type_traits>
13#include <span>
15#include <optional>
16
17export module helios.opengl.OpenGLBackend;
18
19import helios.math;
20
21import helios.engine.util.log;
22
23import helios.engine.rendering.viewport.ViewportEntity;
24
25import helios.engine.rendering.renderTarget.RenderTargetEntity;
26import helios.engine.rendering.common.types;
27import helios.engine.rendering.common.components;
28
29import helios.engine.spatial.components;
30
31import helios.engine.core.components;
32
33import helios.opengl.OpenGLUniformWriter;
34import helios.opengl.components;
35import helios.opengl.types;
36
37
38import helios.engine.rendering.mesh;
39import helios.engine.rendering.shader;
40import helios.engine.rendering.material;
41import helios.engine.rendering.renderTarget;
42import helios.engine.rendering.viewport;
43import helios.engine.util.Colors;
44
45import helios.engine.scene.components;
46import helios.engine.scene.types;
47
48import helios.engine.runtime.world.EngineWorld;
49
50import helios.opengl.types;
51
52using namespace helios::engine::core::components;
53using namespace helios::engine::rendering;
54using namespace helios::engine::rendering::mesh::components;
55using namespace helios::engine::rendering::shader;
56using namespace helios::engine::rendering::shader::types;
57using namespace helios::opengl;
58using namespace helios::opengl::components;
59using namespace helios::opengl::types;
60using namespace helios::engine::spatial::components;
61using namespace helios::engine::rendering::material::types;
62using namespace helios::engine::rendering::common::types;
63using namespace helios::engine::rendering::common::components;
64using namespace helios::engine::rendering::mesh::types;
65using namespace helios::engine::rendering::renderTarget;
66using namespace helios::engine::rendering::renderTarget::types;
67using namespace helios::engine::rendering::viewport;
68using namespace helios::engine::rendering::viewport::types;
69using namespace helios::engine::scene::components;
70using namespace helios::engine::scene::types;
71using namespace helios::engine::runtime::world;
72using namespace helios::engine::util::log;
73
74#define HELIOS_LOG_SCOPE "helios::opengl"
75export namespace helios::opengl {
76
77
85 private:
86
87
91 bool isInitialized_ = false;
92
93 inline static const helios::engine::util::log::Logger& logger_ = helios::engine::util::log::LogManager::loggerForScope(
95 );
96
100 OpenGLMeshComponent<MeshHandle>* currentOpenGLMesh_ = nullptr;
101
105 UniformValueBag<UniformScope::Pass> passUniformValueBag_{};
106
110 UniformValueBag<UniformScope::Draw> drawUniformValueBag_{};
111
115 RenderTargetHandle currentRenderTargetHandle_{};
116
120 ShaderHandle currentShaderHandle_{};
121
122
126 EngineWorld& engineWorld_;
127
131 struct ViewProjection {
132 helios::math::mat4f viewMatrix;
133 helios::math::mat4f projectionMatrix;
134 };
135
143 [[nodiscard]] std::optional<ViewProjection> viewProjection(const ViewportEntity& vieportEntity) const noexcept {
144
145 auto* cbc = vieportEntity.get<CameraBindingComponent<ViewportHandle>>();
146 if (!cbc) {
147 logger_.error("Expected CameraBindingComponent on ViewportEntity, but couldn't find any.");
148 return std::nullopt;
149 }
150 auto camera = engineWorld_.find(cbc->targetHandle());
151 if (!camera) {
152 logger_.error("Expected CameraEntity, but couldn't find any.");
153 return std::nullopt;
154 }
155 using CameraHandleType = std::remove_cvref_t<decltype(cbc->targetHandle())>;
156 auto* vm = camera->get<ViewMatrixComponent<CameraHandleType>>();
157 if (!vm) {
158 logger_.error("Expected ViewMatrixComponent, but couldn't find any.");
159 return std::nullopt;
160 }
161
162 auto* pm = camera->get<ProjectionMatrixComponent<CameraHandleType>>();
163 if (!pm) {
164 logger_.error("Expected ProjectionMatrixComponent, but couldn't find any.");
165 return std::nullopt;
166 }
167
168 return ViewProjection{
169 vm->value(), pm->value()
170 };
171
172 }
173
186 template<typename TUniformScope>
187 void writeUniformValues(ShaderEntity shaderEntity, UniformValueBag<TUniformScope>& uniformValueBag) noexcept {
188
190
191 if (!ulc) {
192 logger_.error("OpenGLUniformWritePlanComponent<{0}> expected, but not found", typeid(TUniformScope).name());
193 assert(false && "OpenGLUniformWritePlanComponent not found");
194 return;
195 }
196
197 OpenGLUniformWriter::write(ulc->operations, uniformValueBag);
198 }
199
200
209 template<typename THandle, typename TEntity>
210 void clearColor(TEntity& entity) noexcept {
211
212 auto* colorComp = entity->template get<ColorComponent<THandle>>();
213 auto* clearComp = entity->template get<ClearComponent<THandle>>();
214
215 if (colorComp) {
216 const auto clearColor = colorComp->value();
217 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
218 }
219
220 if (clearComp) {
221 const auto clearFlags = std::to_underlying(clearComp->flags);
222 const auto clearMask = ((clearFlags & std::to_underlying(ClearFlags::Color)) ? GL_COLOR_BUFFER_BIT : 0) |
223 ((clearFlags & std::to_underlying(ClearFlags::Depth)) ? GL_DEPTH_BUFFER_BIT : 0) |
224 ((clearFlags & std::to_underlying(ClearFlags::Stencil)) ? GL_STENCIL_BUFFER_BIT : 0);
225
226 if (clearMask != 0) {
227 glClear(clearMask);
228 }
229 }
230 }
231
232
233 public:
234
235
236
242 explicit OpenGLBackend(EngineWorld& engineWorld) : engineWorld_(engineWorld){}
243
244
253 void beginRenderTargetBatch(const RenderTargetHandle renderTargetHandle) noexcept {
254
255 auto renderTargetEntity = engineWorld_.find<RenderTargetHandle>(renderTargetHandle);
256
257 #ifdef HELIOS_DEBUG
258 if (!renderTargetEntity) {
259 logger_.error("Missing RenderTargetEntity for handle {0}.", renderTargetHandle.entityId);
260 assert(renderTargetEntity && "Missing RenderTargetEntity for handle.");
261 }
262 #endif
263
264 currentRenderTargetHandle_ = renderTargetHandle;
265
266 const auto renderTargetId = renderTargetEntity->get<OpenGLRenderTargetIdComponent<RenderTargetHandle>>()->value();
267
268 glBindFramebuffer(GL_FRAMEBUFFER, renderTargetId);
269
270 #ifdef HELIOS_DEBUG
271 const auto isValidRenderTarget = renderTargetId == 0 ||
272 (glIsFramebuffer(renderTargetId) == GL_TRUE && glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
273 if (!isValidRenderTarget) {
274 logger_.error("RenderTargetEntity with EntityId {0} undefined.", renderTargetId);
275 assert(isValidRenderTarget && "RenderTargetEntity EntityId does not seem to be a valid id.");
276 }
277 #endif
278
279 auto renderTargetSize = renderTargetEntity->get<Size2DComponent<RenderTargetHandle>>()->value();
280
281 glViewport(0, 0,
282 static_cast<int>(renderTargetSize[0]),
283 static_cast<int>(renderTargetSize[1])
284 );
285
286 clearColor<RenderTargetHandle>(renderTargetEntity);
287
288 // this is equally important for the GlpyhTextRenderer
289 // enable blending since the font's fragment shader uses the alpha channel
290 glEnable(GL_BLEND);
291 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
292 }
293
301 void endRenderTargetBatch(const RenderTargetHandle renderTargetHandle) noexcept {
302
303 currentRenderTargetHandle_ = RenderTargetHandle{};
304 passUniformValueBag_.clearValues();
305 drawUniformValueBag_.clearValues();
306 }
307
316 void beginViewportBatch(const ViewportHandle viewportHandle) noexcept {
317
318 auto viewport = engineWorld_.find<ViewportHandle>(viewportHandle);
319 auto renderTargetEntity = engineWorld_.find<RenderTargetHandle>(currentRenderTargetHandle_);
320
321 #ifdef HELIOS_DEBUG
322 if (!renderTargetEntity) {
323 logger_.error("Missing RenderTargetEntity for handle {0}.", renderTargetEntity->handle().entityId);
324 assert(renderTargetEntity && "Missing RenderTargetEntity for handle.");
325 }
326 if (!viewport) {
327 logger_.error("Missing Viewport for handle {0}.", viewportHandle.entityId);
328 assert(viewport && "Missing Viewport for handle.");
329 }
330 #endif
331
332 auto vp = viewProjection(*viewport);
333 if (!vp) {
334 logger_.warn("Could not determine View/Projection-matrices for RenderPass");
335 passUniformValueBag_.set<ProjectionMatrixUniform>(helios::math::mat4f{1.0f});
336 passUniformValueBag_.set<ViewMatrixUniform>(helios::math::mat4f{1.0f});
337 } else {
338 passUniformValueBag_.set<ProjectionMatrixUniform>(vp->projectionMatrix);
339 passUniformValueBag_.set<ViewMatrixUniform>(vp->viewMatrix);
340 }
341
342 auto viewportBounds = viewport->get<RectComponent<ViewportHandle>>()->value();
343 auto renderTargetSize = renderTargetEntity->get<Size2DComponent<RenderTargetHandle>>()->value();
344
345 const auto x = static_cast<int>(renderTargetSize[0] * viewportBounds[0]);
346 const auto y = static_cast<int>(renderTargetSize[1] * viewportBounds[1]);
347 const auto width = static_cast<int>(renderTargetSize[0] * viewportBounds[2]);
348 const auto height = static_cast<int>(renderTargetSize[1] * viewportBounds[3]);
349
350
351 glViewport(x, y, width, height);
352 glScissor(x, y, width, height);
353 glEnable(GL_SCISSOR_TEST);
354
355 clearColor<ViewportHandle>(viewport);
356 }
357
363 void endViewportBatch(const ViewportHandle viewportHandle) noexcept {
364 glDisable(GL_SCISSOR_TEST);
365 }
366
374 void beginShaderBatch(ShaderHandle shaderHandle) noexcept {
375
376 auto shaderEntity = engineWorld_.find(shaderHandle);
377 if (!shaderEntity) {
378 logger_.error("ShaderEntity expected, but not found");
379 assert(false && "ShaderEntity not found");
380 return;
381 }
382
383 currentShaderHandle_ = shaderHandle;
384
385 auto* openglShader = shaderEntity->template get<OpenGLShaderComponent<ShaderHandle>>();
386 if (!openglShader) {
387 logger_.error("OpenGLShader expected, but not found");
388 assert(false && "OpenGLShader not found");
389 return;
390 }
391
392 glUseProgram(openglShader->programId);
393 writeUniformValues<UniformScope::Pass>(*shaderEntity, passUniformValueBag_);
394 }
395
401 void endShaderBatch(ShaderHandle handle) noexcept {
402 currentShaderHandle_ = ShaderHandle{};
403 }
404
412 void beginMaterialBatch(MaterialHandle materialHandle) noexcept {
413 auto materialEntity = engineWorld_.find(materialHandle);
414 if (!materialEntity) {
415 logger_.error("MaterialEntity expected, but not found");
416 assert(false && "MaterialEntity not found");
417 return;
418 }
419
420 auto* colorComponent = materialEntity->template get<ColorComponent<MaterialHandle>>();
421 if (colorComponent) {
422 drawUniformValueBag_.set<MaterialBaseColorUniform>(colorComponent->value());
423 }
424
425 }
426
432 void endMaterialBatch(MaterialHandle handle) noexcept {
433 // intentionally left empty
434 }
435
443 void beginMeshBatch(MeshHandle meshHandle) noexcept {
444
445 auto meshEntity = engineWorld_.find(meshHandle);
446 if (!meshEntity) {
447 logger_.error("MeshEntity expected, but not found");
448 assert(false && "MeshEntity not found");
449 return;
450 }
451
452 auto* openglMesh = meshEntity->template get<OpenGLMeshComponent<MeshHandle>>();
453 if (!openglMesh) {
454 logger_.error("OpenGLMesh expected, but not found");
455 assert(false && "OpenGLMesh not found");
456 return;
457 } else {
458 currentOpenGLMesh_ = openglMesh;
459 glBindVertexArray(openglMesh->vao);
460 }
461 }
462
468 void endMeshBatch(MeshHandle handle) noexcept {
469 currentOpenGLMesh_ = nullptr;
470 glBindVertexArray(0);
471 }
472
482 template<typename THandle>
483 void renderBatch(std::span<SceneMemberRenderContext<THandle>> sceneMemberRenderContexts) noexcept {
484
485 if (!currentOpenGLMesh_) {
486 logger_.error("OpenGLMesh expected, but not available");
487 return;
488 }
489 if (!currentShaderHandle_.isValid()) {
490 logger_.error("Expected valid currentShaderHandle_, but found {0}.", currentShaderHandle_.entityId);
491 return;
492 }
493
494 auto shaderEntity = engineWorld_.find(currentShaderHandle_);
495
496 assert(shaderEntity && "ShaderEntity expected, but not found");
497 assert(currentOpenGLMesh_ && "Current OpenGL mesh expected, but not found");
498
499 for (auto& renderContext : sceneMemberRenderContexts) {
500
501 drawUniformValueBag_.set<ModelMatrixUniform>(renderContext.worldMatrix);
502 writeUniformValues<UniformScope::Draw>(*shaderEntity, drawUniformValueBag_);
503 glDrawElements(
504 currentOpenGLMesh_->primitiveType,
505 currentOpenGLMesh_->indexCount,
506 GL_UNSIGNED_INT,
507 nullptr
508 );
509
510 }
511 }
512
519 void provideWindowHints() noexcept {
520
521 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
522 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
523 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
524
525 }
526
534 [[nodiscard]] bool init() noexcept {
535
536 assert(!isInitialized_ && "Backend already initialized");
537
538 const GLADloadfunc procAddressLoader = glfwGetProcAddress;
539 const int gl_ver = gladLoadGL(procAddressLoader);
540
541 if (gl_ver == 0) {
542 logger_.error("Failed to load OpenGL");
543 assert(false && "Failed to load OpenGL");
544 return false;
545 }
546
547 logger_.info("OpenGL {0}.{1} loaded", GLAD_VERSION_MAJOR(gl_ver), GLAD_VERSION_MINOR(gl_ver));
548
549 isInitialized_ = true;
550 return true;
551
552 }
553
557 [[nodiscard]] bool isInitialized() const noexcept {
558 return isInitialized_;
559 }
560
561 };
562} // namespace helios::opengl

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.