use core::ops::{Mul, MulAssign};
use crate::BackingStore;
use crate::ChannelMap;
use crate::Color;
use crate::illuminant::Illuminant;
use crate::model::{Lab, Oklab, Rgb, Spectral, SpectralKind, WavelengthGrid};
use crate::primaries::Primaries;
use crate::transfer::Linear;
macro_rules! impl_scalar_mul_perceptual {
($name:ident, $bound:tt) => {
impl<$bound> Mul<f32> for Color<[f32; 3], $name<$bound>>
where
$bound: Illuminant,
{
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
Color::new(self.inner().map(|v| v * s))
}
}
impl<$bound, const O: usize> Mul<f32> for Color<[f32; 4], $name<$bound, O>>
where
$bound: Illuminant,
{
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
let ch = self.inner();
let mut out = ch;
out[O] = ch[O] * s;
out[O + 1] = ch[O + 1] * s;
out[O + 2] = ch[O + 2] * s;
Color::new(out)
}
}
};
($name:ident) => {
impl Mul<f32> for Color<[f32; 3], $name> {
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
Color::new(self.inner().map(|v| v * s))
}
}
impl<const O: usize> Mul<f32> for Color<[f32; 4], $name<O>> {
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
let ch = self.inner();
let mut out = ch;
out[O] = ch[O] * s;
out[O + 1] = ch[O + 1] * s;
out[O + 2] = ch[O + 2] * s;
Color::new(out)
}
}
};
}
impl_scalar_mul_perceptual!(Lab, W);
impl_scalar_mul_perceptual!(Oklab);
impl<P, L> Mul<f32> for Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
Color::new(self.inner().map(|v| v * s))
}
}
impl<P, L> Mul<f32> for Color<[f32; 4], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 4]> + ChannelMap<4>,
{
type Output = Self;
#[inline(always)]
fn mul(self, s: f32) -> Self {
let ch = self.inner();
let [ri, gi, bi, _] = L::INDICES;
let mut out = ch;
out[ri] = ch[ri] * s;
out[gi] = ch[gi] * s;
out[bi] = ch[bi] * s;
Color::new(out)
}
}
impl<P, L> Mul for Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
type Output = Self;
#[inline(always)]
fn mul(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 BANDS: usize, G, K> Mul 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 mul(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<const BANDS: usize, G, K> Mul<f32> 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 mul(self, s: f32) -> Self {
let mut out = self.inner();
for v in &mut out {
*v *= s;
}
Color::new(out)
}
}
impl<P, L> Mul for Color<[f32; 4], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 4]> + ChannelMap<4>,
{
type Output = Self;
#[inline(always)]
fn mul(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> MulAssign<f32> for Color<[f32; BANDS], Spectral<BANDS, G, K>>
where
G: WavelengthGrid<BANDS>,
K: SpectralKind,
Spectral<BANDS, G, K>: BackingStore<[f32; BANDS]>,
{
#[inline(always)]
fn mul_assign(&mut self, s: f32) {
let mut out = self.inner();
for v in &mut out {
*v *= s;
}
*self = Color::new(out);
}
}
impl<P, L> MulAssign<f32> for Color<[f32; 3], Rgb<P, Linear, L>>
where
P: Primaries,
L: BackingStore<[f32; 3]>,
{
#[inline(always)]
fn mul_assign(&mut self, s: f32) {
let [a0, a1, a2] = self.inner();
*self = Color::new([a0 * s, a1 * s, a2 * s]);
}
}