diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-28 18:18:13 +0100 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-28 18:18:13 +0100 |
commit | 0e45d4835f65ff9127a16adcbe9a9f0a20370cfc (patch) | |
tree | dc67a18640c8b65c575e97d161059944f0b1757a | |
parent | a685e5f743786cc6499e7ce8973bb78a83d101f7 (diff) |
implement resource manager
-rw-r--r-- | src/crepe/ResourceManager.cpp | 37 | ||||
-rw-r--r-- | src/crepe/ResourceManager.h | 51 | ||||
-rw-r--r-- | src/crepe/ResourceManager.hpp | 26 | ||||
-rw-r--r-- | src/test/ResourceManagerTest.cpp | 95 |
4 files changed, 87 insertions, 122 deletions
diff --git a/src/crepe/ResourceManager.cpp b/src/crepe/ResourceManager.cpp index 111b9e0..8b1fbf5 100644 --- a/src/crepe/ResourceManager.cpp +++ b/src/crepe/ResourceManager.cpp @@ -1,5 +1,3 @@ -#include <stdexcept> - #include "util/Log.h" #include "ResourceManager.h" @@ -11,26 +9,23 @@ ResourceManager::~ResourceManager() { dbg_trace(); } ResourceManager::ResourceManager() { dbg_trace(); } void ResourceManager::clear() { + std::erase_if(this->resources, [](const pair<const Asset, CacheEntry> & pair) { + const CacheEntry & entry = pair.second; + return entry.persistent == false; + }); +} + +void ResourceManager::clear_all() { this->resources.clear(); } -// template <typename T> -// T & ResourceManager::cache(const Asset & asset) { -// dbg_trace(); -// static_assert(is_base_of<Resource, T>::value, "cache must recieve a derivative class of Resource"); -// -// if (!this->resources.contains(asset)) -// this->resources[asset] = make_unique<T>(asset); -// -// Resource * resource = this->resources.at(asset).get(); -// T * concrete_resource = dynamic_cast<T *>(resource); -// -// if (concrete_resource == nullptr) -// throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); -// -// return *concrete_resource; -// } -// -// #include "facade/Sound.h" -// template Sound & ResourceManager::cache(const Asset &); +void ResourceManager::set_persistent(const Asset & asset, bool persistent) { + this->get_entry(asset).persistent = persistent; +} + +ResourceManager::CacheEntry & ResourceManager::get_entry(const Asset & asset) { + if (!this->resources.contains(asset)) + this->resources[asset] = {}; + return this->resources.at(asset); +} diff --git a/src/crepe/ResourceManager.h b/src/crepe/ResourceManager.h index 26a86a8..fc50b65 100644 --- a/src/crepe/ResourceManager.h +++ b/src/crepe/ResourceManager.h @@ -5,12 +5,10 @@ #include "api/Asset.h" -#include "Component.h" #include "Resource.h" namespace crepe { - /** * \brief The ResourceManager is responsible for storing and managing assets over * multiple scenes. @@ -26,51 +24,24 @@ public: virtual ~ResourceManager(); // dbg_trace private: - template <typename Resource> - Resource & get_internal(const Component & component, const Asset & asset); - - template <typename Resource> - const Asset & get_source(const Component & component) const; - + struct CacheEntry { + std::unique_ptr<Resource> resource = nullptr; + bool persistent = false; + }; //! A cache that holds all the assets, accessible by their file path, over multiple scenes. - std::unordered_map<const Asset, std::unique_ptr<Resource>> resources; + std::unordered_map<const Asset, CacheEntry> resources; + CacheEntry & get_entry(const Asset & asset); public: - /** - * \brief Caches an asset by loading it from the given file path. - * - * \param file_path The path to the asset file to load. - * \param reload If true, the asset will be reloaded from the file, even if - * it is already cached. - * \tparam T The type of asset to cache (e.g., texture, sound, etc.). - * - * \return A reference to the resource - * - * This template function caches the asset at the given file path. If the - * asset is already cached, the existing instance will be returned. - * Otherwise, the concrete resource will be instantiated and added to the - * cache. - */ - template <typename Resource> - void cache(const Asset & asset, bool persistent = false); - - template <typename Component> - void cache(const Component & component, bool persistent = false); - - // void resman.cache<Resource>(Asset, Lifetime); - // void resman.cache(Component, Asset, Lifetime); + void set_persistent(const Asset & asset, bool persistent); - template <typename Resource, typename Component> - Resource & get(const Component & component); + template <typename Resource> + Resource & get(const Asset & asset); - //! Clear the resource cache void clear(); + void clear_all(); }; -class Sound; -class AudioSource; -template <> -Sound & ResourceManager::get(const AudioSource & component); - } // namespace crepe +#include "ResourceManager.hpp" diff --git a/src/crepe/ResourceManager.hpp b/src/crepe/ResourceManager.hpp new file mode 100644 index 0000000..8270bc5 --- /dev/null +++ b/src/crepe/ResourceManager.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <format> + +#include "ResourceManager.h" + +namespace crepe { + +template <typename T> +T & ResourceManager::get(const Asset & asset) { + using namespace std; + static_assert(is_base_of<Resource, T>::value, "cache must recieve a derivative class of Resource"); + + CacheEntry & entry = this->get_entry(asset); + if (entry.resource == nullptr) + entry.resource = make_unique<T>(asset); + + T * concrete_resource = dynamic_cast<T *>(entry.resource.get()); + if (concrete_resource == nullptr) + throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); + + return *concrete_resource; +} + +} + diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index f57c419..cc3b022 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -6,96 +6,69 @@ #include <crepe/util/Log.h> #include <crepe/ResourceManager.h> #include <crepe/api/GameObject.h> -#include <crepe/Component.h> -#include <crepe/ComponentManager.h> using namespace std; using namespace crepe; using namespace testing; -class TestComponent : public Component { -public: - TestComponent(game_object_id_t id, const Asset & asset) - : Component(id), - source(asset) {} - const Asset source; -}; - -class TestResource : public Resource { -public: - static unsigned instances; - -public: - const unsigned instance; - TestResource(const Asset & src) - : Resource(src), - instance(this->instances++) { } -}; -unsigned TestResource::instances = 0; - -template <> -TestResource & ResourceManager::get(const TestComponent & component) { - return this->get_internal<TestResource>(component, component.source); -} - class ResourceManagerTest : public Test { public: ResourceManager resource_manager{}; - static constexpr const char * ASSET_LOCATION = "asset/texture/img.png"; + Asset asset_a{"asset/texture/img.png"}; + Asset asset_b{"asset/texture/ERROR.png"}; + + class TestResource : public Resource { + public: + static unsigned instances; - TestComponent a{0, ASSET_LOCATION}; - TestComponent b{1, ASSET_LOCATION}; + public: + const unsigned instance; + TestResource(const Asset & src) + : Resource(src), + instance(this->instances++) { } + ~TestResource() { this->instances--; } + bool operator == (const TestResource & other) const { + return this->instance == other.instance; + } + }; private: void SetUp() override { TestResource::instances = 0; } }; +unsigned ResourceManagerTest::TestResource::instances = 0; -TEST_F(ResourceManagerTest, Uncached) { - TestResource & res_1 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_2 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_3 = resource_manager.get<TestResource>(b); // 2 - TestResource & res_4 = resource_manager.get<TestResource>(b); // 2 +TEST_F(ResourceManagerTest, Default) { + TestResource & res_1 = resource_manager.get<TestResource>(asset_a); + TestResource & res_2 = resource_manager.get<TestResource>(asset_a); + TestResource & res_3 = resource_manager.get<TestResource>(asset_b); + TestResource & res_4 = resource_manager.get<TestResource>(asset_b); ASSERT_EQ(res_1, res_2); ASSERT_EQ(res_3, res_4); EXPECT_NE(res_1, res_3); EXPECT_EQ(TestResource::instances, 2); -} - -// TODO: per GameObject / Component -TEST_F(ResourceManagerTest, PerComponent) { - resource_manager.cache(a); - resource_manager.cache(b); - TestResource & res_1 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_2 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_3 = resource_manager.get<TestResource>(b); // 2 - TestResource & res_4 = resource_manager.get<TestResource>(b); // 2 + resource_manager.clear(); +} - ASSERT_EQ(res_1, res_2); - ASSERT_EQ(res_3, res_4); - EXPECT_NE(res_1, res_3); +TEST_F(ResourceManagerTest, Persistent) { + resource_manager.set_persistent(asset_a, true); + EXPECT_EQ(TestResource::instances, 0); + resource_manager.get<TestResource>(asset_a); + resource_manager.get<TestResource>(asset_a); + resource_manager.get<TestResource>(asset_b); + resource_manager.get<TestResource>(asset_b); EXPECT_EQ(TestResource::instances, 2); -} -TEST_F(ResourceManagerTest, PerAsset) { - resource_manager.cache(ASSET_LOCATION); + resource_manager.clear(); EXPECT_EQ(TestResource::instances, 1); - TestResource & res_1 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_2 = resource_manager.get<TestResource>(a); // 1 - TestResource & res_3 = resource_manager.get<TestResource>(b); // 1 - TestResource & res_4 = resource_manager.get<TestResource>(b); // 1 - - EXPECT_EQ(res_1, res_2); - EXPECT_EQ(res_2, res_3); - EXPECT_EQ(res_3, res_4); - - EXPECT_EQ(TestResource::instances, 1); + resource_manager.clear_all(); + EXPECT_EQ(TestResource::instances, 0); } |