filtrate 0.2.0

GPU texture filter library: built-in filters (blur, brightness, color matrix, ...) and runtime, built on filtrate-core.
Documentation
// Gloom, first (horizontal) pass: extracts thresholded highlight energy and
// box-accumulates it horizontally (gloom dulls highlights, so it spreads
// the same energy bloom does and subtracts it in the second pass).
//
// Each tap contributes `color * max(luma - threshold, 0)` and the pass
// normalizes by tap count, so the threshold controls the MAGNITUDE of the
// effect — a fully sub-threshold neighbourhood contributes exactly zero.
//
// Parameters: radius (param 0), threshold (param 1).

fn bright_energy(sample_color: vec4<f32>, threshold: f32) -> vec3<f32> {
    let bright = max(luminance(sample_color.rgb) - threshold, 0.0);
    return sample_color.rgb * bright;
}

@compute @workgroup_size(WORKGROUP_X, WORKGROUP_Y)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
    let dims = vec2<u32>(uniforms.output_dimensions);
    if gid.x >= dims.x || gid.y >= dims.y {
        return;
    }
    let center = map_to_input(gid.xy);
    let radius = max(i32(round(param(0u))), 1);
    let threshold = max(param(1u), 0.0);

    var sum = vec3<f32>(0.0);
    for (var x = -radius; x <= radius; x++) {
        sum += bright_energy(load_input(center + vec2<i32>(x, 0)), threshold);
    }
    let energy = sum / f32(2 * radius + 1);
    textureStore(output_texture, vec2<i32>(gid.xy), vec4<f32>(energy, 0.0));
}