1#![allow(dead_code)]
2
3use std::{
4 fmt::Display,
5 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
6};
7
8use super::{RGBAf, RGBf, RGB24, RGBA, RGBA32};
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 RGB {
17 r: f64,
18 g: f64,
19 b: f64,
20}
21
22impl Display for RGB {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "RGB(r: {}, g: {}, b: {})", self.r, self.g, self.b)
25 }
26}
27
28impl Default for RGB {
29 fn default() -> Self {
30 Self {
31 r: 0.0,
32 g: 0.0,
33 b: 0.0,
34 }
35 }
36}
37
38impl Add<RGB> for RGB {
39 type Output = RGB;
40
41 fn add(self, rhs: RGB) -> Self::Output {
42 RGB::new(self.r + rhs.r, self.g + rhs.g, self.b + rhs.b)
43 }
44}
45
46impl Add<f64> for RGB {
47 type Output = RGB;
48
49 fn add(self, rhs: f64) -> Self::Output {
50 RGB::new(self.r + rhs, self.g + rhs, self.b + rhs)
51 }
52}
53
54impl Add<RGB> for f64 {
55 type Output = RGB;
56
57 fn add(self, rhs: RGB) -> Self::Output {
58 RGB::new(self + rhs.r, self + rhs.g, self + rhs.b)
59 }
60}
61
62impl AddAssign<RGB> for RGB {
63 fn add_assign(&mut self, rhs: RGB) {
64 *self = *self + rhs;
65 }
66}
67
68impl AddAssign<f64> for RGB {
69 fn add_assign(&mut self, rhs: f64) {
70 *self = *self + rhs;
71 }
72}
73
74impl Sub<RGB> for RGB {
75 type Output = RGB;
76
77 fn sub(self, rhs: RGB) -> Self::Output {
78 RGB::new(self.r - rhs.r, self.g - rhs.g, self.b - rhs.b)
79 }
80}
81
82impl Sub<f64> for RGB {
83 type Output = RGB;
84
85 fn sub(self, rhs: f64) -> Self::Output {
86 RGB::new(self.r - rhs, self.g - rhs, self.b - rhs)
87 }
88}
89
90impl Sub<RGB> for f64 {
91 type Output = RGB;
92
93 fn sub(self, rhs: RGB) -> Self::Output {
94 RGB::new(self - rhs.r, self - rhs.g, self - rhs.b)
95 }
96}
97
98impl SubAssign<RGB> for RGB {
99 fn sub_assign(&mut self, rhs: RGB) {
100 *self = *self - rhs;
101 }
102}
103
104impl SubAssign<f64> for RGB {
105 fn sub_assign(&mut self, rhs: f64) {
106 *self = *self - rhs;
107 }
108}
109
110impl Mul<RGB> for RGB {
111 type Output = RGB;
112
113 fn mul(self, rhs: RGB) -> Self::Output {
114 RGB::new(self.r * rhs.r, self.g * rhs.g, self.b * rhs.b)
115 }
116}
117
118impl Mul<f64> for RGB {
119 type Output = RGB;
120
121 fn mul(self, rhs: f64) -> Self::Output {
122 RGB::new(self.r * rhs, self.g * rhs, self.b * rhs)
123 }
124}
125
126impl Mul<RGB> for f64 {
127 type Output = RGB;
128
129 fn mul(self, rhs: RGB) -> Self::Output {
130 RGB::new(self * rhs.r, self * rhs.g, self * rhs.b)
131 }
132}
133
134impl MulAssign<RGB> for RGB {
135 fn mul_assign(&mut self, rhs: RGB) {
136 *self = *self * rhs;
137 }
138}
139
140impl MulAssign<f64> for RGB {
141 fn mul_assign(&mut self, rhs: f64) {
142 *self = *self * rhs;
143 }
144}
145
146impl Div<RGB> for RGB {
147 type Output = RGB;
148
149 fn div(self, rhs: RGB) -> Self::Output {
150 RGB::new(self.r / rhs.r, self.g / rhs.g, self.b / rhs.b)
151 }
152}
153
154impl Div<f64> for RGB {
155 type Output = RGB;
156
157 fn div(self, rhs: f64) -> Self::Output {
158 RGB::new(self.r / rhs, self.g / rhs, self.b / rhs)
159 }
160}
161
162impl Div<RGB> for f64 {
163 type Output = RGB;
164
165 fn div(self, rhs: RGB) -> Self::Output {
166 RGB::new(self / rhs.r, self / rhs.g, self / rhs.b)
167 }
168}
169
170impl DivAssign<RGB> for RGB {
171 fn div_assign(&mut self, rhs: RGB) {
172 *self = *self / rhs;
173 }
174}
175
176impl DivAssign<f64> for RGB {
177 fn div_assign(&mut self, rhs: f64) {
178 *self = *self / rhs;
179 }
180}
181
182impl Neg for RGB {
183 type Output = RGB;
184
185 fn neg(self) -> Self::Output {
186 RGB::new(-self.r, -self.g, -self.b)
187 }
188}
189
190impl Index<usize> for RGB {
191 type Output = f64;
192
193 fn index(&self, index: usize) -> &Self::Output {
194 match index {
195 0 => &self.r,
196 1 => &self.g,
197 2 => &self.b,
198 _ => panic!("`rmath::color::RGB::index`: index out of bounds."),
199 }
200 }
201}
202
203impl IndexMut<usize> for RGB {
204 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
205 match index {
206 0 => &mut self.r,
207 1 => &mut self.g,
208 2 => &mut self.b,
209 _ => panic!("`rmath::color::RGB::index_mut`: index out of bounds."),
210 }
211 }
212}
213
214impl From<f64> for RGB {
215 fn from(rgb: f64) -> Self {
216 Self::new(rgb, rgb, rgb)
217 }
218}
219
220impl From<(f64, f64, f64)> for RGB {
221 fn from(rgb: (f64, f64, f64)) -> Self {
222 Self::new(rgb.0, rgb.1, rgb.2)
223 }
224}
225
226impl From<[f64; 3]> for RGB {
227 fn from(rgb: [f64; 3]) -> Self {
228 Self::new(rgb[0], rgb[1], rgb[2])
229 }
230}
231
232impl From<u32> for RGB {
233 fn from(rgb_: u32) -> Self {
234 let r = ((rgb_ >> 16) & 0xff) as f64 / 255.0;
235 let g = ((rgb_ >> 8) & 0xff) as f64 / 255.0;
236 let b = (rgb_ & 0xff) as f64 / 255.0;
237 Self::new(r, g, b)
238 }
239}
240
241impl From<u8> for RGB {
242 fn from(rgb: u8) -> Self {
243 let rgb = rgb as f64 / 255.0;
244 Self::new(rgb, rgb, rgb)
245 }
246}
247
248impl From<(u8, u8, u8)> for RGB {
249 fn from(rgb: (u8, u8, u8)) -> Self {
250 let (r, g, b) = rgb;
251 let r = r as f64 / 255.0;
252 let g = g as f64 / 255.0;
253 let b = b as f64 / 255.0;
254 Self::new(r, g, b)
255 }
256}
257
258impl From<[u8; 3]> for RGB {
259 fn from(rgb: [u8; 3]) -> Self {
260 let r = rgb[0] as f64 / 255.0;
261 let g = rgb[1] as f64 / 255.0;
262 let b = rgb[2] as f64 / 255.0;
263 Self::new(r, g, b)
264 }
265}
266
267impl From<RGBf> for RGB {
268 fn from(color: RGBf) -> Self {
269 color.to_rgb()
270 }
271}
272
273impl From<RGBA> for RGB {
274 fn from(color: RGBA) -> Self {
275 color.to_rgb()
276 }
277}
278
279impl From<RGBAf> for RGB {
280 fn from(color: RGBAf) -> Self {
281 color.to_rgb()
282 }
283}
284
285impl From<RGB24> for RGB {
286 fn from(color: RGB24) -> Self {
287 color.to_rgb()
288 }
289}
290
291impl From<RGBA32> for RGB {
292 fn from(color: RGBA32) -> Self {
293 color.to_rgb()
294 }
295}
296
297impl RGB {
298 pub fn new(r: f64, g: f64, b: f64) -> Self {
299 Self { r, g, b }
300 }
301
302 pub fn black() -> Self {
303 Self::new(0.0, 0.0, 0.0)
304 }
305
306 pub fn white() -> Self {
307 Self::new(1.0, 1.0, 1.0)
308 }
309
310 pub fn red() -> Self {
311 Self::new(1.0, 0.0, 0.0)
312 }
313
314 pub fn green() -> Self {
315 Self::new(0.0, 1.0, 0.0)
316 }
317
318 pub fn blue() -> Self {
319 Self::new(0.0, 0.0, 1.0)
320 }
321
322 pub fn r(self) -> f64 {
323 self.r
324 }
325
326 pub fn g(self) -> f64 {
327 self.g
328 }
329
330 pub fn b(self) -> f64 {
331 self.b
332 }
333}
334
335impl RGB {
336 pub fn sum(self) -> f64 {
337 self.r + self.g + self.b
338 }
339
340 pub fn gray(self) -> f64 {
341 self.sum() / 3.0
342 }
343
344 pub fn luma1(self) -> f64 {
345 0.299 * self.r + 0.587 * self.g + 0.144 * self.b
346 }
347
348 pub fn luma2(self) -> f64 {
349 0.2126 * self.r + 0.7152 * self.g + 0.0722 * self.b
350 }
351
352 pub fn min_element(self) -> f64 {
353 self.r.min(self.g).min(self.b)
354 }
355
356 pub fn max_element(self) -> f64 {
357 self.r.max(self.g).max(self.b)
358 }
359
360 pub fn is_finite(self) -> bool {
361 self.r.is_finite() && self.g.is_finite() && self.b.is_finite()
362 }
363
364 pub fn is_nan(self) -> bool {
365 self.r.is_nan() || self.g.is_nan() || self.b.is_nan()
366 }
367
368 pub fn is_infinite(self) -> bool {
369 self.r.is_infinite() || self.g.is_infinite() || self.b.is_infinite()
370 }
371
372 pub fn clamp(self, min: Self, max: Self) -> Self {
373 ruby_assert!(min.r <= max.r);
374 ruby_assert!(min.g <= max.g);
375 ruby_assert!(min.b <= max.b);
376
377 self.min(max).max(min)
378 }
379
380 pub fn min(self, rhs: Self) -> Self {
381 Self::new(self.r.min(rhs.r), self.g.min(rhs.g), self.b.min(rhs.b))
382 }
383
384 pub fn max(self, rhs: Self) -> Self {
385 Self::new(self.r.max(rhs.r), self.g.max(rhs.g), self.b.max(rhs.b))
386 }
387
388 pub fn abs(self) -> Self {
389 Self::new(self.r.abs(), self.g.abs(), self.b.abs())
390 }
391
392 pub fn round(self) -> Self {
393 Self::new(self.r.round(), self.g.round(), self.b.round())
394 }
395
396 pub fn floor(self) -> Self {
397 Self::new(self.r.floor(), self.g.floor(), self.b.floor())
398 }
399
400 pub fn ceil(self) -> Self {
401 Self::new(self.r.ceil(), self.g.ceil(), self.b.ceil())
402 }
403
404 pub fn trunc(self) -> Self {
405 Self::new(self.r.trunc(), self.g.trunc(), self.b.trunc())
406 }
407
408 pub fn fract(self) -> Self {
409 Self::new(self.r.fract(), self.g.fract(), self.b.fract())
410 }
411
412 pub fn sqrt(self) -> Self {
413 Self::new(self.r.sqrt(), self.g.sqrt(), self.b.sqrt())
414 }
415
416 pub fn exp(self) -> Self {
417 Self::new(self.r.exp(), self.g.exp(), self.b.exp())
418 }
419
420 pub fn exp2(self) -> Self {
421 Self::new(self.r.exp2(), self.g.exp2(), self.b.exp2())
422 }
423
424 pub fn ln(self) -> Self {
425 Self::new(self.r.ln(), self.g.ln(), self.b.ln())
426 }
427
428 pub fn log(self, base: f64) -> Self {
429 Self::new(self.r.log(base), self.g.log(base), self.b.log(base))
430 }
431
432 pub fn log2(self) -> Self {
433 Self::new(self.r.log2(), self.g.log2(), self.b.log2())
434 }
435
436 pub fn log10(self) -> Self {
437 Self::new(self.r.log10(), self.g.log10(), self.b.log10())
438 }
439
440 pub fn cbrt(self) -> Self {
441 Self::new(self.r.cbrt(), self.g.cbrt(), self.b.cbrt())
442 }
443
444 pub fn powf(self, n: f64) -> Self {
445 Self::new(self.r.powf(n), self.g.powf(n), self.b.powf(n))
446 }
447
448 pub fn sin(self) -> Self {
449 Self::new(self.r.sin(), self.g.sin(), self.b.sin())
450 }
451
452 pub fn cos(self) -> Self {
453 Self::new(self.r.cos(), self.g.cos(), self.b.cos())
454 }
455
456 pub fn tan(self) -> Self {
457 Self::new(self.r.tan(), self.g.tan(), self.b.tan())
458 }
459
460 pub fn sin_cos(self) -> (Self, Self) {
461 (self.sin(), self.cos())
462 }
463
464 pub fn recip(self) -> Self {
465 Self::new(self.r.recip(), self.g.recip(), self.b.recip())
466 }
467
468 pub fn saturate(self) -> Self {
469 self.clamp(Self::black(), Self::white())
470 }
471
472 pub fn lerp(self, rhs: Self, s: f64) -> Self {
473 (rhs - self) * s + self
474 }
475
476 pub fn gamma_correct(self) -> Self {
477 self.powf(1.0 / 2.2)
478 }
479}
480
481impl RGB {
482 pub fn to_array(self) -> [f64; 3] {
483 [self.r, self.g, self.b]
484 }
485
486 pub fn to_tuple(self) -> (f64, f64, f64) {
487 (self.r, self.g, self.b)
488 }
489
490 pub fn to_rgbf(self) -> RGBf {
491 RGBf::new(self.r as f32, self.g as f32, self.b as f32)
492 }
493
494 pub fn to_rgba(self) -> RGBA {
495 RGBA::new(self.r, self.g, self.b, 1.0)
496 }
497
498 pub fn to_rgba_alpha(self, alpha: f64) -> RGBA {
499 RGBA::new(self.r, self.g, self.b, alpha)
500 }
501
502 pub fn to_rgbaf(self) -> RGBAf {
503 RGBAf::new(self.r as f32, self.g as f32, self.b as f32, 1.0)
504 }
505
506 pub fn to_rgbaf_alpha(self, alpha: f32) -> RGBAf {
507 RGBAf::new(self.r as f32, self.g as f32, self.b as f32, alpha)
508 }
509
510 pub fn to_rgb24(self) -> RGB24 {
511 RGB24::new(
512 convert_f64_to_u8(self.r),
513 convert_f64_to_u8(self.g),
514 convert_f64_to_u8(self.b),
515 )
516 }
517
518 pub fn to_rgba32(self) -> RGBA32 {
519 RGBA32::new(
520 convert_f64_to_u8(self.r),
521 convert_f64_to_u8(self.g),
522 convert_f64_to_u8(self.b),
523 255,
524 )
525 }
526
527 pub fn to_rgba32_alpha(self, alpha: u8) -> RGBA32 {
528 RGBA32::new(
529 convert_f64_to_u8(self.r),
530 convert_f64_to_u8(self.g),
531 convert_f64_to_u8(self.b),
532 alpha,
533 )
534 }
535}