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}