phosphor-crt 0.1.0

A real-time plotter of waveforms, imitating oscillscope CRTs
Documentation
struct VertexOutput {
    @builtin(position) position: vec4f,
    @location(1) uv: vec2f
};

@group(0) @binding(0)
var screen_linear: texture_2d<f32>;

@group(0) @binding(1)
var sampler_screen_linear: sampler;

@group(1) @binding(0)
var color_lut: texture_1d<f32>;

@group(1) @binding(1)
var sampler_color_lut: sampler;

@if(auto_intensity_enabled)
@group(2) @binding(0)
var<storage, read> max_value: u32;
@endif

@group(3) @binding(0)
var<uniform> viewport: ViewportUniform;

struct ViewportUniform {
    transform: mat3x3<f32>,  // the transform from scene coordinates to pixel coordinates
    resolution: vec2<u32>,  // the size of the viewport
    beam_radius: f32,  // the size of the beam (in pixels)
    intensity: f32,
    gamma: f32,
    decay_per_sample: f32
};

@vertex
fn postfx_vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
    // Generate full-screen triangle:
    // -> uv (0,0), (2,0), (0,2)
    // -> positions (-1,1), (3,1), (-1,-3)
    var out: VertexOutput;
    out.uv = vec2f(f32(vertex_index & 1), f32(vertex_index >> 1)) * 2.0;
    var pos: vec2f = (out.uv * 2.0 - vec2f(1., 1.));
    pos.y = - pos.y;
    out.position = vec4f(pos, 0.0, 1.0);
    return out;
}

@fragment
fn postfx_fs_main(in: VertexOutput) -> @location(0) vec4f {
    var sampled_intensity = textureSample(screen_linear, sampler_screen_linear, in.uv).x;

    sampled_intensity *= viewport.intensity;

    @if(auto_intensity_enabled)
        // Rescale using the computed maximum value
        let max_value_f32 = f32(max_value) / f32(1 << 16);
        if (max_value_f32 > 0.0) {
            sampled_intensity /= max_value_f32;
        }
    @endif

    sampled_intensity = pow(sampled_intensity, viewport.gamma); // gamma correction
    var sampled_color = textureSample(color_lut, sampler_color_lut, sampled_intensity).xyz;
    return vec4(sampled_color, 1.0);
}