golem/blend.rs
1//! Various options to specify how to combine pixels with what they draw over
2//!
3//! GPU blending follows the equation:
4//!
5//! `Output = Operation(SourceFunction(Source), DestFunction(Destination))`
6//!
7//! The `Operation` is controlled by [`BlendEquation`], and the
8//! `SourceFunction` and `DestFunction` are controlled by [`BlendFunction`]. Both of these are
9//! combined to form a [`BlendMode`], which can be applied by [`Context::set_blend_mode`].
10//!
11//! The default [`BlendMode`] produces the result of:
12//!
13//! `Output = Source.Alpha * Source + (1 - Source.Alpha) * Destination`
14//!
15//! and looks like:
16//!
17//! ```no_run
18//! # use golem::blend::{
19//! # BlendMode, BlendInput, BlendFactor, BlendChannel, BlendOperation, BlendEquation,
20//! # BlendFunction,
21//! # };
22//! # fn test() -> BlendMode {
23//! BlendMode {
24//! equation: BlendEquation::Same(BlendOperation::Add),
25//! function: BlendFunction::Same {
26//! source: BlendFactor::Color {
27//! input: BlendInput::Source,
28//! channel: BlendChannel::Alpha,
29//! is_inverse: false,
30//! },
31//! destination: BlendFactor::Color {
32//! input: BlendInput::Source,
33//! channel: BlendChannel::Alpha,
34//! is_inverse: true,
35//! },
36//! },
37//! global_color: [0.0; 4]
38//! }
39//! # }
40//! ```
41//!
42//! For more information, see the documentation for the individual Blend enums.
43//!
44//! [`Context::set_blend_mode`]: crate::Context::set_blend_mode
45
46/// The state of the blend pipeline
47///
48/// See [`Context::set_blend_mode`]
49///
50/// [`Context::set_blend_mode`]: crate::Context::set_blend_mode
51#[derive(Copy, Clone, Debug, PartialEq)]
52pub struct BlendMode {
53 /// How to combine the source and destination
54 pub equation: BlendEquation,
55 /// How to transform the inputs to the `equation`
56 pub function: BlendFunction,
57 /// A color in blending that's neither the source nor destination, specified as [R, G, B, A]
58 ///
59 /// This provides the value for [`BlendInput::GlobalBlend`]
60 pub global_color: [f32; 4],
61}
62
63impl Default for BlendMode {
64 fn default() -> BlendMode {
65 BlendMode {
66 equation: BlendEquation::default(),
67 function: BlendFunction::default(),
68 global_color: [0.0; 4],
69 }
70 }
71}
72
73/// How to combine the values when blending
74///
75/// Almost all the time you'll want `BlendEquation::Same(BlendOperation::Add)`, but there are cases
76/// where other blend equatiosn come in handy.
77#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
78pub enum BlendEquation {
79 /// Apply the same equation to the color and alpha of the blended pixels
80 Same(BlendOperation),
81 /// Apply a different equation to the color and alpha channel of the blended pixels
82 Separate {
83 color: BlendOperation,
84 alpha: BlendOperation,
85 },
86}
87
88impl Default for BlendEquation {
89 fn default() -> BlendEquation {
90 BlendEquation::Same(BlendOperation::Add)
91 }
92}
93
94/// The operation to apply to the pixels during blending
95#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
96pub enum BlendOperation {
97 /// Output = Source + Destination
98 Add,
99 /// Output = Source - Destination
100 Subtract,
101 /// Output = Destination - Source
102 ReverseSubtract,
103 /// Output = Max(Source, Destination)
104 Max,
105 /// Output = Min(Source, Destination)
106 Min,
107}
108
109impl BlendOperation {
110 pub(crate) fn to_gl(self) -> u32 {
111 use BlendOperation::*;
112 match self {
113 Add => glow::FUNC_ADD,
114 Subtract => glow::FUNC_SUBTRACT,
115 ReverseSubtract => glow::FUNC_REVERSE_SUBTRACT,
116 Max => glow::MAX,
117 Min => glow::MIN,
118 }
119 }
120}
121
122/// The blend function controls how the source and destination are transformed
123///
124/// Before being passed to the [`BlendEquation`], the source and destination are multiplied by the
125/// value determined by `BlendFunction`.
126#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
127pub enum BlendFunction {
128 /// Use the same [`BlendFactor`] on the color and alpha channels
129 Same {
130 source: BlendFactor,
131 destination: BlendFactor,
132 },
133 /// Use different [`BlendFactor`]s on the color and alpha channels
134 Separate {
135 source_color: BlendFactor,
136 source_alpha: BlendFactor,
137 destination_color: BlendFactor,
138 destination_alpha: BlendFactor,
139 },
140}
141
142impl Default for BlendFunction {
143 fn default() -> BlendFunction {
144 BlendFunction::Same {
145 source: BlendFactor::Color {
146 input: BlendInput::Source,
147 channel: BlendChannel::Alpha,
148 is_inverse: false,
149 },
150 destination: BlendFactor::Color {
151 input: BlendInput::Source,
152 channel: BlendChannel::Alpha,
153 is_inverse: true,
154 },
155 }
156 }
157}
158
159/// The various coefficients to multiply the color inputs by
160#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
161pub enum BlendFactor {
162 Zero,
163 One,
164 Color {
165 /// Which source of color
166 input: BlendInput,
167 /// Which channel of the `input` to use
168 channel: BlendChannel,
169 /// Whether to use (1 - Value) instead of Value
170 is_inverse: bool,
171 },
172}
173
174impl BlendFactor {
175 pub(crate) fn to_gl(self) -> u32 {
176 use BlendChannel::*;
177 use BlendFactor::{Color as Col, One, Zero};
178 use BlendInput::*;
179
180 match self {
181 Zero => glow::ZERO,
182 One => glow::ONE,
183 Col {
184 input: Source,
185 channel: Color,
186 is_inverse: false,
187 } => glow::SRC_COLOR,
188 Col {
189 input: Source,
190 channel: Color,
191 is_inverse: true,
192 } => glow::ONE_MINUS_SRC_COLOR,
193 Col {
194 input: Source,
195 channel: Alpha,
196 is_inverse: false,
197 } => glow::SRC_ALPHA,
198 Col {
199 input: Source,
200 channel: Alpha,
201 is_inverse: true,
202 } => glow::ONE_MINUS_SRC_ALPHA,
203 Col {
204 input: Destination,
205 channel: Color,
206 is_inverse: false,
207 } => glow::DST_COLOR,
208 Col {
209 input: Destination,
210 channel: Color,
211 is_inverse: true,
212 } => glow::ONE_MINUS_DST_COLOR,
213 Col {
214 input: Destination,
215 channel: Alpha,
216 is_inverse: false,
217 } => glow::DST_ALPHA,
218 Col {
219 input: Destination,
220 channel: Alpha,
221 is_inverse: true,
222 } => glow::ONE_MINUS_DST_ALPHA,
223 Col {
224 input: GlobalBlend,
225 channel: Color,
226 is_inverse: false,
227 } => glow::CONSTANT_COLOR,
228 Col {
229 input: GlobalBlend,
230 channel: Color,
231 is_inverse: true,
232 } => glow::ONE_MINUS_CONSTANT_COLOR,
233 Col {
234 input: GlobalBlend,
235 channel: Alpha,
236 is_inverse: false,
237 } => glow::CONSTANT_ALPHA,
238 Col {
239 input: GlobalBlend,
240 channel: Alpha,
241 is_inverse: true,
242 } => glow::ONE_MINUS_CONSTANT_ALPHA,
243 }
244 }
245}
246
247/// A color to pull from when blending
248#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
249pub enum BlendInput {
250 /// The pixel that is being drawn
251 Source,
252 /// The pixel that is being replaced
253 Destination,
254 /// The color supplied to [`BlendMode::global_color`]
255 GlobalBlend,
256}
257
258/// Which part of the [`BlendInput`] to pull from
259#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
260pub enum BlendChannel {
261 /// The RGB component when using separate functions, or RGBA otherwise
262 Color,
263 /// The Alpha component
264 Alpha,
265}