use std::fmt;
use crate::genome::{Background, VisualGenes};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Rgb {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl Rgb {
#[must_use]
pub const fn new(r: u8, g: u8, b: u8) -> Self {
Rgb { r, g, b }
}
pub(crate) fn scale(self, k: f64) -> Rgb {
let f = |c: u8| (f64::from(c) * k).round().clamp(0.0, 255.0) as u8;
Rgb::new(f(self.r), f(self.g), f(self.b))
}
}
impl fmt::Display for Rgb {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
}
}
pub(crate) fn hsl(h: f64, s: f64, l: f64) -> Rgb {
let h = h.rem_euclid(360.0) / 60.0;
let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
let x = c * (1.0 - (h % 2.0 - 1.0).abs());
let (r, g, b) = match h as u32 {
0 => (c, x, 0.0),
1 => (x, c, 0.0),
2 => (0.0, c, x),
3 => (0.0, x, c),
4 => (x, 0.0, c),
_ => (c, 0.0, x),
};
let m = l - c / 2.0;
let to8 = |v: f64| ((v + m) * 255.0).round() as u8;
Rgb::new(to8(r), to8(g), to8(b))
}
const HUE_STEPS: f64 = 32.0;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct Palette {
pub base: Rgb,
pub accent1: Rgb,
pub accent2: Rgb,
pub background: Rgb,
}
impl Palette {
#[must_use]
pub fn from_genes(g: &VisualGenes) -> Palette {
let h = f64::from(g.hue) * 360.0 / HUE_STEPS;
let (o1, o2) = g.scheme.offsets();
let background = match g.background {
Background::Dark => Rgb::new(18, 18, 24),
Background::Light => Rgb::new(240, 240, 236),
Background::DarkTint => hsl(h, 0.35, 0.12),
Background::LightTint => hsl(h, 0.45, 0.92),
};
Palette {
base: hsl(h, 0.65, 0.55),
accent1: hsl(h + o1, 0.6, 0.62),
accent2: hsl(h + o2, 0.55, 0.44),
background,
}
}
}