diff --git a/include/Nazara/Core/Listenable.hpp b/include/Nazara/Core/Listenable.hpp new file mode 100644 index 000000000..66c6edcd3 --- /dev/null +++ b/include/Nazara/Core/Listenable.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LISTENABLE_HPP +#define NAZARA_LISTENABLE_HPP + +#include +#include + +template +class NzListenable +{ + public: + NzListenable(); + ~NzListenable() = default; + + template void AddListener(L* listener, void* userdata = nullptr) const; + template void RemoveListener(L* listener) const; + + template void Notify(F callback, Args&&... args); + template void NotifyRelease(F callback); + + private: + mutable std::unordered_map m_listeners; + bool m_listenersLocked; +}; + +#include + +#endif // NAZARA_LISTENABLE_HPP diff --git a/include/Nazara/Core/Listenable.inl b/include/Nazara/Core/Listenable.inl new file mode 100644 index 000000000..c69dc6260 --- /dev/null +++ b/include/Nazara/Core/Listenable.inl @@ -0,0 +1,68 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +template +NzListenable::NzListenable() : +m_listenersLocked(false) +{ +} + +template +template +void NzListenable::AddListener(L* listener, void* userdata) const +{ + static_assert(std::is_base_of::value, "`listener` does not derive from a Listener"); + + if (!m_listenersLocked) + m_listeners.insert(std::make_pair(listener, userdata)); +} + +template +template +void NzListenable::RemoveListener(L* listener) const +{ + static_assert(std::is_base_of::value, "`listener` does not derive from a Listener"); + + if (!m_listenersLocked) + m_listeners.erase(listener); +} + +template +template +void NzListenable::Notify(F callback, Args&&... args) +{ + using Listener = typename Base::Listener; + + m_listenersLocked = true; + + auto it = m_listeners.begin(); + while (it != m_listeners.end()) + { + Listener* listener = static_cast(it->first); + if (!(listener->*callback)(static_cast(this), std::forward(args)..., it->second)) + m_listeners.erase(it++); + else + ++it; + } + + m_listenersLocked = false; +} + +template +template +void NzListenable::NotifyRelease(F callback) +{ + using Listener = typename Base::Listener; + + m_listenersLocked = true; + for (auto& pair : m_listeners) + { + Listener* listener = static_cast(pair.first); + (listener->*callback)(static_cast(this), pair.second); + } +} + +#include diff --git a/include/Nazara/Renderer/RenderTarget.hpp b/include/Nazara/Renderer/RenderTarget.hpp index b9f5643ad..d6affd968 100644 --- a/include/Nazara/Renderer/RenderTarget.hpp +++ b/include/Nazara/Renderer/RenderTarget.hpp @@ -8,24 +8,21 @@ #define NAZARA_RENDERTARGET_HPP #include +#include #include #include #include class NzRenderer; -class NAZARA_API NzRenderTarget +class NAZARA_API NzRenderTarget : public NzListenable { friend class NzRenderer; public: - class Listener; - - NzRenderTarget(); + NzRenderTarget() = default; virtual ~NzRenderTarget(); - void AddListener(Listener* listener, void* userdata = nullptr) const; - virtual unsigned int GetHeight() const = 0; virtual NzRenderTargetParameters GetParameters() const = 0; virtual unsigned int GetWidth() const = 0; @@ -33,8 +30,6 @@ class NAZARA_API NzRenderTarget bool IsActive() const; virtual bool IsRenderable() const = 0; - void RemoveListener(Listener* listener) const; - bool SetActive(bool active); // Fonctions OpenGL @@ -55,13 +50,6 @@ class NAZARA_API NzRenderTarget virtual bool Activate() const = 0; virtual void Desactivate() const; virtual void EnsureTargetUpdated() const = 0; - - void NotifyParametersChange(); - void NotifySizeChange(); - - private: - mutable std::unordered_map m_listeners; - bool m_listenersLocked; }; #endif // NAZARA_RENDERTARGET_HPP diff --git a/include/Nazara/Utility/AbstractAtlas.hpp b/include/Nazara/Utility/AbstractAtlas.hpp index eb0a240ae..b9f49181a 100644 --- a/include/Nazara/Utility/AbstractAtlas.hpp +++ b/include/Nazara/Utility/AbstractAtlas.hpp @@ -8,6 +8,7 @@ #define NAZARA_ABSTRACTATLAS_HPP #include +#include #include #include #include @@ -16,16 +17,12 @@ class NzAbstractImage; class NzImage; -class NAZARA_API NzAbstractAtlas +class NAZARA_API NzAbstractAtlas : public NzListenable { public: - class Listener; - - NzAbstractAtlas(); + NzAbstractAtlas() = default; virtual ~NzAbstractAtlas(); - void AddListener(Listener* font, void* userdata = nullptr) const; - virtual void Clear() = 0; virtual void Free(NzSparsePtr rects, NzSparsePtr layers, unsigned int count) = 0; virtual NzAbstractImage* GetLayer(unsigned int layerIndex) const = 0; @@ -33,8 +30,6 @@ class NAZARA_API NzAbstractAtlas virtual nzUInt32 GetStorage() const = 0; virtual bool Insert(const NzImage& image, NzRectui* rect, bool* flipped, unsigned int* layerIndex) = 0; - void RemoveListener(Listener* font) const; - class NAZARA_API Listener { public: @@ -45,14 +40,6 @@ class NAZARA_API NzAbstractAtlas virtual bool OnAtlasLayerChange(const NzAbstractAtlas* atlas, NzAbstractImage* oldLayer, NzAbstractImage* newLayer, void* userdata); virtual void OnAtlasReleased(const NzAbstractAtlas* atlas, void* userdata); }; - - protected: - void NotifyCleared(); - void NotifyLayerChange(NzAbstractImage* oldLayer, NzAbstractImage* newLayer); - - private: - mutable std::unordered_map m_listeners; - bool m_listenersLocked; }; #endif // NAZARA_ABSTRACTATLAS_HPP diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp index bc24f9d7e..116dd1045 100644 --- a/include/Nazara/Utility/Node.hpp +++ b/include/Nazara/Utility/Node.hpp @@ -8,6 +8,7 @@ #define NAZARA_NODE_HPP #include +#include #include #include #include @@ -15,17 +16,13 @@ #include #include -class NAZARA_API NzNode +class NAZARA_API NzNode : public NzListenable { public: - class Listener; - NzNode(); NzNode(const NzNode& node); virtual ~NzNode(); - void AddListener(Listener* listener, void* userdata = nullptr) const; - void EnsureDerivedUpdate() const; void EnsureTransformMatrixUpdate() const; @@ -56,7 +53,6 @@ class NAZARA_API NzNode NzNode& Move(const NzVector3f& movement, nzCoordSys coordSys = nzCoordSys_Local); NzNode& Move(float movementX, float movementY, float movementZ = 0.f, nzCoordSys coordSys = nzCoordSys_Local); - void RemoveListener(Listener* listener) const; NzNode& Rotate(const NzQuaternionf& rotation, nzCoordSys coordSys = nzCoordSys_Local); NzNode& Scale(const NzVector3f& scale); @@ -131,14 +127,6 @@ class NAZARA_API NzNode bool m_inheritScale; mutable bool m_transformMatrixUpdated; - private: - void NotifyInvalidation(); - void NotifyParented(const NzNode* parent); - - private: - mutable std::unordered_map m_listeners; - bool m_listenersLocked; - }; #endif // NAZARA_NODE_HPP diff --git a/src/Nazara/Renderer/RenderTarget.cpp b/src/Nazara/Renderer/RenderTarget.cpp index 47bd8db6d..86625ff2d 100644 --- a/src/Nazara/Renderer/RenderTarget.cpp +++ b/src/Nazara/Renderer/RenderTarget.cpp @@ -6,22 +6,9 @@ #include #include -NzRenderTarget::NzRenderTarget() : -m_listenersLocked(false) -{ -} - NzRenderTarget::~NzRenderTarget() { - m_listenersLocked = true; - for (auto& pair : m_listeners) - pair.first->OnRenderTargetReleased(this, pair.second); -} - -void NzRenderTarget::AddListener(Listener* listener, void* userdata) const -{ - if (!m_listenersLocked) - m_listeners.insert(std::make_pair(listener, userdata)); + NotifyRelease(Listener::OnRenderTargetReleased); } bool NzRenderTarget::IsActive() const @@ -29,12 +16,6 @@ bool NzRenderTarget::IsActive() const return NzRenderer::GetTarget() == this; } -void NzRenderTarget::RemoveListener(Listener* listener) const -{ - if (!m_listenersLocked) - m_listeners.erase(listener); -} - bool NzRenderTarget::SetActive(bool active) { if (active) @@ -50,38 +31,6 @@ void NzRenderTarget::Desactivate() const // Seuls les target sans contextes (ex: NzRenderTexture) nécessitent une désactivation } -void NzRenderTarget::NotifyParametersChange() -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnRenderTargetParametersChange(this, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - -void NzRenderTarget::NotifySizeChange() -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnRenderTargetSizeChange(this, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - NzRenderTarget::Listener::~Listener() = default; bool NzRenderTarget::Listener::OnRenderTargetParametersChange(const NzRenderTarget* renderTarget, void* userdata) diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index 4f1b53962..5793dde87 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -376,8 +376,8 @@ bool NzRenderTexture::Create(bool lock) onExit.Reset(); } - NotifyParametersChange(); - NotifySizeChange(); + Notify(Listener::OnRenderTargetParametersChange); + Notify(Listener::OnRenderTargetSizeChange); return true; } diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 479fdb2ff..c7ac5ca49 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -278,8 +278,8 @@ bool NzRenderWindow::OnWindowCreated() NzOpenGL::SetScissorBox(NzRecti(0, 0, size.x, size.y)); NzOpenGL::SetViewport(NzRecti(0, 0, size.x, size.y)); - NotifyParametersChange(); - NotifySizeChange(); + Notify(Listener::OnRenderTargetParametersChange); + Notify(Listener::OnRenderTargetSizeChange); m_clock.Restart(); @@ -300,5 +300,5 @@ void NzRenderWindow::OnWindowDestroy() void NzRenderWindow::OnWindowResized() { - NotifySizeChange(); + Notify(Listener::OnRenderTargetSizeChange); } diff --git a/src/Nazara/Utility/AbstractAtlas.cpp b/src/Nazara/Utility/AbstractAtlas.cpp index dac73acf7..14283bb88 100644 --- a/src/Nazara/Utility/AbstractAtlas.cpp +++ b/src/Nazara/Utility/AbstractAtlas.cpp @@ -5,63 +5,11 @@ #include #include -NzAbstractAtlas::NzAbstractAtlas() : -m_listenersLocked(false) -{ -} - NzAbstractAtlas::~NzAbstractAtlas() { - m_listenersLocked = true; - for (auto& pair : m_listeners) - pair.first->OnAtlasReleased(this, pair.second); + NotifyRelease(Listener::OnAtlasReleased); } -void NzAbstractAtlas::AddListener(Listener* listener, void* userdata) const -{ - if (!m_listenersLocked) - m_listeners.insert(std::make_pair(listener, userdata)); -} - -void NzAbstractAtlas::RemoveListener(Listener* listener) const -{ - if (!m_listenersLocked) - m_listeners.erase(listener); -} - -void NzAbstractAtlas::NotifyCleared() -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnAtlasCleared(this, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - -void NzAbstractAtlas::NotifyLayerChange(NzAbstractImage* oldLayer, NzAbstractImage* newLayer) -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnAtlasLayerChange(this, oldLayer, newLayer, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - - NzAbstractAtlas::Listener::~Listener() = default; bool NzAbstractAtlas::Listener::OnAtlasCleared(const NzAbstractAtlas* atlas, void* userdata) diff --git a/src/Nazara/Utility/GuillotineImageAtlas.cpp b/src/Nazara/Utility/GuillotineImageAtlas.cpp index 96d52f12a..94aafd47d 100644 --- a/src/Nazara/Utility/GuillotineImageAtlas.cpp +++ b/src/Nazara/Utility/GuillotineImageAtlas.cpp @@ -22,7 +22,7 @@ NzGuillotineImageAtlas::~NzGuillotineImageAtlas() = default; void NzGuillotineImageAtlas::Clear() { m_layers.clear(); - NotifyCleared(); + Notify(Listener::OnAtlasCleared); } void NzGuillotineImageAtlas::Free(NzSparsePtr rects, NzSparsePtr layers, unsigned int count) @@ -187,7 +187,7 @@ bool NzGuillotineImageAtlas::ResizeLayer(Layer& layer, const NzVector2ui& size) // On indique à ceux que ça intéresse qu'on a changé de pointeur // (chose très importante pour ceux qui le stockent) - NotifyLayerChange(layer.image.get(), newImage.get()); + Notify(Listener::OnAtlasLayerChange, layer.image.get(), newImage.get()); // Et on ne met à jour le pointeur qu'après (car cette ligne libère également l'ancienne image) layer.image = std::move(newImage); diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp index be5fe899a..317fdaec3 100644 --- a/src/Nazara/Utility/Node.cpp +++ b/src/Nazara/Utility/Node.cpp @@ -50,15 +50,7 @@ NzNode::~NzNode() SetParent(nullptr); - m_listenersLocked = true; - for (auto& pair : m_listeners) - pair.first->OnNodeReleased(this, pair.second); -} - -void NzNode::AddListener(Listener* listener, void* userdata) const -{ - if (!m_listenersLocked) - m_listeners.insert(std::make_pair(listener, userdata)); + NotifyRelease(Listener::OnNodeReleased); } void NzNode::EnsureDerivedUpdate() const @@ -293,12 +285,6 @@ NzNode& NzNode::Move(float moveX, float moveY, float moveZ, nzCoordSys coordSys) return Move(NzVector3f(moveX, moveY, moveZ), coordSys); } -void NzNode::RemoveListener(Listener* listener) const -{ - if (!m_listenersLocked) - m_listeners.erase(listener); -} - NzNode& NzNode::Rotate(const NzQuaternionf& rotation, nzCoordSys coordSys) { // Évitons toute mauvaise surprise .. @@ -662,12 +648,12 @@ void NzNode::InvalidateNode() for (NzNode* node : m_childs) node->InvalidateNode(); - NotifyInvalidation(); + Notify(Listener::OnNodeInvalidated); } void NzNode::OnParenting(const NzNode* parent) { - NotifyParented(parent); + Notify(Listener::OnNodeParented, parent); } void NzNode::RemoveChild(NzNode* node) const @@ -722,38 +708,6 @@ void NzNode::UpdateTransformMatrix() const m_transformMatrixUpdated = true; } -void NzNode::NotifyInvalidation() -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnNodeInvalidated(this, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - -void NzNode::NotifyParented(const NzNode* parent) -{ - m_listenersLocked = true; - - auto it = m_listeners.begin(); - while (it != m_listeners.end()) - { - if (!it->first->OnNodeParented(this, parent, it->second)) - m_listeners.erase(it++); - else - ++it; - } - - m_listenersLocked = false; -} - NzNode::Listener::~Listener() = default; bool NzNode::Listener::OnNodeInvalidated(const NzNode* node, void* userdata)