use core::ops::{Add, AddAssign};
use crate::Color;
use crate::BackingStore;
use crate::ChannelMap;
use crate::illuminant::Illuminant;
use crate::model::{Lab, Oklab, Rgb, Spectral, SpectralKind, WavelengthGrid};
use crate::primaries::Primaries;
use crate::transfer::Linear;
macro_rules! impl_add_perceptual {
($name:ident, $bound:tt) => {
impl<$bound> Add for Color<[f32; 3], $name<$bound>> where $bound: Illuminant {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + b0, a1 + b1, a2 + b2])
}
}
impl<$bound, const O: usize> Add for Color<[f32; 4], $name<$bound, O>> where $bound: Illuminant {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let s = self.inner();
let r = rhs.inner();
let mut out = s;
out[O] = s[O] + r[O];
out[O + 1] = s[O + 1] + r[O + 1];
out[O + 2] = s[O + 2] + r[O + 2];
Color::new(out)
}
}
};
($name:ident) => {
impl Add for Color<[f32; 3], $name> {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + b0, a1 + b1, a2 + b2])
}
}
impl<const O: usize> Add for Color<[f32; 4], $name<O>> {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let s = self.inner();
let r = rhs.inner();
let mut out = s;
out[O] = s[O] + r[O];
out[O + 1] = s[O + 1] + r[O + 1];
out[O + 2] = s[O + 2] + r[O + 2];
Color::new(out)
}
}
};
}
impl_add_perceptual!(Lab, W);
impl_add_perceptual!(Oklab);
impl<const BANDS: usize, G, K> Add for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
G: WavelengthGrid<BANDS>,
K: SpectralKind,
Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let a = self.inner();
let b = rhs.inner();
let mut out = a;
for i in 0..BANDS { out[i] = a[i] + b[i]; }
Color::new(out)
}
}
impl<P, L> Add for Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
Color::new([a0 + b0, a1 + b1, a2 + b2])
}
}
impl<P, L> Add for Color<[f32; 4], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 4]> + ChannelMap<4>,
{
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
let s = self.inner();
let r = rhs.inner();
let [ri, gi, bi, _] = L::INDICES;
let mut out = s;
out[ri] = s[ri] + r[ri];
out[gi] = s[gi] + r[gi];
out[bi] = s[bi] + r[bi];
Color::new(out)
}
}
impl<const BANDS: usize, G, K> AddAssign for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
G: WavelengthGrid<BANDS>,
K: SpectralKind,
Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
let b = rhs.inner();
let mut out = self.inner();
for i in 0..BANDS { out[i] += b[i]; }
*self = Color::new(out);
}
}
impl<P, L> AddAssign for Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
let [a0, a1, a2] = self.inner();
let [b0, b1, b2] = rhs.inner();
*self = Color::new([a0 + b0, a1 + b1, a2 + b2]);
}
}