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