1#![allow(dead_code)]
2
3use std::{
4 fmt::Display,
5 ops::{Index, IndexMut},
6};
7
8use super::{RGBAf, RGBf, RGB, RGB24, RGBA};
9
10fn convert_f64_to_u8(v: f64) -> u8 {
11 let v = (v * 255.0 + 0.5) as i32;
12 v.max(0).min(255) as u8
13}
14
15#[derive(Clone, Copy, PartialEq, Debug)]
16pub struct RGBA32 {
17 r: u8,
18 g: u8,
19 b: u8,
20 a: u8,
21}
22
23impl Display for RGBA32 {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(
26 f,
27 "RGBA32(r: {}, g: {}, b: {}, a: {})",
28 self.r, self.g, self.b, self.a
29 )
30 }
31}
32
33impl Default for RGBA32 {
34 fn default() -> Self {
35 Self {
36 r: 0,
37 g: 0,
38 b: 0,
39 a: 0,
40 }
41 }
42}
43
44impl Index<usize> for RGBA32 {
45 type Output = u8;
46
47 fn index(&self, index: usize) -> &Self::Output {
48 match index {
49 0 => &self.r,
50 1 => &self.g,
51 2 => &self.b,
52 3 => &self.a,
53 _ => panic!("`rmath::color::RGBA32::index`: index out of bounds."),
54 }
55 }
56}
57
58impl IndexMut<usize> for RGBA32 {
59 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
60 match index {
61 0 => &mut self.r,
62 1 => &mut self.g,
63 2 => &mut self.b,
64 3 => &mut self.a,
65 _ => panic!("`rmath::color::RGBA32::index_mut`: index out of bounds."),
66 }
67 }
68}
69
70impl From<f64> for RGBA32 {
71 fn from(rgb: f64) -> Self {
72 let rgb = convert_f64_to_u8(rgb);
73 Self::new(rgb, rgb, rgb, rgb)
74 }
75}
76
77impl From<(f64, f64, f64)> for RGBA32 {
78 fn from(rgb: (f64, f64, f64)) -> Self {
79 let (r, g, b) = rgb;
80 let r = convert_f64_to_u8(r);
81 let g = convert_f64_to_u8(g);
82 let b = convert_f64_to_u8(b);
83 Self::new(r, g, b, 255)
84 }
85}
86
87impl From<(f64, f64, f64, f64)> for RGBA32 {
88 fn from(rgba: (f64, f64, f64, f64)) -> Self {
89 let (r, g, b, a) = rgba;
90 let r = convert_f64_to_u8(r);
91 let g = convert_f64_to_u8(g);
92 let b = convert_f64_to_u8(b);
93 let a = convert_f64_to_u8(a);
94 Self::new(r, g, b, a)
95 }
96}
97
98impl From<[f64; 3]> for RGBA32 {
99 fn from(rgb: [f64; 3]) -> Self {
100 let r = convert_f64_to_u8(rgb[0]);
101 let g = convert_f64_to_u8(rgb[1]);
102 let b = convert_f64_to_u8(rgb[2]);
103 Self::new(r, g, b, 255)
104 }
105}
106
107impl From<[f64; 4]> for RGBA32 {
108 fn from(rgba: [f64; 4]) -> Self {
109 let r = convert_f64_to_u8(rgba[0]);
110 let g = convert_f64_to_u8(rgba[1]);
111 let b = convert_f64_to_u8(rgba[2]);
112 let a = convert_f64_to_u8(rgba[3]);
113 Self::new(r, g, b, a)
114 }
115}
116
117impl From<u32> for RGBA32 {
118 fn from(rgba: u32) -> Self {
119 let r = ((rgba >> 24) & 0xff) as u8;
120 let g = ((rgba >> 16) & 0xff) as u8;
121 let b = ((rgba >> 8) & 0xff) as u8;
122 let a = (rgba & 0xff) as u8;
123 Self::new(r, g, b, a)
124 }
125}
126
127impl From<u8> for RGBA32 {
128 fn from(rgb: u8) -> Self {
129 Self::new(rgb, rgb, rgb, 255)
130 }
131}
132
133impl From<(u8, u8, u8)> for RGBA32 {
134 fn from(rgb: (u8, u8, u8)) -> Self {
135 let (r, g, b) = rgb;
136 Self::new(r, g, b, 255)
137 }
138}
139
140impl From<(u8, u8, u8, u8)> for RGBA32 {
141 fn from(rgba: (u8, u8, u8, u8)) -> Self {
142 let (r, g, b, a) = rgba;
143 Self::new(r, g, b, a)
144 }
145}
146
147impl From<[u8; 3]> for RGBA32 {
148 fn from(rgb: [u8; 3]) -> Self {
149 Self::new(rgb[0], rgb[1], rgb[2], 255)
150 }
151}
152
153impl From<[u8; 4]> for RGBA32 {
154 fn from(rgba: [u8; 4]) -> Self {
155 Self::new(rgba[0], rgba[1], rgba[2], rgba[3])
156 }
157}
158
159impl From<RGB> for RGBA32 {
160 fn from(color: RGB) -> Self {
161 color.to_rgba32()
162 }
163}
164
165impl From<(RGB, u8)> for RGBA32 {
166 fn from(color: (RGB, u8)) -> Self {
167 color.0.to_rgba32_alpha(color.1)
168 }
169}
170
171impl From<RGBf> for RGBA32 {
172 fn from(color: RGBf) -> Self {
173 color.to_rgba32()
174 }
175}
176
177impl From<(RGBf, u8)> for RGBA32 {
178 fn from(color: (RGBf, u8)) -> Self {
179 color.0.to_rgba32_alpha(color.1)
180 }
181}
182
183impl From<RGBA> for RGBA32 {
184 fn from(color: RGBA) -> Self {
185 color.to_rgba32()
186 }
187}
188
189impl From<RGBAf> for RGBA32 {
190 fn from(color: RGBAf) -> Self {
191 color.to_rgba32()
192 }
193}
194
195impl From<RGB24> for RGBA32 {
196 fn from(color: RGB24) -> Self {
197 color.to_rgba32()
198 }
199}
200
201impl From<(RGB24, u8)> for RGBA32 {
202 fn from(color: (RGB24, u8)) -> Self {
203 color.0.to_rgba32_alpha(color.1)
204 }
205}
206
207impl RGBA32 {
208 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
209 Self { r, g, b, a }
210 }
211
212 pub fn black() -> Self {
213 Self::new(0, 0, 0, 255)
214 }
215
216 pub fn white() -> Self {
217 Self::new(255, 255, 255, 255)
218 }
219
220 pub fn red() -> Self {
221 Self::new(255, 0, 0, 255)
222 }
223
224 pub fn green() -> Self {
225 Self::new(0, 1, 0, 255)
226 }
227
228 pub fn blue() -> Self {
229 Self::new(0, 0, 255, 255)
230 }
231
232 pub fn black_alpha(alpha: u8) -> Self {
233 Self::new(0, 0, 0, alpha)
234 }
235
236 pub fn white_alpha(alpha: u8) -> Self {
237 Self::new(255, 255, 255, alpha)
238 }
239
240 pub fn red_alpha(alpha: u8) -> Self {
241 Self::new(255, 0, 0, alpha)
242 }
243
244 pub fn green_alpha(alpha: u8) -> Self {
245 Self::new(0, 1, 0, alpha)
246 }
247
248 pub fn blue_alpha(alpha: u8) -> Self {
249 Self::new(0, 0, 255, alpha)
250 }
251
252 pub fn r(self) -> u8 {
253 self.r
254 }
255
256 pub fn g(self) -> u8 {
257 self.g
258 }
259
260 pub fn b(self) -> u8 {
261 self.b
262 }
263
264 pub fn a(self) -> u8 {
265 self.a
266 }
267}
268
269impl RGBA32 {
270 pub fn sum(self) -> i32 {
271 self.r as i32 + self.g as i32 + self.b as i32
272 }
273
274 pub fn gray(self) -> u8 {
275 (self.sum() / 3) as u8
276 }
277
278 pub fn min_element(self) -> u8 {
279 self.r.min(self.g).min(self.b).min(self.a)
280 }
281
282 pub fn max_element(self) -> u8 {
283 self.r.max(self.g).max(self.b).max(self.a)
284 }
285
286 pub fn clamp(self, min: Self, max: Self) -> Self {
287 ruby_assert!(min.r <= max.r);
288 ruby_assert!(min.g <= max.g);
289 ruby_assert!(min.b <= max.b);
290 ruby_assert!(min.a <= max.a);
291
292 self.min(max).max(min)
293 }
294
295 pub fn min(self, rhs: Self) -> Self {
296 Self::new(
297 self.r.min(rhs.r),
298 self.g.min(rhs.g),
299 self.b.min(rhs.b),
300 self.a.min(rhs.a),
301 )
302 }
303
304 pub fn max(self, rhs: Self) -> Self {
305 Self::new(
306 self.r.max(rhs.r),
307 self.g.max(rhs.g),
308 self.b.max(rhs.b),
309 self.a.max(rhs.a),
310 )
311 }
312
313 pub fn saturate(self) -> Self {
314 self.clamp(Self::black_alpha(0), Self::white_alpha(255))
315 }
316}
317
318impl RGBA32 {
319 pub fn to_array(self) -> [u8; 4] {
320 [self.r, self.g, self.b, self.a]
321 }
322
323 pub fn to_tuple(self) -> (u8, u8, u8, u8) {
324 (self.r, self.g, self.b, self.a)
325 }
326
327 pub fn to_rgb(self) -> RGB {
328 RGB::new(
329 self.r as f64 / 255.0,
330 self.g as f64 / 255.0,
331 self.b as f64 / 255.0,
332 )
333 }
334
335 pub fn to_rgbf(self) -> RGBf {
336 RGBf::new(
337 self.r as f32 / 255.0,
338 self.g as f32 / 255.0,
339 self.b as f32 / 255.0,
340 )
341 }
342
343 pub fn to_rgba(self) -> RGBA {
344 RGBA::new(
345 self.r as f64 / 255.0,
346 self.g as f64 / 255.0,
347 self.b as f64 / 255.0,
348 self.a as f64 / 255.0,
349 )
350 }
351
352 pub fn to_rgbaf(self) -> RGBAf {
353 RGBAf::new(
354 self.r as f32 / 255.0,
355 self.g as f32 / 255.0,
356 self.b as f32 / 255.0,
357 self.a as f32 / 255.0,
358 )
359 }
360
361 pub fn to_rgb24(self) -> RGB24 {
362 RGB24::new(self.r, self.g, self.b)
363 }
364}