vtk-pure-rs 0.2.0

Pure Rust visualization toolkit — data structures, filters, I/O, rendering
Documentation
struct BloomUniforms {
    threshold: f32,
    intensity: f32,
    texel_size: vec2<f32>,
    horizontal: f32,
    _pad: vec3<f32>,
    weights: array<f32, 16>,
    num_weights: f32,
    _pad2: vec3<f32>,
};

@group(0) @binding(0)
var<uniform> uniforms: BloomUniforms;
@group(0) @binding(1)
var source_tex: texture_2d<f32>;
@group(0) @binding(2)
var source_sampler: sampler;

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0) uv: vec2<f32>,
};

// Full-screen triangle (3 vertices, no vertex buffer needed)
@vertex
fn vs_fullscreen(@builtin(vertex_index) idx: u32) -> VertexOutput {
    var out: VertexOutput;
    // Generate full-screen triangle covering [-1,1] x [-1,1]
    let x = f32(i32(idx & 1u)) * 4.0 - 1.0;
    let y = f32(i32(idx >> 1u)) * 4.0 - 1.0;
    out.position = vec4<f32>(x, y, 0.0, 1.0);
    out.uv = vec2<f32>((x + 1.0) * 0.5, (1.0 - y) * 0.5);
    return out;
}

// Pass 1: Extract bright pixels
@fragment
fn fs_extract(in: VertexOutput) -> @location(0) vec4<f32> {
    let color = textureSample(source_tex, source_sampler, in.uv);
    let brightness = dot(color.rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
    if brightness > uniforms.threshold {
        return vec4<f32>(color.rgb * (brightness - uniforms.threshold), 1.0);
    }
    return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}

// Pass 2/3: Gaussian blur (horizontal or vertical)
@fragment
fn fs_blur(in: VertexOutput) -> @location(0) vec4<f32> {
    let nw = i32(uniforms.num_weights);
    let center = nw / 2;
    var result = vec3<f32>(0.0);

    for (var i = 0; i < nw && i < 16; i = i + 1) {
        let offset = f32(i - center);
        var uv_offset: vec2<f32>;
        if uniforms.horizontal > 0.5 {
            uv_offset = vec2<f32>(offset * uniforms.texel_size.x, 0.0);
        } else {
            uv_offset = vec2<f32>(0.0, offset * uniforms.texel_size.y);
        }
        let sample = textureSample(source_tex, source_sampler, in.uv + uv_offset);
        result += sample.rgb * uniforms.weights[i];
    }

    return vec4<f32>(result, 1.0);
}

// Pass 4: Additive composite (pipeline has additive blend state)
@fragment
fn fs_composite(in: VertexOutput) -> @location(0) vec4<f32> {
    let bloom = textureSample(source_tex, source_sampler, in.uv);
    return vec4<f32>(bloom.rgb * uniforms.intensity, 1.0);
}