diff --git a/src/dawn/component/CMakeLists.txt b/src/dawn/component/CMakeLists.txt index d8011291..8e276b0f 100644 --- a/src/dawn/component/CMakeLists.txt +++ b/src/dawn/component/CMakeLists.txt @@ -3,10 +3,10 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT -# target_sources(${DAWN_TARGET_NAME} -# PRIVATE -# Game.cpp -# ) +target_sources(${DAWN_TARGET_NAME} + PRIVATE + SimpleComponent.cpp +) # Subdirs add_subdirectory(display) \ No newline at end of file diff --git a/src/dawn/component/SimpleComponent.cpp b/src/dawn/component/SimpleComponent.cpp new file mode 100644 index 00000000..5ce8f0ab --- /dev/null +++ b/src/dawn/component/SimpleComponent.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "SimpleComponent.hpp" + +using namespace Dawn; + +void SimpleComponent::onInit() { + this->initMethod(*this, events); +} + +void SimpleComponent::onDispose() { + for(auto &event : events) { + event(); + } +} + +std::shared_ptr Dawn::addSimpleComponent( + std::shared_ptr item, + std::function>&)> init +) { + auto cmp = item->addComponent(); + cmp->initMethod = init; + return cmp; +} \ No newline at end of file diff --git a/src/dawn/component/SimpleComponent.hpp b/src/dawn/component/SimpleComponent.hpp new file mode 100644 index 00000000..9f51812c --- /dev/null +++ b/src/dawn/component/SimpleComponent.hpp @@ -0,0 +1,31 @@ +// 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 SimpleComponent final : public SceneComponent { + private: + std::vector> events; + + public: + std::function>& + )> initMethod; + + void onInit() override; + void onDispose() override; + }; + + std::shared_ptr addSimpleComponent( + std::shared_ptr item, + std::function>& + )> init + ); +} \ No newline at end of file diff --git a/src/dawn/component/display/Camera.cpp b/src/dawn/component/display/Camera.cpp index 062c7e4c..49a370c3 100644 --- a/src/dawn/component/display/Camera.cpp +++ b/src/dawn/component/display/Camera.cpp @@ -10,11 +10,11 @@ using namespace Dawn; void Camera::onInit() { - if(renderTarget == nullptr) { - this->setRenderTarget( - getGame()->renderHost.backBufferRenderTarget - ); - } + this->onResizeListener = this->getRenderTarget()->onResize.listen([&]( + float_t width, float_t height + ) { + this->onResize.emit(this->getRenderTarget(), width, height); + }); } void Camera::onDispose() { @@ -22,7 +22,8 @@ void Camera::onDispose() { } std::shared_ptr Camera::getRenderTarget() { - return this->renderTarget; + if(this->renderTarget) return this->renderTarget; + return getGame()->renderHost.getBackBufferRenderTarget(); } glm::mat4 Camera::getProjection() { @@ -52,13 +53,15 @@ glm::mat4 Camera::getProjection() { float_t Camera::getAspect() { auto rt = this->getRenderTarget(); - if(rt == nullptr) rt = getGame()->renderHost.getBackBufferRenderTarget(); return rt->getWidth() / rt->getHeight(); } void Camera::setRenderTarget(std::shared_ptr renderTarget) { - if(this->renderTarget != nullptr) { - - } + onResizeListener(); this->renderTarget = renderTarget; + this->onResizeListener = this->getRenderTarget()->onResize.listen([&]( + float_t width, float_t height + ) { + this->onResize.emit(this->getRenderTarget(), width, height); + }); } \ No newline at end of file diff --git a/src/dawn/component/display/Camera.hpp b/src/dawn/component/display/Camera.hpp index d804b7fd..f6103955 100644 --- a/src/dawn/component/display/Camera.hpp +++ b/src/dawn/component/display/Camera.hpp @@ -16,8 +16,10 @@ namespace Dawn { class Camera final : public SceneComponent { private: std::shared_ptr renderTarget; + std::function onResizeListener; public: + Event, float_t, float_t> onResize; float_t clipNear = 0.01f; float_t clipFar = 1000.0f; enum CameraType type = CameraType::PERSPECTIVE; diff --git a/src/dawn/display/RenderPipeline.cpp b/src/dawn/display/RenderPipeline.cpp index 5edfc27f..2b1df000 100644 --- a/src/dawn/display/RenderPipeline.cpp +++ b/src/dawn/display/RenderPipeline.cpp @@ -44,13 +44,13 @@ void RenderPipeline::renderScene( for(auto camera : cameras) { auto rt = camera->getRenderTarget(); // Is this camera the backbuffer camera? - if(rt == backBuffer || rt == nullptr) { + if(rt == backBuffer) { backbufferCamera = camera; continue; } // Render scene with this camera - renderSceneCamera(game, scene, camera, camera->getRenderTarget()); + renderSceneCamera(game, scene, camera, rt); } if(backbufferCamera) { diff --git a/src/dawn/display/RenderTarget.hpp b/src/dawn/display/RenderTarget.hpp index a049895b..59bdce25 100644 --- a/src/dawn/display/RenderTarget.hpp +++ b/src/dawn/display/RenderTarget.hpp @@ -4,7 +4,7 @@ // https://opensource.org/licenses/MIT #pragma once -#include "dawnlibs.hpp" +#include "event/Event.hpp" #define RENDER_TARGET_CLEAR_COLOR 1 << 0 #define RENDER_TARGET_CLEAR_DEPTH 1 << 1 @@ -12,6 +12,8 @@ namespace Dawn { class RenderTarget { public: + Event onResize; + /** * Return the width of the render target. * diff --git a/src/dawn/event/Event.hpp b/src/dawn/event/Event.hpp index 50bea65f..638da515 100644 --- a/src/dawn/event/Event.hpp +++ b/src/dawn/event/Event.hpp @@ -11,13 +11,20 @@ namespace Dawn { class Event { private: int32_t nextId = 0; - std::unordered_map> listeners; + std::map> listeners; public: + /** + * Constructs a new Event. + */ Event() { } + /** + * Emits the event. + * @param args The arguments to pass to the listeners. + */ void emit(A ...args) { auto copy = listeners; for(auto &pair : copy) { @@ -25,6 +32,11 @@ namespace Dawn { } } + /** + * Listens to the event. + * @param listener The listener to add. + * @returns A function that can be called to remove the listener. + */ std::function listen(const std::function listener) { int32_t id = nextId++; listeners[id] = listener; @@ -33,8 +45,12 @@ namespace Dawn { }; } + /** + * Removes a listener from the event. + * @param id The id of the listener to remove. + */ virtual ~Event() { listeners.clear(); } - } + }; } \ No newline at end of file diff --git a/src/dawn/game/Game.cpp b/src/dawn/game/Game.cpp index 7724fc8c..a45401e7 100644 --- a/src/dawn/game/Game.cpp +++ b/src/dawn/game/Game.cpp @@ -22,14 +22,15 @@ void Game::init() { } void Game::update() { - timeManager.update(); - renderHost.update(shared_from_this()); - if(nextFrameScene) { nextFrameScene->stage(); currentScene = nextFrameScene; nextFrameScene = nullptr; } + + timeManager.update(); + if(currentScene) currentScene->update(); + renderHost.update(shared_from_this()); } bool_t Game::isCloseRequested() { diff --git a/src/dawn/game/Game.hpp b/src/dawn/game/Game.hpp index f3c3a4e6..e796e995 100644 --- a/src/dawn/game/Game.hpp +++ b/src/dawn/game/Game.hpp @@ -14,8 +14,8 @@ namespace Dawn { class Game : public std::enable_shared_from_this { private: - std::shared_ptr currentScene; - std::shared_ptr nextFrameScene; + std::shared_ptr currentScene = nullptr; + std::shared_ptr nextFrameScene = nullptr; public: RenderHost renderHost; diff --git a/src/dawn/scene/Scene.cpp b/src/dawn/scene/Scene.cpp index 476b078b..50f177e9 100644 --- a/src/dawn/scene/Scene.cpp +++ b/src/dawn/scene/Scene.cpp @@ -22,6 +22,22 @@ void Scene::stage() { sceneInitializer(selfReference); } +void Scene::update() { + if(!hasInitialized) { + hasInitialized = true; + for(auto &item : sceneItems) { + item->init(); + } + } + + float_t delta = getGame()->timeManager.delta; + if(paused) { + onPausedUpdate.emit(delta); + } else { + onUnpausedUpdate.emit(delta); + } +} + std::shared_ptr Scene::getGame() { return game.lock(); } diff --git a/src/dawn/scene/Scene.hpp b/src/dawn/scene/Scene.hpp index 1c384463..71d07f91 100644 --- a/src/dawn/scene/Scene.hpp +++ b/src/dawn/scene/Scene.hpp @@ -13,8 +13,13 @@ namespace Dawn { std::weak_ptr game; const std::function sceneInitializer; std::vector> sceneItems; + bool_t paused = false; + bool_t hasInitialized = false; public: + Event onUnpausedUpdate; + Event onPausedUpdate; + /** * Constructs a scene object. * @@ -30,6 +35,14 @@ namespace Dawn { */ void stage(); + /** + * Called by the game every frame that the scene is set as the currently + * active scene. This may not be sequential, for example a scene can be + * active, then switched to a different scene temporarily, and then can be + * switched back to the active one. + */ + void update(); + /** * Returns a copy of the game instance that this scene belongs to. * diff --git a/src/dawn/scene/SceneItem.cpp b/src/dawn/scene/SceneItem.cpp index 98c97e94..0ca1d838 100644 --- a/src/dawn/scene/SceneItem.cpp +++ b/src/dawn/scene/SceneItem.cpp @@ -23,6 +23,13 @@ std::shared_ptr SceneItem::getScene() { return scene.lock(); } +void SceneItem::init() { + auto sharedThis = shared_from_this(); + for(auto &component : components) { + component->init(sharedThis); + } +} + SceneItem::~SceneItem() { std::for_each( components.begin(), diff --git a/src/dawn/scene/SceneItem.hpp b/src/dawn/scene/SceneItem.hpp index 0b384886..1c2b464b 100644 --- a/src/dawn/scene/SceneItem.hpp +++ b/src/dawn/scene/SceneItem.hpp @@ -29,6 +29,12 @@ namespace Dawn { */ SceneItem(const std::weak_ptr scene); + /** + * Called when the scene item is supposed to initialize. Should happen + * on the first frame that the scene item is staged. + */ + void init(); + /** * Returns the scene that this scene item belongs to. * diff --git a/src/dawn/scene/item/SceneItemComponents.hpp b/src/dawn/scene/item/SceneItemComponents.hpp index 40622478..6a178309 100644 --- a/src/dawn/scene/item/SceneItemComponents.hpp +++ b/src/dawn/scene/item/SceneItemComponents.hpp @@ -43,9 +43,6 @@ namespace Dawn { this->components.push_back( static_pointer_cast(component) ); - - // Init compoonent and return - component->init(sceneItemComponentsSelf()); return component; } diff --git a/src/dawn/scene/item/SceneItemTransform.cpp b/src/dawn/scene/item/SceneItemTransform.cpp index 807def5e..7f0e4b37 100644 --- a/src/dawn/scene/item/SceneItemTransform.cpp +++ b/src/dawn/scene/item/SceneItemTransform.cpp @@ -64,6 +64,29 @@ void SceneItemTransform::updateWorldTransformFromParent() { this->updateChildrenWorldTransforms(); } +void SceneItemTransform::updateLocalTransformFromLocalValues() { + this->transformLocal = glm::translate( + glm::mat4(1.0f), + this->localPosition + ) * glm::mat4_cast(this->localRotation) * glm::scale( + glm::mat4(1.0f), + this->localScale + ); + this->updateWorldTransformFromLocalTransform(); +} + +void SceneItemTransform::updateWorldTransformFromLocalTransform() { + auto parent = this->getParent(); + if(!parent) { + this->transformWorld = this->transformLocal; + } else { + this->transformWorld = ( + parent->transformWorld * this->transformLocal + ); + } + this->updateChildrenWorldTransforms(); +} + std::shared_ptr SceneItemTransform::getParent() { return parent.lock(); } @@ -88,12 +111,39 @@ glm::mat4 SceneItemTransform::getWorldTransform() { return this->transformWorld; } +glm::vec3 SceneItemTransform::getLocalPosition() { + return this->localPosition; +} + +glm::vec3 SceneItemTransform::getLocalScale() { + return this->localScale; +} + +glm::quat SceneItemTransform::getLocalRotation() { + return this->localRotation; +} + void SceneItemTransform::setWorldTransform(const glm::mat4 transform) { this->transformWorld = transform; this->updateLocalTransformFromWorldTransform(); this->updateChildrenWorldTransforms(); } +void SceneItemTransform::setLocalPosition(const glm::vec3 position) { + this->localPosition = position; + this->updateLocalTransformFromLocalValues(); +} + +void SceneItemTransform::setLocalScale(const glm::vec3 scale) { + this->localScale = scale; + this->updateLocalTransformFromLocalValues(); +} + +void SceneItemTransform::setLocalRotation(const glm::quat rotation) { + this->localRotation = rotation; + this->updateLocalTransformFromLocalValues(); +} + bool_t SceneItemTransform::isChildOf(std::shared_ptr item) { assertNotNull(item, "Cannot check if child of null item."); auto parent = this->getParent(); diff --git a/src/dawn/scene/item/SceneItemTransform.hpp b/src/dawn/scene/item/SceneItemTransform.hpp index 91cb91c6..b8151c7c 100644 --- a/src/dawn/scene/item/SceneItemTransform.hpp +++ b/src/dawn/scene/item/SceneItemTransform.hpp @@ -45,6 +45,16 @@ namespace Dawn { */ void updateWorldTransformFromParent(); + /** + * Updates the local transform of this item from the local values. + */ + void updateLocalTransformFromLocalValues(); + + /** + * Updates the world transform from this items local transform. + */ + void updateWorldTransformFromLocalTransform(); + public: SceneItemTransform(); @@ -75,6 +85,27 @@ namespace Dawn { * @return World transform of this item. */ glm::mat4 getWorldTransform(); + + /** + * Gets the local position of this item (relative to its parent). + * + * @return Local position of this item. + */ + glm::vec3 getLocalPosition(); + + /** + * Local scale of this item (relative to its parent). + * + * @return Local scale of this item. + */ + glm::vec3 getLocalScale(); + + /** + * Local rotation of this item (relative to its parent). + * + * @return Local rotation of this item. + */ + glm::quat getLocalRotation(); /** * Sets the transform of this item within world space (relative to scene @@ -84,6 +115,27 @@ namespace Dawn { */ void setWorldTransform(const glm::mat4 transform); + /** + * Sets the local position of this item (relative to its parent). + * + * @param position Local position of this item. + */ + void setLocalPosition(const glm::vec3 position); + + /** + * Sets the local scale of this item (relative to its parent). + * + * @param scale Local scale of this item. + */ + void setLocalScale(const glm::vec3 scale); + + /** + * Sets the local rotation of this item (relative to its parent). + * + * @param rotation Local rotation of this item. + */ + void setLocalRotation(const glm::quat rotation); + /** * Returns whether or not this item is a child of the given item. This * will traverse up the entire heirarchy to confirm. diff --git a/src/dawnglfw/display/RenderHost.cpp b/src/dawnglfw/display/RenderHost.cpp index dba4aabb..3590c111 100644 --- a/src/dawnglfw/display/RenderHost.cpp +++ b/src/dawnglfw/display/RenderHost.cpp @@ -82,8 +82,6 @@ void RenderHost::init(const std::shared_ptr game) { } void RenderHost::update(const std::shared_ptr game) { - - // Prepare the initial values glPixelStorei(GL_UNPACK_ALIGNMENT, 1); assertNoGLError(); diff --git a/src/dawnhelloworld/scene/HelloWorldScene.cpp b/src/dawnhelloworld/scene/HelloWorldScene.cpp index 0b801618..86612b36 100644 --- a/src/dawnhelloworld/scene/HelloWorldScene.cpp +++ b/src/dawnhelloworld/scene/HelloWorldScene.cpp @@ -8,6 +8,7 @@ #include "component/display/MeshRenderer.hpp" #include "component/display/material/SimpleTexturedMaterial.hpp" #include "display/mesh/CubeMesh.hpp" +#include "component/SimpleComponent.hpp" using namespace Dawn; @@ -26,4 +27,11 @@ void Dawn::helloWorldScene(Scene &s) { auto cubeMeshRenderer = cubeItem->addComponent(); cubeMeshRenderer->mesh = cubeMesh; auto cubeMaterial = cubeItem->addComponent(); + addSimpleComponent(cubeItem, [](auto &cmp, auto &events) { + events.push_back(cmp.getScene()->onUnpausedUpdate.listen([&](float_t delta) { + auto item = cmp.getItem(); + item->setLocalRotation(item->getLocalRotation() * glm::quat(glm::vec3(1, 1, 0) * delta)); + // item->setLocalScale(item->getLocalScale() + glm::vec3(1, 1, 1) * delta); + })); + }); } \ No newline at end of file diff --git a/src/dawnopengl/display/BackBufferRenderTarget.cpp b/src/dawnopengl/display/BackBufferRenderTarget.cpp index 318fba72..17628d81 100644 --- a/src/dawnopengl/display/BackBufferRenderTarget.cpp +++ b/src/dawnopengl/display/BackBufferRenderTarget.cpp @@ -36,7 +36,8 @@ void BackBufferRenderTarget::setSize( // Fixes a new bug that it seems GLFW has introduced. this->width = width == 0 ? 1 : width; this->height = height == 0 ? 1 : height; - // this->eventRenderTargetResized.invoke(*this, width, height); + + onResize.emit(this->width, this->height); } void BackBufferRenderTarget::setClearColor(const struct Color color) {