ruby_math/color/
rgb.rs

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}