algebraeon_drawing/
canvas.rs1use std::{cell::OnceCell, sync::Arc};
2use winit::{
3 application::ApplicationHandler,
4 dpi::PhysicalSize,
5 event::WindowEvent,
6 event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
7 window::{Window, WindowId},
8};
9
10pub struct WgpuState {
11 pub window: Arc<Window>,
12 pub surface: wgpu::Surface<'static>,
13 pub device: wgpu::Device,
14 pub queue: wgpu::Queue,
15 pub config: wgpu::SurfaceConfiguration,
16 pub size: winit::dpi::PhysicalSize<u32>,
17}
18
19impl WgpuState {
20 pub fn new(window: Arc<Window>) -> Self {
21 let size = window.inner_size();
22
23 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
26 backends: wgpu::Backends::PRIMARY,
27 ..Default::default()
28 });
29
30 let surface = instance.create_surface(window.clone()).unwrap();
31
32 let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
34 power_preference: wgpu::PowerPreference::default(),
35 compatible_surface: Some(&surface),
36 force_fallback_adapter: false,
37 }))
38 .unwrap();
39
40 let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
41 required_features: wgpu::Features::empty(),
42 required_limits: wgpu::Limits::default(),
43 label: None,
44 memory_hints: Default::default(),
45 trace: wgpu::Trace::Off,
46 }))
47 .unwrap();
48
49 let surface_caps = surface.get_capabilities(&adapter);
50 let surface_format = surface_caps
51 .formats
52 .iter()
53 .find(|f| f.is_srgb())
54 .copied()
55 .unwrap_or(surface_caps.formats[0]);
56 let config = wgpu::SurfaceConfiguration {
57 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
58 format: surface_format,
59 width: size.width,
60 height: size.height,
61 present_mode: wgpu::PresentMode::Immediate,
62 alpha_mode: surface_caps.alpha_modes[0],
64 view_formats: vec![],
65 desired_maximum_frame_latency: 2,
66 };
67
68 surface.configure(&device, &config);
69
70 Self {
71 window,
72 surface,
73 device,
74 queue,
75 config,
76 size,
77 }
78 }
79
80 pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
81 if new_size.width > 0 && new_size.height > 0 {
82 self.size = new_size;
83 self.config.width = new_size.width;
84 self.config.height = new_size.height;
85 self.surface.configure(&self.device, &self.config);
86 }
87 }
88
89 pub fn reconfigure(&mut self) {
90 self.resize(self.size);
91 }
92}
93
94pub trait Canvas: Sized {
95 type WindowState;
96
97 fn new_window_state(&self, window: Arc<Window>) -> Self::WindowState;
98
99 fn run(self) {
100 let event_loop = EventLoop::new().unwrap();
101 event_loop.set_control_flow(ControlFlow::Poll);
102 let mut app = CanvasApplicationHandler {
103 canvas: self,
104 window: OnceCell::default(),
105 window_state: None,
106 };
107 event_loop.run_app(&mut app).unwrap();
108 }
109
110 fn window_event(
111 &mut self,
112 window_state: &mut Self::WindowState,
113 event_loop: &ActiveEventLoop,
114 id: WindowId,
115 event: WindowEvent,
116 );
117}
118
119struct CanvasApplicationHandler<C: Canvas> {
120 canvas: C,
121 window: OnceCell<Arc<Window>>,
122 window_state: Option<C::WindowState>,
123}
124
125impl<C: Canvas> ApplicationHandler for CanvasApplicationHandler<C> {
126 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
127 let window = self
128 .window
129 .get_or_init(|| {
130 Arc::new(
131 event_loop
132 .create_window(
133 Window::default_attributes()
134 .with_inner_size(PhysicalSize::new(2000, 1600)),
135 )
136 .unwrap(),
137 )
138 })
139 .clone();
140 self.window_state = Some(self.canvas.new_window_state(window));
141 }
142
143 fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
144 self.canvas
145 .window_event(self.window_state.as_mut().unwrap(), event_loop, id, event);
146 }
147}