#define PI 3.14159265

vec3  rot(vec3 p,vec3 a,float t)
{
	a=normalize(a);
	return mix(a*dot(p,a),p,cos(t))+sin(t)*cross(p,a);
}

float map(vec3 p)
{
	p=rot(p,vec3(cos(iTime*.3),sin(iTime*.5),.5*sin(iTime*.2)),iTime*.7);
    p.zx=vec2(atan(p.z,p.x)/PI*4., length(p.zx)-1.5);
    p.xy=vec2(atan(p.x,p.y)/PI*.7, length(p.xy)-.3);
    p.x+=p.z;
    p.x=mod(p.x,.2)-.1;
    return length(p.xy)-.07;
}

vec3 calcNormal(vec3 p)
{
    vec3 e = .001*vec3(-1,1,1);
    return normalize ( e*map(p+e) + e.yxy*map(p+e.yxy) + e.yyx*map(p+e.yyx) - e.xxx*map(p-e.xxx) );
}

/*
vec3 calcNormal(vec3 p)
{
  vec3 n=vec3(0);
  for(int i=0; i<4; i++){
    vec3 e=.001*(vec3(9>>i&1, i>>1&1, i&1)*2.-1.);
    n+=e*map(p+e);
  }
  return normalize(n);
}
*/

float march(vec3 ro, vec3 rd, float near, float far)
{
    float t=near,d;
    for(int i=0;i<70;i++)
    {
        t+=d=map(ro+rd*t);
        if (d<.001) return t;
        if (t>=far) return far;
    }
    return far;
}

vec3 doColor(vec3 p)
{
    return vec3(.7,.5,.3)+cos(p*2.)*.5+.5;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord.xy*2.-iResolution.xy)/iResolution.y;
    vec3 ro = vec3(0,0,-6);
    vec3 rd = normalize(vec3(uv,3));
    vec3 col= vec3(0);
	const float maxd=50.;
    float t=march(ro,rd,0.,maxd);
    if(t<maxd)
    {
        vec3 p=ro+rd*t;
        col=doColor(p); 
        vec3 n=calcNormal(p);      
		vec3 lightPos=ro+vec3(2,5,2);
    	vec3 li=lightPos-p;
		float len=length(li);
		li/=len;
		float dif=clamp(dot(n,li),0.1,1.);
        col*=max(dif,0.);
        float rimd=pow(clamp(1.-dot(reflect(-li,n),-rd),0.,1.),2.5);
		float frn=rimd+2.2*(1.-rimd);
    	col*=frn*.8;
        col*=max(.5+.5*n.y,.1);
        col*=exp2(-2.*pow(max(0.,1.-map(p+n*.8)/.8),2.));
        col+=vec3(.8,.6,.2)*pow(clamp(dot(reflect(rd,n),li),0.,1.),10.);
    }
    col=pow(col,vec3(1./2.2));
    fragColor.xyz=col;
}
