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.
This commit is contained in:
EnderTheCoder
2026-09-28 22:57:19 +08:00
parent d0ae4c76ba
commit 70d4beca4f
22 changed files with 1341 additions and 72 deletions
+18 -4
View File
@@ -62,9 +62,9 @@ umbrella module re-exports the SDK; applications import `ra3` only.
| \ |
| \ v
| ra3.display (backend pick)
| / | \
v ra3.ui ra3.vulkan ra3.dx
| (SDL3) (Vulkan) (D3D11/12)
| / | \ \
v ra3.ui ra3.vulkan ra3.dx ra3.webgl
| (SDL3) (Vulkan) (D3D11/12) (WebGL2)
---------------------------------------------------------------------------
v
L2 simulation ra3.logic ra3.modules ra3.combat ra3.movement
@@ -80,7 +80,7 @@ umbrella module re-exports the SDK; applications import `ra3` only.
The current concrete modules (`ra3.core`, `ra3.logic`, `ra3.data`,
`ra3.skirmish`, `ra3.fs`, `ra3.map`, `ra3.terrain`, `ra3.render`, `ra3.ui.*`,
`ra3.vulkan.*`, `ra3.dx.*`, `ra3.display`, `ra3.game`, `ra3.client`, and the
`ra3.vulkan.*`, `ra3.dx.*`, `ra3.webgl.*`, `ra3.display`, `ra3.game`, `ra3.client`, and the
vendored `ender.log`) are the **seeds** of the
target modules below. `ra3.skirmish` and `ra3.game` will be absorbed into
`ra3.ai` / `ra3.match`; new modules are added as their subsystems are recovered.
@@ -595,6 +595,20 @@ Mirrors SAGE `GameEngine/Common`. Everything else speaks this.
- **F5 Null fallback** `[D]`
- `[x]` non-Windows builds link a stub that fails `init`
### M18c `ra3.webgl` — WebGL backend `[P]`
- **F1 Device & canvas** `[D]`
- `[x]` Emscripten-only; SDL3 canvas + GLES 3.0 (WebGL2) via `-sUSE_SDL=3`
- **F2 2D image path** `[D]`
- `[x]` BGRA texture + fullscreen triangle (GLSL ES 300), `.bgra` swizzle
- **F3 Terrain presentation** `[D]`
- `[x]` GPU heightfield raymarch (GLSL ES port of `terrain.frag`)
- **F4 Wasm packaging** `[~]`
- `[x]` `openra3.html/.js/.wasm`, assets preloaded into the FS at `/assets`
- `[ ]` async/fetch streaming assets instead of a single preload blob `(v0.6)`
- **F5 Null fallback** `[D]`
- `[x]` non-Emscripten builds link a stub that fails `init`
### M19 `ra3.audio` — audio `[ ]`
- **F1 SFX** `[ ]`