astrelis_render/
window.rs1use astrelis_core::{geometry::Size, profiling::profile_function};
2use astrelis_winit::{
3 WindowId,
4 event::PhysicalSize,
5 window::{Window, WindowBackend},
6};
7
8use crate::{
9 context::GraphicsContext,
10 frame::{FrameContext, FrameStats, Surface},
11};
12
13#[derive(Debug, Clone, Copy)]
15pub struct Viewport {
16 pub x: f32,
17 pub y: f32,
18 pub width: f32,
19 pub height: f32,
20 pub scale_factor: f64,
21}
22
23impl Default for Viewport {
24 fn default() -> Self {
25 Self {
26 x: 0.0,
27 y: 0.0,
28 width: 800.0,
29 height: 600.0,
30 scale_factor: 1.0,
32 }
33 }
34}
35
36impl Viewport {
37 pub fn is_valid(&self) -> bool {
38 self.width > 0.0 && self.height > 0.0 && self.scale_factor > 0.0
39 }
40
41 pub fn to_logical(&self) -> Size<f32> {
43 Size {
44 width: self.width as f32 / self.scale_factor as f32,
45 height: self.height as f32 / self.scale_factor as f32,
46 }
47 }
48}
49
50#[derive(Default)]
52pub struct WindowContextDescriptor {
53 pub format: Option<wgpu::TextureFormat>,
55 pub present_mode: Option<wgpu::PresentMode>,
57 pub alpha_mode: Option<wgpu::CompositeAlphaMode>,
59}
60
61pub struct PendingReconfigure {
62 pub resize: Option<PhysicalSize<u32>>,
63}
64
65impl PendingReconfigure {
66 const fn new() -> Self {
67 Self { resize: None }
68 }
69}
70
71pub struct WindowContext {
73 pub(crate) window: Window,
74 pub(crate) context: &'static GraphicsContext,
75 pub(crate) surface: wgpu::Surface<'static>,
76 pub(crate) config: wgpu::SurfaceConfiguration,
77 pub(crate) reconfigure: PendingReconfigure,
78}
79
80impl WindowContext {
81 pub fn new(
82 window: Window,
83 context: &'static GraphicsContext,
84 descriptor: WindowContextDescriptor,
85 ) -> Self {
86 let scale_factor = window.window.scale_factor();
87 let Size { width, height } = window.size();
88 let (width, height) = (
89 (width as f64 * scale_factor) as u32,
90 (height as f64 * scale_factor) as u32,
91 );
92
93 let surface = context
94 .instance
95 .create_surface(window.window.clone())
96 .expect("Failed to create surface");
97
98 let mut config = surface
99 .get_default_config(&context.adapter, width, height)
100 .expect("Failed to get default surface configuration");
101
102 if let Some(format) = descriptor.format {
103 config.format = format;
104 }
105 if let Some(present_mode) = descriptor.present_mode {
106 config.present_mode = present_mode;
107 }
108 if let Some(alpha_mode) = descriptor.alpha_mode {
109 config.alpha_mode = alpha_mode;
110 }
111
112 surface.configure(&context.device, &config);
113
114 Self {
115 window,
116 surface,
117 config,
118 reconfigure: PendingReconfigure::new(),
119 context,
120 }
121 }
122
123 pub fn resized(&mut self, new_size: Size<u32>) {
125 let scale_factor = self.window.window.scale_factor();
126 self.reconfigure.resize = Some(PhysicalSize {
127 width: (new_size.width as f64 * scale_factor) as u32,
128 height: (new_size.height as f64 * scale_factor) as u32,
129 });
130 }
131
132 pub fn window(&self) -> &Window {
133 &self.window
134 }
135
136 pub fn graphics_context(&self) -> &GraphicsContext {
137 self.context
138 }
139
140 pub fn surface(&self) -> &wgpu::Surface<'static> {
141 &self.surface
142 }
143
144 pub fn surface_config(&self) -> &wgpu::SurfaceConfiguration {
145 &self.config
146 }
147
148 pub fn size(&self) -> Size<u32> {
150 self.window.size()
151 }
152
153 pub fn size_f32(&self) -> Size<f32> {
154 let size = self.size();
155 Size {
156 width: size.width as f32,
157 height: size.height as f32,
158 }
159 }
160
161 pub fn inner_size(&self) -> PhysicalSize<u32> {
163 self.window.inner_size()
164 }
165
166 pub fn reconfigure_surface(&mut self, config: wgpu::SurfaceConfiguration) {
168 self.config = config;
169 self.surface.configure(&self.context.device, &self.config);
170 }
171}
172
173impl WindowBackend for WindowContext {
174 type FrameContext = FrameContext;
175
176 fn begin_drawing(&mut self) -> Self::FrameContext {
177 profile_function!();
178
179 let mut configure_needed = false;
180 if let Some(new_size) = self.reconfigure.resize.take() {
181 self.config.width = new_size.width;
182 self.config.height = new_size.height;
183 configure_needed = true;
184 }
185
186 if configure_needed {
187 self.surface.configure(&self.context.device, &self.config);
188 }
189
190 let frame = self.surface.get_current_texture().unwrap();
191 let view = frame
192 .texture
193 .create_view(&wgpu::TextureViewDescriptor::default());
194
195 let encoder = self
196 .context
197 .device
198 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
199 label: Some("Frame Encoder"),
200 });
201
202 FrameContext {
203 surface: Some(Surface {
204 texture: frame,
205 view,
206 }),
207 encoder: Some(encoder),
208 context: self.context,
209 stats: FrameStats::new(),
210 window: self.window.window.clone(),
211 surface_format: self.config.format,
212 }
213 }
214}
215
216pub struct RenderableWindow {
218 pub(crate) context: WindowContext,
219}
220
221impl RenderableWindow {
222 pub fn new(window: Window, context: &'static GraphicsContext) -> Self {
223 Self::new_with_descriptor(window, context, WindowContextDescriptor::default())
224 }
225
226 pub fn new_with_descriptor(
227 window: Window,
228 context: &'static GraphicsContext,
229 descriptor: WindowContextDescriptor,
230 ) -> Self {
231 let context = WindowContext::new(window, context, descriptor);
232 Self { context }
233 }
234
235 pub fn id(&self) -> WindowId {
236 self.context.window.id()
237 }
238
239 pub fn window(&self) -> &Window {
240 &self.context.window
241 }
242
243 pub fn context(&self) -> &WindowContext {
244 &self.context
245 }
246
247 pub fn context_mut(&mut self) -> &mut WindowContext {
248 &mut self.context
249 }
250
251 pub fn resized(&mut self, new_size: Size<u32>) {
253 self.context.resized(new_size);
254 }
255
256 pub fn inner_size(&self) -> PhysicalSize<u32> {
258 self.context.inner_size()
259 }
260
261 pub fn scale_factor(&self) -> f64 {
262 self.window.window.scale_factor()
263 }
264
265 pub fn viewport(&self) -> Viewport {
266 let PhysicalSize { width, height } = self.inner_size();
267 let scale_factor = self.scale_factor();
268
269 Viewport {
270 x: 0.0,
271 y: 0.0,
272 width: width as f32,
273 height: height as f32,
274 scale_factor,
275 }
276 }
277}
278
279impl std::ops::Deref for RenderableWindow {
280 type Target = WindowContext;
281
282 fn deref(&self) -> &Self::Target {
283 &self.context
284 }
285}
286
287impl std::ops::DerefMut for RenderableWindow {
288 fn deref_mut(&mut self) -> &mut Self::Target {
289 &mut self.context
290 }
291}
292
293impl WindowBackend for RenderableWindow {
294 type FrameContext = FrameContext;
295
296 fn begin_drawing(&mut self) -> Self::FrameContext {
297 self.context.begin_drawing()
298 }
299}