telar_renderer_core/style/
gradient.rs1use geometry_core::Point;
2
3use crate::Color;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct GradientStop {
7 pub position: f32,
8 pub color: Color,
9}
10
11impl GradientStop {
12 pub fn new(position: f32, color: Color) -> Self {
13 Self { position, color }
14 }
15}
16
17#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct GradientStops {
20 stops: [GradientStop; 8],
21 count: u8,
22}
23
24impl GradientStops {
25 pub fn new(stops: &[(f32, Color)]) -> Self {
26 debug_assert!(
27 stops.len() <= 8,
28 "gradient has {} stops, max is 8",
29 stops.len()
30 );
31 let count = stops.len().min(8) as u8;
32 let mut arr = [GradientStop::new(0.0, Color::TRANSPARENT); 8];
33 for (i, &(position, color)) in stops.iter().take(8).enumerate() {
34 arr[i] = GradientStop::new(position, color);
35 }
36 Self { stops: arr, count }
37 }
38
39 pub fn active(&self) -> &[GradientStop] {
40 &self.stops[..self.count as usize]
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq)]
45pub enum GradientKind {
46 Linear { start: Point, end: Point },
47 Radial { center: Point, radius: f32 },
48}
49
50#[derive(Debug, Clone, Copy, PartialEq)]
51pub struct Gradient {
52 pub kind: GradientKind,
53 pub stops: GradientStops,
54}
55
56impl Gradient {
57 pub fn linear(start: Point, end: Point, stops: &[(f32, Color)]) -> Self {
58 Self {
59 kind: GradientKind::Linear { start, end },
60 stops: GradientStops::new(stops),
61 }
62 }
63
64 pub fn radial(center: Point, radius: f32, stops: &[(f32, Color)]) -> Self {
65 Self {
66 kind: GradientKind::Radial { center, radius },
67 stops: GradientStops::new(stops),
68 }
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn gradient_stops_new_stores_stops() {
78 let stops = GradientStops::new(&[(0.0, Color::BLACK), (1.0, Color::WHITE)]);
79 assert_eq!(stops.active().len(), 2);
80 assert_eq!(stops.active()[0].color, Color::BLACK);
81 assert_eq!(stops.active()[1].color, Color::WHITE);
82 }
83
84 #[test]
85 fn gradient_stops_new_truncates_to_eight() {
86 let raw: Vec<(f32, Color)> = (0..6).map(|i| (i as f32 / 5.0, Color::BLACK)).collect();
87 let stops = GradientStops::new(&raw);
88 assert_eq!(stops.active().len(), 6);
89 }
90
91 #[test]
92 fn gradient_linear_stores_stops() {
93 let p1 = Point::new(0.0, 0.0);
94 let p2 = Point::new(1.0, 0.0);
95 let g = Gradient::linear(p1, p2, &[(0.0, Color::BLACK), (1.0, Color::WHITE)]);
96 assert_eq!(g.stops.active().len(), 2);
97 assert_eq!(g.stops.active()[0].color, Color::BLACK);
98 }
99
100 #[test]
101 fn gradient_radial_stores_stops() {
102 let c = Point::new(0.5, 0.5);
103 let g = Gradient::radial(c, 1.0, &[(0.0, Color::RED), (1.0, Color::TRANSPARENT)]);
104 assert_eq!(g.stops.active().len(), 2);
105 assert_eq!(g.stops.active()[0].color, Color::RED);
106 }
107}