Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for wasm32-unknown-unknown target (WebGL) #149

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Check
on:
push:
branches: [master]
branches: [master, vange-rs-web]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we are already in vange-rs repo, perhaps the branch could just be called web?

pull_request:
branches: [master]
branches: [master, vange-rs-web]

jobs:
build:
Expand All @@ -14,7 +14,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- run: rustup target add wasm32-unknown-unknown
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add a note to tell what we are doing to whoever is reading the log

- run: cargo check
- run: cargo check --bin road --features nodata --target wasm32-unknown-unknown
- if: matrix.os == 'ubuntu-latest'
run: cargo check --features glsl
- run: cargo test
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@
.fuse_hidden*
.DS_Store
last-shader.wgsl

# web version
web/assets/res
web/assets/road.css
web/road*
res_linux
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [
default = []
glsl = ["glsl-to-spirv", "wgpu/spirv"]
profile = ["profiling/profile-with-tracy"]
nodata = []

[[bin]]
name = "road"
Expand Down Expand Up @@ -60,13 +61,13 @@ rust-ini = "0.17"
serde = "1.0"
serde_derive = "1.0"
serde_scan = "0.4"
wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "c8d572a", features = [] }
wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "c8d572a", features = ["webgl"] }
# binaries
env_logger = "0.8"
getopts = "0.2"
obj = "0.10"
png = "0.16"
winit = "0.26"
winit = { version = "0.26", features = [] }

[dev-dependencies]
naga = { git = "https://github.com/gfx-rs/naga", rev = "c69f676", features = ["wgsl-in"] }
Expand All @@ -82,5 +83,11 @@ default-features = false
#wgpu-core = { path = "../wgpu/wgpu-core" }
#wgpu-types = { path = "../wgpu/wgpu-types" }

[patch."https://github.com/gfx-rs/naga"]
#naga = { path = "../naga" }
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3.55", features = [] }
wasm-bindgen = "0.2.78"
wasm-bindgen-futures = "0.4"
console_error_panic_hook = { version = "0.1.7" }

[target.'cfg(target_arch = "wasm32")'.dependencies.getrandom]
features = ["js"]
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,45 @@ Controls:

<img alt="game" src="etc/shots/Road11-pause.png" width="25%">

### Web version

