#version 410 core

uniform vec2 uResolution;
uniform float uTime;

uniform float uSyncA;
uniform float uSyncB;
uniform float uSyncC;
uniform float uSyncD;

out vec4 outcolor;

#define STEPS 70
#define EPSILON .0001



vec3 sunPos = vec3( 100.0, 500.0, 80.0 );



vec3 hsv(float h,float s,float v) {return mix(vec3(1.),clamp((abs(fract(h+vec3(3.,2.,1.)/3.)*6.-3.)-1.),0.,1.),s)*v;}
float udRoundBox( vec3 p, vec3 b, float r ){  return length(max(abs(p)-b,0.0))-r;}
float udBox( vec3 p, vec3 b ){ return length(max(abs(p)-b,0.0));}
float sdSphere( vec3 p, float s ){  return length(p)-s;}
float sdPlane( vec3 p, vec4 n ){ n = normalize(n); return dot(p,n.xyz) + n.w; } // n must be normalized


float opU( float d1, float d2 ){ return min(d1,d2); } // union
float opS( float d1, float d2 ){ return max(-d1,d2);} // substract
float opI( float d1, float d2 ){ return max(d1,d2); } // intersect

void rX(inout vec3 p, float a) {
	float c,s;vec3 q=p;
	c = cos(a); s = sin(a);
	p.y = c * q.y - s * q.z;
	p.z = s * q.y + c * q.z;
}

void rY(inout vec3 p, float a) {
	float c,s;vec3 q=p;
	c = cos(a); s = sin(a);
	p.x = c * q.x + s * q.z;
	p.z = -s * q.x + c * q.z;
}

void rZ(inout vec3 p, float a) {
	float c,s;vec3 q=p;
	c = cos(a); s = sin(a);
	p.x = c * q.x - s * q.y;
	p.y = s * q.x + c * q.y;
}


float usin(float f){ return sin(f)*.5+.5; }


float udBoxRep( vec3 p, vec3 c, float s){
	//p += c/2.0;
	vec3 q = mod(p,c)-0.5*c;
	
	return udRoundBox( q, vec3(s,s,s), 1.0/30.0 );
}


float map(vec3 p){
    rZ(p, uTime*.168);
    rX(p, uTime*.02);
	float d = udBoxRep( p + vec3(0,1,0), vec3(1.3), .2 - uSyncD*.02 );
	return d;
}


vec3 march(vec3 ro, vec3 rd){
	
	vec3 p = ro;
	float d = .0;
	for(int i = 0; i < STEPS; i++){
		p += rd * d;
		d = map(p);
		
		if(abs(d) < EPSILON )
			break;
        
        
	}
	
	return p;
}


void main(void){
	float aspect = uResolution.x/uResolution.y;
	vec2 uv = gl_FragCoord.xy / uResolution.xy;
	vec2 ndc = uv*2.0 - 1.0;
	ndc.x *= aspect;
    
	// setup
	float t = uTime;
	vec3 ro = vec3( 0,0, .4);
	ro.z -= t*2.0;
	vec3 rd = normalize(vec3(ndc.xy, -1.8));
	//rd.x += sin(t)*.4;
	//rd.y += cos(t*.4)*.5;
    
	// march to surface
	vec3 p = march(ro, rd);
	
    // reflectance
    vec3 Ks = vec3 (1.0, 1.0, 1.0); // specular
    vec3 Kd = hsv(.06,1.0,1.0); // diffuse
    vec3 Ka = vec3 (.0); // ambient
    
	// lighting
	vec3 sunDir = normalize(sunPos-p);
	vec2 ne = vec2(0.01, 0.0); // epsilon for normal
	vec3 normal = (vec3(map(p+ne.xyy),map(p+ne.yxy),map(p+ne.yyx))-map(p) )/ne.x;
	
	float sunDot = max(.0, dot( sunDir, normal) );
    float spec_intensity = pow( max (dot (reflect (-sunDir, normal), normalize(-p) ), 0.0), 100.0);
    
    vec3 c = Ks*spec_intensity +Kd*sunDot+Ka;
    
	c += length(ro-p)*.045; // distance glow
	
	c = pow( c, vec3(1.0/2.2) ); // gamma
    
	outcolor = vec4(c, 1.0);
}