From 07a531e965c0de640730ff043e16d667a3f498b6 Mon Sep 17 00:00:00 2001 From: Paul DE TEMMERMAN Date: Tue, 24 Sep 2024 23:08:54 +0200 Subject: [PATCH 1/4] winit 0.30 --- Cargo.toml | 10 +- examples/multiwindow/Cargo.toml | 2 +- examples/multiwindow/src/main.rs | 58 +++---- examples/winit_window/Cargo.toml | 2 +- examples/winit_window/src/main.rs | 76 ++++---- src/window/winit_window.rs | 152 +++++++++------- .../winit_window/frame_input_generator.rs | 164 +++++++++--------- src/window/winit_window/windowed_context.rs | 18 +- web/package.json | 16 +- 9 files changed, 268 insertions(+), 230 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1caee3a74..b6084f53c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows [features] default = ["window"] -window = ["glutin", "winit", "raw-window-handle", "wasm-bindgen", "serde", "serde-wasm-bindgen", "web-sys"] # Window module +window = ["glutin", "winit", "wasm-bindgen", "serde", "serde-wasm-bindgen", "web-sys"] # Window module headless = ["glutin_029"] # Headless rendering egui-gui = ["egui_glow", "egui", "getrandom"] # Additional GUI features text = ["swash", "lyon"] # Text mesh generation features @@ -29,7 +29,7 @@ cgmath = "0.18" three-d-asset = "0.9" thiserror = "2" open-enum = "0.5" -winit = {version = "0.28", optional = true} +winit = {version = "0.30", optional = true} egui = { version = "0.30", optional = true } egui_glow = { version = "0.30", optional = true } getrandom = { version = "0.2", features = ["js"], optional = true } @@ -37,9 +37,8 @@ swash = { version = "0.1", optional = true } lyon = { version = "1", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -glutin = { version = "0.30", optional = true } +glutin = { version = "0.32", optional = true } glutin_029 = { package = "glutin", version = "0.29", optional = true } -raw-window-handle = { version = "0.5", optional = true } image = { version = "0.25", default-features = false, features = ["png"], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -47,13 +46,12 @@ wasm-bindgen = {version = "0.2", optional = true } serde = { version = "1", features = ["derive"], optional = true } serde-wasm-bindgen = { version = "0.6", optional = true } web-sys = { version = "0.3", features = ['Document', 'HtmlCollection', 'HtmlCanvasElement', 'Window'], optional = true } -instant = "0.1.11" +web-time = "1.1" [dev-dependencies] rand = "0.7" three-d-asset = {version = "0.9", features = ["hdr", "gltf", "obj", "vol", "pcd", "png", "jpeg", "http", "data-url"] } noise = {version = "0.6", default-features = false} -winit = "0.28" [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] tokio = { version = "1", features = ["macros", "rt-multi-thread"] } diff --git a/examples/multiwindow/Cargo.toml b/examples/multiwindow/Cargo.toml index 3f2dbd829..0cf4bea85 100644 --- a/examples/multiwindow/Cargo.toml +++ b/examples/multiwindow/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] three-d = { path = "../../" } -winit = "0.28" +winit = "0.30" web-sys = "0.3" wasm-bindgen = "0.2" diff --git a/examples/multiwindow/src/main.rs b/examples/multiwindow/src/main.rs index 3904d0108..7dae94fcf 100644 --- a/examples/multiwindow/src/main.rs +++ b/examples/multiwindow/src/main.rs @@ -8,7 +8,7 @@ struct Scene { } pub fn main() { - let event_loop = winit::event_loop::EventLoop::new(); + let event_loop = winit::event_loop::EventLoop::new().unwrap(); // Create a CPU-side mesh consisting of a single colored triangle let positions = vec![ @@ -30,7 +30,7 @@ pub fn main() { let mut windows = HashMap::new(); for i in 0..2 { #[cfg(not(target_arch = "wasm32"))] - let window_builder = winit::window::WindowBuilder::new() + let window_builder = winit::window::Window::default_attributes() .with_title("winit window") .with_min_inner_size(winit::dpi::LogicalSize::new(720, 720)) .with_inner_size(winit::dpi::LogicalSize::new(720, 720)) @@ -38,8 +38,8 @@ pub fn main() { #[cfg(target_arch = "wasm32")] let window_builder = { use wasm_bindgen::JsCast; - use winit::platform::web::WindowBuilderExtWebSys; - winit::window::WindowBuilder::new() + use winit::platform::web::WindowAttributesExtWebSys; + window::Window::default_attributes() .with_canvas(Some( web_sys::window() .unwrap() @@ -54,7 +54,7 @@ pub fn main() { .with_inner_size(winit::dpi::LogicalSize::new(720, 720)) .with_prevent_default(true) }; - let window = window_builder.build(&event_loop).unwrap(); + let window = event_loop.create_window(window_builder).unwrap(); let context = WindowedContext::from_winit_window( &window, three_d::SurfaceSettings { @@ -89,31 +89,12 @@ pub fn main() { ); } - event_loop.run(move |event, _, control_flow| match &event { - winit::event::Event::MainEventsCleared => { + _ = event_loop.run(move |event, event_loop| match &event { + winit::event::Event::AboutToWait => { for (window, _, _, _) in windows.values() { window.request_redraw(); } } - winit::event::Event::RedrawRequested(window_id) => { - if let Some((window, context, frame_input_generator, scene)) = - windows.get_mut(window_id) - { - context.make_current().unwrap(); - let frame_input = frame_input_generator.generate(context); - - scene.camera.set_viewport(frame_input.viewport); - scene.model.animate(frame_input.accumulated_time as f32); - frame_input - .screen() - .clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)) - .render(&scene.camera, &scene.model, &[]); - - context.swap_buffers().unwrap(); - control_flow.set_poll(); - window.request_redraw(); - } - } winit::event::Event::WindowEvent { event, window_id } => { if let Some((_, context, frame_input_generator, _)) = windows.get_mut(window_id) { frame_input_generator.handle_winit_window_event(event); @@ -121,9 +102,28 @@ pub fn main() { winit::event::WindowEvent::Resized(physical_size) => { context.resize(*physical_size); } - winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - context.resize(**new_inner_size); + winit::event::WindowEvent::RedrawRequested => { + if let Some((window, context, frame_input_generator, scene)) = + windows.get_mut(window_id) + { + context.make_current().unwrap(); + let frame_input = frame_input_generator.generate(context); + + scene.camera.set_viewport(frame_input.viewport); + scene.model.animate(frame_input.accumulated_time as f32); + frame_input + .screen() + .clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)) + .render(&scene.camera, &scene.model, &[]); + + context.swap_buffers().unwrap(); + event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll); + window.request_redraw(); + } } + // winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + // context.resize(**new_inner_size); + // } winit::event::WindowEvent::CloseRequested => { if let Some((_, context, _, _)) = windows.get_mut(window_id) { context.make_current().unwrap(); @@ -132,7 +132,7 @@ pub fn main() { windows.remove(window_id); if windows.is_empty() { - control_flow.set_exit(); + event_loop.exit(); } } _ => (), diff --git a/examples/winit_window/Cargo.toml b/examples/winit_window/Cargo.toml index 77ff637e0..b0a938409 100644 --- a/examples/winit_window/Cargo.toml +++ b/examples/winit_window/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] three-d = { path = "../../" } -winit = "0.28" +winit = "0.30" web-sys = "0.3" wasm-bindgen = "0.2" diff --git a/examples/winit_window/src/main.rs b/examples/winit_window/src/main.rs index fe8af5bba..164e225a9 100644 --- a/examples/winit_window/src/main.rs +++ b/examples/winit_window/src/main.rs @@ -1,18 +1,18 @@ use three_d::{renderer::*, FrameInputGenerator, SurfaceSettings, WindowedContext}; pub fn main() { - let event_loop = winit::event_loop::EventLoop::new(); + let event_loop = winit::event_loop::EventLoop::new().unwrap(); #[cfg(not(target_arch = "wasm32"))] - let window_builder = winit::window::WindowBuilder::new() + let window_builder = winit::window::Window::default_attributes() .with_title("winit window") .with_min_inner_size(winit::dpi::LogicalSize::new(1280, 720)) .with_maximized(true); #[cfg(target_arch = "wasm32")] let window_builder = { use wasm_bindgen::JsCast; - use winit::platform::web::WindowBuilderExtWebSys; - winit::window::WindowBuilder::new() + use winit::platform::web::WindowAttributesExtWebSys; + window::Window::default_attributes() .with_canvas(Some( web_sys::window() .unwrap() @@ -27,7 +27,7 @@ pub fn main() { .with_inner_size(winit::dpi::LogicalSize::new(1280, 720)) .with_prevent_default(true) }; - let window = window_builder.build(&event_loop).unwrap(); + let window = event_loop.create_window(window_builder).unwrap(); let context = WindowedContext::from_winit_window(&window, SurfaceSettings::default()).unwrap(); // Create camera @@ -54,40 +54,42 @@ pub fn main() { // Event loop let mut frame_input_generator = FrameInputGenerator::from_winit_window(&window); - event_loop.run(move |event, _, control_flow| match event { - winit::event::Event::MainEventsCleared => { - window.request_redraw(); - } - winit::event::Event::RedrawRequested(_) => { - let mut frame_input = frame_input_generator.generate(&context); + _ = event_loop.run( + move |event: winit::event::Event<()>, event_loop| match event { + winit::event::Event::AboutToWait => { + window.request_redraw(); + } + winit::event::Event::WindowEvent { ref event, .. } => { + frame_input_generator.handle_winit_window_event(event); + match event { + winit::event::WindowEvent::Resized(physical_size) => { + context.resize(*physical_size); + } + winit::event::WindowEvent::RedrawRequested => { + let mut frame_input = frame_input_generator.generate(&context); - control.handle_events(&mut camera, &mut frame_input.events); - camera.set_viewport(frame_input.viewport); - model.animate(frame_input.accumulated_time as f32); - frame_input - .screen() - .clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)) - .render(&camera, &model, &[]); + control.handle_events(&mut camera, &mut frame_input.events); + camera.set_viewport(frame_input.viewport); + model.animate(frame_input.accumulated_time as f32); + frame_input + .screen() + .clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0)) + .render(&camera, &model, &[]); - context.swap_buffers().unwrap(); - control_flow.set_poll(); - window.request_redraw(); - } - winit::event::Event::WindowEvent { ref event, .. } => { - frame_input_generator.handle_winit_window_event(event); - match event { - winit::event::WindowEvent::Resized(physical_size) => { - context.resize(*physical_size); - } - winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - context.resize(**new_inner_size); - } - winit::event::WindowEvent::CloseRequested => { - control_flow.set_exit(); + context.swap_buffers().unwrap(); + event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll); + window.request_redraw(); + } + // winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + // context.resize(**new_inner_size); + // } + winit::event::WindowEvent::CloseRequested => { + event_loop.exit(); + } + _ => (), } - _ => (), } - } - _ => {} - }); + _ => {} + }, + ); } diff --git a/src/window/winit_window.rs b/src/window/winit_window.rs index 6f3a81006..4f2939028 100644 --- a/src/window/winit_window.rs +++ b/src/window/winit_window.rs @@ -2,7 +2,6 @@ use crate::core::{Context, CoreError, Viewport}; use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; -use winit::window::WindowBuilder; use winit::*; mod settings; @@ -28,7 +27,7 @@ pub enum WindowError { #[error("glutin error")] GlutinError(#[from] glutin::error::Error), #[error("winit error")] - WinitError(#[from] winit::error::OsError), + WinitError(#[from] WinitError), #[error("error in three-d")] ThreeDError(#[from] CoreError), #[error("the number of MSAA samples must be a power of two")] @@ -37,6 +36,20 @@ pub enum WindowError { SurfaceCreationError, } +/// +/// Error associated with a winit window. +/// +#[derive(Error, Debug)] +#[allow(missing_docs)] +pub enum WinitError { + #[error("os error")] + OsError(#[from] winit::error::OsError), + #[error("handle error")] + HandleError(#[from] winit::raw_window_handle::HandleError), + #[error("event loop error")] + EventLoopError(#[from] winit::error::EventLoopError), +} + /// /// Error associated with a window. /// @@ -45,9 +58,11 @@ pub enum WindowError { #[allow(missing_docs)] pub enum WindowError { #[error("failed to create a new winit window")] - WinitError(#[from] winit::error::OsError), + WinitError(#[from] WinitError), #[error("failed creating a new window")] WindowCreation, + #[error("failed to retrieve canvas from the window")] + MissingCanvas, #[error("unable to get document from canvas")] DocumentMissing, #[error("unable to convert canvas to html canvas: {0}")] @@ -86,7 +101,10 @@ impl Window { /// /// [settings]: WindowSettings pub fn new(window_settings: WindowSettings) -> Result { - Self::from_event_loop(window_settings, EventLoop::new()) + Self::from_event_loop( + window_settings, + EventLoop::new().map_err(|e| WinitError::EventLoopError(e))?, + ) } /// Exactly the same as [`Window::new()`] except with the ability to supply @@ -97,7 +115,7 @@ impl Window { ) -> Result { #[cfg(not(target_arch = "wasm32"))] let window_builder = { - let window_builder = WindowBuilder::new() + let window_builder = window::Window::default_attributes() .with_title(&window_settings.title) .with_min_inner_size(dpi::LogicalSize::new( window_settings.min_size.0, @@ -123,7 +141,7 @@ impl Window { #[cfg(target_arch = "wasm32")] let window_builder = { use wasm_bindgen::JsCast; - use winit::{dpi::LogicalSize, platform::web::WindowBuilderExtWebSys}; + use winit::{dpi::LogicalSize, platform::web::WindowAttributesExtWebSys}; let canvas = if let Some(canvas) = window_settings.canvas { canvas @@ -157,14 +175,16 @@ impl Window { ) }); - WindowBuilder::new() + window::Window::default_attributes() .with_title(window_settings.title) .with_canvas(Some(canvas)) .with_inner_size(inner_size) .with_prevent_default(true) }; - let winit_window = window_builder.build(&event_loop)?; + let winit_window = event_loop + .create_window(window_builder) + .map_err(WinitError::OsError)?; winit_window.focus_window(); Self::from_winit_window( winit_window, @@ -201,6 +221,7 @@ impl Window { }) as Box); winit_window .canvas() + .ok_or(WindowError::MissingCanvas)? .add_event_listener_with_callback("contextmenu", closure.as_ref().unchecked_ref()) .expect("failed to listen to canvas context menu"); closure @@ -221,15 +242,14 @@ impl Window { /// pub fn render_loop FrameOutput>(self, mut callback: F) { let mut frame_input_generator = FrameInputGenerator::from_winit_window(&self.window); - self.event_loop - .run(move |event, _, control_flow| match event { - Event::LoopDestroyed => { - #[cfg(target_arch = "wasm32")] - { - use wasm_bindgen::JsCast; - use winit::platform::web::WindowExtWebSys; - self.window - .canvas() + _ = self.event_loop.run(move |event, event_loop| match event { + Event::LoopExiting => { + #[cfg(target_arch = "wasm32")] + { + use wasm_bindgen::JsCast; + use winit::platform::web::WindowExtWebSys; + if let Some(canvas) = self.window.canvas() { + canvas .remove_event_listener_with_callback( "contextmenu", self.closure.as_ref().unchecked_ref(), @@ -237,59 +257,65 @@ impl Window { .unwrap(); } } - Event::MainEventsCleared => { - self.window.request_redraw(); - } - Event::RedrawRequested(_) => { - #[cfg(target_arch = "wasm32")] - if self.maximized || option_env!("THREE_D_SCREENSHOT").is_some() { - use winit::platform::web::WindowExtWebSys; - - let html_canvas = self.window.canvas(); - let browser_window = html_canvas - .owner_document() - .and_then(|doc| doc.default_view()) - .or_else(web_sys::window) - .unwrap(); - - self.window.set_inner_size(dpi::LogicalSize { - width: browser_window.inner_width().unwrap().as_f64().unwrap(), - height: browser_window.inner_height().unwrap().as_f64().unwrap(), - }); + } + Event::AboutToWait => { + self.window.request_redraw(); + } + Event::WindowEvent { ref event, .. } => { + frame_input_generator.handle_winit_window_event(event); + match event { + WindowEvent::Resized(physical_size) => { + self.gl.resize(*physical_size); } + WindowEvent::RedrawRequested => { + #[cfg(target_arch = "wasm32")] + if self.maximized || option_env!("THREE_D_SCREENSHOT").is_some() { + use winit::platform::web::WindowExtWebSys; - let frame_input = frame_input_generator.generate(&self.gl); - let frame_output = callback(frame_input); - if frame_output.exit { - *control_flow = ControlFlow::Exit; - } else { - if frame_output.swap_buffers && option_env!("THREE_D_SCREENSHOT").is_none() - { - self.gl.swap_buffers().unwrap(); + if let Some(html_canvas) = self.window.canvas() { + let browser_window = html_canvas + .owner_document() + .and_then(|doc| doc.default_view()) + .or_else(web_sys::window) + .unwrap(); + _ = self.window.request_inner_size(dpi::LogicalSize { + width: browser_window.inner_width().unwrap().as_f64().unwrap(), + height: browser_window + .inner_height() + .unwrap() + .as_f64() + .unwrap(), + }); + } } - if frame_output.wait_next_event { - *control_flow = ControlFlow::Wait; + + let frame_input = frame_input_generator.generate(&self.gl); + let frame_output = callback(frame_input); + if frame_output.exit { + event_loop.exit(); } else { - *control_flow = ControlFlow::Poll; - self.window.request_redraw(); + if frame_output.swap_buffers + && option_env!("THREE_D_SCREENSHOT").is_none() + { + self.gl.swap_buffers().unwrap(); + } + if frame_output.wait_next_event { + event_loop.set_control_flow(ControlFlow::Wait); + } else { + event_loop.set_control_flow(ControlFlow::Poll); + self.window.request_redraw(); + } } } + // WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + // self.gl.resize(**new_inner_size); + // } + WindowEvent::CloseRequested => event_loop.exit(), + _ => (), } - Event::WindowEvent { ref event, .. } => { - frame_input_generator.handle_winit_window_event(event); - match event { - WindowEvent::Resized(physical_size) => { - self.gl.resize(*physical_size); - } - WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - self.gl.resize(**new_inner_size); - } - WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, - _ => (), - } - } - _ => (), - }); + } + _ => (), + }); } /// diff --git a/src/window/winit_window/frame_input_generator.rs b/src/window/winit_window/frame_input_generator.rs index b4019d089..59ed63765 100644 --- a/src/window/winit_window/frame_input_generator.rs +++ b/src/window/winit_window/frame_input_generator.rs @@ -1,13 +1,14 @@ use super::FrameInput; use crate::control::*; use crate::core::*; -#[cfg(target_arch = "wasm32")] -use instant::Instant; #[cfg(not(target_arch = "wasm32"))] use std::time::Instant; +#[cfg(target_arch = "wasm32")] +use web_time::Instant; use winit::dpi::PhysicalSize; use winit::event::TouchPhase; use winit::event::WindowEvent; +use winit::keyboard::PhysicalKey; /// /// Use this to generate [FrameInput] for a new frame with a custom [winit](https://crates.io/crates/winit) window. @@ -127,21 +128,22 @@ impl FrameInputGenerator { } WindowEvent::ScaleFactorChanged { scale_factor, - new_inner_size, + // new_inner_size, + .. } => { self.device_pixel_ratio = *scale_factor; - self.viewport = Viewport::new_at_origo(new_inner_size.width, new_inner_size.height); - let logical_size = new_inner_size.to_logical(self.device_pixel_ratio); - self.window_width = logical_size.width; - self.window_height = logical_size.height; + // self.viewport = Viewport::new_at_origo(new_inner_size.width, new_inner_size.height); + // let logical_size = new_inner_size.to_logical(self.device_pixel_ratio); + // self.window_width = logical_size.width; + // self.window_height = logical_size.height; } WindowEvent::Occluded(false) => { self.first_frame = true; } - WindowEvent::KeyboardInput { input, .. } => { - if let Some(keycode) = input.virtual_keycode { - use winit::event::VirtualKeyCode; - let state = input.state == winit::event::ElementState::Pressed; + WindowEvent::KeyboardInput { event, .. } => { + if let PhysicalKey::Code(keycode) = event.physical_key { + use winit::keyboard::KeyCode; + let state = event.state == winit::event::ElementState::Pressed; if let Some(kind) = translate_virtual_key_code(keycode) { self.events.push(if state { crate::Event::KeyPress { @@ -156,9 +158,7 @@ impl FrameInputGenerator { handled: false, } }); - } else if keycode == VirtualKeyCode::LControl - || keycode == VirtualKeyCode::RControl - { + } else if keycode == KeyCode::ControlLeft || keycode == KeyCode::ControlRight { self.modifiers.ctrl = state; if !cfg!(target_os = "macos") { self.modifiers.command = state; @@ -166,18 +166,17 @@ impl FrameInputGenerator { self.events.push(crate::Event::ModifiersChange { modifiers: self.modifiers, }); - } else if keycode == VirtualKeyCode::LAlt || keycode == VirtualKeyCode::RAlt { + } else if keycode == KeyCode::AltLeft || keycode == KeyCode::AltRight { self.modifiers.alt = state; self.events.push(crate::Event::ModifiersChange { modifiers: self.modifiers, }); - } else if keycode == VirtualKeyCode::LShift || keycode == VirtualKeyCode::RShift - { + } else if keycode == KeyCode::ShiftLeft || keycode == KeyCode::ShiftRight { self.modifiers.shift = state; self.events.push(crate::Event::ModifiersChange { modifiers: self.modifiers, }); - } else if (keycode == VirtualKeyCode::LWin || keycode == VirtualKeyCode::RWin) + } else if (keycode == KeyCode::SuperLeft || keycode == KeyCode::SuperRight) && cfg!(target_os = "macos") { self.modifiers.command = state; @@ -186,6 +185,18 @@ impl FrameInputGenerator { }); } } + if let Some(text) = &event.text { + let mut s = String::new(); + for ch in text.chars() { + if is_printable_char(ch) && !self.modifiers.ctrl && !self.modifiers.command + { + s.push(ch); + } + } + if !s.is_empty() { + self.events.push(crate::Event::Text(s)); + } + } } WindowEvent::MouseWheel { delta, .. } => { if let Some(position) = self.cursor_pos { @@ -211,8 +222,7 @@ impl FrameInputGenerator { } } } - WindowEvent::TouchpadMagnify { delta, .. } => { - // Renamed to PinchGesture in winit 0.30.0 + WindowEvent::PinchGesture { delta, .. } => { if let Some(position) = self.cursor_pos { let d = *delta as f32; self.events.push(crate::Event::PinchGesture { @@ -223,8 +233,7 @@ impl FrameInputGenerator { }); } } - WindowEvent::TouchpadRotate { delta, .. } => { - // Renamed to RotationGesture in winit 0.30.0 + WindowEvent::RotationGesture { delta, .. } => { if let Some(position) = self.cursor_pos { let d = radians(*delta); self.events.push(crate::Event::RotationGesture { @@ -287,11 +296,6 @@ impl FrameInputGenerator { }); self.cursor_pos = Some(position); } - WindowEvent::ReceivedCharacter(ch) => { - if is_printable_char(*ch) && !self.modifiers.ctrl && !self.modifiers.command { - self.events.push(crate::Event::Text(ch.to_string())); - } - } WindowEvent::CursorEntered { .. } => { self.events.push(crate::Event::MouseEnter); } @@ -400,65 +404,65 @@ fn is_printable_char(chr: char) -> bool { !is_in_private_use_area && !chr.is_ascii_control() } -fn translate_virtual_key_code(key: winit::event::VirtualKeyCode) -> Option { - use winit::event::VirtualKeyCode::*; +fn translate_virtual_key_code(key: winit::keyboard::KeyCode) -> Option { + use winit::keyboard::KeyCode; Some(match key { - Down => Key::ArrowDown, - Left => Key::ArrowLeft, - Right => Key::ArrowRight, - Up => Key::ArrowUp, + KeyCode::ArrowDown => Key::ArrowDown, + KeyCode::ArrowLeft => Key::ArrowLeft, + KeyCode::ArrowRight => Key::ArrowRight, + KeyCode::ArrowUp => Key::ArrowUp, - Escape => Key::Escape, - Tab => Key::Tab, - Back => Key::Backspace, - Return => Key::Enter, - Space => Key::Space, + KeyCode::Escape => Key::Escape, + KeyCode::Tab => Key::Tab, + KeyCode::Backspace => Key::Backspace, + KeyCode::Enter => Key::Enter, + KeyCode::Space => Key::Space, - Insert => Key::Insert, - Delete => Key::Delete, - Home => Key::Home, - End => Key::End, - PageUp => Key::PageUp, - PageDown => Key::PageDown, + KeyCode::Insert => Key::Insert, + KeyCode::Delete => Key::Delete, + KeyCode::Home => Key::Home, + KeyCode::End => Key::End, + KeyCode::PageUp => Key::PageUp, + KeyCode::PageDown => Key::PageDown, - Key0 | Numpad0 => Key::Num0, - Key1 | Numpad1 => Key::Num1, - Key2 | Numpad2 => Key::Num2, - Key3 | Numpad3 => Key::Num3, - Key4 | Numpad4 => Key::Num4, - Key5 | Numpad5 => Key::Num5, - Key6 | Numpad6 => Key::Num6, - Key7 | Numpad7 => Key::Num7, - Key8 | Numpad8 => Key::Num8, - Key9 | Numpad9 => Key::Num9, + KeyCode::Digit0 | KeyCode::Numpad0 => Key::Num0, + KeyCode::Digit1 | KeyCode::Numpad1 => Key::Num1, + KeyCode::Digit2 | KeyCode::Numpad2 => Key::Num2, + KeyCode::Digit3 | KeyCode::Numpad3 => Key::Num3, + KeyCode::Digit4 | KeyCode::Numpad4 => Key::Num4, + KeyCode::Digit5 | KeyCode::Numpad5 => Key::Num5, + KeyCode::Digit6 | KeyCode::Numpad6 => Key::Num6, + KeyCode::Digit7 | KeyCode::Numpad7 => Key::Num7, + KeyCode::Digit8 | KeyCode::Numpad8 => Key::Num8, + KeyCode::Digit9 | KeyCode::Numpad9 => Key::Num9, - A => Key::A, - B => Key::B, - C => Key::C, - D => Key::D, - E => Key::E, - F => Key::F, - G => Key::G, - H => Key::H, - I => Key::I, - J => Key::J, - K => Key::K, - L => Key::L, - M => Key::M, - N => Key::N, - O => Key::O, - P => Key::P, - Q => Key::Q, - R => Key::R, - S => Key::S, - T => Key::T, - U => Key::U, - V => Key::V, - W => Key::W, - X => Key::X, - Y => Key::Y, - Z => Key::Z, + KeyCode::KeyA => Key::A, + KeyCode::KeyB => Key::B, + KeyCode::KeyC => Key::C, + KeyCode::KeyD => Key::D, + KeyCode::KeyE => Key::E, + KeyCode::KeyF => Key::F, + KeyCode::KeyG => Key::G, + KeyCode::KeyH => Key::H, + KeyCode::KeyI => Key::I, + KeyCode::KeyJ => Key::J, + KeyCode::KeyK => Key::K, + KeyCode::KeyL => Key::L, + KeyCode::KeyM => Key::M, + KeyCode::KeyN => Key::N, + KeyCode::KeyO => Key::O, + KeyCode::KeyP => Key::P, + KeyCode::KeyQ => Key::Q, + KeyCode::KeyR => Key::R, + KeyCode::KeyS => Key::S, + KeyCode::KeyT => Key::T, + KeyCode::KeyU => Key::U, + KeyCode::KeyV => Key::V, + KeyCode::KeyW => Key::W, + KeyCode::KeyX => Key::X, + KeyCode::KeyY => Key::Y, + KeyCode::KeyZ => Key::Z, _ => { return None; diff --git a/src/window/winit_window/windowed_context.rs b/src/window/winit_window/windowed_context.rs index d828142cf..4c9c87ea8 100644 --- a/src/window/winit_window/windowed_context.rs +++ b/src/window/winit_window/windowed_context.rs @@ -33,7 +33,7 @@ mod inner { window: &Window, settings: SurfaceSettings, ) -> Result { - let canvas = window.canvas(); + let canvas = window.canvas().ok_or(WindowError::WindowCreation)?; // get webgl context and verify extensions let webgl_context = canvas @@ -90,7 +90,9 @@ mod inner { #[cfg(not(target_arch = "wasm32"))] mod inner { - use glutin::{prelude::PossiblyCurrentContextGlSurfaceAccessor, surface::*}; + use glutin::{prelude::PossiblyCurrentGlContext, surface::*}; + + use crate::WinitError; use super::*; /// @@ -114,9 +116,15 @@ mod inner { Err(WindowError::InvalidNumberOfMSAASamples)?; } use glutin::prelude::*; - use raw_window_handle::*; - let raw_display_handle = window.raw_display_handle(); - let raw_window_handle = window.raw_window_handle(); + use winit::raw_window_handle::*; + let raw_display_handle = window + .display_handle() + .map_err(WinitError::HandleError)? + .as_raw(); + let raw_window_handle = window + .window_handle() + .map_err(WinitError::HandleError)? + .as_raw(); // EGL is crossplatform and the official khronos way // but sometimes platforms/drivers may not have it, so we use back up options diff --git a/web/package.json b/web/package.json index 2cf9010db..d9405ba22 100644 --- a/web/package.json +++ b/web/package.json @@ -1,13 +1,13 @@ { "scripts": { - "build": "webpack", - "serve": "webpack serve" + "build": "webpack", + "serve": "webpack serve" }, "devDependencies": { - "html-webpack-plugin": "^5.5.3", - "text-encoding": "^0.7.0", - "webpack": "^5.87.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1" + "html-webpack-plugin": "^5.5.3", + "text-encoding": "^0.7.0", + "webpack": "^5.87.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.1.0" } - } +} From 7e329dfc737e437edfd76199a489add7c2da6f1e Mon Sep 17 00:00:00 2001 From: Paul DE TEMMERMAN Date: Mon, 10 Feb 2025 02:32:40 +0100 Subject: [PATCH 2/4] fix wasm resize window --- src/window/winit_window.rs | 34 +++++++++------------ src/window/winit_window/windowed_context.rs | 8 ++++- web/index.html | 17 +++++++++-- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/window/winit_window.rs b/src/window/winit_window.rs index 4f2939028..b96cca3a2 100644 --- a/src/window/winit_window.rs +++ b/src/window/winit_window.rs @@ -159,27 +159,16 @@ impl Window { .map_err(|e| WindowError::CanvasConvertFailed(format!("{:?}", e)))? }; - let inner_size = window_settings - .initial_size - .or(window_settings.max_size) - .map(|(width, height)| LogicalSize::new(width as f64, height as f64)) - .unwrap_or_else(|| { - let browser_window = canvas - .owner_document() - .and_then(|doc| doc.default_view()) - .or_else(web_sys::window) - .unwrap(); - LogicalSize::new( - browser_window.inner_width().unwrap().as_f64().unwrap(), - browser_window.inner_height().unwrap().as_f64().unwrap(), - ) - }); - - window::Window::default_attributes() + let window_attributes = window::Window::default_attributes() .with_title(window_settings.title) .with_canvas(Some(canvas)) - .with_inner_size(inner_size) - .with_prevent_default(true) + .with_prevent_default(true); + + if let Some((width, height)) = window_settings.max_size { + window_attributes.with_inner_size(LogicalSize::new(width as f64, height as f64)) + } else { + window_attributes + } }; let winit_window = event_loop @@ -265,6 +254,13 @@ impl Window { frame_input_generator.handle_winit_window_event(event); match event { WindowEvent::Resized(physical_size) => { + #[cfg(target_arch = "wasm32")] + { + use winit::platform::web::WindowExtWebSys; + let canvas = self.window.canvas().unwrap(); + canvas.set_width(canvas.client_width() as u32); + canvas.set_height(canvas.client_height() as u32); + } self.gl.resize(*physical_size); } WindowEvent::RedrawRequested => { diff --git a/src/window/winit_window/windowed_context.rs b/src/window/winit_window/windowed_context.rs index 4c9c87ea8..fff80ff0d 100644 --- a/src/window/winit_window/windowed_context.rs +++ b/src/window/winit_window/windowed_context.rs @@ -8,6 +8,7 @@ use winit::window::Window; mod inner { use crate::HardwareAcceleration; use serde::{Deserialize, Serialize}; + use three_d_asset::Viewport; use wasm_bindgen::JsCast; use winit::platform::web::WindowExtWebSys; @@ -74,7 +75,12 @@ mod inner { } /// Resizes the context - pub fn resize(&self, _physical_size: winit::dpi::PhysicalSize) {} + pub fn resize(&self, physical_size: winit::dpi::PhysicalSize) { + self.context.set_viewport(Viewport::new_at_origo( + physical_size.width.max(1), + physical_size.height.max(1), + )); + } /// Make this context current. Needed when using multiple windows (contexts) on native. pub fn make_current(&self) -> Result<(), WindowError> { diff --git a/web/index.html b/web/index.html index 7eb85b30c..7bf0032e5 100644 --- a/web/index.html +++ b/web/index.html @@ -1,9 +1,22 @@ + - - +
+ +
From 088d5d77af310d6a268d4793b9078996034516dd Mon Sep 17 00:00:00 2001 From: Paul DE TEMMERMAN Date: Wed, 5 Mar 2025 03:22:11 +0100 Subject: [PATCH 3/4] fix wasm resize not accurate --- src/window/winit_window.rs | 19 +++++++++++++++++++ .../winit_window/frame_input_generator.rs | 10 ++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/window/winit_window.rs b/src/window/winit_window.rs index b96cca3a2..88df9d55b 100644 --- a/src/window/winit_window.rs +++ b/src/window/winit_window.rs @@ -285,6 +285,25 @@ impl Window { } } + #[cfg(target_arch = "wasm32")] + { + // NOTE: This is needed because the canvas resize events are not all received. + use winit::platform::web::WindowExtWebSys; + let canvas = self.window.canvas().unwrap(); + let canvas_width = canvas.client_width() as u32; + let canvas_height = canvas.client_height() as u32; + if canvas_width != frame_input_generator.window_width() + || canvas_height != frame_input_generator.window_height() + { + let physical_size = + dpi::PhysicalSize::new(canvas_width, canvas_height); + self.gl.resize(physical_size); + frame_input_generator.handle_winit_window_event( + &WindowEvent::Resized(physical_size), + ); + } + } + let frame_input = frame_input_generator.generate(&self.gl); let frame_output = callback(frame_input); if frame_output.exit { diff --git a/src/window/winit_window/frame_input_generator.rs b/src/window/winit_window/frame_input_generator.rs index 59ed63765..6e56924aa 100644 --- a/src/window/winit_window/frame_input_generator.rs +++ b/src/window/winit_window/frame_input_generator.rs @@ -63,6 +63,16 @@ impl FrameInputGenerator { Self::new(window.inner_size(), window.scale_factor()) } + #[cfg(target_arch = "wasm32")] + pub(crate) fn window_width(&self) -> u32 { + self.window_width + } + + #[cfg(target_arch = "wasm32")] + pub(crate) fn window_height(&self) -> u32 { + self.window_height + } + /// /// Generates [FrameInput] for a new frame. This should be called each frame and the generated data should only be used for one frame. /// From de00c99dcba8908d5057fd55a04991cdbcbf3151 Mon Sep 17 00:00:00 2001 From: Paul DE TEMMERMAN Date: Mon, 3 Mar 2025 23:08:30 +0100 Subject: [PATCH 4/4] egui 0.31 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6084f53c..e61c73570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,8 @@ three-d-asset = "0.9" thiserror = "2" open-enum = "0.5" winit = {version = "0.30", optional = true} -egui = { version = "0.30", optional = true } -egui_glow = { version = "0.30", optional = true } +egui = { version = "0.31", optional = true } +egui_glow = { version = "0.31", optional = true } getrandom = { version = "0.2", features = ["js"], optional = true } swash = { version = "0.1", optional = true } lyon = { version = "1", optional = true }