#version 330 core
in vec2 UV;
out vec4 fragColor;
uniform sampler2D iChannel0; // Noise tex
uniform vec2 iResolution;
uniform float iGlobalTime;

const float epsilon = 0.001;
const float e = epsilon;
const vec3 lightcolor = vec3(0.85, 0.7, 0.55);
const vec3 ambient = vec3(0.67, 0.59, 0.53);
const vec3 diffuse = 1.25*lightcolor;
float time = iGlobalTime * 2.7;

vec3 gl;

#define FAR_CLIP 3.0

mat3 rotX(float a)
{
	return mat3(1.0,0.0,0.0,0.0,cos(a),-sin(a),0.0,sin(a),cos(a));
}
mat3 rotY(float a)
{
	return mat3(cos(a),0.0,sin(a),0.0,1.0,0.0,-sin(a),0.0,cos(a));
}
mat3 rotZ(float a)
{
	return mat3(cos(a),-sin(a),0.0,sin(a),cos(a),0.0,0.0,0.0,1.0);
}

vec3 noise(vec2 c)
{
	return vec3(fract(sin(dot(c.xy, vec2(12.9898,78.233))) * 43758.5453));
}

float dist3(vec3 a, vec3 b)
{
	return sqrt(pow(b.x-a.x,2.0)+pow(b.y-a.y,2.0)+pow(b.z-a.z,2.0));   
}

float displacement(vec3 p, float a)
{
 	p *= (rotX(0.0081*time)*rotY(0.0046*time)*rotZ(0.00667*time));
	return .003*atan(sin(a*p.x)*cos(a*p.y)*sin(a*p.z), 0.10);
}

float smoother(float a, float b, float k)
{
	float h = clamp(0.5+0.5*(b-a)/k, 0.0, 1.0);
	return mix(b, a, h) - k*h*(1.0-h);
}

float stair(float a, float b, float k)
{
    float v = 1.2+0.6*sin(iGlobalTime*2.6);
    float h = clamp(0.5-1.5*(b-a)/k, 0.0, 1.0);
    return mix(b, a, h) + (v)*k*h*(0.7-h);
}

float pallo(vec3 p, float s)
{
	return length(p) - s;
}

float box(vec3 p, vec3 b)
{
	return length(max(abs(p)-b,0.0));
}

