diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 1f90e83..a5b4d78 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -12,6 +12,49 @@ #include "game/options.hpp" #include "utils/utils.hpp" +#ifdef __EMSCRIPTEN__ +#include +#include + +// --- Fix per a fullscreen/resize en Emscripten --- +// +// SDL3 + Emscripten no emet de forma fiable SDL_EVENT_WINDOW_LEAVE_FULLSCREEN +// (libsdl-org/SDL#13300) ni SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED / +// SDL_EVENT_DISPLAY_ORIENTATION (libsdl-org/SDL#11389). Quan l'usuari ix de +// fullscreen amb Esc o rota el mòbil, el canvas HTML torna al tamany correcte +// però l'estat intern de SDL creu que segueix en fullscreen amb la resolució +// anterior i el viewport queda desencuadrat. +// +// Solució: registrar callbacks natius d'Emscripten, diferir la feina un tick +// del event loop (el canvas encara no està estable en el moment del callback) +// i re-sincronitzar SDL cridant SDL_SetWindowFullscreen + applyFallbackPresentation. +// La crida interna a SDL_SetWindowFullscreen és la peça que realment fa +// resincronitzar l'estat intern de SDL — sense això la logical presentation +// no encaixa amb el canvas real. +namespace { +Screen* g_screen_instance = nullptr; + +void deferredCanvasResize(void* /*userData*/) { + if (g_screen_instance != nullptr) { + g_screen_instance->handleCanvasResized(); + } +} + +EM_BOOL onEmFullscreenChange(int /*eventType*/, const EmscriptenFullscreenChangeEvent* event, void* /*userData*/) { + if (g_screen_instance != nullptr && event != nullptr) { + g_screen_instance->syncFullscreenFlagFromBrowser(event->isFullscreen != 0); + } + emscripten_async_call(deferredCanvasResize, nullptr, 0); + return EM_FALSE; +} + +EM_BOOL onEmOrientationChange(int /*eventType*/, const EmscriptenOrientationChangeEvent* /*event*/, void* /*userData*/) { + emscripten_async_call(deferredCanvasResize, nullptr, 0); + return EM_FALSE; +} +} // namespace +#endif // __EMSCRIPTEN__ + Screen* Screen::instance_ = nullptr; void Screen::init() { @@ -57,9 +100,23 @@ Screen::Screen() { initShaders(); std::cout << "Screen initialized: " << w << "x" << h << " (zoom " << zoom_ << ", max " << max_zoom_ << ")\n"; + +#ifdef __EMSCRIPTEN__ + // IMPORTANT: NO registrem resize callback genèric. En mòbil, fer scroll + // fa que el navegador oculti/mostri la barra d'URL, disparant un resize + // del DOM per cada scroll. Això portaria a re-aplicar logical presentation + // per cada scroll i corrompria el viewport intern de SDL. + g_screen_instance = this; + emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_TRUE, onEmFullscreenChange); + emscripten_set_orientationchange_callback(nullptr, EM_TRUE, onEmOrientationChange); +#endif } Screen::~Screen() { +#ifdef __EMSCRIPTEN__ + g_screen_instance = nullptr; +#endif + // Guarda opcions abans de destruir Options::window.zoom = zoom_; Options::window.fullscreen = fullscreen_; @@ -561,3 +618,25 @@ void Screen::calculateMaxZoom() { if (max_zoom_ < 1) max_zoom_ = 1; } } + +#ifdef __EMSCRIPTEN__ +// ============================================================================ +// Emscripten — fix per a fullscreen/resize (veure el bloc de comentaris al +// principi del fitxer i l'anonymous namespace amb els callbacks natius). +// ============================================================================ + +void Screen::handleCanvasResized() { + if (window_ == nullptr) return; + // Re-sincronitza l'estat intern de SDL amb el canvas HTML real. La crida + // a SDL_SetWindowFullscreen és l'única manera de forçar SDL a reconèixer + // la mida actual del canvas; després re-apliquem la logical presentation + // (el path WASM sempre va pel fallback SDL_Renderer, sense shaders GPU). + SDL_SetWindowFullscreen(window_, fullscreen_); + applyFallbackPresentation(); +} + +void Screen::syncFullscreenFlagFromBrowser(bool is_fullscreen) { + fullscreen_ = is_fullscreen; + Options::window.fullscreen = is_fullscreen; +} +#endif diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 00464a9..e5365de 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -52,6 +52,14 @@ class Screen { [[nodiscard]] auto getWindow() -> SDL_Window* { return window_; } [[nodiscard]] auto getRenderer() -> SDL_Renderer* { return renderer_; } +#ifdef __EMSCRIPTEN__ + // Sincronització amb el canvas HTML quan el navegador canvia la mida + // (fullscreen entrant/eixint, rotació de mòbil). Cridat pels callbacks + // natius d'Emscripten registrats al constructor. + void handleCanvasResized(); + void syncFullscreenFlagFromBrowser(bool is_fullscreen); +#endif + private: Screen(); ~Screen();