show_image/backend/
window.rs

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
17/// Internal shorthand for window event handlers.
18type DynWindowEventHandler = dyn FnMut(WindowHandle, &mut WindowEvent, &mut EventHandlerControlFlow);
19
20/// Window capable of displaying images using wgpu.
21pub(crate) struct Window {
22	/// The winit window.
23	pub window: winit::window::Window,
24
25	/// If true, preserve the aspect ratio of images.
26	pub preserve_aspect_ratio: bool,
27
28	/// The background color of the window.
29	pub background_color: Color,
30
31	/// The wgpu surface to render to.
32	pub surface: wgpu::Surface,
33
34	/// The window specific uniforms for the render pipeline.
35	pub uniforms: UniformsBuffer<WindowUniforms>,
36
37	/// The image to display (if any).
38	pub image: Option<GpuImage>,
39
40	/// Overlays for the window.
41	pub overlays: IndexMap<String, Overlay>,
42
43	/// Transformation to apply to the image, in virtual window space.
44	///
45	/// Virtual window space goes from (0, 0) in the top left to (1, 1) in the bottom right.
46	pub user_transform: Affine2,
47
48	/// The event handlers for this specific window.
49	pub event_handlers: Vec<Box<DynWindowEventHandler>>,
50}
51
52/// An overlay added to a window.
53pub(crate) struct Overlay {
54	/// The image to show.
55	pub image: GpuImage,
56
57	/// If true, show the overlay, otherwise do not.
58	pub visible: bool,
59}
60
61/// Handle to a window.
62///
63/// A [`WindowHandle`] can be used to interact with a window from within the global context thread.
64/// To interact with a window from another thread, you need a [`WindowProxy`].
65pub struct WindowHandle<'a> {
66	/// The context handle to use.
67	context_handle: ContextHandle<'a>,
68
69	/// The index of the window in [`Context::windows`].
70	index: usize,
71
72	/// Flag to signal to the handle creator that the window was destroyed.
73	destroy_flag: Option<&'a mut bool>,
74}
75
76impl<'a> WindowHandle<'a> {
77	/// Create a new window handle from a context handle and a window ID.
78	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	/// Get a reference to the context.
83	fn context(&self) -> &Context {
84		self.context_handle().context
85	}
86
87	/// Get a mutable reference to the context.
88	///
89	/// # Safety
90	/// The current window may not be moved or removed through the returned reference.
91	/// In practise, this means that you may not create or destroy any windows.
92	unsafe fn context_mut(&mut self) -> &mut Context {
93		self.context_handle.context
94	}
95
96	/// Get a reference to the window.
97	fn window(&self) -> &Window {
98		&self.context().windows[self.index]
99	}
100
101	/// Get a mutable reference to the window.
102	fn window_mut(&mut self) -> &mut Window {
103		let index = self.index;
104		unsafe { &mut self.context_mut().windows[index] }
105	}
106
107	/// Get the window ID.
108	pub fn id(&self) -> WindowId {
109		self.window().id()
110	}
111
112	/// Get a proxy object for the window to interact with it from a different thread.
113	///
114	/// You should not use proxy objects from withing the global context thread.
115	/// The proxy objects often wait for the global context to perform some action.
116	/// Doing so from within the global context thread would cause a deadlock.
117	pub fn proxy(&self) -> WindowProxy {
118		WindowProxy::new(self.id(), self.context_handle.proxy())
119	}
120
121	/// Release the window handle to get a [`ContextHandle`].
122	///
123	/// This can be used inside a window event handler to gain access to the [`ContextHandle`].
124	/// If you do not need mutable access to the context, you can also use [`context_handle()`](Self::context_handle).
125	pub fn release(self) -> ContextHandle<'a> {
126		self.context_handle
127	}
128
129	/// Get a reference to the context handle.
130	///
131	/// If you need mutable access to the context, use [`release()`](Self::release) instead.
132	pub fn context_handle(&self) -> &ContextHandle<'a> {
133		&self.context_handle
134	}
135
136	/// Destroy the window.
137	///
138	/// Any subsequent operation on the window through an existing [`WindowProxy`] will return [`InvalidWindowId`](crate::error::InvalidWindowId).
139	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	/// Set the title of the window.
149	pub fn set_title(&self, title: impl AsRef<str>) {
150		self.window().window.set_title(title.as_ref());
151	}
152
153	/// Get the image info.
154	///
155	/// Returns [`None`] if no image is set for the window.
156	pub fn image_info(&self) -> Option<&ImageInfo> {
157		Some(self.window().image.as_ref()?.info())
158	}
159
160	/// Check if the window will preserve the aspect ratio of images it displays.
161	pub fn preserve_aspect_ratio(&self) -> bool {
162		self.window().preserve_aspect_ratio
163	}
164
165	/// Set if the window will preserve the aspect ratio of images it displays.
166	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	/// Get the background color of the window.
172	pub fn background_color(&self) -> Color {
173		self.window().background_color
174	}
175
176	/// Set the background color of the window.
177	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	/// Make the window visible or invisible.
183	pub fn set_visible(&mut self, visible: bool) {
184		self.window_mut().set_visible(visible);
185		self.window().window.request_redraw();
186	}
187
188	/// Set the window position in pixels.
189	///
190	/// This will automatically un-maximize the window.
191	///
192	/// Some window managers or platforms may ignore this property.
193	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	/// Get the inner size of the window in physical pixels.
199	///
200	/// This returns the size of the window contents, excluding borders, the title bar and other decorations.
201	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	/// Get the outer size of the window in physical pixels.
207	///
208	/// This returns the size of the entire window, including borders, the title bar and other decorations.
209	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	/// Set the inner size of the window in pixels.
215	///
216	/// The size is excluding borders, the title bar and other decorations.
217	///
218	/// Some window managers may ignore this property.
219	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	/// Set if the window should be resizable for the user.
226	///
227	/// Some window managers may ignore this property.
228	pub fn set_resizable(&mut self, resizable: bool) {
229		self.window().window.set_resizable(resizable);
230	}
231
232	/// Set if the window should be drawn without borders.
233	///
234	/// Some window managers may ignore this property.
235	pub fn set_borderless(&mut self, borderless: bool) {
236		self.window().window.set_decorations(!borderless);
237	}
238
239	/// Set the window in fullscreen mode or back.
240	///
241	/// This will set the window to borderless fullscreen on the current monitor or back.
242	/// Fullscreen is set if the argument is `true`, otherwise the window is returned to normal size.
243	///
244	/// Some window managers may ignore this property.
245	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	/// Check if the window is set to fullscreen mode.
255	///
256	/// Note that some window managers may ignore the request for fullscreen mode.
257	/// In that case, this function may return true while the window is not displayed in fullscreen mode.
258	pub fn is_fullscreen(&self) -> bool {
259		self.window().window.fullscreen().is_some()
260	}
261
262	/// Set the image to display on the window.
263	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	/// Add an overlay to the window.
271	///
272	/// Overlays are drawn on top of the image in the order that they are first added.
273	/// If you wish to change the order of existing overlays, you must remove and re-add the overlays.
274	///
275	/// If the window already has an overlay with the same name,
276	/// the overlay is overwritten and the `initially_visible` argument is ignored.
277	/// If you want to change the visibility of the overlay, you can call [`set_overlay_visible()`][Self::set_overlay_visible].
278	/// If you do so before your function returns, it is guaranteed to have taken effect before the next redraw.
279	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	/// Remove an overlay from the window.
299	///
300	/// Returns `true` if there was an overlay to remove.
301	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	/// Remove all overlays from the window.
308	pub fn clear_overlays(&mut self) {
309		self.window_mut().overlays.clear();
310		self.window().window.request_redraw()
311	}
312
313	/// Check if an overlay is visible or not.
314	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	/// Make a specific overlay visible or invisible for this window.
319	///
320	/// The overlay is not removed, but it will not be rendered anymore untill you make it visible again.
321	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	/// Toggle an overlay between visible and invisible.
328	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	/// Make all overlays visible or invisible for this window.
336	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	/// Add an event handler to the window.
344	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	/// Get the image transformation.
352	///
353	/// The image transformation is applied to the image and all overlays in virtual window space.
354	///
355	/// Virtual window space goes from `(0, 0)` in the top left corner of the window to `(1, 1)` in the bottom right corner.
356	///
357	/// This transformation does not include scaling introduced by the [`Self::preserve_aspect_ratio()`] property.
358	/// Use [`Self::effective_transform()`] if you need that.
359	pub fn transform(&self) -> Affine2 {
360		self.window().user_transform
361	}
362
363	/// Get the full effective transformation from image space to virtual window space.
364	///
365	/// This transformation maps the image coordinates to virtual window coordinates.
366	/// Unlike [`Self::transform()`], this function returns a transformation that include the scaling introduced by the [`Self::preserve_aspect_ratio()`] property.
367	/// This is useful to transform between window coordinates and image coordinates.
368	///
369	/// If no image is set on the window yet, this returns the same transformation as [`Self::transform()`].
370	///
371	/// Virtual window space goes from `(0, 0)` in the top left corner of the window to `(1, 1)` in the bottom right corner.
372	///
373	/// Note that physical pixel locations must be transformed to virtual window coordinates first.
374	pub fn effective_transform(&self) -> Affine2 {
375		self.window().calculate_uniforms().transform
376	}
377
378	/// Set the image transformation to a value.
379	///
380	/// The image transformation is applied to the image and all overlays in virtual window space.
381	///
382	/// Virtual window space goes from `(0, 0)` in the top left corner of the window to `(1, 1)` in the bottom right corner.
383	///
384	/// This transformation should not include any scaling related to the [`Self::preserve_aspect_ratio()`] property.
385	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	/// Pre-apply a transformation to the existing image transformation.
392	///
393	/// This is equivalent to:
394	/// ```
395	/// # use show_image::{glam::Affine2, WindowHandle};
396	/// # fn foo(window: &mut WindowHandle, transform: Affine2) {
397	/// window.set_transform(transform * window.transform())
398	/// # }
399	/// ```
400	///
401	/// See [`Self::set_transform`] for more information about the image transformation.
402	pub fn pre_apply_transform(&mut self, transform: Affine2) {
403		self.set_transform(transform * self.transform());
404	}
405
406	/// Post-apply a transformation to the existing image transformation.
407	///
408	/// This is equivalent to:
409	/// ```
410	/// # use show_image::{glam::Affine2, WindowHandle};
411	/// # fn foo(window: &mut WindowHandle, transform: Affine2) {
412	/// window.set_transform(window.transform() * transform)
413	/// # }
414	/// ```
415	///
416	/// See [`Self::set_transform`] for more information about the image transformation.
417	pub fn post_apply_transform(&mut self, transform: Affine2) {
418		self.set_transform(self.transform() * transform)
419	}
420}
421
422/// Options for creating a new window.
423#[derive(Debug, Clone)]
424pub struct WindowOptions {
425	/// Preserve the aspect ratio of the image when scaling.
426	pub preserve_aspect_ratio: bool,
427
428	/// The background color for the window.
429	///
430	/// This is used to color areas without image data if `preserve_aspect_ratio` is true.
431	pub background_color: Color,
432
433	/// Create the window hidden.
434	///
435	/// The window can manually be made visible at a later time.
436	pub start_hidden: bool,
437
438	/// The initial size of the window in pixel.
439	///
440	/// This may be ignored by some window managers.
441	pub size: Option<[u32; 2]>,
442
443	/// If true allow the window to be resized.
444	///
445	/// This may be ignored by some window managers.
446	pub resizable: bool,
447
448	/// Make the window borderless.
449	///
450	/// This may be ignored by some window managers.
451	pub borderless: bool,
452
453	/// Make the window fullscreen.
454	///
455	/// This may be ignored by some window managers.
456	pub fullscreen: bool,
457
458	/// If true, draw overlays on the image.
459	///
460	/// Defaults to true.
461	pub overlays_visible: bool,
462
463	/// If true, enable default mouse based controls for panning and zooming the image.
464	///
465	/// Defaults to true.
466	pub default_controls: bool,
467}
468
469impl Default for WindowOptions {
470	fn default() -> Self {
471		Self::new()
472	}
473}
474
475impl WindowOptions {
476	/// Create new window options with default values.
477	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	/// Preserve the aspect ratio of displayed images, or not.
492	///
493	/// This function consumes and returns `self` to allow daisy chaining.
494	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	/// Set the background color of the window.
500	///
501	/// This function consumes and returns `self` to allow daisy chaining.
502	pub fn set_background_color(mut self, background_color: Color) -> Self {
503		self.background_color = background_color;
504		self
505	}
506
507	/// Start the window hidden.
508	///
509	/// This function consumes and returns `self` to allow daisy chaining.
510	pub fn set_start_hidden(mut self, start_hidden: bool) -> Self {
511		self.start_hidden = start_hidden;
512		self
513	}
514
515	/// Set the initial size of the window.
516	///
517	/// Pass [`None`] to clear a previously set value,
518	/// which will let the window manager choose the initial size.
519	///
520	/// This property may be ignored by some window managers.
521	///
522	/// This function consumes and returns `self` to allow daisy chaining.
523	pub fn set_size(mut self, size: impl Into<Option<[u32; 2]>>) -> Self {
524		self.size = size.into();
525		self
526	}
527
528	/// Make the window resizable or not.
529	///
530	/// This property may be ignored by some window managers.
531	///
532	/// This function consumes and returns `self` to allow daisy chaining.
533	pub fn set_resizable(mut self, resizable: bool) -> Self {
534		self.resizable = resizable;
535		self
536	}
537
538	/// Make the window borderless or not.
539	///
540	/// This function consumes and returns `self` to allow daisy chaining.
541	pub fn set_borderless(mut self, borderless: bool) -> Self {
542		self.borderless = borderless;
543		self
544	}
545
546	/// Make the window fullscreen or not.
547	///
548	/// This function consumes and returns `self` to allow daisy chaining.
549	pub fn set_fullscreen(mut self, fullscreen: bool) -> Self {
550		self.fullscreen = fullscreen;
551		self
552	}
553
554	/// Set whether or not overlays should be drawn on the window.
555	pub fn set_show_overlays(mut self, overlays_visible: bool) -> Self {
556		self.overlays_visible = overlays_visible;
557		self
558	}
559
560	/// Set whether or not default mouse controls for panning and zooming the image should be added.
561	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	/// Get the window ID.
569	pub fn id(&self) -> WindowId {
570		self.window.id()
571	}
572
573	/// Make the window visible or invisible.
574	pub fn set_visible(&mut self, visible: bool) {
575		self.window.set_visible(visible);
576	}
577
578	/// Recalculate the uniforms for the render pipeline from the window state.
579	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/// The window specific uniforms for the render pipeline.
612#[derive(Debug, Copy, Clone)]
613pub(crate) struct WindowUniforms {
614	/// The transformation applied to the image.
615	///
616	/// With the identity transform, the image is stretched to the inner window size,
617	/// without preserving the aspect ratio.
618	pub transform: Affine2,
619
620	/// The size of the image in pixels.
621	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	/// Pre-apply a transformation.
657	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/// Window specific unfiforms, layout compatible with glsl std140.
730#[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
748/// Event handler that implements the default controls.
749pub(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}