1use crate::graphics::{Graphics, Rc, create_graphics};
2use crate::plinth_app::PlinthApp;
3use std::cell::RefCell;
4use winit::{
5 application::ApplicationHandler,
6 dpi::PhysicalSize,
7 event::WindowEvent,
8 event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy},
9 window::{Window, WindowId},
10};
11
12enum State {
13 Ready(Graphics),
14 Init(Option<EventLoopProxy<Graphics>>),
15}
16
17pub struct App {
18 _title: String,
19 state: State,
20 user_app: Rc<RefCell<dyn PlinthApp>>,
21}
22
23impl App {
24 pub fn new(event_loop: &EventLoop<Graphics>, user_app: Rc<RefCell<dyn PlinthApp>>) -> Self {
25 Self {
26 _title: "WebGPU Example".to_string(),
27 state: State::Init(Some(event_loop.create_proxy())),
28 user_app,
29 }
30 }
31
32 fn draw(&mut self) {
33 if let State::Ready(gfx) = &mut self.state {
34 self.user_app.borrow_mut().before_render();
35 self.user_app.borrow_mut().render(gfx);
36 self.user_app.borrow_mut().after_render();
37 }
38 }
39
40 fn resized(&mut self, size: PhysicalSize<u32>) {
41 if let State::Ready(gfx) = &mut self.state {
42 gfx.resize(size);
43 self.user_app.borrow_mut().render(gfx);
44 }
45 }
46
47 pub fn _set_title(&mut self, title: &str) {
48 self._title = title.to_string();
49 }
50}
51
52impl ApplicationHandler<Graphics> for App {
53 fn window_event(
54 &mut self,
55 event_loop: &ActiveEventLoop,
56 _window_id: WindowId,
57 event: WindowEvent,
58 ) {
59 match event {
60 WindowEvent::Resized(size) => self.resized(size),
61 WindowEvent::RedrawRequested => self.draw(),
62 WindowEvent::CloseRequested => {
63 self.user_app.borrow_mut().on_close();
64 event_loop.exit()
65 }
66 _ => {}
67 }
68 self.user_app
69 .borrow_mut()
70 .event_handler(event_loop, _window_id, &event);
71 }
72
73 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
74 if let State::Init(proxy) = &mut self.state {
75 if let Some(proxy) = proxy.take() {
76 let mut win_attr = Window::default_attributes();
77
78 #[cfg(not(target_arch = "wasm32"))]
79 {
80 win_attr = win_attr.with_title(self._title.as_str());
81 }
82
83 #[cfg(target_arch = "wasm32")]
84 {
85 use winit::platform::web::WindowAttributesExtWebSys;
86 win_attr = win_attr.with_append(true);
87 }
88
89 let window = Rc::new(
90 event_loop
91 .create_window(win_attr)
92 .expect("create window err."),
93 );
94
95 let user_app = Rc::clone(&self.user_app);
96
97 #[cfg(target_arch = "wasm32")]
98 wasm_bindgen_futures::spawn_local(create_graphics(window, proxy, user_app));
99
100 #[cfg(not(target_arch = "wasm32"))]
101 pollster::block_on(create_graphics(window, proxy, user_app));
102 }
103 }
104 }
105
106 fn user_event(&mut self, _event_loop: &ActiveEventLoop, graphics: Graphics) {
107 self.state = State::Ready(graphics);
108 if let State::Ready(gfx) = &mut self.state {
109 let scale_factor = gfx.window.scale_factor();
110 let logical_size = gfx.window.inner_size();
111 let physical_size = winit::dpi::PhysicalSize::new(
112 (logical_size.width as f64 * scale_factor) as u32,
113 (logical_size.height as f64 * scale_factor) as u32,
114 );
115 self.resized(physical_size);
116 }
117 self.user_app.borrow_mut().init();
118 }
119}
120
121pub fn start_app(user_app: Rc<RefCell<dyn PlinthApp>>) {
122 let event_loop = EventLoop::<Graphics>::with_user_event().build().unwrap();
123 event_loop.set_control_flow(ControlFlow::Poll);
124 let app = App::new(&event_loop, user_app);
125 run_app(event_loop, app);
126}
127
128#[cfg(target_arch = "wasm32")]
129fn run_app(event_loop: EventLoop<Graphics>, app: App) {
130 std::panic::set_hook(Box::new(console_error_panic_hook::hook));
132 console_log::init_with_level(log::Level::Error).expect("Couldn't initialize logger");
133
134 use winit::platform::web::EventLoopExtWebSys;
136 wasm_bindgen_futures::spawn_local(async move {
137 event_loop.spawn_app(app);
138 });
139}
140
141#[cfg(not(target_arch = "wasm32"))]
142fn run_app(event_loop: EventLoop<Graphics>, mut app: App) {
143 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("error")).init();
146
147 let _ = event_loop.run_app(&mut app);
149}