#pragma once #include // Para SDL_FRect, SDL_HideWindow, SDL_Renderer, SDL_ShowWindow, Uint32, SDL_Texture, SDL_Window #include // Para shared_ptr #include // Para basic_string, string #include "options.h" // Para VideoOptions, video #include "utils.h" // Para Color class Notifier; class ServiceMenu; class Text; // Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales class Screen { public: // --- Métodos de singleton --- static void init(); // Inicializa el objeto Screen static void destroy(); // Libera el objeto Screen static Screen *get(); // Obtiene el puntero al objeto Screen // --- Métodos principales --- void update(); // Actualiza la lógica de la clase void coreUpdate(); // Actualiza los elementos mínimos void clean(Color color = Color(0x00, 0x00, 0x00)); // Limpia la pantalla void start(); // Prepara para empezar a dibujar en la textura de juego void render(); // Vuelca el contenido del renderizador en pantalla void coreRender(); // Vuelca el contenido del renderizador en pantalla exceptuando ciertas partes // --- Configuración de ventana y render --- void setFullscreenMode(); // Establece el modo de pantalla completa void toggleFullscreen(); // Cambia entre pantalla completa y ventana void setWindowZoom(int size); // Cambia el tamaño de la ventana bool decWindowSize(); // Reduce el tamaño de la ventana bool incWindowSize(); // Aumenta el tamaño de la ventana void applySettings(); // Aplica los valores de las opciones void initShaders(); // Inicializa los shaders // --- Efectos visuales --- void shake(int desp = 2, int delay = 3, int lenght = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, lenght); } // Agita la pantalla void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Pone la pantalla de color void toggleShaders(); // Alterna entre activar y desactivar los shaders void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero void toggleVSync(); // Alterna entre activar y desactivar el V-Sync void setVSync(bool enabled); // Establece el estado del V-Sync void attenuate(bool value) { attenuate_effect_ = value; } // Atenúa la pantalla // --- Getters --- SDL_Renderer *getRenderer() { return renderer_; } // Obtiene el renderizador void show() { SDL_ShowWindow(window_); } // Muestra la ventana void hide() { SDL_HideWindow(window_); } // Oculta la ventana void getSingletons(); // Obtiene los punteros a los singletones bool getVSync() const { return Options::video.v_sync; } // Obtiene el valor de V-Sync std::shared_ptr getText() const { return text_; } // Obtiene el puntero al texto de Screen #ifdef DEBUG // --- Debug --- void toggleDebugInfo() { debug_info_.show = !debug_info_.show; } void setDebugInfoEnabled(bool value) { debug_info_.show = value; } #endif private: // --- Constantes --- static constexpr int WINDOWS_DECORATIONS_ = 35; // --- Estructuras internas --- struct FPS { Uint32 ticks; // Tiempo en milisegundos desde que se comenzó a contar. int frameCount; // Número acumulado de frames en el intervalo. int lastValue; // Número de frames calculado en el último segundo. FPS() : ticks(0), frameCount(0), lastValue(0) {} void increment() { frameCount++; } int calculate(Uint32 currentTicks) { if (currentTicks - ticks >= 1000) { lastValue = frameCount; frameCount = 0; ticks = currentTicks; } return lastValue; } }; // Efecto de flash en pantalla: pinta la pantalla de un color durante unos frames struct FlashEffect { bool enabled; // Indica si el efecto está activo int lenght; // Duración total del efecto en frames int delay; // Retraso antes de mostrar el flash int counter; // Contador de frames restantes Color color; // Color del flash explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF)) : enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {} void update() { (enabled && counter > 0) ? counter-- : enabled = false; } bool isRendarable() { return enabled && counter < lenght - delay; } }; // Efecto de sacudida/agitación de pantalla: mueve la imagen para simular un temblor struct ShakeEffect { int desp; // Desplazamiento máximo de la sacudida (en píxeles) int delay; // Frames entre cada movimiento de sacudida int counter; // Contador de frames para el siguiente movimiento int lenght; // Duración total del efecto en frames int remaining; // Frames restantes de sacudida int original_pos; // Posición original de la imagen (x) int original_width; // Ancho original de la imagen bool enabled; // Indica si el efecto está activo explicit ShakeEffect(bool en = false, int dp = 2, int dl = 3, int cnt = 0, int len = 8, int rem = 0, int origPos = 0, int origWidth = 800) : desp(dp), delay(dl), counter(cnt), lenght(len), remaining(rem), original_pos(origPos), original_width(origWidth), enabled(en) {} // Activa el efecto de sacudida y guarda la posición y tamaño originales void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_lenght = -1) { if (!enabled) { enabled = true; original_pos = src_rect.x; original_width = src_rect.w; // Usar nuevos valores si se proporcionan, sino mantener los actuales if (new_desp != -1) desp = new_desp; if (new_delay != -1) delay = new_delay; if (new_lenght != -1) lenght = new_lenght; src_rect.w -= desp; dst_rect.w = src_rect.w; } remaining = lenght; counter = delay; } // Actualiza el estado del efecto de sacudida void update(SDL_FRect &src_rect, SDL_FRect &dst_rect) { if (enabled) { if (counter > 0) { counter--; } else { counter = delay; const auto SRC_DESP = (remaining % 2 == 0) ? 0 : desp; const auto DST_DESP = (remaining % 2 == 1) ? 0 : desp; src_rect.x = original_pos + SRC_DESP; dst_rect.x = original_pos + DST_DESP; remaining--; if (remaining == -1) { enabled = false; src_rect.x = original_pos; src_rect.w = original_width; dst_rect.x = original_pos; dst_rect.w = original_width; } } } } bool isEnabled() const { return enabled; } }; #ifdef DEBUG struct Debug { std::shared_ptr text; bool show = false; }; #endif // --- Singleton --- static Screen *instance_; // --- Objetos y punteros --- SDL_Window *window_; // Ventana de la aplicación SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla // --- Variables de estado --- SDL_FRect src_rect_; // Coordenadas de origen para dibujar la textura del juego SDL_FRect dst_rect_; // Coordenadas destino para dibujar la textura del juego FPS fps_; // Gestión de frames por segundo std::string shader_source_; // Almacena el contenido del archivo GLSL FlashEffect flash_effect_; // Efecto de flash en pantalla ShakeEffect shake_effect_; // Efecto de agitar la pantalla bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada #ifdef DEBUG Debug debug_info_; // Información de debug #endif // --- Texto --- std::shared_ptr text_; // Objeto para escribir texto en pantalla // --- Métodos internos --- bool initSDLVideo(); // Arranca SDL VIDEO y crea la ventana void renderFlash(); // Dibuja el efecto de flash en la pantalla void renderShake(); // Aplica el efecto de agitar la pantalla void renderInfo(); // Muestra información por pantalla void renderScreen(); // Selecciona y ejecuta el método de renderizado adecuado void loadShaders(); // Carga el contenido del archivo GLSL void adjustWindowSize(); // Calcula el tamaño de la ventana static void getDisplayInfo(); // Obtiene información sobre la pantalla void renderOverlays(); // Renderiza todos los overlays y efectos void renderAttenuate(); // Atenúa la pantalla void createText(); // Crea el objeto de texto // --- Constructores y destructor --- Screen(); ~Screen(); };