Refactorizar sistema de recursos: crear ResourceManager centralizado
- Crear ResourceManager singleton para gestión centralizada de recursos - Separar lógica de ResourcePack de la clase Texture - Adaptar TextRenderer para cargar fuentes TTF desde pack - Adaptar LogoScaler para cargar imágenes PNG desde pack - Actualizar main.cpp y engine.cpp para usar ResourceManager - Regenerar resources.pack con fuentes y logos incluidos Fixes: - Resuelve error de carga de fuentes desde disco - Resuelve error de carga de logos (can't fopen) - Implementa fallback automático a disco si no existe pack - Todas las clases ahora pueden cargar recursos desde pack 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
BIN
resources.pack
BIN
resources.pack
Binary file not shown.
@@ -17,6 +17,8 @@
|
||||
#include <iostream> // for cout
|
||||
#include <string> // for string
|
||||
|
||||
#include "resource_manager.h" // for ResourceManager
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // 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) {
|
||||
|
||||
66
source/external/texture.cpp
vendored
66
source/external/texture.cpp
vendored
@@ -12,38 +12,7 @@
|
||||
#include <string> // 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<std::string> Texture::getPackResourceList() {
|
||||
if (g_resourcePack != nullptr) {
|
||||
return g_resourcePack->getResourceList();
|
||||
}
|
||||
return std::vector<std::string>(); // 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<int>(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<int>(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;
|
||||
|
||||
5
source/external/texture.h
vendored
5
source/external/texture.h
vendored
@@ -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<std::string> getPackResourceList();
|
||||
static bool isPackLoaded();
|
||||
|
||||
// Inicializa las variables
|
||||
explicit Texture(SDL_Renderer *renderer);
|
||||
Texture(SDL_Renderer *renderer, const std::string &file_path);
|
||||
|
||||
@@ -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<int>(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;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#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;
|
||||
|
||||
|
||||
91
source/resource_manager.cpp
Normal file
91
source/resource_manager.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "resource_manager.h"
|
||||
#include "resource_pack.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
// 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<size_t>(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Alocar buffer y leer
|
||||
data = new unsigned char[size];
|
||||
file.read(reinterpret_cast<char*>(data), size);
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResourceManager::isPackLoaded() {
|
||||
return resourcePack_ != nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> ResourceManager::getResourceList() {
|
||||
if (resourcePack_ != nullptr) {
|
||||
return resourcePack_->getResourceList();
|
||||
}
|
||||
return std::vector<std::string>(); // Vacío si no hay pack
|
||||
}
|
||||
|
||||
size_t ResourceManager::getResourceCount() {
|
||||
if (resourcePack_ != nullptr) {
|
||||
return resourcePack_->getResourceCount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
85
source/resource_manager.h
Normal file
85
source/resource_manager.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef RESOURCE_MANAGER_H
|
||||
#define RESOURCE_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<std::string> 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
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "textrenderer.h"
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
#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<size_t>(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<size_t>(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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user