#![allow(dead_code)]
use std::{
fmt::Display,
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
};
use super::{RGBAf, RGBf, RGB24, RGBA, RGBA32};
fn convert_f64_to_u8(v: f64) -> u8 {
let v = (v * 255.0 + 0.5) as i32;
v.max(0).min(255) as u8
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct RGB {
r: f64,
g: f64,
b: f64,
}
impl Display for RGB {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RGB(r: {}, g: {}, b: {})", self.r, self.g, self.b)
}
}
impl Default for RGB {
fn default() -> Self {
Self {
r: 0.0,
g: 0.0,
b: 0.0,
}
}
}
impl Add<RGB> for RGB {
type Output = RGB;
fn add(self, rhs: RGB) -> Self::Output {
RGB::new(self.r + rhs.r, self.g + rhs.g, self.b + rhs.b)
}
}
impl Add<f64> for RGB {
type Output = RGB;
fn add(self, rhs: f64) -> Self::Output {
RGB::new(self.r + rhs, self.g + rhs, self.b + rhs)
}
}
impl Add<RGB> for f64 {
type Output = RGB;
fn add(self, rhs: RGB) -> Self::Output {
RGB::new(self + rhs.r, self + rhs.g, self + rhs.b)
}
}
impl AddAssign<RGB> for RGB {
fn add_assign(&mut self, rhs: RGB) {
*self = *self + rhs;
}
}
impl AddAssign<f64> for RGB {
fn add_assign(&mut self, rhs: f64) {
*self = *self + rhs;
}
}
impl Sub<RGB> for RGB {
type Output = RGB;
fn sub(self, rhs: RGB) -> Self::Output {
RGB::new(self.r - rhs.r, self.g - rhs.g, self.b - rhs.b)
}
}
impl Sub<f64> for RGB {
type Output = RGB;
fn sub(self, rhs: f64) -> Self::Output {
RGB::new(self.r - rhs, self.g - rhs, self.b - rhs)
}
}
impl Sub<RGB> for f64 {
type Output = RGB;
fn sub(self, rhs: RGB) -> Self::Output {
RGB::new(self - rhs.r, self - rhs.g, self - rhs.b)
}
}
impl SubAssign<RGB> for RGB {
fn sub_assign(&mut self, rhs: RGB) {
*self = *self - rhs;
}
}
impl SubAssign<f64> for RGB {
fn sub_assign(&mut self, rhs: f64) {
*self = *self - rhs;
}
}
impl Mul<RGB> for RGB {
type Output = RGB;
fn mul(self, rhs: RGB) -> Self::Output {
RGB::new(self.r * rhs.r, self.g * rhs.g, self.b * rhs.b)
}
}
impl Mul<f64> for RGB {
type Output = RGB;
fn mul(self, rhs: f64) -> Self::Output {
RGB::new(self.r * rhs, self.g * rhs, self.b * rhs)
}
}
impl Mul<RGB> for f64 {
type Output = RGB;
fn mul(self, rhs: RGB) -> Self::Output {
RGB::new(self * rhs.r, self * rhs.g, self * rhs.b)
}
}
impl MulAssign<RGB> for RGB {
fn mul_assign(&mut self, rhs: RGB) {
*self = *self * rhs;
}
}
impl MulAssign<f64> for RGB {
fn mul_assign(&mut self, rhs: f64) {
*self = *self * rhs;
}
}
impl Div<RGB> for RGB {
type Output = RGB;
fn div(self, rhs: RGB) -> Self::Output {
RGB::new(self.r / rhs.r, self.g / rhs.g, self.b / rhs.b)
}
}
impl Div<f64> for RGB {
type Output = RGB;
fn div(self, rhs: f64) -> Self::Output {
RGB::new(self.r / rhs, self.g / rhs, self.b / rhs)
}
}
impl Div<RGB> for f64 {
type Output = RGB;
fn div(self, rhs: RGB) -> Self::Output {
RGB::new(self / rhs.r, self / rhs.g, self / rhs.b)
}
}
impl DivAssign<RGB> for RGB {
fn div_assign(&mut self, rhs: RGB) {
*self = *self / rhs;
}
}
impl DivAssign<f64> for RGB {
fn div_assign(&mut self, rhs: f64) {
*self = *self / rhs;
}
}
impl Neg for RGB {
type Output = RGB;
fn neg(self) -> Self::Output {
RGB::new(-self.r, -self.g, -self.b)
}
}
impl Index<usize> for RGB {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.r,
1 => &self.g,
2 => &self.b,
_ => panic!("`rmath::color::RGB::index`: index out of bounds."),
}
}
}
impl IndexMut<usize> for RGB {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.r,
1 => &mut self.g,
2 => &mut self.b,
_ => panic!("`rmath::color::RGB::index_mut`: index out of bounds."),
}
}
}
impl From<f64> for RGB {
fn from(rgb: f64) -> Self {
Self::new(rgb, rgb, rgb)
}
}
impl From<(f64, f64, f64)> for RGB {
fn from(rgb: (f64, f64, f64)) -> Self {
Self::new(rgb.0, rgb.1, rgb.2)
}
}
impl From<[f64; 3]> for RGB {
fn from(rgb: [f64; 3]) -> Self {
Self::new(rgb[0], rgb[1], rgb[2])
}
}
impl From<u32> for RGB {
fn from(rgb_: u32) -> Self {
let r = ((rgb_ >> 16) & 0xff) as f64 / 255.0;
let g = ((rgb_ >> 8) & 0xff) as f64 / 255.0;
let b = (rgb_ & 0xff) as f64 / 255.0;
Self::new(r, g, b)
}
}
impl From<u8> for RGB {
fn from(rgb: u8) -> Self {
let rgb = rgb as f64 / 255.0;
Self::new(rgb, rgb, rgb)
}
}
impl From<(u8, u8, u8)> for RGB {
fn from(rgb: (u8, u8, u8)) -> Self {
let (r, g, b) = rgb;
let r = r as f64 / 255.0;
let g = g as f64 / 255.0;
let b = b as f64 / 255.0;
Self::new(r, g, b)
}
}
impl From<[u8; 3]> for RGB {
fn from(rgb: [u8; 3]) -> Self {
let r = rgb[0] as f64 / 255.0;
let g = rgb[1] as f64 / 255.0;
let b = rgb[2] as f64 / 255.0;
Self::new(r, g, b)
}
}
impl From<RGBf> for RGB {
fn from(color: RGBf) -> Self {
color.to_rgb()
}
}
impl From<RGBA> for RGB {
fn from(color: RGBA) -> Self {
color.to_rgb()
}
}
impl From<RGBAf> for RGB {
fn from(color: RGBAf) -> Self {
color.to_rgb()
}
}
impl From<RGB24> for RGB {
fn from(color: RGB24) -> Self {
color.to_rgb()
}
}
impl From<RGBA32> for RGB {
fn from(color: RGBA32) -> Self {
color.to_rgb()
}
}
impl RGB {
pub fn new(r: f64, g: f64, b: f64) -> Self {
Self { r, g, b }
}
pub fn black() -> Self {
Self::new(0.0, 0.0, 0.0)
}
pub fn white() -> Self {
Self::new(1.0, 1.0, 1.0)
}
pub fn red() -> Self {
Self::new(1.0, 0.0, 0.0)
}
pub fn green() -> Self {
Self::new(0.0, 1.0, 0.0)
}
pub fn blue() -> Self {
Self::new(0.0, 0.0, 1.0)
}
pub fn r(self) -> f64 {
self.r
}
pub fn g(self) -> f64 {
self.g
}
pub fn b(self) -> f64 {
self.b
}
}
impl RGB {
pub fn sum(self) -> f64 {
self.r + self.g + self.b
}
pub fn gray(self) -> f64 {
self.sum() / 3.0
}
pub fn luma1(self) -> f64 {
0.299 * self.r + 0.587 * self.g + 0.144 * self.b
}
pub fn luma2(self) -> f64 {
0.2126 * self.r + 0.7152 * self.g + 0.0722 * self.b
}
pub fn min_element(self) -> f64 {
self.r.min(self.g).min(self.b)
}
pub fn max_element(self) -> f64 {
self.r.max(self.g).max(self.b)
}
pub fn is_finite(self) -> bool {
self.r.is_finite() && self.g.is_finite() && self.b.is_finite()
}
pub fn is_nan(self) -> bool {
self.r.is_nan() || self.g.is_nan() || self.b.is_nan()
}
pub fn is_infinite(self) -> bool {
self.r.is_infinite() || self.g.is_infinite() || self.b.is_infinite()
}
pub fn clamp(self, min: Self, max: Self) -> Self {
ruby_assert!(min.r <= max.r);
ruby_assert!(min.g <= max.g);
ruby_assert!(min.b <= max.b);
self.min(max).max(min)
}
pub fn min(self, rhs: Self) -> Self {
Self::new(self.r.min(rhs.r), self.g.min(rhs.g), self.b.min(rhs.b))
}
pub fn max(self, rhs: Self) -> Self {
Self::new(self.r.max(rhs.r), self.g.max(rhs.g), self.b.max(rhs.b))
}
pub fn abs(self) -> Self {
Self::new(self.r.abs(), self.g.abs(), self.b.abs())
}
pub fn round(self) -> Self {
Self::new(self.r.round(), self.g.round(), self.b.round())
}
pub fn floor(self) -> Self {
Self::new(self.r.floor(), self.g.floor(), self.b.floor())
}
pub fn ceil(self) -> Self {
Self::new(self.r.ceil(), self.g.ceil(), self.b.ceil())
}
pub fn trunc(self) -> Self {
Self::new(self.r.trunc(), self.g.trunc(), self.b.trunc())
}
pub fn fract(self) -> Self {
Self::new(self.r.fract(), self.g.fract(), self.b.fract())
}
pub fn sqrt(self) -> Self {
Self::new(self.r.sqrt(), self.g.sqrt(), self.b.sqrt())
}
pub fn exp(self) -> Self {
Self::new(self.r.exp(), self.g.exp(), self.b.exp())
}
pub fn exp2(self) -> Self {
Self::new(self.r.exp2(), self.g.exp2(), self.b.exp2())
}
pub fn ln(self) -> Self {
Self::new(self.r.ln(), self.g.ln(), self.b.ln())
}
pub fn log(self, base: f64) -> Self {
Self::new(self.r.log(base), self.g.log(base), self.b.log(base))
}
pub fn log2(self) -> Self {
Self::new(self.r.log2(), self.g.log2(), self.b.log2())
}
pub fn log10(self) -> Self {
Self::new(self.r.log10(), self.g.log10(), self.b.log10())
}
pub fn cbrt(self) -> Self {
Self::new(self.r.cbrt(), self.g.cbrt(), self.b.cbrt())
}
pub fn powf(self, n: f64) -> Self {
Self::new(self.r.powf(n), self.g.powf(n), self.b.powf(n))
}
pub fn sin(self) -> Self {
Self::new(self.r.sin(), self.g.sin(), self.b.sin())
}
pub fn cos(self) -> Self {
Self::new(self.r.cos(), self.g.cos(), self.b.cos())
}
pub fn tan(self) -> Self {
Self::new(self.r.tan(), self.g.tan(), self.b.tan())
}
pub fn sin_cos(self) -> (Self, Self) {
(self.sin(), self.cos())
}
pub fn recip(self) -> Self {
Self::new(self.r.recip(), self.g.recip(), self.b.recip())
}
pub fn saturate(self) -> Self {
self.clamp(Self::black(), Self::white())
}
pub fn lerp(self, rhs: Self, s: f64) -> Self {
(rhs - self) * s + self
}
pub fn gamma_correct(self) -> Self {
self.powf(1.0 / 2.2)
}
}
impl RGB {
pub fn to_array(self) -> [f64; 3] {
[self.r, self.g, self.b]
}
pub fn to_tuple(self) -> (f64, f64, f64) {
(self.r, self.g, self.b)
}
pub fn to_rgbf(self) -> RGBf {
RGBf::new(self.r as f32, self.g as f32, self.b as f32)
}
pub fn to_rgba(self) -> RGBA {
RGBA::new(self.r, self.g, self.b, 1.0)
}
pub fn to_rgba_alpha(self, alpha: f64) -> RGBA {
RGBA::new(self.r, self.g, self.b, alpha)
}
pub fn to_rgbaf(self) -> RGBAf {
RGBAf::new(self.r as f32, self.g as f32, self.b as f32, 1.0)
}
pub fn to_rgbaf_alpha(self, alpha: f32) -> RGBAf {
RGBAf::new(self.r as f32, self.g as f32, self.b as f32, alpha)
}
pub fn to_rgb24(self) -> RGB24 {
RGB24::new(
convert_f64_to_u8(self.r),
convert_f64_to_u8(self.g),
convert_f64_to_u8(self.b),
)
}
pub fn to_rgba32(self) -> RGBA32 {
RGBA32::new(
convert_f64_to_u8(self.r),
convert_f64_to_u8(self.g),
convert_f64_to_u8(self.b),
255,
)
}
pub fn to_rgba32_alpha(self, alpha: u8) -> RGBA32 {
RGBA32::new(
convert_f64_to_u8(self.r),
convert_f64_to_u8(self.g),
convert_f64_to_u8(self.b),
alpha,
)
}
}