diff --git a/source/core/resources/resource_helper.cpp b/source/core/resources/resource_helper.cpp index c30f63d..abaa67a 100644 --- a/source/core/resources/resource_helper.cpp +++ b/source/core/resources/resource_helper.cpp @@ -9,72 +9,77 @@ namespace Resource::Helper { -// Inicialitzar el sistema de recursos -auto initializeResourceSystem(const std::string& pack_file, bool fallback) -> bool { - return Loader::get().initialize(pack_file, fallback); -} + // Inicialitzar el sistema de recursos + auto initializeResourceSystem(const std::string& pack_file, bool fallback) -> bool { + return Loader::get().initialize(pack_file, fallback); + } -// Carregar un file -auto loadFile(const std::string& filepath) -> std::vector { - // Normalitzar la ruta - std::string normalized = normalizePath(filepath); + // Carregar un file + auto loadFile(const std::string& filepath) -> std::vector { + // Normalitzar la ruta + std::string normalized = normalizePath(filepath); - // Carregar del sistema de recursos - return Loader::get().loadResource(normalized); -} + // Carregar del sistema de recursos + return Loader::get().loadResource(normalized); + } -// Comprovar si existeix un file -auto fileExists(const std::string& filepath) -> bool { - std::string normalized = normalizePath(filepath); - return Loader::get().resourceExists(normalized); -} + // Llistar recursos amb un prefix donat + auto listResources(const std::string& prefix) -> std::vector { + return Loader::get().listResources(prefix); + } -// Obtenir ruta normalitzada per al paquet -// Elimina prefixos "data/", rutes absolutes, etc. -auto getPackPath(const std::string& asset_path) -> std::string { - std::string path = asset_path; + // Comprovar si existeix un file + auto fileExists(const std::string& filepath) -> bool { + std::string normalized = normalizePath(filepath); + return Loader::get().resourceExists(normalized); + } - // Eliminar rutes absolutes (detectar / o C:\ al principi) - if (!path.empty() && path[0] == '/') { - // Buscar "data/" i agafar el que ve después - size_t data_pos = path.find("/data/"); - if (data_pos != std::string::npos) { - path = path.substr(data_pos + 6); // Saltar "/data/" + // Obtenir ruta normalitzada per al paquet + // Elimina prefixos "data/", rutes absolutes, etc. + auto getPackPath(const std::string& asset_path) -> std::string { + std::string path = asset_path; + + // Eliminar rutes absolutes (detectar / o C:\ al principi) + if (!path.empty() && path[0] == '/') { + // Buscar "data/" i agafar el que ve después + size_t data_pos = path.find("/data/"); + if (data_pos != std::string::npos) { + path = path.substr(data_pos + 6); // Saltar "/data/" + } } + + // Eliminar "./" i "../" del principi + while (path.starts_with("./")) { + path = path.substr(2); + } + while (path.starts_with("../")) { + path = path.substr(3); + } + + // Eliminar "data/" del principi + if (path.starts_with("data/")) { + path = path.substr(5); + } + + // Eliminar "Resources/" (macOS bundles) + if (path.starts_with("Resources/")) { + path = path.substr(10); + } + + // Convertir barres invertides a normals + std::ranges::replace(path, '\\', '/'); + + return path; } - // Eliminar "./" i "../" del principi - while (path.starts_with("./")) { - path = path.substr(2); - } - while (path.starts_with("../")) { - path = path.substr(3); + // Normalitzar ruta (alias de getPackPath) + auto normalizePath(const std::string& path) -> std::string { + return getPackPath(path); } - // Eliminar "data/" del principi - if (path.starts_with("data/")) { - path = path.substr(5); + // Comprovar si hay paquet carregat + auto isPackLoaded() -> bool { + return Loader::get().isPackLoaded(); } - // Eliminar "Resources/" (macOS bundles) - if (path.starts_with("Resources/")) { - path = path.substr(10); - } - - // Convertir barres invertides a normals - std::ranges::replace(path, '\\', '/'); - - return path; -} - -// Normalitzar ruta (alias de getPackPath) -auto normalizePath(const std::string& path) -> std::string { - return getPackPath(path); -} - -// Comprovar si hay paquet carregat -auto isPackLoaded() -> bool { - return Loader::get().isPackLoaded(); -} - } // namespace Resource::Helper diff --git a/source/core/resources/resource_helper.hpp b/source/core/resources/resource_helper.hpp index e3102e9..ac6ad4d 100644 --- a/source/core/resources/resource_helper.hpp +++ b/source/core/resources/resource_helper.hpp @@ -10,18 +10,21 @@ namespace Resource::Helper { -// Inicialización del sistema -auto initializeResourceSystem(const std::string& pack_file, bool fallback) -> bool; + // Inicialización del sistema + auto initializeResourceSystem(const std::string& pack_file, bool fallback) -> bool; -// Càrrega de archivos -auto loadFile(const std::string& filepath) -> std::vector; -auto fileExists(const std::string& filepath) -> bool; + // Càrrega de archivos + auto loadFile(const std::string& filepath) -> std::vector; + auto fileExists(const std::string& filepath) -> bool; -// Normalització de rutes -auto getPackPath(const std::string& asset_path) -> std::string; -auto normalizePath(const std::string& path) -> std::string; + // Llistat de recursos disponibles amb un prefix (ex. "shapes/", "sounds/"). + auto listResources(const std::string& prefix) -> std::vector; -// Estat -auto isPackLoaded() -> bool; + // Normalització de rutes + auto getPackPath(const std::string& asset_path) -> std::string; + auto normalizePath(const std::string& path) -> std::string; + + // Estat + auto isPackLoaded() -> bool; } // namespace Resource::Helper diff --git a/source/core/resources/resource_loader.cpp b/source/core/resources/resource_loader.cpp index cef931f..d9dc1ae 100644 --- a/source/core/resources/resource_loader.cpp +++ b/source/core/resources/resource_loader.cpp @@ -3,141 +3,178 @@ #include "resource_loader.hpp" +#include #include #include #include namespace Resource { -// Singleton -auto Loader::get() -> Loader& { - static Loader instance_; - return instance_; -} - -// Inicialitzar el sistema de recursos -auto Loader::initialize(const std::string& pack_file, bool enable_fallback) -> bool { - fallback_enabled_ = enable_fallback; - - // Intentar load el paquet - pack_ = std::make_unique(); - - if (!pack_->loadPack(pack_file)) { - if (!fallback_enabled_) { - std::cerr << "[ResourceLoader] ERROR FATAL: No es pot load " << pack_file - << " y el fallback está desactivat\n"; - return false; - } - - std::cout << "[ResourceLoader] Paquet no trobat, usant fallback al sistema de archivos\n"; - pack_.reset(); // No hay paquet - return true; + // Singleton + auto Loader::get() -> Loader& { + static Loader instance_; + return instance_; } - std::cout << "[ResourceLoader] Paquet carregat: " << pack_file << "\n"; - return true; -} + // Inicialitzar el sistema de recursos + auto Loader::initialize(const std::string& pack_file, bool enable_fallback) -> bool { + fallback_enabled_ = enable_fallback; -// Carregar un recurs -auto Loader::loadResource(const std::string& filename) -> std::vector { - // Intentar load del paquet primer - if (pack_) { - if (pack_->hasResource(filename)) { - auto data = pack_->getResource(filename); - if (!data.empty()) { - return data; + // Intentar load el paquet + pack_ = std::make_unique(); + + if (!pack_->loadPack(pack_file)) { + if (!fallback_enabled_) { + std::cerr << "[ResourceLoader] ERROR FATAL: No es pot load " << pack_file + << " y el fallback está desactivat\n"; + return false; } - std::cerr << "[ResourceLoader] Advertència: recurs buit al paquet: " << filename - << "\n"; + + std::cout << "[ResourceLoader] Paquet no trobat, usant fallback al sistema de archivos\n"; + pack_.reset(); // No hay paquet + return true; } - // Si no está al paquet y no hay fallback, falla - if (!fallback_enabled_) { - std::cerr << "[ResourceLoader] ERROR: Recurs no trobat al paquet i fallback desactivat: " - << filename << "\n"; - return {}; - } - } - - // Fallback al sistema de archivos - if (fallback_enabled_) { - return loadFromFilesystem(filename); - } - - return {}; -} - -// Comprovar si existeix un recurs -auto Loader::resourceExists(const std::string& filename) -> bool { - // Comprovar al paquet - if (pack_ && pack_->hasResource(filename)) { + std::cout << "[ResourceLoader] Paquet carregat: " << pack_file << "\n"; return true; } - // Comprovar al sistema de archivos si está activat el fallback - if (fallback_enabled_) { - std::string fullpath = base_path_.empty() ? "data/" + filename : base_path_ + "/data/" + filename; - return std::filesystem::exists(fullpath); + // Carregar un recurs + auto Loader::loadResource(const std::string& filename) -> std::vector { + // Intentar load del paquet primer + if (pack_) { + if (pack_->hasResource(filename)) { + auto data = pack_->getResource(filename); + if (!data.empty()) { + return data; + } + std::cerr << "[ResourceLoader] Advertència: recurs buit al paquet: " << filename + << "\n"; + } + + // Si no está al paquet y no hay fallback, falla + if (!fallback_enabled_) { + std::cerr << "[ResourceLoader] ERROR: Recurs no trobat al paquet i fallback desactivat: " + << filename << "\n"; + return {}; + } + } + + // Fallback al sistema de archivos + if (fallback_enabled_) { + return loadFromFilesystem(filename); + } + + return {}; } - return false; -} + auto Loader::listResources(const std::string& prefix) -> std::vector { + std::vector result; + + if (pack_) { + for (const auto& path : pack_->getResourceList()) { + if (path.starts_with(prefix)) { + result.push_back(path); + } + } + return result; + } + + if (!fallback_enabled_) { + return result; + } + + std::string root = base_path_.empty() ? "data/" + prefix : base_path_ + "/data/" + prefix; + if (!std::filesystem::exists(root)) { + return result; + } + + for (const auto& entry : std::filesystem::recursive_directory_iterator(root)) { + if (!entry.is_regular_file()) { + continue; + } + std::string full = entry.path().generic_string(); + if (auto pos = full.find("/data/"); pos != std::string::npos) { + result.push_back(full.substr(pos + 6)); + } else if (full.starts_with("data/")) { + result.push_back(full.substr(5)); + } + } + std::ranges::sort(result); + return result; + } + + // Comprovar si existeix un recurs + auto Loader::resourceExists(const std::string& filename) -> bool { + // Comprovar al paquet + if (pack_ && pack_->hasResource(filename)) { + return true; + } + + // Comprovar al sistema de archivos si está activat el fallback + if (fallback_enabled_) { + std::string fullpath = base_path_.empty() ? "data/" + filename : base_path_ + "/data/" + filename; + return std::filesystem::exists(fullpath); + } -// Validar el paquet -auto Loader::validatePack() -> bool { - if (!pack_) { - std::cerr << "[ResourceLoader] Advertència: no hay paquet carregat per validar\n"; return false; } - return pack_->validatePack(); -} + // Validar el paquet + auto Loader::validatePack() -> bool { + if (!pack_) { + std::cerr << "[ResourceLoader] Advertència: no hay paquet carregat per validar\n"; + return false; + } -// Comprovar si hay paquet carregat -auto Loader::isPackLoaded() const -> bool { - return pack_ != nullptr; -} - -// Establir la ruta base -void Loader::setBasePath(const std::string& path) { - base_path_ = path; - std::cout << "[ResourceLoader] Ruta base establerta: " << base_path_ << "\n"; -} - -// Obtenir la ruta base -auto Loader::getBasePath() const -> const std::string& { - return base_path_; -} - -// Carregar des del sistema de archivos (fallback) -auto Loader::loadFromFilesystem(const std::string& filename) -> std::vector { - // The filename is already normalized (e.g., "shapes/logo/letra_j.shp") - // We need to prepend base_path + "data/" - std::string fullpath; - - if (base_path_.empty()) { - fullpath = "data/" + filename; - } else { - fullpath = base_path_ + "/data/" + filename; + return pack_->validatePack(); } - std::ifstream file(fullpath, std::ios::binary | std::ios::ate); - if (!file) { - std::cerr << "[ResourceLoader] Error: no es pot obrir " << fullpath << "\n"; - return {}; + // Comprovar si hay paquet carregat + auto Loader::isPackLoaded() const -> bool { + return pack_ != nullptr; } - std::streamsize file_size = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector data(file_size); - if (!file.read(reinterpret_cast(data.data()), file_size)) { - std::cerr << "[ResourceLoader] Error: no es pot llegir " << fullpath << "\n"; - return {}; + // Establir la ruta base + void Loader::setBasePath(const std::string& path) { + base_path_ = path; + std::cout << "[ResourceLoader] Ruta base establerta: " << base_path_ << "\n"; } - std::cout << "[ResourceLoader] Carregat des del sistema de archivos: " << fullpath << "\n"; - return data; -} + // Obtenir la ruta base + auto Loader::getBasePath() const -> const std::string& { + return base_path_; + } + + // Carregar des del sistema de archivos (fallback) + auto Loader::loadFromFilesystem(const std::string& filename) -> std::vector { + // The filename is already normalized (e.g., "shapes/logo/letra_j.shp") + // We need to prepend base_path + "data/" + std::string fullpath; + + if (base_path_.empty()) { + fullpath = "data/" + filename; + } else { + fullpath = base_path_ + "/data/" + filename; + } + + std::ifstream file(fullpath, std::ios::binary | std::ios::ate); + if (!file) { + std::cerr << "[ResourceLoader] Error: no es pot obrir " << fullpath << "\n"; + return {}; + } + + std::streamsize file_size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector data(file_size); + if (!file.read(reinterpret_cast(data.data()), file_size)) { + std::cerr << "[ResourceLoader] Error: no es pot llegir " << fullpath << "\n"; + return {}; + } + + std::cout << "[ResourceLoader] Carregat des del sistema de archivos: " << fullpath << "\n"; + return data; + } } // namespace Resource diff --git a/source/core/resources/resource_loader.hpp b/source/core/resources/resource_loader.hpp index c8ca4e2..bb85bef 100644 --- a/source/core/resources/resource_loader.hpp +++ b/source/core/resources/resource_loader.hpp @@ -12,9 +12,9 @@ namespace Resource { -// Singleton per gestionar la càrrega de recursos -class Loader { - public: + // Singleton per gestionar la càrrega de recursos + class Loader { + public: // Singleton static auto get() -> Loader&; @@ -25,6 +25,11 @@ class Loader { auto loadResource(const std::string& filename) -> std::vector; auto resourceExists(const std::string& filename) -> bool; + // Llistat de recursos amb prefix (ex. "shapes/", "sounds/"). Si hi ha + // pack, retorna els fitxers del pack filtrats; si no, escaneja el + // sistema de fitxers recursivament a `data/`. + auto listResources(const std::string& prefix) -> std::vector; + // Validació auto validatePack() -> bool; [[nodiscard]] auto isPackLoaded() const -> bool; @@ -37,7 +42,7 @@ class Loader { Loader(const Loader&) = delete; auto operator=(const Loader&) -> Loader& = delete; - private: + private: Loader() = default; ~Loader() = default; @@ -48,6 +53,6 @@ class Loader { // Funciones auxiliars auto loadFromFilesystem(const std::string& filename) -> std::vector; -}; + }; } // namespace Resource diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index f85aa3c..36f8fd9 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -12,6 +12,7 @@ #include "core/audio/audio.hpp" #include "core/audio/audio_adapter.hpp" #include "core/defaults/window.hpp" +#include "core/graphics/shape_loader.hpp" #include "core/input/input.hpp" #include "core/input/mouse.hpp" #include "core/locale/locale.hpp" @@ -147,10 +148,21 @@ Director::Director(int argc, char* argv[]) Audio::init(AUDIO_CONFIG); Audio::get()->applySettings(AUDIO_CONFIG); - AudioResource::getMusic("title.ogg"); - AudioResource::getMusic("game.ogg"); + // Precàrrega blocant de tots els recursos al boot per evitar hits d'I/O i + // de decodificació en transicions (TITLE → GAME, primera explosió, etc.). + // Mateix patró que aee_arcade: iterem `listResources` i forcem la càrrega + // al cache de cada subsistema. + for (const auto& path : Resource::Helper::listResources("music/")) { + AudioResource::getMusic(path.substr(std::string_view{"music/"}.size())); + } + for (const auto& path : Resource::Helper::listResources("sounds/")) { + AudioResource::getSound(path.substr(std::string_view{"sounds/"}.size())); + } + for (const auto& path : Resource::Helper::listResources("shapes/")) { + Graphics::ShapeLoader::load(path.substr(std::string_view{"shapes/"}.size())); + } if (cfg_->console) { - std::cout << "Música precacheada\n"; + std::cout << "Recursos precachejats (música, sons, shapes)\n"; } context_ = std::make_unique();