bevy_color/
color_gradient.rs1use crate::Mix;
2use bevy_math::curve::{
3 cores::{EvenCore, EvenCoreError},
4 Curve, Interval,
5};
6
7#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
11pub struct ColorCurve<T> {
12 core: EvenCore<T>,
13}
14
15impl<T> ColorCurve<T>
16where
17 T: Mix + Clone,
18{
19 pub fn new(colors: impl IntoIterator<Item = T>) -> Result<Self, EvenCoreError> {
43 let colors = colors.into_iter().collect::<Vec<_>>();
44 Interval::new(0.0, colors.len().saturating_sub(1) as f32)
45 .map_err(|_| EvenCoreError::NotEnoughSamples {
46 samples: colors.len(),
47 })
48 .and_then(|domain| EvenCore::new(domain, colors))
49 .map(|core| Self { core })
50 }
51}
52
53impl<T> Curve<T> for ColorCurve<T>
54where
55 T: Mix + Clone,
56{
57 #[inline]
58 fn domain(&self) -> Interval {
59 self.core.domain()
60 }
61
62 #[inline]
63 fn sample_clamped(&self, t: f32) -> T {
64 self.core.sample_with(t, T::mix)
66 }
67
68 #[inline]
69 fn sample_unchecked(&self, t: f32) -> T {
70 self.sample_clamped(t)
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::{palettes::basic, Srgba};
78
79 #[test]
80 fn test_color_curve() {
81 let broken = ColorCurve::new([basic::RED]);
82 assert!(broken.is_err());
83
84 let gradient = [basic::RED, basic::LIME, basic::BLUE];
85 let curve = ColorCurve::new(gradient).unwrap();
86
87 assert_eq!(curve.domain(), Interval::new(0.0, 2.0).unwrap());
88
89 let brighter_curve = curve.map(|c: Srgba| c.mix(&basic::WHITE, 0.5));
90
91 [
92 (-0.1, None),
93 (0.0, Some([1.0, 0.5, 0.5, 1.0])),
94 (0.5, Some([0.75, 0.75, 0.5, 1.0])),
95 (1.0, Some([0.5, 1.0, 0.5, 1.0])),
96 (1.5, Some([0.5, 0.75, 0.75, 1.0])),
97 (2.0, Some([0.5, 0.5, 1.0, 1.0])),
98 (2.1, None),
99 ]
100 .map(|(t, maybe_rgba)| {
101 let maybe_srgba = maybe_rgba.map(|[r, g, b, a]| Srgba::new(r, g, b, a));
102 (t, maybe_srgba)
103 })
104 .into_iter()
105 .for_each(|(t, maybe_color)| {
106 assert_eq!(brighter_curve.sample(t), maybe_color);
107 });
108 }
109}