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:
@@ -1,103 +0,0 @@
|
||||
#include "Resources/AsyncLoader.h"
|
||||
#include "Resources/ResourceManager.h"
|
||||
#include "Resources/ResourceTypes.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
Core::uint64 LoadRequest::GenerateRequestId() {
|
||||
static std::atomic<Core::uint64> s_requestId{0};
|
||||
return ++s_requestId;
|
||||
}
|
||||
|
||||
AsyncLoader& AsyncLoader::Get() {
|
||||
static AsyncLoader instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void AsyncLoader::Initialize(Core::uint32 workerThreadCount) {
|
||||
(void)workerThreadCount;
|
||||
}
|
||||
|
||||
void AsyncLoader::Shutdown() {
|
||||
CancelAll();
|
||||
}
|
||||
|
||||
void AsyncLoader::Submit(const Containers::String& path, ResourceType type,
|
||||
std::function<void(LoadResult)> callback) {
|
||||
Submit(path, type, nullptr, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncLoader::Submit(const Containers::String& path, ResourceType type, ImportSettings* settings,
|
||||
std::function<void(LoadResult)> callback) {
|
||||
LoadRequest request(path, type, std::move(callback), settings);
|
||||
SubmitInternal(std::move(request));
|
||||
}
|
||||
|
||||
void AsyncLoader::SubmitInternal(LoadRequest request) {
|
||||
IResourceLoader* loader = FindLoader(request.type);
|
||||
|
||||
if (!loader) {
|
||||
if (request.callback) {
|
||||
LoadResult result(Containers::String("No loader for type: ") +
|
||||
GetResourceTypeName(request.type));
|
||||
request.callback(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_queueMutex);
|
||||
m_pendingQueue.PushBack(std::move(request));
|
||||
m_pendingCount++;
|
||||
m_totalRequested++;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncLoader::Update() {
|
||||
Containers::Array<LoadRequest> completed;
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_completedMutex);
|
||||
completed = std::move(m_completedQueue);
|
||||
m_completedQueue.Clear();
|
||||
}
|
||||
|
||||
for (auto& request : completed) {
|
||||
m_pendingCount--;
|
||||
|
||||
if (request.callback) {
|
||||
LoadResult result(true);
|
||||
request.callback(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AsyncLoader::GetProgress() const {
|
||||
if (m_totalRequested == 0) return 1.0f;
|
||||
return static_cast<float>(m_totalRequested - m_pendingCount.load()) / m_totalRequested;
|
||||
}
|
||||
|
||||
void AsyncLoader::CancelAll() {
|
||||
std::lock_guard lock(m_queueMutex);
|
||||
m_pendingQueue.Clear();
|
||||
m_pendingCount = 0;
|
||||
}
|
||||
|
||||
void AsyncLoader::Cancel(Core::uint64 requestId) {
|
||||
std::lock_guard lock(m_queueMutex);
|
||||
(void)requestId;
|
||||
}
|
||||
|
||||
IResourceLoader* AsyncLoader::FindLoader(ResourceType type) const {
|
||||
return ResourceManager::Get().GetLoader(type);
|
||||
}
|
||||
|
||||
void AsyncLoader::QueueCompleted(LoadRequest request, LoadResult result) {
|
||||
std::lock_guard lock(m_completedMutex);
|
||||
(void)request;
|
||||
(void)result;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,97 +0,0 @@
|
||||
#include "Resources/FileArchive.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
FileArchive::FileArchive() = default;
|
||||
FileArchive::~FileArchive() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool FileArchive::Open(const Containers::String& path) {
|
||||
m_archivePath = path;
|
||||
m_isValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileArchive::Close() {
|
||||
m_archivePath = "";
|
||||
m_isValid = false;
|
||||
}
|
||||
|
||||
bool FileArchive::Read(const Containers::String& fileName, void* buffer, size_t size, size_t offset) const {
|
||||
if (!m_isValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::String fullPath = m_archivePath;
|
||||
if (!fullPath.EndsWith("/") && !fullPath.EndsWith("\\")) {
|
||||
fullPath += "/";
|
||||
}
|
||||
fullPath += fileName;
|
||||
|
||||
FILE* file = std::fopen(fullPath.CStr(), "rb");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
std::fseek(file, static_cast<long>(offset), SEEK_SET);
|
||||
}
|
||||
|
||||
size_t bytesRead = std::fread(buffer, 1, size, file);
|
||||
std::fclose(file);
|
||||
|
||||
return bytesRead == size;
|
||||
}
|
||||
|
||||
size_t FileArchive::GetSize(const Containers::String& fileName) const {
|
||||
if (!m_isValid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Containers::String fullPath = m_archivePath;
|
||||
if (!fullPath.EndsWith("/") && !fullPath.EndsWith("\\")) {
|
||||
fullPath += "/";
|
||||
}
|
||||
fullPath += fileName;
|
||||
|
||||
FILE* file = std::fopen(fullPath.CStr(), "rb");
|
||||
if (!file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::fseek(file, 0, SEEK_END);
|
||||
size_t size = static_cast<size_t>(std::ftell(file));
|
||||
std::fclose(file);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool FileArchive::Exists(const Containers::String& fileName) const {
|
||||
if (!m_isValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::String fullPath = m_archivePath;
|
||||
if (!fullPath.EndsWith("/") && !fullPath.EndsWith("\\")) {
|
||||
fullPath += "/";
|
||||
}
|
||||
fullPath += fileName;
|
||||
|
||||
FILE* file = std::fopen(fullPath.CStr(), "rb");
|
||||
if (file) {
|
||||
std::fclose(file);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileArchive::Enumerate(const Containers::String& pattern, Containers::Array<Containers::String>& outFiles) const {
|
||||
outFiles.Clear();
|
||||
// TODO: Implement pattern-based enumeration
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "XCEngine/Resources/IResourceLoader.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
Containers::Array<Core::uint8> IResourceLoader::ReadFileData(const Containers::String& path) {
|
||||
Containers::Array<Core::uint8> data;
|
||||
|
||||
std::ifstream file(path.CStr(), std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
data.Resize(static_cast<size_t>(size));
|
||||
if (!file.read(reinterpret_cast<char*>(data.Data()), size)) {
|
||||
data.Clear();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Containers::String IResourceLoader::GetExtension(const Containers::String& path) {
|
||||
Containers::String ext;
|
||||
size_t dotPos = Containers::String::npos;
|
||||
for (size_t i = path.Length(); i > 0; --i) {
|
||||
if (path[i - 1] == '.') {
|
||||
dotPos = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dotPos != Containers::String::npos) {
|
||||
ext = path.Substring(dotPos + 1);
|
||||
}
|
||||
return ext;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,141 +0,0 @@
|
||||
#include "Resources/ResourceCache.h"
|
||||
#include "Resources/ResourceManager.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
static Core::uint64 g_currentTick = 0;
|
||||
|
||||
Core::uint64 CacheEntry::GetCurrentTick() {
|
||||
return ++g_currentTick;
|
||||
}
|
||||
|
||||
CacheEntry::CacheEntry(IResource* res, size_t size)
|
||||
: resource(res), guid(res->GetGUID()), memorySize(size),
|
||||
lastAccessTime(GetCurrentTick()), accessCount(1) {}
|
||||
|
||||
ResourceCache::ResourceCache() = default;
|
||||
ResourceCache::~ResourceCache() = default;
|
||||
|
||||
void ResourceCache::Add(ResourceGUID guid, IResource* resource) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_cache.Contains(guid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CacheEntry entry(resource, resource->GetMemorySize());
|
||||
m_cache.Insert(guid, entry);
|
||||
m_lruOrder.PushBack(guid);
|
||||
m_memoryUsage += entry.memorySize;
|
||||
}
|
||||
|
||||
void ResourceCache::Remove(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_cache.Find(guid);
|
||||
if (it != nullptr) {
|
||||
m_memoryUsage -= it->memorySize;
|
||||
m_cache.Erase(guid);
|
||||
|
||||
// Simple workaround: rebuild LRU list without the guid
|
||||
Containers::Array<ResourceGUID> newList;
|
||||
for (size_t i = 0; i < m_lruOrder.Size(); ++i) {
|
||||
if (m_lruOrder[i] != guid) {
|
||||
newList.PushBack(m_lruOrder[i]);
|
||||
}
|
||||
}
|
||||
m_lruOrder = std::move(newList);
|
||||
}
|
||||
}
|
||||
|
||||
IResource* ResourceCache::Find(ResourceGUID guid) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_cache.Find(guid);
|
||||
return it != nullptr ? it->resource : nullptr;
|
||||
}
|
||||
|
||||
void ResourceCache::Touch(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_cache.Find(guid);
|
||||
if (it != nullptr) {
|
||||
it->lastAccessTime = CacheEntry::GetCurrentTick();
|
||||
it->accessCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceCache::SetMemoryBudget(size_t bytes) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_memoryBudget = bytes;
|
||||
}
|
||||
|
||||
void ResourceCache::OnMemoryPressure(size_t requiredBytes) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_memoryUsage + requiredBytes <= m_memoryBudget) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t targetRelease = (m_memoryUsage + requiredBytes) - m_memoryBudget;
|
||||
Evict(targetRelease);
|
||||
}
|
||||
|
||||
void ResourceCache::OnZeroRefCount(ResourceGUID guid) {
|
||||
|
||||
}
|
||||
|
||||
void ResourceCache::Evict(size_t requiredBytes) {
|
||||
size_t released = 0;
|
||||
|
||||
// Simple eviction: remove from end of LRU list
|
||||
while (released < requiredBytes && m_lruOrder.Size() > 0) {
|
||||
ResourceGUID guid = m_lruOrder.Back();
|
||||
m_lruOrder.PopBack();
|
||||
|
||||
auto* it = m_cache.Find(guid);
|
||||
if (it != nullptr) {
|
||||
m_memoryUsage -= it->memorySize;
|
||||
released += it->memorySize;
|
||||
it->resource->Release();
|
||||
m_cache.Erase(guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceCache::Flush() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Release all resources
|
||||
for (size_t i = 0; i < m_cache.Size(); ++i) {
|
||||
// Would need iteration support
|
||||
}
|
||||
|
||||
m_cache.Clear();
|
||||
m_lruOrder.Clear();
|
||||
m_memoryUsage = 0;
|
||||
}
|
||||
|
||||
void ResourceCache::Clear() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.Clear();
|
||||
m_lruOrder.Clear();
|
||||
m_memoryUsage = 0;
|
||||
}
|
||||
|
||||
Containers::Array<ResourceGUID> ResourceCache::GetLRUList(size_t count) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
Containers::Array<ResourceGUID> result;
|
||||
size_t n = std::min(count, static_cast<size_t>(m_lruOrder.Size()));
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
result.PushBack(m_lruOrder[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,224 +0,0 @@
|
||||
#include "Resources/ResourceDependencyGraph.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
ResourceDependencyGraph::ResourceDependencyGraph() = default;
|
||||
ResourceDependencyGraph::~ResourceDependencyGraph() = default;
|
||||
|
||||
void ResourceDependencyGraph::AddNode(ResourceGUID guid, ResourceType type) {
|
||||
if (m_nodes.Contains(guid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DependencyNode node;
|
||||
node.guid = guid;
|
||||
node.type = type;
|
||||
node.refCount = 0;
|
||||
m_nodes.Insert(guid, node);
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::RemoveNode(ResourceGUID guid) {
|
||||
m_nodes.Erase(guid);
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::AddDependency(ResourceGUID owner, ResourceGUID dependency) {
|
||||
DependencyNode* ownerNode = m_nodes.Find(owner);
|
||||
DependencyNode* depNode = m_nodes.Find(dependency);
|
||||
|
||||
if (!ownerNode || !depNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool alreadyExists = false;
|
||||
for (size_t i = 0; i < ownerNode->dependencies.Size(); ++i) {
|
||||
if (ownerNode->dependencies[i] == dependency) {
|
||||
alreadyExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyExists) {
|
||||
ownerNode->dependencies.PushBack(dependency);
|
||||
depNode->dependents.PushBack(owner);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::RemoveDependency(ResourceGUID owner, ResourceGUID dependency) {
|
||||
DependencyNode* ownerNode = m_nodes.Find(owner);
|
||||
DependencyNode* depNode = m_nodes.Find(dependency);
|
||||
|
||||
if (!ownerNode || !depNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ownerNode->dependencies.Size(); ++i) {
|
||||
if (ownerNode->dependencies[i] == dependency) {
|
||||
ownerNode->dependencies[i] = ownerNode->dependencies.Back();
|
||||
ownerNode->dependencies.PopBack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < depNode->dependents.Size(); ++i) {
|
||||
if (depNode->dependents[i] == owner) {
|
||||
depNode->dependents[i] = depNode->dependents.Back();
|
||||
depNode->dependents.PopBack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetDependencies(ResourceGUID guid) const {
|
||||
Containers::Array<ResourceGUID> result;
|
||||
|
||||
const DependencyNode* node = m_nodes.Find(guid);
|
||||
if (node) {
|
||||
result = node->dependencies;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetDependents(ResourceGUID guid) const {
|
||||
Containers::Array<ResourceGUID> result;
|
||||
|
||||
const DependencyNode* node = m_nodes.Find(guid);
|
||||
if (node) {
|
||||
result = node->dependents;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetAllDependencies(ResourceGUID guid) const {
|
||||
Containers::Array<ResourceGUID> result;
|
||||
Containers::Array<ResourceGUID> stack;
|
||||
stack.PushBack(guid);
|
||||
|
||||
while (stack.Size() > 0) {
|
||||
ResourceGUID current = stack.Back();
|
||||
stack.PopBack();
|
||||
|
||||
bool visited = false;
|
||||
for (size_t i = 0; i < result.Size(); ++i) {
|
||||
if (result[i] == current) {
|
||||
visited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (visited) continue;
|
||||
|
||||
if (current != guid) {
|
||||
result.PushBack(current);
|
||||
}
|
||||
|
||||
const DependencyNode* node = m_nodes.Find(current);
|
||||
if (node) {
|
||||
for (size_t i = 0; i < node->dependencies.Size(); ++i) {
|
||||
stack.PushBack(node->dependencies[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::IncrementRefCount(ResourceGUID guid) {
|
||||
DependencyNode* node = m_nodes.Find(guid);
|
||||
if (node) {
|
||||
node->refCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::DecrementRefCount(ResourceGUID guid) {
|
||||
DependencyNode* node = m_nodes.Find(guid);
|
||||
if (node && node->refCount > 0) {
|
||||
node->refCount--;
|
||||
}
|
||||
}
|
||||
|
||||
Core::uint32 ResourceDependencyGraph::GetRefCount(ResourceGUID guid) const {
|
||||
const DependencyNode* node = m_nodes.Find(guid);
|
||||
if (node) {
|
||||
return node->refCount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ResourceDependencyGraph::HasCircularDependency(ResourceGUID guid, Containers::Array<ResourceGUID>& outCycle) const {
|
||||
Containers::Array<ResourceGUID> path;
|
||||
Containers::Array<ResourceGUID> stack;
|
||||
stack.PushBack(guid);
|
||||
|
||||
while (stack.Size() > 0) {
|
||||
ResourceGUID current = stack.Back();
|
||||
stack.PopBack();
|
||||
|
||||
bool inPath = false;
|
||||
for (size_t i = 0; i < path.Size(); ++i) {
|
||||
if (path[i] == current) {
|
||||
inPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inPath) {
|
||||
outCycle = path;
|
||||
outCycle.PushBack(current);
|
||||
return true;
|
||||
}
|
||||
|
||||
path.PushBack(current);
|
||||
|
||||
const DependencyNode* node = m_nodes.Find(current);
|
||||
if (node) {
|
||||
for (size_t i = 0; i < node->dependencies.Size(); ++i) {
|
||||
stack.PushBack(node->dependencies[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<ResourceGUID> ResourceDependencyGraph::TopologicalSort() const {
|
||||
Containers::Array<ResourceGUID> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ResourceDependencyGraph::Unload(ResourceGUID guid) {
|
||||
DependencyNode* node = m_nodes.Find(guid);
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->refCount > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node->dependents.Size(); ++i) {
|
||||
DependencyNode* depNode = m_nodes.Find(node->dependents[i]);
|
||||
if (depNode && depNode->refCount > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourceDependencyGraph::Clear() {
|
||||
m_nodes.Clear();
|
||||
}
|
||||
|
||||
bool ResourceDependencyGraph::HasNode(ResourceGUID guid) const {
|
||||
return m_nodes.Find(guid) != nullptr;
|
||||
}
|
||||
|
||||
bool ResourceDependencyGraph::HasCircularDependencyInternal(ResourceGUID guid, Containers::HashMap<ResourceGUID, bool>& visited,
|
||||
Containers::Array<ResourceGUID>& path, Containers::Array<ResourceGUID>& outCycle) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,190 +0,0 @@
|
||||
#include "Resources/ResourceFileSystem.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
ResourceFileSystem::ResourceFileSystem() = default;
|
||||
ResourceFileSystem::~ResourceFileSystem() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void ResourceFileSystem::Initialize(const Containers::String& rootPath) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_rootPath = rootPath;
|
||||
}
|
||||
|
||||
void ResourceFileSystem::Shutdown() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
m_archives.Clear();
|
||||
m_directories.Clear();
|
||||
m_infoCache.Clear();
|
||||
m_rootPath = "";
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::AddArchive(const Containers::String& archivePath) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// TODO: Implement archive loading
|
||||
// For now, just store the path for later resolution
|
||||
m_directories.PushBack(archivePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::AddDirectory(const Containers::String& directoryPath) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_directories.PushBack(directoryPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourceFileSystem::RemoveArchive(const Containers::String& archivePath) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Remove directories - rebuild without the matching one
|
||||
Containers::Array<Containers::String> newDirs;
|
||||
for (size_t i = 0; i < m_directories.Size(); ++i) {
|
||||
if (m_directories[i] != archivePath) {
|
||||
newDirs.PushBack(m_directories[i]);
|
||||
}
|
||||
}
|
||||
m_directories = std::move(newDirs);
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::FindResource(const Containers::String& relativePath, Containers::String& outAbsolutePath) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (FindInDirectories(relativePath, outAbsolutePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FindInArchives(relativePath, outAbsolutePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> ResourceFileSystem::ReadResource(const Containers::String& relativePath) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
Containers::String absolutePath;
|
||||
if (!FindResource(relativePath, absolutePath)) {
|
||||
return Containers::Array<Core::uint8>();
|
||||
}
|
||||
|
||||
// Read file
|
||||
FILE* file = std::fopen(absolutePath.CStr(), "rb");
|
||||
if (!file) {
|
||||
return Containers::Array<Core::uint8>();
|
||||
}
|
||||
|
||||
std::fseek(file, 0, SEEK_END);
|
||||
size_t size = std::ftell(file);
|
||||
std::fseek(file, 0, SEEK_SET);
|
||||
|
||||
Containers::Array<Core::uint8> data;
|
||||
data.Resize(size);
|
||||
|
||||
size_t readSize = std::fread(data.Data(), 1, size, file);
|
||||
std::fclose(file);
|
||||
|
||||
if (readSize != size) {
|
||||
return Containers::Array<Core::uint8>();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::Exists(const Containers::String& relativePath) const {
|
||||
Containers::String absolutePath;
|
||||
return FindResource(relativePath, absolutePath);
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::GetResourceInfo(const Containers::String& relativePath, ResourceInfo& outInfo) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Check cache first
|
||||
auto* cached = m_infoCache.Find(relativePath);
|
||||
if (cached != nullptr) {
|
||||
outInfo = *cached;
|
||||
return true;
|
||||
}
|
||||
|
||||
Containers::String absolutePath;
|
||||
if (!FindResource(relativePath, absolutePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get file info
|
||||
outInfo.path = relativePath;
|
||||
outInfo.inArchive = false;
|
||||
|
||||
// TODO: Get actual file size and modification time
|
||||
|
||||
m_infoCache.Insert(relativePath, outInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourceFileSystem::EnumerateResources(const Containers::String& pattern, Containers::Array<ResourceInfo>& outResources) const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
outResources.Clear();
|
||||
|
||||
// TODO: Implement pattern matching
|
||||
}
|
||||
|
||||
ResourceFileSystem& ResourceFileSystem::Get() {
|
||||
static ResourceFileSystem instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
IArchive* ResourceFileSystem::FindArchive(const Containers::String& relativePath) const {
|
||||
for (size_t i = 0; i < m_archives.Size(); ++i) {
|
||||
if (m_archives[i]->Exists(relativePath)) {
|
||||
return m_archives[i].get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::FindInDirectories(const Containers::String& relativePath, Containers::String& outAbsolutePath) const {
|
||||
// Try root directory first
|
||||
if (m_rootPath.Length() > 0) {
|
||||
outAbsolutePath = m_rootPath;
|
||||
if (!outAbsolutePath.EndsWith("/") && !outAbsolutePath.EndsWith("\\")) {
|
||||
outAbsolutePath += "/";
|
||||
}
|
||||
outAbsolutePath += relativePath;
|
||||
|
||||
// Simple check - in real implementation, use OS APIs
|
||||
// For now, just return the path
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try each registered directory
|
||||
for (size_t i = 0; i < m_directories.Size(); ++i) {
|
||||
outAbsolutePath = m_directories[i];
|
||||
if (!outAbsolutePath.EndsWith("/") && !outAbsolutePath.EndsWith("\\")) {
|
||||
outAbsolutePath += "/";
|
||||
}
|
||||
outAbsolutePath += relativePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResourceFileSystem::FindInArchives(const Containers::String& relativePath, Containers::String& outArchivePath) const {
|
||||
// Check if resource is in any archive
|
||||
IArchive* archive = FindArchive(relativePath);
|
||||
if (archive != nullptr) {
|
||||
outArchivePath = archive->IsValid() ? "archive://" + relativePath : "";
|
||||
return archive->IsValid();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,211 +0,0 @@
|
||||
#include "Resources/ResourceManager.h"
|
||||
#include "Resources/ResourceHandle.h"
|
||||
#include "Resources/ResourceTypes.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
ResourceManager& ResourceManager::Get() {
|
||||
static ResourceManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ResourceManager::Initialize() {
|
||||
m_asyncLoader = Core::MakeUnique<AsyncLoader>();
|
||||
m_asyncLoader->Initialize(2);
|
||||
}
|
||||
|
||||
void ResourceManager::Shutdown() {
|
||||
UnloadAll();
|
||||
m_asyncLoader->Shutdown();
|
||||
m_asyncLoader.reset();
|
||||
}
|
||||
|
||||
void ResourceManager::SetResourceRoot(const Containers::String& rootPath) {
|
||||
m_resourceRoot = rootPath;
|
||||
}
|
||||
|
||||
const Containers::String& ResourceManager::GetResourceRoot() const {
|
||||
return m_resourceRoot;
|
||||
}
|
||||
|
||||
void ResourceManager::AddRef(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_refCounts.Find(guid);
|
||||
if (it == nullptr) {
|
||||
m_refCounts.Insert(guid, 1);
|
||||
} else {
|
||||
(*it)++;
|
||||
}
|
||||
|
||||
if (!m_resourceCache.Contains(guid)) {
|
||||
ReloadResource(guid);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::Release(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_refCounts.Find(guid);
|
||||
if (it != nullptr) {
|
||||
(*it)--;
|
||||
|
||||
if (*it == 0) {
|
||||
m_refCounts.Erase(guid);
|
||||
m_cache.OnZeroRefCount(guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::uint32 ResourceManager::GetRefCount(ResourceGUID guid) const {
|
||||
auto* it = m_refCounts.Find(guid);
|
||||
return it != nullptr ? *it : 0;
|
||||
}
|
||||
|
||||
void ResourceManager::RegisterLoader(IResourceLoader* loader) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_loaders.Insert(loader->GetResourceType(), loader);
|
||||
}
|
||||
|
||||
IResourceLoader* ResourceManager::GetLoader(ResourceType type) const {
|
||||
auto* it = m_loaders.Find(type);
|
||||
return it != nullptr ? *it : nullptr;
|
||||
}
|
||||
|
||||
IResourceLoader* ResourceManager::FindLoader(ResourceType type) {
|
||||
return GetLoader(type);
|
||||
}
|
||||
|
||||
IResource* ResourceManager::FindInCache(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_resourceCache.Find(guid);
|
||||
return it != nullptr ? *it : nullptr;
|
||||
}
|
||||
|
||||
void ResourceManager::AddToCache(ResourceGUID guid, IResource* resource) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
m_resourceCache.Insert(guid, resource);
|
||||
m_memoryUsage += resource->GetMemorySize();
|
||||
m_cache.Add(guid, resource);
|
||||
|
||||
if (m_memoryUsage > m_memoryBudget) {
|
||||
m_cache.OnMemoryPressure(m_memoryUsage - m_memoryBudget);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::Unload(ResourceGUID guid) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto* it = m_resourceCache.Find(guid);
|
||||
if (it != nullptr) {
|
||||
IResource* resource = *it;
|
||||
m_resourceCache.Erase(guid);
|
||||
m_memoryUsage -= resource->GetMemorySize();
|
||||
resource->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::UnloadAll() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
for (size_t i = 0; i < m_resourceCache.Size(); ++i) {
|
||||
// This is a simplified approach - we'd need a way to iterate
|
||||
// For now, just clear everything
|
||||
}
|
||||
m_resourceCache.Clear();
|
||||
m_refCounts.Clear();
|
||||
m_memoryUsage = 0;
|
||||
}
|
||||
|
||||
void ResourceManager::SetMemoryBudget(size_t bytes) {
|
||||
m_memoryBudget = bytes;
|
||||
}
|
||||
|
||||
size_t ResourceManager::GetMemoryUsage() const {
|
||||
return m_memoryUsage;
|
||||
}
|
||||
|
||||
size_t ResourceManager::GetMemoryBudget() const {
|
||||
return m_memoryBudget;
|
||||
}
|
||||
|
||||
void ResourceManager::FlushCache() {
|
||||
m_cache.Flush();
|
||||
}
|
||||
|
||||
IResource* ResourceManager::Find(const Containers::String& path) {
|
||||
return Find(ResourceGUID::Generate(path));
|
||||
}
|
||||
|
||||
IResource* ResourceManager::Find(ResourceGUID guid) {
|
||||
return FindInCache(guid);
|
||||
}
|
||||
|
||||
bool ResourceManager::Exists(const Containers::String& path) const {
|
||||
return Exists(ResourceGUID::Generate(path));
|
||||
}
|
||||
|
||||
bool ResourceManager::Exists(ResourceGUID guid) const {
|
||||
return m_resourceCache.Contains(guid);
|
||||
}
|
||||
|
||||
Containers::String ResourceManager::ResolvePath(const Containers::String& relativePath) const {
|
||||
return m_resourceRoot + "/" + relativePath;
|
||||
}
|
||||
|
||||
void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type,
|
||||
std::function<void(LoadResult)> callback) {
|
||||
LoadAsync(path, type, nullptr, callback);
|
||||
}
|
||||
|
||||
void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type,
|
||||
ImportSettings* settings,
|
||||
std::function<void(LoadResult)> callback) {
|
||||
m_asyncLoader->Submit(path, type, settings, callback);
|
||||
}
|
||||
|
||||
void ResourceManager::Unload(const Containers::String& path) {
|
||||
Unload(ResourceGUID::Generate(path));
|
||||
}
|
||||
|
||||
void ResourceManager::UnloadUnused() {
|
||||
|
||||
}
|
||||
|
||||
void ResourceManager::UnregisterLoader(ResourceType type) {
|
||||
m_loaders.Erase(type);
|
||||
}
|
||||
|
||||
void ResourceManager::ReloadResource(ResourceGUID guid) {
|
||||
auto* pathIt = m_guidToPath.Find(guid);
|
||||
if (pathIt == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Containers::Array<Containers::String> ResourceManager::GetResourcePaths() const {
|
||||
Containers::Array<Containers::String> paths;
|
||||
for (const auto& pair : m_guidToPath) {
|
||||
paths.PushBack(pair.second);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
void ResourceManager::UnloadGroup(const Containers::Array<ResourceGUID>& guids) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
for (const auto& guid : guids) {
|
||||
auto* it = m_resourceCache.Find(guid);
|
||||
if (it != nullptr) {
|
||||
IResource* resource = *it;
|
||||
m_resourceCache.Erase(guid);
|
||||
m_memoryUsage -= resource->GetMemorySize();
|
||||
resource->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "Resources/ResourcePackage.h"
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
static constexpr const char* PACKAGE_MAGIC = "XCRP";
|
||||
static constexpr Core::uint16 PACKAGE_VERSION = 1;
|
||||
|
||||
ResourcePackageBuilder::ResourcePackageBuilder() = default;
|
||||
ResourcePackageBuilder::~ResourcePackageBuilder() = default;
|
||||
|
||||
bool ResourcePackageBuilder::AddFile(const Containers::String& sourcePath, const Containers::String& relativePath) {
|
||||
FILE* file = std::fopen(sourcePath.CStr(), "rb");
|
||||
if (!file) {
|
||||
m_error = "Cannot open file: " + sourcePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::fseek(file, 0, SEEK_END);
|
||||
long size = std::ftell(file);
|
||||
std::fseek(file, 0, SEEK_SET);
|
||||
|
||||
std::fclose(file);
|
||||
|
||||
FileEntry entry;
|
||||
entry.sourcePath = sourcePath;
|
||||
entry.relativePath = relativePath;
|
||||
entry.size = static_cast<size_t>(size);
|
||||
entry.checksum = 0;
|
||||
|
||||
m_files.PushBack(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePackageBuilder::AddDirectory(const Containers::String& sourceDir, const Containers::String& relativeBase) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePackageBuilder::Build() {
|
||||
if (m_outputPath.Empty()) {
|
||||
m_error = "Output path not set";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_files.Empty()) {
|
||||
m_error = "No files to package";
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* output = std::fopen(m_outputPath.CStr(), "wb");
|
||||
if (!output) {
|
||||
m_error = "Cannot create output file: " + m_outputPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t headerSize = 4 + 2 + 4 + 4 + 8;
|
||||
size_t dataOffset = headerSize;
|
||||
|
||||
for (auto& file : m_files) {
|
||||
file.offset = dataOffset;
|
||||
dataOffset += file.size;
|
||||
}
|
||||
|
||||
bool success = WriteHeader(output, dataOffset) &&
|
||||
WriteManifest(output) &&
|
||||
WriteData(output);
|
||||
|
||||
std::fclose(output);
|
||||
|
||||
if (!success) {
|
||||
std::remove(m_outputPath.CStr());
|
||||
}
|
||||
|
||||
m_progress = 1.0f;
|
||||
return success;
|
||||
}
|
||||
|
||||
Core::uint64 ResourcePackageBuilder::CalculateChecksum(const void* data, size_t size) {
|
||||
const Core::uint8* bytes = static_cast<const Core::uint8*>(data);
|
||||
Core::uint64 hash = 14695981039346656037ULL;
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
hash ^= static_cast<Core::uint64>(bytes[i]);
|
||||
hash *= 1099511628211ULL;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool ResourcePackageBuilder::WriteHeader(FILE* file, size_t dataOffset) {
|
||||
std::fwrite(PACKAGE_MAGIC, 1, 4, file);
|
||||
|
||||
Core::uint16 version = PACKAGE_VERSION;
|
||||
std::fwrite(&version, 2, 1, file);
|
||||
|
||||
Core::uint32 manifestSize = 0;
|
||||
std::fwrite(&manifestSize, 4, 1, file);
|
||||
|
||||
Core::uint32 fileCount = static_cast<Core::uint32>(m_files.Size());
|
||||
std::fwrite(&fileCount, 4, 1, file);
|
||||
|
||||
Core::uint64 offset = static_cast<Core::uint64>(dataOffset);
|
||||
std::fwrite(&offset, 8, 1, file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePackageBuilder::WriteManifest(FILE* file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePackageBuilder::WriteData(FILE* file) {
|
||||
for (size_t i = 0; i < m_files.Size(); ++i) {
|
||||
auto& fileEntry = m_files[i];
|
||||
|
||||
FILE* input = std::fopen(fileEntry.sourcePath.CStr(), "rb");
|
||||
if (!input) {
|
||||
m_error = "Cannot open file: " + fileEntry.sourcePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> buffer(fileEntry.size);
|
||||
size_t readSize = std::fread(buffer.Data(), 1, fileEntry.size, input);
|
||||
std::fclose(input);
|
||||
|
||||
if (readSize != fileEntry.size) {
|
||||
m_error = "Failed to read file: " + fileEntry.sourcePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
fileEntry.checksum = CalculateChecksum(buffer.Data(), buffer.Size());
|
||||
|
||||
size_t written = std::fwrite(buffer.Data(), 1, buffer.Size(), file);
|
||||
if (written != buffer.Size()) {
|
||||
m_error = "Failed to write to package";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_progress = static_cast<float>(i + 1) / static_cast<float>(m_files.Size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ResourcePackage::ResourcePackage() = default;
|
||||
ResourcePackage::~ResourcePackage() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool ResourcePackage::Open(const Containers::String& packagePath) {
|
||||
FILE* file = std::fopen(packagePath.CStr(), "rb");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_packagePath = packagePath;
|
||||
|
||||
bool success = ReadHeader(file) && ReadManifest(file);
|
||||
std::fclose(file);
|
||||
|
||||
if (!success) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_isValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourcePackage::Close() {
|
||||
m_isValid = false;
|
||||
m_packagePath = "";
|
||||
m_entries.Clear();
|
||||
m_dataOffset = 0;
|
||||
}
|
||||
|
||||
bool ResourcePackage::Exists(const Containers::String& relativePath) const {
|
||||
for (const auto& entry : m_entries) {
|
||||
if (entry.path == relativePath) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> ResourcePackage::Read(const Containers::String& relativePath) const {
|
||||
Containers::Array<Core::uint8> data;
|
||||
|
||||
for (const auto& entry : m_entries) {
|
||||
if (entry.path == relativePath) {
|
||||
FILE* file = std::fopen(m_packagePath.CStr(), "rb");
|
||||
if (!file) {
|
||||
return data;
|
||||
}
|
||||
|
||||
std::fseek(file, static_cast<long>(m_dataOffset + entry.offset), SEEK_SET);
|
||||
data.Resize(entry.size);
|
||||
size_t read = std::fread(data.Data(), 1, entry.size, file);
|
||||
std::fclose(file);
|
||||
|
||||
if (read != entry.size) {
|
||||
data.Clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
size_t ResourcePackage::GetSize(const Containers::String& relativePath) const {
|
||||
for (const auto& entry : m_entries) {
|
||||
if (entry.path == relativePath) {
|
||||
return entry.size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ResourcePackage::Enumerate(const Containers::String& pattern, Containers::Array<Containers::String>& outFiles) const {
|
||||
outFiles.Clear();
|
||||
for (const auto& entry : m_entries) {
|
||||
outFiles.PushBack(entry.path);
|
||||
}
|
||||
}
|
||||
|
||||
bool ResourcePackage::ReadHeader(FILE* file) {
|
||||
char magic[5] = {0};
|
||||
if (std::fread(magic, 1, 4, file) != 4 || std::strncmp(magic, PACKAGE_MAGIC, 4) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::uint16 version;
|
||||
if (std::fread(&version, 2, 1, file) != 1 || version != PACKAGE_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::uint32 manifestSize;
|
||||
if (std::fread(&manifestSize, 4, 1, file) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::uint32 fileCount;
|
||||
if (std::fread(&fileCount, 4, 1, file) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::uint64 dataOffset;
|
||||
if (std::fread(&dataOffset, 8, 1, file) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_info.path = m_packagePath;
|
||||
m_info.version = version;
|
||||
m_info.fileCount = fileCount;
|
||||
m_info.totalSize = 0;
|
||||
m_dataOffset = static_cast<size_t>(dataOffset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourcePackage::ReadManifest(FILE* file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,136 +0,0 @@
|
||||
#include <XCEngine/Resources/ResourcePath.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
static size_t FindLastOf(const Containers::String& str, char ch) {
|
||||
for (size_t i = str.Length(); i > 0; --i) {
|
||||
if (str[i - 1] == ch) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return Containers::String::npos;
|
||||
}
|
||||
|
||||
ResourcePath::ResourcePath(const char* path)
|
||||
: m_path(path) {}
|
||||
|
||||
ResourcePath::ResourcePath(const Containers::String& path)
|
||||
: m_path(path) {}
|
||||
|
||||
Containers::String ResourcePath::GetExtension() const {
|
||||
if (m_path.Empty()) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
size_t dotPos = FindLastOf(m_path, '.');
|
||||
if (dotPos == Containers::String::npos) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
return m_path.Substring(dotPos);
|
||||
}
|
||||
|
||||
Containers::String ResourcePath::GetStem() const {
|
||||
if (m_path.Empty()) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
size_t slashPos = FindLastOf(m_path, '/');
|
||||
size_t backslashPos = FindLastOf(m_path, '\\');
|
||||
size_t nameStart = (slashPos != Containers::String::npos && backslashPos != Containers::String::npos)
|
||||
? std::max(slashPos, backslashPos)
|
||||
: (slashPos != Containers::String::npos ? slashPos : backslashPos);
|
||||
|
||||
if (nameStart == Containers::String::npos) {
|
||||
nameStart = 0;
|
||||
} else {
|
||||
nameStart += 1;
|
||||
}
|
||||
|
||||
size_t dotPos = FindLastOf(m_path, '.');
|
||||
if (dotPos == Containers::String::npos || dotPos < nameStart) {
|
||||
return m_path.Substring(nameStart);
|
||||
}
|
||||
|
||||
return m_path.Substring(nameStart, dotPos - nameStart);
|
||||
}
|
||||
|
||||
Containers::String ResourcePath::GetFullPath() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
Containers::String ResourcePath::GetFileName() const {
|
||||
if (m_path.Empty()) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
size_t slashPos = FindLastOf(m_path, '/');
|
||||
size_t backslashPos = FindLastOf(m_path, '\\');
|
||||
size_t nameStart = (slashPos != Containers::String::npos && backslashPos != Containers::String::npos)
|
||||
? std::max(slashPos, backslashPos)
|
||||
: (slashPos != Containers::String::npos ? slashPos : backslashPos);
|
||||
|
||||
if (nameStart == Containers::String::npos) {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
return m_path.Substring(nameStart + 1);
|
||||
}
|
||||
|
||||
Containers::String ResourcePath::GetDirectory() const {
|
||||
if (m_path.Empty()) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
size_t slashPos = FindLastOf(m_path, '/');
|
||||
size_t backslashPos = FindLastOf(m_path, '\\');
|
||||
size_t dirEnd = (slashPos != Containers::String::npos && backslashPos != Containers::String::npos)
|
||||
? std::max(slashPos, backslashPos)
|
||||
: (slashPos != Containers::String::npos ? slashPos : backslashPos);
|
||||
|
||||
if (dirEnd == Containers::String::npos) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
return m_path.Substring(0, dirEnd);
|
||||
}
|
||||
|
||||
Containers::String ResourcePath::GetRelativePath() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
ResourceGUID ResourcePath::ToGUID() const {
|
||||
return ResourceGUID::Generate(m_path);
|
||||
}
|
||||
|
||||
bool ResourcePath::HasExtension(const char* ext) const {
|
||||
if (!ext || m_path.Empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::String pathExt = GetExtension();
|
||||
if (pathExt.Empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pathExt == ext;
|
||||
}
|
||||
|
||||
bool ResourcePath::HasAnyExtension(const char* const* extensions, Core::uint32 count) const {
|
||||
if (!extensions || count == 0 || m_path.Empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Core::uint32 i = 0; i < count; ++i) {
|
||||
if (HasExtension(extensions[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "Resources/ResourceTypes.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
ResourceGUID ResourceGUID::Generate(const char* path) {
|
||||
Core::uint64 hash = 14695981039346656037ULL;
|
||||
|
||||
while (*path) {
|
||||
hash ^= static_cast<Core::uint64>(*path);
|
||||
hash *= 1099511628211ULL;
|
||||
path++;
|
||||
}
|
||||
|
||||
return ResourceGUID(hash);
|
||||
}
|
||||
|
||||
ResourceGUID ResourceGUID::Generate(const Containers::String& path) {
|
||||
return Generate(path.CStr());
|
||||
}
|
||||
|
||||
Containers::String ResourceGUID::ToString() const {
|
||||
char buffer[17];
|
||||
snprintf(buffer, sizeof(buffer), "%016llx", value);
|
||||
return Containers::String(buffer);
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user