use crate::{Vec3, Float};
use std::ops::{
Add, AddAssign, Sub, SubAssign,
Mul, MulAssign, Div, DivAssign
};
#[derive(Clone, Copy)]
pub struct Color {
pub rgb: Vec3,
}
impl Color {
pub const BLACK: Self = Self { rgb: Vec3::ZERO };
pub const WHITE: Self = Self { rgb: Vec3::ONE };
pub fn new(r: u8, g: u8, b: u8) -> Self {
let rgb = Vec3::new(
(r as Float / 255.0).powf(2.2),
(g as Float / 255.0).powf(2.2),
(b as Float / 255.0).powf(2.2),
);
Self { rgb }
}
pub fn splat(value: Float) -> Self {
Self { rgb: Vec3::splat(value) }
}
pub fn luminance(&self) -> Float {
self.rgb.dot(Vec3::new(0.2126, 0.7152, 0.0722))
}
pub fn lerp(&self, other: Self, c: Float) -> Self {
Self { rgb: self.rgb.lerp(other.rgb, c) }
}
pub fn gamma_enc(&self) -> (u8, u8, u8) {
let enc = self.rgb.powf(1.0 / 2.2) * 255.0;
(enc.x as u8, enc.y as u8, enc.z as u8)
}
pub fn clamp(&self, lb: Float, ub: Float) -> Self {
Self { rgb: self.rgb.clamp(Vec3::splat(lb), Vec3::splat(ub)) }
}
pub fn is_black(&self) -> bool {
self.rgb.length_squared() == 0.0
}
pub fn mean(&self) -> Float {
self.rgb.dot(Vec3::ONE) / 3.0
}
}
impl From<Vec3> for Color {
fn from(value: Vec3) -> Self {
Self { rgb: value }
}
}
impl Div<Float> for Color {
type Output = Self;
fn div(self, rhs: Float) -> Self::Output {
Self { rgb: self.rgb / rhs }
}
}
impl DivAssign<Float> for Color {
fn div_assign(&mut self, rhs: Float) {
self.rgb /= rhs;
}
}
impl Mul<Float> for Color {
type Output = Self;
fn mul(self, rhs: Float) -> Self::Output {
Self { rgb: self.rgb * rhs }
}
}
impl Mul<Color> for Float {
type Output = Color;
fn mul(self, rhs: Color) -> Self::Output {
Color { rgb: rhs.rgb * self }
}
}
impl Add<Float> for Color {
type Output = Self;
fn add(self, rhs: Float) -> Self::Output {
Self { rgb: self.rgb + rhs }
}
}
impl Add<Color> for Float {
type Output = Color;
fn add(self, rhs: Color) -> Self::Output {
Color { rgb: rhs.rgb + self }
}
}
impl Sub<Float> for Color {
type Output = Self;
fn sub(self, rhs: Float) -> Self::Output {
Self { rgb: self.rgb - rhs }
}
}
impl Add for Color {
type Output = Self;
fn add(self, rhs: Color) -> Self::Output {
Self { rgb: self.rgb + rhs.rgb }
}
}
impl AddAssign for Color {
fn add_assign(&mut self, rhs: Color) {
self.rgb += rhs.rgb;
}
}
impl Sub for Color {
type Output = Self;
fn sub(self, rhs: Color) -> Self::Output {
Self { rgb: self.rgb - rhs.rgb }
}
}
impl SubAssign for Color {
fn sub_assign(&mut self, rhs: Color) {
self.rgb -= rhs.rgb;
}
}
impl Mul for Color {
type Output = Self;
fn mul(self, rhs: Color) -> Self::Output {
Self { rgb: self.rgb * rhs.rgb }
}
}
impl MulAssign for Color {
fn mul_assign(&mut self, rhs: Color) {
self.rgb *= rhs.rgb;
}
}
impl Div for Color {
type Output = Self;
fn div(self, rhs: Color) -> Self::Output {
Self { rgb: self.rgb / rhs.rgb }
}
}