Skip to main content

three_d/renderer/control/
control2d.rs

1use super::*;
2
3///
4/// A control for 2D camera movements.
5///
6#[derive(Clone, Copy, Debug)]
7pub struct Control2D {
8    /// The minimum zoom factor.
9    pub min_zoom_factor: f32,
10    /// The maximum zoom factor.
11    pub max_zoom_factor: f32,
12}
13
14impl Control2D {
15    /// Creates a new 2D camera control with the given minimum and maximum zoom factor.
16    pub fn new(min_zoom_factor: f32, max_zoom_factor: f32) -> Self {
17        Self {
18            min_zoom_factor,
19            max_zoom_factor,
20        }
21    }
22
23    /// Handles the events. Must be called each frame.
24    pub fn handle_events(
25        &mut self,
26        camera: &mut three_d_asset::Camera,
27        events: &mut [Event],
28        device_pixel_ratio: f32,
29    ) -> bool {
30        let mut change = false;
31        for event in events.iter_mut() {
32            match event {
33                Event::PinchGesture {
34                    delta,
35                    position,
36                    handled,
37                    ..
38                } if !*handled => {
39                    self.zoom(camera, *delta, *position, 0.5);
40                    *handled = true;
41                    change = true;
42                }
43                Event::MouseWheel {
44                    delta,
45                    position,
46                    handled,
47                    ..
48                } if !*handled && delta.0.abs() + delta.1.abs() > f32::EPSILON => {
49                    if delta.0.abs() < f32::EPSILON && delta.1.fract().abs() > f32::EPSILON {
50                        self.zoom(camera, delta.1, *position, 0.005);
51                    } else {
52                        self.pan(camera, *delta, device_pixel_ratio);
53                    }
54                    *handled = true;
55                    change = true;
56                }
57                Event::MouseMotion {
58                    delta,
59                    button,
60                    handled,
61                    ..
62                } if !*handled && Some(MouseButton::Right) == *button => {
63                    self.pan(camera, *delta, device_pixel_ratio);
64                    *handled = true;
65                    change = true;
66                }
67                _ => {}
68            }
69        }
70        change
71    }
72
73    fn zoom(
74        &self,
75        camera: &mut three_d_asset::Camera,
76        delta: f32,
77        position: PhysicalPoint,
78        sensitivity: f32,
79    ) {
80        let mut target = camera.position_at_pixel(position);
81        target.z = 0.0;
82        let distance = 1.0 / camera.zoom_factor();
83        let zoom_amount = distance * (1.0 - (-delta * sensitivity).exp());
84        camera.zoom_towards(
85            target,
86            zoom_amount,
87            1.0 / self.max_zoom_factor,
88            1.0 / self.min_zoom_factor,
89        );
90    }
91
92    fn pan(&self, camera: &mut three_d_asset::Camera, delta: (f32, f32), device_pixel_ratio: f32) {
93        let origo = camera.position_at_pixel(vec2(0.0, 0.0));
94        let point = camera.position_at_pixel(vec2(device_pixel_ratio * delta.0, 0.0));
95        let x = delta.0.signum() * (point - origo).magnitude();
96        let point = camera.position_at_pixel(vec2(device_pixel_ratio * delta.1, 0.0));
97        let y = delta.1.signum() * (point - origo).magnitude();
98        let right = camera.right_direction();
99        let up = right.cross(camera.view_direction());
100        camera.translate(-right * x + up * y);
101    }
102}