#version 410 core

uniform float fGlobalTime; // in seconds
uniform vec2 v2Resolution; // viewport resolution (in pixels)

uniform sampler1D texFFT; // towards 0.0 is bass / lower freq, towards 1.0 is higher / treble freq
uniform sampler1D texFFTSmoothed; // this one has longer falloff and less harsh transients
uniform sampler1D texFFTIntegrated; // this is continually increasing

layout(location = 0) out vec4 out_color; // out_color must be written in order to see anything


#define FK(k) floatBitsToInt(cos(k))^floatBitsToInt(k)
float hash(vec2 p) {
int x = FK(p.x);int y = FK(p.y);
return float((x*x-y)*(y*y+x)-x)/2.14e9;
}

float maze(vec2 p) {
vec2 id = floor(p);
float sgn = sign(hash(id));
p = fract(p)-0.5;
return abs(abs(p.x+p.y*sgn)-0.5)/sqrt(2);
}

float linedist(vec2 p, vec2 a, vec2 b) {
return distance(p, mix(a, b, clamp(dot(p-a,b-a)/dot(b-a,b-a),0,1)));
}

float scene(vec3 p) {
vec2 crds = vec2(maze(p.xy), p.z);
float walls = linedist(crds, vec2(0,0),vec2(0,1));
return min(walls-0.05, p.z);
}

float light(vec3 p, vec3 l) {
return pow(max(0, scene(p)-scene(p+l*0.01))/0.01,2);
}

void pac(vec2 uv, inout vec3 col) {
uv.y = abs(uv.y);
if (length(uv) > 1) return;
if (atan(uv.x/uv.y) < -1 - sin(fGlobalTime*12)*0.35-0.2) return;
col = vec3(1,1,0);
}

void goast(vec2 uv, inout vec3 col, vec3 colgo) {
vec2 head = vec2(0,0.2);
if (length(uv-head+vec2(0.5,0)) < 0.1) {col = vec3(0); return;}
if (length(uv-head-vec2(0.3,0)) < 0.1) {col = vec3(0); return;}
if (length(uv-head+vec2(0.4,0)) < 0.2) {col = vec3(1); return;}
if (length(uv-head-vec2(0.4,0)) < 0.2) {col = vec3(1); return;}
if (abs(uv.x) > 0.8) return;
if (uv.y < -1) return;
if (uv.y > .2 && length(uv - head) > 0.8) return;
float tail = asin(sin((uv.x + floor(fGlobalTime)*3)*20))*0.05;
if (uv.y+tail < -0.9) return;
col = colgo;
}

vec3 colgo4t(float t) {
t = mod(t ,4);
if (t < 1) return vec3(1,0,0);
if (t < 2) return vec3(0,1,1);
if (t < 3) return vec3(1,0.5,0);
if (t < 4) return vec3(0.7,0,1);
return vec3(0);
}

float bpm = 23*6;

void dots(vec2 uv, float bt, inout vec3 col) {
float old = uv.x;
uv.x = fract(uv.x)-0.5;
if (length(uv) > smoothstep(0,1, bt+12)*0.1) return;
if (old+bt > 0) return;
col = vec3(1,1,0);
}

void main(void)
{
 vec2 uv = vec2(gl_FragCoord.x / v2Resolution.x, gl_FragCoord.y / v2Resolution.y);
 uv -= 0.5;
 uv /= vec2(v2Resolution.y / v2Resolution.x, 1);
vec2 olduv = uv*10;

float beat =  fract(fGlobalTime/60*bpm);

uv = vec2(uv.x*sign(uv.y), -abs(uv.y));
vec3 cam =normalize(vec3(0.5 + beat*0.03,uv));
vec3 init = vec3(-4+fGlobalTime,fGlobalTime/10,2);
vec3 p = init;
bool hit = false;
for (int i = 0; i< 100; i++) {
float dist = scene(p);
if (abs(dist) < 0.001) { hit = true; break; }

p += cam*dist;
}
float l = light(p, cam);
vec3 col = hit ? vec3(0.2,0.4,1)*l: vec3(0);
out_color = vec4(col ,0);

float bt = (fract(fGlobalTime/5)-0.5)*30;
float bk = floor(fGlobalTime/5);
vec2 anim = olduv + vec2(bt,0);
pac(anim, out_color.xyz);
dots(olduv, bt, out_color.xyz);
goast(anim - vec2(3,0), out_color.xyz, colgo4t(bk));
}