// Shader by Frostbyte
// Licensed under CC BY-NC-SA 4.0

#version 330 core

#define t iTime

in vec2 vUV;
out vec4 FragColor;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;

// Value noise (based on IQ’s shader: https://www.shadertoy.com/view/4sfGzS)
float hash(ivec3 p) {
    int n = p.x * 3 + p.y * 113 + p.z * 311;
    n = (n << 13) ^ n;
    n = n * (n * n * 15731 + 789221) + 1376312589;
    return float(n & 0x0fffffff) / float(0x0fffffff);
}

float noise(vec3 x) {
    ivec3 i = ivec3(floor(x));
    vec3 f = fract(x);
    f = f * f * (3.0 - 2.0 * f);
    return mix(
        mix(
            mix(hash(i + ivec3(0, 0, 0)),
                hash(i + ivec3(1, 0, 0)), f.x),
            mix(hash(i + ivec3(0, 1, 0)),
                hash(i + ivec3(1, 1, 0)), f.x), f.y),
        mix(
            mix(hash(i + ivec3(0, 0, 1)),
                hash(i + ivec3(1, 0, 1)), f.x),
            mix(hash(i + ivec3(0, 1, 1)),
                hash(i + ivec3(1, 1, 1)), f.x), f.y),
        f.z
    );
}

// https://www.stevenfrady.com/tools/palette?p=[[0.49,0.83,0.22],[0.98,1,1],[0,1,1],[0.59,0,0]]
vec3 palette(float t){
  vec3 a=vec3(0.49,0.83,0.22);
  vec3 b=vec3(0.98,1,1);
  vec3 c=vec3(0,1,1);
  vec3 d=vec3(0.59,0,0);
  return a+b*cos(6.28318*(c*t+d));
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    vec4 col = vec4(0.0);
    float d = 0.0;
    float s = 0.0;
    vec3 p = vec3(0.0);

    for (int ii = 0; ii < 300; ++ii) {
        s = 0.001 + abs(s) * 0.05;
        d += s;

        col.rgb += palette(sin(s*d+p.z)*.5+.5) / s;

        p = vec3(uv*2.0 * d, d + t * 2.0);
        p.x = abs(p.x);
        float ds = sin(length(p.xy+t*0.5)-0.05+p.z)*2.0;
        float density = noise(p * 9.0 + t) - noise(p + t*2.0) * (0.1);
        vec2 twist = cos(p.z * 0.1 + vec2(0.0, 11.0));
        float clear = abs(dot(p.xy+twist, twist)*0.7);
        s = max(s, clear);
        s += abs(min(density,ds));
    }

    fragColor = 2.0*pow(tanh(col * col * col * col * col /8e21), vec4(0.4545));
}

void main()
{
    vec2 fragCoord = vUV * iResolution.xy;
    vec4 outCol;
    mainImage(outCol, fragCoord);
    outCol.a *= uAlpha;
    FragColor = outCol;
}
