use crate::Color;
use crate::chromatic_adaptation::ChromaticAdaptation;
use crate::illuminant::Illuminant;
use crate::math::Mat3;
use crate::model::Xyz;
pub const fn adapt<A: ChromaticAdaptation>(src_xyz: [f32; 3], dst_xyz: [f32; 3]) -> Mat3 {
let m = Mat3::from_rows(A::M);
let m_inv = Mat3::invert(&m);
let cs = m.apply(src_xyz);
let cd = m.apply(dst_xyz);
let s = [cd[0] / cs[0], cd[1] / cs[1], cd[2] / cs[2]];
let sm = Mat3::from_rows([
[s[0] * A::M[0][0], s[0] * A::M[0][1], s[0] * A::M[0][2]],
[s[1] * A::M[1][0], s[1] * A::M[1][1], s[1] * A::M[1][2]],
[s[2] * A::M[2][0], s[2] * A::M[2][1], s[2] * A::M[2][2]],
]);
Mat3::mul(&m_inv, &sm)
}
impl<W1: Illuminant> Color<[f32; 3], Xyz<W1>> {
pub fn adapt<W2, CA>(self) -> Color<[f32; 3], Xyz<W2>>
where
W2: Illuminant<Observer = <W1 as Illuminant>::Observer>,
CA: ChromaticAdaptation,
{
const fn matrix<W1: Illuminant, W2: Illuminant, CA: ChromaticAdaptation>() -> Mat3 {
adapt::<CA>(W1::WHITE_POINT_XYZ, W2::WHITE_POINT_XYZ)
}
let [x, y, z] = self.inner();
Color::new(const { matrix::<W1, W2, CA>() }.apply([x, y, z]))
}
}
impl<W1: Illuminant> Color<[f32; 4], Xyz<W1>> {
pub fn adapt<W2, CA>(self) -> Color<[f32; 4], Xyz<W2>>
where
W2: Illuminant<Observer = <W1 as Illuminant>::Observer>,
CA: ChromaticAdaptation,
{
const fn matrix<W1: Illuminant, W2: Illuminant, CA: ChromaticAdaptation>() -> Mat3 {
adapt::<CA>(W1::WHITE_POINT_XYZ, W2::WHITE_POINT_XYZ)
}
let [x, y, z, a] = self.inner();
let out = const { matrix::<W1, W2, CA>() }.apply([x, y, z]);
Color::new([out[0], out[1], out[2], a])
}
}
#[cfg(feature = "glam")]
impl<W1: Illuminant> Color<glam::Vec3A, Xyz<W1>> {
pub fn adapt<W2, CA>(self) -> Color<glam::Vec3A, Xyz<W2>>
where
W2: Illuminant<Observer = <W1 as Illuminant>::Observer>,
CA: ChromaticAdaptation,
Xyz<W2>: crate::BackingStore<glam::Vec3A>,
{
const fn matrix<W1: Illuminant, W2: Illuminant, CA: ChromaticAdaptation>() -> Mat3 {
adapt::<CA>(W1::WHITE_POINT_XYZ, W2::WHITE_POINT_XYZ)
}
let [x, y, z] = self.inner().to_array();
let out = const { matrix::<W1, W2, CA>() }.apply([x, y, z]);
Color::new(glam::Vec3A::from_array(out))
}
}
#[cfg(feature = "glam")]
impl<W1: Illuminant> Color<glam::Vec4, Xyz<W1>> {
pub fn adapt<W2, CA>(self) -> Color<glam::Vec4, Xyz<W2>>
where
W2: Illuminant<Observer = <W1 as Illuminant>::Observer>,
CA: ChromaticAdaptation,
Xyz<W2>: crate::BackingStore<glam::Vec4>,
{
const fn matrix<W1: Illuminant, W2: Illuminant, CA: ChromaticAdaptation>() -> Mat3 {
adapt::<CA>(W1::WHITE_POINT_XYZ, W2::WHITE_POINT_XYZ)
}
let [x, y, z, a] = self.inner().to_array();
let out = const { matrix::<W1, W2, CA>() }.apply([x, y, z]);
Color::new(glam::Vec4::new(out[0], out[1], out[2], a))
}
}