// Copyright (c) 2022 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "RenderPipeline.hpp" #include "game/DawnGame.hpp" #include "display/mesh/QuadMesh.hpp" #include "scene/SceneItem.hpp" using namespace Dawn; RenderPipeline::RenderPipeline(RenderManager *renderManager) { assertNotNull(renderManager); this->renderManager = renderManager; } void RenderPipeline::init() { } void RenderPipeline::render() { this->renderScene(this->renderManager->game->scene); } void RenderPipeline::renderScene(Scene *scene) { assertNotNull(scene); auto backBuffer = this->renderManager->getBackBuffer(); auto cameras = scene->findComponents(); Camera *backBufferCamera = nullptr; // First, render all non-backbuffer cameras. auto it = cameras.begin(); while(it != cameras.end()) { RenderTarget *cameraTarget = (*it)->getRenderTarget(); // Leave the backbuffer camera(s) to last, so we skip them. if(cameraTarget == backBuffer) { backBufferCamera = *it; } else { this->renderSceneCamera(scene, *it); } ++it; } // Now render the backbuffer camera. if(backBufferCamera == nullptr) return; this->renderSceneCamera(scene, backBufferCamera); // Now we try and render UI components auto uiCanvasList = scene->findComponents(); auto itCanvas = uiCanvasList.begin(); while(itCanvas != uiCanvasList.end()) { this->renderUI(scene, backBufferCamera, *itCanvas); ++itCanvas; } } void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) { assertNotNull(scene); assertNotNull(camera); RenderTarget *renderTarget = camera->getRenderTarget(); assertNotNull(renderTarget); renderTarget->bind(); renderTarget->clear( RENDER_TARGET_CLEAR_FLAG_DEPTH | RENDER_TARGET_CLEAR_FLAG_COLOR ); this->renderManager->setRenderFlags( RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST | RENDER_MANAGER_RENDER_FLAG_BLEND ); auto meshes = scene->findComponents(); auto it = meshes.begin(); while(it != meshes.end()) { auto mesh = *it; auto material = mesh->item->getComponent(); // TODO: fallback material? if(material == nullptr) { ++it; continue; } auto shader = material->getShader(); shader->bind(); shader->setGlobalParameters(camera->projection, camera->transform->getWorldTransform()); shader->setMeshParameters(mesh->item->transform.getWorldTransform()); material->setShaderParameters(); mesh->mesh->draw(MESH_DRAW_MODE_TRIANGLES, 0, -1); ++it; } } void RenderPipeline::renderUI( Scene *scene, Camera *camera, UICanvas *canvas ) { assertNotNull(scene); assertNotNull(camera); assertNotNull(canvas); RenderTarget *renderTarget; glm::mat4 transform; glm::mat4 projection; switch(canvas->drawType) { case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE: transform = glm::mat4(1.0f); projection = glm::ortho(0.0f, canvas->getWidth(), canvas->getHeight(), 0.0f); renderTarget = camera->getRenderTarget(); break; default: assertUnreachable(); } assertNotNull(renderTarget); // Clear / Bind / Update the render target. renderTarget->bind(); this->renderManager->setRenderFlags( RENDER_MANAGER_RENDER_FLAG_BLEND ); // Prepare the UI Shader auto shader = this->renderManager->getUIShader(); assertNotNull(shader); shader->bind(); shader->setUICamera(transform, projection); // Render the children glm::mat4 rootMatrix = canvas->transform->getWorldTransform(); auto it = canvas->children.begin(); while(it != canvas->children.end()) { (*it)->draw(shader, rootMatrix); ++it; } } RenderPipeline::~RenderPipeline() { }