#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Color {
pub r: f32,
pub g: f32,
pub b: f32
}
impl Color {
pub const BLACK: Color = Color { r: 0.0, g: 0.0, b: 0.0 };
pub const WHITE: Color = Color { r: 1.0, g: 1.0, b: 1.0 };
pub const RED: Color = Color { r: 1.0, g: 0.0, b: 0.0 };
pub const GREEN: Color = Color { r: 0.0, g: 1.0, b: 0.0 };
pub const BLUE: Color = Color { r: 0.0, g: 0.0, b: 1.0 };
pub const CYAN: Color = Color { r: 0.0, g: 1.0, b: 1.0 };
pub const MAGENTA: Color = Color { r: 1.0, g: 0.0, b: 1.0 };
pub const YELLOW: Color = Color { r: 1.0, g: 1.0, b: 0.0 };
pub fn new(r: f32, g: f32, b: f32) -> Self {
return Self { r, g, b };
}
pub fn from_hue(hue: f32) -> Self {
return match hue * 6.0 {
hue if (0.0..1.0).contains(&hue) => Self::new(1.0, hue, 0.0), hue if (1.0..2.0).contains(&hue) => Self::new(2.0 - hue, 1.0, 0.0), hue if (2.0..3.0).contains(&hue) => Self::new(0.0, 1.0, hue - 2.0), hue if (3.0..4.0).contains(&hue) => Self::new(0.0, 4.0 - hue, 1.0), hue if (4.0..5.0).contains(&hue) => Self::new(hue - 4.0, 0.0, 1.0), hue if (5.0..6.0).contains(&hue) => Self::new(1.0, 0.0, 6.0 - hue), _ => {
let hue = hue.fract();
let hue = if hue < 0.0 { 1.0 + hue } else { hue };
return Self::from_hue(hue);
}
}
}
pub fn red_green_color(hue: f32) -> Self {
let a = |x| if x < 0.25 { 4.0 * x } else if x >= 0.75 { 4.0 - 4.0 * x } else { 1.0 };
let r = a(hue.fract());
let g = a((hue + 0.5).fract());
return Self::new(r, g, 0.0);
}
pub fn quantize(self, range: u16) -> (u8, u8, u8) {
let quant = |f: f32| (f * range as f32).max(0.0).min(range as f32 - 1.0) as u8;
(quant(self.r), quant(self.g), quant(self.b))
}
pub fn mix(self, other: Color, proportion_of_other: f32) -> Color {
other * proportion_of_other + self * (1.0 - proportion_of_other)
}
}
impl std::ops::Mul<f32> for Color {
type Output = Self;
fn mul(self, multiplier: f32) -> Self::Output {
return Self {
r: self.r * multiplier,
g: self.g * multiplier,
b: self.b * multiplier,
};
}
}
impl std::ops::Div<f32> for Color {
type Output = Self;
fn div(self, multiplier: f32) -> Self::Output {
return Self {
r: self.r / multiplier,
g: self.g / multiplier,
b: self.b / multiplier,
};
}
}
impl std::ops::Add for Color {
type Output = Self;
fn add(self, other: Self) -> Self {
return Self {
r: self.r + other.r,
g: self.g + other.g,
b: self.b + other.b,
};
}
}
impl std::ops::Sub for Color {
type Output = Self;
fn sub(self, other: Self) -> Self {
return Self {
r: self.r - other.r,
g: self.g - other.g,
b: self.b - other.b,
};
}
}
impl std::ops::Add<f32> for Color {
type Output = Self;
fn add(self, addend: f32) -> Self {
return Self {
r: self.r + addend,
g: self.g + addend,
b: self.b + addend,
};
}
}
impl std::ops::Sub<f32> for Color {
type Output = Self;
fn sub(self, subtrand : f32) -> Self {
return Self {
r: self.r - subtrand,
g: self.g - subtrand,
b: self.b - subtrand,
};
}
}
impl std::ops::Neg for Color {
type Output = Self;
fn neg(self) -> Self {
Self {
r: -self.r,
g: -self.g,
b: -self.b,
}
}
}
impl std::iter::Sum for Color {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Color::BLACK, |a, b| a + b)
}
}
#[cfg(feature = "embedded-graphics-support")]
impl From<Color> for embedded_graphics::pixelcolor::Rgb888 {
fn from(color: Color) -> Self {
let (r, g, b) = color.quantize(256);
Self::new(r, g, b)
}
}
#[cfg(feature = "embedded-graphics-support")]
impl From<embedded_graphics::pixelcolor::Rgb888> for Color {
fn from(color: embedded_graphics::pixelcolor::Rgb888) -> Self {
use embedded_graphics::pixelcolor::RgbColor;
Color::new(
(color.r() as f32 + 0.5) / 256.0,
(color.g() as f32 + 0.5) / 256.0,
(color.b() as f32 + 0.5) / 256.0,
)
}
}