Files
coffee_crisis_arcade_edition/source/screen.h
Sergio Valor 1db80485a6 resolt bug en jail_audio
treballant en Screen::renderInfo() deixa el programa congelat
2025-03-28 17:23:08 +01:00

301 lines
8.8 KiB
C++

#pragma once
#include <SDL3/SDL_rect.h> // Para SDL_FRect
#include <SDL3/SDL_render.h> // Para SDL_Renderer, SDL_SetRenderLogicalPrese...
#include <SDL3/SDL_stdinc.h> // Para Uint32
#include <SDL3/SDL_video.h> // Para SDL_Window, SDL_HideWindow, SDL_ShowWindow
#include <SDL3/SDL_log.h> // Para SDL_LogCategory, SDL_LogError, SDL_L...
#include <string> // Para string
#include <memory> // 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 Screen
{
private:
// Constantes
static constexpr int WINDOWS_DECORATIONS_ = 35;
// Estructura para gestionar los fotogramas por segundo
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.
// Constructor para inicializar la estructura.
FPS() : ticks(0), frameCount(0), lastValue(0) {}
// Incrementador que se llama en cada frame.
void increment()
{
frameCount++;
}
// Método para calcular y devolver el valor de FPS.
int calculate(Uint32 currentTicks)
{
if (currentTicks - ticks >= 1000) // Si ha pasado un segundo o más.
{
lastValue = frameCount; // Actualizamos el valor del último FPS.
frameCount = 0; // Reiniciamos el contador de frames.
ticks = currentTicks; // Actualizamos el tiempo base.
}
return lastValue;
}
};
// Estructura para gestionar el efecto de flash en la pantalla
struct FlashEffect
{
bool enabled; // Indica si el efecto está activo
int lenght; // Duración del efecto
int delay; // Frames iniciales en los que no se aplica
int counter; // Contador para el efecto
Color color; // Color del efecto
// Constructor
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) {}
// Actualiza
void update() { (enabled && counter > 0) ? counter-- : enabled = false; }
// Indica si se pude dibujar
bool isRendarable() { return enabled && counter < lenght - delay; }
};
// Estructura para agitar la pantalla
struct ShakeEffect
{
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse
int counter; // Contador para el retraso
int lenght; // Cantidad de desplazamientos a realizar
int remaining; // Cantidad de desplazamientos pendientes a realizar
int original_pos; // Posición inicial de la pantalla para dejarla igual tras el desplazamiento
int original_width; // Anchura inicial de la pantalla para dejarla igual tras el desplazamiento
bool enabled; // Indica si el efecto está activo
// Constructor
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) {}
// Método para habilitar el efecto
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect)
{
if (!enabled)
{
// Configurar el estado inicial si el efecto no está activo
enabled = true;
original_pos = src_rect.x;
original_width = src_rect.w;
// Acortar los anchos iniciales durante el efecto
src_rect.w -= desp;
dst_rect.w = src_rect.w;
}
// Renovar contadores y duración del efecto
remaining = lenght;
counter = delay;
}
// Método para actualizar el efecto de movimiento/agitación
void update(SDL_FRect &src_rect, SDL_FRect &dst_rect)
{
if (enabled)
{
if (counter > 0)
{
counter--;
}
else
{
counter = delay;
// Calcular desplazamientos según el estado de la agitación
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)
{
// Restaurar posición y dimensiones originales
enabled = false;
src_rect.x = original_pos;
src_rect.w = original_width;
dst_rect.x = original_pos;
dst_rect.w = original_width;
}
}
}
}
// Método para comprobar si el efecto está activo
bool isEnabled() const
{
return enabled;
}
};
#ifdef DEBUG
// Estructura pra mostrar la información de debug
struct Debug
{
std::shared_ptr<Text> text = nullptr; // Objeto de texto para escribir
bool show = false; // Indica si se ha de mostrar la informacion por pantalla
void init()
{
if (Resource::get())
{
text = Resource::get()->getText("smb2");
if (!text)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to retrieve debug_.text object!");
return;
}
}
}
};
#endif
// [SINGLETON] Objeto privado
static Screen *screen_;
// 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
// Variables
SDL_FRect src_rect_; // Coordenadas de donde va a pillar la textura del juego para dibujarla
SDL_FRect dst_rect_; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
FPS fps_; // Variable para gestionar los frames por segundo
std::string shader_source_; // Almacena el contenido del archivo GLSL
FlashEffect flash_effect_; // Variable para gestionar el efecto de flash
ShakeEffect shake_effect_; // Variable para gestionar el efecto de agitar la pantalla
bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada
#ifdef DEBUG
Debug debug_info_; // Variable para gestionar la informaciçón de debug
#endif
// Arranca SDL VIDEO y crea la ventana
bool initSDL();
// Dibuja el efecto de flash en la pantalla
void renderFlash();
// Aplica el efecto de agitar la pantalla
void renderShake();
// Muestra información por pantalla
void renderInfo();
// Selecciona y ejecuta el método de renderizado adecuado basado en la configuración de shaders
void renderScreen();
// Carga el contenido del archivo GLSL
void loadShaders();
// Inicializa los shaders
void initShaders();
// Calcula el tamaño de la ventana
void adjustWindowSize();
// Ajusta el tamaño lógico del renderizador
void adjustRenderLogicalSize() { SDL_SetRenderLogicalPresentation(renderer_, param.game.width, param.game.height, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); }
// Obtiene información sobre la pantalla
void getDisplayInfo();
// Renderiza todos los overlays y efectos
void renderOverlays();
// Atenua la pantalla
void renderAttenuate();
// Constructor
Screen();
// Destructor
~Screen();
public:
// [SINGLETON] Crearemos el objeto con esta función estática
static void init();
// [SINGLETON] Destruiremos el objeto con esta función estática
static void destroy();
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
static Screen *get();
// Actualiza la lógica de la clase
void update();
// Limpia la pantalla
void clean(Color color = Color(0x00, 0x00, 0x00));
// Prepara para empezar a dibujar en la textura de juego
void start();
// Vuelca el contenido del renderizador en pantalla
void render();
// Establece el modo de video
void setFullscreenMode(bool mode = options.video.fullscreen);
// Cambia entre pantalla completa y ventana
void toggleFullscreen();
// Cambia el tamaño de la ventana
void setWindowZoom(int size);
// Reduce el tamaño de la ventana
bool decWindowZoom();
// Aumenta el tamaño de la ventana
bool incWindowZoom();
// Agita la pantalla
void shake() { shake_effect_.enable(src_rect_, dst_rect_); }
// Pone la pantalla de color
void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); }
// Activa / desactiva los shaders
void toggleShaders() { options.video.shaders = !options.video.shaders; }
#ifdef DEBUG
// Activa / desactiva la información de debug
void toggleDebugInfo() { debug_info_.show = !debug_info_.show; }
void setDebugInfoEnabled(bool value) { debug_info_.show = value; }
void initDebugInfo() { debug_info_.init(); }
#endif
// Activa / desactiva el escalado entero
void toggleIntegerScale();
// Activa / desactiva el vsync
void toggleVSync();
// Getters
SDL_Renderer *getRenderer() { return renderer_; }
// Muestra la ventana
void show() { SDL_ShowWindow(window_); }
// Oculta la ventana
void hide() { SDL_HideWindow(window_); }
// Atenua la pantalla
void attenuate(bool value) { attenuate_effect_ = value; }
};