Skip to main content

wisp/scene/
privacy_blur.rs

1//! Renderer-side data for the privacy-blur composition primitive.
2//!
3//! [`PrivacyBlur`] bundles a [`MaskShape`] (where) with a
4//! [`BlurStrength`] (how strong). A `PrivacyBlur` value is what the
5//! editor inspector will eventually persist + animate; the renderer
6//! consumes one via
7//! [`Renderer::apply_privacy_blur_data`](crate::render::Renderer::apply_privacy_blur_data),
8//! a one-liner wrapper over the lower-level
9//! [`Renderer::apply_privacy_blur`](crate::render::Renderer::apply_privacy_blur).
10//!
11//! The strength enum has named presets (Soft/Medium/Strong) plus a
12//! `Custom(f32)` escape hatch. Presets exist because the editor's
13//! "blur strength" slider should snap to a small set of cinematic
14//! values rather than expose raw pixel radii to the user — but the
15//! renderer-data layer keeps both the symbolic name and the numeric
16//! radius reachable so AUT-22's "story variants demonstrate different
17//! blur strengths" stays deterministic.
18
19use crate::scene::clip::MaskShape;
20
21/// Strength of a privacy blur, in symbolic + numeric form.
22///
23/// The variants compile down to the same call into
24/// [`BlurFilter::new`](crate::filter::BlurFilter::new) — the enum exists so
25/// the *editor* can persist a stable name even when we later retune
26/// the underlying pixel radii.
27#[derive(Debug, Clone, Copy, PartialEq, Default)]
28#[non_exhaustive]
29pub enum BlurStrength {
30    /// Cinematic soft blur — readable shapes still hint through.
31    /// Useful for visual polish where strict redaction isn't needed.
32    Soft,
33    /// Balanced redaction — text becomes unreadable, broad shapes
34    /// remain visible. The default for "blur this private region."
35    #[default]
36    Medium,
37    /// Heavy redaction — a strong mosaic-feel blur that wipes nearly
38    /// all detail. Use when publishing to an audience that may zoom in.
39    Strong,
40    /// Application-specified pixel radius. Clamped to a sane upper
41    /// bound at render time to keep the offscreen RT cost finite.
42    Custom(f32),
43}
44
45impl BlurStrength {
46    /// Pixel radius this strength corresponds to.
47    ///
48    /// The Soft/Medium/Strong values are the "stable points" — if we
49    /// retune them later we keep the editor's persisted enum stable
50    /// and only the numbers move.
51    #[must_use]
52    pub fn radius_px(self) -> f32 {
53        match self {
54            Self::Soft => 6.0,
55            Self::Medium => 12.0,
56            Self::Strong => 24.0,
57            Self::Custom(r) => r.clamp(0.0, 64.0),
58        }
59    }
60}
61
62/// Renderer data for a privacy-blur composition.
63#[derive(Debug, Clone, Copy, PartialEq)]
64pub struct PrivacyBlur {
65    /// Where the blur applies. NDC `[-1, +1]²`.
66    pub shape: MaskShape,
67    /// How strong the blur is.
68    pub strength: BlurStrength,
69}
70
71impl PrivacyBlur {
72    /// Convenience constructor for the most common case (rectangle +
73    /// medium strength).
74    #[must_use]
75    pub fn rect(rect: crate::math::Rect) -> Self {
76        Self {
77            shape: MaskShape::rect(rect),
78            strength: BlurStrength::default(),
79        }
80    }
81
82    /// Convenience constructor for a rounded-rect blur with default
83    /// (Medium) strength.
84    #[must_use]
85    pub fn rounded_rect(rect: crate::math::Rect, radius: f32) -> Self {
86        Self {
87            shape: MaskShape::rounded_rect(rect, radius),
88            strength: BlurStrength::default(),
89        }
90    }
91
92    /// Builder-style override of the strength.
93    #[must_use]
94    pub fn with_strength(mut self, strength: BlurStrength) -> Self {
95        self.strength = strength;
96        self
97    }
98}