From eb5529e4334483068caec416a7d2e8682d39d859 Mon Sep 17 00:00:00 2001 From: Andreas Monitzer Date: Sun, 2 Oct 2022 20:59:21 +0200 Subject: [PATCH] Implemented support for creating a render surface from canvas or offscreencanvas elements on the wasm target. --- crates/bevy_render/src/lib.rs | 11 +++++++++++ crates/bevy_render/src/view/window.rs | 15 +++++++++++++++ crates/bevy_window/src/window.rs | 24 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index adf5a97c19a8d7..0cd77ea856aa62 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -147,6 +147,17 @@ impl Plugin for RenderPlugin { let surface = { let windows = app.world.resource_mut::(); let raw_handle = windows.get_primary().map(|window| unsafe { + #[cfg(target_arch = "wasm32")] + if let Some(canvas) = &window.canvas_element { + return match canvas { + bevy_window::Canvas::HtmlCanvas(canvas) => { + instance.create_surface_from_canvas(canvas) + } + bevy_window::Canvas::OffscreenCanvas(canvas) => { + instance.create_surface_from_offscreen_canvas(canvas) + } + }; + } let handle = window.raw_window_handle().get_handle(); instance.create_surface(&handle) }); diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 6fe1bc8627fdaf..1488d51a90848c 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -47,6 +47,8 @@ pub struct ExtractedWindow { pub swap_chain_texture: Option, pub size_changed: bool, pub present_mode_changed: bool, + #[cfg(target_arch = "wasm32")] + pub canvas: Option, } #[derive(Default, Resource)] @@ -92,6 +94,8 @@ fn extract_windows( swap_chain_texture: None, size_changed: false, present_mode_changed: false, + #[cfg(target_arch = "wasm32")] + canvas: window.canvas_element.clone(), }); // NOTE: Drop the swap chain frame here @@ -168,6 +172,17 @@ pub fn prepare_windows( .surfaces .entry(window.id) .or_insert_with(|| unsafe { + #[cfg(target_arch = "wasm32")] + if let Some(canvas) = &window.canvas { + return match canvas { + bevy_window::Canvas::HtmlCanvas(canvas) => { + render_instance.create_surface_from_canvas(canvas) + } + bevy_window::Canvas::OffscreenCanvas(canvas) => { + render_instance.create_surface_from_offscreen_canvas(canvas) + } + }; + } // NOTE: On some OSes this MUST be called from the main thread. render_instance.create_surface(&window.handle.get_handle()) }); diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 127eb4ca5a2cae..4de575e44cb11f 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -210,6 +210,8 @@ pub struct Window { focused: bool, mode: WindowMode, canvas: Option, + #[cfg(target_arch = "wasm32")] + pub canvas_element: Option, fit_canvas_to_parent: bool, command_queue: Vec, } @@ -339,6 +341,8 @@ impl Window { focused: true, mode: window_descriptor.mode, canvas: window_descriptor.canvas.clone(), + #[cfg(target_arch = "wasm32")] + canvas_element: window_descriptor.canvas_element.clone(), fit_canvas_to_parent: window_descriptor.fit_canvas_to_parent, command_queue: Vec::new(), } @@ -781,6 +785,17 @@ pub enum MonitorSelection { Index(usize), } +#[cfg(target_arch = "wasm32")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Canvas { + HtmlCanvas(web_sys::HtmlCanvasElement), + OffscreenCanvas(web_sys::OffscreenCanvas), +} +#[cfg(target_arch = "wasm32")] +unsafe impl Send for Canvas {} +#[cfg(target_arch = "wasm32")] +unsafe impl Sync for Canvas {} + /// Describes the information needed for creating a window. /// /// This should be set up before adding the [`WindowPlugin`](crate::WindowPlugin). @@ -859,6 +874,8 @@ pub struct WindowDescriptor { /// /// This value has no effect on non-web platforms. pub canvas: Option, + #[cfg(target_arch = "wasm32")] + pub canvas_element: Option, /// Whether or not to fit the canvas element's size to its parent element's size. /// /// **Warning**: this will not behave as expected for parents that set their size according to the size of their @@ -869,6 +886,11 @@ pub struct WindowDescriptor { pub fit_canvas_to_parent: bool, } +#[cfg(target_arch = "wasm32")] +unsafe impl Send for WindowDescriptor {} +#[cfg(target_arch = "wasm32")] +unsafe impl Sync for WindowDescriptor {} + impl Default for WindowDescriptor { fn default() -> Self { WindowDescriptor { @@ -887,6 +909,8 @@ impl Default for WindowDescriptor { mode: WindowMode::Windowed, transparent: false, canvas: None, + #[cfg(target_arch = "wasm32")] + canvas_element: None, fit_canvas_to_parent: false, } }