From 68b5cd8df5475e32148bf61dd1f6731d5be2fd2a Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 28 Feb 2023 22:18:26 -0800 Subject: [PATCH] Updated useEvent --- src/dawn/scene/Scene.hpp | 3 +- src/dawn/scene/SceneItemComponent.hpp | 2 +- src/dawn/scene/components/display/Camera.cpp | 33 ++++++---- .../components/display/PixelPerfectCamera.cpp | 8 +-- .../display/SimpleRenderTargetQuad.cpp | 4 +- src/dawn/state/State.hpp | 62 +++++++++++++++---- src/dawn/state/StateEvent.hpp | 56 ++++++++++++++--- src/dawn/state/StateProperty.hpp | 8 ++- .../components/TicTacToeTile.cpp | 3 +- src/dawntictactoe/scenes/TicTacToeScene.hpp | 2 + 10 files changed, 135 insertions(+), 46 deletions(-) diff --git a/src/dawn/scene/Scene.hpp b/src/dawn/scene/Scene.hpp index 3e8a0add..155d9d6a 100644 --- a/src/dawn/scene/Scene.hpp +++ b/src/dawn/scene/Scene.hpp @@ -8,6 +8,7 @@ #include "asset/Asset.hpp" #include "scene/debug/SceneDebugLine.hpp" #include "physics/ScenePhysicsManager.hpp" +#include "state/State.hpp" namespace Dawn { class DawnGame; @@ -20,7 +21,7 @@ namespace Dawn { template T * _sceneForwardGetComponent(SceneItem *item); - class Scene { + class Scene : public StateOwner { private: sceneitemid_t nextId; std::map items; diff --git a/src/dawn/scene/SceneItemComponent.hpp b/src/dawn/scene/SceneItemComponent.hpp index c4ef6159..15156560 100644 --- a/src/dawn/scene/SceneItemComponent.hpp +++ b/src/dawn/scene/SceneItemComponent.hpp @@ -76,7 +76,7 @@ namespace Dawn { /** * Cleanup the SceneItemComponent. */ - ~SceneItemComponent(); + virtual ~SceneItemComponent(); }; diff --git a/src/dawn/scene/components/display/Camera.cpp b/src/dawn/scene/components/display/Camera.cpp index d1228660..eaf4a815 100644 --- a/src/dawn/scene/components/display/Camera.cpp +++ b/src/dawn/scene/components/display/Camera.cpp @@ -78,7 +78,7 @@ glm::vec3 Camera::getRayDirectionFromScreenSpace(glm::vec2 screenSpace) { void Camera::onStart() { // Render Target - useEffect(renderTarget, [&]{ + useEffect([&]{ if(renderTarget.previous != nullptr) { renderTarget.previous->eventRenderTargetResized.removeListener( this, &Camera::onRenderTargetResize @@ -94,21 +94,30 @@ void Camera::onStart() { rt->getWidth(), rt->getHeight() ); this->event2RenderTargetResized.invoke(rt->getWidth(), rt->getHeight()); - }); + }, renderTarget); // All regular properties. - auto cbUpdateProj = [&]{ + useEffect([&]{ this->projectionNeedsUpdating = true; - }; + }, { + &fov, + &type, + &orthoLeft, + &orthoRight, + &orthoBottom, + &orthoTop, + &clipNear, + &clipFar + }); - useEffect(fov, cbUpdateProj); - useEffect(type, cbUpdateProj); - useEffect(orthoLeft, cbUpdateProj); - useEffect(orthoRight, cbUpdateProj); - useEffect(orthoBottom, cbUpdateProj); - useEffect(orthoTop, cbUpdateProj); - useEffect(clipNear, cbUpdateProj); - useEffect(clipFar, cbUpdateProj); + // useEffect(fov, cbUpdateProj); + // useEffect(type, cbUpdateProj); + // useEffect(orthoLeft, cbUpdateProj); + // useEffect(orthoRight, cbUpdateProj); + // useEffect(orthoBottom, cbUpdateProj); + // useEffect(orthoTop, cbUpdateProj); + // useEffect(clipNear, cbUpdateProj); + // useEffect(clipFar, cbUpdateProj); getRenderTarget()->eventRenderTargetResized.addListener(this, &Camera::onRenderTargetResize); } diff --git a/src/dawn/scene/components/display/PixelPerfectCamera.cpp b/src/dawn/scene/components/display/PixelPerfectCamera.cpp index 8edc8139..d5ed5fc6 100644 --- a/src/dawn/scene/components/display/PixelPerfectCamera.cpp +++ b/src/dawn/scene/components/display/PixelPerfectCamera.cpp @@ -55,11 +55,11 @@ void PixelPerfectCamera::onStart() { assertNotNull(this->camera); this->updateDimensions(); - useEvent(this->camera->event2RenderTargetResized, [&](float_t w, float_t h){ + useEvent([&](float_t w, float_t h){ this->updateDimensions(); - }); + }, this->camera->event2RenderTargetResized); - useEffect(scale, [&]{ + useEffect([&]{ this->updateDimensions(); - }); + }, scale); } \ No newline at end of file diff --git a/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp b/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp index 94373399..afe00737 100644 --- a/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp +++ b/src/dawn/scene/components/display/SimpleRenderTargetQuad.cpp @@ -42,7 +42,7 @@ void SimpleRenderTargetQuad::onStart() { // Create quad mesh this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT); - useEffect(this->renderTarget, [&]{ + useEffect([&]{ if(this->renderTarget.previous != nullptr) { this->renderTarget.previous->eventRenderTargetResized.addListener( this, &SimpleRenderTargetQuad::onRenderTargetResized @@ -66,7 +66,7 @@ void SimpleRenderTargetQuad::onStart() { ((RenderTarget*)this->renderTarget)->eventRenderTargetResized.addListener( this, &SimpleRenderTargetQuad::onRenderTargetResized ); - }); + }, this->renderTarget); // Perform first resize. if(this->renderTarget != nullptr) { diff --git a/src/dawn/state/State.hpp b/src/dawn/state/State.hpp index b6308caf..9f9c39f4 100644 --- a/src/dawn/state/State.hpp +++ b/src/dawn/state/State.hpp @@ -11,24 +11,40 @@ namespace Dawn { class StateOwner { private: std::vector eventsSubscribed; - + public: /** - * Listen for changees to a state property and involke the provided func + * Listen for changes to a state property and invoke the provided func * when the value is changed. * - * @tparam V The type of the state property. - * @param property Property to listen for affect changees to. * @param fn The callback to be invoked when the state value changes. + * @param property Property to listen for affect changees to. */ - template void useEffect( - StateProperty &property, - const std::function &fn + const std::function &fn, + IStateProperty &property ) { property._effectListners.push_back(fn); } + /** + * Listen for changes to a set of state properties and invoke the provided + * func when any of their values are changed. + * + * @param fn The callback to be invoked when the state value changes. + * @param property Vector list of properties to listen for changes to. + */ + void useEffect( + const std::function &fn, + std::vector props + ) { + auto itProp = props.begin(); + while(itProp != props.end()) { + (*itProp)->_effectListners.push_back(fn); + ++itProp; + } + } + /** * Listen for when an event is invoked by a state event. This is intended * to allow for cross-state-owner communication in a simple and effective @@ -36,16 +52,38 @@ namespace Dawn { * * @tparam F The type of the callback function. * @tparam A The arguments from the state event that are calledback. - * @param event The event that is being subscribed to. * @param fn The function to be inokved on event trigger. + * @param event The event that is being subscribed to. */ template - void useEvent(StateEvent &event, F fn) { - event._eventListeners[this].push_back(fn); - this->eventsSubscribed.push_back(&event); + std::function useEvent(F fn, StateEvent &event) { + + // Create a listener structure + struct StateEventListener listener; + listener.listener = fn; + listener.owner = this; + listener.event = &event; + listener.unsubWithParams = [&](struct StateEventListener listener) { + auto itFound = listener.event->_eventListeners.begin(); + while(itFound != listener.event->_eventListeners.end()) { + if(itFound->id == listener.id) { + listener.event->_eventListeners.erase(itFound); + break; + } + ++itFound++; + } + }; + listener.id = event.stateEventId++; + listener.unsub = std::bind(listener.unsubWithParams, listener); + + // Put that listener structure on to the event stack + event._eventListeners.push_back(listener); + this->eventsSubscribed.push_back(&event); + + return listener.unsub; } - ~StateOwner() { + virtual ~StateOwner() { auto it = this->eventsSubscribed.begin(); while(it != this->eventsSubscribed.end()) { (*it)->_stateOwnerDestroyed(this); diff --git a/src/dawn/state/StateEvent.hpp b/src/dawn/state/StateEvent.hpp index 753b5ba6..2e048388 100644 --- a/src/dawn/state/StateEvent.hpp +++ b/src/dawn/state/StateEvent.hpp @@ -9,8 +9,28 @@ namespace Dawn { class StateOwner; + template + class StateEvent; + + template + struct StateEventListener { + uint32_t id; + StateOwner *owner; + std::function listener; + std::function)> unsubWithParams; + std::function unsub; + StateEvent *event; + }; + class IStateEvent { protected: + /** + * Received notification from a state owner to let this state event know + * that it wishes to unsubscribe all the event listeners that it may have + * attached to this event. + * + * @param owner State owner that is being disposed. + */ virtual void _stateOwnerDestroyed(StateOwner *owner) = 0; friend class StateOwner; @@ -19,12 +39,21 @@ namespace Dawn { template class StateEvent : public IStateEvent { protected: + uint32_t stateEventId = 0; + void _stateOwnerDestroyed(StateOwner *owner) override { - this->_eventListeners.erase(owner); + auto it = this->_eventListeners.begin(); + while(it != this->_eventListeners.end()) { + if(it->owner == owner) { + it = this->_eventListeners.erase(it); + } else { + ++it; + } + } } public: - std::map>> _eventListeners; + std::vector> _eventListeners; /** * Invokes the event and emits to all of the listeners. @@ -32,15 +61,22 @@ namespace Dawn { * @param args Arguments for this event to pass to the listeners. */ void invoke(A... args) { - auto itListeners = this->_eventListeners.begin(); - while(itListeners != this->_eventListeners.end()) { - auto itLists = itListeners->second.begin(); - while(itLists != itListeners->second.end()) { - (*itLists)(args...); - ++itLists; - } - ++itListeners; + auto it = this->_eventListeners.begin(); + while(it != this->_eventListeners.end()) { + it->listener(args...); + ++it; } + // auto itListeners = this->_eventListeners.begin(); + // while(itListeners != this->_eventListeners.end()) { + // auto itLists = itListeners->second.begin(); + // while(itLists != itListeners->second.end()) { + // (*itLists)(args...); + // ++itLists; + // } + // ++itListeners; + // } } + + friend class StateOwner; }; } \ No newline at end of file diff --git a/src/dawn/state/StateProperty.hpp b/src/dawn/state/StateProperty.hpp index 3b83c319..15ab7a54 100644 --- a/src/dawn/state/StateProperty.hpp +++ b/src/dawn/state/StateProperty.hpp @@ -7,8 +7,13 @@ #include "assert/assert.hpp" namespace Dawn { + class IStateProperty { + public: + std::vector> _effectListners; + }; + template - class StateProperty { + class StateProperty : public IStateProperty { private: /** * Method that is invoked every time that the value of this state property @@ -31,7 +36,6 @@ namespace Dawn { public: V _realValue; - std::vector> _effectListners; V previous; /** diff --git a/src/dawntictactoe/components/TicTacToeTile.cpp b/src/dawntictactoe/components/TicTacToeTile.cpp index e733eba5..3731dbd1 100644 --- a/src/dawntictactoe/components/TicTacToeTile.cpp +++ b/src/dawntictactoe/components/TicTacToeTile.cpp @@ -25,7 +25,6 @@ void TicTacToeTile::onStart() { } }; - useEffect(tileState, cb); - useEffect(hovered, cb); + useEffect(cb, { &tileState, &hovered }); cb(); } \ No newline at end of file diff --git a/src/dawntictactoe/scenes/TicTacToeScene.hpp b/src/dawntictactoe/scenes/TicTacToeScene.hpp index e02dc11d..9acb84f3 100644 --- a/src/dawntictactoe/scenes/TicTacToeScene.hpp +++ b/src/dawntictactoe/scenes/TicTacToeScene.hpp @@ -17,6 +17,8 @@ namespace Dawn { class TicTacToeScene : public Scene { protected: Camera *camera; + StateProperty age; + StateEvent ageEvent; void stage() override { camera = Camera::create(this);