Skip to main content

wisp_storybook/stories/
s_privacy_blur_rounded.rs

1//! Story: rounded-rectangle privacy blur (M-MASK.3 / AUT-21).
2//!
3//! Same pre-render-and-redact as `s_privacy_blur_rect`, but the
4//! privacy region uses `MaskShape::RoundedRect` so the redaction has
5//! cinematic rounded corners matching modern app surfaces. Builds on
6//! AUT-20's `apply_privacy_blur` — just a different shape.
7
8use glam::Vec2;
9use wisp::application::Application;
10use wisp::math::Rect;
11use wisp::render::Renderer;
12use wisp::{Color, Fill, Graphics, MaskShape, RenderTexture, Sprite, Stage, Texture};
13
14use crate::story::Story;
15
16pub fn story() -> Story {
17    Story {
18        id: "privacy-blur-rounded",
19        category: "Mask",
20        title: "Rounded privacy blur",
21        milestone: "M-MASK.3 / AUT-21",
22        writeup: include_str!("writeups/privacy_blur_rounded.md"),
23        build,
24        tick: None,
25    }
26}
27
28fn build(app: &Application, stage: &mut Stage) {
29    let format = wgpu::TextureFormat::Rgba8Unorm;
30    let renderer = Renderer::new(app, format).expect("renderer");
31
32    let mut capture_stage = Stage::new();
33
34    let mut bg = Graphics::new();
35    bg.fill(Fill::LinearGradient {
36        start: Vec2::new(-1.0, 1.0),
37        end: Vec2::new(1.0, -1.0),
38        color_a: Color::rgba_u8(80, 130, 210, 255),
39        color_b: Color::rgba_u8(220, 110, 80, 255),
40    });
41    bg.draw_rect(Rect::new(-1.0, -1.0, 2.0, 2.0));
42    let _ = capture_stage.add_child(capture_stage.root(), bg);
43
44    for i in -4i16..=4 {
45        let x = f32::from(i) * 0.2;
46        let mut line = Graphics::new();
47        line.fill(Fill::Solid(Color::rgba_u8(255, 255, 255, 200)));
48        line.draw_rect(Rect::new(x - 0.005, -1.0, 0.01, 2.0));
49        let _ = capture_stage.add_child(capture_stage.root(), line);
50    }
51    for j in -4i16..=4 {
52        let y = f32::from(j) * 0.2;
53        let mut line = Graphics::new();
54        line.fill(Fill::Solid(Color::rgba_u8(255, 255, 255, 200)));
55        line.draw_rect(Rect::new(-1.0, y - 0.005, 2.0, 0.01));
56        let _ = capture_stage.add_child(capture_stage.root(), line);
57    }
58
59    let base_rt = RenderTexture::with_format(app, 256, 256, format);
60    let _ = renderer.render_stage(app, base_rt.view(), Color::BLACK, &capture_stage);
61
62    let output_rt = RenderTexture::with_format(app, 256, 256, format);
63    let region = Rect::new(0.05, -0.45, 0.55, 0.6);
64    let radius = 0.12;
65    renderer.apply_privacy_blur(
66        app,
67        MaskShape::rounded_rect(region, radius),
68        12.0,
69        &base_rt,
70        &output_rt,
71    );
72
73    let bytes = output_rt.read_pixels(app);
74    let result_tex = Texture::from_rgba(app, 256, 256, &bytes);
75
76    let mut shown = Sprite::from_texture(result_tex).with_anchor(Vec2::splat(0.5));
77    shown.container.transform.scale = Vec2::splat(0.9);
78    let _ = stage.add_child(stage.root(), shown);
79
80    // Outline the rounded region in a contrasting color. The stroke
81    // is drawn as four tiny rects approximating the rounded corners
82    // by drawing a slightly inset rect to suggest the corner curve.
83    let mut outline = Graphics::new();
84    outline.fill(Fill::Solid(Color::rgba_u8(255, 240, 0, 200)));
85    let inner = Rect::new(0.05 * 0.9, -0.45 * 0.9, 0.55 * 0.9, 0.6 * 0.9);
86    let r_scaled = radius * 0.9;
87    let t = 0.008;
88    // Top edge (sits between the two rounded corners).
89    outline.draw_rect(Rect::new(
90        inner.min.x + r_scaled,
91        inner.min.y + inner.size.y - t,
92        inner.size.x - 2.0 * r_scaled,
93        t,
94    ));
95    // Bottom edge.
96    outline.draw_rect(Rect::new(
97        inner.min.x + r_scaled,
98        inner.min.y,
99        inner.size.x - 2.0 * r_scaled,
100        t,
101    ));
102    // Left edge.
103    outline.draw_rect(Rect::new(
104        inner.min.x,
105        inner.min.y + r_scaled,
106        t,
107        inner.size.y - 2.0 * r_scaled,
108    ));
109    // Right edge.
110    outline.draw_rect(Rect::new(
111        inner.min.x + inner.size.x - t,
112        inner.min.y + r_scaled,
113        t,
114        inner.size.y - 2.0 * r_scaled,
115    ));
116    let _ = stage.add_child(stage.root(), outline);
117}