#pragma once #include // Para SDL_FRect, SDL_HideWindow, SDL_Renderer, SDL_ShowWindow, Uint32, SDL_Texture, SDL_Window #include // Para shared_ptr #include // Para string #include "color.h" // Para Color #include "options.h" // Para VideoOptions, video class Notifier; class ServiceMenu; class Text; // --- Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales (singleton) --- class Screen { public: // --- Métodos de singleton --- static void init(); // Inicializa el objeto Screen static void destroy(); // Libera el objeto Screen static auto get() -> Screen *; // Obtiene el puntero al objeto Screen // --- Métodos principales --- void update(float delta_time); // Recibe deltaTime de las secciones y actualiza la lógica 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 zoom); // Cambia el tamaño de la ventana auto decWindowSize() -> bool; // Reduce el tamaño de la ventana auto incWindowSize() -> bool; // 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, float delay_s = 0.05f, float duration_s = 0.133f) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay_s, duration_s); } // Agita la pantalla (tiempo en segundos) void flash(Color color, float duration_s = 0.167f, float delay_s = 0.0f) { flash_effect_ = FlashEffect(true, duration_s, delay_s, color); } // Pone la pantalla de color (tiempo en segundos) 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 --- auto getRenderer() -> SDL_Renderer * { 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 [[nodiscard]] static auto getVSync() -> bool { return Options::video.vsync; } // Obtiene el valor de V-Sync [[nodiscard]] auto getText() const -> std::shared_ptr { 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; // Decoraciones de la ventana // --- Estructuras privadas --- struct FPS { Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar. int frame_count{0}; // Número acumulado de frames en el intervalo. int last_value{0}; // Número de frames calculado en el último segundo. FPS() = default; void increment() { frame_count++; } auto calculate(Uint32 current_ticks) -> int { if (current_ticks - ticks >= 1000) { last_value = frame_count; frame_count = 0; ticks = current_ticks; } return last_value; } }; // Efecto de flash en pantalla: pinta la pantalla de un color durante un tiempo struct FlashEffect { bool enabled; // Indica si el efecto está activo float duration_s; // Duración total del efecto en segundos float delay_s; // Retraso antes de mostrar el flash en segundos float timer_s; // Timer en segundos (contador decreciente) Color color; // Color del flash explicit FlashEffect(bool enabled = false, float duration_s = 0.0f, float delay_s = 0.0f, Color color = Color(0xFF, 0xFF, 0xFF)) : enabled(enabled), duration_s(duration_s), delay_s(delay_s), timer_s(duration_s), color(color) {} void update(float delta_time) { if (enabled && timer_s > 0.0f) { timer_s -= delta_time; if (timer_s <= 0.0f) { enabled = false; } } } [[nodiscard]] auto isRendarable() const -> bool { return enabled && timer_s < duration_s - delay_s; } }; // 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) float delay_s; // Segundos entre cada movimiento de sacudida float counter_s; // Timer para el siguiente movimiento (decreciente) float duration_s; // Duración total del efecto en segundos float remaining_s; // Tiempo restante 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, float dl_s = 0.05f, float cnt_s = 0.0f, float len_s = 0.133f, float rem_s = 0.0f, int orig_pos = 0, int orig_width = 800) : desp(dp), delay_s(dl_s), counter_s(cnt_s), duration_s(len_s), remaining_s(rem_s), original_pos(orig_pos), original_width(orig_width), 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, float new_delay_s = -1.0f, float new_duration_s = -1.0f) { 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_s >= 0.0f) { delay_s = new_delay_s; } if (new_duration_s >= 0.0f) { duration_s = new_duration_s; } src_rect.w -= desp; dst_rect.w = src_rect.w; } remaining_s = duration_s; counter_s = delay_s; } // Actualiza el estado del efecto de sacudida void update(SDL_FRect &src_rect, SDL_FRect &dst_rect, float delta_time) { if (enabled) { counter_s -= delta_time; if (counter_s <= 0.0f) { counter_s = delay_s; // Alternar desplazamiento basado en tiempo restante const bool SHAKE_LEFT = static_cast(remaining_s * 30.0f) % 2 == 0; // ~30 cambios por segundo const auto SRC_DESP = SHAKE_LEFT ? 0 : desp; const auto DST_DESP = SHAKE_LEFT ? desp : 0; src_rect.x = original_pos + SRC_DESP; dst_rect.x = original_pos + DST_DESP; remaining_s -= delay_s; if (remaining_s <= 0.0f) { enabled = false; src_rect.x = original_pos; src_rect.w = original_width; dst_rect.x = original_pos; dst_rect.w = original_width; } } } } [[nodiscard]] auto isEnabled() const -> bool { return enabled; } }; #ifdef _DEBUG struct Debug { std::shared_ptr text; bool show = false; }; #endif // --- 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 std::shared_ptr text_; // Objeto para escribir texto en 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 std::string shader_source_; // Almacena el contenido del archivo GLSL FPS fps_; // Gestión de frames por segundo 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 // --- Métodos internos --- auto initSDLVideo() -> bool; // 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 renderPresent(); // 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 privados (singleton) --- Screen(); // Constructor privado ~Screen(); // Destructor privado // --- Instancia singleton --- static Screen *instance; // Instancia única de Screen };