#version 330 core
// Wormhole, adapted from "The Universe Within" by Martijn Steinrucken aka BigWings, 2018.
// Original license: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported.

in vec2 vUV;
out vec4 FragColor;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform float uAudioBoost;
uniform float uParallax;

#define S(a, b, t) smoothstep(a, b, t)
#define NUM_LAYERS 4.0

float N21(vec2 p)
{
    vec3 a = fract(vec3(p.xyx) * vec3(213.897, 653.453, 253.098));
    a += dot(a, a.yzx + 79.76);
    return fract((a.x + a.y) * a.z);
}

vec2 GetPos(vec2 id, vec2 offs, float t)
{
    float n = N21(id + offs);
    float n1 = fract(n * 10.0);
    float n2 = fract(n * 100.0);
    float a = t + n;
    return offs + vec2(sin(a * n1), cos(a * n2)) * 0.4;
}

float df_line(vec2 a, vec2 b, vec2 p)
{
    vec2 pa = p - a;
    vec2 ba = b - a;
    float h = clamp(dot(pa, ba) / max(dot(ba, ba), 0.0001), 0.0, 1.0);
    return length(pa - ba * h);
}

float line(vec2 a, vec2 b, vec2 uv)
{
    float d = df_line(a, b, uv);
    float d2 = length(a - b);
    float fade = S(6.0, 0.0, d2);
    fade += S(0.05, 0.02, abs(d2 - 0.75));
    return S(0.04, 0.01, d) * fade;
}

float NetLayer(vec2 st, float n, float t)
{
    vec2 id = floor(st) + n;
    st = fract(st) - 0.5;

    vec2 p[9];
    int k = 0;
    for (float y = -1.0; y <= 1.0; y++)
    {
        for (float x = -1.0; x <= 1.0; x++)
        {
            p[k++] = GetPos(id, vec2(x, y), t);
        }
    }

    float m = 0.0;
    float sparkle = 0.0;

    for (int i = 0; i < 9; i++)
    {
        m += line(p[4], p[i], st);

        float d = length(st - p[i]);
        float s = 0.005 / max(d * d, 0.0001);
        s *= S(1.0, 0.7, d);

        float pulse = sin((fract(p[i].x) + fract(p[i].y) + t) * 5.0) * 0.4 + 0.6;
        sparkle += s * pow(pulse, 20.0);
    }

    m += line(p[1], p[3], st);
    m += line(p[1], p[5], st);
    m += line(p[7], p[5], st);
    m += line(p[7], p[3], st);

    float sPhase = (sin(t + n) + sin(t * 0.1)) * 0.25 + 0.5;
    sPhase += pow(sin(t * 0.1) * 0.5 + 0.5, 50.0) * 5.0;
    return m + sparkle * sPhase;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord - iResolution.xy * 0.5) / iResolution.y;
    vec2 M = vec2(0.16, -0.10) * uParallax;

    float t = 8.0 * sin(iTime * 0.4);
    float s = sin(t);
    float c = cos(t);
    mat2 rot = mat2(c, -s, s, c);

    vec2 st = uv * rot;
    M = M * rot * 2.0;

    float m = 0.0;
    for (float i = 0.0; i < 1.0; i += 1.0 / NUM_LAYERS)
    {
        float z = fract(t + i);
        float size = mix(15.0, 1.0, z);
        float fade = S(0.0, 0.6, z) * S(1.0, 0.8, z);
        m += fade * NetLayer(st * size - M * z, i, iTime);
    }

    float fft = (0.55 + 0.45 * sin(iTime * 5.7 + uv.x * 9.0 - uv.y * 4.0)) * uAudioBoost;
    float glow = -uv.y * fft * 4.0;

    vec3 baseCol = vec3(s, cos(t * 0.2), sin(t * 0.5));
    baseCol = baseCol * 0.5 + 0.55;

    vec3 col = baseCol * m;
    col += baseCol * glow;
    col *= max(0.0, 1.0 - dot(uv, uv));

    float introTime = mod(iTime, 230.0);
    col *= S(0.0, 20.0, introTime) * S(224.0, 200.0, introTime);

    fragColor = vec4(max(col, 0.0), uAlpha);
}

void main()
{
    mainImage(FragColor, vUV * iResolution.xy);
}
