#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Rgb(pub u8, pub u8, pub u8);
pub fn lerp_rgb(a: Rgb, b: Rgb, t: f32) -> Rgb {
let t = t.clamp(0.0, 1.0);
Rgb(
lerp_u8(a.0, b.0, t),
lerp_u8(a.1, b.1, t),
lerp_u8(a.2, b.2, t),
)
}
pub(crate) fn lerp_u8(a: u8, b: u8, t: f32) -> u8 {
let af = a as f32;
let bf = b as f32;
(af + (bf - af) * t).round().clamp(0.0, 255.0) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lerp_rgb_endpoints_are_exact() {
let a = Rgb(10, 20, 30);
let b = Rgb(200, 100, 50);
assert_eq!(lerp_rgb(a, b, 0.0), a);
assert_eq!(lerp_rgb(a, b, 1.0), b);
}
#[test]
fn lerp_rgb_clamps_out_of_range_t() {
let a = Rgb(0, 0, 0);
let b = Rgb(100, 100, 100);
assert_eq!(lerp_rgb(a, b, -1.0), a);
assert_eq!(lerp_rgb(a, b, 2.0), b);
}
#[test]
fn lerp_rgb_midpoint_is_average() {
let a = Rgb(0, 0, 0);
let b = Rgb(200, 100, 50);
assert_eq!(lerp_rgb(a, b, 0.5), Rgb(100, 50, 25));
}
}