#pragma header
vec2 uv = openfl_TextureCoordv.xy;
vec2 fragCoord = openfl_TextureCoordv * openfl_TextureSize;
vec2 iResolution = openfl_TextureSize;
uniform float iTime;
#define iChannel0 bitmap
#define texture flixel_texture2D
#define fragColor gl_FragColor
#define mainImage main

// Controls for customization
uniform float BEND_AMOUNT;      // How much the CRT screen bends (higher = less bend)
uniform float VIGNETTE_OFFSET;  // Offset for vignette center (0.5 = center)
uniform float RGB_SHIFT_R;      // Red channel shift
uniform float RGB_SHIFT_G;      // Green channel shift
uniform float RGB_SHIFT_B;      // Blue channel shift
uniform float SCAN_LINE_INTENSITY; // How visible the scan lines are
uniform float NOISE_SCALE;      // Scale of the noise effect
uniform float NOISE_INTENSITY;  // How visible the noise is
uniform float REFRESH_FLICKER;  // Speed of random brightness flickering
uniform float ZOOM;

vec2 crt_coords(vec2 uv, float bend) {
    uv -= 0.5;
    uv *= 2.5;
    
    float distort_x = pow(abs(uv.y) / bend, 2.0);
    float distort_y = pow(abs(uv.x) / bend, 2.0);
    
    uv.x *= 1.0 + distort_x;
    uv.y *= 1.0 + distort_y;
    
    uv /= 2.5;
    return uv + 0.5;
}

vec2 apply_zoom(vec2 uv, float zoom) {
    uv -= 0.5;
    float zoom_factor = 1.0 / (1.0 + zoom);
    uv *= zoom_factor;
    uv += 0.5;
    return uv;
}

float random(vec2 uv) {
    return fract(sin(dot(uv, vec2(15.5151, 42.2561))) * 12341.14122 * (1.0 + sin(iTime * REFRESH_FLICKER) * 0.1));
}

float noise(vec2 uv) {
    vec2 i = floor(uv);
    vec2 f = fract(uv);

    float a = random(i);
    float b = random(i + vec2(0.3, 0.0));
    float c = random(i + vec2(0.0, 0.3));
    float d = random(i + vec2(0.3));
    
    vec2 u = smoothstep(0.0, 0.5, f);
    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

void mainImage() {
    vec2 uv = fragCoord / iResolution.xy;

    uv = apply_zoom(uv, ZOOM);
    
    vec2 crt_uv = crt_coords(uv, BEND_AMOUNT);
    
    if (crt_uv.x < 0.0 || crt_uv.x > 1.0 || crt_uv.y < 0.0 || crt_uv.y > 1.0) {
        fragColor = vec4(0.0, 0.0, 0.0, 1.0);
        return;
    }
    
    vec4 col;
    col.r = texture(iChannel0, crt_uv + vec2(0.0, RGB_SHIFT_R)).r;
    col.g = texture(iChannel0, crt_uv + vec2(0.0, RGB_SHIFT_G)).g;
    col.b = texture(iChannel0, crt_uv + vec2(0.0, -RGB_SHIFT_B)).b;
    col.a = texture(iChannel0, crt_uv).a;
    
    float scanEffect = sin(uv.y * 200.0 + iTime * -10.0);
    scanEffect += 0.2 * sin(uv.y * 20.0 + iTime * -3.0 + uv.x * 5.0);
    
    // float horizontalLines = sin(uv.x * 500.0 - iTime * 2.0) * 0.02;
    float flicker = 0.97 + 0.03 * sin(iTime * 8.7);
    
    vec4 bloomColor = max(col - 0.6, 0.0) * 1.5;
    
    col = mix(col, col + vec4(scanEffect), SCAN_LINE_INTENSITY);
    // col += horizontalLines;
    col = mix(col, col + bloomColor, 0.2);
    col *= flicker;

    fragColor = mix(col, vec4(noise(uv * NOISE_SCALE)), NOISE_INTENSITY);
}
