From 2fc010263d76e00c5db310cd9e38eddf588621d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 24 Nov 2012 17:42:59 +0100 Subject: [PATCH] Class AbstractResourceLoader. Base for (a)synchronous resource loading automatically trigerred from ResourceManager. --- src/AbstractResourceLoader.h | 137 +++++++++++++++++++++++++++++++ src/CMakeLists.txt | 1 + src/ResourceManager.h | 49 ++++++++++- src/Test/ResourceManagerTest.cpp | 34 +++++++- src/Test/ResourceManagerTest.h | 1 + 5 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 src/AbstractResourceLoader.h diff --git a/src/AbstractResourceLoader.h b/src/AbstractResourceLoader.h new file mode 100644 index 000000000..038054604 --- /dev/null +++ b/src/AbstractResourceLoader.h @@ -0,0 +1,137 @@ +#ifndef Magnum_AbstractResourceLoader_h +#define Magnum_AbstractResourceLoader_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::AbstractResourceLoader + */ + +#include "Magnum.h" + +#include + +#include "ResourceManager.h" + +namespace Magnum { + +/** +@brief Base for resource loaders + +Provides asynchronous resource loading for ResourceManager. +*/ +template class AbstractResourceLoader { + friend class Implementation::ResourceManagerData; + + public: + inline AbstractResourceLoader(): manager(nullptr), _requestedCount(0), _loadedCount(0), _notFoundCount(0) {} + + inline virtual ~AbstractResourceLoader() { + if(manager) manager->_loader = nullptr; + } + + /** + * @brief Count of requested resources + * + * Count of resources requested by calling load(). + */ + inline std::size_t requestedCount() const { return _requestedCount; } + + /** + * @brief Count of not found resources + * + * Count of resources requested by calling load(), but not found by + * the loader. + */ + inline std::size_t notFountCount() const { return _notFoundCount; } + + /** + * @brief Count of loaded resources + * + * Count of resources requested by calling load(), but not found by + * the loader. + */ + inline std::size_t loadedCount() const { return _loadedCount; } + + /** + * @brief %Resource name corresponding to given key + * + * If no such resource exists or the resource name is not available, + * returns empty string. Default implementation returns empty string. + */ + virtual std::string name(ResourceKey key) const; + + /** + * @brief Request resource to be loaded + * + * If the resource isn't yet loaded or loading, state of the resource + * is set to @ref Resource::ResourceState "ResourceState::Loading" and count of + * requested features is incremented. + * + * The resource might be loaded asynchronously and added to + * ResourceManager when loading is done. + * @see ResourceManager::state(), requestedCount(), notFountCount(), + * loadedCount() + */ + virtual void load(ResourceKey key) = 0; + + protected: + /** + * @brief Set loaded resource to resource manager + * + * Also increments count of loaded resources. Parameter @p state + * must be either @ref ResourceManager::ResourceDataState "ResourceDataState::Mutable" + * or @ref ResourceManager::ResourceDataState "ResourceDataState::Final". See + * ResourceManager::set() for more information. + * @see loadedCount() + */ + inline void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { + CORRADE_ASSERT(state == ResourceDataState::Mutable || state == ResourceDataState::Final, + "AbstractResourceLoader::set(): state must be either Mutable or Final", ); + ++_loadedCount; + manager->set(key, data, state, policy); + } + + /** + * @brief Mark resource as not found + * + * Also increments count of not found resources. See + * ResourceManager::setNotFound() for more information. + * @see notFountCount() + */ + inline void setNotFound(ResourceKey key) { + ++_notFoundCount; + /** @todo What policy for notfound resources? */ + manager->set(key, nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident); + } + + private: + Implementation::ResourceManagerData* manager; + std::size_t _requestedCount; + std::size_t _loadedCount; + std::size_t _notFoundCount; +}; + +template inline std::string AbstractResourceLoader::name(ResourceKey) const { return {}; } + +template inline void AbstractResourceLoader::load(ResourceKey key) { + ++_requestedCount; + /** @todo What policy for loading resources? */ + manager->set(key, nullptr, ResourceDataState::Loading, ResourcePolicy::Resident); +} + +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 26601309b..bbb9506dc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,7 @@ endif() set(Magnum_HEADERS AbstractImage.h + AbstractResourceLoader.h AbstractShaderProgram.h AbstractTexture.h Buffer.h diff --git a/src/ResourceManager.h b/src/ResourceManager.h index 22fe1c0b0..9546e3dc5 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -78,6 +78,8 @@ enum class ResourcePolicy: std::uint8_t { ReferenceCounted }; +template class AbstractResourceLoader; + #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { struct ResourceKeyHash { @@ -88,6 +90,7 @@ namespace Implementation { template class ResourceManagerData { template friend class Resource; + friend class AbstractResourceLoader; ResourceManagerData(const ResourceManagerData&) = delete; ResourceManagerData(ResourceManagerData&&) = delete; @@ -97,6 +100,11 @@ namespace Implementation { public: inline virtual ~ResourceManagerData() { delete _fallback; + + if(_loader) { + _loader->manager = nullptr; + delete _loader; + } } inline std::size_t lastChange() const { return _lastChange; } @@ -133,6 +141,10 @@ namespace Implementation { } template inline Resource get(ResourceKey key) { + /* Ask loader for the data, if they aren't there yet */ + if(_loader && _data.find(key) == _data.end()) + _loader->load(key); + return Resource(this, key); } @@ -188,8 +200,20 @@ namespace Implementation { } } + inline AbstractResourceLoader* loader() { return _loader; } + inline const AbstractResourceLoader* loader() const { return _loader; } + + inline void setLoader(AbstractResourceLoader* loader) { + /* Delete previous loader */ + delete _loader; + + /* Add new loader */ + _loader = loader; + if(_loader) _loader->manager = this; + } + protected: - inline ResourceManagerData(): _fallback(nullptr), _lastChange(0) {} + inline ResourceManagerData(): _fallback(nullptr), _loader(nullptr), _lastChange(0) {} private: struct Data { @@ -233,6 +257,7 @@ namespace Implementation { std::unordered_map _data; T* _fallback; + AbstractResourceLoader* _loader; std::size_t _lastChange; }; } @@ -422,6 +447,26 @@ template class ResourceManager: private Implementation::Resource freeInternal(std::common_type()...); } + /** @brief Loader for given type of resources */ + template inline AbstractResourceLoader* loader() { + return this->Implementation::ResourceManagerData::loader(); + } + + /** @overload */ + template inline const AbstractResourceLoader* loader() const { + return this->Implementation::ResourceManagerData::loader(); + } + + /** + * @brief Set loader for given type of resources + * + * The loader will affect only loading of resources requested after + * that. + */ + template inline void setLoader(AbstractResourceLoader* loader) { + return this->Implementation::ResourceManagerData::setLoader(loader); + } + private: template inline void freeInternal(std::common_type, std::common_type... t) { free(); @@ -441,5 +486,7 @@ template ResourceManager*& ResourceManager:: } +/* Make the definition complete */ +#include "AbstractResourceLoader.h" #endif diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index 863a5d2c1..9b87ea360 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -17,6 +17,7 @@ #include +#include "AbstractResourceLoader.h" #include "ResourceManager.h" using namespace std; @@ -36,6 +37,18 @@ class Data { typedef Magnum::ResourceManager ResourceManager; +class IntResourceLoader: public AbstractResourceLoader { + public: + void load(ResourceKey key) override { + AbstractResourceLoader::load(key); + } + + void load() { + set("hello", new std::int32_t(773), ResourceDataState::Final, ResourcePolicy::Resident); + setNotFound("world"); + } +}; + size_t Data::count = 0; ResourceManagerTest::ResourceManagerTest() { @@ -45,7 +58,8 @@ ResourceManagerTest::ResourceManagerTest() { &ResourceManagerTest::basic, &ResourceManagerTest::residentPolicy, &ResourceManagerTest::referenceCountedPolicy, - &ResourceManagerTest::manualPolicy); + &ResourceManagerTest::manualPolicy, + &ResourceManagerTest::loader); } void ResourceManagerTest::state() { @@ -205,4 +219,22 @@ void ResourceManagerTest::manualPolicy() { CORRADE_COMPARE(Data::count, 1); } +void ResourceManagerTest::loader() { + ResourceManager rm; + IntResourceLoader loader; + rm.setLoader(&loader); + + Resource data = rm.get("data"); + Resource hello = rm.get("hello"); + Resource world = rm.get("world"); + CORRADE_COMPARE(data.state(), ResourceState::NotLoaded); + CORRADE_COMPARE(hello.state(), ResourceState::Loading); + CORRADE_COMPARE(world.state(), ResourceState::Loading); + + loader.load(); + CORRADE_COMPARE(hello.state(), ResourceState::Final); + CORRADE_COMPARE(*hello, 773); + CORRADE_COMPARE(world.state(), ResourceState::NotFound); +} + }} diff --git a/src/Test/ResourceManagerTest.h b/src/Test/ResourceManagerTest.h index 73b4a49ea..fa95ec724 100644 --- a/src/Test/ResourceManagerTest.h +++ b/src/Test/ResourceManagerTest.h @@ -30,6 +30,7 @@ class ResourceManagerTest: public Corrade::TestSuite::Tester