~raph/blurrr

d2260c37b42087c19b775d07fa0ef8313414c53d — Raph Levien 4 years ago cde0387
Iterating towards auto distance field params
3 files changed, 31 insertions(+), 10 deletions(-)

M src/distfield.rs
M src/image.rs
M src/main.rs
M src/distfield.rs => src/distfield.rs +13 -6
@@ 2,14 2,21 @@

use crate::math::compute_erf7;

const EXPONENT: f64 = 2.0;
const RECIP_EXPONENT: f64 = 1.0 / EXPONENT;

/// Generate a blurred rounded rectangle using distance field approximation.
pub fn gen_distfield(width: usize, height: usize, w: f64, h: f64, r: f64, s: f64) -> Vec<u8> {
pub fn gen_distfield(width: usize, height: usize, w: f64, h: f64, r: f64, s: f64, r_mul: f64, exponent: f64) -> Vec<u8> {
    // Try to calculate parameters
    let r_orig = r;
    let r = r.hypot(s * 1.25);

    let r = r * r_mul;

    let r = r.min(0.5 * w.min(h));

    let s_inv = s.max(1e-6).recip();
    let recip_exponent = exponent.recip();
    let mut buf = vec![0u8; width * height];
    let min_edge = w.min(h);
    let scale = 0.5 * compute_erf7(s_inv * 0.5 * (w.max(h) - 0.5 * r_orig));
    for j in 0..height {
        let y = (j as f64) + 0.5 - 0.5 * (height as f64);
        let y0 = y.abs() - (h * 0.5 - r);


@@ 18,10 25,10 @@ pub fn gen_distfield(width: usize, height: usize, w: f64, h: f64, r: f64, s: f64
            let x = (i as f64) + 0.5 - 0.5 * (width as f64);
            let x0 = x.abs() - (w * 0.5 - r);
            let x1 = x0.max(0.0);
            let d_pos = (x1.powf(EXPONENT) + y1.powf(EXPONENT)).powf(RECIP_EXPONENT);
            let d_pos = (x1.powf(exponent) + y1.powf(exponent)).powf(recip_exponent);
            let d_neg = x0.max(y0).min(0.0);
            let d = d_pos + d_neg - r;
            let z = 0.5 * (compute_erf7(s_inv * (min_edge + d)) - compute_erf7(s_inv * d));
            let z = scale * (compute_erf7(s_inv * (min_edge + d)) - compute_erf7(s_inv * d));
            buf[j * width + i] = (z * 255.0).round() as u8;
        }
    }

M src/image.rs => src/image.rs +2 -2
@@ 17,8 17,8 @@ pub fn make_image_one(ctx: &mut PaintCtx, w: usize, h: usize, data: &[u8]) -> Im
pub fn make_image_two(ctx: &mut PaintCtx, w: usize, h: usize, d0: &[u8], d1: &[u8]) -> Image {
    let mut buf = vec![255u8; w * h * 4];
    for i in 0..(w * h) {
        let r = d0[i];
        let g = d1[i];
        let r = d0[i] ^ 0;
        let g = d1[i] ^ 0;
        buf[i * 4] = r;
        buf[i * 4 + 1] = g;
        buf[i * 4 + 2] = g;

M src/main.rs => src/main.rs +16 -2
@@ 14,6 14,10 @@ struct AppState {
    height: f64,
    radius: f64,
    std_dev: f64,

    // extra parameters for distance field renderer
    r_mul: f64,
    exponent: f64,
}

struct BlurWidget;


@@ 55,6 59,8 @@ impl Widget<AppState> for BlurWidget {
            data.height,
            radius,
            data.std_dev,
            data.r_mul,
            data.exponent,
        );
        let d1 = integration::gen_integrate(
            IM_WIDTH,


@@ 65,8 71,9 @@ impl Widget<AppState> for BlurWidget {
            data.std_dev,
        );
        let image = image::make_image_two(ctx, IM_WIDTH, IM_HEIGHT, &d0, &d1);
        let rect = Size::new(IM_WIDTH as f64, IM_HEIGHT as f64).to_rect();
        ctx.draw_image(&image, rect, InterpolationMode::Bilinear);
        let scale = (ctx.size().width / IM_WIDTH as f64).min(ctx.size().height / IM_HEIGHT as f64);
        let rect = (Size::new(IM_WIDTH as f64, IM_HEIGHT as f64) * scale).to_rect();
        ctx.draw_image(&image, rect, InterpolationMode::NearestNeighbor);
    }
}



@@ 81,6 88,10 @@ fn ui_builder() -> impl Widget<AppState> {
        .with_spacer(5.0)
        .with_child(Slider::new().with_range(0.0, 50.0).lens(AppState::std_dev))
        .with_spacer(5.0)
        .with_child(Slider::new().with_range(1.0, 5.0).lens(AppState::r_mul))
        .with_spacer(5.0)
        .with_child(Slider::new().with_range(2.0, 10.0).lens(AppState::exponent))
        .with_spacer(5.0)
        .with_flex_child(BlurWidget, 1.0)
}



@@ 90,6 101,9 @@ fn main() {
        height: 80.0,
        radius: 5.0,
        std_dev: 5.0,

        r_mul: 1.0,
        exponent: 2.0,
    };
    let main_window = WindowDesc::new(ui_builder).title(LocalizedString::new("blur toy"));
    AppLauncher::with_window(main_window).launch(data).unwrap();