corregit bug de fullscreen en emscripten

This commit is contained in:
2026-04-13 21:03:46 +02:00
parent ccdf9732d1
commit e0498d642d
2 changed files with 94 additions and 0 deletions

View File

@@ -10,6 +10,53 @@
#include "mouse.hpp" // for Mouse::cursorVisible, Mouse::lastMouseMoveTime
#include "text.h" // for Text, TXT_CENTER, TXT_COLOR, TXT_STROKE
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
// --- 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 cridar setVideoMode() amb el flag de fullscreen actualitzat. La crida
// interna a SDL_SetWindowFullscreen(false) és la peça que realment fa eixir
// SDL del seu estat intern de fullscreen — sense això res més funciona.
namespace {
Screen *g_screen_instance = nullptr;
void deferredCanvasResize(void * /*userData*/) {
if (g_screen_instance) {
g_screen_instance->handleCanvasResized();
}
}
EM_BOOL onEmFullscreenChange(int /*eventType*/, const EmscriptenFullscreenChangeEvent *event, void * /*userData*/) {
if (g_screen_instance && event) {
g_screen_instance->syncFullscreenFlagFromBrowser(event->isFullscreen != 0);
}
emscripten_async_call(deferredCanvasResize, nullptr, 0);
return EM_FALSE;
}
EM_BOOL onEmResize(int /*eventType*/, const EmscriptenUiEvent * /*event*/, void * /*userData*/) {
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__
// Constructor
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options) {
// Inicializa variables
@@ -47,6 +94,9 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
notificationOutlineColor = {0x00, 0x00, 0x00};
notificationEndTime = 0;
notificationY = 2;
// Registra callbacks natius d'Emscripten per a fullscreen/resize/orientation
registerEmscriptenEventCallbacks();
}
// Destructor
@@ -254,6 +304,35 @@ void Screen::clearNotification() {
notificationMessage.clear();
}
// --- Fix per a fullscreen/resize en Emscripten ---
// Vore el bloc de comentaris a dalt i l'anonymous namespace amb els callbacks.
void Screen::handleCanvasResized() {
#ifdef __EMSCRIPTEN__
// La crida a SDL_SetWindowFullscreen + SDL_SetRenderLogicalPresentation
// que fa setVideoMode és l'única manera de resincronitzar l'estat intern
// de SDL amb el canvas HTML real.
setVideoMode(options->videoMode);
#endif
}
void Screen::syncFullscreenFlagFromBrowser(bool isFullscreen) {
#ifdef __EMSCRIPTEN__
options->videoMode = isFullscreen ? SDL_WINDOW_FULLSCREEN : 0;
#else
(void)isFullscreen;
#endif
}
void Screen::registerEmscriptenEventCallbacks() {
#ifdef __EMSCRIPTEN__
g_screen_instance = this;
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onEmFullscreenChange);
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onEmResize);
emscripten_set_orientationchange_callback(nullptr, EM_FALSE, onEmOrientationChange);
#endif
}
// Dibuja la notificación activa (si la hay) sobre el gameCanvas
void Screen::renderNotification() {
if (SDL_GetTicks() >= notificationEndTime) {