#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 hash2(float a, float b) {
  return hash(vec2(a, b));
}

float hash3(float a, float b, float c) {
  return hash(vec2(hash(vec2(a,b)),c));
}

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

float rep(vec3 p, vec3 sc, vec3 off, float ro) {
  p = erot(p, vec3(0,1,0), ro);
  p = erot(p, vec3(0,0,1), 3.1415*hash2(ro, ro));
  p = erot(p, vec3(1,0,0), 3.1415*hash3(ro, ro, ro));
  p -= off*sc;
  p = (fract(p/sc)-0.5)*sc;
  return length(p);
}

float scene(vec3 p) {
  float dist = 0.;
  float cum = 0.;
  for (int i = 0; i < 10; i ++) {
    float ro = hash2(float(i+1), 2.3238) * 3.14159;
    vec3 off = vec3(hash2(float(i+1), 384.12), hash2(float(i+1), 6969.0), hash2(float(i+1), 420.348));
    float sc = 1./float(i+1);
    dist += rep(p, vec3(sc), off, ro);
    cum += 1.;
  }
  return (dist - 1.2)/sqrt(cum);
}

vec3 shadeDistance(float d) {
    float dist = d*200.0;
    float banding = max(sin(dist), 0.0);
    float strength = sqrt(clamp(log(abs(d)+1.0)*1.5, 0.0, 1.0));
    float pattern = mix(strength, banding, (0.6-abs(strength-0.5))*0.3);
    
    vec3 color = vec3(pattern);
    
    if (d > 0.0) {
        //red tint
        color *= vec3(1.0,0.56,0.4);
    } else {
        //blue tint
        color *= vec3(0.4,0.9,1.0);
        
    }
    return color;
}

vec3 planeinterp(vec3 a, vec3 b, vec3 c, vec3 d, vec2 k) {
  a = a*a;
  b = b*b;
  c = c*c;
  d = d*d;
  return mix(mix(a,b,k.x),mix(c,d,k.x),k.y);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{

  vec2 uv = vec2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
  uv -= 0.5;
  uv /= vec2(iResolution.y / iResolution.x, 1);
  uv *=3.;
  
  vec3 cam = normalize(vec3(1, uv));
  float ro = iTime/12.;
  float str = 2.;
  vec3 init = vec3(-4.+iTime/5., cos(ro)*str, sin(ro)*str);
  vec3 p = init;
  float k = 1.;
  float iter = 20. + cos(iTime/2.)*10.;
  for( int i = 0; i < int(iter); i++) {
    float dst = scene(p);
    if (i == 0) k = sign(dst);
    dst*=k;
    if (abs(dst) < 0.001) { break; }
    
    if (distance(p, init) > 100.) break;
    p += cam*dst;
  }
  
  float hs1 =  hash(uv*iTime)*0.05;
  float hs2 =  hash(uv*iTime*43.43)*0.05;
  float c = length(sin(p)*0.5+0.5)/sqrt(3.) + hs1;
  float d = 1.-exp(-distance(init,p))/exp(0.) + hs2;
  fragColor.xyz = sqrt(planeinterp(
    vec3(78./255., 58./255., 88./255.), vec3(54./255., 193./255., 251./255.),
    vec3(192./255., 69./255., 124./255.), vec3(241./255., 255./255., 194./255.),
    vec2(c, d)
  ));
  //fragColor.xyz = shadeDistance(scene(vec3(uv, iTime*0.1)));
}
