#[derive(Clone, Copy, Debug)]
pub struct Color {
pub r: f64,
pub g: f64,
pub b: f64,
}
impl Default for Color {
fn default() -> Self { Self::BLACK }
}
#[inline]
pub fn clamped(n: f64) -> f64 { n.clamp(0.0, 1.0) }
#[inline]
pub fn modulo(dividend: f64, divisor: f64) -> f64 {
let a = (dividend as f32) % (divisor as f32);
let b = (a + divisor as f32) % (divisor as f32);
b as f64
}
#[inline]
pub fn lerp_to(to_a: f64, to_b: f64, t: f64) -> f64 { t * (to_b - to_a) + to_a }
#[inline]
pub fn lerp_from(from_a: f64, from_b: f64, t: f64) -> f64 {
(from_a - t) / (from_a - from_b)
}
#[inline]
pub fn lerp(from_a: f64, from_b: f64, to_c: f64, to_d: f64, t: f64) -> f64 {
lerp_to(to_c, to_d, lerp_from(from_a, from_b, t))
}
impl Color {
pub const WHITE: Color = Color { r: 1.0, g: 1.0, b: 1.0 };
pub const BLACK: Color = Color { r: 0.0, g: 0.0, b: 0.0 };
#[allow(dead_code)]
pub const RED: Color = Color { r: 1.0, g: 0.0, b: 0.0 };
#[allow(dead_code)]
pub const GREEN: Color = Color { r: 0.0, g: 1.0, b: 0.0 };
#[allow(dead_code)]
pub const BLUE: Color = Color { r: 0.0, g: 0.0, b: 1.0 };
#[allow(dead_code)]
pub const CYAN: Color = Color { r: 0.0, g: 1.0, b: 1.0 };
#[allow(dead_code)]
pub const MAGENTA: Color = Color { r: 1.0, g: 0.0, b: 1.0 };
#[allow(dead_code)]
pub const YELLOW: Color = Color { r: 1.0, g: 1.0, b: 0.0 };
pub fn new(r: f64, g: f64, b: f64) -> Self { Self { r, g, b } }
pub fn from_uint8_values(r: u8, g: u8, b: u8) -> Self {
Self {
r: r as f64 / 255.0,
g: g as f64 / 255.0,
b: b as f64 / 255.0,
}
}
pub fn lerp_to(&self, other: &Color, t: f64) -> Color {
let f = clamped(t);
let red = clamped(self.r * (1.0 - f) + other.r * f);
let green = clamped(self.g * (1.0 - f) + other.g * f);
let blue = clamped(self.b * (1.0 - f) + other.b * f);
Color::new(red, green, blue)
}
pub fn lighten(&self, t: f64) -> Color { self.lerp_to(&Color::WHITE, t) }
pub fn darken(&self, t: f64) -> Color { self.lerp_to(&Color::BLACK, t) }
pub fn burn(&self, t: f64) -> Color {
let f = (1.0 - t).max(1.0e-7);
Color::new(
(1.0 - (1.0 - self.r) / f).min(1.0),
(1.0 - (1.0 - self.g) / f).min(1.0),
(1.0 - (1.0 - self.b) / f).min(1.0),
)
}
pub fn luminance(&self) -> f64 {
let r = (0.299 * self.r) as f32;
let g = (0.587 * self.g) as f32;
let b = (0.114 * self.b) as f32;
let val = r.powi(2) + g.powi(2) + b.powi(2);
val.sqrt() as f64
}
}