#define PI 3.1415326


#define HIGH_QUALITY_NOISE

// 3D noise
float noise(in vec3 x)
{
    vec3 p = floor(x);
    vec3 f = fract(x);
	f = f*f*(3.0-2.0*f);
#ifndef HIGH_QUALITY_NOISE
	vec2 uv = (p.xy+vec2(37.0, 17.0)*p.z) + f.xy;
	vec2 rg = textureLod(iChannel0, (uv+ 0.5)/256.0, 0.0).yx;
#else
	vec2 uv  = (p.xy+vec2(37.0,17.0)*p.z);
	vec2 rg1 = textureLod(iChannel0, (uv+ vec2(0.5,0.5))/256.0, 0.0).yx;
	vec2 rg2 = textureLod(iChannel0, (uv+ vec2(1.5,0.5))/256.0, 0.0).yx;
	vec2 rg3 = textureLod(iChannel0, (uv+ vec2(0.5,1.5))/256.0, 0.0).yx;
	vec2 rg4 = textureLod(iChannel0, (uv+ vec2(1.5,1.5))/256.0, 0.0).yx;
	vec2 rg  = mix(mix(rg1, rg2, f.x), mix(rg3,rg4,f.x), f.y );
#endif
	return mix(rg.x, rg.y, f.z);
}

mat2 rotate2D(float r) {
    return mat2(cos(r), sin(r), -sin(r), cos(r));
}

vec3 hsv(float h, float s, float v){
    vec4 t = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(vec3(h) + t.xyz) * 6.0 - vec3(t.w));
    return v * mix(vec3(t.x), clamp(p - vec3(t.x), 0.0, 1.0), s);
}

// Distance of point p to spherical noise surface
float distanceTo(vec3 p) {
    p = mod(p+.5+round(p.z),2.)-1.; // Repeat the noise spheres
    return (length(p)-abs(noise(normalize(p)*vec3(12.)))); // Use 12 unit cube for noise
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    float eyeDist = iTime; // Clipping plane keeps moving
    float i;

    vec3 eyePos = vec3(0, 0, -1);
    vec3 ray = vec3((fragCoord.xy-.5*iResolution.xy)/iResolution.x, 1.);
    ray = normalize(ray);

    for(float minDist=1.; i<100. && minDist>0.1; i++) {
        // Point to check
        vec3 p = eyePos+eyeDist*ray;

        // Camera motion
        //p.xy += iTime/10.;
        p.xy *= rotate2D(sin(iTime+eyeDist*.4)); // Depth affects motion

        minDist = distanceTo(p);
        eyeDist += minDist*0.1;
    }
    // Hue is based on distance, brightness based on distance
    fragColor.rgb = hsv(.4-.1*eyeDist, 1., 1.-i/100.);
//    fragColor.rgb += 1000./(i*i);
}
