#pragma once #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; typedef uint32_t StorageType; template class StorageBackend { public: template static Scope load(StorageType storageId); }; template class Resource { public: int32_t getResourceId() const { return resourceId; } StorageType getStorageId() const { return ResourceManager::getStorageId(*this); } bool isValid() const { return ResourceManager::isValid(*this); } T& getData() { return ResourceManager::getResourceData(*this); } static Resource unsafeFromId(int32_t id) { Resource res; res.resourceId = id; return res; } inline explicit operator bool() const { return resourceId >= 0; } private: 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(Scope _data, StorageType _storageId) : data(_data), storageId(_storageId) {} Scope data; StorageType storageId; }; static std::vector resources; static std::unordered_map> resourceCache; public: template static Resource loadResource(StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; using ResourceBaseType = typename ResourceBuilder::BaseDataType; Scope data; Scope baseData = StorageBackend::template load(storageId); data = ResourceBuilder::buildResource(*baseData.get()); Resource resource = Resource::unsafeFromId(resources.size()); resources.push_back({storageId, std::move(data)}); resourceCache[storageId] = resource; return resource; } static Resource getResource(StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; return Resource(); } static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, StorageType storageId) { if (resourceCache.contains(storageId)) return resourceCache[storageId]; Scope data = ResourceBuilder::buildResource(resourceData); Resource resource = Resource::unsafeFromId(resources.size()); resources.push_back({std::move(data), storageId}); 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 StorageType getStorageId(Resource res) { if (!isValid(res)) return 0; 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 // BUILTIN RESOURCE IDS #define RESOURCE_CUBE_ID 0x1 #define RESOURCE_SPHERE_ID 0x2 #define RESOURCE_BASIC_SHADER_ID 0x3