v0.7.0: SDL-free wasm worker backend (WebGPU + WebGL2) with on-demand assets
The engine now runs on a plain Web Worker (no SDL, no PROXY_TO_PTHREAD: in a pthread Emscripten proxies every filesystem syscall to the main browser thread, where synchronous XHR - and thus FS.createLazyFile - is forbidden). A page/worker pair transfers an OffscreenCanvas and forwards DOM input; assets load lazily from an embedded manifest, so entering a map fetches only that map and its tiles. Presentation: ra3.webgpu (WebGPU via Emscripten's emdawnwebgpu port, WGSL shaders, the default on wasm) and ra3.wasmgl (WebGL2, GLSL ES). The legacy SDL ra3.webgl backend is removed.
This commit is contained in:
+27
-11
@@ -121,7 +121,7 @@ namespace {
|
||||
std::puts(" [--3d] [--cam-pitch DEG] [--cam-yaw DEG] [--cam-x U] [--cam-y U]");
|
||||
std::puts(" [--cam-height U] [--fov DEG] [--width W] [--height H]");
|
||||
std::puts(" [--fullscreen] [--fps N] (0 = vsync)");
|
||||
std::puts(" [--vulkan] [--dx11] [--dx12] [--webgl] [--sdl] (preferred display backend)");
|
||||
std::puts(" [--vulkan] [--dx11] [--dx12] [--webgpu] [--wasmgl] [--sdl] (preferred display backend)");
|
||||
std::puts("assets: read from <exe_dir>/assets (extracted at build time by the openra3_assets target)");
|
||||
}
|
||||
|
||||
@@ -140,7 +140,8 @@ namespace {
|
||||
[[nodiscard]] auto display_backend_from_args(const std::vector<std::string> &args) -> ra3::display::backend {
|
||||
if (has_flag(args, "--dx11") || has_flag(args, "--d3d11")) return ra3::display::backend::d3d11;
|
||||
if (has_flag(args, "--dx12") || has_flag(args, "--d3d12")) return ra3::display::backend::d3d12;
|
||||
if (has_flag(args, "--webgl")) return ra3::display::backend::webgl;
|
||||
if (has_flag(args, "--webgpu")) return ra3::display::backend::webgpu;
|
||||
if (has_flag(args, "--wasmgl")) return ra3::display::backend::wasmgl;
|
||||
if (has_flag(args, "--sdl")) return ra3::display::backend::sdl;
|
||||
return ra3::display::backend::vulkan;
|
||||
}
|
||||
@@ -149,7 +150,9 @@ namespace {
|
||||
auto executable_dir(const char *argv0) -> std::filesystem::path {
|
||||
std::error_code ec;
|
||||
const auto path = std::filesystem::absolute(argv0, ec);
|
||||
return ec ? std::filesystem::current_path() : path.parent_path();
|
||||
// lexically_normal drops the "." element Emscripten leaves in argv[0]
|
||||
// ("/./openra3.js" -> "/"), which the wasm FS does not collapse itself.
|
||||
return ec ? std::filesystem::current_path() : path.parent_path().lexically_normal();
|
||||
}
|
||||
|
||||
auto read_file(const std::filesystem::path &path) -> std::vector<ra3::core::uint8> {
|
||||
@@ -610,10 +613,12 @@ namespace {
|
||||
* then the others in turn, so an unavailable backend degrades gracefully.
|
||||
* Direct3D is Windows-only; on other hosts those entries fall through.
|
||||
*/
|
||||
inline constexpr std::array<ra3::display::backend, 5> renderer_backends{ra3::display::backend::vulkan, ra3::display::backend::d3d11,
|
||||
ra3::display::backend::d3d12, ra3::display::backend::webgl,
|
||||
ra3::display::backend::sdl};
|
||||
inline constexpr std::array<std::string_view, 5> renderer_names{"Vulkan", "Direct3D 11", "Direct3D 12", "WebGL", "SDL (software)"};
|
||||
inline constexpr std::array<ra3::display::backend, 6> renderer_backends{ra3::display::backend::vulkan, ra3::display::backend::d3d11,
|
||||
ra3::display::backend::d3d12, ra3::display::backend::webgpu,
|
||||
ra3::display::backend::wasmgl, ra3::display::backend::sdl};
|
||||
inline constexpr std::array<std::string_view, 6> renderer_names{"Vulkan", "Direct3D 11", "Direct3D 12", "WebGPU", "WebGL (worker)",
|
||||
"SDL (software)"};
|
||||
inline constexpr int renderer_count = static_cast<int>(renderer_backends.size());
|
||||
|
||||
[[nodiscard]] inline auto renderer_backend(int index) -> ra3::display::backend {
|
||||
return renderer_backends[static_cast<std::size_t>(std::clamp(index, 0, static_cast<int>(renderer_backends.size()) - 1))];
|
||||
@@ -698,7 +703,7 @@ namespace {
|
||||
case 15: return s.fullscreen ? "yes" : "no";
|
||||
case 16: return std::string{fps_names[static_cast<std::size_t>(std::clamp(s.fps_index, 0, 4))]} + " fps";
|
||||
case 17: return "start";
|
||||
case 18: return std::string{renderer_names[static_cast<std::size_t>(std::clamp(s.renderer, 0, 4))]};
|
||||
case 18: return std::string{renderer_names[static_cast<std::size_t>(std::clamp(s.renderer, 0, renderer_count - 1))]};
|
||||
default: return "exit";
|
||||
}
|
||||
}
|
||||
@@ -721,7 +726,7 @@ namespace {
|
||||
case 13: s.thumbnail = !s.thumbnail; break;
|
||||
case 15: s.fullscreen = !s.fullscreen; break;
|
||||
case 16: s.fps_index = (s.fps_index + delta + 5) % 5; break;
|
||||
case 18: s.renderer = (s.renderer + delta + 5) % 5; break;
|
||||
case 18: s.renderer = (s.renderer + delta + renderer_count) % renderer_count; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -1121,8 +1126,9 @@ namespace {
|
||||
if (has_flag(args, "--vulkan")) st.settings.renderer = 0;
|
||||
if (has_flag(args, "--dx11") || has_flag(args, "--d3d11")) st.settings.renderer = 1;
|
||||
if (has_flag(args, "--dx12") || has_flag(args, "--d3d12")) st.settings.renderer = 2;
|
||||
if (has_flag(args, "--webgl")) st.settings.renderer = 3;
|
||||
if (has_flag(args, "--sdl")) st.settings.renderer = 4;
|
||||
if (has_flag(args, "--webgpu")) st.settings.renderer = 3;
|
||||
if (has_flag(args, "--wasmgl")) st.settings.renderer = 4;
|
||||
if (has_flag(args, "--sdl")) st.settings.renderer = 5;
|
||||
if (const auto value = option_value(args, "--width")) st.settings.width = std::stoi(*value);
|
||||
if (const auto value = option_value(args, "--height")) st.settings.height = std::stoi(*value);
|
||||
if (const auto value = option_value(args, "--cam-pitch")) st.settings.cam_pitch = std::stof(*value);
|
||||
@@ -1259,6 +1265,16 @@ auto main(int argc, char **argv) -> int {
|
||||
const auto exe_dir = executable_dir(argc > 0 ? argv[0] : ".");
|
||||
const auto assets = exe_dir / "assets";
|
||||
setup_logging(exe_dir);
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// The wasm build runs on a Web Worker (its runtime's main thread lives
|
||||
// there), where synchronous XHR is legal, so the asset tree is mounted
|
||||
// lazily from a manifest instead of being preloaded: the browser fetches
|
||||
// only the files the engine actually opens. On wasm the executable dir is
|
||||
// "/", so the manifest sits at /assets.manifest.json and the lazy file URLs
|
||||
// are "assets/<rel>" relative to the page.
|
||||
const int mounted = ra3::wasmgl::mount_assets((exe_dir / "assets.manifest.json").string(), assets.string(), "assets/");
|
||||
ender::log::info(std::format("wasm assets: {} files mounted lazily under {}", mounted, assets.string()));
|
||||
#endif
|
||||
|
||||
if (args.empty()) return command_menu({}, assets);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user