// using lighting techniques from: https://www.shadertoy.com/view/4tGGRV by zackpudil
// philip.bertani@gmail.com

int max_iter = 5;  //play with this
float ifs_scale, myTime;
vec3 ro;


//hard coding the vertices for a dodecahedron
const float gmh=(sqrt(5.)+1.)/2.;
const float gmi=1./gmh;

vec3[] d12 = vec3[]  (
vec3(1.,1.,1.),
vec3(1.,1.,-1.),
vec3(1.,-1,1.),
vec3(1.,-1,-1.),
vec3(-1,1.,1.),
vec3(-1.,1.,-1),
vec3(-1.,-1.,1.),
vec3(-1.,-1.,-1.),
vec3(0.,gmh,gmi),
vec3(0.,gmh,-gmi),
vec3(0.,-gmh,gmi),
vec3(0.,-gmh,-gmi),
vec3(gmi,0.,gmh),
vec3(gmi,0.,-gmh),
vec3(-gmi,0.,gmh),
vec3(-gmi,0.,-gmh),
vec3(gmh,gmi,0.),
vec3(gmh,-gmi,0.),
vec3(-gmh,gmi,0.),
vec3(-gmh,-gmi,0.)
);


float hash(float n) {
    return fract(sin(n)*50000.);
}


mat3 rotx(float an) {
    float cc = cos(an), ss=sin(an);
    return mat3(1,0.,0.,0.,cc,-ss,0.,ss,cc);

}

mat3 rot(float an) {
    float cc = cos(an), ss=sin(an);
    return mat3(cc,0.,-ss,0.,1.,0.,ss,0.,cc);

}


//dodecahedral ifs here
float de(vec3 z) {
    
    vec3 min_vtx;
    vec3 orig_z = z;
    float n=0.;
    float min_dist,dist_to_vtx;


    for (int i=0; i<100; i++) {
       
        if ( i > max_iter ) break;

        float sc = 4.;
        float w = myTime/2.;
        vec3 dd_0 = rot(w)*d12[0]*sc;
        min_vtx = dd_0;
        min_dist=length(z-dd_0);
        for (int j=1; j<20; j++) {
            vec3 ddj = rot(w)*d12[j]*sc;
            dist_to_vtx=length(z-ddj); 
            if (dist_to_vtx<min_dist) {min_vtx=ddj; min_dist=dist_to_vtx;}
            
        }
        
        z = min_vtx + ifs_scale*(z-min_vtx);
                
        n++;
        
    }

    
    float dz = pow(ifs_scale, float(n) );
    
    float f = (length(z)-(.07+myTime/20.))/dz;
    
    f = max( f, -(length(orig_z-ro)-4.1) );
    
    return f;
}

float trace(vec3 ro, vec3 rd, float mx) {
    float t = 0.0;
    for(int i = 0; i < 80; i++) {
        float d = de(ro + rd*t);
        if(d < 0.001 || t >= mx) break;
        t += d;
    }
    
    if(t < mx) return t;
    return -1.0;
}


vec3 normal(vec3 p) {
    vec2 h = vec2(0.001, 0.0);
    
    vec3 n1 = vec3(
        de(p + h.xyy),
        de(p + h.yxy),
        de(p + h.yyx)
	);
    
    vec3 n2 = vec3(
        de(p - h.xyy),
        de(p - h.yxy),
        de(p - h.yyx)
	);
    
    return normalize(n1 - n2);
}


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 uv = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;
    
    myTime = mod(iTime,20.);
    ifs_scale = 1.1 + myTime/60. ;
    
    ro = vec3(0.,0.,7.5);
    vec3 rd = normalize( vec3(uv, -2.));
    
    vec3 col = vec3(.1,.2,.4);
    
    float t = trace(ro, rd, 30.0);
    if(t > 0.0) {
        float edg;
        vec3 pos = ro + rd*t;
        vec3 nor = normal(pos);
               
     
        vec3 lig = normalize(-pos);
        float dis = length(pos);
        
        // direct lighting with hard shadows.
        col += .7*clamp(dot(lig, nor), 0.0, 1.0)
            *step(0.0, -trace(pos + nor*0.001, lig, dis));
        
        // indirect lighting
        col += .5*clamp(dot(-lig, nor), 0.0, 1.0);
        
        // decay with distance
        col *= exp(-t/10.);
  

    }
    

	fragColor = vec4(col, 1);
}
