- 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
191 lines
5.3 KiB
C++
191 lines
5.3 KiB
C++
#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
|