Vangers 3D: example of using Emscripten in Rust

Ray tracing in original game.

Vangers in 2022 continue to amaze. Great community of people who once loved this game, and today put a lot of effort into making it better, more modern. The original game received an update with support for full-fledged 3D, and not just any, but cross-platform — working on all systems and even in the browser.

This is a logical continuation of the previous article Vange-rs: WebAssembly in Rust. Readers might get the impression that I was offended by Rust due to the fact that the community refuses emscripten, for the sake of the wasm32-unknown-unknown.

This is not the case at all, I’m pretty impressed with the level of wasm integration in Rust, in particular the ease that wasm-bindgen gives for linking js and Rust. Objectively, this is the best solution for projects written in Rust (RIIR).

At the same time, Emscripten is aimed more at C/C++ projects, so it’s okay that it’s used much less often in Rust. However, wasm32-unknown-emscripten works well and most crates compile without errors out of the box. E.g., Vange-rs depends on 211 crates, and only 4 had compatibility issues with Emscripten (winit, fixed as for today: glow, ron, wgpu). Difficulties begin when you need to use the browser API, all the crates that wrap this API are built on the basis of wasm-bindgen, and it does not support Emscripten. Therefore, if a Rust project performs not only calculations, but also implies some kind of visual interface or user interaction, then most likely it will not be possible to compile it into WebAssembly using Emsripten.

However, this rule also applies vice versa: if your project is written in C/C++ and links (statically/dynamically) Rust libraries, then this automatically means that you will not be able to compile it into WebAssembly and run it in a browser using wasm32- unknown-unknown. Because ABI unknown is not the same as ABI Emscripten or wasi, and there is no C/C++ compiler into ABI unknown.

For this projects Emscripten is a best choice.

Are there such projects?

In the last article, the vange-rs project, from the author wgpu @kvark, was used for experiments. It includes modern GPU rendering based on several original techniques, the most promising is done using ray tracing. This project was taken for a reason. The idea was to implement a vange-rs based renderer into original the game. Everyone liked this ambitious goal so much that a small team of strong programmers and sympathizers gathered around it.

Nikita Pryanichnikov created a general rendering abstraction that allows to switch the original Vangers renderer and dynamically connected from vange-rs. @kvark made a ffi library from his project that implements this abstraction. Thus, using static linking, it was possible to get the vange-rs render in the original Vangers.

vange-rs is currently only used as surface rendering, everything else is rendered using the original Vangers code. And it works as follows. Nikita managed to separate the Vangers rendering into two layers: the bottom layer of the map and the top layer with mechos, effects, interface, etc. These two layers are combined into a single image before the frame is displayed on the screen.

Layers of renderer

vange-rs acts as a replacement for the original map layer, and the interface layer is rendered using the original code. To achieve a visual match, we had to synchronize the cameras of the vange-rs and the Vangers, as well as regularly send any changes that the game makes to the map (for example, wheel tracks). The algorithm for working with the map is very tricky and is spread all over the code of the original game. So, the display of most effects affects the landscape and makes changes to it. Therefore, the original map render is always performed, while the 3D render uses the 2D map data in its work. A lot of work has been done to isolate all the places where the terrain is changing and to perform synchronization. Many thanks to the guys for the work done!

How it’s possible?

The images above don’t seem to work in layered rendering, but they do! The Vangers code, like the game itself, is amazing. The top layer with mechos takes into account the landscape of its location and is displayed accordingly. Mechos are higher in the layer hierarchy, but display correctly.

Solved!

So, 3D rendering in Vangers is the combination of C ++ and Rust that can be compiled into WebAssembly using Emscripten or wasi. Moreover, Vangers have already been compiled to WebAssembly using Emscripten. It remains only to add Emscripten support to wgpu. Note how few edits were required to achieve this. wgpu does not use browser APIs for the GL backend, and Emscripten replaces native GL with its WebGL-2 implementation. This will allow C/C++ projects using wgpu (wgpu-native) to run in the browser via the GLES-3 backend. wgpu becomes an alternative to bgfx or sokol in the browser. You can take the glfw / SDL 1/2, use themwith wgpu-native and be sure that the project will work in the browser.

For example, other KD-Lab projects: Perimeter and Samogonki use the old render on DX9, which is why they only work on windows. The community wants to replace this renderer with something more modern like wgpu or bgfx. The decision has not yet been made, but now there is confidence that if this happens, these games will be available in the browser.

Vangers 3D in the browser

Let’s get back to our favorite game. Here is the sequence of steps required to add vange-rs rust library in Emscripten:

cd ${VANGE_RS_ROOT}/ffi 
cargo build --target wasm32-unknown-emscripten --release --features emscripten
# CMakeLists.txt
target_link_directories(vangers-web PUBLIC "${VANGE_RS_ROOT}/target/wasm32-unknown-emscripten/release/")
target_link_libraries(vangers-web rusty_vangers)

And it’s all! Exactly the same as with other gcc/clang compilers. Emscripten also has a powerful WebAssembly optimizer:

vange-rs web version: 25Mb // from previous articlelibrusty_vangers.a (rust) 
debug: 151 Mb
release: 25 Mb
vangers (c++):
relaese: 1.8Mb
optimized and linked with Vangers:
debug: 77 Mb
release: 3.7 Mb

Only 3.7Mb (1.9Mb — 3D render) is a full Vangers game + Rust 3D render.

Now there is an active development of a new render, so compatibility is not in priority. 3D requires WebGL-2 support and 16384px textures to run in browser (only works for me in Chrome on PC). To run in a browser:

  1. Open Vangers on gamepix
  2. Go into “ Options” -> “ Addons
  3. Enable “ 3D
  4. In the game, adjust the camera to tilt or rotate to see amazing 3D
  5. The “\” key dynamically switches the game display mode

P. S. I express my deep gratitude to GamePix for the possibility of publishing Vangers in the browser.

Originally published at https://habr.com on February 3, 2022.

Author of js-dos project, games porting expert

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexander Guryanov (caiiiycuk)

Alexander Guryanov (caiiiycuk)

Author of js-dos project, games porting expert

More from Medium

The Sweet Taste of Wasm & Rust

An HTTP Reverse Proxy in Rust with the actix-web framework

Practice Rust and TAURI: Make an Image Viewer #3

Profiling Rust applications