arreglos en screen
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
#include "core/rendering/screen.hpp"
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_RenderTexture, SDL_SetRenderDrawColor, SDL_SetRenderVSync, SDL_LogCategory, SDL_GetError, SDL_LogError, SDL_LogInfo, SDL_RendererLogicalPresentation, SDL_SetRenderLogicalPresentation, SDL_CreateTexture, SDL_DestroyTexture, SDL_DestroyWindow, SDL_GetDisplayName, SDL_GetTicks, SDL_Quit, SDL_RENDERER_VSYNC_DISABLED, SDL_RenderClear, SDL_CreateRenderer, SDL_CreateWindow, SDL_DestroyRenderer, SDL_DisplayID, SDL_FRect, SDL_GetCurrentDisplayMode, SDL_GetDisplays, SDL_GetRenderTarget, SDL_GetWindowPosition, SDL_GetWindowSize, SDL_Init, SDL_LogWarn, SDL_PixelFormat, SDL_RenderFillRect, SDL_RenderPresent, SDL_SetHint, SDL_SetRenderDrawBlendMode, SDL_SetTextureScaleMode, SDL_SetWindowFullscreen, SDL_SetWindowPosition, SDL_SetWindowSize, SDL_TextureAccess, SDL_free, SDL_BLENDMODE_BLEND, SDL_HINT_RENDER_DRIVER, SDL_INIT_VIDEO, SDL_ScaleMode, SDL_WINDOW_FULLSCREEN, SDL_WindowFlags
|
||||
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_RenderTexture, SDL_SetRenderDrawColor, SDL_SetRenderVSync, SDL_LogCategory, SDL_GetError, SDL_LogError, SDL_LogInfo, SDL_RendererLogicalPresentation, SDL_SetRenderLogicalPresentation, SDL_CreateTexture, SDL_DestroyTexture, SDL_DestroyWindow, SDL_GetDisplayName, SDL_GetTicks, SDL_Quit, SDL_RENDERER_VSYNC_DISABLED, SDL_RenderClear, SDL_CreateRenderer, SDL_CreateWindow, SDL_DestroyRenderer, SDL_DisplayID, SDL_FRect, SDL_GetCurrentDisplayMode, SDL_GetDisplays, SDL_GetRenderTarget, SDL_GetWindowPosition, SDL_GetWindowSize, SDL_Init, SDL_LogWarn, SDL_PixelFormat, SDL_RenderFillRect, SDL_RenderPresent, SDL_SetHint, SDL_SetRenderDrawBlendMode, SDL_SetTextureScaleMode, SDL_SetWindowFullscreen, SDL_SetWindowPosition, SDL_SetWindowSize, SDL_SyncWindow, SDL_TextureAccess, SDL_free, SDL_BLENDMODE_BLEND, SDL_HINT_RENDER_DRIVER, SDL_INIT_VIDEO, SDL_ScaleMode, SDL_WINDOW_FULLSCREEN, SDL_WindowFlags
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm> // Para min, max
|
||||
#include <cstring> // Para memcpy
|
||||
@@ -27,6 +31,43 @@
|
||||
// Singleton
|
||||
Screen* Screen::instance = nullptr;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// ============================================================================
|
||||
// Restauración del canvas en wasm/Emscripten
|
||||
// ============================================================================
|
||||
// SDL3 + Emscripten no notifica de forma fiable los cambios de estado del
|
||||
// canvas HTML (fullscreen exit vía Esc, rotación del dispositivo, etc.).
|
||||
// Registramos callbacks nativos de Emscripten que delegan en
|
||||
// Screen::handleCanvasResized(), el cual re-aplica el modo de fullscreen y
|
||||
// reajusta la ventana para que SDL salga de su estado interno de fullscreen.
|
||||
//
|
||||
// Los callbacks difieren el trabajo con emscripten_async_call(0ms) porque el
|
||||
// navegador todavía no ha acabado de redimensionar el canvas cuando el evento
|
||||
// se dispara; posponer al siguiente tick garantiza valores estables.
|
||||
//
|
||||
// Referencias: libsdl-org/SDL#13300, libsdl-org/SDL#11389.
|
||||
// ============================================================================
|
||||
namespace {
|
||||
void deferredCanvasResize(void* /*user_data*/) {
|
||||
if (Screen::get() != nullptr) { Screen::get()->handleCanvasResized(); }
|
||||
}
|
||||
|
||||
auto onEmFullscreenChange(int /*event_type*/, const EmscriptenFullscreenChangeEvent* event, void* /*user_data*/) -> EM_BOOL {
|
||||
// Sincronizamos Options::video.fullscreen con el estado real del navegador
|
||||
// antes de diferir la restauración: cuando el usuario sale con Esc no pasa
|
||||
// por toggleFullscreen() y el estado interno quedaría desincronizado.
|
||||
Options::video.fullscreen = (event != nullptr && event->isFullscreen != 0);
|
||||
emscripten_async_call(deferredCanvasResize, nullptr, 0);
|
||||
return EM_FALSE;
|
||||
}
|
||||
|
||||
auto onEmOrientationChange(int /*event_type*/, const EmscriptenOrientationChangeEvent* /*event*/, void* /*user_data*/) -> EM_BOOL {
|
||||
emscripten_async_call(deferredCanvasResize, nullptr, 0);
|
||||
return EM_FALSE;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
// Inicializa la instancia única del singleton
|
||||
void Screen::init() {
|
||||
Screen::instance = new Screen();
|
||||
@@ -69,6 +110,14 @@ Screen::Screen()
|
||||
// Renderizar una vez la textura vacía para que tenga contenido válido antes de inicializar los shaders (evita pantalla negra)
|
||||
SDL_RenderTexture(renderer_, game_canvas_, nullptr, nullptr);
|
||||
|
||||
// Aplicar la configuración inicial completa (vsync + logical presentation +
|
||||
// fullscreen + tamaño de ventana). En Emscripten es necesario porque el
|
||||
// canvas HTML tiene un tamaño propio y SDL_CreateWindow solo no basta para
|
||||
// que SDL sincronice su viewport interno con el canvas real: sin este
|
||||
// applySettings el canvas inicial sale descolocado con barras negras a los
|
||||
// lados y el juego pequeño en el centro hasta el primer toggle de fullscreen.
|
||||
applySettings();
|
||||
|
||||
// Limpiar renderer
|
||||
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
|
||||
SDL_RenderClear(renderer_);
|
||||
@@ -145,10 +194,39 @@ void Screen::setFullscreenMode() {
|
||||
SDL_SetWindowFullscreen(window_, Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Camibia entre pantalla completa y ventana
|
||||
// Cambia entre pantalla completa y ventana. Usamos applySettings en vez de
|
||||
// setFullscreenMode porque applySettings también re-aplica la logical
|
||||
// presentation — sin eso, al entrar en fullscreen SDL no recalcula el viewport
|
||||
// y el juego se ve pequeño (especialmente en Android).
|
||||
void Screen::toggleFullscreen() {
|
||||
Options::video.fullscreen = !Options::video.fullscreen;
|
||||
setFullscreenMode();
|
||||
applySettings();
|
||||
}
|
||||
|
||||
// Re-sincroniza SDL con el estado real del canvas del navegador. Lo invocan los
|
||||
// callbacks nativos de Emscripten (vegeu el bloc al principi del fitxer) cuando
|
||||
// se detecta un fullscreenchange o un orientationchange. Re-aplica fullscreen y
|
||||
// reajusta la ventana porque SDL no emite SDL_EVENT_WINDOW_LEAVE_FULLSCREEN en
|
||||
// Emscripten y su estado interno queda desincronizado al salir con Esc.
|
||||
// Fuera de Emscripten es un no-op (desktop sí emite los events correctamente).
|
||||
void Screen::handleCanvasResized() {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// SDL_SetWindowFullscreen es imprescindible para sacar a SDL de su estado
|
||||
// interno de fullscreen cuando el usuario ha salido sin pasar por
|
||||
// toggleFullscreen (onEmFullscreenChange ya ha actualizado Options).
|
||||
SDL_SetWindowFullscreen(window_, Options::video.fullscreen);
|
||||
SDL_SyncWindow(window_);
|
||||
adjustWindowSize();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Registra los callbacks nativos de Emscripten que restauran el canvas cuando
|
||||
// SDL3 no emite los events equivalentes. Fuera de Emscripten es un no-op.
|
||||
void Screen::registerEmscriptenEventCallbacks() { // NOLINT(readability-convert-member-functions-to-static)
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_TRUE, onEmFullscreenChange);
|
||||
emscripten_set_orientationchange_callback(nullptr, EM_TRUE, onEmOrientationChange);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Cambia el tamaño de la ventana
|
||||
@@ -424,6 +502,8 @@ auto Screen::initSDLVideo() -> bool {
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderVSync(renderer_, Options::video.vsync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
|
||||
registerEmscriptenEventCallbacks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -611,12 +691,17 @@ void Screen::getSingletons() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Aplica los valores de las opciones
|
||||
// Aplica los valores de las opciones.
|
||||
// IMPORTANTE: el orden importa. SDL_SetRenderLogicalPresentation calcula el
|
||||
// viewport en función del tamaño actual de la ventana SDL, así que DEBE llamarse
|
||||
// DESPUÉS de setFullscreenMode/adjustWindowSize — si no, al entrar en fullscreen
|
||||
// el viewport queda cacheado al tamaño de la ventana pequeña previa y el juego
|
||||
// se ve pequeño y centrado con barras negras alrededor.
|
||||
void Screen::applySettings() {
|
||||
SDL_SetRenderVSync(renderer_, Options::video.vsync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
SDL_SetRenderLogicalPresentation(Screen::get()->getRenderer(), param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
setFullscreenMode();
|
||||
adjustWindowSize();
|
||||
SDL_SetRenderLogicalPresentation(renderer_, param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
}
|
||||
|
||||
// Crea el objeto de texto
|
||||
|
||||
@@ -34,6 +34,7 @@ class Screen {
|
||||
// --- Configuración de ventana y render ---
|
||||
void setFullscreenMode(); // Establece el modo de pantalla completa
|
||||
void toggleFullscreen(); // Cambia entre pantalla completa y ventana
|
||||
void handleCanvasResized(); // Restaura el canvas cuando SDL3 no reporta el cambio (emscripten only: salida de fullscreen con Esc, rotación); no-op fuera de emscripten
|
||||
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
|
||||
@@ -232,7 +233,8 @@ class Screen {
|
||||
#endif
|
||||
|
||||
// --- Métodos internos ---
|
||||
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
||||
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
||||
void registerEmscriptenEventCallbacks(); // Registra callbacks nativos para restaurar el canvas en wasm (no-op fuera de emscripten)
|
||||
void renderFlash(); // Dibuja el efecto de flash en la pantalla
|
||||
void renderShake(); // Aplica el efecto de agitar la pantalla
|
||||
void renderInfo() const; // Muestra información por pantalla
|
||||
|
||||
Reference in New Issue
Block a user