#version 330 core

in vec2 vUV;
out vec4 FragColor;

uniform vec3 iResolution; // x=width, y=height
uniform float iTime;
uniform float uAlpha;
uniform sampler2D iChannel0; // optional backbuffer / texture

#define TAU 6.28318530718
#define PI 3.141592
#define Octaves 8
#define OCTAVES 4

float circ(vec2 p) {
    float r = length(p);
    r = 0.2 * log(r);
    return abs(mod(r*5.0,TAU)-3.14)*2.0+2.2;
}

float random (vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}

float boxnoise(vec2 st){
    vec2 p = floor(st);
    return random(p);
}

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

    float a = random(i + vec2(0.0, 0.0));
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));

    vec2 u = f * f * (3.0 - 2.0 * f);

    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

float fbm(vec2 st){
    float v = 0.0;
    float a = 0.6;

    for (int i = 0; i < OCTAVES; i++)
    {
        v += a * noise(st);
        st = st * 2.0;
        a *= 0.5;
    }

    return v;
}

float city (vec2 uv, float offset, float height,float width)
{
    vec2 grid = vec2(width, 1.0);
    uv.x += offset;
    // id based on grid
    vec2 gid = floor(uv * grid);
    float n1 = fbm((gid) + 0.5);
    uv.x *= n1 * 6.0;
    vec2 id = gid + 0.5;
    float n = fbm(id);
    float buildingHeight = n * height;
    if (n1 > 0.3) {
        buildingHeight += fract(uv * grid).x * n1 * 0.0;
    }
    return (uv.y < buildingHeight) ? 1.0 : 0.0;
}

void mainImage(out vec4 O, in vec2 fragCoord)
{
    vec2 p = fragCoord / iResolution.xy - 0.5;
    p.x *= iResolution.x / iResolution.y;

    p *= 12.0;

    float tt = iTime * 0.25;

    vec2 pixuv = vec2((fragCoord / iResolution.xy - 0.5).x * 1.0, (fragCoord / iResolution.xy - 0.5).y * 1.0);

    vec2 p2 = mod(pixuv * TAU, TAU) - 250.0;
    vec2 s = vec2(p2);
    float c = 1.0;
    float inten = 0.005;

    for (int n = 0; n < Octaves; n++)
    {
        float t = tt * (1.0 - (3.0 / float(n+1)));
        s = p + vec2(cos(t - s.x) + sin(t + s.y), sin(t - s.y) + cos(t + s.x));
        vec2 denom = vec2(p2.x / (sin(s.x+t)/inten), p2.y / (cos(s.y+t)/inten));
        c += 1.0 / length(denom);
    }
    c /= float(Octaves);
    c = 1.17 - pow(abs(c), 1.4);

    float colr = pow(abs(c), 8.0);

    p /= exp(mod((0.5)*6.0, PI));
    colr *= pow(abs((0.3 - circ(p + vec2(0.0, -0.2)))), 3.0);

    vec3 col = vec3(1.0, 1.0, 1.5) / max(colr, 1e-6);
    col = pow(col, vec3(1.0, 0.9, 0.85));
    col -= city((fragCoord / iResolution.xy), 1.5, 0.7, 30.0) * 0.08; //City color 1
    col += city((fragCoord / iResolution.xy), 1.0, 0.65, 20.0) * 0.02; //City color 2

    O = vec4(col, 1.0); //Multiplical col por valor para ajustar brillo
}

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