Dawn/src/dawn/display/RenderPipeline.cpp

151 lines
3.8 KiB
C++

// 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>();
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<UICanvas>();
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<MeshRenderer>();
auto it = meshes.begin();
while(it != meshes.end()) {
auto mesh = *it;
auto material = mesh->item->getComponent<Material>();
// 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() {
}