1use std::fmt;
2
3#[repr(C)]
5#[derive(Copy, Clone, Debug, PartialEq)]
6pub struct Color {
7 pub r: f32,
8 pub g: f32,
9 pub b: f32,
10 pub a: f32,
11}
12
13impl Color {
14 pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
15 Self { r, g, b, a }
16 }
17 pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
18 Self::new(r, g, b, 1.0)
19 }
20 pub fn from_rgba_bytes(r: u8, g: u8, b: u8, a: u8) -> Self {
21 Self::new(
22 r as f32 / 255.0,
23 g as f32 / 255.0,
24 b as f32 / 255.0,
25 a as f32 / 255.0,
26 )
27 }
28 pub fn from_rgb_bytes(r: u8, g: u8, b: u8) -> Self {
29 Self::from_rgba_bytes(r, g, b, 255)
30 }
31 pub fn from_imgui_u32(abgr: u32) -> Self {
36 let a = ((abgr >> 24) & 0xFF) as u8;
37 let b = ((abgr >> 16) & 0xFF) as u8;
38 let g = ((abgr >> 8) & 0xFF) as u8;
39 let r = (abgr & 0xFF) as u8;
40 Self::from_rgba_bytes(r, g, b, a)
41 }
42
43 pub fn from_rgb_u32(rgb: u32) -> Self {
45 Self::from_rgba_bytes(
46 ((rgb >> 16) & 0xFF) as u8,
47 ((rgb >> 8) & 0xFF) as u8,
48 (rgb & 0xFF) as u8,
49 255,
50 )
51 }
52
53 pub fn to_imgui_u32(self) -> u32 {
55 let r = (self.r * 255.0).round() as u32;
56 let g = (self.g * 255.0).round() as u32;
57 let b = (self.b * 255.0).round() as u32;
58 let a = (self.a * 255.0).round() as u32;
59 (a << 24) | (b << 16) | (g << 8) | r
60 }
61 pub fn to_array(self) -> [f32; 4] {
62 [self.r, self.g, self.b, self.a]
63 }
64 pub fn from_array(arr: [f32; 4]) -> Self {
65 Self::new(arr[0], arr[1], arr[2], arr[3])
66 }
67 pub fn with_alpha(mut self, alpha: f32) -> Self {
68 self.a = alpha;
69 self
70 }
71 pub fn lerp(self, other: Self, t: f32) -> Self {
72 let t = t.clamp(0.0, 1.0);
73 Self::new(
74 self.r + (other.r - self.r) * t,
75 self.g + (other.g - self.g) * t,
76 self.b + (other.b - self.b) * t,
77 self.a + (other.a - self.a) * t,
78 )
79 }
80 pub fn to_hsv(self) -> (f32, f32, f32) {
81 let max = self.r.max(self.g).max(self.b);
82 let min = self.r.min(self.g).min(self.b);
83 let delta = max - min;
84 let h = if delta == 0.0 {
85 0.0
86 } else if max == self.r {
87 60.0 * (((self.g - self.b) / delta) % 6.0)
88 } else if max == self.g {
89 60.0 * (((self.b - self.r) / delta) + 2.0)
90 } else {
91 60.0 * (((self.r - self.g) / delta) + 4.0)
92 };
93 let s = if max == 0.0 { 0.0 } else { delta / max };
94 let v = max;
95 (h, s, v)
96 }
97 pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
98 let h = h % 360.0;
99 let c = v * s;
100 let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
101 let m = v - c;
102 let (r, g, b) = if h < 60.0 {
103 (c, x, 0.0)
104 } else if h < 120.0 {
105 (x, c, 0.0)
106 } else if h < 180.0 {
107 (0.0, c, x)
108 } else if h < 240.0 {
109 (0.0, x, c)
110 } else if h < 300.0 {
111 (x, 0.0, c)
112 } else {
113 (c, 0.0, x)
114 };
115 Self::new(r + m, g + m, b + m, 1.0)
116 }
117}
118
119impl Default for Color {
120 fn default() -> Self {
121 Self::new(1.0, 1.0, 1.0, 1.0)
122 }
123}
124impl From<[f32; 4]> for Color {
125 fn from(arr: [f32; 4]) -> Self {
126 Self::from_array(arr)
127 }
128}
129impl From<Color> for [f32; 4] {
130 fn from(color: Color) -> Self {
131 color.to_array()
132 }
133}
134impl From<(f32, f32, f32, f32)> for Color {
135 fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self {
136 Self::new(r, g, b, a)
137 }
138}
139impl From<Color> for (f32, f32, f32, f32) {
140 fn from(color: Color) -> Self {
141 (color.r, color.g, color.b, color.a)
142 }
143}
144
145impl fmt::Display for Color {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 write!(
148 f,
149 "rgba({:.3}, {:.3}, {:.3}, {:.3})",
150 self.r, self.g, self.b, self.a
151 )
152 }
153}
154
155impl Color {
157 pub const TRANSPARENT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
158 pub const BLACK: Color = Color::new(0.0, 0.0, 0.0, 1.0);
159 pub const WHITE: Color = Color::new(1.0, 1.0, 1.0, 1.0);
160 pub const RED: Color = Color::new(1.0, 0.0, 0.0, 1.0);
161 pub const GREEN: Color = Color::new(0.0, 1.0, 0.0, 1.0);
162 pub const BLUE: Color = Color::new(0.0, 0.0, 1.0, 1.0);
163 pub const YELLOW: Color = Color::new(1.0, 1.0, 0.0, 1.0);
164 pub const CYAN: Color = Color::new(0.0, 1.0, 1.0, 1.0);
165 pub const MAGENTA: Color = Color::new(1.0, 0.0, 1.0, 1.0);
166}