Skip to main content

agg_gui/gfx_ctx/
layers.rs

1//! Offscreen compositing layer support for `GfxCtx`.
2//!
3//! Layers let widgets and SVG groups render into temporary transparent
4//! framebuffers before compositing the result back into the active target.
5
6use super::*;
7
8impl GfxCtx<'_> {
9    // -------------------------------------------------------------------------
10    // Layer compositing
11    // -------------------------------------------------------------------------
12
13    /// Begin an offscreen compositing layer of `width × height` pixels.
14    ///
15    /// All draw calls until the matching `pop_layer` are redirected into a fresh
16    /// transparent `Framebuffer`.  The current CTM's translation records the
17    /// layer's screen-space origin; drawing inside uses a reset local transform.
18    pub fn push_layer(&mut self, width: f64, height: f64) {
19        self.push_layer_with_alpha(width, height, 1.0);
20    }
21
22    pub fn push_layer_with_alpha(&mut self, width: f64, height: f64, alpha: f64) {
23        let origin_x = self.state.transform.tx;
24        let origin_y = self.state.transform.ty;
25        let saved_state = self.state.clone();
26        let saved_stack = std::mem::take(&mut self.state_stack);
27        let layer_fb = Framebuffer::new(width.ceil() as u32, height.ceil() as u32);
28        self.layer_stack.push(LayerEntry {
29            fb: layer_fb,
30            saved_state,
31            saved_stack,
32            origin_x,
33            origin_y,
34            alpha: alpha.clamp(0.0, 1.0),
35        });
36        // Reset to local-space origin for the new layer.
37        self.state.transform = TransAffine::new();
38        self.state.clip = None;
39    }
40
41    /// SrcOver-composite the current layer into the previous render target, then
42    /// restore the graphics state that was active at the matching `push_layer`.
43    pub fn pop_layer(&mut self) {
44        let Some(layer) = self.layer_stack.pop() else {
45            return;
46        };
47        let ox = layer.origin_x as i32;
48        let oy = layer.origin_y as i32;
49        self.state = layer.saved_state;
50        self.state_stack = layer.saved_stack;
51        // Composite: src = layer.fb, dst = now-active framebuffer.
52        if let Some(top) = self.layer_stack.last_mut() {
53            composite_framebuffers(&mut top.fb, &layer.fb, ox, oy, layer.alpha);
54        } else {
55            composite_framebuffers(self.base_fb, &layer.fb, ox, oy, layer.alpha);
56        }
57    }
58}