2026-03-08 22:25:55 +01:00

148 lines
3.8 KiB
C++

#pragma once
#include "DeerRender/Log.h"
#include "DeerRender/Tools/Memory.h"
#include "DeerRender/Tools/Path.h"
#include "DeerRender/Tools/TypeDefs.h"
#include <cxxabi.h>
#include <unordered_map>
#include <vector>
namespace Deer {
template <typename T>
class ResourceManager;
typedef uint32_t StorageType;
StorageType generatePhyisicalStorageId();
StorageType generateRuntimeStorageId();
template <typename DataSource>
class StorageBackend {
public:
template <typename T>
static Scope<T> load(StorageType storageId);
};
template <typename T>
class Resource {
public:
int32_t getResourceId() const { return resourceId; }
StorageType getStorageId() const { return ResourceManager<T>::getStorageId(*this); }
bool isValid() const { return ResourceManager<T>::isValid(*this); }
T& getData() { return ResourceManager<T>::getResourceData(*this); }
static Resource<T> unsafeFromId(int32_t id) {
Resource<T> res;
res.resourceId = id;
return res;
}
inline explicit operator bool() const { return resourceId >= 0; }
private:
int32_t resourceId = -1;
friend ResourceManager<T>;
};
template <typename T>
class ResourceBuilder {
public:
using BaseDataType = char;
static Scope<T> buildResource(const BaseDataType& baseData) {
static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T");
return nullptr;
}
};
template <typename T>
class ResourceManager {
private:
struct ResourceData {
public:
Scope<T> data = nullptr;
StorageType storageId = 0;
};
static std::vector<ResourceData> resources;
static std::unordered_map<StorageType, Resource<T>> resourceCache;
public:
template <typename DataSource>
static Resource<T> loadResource(StorageType storageId) {
if (resourceCache.contains(storageId))
return resourceCache[storageId];
using ResourceBaseType = typename ResourceBuilder<T>::BaseDataType;
Scope<T> data;
Scope<ResourceBaseType> baseData = StorageBackend<DataSource>::template load<ResourceBaseType>(storageId);
data = ResourceBuilder<T>::buildResource(*baseData.get());
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
resources.push_back();
ResourceData& rd = resources.back();
rd.data = std::move(data);
rd.storageId = storageId;
resourceCache[storageId] = resource;
return resource;
}
static Resource<T> getResource(StorageType storageId) {
if (resourceCache.contains(storageId))
return resourceCache[storageId];
return Resource<T>();
}
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, StorageType storageId) {
if (resourceCache.contains(storageId))
return resourceCache[storageId];
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());
resources.push_back({});
ResourceData& rd = resources.back();
rd.data = std::move(data);
rd.storageId = storageId;
return resource;
}
static void unloadResources() {
resourceCache.clear();
resources.clear();
}
static inline bool isValid(Resource<T> res) {
return res.resourceId >= 0 && res.resourceId < static_cast<int32_t>(resources.size());
}
static inline StorageType getStorageId(Resource<T> res) {
if (!isValid(res))
return 0;
return resources[res.resourceId].storageId;
}
static T& getResourceData(Resource<T> res) {
return *resources[res.resourceId].data;
}
};
template <typename T>
std::vector<typename ResourceManager<T>::ResourceData> ResourceManager<T>::resources;
template <typename T>
std::unordered_map<StorageType, Resource<T>> ResourceManager<T>::resourceCache;
} // namespace Deer
// BUILTIN RESOURCE IDS
#define RESOURCE_CUBE_ID 0x1
#define RESOURCE_SPHERE_ID 0x2
#define RESOURCE_BASIC_SHADER_ID 0x3