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.scene.types> #include <helios.opengl.types> #include <helios.engine.rendering.renderTarget> #include <helios.engine.scene.components> #include <helios.ecs.types> #include <helios.engine.rendering.viewport> #include <helios.engine.core.components> #include <helios.opengl.OpenGLUniformWriter> #include <helios.engine.rendering.viewport.ViewportEntity> #include <helios.engine.rendering.renderTarget.RenderTargetEntity> #include <helios.engine.runtime.world.EngineWorld> #include <helios.engine.util.Colors> #include <helios.opengl.components> #include <helios.engine.util.log> #include <helios.engine.rendering.material> #include <helios.math> #include <helios.engine.rendering.common.types> #include <helios.engine.rendering.mesh> #include <helios.engine.rendering.shader> #include <helios.engine.rendering.common.components> #include <helios.engine.spatial.components>

Namespaces Index

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

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 77 of file OpenGLBackend.ixx.

77#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.ecs.types;
20
21import helios.math;
22
23import helios.engine.util.log;
24
25import helios.engine.rendering.viewport.ViewportEntity;
26
27import helios.engine.rendering.renderTarget.RenderTargetEntity;
28import helios.engine.rendering.common.types;
29import helios.engine.rendering.common.components;
30
31import helios.engine.spatial.components;
32
33import helios.engine.core.components;
34
35import helios.opengl.OpenGLUniformWriter;
36import helios.opengl.components;
37import helios.opengl.types;
38
39
40import helios.engine.rendering.mesh;
41import helios.engine.rendering.shader;
42import helios.engine.rendering.material;
43import helios.engine.rendering.renderTarget;
44import helios.engine.rendering.viewport;
45import helios.engine.util.Colors;
46
47import helios.engine.scene.components;
48import helios.engine.scene.types;
49
50import helios.engine.runtime.world.EngineWorld;
51
52import helios.opengl.types;
53
54using namespace helios::engine::core::components;
55using namespace helios::engine::rendering;
56using namespace helios::engine::rendering::mesh::components;
57using namespace helios::engine::rendering::shader;
58using namespace helios::engine::rendering::shader::types;
59using namespace helios::opengl;
60using namespace helios::opengl::components;
61using namespace helios::opengl::types;
62using namespace helios::engine::spatial::components;
63using namespace helios::engine::rendering::material::types;
64using namespace helios::engine::rendering::common::types;
65using namespace helios::engine::rendering::common::components;
66using namespace helios::engine::rendering::mesh::types;
67using namespace helios::engine::rendering::renderTarget;
68using namespace helios::engine::rendering::renderTarget::types;
69using namespace helios::engine::rendering::viewport;
70using namespace helios::engine::rendering::viewport::types;
71using namespace helios::engine::scene::components;
72using namespace helios::engine::scene::types;
73using namespace helios::engine::runtime::world;
74using namespace helios::engine::util::log;
75using namespace helios::ecs::types;
76
77#define HELIOS_LOG_SCOPE "helios::opengl"
78export namespace helios::opengl {
79
80
88 private:
89
90
94 bool isInitialized_ = false;
95
96 inline static const helios::engine::util::log::Logger& logger_ = helios::engine::util::log::LogManager::loggerForScope(
98 );
99
103 OpenGLMeshComponent<MeshHandle>* currentOpenGLMesh_ = nullptr;
104
108 UniformValueBag<UniformScope::Pass> passUniformValueBag_{};
109
113 UniformValueBag<UniformScope::Draw> drawUniformValueBag_{};
114
118 RenderTargetHandle currentRenderTargetHandle_{};
119
123 ShaderHandle currentShaderHandle_{};
124
125
129 EngineWorld& engineWorld_;
130
134 struct ViewProjection {
135 helios::math::mat4f viewMatrix;
136 helios::math::mat4f projectionMatrix;
137 };
138
146 [[nodiscard]] std::optional<ViewProjection> viewProjection(const ViewportEntity& vieportEntity) const noexcept {
147
148 auto* cbc = vieportEntity.get<CameraBindingComponent<ViewportHandle>>();
149 if (!cbc) {
150 logger_.error("Expected CameraBindingComponent on ViewportEntity, but couldn't find any.");
151 return std::nullopt;
152 }
153 auto camera = engineWorld_.find(cbc->targetHandle());
154 if (!camera) {
155 logger_.error("Expected CameraEntity, but couldn't find any.");
156 return std::nullopt;
157 }
158 using CameryHandleType = std::remove_cvref_t<decltype(cbc->targetHandle())>;
159 auto* vm = camera->get<ViewMatrixComponent<CameryHandleType>>();
160 if (!vm) {
161 logger_.error("Expected ViewMatrixComponent, but couldn't find any.");
162 return std::nullopt;
163 }
164
165 auto* pm = camera->get<ProjectionMatrixComponent<CameryHandleType>>();
166 if (!pm) {
167 logger_.error("Expected ProjectionMatrixComponent, but couldn't find any.");
168 return std::nullopt;
169 }
170
171 return ViewProjection{
172 vm->value(), pm->value()
173 };
174
175 }
176
189 template<typename TUniformScope>
190 void writeUniformValues(ShaderEntity shaderEntity, UniformValueBag<TUniformScope>& uniformValueBag) noexcept {
191
193
194 if (!ulc) {
195 logger_.error("OpenGLUniformWritePlanComponent<{0}> expected, but not found", typeid(TUniformScope).name());
196 assert(false && "OpenGLUniformWritePlanComponent not found");
197 return;
198 }
199
200 OpenGLUniformWriter::write(ulc->operations, uniformValueBag);
201 }
202
203
204 public:
205
206
207
213 explicit OpenGLBackend(EngineWorld& engineWorld) : engineWorld_(engineWorld){}
214
215
224 void beginRenderTargetBatch(const RenderTargetHandle renderTargetHandle) noexcept {
225
226 auto renderTargetEntity = engineWorld_.find<RenderTargetHandle>(renderTargetHandle);
227
228 #ifdef HELIOS_DEBUG
229 if (!renderTargetEntity) {
230 logger_.error("Missing RenderTargetEntity for handle {0}.", renderTargetHandle.entityId);
231 assert(renderTargetEntity && "Missing RenderTargetEntity for handle.");
232 }
233 #endif
234
235 currentRenderTargetHandle_ = renderTargetHandle;
236
237 const auto renderTargetId = renderTargetEntity->get<OpenGLRenderTargetIdComponent<RenderTargetHandle>>()->value();
238
239 glBindFramebuffer(GL_FRAMEBUFFER, renderTargetId);
240
241 #ifdef HELIOS_DEBUG
242 const auto isValidRenderTarget = renderTargetId == 0 ||
243 (glIsFramebuffer(renderTargetId) == GL_TRUE && glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
244 if (!isValidRenderTarget) {
245 logger_.error("RenderTargetEntity with EntityId {0} undefined.", renderTargetId);
246 assert(isValidRenderTarget && "RenderTargetEntity EntityId does not seem to be a valid id.");
247 }
248 #endif
249
250 // this is equally important for the GlpyhTextRenderer
251 // enable blending since the font's fragment shader uses the alpha channel
252 glEnable(GL_BLEND);
253 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
254
255 const auto clearColor = renderTargetEntity->get<ColorComponent<RenderTargetHandle>>()->value();
256 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
257 }
258
266 void endRenderTargetBatch(const RenderTargetHandle renderTargetHandle) noexcept {
267
268 currentRenderTargetHandle_ = RenderTargetHandle{};
269 passUniformValueBag_.clearValues();
270 drawUniformValueBag_.clearValues();
271 }
272
281 void beginViewportBatch(const ViewportHandle viewportHandle) noexcept {
282
283 auto viewport = engineWorld_.find<ViewportHandle>(viewportHandle);
284 auto renderTargetEntity = engineWorld_.find<RenderTargetHandle>(currentRenderTargetHandle_);
285
286 #ifdef HELIOS_DEBUG
287 if (!renderTargetEntity) {
288 logger_.error("Missing RenderTargetEntity for handle {0}.", renderTargetEntity->handle().entityId);
289 assert(renderTargetEntity && "Missing RenderTargetEntity for handle.");
290 }
291 if (!viewport) {
292 logger_.error("Missing Viewport for handle {0}.", viewportHandle.entityId);
293 assert(viewport && "Missing Viewport for handle.");
294 }
295 #endif
296
297 auto vp = viewProjection(*viewport);
298 if (!vp) {
299 logger_.warn("Could not determine View/Projection-matrices for RenderPass");
300 passUniformValueBag_.set<ProjectionMatrixUniform>(helios::math::mat4f{1.0f});
301 passUniformValueBag_.set<ViewMatrixUniform>(helios::math::mat4f{1.0f});
302 } else {
303 passUniformValueBag_.set<ProjectionMatrixUniform>(vp->projectionMatrix);
304 passUniformValueBag_.set<ViewMatrixUniform>(vp->viewMatrix);
305 }
306
307 auto viewportBounds = viewport->get<BoundsComponent<ViewportHandle>>()->value();
308 auto renderTargetSize = renderTargetEntity->get<Size2DComponent<RenderTargetHandle>>()->value();
309
310 const auto x = static_cast<int>(renderTargetSize[0] * viewportBounds[0]);
311 const auto y = static_cast<int>(renderTargetSize[1] * viewportBounds[1]);
312 const auto width = static_cast<int>(renderTargetSize[0] * viewportBounds[2]);
313 const auto height = static_cast<int>(renderTargetSize[1] * viewportBounds[3]);
314
315
316 glViewport(x, y, width, height);
317 glScissor(x, y, width, height);
318 glEnable(GL_SCISSOR_TEST);
319
320 const auto clearFlags = std::to_underlying(renderTargetEntity->get<ClearComponent<RenderTargetHandle>>()->flags);
321 const auto clearMask = ((clearFlags & std::to_underlying(ClearFlags::Color)) ? GL_COLOR_BUFFER_BIT : 0) |
322 ((clearFlags & std::to_underlying(ClearFlags::Depth)) ? GL_DEPTH_BUFFER_BIT : 0) |
323 ((clearFlags & std::to_underlying(ClearFlags::Stencil)) ? GL_STENCIL_BUFFER_BIT : 0);
324
325 if (clearMask != 0) {
326 glClear(clearMask);
327 }
328 }
329
335 void endViewportBatch(const ViewportHandle viewportHandle) noexcept {
336 glDisable(GL_SCISSOR_TEST);
337 }
338
346 void beginShaderBatch(ShaderHandle shaderHandle) noexcept {
347
348 auto shaderEntity = engineWorld_.find(shaderHandle);
349 if (!shaderEntity) {
350 logger_.error("ShaderEntity expected, but not found");
351 assert(false && "ShaderEntity not found");
352 return;
353 }
354
355 currentShaderHandle_ = shaderHandle;
356
357 auto* openglShader = shaderEntity->template get<OpenGLShaderComponent<ShaderHandle>>();
358 if (!openglShader) {
359 logger_.error("OpenGLShader expected, but not found");
360 assert(false && "OpenGLShader not found");
361 return;
362 }
363
364 glUseProgram(openglShader->programId);
365 writeUniformValues<UniformScope::Pass>(*shaderEntity, passUniformValueBag_);
366 }
367
373 void endShaderBatch(ShaderHandle handle) noexcept {
374 currentShaderHandle_ = ShaderHandle{};
375 }
376
384 void beginMaterialBatch(MaterialHandle materialHandle) noexcept {
385 auto materialEntity = engineWorld_.find(materialHandle);
386 if (!materialEntity) {
387 logger_.error("MaterialEntity expected, but not found");
388 assert(false && "MaterialEntity not found");
389 return;
390 }
391
392 auto* colorComponent = materialEntity->template get<ColorComponent<MaterialHandle>>();
393 if (colorComponent) {
394 drawUniformValueBag_.set<MaterialBaseColorUniform>(colorComponent->value());
395 }
396
397 }
398
404 void endMaterialBatch(MaterialHandle handle) noexcept {
405 // intentionally left empty
406 }
407
415 void beginMeshBatch(MeshHandle meshHandle) noexcept {
416
417 auto meshEntity = engineWorld_.find(meshHandle);
418 if (!meshEntity) {
419 logger_.error("MeshEntity expected, but not found");
420 assert(false && "MeshEntity not found");
421 return;
422 }
423
424 auto* openglMesh = meshEntity->template get<OpenGLMeshComponent<MeshHandle>>();
425 if (!openglMesh) {
426 logger_.error("OpenGLMesh expected, but not found");
427 assert(false && "OpenGLMesh not found");
428 return;
429 } else {
430 currentOpenGLMesh_ = openglMesh;
431 glBindVertexArray(openglMesh->vao);
432 }
433 }
434
440 void endMeshBatch(MeshHandle handle) noexcept {
441 currentOpenGLMesh_ = nullptr;
442 glBindVertexArray(0);
443 }
444
454 template<typename THandle>
455 void renderBatch(std::span<SceneMemberRenderContext<THandle>> sceneMemberRenderContexts) noexcept {
456
457 if (!currentOpenGLMesh_) {
458 logger_.error("OpenGLMesh expected, but not available");
459 return;
460 }
461 if (!currentShaderHandle_.isValid()) {
462 logger_.error("Expected valid currentShaderHandle_, but found {0}.", currentShaderHandle_.entityId);
463 return;
464 }
465
466 auto shaderEntity = engineWorld_.find(currentShaderHandle_);
467
468 assert(shaderEntity && "ShaderEntity expected, but not found");
469 assert(currentOpenGLMesh_ && "Current OpenGL mesh expected, but not found");
470
471 for (auto& renderContext : sceneMemberRenderContexts) {
472
473 drawUniformValueBag_.set<ModelMatrixUniform>(renderContext.worldMatrix);
474 writeUniformValues<UniformScope::Draw>(*shaderEntity, drawUniformValueBag_);
475 glDrawElements(
476 currentOpenGLMesh_->primitiveType,
477 currentOpenGLMesh_->indexCount,
478 GL_UNSIGNED_INT,
479 nullptr
480 );
481
482 }
483 }
484
491 void provideWindowHints() noexcept {
492
493 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
494 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
495 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
496
497 }
498
506 [[nodiscard]] bool init() noexcept {
507
508 assert(!isInitialized_ && "Backend already initialized");
509
510 const GLADloadfunc procAddressLoader = glfwGetProcAddress;
511 const int gl_ver = gladLoadGL(procAddressLoader);
512
513 if (gl_ver == 0) {
514 logger_.error("Failed to load OpenGL");
515 assert(false && "Failed to load OpenGL");
516 return false;
517 }
518
519 logger_.info("OpenGL {0}.{1} loaded", GLAD_VERSION_MAJOR(gl_ver), GLAD_VERSION_MINOR(gl_ver));
520
521 isInitialized_ = true;
522 return true;
523
524 }
525
529 [[nodiscard]] bool isInitialized() const noexcept {
530 return isInitialized_;
531 }
532
533 };
534} // namespace helios::opengl

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.