#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 80
#define EPSILON .001

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


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;
	float col = floor(p.x*c.x)/c.x;
	float row = floor(p.z*c.z)/c.z;
	float h = usin( row*1.5 + col*2.0 + uSyncD );
	h *= .25;
	
	return udRoundBox( q, vec3(s,s+h,s), 1.0/30.0 );
}


float map(vec3 p){
	float d;
	d = udBoxRep( p + vec3(0,1,0), vec3(1,1000,1), .4 );
	//d = sdPlane(p, vec4(0,1,0,1)) + sin(p.z*10.0)*.1;
	//d = min(d, sdSphere( p + vec3(.0, .0, 1.0), 1.0 ) );
	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;
    
    vec3 c;
    
    
    if( ndc.y > 0.0){
        float th = atan(ndc.y, ndc.x);
        c = mix( hsv(.06, 1.0, 1.0), vec3(1), vec3( floor( mod((th/3.14)*14.0 + uTime, 2.0) ) ) );
		if( abs( ndc.x ) + ndc.y*.8  < 0.5) c = vec3(1);
	} else {
        
        // setup
        vec3 ro = vec3(0,.5, 3.0);
        ro.z -= uTime;
        vec3 rd = normalize( vec3(ndc.xy, -1.0) );
        rd.y -= .1;
        
        // march to surface
        vec3 p = march(ro, rd);
        
        
        // 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) );
        
        c = vec3( sunDot )*hsv(.06,1.0,1.0);
        
        if(map(p) > EPSILON){
            // we didn't hit anything
            c = vec3( 1.0 - .5*length( vec2(ndc.x*.5, uv.y) ) );
        }
        
        c += length(ro-p)*.005; // distance glow
        
        
    }
    
	c += vec3( pow(1.0 - abs(ndc.y ), 15.0)*2.0 ); // midline
    
    
	
	c = pow( c, vec3(1.0/2.2) ); // gamma
	outcolor = vec4(c, 1.0);
}