float sbox(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 tiles(vec3 r, float b, float s)
{
    return 0.0;
}

float scene(vec3 r)
{
    r /= 1.0+0.1*length(r);
    
    float dist = 0.08+0.05*cos(iGlobalTime*1.87);
    float pos = iGlobalTime;
    mat3 ro = rotX(time*0.33)*rotY(time*0.39)*rotZ(time*0.47);
    //float o1 = 100.0;//pallo(ro*vec3(r.x+0.4, r.y-0.3, r.z+0.1),      0.5);
    //float o1 = pallo(vec3(r.x-1.0, r.y+1.0, r.z), 0.15);
    float o2 = sbox (ro*vec3(r.x, r.y+0.2, r.z-0.2), vec3(0.5, 0.5, 0.5));
    //float o3 = pallo(vec3(r.x-0.25, r.y+1.75, r.z+0.4), 0.0);
    float pl = sbox(vec3(r.x,r.y+0.5,r.z), vec3(10.0, 0.1+(dist)*(sin(-r.x*4.0+pos)+cos(r.z*4.0+pos)), 10.0));
    
    return stair(o2,pl, 0.5);
    //return stair( min(min(o1,o2),o3), pl, 0.5);
}
/*
float scene(vec3 r)
{
	vec3 b1pos = vec3(r.x+0.2*sin(time*5.01), r.y-0.2*cos(time*4.91), r.z+0.2*cos(time*5.21));
	vec3 b2pos = vec3(r.x-0.2*sin(time*4.78), r.y+0.2*cos(time*5.38), r.z+0.2*sin(time*4.81));
	vec3 b3pos = vec3(r.x+0.2*cos(time*5.09), r.y-0.2*sin(time*5.33), r.z-0.2*cos(time*5.15));
	vec3 b4pos = vec3(r.x-0.2*cos(time*5.59), r.y-0.2*cos(time*4.49), r.z-0.2*sin(time*5.15));
	vec3 b5pos = vec3(r.x+0.2*sin(time*5.55), r.y+0.2*sin(time*4.63), r.z+0.2*cos(time*5.65));
	float pallo1 = pallo(b1pos, 0.15);
	float pallo2 = pallo(b2pos, 0.15);
	float pallo3 = pallo(b3pos, 0.15);
	float pallo4 = pallo(b4pos, 0.15);
	float pallo5 = pallo(b5pos, 0.15);
	
    float d;
    float balls = displacement(r, 25.)+smoother(smoother(smoother(smoother(pallo1,pallo2,.1),pallo3,.1),pallo4,.1),pallo5,.1);
    r.y -= 0.32;
    float plane = box(r, vec3(1.0, 0.01, 1.0));
    d = smoother(balls, plane, 0.5);
    //d = min(d, light);
    return d;
}
*/
vec3 normal(vec3 p) {
	float e = 1e-2;
	vec3 n = vec3(scene(p + vec3(e, 0.0, 0.0)) - scene(p - vec3(e, 0.0, 0.0)),
				  scene(p + vec3(0.0, e, 0.0)) - scene(p - vec3(0.0, e, 0.0)),
				  scene(p + vec3(0.0, 0.0, e)) - scene(p - vec3(0.0, 0.0, e)));
	return normalize(n);
}

float shadow(vec3 ro, vec3 rd, float mint, float maxt, float k)
{
    float res = 1.0;
    float t = mint;
    
    for(int i=0;i<24;++i)
    {
        float h = scene(ro + rd*t);
        if(h<0.005)
            return 0.0;
        res = min(res, k*h/t);
        t += h;
        if(t > maxt) break;
    }
    return res;
}

vec3 mars(vec3 c, vec3 p)
{
    vec3 fogcolr = normalize(1.0-vec3(0.2, 0.65, 0.7));
    float lt = iGlobalTime*1.9;
    vec3 lpos = vec3(14.0*cos(iGlobalTime*1.73), 5.0, 14.0*sin(iGlobalTime*2.0));
    gl = lpos;
    vec3 pnorm;
	float rDist, sDist = 0.0;
	vec3 rpos;
    vec3 light;
	for(int i = 0; i < 96; ++i){
		rpos   = c + rDist*p;
		sDist  = scene(rpos);
		rDist += sDist;
        if(sDist >= FAR_CLIP) break;
		if(sDist <= epsilon){
            pnorm = normal(rpos);
            vec3 ldir = -normalize(lpos+rpos);
            light = diffuse*max(0.0, dot(pnorm,ldir));
            float shade = 0.2+0.8*shadow(rpos, ldir, 0.1, 30.0, 2.0);
            vec3 fog = 0.9-fogcolr*rDist/9.0;
            return 1.1*fog*ambient*light*shade;
		}
	}
    return vec3(0.0);
}

vec3 cc(vec3 color)
{
 	vec3 c = pow(0.2+color, vec3(2.5));
    return c*2.6-0.015;
}

vec3 fisheye(vec3 v)
{
    v.xy *= 1.4;
	v.xy /= cos(length(v.xy));
    return v;
}

void main()
{
	// Normalized location
	vec2 p = 1.0 - 2.0*UV;
	// Aspect ratio fix
	p.y *= iResolution.y/iResolution.x;
    
	// distance from origin
	float zOff = 3.5;

	// Rotation matrix & projection plane & camera
    mat3 angle = rotX(0.7)*rotY(2.0*3.141*1.0/iResolution.x)*rotZ(0.0);
    mat3 shake = rotX(0.0);
    mat3 rot = angle;//*shake;
    
    // "camera"
	vec3 c = vec3(-0.2, -0.2, zOff)*rot;
    
    // "image plane"
    vec3 pp = vec3(p, zOff-7.0)*rot;
	pp = normalize(pp);
    
	// March objects
	vec3 s = mars(c, pp);
    s = 1.5*cc(pow(s, vec3(0.75)));
    
	float v = 1.0 / (0.8 + 2.0*dot(p, p));
	float f = 0.99 + 0.02*smoothstep(0.0, 0.25, 0.7*sin(3000.0*time));
	s = pow(s, vec3(1.0/1.1));
	fragColor = vec4( 0.025*noise(p*time)+s*v*f, 1.0);
}
