#define s(a, b, t) smoothstep(a, b, t)

// Shader implementation as described on the excelent Art of The Code video: https://www.youtube.com/watch?v=3CycKKJiwis

// distance of the point p to the line that starts on the point a and ends on the point b
float dist_line(vec2 p, vec2 a, vec2 b) {
    vec2 pa = p-a;
    vec2 ba = b-a;
    float t = clamp(dot(pa, ba)/dot(ba, ba), 0., 1.);
    return length(pa - ba * t);    
}

// pseudo random float
float n21(vec2 p) {
    p = fract(p * vec2(233.24, 851.73));
    p += dot(p, p + 23.45);
    return fract(p.x * p.y);
}

// pseudo random vec2
vec2 n22(vec2 p) {
    float n = n21(p);
    return vec2(n, n21(p+n));
}

vec2 get_pos(vec2 id, vec2 offs) {
    vec2 n = n22(id + offs) * iTime;
    return offs + sin(n) * .4;
}

float line(vec2 p, vec2 a, vec2 b) {
    float d = dist_line(p, a, b);
    float m = s(.03, .01, d);
    float d2 = length(a-b);
    m *= s(1.6, .5, d2)*.5 + s(.05, .03, abs(d2-.75));
    return m;
}

float layer(vec2 uv) {
    float m = 0.;
    // fract returns the fractional component of the number (ex: 0.1, 0.3, 0.43)
    vec2 gv = fract(uv) - .5;
    // floor returns the integer part of the number, we use to give a cell an identification   
    vec2 id = floor(uv);
    
    vec2 p[9];
    int i = 0;
    for (float y = -1.; y <= 1.0; y++) {
        for (float x = -1.; x <= 1.0; x++) {
            p[i++] = get_pos(id, vec2(x, y));
        }
    }
    
    float t = iTime * 10.;
    for (int i = 0; i < 9; i++) {
        m += line(gv, p[4], p[i]);
        vec2 j = (p[i] - gv) * 10.;
        float sparkle = 1./dot(j, j);
        m += sparkle * (sin(t + fract(p[i].x) * 10.) *.5 + .5);
    }
    
    m += line(gv, p[1], p[3]);
    m += line(gv, p[1], p[5]);
    m += line(gv, p[5], p[7]);
    m += line(gv, p[3], p[7]);
    
    return m;
}


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // set the coordinates system to the middle of the canvas
    vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
    
    float gradient = uv.y;
    
    vec2 mouse = (iMouse.xy/iResolution.xy)-.5;
    
    float m = 0.;
    
    float t = iTime*.1;
    
    float s = sin(t*2.);
    float c = cos(t*5.);
    mat2 rot = mat2(c, -s, s, c);
    uv *= rot * 3.;
    mouse *= rot;
    for (float i=0. ; i < 1.; i += 1./4.) {
        float z = fract(i+t);
        float size = mix(10., .5, z);
        float fade = s(0., .5, z) * s(1., .8, z);
        m += layer(uv*size+i*20.-mouse) * fade;
    }
    
    vec3 base = sin(t*20.*vec3(.345, .543, .682)) *.25 + .75;
    
    vec3 col = m * base;
    
    float fft = texelFetch(iChannel0, ivec2(.1,0), 0).x;
    
    gradient *= fft*2.;
    
    col -= gradient * base;
    
    fragColor = vec4(col,1.0);
}
