From e3de7e6f3cbf79b4be8a12aae1141955494f43c6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 16 Jan 2015 12:36:13 +0100 Subject: [PATCH] Added Atlas listeners Former-commit-id: a487b6ed53d9b97bfee27b28ba5523e43c1e9e7e --- include/Nazara/Utility/AbstractFontAtlas.hpp | 26 ++++++-- include/Nazara/Utility/Font.hpp | 5 +- .../Nazara/Utility/GuillotineImageAtlas.hpp | 2 - src/Nazara/Utility/AbstractFontAtlas.cpp | 63 +++++++++++++++++++ src/Nazara/Utility/Font.cpp | 52 +++++++++++++-- 5 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 src/Nazara/Utility/AbstractFontAtlas.cpp diff --git a/include/Nazara/Utility/AbstractFontAtlas.hpp b/include/Nazara/Utility/AbstractFontAtlas.hpp index f3f06346a..f029731f2 100644 --- a/include/Nazara/Utility/AbstractFontAtlas.hpp +++ b/include/Nazara/Utility/AbstractFontAtlas.hpp @@ -10,31 +10,45 @@ #include #include #include -#include +#include class NzAbstractImage; -class NzFont; class NzImage; class NAZARA_API NzAbstractFontAtlas { public: - NzAbstractFontAtlas() = default; + class Listener; + + NzAbstractFontAtlas(); virtual ~NzAbstractFontAtlas(); + 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; virtual unsigned int GetLayerCount() const = 0; virtual bool Insert(const NzImage& image, NzRectui* rect, bool* flipped, unsigned int* layerIndex) = 0; - void RegisterFont(NzFont* font); - void UnregisterFont(NzFont* font); + + void RemoveListener(Listener* font) const; + + class Listener + { + public: + Listener() = default; + virtual ~Listener(); + + virtual bool OnAtlasCleared(const NzAbstractFontAtlas* atlas, void* userdata); + virtual void OnAtlasReleased(const NzAbstractFontAtlas* atlas, void* userdata); + }; protected: void NotifyCleared(); private: - std::set m_registredFonts; + mutable std::unordered_map m_listeners; + bool m_listenersLocked; }; #endif // NAZARA_ABSTRACTFONTATLAS_HPP diff --git a/include/Nazara/Utility/Font.hpp b/include/Nazara/Utility/Font.hpp index c2a5f1412..82164b09f 100644 --- a/include/Nazara/Utility/Font.hpp +++ b/include/Nazara/Utility/Font.hpp @@ -29,7 +29,7 @@ using NzFontConstRef = NzResourceRef; using NzFontLoader = NzResourceLoader; using NzFontRef = NzResourceRef; -class NAZARA_API NzFont : public NzResource, NzNonCopyable +class NAZARA_API NzFont : public NzResource, NzAbstractFontAtlas::Listener, NzNonCopyable { friend NzAbstractFontAtlas; friend NzFontLoader; @@ -108,7 +108,8 @@ class NAZARA_API NzFont : public NzResource, NzNonCopyable using GlyphMap = std::unordered_map; nzUInt64 ComputeKey(unsigned int characterSize, nzUInt32 style) const; - void OnAtlasCleared(); + bool OnAtlasCleared(const NzAbstractFontAtlas* atlas, void* userdata) override; + void OnAtlasReleased(const NzAbstractFontAtlas* atlas, void* userdata) override; const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const; std::shared_ptr m_atlas; diff --git a/include/Nazara/Utility/GuillotineImageAtlas.hpp b/include/Nazara/Utility/GuillotineImageAtlas.hpp index dc1542560..1bc478427 100644 --- a/include/Nazara/Utility/GuillotineImageAtlas.hpp +++ b/include/Nazara/Utility/GuillotineImageAtlas.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include class NAZARA_API NzGuillotineImageAtlas : public NzAbstractFontAtlas @@ -59,7 +58,6 @@ class NAZARA_API NzGuillotineImageAtlas : public NzAbstractFontAtlas private: void ProcessGlyphQueue(Layer& layer) const; - std::set m_fonts; mutable std::vector m_layers; NzGuillotineBinPack::FreeRectChoiceHeuristic m_rectChoiceHeuristic; NzGuillotineBinPack::GuillotineSplitHeuristic m_rectSplitHeuristic; diff --git a/src/Nazara/Utility/AbstractFontAtlas.cpp b/src/Nazara/Utility/AbstractFontAtlas.cpp new file mode 100644 index 000000000..710c52d8f --- /dev/null +++ b/src/Nazara/Utility/AbstractFontAtlas.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +NzAbstractFontAtlas::NzAbstractFontAtlas() : +m_listenersLocked(false) +{ +} + +NzAbstractFontAtlas::~NzAbstractFontAtlas() +{ + m_listenersLocked = true; + for (auto& pair : m_listeners) + pair.first->OnAtlasReleased(this, pair.second); +} + +void NzAbstractFontAtlas::AddListener(Listener* listener, void* userdata) const +{ + if (!m_listenersLocked) + m_listeners.insert(std::make_pair(listener, userdata)); +} + +void NzAbstractFontAtlas::RemoveListener(Listener* listener) const +{ + if (!m_listenersLocked) + m_listeners.erase(listener); +} + +void NzAbstractFontAtlas::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; +} + +NzAbstractFontAtlas::Listener::~Listener() = default; + +bool NzAbstractFontAtlas::Listener::OnAtlasCleared(const NzAbstractFontAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + return true; +} + +void NzAbstractFontAtlas::Listener::OnAtlasReleased(const NzAbstractFontAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); +} diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index 81def3c1e..d1e061b0b 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -28,8 +28,11 @@ void NzFont::ClearGlyphCache() { if (m_atlas) { - if (m_atlas.use_count() > 1) // Au moins une autre police utilise cet atlas, on vire nos glyphes + if (m_atlas.unique()) + m_atlas->Clear(); // Appellera OnAtlasCleared + else { + // Au moins une autre police utilise cet atlas, on vire nos glyphes un par un for (auto mapIt = m_glyphes.begin(); mapIt != m_glyphes.end(); ++mapIt) { GlyphMap& glyphMap = mapIt->second; @@ -40,12 +43,10 @@ void NzFont::ClearGlyphCache() } } - // Destruction des glyphes mémorisés + // Destruction des glyphes mémorisés et notification m_glyphes.clear(); NotifyModified(ModificationCode_GlyphCacheCleared); } - else - m_atlas->Clear(); } } @@ -268,7 +269,12 @@ void NzFont::SetAtlas(std::shared_ptr atlas) { ClearGlyphCache(); + if (m_atlas) + m_atlas->RemoveListener(this); + m_atlas = atlas; + if (m_atlas) + m_atlas->AddListener(this); } void NzFont::SetGlyphBorder(unsigned int borderSize) @@ -293,7 +299,10 @@ void NzFont::SetMinimumStepSize(unsigned int minimumStepSize) nzUInt64 NzFont::ComputeKey(unsigned int characterSize, nzUInt32 style) const { + // On prend le pas en compte nzUInt64 sizePart = static_cast((characterSize/m_minimumSizeStep)*m_minimumSizeStep); + + // Ainsi que le style (uniquement le gras et l'italique, les autres sont gérés par un TextDrawer) nzUInt64 stylePart = 0; if (style & nzTextStyle_Bold) @@ -305,12 +314,43 @@ nzUInt64 NzFont::ComputeKey(unsigned int characterSize, nzUInt32 style) const return (stylePart << 32) | sizePart; } -void NzFont::OnAtlasCleared() +bool NzFont::OnAtlasCleared(const NzAbstractFontAtlas* atlas, void* userdata) { + NazaraUnused(atlas); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + // Est-ce qu'il s'agit bien de notre atlas ? + if (m_atlas != atlas) + { + NazaraInternalError("Notified by a non-listening-to resource"); + return false; // On ne veut plus être notifié par cette ressource, évidemment + } + #endif + // Notre atlas vient d'être vidé, détruisons le cache de glyphe m_glyphes.clear(); - NotifyModified(ModificationCode_GlyphCacheCleared); + + return true; +} + +void NzFont::OnAtlasReleased(const NzAbstractFontAtlas* atlas, void* userdata) +{ + NazaraUnused(atlas); + NazaraUnused(userdata); + + #ifdef NAZARA_DEBUG + // Est-ce qu'il s'agit bien de notre atlas ? + if (m_atlas != atlas) + { + NazaraInternalError("Notified by a non-listening-to resource"); + return; + } + #endif + + // Nous ne pouvons pas faire grand chose d'autre que se balancer une erreur à la tête de l'utilisateur avant un potentiel crash... + NazaraError("Atlas has been released while in use"); } const NzFont::Glyph& NzFont::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, nzUInt32 style, char32_t character) const