// Created by Stephane Cuillerdier - Aiekick/2017 (twitter:@aiekick)
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// Tuned via XShade (http://www.funparadigm.com/xshade/)

#define path(t) vec2(cos(t * .2), sin(t * .2)) * 3.

float df(vec3 p)
{
    p.xy -= path(p.z);
	return 2. - length(p.xy) - cos(p.x) * sin(p.y) * sin(p.z);
}

vec3 nor( vec3 p, float prec )
{
    vec3 e = vec3( prec, 0, 0);
    vec3 n = vec3(
    df(p+e.xyz) - df(p-e.xyz),
    df(p+e.yxz) - df(p-e.yxz),
    df(p+e.yzx) - df(p-e.yzx) );
    return normalize(n);
}

vec3 cam(vec2 uv, vec3 ro, vec3 cu, vec3 cv)
{
	vec3 rov = normalize(cv-ro);
    vec3 u =  normalize(cross(cu, rov));
    vec3 v =  normalize(cross(rov, u));
    return normalize(rov + u*uv.x + v*uv.y);
}

// https://www.shadertoy.com/view/XlsfDf	
vec3 GetRainBow(float r)
{
    int i = int(3.*fract(r)); 
	vec4 C = vec4(.25);   
    C[(i+1)%3] += r = fract(3.*r);
    C[i]       += 1.-r;
	return C.rgb;
}

void mainImage( out vec4 f, in vec2 g )
{
    g = (g+g-iResolution.xy)/iResolution.y;
	vec3 ro = vec3(path(iTime),iTime);
    vec3 rd = cam(g, ro, vec3(0,1,0), ro + vec3(0,0,.1));

    float d = 0.;
    for(int i=0;i<60;i++)  
		d += df(ro+rd*d);

	vec3 p = ro + rd * d;
	vec3 n = nor(p, .01);
	float ayz = atan(n.y,n.z)/3.14159;
	float axy = atan(n.x,n.y)/3.14159;
	float b = dot(n,normalize(ro-p)*1.5)*.8;
	vec3 col = mix(GetRainBow(axy),GetRainBow(ayz),n.z); // 1.-n.z is cool also
    
	f = mix( 
        (b*vec4(col,1)+pow(b,0.2))*(1.0-d*.01), 
        vec4(0,0,.1,1), 
        1.0 - exp( -d*0.2) ); 
    
    /*if (g.x>0.)*/ f = sqrt(f*f*f*1.2);
}
