1pub use colors::*;
4
5#[repr(C)]
7#[derive(Clone, Copy, Debug, Default, PartialEq)]
8pub struct Color {
9 pub r: f32,
11 pub g: f32,
13 pub b: f32,
15 pub a: f32,
17}
18
19#[macro_export]
24macro_rules! color_u8 {
25 ($r:expr, $g:expr, $b:expr, $a:expr) => {
26 Color::new(
27 $r as f32 / 255.,
28 $g as f32 / 255.,
29 $b as f32 / 255.,
30 $a as f32 / 255.,
31 )
32 };
33}
34
35#[test]
36fn color_from_bytes() {
37 assert_eq!(Color::new(1.0, 0.0, 0.0, 1.0), color_u8!(255, 0, 0, 255));
38 assert_eq!(
39 Color::new(1.0, 0.5, 0.0, 1.0),
40 color_u8!(255, 127.5, 0, 255)
41 );
42 assert_eq!(
43 Color::new(0.0, 1.0, 0.5, 1.0),
44 color_u8!(0, 255, 127.5, 255)
45 );
46}
47
48impl From<Color> for [u8; 4] {
49 fn from(val: Color) -> Self {
50 [
51 (val.r * 255.) as u8,
52 (val.g * 255.) as u8,
53 (val.b * 255.) as u8,
54 (val.a * 255.) as u8,
55 ]
56 }
57}
58
59impl From<[u8; 4]> for Color {
60 fn from(val: [u8; 4]) -> Self {
61 Color::new(
62 val[0] as f32 / 255.,
63 val[1] as f32 / 255.,
64 val[2] as f32 / 255.,
65 val[3] as f32 / 255.,
66 )
67 }
68}
69
70impl From<Color> for [f32; 4] {
71 fn from(val: Color) -> Self {
72 [val.r, val.g, val.b, val.a]
73 }
74}
75
76impl From<[f32; 4]> for Color {
77 fn from(colors: [f32; 4]) -> Color {
78 Color::new(colors[0], colors[1], colors[2], colors[3])
79 }
80}
81
82impl Color {
83 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Color {
101 Color { r, g, b, a }
102 }
103
104 pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
106 Color::new(
107 r as f32 / 255.,
108 g as f32 / 255.,
109 b as f32 / 255.,
110 a as f32 / 255.,
111 )
112 }
113
114 pub const fn from_hex(hex: u32) -> Color {
128 let bytes: [u8; 4] = hex.to_be_bytes();
129
130 Self::from_rgba(bytes[1], bytes[2], bytes[3], 255)
131 }
132
133 pub const fn to_vec(&self) -> glam::Vec4 {
135 glam::Vec4::new(self.r, self.g, self.b, self.a)
136 }
137
138 pub const fn from_vec(vec: glam::Vec4) -> Self {
140 Self::new(vec.x, vec.y, vec.z, vec.w)
141 }
142
143 pub const fn with_alpha(&self, alpha: f32) -> Color {
145 Color::new(self.r, self.g, self.b, alpha)
146 }
147}
148
149pub mod colors {
150 use super::Color;
153
154 pub const LIGHTGRAY: Color = Color::new(0.78, 0.78, 0.78, 1.00);
155 pub const GRAY: Color = Color::new(0.51, 0.51, 0.51, 1.00);
156 pub const DARKGRAY: Color = Color::new(0.31, 0.31, 0.31, 1.00);
157 pub const YELLOW: Color = Color::new(0.99, 0.98, 0.00, 1.00);
158 pub const GOLD: Color = Color::new(1.00, 0.80, 0.00, 1.00);
159 pub const ORANGE: Color = Color::new(1.00, 0.63, 0.00, 1.00);
160 pub const PINK: Color = Color::new(1.00, 0.43, 0.76, 1.00);
161 pub const RED: Color = Color::new(0.90, 0.16, 0.22, 1.00);
162 pub const MAROON: Color = Color::new(0.75, 0.13, 0.22, 1.00);
163 pub const GREEN: Color = Color::new(0.00, 0.89, 0.19, 1.00);
164 pub const LIME: Color = Color::new(0.00, 0.62, 0.18, 1.00);
165 pub const DARKGREEN: Color = Color::new(0.00, 0.46, 0.17, 1.00);
166 pub const SKYBLUE: Color = Color::new(0.40, 0.75, 1.00, 1.00);
167 pub const BLUE: Color = Color::new(0.00, 0.47, 0.95, 1.00);
168 pub const DARKBLUE: Color = Color::new(0.00, 0.32, 0.67, 1.00);
169 pub const PURPLE: Color = Color::new(0.78, 0.48, 1.00, 1.00);
170 pub const VIOLET: Color = Color::new(0.53, 0.24, 0.75, 1.00);
171 pub const DARKPURPLE: Color = Color::new(0.44, 0.12, 0.49, 1.00);
172 pub const BEIGE: Color = Color::new(0.83, 0.69, 0.51, 1.00);
173 pub const BROWN: Color = Color::new(0.50, 0.42, 0.31, 1.00);
174 pub const DARKBROWN: Color = Color::new(0.30, 0.25, 0.18, 1.00);
175 pub const WHITE: Color = Color::new(1.00, 1.00, 1.00, 1.00);
176 pub const BLACK: Color = Color::new(0.00, 0.00, 0.00, 1.00);
177 pub const BLANK: Color = Color::new(0.00, 0.00, 0.00, 0.00);
178 pub const MAGENTA: Color = Color::new(1.00, 0.00, 1.00, 1.00);
179}
180
181#[rustfmt::skip]
182pub fn hsl_to_rgb(h: f32, s: f32, l: f32) -> Color {
183 let r;
184 let g;
185 let b;
186
187 if s == 0.0 { r = l; g = l; b = l; }
188 else {
189 fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
190 if t < 0.0 { t += 1.0 }
191 if t > 1.0 { t -= 1.0 }
192 if t < 1.0 / 6.0 { return p + (q - p) * 6.0 * t; }
193 if t < 1.0 / 2.0 { return q; }
194 if t < 2.0 / 3.0 { return p + (q - p) * (2.0 / 3.0 - t) * 6.0; }
195 p
196 }
197
198 let q = if l < 0.5 {
199 l * (1.0 + s)
200 } else {
201 l + s - l * s
202 };
203 let p = 2.0 * l - q;
204 r = hue_to_rgb(p, q, h + 1.0 / 3.0);
205 g = hue_to_rgb(p, q, h);
206 b = hue_to_rgb(p, q, h - 1.0 / 3.0);
207 }
208
209 Color::new(r, g, b, 1.0)
210}
211
212pub fn rgb_to_hsl(color: Color) -> (f32, f32, f32) {
213 fn max(a: f32, b: f32) -> f32 {
214 if a > b {
215 a
216 } else {
217 b
218 }
219 }
220 fn min(a: f32, b: f32) -> f32 {
221 if a < b {
222 a
223 } else {
224 b
225 }
226 }
227
228 let Color { r, g, b, .. } = color;
229
230 let max = max(max(r, g), b);
231 let min = min(min(r, g), b);
232
233 let l = (max + min) / 2.0;
235
236 let delta: f32 = max - min;
238 if delta == 0.0 {
239 return (0.0, 0.0, l);
241 }
242
243 let s = if l < 0.5 {
245 delta / (max + min)
246 } else {
247 delta / (2.0 - max - min)
248 };
249
250 let r2 = (((max - r) / 6.0) + (delta / 2.0)) / delta;
252 let g2 = (((max - g) / 6.0) + (delta / 2.0)) / delta;
253 let b2 = (((max - b) / 6.0) + (delta / 2.0)) / delta;
254
255 let mut h = match max {
256 x if x == r => b2 - g2,
257 x if x == g => (1.0 / 3.0) + r2 - b2,
258 _ => (2.0 / 3.0) + g2 - r2,
259 };
260
261 if h < 0 as f32 {
263 h += 1.0;
264 } else if h > 1 as f32 {
265 h -= 1.0;
266 }
267
268 (h, s, l)
269}