refactor: reorganize Resources module into Core/Asset, Core/IO and Resources subdirectories
- Split core resource architecture into Core/Asset/ (IResource, ResourceManager, ResourceCache, etc.)
- Moved IO layer into Core/IO/ (IResourceLoader, ResourceFileSystem, etc.)
- Reorganized concrete resource types into Resources/{Texture,Mesh,Material,Shader,AudioClip}/
- Updated all include paths from relative to <XCEngine/...> format
- Fixed circular dependency in Material.h (removed unnecessary ResourceManager.h include)
- Fixed malformed include syntax in ResourceManager.h and AsyncLoader.h
- Fixed glad.h path issues in CMakeLists.txt
This commit is contained in:
94
engine/include/XCEngine/Core/Asset/AsyncLoader.h
Normal file
94
engine/include/XCEngine/Core/Asset/AsyncLoader.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "IResourceLoader.h"
|
||||
#include "ImportSettings.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Threading/Mutex.h"
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
struct LoadRequest {
|
||||
Containers::String path;
|
||||
ResourceType type;
|
||||
std::function<void(LoadResult)> callback;
|
||||
ImportSettings* settings;
|
||||
Core::uint64 requestId;
|
||||
|
||||
LoadRequest() : requestId(0), settings(nullptr) {}
|
||||
|
||||
LoadRequest(const Containers::String& p, ResourceType t,
|
||||
std::function<void(LoadResult)> cb, ImportSettings* s = nullptr)
|
||||
: path(p), type(t), callback(std::move(cb)),
|
||||
settings(s), requestId(GenerateRequestId()) {}
|
||||
|
||||
LoadRequest(LoadRequest&& other) noexcept
|
||||
: path(std::move(other.path)), type(other.type),
|
||||
callback(std::move(other.callback)), settings(other.settings),
|
||||
requestId(other.requestId) {
|
||||
other.settings = nullptr;
|
||||
}
|
||||
|
||||
LoadRequest& operator=(LoadRequest&& other) noexcept {
|
||||
if (this != &other) {
|
||||
path = std::move(other.path);
|
||||
type = other.type;
|
||||
callback = std::move(other.callback);
|
||||
settings = other.settings;
|
||||
requestId = other.requestId;
|
||||
other.settings = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
LoadRequest(const LoadRequest&) = default;
|
||||
LoadRequest& operator=(const LoadRequest&) = default;
|
||||
|
||||
private:
|
||||
static Core::uint64 GenerateRequestId();
|
||||
};
|
||||
|
||||
class AsyncLoader {
|
||||
public:
|
||||
static AsyncLoader& Get();
|
||||
|
||||
void Initialize(Core::uint32 workerThreadCount = 2);
|
||||
void Shutdown();
|
||||
|
||||
void Submit(const Containers::String& path, ResourceType type,
|
||||
std::function<void(LoadResult)> callback);
|
||||
void Submit(const Containers::String& path, ResourceType type, ImportSettings* settings,
|
||||
std::function<void(LoadResult)> callback);
|
||||
|
||||
void Update();
|
||||
bool IsLoading() const { return m_pendingCount > 0; }
|
||||
Core::uint32 GetPendingCount() const { return m_pendingCount; }
|
||||
float GetProgress() const;
|
||||
void CancelAll();
|
||||
void Cancel(Core::uint64 requestId);
|
||||
|
||||
~AsyncLoader() = default;
|
||||
|
||||
AsyncLoader() = default;
|
||||
|
||||
private:
|
||||
void SubmitInternal(LoadRequest request);
|
||||
IResourceLoader* FindLoader(ResourceType type) const;
|
||||
|
||||
void QueueCompleted(LoadRequest request, LoadResult result);
|
||||
|
||||
Threading::Mutex m_queueMutex;
|
||||
Containers::Array<LoadRequest> m_pendingQueue;
|
||||
|
||||
Threading::Mutex m_completedMutex;
|
||||
Containers::Array<LoadRequest> m_completedQueue;
|
||||
|
||||
std::atomic<Core::uint32> m_pendingCount{0};
|
||||
std::atomic<Core::uint32> m_completedCount{0};
|
||||
Core::uint32 m_totalRequested = 0;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
46
engine/include/XCEngine/Core/Asset/IResource.h
Normal file
46
engine/include/XCEngine/Core/Asset/IResource.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/String.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class IResource {
|
||||
public:
|
||||
virtual ~IResource() = default;
|
||||
|
||||
virtual ResourceType GetType() const = 0;
|
||||
virtual const Containers::String& GetName() const = 0;
|
||||
virtual const Containers::String& GetPath() const = 0;
|
||||
virtual ResourceGUID GetGUID() const = 0;
|
||||
virtual bool IsValid() const = 0;
|
||||
virtual size_t GetMemorySize() const = 0;
|
||||
virtual void Release() = 0;
|
||||
|
||||
struct ConstructParams {
|
||||
Containers::String name;
|
||||
Containers::String path;
|
||||
ResourceGUID guid;
|
||||
size_t memorySize = 0;
|
||||
};
|
||||
|
||||
void Initialize(const ConstructParams& params) {
|
||||
m_name = params.name;
|
||||
m_path = params.path;
|
||||
m_guid = params.guid;
|
||||
m_memorySize = params.memorySize;
|
||||
m_isValid = true;
|
||||
}
|
||||
|
||||
void SetInvalid() { m_isValid = false; }
|
||||
|
||||
Containers::String m_name;
|
||||
Containers::String m_path;
|
||||
ResourceGUID m_guid;
|
||||
bool m_isValid = false;
|
||||
size_t m_memorySize = 0;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
19
engine/include/XCEngine/Core/Asset/ImportSettings.h
Normal file
19
engine/include/XCEngine/Core/Asset/ImportSettings.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Core/SmartPtr.h"
|
||||
#include "ResourceTypes.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class ImportSettings {
|
||||
public:
|
||||
virtual ~ImportSettings() = default;
|
||||
|
||||
virtual Core::UniqueRef<ImportSettings> Clone() const = 0;
|
||||
virtual bool LoadFromJSON(const Containers::String& json) { return false; }
|
||||
virtual Containers::String SaveToJSON() const { return Containers::String(); }
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
64
engine/include/XCEngine/Core/Asset/ResourceCache.h
Normal file
64
engine/include/XCEngine/Core/Asset/ResourceCache.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/HashMap.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Threading/Mutex.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class IResource;
|
||||
|
||||
struct CacheEntry {
|
||||
IResource* resource;
|
||||
ResourceGUID guid;
|
||||
size_t memorySize;
|
||||
Core::uint64 lastAccessTime;
|
||||
Core::uint32 accessCount;
|
||||
|
||||
CacheEntry() : resource(nullptr), memorySize(0), lastAccessTime(0), accessCount(0) {}
|
||||
CacheEntry(IResource* res, size_t size);
|
||||
|
||||
static Core::uint64 GetCurrentTick();
|
||||
};
|
||||
|
||||
class ResourceCache {
|
||||
public:
|
||||
ResourceCache();
|
||||
~ResourceCache();
|
||||
|
||||
void Add(ResourceGUID guid, IResource* resource);
|
||||
void Remove(ResourceGUID guid);
|
||||
IResource* Find(ResourceGUID guid) const;
|
||||
void Touch(ResourceGUID guid);
|
||||
|
||||
size_t GetSize() const { return m_cache.Size(); }
|
||||
size_t GetMemoryUsage() const { return m_memoryUsage; }
|
||||
|
||||
void SetMemoryBudget(size_t bytes);
|
||||
size_t GetMemoryBudget() const { return m_memoryBudget; }
|
||||
|
||||
void OnMemoryPressure(size_t requiredBytes);
|
||||
void OnZeroRefCount(ResourceGUID guid);
|
||||
void Flush();
|
||||
void Clear();
|
||||
|
||||
Containers::Array<ResourceGUID> GetLRUList(size_t count) const;
|
||||
|
||||
private:
|
||||
void Evict(size_t requiredBytes);
|
||||
void UpdateMemoryStats();
|
||||
|
||||
Containers::HashMap<ResourceGUID, CacheEntry> m_cache;
|
||||
Containers::Array<ResourceGUID> m_lruOrder;
|
||||
size_t m_memoryUsage = 0;
|
||||
size_t m_memoryBudget = 512 * 1024 * 1024;
|
||||
|
||||
Threading::Mutex m_mutex;
|
||||
mutable Threading::Mutex m_cacheMutex;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
56
engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h
Normal file
56
engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/HashMap.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Core/Types.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
struct DependencyNode {
|
||||
ResourceGUID guid;
|
||||
ResourceType type;
|
||||
Containers::Array<ResourceGUID> dependencies;
|
||||
Containers::Array<ResourceGUID> dependents;
|
||||
Core::uint32 refCount = 0;
|
||||
};
|
||||
|
||||
class ResourceDependencyGraph {
|
||||
public:
|
||||
ResourceDependencyGraph();
|
||||
~ResourceDependencyGraph();
|
||||
|
||||
void AddNode(ResourceGUID guid, ResourceType type);
|
||||
void RemoveNode(ResourceGUID guid);
|
||||
|
||||
void AddDependency(ResourceGUID owner, ResourceGUID dependency);
|
||||
void RemoveDependency(ResourceGUID owner, ResourceGUID dependency);
|
||||
|
||||
Containers::Array<ResourceGUID> GetDependencies(ResourceGUID guid) const;
|
||||
Containers::Array<ResourceGUID> GetDependents(ResourceGUID guid) const;
|
||||
Containers::Array<ResourceGUID> GetAllDependencies(ResourceGUID guid) const;
|
||||
|
||||
void IncrementRefCount(ResourceGUID guid);
|
||||
void DecrementRefCount(ResourceGUID guid);
|
||||
Core::uint32 GetRefCount(ResourceGUID guid) const;
|
||||
|
||||
bool HasCircularDependency(ResourceGUID guid, Containers::Array<ResourceGUID>& outCycle) const;
|
||||
|
||||
Containers::Array<ResourceGUID> TopologicalSort() const;
|
||||
|
||||
bool Unload(ResourceGUID guid);
|
||||
|
||||
void Clear();
|
||||
|
||||
bool HasNode(ResourceGUID guid) const;
|
||||
|
||||
private:
|
||||
bool HasCircularDependencyInternal(ResourceGUID guid, Containers::HashMap<ResourceGUID, bool>& visited,
|
||||
Containers::Array<ResourceGUID>& path, Containers::Array<ResourceGUID>& outCycle) const;
|
||||
|
||||
Containers::HashMap<ResourceGUID, DependencyNode> m_nodes;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
104
engine/include/XCEngine/Core/Asset/ResourceHandle.h
Normal file
104
engine/include/XCEngine/Core/Asset/ResourceHandle.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "IResource.h"
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
// Forward declaration
|
||||
class ResourceManager;
|
||||
|
||||
template<typename T>
|
||||
class ResourceHandle {
|
||||
static_assert(std::is_base_of_v<IResource, T>, "T must derive from IResource");
|
||||
|
||||
public:
|
||||
ResourceHandle() = default;
|
||||
|
||||
explicit ResourceHandle(T* resource)
|
||||
: m_resource(resource) {
|
||||
if (m_resource) {
|
||||
ResourceManager::Get().AddRef(m_resource->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
ResourceHandle(const ResourceHandle& other)
|
||||
: m_resource(other.m_resource) {
|
||||
if (m_resource) {
|
||||
ResourceManager::Get().AddRef(m_resource->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
ResourceHandle(ResourceHandle&& other) noexcept
|
||||
: m_resource(other.m_resource) {
|
||||
other.m_resource = nullptr;
|
||||
}
|
||||
|
||||
~ResourceHandle() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
ResourceHandle& operator=(const ResourceHandle& other) {
|
||||
if (this != &other) {
|
||||
Reset();
|
||||
m_resource = other.m_resource;
|
||||
if (m_resource) {
|
||||
ResourceManager::Get().AddRef(m_resource->GetGUID());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceHandle& operator=(ResourceHandle&& other) noexcept {
|
||||
if (this != &other) {
|
||||
Reset();
|
||||
m_resource = other.m_resource;
|
||||
other.m_resource = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* Get() const { return m_resource; }
|
||||
T* operator->() const { return m_resource; }
|
||||
T& operator*() const { return *m_resource; }
|
||||
|
||||
bool IsValid() const { return m_resource != nullptr && m_resource->IsValid(); }
|
||||
explicit operator bool() const { return IsValid(); }
|
||||
|
||||
ResourceGUID GetGUID() const {
|
||||
return m_resource ? m_resource->GetGUID() : ResourceGUID(0);
|
||||
}
|
||||
|
||||
ResourceType GetResourceType() const {
|
||||
return m_resource ? m_resource->GetType() : ResourceType::Unknown;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (m_resource) {
|
||||
ResourceManager::Get().Release(m_resource->GetGUID());
|
||||
m_resource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Swap(ResourceHandle& other) {
|
||||
std::swap(m_resource, other.m_resource);
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_resource = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const ResourceHandle<T>& lhs, const ResourceHandle<T>& rhs) {
|
||||
return lhs.GetGUID() == rhs.GetGUID();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator!=(const ResourceHandle<T>& lhs, const ResourceHandle<T>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
132
engine/include/XCEngine/Core/Asset/ResourceManager.h
Normal file
132
engine/include/XCEngine/Core/Asset/ResourceManager.h
Normal file
@@ -0,0 +1,132 @@
|
||||
#pragma once
|
||||
|
||||
#include "IResourceLoader.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "AsyncLoader.h"
|
||||
#include "ResourceHandle.h"
|
||||
#include "ImportSettings.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Containers/HashMap.h"
|
||||
#include "../Threading/Mutex.h"
|
||||
#include "../Debug/Logger.h"
|
||||
#include <type_traits>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class ResourceManager {
|
||||
public:
|
||||
static ResourceManager& Get();
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void SetResourceRoot(const Containers::String& rootPath);
|
||||
const Containers::String& GetResourceRoot() const;
|
||||
|
||||
template<typename T>
|
||||
ResourceHandle<T> Load(const Containers::String& path, ImportSettings* settings = nullptr) {
|
||||
static_assert(std::is_base_of_v<IResource, T>, "T must derive from IResource");
|
||||
|
||||
ResourceGUID guid = ResourceGUID::Generate(path);
|
||||
|
||||
IResource* cached = FindInCache(guid);
|
||||
if (cached) {
|
||||
return ResourceHandle<T>(static_cast<T*>(cached));
|
||||
}
|
||||
|
||||
IResourceLoader* loader = FindLoader(GetResourceType<T>());
|
||||
if (!loader) {
|
||||
Debug::Logger::Get().Warning(Debug::LogCategory::FileSystem,
|
||||
Containers::String("No loader found for resource type: ") +
|
||||
GetResourceTypeName(GetResourceType<T>()));
|
||||
return ResourceHandle<T>();
|
||||
}
|
||||
|
||||
LoadResult result = loader->Load(path, settings);
|
||||
if (!result) {
|
||||
Debug::Logger::Get().Error(Debug::LogCategory::FileSystem,
|
||||
Containers::String("Failed to load resource: ") + path + " - " + result.errorMessage);
|
||||
return ResourceHandle<T>();
|
||||
}
|
||||
|
||||
AddToCache(guid, result.resource);
|
||||
|
||||
return ResourceHandle<T>(static_cast<T*>(result.resource));
|
||||
}
|
||||
|
||||
void LoadAsync(const Containers::String& path, ResourceType type,
|
||||
std::function<void(LoadResult)> callback);
|
||||
void LoadAsync(const Containers::String& path, ResourceType type, ImportSettings* settings,
|
||||
std::function<void(LoadResult)> callback);
|
||||
|
||||
void Unload(const Containers::String& path);
|
||||
void Unload(ResourceGUID guid);
|
||||
void UnloadUnused();
|
||||
void UnloadAll();
|
||||
|
||||
void AddRef(ResourceGUID guid);
|
||||
void Release(ResourceGUID guid);
|
||||
Core::uint32 GetRefCount(ResourceGUID guid) const;
|
||||
|
||||
void RegisterLoader(IResourceLoader* loader);
|
||||
void UnregisterLoader(ResourceType type);
|
||||
IResourceLoader* GetLoader(ResourceType type) const;
|
||||
|
||||
void SetMemoryBudget(size_t bytes);
|
||||
size_t GetMemoryUsage() const;
|
||||
size_t GetMemoryBudget() const;
|
||||
void FlushCache();
|
||||
|
||||
IResource* Find(const Containers::String& path);
|
||||
IResource* Find(ResourceGUID guid);
|
||||
bool Exists(const Containers::String& path) const;
|
||||
bool Exists(ResourceGUID guid) const;
|
||||
|
||||
Containers::String ResolvePath(const Containers::String& relativePath) const;
|
||||
|
||||
template<typename T>
|
||||
void LoadGroup(const Containers::Array<Containers::String>& paths,
|
||||
std::function<void(ResourceHandle<T>)> callback) {
|
||||
for (const auto& path : paths) {
|
||||
LoadAsync(path, GetResourceType<T>(), [callback](LoadResult result) {
|
||||
if (result && result.resource) {
|
||||
callback(ResourceHandle<T>(static_cast<T*>(result.resource)));
|
||||
} else {
|
||||
callback(ResourceHandle<T>());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Containers::Array<Containers::String> GetResourcePaths() const;
|
||||
void UnloadGroup(const Containers::Array<ResourceGUID>& guids);
|
||||
|
||||
private:
|
||||
ResourceManager() = default;
|
||||
~ResourceManager() = default;
|
||||
|
||||
IResource* FindInCache(ResourceGUID guid);
|
||||
void AddToCache(ResourceGUID guid, IResource* resource);
|
||||
IResourceLoader* FindLoader(ResourceType type);
|
||||
void ReloadResource(ResourceGUID guid);
|
||||
|
||||
Containers::String m_resourceRoot;
|
||||
Containers::HashMap<ResourceGUID, IResource*> m_resourceCache;
|
||||
Containers::HashMap<ResourceGUID, Core::uint32> m_refCounts;
|
||||
Containers::HashMap<ResourceGUID, Containers::String> m_guidToPath;
|
||||
Containers::HashMap<ResourceType, IResourceLoader*> m_loaders;
|
||||
|
||||
size_t m_memoryUsage = 0;
|
||||
size_t m_memoryBudget = 512 * 1024 * 1024;
|
||||
|
||||
ResourceCache m_cache;
|
||||
Core::UniqueRef<AsyncLoader> m_asyncLoader;
|
||||
Threading::Mutex m_mutex;
|
||||
|
||||
friend class ResourceHandleBase;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
94
engine/include/XCEngine/Core/Asset/ResourceTypes.h
Normal file
94
engine/include/XCEngine/Core/Asset/ResourceTypes.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Core/Types.h"
|
||||
#include "../Core/SmartPtr.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
enum class ResourceType : Core::uint8 {
|
||||
Unknown = 0,
|
||||
Texture,
|
||||
Mesh,
|
||||
Material,
|
||||
Shader,
|
||||
AudioClip,
|
||||
Binary,
|
||||
AnimationClip,
|
||||
Skeleton,
|
||||
Font,
|
||||
ParticleSystem,
|
||||
Scene,
|
||||
Prefab
|
||||
};
|
||||
|
||||
constexpr const char* GetResourceTypeName(ResourceType type) {
|
||||
switch (type) {
|
||||
case ResourceType::Texture: return "Texture";
|
||||
case ResourceType::Mesh: return "Mesh";
|
||||
case ResourceType::Material: return "Material";
|
||||
case ResourceType::Shader: return "Shader";
|
||||
case ResourceType::AudioClip: return "AudioClip";
|
||||
case ResourceType::Binary: return "Binary";
|
||||
case ResourceType::AnimationClip: return "AnimationClip";
|
||||
case ResourceType::Skeleton: return "Skeleton";
|
||||
case ResourceType::Font: return "Font";
|
||||
case ResourceType::ParticleSystem: return "ParticleSystem";
|
||||
case ResourceType::Scene: return "Scene";
|
||||
case ResourceType::Prefab: return "Prefab";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct ResourceGUID {
|
||||
Core::uint64 value;
|
||||
|
||||
ResourceGUID() : value(0) {}
|
||||
explicit ResourceGUID(Core::uint64 v) : value(v) {}
|
||||
|
||||
bool IsValid() const { return value != 0; }
|
||||
|
||||
bool operator==(const ResourceGUID& other) const { return value == other.value; }
|
||||
bool operator!=(const ResourceGUID& other) const { return value != other.value; }
|
||||
|
||||
static ResourceGUID Generate(const char* path);
|
||||
static ResourceGUID Generate(const Containers::String& path);
|
||||
|
||||
Containers::String ToString() const;
|
||||
};
|
||||
|
||||
inline ResourceGUID MakeResourceGUID(const char* path) {
|
||||
return ResourceGUID::Generate(path);
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
|
||||
} // namespace XCEngine
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<XCEngine::Resources::ResourceGUID> {
|
||||
size_t operator()(const XCEngine::Resources::ResourceGUID& guid) const noexcept {
|
||||
return static_cast<size_t>(guid.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
template<typename T>
|
||||
ResourceType GetResourceType();
|
||||
|
||||
template<> inline ResourceType GetResourceType<class Texture>() { return ResourceType::Texture; }
|
||||
template<> inline ResourceType GetResourceType<class Mesh>() { return ResourceType::Mesh; }
|
||||
template<> inline ResourceType GetResourceType<class Material>() { return ResourceType::Material; }
|
||||
template<> inline ResourceType GetResourceType<class Shader>() { return ResourceType::Shader; }
|
||||
template<> inline ResourceType GetResourceType<class AudioClip>() { return ResourceType::AudioClip; }
|
||||
template<> inline ResourceType GetResourceType<class BinaryResource>() { return ResourceType::Binary; }
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
32
engine/include/XCEngine/Core/IO/FileArchive.h
Normal file
32
engine/include/XCEngine/Core/IO/FileArchive.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceFileSystem.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class FileArchive : public IArchive {
|
||||
public:
|
||||
FileArchive();
|
||||
virtual ~FileArchive() override;
|
||||
|
||||
bool Open(const Containers::String& path) override;
|
||||
void Close() override;
|
||||
|
||||
bool Read(const Containers::String& fileName, void* buffer, size_t size, size_t offset) const override;
|
||||
size_t GetSize(const Containers::String& fileName) const override;
|
||||
bool Exists(const Containers::String& fileName) const override;
|
||||
void Enumerate(const Containers::String& pattern, Containers::Array<Containers::String>& outFiles) const override;
|
||||
|
||||
bool IsValid() const override { return m_isValid; }
|
||||
|
||||
const Containers::String& GetPath() const { return m_archivePath; }
|
||||
|
||||
private:
|
||||
Containers::String m_archivePath;
|
||||
bool m_isValid = false;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
62
engine/include/XCEngine/Core/IO/IResourceLoader.h
Normal file
62
engine/include/XCEngine/Core/IO/IResourceLoader.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "IResource.h"
|
||||
#include "ResourceTypes.h"
|
||||
#include "ImportSettings.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include <functional>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
struct LoadResult {
|
||||
IResource* resource = nullptr;
|
||||
bool success = false;
|
||||
Containers::String errorMessage;
|
||||
|
||||
LoadResult() = default;
|
||||
explicit LoadResult(IResource* res) : resource(res), success(res != nullptr) {}
|
||||
explicit LoadResult(const Containers::String& error) : success(false), errorMessage(error) {}
|
||||
explicit LoadResult(bool inSuccess, const Containers::String& error = "")
|
||||
: success(inSuccess), errorMessage(error) {}
|
||||
|
||||
operator bool() const { return success && resource != nullptr; }
|
||||
};
|
||||
|
||||
class IResourceLoader {
|
||||
public:
|
||||
virtual ~IResourceLoader() = default;
|
||||
|
||||
virtual ResourceType GetResourceType() const = 0;
|
||||
virtual Containers::Array<Containers::String> GetSupportedExtensions() const = 0;
|
||||
virtual bool CanLoad(const Containers::String& path) const = 0;
|
||||
virtual LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) = 0;
|
||||
|
||||
virtual void LoadAsync(const Containers::String& path,
|
||||
const ImportSettings* settings,
|
||||
std::function<void(LoadResult)> callback) {
|
||||
LoadResult result = Load(path, settings);
|
||||
if (callback) {
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ImportSettings* GetDefaultSettings() const = 0;
|
||||
|
||||
protected:
|
||||
static Containers::Array<Core::uint8> ReadFileData(const Containers::String& path);
|
||||
static Containers::String GetExtension(const Containers::String& path);
|
||||
};
|
||||
|
||||
#define REGISTER_RESOURCE_LOADER(loaderType) \
|
||||
namespace { \
|
||||
struct loaderType##Registrar { \
|
||||
loaderType##Registrar() { \
|
||||
ResourceManager::Get().RegisterLoader(new loaderType()); \
|
||||
} \
|
||||
} g_##loaderType##Registrar; \
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
75
engine/include/XCEngine/Core/IO/ResourceFileSystem.h
Normal file
75
engine/include/XCEngine/Core/IO/ResourceFileSystem.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Containers/HashMap.h"
|
||||
#include "../Core/SmartPtr.h"
|
||||
#include "../Threading/Mutex.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class IArchive {
|
||||
public:
|
||||
virtual ~IArchive() = default;
|
||||
|
||||
virtual bool Open(const Containers::String& path) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual bool Read(const Containers::String& fileName, void* buffer, size_t size, size_t offset) const = 0;
|
||||
virtual size_t GetSize(const Containers::String& fileName) const = 0;
|
||||
virtual bool Exists(const Containers::String& fileName) const = 0;
|
||||
virtual void Enumerate(const Containers::String& pattern, Containers::Array<Containers::String>& outFiles) const = 0;
|
||||
|
||||
virtual bool IsValid() const = 0;
|
||||
};
|
||||
|
||||
struct ResourceInfo {
|
||||
Containers::String path;
|
||||
size_t size = 0;
|
||||
Core::uint64 modifiedTime = 0;
|
||||
bool inArchive = false;
|
||||
Containers::String archivePath;
|
||||
};
|
||||
|
||||
class ResourceFileSystem {
|
||||
public:
|
||||
ResourceFileSystem();
|
||||
~ResourceFileSystem();
|
||||
|
||||
void Initialize(const Containers::String& rootPath);
|
||||
void Shutdown();
|
||||
|
||||
bool AddArchive(const Containers::String& archivePath);
|
||||
bool AddDirectory(const Containers::String& directoryPath);
|
||||
|
||||
void RemoveArchive(const Containers::String& archivePath);
|
||||
|
||||
bool FindResource(const Containers::String& relativePath, Containers::String& outAbsolutePath) const;
|
||||
|
||||
Containers::Array<Core::uint8> ReadResource(const Containers::String& relativePath) const;
|
||||
|
||||
bool Exists(const Containers::String& relativePath) const;
|
||||
|
||||
bool GetResourceInfo(const Containers::String& relativePath, ResourceInfo& outInfo) const;
|
||||
|
||||
void EnumerateResources(const Containers::String& pattern, Containers::Array<ResourceInfo>& outResources) const;
|
||||
|
||||
static ResourceFileSystem& Get();
|
||||
|
||||
private:
|
||||
IArchive* FindArchive(const Containers::String& relativePath) const;
|
||||
bool FindInDirectories(const Containers::String& relativePath, Containers::String& outAbsolutePath) const;
|
||||
bool FindInArchives(const Containers::String& relativePath, Containers::String& outArchivePath) const;
|
||||
|
||||
Containers::String m_rootPath;
|
||||
Containers::Array<Core::UniqueRef<IArchive>> m_archives;
|
||||
Containers::Array<Containers::String> m_directories;
|
||||
|
||||
mutable Containers::HashMap<Containers::String, ResourceInfo> m_infoCache;
|
||||
mutable Threading::Mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
100
engine/include/XCEngine/Core/IO/ResourcePackage.h
Normal file
100
engine/include/XCEngine/Core/IO/ResourcePackage.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Core/Types.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
struct PackageFileEntry {
|
||||
Containers::String relativePath;
|
||||
size_t size;
|
||||
Core::uint64 checksum;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
class ResourcePackageBuilder {
|
||||
public:
|
||||
ResourcePackageBuilder();
|
||||
~ResourcePackageBuilder();
|
||||
|
||||
bool AddFile(const Containers::String& sourcePath, const Containers::String& relativePath);
|
||||
bool AddDirectory(const Containers::String& sourceDir, const Containers::String& relativeBase = "");
|
||||
|
||||
void SetOutputPath(const Containers::String& path) { m_outputPath = path; }
|
||||
const Containers::String& GetOutputPath() const { return m_outputPath; }
|
||||
|
||||
bool Build();
|
||||
|
||||
float GetProgress() const { return m_progress; }
|
||||
const Containers::String& GetError() const { return m_error; }
|
||||
|
||||
private:
|
||||
Core::uint64 CalculateChecksum(const void* data, size_t size);
|
||||
bool WriteHeader(FILE* file, size_t dataOffset);
|
||||
bool WriteManifest(FILE* file);
|
||||
bool WriteData(FILE* file);
|
||||
|
||||
struct FileEntry {
|
||||
Containers::String sourcePath;
|
||||
Containers::String relativePath;
|
||||
size_t size;
|
||||
Core::uint64 checksum;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
Containers::String m_outputPath;
|
||||
Containers::Array<FileEntry> m_files;
|
||||
float m_progress = 0.0f;
|
||||
Containers::String m_error;
|
||||
};
|
||||
|
||||
class ResourcePackage {
|
||||
public:
|
||||
ResourcePackage();
|
||||
~ResourcePackage();
|
||||
|
||||
bool Open(const Containers::String& packagePath);
|
||||
void Close();
|
||||
|
||||
bool IsValid() const { return m_isValid; }
|
||||
|
||||
bool Exists(const Containers::String& relativePath) const;
|
||||
|
||||
Containers::Array<Core::uint8> Read(const Containers::String& relativePath) const;
|
||||
size_t GetSize(const Containers::String& relativePath) const;
|
||||
|
||||
void Enumerate(const Containers::String& pattern, Containers::Array<Containers::String>& outFiles) const;
|
||||
|
||||
struct PackageInfo {
|
||||
Containers::String path;
|
||||
Core::uint16 version;
|
||||
size_t fileCount;
|
||||
size_t totalSize;
|
||||
};
|
||||
|
||||
const PackageInfo& GetInfo() const { return m_info; }
|
||||
|
||||
private:
|
||||
bool ReadHeader(FILE* file);
|
||||
bool ReadManifest(FILE* file);
|
||||
|
||||
bool m_isValid = false;
|
||||
PackageInfo m_info;
|
||||
|
||||
Containers::String m_packagePath;
|
||||
size_t m_dataOffset;
|
||||
|
||||
struct FileEntryInternal {
|
||||
Containers::String path;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
Core::uint64 checksum;
|
||||
};
|
||||
Containers::Array<FileEntryInternal> m_entries;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
46
engine/include/XCEngine/Core/IO/ResourcePath.h
Normal file
46
engine/include/XCEngine/Core/IO/ResourcePath.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceTypes.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Containers/Array.h"
|
||||
#include "../Core/Types.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class ResourcePath {
|
||||
public:
|
||||
ResourcePath() = default;
|
||||
ResourcePath(const char* path);
|
||||
ResourcePath(const Containers::String& path);
|
||||
|
||||
Containers::String GetExtension() const;
|
||||
|
||||
Containers::String GetStem() const;
|
||||
|
||||
Containers::String GetFullPath() const;
|
||||
|
||||
Containers::String GetFileName() const;
|
||||
|
||||
Containers::String GetDirectory() const;
|
||||
|
||||
Containers::String GetRelativePath() const;
|
||||
|
||||
ResourceGUID ToGUID() const;
|
||||
|
||||
bool HasExtension(const char* ext) const;
|
||||
|
||||
bool HasAnyExtension(const char* const* extensions, Core::uint32 count) const;
|
||||
|
||||
bool IsValid() const { return !m_path.Empty(); }
|
||||
|
||||
const Containers::String& GetPath() const { return m_path; }
|
||||
|
||||
void SetPath(const Containers::String& path) { m_path = path; }
|
||||
|
||||
private:
|
||||
Containers::String m_path;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user