vger/
paint.rs

1use crate::color::*;
2use crate::defs::*;
3
4#[derive(Clone, Copy)]
5#[repr(C)]
6pub struct Paint {
7    xform: LocalTransform, // mat3x2<f32>
8
9    glow: f32,
10    pub image: i32,
11
12    inner_color: Color, // vec4<f32>
13    outer_color: Color, // vec4<f32>
14}
15
16impl Paint {
17    #[allow(dead_code)]
18    pub fn apply(&self, p: LocalPoint) -> Color {
19        let local_point = self.xform.transform_point(p);
20        let d = local_point
21            .clamp(LocalPoint::zero(), LocalPoint::new(1.0, 1.0))
22            .x;
23
24        self.inner_color.mix(self.outer_color, d)
25    }
26
27    pub fn solid_color(color: Color) -> Self {
28        Self {
29            xform: LocalTransform::identity(),
30            inner_color: color,
31            outer_color: color,
32            image: -1,
33            glow: 0.0,
34        }
35    }
36
37    pub fn linear_gradient(
38        start: LocalPoint,
39        end: LocalPoint,
40        inner_color: Color,
41        outer_color: Color,
42        glow: f32,
43    ) -> Self {
44        // Calculate transform aligned to the line
45        let mut d = end - start;
46        if d.length() < 0.0001 {
47            d = LocalVector::new(0.0, 1.0);
48        }
49
50        let xform = LocalTransform::new(d.x, d.y, -d.y, d.x, start.x, start.y)
51            .inverse()
52            .unwrap();
53
54        Self {
55            xform,
56            inner_color,
57            outer_color,
58            image: -1,
59            glow,
60        }
61    }
62}
63
64#[cfg(test)]
65mod tests {
66
67    use super::*;
68
69    #[test]
70    fn test_paint_size() {
71        assert_eq!(std::mem::size_of::<Paint>(), 64);
72    }
73
74    #[test]
75    fn test_linear_gradient() {
76        {
77            let paint = Paint::linear_gradient(
78                LocalPoint::new(0.0, 0.0),
79                LocalPoint::new(1.0, 0.0),
80                Color::gray(0.0),
81                Color::gray(1.0),
82                0.0,
83            );
84
85            assert_eq!(paint.apply(LocalPoint::new(0.0, 0.0)), Color::gray(0.0));
86            assert_eq!(paint.apply(LocalPoint::new(0.5, 0.0)), Color::gray(0.5));
87            assert_eq!(paint.apply(LocalPoint::new(1.0, 0.0)), Color::gray(1.0));
88        }
89
90        {
91            let paint = Paint::linear_gradient(
92                LocalPoint::new(0.0, 0.0),
93                LocalPoint::new(0.0, 1.0),
94                Color::gray(0.0),
95                Color::gray(1.0),
96                0.0,
97            );
98
99            assert_eq!(paint.apply(LocalPoint::new(0.0, 0.0)), Color::gray(0.0));
100            assert_eq!(paint.apply(LocalPoint::new(0.0, 1.0)), Color::gray(1.0));
101        }
102
103        {
104            let paint = Paint::linear_gradient(
105                LocalPoint::new(1.0, 0.0),
106                LocalPoint::new(2.0, 0.0),
107                Color::gray(0.0),
108                Color::gray(1.0),
109                0.0,
110            );
111
112            assert_eq!(paint.apply(LocalPoint::new(0.0, 0.0)), Color::gray(0.0));
113            assert_eq!(paint.apply(LocalPoint::new(1.0, 0.0)), Color::gray(0.0));
114            assert_eq!(paint.apply(LocalPoint::new(1.5, 0.0)), Color::gray(0.5));
115            assert_eq!(paint.apply(LocalPoint::new(2.0, 0.0)), Color::gray(1.0));
116            assert_eq!(paint.apply(LocalPoint::new(3.0, 0.0)), Color::gray(1.0));
117        }
118    }
119}