Files
OpenRA3/cmake/toolchains/emscripten-wasm.cmake
T
EnderTheCoder 70d4beca4f v0.6.0: WebAssembly build with a WebGL backend (playable in the browser)
- ra3.webgl: a Web peer of Vulkan/Direct3D (SDL3 canvas + GLES3/WebGL2), with
  2D blit and the GPU terrain raymarch; GLSL ES shaders; null fallback off
  Emscripten. backend::webgl + default_backend() (webgl under Emscripten).
- Emscripten toolchain + Dockerfile.wasm + scripts/build-wasm.sh; import std,
  global -fexceptions, and Asyncify so the blocking frame loop yields to the
  browser (display::sleep_frame calls emscripten_sleep).
- apps/web/shell.html + apps/web/serve.py (Range-capable dev server).
- Assets: browsers forbid synchronous on-demand reads on the main thread (and
  FS.createLazyFile / the WasmFS fetch backend are worker-only; SDL3's Emscripten
  backend is main-thread DOM only, so the engine cannot run in a worker). The
  wasm build therefore preloads a compact per-map set via OPENRA3_WEB_ASSETS.
- New openra3 textures --map ID lists the loose terrain TGAs a map resolves to
  (terrain::resolve_texture_files, shared with load_textures_from_dir).
- Fixes: webgl heightmap used GL_R16 = 0x8229 (that is R8) -> upload rejected,
  terrain flattened to water; now 0x822A. Logger uses a stdout console sink on
  the web (stderr maps to console.error); a GL error check logs bad uploads.
- CI: wasm image + build jobs.
2026-09-28 22:57:19 +08:00

47 lines
2.4 KiB
CMake

# WebAssembly cross-build via Emscripten.
#
# Includes Emscripten's own platform toolchain (found through $EMSDK, set by the
# emsdk image / `emsdk_env.sh`) and then layers the project's requirements:
#
# * C++26 `import std;`. Emscripten ships the libc++ `std` module source and a
# modules.json in its sysroot; its toolchain wires that up, but only if
# `CMAKE_CXX_MODULE_STD` is on and no std-modules JSON has been set yet, so
# both are arranged before Emscripten.cmake is included and before the
# compiler is probed.
# * Global `-fexceptions`. Emscripten disables exceptions by default, and the
# libc++ `std` module must be built with the same setting as its consumers,
# or clang rejects the prebuilt module ("configuration mismatch"). The engine
# throws, so exceptions are enabled everywhere.
# * The SDL3 web port (`-sUSE_SDL=3`) is attached by CMake to the SDL interface
# target, not here, so only the targets that use SDL pay for it.
# `import std` support: the gate and the module switch must be in place before
# Emscripten.cmake runs and before the compiler is probed.
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
set(CMAKE_CXX_MODULE_STD ON)
# Let Emscripten.cmake point CMake at its own sysroot modules.json.
unset(CMAKE_CXX_STDLIB_MODULES_JSON)
if(DEFINED ENV{EMSDK})
set(OPENRA3_EMSCRIPTEN_CMAKE "$ENV{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")
elseif(DEFINED ENV{EMSCRIPTEN_ROOT})
set(OPENRA3_EMSCRIPTEN_CMAKE "$ENV{EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
endif()
if(NOT EXISTS "${OPENRA3_EMSCRIPTEN_CMAKE}")
message(FATAL_ERROR "Emscripten.cmake not found (set EMSDK); looked at '${OPENRA3_EMSCRIPTEN_CMAKE}'")
endif()
include("${OPENRA3_EMSCRIPTEN_CMAKE}")
# Exceptions are used by the engine; keep them on globally so the std module and
# its consumers agree.
#
# Asyncify turns `emscripten_sleep` (used by display::sleep_frame on Emscripten)
# into a yield to the browser: the engine's frame loops are blocking, and
# without yielding the page freezes and never paints.
set(CMAKE_CXX_FLAGS_INIT "-fexceptions -sASYNCIFY=1")
set(CMAKE_C_FLAGS_INIT "-sASYNCIFY=1")
set(CMAKE_EXE_LINKER_FLAGS_INIT
"-fexceptions -sDISABLE_EXCEPTION_CATCHING=0 -sALLOW_MEMORY_GROWTH=1 -sASYNCIFY=1")
set(CMAKE_SHARED_LINKER_FLAGS_INIT
"-fexceptions -sDISABLE_EXCEPTION_CATCHING=0 -sALLOW_MEMORY_GROWTH=1 -sASYNCIFY=1")