#pragma once #include "DeerRender/DataManagment.h" #include "DeerRender/Log.h" #include "DeerRender/Tools/Memory.h" #include "DeerRender/Tools/Path.h" #include "DeerRender/Tools/TypeDefs.h" #include #include #include namespace Deer { template class ResourceManager; template class Resource { public: int32_t getResourceId() const { return resourceId; } bool isValid() const { return ResourceManager::isValid(*this); } T& getData() { return ResourceManager::getResourceData(*this); } const std::string& getStorageId() const { return ResourceManager::getStorageId(); } inline explicit operator bool() const { return resourceId >= 0; } static Resource unsafeFromId(int32_t id) { Resource res; res.resourceId = id; return res; } private: // -1 = no resource loaded int32_t resourceId = -1; friend ResourceManager; }; template class ResourceBuilder { public: using BaseDataType = char; static Scope buildResource(const BaseDataType& baseData) { static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T"); return nullptr; } }; template class ResourceManager { private: struct ResourceData { public: ResourceData(const std::string& _resourceId, Scope&& _data) : storageId(_resourceId), data(std::move(_data)) {} Scope data; const std::string storageId; }; static std::vector resources; static std::unordered_map> resourceCache; public: template static Resource loadResource(const std::string& storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; using ResourceBuilderBaseDataType = typename ResourceBuilder::BaseDataType; Scope data; if constexpr (!std::is_void_v) { Scope baseData = DataManager::template load(storageId); if (!baseData) { const char* baseDataType = abi::__cxa_demangle(typeid(ResourceBuilderBaseDataType).name(), 0, 0, nullptr); const char* dataType = abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr); DEER_CORE_ERROR("Error loading base resource {} for resource {} with id {}", baseDataType, dataType, storageId.c_str()); return Resource(); } data = ResourceBuilder::buildResource(*baseData.get()); } else { data = ResourceBuilder::buildResource(); // No base data } Resource resource = Resource::unsafeFromId(resources.size()); resources.push_back({storageId, std::move(data)}); resourceCache[storageId] = resource; return resource; } static void unloadResources() { resourceCache.clear(); resources.clear(); } static inline bool isValid(Resource res) { return res.resourceId >= 0 && res.resourceId < static_cast(resources.size()); } static inline const std::string& getStorageId(Resource res) { const static std::string invalid("NULL"); if (!isValid(res)) return invalid; return resources[res.resourceId].storageId; } static T& getResourceData(Resource res) { return *resources[res.resourceId].data; } }; template std::vector::ResourceData> ResourceManager::resources; template std::unordered_map> ResourceManager::resourceCache; } // namespace Deer