diff --git a/resources.pack b/resources.pack index 57a7ef9..71e247e 100644 Binary files a/resources.pack and b/resources.pack differ diff --git a/source/engine.cpp b/source/engine.cpp index 48b0f4c..324bce5 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -17,6 +17,8 @@ #include // for cout #include // for string +#include "resource_manager.h" // for ResourceManager + #ifdef _WIN32 #include // for GetModuleFileName #endif @@ -164,9 +166,9 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen, AppMod } } } else { - // Fallback: cargar texturas desde pack usando la lista del ResourcePack - if (Texture::isPackLoaded()) { - auto pack_resources = Texture::getPackResourceList(); + // Fallback: cargar texturas desde pack usando la lista del ResourceManager + if (ResourceManager::isPackLoaded()) { + auto pack_resources = ResourceManager::getResourceList(); // Filtrar solo los recursos en balls/ con extensión .png for (const auto& resource : pack_resources) { diff --git a/source/external/texture.cpp b/source/external/texture.cpp index 0d8df3e..bd6ea20 100644 --- a/source/external/texture.cpp +++ b/source/external/texture.cpp @@ -12,38 +12,7 @@ #include // Para operator<<, string #include "stb_image.h" // Para stbi_failure_reason, stbi_image_free -#include "../resource_pack.h" // Sistema de empaquetado de recursos - -// Instancia global de ResourcePack (se inicializa al primer uso) -static ResourcePack* g_resourcePack = nullptr; - -// Inicializar el sistema de recursos (llamar desde main antes de cargar texturas) -void Texture::initResourceSystem(const std::string& packFilePath) { - if (g_resourcePack == nullptr) { - g_resourcePack = new ResourcePack(); - if (!g_resourcePack->loadPack(packFilePath)) { - // Si falla, borrar instancia (usará fallback a disco) - delete g_resourcePack; - g_resourcePack = nullptr; - std::cout << "resources.pack no encontrado - usando carpeta data/" << std::endl; - } else { - std::cout << "resources.pack cargado (" << g_resourcePack->getResourceCount() << " recursos)" << std::endl; - } - } -} - -// Obtener lista de recursos disponibles en el pack -std::vector Texture::getPackResourceList() { - if (g_resourcePack != nullptr) { - return g_resourcePack->getResourceList(); - } - return std::vector(); // Vacío si no hay pack -} - -// Verificar si el pack está cargado -bool Texture::isPackLoaded() { - return g_resourcePack != nullptr; -} +#include "../resource_manager.h" // Sistema de empaquetado de recursos centralizado Texture::Texture(SDL_Renderer *renderer) : renderer_(renderer), @@ -70,30 +39,29 @@ bool Texture::loadFromFile(const std::string &file_path) { int width, height, orig_format; unsigned char *data = nullptr; - // 1. Intentar cargar desde pack (si está inicializado) - if (g_resourcePack != nullptr) { - ResourcePack::ResourceData packData = g_resourcePack->loadResource(file_path); - if (packData.data != nullptr) { - // Descodificar imagen desde memoria usando stb_image - data = stbi_load_from_memory(packData.data, static_cast(packData.size), - &width, &height, &orig_format, req_format); - delete[] packData.data; // Liberar buffer temporal del pack + // 1. Intentar cargar desde ResourceManager (pack o disco) + unsigned char* resourceData = nullptr; + size_t resourceSize = 0; - if (data != nullptr) { + if (ResourceManager::loadResource(file_path, resourceData, resourceSize)) { + // Descodificar imagen desde memoria usando stb_image + data = stbi_load_from_memory(resourceData, static_cast(resourceSize), + &width, &height, &orig_format, req_format); + delete[] resourceData; // Liberar buffer temporal + + if (data != nullptr) { + if (ResourceManager::isPackLoaded()) { std::cout << "Imagen cargada desde pack: " << filename.c_str() << std::endl; + } else { + std::cout << "Imagen cargada desde disco: " << filename.c_str() << std::endl; } } } - // 2. Fallback: cargar desde disco (modo desarrollo) + // 2. Si todo falla, error if (data == nullptr) { - data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format); - if (data == nullptr) { - SDL_Log("Error al cargar la imagen: %s", stbi_failure_reason()); - exit(1); - } else { - std::cout << "Imagen cargada desde disco: " << filename.c_str() << std::endl; - } + SDL_Log("Error al cargar la imagen: %s", stbi_failure_reason()); + exit(1); } int pitch; diff --git a/source/external/texture.h b/source/external/texture.h index dc91634..bbfd014 100644 --- a/source/external/texture.h +++ b/source/external/texture.h @@ -16,11 +16,6 @@ class Texture { int height_; public: - // Sistema de recursos empaquetados (inicializar desde main) - static void initResourceSystem(const std::string& packFilePath); - static std::vector getPackResourceList(); - static bool isPackLoaded(); - // Inicializa las variables explicit Texture(SDL_Renderer *renderer); Texture(SDL_Renderer *renderer, const std::string &file_path); diff --git a/source/logo_scaler.cpp b/source/logo_scaler.cpp index 2601837..4caee9a 100644 --- a/source/logo_scaler.cpp +++ b/source/logo_scaler.cpp @@ -13,6 +13,7 @@ #include "external/stb_image.h" // Para stbi_load, stbi_image_free #include "external/stb_image_resize2.h" // Para stbir_resize_uint8_srgb +#include "resource_manager.h" // Para cargar desde pack // ============================================================================ // Detectar resolución nativa del monitor principal @@ -51,10 +52,22 @@ bool LogoScaler::detectNativeResolution(int& native_width, int& native_height) { unsigned char* LogoScaler::loadAndScale(const std::string& path, int target_width, int target_height, int& out_width, int& out_height) { - // 1. Cargar imagen original con stb_image + // 1. Intentar cargar imagen desde ResourceManager (pack o disco) int orig_width, orig_height, orig_channels; - unsigned char* orig_data = stbi_load(path.c_str(), &orig_width, &orig_height, &orig_channels, STBI_rgb_alpha); + unsigned char* orig_data = nullptr; + // 1a. Cargar desde ResourceManager + unsigned char* resourceData = nullptr; + size_t resourceSize = 0; + + if (ResourceManager::loadResource(path, resourceData, resourceSize)) { + // Descodificar imagen desde memoria usando stb_image + orig_data = stbi_load_from_memory(resourceData, static_cast(resourceSize), + &orig_width, &orig_height, &orig_channels, STBI_rgb_alpha); + delete[] resourceData; // Liberar buffer temporal + } + + // 1b. Si falla todo, error if (orig_data == nullptr) { SDL_Log("Error al cargar imagen %s: %s", path.c_str(), stbi_failure_reason()); return nullptr; diff --git a/source/main.cpp b/source/main.cpp index c67e624..9f8bbb8 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -3,6 +3,7 @@ #include #include "engine.h" #include "defines.h" +#include "resource_manager.h" // getExecutableDirectory() ya está definido en defines.h como inline @@ -108,7 +109,7 @@ int main(int argc, char* argv[]) { // Inicializar sistema de recursos empaquetados (intentar cargar resources.pack) std::string resources_dir = getResourcesDirectory(); std::string pack_path = resources_dir + "/resources.pack"; - Texture::initResourceSystem(pack_path); + ResourceManager::init(pack_path); Engine engine; diff --git a/source/resource_manager.cpp b/source/resource_manager.cpp new file mode 100644 index 0000000..b5efd7d --- /dev/null +++ b/source/resource_manager.cpp @@ -0,0 +1,91 @@ +#include "resource_manager.h" +#include "resource_pack.h" + +#include +#include + +// Inicializar el puntero estático +ResourcePack* ResourceManager::resourcePack_ = nullptr; + +bool ResourceManager::init(const std::string& packFilePath) { + // Si ya estaba inicializado, liberar primero + if (resourcePack_ != nullptr) { + delete resourcePack_; + resourcePack_ = nullptr; + } + + // Intentar cargar el pack + resourcePack_ = new ResourcePack(); + if (!resourcePack_->loadPack(packFilePath)) { + // Si falla, borrar instancia (usará fallback a disco) + delete resourcePack_; + resourcePack_ = nullptr; + std::cout << "resources.pack no encontrado - usando carpeta data/" << std::endl; + return false; + } + + std::cout << "resources.pack cargado (" << resourcePack_->getResourceCount() << " recursos)" << std::endl; + return true; +} + +void ResourceManager::shutdown() { + if (resourcePack_ != nullptr) { + delete resourcePack_; + resourcePack_ = nullptr; + } +} + +bool ResourceManager::loadResource(const std::string& resourcePath, unsigned char*& data, size_t& size) { + data = nullptr; + size = 0; + + // 1. Intentar cargar desde pack (si está disponible) + if (resourcePack_ != nullptr) { + ResourcePack::ResourceData packData = resourcePack_->loadResource(resourcePath); + if (packData.data != nullptr) { + data = packData.data; + size = packData.size; + return true; + } + } + + // 2. Fallback: cargar desde disco + std::ifstream file(resourcePath, std::ios::binary | std::ios::ate); + if (!file) { + // Intentar con "data/" como prefijo si no se encontró + std::string dataPath = "data/" + resourcePath; + file.open(dataPath, std::ios::binary | std::ios::ate); + if (!file) { + return false; + } + } + + // Obtener tamaño del archivo + size = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + + // Alocar buffer y leer + data = new unsigned char[size]; + file.read(reinterpret_cast(data), size); + file.close(); + + return true; +} + +bool ResourceManager::isPackLoaded() { + return resourcePack_ != nullptr; +} + +std::vector ResourceManager::getResourceList() { + if (resourcePack_ != nullptr) { + return resourcePack_->getResourceList(); + } + return std::vector(); // Vacío si no hay pack +} + +size_t ResourceManager::getResourceCount() { + if (resourcePack_ != nullptr) { + return resourcePack_->getResourceCount(); + } + return 0; +} diff --git a/source/resource_manager.h b/source/resource_manager.h new file mode 100644 index 0000000..4506756 --- /dev/null +++ b/source/resource_manager.h @@ -0,0 +1,85 @@ +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#include +#include + +class ResourcePack; + +/** + * ResourceManager - Gestor centralizado de recursos empaquetados + * + * Singleton que administra el sistema de recursos empaquetados (resources.pack) + * y proporciona fallback automático a disco cuando el pack no está disponible. + * + * Uso: + * // En main.cpp, antes de inicializar cualquier sistema: + * ResourceManager::init("resources.pack"); + * + * // Desde cualquier clase que necesite recursos: + * unsigned char* data = nullptr; + * size_t size = 0; + * if (ResourceManager::loadResource("textures/ball.png", data, size)) { + * // Usar datos... + * delete[] data; // Liberar cuando termine + * } + */ +class ResourceManager { +public: + /** + * Inicializa el sistema de recursos empaquetados + * Debe llamarse una única vez al inicio del programa + * + * @param packFilePath Ruta al archivo .pack (ej: "resources.pack") + * @return true si el pack se cargó correctamente, false si no existe (fallback a disco) + */ + static bool init(const std::string& packFilePath); + + /** + * Libera el sistema de recursos + * Opcional - se llama automáticamente al cerrar el programa + */ + static void shutdown(); + + /** + * Carga un recurso desde el pack (o disco si no existe pack) + * + * @param resourcePath Ruta relativa del recurso (ej: "textures/ball.png") + * @param data [out] Puntero donde se almacenará el buffer (debe liberar con delete[]) + * @param size [out] Tamaño del buffer en bytes + * @return true si se cargó correctamente, false si falla + */ + static bool loadResource(const std::string& resourcePath, unsigned char*& data, size_t& size); + + /** + * Verifica si el pack está cargado + * @return true si hay un pack cargado, false si se usa disco + */ + static bool isPackLoaded(); + + /** + * Obtiene la lista de recursos disponibles en el pack + * @return Vector con las rutas de todos los recursos, vacío si no hay pack + */ + static std::vector getResourceList(); + + /** + * Obtiene el número de recursos en el pack + * @return Número de recursos, 0 si no hay pack + */ + static size_t getResourceCount(); + +private: + // Constructor privado (singleton) + ResourceManager() = default; + ~ResourceManager() = default; + + // Deshabilitar copia y asignación + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(const ResourceManager&) = delete; + + // Instancia del pack (nullptr si no está cargado) + static ResourcePack* resourcePack_; +}; + +#endif // RESOURCE_MANAGER_H diff --git a/source/text/textrenderer.cpp b/source/text/textrenderer.cpp index ac30b9c..6dffae1 100644 --- a/source/text/textrenderer.cpp +++ b/source/text/textrenderer.cpp @@ -1,6 +1,7 @@ #include "textrenderer.h" #include #include +#include "../resource_manager.h" TextRenderer::TextRenderer() : renderer_(nullptr), font_(nullptr), font_size_(0), use_antialiasing_(true) { } @@ -23,7 +24,30 @@ bool TextRenderer::init(SDL_Renderer* renderer, const char* font_path, int font_ } } - // Cargar la fuente + // Intentar cargar la fuente desde ResourceManager (pack o disco) + unsigned char* fontData = nullptr; + size_t fontDataSize = 0; + + if (ResourceManager::loadResource(font_path, fontData, fontDataSize)) { + // Crear SDL_IOStream desde memoria + SDL_IOStream* fontIO = SDL_IOFromConstMem(fontData, static_cast(fontDataSize)); + if (fontIO != nullptr) { + // Cargar fuente desde IOStream + font_ = TTF_OpenFontIO(fontIO, true, font_size); // true = cerrar stream automáticamente + delete[] fontData; // Liberar buffer temporal después de crear el stream + + if (font_ == nullptr) { + SDL_Log("Error al cargar fuente desde memoria '%s': %s", font_path, SDL_GetError()); + return false; + } + + return true; + } else { + delete[] fontData; + } + } + + // Fallback final: intentar cargar directamente desde disco (por si falla ResourceManager) font_ = TTF_OpenFont(font_path, font_size); if (font_ == nullptr) { SDL_Log("Error al cargar fuente '%s': %s", font_path, SDL_GetError()); @@ -51,7 +75,30 @@ bool TextRenderer::reinitialize(int new_font_size) { font_ = nullptr; } - // Cargar fuente con nuevo tamaño + // Intentar cargar la fuente desde ResourceManager con el nuevo tamaño + unsigned char* fontData = nullptr; + size_t fontDataSize = 0; + + if (ResourceManager::loadResource(font_path_, fontData, fontDataSize)) { + SDL_IOStream* fontIO = SDL_IOFromConstMem(fontData, static_cast(fontDataSize)); + if (fontIO != nullptr) { + font_ = TTF_OpenFontIO(fontIO, true, new_font_size); + delete[] fontData; + + if (font_ == nullptr) { + SDL_Log("Error al recargar fuente '%s' con tamaño %d: %s", + font_path_.c_str(), new_font_size, SDL_GetError()); + return false; + } + + font_size_ = new_font_size; + return true; + } else { + delete[] fontData; + } + } + + // Fallback: cargar directamente desde disco font_ = TTF_OpenFont(font_path_.c_str(), new_font_size); if (font_ == nullptr) { SDL_Log("Error al recargar fuente '%s' con tamaño %d: %s", @@ -59,9 +106,7 @@ bool TextRenderer::reinitialize(int new_font_size) { return false; } - // Actualizar tamaño almacenado font_size_ = new_font_size; - return true; }