afegits events de canvas d'emscripten

This commit is contained in:
2026-04-16 22:12:30 +02:00
parent e8b0b12f98
commit 1c11a3057b
2 changed files with 87 additions and 0 deletions

View File

@@ -12,6 +12,49 @@
#include "game/options.hpp" #include "game/options.hpp"
#include "utils/utils.hpp" #include "utils/utils.hpp"
#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 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; Screen* Screen::instance_ = nullptr;
void Screen::init() { void Screen::init() {
@@ -57,9 +100,23 @@ Screen::Screen() {
initShaders(); initShaders();
std::cout << "Screen initialized: " << w << "x" << h << " (zoom " << zoom_ << ", max " << max_zoom_ << ")\n"; 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() { Screen::~Screen() {
#ifdef __EMSCRIPTEN__
g_screen_instance = nullptr;
#endif
// Guarda opcions abans de destruir // Guarda opcions abans de destruir
Options::window.zoom = zoom_; Options::window.zoom = zoom_;
Options::window.fullscreen = fullscreen_; Options::window.fullscreen = fullscreen_;
@@ -561,3 +618,25 @@ void Screen::calculateMaxZoom() {
if (max_zoom_ < 1) max_zoom_ = 1; 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

View File

@@ -52,6 +52,14 @@ class Screen {
[[nodiscard]] auto getWindow() -> SDL_Window* { return window_; } [[nodiscard]] auto getWindow() -> SDL_Window* { return window_; }
[[nodiscard]] auto getRenderer() -> SDL_Renderer* { return renderer_; } [[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: private:
Screen(); Screen();
~Screen(); ~Screen();