Skip to main content

algebraeon_drawing/
canvas.rs

1use 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        // The instance is a handle to our GPU
24        // Backends::all => Vulkan + Metal + DX12 + Browser WebGPU
25        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        // Use instance.enumerate_adapters(wgpu::Backends::all()) for a full list of adapters
33        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            // present_mode: surface_caps.present_modes[0],
63            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}