Stage | State | Note |
-------------------- | ------------------ | ----------- |
Support FS | :white_check_mark: | [rust-memfs](https://github.com/caiiiycuk/rust-memfs/blob/memfs/README.md) |
WebGL Initialization | :white_check_mark: ||
Loading worlds | :white_check_mark: ||
Loading heights | :white_check_mark: ||
Loading data | :white_check_mark: ||
Loading flood | :white_check_mark: ||
Render | :white_check_mark: | WebGPU not tested |

**Requrements**

* To build game **you must** put resources of original game in `res_linux/data` folder.
* You must install [wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/reference/cli.html)
* If you intended to run the build, then you must use [rust-memfs](https://github.com/caiiiycuk/rust-memfs/blob/memfs/README.md). [explanation (RU)](https://habr.com/ru/post/594611/)

**Debug build**

```sh
cargo build --target wasm32-unknown-unknown --bin road --verbose && \
wasm-bindgen --out-dir web/ --target web --keep-debug target/wasm32-unknown-unknown/debug/road.wasm
```

**Release build**
```sh
cargo build --target wasm32-unknown-unknown --bin road --verbose --release && \
wasm-bindgen --out-dir web/ --target web target/wasm32-unknown-unknown/release/road.wasm
```

**Build web page**
```sh
cd web
./build.sh
```

After building you can run game just by serving `web` folder.

### Mechous viewer/debugger
`car` binary allows to see the mechos with items selected by the configuration. It also shows the debug collision info.
```bash
Expand Down
99 changes: 73 additions & 26 deletions bin/boilerplate.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#![allow(clippy::single_match)]
use std::{cell::RefCell, rc::Rc};

use vangers::{
config,
render::{ScreenTargets, DEPTH_FORMAT},
};


use futures::executor::{LocalPool, LocalSpawner};
use log::info;
use winit::{
Expand All @@ -12,6 +15,12 @@ use winit::{
window::{Window, WindowBuilder},
};

#[cfg(not(target_arch="wasm32"))]
use futures::executor::block_on;

#[cfg(target_arch="wasm32")]
use crate::web;

pub trait Application {
fn on_key(&mut self, input: event::KeyboardInput) -> bool;
fn on_mouse_wheel(&mut self, _delta: event::MouseScrollDelta) {}
Expand Down Expand Up @@ -53,12 +62,15 @@ pub struct HarnessOptions {
}

impl Harness {
#[cfg(not(target_arch = "wasm32"))]
pub fn init(options: HarnessOptions) -> (Self, config::Settings) {
env_logger::init();
let mut task_pool = LocalPool::new();
block_on(Harness::init_async(options))
}

pub async fn init_async(options: HarnessOptions) -> (Self, config::Settings) {
info!("Loading the settings");
let settings = config::Settings::load("config/settings.ron");

let extent = wgpu::Extent3d {
width: settings.window.size[0],
height: settings.window.size[1],
Expand All @@ -76,19 +88,25 @@ impl Harness {
.unwrap();
let surface = unsafe { instance.create_surface(&window) };

info!("Initializing the device");
let adapter = task_pool
.run_until(instance.request_adapter(&wgpu::RequestAdapterOptions {
info!("Initializing the device:adapter");
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
}))
.expect("Unable to initialize GPU via the selected backend.");
})
.await
.expect("Unable to initialize GPU via the selected backend (adapter).");

let downlevel_caps = adapter.get_downlevel_properties();
let adapter_limits = adapter.limits();

#[cfg(target_arch = "wasm32")]
let mut limits = wgpu::Limits::downlevel_webgl2_defaults();

#[cfg(not(target_arch = "wasm32"))]
let mut limits = wgpu::Limits::downlevel_defaults();

if options.uses_level {
let desired_height = 16 << 10;
limits.max_texture_dimension_2d =
Expand All @@ -102,8 +120,10 @@ impl Harness {
desired_height
};
}
let (device, queue) = task_pool
.run_until(adapter.request_device(

info!("Initializing the device:request");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::empty(),
Expand All @@ -114,8 +134,9 @@ impl Harness {
} else {
Some(std::path::Path::new(&settings.render.wgpu_trace_path))
},
))
.unwrap();
)
.await
.expect("Unable to initialize GPU via the selected backend (request).");

let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
Expand All @@ -141,7 +162,7 @@ impl Harness {
.create_view(&wgpu::TextureViewDescriptor::default());

let harness = Harness {
task_pool,
task_pool: LocalPool::new(),
event_loop,
window,
device,
Expand All @@ -157,10 +178,18 @@ impl Harness {
(harness, settings)
}

pub fn main_loop<A: 'static + Application>(self, mut app: A) {
pub fn main_loop<A: Application + 'static>(self, app: A) {
#[cfg(not(target_arch = "wasm32"))]
use std::time;

let app = Rc::new(RefCell::new(app));

#[cfg(target_arch = "wasm32")]
let mut last_time = web::now();

#[cfg(not(target_arch = "wasm32"))]
let mut last_time = time::Instant::now();

let mut needs_reload = false;
let Harness {
mut task_pool,
Expand All @@ -181,6 +210,9 @@ impl Harness {
*control_flow = ControlFlow::Poll;
task_pool.run_until_stalled();

#[cfg(target_arch = "wasm32")]
web::bind_once(Rc::clone(&app));

match event {
event::Event::WindowEvent {
event: event::WindowEvent::Resized(size),
Expand Down Expand Up @@ -211,43 +243,58 @@ impl Harness {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
})
.create_view(&wgpu::TextureViewDescriptor::default());
app.resize(&device, extent);
app.borrow_mut().resize(&device, extent);
}
event::Event::WindowEvent { event, .. } => match event {
event::WindowEvent::Focused(false) => {
needs_reload = reload_on_focus;
}
event::WindowEvent::Focused(true) if needs_reload => {
info!("Reloading shaders");
app.reload(&device);
app.borrow_mut().reload(&device);
needs_reload = false;
}
event::WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
event::WindowEvent::KeyboardInput { input, .. } => {
if !app.on_key(input) {
if !app.borrow_mut().on_key(input) {
*control_flow = ControlFlow::Exit;
}
}
event::WindowEvent::MouseWheel { delta, .. } => app.on_mouse_wheel(delta),
event::WindowEvent::MouseWheel { delta, .. } => app.borrow_mut().on_mouse_wheel(delta),
event::WindowEvent::CursorMoved { position, .. } => {
app.on_cursor_move(position.into())
app.borrow_mut().on_cursor_move(position.into())
}
event::WindowEvent::MouseInput { state, button, .. } => {
app.on_mouse_button(state, button)
app.borrow_mut().on_mouse_button(state, button)
}
_ => {}
},
event::Event::MainEventsCleared => {
let spawner = task_pool.spawner();
let duration = time::Instant::now() - last_time;
last_time += duration;
let delta = duration.as_secs() as f32 + duration.subsec_nanos() as f32 * 1.0e-9;

let update_command_buffers = app.update(&device, delta, &spawner);
if !update_command_buffers.is_empty() {
queue.submit(update_command_buffers);
let delta: f32;

#[cfg(target_arch = "wasm32")]
{
let duration = web::now() - last_time;
last_time += duration;
delta = (duration / 1000.0) as f32;
}

#[cfg(not(target_arch = "wasm32"))]
{
let duration = time::Instant::now() - last_time;
last_time += duration;
delta = duration.as_secs() as f32 + duration.subsec_nanos() as f32 * 1.0e-9;
}
caiiiycuk marked this conversation as resolved.
Show resolved Hide resolved

if delta > 0.0 {
let update_command_buffers = app.borrow_mut().update(&device, delta, &spawner);
if !update_command_buffers.is_empty() {
queue.submit(update_command_buffers);
}
}

match surface.get_current_texture() {
Expand All @@ -260,7 +307,7 @@ impl Harness {
color: &view,
depth: &depth_target,
};
let render_command_buffer = app.draw(&device, targets, &spawner);
let render_command_buffer = app.borrow_mut().draw(&device, targets, &spawner);
queue.submit(Some(render_command_buffer));
frame.present();
}
Expand Down
Loading