~raph/blurrr

ref: fa3bce5fbcf5640b1414c10ef93c57d4db41793e blurrr/src/integration.rs -rw-r--r-- 1.5 KiB
fa3bce5fRaph Levien All parameters automatically tuned 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//! Computation of blurred rounded rectangle blur through integration

use crate::math::{approx_inv_erf, compute_erf7, solve_rr};

const N_INTEGRATE: usize = 256;
const EXTENT: f64 = 3.0;

/// Generate a blurred rounded rectangle.
pub fn gen_integrate(width: usize, height: usize, w: f64, h: f64, r: f64, s: f64) -> Vec<u8> {
    let s_inv = s.max(1e-6).recip();
    let mut buf = vec![0u8; width * height];
    let mut line = vec![0.0f64; width / 2];
    for j in 0..(height / 2) {
        for i in 0..(width / 2) {
            line[i] = 0.0;
        }
        let y = (j as f64) + 0.5;
        for k in 0..N_INTEGRATE {
            let jf = (k + 1) as f64 * (2.0 / ((N_INTEGRATE + 1) as f64)) - 1.0;
            let yf = y + s * approx_inv_erf(jf);
            let xmax = solve_rr(w, h, r, yf);
            if xmax > 0.0 {
                let imax = ((xmax + EXTENT * s).ceil() as usize).min(width / 2);
                for i in 0..imax {
                    let x = (i as f64) + 0.5;
                    line[i] += compute_erf7((xmax - x) * s_inv) + compute_erf7((xmax + x) * s_inv);
                }
            }
        }
        let off0 = (j + height / 2) * width;
        let off1 = (height / 2 - j - 1) * width;
        for i in 0..(width / 2) {
            let g = (255.0 * (0.5 / N_INTEGRATE as f64) * line[i]).round() as u8;
            buf[off0 + width / 2 + i] = g;
            buf[off0 + width / 2 - i - 1] = g;
            buf[off1 + width / 2 + i] = g;
            buf[off1 + width / 2 - i - 1] = g;
        }
    }
    buf
}