/*
    Retro CRT Shader
    Inspired by various effects from shadertoy.
*/

struct VertexInput {
    @location(0) pos: vec2<f32>,
    @location(1) tex_coord: vec2<f32>,
    @location(2) color: vec4<f32>,
};

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

struct Uniforms {
    resolution: vec2<f32>,
    time: f32,
    barrel_dist_amount: f32,
    color_bleed_amount: f32,
    scanline_size: f32,
    scanline_speed: f32,
    scanline_brightness: f32,
    vignette_brightness: f32,
    vignette_amount: f32,
};

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

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

@group(0) @binding(2)
var<uniform> uniforms: Uniforms;

@vertex
fn vs_main(in: VertexInput) -> VertexOutput {
    var output: VertexOutput;
    output.pos = vec4<f32>(in.pos, 0.0, 1.0);
    output.tex_coord = in.tex_coord;
    return output;
}

// Applies barrel distortion to the UV coordinates.
fn barrel_dist(uv: vec2<f32>) -> vec2<f32> {
    let r = length(uv);
    let r_distorted = pow(r, 1.0 + uniforms.barrel_dist_amount);
    return uv * (r_distorted / r);
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    let PI = 3.141592;

    // Center and normalize UVs
    var uv = (in.tex_coord - 0.5) * 2.0;

    // Apply barrel distortion
    uv = barrel_dist(uv);

    // Denormalize UVs
    uv = uv * 0.5 + 0.5;

    let inside = uv.x > 0.0 && uv.x < 1.0 && uv.y > 0.0 && uv.y < 1.0;

    // Base sample
    var col = textureSample(screen_texture, texture_sampler, uv);

    // Color Bleed
    let bleed_offset = uniforms.color_bleed_amount / uniforms.resolution.x;
    let bleed_r = textureSample(screen_texture, texture_sampler, uv + vec2<f32>(bleed_offset, 0.0)).r;
    let bleed_b = textureSample(screen_texture, texture_sampler, uv - vec2<f32>(bleed_offset, 0.0)).b;
    col = vec4<f32>(bleed_r, col.g, bleed_b, col.a);

    // Scanlines
    let scanline = sin((uv.y * uniforms.resolution.y + uniforms.time * uniforms.scanline_speed) * PI / uniforms.scanline_size) * 0.5 + 0.5;
    let scanline_bright = scanline * (1.0 - uniforms.scanline_brightness) + uniforms.scanline_brightness;
    col *= vec4<f32>(vec3<f32>(scanline_bright), 1.0);

    // Vignette
    let dist_from_center = length((in.tex_coord - 0.5) * 2.0);
    let vignette = pow(dist_from_center, uniforms.vignette_amount) + uniforms.vignette_brightness;
    col *= vec4<f32>(vec3<f32>(vignette), 1.0);

    return select(vec4<f32>(0.0, 0.0, 0.0, 1.0), col, inside);
}
