// Using code from

//Morgan McGuire for the noise function
// https://www.shadertoy.com/view/4dS3Wd

#define time iTime
#define depth 70.0
#define fogSize 25.0
float fogCoef=1.0/(depth-fogSize);
float PI=acos(-1.0);

float random (in float x) {
	return fract(sin(x)*1e4);
}
float hash(float p) { p = fract(p * 0.011); p *= p + 7.5; p *= p + p; return fract(p); }
float hash(vec2 p) {vec3 p3 = fract(vec3(p.xyx) * 0.13); p3 += dot(p3, p3.yzx + 3.333); return fract((p3.x + p3.y) * p3.z); }

float noise(float x) {
    float i = floor(x);
    float f = fract(x);
    float u = f * f * (3.0 - 2.0 * f);
    return mix(hash(i), hash(i + 1.0), u);
}
float noise(vec3 x) {
    const vec3 step = vec3(110, 241, 171);

    vec3 i = floor(x);
    vec3 f = fract(x);
 
    // For performance, compute the base input to a 1D hash from the integer part of the argument and the 
    // incremental change to the 1D based on the 3D -> 1D wrapping
    float n = dot(i, step);

    vec3 u = f * f * (3.0 - 2.0 * f);
    return mix(mix(mix( hash(n + dot(step, vec3(0, 0, 0))), hash(n + dot(step, vec3(1, 0, 0))), u.x),
                   mix( hash(n + dot(step, vec3(0, 1, 0))), hash(n + dot(step, vec3(1, 1, 0))), u.x), u.y),
               mix(mix( hash(n + dot(step, vec3(0, 0, 1))), hash(n + dot(step, vec3(1, 0, 1))), u.x),
                   mix( hash(n + dot(step, vec3(0, 1, 1))), hash(n + dot(step, vec3(1, 1, 1))), u.x), u.y), u.z);
}

mat2 rot(float a) {
	float ca=cos(a);
	float sa=sin(a);
	return mat2(ca,sa,-sa,ca);
}

float cloud(in vec3 p,float distortion,float scale ) {
	float l = length(p*distortion);
	vec3 d = vec3(p.x+sin(l+time)*2.0,p.y+sin(l)*2.0,0.0);
    float coef = length(d)-4.0;
	float c=1.0;
	float n1=1.0;
	for(int i=0; i<8; ++i) {
		n1+=1.0/c*abs(noise((p*c+time*1.0)*scale));
		c*=2.0;
	}
	return n1*(coef);
}

float mapHyper(vec3 p){

	return cloud(p,0.1,0.5);
}  

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);
	vec3 s=vec3(0.5,0.5,100);
	float t2=(time*1.5);
	s.xz *= rot(sin(t2)*0.005);
	vec3 t=vec3(0,0,0);
	s.x += cos(t2*0.2)*0.10*sin(time*0.01);
	s.y += sin(t2*0.2)*0.10*sin(time*0.01+10.0);
	vec3 cz=normalize(t-s);
	vec3 cx=normalize(cross(cz,vec3(0,1,0)));
	vec3 cy=normalize(cross(cz,cx));
	vec3 r=normalize(uv.x*cx+uv.y*cy+cz*0.7);
	s.z+=time*8.0;
	
	vec3 p=s;
	float d;
	float seuil=mix(2.0,8.0,noise(time*0.5));
	float c= 0.0;
	float cl;
	for(int i=0; i<500; ++i) {
		float d=0.0;
		d = mapHyper(p);
		c+=d;  
        if(c>seuil*10.0)break;
        p+=r*(d-seuil)*0.09;
	}
    c=0.0;
    vec3 p2=p;
    for(int i=0; i<20; ++i) {
		float d2=0.0;
		d2= mapHyper(p2);
		c+=d2; 
        p2 +=normalize(vec3(0.0,0.0,-1.0))*(-d2)*0.09;
	}
    cl = 1.0-length(p-p2)/15.0;
	
	//compositing
	vec3 col=vec3(0);
	col = mix(vec3(0.0,0.0,0.2),vec3(0.88,0.88,0.9),cl);
	float fog =  clamp((length(p2-s)-fogSize)*fogCoef,0.0,1.0);
	col = mix(col,vec3(0.88,0.88,0.9),fog);
    
	fragColor = vec4(col,1.0);
}
