Skip to main content

wisp/scene/
dim_outside.rs

1//! Renderer-side data for the dim-outside composition primitive
2//! (M-MASK / AUT-29). Companion to [`PrivacyBlur`](super::PrivacyBlur)
3//! and the lower-level
4//! [`Renderer::apply_spotlight`](crate::render::Renderer::apply_spotlight).
5//!
6//! [`DimOutside`] bundles a [`MaskShape`] (where the focus is) with a
7//! [`DimStrength`] (how dark the surrounding context becomes). The
8//! editor inspector will eventually persist + animate this struct;
9//! the renderer consumes one via
10//! [`Renderer::apply_dim_outside_data`](crate::render::Renderer::apply_dim_outside_data),
11//! a one-line wrapper that calls `apply_spotlight` with a black
12//! overlay at the right alpha.
13
14use crate::scene::clip::MaskShape;
15
16/// Strength of the dim applied outside the focus shape.
17///
18/// Like [`BlurStrength`](super::BlurStrength), the variants compile
19/// down to numbers — but the symbolic enum is what the editor
20/// persists, so retuning a preset later doesn't break project files.
21#[derive(Debug, Clone, Copy, PartialEq, Default)]
22#[non_exhaustive]
23pub enum DimStrength {
24    /// Light context dim — surrounding area still legible. Useful for
25    /// "this is the active panel" gentle hints.
26    Light,
27    /// Balanced dim — surrounding area visibly faded but still
28    /// recognizable. The default for "follow the walkthrough."
29    #[default]
30    Medium,
31    /// Heavy dim — surrounding area nearly black. The cinematic
32    /// "spotlight only" treatment.
33    Heavy,
34    /// Application-specified alpha. Clamped to `[0.0, 1.0]` at render
35    /// time.
36    Custom(f32),
37}
38
39impl DimStrength {
40    /// Alpha (`0..=1`) of the black overlay applied outside the
41    /// focus shape.
42    #[must_use]
43    pub fn alpha(self) -> f32 {
44        match self {
45            Self::Light => 0.4,
46            Self::Medium => 0.7,
47            Self::Heavy => 0.9,
48            Self::Custom(a) => a.clamp(0.0, 1.0),
49        }
50    }
51}
52
53/// Renderer data for a dim-outside composition.
54#[derive(Debug, Clone, Copy, PartialEq)]
55pub struct DimOutside {
56    /// The focus region — pixels inside stay clear, pixels outside
57    /// get the overlay applied.
58    pub shape: MaskShape,
59    /// How strong the surrounding dim is.
60    pub strength: DimStrength,
61}
62
63impl DimOutside {
64    /// Convenience constructor: rectangle focus region, default
65    /// (Medium) dim.
66    #[must_use]
67    pub fn rect(rect: crate::math::Rect) -> Self {
68        Self {
69            shape: MaskShape::rect(rect),
70            strength: DimStrength::default(),
71        }
72    }
73
74    /// Convenience constructor: rounded-rect focus region, default
75    /// (Medium) dim.
76    #[must_use]
77    pub fn rounded_rect(rect: crate::math::Rect, radius: f32) -> Self {
78        Self {
79            shape: MaskShape::rounded_rect(rect, radius),
80            strength: DimStrength::default(),
81        }
82    }
83
84    /// Builder-style override of the strength.
85    #[must_use]
86    pub fn with_strength(mut self, strength: DimStrength) -> Self {
87        self.strength = strength;
88        self
89    }
90}