1use core::ops::{Mul, Sub};
2
3use crate::{
4 blend::{BlendFunction, PreAlpha},
5 cast::ArrayCast,
6 num::{Arithmetics, IsValidDivisor, MinMax, One, Real, Sqrt, Zero},
7};
8
9use super::{zip_colors, Premultiply};
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18pub struct Equations {
19 pub color_equation: Equation,
21
22 pub alpha_equation: Equation,
24
25 pub color_parameters: Parameters,
27
28 pub alpha_parameters: Parameters,
30}
31
32impl Equations {
33 pub fn from_equations(color: Equation, alpha: Equation) -> Equations {
36 Equations {
37 color_equation: color,
38 alpha_equation: alpha,
39 color_parameters: Parameters {
40 source: Parameter::One,
41 destination: Parameter::One,
42 },
43 alpha_parameters: Parameters {
44 source: Parameter::One,
45 destination: Parameter::One,
46 },
47 }
48 }
49
50 pub fn from_parameters(source: Parameter, destination: Parameter) -> Equations {
53 Equations {
54 color_equation: Equation::Add,
55 alpha_equation: Equation::Add,
56 color_parameters: Parameters {
57 source,
58 destination,
59 },
60 alpha_parameters: Parameters {
61 source,
62 destination,
63 },
64 }
65 }
66}
67
68impl<C, S, const N: usize, const M: usize> BlendFunction<C> for Equations
69where
70 C: Clone
71 + Premultiply<Scalar = S>
72 + Mul<Output = C>
73 + Mul<S, Output = C>
74 + ArrayCast<Array = [S; N]>,
75 PreAlpha<C>: ArrayCast<Array = [S; M]>,
76 S: Real + One + Zero + MinMax + Sqrt + IsValidDivisor + Arithmetics + Clone,
77{
78 fn apply_to(self, source: PreAlpha<C>, destination: PreAlpha<C>) -> PreAlpha<C> {
79 let (src_color, mut dst_color) =
80 if matches!(self.color_equation, Equation::Min | Equation::Max) {
81 (source.color.clone(), destination.color.clone())
82 } else {
83 let col_src_param = self
84 .color_parameters
85 .source
86 .apply_to(source.clone(), destination.clone());
87 let col_dst_param = self
88 .color_parameters
89 .destination
90 .apply_to(source.clone(), destination.clone());
91
92 (
93 col_src_param.mul_color(source.color.clone()),
94 col_dst_param.mul_color(destination.color.clone()),
95 )
96 };
97
98 let (src_alpha, dst_alpha) = if matches!(self.alpha_equation, Equation::Min | Equation::Max)
99 {
100 (source.alpha, destination.alpha)
101 } else {
102 let alpha_src_param = self
103 .alpha_parameters
104 .source
105 .apply_to(source.clone(), destination.clone());
106 let alpha_dst_param = self
107 .alpha_parameters
108 .destination
109 .apply_to(source.clone(), destination.clone());
110
111 (
112 alpha_src_param.mul_constant(source.alpha),
113 alpha_dst_param.mul_constant(destination.alpha),
114 )
115 };
116
117 let color_op = match self.color_equation {
118 Equation::Add => |src, dst| src + dst,
119 Equation::Subtract => |src, dst| src - dst,
120 Equation::ReverseSubtract => |src, dst| dst - src,
121 Equation::Min => MinMax::min,
122 Equation::Max => MinMax::max,
123 };
124
125 let alpha_op = match self.alpha_equation {
126 Equation::Add => |src, dst| src + dst,
127 Equation::Subtract => |src, dst| src - dst,
128 Equation::ReverseSubtract => |src, dst| dst - src,
129 Equation::Min => MinMax::min,
130 Equation::Max => MinMax::max,
131 };
132
133 for (src, dst) in zip_colors(src_color, &mut dst_color) {
134 *dst = color_op(src, dst.clone());
135 }
136
137 PreAlpha {
138 color: dst_color,
139 alpha: alpha_op(src_alpha, dst_alpha),
140 }
141 }
142}
143
144#[derive(Clone, Copy, PartialEq, Eq, Debug)]
146pub enum Equation {
147 Add,
149
150 Subtract,
153
154 ReverseSubtract,
157
158 Min,
162
163 Max,
167}
168
169#[derive(Clone, Copy, PartialEq, Eq, Debug)]
171pub struct Parameters {
172 pub source: Parameter,
174
175 pub destination: Parameter,
177}
178
179#[derive(Clone, Copy, PartialEq, Eq, Debug)]
181pub enum Parameter {
182 One,
184
185 Zero,
187
188 SourceColor,
190
191 OneMinusSourceColor,
193
194 DestinationColor,
196
197 OneMinusDestinationColor,
199
200 SourceAlpha,
202
203 OneMinusSourceAlpha,
205
206 DestinationAlpha,
208
209 OneMinusDestinationAlpha,
211}
212
213impl Parameter {
214 fn apply_to<C, T, const N: usize>(
215 &self,
216 source: PreAlpha<C>,
217 destination: PreAlpha<C>,
218 ) -> ParamOut<C>
219 where
220 C: Premultiply<Scalar = T>,
221 PreAlpha<C>: ArrayCast<Array = [T; N]>,
222 T: Real + One + Zero + Sub<Output = T>,
223 {
224 match *self {
225 Parameter::One => ParamOut::Constant(T::one()),
226 Parameter::Zero => ParamOut::Constant(T::zero()),
227 Parameter::SourceColor => ParamOut::Color(source),
228 Parameter::OneMinusSourceColor => {
229 ParamOut::Color(<[T; N]>::from(source).map(|a| T::one() - a).into())
230 }
231 Parameter::DestinationColor => ParamOut::Color(destination),
232 Parameter::OneMinusDestinationColor => {
233 ParamOut::Color(<[T; N]>::from(destination).map(|a| T::one() - a).into())
234 }
235 Parameter::SourceAlpha => ParamOut::Constant(source.alpha),
236 Parameter::OneMinusSourceAlpha => ParamOut::Constant(T::one() - source.alpha),
237 Parameter::DestinationAlpha => ParamOut::Constant(destination.alpha),
238 Parameter::OneMinusDestinationAlpha => ParamOut::Constant(T::one() - destination.alpha),
239 }
240 }
241}
242
243enum ParamOut<C: Premultiply> {
244 Color(PreAlpha<C>),
245 Constant(C::Scalar),
246}
247
248impl<C, T> ParamOut<C>
249where
250 C: Mul<Output = C> + Mul<T, Output = C> + Premultiply<Scalar = T>,
251 T: Mul<Output = T> + Clone,
252{
253 fn mul_constant(self, other: T) -> T {
254 match self {
255 ParamOut::Color(c) => c.alpha * other,
256 ParamOut::Constant(c) => c * other,
257 }
258 }
259
260 fn mul_color(self, other: C) -> C {
261 match self {
262 ParamOut::Color(c) => other * c.color,
263 ParamOut::Constant(c) => other * c,
264 }
265 }
266}