fret_core/scene/composite.rs
1use super::{EffectQuality, Rect};
2
3#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
4pub enum BlendMode {
5 /// Premultiplied alpha-over (the baseline compositing contract; ADR 0040).
6 #[default]
7 Over,
8 /// Additive blending (used for glow/beam).
9 Add,
10 /// Multiply blending (used for grain/darken overlays).
11 Multiply,
12 /// Screen blending (used for light overlays).
13 Screen,
14 /// Channel-wise darken (`min(dst, src)` for color channels).
15 ///
16 /// This mode is bounded and portable because it maps to a fixed-function blend operation
17 /// (no destination sampling).
18 Darken,
19 /// Channel-wise lighten (`max(dst, src)` for color channels).
20 ///
21 /// This mode is bounded and portable because it maps to a fixed-function blend operation
22 /// (no destination sampling).
23 Lighten,
24 /// Subtract (`dst - src`, clamped to `[0, 1]`) for color channels.
25 ///
26 /// This mode is bounded and portable because it maps to a fixed-function blend operation
27 /// (no destination sampling).
28 Subtract,
29}
30
31impl BlendMode {
32 pub const COUNT: usize = 7;
33
34 pub const ALL: [BlendMode; Self::COUNT] = [
35 BlendMode::Over,
36 BlendMode::Add,
37 BlendMode::Multiply,
38 BlendMode::Screen,
39 BlendMode::Darken,
40 BlendMode::Lighten,
41 BlendMode::Subtract,
42 ];
43
44 pub const fn pipeline_index(self) -> usize {
45 match self {
46 BlendMode::Over => 0,
47 BlendMode::Add => 1,
48 BlendMode::Multiply => 2,
49 BlendMode::Screen => 3,
50 BlendMode::Darken => 4,
51 BlendMode::Lighten => 5,
52 BlendMode::Subtract => 6,
53 }
54 }
55}
56
57/// Descriptor for an isolated compositing group (ADR 0247).
58///
59/// The group is rendered into an offscreen intermediate and then composited back onto the parent
60/// target using the requested `mode`. `bounds` is a computation bound (not an implicit clip).
61#[non_exhaustive]
62#[derive(Debug, Clone, Copy, PartialEq)]
63pub struct CompositeGroupDesc {
64 /// Computation bounds (not an implicit clip), see ADR 0247.
65 pub bounds: Rect,
66 pub mode: BlendMode,
67 pub quality: EffectQuality,
68 /// Group-level opacity multiplier applied when the group is composited back to its parent.
69 ///
70 /// This enables CSS-like isolated opacity semantics (e.g. `saveLayerAlpha`): overlapping
71 /// children inside the group blend with each other normally, then the final group result is
72 /// multiplied by this opacity.
73 ///
74 /// Default: `1.0`.
75 pub opacity: f32,
76}
77
78impl CompositeGroupDesc {
79 pub const fn new(bounds: Rect, mode: BlendMode, quality: EffectQuality) -> Self {
80 Self {
81 bounds,
82 mode,
83 quality,
84 opacity: 1.0,
85 }
86 }
87
88 pub fn with_opacity(mut self, opacity: f32) -> Self {
89 self.opacity = opacity;
90 self
91 }
92}