2026-07-09 02:59:53 +03:00
|
|
|
use crate::helpers::box_blur_f32;
|
|
|
|
|
|
|
|
|
|
pub fn generate_glow(
|
|
|
|
|
alpha: &[u8],
|
|
|
|
|
w: u32,
|
|
|
|
|
h: u32,
|
|
|
|
|
spread: f32,
|
|
|
|
|
size: f32,
|
|
|
|
|
color: [u8; 4],
|
|
|
|
|
inner: bool,
|
|
|
|
|
) -> Vec<u8> {
|
|
|
|
|
let px = (w * h) as usize;
|
|
|
|
|
let mut buf = vec![0u8; px * 4];
|
|
|
|
|
|
|
|
|
|
let radius = size.max(0.0).round() as i32;
|
|
|
|
|
|
|
|
|
|
let glow_alpha = if inner {
|
|
|
|
|
// MAE-optimized against Krita ground truth (48 samples, 3000 combos, 800x800)
|
|
|
|
|
// Best: blur_factor=4.0, passes=4, alpha_scale=0.00, glow_boost=2.00, spread_before_blur=false
|
|
|
|
|
let mut ga = alpha.iter().map(|&a| a as f32).collect::<Vec<f32>>();
|
|
|
|
|
if radius > 0 {
|
|
|
|
|
let gaussian_r = (radius as f32 / 4.0).round().max(1.0) as i32;
|
|
|
|
|
for _ in 0..4 {
|
|
|
|
|
ga = box_blur_f32(&ga, w, h, gaussian_r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i in 0..px {
|
|
|
|
|
ga[i] = 255.0 - ga[i];
|
|
|
|
|
}
|
|
|
|
|
if spread > 0.0 {
|
|
|
|
|
let factor = 1.0 / (1.0 - spread / 100.0);
|
|
|
|
|
for a in ga.iter_mut() {
|
|
|
|
|
*a = (*a * factor).round().min(255.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i in 0..px {
|
|
|
|
|
ga[i] = (ga[i] - alpha[i] as f32 * 0.00).max(0.0) * 2.00 * alpha[i] as f32 / 255.0;
|
|
|
|
|
}
|
|
|
|
|
ga.iter().map(|&a| a as u8).collect::<Vec<u8>>()
|
|
|
|
|
} else {
|
|
|
|
|
let mut ga = alpha.iter().map(|&a| a as f32).collect::<Vec<f32>>();
|
|
|
|
|
// BEGIN_GLOW_TUNING_ZONE
|
|
|
|
|
|
|
|
|
|
// MAE-optimized against Krita ground truth (48 samples, 3000 combos, 800x800)
|
|
|
|
|
// Best: blur_factor=4.0, passes=4, alpha_scale=0.00, glow_boost=2.00, spread_before_blur=false
|
|
|
|
|
if radius > 0 {
|
|
|
|
|
let gaussian_r = (radius as f32 / 4.0).round().max(1.0) as i32;
|
|
|
|
|
for _ in 0..4 {
|
|
|
|
|
ga = box_blur_f32(&ga, w, h, gaussian_r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if spread > 0.0 {
|
|
|
|
|
let factor = 1.0 / (1.0 - spread / 100.0);
|
|
|
|
|
for a in ga.iter_mut() {
|
|
|
|
|
*a = (*a * factor).round().min(255.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for i in 0..px {
|
|
|
|
|
let mask = 255.0 - alpha[i] as f32;
|
|
|
|
|
ga[i] = (ga[i] - alpha[i] as f32 * 0.00).max(0.0) * 2.00 * mask / 255.0;
|
|
|
|
|
}
|
|
|
|
|
// END_GLOW_TUNING_ZONE
|
|
|
|
|
ga.iter().map(|&a| a as u8).collect::<Vec<u8>>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for i in 0..px {
|
|
|
|
|
let a = glow_alpha[i];
|
|
|
|
|
if a > 0 {
|
|
|
|
|
buf[i * 4] = color[0];
|
|
|
|
|
buf[i * 4 + 1] = color[1];
|
|
|
|
|
buf[i * 4 + 2] = color[2];
|
|
|
|
|
buf[i * 4 + 3] = a;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
buf
|
2026-07-16 22:10:22 +03:00
|
|
|
}
|