1use crate::{
2 fast_round, gamma_u8_from_linear_f32, linear_f32_from_gamma_u8, linear_f32_from_linear_u8, Rgba,
3};
4
5#[repr(C)]
15#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
16#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
17#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
18pub struct Color32(pub(crate) [u8; 4]);
19
20impl std::ops::Index<usize> for Color32 {
21 type Output = u8;
22
23 #[inline]
24 fn index(&self, index: usize) -> &u8 {
25 &self.0[index]
26 }
27}
28
29impl std::ops::IndexMut<usize> for Color32 {
30 #[inline]
31 fn index_mut(&mut self, index: usize) -> &mut u8 {
32 &mut self.0[index]
33 }
34}
35
36impl Color32 {
37 pub const TRANSPARENT: Self = Self::from_rgba_premultiplied(0, 0, 0, 0);
40 pub const BLACK: Self = Self::from_rgb(0, 0, 0);
41 pub const DARK_GRAY: Self = Self::from_rgb(96, 96, 96);
42 pub const GRAY: Self = Self::from_rgb(160, 160, 160);
43 pub const LIGHT_GRAY: Self = Self::from_rgb(220, 220, 220);
44 pub const WHITE: Self = Self::from_rgb(255, 255, 255);
45
46 pub const BROWN: Self = Self::from_rgb(165, 42, 42);
47 pub const DARK_RED: Self = Self::from_rgb(0x8B, 0, 0);
48 pub const RED: Self = Self::from_rgb(255, 0, 0);
49 pub const LIGHT_RED: Self = Self::from_rgb(255, 128, 128);
50
51 pub const YELLOW: Self = Self::from_rgb(255, 255, 0);
52 pub const LIGHT_YELLOW: Self = Self::from_rgb(255, 255, 0xE0);
53 pub const KHAKI: Self = Self::from_rgb(240, 230, 140);
54
55 pub const DARK_GREEN: Self = Self::from_rgb(0, 0x64, 0);
56 pub const GREEN: Self = Self::from_rgb(0, 255, 0);
57 pub const LIGHT_GREEN: Self = Self::from_rgb(0x90, 0xEE, 0x90);
58
59 pub const DARK_BLUE: Self = Self::from_rgb(0, 0, 0x8B);
60 pub const BLUE: Self = Self::from_rgb(0, 0, 255);
61 pub const LIGHT_BLUE: Self = Self::from_rgb(0xAD, 0xD8, 0xE6);
62
63 pub const GOLD: Self = Self::from_rgb(255, 215, 0);
64
65 pub const DEBUG_COLOR: Self = Self::from_rgba_premultiplied(0, 200, 0, 128);
66
67 pub const PLACEHOLDER: Self = Self::from_rgba_premultiplied(64, 254, 0, 128);
75
76 #[deprecated = "Renamed to PLACEHOLDER"]
77 pub const TEMPORARY_COLOR: Self = Self::PLACEHOLDER;
78
79 #[inline]
80 pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
81 Self([r, g, b, 255])
82 }
83
84 #[inline]
85 pub const fn from_rgb_additive(r: u8, g: u8, b: u8) -> Self {
86 Self([r, g, b, 0])
87 }
88
89 #[inline]
91 pub const fn from_rgba_premultiplied(r: u8, g: u8, b: u8, a: u8) -> Self {
92 Self([r, g, b, a])
93 }
94
95 #[inline]
97 pub fn from_rgba_unmultiplied(r: u8, g: u8, b: u8, a: u8) -> Self {
98 if a == 255 {
99 Self::from_rgb(r, g, b) } else if a == 0 {
101 Self::TRANSPARENT } else {
103 let r_lin = linear_f32_from_gamma_u8(r);
104 let g_lin = linear_f32_from_gamma_u8(g);
105 let b_lin = linear_f32_from_gamma_u8(b);
106 let a_lin = linear_f32_from_linear_u8(a);
107
108 let r = gamma_u8_from_linear_f32(r_lin * a_lin);
109 let g = gamma_u8_from_linear_f32(g_lin * a_lin);
110 let b = gamma_u8_from_linear_f32(b_lin * a_lin);
111
112 Self::from_rgba_premultiplied(r, g, b, a)
113 }
114 }
115
116 #[inline]
117 pub const fn from_gray(l: u8) -> Self {
118 Self([l, l, l, 255])
119 }
120
121 #[inline]
122 pub const fn from_black_alpha(a: u8) -> Self {
123 Self([0, 0, 0, a])
124 }
125
126 #[inline]
127 pub fn from_white_alpha(a: u8) -> Self {
128 Rgba::from_white_alpha(linear_f32_from_linear_u8(a)).into()
129 }
130
131 #[inline]
132 pub const fn from_additive_luminance(l: u8) -> Self {
133 Self([l, l, l, 0])
134 }
135
136 #[inline]
137 pub const fn is_opaque(&self) -> bool {
138 self.a() == 255
139 }
140
141 #[inline]
142 pub const fn r(&self) -> u8 {
143 self.0[0]
144 }
145
146 #[inline]
147 pub const fn g(&self) -> u8 {
148 self.0[1]
149 }
150
151 #[inline]
152 pub const fn b(&self) -> u8 {
153 self.0[2]
154 }
155
156 #[inline]
157 pub const fn a(&self) -> u8 {
158 self.0[3]
159 }
160
161 #[inline]
163 pub fn to_opaque(self) -> Self {
164 Rgba::from(self).to_opaque().into()
165 }
166
167 #[inline]
169 pub const fn additive(self) -> Self {
170 let [r, g, b, _] = self.to_array();
171 Self([r, g, b, 0])
172 }
173
174 #[inline]
176 pub fn is_additive(self) -> bool {
177 self.a() == 0
178 }
179
180 #[inline]
182 pub const fn to_array(&self) -> [u8; 4] {
183 [self.r(), self.g(), self.b(), self.a()]
184 }
185
186 #[inline]
188 pub const fn to_tuple(&self) -> (u8, u8, u8, u8) {
189 (self.r(), self.g(), self.b(), self.a())
190 }
191
192 #[inline]
193 pub fn to_srgba_unmultiplied(&self) -> [u8; 4] {
194 Rgba::from(*self).to_srgba_unmultiplied()
195 }
196
197 #[inline]
203 pub fn gamma_multiply(self, factor: f32) -> Self {
204 debug_assert!(0.0 <= factor && factor <= 1.0);
205 let Self([r, g, b, a]) = self;
206 Self([
207 (r as f32 * factor + 0.5) as u8,
208 (g as f32 * factor + 0.5) as u8,
209 (b as f32 * factor + 0.5) as u8,
210 (a as f32 * factor + 0.5) as u8,
211 ])
212 }
213
214 #[inline]
219 pub fn linear_multiply(self, factor: f32) -> Self {
220 debug_assert!(0.0 <= factor && factor <= 1.0);
221 Rgba::from(self).multiply(factor).into()
224 }
225
226 #[inline]
231 pub fn to_normalized_gamma_f32(self) -> [f32; 4] {
232 let Self([r, g, b, a]) = self;
233 [
234 r as f32 / 255.0,
235 g as f32 / 255.0,
236 b as f32 / 255.0,
237 a as f32 / 255.0,
238 ]
239 }
240
241 pub fn lerp_to_gamma(&self, other: Self, t: f32) -> Self {
243 use emath::lerp;
244
245 Self::from_rgba_premultiplied(
246 fast_round(lerp((self[0] as f32)..=(other[0] as f32), t)),
247 fast_round(lerp((self[1] as f32)..=(other[1] as f32), t)),
248 fast_round(lerp((self[2] as f32)..=(other[2] as f32), t)),
249 fast_round(lerp((self[3] as f32)..=(other[3] as f32), t)),
250 )
251 }
252}