dioxus_motion/animations/
colors.rs1use crate::animations::core::Animatable;
7use wide::f32x4;
8
9#[derive(Debug, Copy, Clone, PartialEq)]
13pub struct Color {
14 pub r: f32,
16 pub g: f32,
18 pub b: f32,
20 pub a: f32,
22}
23
24impl Color {
25 pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
33 Self {
34 r: r.clamp(0.0, 1.0),
35 g: g.clamp(0.0, 1.0),
36 b: b.clamp(0.0, 1.0),
37 a: a.clamp(0.0, 1.0),
38 }
39 }
40
41 pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
49 Color::new(
50 r as f32 / 255.0,
51 g as f32 / 255.0,
52 b as f32 / 255.0,
53 a as f32 / 255.0,
54 )
55 }
56
57 pub fn to_rgba(&self) -> (u8, u8, u8, u8) {
62 (
63 (self.r * 255.0 + 0.5) as u8,
64 (self.g * 255.0 + 0.5) as u8,
65 (self.b * 255.0 + 0.5) as u8,
66 (self.a * 255.0 + 0.5) as u8,
67 )
68 }
69}
70
71impl Default for Color {
72 fn default() -> Self {
73 Color::new(0.0, 0.0, 0.0, 1.0) }
75}
76
77impl std::ops::Add for Color {
78 type Output = Self;
79
80 fn add(self, other: Self) -> Self {
81 Color::new(
82 (self.r + other.r).clamp(0.0, 1.0),
83 (self.g + other.g).clamp(0.0, 1.0),
84 (self.b + other.b).clamp(0.0, 1.0),
85 (self.a + other.a).clamp(0.0, 1.0),
86 )
87 }
88}
89
90impl std::ops::Sub for Color {
91 type Output = Self;
92
93 fn sub(self, other: Self) -> Self {
94 Color::new(
95 (self.r - other.r).clamp(0.0, 1.0),
96 (self.g - other.g).clamp(0.0, 1.0),
97 (self.b - other.b).clamp(0.0, 1.0),
98 (self.a - other.a).clamp(0.0, 1.0),
99 )
100 }
101}
102
103impl std::ops::Mul<f32> for Color {
104 type Output = Self;
105
106 fn mul(self, factor: f32) -> Self {
107 Color::new(
108 (self.r * factor).clamp(0.0, 1.0),
109 (self.g * factor).clamp(0.0, 1.0),
110 (self.b * factor).clamp(0.0, 1.0),
111 (self.a * factor).clamp(0.0, 1.0),
112 )
113 }
114}
115
116impl Animatable for Color {
119 fn interpolate(&self, target: &Self, t: f32) -> Self {
120 let a = [self.r, self.g, self.b, self.a];
121 let b = [target.r, target.g, target.b, target.a];
122 let va = f32x4::new(a);
123 let vb = f32x4::new(b);
124 let vt = f32x4::splat(t.clamp(0.0, 1.0));
125 let result = va + (vb - va) * vt;
126 let out = result.to_array();
127 Color::new(out[0], out[1], out[2], out[3])
128 }
129
130 fn magnitude(&self) -> f32 {
131 (self.r * self.r + self.g * self.g + self.b * self.b + self.a * self.a).sqrt()
132 }
133
134 }
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_color_new() {
143 let color = Color::new(1.0, 0.5, 0.0, 1.0);
144 assert_eq!(color.r, 1.0);
145 assert_eq!(color.g, 0.5);
146 assert_eq!(color.b, 0.0);
147 assert_eq!(color.a, 1.0);
148 }
149
150 #[test]
151 fn test_color_from_rgba() {
152 let color = Color::from_rgba(255, 128, 0, 255);
153 assert!((color.r - 1.0).abs() < f32::EPSILON);
154 assert!((color.g - 0.5019608).abs() < 0.000001);
155 assert!((color.b - 0.0).abs() < f32::EPSILON);
156 assert!((color.a - 1.0).abs() < f32::EPSILON);
157 }
158
159 #[test]
160 fn test_color_lerp() {
161 let start = Color::new(0.0, 0.0, 0.0, 1.0);
162 let end = Color::new(1.0, 1.0, 1.0, 1.0);
163 let mid = start.interpolate(&end, 0.5);
164
165 assert!((mid.r - 0.5).abs() < f32::EPSILON);
166 assert!((mid.g - 0.5).abs() < f32::EPSILON);
167 assert!((mid.b - 0.5).abs() < f32::EPSILON);
168 assert!((mid.a - 1.0).abs() < f32::EPSILON);
169 }
170
171 #[test]
172 fn test_color_to_rgba() {
173 let color = Color::new(1.0, 0.5, 0.0, 1.0);
174 let (r, g, b, a) = color.to_rgba();
175 assert_eq!(r, 255);
176 assert_eq!(g, 128);
177 assert_eq!(b, 0);
178 assert_eq!(a, 255);
179 }
180}