use ordered_float::OrderedFloat; #[derive(Copy, Clone)] pub struct Color { pub red: u8, pub green: u8, pub blue: u8, pub alpha: u8 } pub type Palette = Vec<((OrderedFloat, OrderedFloat), (Color, Color))>; macro_rules! c { ($r:expr,$g:expr,$b:expr) => { Color { red: $r, green: $g, blue: $b, alpha: 255 } }; ($r:expr,$g:expr,$b:expr,$a:expr) => { Color { red: $r, green: $g, blue: $b, alpha: $a } }; } macro_rules! r { ($f:expr,$t:expr) => { (OrderedFloat($f), OrderedFloat($t)) }; } pub fn create_test_palette() -> Palette { let mut out = vec![]; out.push((r!(f64::NEG_INFINITY, 10.0), (c!(164, 164, 255), c!(164, 164, 255)))); out.push((r!(10.0, 20.0), (c!(64, 128, 255), c!(32, 64, 128)))); out.push((r!(20.0, 30.0), (c!(0, 255, 0), c!(0, 128, 0)))); out.push((r!(30.0, 40.0), (c!(255, 255, 0), c!(255, 128, 0)))); out.push((r!(40.0, 50.0), (c!(255, 255, 0), c!(255, 128, 0)))); out.push((r!(50.0, 60.0), (c!(255, 0, 0), c!(160, 0, 0)))); out.push((r!(60.0, 70.0), (c!(255, 0, 255), c!(128, 0, 128)))); out.push((r!(70.0, 80.0), (c!(255, 255, 255), c!(128, 128, 128)))); out.push((r!(80.0, f64::INFINITY), (c!(128, 128, 128), c!(128, 128, 128)))); out } pub trait ColorPalette { fn colorize(&self, at: f64) -> Color; } impl ColorPalette for Palette { fn colorize(&self, at: f64) -> Color { for (raw_range, color_range) in self { let range = *raw_range.0 .. *raw_range.1; if range.contains(&at) { let mapped_end = *raw_range.1 - *raw_range.0; let mapped_point = at - *raw_range.0; let t = mapped_point / mapped_end; let color_start = color_range.0; let color_end = color_range.1; return lerp_color(color_start, color_end, t); } } Color { red: 0, green: 0, blue: 0, alpha: 0 } } } fn lerp(p0: f64, p1: f64, t: f64) -> f64 { p0 + t * (p1 - p0) } fn lerp_color(c0: Color, c1: Color, t: f64) -> Color { Color { red: lerp(c0.red as f64, c1.red as f64, t) as u8, green: lerp(c0.green as f64, c1.green as f64, t) as u8, blue: lerp(c0.blue as f64, c1.blue as f64, t) as u8, alpha: lerp(c0.alpha as f64, c1.alpha as f64, t) as u8 } }