#define nsteps 128

float sdBox( vec3 p, vec3 b )
{
  vec3 d = abs(p) - b;
  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}

float fplane (vec3 p){
 	return p.y+10.0;   
}

float map(vec3 p){
    vec3 c = vec3(10.0);
    vec3 q = mod(p, c) - 0.5*c;
    q.y = p.y;
    
    float circle = length(q- vec3(0.0, 3.0, 0.0)) - 2.5;
    float circle2 = length(q- vec3(0.0, -1.0, 0.0)) - 2.3;
    float box = sdBox(q, vec3(2.0, 5.0, 2.0));
    float plane = fplane(p);
    float scene0 = min( max(-(min(circle, circle2)), box), plane);
    return min(scene0, length(p - vec3(0.0, 10.0, 20.0)) - 6.0);
}

float march (vec3 o, vec3 r){
 	float t = 0.0;
    for(int i = 0; i < nsteps; i++){
		vec3 p = o + r * t;
        float d = map (p);
        t += d * 0.5;
    }
   return t;
}

vec3 gradient (vec3 p){
 const float df = 0.1;
 const vec3 dx = vec3(df, 0.0, 0.0);
 const vec3 dy = vec3(0.0, df, 0.0);
 const vec3 dz = vec3(0.0, 0.0, df);
    
    return normalize(
        
        vec3(map( p + dx ) - map ( p - dx),
             map( p + dy ) - map ( p - dy),
             map( p + dz ) - map ( p - dz)
            )
        
        );
    
}

//Very dirty and expensive shadows -n-
//Will fix I promise
float shadow (vec3 ro, vec3 rd){
    float k = 8.0;
    float res = 1.0;
    
    for(float t = 1.0; t<16.0; t += 0.2){
     	float h = map(ro + rd*t);
        if (h < 0.001)
            return 0.0;
        res = min (res, k*h/t);
    }
    
    return res;
}

vec3 shade (vec3 p, vec3 n){
    vec3 lFinal = vec3(0.0);
    
    //Light 0
    {
        vec3 col = vec3(0.0);
        vec3 lipos = vec3(cos(iTime)*50.0, 30.0, sin(iTime)*50.0+10.0);
        vec3 licol = vec3(abs(sin(iTime)), abs(cos(iTime)), abs(sin(iTime*0.2)));
        float reflectance = 1.5;

        vec3 lidir = normalize(lipos - p);
        vec3 libir = licol * dot(n, lidir);
        
        float sh = clamp(shadow(p, normalize(lipos - p)), 0.0, 1.0);
        
        col += reflectance * libir;
        col *= 1.0 - (length(p - lipos)*0.01);
        col -= 1.0-sh;
        col = clamp (col, 0.0, 1.0);
        lFinal += col;
    }
    
    //Light 1
        {
        vec3 col = vec3(0.0);
        vec3 lipos = vec3(-cos(iTime)*20.0, 30.0, -sin(iTime)*20.0+10.0);
        vec3 licol = vec3(1.0);
        float reflectance = clamp(sin(iTime/3.0), 0.0, 1.0)*1.5;

        vec3 lidir = normalize(lipos - p);
        vec3 libir = licol * dot(n, lidir);
            
        float sh = clamp(shadow(p, normalize(lipos - p)), 0.0, 1.0);
            
        col += reflectance * libir;
        col *= 1.0 - (length(p - lipos)*0.01);
        col -= 1.0-sh;
        col = clamp (col, 0.0, 1.0);
        lFinal += col;
    }
        //Light 2
        {
        vec3 col = vec3(0.0);
        vec3 lipos = vec3(0.0, 60.0, 0.0);
        vec3 licol = vec3(1.0);
        float reflectance = clamp(1.0, 0.0, 1.0)*1.5;

        vec3 lidir = normalize(lipos - p);
        vec3 libir = licol * dot(n, lidir);
            
        float sh = clamp(shadow(p, normalize(lipos - p)), 0.0, 1.0);
            
        col += reflectance * libir;
        col *= 1.0 - (length(p - lipos)*0.01);
        col -= 1.0-sh;
        col = clamp (col, 0.0, 1.0);
        lFinal += col;
    }

    return clamp(lFinal, vec3(0.0), vec3(1.0));
    
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 uv = fragCoord.xy / iResolution.xy;
    uv = uv * 2. - 1.;
    uv.x *= iResolution.x / iResolution.y;
	vec3 col = vec3(0.0);
    
    vec3 o = vec3(0.0, 10.0, 0.0);
    vec3 ray = vec3(uv, 0.8);
    vec3 r = normalize(ray);

    float tt = sin(iTime/7.0);
    ray.xz *= mat2(cos(tt), -sin(tt), sin(tt), cos(tt));
    
    
    float t = march(o, ray);
    
    vec3 pos = (o + ray * t);
   	vec3 n = gradient(pos);
    
    col = shade (pos, n);
    col -= vec3(t * 0.01);
    
    fragColor = vec4(col, 1.0);
}
