diff --git a/cmake/targets/CMakeLists.txt b/cmake/targets/CMakeLists.txt index 06dcd4bd..3210e1a8 100644 --- a/cmake/targets/CMakeLists.txt +++ b/cmake/targets/CMakeLists.txt @@ -6,9 +6,9 @@ # Check for build target, or default if(NOT DEFINED DAWN_BUILD_TARGET) if(WIN32) - set(DAWN_BUILD_TARGET "target-platformergame-win32-glfw") + set(DAWN_BUILD_TARGET "target-pokergame-win32-glfw") elseif(UNIX AND NOT APPLE) - set(DAWN_BUILD_TARGET "target-platformergame-linux64-glfw") + set(DAWN_BUILD_TARGET "target-pokergame-linux64-glfw") endif() endif() diff --git a/src/dawn/display/RenderPipeline.cpp b/src/dawn/display/RenderPipeline.cpp index 006641cd..2c83a8ad 100644 --- a/src/dawn/display/RenderPipeline.cpp +++ b/src/dawn/display/RenderPipeline.cpp @@ -29,6 +29,26 @@ void RenderPipeline::render() { void RenderPipeline::renderScene(Scene *scene) { assertNotNull(scene); + // Render subscenes first. + auto subSceneControllers = scene->findComponents(); + auto itSubScene = subSceneControllers.begin(); + while(itSubScene != subSceneControllers.end()) { + auto subScene = (*itSubScene)->getSubScene(); + if(subScene == nullptr) { + ++itSubScene; + continue; + } + + if((*itSubScene)->onlyUpdateUnpaused && scene->game->timeManager.isPaused) { + ++itSubScene; + continue; + } + + this->renderScene(subScene); + ++itSubScene; + } + + // Now render backbuffers. auto backBuffer = this->renderManager->getBackBuffer(); auto cameras = scene->findComponents(); Camera *backBufferCamera = nullptr; @@ -38,7 +58,8 @@ void RenderPipeline::renderScene(Scene *scene) { while(it != cameras.end()) { RenderTarget *cameraTarget = (*it)->getRenderTarget(); - // Leave the backbuffer camera(s) to last, so we skip them. + // Leave the backbuffer camera(s) to last, so we skip them. we do this so + // that children framebuffers contain the CURRENT frame, not LAST frame. if(cameraTarget == backBuffer) { backBufferCamera = *it; } else { @@ -51,21 +72,15 @@ void RenderPipeline::renderScene(Scene *scene) { // 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); + auto meshes = scene->findComponents(); + auto uiCanvasList = scene->findComponents(); + auto renderTarget = camera->getRenderTarget(); - RenderTarget *renderTarget = camera->getRenderTarget(); assertNotNull(renderTarget); renderTarget->bind(); @@ -77,8 +92,8 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) { RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST | RENDER_MANAGER_RENDER_FLAG_BLEND ); - - auto meshes = scene->findComponents(); + + // Render all Meshes on the scene auto it = meshes.begin(); while(it != meshes.end()) { auto mesh = *it; @@ -91,6 +106,7 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) { } auto shader = material->getShader(); + assertNotNull(shader); shader->bind(); shader->setGlobalParameters(camera->projection, camera->transform->getWorldTransform()); shader->setMeshParameters(mesh->item->transform.getWorldTransform()); @@ -99,56 +115,69 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) { 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; + // Now we only render world-absolute UI canvas' + auto uiShader = this->renderManager->getUIShader(); + assertNotNull(uiShader); + uiShader->bind(); + uiShader->setUICamera(camera->projection, camera->transform->getWorldTransform()); + this->renderManager->setRenderFlags(RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST); - 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(); + auto it2 = uiCanvasList.begin(); + while(it2 != uiCanvasList.end()) { + auto canvas = *it2; + + switch(canvas->drawType) { + case UI_DRAW_TYPE_WORLD_ABSOLUTE: + break; + + default: + ++it2; + continue; + } + + auto it3 = canvas->children.begin(); + auto rootMatrix = canvas->transform->getWorldTransform(); + while(it3 != canvas->children.end()) { + (*it3)->draw(uiShader, + glm::translate(glm::scale(rootMatrix, glm::vec3(1.0f, -1.0f, 1.0f)), glm::vec3(0, -renderTarget->getHeight(), 0)) + ); + ++it3; + } + ++it2; } - assertNotNull(renderTarget); - - // Clear / Bind / Update the render target. - renderTarget->bind(); - // renderTarget->clear( - // RENDER_TARGET_CLEAR_FLAG_DEPTH | - // RENDER_TARGET_CLEAR_FLAG_COLOR - // ); + + // Now render camera-relative UI this->renderManager->setRenderFlags( RENDER_MANAGER_RENDER_FLAG_BLEND ); + uiShader->setUICamera( + glm::ortho(0.0f, renderTarget->getWidth(), renderTarget->getHeight(), 0.0f), + glm::mat4(1.0f) + ); - // Prepare the UI Shader - auto shader = this->renderManager->getUIShader(); - assertNotNull(shader); - - shader->bind(); - shader->setUICamera(transform, projection); + it2 = uiCanvasList.begin(); + while(it2 != uiCanvasList.end()) { + auto canvas = *it2; - // Render the children - glm::mat4 rootMatrix = canvas->transform->getWorldTransform(); - auto it = canvas->children.begin(); - while(it != canvas->children.end()) { - (*it)->draw(shader, rootMatrix); - ++it; + switch(canvas->drawType) { + case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE: + break; + + default: + ++it2; + continue; + } + + auto it3 = canvas->children.begin(); + auto rootMatrix = canvas->transform->getWorldTransform(); + while(it3 != canvas->children.end()) { + (*it3)->draw(uiShader, rootMatrix); + ++it3; + } + ++it2; } } diff --git a/src/dawn/display/RenderPipeline.hpp b/src/dawn/display/RenderPipeline.hpp index 28ef00a8..8758ecf1 100644 --- a/src/dawn/display/RenderPipeline.hpp +++ b/src/dawn/display/RenderPipeline.hpp @@ -51,19 +51,6 @@ namespace Dawn { */ virtual void renderSceneCamera(Scene *scene, Camera *camera); - /** - * Renders a UI Canvas to the back buffer. - * - * @param scene Scene for the UI canvas. - * @param camera Main backbuffer camera for the canvas. - * @param canvas Canvas to render. - */ - virtual void renderUI( - Scene *scene, - Camera *camera, - UICanvas *canvas - ); - /** * Cleanup a render pipeline that has been initialized. */ diff --git a/src/dawn/scene/Scene.hpp b/src/dawn/scene/Scene.hpp index cbd63022..a44e5f77 100644 --- a/src/dawn/scene/Scene.hpp +++ b/src/dawn/scene/Scene.hpp @@ -10,6 +10,7 @@ namespace Dawn { class DawnGame; + class RenderPipeline; class Scene { private: @@ -127,5 +128,7 @@ namespace Dawn { * Destroys a previously initialized Scene. */ ~Scene(); + + friend class RenderPipeline; }; } \ No newline at end of file diff --git a/src/dawn/scene/components/CMakeLists.txt b/src/dawn/scene/components/CMakeLists.txt index 26216c47..1084ec7f 100644 --- a/src/dawn/scene/components/CMakeLists.txt +++ b/src/dawn/scene/components/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(display) add_subdirectory(example) add_subdirectory(physics) +add_subdirectory(scene) add_subdirectory(ui) \ No newline at end of file diff --git a/src/dawn/scene/components/Components.hpp b/src/dawn/scene/components/Components.hpp index 7cf54cd1..cf6508b0 100644 --- a/src/dawn/scene/components/Components.hpp +++ b/src/dawn/scene/components/Components.hpp @@ -11,7 +11,11 @@ #include "scene/components/display/Material.hpp" #include "scene/components/display/PixelPerfectCamera.hpp" #include "scene/components/display/TiledSprite.hpp" +#include "scene/components/display/SimpleRenderTargetQuad.hpp" #include "scene/components/example/ExampleSpin.hpp" +#include "scene/components/scene/SubSceneController.hpp" +#include "scene/components/scene/SubSceneCameraAlign.hpp" + #include "scene/components/ui/UICanvas.hpp" \ No newline at end of file diff --git a/src/dawn/scene/components/display/CMakeLists.txt b/src/dawn/scene/components/display/CMakeLists.txt index 85974ecd..661db97b 100644 --- a/src/dawn/scene/components/display/CMakeLists.txt +++ b/src/dawn/scene/components/display/CMakeLists.txt @@ -13,4 +13,5 @@ target_sources(${DAWN_TARGET_NAME} MeshRenderer.cpp PixelPerfectCamera.cpp TiledSprite.cpp + SimpleRenderTargetQuad.cpp ) \ No newline at end of file diff --git a/src/dawn/scene/components/display/PixelPerfectCamera.cpp b/src/dawn/scene/components/display/PixelPerfectCamera.cpp index 734a54be..914fc00a 100644 --- a/src/dawn/scene/components/display/PixelPerfectCamera.cpp +++ b/src/dawn/scene/components/display/PixelPerfectCamera.cpp @@ -41,7 +41,13 @@ void PixelPerfectCamera::updateDimensions() { break; case CAMERA_TYPE_PERSPECTIVE: - assertDeprecated(); + this->transform->lookAtPixelPerfect( + glm::vec3(0, 0, 0), + glm::vec3(0, 0, 0), + target->getHeight() / this->scale, + this->camera->fov + ); + // this->transform->lookAt(glm::vec3(360, 360, 360), glm::vec3(0, 0, 0)); break; default: diff --git a/src/dawn/scene/components/display/PixelPerfectCamera.hpp b/src/dawn/scene/components/display/PixelPerfectCamera.hpp index f8258970..ee607122 100644 --- a/src/dawn/scene/components/display/PixelPerfectCamera.hpp +++ b/src/dawn/scene/components/display/PixelPerfectCamera.hpp @@ -19,7 +19,7 @@ namespace Dawn { void updateDimensions(); public: - float_t scale = 4.0f; + float_t scale = 1.0f; /** * Create a new PixelPerfectCamera Component. diff --git a/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp b/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp new file mode 100644 index 00000000..220b1b2e --- /dev/null +++ b/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "SimpleRenderTargetQuad.hpp" +#include "scene/Scene.hpp" + +using namespace Dawn; + +SimpleRenderTargetQuad::SimpleRenderTargetQuad(SceneItem *i) : + SceneItemComponent(i) +{ +} + +void SimpleRenderTargetQuad::onRenderTargetResized( + RenderTarget *target, float_t w, float_t h +) { + assertTrue(target == this->renderTarget); + // Update mesh + QuadMesh::bufferQuadMesh( + &this->meshHost->mesh, + glm::vec2(0, 0), glm::vec2(0, 0), + glm::vec2(w, h), glm::vec2(1, 1), + 0, 0 + ); +} + + +void SimpleRenderTargetQuad::setRenderTarget(RenderTarget *rt) { + assertTrue(rt != this->renderTarget); + + // Remove old event listener + if(this->renderTarget != nullptr) { + this->renderTarget->eventRenderTargetResized.removeListener( + this, &SimpleRenderTargetQuad::onRenderTargetResized + ); + } + + this->renderTarget = rt; + + // Add new event listener. + if(rt != nullptr) { + rt->eventRenderTargetResized.addListener( + this, &SimpleRenderTargetQuad::onRenderTargetResized + ); + } +} + +std::vector SimpleRenderTargetQuad::getDependencies() { + return std::vector{ + (this->meshHost = this->item->getComponent()) + }; +} + +void SimpleRenderTargetQuad::onStart() { + assertNotNull(this->meshHost); + + // Create quad mesh + this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT); + + // Perform first resize. + if(this->renderTarget != nullptr) { + QuadMesh::bufferQuadMesh( + &this->meshHost->mesh, + glm::vec2(0, 0), + glm::vec2(0, 0), + glm::vec2(this->renderTarget->getWidth(), this->renderTarget->getHeight()), + glm::vec2(1,1), + 0, 0 + ); + } +} + +SimpleRenderTargetQuad::~SimpleRenderTargetQuad() { + if(this->renderTarget != nullptr) { + this->renderTarget->eventRenderTargetResized.removeListener( + this, &SimpleRenderTargetQuad::onRenderTargetResized + ); + } +} \ No newline at end of file diff --git a/src/dawn/scene/components/display/SimpleRenderTargetQuad.hpp b/src/dawn/scene/components/display/SimpleRenderTargetQuad.hpp new file mode 100644 index 00000000..a1d92259 --- /dev/null +++ b/src/dawn/scene/components/display/SimpleRenderTargetQuad.hpp @@ -0,0 +1,42 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "scene/components/display/MeshHost.hpp" +#include "display/RenderTarget.hpp" +#include "display/mesh/QuadMesh.hpp" + +namespace Dawn { + class SimpleRenderTargetQuad : public SceneItemComponent { + protected: + MeshHost *meshHost = nullptr; + RenderTarget *renderTarget = nullptr; + + void onRenderTargetResized(RenderTarget *target, float_t w, float_t h); + + public: + /** + * Creates a SimpleRenderTargetQuad scene item component. This component + * will update the attached MeshHost any time the render target provided + * is updated / resized. + * + * @param item Item that this component is attached to. + */ + SimpleRenderTargetQuad(SceneItem *item); + + /** + * Sets the render target to use for this quad. Can be set to nullptr when + * you no longer wish to listen for resize events. + * + * @param rt Render target to attach to. + */ + void setRenderTarget(RenderTarget *rt); + + std::vector getDependencies() override; + void onStart() override; + + ~SimpleRenderTargetQuad(); + }; +} \ No newline at end of file diff --git a/src/dawn/scene/components/scene/CMakeLists.txt b/src/dawn/scene/components/scene/CMakeLists.txt new file mode 100644 index 00000000..b0ccded6 --- /dev/null +++ b/src/dawn/scene/components/scene/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DAWN_TARGET_NAME} + PRIVATE + SubSceneCameraAlign.cpp + SubSceneController.cpp +) \ No newline at end of file diff --git a/src/dawn/scene/components/scene/SubSceneCameraAlign.cpp b/src/dawn/scene/components/scene/SubSceneCameraAlign.cpp new file mode 100644 index 00000000..bb444be4 --- /dev/null +++ b/src/dawn/scene/components/scene/SubSceneCameraAlign.cpp @@ -0,0 +1,102 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "SubSceneCameraAlign.hpp" + +using namespace Dawn; + +SubSceneCameraAlign::SubSceneCameraAlign(SceneItem *i) : SceneItemComponent(i) { + +} + +void SubSceneCameraAlign::onRenderTargetResize( + RenderTarget *target, float_t w, float_t h +) { + this->realign(); +} + +void SubSceneCameraAlign::realign() { + float_t diff; + if(this->camera == nullptr) return; + if(this->renderTarget == nullptr) return; + + float_t ratio = this->renderTarget->getWidth() / this->renderTarget->getHeight(); + float_t myRatio = this->camera->getRenderTarget()->getWidth() / this->camera->getRenderTarget()->getHeight(); + + this->camera->type = CAMERA_TYPE_ORTHONOGRAPHIC; + this->camera->transform->lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0)); + + if(ratio > myRatio) { + // My Ratio is narrower + this->camera->orthoLeft = 0; + this->camera->orthoRight = this->renderTarget->getWidth(); + diff = (this->renderTarget->getHeight() - (this->renderTarget->getWidth() / myRatio)) / 2.0f; + this->camera->orthoTop = this->renderTarget->getHeight() - diff; + this->camera->orthoBottom = diff; + } else { + // My ratio is wider + this->camera->orthoBottom = 0; + this->camera->orthoTop = this->renderTarget->getHeight(); + diff = (this->renderTarget->getWidth() - (this->renderTarget->getHeight() * myRatio)) / 2.0f; + this->camera->orthoLeft = diff; + this->camera->orthoRight = this->renderTarget->getWidth() - diff; + } + +} + +void SubSceneCameraAlign::setRenderTarget(TextureRenderTarget *renderTarget) { + assertTrue(this->renderTarget != renderTarget); + + if(this->renderTarget != nullptr) { + this->renderTarget->eventRenderTargetResized.removeListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } + + this->renderTarget = renderTarget; + this->realign(); + + if(this->renderTarget != nullptr) { + this->renderTarget->eventRenderTargetResized.addListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } +} + +void SubSceneCameraAlign::setCamera(Camera *camera) { + assertTrue(this->camera != camera); + + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.removeListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } + + this->camera = camera; + this->realign(); + + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.addListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } +} + +void SubSceneCameraAlign::onStart() { + this->realign(); +} + +SubSceneCameraAlign::~SubSceneCameraAlign() { + if(this->renderTarget != nullptr) { + this->renderTarget->eventRenderTargetResized.removeListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.removeListener( + this, &SubSceneCameraAlign::onRenderTargetResize + ); + } +} \ No newline at end of file diff --git a/src/dawn/scene/components/scene/SubSceneCameraAlign.hpp b/src/dawn/scene/components/scene/SubSceneCameraAlign.hpp new file mode 100644 index 00000000..13dc4acd --- /dev/null +++ b/src/dawn/scene/components/scene/SubSceneCameraAlign.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "scene/Scene.hpp" +#include "display/TextureRenderTarget.hpp" +#include "scene/components/display/Camera.hpp" + +namespace Dawn { + class SubSceneCameraAlign : public SceneItemComponent { + protected: + TextureRenderTarget *renderTarget = nullptr; + Camera *camera = nullptr; + + void onRenderTargetResize(RenderTarget *target, float_t w, float_t h); + + void realign(); + + public: + + SubSceneCameraAlign(SceneItem *item); + + void setRenderTarget(TextureRenderTarget *renderTarget); + void setCamera(Camera *camera); + + void onStart() override; + + ~SubSceneCameraAlign(); + }; +} \ No newline at end of file diff --git a/src/dawn/scene/components/scene/SubSceneController.cpp b/src/dawn/scene/components/scene/SubSceneController.cpp new file mode 100644 index 00000000..5cce4e4f --- /dev/null +++ b/src/dawn/scene/components/scene/SubSceneController.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "SubSceneController.hpp" + +using namespace Dawn; + +SubSceneController::SubSceneController(SceneItem *i) : SceneItemComponent(i) { + +} + +void SubSceneController::onSceneUpdate() { + if(this->onlyUpdateUnpaused) return; + if(this->subScene == nullptr) return; + this->subScene->update(); +} + +void SubSceneController::onSceneUnpausedUpdate() { + if(!this->onlyUpdateUnpaused) return; + if(this->subScene == nullptr) return; + this->subScene->update(); +} + +Scene * SubSceneController::getSubScene() { + return this->subScene; +} + +void SubSceneController::setSubScene(Scene *scene) { + assertTrue(scene != this->subScene); + this->subScene = scene; +} + +void SubSceneController::onStart() { + auto myScene = this->getScene(); + myScene->eventSceneUnpausedUpdate.addListener(this, &SubSceneController::onSceneUnpausedUpdate); + myScene->eventSceneUpdate.addListener(this, &SubSceneController::onSceneUpdate); +} + +SubSceneController::~SubSceneController() { + auto myScene = this->getScene(); + myScene->eventSceneUnpausedUpdate.removeListener(this, &SubSceneController::onSceneUnpausedUpdate); + myScene->eventSceneUpdate.removeListener(this, &SubSceneController::onSceneUpdate); +} \ No newline at end of file diff --git a/src/dawn/scene/components/scene/SubSceneController.hpp b/src/dawn/scene/components/scene/SubSceneController.hpp new file mode 100644 index 00000000..6e3e5b5e --- /dev/null +++ b/src/dawn/scene/components/scene/SubSceneController.hpp @@ -0,0 +1,29 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "scene/Scene.hpp" + +namespace Dawn { + class SubSceneController : public SceneItemComponent { + protected: + Scene *subScene = nullptr; + + void onSceneUpdate(); + void onSceneUnpausedUpdate(); + + public: + bool_t onlyUpdateUnpaused = true; + + SubSceneController(SceneItem *item); + + Scene * getSubScene(); + void setSubScene(Scene *scene); + + void onStart() override; + + ~SubSceneController(); + }; +} \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UICanvas.cpp b/src/dawn/scene/components/ui/UICanvas.cpp index 383f921f..367b658c 100644 --- a/src/dawn/scene/components/ui/UICanvas.cpp +++ b/src/dawn/scene/components/ui/UICanvas.cpp @@ -18,25 +18,7 @@ UICanvas * UICanvas::create(Scene *scene) { UICanvas::UICanvas(SceneItem *item) : SceneItemComponent(item) { } -float_t UICanvas::getWidth() { - return this->getGame()->renderManager.getBackBuffer()->getWidth(); -} - -float_t UICanvas::getHeight() { - return this->getGame()->renderManager.getBackBuffer()->getHeight(); -} - -void UICanvas::onStart() { - this->getGame()->renderManager.getBackBuffer()->eventRenderTargetResized - .addListener(this, &UICanvas::onBackBufferResize) - ; -} - -void UICanvas::onBackBufferResize( - RenderTarget *target, - float_t width, - float_t height -) { +void UICanvas::onRenderTargetResize(RenderTarget *target, float_t w, float_t h){ auto it = this->children.begin(); while(it != this->children.end()) { (*it)->updatePositions(); @@ -44,14 +26,55 @@ void UICanvas::onBackBufferResize( } } +void UICanvas::setCamera(Camera *camera) { + assertTrue(camera != this->camera); + + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.removeListener( + this, &UICanvas::onRenderTargetResize + ); + } + + this->camera = camera; + + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.addListener( + this, &UICanvas::onRenderTargetResize + ); + } +} + +float_t UICanvas::getWidth() { + if(this->camera == nullptr) { + return this->getGame()->renderManager.getBackBuffer()->getWidth(); + } + return this->camera->getRenderTarget()->getWidth(); +} + +float_t UICanvas::getHeight() { + if(this->camera == nullptr) { + return this->getGame()->renderManager.getBackBuffer()->getHeight(); + } + return this->camera->getRenderTarget()->getHeight(); +} + +void UICanvas::onStart() { + if(this->camera == nullptr) { + auto camera = this->getScene()->findComponent(); + this->setCamera(camera); + } +} + UICanvas::~UICanvas() { auto it = this->children.begin(); while(it != this->children.end()) { delete *it; ++it; } - - this->getGame()->renderManager.getBackBuffer()->eventRenderTargetResized - .removeListener(this, &UICanvas::onBackBufferResize) - ; + + if(this->camera != nullptr) { + this->camera->getRenderTarget()->eventRenderTargetResized.removeListener( + this, &UICanvas::onRenderTargetResize + ); + } } \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UICanvas.hpp b/src/dawn/scene/components/ui/UICanvas.hpp index e67ac356..2d41d54b 100644 --- a/src/dawn/scene/components/ui/UICanvas.hpp +++ b/src/dawn/scene/components/ui/UICanvas.hpp @@ -6,6 +6,7 @@ #pragma once #include "scene/SceneItemComponent.hpp" #include "display/RenderTarget.hpp" +#include "scene/components/display/Camera.hpp" namespace Dawn { enum UIDrawType { @@ -18,11 +19,9 @@ namespace Dawn { class UICanvas : public SceneItemComponent { protected: - void onBackBufferResize( - RenderTarget *target, - float_t width, - float_t height - ); + Camera *camera = nullptr; + + void onRenderTargetResize(RenderTarget *target, float_t w, float_t h); public: /** @@ -45,6 +44,13 @@ namespace Dawn { */ UICanvas(SceneItem *item); + /** + * Sets the camera used by the UI canvas. + * + * @param camera Camera to set for the UI canvas. + */ + void setCamera(Camera *camera); + /** * Construct and append a UI item to this UI Canvas. * diff --git a/src/dawn/ui/UILabel.cpp b/src/dawn/ui/UILabel.cpp index 10ddf9c5..c8ae664a 100644 --- a/src/dawn/ui/UILabel.cpp +++ b/src/dawn/ui/UILabel.cpp @@ -57,6 +57,10 @@ void UILabel::setFontSize(float_t fontSize) { this->needsRebuffering = true; } +float_t UILabel::getFontSize() { + return this->fontSize; +} + float_t UILabel::getContentWidth() { this->updateMesh(); return this->measure.getWidth(); diff --git a/src/dawn/ui/UILabel.hpp b/src/dawn/ui/UILabel.hpp index 7ed077d8..cd31a908 100644 --- a/src/dawn/ui/UILabel.hpp +++ b/src/dawn/ui/UILabel.hpp @@ -68,6 +68,13 @@ namespace Dawn { */ void setFontSize(float_t fontSize); + /** + * Get the labels' current font size. + * + * @return Font size of the label. + */ + float_t getFontSize(); + ~UILabel(); }; } \ No newline at end of file diff --git a/src/dawn/visualnovel/ui/VisualNovelTextbox.cpp b/src/dawn/visualnovel/ui/VisualNovelTextbox.cpp index 2d32918e..14b50024 100644 --- a/src/dawn/visualnovel/ui/VisualNovelTextbox.cpp +++ b/src/dawn/visualnovel/ui/VisualNovelTextbox.cpp @@ -105,7 +105,7 @@ void VisualNovelTextbox::textboxOnSceneUpdate() { ), this->border.getBorderSize() + this->labelPadding ), - 1.0f + 5.0f ); this->eventNewPage.invoke(); } @@ -167,6 +167,10 @@ void VisualNovelTextbox::setFontSize(float_t fontSize) { this->label.updateMesh(); } +float_t VisualNovelTextbox::getFontSize() { + return this->label.getFontSize(); +} + void VisualNovelTextbox::setLabelPadding(glm::vec2 padding) { this->labelPadding = padding; this->updatePositions(); diff --git a/src/dawn/visualnovel/ui/VisualNovelTextbox.hpp b/src/dawn/visualnovel/ui/VisualNovelTextbox.hpp index badaa56d..78795f2d 100644 --- a/src/dawn/visualnovel/ui/VisualNovelTextbox.hpp +++ b/src/dawn/visualnovel/ui/VisualNovelTextbox.hpp @@ -98,6 +98,13 @@ namespace Dawn { */ void setFontSize(float_t fontSize); + /** + * Returns the current font size. + * + * @return Font size. + */ + float_t getFontSize(); + /** * Sets the padding of the label. This will increase the spacing between * the text and the border. diff --git a/src/dawnglfw/host/DawnGLFWHost.cpp b/src/dawnglfw/host/DawnGLFWHost.cpp index 01b7f9a9..051deb0a 100644 --- a/src/dawnglfw/host/DawnGLFWHost.cpp +++ b/src/dawnglfw/host/DawnGLFWHost.cpp @@ -60,10 +60,10 @@ int32_t DawnHost::init(DawnGame *game) { game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_ENTER); game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_E); game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_SPACE); - game->inputManager.bind(INPUT_BIND_NEGATIVE_X, GLFW_KEY_A); - game->inputManager.bind(INPUT_BIND_POSITIVE_X, GLFW_KEY_D); - game->inputManager.bind(INPUT_BIND_NEGATIVE_Y, GLFW_KEY_S); - game->inputManager.bind(INPUT_BIND_POSITIVE_Y, GLFW_KEY_W); + // game->inputManager.bind(INPUT_BIND_NEGATIVE_X, GLFW_KEY_A); + // game->inputManager.bind(INPUT_BIND_POSITIVE_X, GLFW_KEY_D); + // game->inputManager.bind(INPUT_BIND_NEGATIVE_Y, GLFW_KEY_S); + // game->inputManager.bind(INPUT_BIND_POSITIVE_Y, GLFW_KEY_W); // Initialize the game auto result = game->init(); diff --git a/src/dawnopengl/display/CMakeLists.txt b/src/dawnopengl/display/CMakeLists.txt index d8486d19..35d44d6b 100644 --- a/src/dawnopengl/display/CMakeLists.txt +++ b/src/dawnopengl/display/CMakeLists.txt @@ -10,6 +10,7 @@ target_sources(${DAWN_TARGET_NAME} BackBufferRenderTarget.cpp StandardRenderPipeline.cpp Texture.cpp + TextureRenderTarget.cpp ) # Subdirs diff --git a/src/dawnopengl/display/Texture.hpp b/src/dawnopengl/display/Texture.hpp index 58ef8271..b292c864 100644 --- a/src/dawnopengl/display/Texture.hpp +++ b/src/dawnopengl/display/Texture.hpp @@ -10,6 +10,8 @@ #include "util/memory.hpp" namespace Dawn { + class TextureRenderTarget; + typedef GLuint textureslot_t; class Texture : public ITexture { @@ -34,5 +36,7 @@ namespace Dawn { void bind(textureslot_t slot); ~Texture(); + + friend class TextureRenderTarget; }; } \ No newline at end of file diff --git a/src/dawnopengl/display/TextureRenderTarget.cpp b/src/dawnopengl/display/TextureRenderTarget.cpp new file mode 100644 index 00000000..81ea6350 --- /dev/null +++ b/src/dawnopengl/display/TextureRenderTarget.cpp @@ -0,0 +1,87 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "TextureRenderTarget.hpp" + +using namespace Dawn; + +TextureRenderTarget::TextureRenderTarget(float_t width, float_t height) { + this->setSize(width, height); +} + +Texture * TextureRenderTarget::getTexture() { + return &this->texture; +} + +void TextureRenderTarget::setSize(float_t width, float_t height) { + assertTrue(width > 0); + assertTrue(height > 0); + assertTrue(width != this->getWidth()); + assertTrue(height != this->getHeight()); + + // Delete old buffers. + if(this->rboId != -1) glDeleteRenderbuffers(1, &this->rboId); + if(this->fboId != -1) glDeleteFramebuffers(1, &this->fboId); + + // Resize texture + this->texture.setSize((int32_t)width, (int32_t) height); + this->eventRenderTargetResized.invoke(this, width, height); + + // Create Frame Buffer + glGenFramebuffers(1, &this->fboId); + glBindFramebuffer(GL_FRAMEBUFFER, this->fboId); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, this->texture.id, 0 + ); + + // Create Render Buffer + glGenRenderbuffers(1, &this->rboId); + glBindRenderbuffer(GL_RENDERBUFFER, this->rboId); + glRenderbufferStorage( + GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, + this->texture.width, this->texture.height + ); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, this->rboId + ); + + // Validate things went correct. + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + assertUnreachable(); + } +} + +float_t TextureRenderTarget::getWidth() { + return (float_t)this->texture.getWidth(); +} + +float_t TextureRenderTarget::getHeight() { + return (float_t)this->texture.getHeight(); +} + +void TextureRenderTarget::setClearColor(struct Color color) { + this->clearColor = color; +} + +void TextureRenderTarget::clear(flag8_t clearFlags) { + glClearColor( + this->clearColor.r, + this->clearColor.g, + this->clearColor.b, + this->clearColor.a + ); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void TextureRenderTarget::bind() { + glBindFramebuffer(GL_FRAMEBUFFER, this->fboId); + glViewport(0, 0, this->texture.getWidth(), this->texture.getHeight()); +} + +TextureRenderTarget::~TextureRenderTarget() { + if(this->rboId != -1) glDeleteRenderbuffers(1, &this->rboId); + if(this->fboId != -1) glDeleteFramebuffers(1, &this->fboId); +} \ No newline at end of file diff --git a/src/dawnopengl/display/TextureRenderTarget.hpp b/src/dawnopengl/display/TextureRenderTarget.hpp new file mode 100644 index 00000000..7a1361b6 --- /dev/null +++ b/src/dawnopengl/display/TextureRenderTarget.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "dawnopengl.hpp" +#include "display/RenderTarget.hpp" +#include "display/Texture.hpp" + +namespace Dawn { + class RenderManager; + + class TextureRenderTarget : public RenderTarget { + private: + GLuint fboId = -1; + GLuint rboId = -1; + + Texture texture; + struct Color clearColor = COLOR_CORNFLOWER_BLUE; + + public: + TextureRenderTarget(float_t width, float_t height); + + Texture * getTexture(); + + void setSize(float_t width, float_t height); + + float_t getWidth() override; + float_t getHeight() override; + void setClearColor(struct Color color) override; + void clear(flag8_t clearFlags) override; + void bind() override; + + ~TextureRenderTarget(); + }; +} \ No newline at end of file diff --git a/src/dawnopengl/display/shader/UIShader.hpp b/src/dawnopengl/display/shader/UIShader.hpp index 9d043473..8722c381 100644 --- a/src/dawnopengl/display/shader/UIShader.hpp +++ b/src/dawnopengl/display/shader/UIShader.hpp @@ -99,9 +99,9 @@ namespace Dawn { this->setBoolean(this->paramHasTexture, false); } - void setUICamera(glm::mat4 view, glm::mat4 projection) { - this->setMatrix(this->paramView, view); + void setUICamera(glm::mat4 projection, glm::mat4 view) { this->setMatrix(this->paramProjection, projection); + this->setMatrix(this->paramView, view); } void setUIModel(glm::mat4 model) { diff --git a/src/dawnpokergame/CMakeLists.txt b/src/dawnpokergame/CMakeLists.txt index 3d7b922a..22341131 100644 --- a/src/dawnpokergame/CMakeLists.txt +++ b/src/dawnpokergame/CMakeLists.txt @@ -36,6 +36,7 @@ tool_texture(texture_tavern_morning borrowed/tavern_morning.png) tool_texture(texture_tavern_night borrowed/tavern_night.png) tool_texture(texture_village_day borrowed/village_day.png) tool_tileset(tileset_penny texture_penny characters/penny/penny-blink.png 1 22) +tool_tileset(tileset_cards texture_cards ${DIR_GAME_ASSETS}/cards.png 14 4) tool_truetype(truetype_ark ark-pixel.ttf truetype_ark @@ -46,8 +47,10 @@ tool_truetype(truetype_ark add_dependencies(${DAWN_TARGET_NAME} language_en - texture_test tileset_penny + tileset_cards + + texture_test truetype_ark texture_city_day texture_city_night diff --git a/src/dawnpokergame/game/DawnGame.cpp b/src/dawnpokergame/game/DawnGame.cpp index 9336af7b..7bc14c61 100644 --- a/src/dawnpokergame/game/DawnGame.cpp +++ b/src/dawnpokergame/game/DawnGame.cpp @@ -4,8 +4,7 @@ // https://opensource.org/licenses/MIT #include "DawnGame.hpp" -#include "scenes/Scene_1_1.hpp" -#include "scenes/TestScene.hpp" +#include "scenes/SubsceneTest.hpp" using namespace Dawn; @@ -23,7 +22,7 @@ int32_t DawnGame::init() { this->localeManager.init(); this->renderManager.init(); - this->scene = new TestScene(this); + this->scene = new SubsceneTest(this); return DAWN_GAME_INIT_RESULT_SUCCESS; } diff --git a/src/dawnpokergame/prefabs/ui/UIBorderPrefab.hpp b/src/dawnpokergame/prefabs/ui/UIBorderPrefab.hpp index 586d2b6c..31d337e7 100644 --- a/src/dawnpokergame/prefabs/ui/UIBorderPrefab.hpp +++ b/src/dawnpokergame/prefabs/ui/UIBorderPrefab.hpp @@ -19,7 +19,7 @@ namespace Dawn { static void prefabApply(AssetManager *man, UIBorder *border) { auto text = man->get("texture_test"); border->texture = &text->texture; - border->setBorderSize(glm::vec2(16, 16)); + border->setBorderSize(glm::vec2(8, 8)); } }; } \ No newline at end of file diff --git a/src/dawnpokergame/prefabs/ui/VisualNovelTextboxPrefab.hpp b/src/dawnpokergame/prefabs/ui/VisualNovelTextboxPrefab.hpp index fcdba540..f120dd0d 100644 --- a/src/dawnpokergame/prefabs/ui/VisualNovelTextboxPrefab.hpp +++ b/src/dawnpokergame/prefabs/ui/VisualNovelTextboxPrefab.hpp @@ -22,11 +22,11 @@ namespace Dawn { auto assetFont = man->get("truetype_ark"); UIBorderPrefab::apply(&textbox->border); textbox->setFont(&assetFont->font); - textbox->setFontSize(40); - textbox->setLabelPadding(glm::vec2(10, 8)); + textbox->setFontSize(11); + textbox->setLabelPadding(glm::vec2(4, 4)); textbox->setTransform( UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_END, - glm::vec4(0, 238, 0, 0), + glm::vec4(0, assetFont->font.getLineHeight(textbox->getFontSize()) * 4, 0, 0), 0.0f ); } diff --git a/src/dawnpokergame/scenes/PokerVNScene.cpp b/src/dawnpokergame/scenes/PokerVNScene.cpp index f0cf6e60..acc5e2e6 100644 --- a/src/dawnpokergame/scenes/PokerVNScene.cpp +++ b/src/dawnpokergame/scenes/PokerVNScene.cpp @@ -7,19 +7,27 @@ using namespace Dawn; -PokerVNScene::PokerVNScene(DawnGame *game) : SimpleVNScene(game) { +PokerVNScene::PokerVNScene(DawnGame *game) : + SimpleVNScene(game), + renderTarget(320, 180) +{ } std::vector PokerVNScene::getRequiredAssets() { auto assMan = &this->game->assetManager; - std::vector assets, l; - vectorAppend(&assets,SimpleVNScene::getRequiredAssets()); - vectorAppend(&assets, &(l = PokerPlayerDisplay::getAssets(assMan))); + std::vector assets; + vectorAppend(&assets, SimpleVNScene::getRequiredAssets()); + vectorAppend(&assets, PokerPlayerDisplay::getAssets(assMan)); return assets; } void PokerVNScene::vnStage() { + this->renderTarget.setClearColor(COLOR_RED); + this->camera->setRenderTarget(&this->renderTarget); + + auto pixelPerfectCamera = this->camera->item->addComponent(); + auto pokerGameItem = this->createSceneItem(); this->pokerGame = pokerGameItem->addComponent(); diff --git a/src/dawnpokergame/scenes/PokerVNScene.hpp b/src/dawnpokergame/scenes/PokerVNScene.hpp index d16ba98e..213e6fa8 100644 --- a/src/dawnpokergame/scenes/PokerVNScene.hpp +++ b/src/dawnpokergame/scenes/PokerVNScene.hpp @@ -9,6 +9,7 @@ #include "visualnovel/events/PokerBetLoopEvent.hpp" #include "visualnovel/events/PokerInitialEvent.hpp" #include "ui/PokerPlayerDisplay.hpp" +#include "display/TextureRenderTarget.hpp" namespace Dawn { class PokerVNScene : public SimpleVNScene { @@ -23,7 +24,10 @@ namespace Dawn { */ virtual std::vector getPokerPlayers() = 0; + + public: + TextureRenderTarget renderTarget; PokerGame *pokerGame; std::vector pokerPlayers; std::map pokerPlayerDisplays; diff --git a/src/dawnpokergame/scenes/SubsceneTest.hpp b/src/dawnpokergame/scenes/SubsceneTest.hpp new file mode 100644 index 00000000..4c659038 --- /dev/null +++ b/src/dawnpokergame/scenes/SubsceneTest.hpp @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "scene/Scene.hpp" +#include "game/DawnGame.hpp" +#include "scenes/TestScene.hpp" + +namespace Dawn { + class SubsceneTest : public Scene { + public: + Camera *camera; + SceneItem *sceneItem; + TestScene subScene; + + SubsceneTest(DawnGame *game) : Scene(game), subScene(game) { + + } + + std::vector getRequiredAssets() override { + return this->subScene.getRequiredAssets(); + } + + void stage() override { + this->camera = Camera::create(this); + this->camera->transform->lookAt(glm::vec3(300, 300, 300), glm::vec3(0, 0, 0)); + + this->subScene.stage(); + + this->sceneItem = this->createSceneItem(); + auto host = this->sceneItem->addComponent(); + auto renderer = this->sceneItem->addComponent(); + + auto material = this->sceneItem->addComponent(); + material->textureValues[material->getShader()->getParameterByName("u_Text")] = this->subScene.renderTarget.getTexture(); + + auto renderTargetQuad = this->sceneItem->addComponent(); + renderTargetQuad->setRenderTarget(&this->subScene.renderTarget); + + auto subSceneController = this->sceneItem->addComponent(); + subSceneController->setSubScene(&this->subScene); + + auto subSceneCameraAlign = this->sceneItem->addComponent(); + subSceneCameraAlign->setRenderTarget(&this->subScene.renderTarget); + subSceneCameraAlign->setCamera(this->camera); + } + }; +} \ No newline at end of file