1#![doc = include_str!("../README.md")]
2
3mod multisampling;
4
5use winit::{dpi::PhysicalSize, event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
6
7use multisampling::Multisampling;
8
9pub struct Graphics {
11 pub device: wgpu::Device,
12 pub queue: wgpu::Queue,
13
14 format: wgpu::TextureFormat,
15 surface: wgpu::Surface<'static>,
16 surface_config: wgpu::SurfaceConfiguration,
17 size: PhysicalSize<u32>,
18 sample_count: u32,
19 multisampling: Multisampling,
20
21 window: yakui_winit::YakuiWinit,
22 pub renderer: yakui_wgpu::YakuiWgpu,
23 pub is_init: bool,
25}
26
27impl Graphics {
28 pub async fn new(window: &Window, sample_count: u32) -> Self {
29 let mut size = window.inner_size();
30
31 if size == PhysicalSize::new(0, 0) {
35 size = PhysicalSize::new(800, 600);
36 }
37
38 let instance = wgpu::Instance::default();
39 let surface = unsafe {
40 instance.create_surface_unsafe(
41 wgpu::SurfaceTargetUnsafe::from_window(&window)
42 .expect("Could not create wgpu surface from window"),
43 )
44 }
45 .expect("Could not create wgpu surface");
46
47 let adapter = instance
48 .request_adapter(&wgpu::RequestAdapterOptions {
49 power_preference: wgpu::PowerPreference::default(),
50 compatible_surface: Some(&surface),
51 force_fallback_adapter: false,
52 })
53 .await
54 .unwrap();
55
56 let (device, queue) = adapter
57 .request_device(
58 &wgpu::DeviceDescriptor {
59 required_features: wgpu::Features::empty(),
60 required_limits: if cfg!(target_arch = "wasm32") {
63 wgpu::Limits::downlevel_webgl2_defaults()
64 } else {
65 wgpu::Limits::default()
66 },
67 memory_hints: Default::default(),
68 label: None,
69 },
70 None, )
72 .await
73 .unwrap();
74
75 let capabilities = surface.get_capabilities(&adapter);
76 let format = capabilities.formats[0];
77 let surface_config = wgpu::SurfaceConfiguration {
78 alpha_mode: wgpu::CompositeAlphaMode::Auto,
79 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
80 format,
81 view_formats: Vec::new(),
82 width: size.width,
83 height: size.height,
84 present_mode: wgpu::PresentMode::Fifo,
85 desired_maximum_frame_latency: 2,
86 };
87 surface.configure(&device, &surface_config);
88
89 let renderer = yakui_wgpu::YakuiWgpu::new(&device, &queue);
92
93 let window = yakui_winit::YakuiWinit::new(window);
96
97 Self {
98 device,
99 queue,
100
101 format,
102 surface,
103 surface_config,
104 size,
105 sample_count,
106 multisampling: Multisampling::new(),
107
108 renderer,
109 window,
110 is_init: true,
111 }
112 }
113
114 pub fn renderer_mut(&mut self) -> &mut yakui_wgpu::YakuiWgpu {
115 &mut self.renderer
116 }
117
118 pub fn window_mut(&mut self) -> &mut yakui_winit::YakuiWinit {
119 &mut self.window
120 }
121
122 pub fn surface_format(&self) -> wgpu::TextureFormat {
123 self.surface_config.format
124 }
125
126 pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
127 if new_size.width > 0 && new_size.height > 0 && new_size != self.size {
128 self.size = new_size;
129 self.surface_config.width = new_size.width;
130 self.surface_config.height = new_size.height;
131 self.surface.configure(&self.device, &self.surface_config);
132 }
133 }
134
135 #[cfg_attr(feature = "profiling", profiling::function)]
136 pub fn paint(&mut self, yak: &mut yakui_core::Yakui, bg: wgpu::Color) {
137 let output = match self.surface.get_current_texture() {
138 Ok(output) => output,
139 Err(_) => return,
140 };
141
142 let view = output
143 .texture
144 .create_view(&wgpu::TextureViewDescriptor::default());
145
146 let surface = self.multisampling.surface_info(
147 &self.device,
148 &view,
149 self.size,
150 self.format,
151 self.sample_count,
152 );
153
154 let mut encoder = self
155 .device
156 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
157 label: Some("Render Encoder"),
158 });
159
160 {
161 let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
162 label: Some("Render Pass"),
163 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
164 view: surface.color_attachment,
165 resolve_target: surface.resolve_target,
166 ops: wgpu::Operations {
167 load: wgpu::LoadOp::Clear(bg),
168 store: wgpu::StoreOp::Store,
169 },
170 })],
171 ..Default::default()
172 });
173 }
174
175 let clear = encoder.finish();
176
177 let paint_yak = self.renderer.paint(yak, &self.device, &self.queue, surface);
178
179 self.queue.submit([clear, paint_yak]);
180 output.present();
181 }
182
183 pub fn handle_window_event(
184 &mut self,
185 yak: &mut yakui::Yakui,
186 event: &WindowEvent,
187 event_loop: &ActiveEventLoop,
188 ) -> bool {
189 if self.window.handle_window_event(yak, event) {
193 return true;
194 }
195
196 match event {
197 WindowEvent::CloseRequested => {
198 event_loop.exit();
199 }
200
201 WindowEvent::Resized(size) => {
202 if self.is_init {
208 return false;
209 }
210
211 self.resize(*size);
212 }
213
214 _ => (),
215 }
216
217 false
218 }
219}