Get it running in Chrome!
This commit is contained in:
parent
aae336ca66
commit
042f2dca79
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[alias]
|
||||||
|
run-wasm = "run --release --package run-wasm --"
|
1739
Cargo.lock
generated
1739
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,9 @@ anyhow = "1.0.82"
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"run-wasm",
|
||||||
"crates/editor",
|
"crates/editor",
|
||||||
"crates/minifb_host",
|
"crates/minifb_host",
|
||||||
"crates/player"
|
"crates/player",
|
||||||
|
"crates/web_runner"
|
||||||
]
|
]
|
@ -4,3 +4,12 @@ To launch the editor:
|
|||||||
$ cargo run --manifest-path crates\editor\Cargo.toml
|
$ cargo run --manifest-path crates\editor\Cargo.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To run the web runner:
|
||||||
|
```
|
||||||
|
$ cargo run-wasm --manifest-path crates\web_runner\Cargo.toml --release --package web_runner
|
||||||
|
```
|
||||||
|
|
||||||
|
To build the web runner:
|
||||||
|
```
|
||||||
|
$ wasm-pack build crates\web_runner
|
||||||
|
```
|
@ -8,4 +8,5 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
viperid = { path = "../.." }
|
viperid = { path = "../.." }
|
||||||
|
wasm-timer = "0.2.5"
|
||||||
wasmi = "0.31.2"
|
wasmi = "0.31.2"
|
||||||
|
@ -50,7 +50,7 @@ impl MinimalPreview1 for StockWasi {
|
|||||||
println!("clock_time_get: {} {} {}", id, precision, outptr);
|
println!("clock_time_get: {} {} {}", id, precision, outptr);
|
||||||
// TODO: Actually fetch time
|
// TODO: Actually fetch time
|
||||||
let duration =
|
let duration =
|
||||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
|
wasm_timer::SystemTime::now().duration_since(wasm_timer::SystemTime::UNIX_EPOCH)
|
||||||
.expect("time must be post-epoch");
|
.expect("time must be post-epoch");
|
||||||
|
|
||||||
write_u64(memory, outptr, duration.as_nanos() as u64);
|
write_u64(memory, outptr, duration.as_nanos() as u64);
|
||||||
|
30
crates/web_runner/Cargo.toml
Normal file
30
crates/web_runner/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "web_runner"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "wasm32-unknown-unknown"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
optimize = ["log/release_max_level_warn"]
|
||||||
|
default = ["optimize"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
error-iter = "0.4"
|
||||||
|
log = "0.4"
|
||||||
|
pixels = "0.13.0"
|
||||||
|
player = { path = "../player" }
|
||||||
|
viperid = { path = "../.." }
|
||||||
|
|
||||||
|
winit = "0.28"
|
||||||
|
winit_input_helper = "0.14"
|
||||||
|
console_error_panic_hook = "0.1"
|
||||||
|
console_log = "1"
|
||||||
|
wasm-bindgen = "0.2"
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
web-sys = { version = "0.3", features = ["GpuTextureFormat"] }
|
||||||
|
anyhow = "1.0.82"
|
||||||
|
|
128
crates/web_runner/src/main.rs
Normal file
128
crates/web_runner/src/main.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use error_iter::ErrorIter as _;
|
||||||
|
use log::error;
|
||||||
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
|
use viperid::{Device, VResult, SCREEN_H, SCREEN_W};
|
||||||
|
// https://github.com/parasyte/pixels/blob/main/examples/minimal-web/src/main.rs
|
||||||
|
use winit::{dpi::LogicalSize, event::Event, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||||
|
console_log::init_with_level(log::Level::Trace).expect("error initializing logger");
|
||||||
|
wasm_bindgen_futures::spawn_local(run());
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
let wasm = include_bytes!("../../../example_project/build/game.wasm");
|
||||||
|
let device = Device::new();
|
||||||
|
let mut executor =
|
||||||
|
player::Executor::new(device.share(), wasm)
|
||||||
|
.expect("should have been able to create executor");
|
||||||
|
|
||||||
|
host(device, move || {
|
||||||
|
executor.update();
|
||||||
|
executor.get_error()?;
|
||||||
|
Ok(())
|
||||||
|
}).await.expect("error while hosting");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host(
|
||||||
|
device: Device,
|
||||||
|
mut update: impl FnMut() -> VResult<()> + 'static
|
||||||
|
) -> VResult<()> {
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
let size = LogicalSize::new(SCREEN_W as f64, SCREEN_H as f64);
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("viperid")
|
||||||
|
.with_inner_size(size)
|
||||||
|
.with_min_inner_size(size)
|
||||||
|
.build(&event_loop)
|
||||||
|
.expect("WindowBuilder error");
|
||||||
|
let window = Rc::new(window);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use winit::platform::web::WindowExtWebSys;
|
||||||
|
|
||||||
|
// Retrieve current width and height dimensions of browser client window
|
||||||
|
let get_window_size = || {
|
||||||
|
let client_window = web_sys::window().unwrap();
|
||||||
|
LogicalSize::new(
|
||||||
|
client_window.inner_width().unwrap().as_f64().unwrap(),
|
||||||
|
client_window.inner_height().unwrap().as_f64().unwrap(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let window = Rc::clone(&window);
|
||||||
|
|
||||||
|
// Initialize winit window with current dimensions of browser client
|
||||||
|
// window.set_inner_size(get_window_size());
|
||||||
|
|
||||||
|
let client_window = web_sys::window().unwrap();
|
||||||
|
|
||||||
|
// Attach winit canvas to body element
|
||||||
|
web_sys::window()
|
||||||
|
.and_then(|win| win.document())
|
||||||
|
.and_then(|doc| doc.body())
|
||||||
|
.and_then(|body| {
|
||||||
|
body.append_child(&web_sys::Element::from(window.canvas()))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.expect("couldn't append canvas to document body");
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Listen for resize event on browser client. Adjust winit window dimensions
|
||||||
|
// on event trigger
|
||||||
|
let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| {
|
||||||
|
let size = get_window_size();
|
||||||
|
window.set_inner_size(size)
|
||||||
|
}) as Box<dyn FnMut(_)>);
|
||||||
|
client_window
|
||||||
|
.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
closure.forget();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// let mut input = WinitInputHelper::new();
|
||||||
|
let mut pixels = {
|
||||||
|
let window_size = window.inner_size();
|
||||||
|
let surface_texture =
|
||||||
|
SurfaceTexture::new(window_size.width, window_size.height, window.as_ref());
|
||||||
|
Pixels::new_async(SCREEN_W as u32, SCREEN_H as u32, surface_texture).await.expect("Pixels error")
|
||||||
|
};
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
if let Event::RedrawRequested(_) = event {
|
||||||
|
let frame = pixels.frame_mut();
|
||||||
|
if let Err(err) = update() {
|
||||||
|
log_anyhow_error("update", err);
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
device.shared.screen.to_bitmap_slice(frame).expect("to_bitmap_slice error");
|
||||||
|
if let Err(err) = pixels.render() {
|
||||||
|
log_error("pixels.render", err);
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.request_redraw();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_error<E: std::error::Error + 'static>(method_name: &str, err: E) {
|
||||||
|
error!("{method_name}() failed: {err}");
|
||||||
|
for source in err.sources().skip(1) {
|
||||||
|
error!(" Caused by: {source}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn log_anyhow_error(method_name: &str, err: anyhow::Error) {
|
||||||
|
error!("{method_name}() failed: {err}");
|
||||||
|
}
|
7
run-wasm/Cargo.toml
Normal file
7
run-wasm/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "run-wasm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cargo-run-wasm = "0.3"
|
9
run-wasm/src/main.rs
Normal file
9
run-wasm/src/main.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fn main() {
|
||||||
|
let css = r#"body {
|
||||||
|
background-color: #000;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
cargo_run_wasm::run_wasm_with_css(css);
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use crate::PALETTE;
|
use crate::{VResult, PALETTE};
|
||||||
|
|
||||||
pub const SCREEN_W: usize = 640;
|
pub const SCREEN_W: usize = 640;
|
||||||
pub const SCREEN_H: usize = 480;
|
pub const SCREEN_H: usize = 480;
|
||||||
@ -29,6 +29,18 @@ impl Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_bitmap_slice(&self, slice: &mut [u8]) -> VResult<()> {
|
||||||
|
if slice.len() != SCREEN_W * SCREEN_H * 4 {
|
||||||
|
anyhow::bail!("slice should be {} x {} in length", SCREEN_W, SCREEN_H);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pxl = self.pixels.borrow();
|
||||||
|
for i in 0..pxl.len() {
|
||||||
|
slice[i * 4..i * 4 + 4].copy_from_slice(&(0xff000000 | PALETTE[pxl[i] as usize]).to_le_bytes());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pset(&self, x: i32, y: i32, color: u8) {
|
pub fn pset(&self, x: i32, y: i32, color: u8) {
|
||||||
let px0 = x * PIXEL_SCALAR as i32;
|
let px0 = x * PIXEL_SCALAR as i32;
|
||||||
let py0 = y * PIXEL_SCALAR as i32;
|
let py0 = y * PIXEL_SCALAR as i32;
|
||||||
|
Loading…
Reference in New Issue
Block a user