diff --git a/source/director.cpp b/source/director.cpp index bc25de3..74b96ec 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -305,12 +305,12 @@ bool Director::initSDL() SDL_GetCurrentDisplayMode(0, &DM); // Calcula el máximo factor de zoom que se puede aplicar a la pantalla - options.video.window.max_size = std::min(DM.w / param.game.width, DM.h / param.game.height); - options.video.window.size = std::min(options.video.window.size, options.video.window.max_size); + options.video.window.max_zoom = std::min(DM.w / param.game.width, DM.h / param.game.height); + options.video.window.zoom = std::min(options.video.window.zoom, options.video.window.max_zoom); // Muestra información sobre el tamaño de la pantalla y de la ventana de juego std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl; - std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl; + std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.zoom << std::endl; // Establece el filtro de la textura if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(static_cast(options.video.filter)).c_str())) @@ -324,7 +324,7 @@ bool Director::initSDL() } // Crea la ventana - window_ = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, param.game.width * options.video.window.size, param.game.height * options.video.window.size, SDL_WINDOW_HIDDEN); + window_ = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, param.game.width * options.video.window.zoom, param.game.height * options.video.window.zoom, SDL_WINDOW_HIDDEN); if (!window_) { std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl; @@ -354,6 +354,7 @@ bool Director::initSDL() SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF); SDL_RenderSetLogicalSize(renderer_, param.game.width, param.game.height); SDL_RenderSetIntegerScale(renderer_, static_cast(options.video.integer_scale)); + SDL_SetWindowFullscreen(window_, static_cast(options.video.mode)); SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); } } diff --git a/source/global_inputs.cpp b/source/global_inputs.cpp index d1752c9..dcfd169 100644 --- a/source/global_inputs.cpp +++ b/source/global_inputs.cpp @@ -172,18 +172,20 @@ namespace globalInputs // Comprueba el teclado para decrementar el tamaño de la ventana if (Input::get()->checkInput(InputType::WINDOW_DEC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { - Screen::get()->decWindowSize(); - const std::string size = std::to_string(options.video.window.size); - Notifier::get()->show({"Window size x" + size}); + if (Screen::get()->decWindowZoom()) + { + Notifier::get()->show({"Window zoom x" + std::to_string(options.video.window.zoom)}); + } return; } // Comprueba el teclado para incrementar el tamaño de la ventana if (Input::get()->checkInput(InputType::WINDOW_INC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) { - Screen::get()->incWindowSize(); - const std::string size = std::to_string(options.video.window.size); - Notifier::get()->show({"Window size x" + size}); + if (Screen::get()->incWindowZoom()) + { + Notifier::get()->show({"Window zoom x" + std::to_string(options.video.window.zoom)}); + } return; } #endif diff --git a/source/options.cpp b/source/options.cpp index c7f1910..30ae5bd 100644 --- a/source/options.cpp +++ b/source/options.cpp @@ -25,7 +25,7 @@ void initOptions() options.video.window.size = 3; #else options.video.mode = ScreenVideoMode::WINDOW; - options.video.window.size = 2; + options.video.window.zoom = 2; #endif options.video.filter = ScreenFilter::NEAREST; options.video.v_sync = true; @@ -105,7 +105,7 @@ bool loadOptionsFile(std::string file_path) options.video.mode = ScreenVideoMode::WINDOW; } - options.video.window.size = std::clamp(options.video.window.size, 1, 4); + options.video.window.zoom = std::clamp(options.video.window.zoom, 1, 4); if (options.game.language != lang::Code::en_UK && options.game.language != lang::Code::ba_BA && @@ -137,7 +137,7 @@ bool saveOptionsFile(std::string file_path) file << "\n"; file << "video.mode=" << static_cast(options.video.mode) << "\n"; - file << "video.window.size=" << options.video.window.size << "\n"; + file << "video.window.size=" << options.video.window.zoom << "\n"; file << "video.filter=" << static_cast(options.video.filter) << "\n"; file << "video.v_sync=" << boolToString(options.video.v_sync) << "\n"; file << "video.integer_scale=" << boolToString(options.video.integer_scale) << "\n"; @@ -204,10 +204,10 @@ bool setOptions(const std::string &var, const std::string &value) } else if (var == "video.window.size") { - options.video.window.size = std::stoi(value); - if ((options.video.window.size < 1) || (options.video.window.size > 4)) + options.video.window.zoom = std::stoi(value); + if ((options.video.window.zoom < 1) || (options.video.window.zoom > 4)) { - options.video.window.size = 3; + options.video.window.zoom = 3; } } else if (var == "video.filter") diff --git a/source/options.h b/source/options.h index bdcb54b..2fb6782 100644 --- a/source/options.h +++ b/source/options.h @@ -6,7 +6,7 @@ #include "input.h" // Para InputType, InputDeviceToUse #include "manage_hiscore_table.h" // Para HiScoreEntry enum class ScreenFilter : int; // lines 10-10 -enum class ScreenVideoMode : int; // lines 11-11 +enum class ScreenVideoMode : Uint32; // lines 11-11 namespace lang { enum class Code : int; @@ -23,8 +23,8 @@ enum class GameDifficulty // Estructura para las opciones de la ventana struct OptionsWindow { - int size = 1; // Contiene el valor por el que se multiplica el tamaño de la ventana - int max_size = 1; // Tamaño máximo para que el tamaño de la ventana no sea mayor que el tamaño de la pantalla + int zoom = 1; // Contiene el valor por el que se multiplica el tamaño de la ventana + int max_zoom = 1; // Tamaño máximo para que el tamaño de la ventana no sea mayor que el tamaño de la pantalla }; // Estructura con opciones para el video @@ -64,18 +64,18 @@ struct OptionsAudio // Estructura para las opciones del juego struct OptionsGame { - GameDifficulty difficulty; // Dificultad del juego - lang::Code language; // Idioma usado en el juego - bool autofire; // Indicador de autofire - std::vector hi_score_table; // Tabla de mejores puntuaciones - std::vector last_hi_score_entry = { -1, -1 }; // Inicialización directa con dos elementos en -1 + GameDifficulty difficulty; // Dificultad del juego + lang::Code language; // Idioma usado en el juego + bool autofire; // Indicador de autofire + std::vector hi_score_table; // Tabla de mejores puntuaciones + std::vector last_hi_score_entry = {-1, -1}; // Inicialización directa con dos elementos en -1 - // Método para reiniciar las últimas entradas de puntuación - void clear_last_hi_score_entries() - { - last_hi_score_entry[0] = -1; - last_hi_score_entry[1] = -1; - } + // Método para reiniciar las últimas entradas de puntuación + void clear_last_hi_score_entries() + { + last_hi_score_entry[0] = -1; + last_hi_score_entry[1] = -1; + } }; // Estructura para los controles del juego diff --git a/source/player.cpp b/source/player.cpp index ae0b8d8..b7c7394 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -11,6 +11,7 @@ #include "resource.h" #include "jail_audio.h" #include "stage.h" +#include // Constructor Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector> texture, const std::vector> &animations) diff --git a/source/screen.cpp b/source/screen.cpp index 02861b0..d41bbf5 100644 --- a/source/screen.cpp +++ b/source/screen.cpp @@ -21,22 +21,13 @@ 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(SDL_Window *window, SDL_Renderer *renderer) { Screen::screen_ = new Screen(window, renderer); } // [SINGLETON] Destruiremos el objeto con esta función estática -void Screen::destroy() -{ - delete Screen::screen_; -} +void Screen::destroy() { delete Screen::screen_; } // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él -Screen *Screen::get() -{ - return Screen::screen_; -} +Screen *Screen::get() { return Screen::screen_; } // Constructor Screen::Screen(SDL_Window *window, SDL_Renderer *renderer) @@ -51,18 +42,15 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer) SDL_GetCurrentDisplayMode(0, &DM); info_resolution_ = std::to_string(DM.w) + " X " + std::to_string(DM.h) + " AT " + std::to_string(DM.refresh_rate) + " HZ"; - // Establece el modo de video - setVideoMode(options.video.mode); + // Inicializa los shaders + initShaders(); // Muestra la ventana - SDL_ShowWindow(window_); + show(); } // Destructor -Screen::~Screen() -{ - SDL_DestroyTexture(game_canvas_); -} +Screen::~Screen() { SDL_DestroyTexture(game_canvas_); } // Limpia la pantalla void Screen::clean(Color color) @@ -72,24 +60,13 @@ void Screen::clean(Color color) } // Prepara para empezar a dibujar en la textura de juego -void Screen::start() -{ - SDL_SetRenderTarget(renderer_, game_canvas_); -} +void Screen::start() { SDL_SetRenderTarget(renderer_, game_canvas_); } // Vuelca el contenido del renderizador en pantalla void Screen::render() { - // Actualiza el contador de FPS - ++fps_counter_; - - // Dibuja efectos y elementos sobre el game_canvas_ - renderFlash(); - renderAttenuate(); - renderShake(); - OnScreenHelp::get()->render(); - renderInfo(); - Notifier::get()->render(); + // Renderiza todos los overlays y efectos + renderOverlays(); // Renderiza el contenido del game_canvas_ renderScreen(); @@ -98,65 +75,31 @@ void Screen::render() // Renderiza el contenido del game_canvas_ void Screen::renderScreen() { - // Restablece el objetivo de renderizado al buffer de pantalla predeterminado SDL_SetRenderTarget(renderer_, nullptr); clean(); if (options.video.shaders) { - // Aplica shaders y renderiza el contenido shader::render(); } else { - // Actualiza la pantalla con el contenido del buffer de renderizado SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr); SDL_RenderPresent(renderer_); } } // Establece el modo de video -void Screen::setVideoMode(ScreenVideoMode videoMode) +void Screen::setVideoMode(ScreenVideoMode video_mode) { - switch (options.video.mode) + // Actualiza las opciones + options.video.mode = video_mode; + + // Configura el modo de pantalla + Uint32 flags = SDL_GetWindowFlags(window_); + if (flags != static_cast(options.video.mode)) { - case ScreenVideoMode::WINDOW: - { - // Cambia a modo de ventana - SDL_SetWindowFullscreen(window_, 0); - - // Modifica el tamaño de la ventana - SDL_Point pos = getNewPosition(); - SDL_SetWindowSize(window_, param.game.width * options.video.window.size, param.game.height * options.video.window.size); - SDL_SetWindowPosition(window_, pos.x, pos.y); - - break; - } - - // Si está activo el modo de pantalla completa añade el borde - case ScreenVideoMode::FULLSCREEN: - { - // Aplica el modo de video - SDL_SetWindowFullscreen(window_, SDL_WINDOW_FULLSCREEN_DESKTOP); - - // Oculta el puntero - SDL_ShowCursor(SDL_DISABLE); - - break; - } - - default: - break; - } - - // Reinicia los shaders - if (options.video.shaders) - { - const std::string glsl_file = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl"; - std::ifstream f(Asset::get()->get(glsl_file).c_str()); - std::string source((std::istreambuf_iterator(f)), std::istreambuf_iterator()); - - shader::init(window_, game_canvas_, source.c_str()); + SDL_SetWindowFullscreen(window_, static_cast(options.video.mode)); } } @@ -164,43 +107,56 @@ void Screen::setVideoMode(ScreenVideoMode videoMode) void Screen::toggleVideoMode() { options.video.mode = options.video.mode == ScreenVideoMode::WINDOW ? ScreenVideoMode::FULLSCREEN : ScreenVideoMode::WINDOW; - setVideoMode(options.video.mode); + setVideoMode(); } // Cambia el tamaño de la ventana -void Screen::setWindowSize(int size) +void Screen::setWindowZoom(int zoom) { - options.video.window.size = size; - setVideoMode(ScreenVideoMode::WINDOW); + options.video.window.zoom = zoom; + adjustWindowSize(); } // Reduce el tamaño de la ventana -void Screen::decWindowSize() +bool Screen::decWindowZoom() { - --options.video.window.size; - options.video.window.size = std::max(options.video.window.size, 1); - setVideoMode(ScreenVideoMode::WINDOW); + if (options.video.mode == ScreenVideoMode::WINDOW) + { + const int PREVIOUS_ZOOM = options.video.window.zoom; + --options.video.window.zoom; + options.video.window.zoom = std::max(options.video.window.zoom, 1); + + if (options.video.window.zoom != PREVIOUS_ZOOM) + { + adjustWindowSize(); + return true; + } + } + + return false; } // Aumenta el tamaño de la ventana -void Screen::incWindowSize() +bool Screen::incWindowZoom() { - ++options.video.window.size; - options.video.window.size = std::min(options.video.window.size, options.video.window.max_size); - setVideoMode(ScreenVideoMode::WINDOW); -} + if (options.video.mode == ScreenVideoMode::WINDOW) + { + const int PREVIOUS_ZOOM = options.video.window.zoom; + ++options.video.window.zoom; + options.video.window.zoom = std::min(options.video.window.zoom, options.video.window.max_zoom); -// Cambia el color del borde -void Screen::setBorderColor(Color color) -{ - border_color_ = color; + if (options.video.window.zoom != PREVIOUS_ZOOM) + { + adjustWindowSize(); + return true; + } + } + + return false; } // Cambia el tipo de mezcla -void Screen::setBlendMode(SDL_BlendMode blendMode) -{ - SDL_SetRenderDrawBlendMode(renderer_, blendMode); -} +void Screen::setBlendMode(SDL_BlendMode blendMode) { SDL_SetRenderDrawBlendMode(renderer_, blendMode); } // Actualiza la lógica de la clase void Screen::update() @@ -260,10 +216,7 @@ void Screen::updateShakeEffect() } // Pone la pantalla de color -void Screen::flash(Color color, int lenght, int delay) -{ - flash_effect_ = FlashEffect(true, lenght, delay, color); -} +void Screen::flash(Color color, int lenght, int delay) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Actualiza y dibuja el efecto de flash en la pantalla void Screen::renderFlash() @@ -276,10 +229,7 @@ void Screen::renderFlash() } // Actualiza el efecto de flash -void Screen::updateFlash() -{ - flash_effect_.update(); -} +void Screen::updateFlash() { flash_effect_.update(); } // Atenua la pantalla void Screen::renderAttenuate() @@ -322,22 +272,14 @@ void Screen::renderShake() void Screen::toggleShaders() { options.video.shaders = !options.video.shaders; - setVideoMode(options.video.mode); - const std::string value = options.video.shaders ? "on" : "off"; - Notifier::get()->show({"Shaders " + value}); + Notifier::get()->show({"Shaders " + std::string(options.video.shaders ? "on" : "off")}); } // Activa / desactiva la información de debug -void Screen::toggleDebugInfo() -{ - show_info_ = !show_info_; -} +void Screen::toggleDebugInfo() { show_debug_info_ = !show_debug_info_; } // Atenua la pantalla -void Screen::attenuate(bool value) -{ - attenuate_effect_ = value; -} +void Screen::attenuate(bool value) { attenuate_effect_ = value; } // Calcula los frames por segundo void Screen::updateFPS() @@ -353,7 +295,7 @@ void Screen::updateFPS() // Muestra información por pantalla void Screen::renderInfo() { - if (show_info_) + if (show_debug_info_) { // FPS const std::string fpstext = std::to_string(fps_) + " FPS"; @@ -370,38 +312,77 @@ void Screen::renderInfo() } } -// Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño -SDL_Point Screen::getNewPosition() +// Reinicia los shaders +void Screen::initShaders() { - // Obtiene la posición actual de la ventana - SDL_Point current_position; - SDL_GetWindowPosition(window_, ¤t_position.x, ¤t_position.y); + if (options.video.shaders) + { + const std::string GLSL_FILE = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl"; + std::ifstream f(Asset::get()->get(GLSL_FILE).c_str()); + std::string source((std::istreambuf_iterator(f)), std::istreambuf_iterator()); - // Obtiene las dimensiones actuales de la ventana - int current_width, current_height; - SDL_GetWindowSize(window_, ¤t_width, ¤t_height); + shader::init(window_, game_canvas_, source.c_str()); + } +} - // Obtiene las dimesiones que tendrá la ventana - const int new_width = param.game.width * options.video.window.size; - const int new_height = param.game.height * options.video.window.size; +// Calcula el tamaño de la ventana +void Screen::adjustWindowSize() +{ + options.video.window.max_zoom = getMaxZoom(); - // Obtiene el centro de la ventana actual - SDL_Point center; - center.x = current_position.x + current_width / 2; - center.y = current_position.y + current_height / 2; + // Establece el nuevo tamaño + if (options.video.mode == ScreenVideoMode::WINDOW) + { + const int WIDTH = param.game.width * options.video.window.zoom; + const int HEIGHT = param.game.height * options.video.window.zoom; - // Calcula la nueva posición a partir del centro y las nuevas diemsiones - SDL_Point new_pos; - new_pos.x = center.x - new_width / 2; - new_pos.y = center.y - new_height / 2; + int old_width, old_height; + SDL_GetWindowSize(window_, &old_width, &old_height); - // Obtiene las dimensiones del escritorio + int old_pos_x, old_pos_y; + SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y); + + const int NEW_POS_X = old_pos_x + (old_width - WIDTH) / 2; + const int NEW_POS_Y = old_pos_y + (old_height - HEIGHT) / 2; + + SDL_Rect viewport = {0, 0, WIDTH, HEIGHT}; + SDL_RenderSetViewport(renderer_, &viewport); + + SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS_), std::max(NEW_POS_Y, 0)); + SDL_SetWindowSize(window_, WIDTH, HEIGHT); + } +} + +// Ajusta el tamaño lógico del renderizador +void Screen::adjustRenderLogicalSize() { SDL_RenderSetLogicalSize(renderer_, param.game.width, param.game.height); } + +// Obtiene el tamaño máximo de zoom posible para la ventana +int Screen::getMaxZoom() +{ + // Obtiene información sobre la pantalla SDL_DisplayMode DM; SDL_GetCurrentDisplayMode(0, &DM); - // Evita que la ventana quede fuera del escritorio - new_pos.x = std::clamp(new_pos.x, 30, DM.w - new_width); - new_pos.y = std::clamp(new_pos.y, 30, DM.h - new_height); + // Calcula el máximo factor de zoom que se puede aplicar a la pantalla + const int MAX_ZOOM = std::min(DM.w / param.game.width, (DM.h - WINDOWS_DECORATIONS_) / param.game.height); - return new_pos; + // Normaliza los valores de zoom + options.video.window.zoom = std::min(options.video.window.zoom, MAX_ZOOM); + + return MAX_ZOOM; +} + +// Renderiza todos los overlays y efectos +void Screen::renderOverlays() +{ + // Actualiza el contador de FPS + ++fps_counter_; + + // Dibuja efectos y elementos sobre el game_canvas_ + renderShake(); + renderFlash(); + renderAttenuate(); + OnScreenHelp::get()->render(); + renderInfo(); + Notifier::get()->render(); } \ No newline at end of file diff --git a/source/screen.h b/source/screen.h index 260419a..37bbb95 100644 --- a/source/screen.h +++ b/source/screen.h @@ -8,6 +8,7 @@ #include // Para string #include "param.h" // Para Param, ParamGame, param #include "utils.h" // Para Color +#include "options.h" enum class ScreenFilter : int { @@ -15,15 +16,18 @@ enum class ScreenFilter : int LINEAL = 1, }; -enum class ScreenVideoMode : int +enum class ScreenVideoMode : Uint32 { WINDOW = 0, - FULLSCREEN = 1, + FULLSCREEN = SDL_WINDOW_FULLSCREEN_DESKTOP, }; class Screen { private: + // Constantes + static constexpr int WINDOWS_DECORATIONS_ = 35; + // [SINGLETON] Objeto privado static Screen *screen_; @@ -35,7 +39,6 @@ private: // Variables SDL_Rect src_rect_; // Coordenadas de donde va a pillar la textura del juego para dibujarla SDL_Rect dst_rect_; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana - Color border_color_ = Color(); // Color del borde añadido a la textura de juego para rellenar la pantalla bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada Uint32 fps_ticks_ = 0; // Ticks para contar los frames por segundo int fps_counter_ = 0; // Contador de frames por segundo @@ -44,7 +47,7 @@ private: #ifdef DEBUG bool show_info_ = false; // Indica si ha de mostrar/ocultar la información de la pantalla #else - bool show_info_ = false; // Indica si ha de mostrar/ocultar la información de la pantalla + bool show_debug_info_ = false; // Indica si ha de mostrar/ocultar la información de la pantalla #endif struct FlashEffect @@ -107,12 +110,24 @@ private: // Muestra información por pantalla void renderInfo(); - // Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño - SDL_Point getNewPosition(); - // Selecciona y ejecuta el método de renderizado adecuado basado en la configuración de shaders void renderScreen(); + // Reinicia los shaders + void initShaders(); + + // Calcula el tamaño de la ventana + void adjustWindowSize(); + + // Ajusta el tamaño lógico del renderizador + void adjustRenderLogicalSize(); + + // Obtiene el tamaño máximo de zoom posible para la ventana + int getMaxZoom(); + + // Renderiza todos los overlays y efectos + void renderOverlays(); + // Constructor Screen(SDL_Window *window, SDL_Renderer *renderer); @@ -142,22 +157,19 @@ public: void render(); // Establece el modo de video - void setVideoMode(ScreenVideoMode video_mode); + void setVideoMode(ScreenVideoMode video_mode = options.video.mode); // Cambia entre pantalla completa y ventana void toggleVideoMode(); // Cambia el tamaño de la ventana - void setWindowSize(int size); + void setWindowZoom(int size); // Reduce el tamaño de la ventana - void decWindowSize(); + bool decWindowZoom(); // Aumenta el tamaño de la ventana - void incWindowSize(); - - // Cambia el color del borde - void setBorderColor(Color color); + bool incWindowZoom(); // Cambia el tipo de mezcla void setBlendMode(SDL_BlendMode blend_mode); @@ -179,4 +191,10 @@ public: // Getters SDL_Renderer *getRenderer() { return renderer_; } + + // Muestra la ventana + void show() { SDL_ShowWindow(window_); } + + // Oculta la ventana + void hide() { SDL_HideWindow(window_); } }; \ No newline at end of file