1use gizmo_math::Vec4;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Color(pub Vec4);
6
7impl Color {
8 pub const RED: Color = Color(Vec4::new(1.0, 0.0, 0.0, 1.0));
10 pub const GREEN: Color = Color(Vec4::new(0.0, 1.0, 0.0, 1.0));
11 pub const BLUE: Color = Color(Vec4::new(0.0, 0.0, 1.0, 1.0));
12 pub const WHITE: Color = Color(Vec4::new(1.0, 1.0, 1.0, 1.0));
13 pub const BLACK: Color = Color(Vec4::new(0.0, 0.0, 0.0, 1.0));
14 pub const YELLOW: Color = Color(Vec4::new(1.0, 1.0, 0.0, 1.0));
15 pub const CYAN: Color = Color(Vec4::new(0.0, 1.0, 1.0, 1.0));
16 pub const MAGENTA: Color = Color(Vec4::new(1.0, 0.0, 1.0, 1.0));
17 pub const ORANGE: Color = Color(Vec4::new(1.0, 0.5, 0.0, 1.0));
18 pub const GRAY: Color = Color(Vec4::new(0.5, 0.5, 0.5, 1.0));
19 pub const DARK_GRAY: Color = Color(Vec4::new(0.2, 0.2, 0.2, 1.0));
20 pub const TRANSPARENT: Color = Color(Vec4::new(0.0, 0.0, 0.0, 0.0));
21
22 #[inline]
26 pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
27 Color(Vec4::new(r, g, b, 1.0))
28 }
29
30 #[inline]
32 pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
33 Color(Vec4::new(r, g, b, a))
34 }
35
36 #[inline]
38 pub fn rgb8(r: u8, g: u8, b: u8) -> Self {
39 Color(Vec4::new(
40 r as f32 / 255.0,
41 g as f32 / 255.0,
42 b as f32 / 255.0,
43 1.0,
44 ))
45 }
46
47 pub fn hex(s: &str) -> Self {
49 let s = s.trim_start_matches('#');
50 let bytes = s.as_bytes();
51 let parse = |i: usize| -> f32 {
52 let slice = std::str::from_utf8(&bytes[i..i + 2]).unwrap_or("ff");
53 u8::from_str_radix(slice, 16).unwrap_or(255) as f32 / 255.0
54 };
55 if bytes.len() >= 8 {
56 Color(Vec4::new(parse(0), parse(2), parse(4), parse(6)))
57 } else if bytes.len() >= 6 {
58 Color(Vec4::new(parse(0), parse(2), parse(4), 1.0))
59 } else {
60 Color::WHITE
61 }
62 }
63
64 pub fn to_hex(self) -> String {
66 let r = (self.0.x.clamp(0.0, 1.0) * 255.0).round() as u8;
67 let g = (self.0.y.clamp(0.0, 1.0) * 255.0).round() as u8;
68 let b = (self.0.z.clamp(0.0, 1.0) * 255.0).round() as u8;
69
70 if self.0.w < 0.999 {
71 let a = (self.0.w.clamp(0.0, 1.0) * 255.0).round() as u8;
72 format!("#{:02X}{:02X}{:02X}{:02X}", r, g, b, a)
73 } else {
74 format!("#{:02X}{:02X}{:02X}", r, g, b)
75 }
76 }
77
78 pub fn lerp(self, other: Color, t: f32) -> Color {
80 let t = t.clamp(0.0, 1.0);
81 Color(Vec4::new(
82 self.0.x + (other.0.x - self.0.x) * t,
83 self.0.y + (other.0.y - self.0.y) * t,
84 self.0.z + (other.0.z - self.0.z) * t,
85 self.0.w + (other.0.w - self.0.w) * t,
86 ))
87 }
88
89 #[inline]
91 pub fn with_alpha(mut self, a: f32) -> Self {
92 self.0.w = a;
93 self
94 }
95
96 #[inline]
98 pub fn to_vec4(self) -> Vec4 {
99 self.0
100 }
101}
102
103impl From<Color> for Vec4 {
104 fn from(c: Color) -> Vec4 {
105 c.0
106 }
107}
108
109impl From<Vec4> for Color {
110 fn from(v: Vec4) -> Color {
111 Color(v)
112 }
113}