1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use limelight::Uniform;

pub struct TransformUniform {
    scale: (f32, f32),
    center: (f32, f32),
    uniform: Uniform<[[f32; 4]; 4]>,
    shear: (f32, f32),
}

fn scale_center_to_matrix(
    (scale_x, scale_y): (f32, f32),
    (center_x, center_y): (f32, f32),
    (shear_x, shear_y): (f32, f32),
) -> [[f32; 4]; 4] {
    [
        [scale_x, 0., 0., -center_x],
        [0., scale_y, 0., -center_y],
        [0., 0., 1., 0.],
        [shear_x, shear_y, 0., 1.],
    ]
}

impl Default for TransformUniform {
    fn default() -> Self {
        Self::new()
    }
}

impl TransformUniform {
    pub fn new() -> Self {
        let scale = (1., 1.);
        let center = (0., 0.);
        let shear = (0., 0.);
        let uniform = Uniform::new(scale_center_to_matrix(scale, center, shear));
        TransformUniform {
            scale,
            center,
            shear,
            uniform,
        }
    }

    pub fn uniform(&self) -> Uniform<[[f32; 4]; 4]> {
        self.uniform.clone()
    }

    fn update_uniform(&self) {
        self.uniform
            .set_value(scale_center_to_matrix(self.scale, self.center, self.shear));
    }

    /// Multiply the current scale, in such a way that the given point
    /// remains stationary.
    ///
    /// i.e. if `v * self.uniform.value = scale_center` is true before the
    /// scale is applied, it should also be true after.
    pub fn scale(&mut self, scale_factor: f32, scale_center: (f32, f32)) {
        let old_scale_x = self.scale.0;
        let old_scale_y = self.scale.1;

        self.scale.0 *= scale_factor;
        self.scale.1 *= scale_factor;

        self.center.0 =
            (self.scale.0 / old_scale_x) * (scale_center.0 + self.center.0) - scale_center.0;
        self.center.1 =
            (self.scale.1 / old_scale_y) * (scale_center.1 + self.center.1) - scale_center.1;

        self.update_uniform();
    }

    // Pan by the given amount, provided in destination units.
    pub fn pan(&mut self, vector: (f32, f32)) {
        self.center.0 -= vector.0;
        self.center.1 -= vector.1;
        self.update_uniform();
    }

    pub fn shear(&mut self, vector: (f32, f32)) {
        self.shear.0 -= vector.0;
        self.shear.1 -= vector.1;
        self.update_uniform();
    }
}