use std::cmp::max; use std::sync::Arc; use pollster::FutureExt; use wgpu::{Adapter, Device, Instance, PresentMode, Queue, Surface, SurfaceCapabilities}; use winit::application::ApplicationHandler; use winit::dpi::PhysicalSize; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::window::{Window, WindowId}; pub async fn run() { let event_loop = EventLoop::new().unwrap(); let mut window_state = StateApplication::new(); let _ = event_loop.run_app(&mut window_state); } struct StateApplication<'a> { state: Option>, } impl<'a> StateApplication<'a> { pub fn new() -> Self { Self { state: None, } } } impl<'a> ApplicationHandler for StateApplication<'a>{ fn resumed(&mut self, event_loop: &ActiveEventLoop) { let window = event_loop.create_window(Window::default_attributes().with_title("Hello!")).unwrap(); self.state = Some(State::new(window)); } fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { let window = self.state.as_ref().unwrap().window(); if window.id() == window_id { match event { WindowEvent::CloseRequested => { event_loop.exit(); } WindowEvent::Resized(physical_size) => { self.state.as_mut().unwrap().resize(physical_size); } WindowEvent::RedrawRequested => { self.state.as_mut().unwrap().update(); self.state.as_mut().unwrap().render().unwrap(); } WindowEvent::KeyboardInput { .. } => { if let Some(state) = self.state.as_mut() { if state.input(&event) { return; } } } _ => {} } } } fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { let window = self.state.as_ref().unwrap().window(); window.request_redraw(); } } struct State<'a> { surface: Surface<'a>, device: Device, queue: Queue, config: wgpu::SurfaceConfiguration, size: PhysicalSize, window: Arc, } impl<'a> State<'a> { pub fn new (window: Window) -> Self { let window_arc = Arc::new(window); let size = window_arc.inner_size(); let instance = Self::create_gpu_instance(); let surface = instance.create_surface(window_arc.clone()).unwrap(); let adapter = Self::create_adapter(instance, &surface); let (device, queue) = Self::create_device(&adapter); let surface_caps = surface.get_capabilities(&adapter); let config = Self::create_surface_config(size, surface_caps); surface.configure(&device, &config); Self { surface, device, queue, config, size, window: window_arc, } } pub fn input(&mut self, event: &WindowEvent) -> bool { false } fn update(&mut self) { // TODO: Update logic here } fn create_surface_config(size: PhysicalSize, capabilities: SurfaceCapabilities) -> wgpu::SurfaceConfiguration { let surface_format = capabilities.formats.iter() .find(|f| f.is_srgb()) .copied() .unwrap_or(capabilities.formats[0]); wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: surface_format, width: size.width, height: size.height, present_mode: PresentMode::AutoNoVsync, alpha_mode: capabilities.alpha_modes[0], view_formats: vec![], desired_maximum_frame_latency: 2, } } fn create_device(adapter: &Adapter) -> (Device, Queue) { adapter.request_device( &wgpu::DeviceDescriptor { required_features: wgpu::Features::empty(), required_limits: wgpu::Limits::default(), memory_hints: Default::default(), label: None, trace: Default::default(), }).block_on().unwrap() } fn create_adapter(instance: Instance, surface: &Surface) -> Adapter { instance.request_adapter( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), compatible_surface: Some(&surface), force_fallback_adapter: false, } ).block_on().unwrap() } fn create_gpu_instance() -> Instance { Instance::new(&wgpu::InstanceDescriptor { backends: wgpu::Backends::PRIMARY, ..Default::default() }) } pub fn resize(&mut self, new_size: PhysicalSize) { self.size = new_size; self.config.width = max(new_size.width, 1); self.config.height = max(new_size.height, 1); self.surface.configure(&self.device, &self.config); println!("Resized to {:?} from state!", new_size); } pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { let output = self.surface.get_current_texture().unwrap(); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"), }); { let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(wgpu::Color { r: 1.0, g: 0.2, b: 0.3, a: 1.0, }), store: wgpu::StoreOp::Store, } })], depth_stencil_attachment: None, occlusion_query_set: None, timestamp_writes: None, }); } self.queue.submit(std::iter::once(encoder.finish())); output.present(); Ok(()) } pub fn window(&self) -> &Window { &self.window } } fn main() { pollster::block_on(run()); }