From 098dd61a75d8aac928e3e084ee0fbc8fdf304910 Mon Sep 17 00:00:00 2001 From: Natalie Martin Date: Mon, 5 Feb 2024 17:45:09 -0700 Subject: [PATCH] Add ResourceLibrary class and refactor TextureManager We want to reuse the TextureManager logic in a few other places in our engine for handling assets. Create a ResourceLibrary template class and then refactor TextureManager to use it instead of code customized just for textures. --- src/graphics/Texture2D.cpp | 21 ++----- src/graphics/Texture2D.h | 19 +++--- src/graphics/TextureLoader.h | 3 +- src/graphics/TextureManager-impl.h | 49 +++------------- src/graphics/TextureManager.h | 19 +----- src/resource/Asset.h | 34 +++++++++++ src/resource/AssetLoader.h | 15 +++++ src/resource/InternalAssetWithSecret.h | 13 +++++ src/resource/ResourceLibrary.h | 81 ++++++++++++++++++++++++++ 9 files changed, 167 insertions(+), 87 deletions(-) create mode 100644 src/resource/Asset.h create mode 100644 src/resource/AssetLoader.h create mode 100644 src/resource/InternalAssetWithSecret.h create mode 100644 src/resource/ResourceLibrary.h diff --git a/src/graphics/Texture2D.cpp b/src/graphics/Texture2D.cpp index 992fdfe..7b96adf 100644 --- a/src/graphics/Texture2D.cpp +++ b/src/graphics/Texture2D.cpp @@ -3,25 +3,14 @@ Adagio::Texture2D::Texture2D(Adagio::TextureHandle handle, Adagio::TextureHandle secret, unsigned int width, - unsigned int height) { - this->handle = handle; - this->secret = secret; - this->width = width; - this->height = height; -} + unsigned int height) : Asset( + handle, secret, + {width, height}) {} unsigned int Adagio::Texture2D::getHeight() { - return height; + return metadata.height; } unsigned int Adagio::Texture2D::getWidth() { - return width; -} - -Adagio::TextureHandle Adagio::Texture2D::getSecretId() { - return secret; -} - -bool Adagio::Texture2D::isValid() { - return handle != 0; + return metadata.width; } diff --git a/src/graphics/Texture2D.h b/src/graphics/Texture2D.h index c5d421b..c802dc1 100644 --- a/src/graphics/Texture2D.h +++ b/src/graphics/Texture2D.h @@ -1,26 +1,21 @@ #ifndef GL_ADAGIO_TEXTURE2D_H #define GL_ADAGIO_TEXTURE2D_H + +#include "../resource/Asset.h" +#include "TextureDimensions.h" + namespace Adagio { typedef unsigned int TextureHandle; - class Texture2D { + class Texture2D : public Asset { public: + explicit Texture2D(Asset asset); + explicit Texture2D(TextureHandle handle, TextureHandle secret, unsigned int width, unsigned int height); - TextureHandle handle; - unsigned int getWidth(); unsigned int getHeight(); - - TextureHandle getSecretId(); - - bool isValid(); - - private: - TextureHandle secret; - unsigned int width; - unsigned int height; }; } #endif //GL_ADAGIO_TEXTURE2D_H diff --git a/src/graphics/TextureLoader.h b/src/graphics/TextureLoader.h index 8b85528..f43f65b 100644 --- a/src/graphics/TextureLoader.h +++ b/src/graphics/TextureLoader.h @@ -1,11 +1,12 @@ #ifndef GL_ADAGIO_TEXTURELOADER_H #define GL_ADAGIO_TEXTURELOADER_H +#include "../resource/ResourceLibrary.h" #include "TextureDimensions.h" namespace Adagio { template - struct TextureLoader { + struct TextureLoader : public AssetLoader { virtual std::pair load(const char *resource) = 0; virtual void unload(T texture) = 0; diff --git a/src/graphics/TextureManager-impl.h b/src/graphics/TextureManager-impl.h index 4da2ad1..bc649b1 100644 --- a/src/graphics/TextureManager-impl.h +++ b/src/graphics/TextureManager-impl.h @@ -2,60 +2,25 @@ #define GL_ADAGIO_TEXTUREMANAGER_IMPL_H namespace Adagio { template - TextureManager::TextureManager(TextureLoader *loader) { - textureLoader = loader; - textureLibrary.reserve(64); - nextSecret = 1; + TextureManager::TextureManager(TextureLoader *loader) : library(loader) { } template Texture2D TextureManager::load(std::string resource) { - if (loadedFilenames.find(resource) != loadedFilenames.end()) { - TextureHandle handle = loadedFilenames[resource] - 1; - auto internalTexture = textureLibrary[handle]; - return Texture2D(handle + 1, - internalTexture.secret, - internalTexture.dimensions.width, - internalTexture.dimensions.height); - } - auto internalTexture = textureLoader->load(resource.c_str()); - auto dimensions = internalTexture.second; - TextureHandle secret = nextSecret++; - TextureHandle id; - if (!freeHandles.empty()) { - id = freeHandles.back(); - freeHandles.pop_back(); - textureLibrary[id - 1] = {secret, dimensions, internalTexture.first}; - } else { - id = textureLibrary.size() + 1; - textureLibrary.push_back({secret, dimensions, internalTexture.first}); - } - loadedFilenames[resource] = id; - Texture2D handle(id, secret, dimensions.width, dimensions.height); - return handle; + auto asset = library.load(resource); + TextureDimensions metadata = asset.getMetadata(); + return Texture2D(asset.handle, asset.getSecretId(), metadata.width, metadata.height); + // TODO: Probably use pointers instead for polymorphism } template void TextureManager::unload(Adagio::Texture2D texture) { - auto internalTexture = textureLibrary[texture.handle - 1]; - internalTexture.secret = 0; - textureLoader->unload(internalTexture.texture); - freeHandles.push_back(texture.handle); - for (auto it = loadedFilenames.begin(); it != loadedFilenames.end(); it++) { - if (it->second == texture.handle) { - loadedFilenames.erase(it); - break; - } - } + library.unload(texture); } template T TextureManager::useTexture(Adagio::Texture2D texture) { - auto internalTexture = textureLibrary[texture.handle - 1]; - if (texture.getSecretId() != internalTexture.secret) { - throw std::invalid_argument("Unloaded texture used."); - } - return internalTexture.texture; + return library.useResource(texture); } } #endif //GL_ADAGIO_TEXTUREMANAGER_IMPL_H diff --git a/src/graphics/TextureManager.h b/src/graphics/TextureManager.h index 07f9ba6..084a408 100644 --- a/src/graphics/TextureManager.h +++ b/src/graphics/TextureManager.h @@ -2,19 +2,11 @@ #define GL_ADAGIO_TEXTUREMANAGER_H #include -#include -#include -#include "TextureLoader.h" #include "Texture2D.h" +#include "TextureLoader.h" +#include "../resource/ResourceLibrary.h" namespace Adagio { - template - struct TextureWithSecret { - TextureHandle secret; - TextureDimensions dimensions; - T texture; - }; - template class TextureManager { public: @@ -27,12 +19,7 @@ namespace Adagio { T useTexture(Texture2D texture); private: - TextureLoader *textureLoader; - std::vector> textureLibrary; - std::vector freeHandles; - std::unordered_map loadedFilenames; - - TextureHandle nextSecret; + ResourceLibrary library; }; } diff --git a/src/resource/Asset.h b/src/resource/Asset.h new file mode 100644 index 0000000..487f714 --- /dev/null +++ b/src/resource/Asset.h @@ -0,0 +1,34 @@ +#ifndef GL_ADAGIO_ASSET_H +#define GL_ADAGIO_ASSET_H + +namespace Adagio { + template + class Asset { + public: + explicit Asset(HandleType handle, HandleType secret, const MetadataType &metadata) { + this->handle = handle; + this->secret = secret; + this->metadata = metadata; + } + + HandleType handle; + + HandleType getSecretId() const { + return secret; + } + + [[nodiscard]] bool isValid() const { + return secret != 0; + } + + MetadataType getMetadata() const { + return metadata; + } + + protected: + HandleType secret; + MetadataType metadata; + }; +} + +#endif //GL_ADAGIO_ASSET_H diff --git a/src/resource/AssetLoader.h b/src/resource/AssetLoader.h new file mode 100644 index 0000000..4f24cc5 --- /dev/null +++ b/src/resource/AssetLoader.h @@ -0,0 +1,15 @@ +#ifndef GL_ADAGIO_ASSETLOADER_H +#define GL_ADAGIO_ASSETLOADER_H + +#include + +namespace Adagio { + template + struct AssetLoader { + virtual std::pair load(const char *resource) = 0; + + virtual void unload(InternalAssetType asset) = 0; + }; +} + +#endif //GL_ADAGIO_ASSETLOADER_H diff --git a/src/resource/InternalAssetWithSecret.h b/src/resource/InternalAssetWithSecret.h new file mode 100644 index 0000000..39cec7f --- /dev/null +++ b/src/resource/InternalAssetWithSecret.h @@ -0,0 +1,13 @@ +#ifndef GL_ADAGIO_INTERNALASSETWITHSECRET_H +#define GL_ADAGIO_INTERNALASSETWITHSECRET_H + +namespace Adagio { + template + struct InternalAssetWithSecret { + HandleType secret; + MetadataType metadata; + InternalAssetType asset; + }; +} + +#endif //GL_ADAGIO_INTERNALASSETWITHSECRET_H diff --git a/src/resource/ResourceLibrary.h b/src/resource/ResourceLibrary.h new file mode 100644 index 0000000..c549a11 --- /dev/null +++ b/src/resource/ResourceLibrary.h @@ -0,0 +1,81 @@ +#ifndef GL_ADAGIO_RESOURCELIBRARY_H +#define GL_ADAGIO_RESOURCELIBRARY_H + +#include +#include +#include +#include +#include "Asset.h" +#include "AssetLoader.h" +#include "InternalAssetWithSecret.h" + +namespace Adagio { + template + class ResourceLibrary { + typedef Asset ResourceType; + typedef InternalAssetWithSecret ResourceWithSecret; + typedef AssetLoader LoaderType; + + public: + explicit ResourceLibrary(AssetLoader *loader) { + this->loader = loader; + library.reserve(64); + nextSecret = 1; + } + + ResourceType load(std::string resource) { + if (loadedFilenames.find(resource) != loadedFilenames.end()) { + HandleType handle = loadedFilenames[resource] - 1; + ResourceWithSecret internalAsset = library[handle]; + return Asset(handle + 1, + internalAsset.secret, + internalAsset.metadata); + } + auto internalTexture = loader->load(resource.c_str()); + auto dimensions = internalTexture.second; + HandleType secret = nextSecret++; + HandleType id; + if (!freeHandles.empty()) { + id = freeHandles.back(); + freeHandles.pop_back(); + library[id - 1] = {secret, dimensions, internalTexture.first}; + } else { + id = library.size() + 1; + library.push_back({secret, dimensions, internalTexture.first}); + } + loadedFilenames[resource] = id; + Asset handle(id, secret, dimensions); + return handle; + } + + void unload(const ResourceType &asset) { + ResourceWithSecret internalTexture = library[asset.handle - 1]; + internalTexture.secret = 0; + loader->unload(internalTexture.asset); + freeHandles.push_back(asset.handle); + for (auto it = loadedFilenames.begin(); it != loadedFilenames.end(); it++) { + if (it->second == asset.handle) { + loadedFilenames.erase(it); + break; + } + } + } + + InternalAssetType useResource(const ResourceType &asset) { + ResourceWithSecret internalTexture = library[asset.handle - 1]; + if (asset.getSecretId() != internalTexture.secret) { + throw std::invalid_argument("Unloaded texture used."); + } + return internalTexture.asset; + } + + private: + AssetLoader *loader; + std::vector library; + std::vector freeHandles; + std::unordered_map loadedFilenames; + + HandleType nextSecret; + }; +} +#endif //GL_ADAGIO_RESOURCELIBRARY_H