use num_traits::Float;
use {Blend, ComponentWise};
use blend::{BlendFunction, PreAlpha};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Equations {
pub color_equation: Equation,
pub alpha_equation: Equation,
pub color_parameters: Parameters,
pub alpha_parameters: Parameters,
}
impl Equations {
pub fn from_equations(color: Equation, alpha: Equation) -> Equations {
Equations {
color_equation: color,
alpha_equation: alpha,
color_parameters: Parameters {
source: Parameter::One,
destination: Parameter::One,
},
alpha_parameters: Parameters {
source: Parameter::One,
destination: Parameter::One,
},
}
}
pub fn from_parameters(source: Parameter, destination: Parameter) -> Equations {
Equations {
color_equation: Equation::Add,
alpha_equation: Equation::Add,
color_parameters: Parameters {
source: source,
destination: destination,
},
alpha_parameters: Parameters {
source: source,
destination: destination,
},
}
}
}
impl<C: Blend<Color = C> + ComponentWise + Clone> BlendFunction<C> for Equations
where
C::Scalar: Float,
{
fn apply_to(
self,
source: PreAlpha<C, C::Scalar>,
destination: PreAlpha<C, C::Scalar>,
) -> PreAlpha<C, C::Scalar> {
let col_src_param = self.color_parameters
.source
.apply_to(source.clone(), destination.clone());
let col_dst_param = self.color_parameters
.destination
.apply_to(source.clone(), destination.clone());
let alpha_src_param = self.alpha_parameters
.source
.apply_to(source.clone(), destination.clone());
let alpha_dst_param = self.alpha_parameters
.destination
.apply_to(source.clone(), destination.clone());
let src_color = col_src_param.mul_color(source.color.clone());
let dst_color = col_dst_param.mul_color(destination.color.clone());
let src_alpha = alpha_src_param.mul_constant(source.alpha);
let dst_alpha = alpha_dst_param.mul_constant(destination.alpha);
let color = match self.color_equation {
Equation::Add => src_color.component_wise(&dst_color, |a, b| a + b),
Equation::Subtract => src_color.component_wise(&dst_color, |a, b| a - b),
Equation::ReverseSubtract => dst_color.component_wise(&src_color, |a, b| a - b),
Equation::Min => source
.color
.component_wise(&destination.color, |a, b| a.min(b)),
Equation::Max => source
.color
.component_wise(&destination.color, |a, b| a.max(b)),
};
let alpha = match self.alpha_equation {
Equation::Add => src_alpha + dst_alpha,
Equation::Subtract => src_alpha - dst_alpha,
Equation::ReverseSubtract => dst_alpha - src_alpha,
Equation::Min => source.alpha.min(destination.alpha),
Equation::Max => source.alpha.max(destination.alpha),
};
PreAlpha {
color: color,
alpha: alpha,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Equation {
Add,
Subtract,
ReverseSubtract,
Min,
Max,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Parameters {
pub source: Parameter,
pub destination: Parameter,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Parameter {
One,
Zero,
SourceColor,
OneMinusSourceColor,
DestinationColor,
OneMinusDestinationColor,
SourceAlpha,
OneMinusSourceAlpha,
DestinationAlpha,
OneMinusDestinationAlpha,
}
impl Parameter {
fn apply_to<C, T: Float>(
&self,
source: PreAlpha<C, T>,
destination: PreAlpha<C, T>,
) -> ParamOut<C, T>
where
PreAlpha<C, T>: ComponentWise<Scalar = T>,
{
match *self {
Parameter::One => ParamOut::Constant(T::one()),
Parameter::Zero => ParamOut::Constant(T::zero()),
Parameter::SourceColor => ParamOut::Color(source),
Parameter::OneMinusSourceColor => {
ParamOut::Color(source.component_wise_self(|a| T::one() - a))
}
Parameter::DestinationColor => ParamOut::Color(destination),
Parameter::OneMinusDestinationColor => {
ParamOut::Color(destination.component_wise_self(|a| T::one() - a))
}
Parameter::SourceAlpha => ParamOut::Constant(source.alpha),
Parameter::OneMinusSourceAlpha => ParamOut::Constant(T::one() - source.alpha),
Parameter::DestinationAlpha => ParamOut::Constant(destination.alpha),
Parameter::OneMinusDestinationAlpha => ParamOut::Constant(T::one() - destination.alpha),
}
}
}
enum ParamOut<C, T: Float> {
Color(PreAlpha<C, T>),
Constant(T),
}
impl<C: ComponentWise<Scalar = T>, T: Float> ParamOut<C, T> {
fn mul_constant(self, other: T) -> T {
match self {
ParamOut::Color(c) => c.alpha * other,
ParamOut::Constant(c) => c * other,
}
}
fn mul_color(self, other: C) -> C {
match self {
ParamOut::Color(c) => other.component_wise(&c.color, |a, b| a * b),
ParamOut::Constant(c) => other.component_wise_self(|a| a * c),
}
}
}