//CC0 1.0 Universal https://creativecommons.org/publicdomain/zero/1.0/
//To the extent possible under law, Blackle Mori has waived all copyright and related or neighboring rights to this work.

vec3 erot(vec3 p, vec3 ax, float ro) {
  return mix(dot(ax,p)*ax,p,cos(ro)) + sin(ro)*cross(ax,p);
}

vec3 sq(vec2 uv) {
  return vec3(cos(uv.x), sin(uv.x)*sin(uv.y),sin(uv.x)*cos(uv.y));
}

float comp(vec3 p, vec3 off, vec3 ro) {
  float scale = 2.2;
  p+=off;
  p=erot(p,sq(ro.xy),acos(-1.)*ro.z);
  p = (fract(p/scale)-0.5)*scale;
  return length(p) - 0.1;
}

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

vec3 hash3(float a) {
  float t1 = hash(a, cos(a));
  float t2 = hash(t1, cos(a+t1));
  float t3 = hash(t2, cos(a+t2));
  return vec3(t1,t2,t3);
}

float smin(float a, float b, float k){
  float h = max(0.,k-abs(a-b))/k;
  return min(a,b)-h*h*h*k/6.;
}

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

float scene(vec3 p) {
  float dist = 100000.;
  for (int i = 0; i < 4; i++) {
    vec3 off = hash3(float(i));
    vec3 rot = hash3(cos(float(i*i)));
    dist = smin(comp(p,off,rot),dist,0.2);
  }
  float offset = sin(p.x)+cos(p.y*0.8)+sin((p.x+p.y)*0.2)*0.5+cos((p.x-p.y)*0.3)*0.5;
  return linedist(vec2(dist,p.z), vec2(0,0), vec2(0.95+cos(iTime)*0.05,2.5+offset*0.2))-0.2;
}

vec3 norm(vec3 p) {
  mat3 k = mat3(p,p,p)-mat3(0.01);
  return normalize(scene(p) - vec3(scene(k[0]),scene(k[1]),scene(k[2])));
}

vec3 shade(vec3 p, vec3 n, vec3 cam) {
  return pow(smoothstep(-0.3,1.,scene(p+reflect(cam,n))*vec3(0.9,0.9,1)),vec3(2));
}

float borders(vec2 frag, vec2 res) {
  vec2 frg = floor(frag);
  vec2 crungy = floor(abs(frag-res/2.));
  vec2 quad = floor(res/2.-abs(frag-res/2.));
  float borderpos = floor(min(res.x,res.y)/4.);
  if (quad.x == borderpos || quad.y == borderpos) return 1.;
  if (quad.y == borderpos/2.) return 1.;
  if (mod(iTime,2.)>0.5){
  if (frg.x == floor(res.x/2.) && frg.y < res.y/2.+8. && frg.y > res.y/2.-8.) return 1.;
  if (frg.y == floor(res.y/2.) && frg.x < res.x/2.+8. && frg.x > res.x/2.-8.) return 1.;
  }
  return 0.;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = vec2(fragCoord - .5* iResolution.xy ) / iResolution.y;
  

  vec3 cam = normalize(vec3(0.7, uv));
  vec3 init = vec3(0,sin(iTime/30.)*30.,4. + cos(iTime/10.)*0.5);
  cam = erot(cam, vec3(0,1,0), cos(iTime*0.3)*0.5+0.5);
  cam = erot(cam, vec3(0,0,1), sin(iTime*0.3)*0.8);
  
  vec3 p = init;
  bool hit = false;
  for (int i = 0; i < 300; i++) {
    float dist = scene(p);
    if (cam.z>0.)break;
    if (dist*dist < 0.0001) { p+=dist*cam; hit = true; break; }
    if (distance(init, p) > 100.) break;
    p+=dist*cam;
  }
  float fog = sqrt(smoothstep(0.,50.,distance(p,init)));
  vec3 n = norm(p);
  fragColor.xyz = sqrt(hit ? mix(shade(p,n,cam),vec3(0.9),fog) : vec3(0.9));
  float dx = dFdx(fragColor.z);
  float dy = dFdy(fragColor.z);
  fragColor.xyz -= dot(uv,vec2(dx,dy))*vec3(2,1,0);
  
  float b = borders(fragCoord.xy, iResolution.xy);
  fragColor.xyz = mix(fragColor.xyz*0.95 + hash(uv.x+cos(iTime),uv.y+iTime)*0.02, vec3(1), b);
}
