const RADIUS_FACTOR_FLOOR: f32 = 0.25;
const TARGET_DOWNSAMPLED_SIGMA: f32 = 2.0;
#[derive(Debug, Clone, Copy)]
pub struct BlurDownsampleInputs {
pub width: u32,
pub height: u32,
pub sigma_full: f32,
pub quality_pct: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct BlurDownsample {
pub width: u32,
pub height: u32,
pub quality_factor: f32,
pub radius_factor: f32,
}
impl BlurDownsample {
pub fn combined_factor(&self) -> f32 {
self.quality_factor * self.radius_factor
}
}
#[inline]
pub fn radius_scale_factor(sigma_full: f32) -> f32 {
if sigma_full <= TARGET_DOWNSAMPLED_SIGMA {
return 1.0;
}
(TARGET_DOWNSAMPLED_SIGMA / sigma_full).clamp(RADIUS_FACTOR_FLOOR, 1.0)
}
pub fn compute_downsample(inputs: BlurDownsampleInputs) -> BlurDownsample {
let quality_factor = (inputs.quality_pct / 100.0).clamp(0.01, 1.0);
let radius_factor = radius_scale_factor(inputs.sigma_full);
let scale = quality_factor * radius_factor;
let w = ((inputs.width as f32 * scale) as u32).max(1);
let h = ((inputs.height as f32 * scale) as u32).max(1);
BlurDownsample {
width: w,
height: h,
quality_factor,
radius_factor,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn approx_eq(a: f32, b: f32) -> bool {
(a - b).abs() < 1e-5
}
#[test]
fn tiny_sigma_keeps_full_res() {
assert!(approx_eq(radius_scale_factor(0.5), 1.0));
assert!(approx_eq(radius_scale_factor(2.0), 1.0));
}
#[test]
fn medium_sigma_halves_resolution() {
assert!(approx_eq(radius_scale_factor(4.0), 0.5));
}
#[test]
fn huge_sigma_clamps_to_floor() {
assert!(approx_eq(radius_scale_factor(64.0), RADIUS_FACTOR_FLOOR));
assert!(approx_eq(radius_scale_factor(1024.0), RADIUS_FACTOR_FLOOR));
}
#[test]
fn combined_factors_multiply() {
let ds = compute_downsample(BlurDownsampleInputs {
width: 1920,
height: 1080,
sigma_full: 8.0,
quality_pct: 50.0,
});
assert!(approx_eq(ds.quality_factor, 0.5));
assert!(approx_eq(ds.radius_factor, 0.25));
assert!(approx_eq(ds.combined_factor(), 0.125));
assert_eq!(ds.width, 240);
assert_eq!(ds.height, 135);
}
#[test]
fn min_one_texel() {
let ds = compute_downsample(BlurDownsampleInputs {
width: 4,
height: 4,
sigma_full: 256.0,
quality_pct: 1.0,
});
assert!(ds.width >= 1 && ds.height >= 1);
}
}