Skip to content

Commit

Permalink
Add external wasm request redraw through proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
maximetinu committed Apr 28, 2024
1 parent f7833e7 commit bc0170c
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ futures-lite = "2.0.1"
crossbeam-channel = "0.5.0"
argh = "0.1.12"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
once_cell = "1.16"
wasm-bindgen = { version = "0.2" }
web-sys = { version = "0.3", features = ["Window"] }

[[example]]
name = "hello_world"
path = "examples/hello_world.rs"
Expand Down
58 changes: 57 additions & 1 deletion examples/window/framerate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! This example illustrates how to implement basic framerate limit through the Winit settings.
//! Additionally, for wasm, it shows how to force an external redraw, to wake up the app on demand.
use std::time::Duration;

Expand All @@ -11,7 +12,16 @@ fn main() {
App::new()
.insert_resource(Framerate(30.0))
.add_plugins(DefaultPlugins)
.add_systems(Startup, test_setup::setup)
.add_systems(
Startup,
(
test_setup::setup,
// Improvement to force an external redraw in-between frames, so that switching
// from low FPS to high FPS happens instantly rather than at the next frame
#[cfg(target_arch = "wasm32")]
wasm::setup_external_redraw,
),
)
.add_systems(
Update,
(
Expand Down Expand Up @@ -171,3 +181,49 @@ pub(crate) mod test_setup {
));
}
}

#[cfg(target_arch = "wasm32")]
pub(crate) mod wasm {
use std::sync::{Arc, Mutex};

use bevy::{ecs::system::NonSend, window::RequestRedraw, winit::EventLoopProxy};
use once_cell::sync::Lazy;

use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::KeyboardEvent;

pub static EVENT_LOOP_PROXY: Lazy<Arc<Mutex<Option<EventLoopProxy>>>> =
Lazy::new(|| Arc::new(Mutex::new(None)));

#[wasm_bindgen]
pub fn request_redraw() -> Result<(), String> {
let proxy = EVENT_LOOP_PROXY.lock().unwrap();
if let Some(proxy) = &*proxy {
proxy
.send_event(RequestRedraw)
.map_err(|_| "Request redraw error: failed to send event".to_string())
} else {
Err("Request redraw error: event loop proxy not found".to_string())
}
}

pub(crate) fn setup_external_redraw(event_loop_proxy: NonSend<EventLoopProxy>) {
*EVENT_LOOP_PROXY.lock().unwrap() = Some((*event_loop_proxy).clone());

let window = web_sys::window().unwrap();
let document = window.document().unwrap();

let closure = Closure::wrap(Box::new(move |event: KeyboardEvent| {
let key = event.key();
if key.len() == 1 && key.chars().next().map_or(false, |ch| ch.is_digit(10)) {
request_redraw().unwrap();
}
}) as Box<dyn FnMut(KeyboardEvent)>);

document
.add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref())
.unwrap();
closure.forget();
}
}

0 comments on commit bc0170c

Please sign in to comment.