diff --git a/source/director.cpp b/source/director.cpp index f26feba..636b63f 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -59,14 +59,11 @@ Director::Director(int argc, const char* argv[]) { // Carga las opciones desde un fichero loadOptionsFromFile(Asset::get()->get("config.txt")); - // Inicializa SDL - initSDL(); - // Inicializa JailAudio initJailAudio(); // Crea los objetos - Screen::init(window_, renderer_); + Screen::init(); SDL_HideCursor(); Resource::init(); Notifier::init("", "8bithud"); @@ -90,8 +87,6 @@ Director::~Director() { Screen::destroy(); Asset::destroy(); - SDL_DestroyRenderer(renderer_); - SDL_DestroyWindow(window_); SDL_Quit(); std::cout << "\nBye!" << std::endl; @@ -256,77 +251,6 @@ void Director::initJailAudio() { } } -// Arranca SDL y crea la ventana -bool Director::initSDL() { - // Indicador de éxito - bool success = true; - - // Inicializa SDL - if (!SDL_Init(SDL_INIT_VIDEO)) { - if (options.console) { - std::cout << "SDL could not initialize!\nSDL Error: " << SDL_GetError() << std::endl; - } - success = false; - } else { - // Inicia el generador de numeros aleatorios - std::srand(static_cast(SDL_GetTicks())); - - // Activa el render OpenGL - if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) { - std::cout << "Warning: opengl not enabled!\n"; - } - - // Crea la ventana - const auto WINDOW_WIDTH = options.video.border.enabled ? options.game.width + options.video.border.width * 2 : options.game.width; - const auto WINDOW_HEIGHT = options.video.border.enabled ? options.game.height + options.video.border.height * 2 : options.game.height; - -#ifdef __APPLE__ - SDL_WindowFlags window_flags = SDL_WINDOW_METAL; -#else - SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL; -#endif - if (options.video.fullscreen) { - window_flags |= SDL_WINDOW_FULLSCREEN; - } - window_ = SDL_CreateWindow(WINDOW_CAPTION, WINDOW_WIDTH * options.window.zoom, WINDOW_HEIGHT * options.window.zoom, window_flags); - if (window_ == nullptr) { - if (options.console) { - std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl; - } - success = false; - } else { - // Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones - renderer_ = SDL_CreateRenderer(window_, nullptr); - if (renderer_ == nullptr) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "FATAL: Failed to create renderer! SDL Error: %s", - SDL_GetError()); - SDL_DestroyWindow(window_); - window_ = nullptr; - SDL_Quit(); - return false; - } else { - // Configurar renderer - const int EXTRA_WIDTH = options.video.border.enabled ? options.video.border.width * 2 : 0; - const int EXTRA_HEIGHT = options.video.border.enabled ? options.video.border.height * 2 : 0; - SDL_SetRenderLogicalPresentation( - renderer_, - options.game.width + EXTRA_WIDTH, - options.game.height + EXTRA_HEIGHT, - options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX); - SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF); - SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); - SDL_SetRenderVSync(renderer_, options.video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED); - } - } - } - - if (options.console) { - std::cout << std::endl; - } - return success; -} - // Crea el indice de ficheros bool Director::setFileList() { #ifdef MACOS_BUNDLE diff --git a/source/director.h b/source/director.h index 0b06b53..f0e118a 100644 --- a/source/director.h +++ b/source/director.h @@ -6,10 +6,6 @@ class Director { private: - // Objetos y punteros - SDL_Window* window_; // La ventana donde dibujamos - SDL_Renderer* renderer_; // El renderizador de la ventana - // Variables std::string executable_path_; // Path del ejecutable std::string system_folder_; // Carpeta del sistema donde guardar datos @@ -23,10 +19,7 @@ class Director { // Inicializa jail_audio void initJailAudio(); - // Arranca SDL y crea la ventana - bool initSDL(); - - // Inicializa el objeto Input + // Inicializa el objeto Input void initInput(); // Crea el indice de ficheros diff --git a/source/options.h b/source/options.h index 39d75e0..0e81ead 100644 --- a/source/options.h +++ b/source/options.h @@ -208,8 +208,9 @@ struct OptionsStats { // Estructura con opciones de la ventana struct OptionsWindow { - int zoom; // Zoom de la ventana - int max_zoom; // Máximo tamaño de zoom para la ventana + std::string caption = "JailDoctor's Dilemma"; // Texto que aparece en la barra de título de la ventana + int zoom; // Zoom de la ventana + int max_zoom; // Máximo tamaño de zoom para la ventana // Constructor por defecto OptionsWindow() diff --git a/source/screen.cpp b/source/screen.cpp index 9a9ac94..d40c57d 100644 --- a/source/screen.cpp +++ b/source/screen.cpp @@ -22,8 +22,8 @@ Screen* Screen::screen_ = nullptr; // [SINGLETON] Crearemos el objeto con esta función estática -void Screen::init(SDL_Window* window, SDL_Renderer* renderer) { - Screen::screen_ = new Screen(window, renderer); +void Screen::init() { + Screen::screen_ = new Screen(); } // [SINGLETON] Destruiremos el objeto con esta función estática @@ -37,12 +37,10 @@ Screen* Screen::get() { } // Constructor -Screen::Screen(SDL_Window* window, SDL_Renderer* renderer) - : window_(window), - renderer_(renderer), - palettes_(Asset::get()->getListByType(AssetType::PALETTE)) { - // Inicializa variables - getDisplayInfo(); +Screen::Screen() + : palettes_(Asset::get()->getListByType(AssetType::PALETTE)) { + // Arranca SDL VIDEO, crea la ventana y el renderizador + initSDLVideo(); // Ajusta los tamaños game_surface_dstrect_ = {options.video.border.width, options.video.border.height, options.game.width, options.game.height}; @@ -97,14 +95,19 @@ Screen::Screen(SDL_Window* window, SDL_Renderer* renderer) // Establece la surface que actuará como renderer para recibir las llamadas a render() renderer_surface_ = std::make_shared>(game_surface_); - // Establece el modo de video - setVideoMode(options.video.fullscreen); - // Muestra la ventana show(); // Extrae el nombre de las paletas desde su ruta processPaletteList(); + + // Renderizar una vez la textura vacía para que tenga contenido válido + // antes de inicializar los shaders (evita pantalla negra) + SDL_RenderTexture(renderer_, game_texture_, nullptr, nullptr); + SDL_RenderTexture(renderer_, border_texture_, nullptr, nullptr); + + // Ahora sí inicializar los shaders + initShaders(); } // Destructor @@ -195,8 +198,9 @@ void Screen::setBorderColor(Uint8 color) { // Cambia entre borde visible y no visible void Screen::toggleBorder() { options.video.border.enabled = !options.video.border.enabled; - createShadersTexture(); setVideoMode(options.video.fullscreen); + //createShadersTexture(); + initShaders(); } // Dibuja las notificaciones @@ -209,7 +213,7 @@ void Screen::renderNotifications() { // Cambia el estado de los shaders void Screen::toggleShaders() { options.video.shaders = !options.video.shaders; - setVideoMode(options.video.fullscreen); + initShaders(); } // Actualiza la lógica de la clase @@ -224,7 +228,6 @@ void Screen::adjustWindowSize() { window_width_ = options.game.width + (options.video.border.enabled ? options.video.border.width * 2 : 0); window_height_ = options.game.height + (options.video.border.enabled ? options.video.border.height * 2 : 0); - // Establece el nuevo tamaño if (options.video.fullscreen == 0) { int old_width, old_height; @@ -476,7 +479,8 @@ void Screen::initShaders() { if (!shader_backend_) { shader_backend_ = std::make_unique(); } - shader_backend_->init(window_, game_texture_, vertex_shader_source_, fragment_shader_source_); + shader_backend_->init(window_, options.video.border.enabled ? border_texture_ : game_texture_, vertex_shader_source_, fragment_shader_source_); + //shader_backend_->init(window_, shaders_texture_, vertex_shader_source_, fragment_shader_source_); } #else // En macOS, OpenGL está deprecated y rinde mal @@ -490,19 +494,19 @@ void Screen::initShaders() { void Screen::getDisplayInfo() { int i; int num_displays = 0; - SDL_DisplayID *displays = SDL_GetDisplays(&num_displays); + SDL_DisplayID* displays = SDL_GetDisplays(&num_displays); if (displays != nullptr) { for (i = 0; i < num_displays; ++i) { SDL_DisplayID instance_id = displays[i]; - const char *name = SDL_GetDisplayName(instance_id); + const char* name = SDL_GetDisplayName(instance_id); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Display %" SDL_PRIu32 ": %s", instance_id, (name != nullptr) ? name : "Unknown"); } - const auto *dm = SDL_GetCurrentDisplayMode(displays[0]); + const auto* dm = SDL_GetCurrentDisplayMode(displays[0]); // Guarda información del monitor en display_monitor_ - const char *first_display_name = SDL_GetDisplayName(displays[0]); + const char* first_display_name = SDL_GetDisplayName(displays[0]); display_monitor_.name = (first_display_name != nullptr) ? first_display_name : "Unknown"; display_monitor_.width = static_cast(dm->w); display_monitor_.height = static_cast(dm->h); @@ -529,4 +533,91 @@ void Screen::getDisplayInfo() { SDL_free(displays); } +} + +// Arranca SDL VIDEO y crea la ventana +auto Screen::initSDLVideo() -> bool { + // Inicializar SDL + if (!SDL_Init(SDL_INIT_VIDEO)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "FATAL: Failed to initialize SDL_VIDEO! SDL Error: %s", + SDL_GetError()); + return false; + } + + // Obtener información de la pantalla + getDisplayInfo(); + + // Configurar hint para renderizado +#ifdef __APPLE__ + if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal")) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Warning: Failed to set Metal hint!"); + } +#else + // Configurar hint de render driver + if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Warning: Failed to set OpenGL hint!"); + } + +#ifdef _WIN32 + // Windows: Pedir explícitamente OpenGL 3.3 Core Profile + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Solicitando OpenGL 3.3 Core Profile"); +#else + // Linux: Dejar que SDL elija (Desktop 3.3 en PC, ES 3.0 en RPi automáticamente) + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Usando OpenGL por defecto del sistema"); +#endif +#endif + + // Crear ventana + const auto WINDOW_WIDTH = options.video.border.enabled ? options.game.width + options.video.border.width * 2 : options.game.width; + const auto WINDOW_HEIGHT = options.video.border.enabled ? options.game.height + options.video.border.height * 2 : options.game.height; +#ifdef __APPLE__ + SDL_WindowFlags window_flags = SDL_WINDOW_METAL; +#else + SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL; +#endif + if (options.video.fullscreen) { + window_flags |= SDL_WINDOW_FULLSCREEN; + } + window_ = SDL_CreateWindow(options.window.caption.c_str(), WINDOW_WIDTH * options.window.zoom, WINDOW_HEIGHT * options.window.zoom, window_flags); + + if (window_ == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "FATAL: Failed to create window! SDL Error: %s", + SDL_GetError()); + SDL_Quit(); + return false; + } + + // Crear renderer + renderer_ = SDL_CreateRenderer(window_, nullptr); + if (renderer_ == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "FATAL: Failed to create renderer! SDL Error: %s", + SDL_GetError()); + SDL_DestroyWindow(window_); + window_ = nullptr; + SDL_Quit(); + return false; + } + + // Configurar renderer + const int EXTRA_WIDTH = options.video.border.enabled ? options.video.border.width * 2 : 0; + const int EXTRA_HEIGHT = options.video.border.enabled ? options.video.border.height * 2 : 0; + SDL_SetRenderLogicalPresentation( + renderer_, + options.game.width + EXTRA_WIDTH, + options.game.height + EXTRA_HEIGHT, + options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX); + SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF); + SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); + SDL_SetRenderVSync(renderer_, options.video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED); + + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Video system initialized successfully"); + return true; } \ No newline at end of file diff --git a/source/screen.h b/source/screen.h index 21ed88b..63253fe 100644 --- a/source/screen.h +++ b/source/screen.h @@ -24,7 +24,6 @@ class Screen { // Constantes static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana - struct DisplayMonitor { std::string name; int width; @@ -121,24 +120,21 @@ class Screen { // Recrea la textura para los shaders void createShadersTexture(); - void initShaders(); // Inicializa los shaders - void loadShaders(); // Carga el contenido del archivo GLSL - - // Muestra información por pantalla - void renderInfo(); - - // Obtiene información sobre la pantalla - void getDisplayInfo(); + void initShaders(); // Inicializa los shaders + void loadShaders(); // Carga el contenido del archivo GLSL + void renderInfo(); // Muestra información por pantalla + void getDisplayInfo(); // Obtiene información sobre la pantalla + auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana // Constructor - Screen(SDL_Window* window, SDL_Renderer* renderer); + Screen(); // Destructor ~Screen(); public: // [SINGLETON] Crearemos el objeto con esta función estática - static void init(SDL_Window* window, SDL_Renderer* renderer); + static void init(); // [SINGLETON] Destruiremos el objeto con esta función estática static void destroy();