use std::collections::BTreeMap; use renderer::Renderer; use tracing::info; use winit::{ application::ApplicationHandler, dpi::{LogicalSize, PhysicalSize}, event::ElementState, event_loop::EventLoop, raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}, window::{Window, WindowAttributes, WindowId}, }; struct WindowState { last_resize_events: BTreeMap>, window_attrs: WindowAttributes, windows: BTreeMap, renderer: Renderer, } impl WindowState { fn new(window_title: String, display: DisplayHandle) -> WindowState { Self { windows: BTreeMap::new(), last_resize_events: BTreeMap::new(), window_attrs: WindowAttributes::default() .with_title(window_title) .with_resizable(true) .with_inner_size(LogicalSize::new(800, 600)), // TODO: pass down this error and add some kind of error handling UI or dump renderer: Renderer::new(display).expect("renderer"), } } fn handle_final_resize( &mut self, window_id: WindowId, new_size: PhysicalSize, ) { _ = (window_id, new_size); info!("TODO: implement resize events"); if let Some(ctx) = self.renderer.window_contexts.get_mut(&window_id) { ctx.recreate_swapchain(renderer::Extent2D { width: new_size.width, height: new_size.height, }) .expect("swapchain recreation"); } } fn handle_draw_request(&mut self, window_id: WindowId) { _ = window_id; info!( window_id = u64::from(window_id), "TODO: implement draw request" ); self.renderer.debug_draw().expect("drawing"); } fn create_window( &mut self, event_loop: &winit::event_loop::ActiveEventLoop, ) { let window = event_loop .create_window( self.window_attrs .clone() .with_window_level(winit::window::WindowLevel::AlwaysOnTop), ) .expect("new window"); let window_id = window.id(); tracing::info!(window = u64::from(window_id), "created new window"); let size = self .window_attrs .inner_size .map(|size| size.to_physical(1.0)) .unwrap_or(PhysicalSize::new(0, 0)); let extent = renderer::Extent2D { width: size.width, height: size.height, }; let _ = self.renderer.new_window_context( extent, window_id, window.window_handle().expect("window handle"), ); self.windows.insert(window.id(), window); } } impl ApplicationHandler for WindowState { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { tracing::info!("winit::resumed"); self.create_window(event_loop); } fn about_to_wait( &mut self, _event_loop: &winit::event_loop::ActiveEventLoop, ) { tracing::info!("winit::about_to_wait"); for (&window, &resize) in self.last_resize_events.clone().iter() { self.handle_final_resize(window, resize); } self.last_resize_events.clear(); } fn window_event( &mut self, event_loop: &winit::event_loop::ActiveEventLoop, window_id: winit::window::WindowId, event: winit::event::WindowEvent, ) { if !matches!(event, winit::event::WindowEvent::Resized(_)) { if let Some(resize) = self.last_resize_events.remove(&window_id) { self.handle_final_resize(window_id, resize); } } match event { winit::event::WindowEvent::Resized(physical_size) => { _ = self.last_resize_events.insert(window_id, physical_size); } winit::event::WindowEvent::CloseRequested => { tracing::info!( window = u64::from(window_id), "window close requested" ); self.windows.remove(&window_id); self.renderer.window_contexts.remove(&window_id); if self.windows.is_empty() { event_loop.exit(); } } winit::event::WindowEvent::KeyboardInput { event: winit::event::KeyEvent { physical_key: winit::keyboard::PhysicalKey::Code( winit::keyboard::KeyCode::Space, ), state: ElementState::Pressed, repeat: false, .. }, .. } => { self.create_window(event_loop); } winit::event::WindowEvent::KeyboardInput { event: winit::event::KeyEvent { physical_key: winit::keyboard::PhysicalKey::Code( winit::keyboard::KeyCode::KeyQ, ), state: ElementState::Pressed, repeat: false, .. }, .. } => { tracing::info!( window = u64::from(window_id), "window close requested" ); self.windows.remove(&window_id); self.renderer.window_contexts.remove(&window_id); if self.windows.is_empty() { event_loop.exit(); } } winit::event::WindowEvent::KeyboardInput { device_id, event, is_synthetic, } => { _ = (device_id, event, is_synthetic); } winit::event::WindowEvent::CursorMoved { device_id, position, } => { _ = (device_id, position); } winit::event::WindowEvent::MouseInput { device_id, state, button, } => { _ = (device_id, state, button); } winit::event::WindowEvent::RedrawRequested => { self.handle_draw_request(window_id); if let Some(window) = self.windows.get(&window_id) { window.request_redraw(); } } _ => {} // unhandled event } } } fn main() { tracing_subscriber::fmt().init(); let ev = EventLoop::new().unwrap(); ev.set_control_flow(winit::event_loop::ControlFlow::Poll); let display = ev.display_handle().expect("display handle"); let mut game = WindowState::new("Vidya".to_owned(), display); ev.run_app(&mut game).unwrap(); }