build d'emscripten

This commit is contained in:
2026-04-17 10:00:37 +02:00
parent 6ea50cf35e
commit 5eb178b039
12 changed files with 316 additions and 44 deletions

View File

@@ -1,6 +1,10 @@
#include "core/rendering/screen.hpp"
#include <SDL3/SDL.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include <algorithm> // Para max, min, transform
#include <cctype> // Para toupper
@@ -11,9 +15,11 @@
#include <iterator> // Para istreambuf_iterator, operator==
#include <string> // Para char_traits, string, operator+, operator==
#include "core/input/mouse.hpp" // Para updateCursorVisibility
#include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
#include "core/input/mouse.hpp" // Para updateCursorVisibility
#include "core/rendering/render_info.hpp" // Para RenderInfo
#ifndef __EMSCRIPTEN__
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader (no soportado en WebGL2)
#endif
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
#include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource
@@ -26,6 +32,38 @@
// [SINGLETON]
Screen* Screen::screen = nullptr;
#ifdef __EMSCRIPTEN__
// ============================================================================
// Restauración del canvas en wasm/Emscripten
// ============================================================================
// SDL3 + Emscripten no notifica de manera fiable los cambios de tamaño del
// canvas HTML (fullscreen exit con Esc, orientationchange). Registramos
// callbacks nativos de Emscripten que re-sincronizan SDL con el estado real
// del navegador delegando en Screen::handleCanvasResized() → setVideoMode().
// Se difiere con emscripten_async_call(0ms) porque cuando el event llega el
// canvas aún no está estable.
// Referencias:
// - https://github.com/libsdl-org/SDL/issues/13300
// - https://github.com/libsdl-org/SDL/issues/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 {
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
// [SINGLETON] Crearemos el objeto con esta función estática
void Screen::init() {
Screen::screen = new Screen();
@@ -164,6 +202,16 @@ void Screen::toggleVideoMode() {
setVideoMode(Options::video.fullscreen);
}
// Re-sincroniza SDL con el estado real del canvas del navegador. Lo invocan los
// callbacks nativos de Emscripten cuando detectan un fullscreenchange u
// orientationchange. En desktop SDL emite SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED
// correctamente, así que fuera de emscripten es un no-op.
void Screen::handleCanvasResized() {
#ifdef __EMSCRIPTEN__
setVideoMode(Options::video.fullscreen);
#endif
}
// Reduce el tamaño de la ventana
auto Screen::decWindowZoom() -> bool {
if (static_cast<int>(Options::video.fullscreen) == 0) {
@@ -636,6 +684,10 @@ void Screen::nextShader() {
// El device GPU se crea siempre (independientemente de postfx) para evitar
// conflictos SDL_Renderer/SDL_GPU al hacer toggle F4 en Windows/Vulkan.
void Screen::initShaders() {
#ifdef __EMSCRIPTEN__
// En WebGL2 no hay SDL3 GPU; el render va por SDL_Renderer sin shaders.
shader_backend_.reset();
#else
SDL_Texture* tex = Options::video.border.enabled ? border_texture_ : game_texture_;
if (!shader_backend_) {
@@ -664,6 +716,7 @@ void Screen::initShaders() {
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
applyCurrentCrtPiPreset();
}
#endif
}
// Obtiene información sobre la pantalla
@@ -767,10 +820,24 @@ auto Screen::initSDLVideo() -> bool {
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
SDL_SetRenderVSync(renderer_, Options::video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
registerEmscriptenEventCallbacks();
std::cout << "Video system initialized successfully\n";
return true;
}
// 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__
// NO registramos resize callback. En móvil, el scroll hace que el navegador
// oculte/muestre la barra de URL, disparando un resize del DOM por cada scroll,
// lo que nos llevaría a llamar setVideoMode innecesariamente.
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_TRUE, onEmFullscreenChange);
emscripten_set_orientationchange_callback(nullptr, EM_TRUE, onEmOrientationChange);
#endif
}
// Crea el objeto de texto
void Screen::createText() {
// Carga la surface de la fuente directamente del archivo