use num_traits::{Float, One, Zero};
use {cast, clamp, ComponentWise};
use blend::{BlendFunction, PreAlpha};
pub trait Blend: Sized
where
<Self::Color as ComponentWise>::Scalar: Float,
{
type Color: Blend<Color = Self::Color> + ComponentWise;
fn into_premultiplied(self) -> PreAlpha<Self::Color, <Self::Color as ComponentWise>::Scalar>;
fn from_premultiplied(
color: PreAlpha<Self::Color, <Self::Color as ComponentWise>::Scalar>,
) -> Self;
fn blend<F>(self, destination: Self, blend_function: F) -> Self
where
F: BlendFunction<Self::Color>,
{
Self::from_premultiplied(
blend_function.apply_to(self.into_premultiplied(), destination.into_premultiplied()),
)
}
fn over(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color
.component_wise(&dst.color, |a, b| a + b * (one - src.alpha)),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn inside(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise_self(|a| a * dst.alpha),
alpha: clamp(src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn outside(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise_self(|a| a * (one - dst.alpha)),
alpha: clamp(src.alpha * (one - dst.alpha), zero, one),
};
Self::from_premultiplied(result)
}
fn atop(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color
.component_wise(&dst.color, |a, b| a * dst.alpha + b * (one - src.alpha)),
alpha: clamp(dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn xor(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
a * (one - dst.alpha) + b * (one - src.alpha)
}),
alpha: clamp(
src.alpha + dst.alpha - two * src.alpha * dst.alpha,
zero,
one,
),
};
Self::from_premultiplied(result)
}
fn plus(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| a + b),
alpha: clamp(src.alpha + dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn multiply(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
a * b + a * (one - dst.alpha) + b * (one - src.alpha)
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn screen(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| a + b - a * b),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn overlay(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
if b * two <= dst.alpha {
two * a * b + a * (one - dst.alpha) + b * (one - src.alpha)
} else {
a * (one + dst.alpha) + b * (one + src.alpha) - two * a * b
- src.alpha * dst.alpha
}
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn darken(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
(a * dst.alpha).min(b * src.alpha) + a * (one - dst.alpha) + b * (one - src.alpha)
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn lighten(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
(a * dst.alpha).max(b * src.alpha) + a * (one - dst.alpha) + b * (one - src.alpha)
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn dodge(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
if a == src.alpha && !b.is_normal() {
a * (one - dst.alpha)
} else if a == src.alpha {
src.alpha * dst.alpha + a * (one - dst.alpha) + b * (one - src.alpha)
} else {
src.alpha * dst.alpha * one.min((b / dst.alpha) * src.alpha / (src.alpha - a))
+ a * (one - dst.alpha) + b * (one - src.alpha)
}
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn burn(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
if !a.is_normal() && b == dst.alpha {
src.alpha * dst.alpha + b * (one - src.alpha)
} else if !a.is_normal() {
b * (one - src.alpha)
} else {
src.alpha * dst.alpha * (one - one.min((one - b / dst.alpha) * src.alpha / a))
+ a * (one - dst.alpha) + b * (one - src.alpha)
}
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn hard_light(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
if a * two <= src.alpha {
two * a * b + a * (one - dst.alpha) + b * (one - src.alpha)
} else {
a * (one + dst.alpha) + b * (one + src.alpha) - two * a * b
- src.alpha * dst.alpha
}
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn soft_light(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
let m = if dst.alpha.is_normal() {
b / dst.alpha
} else {
zero
};
if a * two <= src.alpha {
b * (src.alpha + (two * a - src.alpha) * (one - m)) + a * (one - dst.alpha)
+ b * (one - src.alpha)
} else if b * cast(4.0) <= dst.alpha {
let m2 = m * m;
let m3 = m2 * m;
dst.alpha * (two * a - src.alpha)
* (m3 * cast(16.0) - m2 * cast(12.0) - m * cast(3.0))
+ a - a * dst.alpha + b
} else {
dst.alpha * (two * a - src.alpha) * (m.sqrt() - m) + a - a * dst.alpha + b
}
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn difference(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color.component_wise(&dst.color, |a, b| {
a + b - two * (a * dst.alpha).min(b * src.alpha)
}),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
fn exclusion(self, other: Self) -> Self {
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let src = self.into_premultiplied();
let dst = other.into_premultiplied();
let result = PreAlpha {
color: src.color
.component_wise(&dst.color, |a, b| a + b - two * a * b),
alpha: clamp(src.alpha + dst.alpha - src.alpha * dst.alpha, zero, one),
};
Self::from_premultiplied(result)
}
}