use crate::Color;
use crate::BackingStore;
use crate::illuminant::Illuminant;
use crate::model::{LCh, Lab, Oklab, Oklch, Rgb};
use crate::primaries::Primaries;
use crate::transfer::Linear;
macro_rules! impl_lerp_perceptual {
($name:ident, $bound:tt) => {
impl<$bound> Color<[f32; 3], $name<$bound>>
where
$bound: Illuminant,
{
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + t * (b0 - a0), a1 + t * (b1 - a1), a2 + t * (b2 - a2)])
}
}
impl<$bound, const O: usize> Color<[f32; 4], $name<$bound, O>>
where
$bound: Illuminant,
{
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2, a3] = self.inner();
let [b0, b1, b2, b3] = rhs.inner();
Color::new([
a0 + t * (b0 - a0),
a1 + t * (b1 - a1),
a2 + t * (b2 - a2),
a3 + t * (b3 - a3),
])
}
}
};
($name:ident) => {
impl Color<[f32; 3], $name> {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + t * (b0 - a0), a1 + t * (b1 - a1), a2 + t * (b2 - a2)])
}
}
impl<const O: usize> Color<[f32; 4], $name<O>> {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2, a3] = self.inner();
let [b0, b1, b2, b3] = rhs.inner();
Color::new([
a0 + t * (b0 - a0),
a1 + t * (b1 - a1),
a2 + t * (b2 - a2),
a3 + t * (b3 - a3),
])
}
}
};
}
impl_lerp_perceptual!(Lab, W);
impl_lerp_perceptual!(Oklab);
#[inline(always)]
fn lerp_hue(a: f32, b: f32, t: f32) -> f32 {
let delta = (b - a + core::f32::consts::PI).rem_euclid(core::f32::consts::TAU) - core::f32::consts::PI;
a + t * delta
}
macro_rules! impl_lerp_polar {
($name:ident, $bound:tt) => {
impl<$bound> Color<[f32; 3], $name<$bound>> where $bound: Illuminant {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [al, ac, ah] = self.inner();
let [bl, bc, bh] = rhs.inner();
Color::new([
al + t * (bl - al),
ac + t * (bc - ac),
lerp_hue(ah, bh, t),
])
}
}
impl<$bound, const O: usize> Color<[f32; 4], $name<$bound, O>> where $bound: Illuminant {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let s = self.inner();
let r = rhs.inner();
let ai = 3 - O * 3;
let mut out = s;
out[O] = s[O] + t * (r[O] - s[O]);
out[O + 1] = s[O + 1] + t * (r[O + 1] - s[O + 1]);
out[O + 2] = lerp_hue(s[O + 2], r[O + 2], t);
out[ai] = s[ai] + t * (r[ai] - s[ai]);
Color::new(out)
}
}
};
($name:ident) => {
impl Color<[f32; 3], $name> {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [al, ac, ah] = self.inner();
let [bl, bc, bh] = rhs.inner();
Color::new([
al + t * (bl - al),
ac + t * (bc - ac),
lerp_hue(ah, bh, t),
])
}
}
impl<const O: usize> Color<[f32; 4], $name<O>> {
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let s = self.inner();
let r = rhs.inner();
let ai = 3 - O * 3;
let mut out = s;
out[O] = s[O] + t * (r[O] - s[O]);
out[O + 1] = s[O + 1] + t * (r[O + 1] - s[O + 1]);
out[O + 2] = lerp_hue(s[O + 2], r[O + 2], t);
out[ai] = s[ai] + t * (r[ai] - s[ai]);
Color::new(out)
}
}
};
}
impl_lerp_polar!(LCh, W);
impl_lerp_polar!(Oklch);
impl<P, L> Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + t * (b0 - a0), a1 + t * (b1 - a1), a2 + t * (b2 - a2)])
}
}
impl<P, L> Color<[f32; 4], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 4]>,
{
#[inline(always)]
pub fn lerp(self, rhs: Self, t: f32) -> Self {
let [a0, a1, a2, a3] = self.inner();
let [b0, b1, b2, b3] = rhs.inner();
Color::new([
a0 + t * (b0 - a0),
a1 + t * (b1 - a1),
a2 + t * (b2 - a2),
a3 + t * (b3 - a3),
])
}
}