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}