1use crate::prelude::{Vector3, Vector4};
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
3
4#[repr(C)]
5#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod, PartialEq)]
6pub struct Color {
7 pub r: f32,
8 pub g: f32,
9 pub b: f32,
10 pub a: f32,
11}
12
13impl Default for Color {
14 fn default() -> Self {
15 BLACK
16 }
17}
18
19#[allow(unused)]
20impl Color {
21 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
23 Self { r, g, b, a }
24 }
25
26 pub const fn with_alpha(&self, alpha: f32) -> Self {
28 Self::new(self.r, self.g, self.b, alpha)
29 }
30
31 pub const fn splat_alpha(v: f32, alpha: f32) -> Self {
33 Self::new(v, v, v, alpha)
34 }
35
36 pub const fn splat(v: f32) -> Self {
38 Self::splat_alpha(v, 1.0)
39 }
40
41 pub fn lerp(self, other: Color, t: f32) -> Self {
43 self + (other - self) * t
44 }
45
46 pub const fn clamped(&self) -> Self {
48 Self::new(
49 self.r.clamp(0.0, 1.0),
50 self.g.clamp(0.0, 1.0),
51 self.b.clamp(0.0, 1.0),
52 self.a.clamp(0.0, 1.0),
53 )
54 }
55
56 pub const fn from_rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
58 Self::new(
59 r as f32 / 255.0,
60 g as f32 / 255.0,
61 b as f32 / 255.0,
62 a as f32 / 255.0,
63 )
64 }
65
66 pub const fn from_rgb8(r: u8, g: u8, b: u8) -> Self {
68 Self::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0)
69 }
70
71 pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
73 Self::from_hsva(h, s, v, 1.0)
74 }
75
76 pub fn from_hsva(mut h: f32, s: f32, v: f32, a: f32) -> Self {
78 h *= 360.0;
79 let h = h.rem_euclid(360.0);
80 let c = v * s;
81 let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
82 let m = v - c;
83
84 let (r, g, b) = match h / 60.0 {
85 h_prime if h_prime < 1.0 => (c, x, 0.0),
86 h_prime if h_prime < 2.0 => (x, c, 0.0),
87 h_prime if h_prime < 3.0 => (0.0, c, x),
88 h_prime if h_prime < 4.0 => (0.0, x, c),
89 h_prime if h_prime < 5.0 => (x, 0.0, c),
90 _ => (c, 0.0, x),
91 };
92
93 Self::new(r + m, g + m, b + m, a)
94 }
95
96 pub fn to_hsv(&self) -> (f32, f32, f32) {
98 let max = self.r.max(self.g).max(self.b);
99 let min = self.r.min(self.g).min(self.b);
100 let delta = max - min;
101
102 let h = if delta == 0.0 {
103 0.0
104 } else if max == self.r {
105 60.0 * (((self.g - self.b) / delta).rem_euclid(6.0))
106 } else if max == self.g {
107 60.0 * (((self.b - self.r) / delta) + 2.0)
108 } else {
109 60.0 * (((self.r - self.g) / delta) + 4.0)
110 };
111
112 let s = if max == 0.0 { 0.0 } else { delta / max };
113 let v = max;
114
115 (h / 360.0, s, v)
116 }
117
118 pub fn to_hsva(&self) -> (f32, f32, f32, f32) {
120 let (h, s, v) = self.to_hsv();
121 (h, s, v, self.a)
122 }
123
124 pub fn from_hex(hex: &str) -> Option<Self> {
126 let hex = hex.trim_start_matches('#');
127
128 let expand = |c: char| -> Option<u8> {
129 let d = c.to_digit(16)? as u8;
130 Some((d << 4) | d)
131 };
132
133 match hex.len() {
134 3 => {
135 let mut chars = hex.chars();
136 let r = expand(chars.next()?)?;
137 let g = expand(chars.next()?)?;
138 let b = expand(chars.next()?)?;
139 Some(Self::from_rgb8(r, g, b))
140 }
141 4 => {
142 let mut chars = hex.chars();
143 let r = expand(chars.next()?)?;
144 let g = expand(chars.next()?)?;
145 let b = expand(chars.next()?)?;
146 let a = expand(chars.next()?)?;
147 Some(Self::from_rgba8(r, g, b, a))
148 }
149 6 => {
150 let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
151 let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
152 let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
153 Some(Self::from_rgb8(r, g, b))
154 }
155 8 => {
156 let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
157 let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
158 let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
159 let a = u8::from_str_radix(&hex[6..8], 16).ok()?;
160 Some(Self::from_rgba8(r, g, b, a))
161 }
162 _ => None,
163 }
164 }
165
166 pub fn to_hex(&self) -> String {
168 format!(
169 "#{:02X}{:02X}{:02X}",
170 (self.r.clamp(0.0, 1.0) * 255.0).round() as u8,
171 (self.g.clamp(0.0, 1.0) * 255.0).round() as u8,
172 (self.b.clamp(0.0, 1.0) * 255.0).round() as u8,
173 )
174 }
175
176 pub fn to_hex_alpha(&self) -> String {
178 format!(
179 "#{:02X}{:02X}{:02X}{:02X}",
180 (self.r.clamp(0.0, 1.0) * 255.0).round() as u8,
181 (self.g.clamp(0.0, 1.0) * 255.0).round() as u8,
182 (self.b.clamp(0.0, 1.0) * 255.0).round() as u8,
183 (self.a.clamp(0.0, 1.0) * 255.0).round() as u8,
184 )
185 }
186
187 pub const fn to_rgb(&self) -> (u8, u8, u8) {
189 (
190 (self.r.clamp(0.0, 1.0) * 255.0).round() as u8,
191 (self.g.clamp(0.0, 1.0) * 255.0).round() as u8,
192 (self.b.clamp(0.0, 1.0) * 255.0).round() as u8,
193 )
194 }
195
196 pub const fn to_rgba(&self) -> (u8, u8, u8, u8) {
198 (
199 (self.r.clamp(0.0, 1.0) * 255.0).round() as u8,
200 (self.g.clamp(0.0, 1.0) * 255.0).round() as u8,
201 (self.b.clamp(0.0, 1.0) * 255.0).round() as u8,
202 (self.a.clamp(0.0, 1.0) * 255.0).round() as u8,
203 )
204 }
205
206 pub const fn from_vec4(vec: Vector4) -> Self {
208 Self::new(vec.x, vec.y, vec.z, vec.w)
209 }
210
211 pub const fn to_vec4(&self) -> Vector4 {
213 Vector4::new(self.r, self.g, self.b, self.a)
214 }
215
216 pub const fn from_vec3(vec: Vector3) -> Self {
218 Self::new(vec.x, vec.y, vec.z, 1.0)
219 }
220
221 pub const fn to_vec3(&self) -> Vector3 {
223 Vector3::new(self.r, self.g, self.b)
224 }
225
226 pub const fn to_array(&self) -> [f32; 4] {
228 [self.r, self.g, self.b, self.a]
229 }
230
231 pub const fn to_wgpu(&self) -> wgpu::Color {
233 wgpu::Color {
234 r: self.r as f64,
235 g: self.g as f64,
236 b: self.b as f64,
237 a: self.a as f64,
238 }
239 }
240}
241
242impl From<Color> for [f32; 4] {
243 fn from(c: Color) -> Self {
244 c.to_array()
245 }
246}
247
248impl From<[f32; 4]> for Color {
249 fn from(arr: [f32; 4]) -> Self {
250 Self::new(arr[0], arr[1], arr[2], arr[3])
251 }
252}
253
254impl Add<Color> for Color {
255 type Output = Self;
256
257 fn add(self, rhs: Color) -> Self::Output {
258 Color::new(
259 self.r + rhs.r,
260 self.g + rhs.g,
261 self.b + rhs.b,
262 self.a + rhs.a,
263 )
264 }
265}
266
267impl Sub<Color> for Color {
268 type Output = Self;
269
270 fn sub(self, rhs: Color) -> Self::Output {
271 Color::new(
272 self.r - rhs.r,
273 self.g - rhs.g,
274 self.b - rhs.b,
275 self.a - rhs.a,
276 )
277 }
278}
279
280impl Mul<Color> for Color {
281 type Output = Self;
282
283 fn mul(self, rhs: Color) -> Self::Output {
284 Color::new(
285 self.r * rhs.r,
286 self.g * rhs.g,
287 self.b * rhs.b,
288 self.a * rhs.a,
289 )
290 }
291}
292
293impl Div<Color> for Color {
294 type Output = Self;
295
296 fn div(self, rhs: Color) -> Self::Output {
297 Color::new(
298 self.r / rhs.r,
299 self.g / rhs.g,
300 self.b / rhs.b,
301 self.a / rhs.a,
302 )
303 }
304}
305
306impl AddAssign<Color> for Color {
307 fn add_assign(&mut self, rhs: Color) {
308 self.r += rhs.r;
309 self.g += rhs.g;
310 self.b += rhs.b;
311 self.a += rhs.a;
312 }
313}
314
315impl SubAssign<Color> for Color {
316 fn sub_assign(&mut self, rhs: Color) {
317 self.r -= rhs.r;
318 self.g -= rhs.g;
319 self.b -= rhs.b;
320 self.a -= rhs.a;
321 }
322}
323
324impl MulAssign<Color> for Color {
325 fn mul_assign(&mut self, rhs: Color) {
326 self.r *= rhs.r;
327 self.g *= rhs.g;
328 self.b *= rhs.b;
329 self.a *= rhs.a;
330 }
331}
332
333impl DivAssign<Color> for Color {
334 fn div_assign(&mut self, rhs: Color) {
335 self.r /= rhs.r;
336 self.g /= rhs.g;
337 self.b /= rhs.b;
338 self.a /= rhs.a;
339 }
340}
341
342impl Mul<f32> for Color {
344 type Output = Self;
345
346 fn mul(self, rhs: f32) -> Self::Output {
347 Color::new(self.r * rhs, self.g * rhs, self.b * rhs, self.a * rhs)
348 }
349}
350
351impl Div<f32> for Color {
352 type Output = Self;
353
354 fn div(self, rhs: f32) -> Self::Output {
355 Color::new(self.r / rhs, self.g / rhs, self.b / rhs, self.a / rhs)
356 }
357}
358
359impl MulAssign<f32> for Color {
360 fn mul_assign(&mut self, rhs: f32) {
361 self.r *= rhs;
362 self.g *= rhs;
363 self.b *= rhs;
364 self.a *= rhs;
365 }
366}
367
368impl DivAssign<f32> for Color {
369 fn div_assign(&mut self, rhs: f32) {
370 self.r /= rhs;
371 self.g /= rhs;
372 self.b /= rhs;
373 self.a /= rhs;
374 }
375}
376
377macro_rules! define_colors {
378 ($($name:ident = ($r:expr, $g:expr, $b:expr, $a:expr)),* $(,)?) => {
379 impl Color {
380 $(pub const $name: Self = Self::new($r, $g, $b, $a);)*
381 }
382 $(pub const $name: Color = Color::$name;)*
383 };
384}
385
386define_colors! {
387 TRANSPARENT = (0.0, 0.0, 0.0, 0.0),
388 WHITE = (1.0, 1.0, 1.0, 1.0),
389 BLACK = (0.0, 0.0, 0.0, 1.0),
390 LIGHT_BLACK = (0.05, 0.05, 0.05, 1.0),
391
392 GRAY = (0.2, 0.2, 0.2, 1.0),
393 DARK_GRAY = (0.1, 0.1, 0.1, 1.0),
394 LIGHT_GRAY = (0.3, 0.3, 0.3, 1.0),
395
396 RED = (1.0, 0.03, 0.04, 1.0),
397 DARK_RED = (0.7, 0.03, 0.04, 1.0),
398 LIGHT_RED = (1.0, 0.2, 0.2, 1.0),
399
400 GREEN = (0.0, 1.0, 0.0, 1.0),
401 DARK_GREEN = (0.0, 0.3, 0.0, 1.0),
402 LIGHT_GREEN = (0.4, 1.0, 0.3, 1.0),
403
404 BLUE = (0.03, 0.04, 1.0, 1.0),
405 DARK_BLUE = (0.02, 0.03, 0.7, 1.0),
406 LIGHT_BLUE = (0.2, 0.4, 1.0, 1.0),
407
408 YELLOW = (1.0, 1.0, 0.03, 1.0),
409 DARK_YELLOW = (0.7, 0.7, 0.02, 1.0),
410 LIGHT_YELLOW= (1.0, 1.0, 0.2, 1.0),
411
412 MAGENTA = (1.0, 0.03, 1.0, 1.0),
413 DARK_MAGENTA = (0.7, 0.02, 0.7, 1.0),
414 LIGHT_MAGENTA = (1.0, 0.2, 1.0, 1.0),
415
416 PURPLE = (0.3, 0.03, 1.0, 1.0),
417 DARK_PURPLE = (0.2, 0.02, 0.7, 1.0),
418 LIGHT_PURPLE = (0.45, 0.2, 1.0, 1.0),
419
420 CYAN = (0.03, 1.0, 1.0, 1.0),
421 DARK_CYAN = (0.02, 0.7, 0.7, 1.0),
422 LIGHT_CYAN = (0.5, 1.0, 1.0, 1.0),
423
424 ORANGE = (1.0, 0.3, 0.03, 1.0),
425 DARK_ORANGE = (0.7, 0.2, 0.02, 1.0),
426 LIGHT_ORANGE= (1.0, 0.45, 0.2, 1.0),
427}