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}