1use std::ops::Deref;
2use std::sync::{Arc, Mutex, MutexGuard};
3
4use winit::{
5 dpi::PhysicalSize,
6 event::{Event, WindowEvent},
7 event_loop::EventLoop,
8 window::{Window, WindowBuilder},
9};
10use winit_input_helper::WinitInputHelper;
11
12use crate::rendering::window::{PresentableWindow, WindowConfig, WindowProvider, WindowRunner};
13
14#[derive(Clone)]
20pub struct Input(Arc<Mutex<WinitInputHelper>>);
21
22impl Input {
23 fn new() -> Self {
24 Self(Arc::new(Mutex::new(WinitInputHelper::new())))
25 }
26
27 pub fn get(&self) -> InputGuard<'_> {
31 InputGuard(self.0.lock().unwrap())
32 }
33
34 fn update(&self, event: &Event<()>) -> bool {
35 return self.0.lock().unwrap().update(event);
36 }
37}
38
39pub struct InputGuard<'a>(MutexGuard<'a, WinitInputHelper>);
40
41impl Deref for InputGuard<'_> {
42 type Target = WinitInputHelper;
43 fn deref(&self) -> &Self::Target {
44 &self.0
45 }
46}
47
48pub struct WinitWindow {
49 window: Arc<Window>,
50 event_loop: EventLoop<()>,
51 input: Input,
52}
53
54impl WindowProvider for WinitWindow {
55 type Handle = Arc<Window>;
56 type Exposed = Input;
57
58 fn create(config: &WindowConfig) -> Self {
59 let event_loop = EventLoop::new().unwrap();
60 event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll);
61
62 let mut window_builder = WindowBuilder::new().with_title(config.title);
63
64 #[cfg(not(target_arch = "wasm32"))]
65 {
66 window_builder =
67 window_builder.with_inner_size(PhysicalSize::new(config.width, config.height));
68 }
69
70 #[cfg(target_arch = "wasm32")]
71 let window = {
72 use wasm_bindgen::JsCast;
73 use winit::platform::web::WindowBuilderExtWebSys;
74
75 let web_window = web_sys::window().expect("no global `window` exists");
76 let document = web_window
77 .document()
78 .expect("should have a document on window");
79 let canvas = document
80 .get_element_by_id("wgpu_canvas")
81 .expect("no element with id `canvas` found — add <canvas id=\"wgpu_canvas\"></canvas> to index.html")
82 .unchecked_into::<web_sys::HtmlCanvasElement>();
83
84 Arc::new(
85 window_builder
86 .with_canvas(Some(canvas))
87 .build(&event_loop)
88 .unwrap(),
89 )
90 };
91
92 #[cfg(not(target_arch = "wasm32"))]
93 let window = Arc::new(window_builder.build(&event_loop).unwrap());
94
95 Self {
96 window,
97 event_loop,
98 input: Input::new(),
99 }
100 }
101
102 fn size(handle: &Self::Handle) -> (u32, u32) {
103 let s = handle.inner_size();
104 (s.width, s.height)
105 }
106
107 fn exposed(&self) -> Self::Exposed {
108 self.input.clone()
109 }
110
111 fn handle(&self) -> &Self::Handle {
112 &self.window
113 }
114}
115
116impl WindowRunner for WinitWindow {
117 fn run(self, mut on_frame: impl FnMut() + 'static) {
118 let Self {
119 window,
120 event_loop,
121 input,
122 } = self;
123
124 event_loop
125 .run(move |event, elwt| {
126 let stepped = input.update(&event);
127
128 match &event {
129 Event::WindowEvent {
130 event: WindowEvent::CloseRequested,
131 ..
132 } => elwt.exit(),
133 _ => {}
134 }
135
136 if stepped {
137 on_frame();
138 window.request_redraw();
139 }
140 })
141 .unwrap();
142 }
143}
144
145impl PresentableWindow for WinitWindow {}