1use crate::Color;
2use crate::ContextHandle;
3use crate::ImageInfo;
4use crate::ImageView;
5use crate::WindowId;
6use crate::WindowProxy;
7use crate::backend::Context;
8use crate::backend::util::GpuImage;
9use crate::backend::util::UniformsBuffer;
10use crate::error;
11use crate::event::EventHandlerControlFlow;
12use crate::event::WindowEvent;
13use glam::Vec3;
14use glam::{Affine2, Vec2};
15use indexmap::IndexMap;
16
17type DynWindowEventHandler = dyn FnMut(WindowHandle, &mut WindowEvent, &mut EventHandlerControlFlow);
19
20pub(crate) struct Window {
22 pub window: winit::window::Window,
24
25 pub preserve_aspect_ratio: bool,
27
28 pub background_color: Color,
30
31 pub surface: wgpu::Surface,
33
34 pub uniforms: UniformsBuffer<WindowUniforms>,
36
37 pub image: Option<GpuImage>,
39
40 pub overlays: IndexMap<String, Overlay>,
42
43 pub user_transform: Affine2,
47
48 pub event_handlers: Vec<Box<DynWindowEventHandler>>,
50}
51
52pub(crate) struct Overlay {
54 pub image: GpuImage,
56
57 pub visible: bool,
59}
60
61pub struct WindowHandle<'a> {
66 context_handle: ContextHandle<'a>,
68
69 index: usize,
71
72 destroy_flag: Option<&'a mut bool>,
74}
75
76impl<'a> WindowHandle<'a> {
77 pub fn new(context_handle: ContextHandle<'a>, index: usize, destroy_flag: Option<&'a mut bool>) -> Self {
79 Self { context_handle, index, destroy_flag }
80 }
81
82 fn context(&self) -> &Context {
84 self.context_handle().context
85 }
86
87 unsafe fn context_mut(&mut self) -> &mut Context {
93 self.context_handle.context
94 }
95
96 fn window(&self) -> &Window {
98 &self.context().windows[self.index]
99 }
100
101 fn window_mut(&mut self) -> &mut Window {
103 let index = self.index;
104 unsafe { &mut self.context_mut().windows[index] }
105 }
106
107 pub fn id(&self) -> WindowId {
109 self.window().id()
110 }
111
112 pub fn proxy(&self) -> WindowProxy {
118 WindowProxy::new(self.id(), self.context_handle.proxy())
119 }
120
121 pub fn release(self) -> ContextHandle<'a> {
126 self.context_handle
127 }
128
129 pub fn context_handle(&self) -> &ContextHandle<'a> {
133 &self.context_handle
134 }
135
136 pub fn destroy(self) -> ContextHandle<'a> {
140 let WindowHandle { context_handle, index, destroy_flag } = self;
141 context_handle.context.windows.remove(index);
142 if let Some(destroy_flag) = destroy_flag {
143 *destroy_flag = true;
144 }
145 context_handle
146 }
147
148 pub fn set_title(&self, title: impl AsRef<str>) {
150 self.window().window.set_title(title.as_ref());
151 }
152
153 pub fn image_info(&self) -> Option<&ImageInfo> {
157 Some(self.window().image.as_ref()?.info())
158 }
159
160 pub fn preserve_aspect_ratio(&self) -> bool {
162 self.window().preserve_aspect_ratio
163 }
164
165 pub fn set_preserve_aspect_ratio(&mut self, preserve_aspect_ratio: bool) {
167 self.window_mut().preserve_aspect_ratio = preserve_aspect_ratio;
168 self.window().window.request_redraw();
169 }
170
171 pub fn background_color(&self) -> Color {
173 self.window().background_color
174 }
175
176 pub fn set_background_color(&mut self, background_color: Color) {
178 self.window_mut().background_color = background_color;
179 self.window().window.request_redraw();
180 }
181
182 pub fn set_visible(&mut self, visible: bool) {
184 self.window_mut().set_visible(visible);
185 self.window().window.request_redraw();
186 }
187
188 pub fn set_outer_position(&self, position: impl Into<glam::IVec2>) {
194 let position = position.into();
195 self.window().window.set_outer_position(winit::dpi::PhysicalPosition::new(position.x, position.y));
196 }
197
198 pub fn inner_size(&self) -> glam::UVec2 {
202 let size = self.window().window.inner_size();
203 glam::UVec2::new(size.width, size.height)
204 }
205
206 pub fn outer_size(&self) -> glam::UVec2 {
210 let size = self.window().window.outer_size();
211 glam::UVec2::new(size.width, size.height)
212 }
213
214 pub fn set_inner_size(&mut self, size: impl Into<glam::UVec2>) {
220 let size = size.into();
221 self.window_mut().window.set_inner_size(winit::dpi::PhysicalSize::new(size.x, size.y));
222 self.window().window.request_redraw();
223 }
224
225 pub fn set_resizable(&mut self, resizable: bool) {
229 self.window().window.set_resizable(resizable);
230 }
231
232 pub fn set_borderless(&mut self, borderless: bool) {
236 self.window().window.set_decorations(!borderless);
237 }
238
239 pub fn set_fullscreen(&mut self, fullscreen: bool) {
246 let opt = if fullscreen {
247 Some(winit::window::Fullscreen::Borderless(None))
248 } else {
249 None
250 };
251 self.window().window.set_fullscreen(opt);
252 }
253
254 pub fn is_fullscreen(&self) -> bool {
259 self.window().window.fullscreen().is_some()
260 }
261
262 pub fn set_image(&mut self, name: impl Into<String>, image: &ImageView) {
264 let image = self.context().make_gpu_image(name, image);
265 self.window_mut().image = Some(image);
266 self.window_mut().uniforms.mark_dirty(true);
267 self.window_mut().window.request_redraw();
268 }
269
270 pub fn set_overlay(&mut self, name: impl Into<String>, image: &ImageView, initially_visible: bool) {
280 use indexmap::map::Entry;
281
282 let name = name.into();
283 let image = self.context().make_gpu_image(name.clone(), image);
284 match self.window_mut().overlays.entry(name) {
285 Entry::Occupied(mut entry) => {
286 entry.get_mut().image = image;
287 },
288 Entry::Vacant(entry) => {
289 entry.insert(Overlay {
290 image,
291 visible: initially_visible,
292 });
293 },
294 };
295 self.window().window.request_redraw()
296 }
297
298 pub fn remove_overlay(&mut self, name: &impl AsRef<str>) -> bool {
302 let removed = self.window_mut().overlays.shift_remove(name.as_ref()).is_some();
303 self.window().window.request_redraw();
304 removed
305 }
306
307 pub fn clear_overlays(&mut self) {
309 self.window_mut().overlays.clear();
310 self.window().window.request_redraw()
311 }
312
313 pub fn is_overlay_visible(&mut self, name: impl AsRef<str>) -> Result<bool, error::UnknownOverlay> {
315 Ok(self.window().get_overlay(name)?.visible)
316 }
317
318 pub fn set_overlay_visible(&mut self, name: impl AsRef<str>, visible: bool) -> Result<(), error::UnknownOverlay> {
322 self.window_mut().get_overlay_mut(name)?.visible = visible;
323 self.window().window.request_redraw();
324 Ok(())
325 }
326
327 pub fn toggle_overlay_visible(&mut self, name: impl AsRef<str>) -> Result<(), error::UnknownOverlay> {
329 let overlay = self.window_mut().get_overlay_mut(name)?;
330 overlay.visible = !overlay.visible;
331 self.window().window.request_redraw();
332 Ok(())
333 }
334
335 pub fn set_all_overlays_visible(&mut self, visible: bool) {
337 for (_name, overlay) in &mut self.window_mut().overlays {
338 overlay.visible = visible;
339 }
340 self.window().window.request_redraw()
341 }
342
343 pub fn add_event_handler<F>(&mut self, handler: F)
345 where
346 F: 'static + FnMut(WindowHandle, &mut WindowEvent, &mut EventHandlerControlFlow),
347 {
348 self.window_mut().event_handlers.push(Box::new(handler))
349 }
350
351 pub fn transform(&self) -> Affine2 {
360 self.window().user_transform
361 }
362
363 pub fn effective_transform(&self) -> Affine2 {
375 self.window().calculate_uniforms().transform
376 }
377
378 pub fn set_transform(&mut self, transform: Affine2) {
386 self.window_mut().user_transform = transform;
387 self.window_mut().uniforms.mark_dirty(true);
388 self.window().window.request_redraw();
389 }
390
391 pub fn pre_apply_transform(&mut self, transform: Affine2) {
403 self.set_transform(transform * self.transform());
404 }
405
406 pub fn post_apply_transform(&mut self, transform: Affine2) {
418 self.set_transform(self.transform() * transform)
419 }
420}
421
422#[derive(Debug, Clone)]
424pub struct WindowOptions {
425 pub preserve_aspect_ratio: bool,
427
428 pub background_color: Color,
432
433 pub start_hidden: bool,
437
438 pub size: Option<[u32; 2]>,
442
443 pub resizable: bool,
447
448 pub borderless: bool,
452
453 pub fullscreen: bool,
457
458 pub overlays_visible: bool,
462
463 pub default_controls: bool,
467}
468
469impl Default for WindowOptions {
470 fn default() -> Self {
471 Self::new()
472 }
473}
474
475impl WindowOptions {
476 pub fn new() -> Self {
478 Self {
479 preserve_aspect_ratio: true,
480 background_color: Color::black(),
481 start_hidden: false,
482 size: None,
483 resizable: true,
484 borderless: false,
485 fullscreen: false,
486 overlays_visible: true,
487 default_controls: true,
488 }
489 }
490
491 pub fn set_preserve_aspect_ratio(mut self, preserve_aspect_ratio: bool) -> Self {
495 self.preserve_aspect_ratio = preserve_aspect_ratio;
496 self
497 }
498
499 pub fn set_background_color(mut self, background_color: Color) -> Self {
503 self.background_color = background_color;
504 self
505 }
506
507 pub fn set_start_hidden(mut self, start_hidden: bool) -> Self {
511 self.start_hidden = start_hidden;
512 self
513 }
514
515 pub fn set_size(mut self, size: impl Into<Option<[u32; 2]>>) -> Self {
524 self.size = size.into();
525 self
526 }
527
528 pub fn set_resizable(mut self, resizable: bool) -> Self {
534 self.resizable = resizable;
535 self
536 }
537
538 pub fn set_borderless(mut self, borderless: bool) -> Self {
542 self.borderless = borderless;
543 self
544 }
545
546 pub fn set_fullscreen(mut self, fullscreen: bool) -> Self {
550 self.fullscreen = fullscreen;
551 self
552 }
553
554 pub fn set_show_overlays(mut self, overlays_visible: bool) -> Self {
556 self.overlays_visible = overlays_visible;
557 self
558 }
559
560 pub fn set_default_controls(mut self, default_controls: bool) -> Self {
562 self.default_controls = default_controls;
563 self
564 }
565}
566
567impl Window {
568 pub fn id(&self) -> WindowId {
570 self.window.id()
571 }
572
573 pub fn set_visible(&mut self, visible: bool) {
575 self.window.set_visible(visible);
576 }
577
578 pub fn calculate_uniforms(&self) -> WindowUniforms {
580 if let Some(image) = &self.image {
581 let image_size = image.info().size.as_vec2();
582 if !self.preserve_aspect_ratio {
583 WindowUniforms::stretch(image_size)
584 .pre_apply_transform(self.user_transform)
585 } else {
586 let window_size = glam::UVec2::new(self.window.inner_size().width, self.window.inner_size().height).as_vec2();
587 WindowUniforms::fit(window_size, image_size)
588 .pre_apply_transform(self.user_transform)
589 }
590 } else {
591 WindowUniforms {
592 transform: self.user_transform,
593 image_size: Vec2::new(0.0, 0.0),
594 }
595 }
596 }
597
598 fn get_overlay(&self, name: impl AsRef<str>) -> Result<&Overlay, error::UnknownOverlay> {
599 let name = name.as_ref();
600 self.overlays.get(name)
601 .ok_or_else(|| error::UnknownOverlay { name: name.into() })
602 }
603
604 fn get_overlay_mut(&mut self, name: impl AsRef<str>) -> Result<&mut Overlay, error::UnknownOverlay> {
605 let name = name.as_ref();
606 self.overlays.get_mut(name)
607 .ok_or_else(|| error::UnknownOverlay { name: name.into() })
608 }
609}
610
611#[derive(Debug, Copy, Clone)]
613pub(crate) struct WindowUniforms {
614 pub transform: Affine2,
619
620 pub image_size: Vec2,
622}
623
624impl WindowUniforms {
625 pub fn no_image() -> Self {
626 Self::stretch(Vec2::new(0.0, 0.0))
627 }
628
629 pub fn stretch(image_size: Vec2) -> Self {
630 Self {
631 transform: Affine2::IDENTITY,
632 image_size,
633 }
634 }
635
636 pub fn fit(window_size: Vec2, image_size: Vec2) -> Self {
637 let ratios = image_size / window_size;
638
639 let w;
640 let h;
641 if ratios.x >= ratios.y {
642 w = 1.0;
643 h = ratios.y / ratios.x;
644 } else {
645 w = ratios.x / ratios.y;
646 h = 1.0;
647 }
648
649 let transform = Affine2::from_scale_angle_translation(Vec2::new(w, h), 0.0, 0.5 * Vec2::new(1.0 - w, 1.0 - h));
650 Self {
651 transform,
652 image_size,
653 }
654 }
655
656 pub fn pre_apply_transform(mut self, transform: Affine2) -> Self {
658 self.transform = transform * self.transform;
659 self
660 }
661}
662
663#[repr(C, align(8))]
664#[derive(Debug, Copy, Clone)]
665struct Vec2A8 {
666 pub x: f32,
667 pub y: f32,
668}
669
670#[repr(C, align(16))]
671#[derive(Debug, Copy, Clone)]
672struct Vec3A16 {
673 pub x: f32,
674 pub y: f32,
675 pub z: f32,
676}
677
678#[repr(C)]
679#[derive(Debug, Copy, Clone)]
680struct Mat3x3 {
681 pub cols: [Vec3A16; 3]
682}
683
684impl Vec2A8 {
685 pub const fn new(x: f32, y: f32) -> Self {
686 Self { x, y }
687 }
688}
689
690impl Vec3A16 {
691 pub const fn new(x: f32, y: f32, z: f32) -> Self {
692 Self { x, y, z }
693 }
694}
695
696impl Mat3x3 {
697 pub const fn new(col0: Vec3A16, col1: Vec3A16, col2: Vec3A16) -> Self {
698 Self {
699 cols: [col0, col1, col2],
700 }
701 }
702}
703
704impl From<Vec2> for Vec2A8 {
705 fn from(other: Vec2) -> Self {
706 Self::new(other.x, other.y)
707 }
708}
709
710impl From<Vec3> for Vec3A16 {
711 fn from(other: Vec3) -> Self {
712 Self::new(other.x, other.y, other.z)
713 }
714}
715
716impl From<Affine2> for Mat3x3 {
717 fn from(other: Affine2) -> Self {
718 let x_axis = other.matrix2.x_axis;
719 let y_axis = other.matrix2.y_axis;
720 let z_axis = other.translation;
721 Self::new(
722 Vec3A16::new(x_axis.x, x_axis.y, 0.0),
723 Vec3A16::new(y_axis.x, y_axis.y, 0.0),
724 Vec3A16::new(z_axis.x, z_axis.y, 1.0),
725 )
726 }
727}
728
729#[repr(C)]
731#[derive(Debug, Copy, Clone)]
732pub struct WindowUniformsStd140 {
733 image_size: Vec2A8,
734 transform: Mat3x3,
735}
736
737unsafe impl crate::backend::util::ToStd140 for WindowUniforms {
738 type Output = WindowUniformsStd140;
739
740 fn to_std140(&self) -> Self::Output {
741 Self::Output {
742 image_size: self.image_size.into(),
743 transform: self.transform.into(),
744 }
745 }
746}
747
748pub(super) fn default_controls_handler(mut window: WindowHandle, event: &mut crate::event::WindowEvent, _control_flow: &mut crate::event::EventHandlerControlFlow) {
750 match event {
751 WindowEvent::MouseWheel(event) => {
752 let delta = match event.delta {
753 winit::event::MouseScrollDelta::LineDelta(_x, y) => y,
754 winit::event::MouseScrollDelta::PixelDelta(delta) => delta.y as f32 / 20.0,
755 };
756 let scale = 1.1f32.powf(delta);
757
758 let origin = event.position
759 .map(|pos| pos / window.inner_size().as_vec2())
760 .unwrap_or_else(|| glam::Vec2::new(0.5, 0.5));
761 let transform = glam::Affine2::from_scale_angle_translation(glam::Vec2::splat(scale), 0.0, origin - scale * origin);
762 window.pre_apply_transform(transform);
763 },
764 WindowEvent::MouseMove(event) => {
765 if event.buttons.is_pressed(crate::event::MouseButton::Left) {
766 let translation = (event.position - event.prev_position) / window.inner_size().as_vec2();
767 window.pre_apply_transform(Affine2::from_translation(translation));
768 }
769 },
770 _ => (),
771 }
772}