#version 330 core
out vec4 fragColor;
in vec2 fragCoord;
uniform float t;

mat4 rotationMatrix(vec3 axis, float angle)
{
    axis = normalize(axis);
    float s = sin(angle);
    float c = cos(angle);
    float oc = 1.0 - c;
    
    return mat4(oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,  0.0,
                oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,  0.0,
                oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c,           0.0,
                0.0,                                0.0,                                0.0,                                1.0);
}

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 sdSphere( vec3 p, float s )
{
  return length(p)-s;
}

float sdTorus( vec3 p, vec2 t )
{
  vec2 q = vec2(length(p.xz)-t.x,p.y);
  return length(q)-t.y;
}

float opTx( vec3 p, mat4 m )
{
    vec3 q = (inverse(m)*vec4(p,1)).xyz;
    return sdBox(q,vec3(1,2,1));
}


float sdf(vec3 p){
	//return sqrt(p.z*p.z + p.y*p.y) - 1.0;   
    //return sdBox(p,vec3(1,2,1));
    //return opTx(p, rotationMatrix(vec3(1,1,1), t));
    mat4 m = rotationMatrix(vec3(1,1,1), t);
    vec3 rep = vec3(0.5,0.5,0.5) * 40.0 * ((sin(t * 0.3) + 1.0) / 2.0 + 0.15);
    vec3 p2 = (inverse(m)*vec4(p,1)).xyz; // Rotate
    vec3 p3 = mod(p2,rep)-0.9*rep; // Repeat
    return sdBox(p3,vec3(1,2,1));
}

vec3 get_normal(vec3 pos)
{
	vec3 eps = vec3(0.01,0,0);
	return normalize(vec3(
		sdf(pos + eps.xyy) - sdf(pos - eps.xyy),
		sdf(pos + eps.yxy) - sdf(pos - eps.yxy),
		sdf(pos + eps.yyx) - sdf(pos - eps.yyx)
	));
}

// Clamped dot
float cdot(vec3 a, vec3 b){
    return max(0.0,dot(a,b));
}

void main()
{
    
    // Fix coordinate system
    float aspect_ratio = 16.0/9.0;
	//vec2 pixel_pos = fragCoord.xy / iResolution.xy; // [0,1]
	vec2 pixel_pos = fragCoord.xy; // [0,1]?
    pixel_pos -= vec2(0.5,0.5); // [-1/2, 1/2]
    pixel_pos *= vec2(2,2); // [-1,1]
    pixel_pos.x *= aspect_ratio;
    
    // Raymarch
    vec3 ray = vec3(pixel_pos.x, pixel_pos.y,-1);
    vec3 v_0 = vec3(0,0,5); // Camera position
    vec3 pos = v_0 + vec3(0,1,0);
    for(int step = 0; step < 30; step++){
  		pos += ray * sdf(pos)*0.98;
    }
    
    // Phong: k_s * cos(alpha)^q * intensity / r^2
    float sun_intensity = 140.0;
    //vec3 sun = vec3(30.0 * sin(t),20,30.0*cos(t));
    vec3 sun = vec3(0,0,50);
    float k_s = 20.0;
    float q = 2.0;    
    
    if(sdf(pos) > 0.1 || length(pos - v_0) < 1.0){ // No hit
        fragColor = vec4(vec3(0.05,0.05,0.15) * 0.02,1);
    }
    else{
        vec3 surface = pos;
        vec3 normal = get_normal(surface);
        vec3 l = surface - sun; // Sun to surface
        float intensity_at_surface = sun_intensity / dot(l,l); // Inverse square decay
        
    	vec3 l_prime = l + 2.0*dot(l,normal)*normal;
        vec3 to_camera = v_0 - surface;
        float cos_angle = cdot(-l_prime, to_camera)/(length(l_prime) * length(to_camera));
        float specular = k_s * pow(cos_angle,q) * intensity_at_surface;
        float diffuse = 0.2 * cdot(normal, -l) * intensity_at_surface;
        float ambient = 0.05;
        vec3 light = vec3(clamp(diffuse + specular + ambient,0.0,1.0));
        fragColor = vec4(light.x*0.2, light.y, light.z,1);
    }

}



