#pragma once #include // Para SDL_FRect #include // Para SDL_Renderer, SDL_SetRenderLogicalPresentation #include // Para Uint32 #include // Para SDL_Window, SDL_HideWindow, SDL_ShowWindow #include // Para SDL_LogCategory, SDL_LogError, SDL_Log #include // Para string #include // Para shared_ptr #include "options.h" // Para Options, VideoOptions, options #include "param.h" // Para Param, ParamGame, param #include "utils.h" // Para Color #ifdef DEBUG #include "text.h" #include "resource.h" #endif class Notifier; class ServiceMenu; // 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 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 // --- Configuración de ventana y render --- void setFullscreenMode(bool mode = options.video.fullscreen); // Establece el modo de video void toggleFullscreen(); // Cambia entre pantalla completa y ventana void setWindowZoom(int size); // Cambia el tamaño de la ventana bool decWindowZoom(); // Reduce el tamaño de la ventana bool incWindowZoom(); // Aumenta el tamaño de la ventana void applySettings(); // Aplica los valores de las opciones // --- Efectos visuales --- void shake() { shake_effect_.enable(src_rect_, dst_rect_); } // 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() { options.video.shaders = !options.video.shaders; } // Activa/desactiva los shaders void toggleIntegerScale(); // Activa/desactiva el escalado entero void toggleVSync(); // Activa/desactiva el vsync 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 #ifdef DEBUG // --- Debug --- void toggleDebugInfo() { debug_info_.show = !debug_info_.show; } void setDebugInfoEnabled(bool value) { debug_info_.show = value; } void initDebugInfo() { debug_info_.init(); } #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; } }; struct FlashEffect { bool enabled; int lenght; int delay; int counter; Color color; 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; } }; struct ShakeEffect { int desp; int delay; int counter; int lenght; int remaining; int original_pos; int original_width; bool enabled; 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) {} void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect) { if (!enabled) { enabled = true; original_pos = src_rect.x; original_width = src_rect.w; src_rect.w -= desp; dst_rect.w = src_rect.w; } remaining = lenght; counter = delay; } 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 = nullptr; bool show = false; void init() { if (Resource::get()) { text = Resource::get()->getText("aseprite"); if (!text) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to retrieve debug_.text object!"); return; } } } }; #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 *serviceMenu_; // 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 // --- Métodos internos --- bool initSDL(); // 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 initShaders(); // Inicializa los shaders void adjustWindowSize(); // Calcula el tamaño de la ventana void adjustRenderLogicalSize() { SDL_SetRenderLogicalPresentation(renderer_, param.game.width, param.game.height, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); } void getDisplayInfo(); // Obtiene información sobre la pantalla void renderOverlays(); // Renderiza todos los overlays y efectos void renderAttenuate(); // Atenúa la pantalla // --- Constructores y destructor --- Screen(); ~Screen(); };