#version 430

layout(binding=0) uniform sampler2D tex;
in vec3 color;
out vec4 frag;

uniform float g_time;


//reflections n water plane3
// written by deepr of adapt - 2012
// use at your own risk
// -:-

//#ifdef GL_ES
// precision mediump float;
// #endif

//uniform float time;
vec2 mouse = vec2(0.10, 0.10);
vec2 resolution = vec2(1280.0, 720.0);

float nois(vec3 p) {
	//return fract(dot(p, vec3(332.4569, 732.262, 243.262137)));
	return fract(cos(dot(p.xyz ,vec3(12.9898,78.233,127.789))) * 43758.5453);
}

vec3 st(vec3 p) {
	/*
  vec3 k = vec3(6.0, -15.0, 10.0);
  vec3 pp = vec3(p.x*p.x, p.y*p.y, p.z*p.z);
  vec3 pp3 = vec3(pp.x*p.x, pp.y*p.y, pp.z*p.z);
  vec3 pp4 = vec3(pp3.x*p.x, pp3.y*p.y, pp3.z*p.z);
  vec3 pp5 = vec3(pp3.x*pp.x, pp3.y*pp.y, pp3.z*pp.z);
  return vec3(pp5.x*k.x+pp4.x*k.y+pp3.x*k.z, pp5.y*k.x+pp4.y*k.y+pp3.y*k.z, pp5.z*k.x+pp5.z*k.y+pp5.z*k.z);
*/
  return smoothstep(0.0, 1.0, p);
}

float pnois(vec3 p) {
/*
 // p.xy += 10000.0;
  p.z += fract((floor(p.x)+floor(p.y))*1.0)*0.5;
  float eps = 1.0;
  vec3 pfp = p-fract(p);
  float n1 = nois(pfp);
  float n2 = nois(pfp+vec3(eps, 0.0, 0.0));
  float n3 = nois(pfp+vec3(0.0, eps, 0.0));
  float n4 = nois(pfp+vec3(eps, eps, 0.0));
  float nb1 = nois(pfp+vec3(0.0, 0.0, eps));
  float nb2 = nois(pfp+vec3(eps, 0.0, eps));
  float nb3 = nois(pfp+vec3(0.0, eps, eps));
  float nb4 = nois(pfp+vec3(eps, eps, eps));	
 // vec3 fr = smoothstep(0.0, 1.0, fract(p));
  vec3 fr = st(fract(p));
  return ((fr.x*n2+(1.0-fr.x)*n1)*(1.0-fr.y)+(fr.x*n4+(1.0-fr.x)*n3)*fr.y)*(1.0-fr.z)+
	 ((fr.x*nb2+(1.0-fr.x)*nb1)*(1.0-fr.y)+(fr.x*nb4+(1.0-fr.x)*nb3)*fr.y)*(fr.z);

     */
     return sin(textureLod(tex, p.xy*0.01, 0.0)+g_time+vec4(p.xy,0.0,0.0)*3.01)*0.5;
}

float pnois2(vec3 p) {
  return (pnois(p)+pnois(p+vec3(0.0,0.0,0.5)))*0.5;
}

float turb(vec3 p, int n) {
	float res=0.0;
	float k=0.50;
	p.z+=0.5;
	for (int i=0; i<5; i++) {
		res+=(pnois(p))*k;
		k*=0.5;
		p*=2.0;
	}
	return res;
}


vec3 rotatexy(vec3 p, float a) {
	vec3 r;
	r.x = cos(a)*p.x-sin(a)*p.y;
	r.y = sin(a)*p.x+cos(a)*p.y;
	r.z = p.z;
	return r;
}

int imo;
int imoHit;

float b(vec3 p) {
	vec3 po=p;
	p+=0.50;
	p*=1.0;
      //  p = rotatexy(p, po.z*0.45);
	imo = int(p.x-fract(p.x));
	//if (imo==1) {
	//  p = rotatexy(p, time*0.2);	
	//}
	p.xy=fract(p.xy)-0.50;
	p.z = p.z-0.50;	
	float val = sqrt(p.x*p.x+p.z*p.z*0.0+p.y*p.y)-0.21*(0.7+0.2*sin(p.z*18.3));
	float m= 0.0;
	if (val<m) {
	//	val += pnois(p*13.2+vec3(0.0, 0.0, g_time*0.0))*m;
	}
	return val; // +pnois(p*23.2+vec3(0.0, 0.0, g_time*0.1))*0.210;
}

float fl(vec3 p) {
    float val = -p.z-1.80+10.0;
	float m = 0.01;
	if (abs(val) < m) {
	 // val += m*turb(p*1.0+vec3(0.0, 0.0, g_time*0.2), 3);
	  val += m*pnois2(p*10.0+vec3(0.0, 0.0, g_time*0.02));
	}
	return val;
}


float f1(vec3 p) {

   p=rotatexy(p,g_time*0.1);


	//return (min(b(p),b(p+vec3(0.1,0.0,0.0))));
	float flo = fl(p);
// return flo; 
	float bal = b(p);
   // return bal;
    
	if (flo < bal) { // hit floor
		imo = 2;
		return flo;
	} else { // hit ball
		return bal;
	}
    
	
}

const int mI=64;
const int bI=32;

const vec3 ep = vec3(0.01, 0.0, 0.0);
vec3 norm(vec3 p, float eps) { 
	
	//return vec3(f1(p+ep.xyz)-f1(p-ep.xyz), f1(p+ep.yxz)-f1(p-ep.yxz), f1(p+ep.yzx)-f1(p-ep.yzx));
	return vec3(f1(p+ep.xyz), f1(p+ep.yxz), f1(p+ep.yzx));
}

float v;

vec3 march(vec3 p, vec3 d, bool inside) {

  	float t=0.0;
	float s=1.0;
	v=0.0;
	float k=1.0;
	float ad;
	int ii=0;
	for (int i=0;i<mI;i++) {
		v=f1(p);
		if ((v < 0.0 && !inside) || (v>0.0 && inside)) {
		  break;
		}
		ad=(0.10+0.0*v);
		//ad=abs(v)/length(norm(p, 0.1));
		t+=ad*k;
 		p+=ad*k*d;
		k*=1.03;
		ii++;
	}
	if (t>99.99) {
		v=1.0;
		return p;
	}
	
	for (int i=0;i<bI;i++) {
		v=f1(p);
		if ((s*v < 0.0 && !inside) || (s*v>0.0 && inside)) {
			s*=-0.5;
		}
		t+=s*k;
		p+=s*k*d;
	}

	return p;
}

vec3 hitNormal;
vec4 hitColor;
vec3 hitPos;
vec3 hitRef;

vec3 origin;
vec3 ray;


void calcHitColor() {
	hitNormal = normalize(norm(hitPos, 0.001));
	
	vec3 light = origin+vec3(0.0, .0, 0.0);
	hitRef = normalize(reflect(ray, hitNormal));
		
	vec3 len = hitPos-origin;

	vec3 c1;
	
	c1 = vec3(1.0, 0.9, 0.84)*1.0;
	if ((imoHit)==0) { 
		c1 = vec3(1.0, 1.19, 0.84)*8.0+textureLod(tex, hitPos.xy*1.1, 0.0).xyz*1.0;
	} else if ((imoHit)==1) {
		c1 = vec3(1.0, 0.79, 1.14)*1.0;
	} else if ((imoHit)==2) {
		c1 = vec3(1.00, 1.0, 1.44)*1.0;
	}
    c1*=0.50;
	vec3 c2 = vec3(1.0, 1.0, 1.20)*0.0;
		
	vec3 vp = (hitPos-light);
	float vpd = length(vp)*0.60; // dot(vp,vp)*32.0;
	vp = normalize(vp);
	float kd = clamp(dot(-hitNormal,vp), 0.0, 1.0);
	float ks = clamp(dot(hitRef,vp), 0.0, 1.0);
	hitColor = vec4(clamp(pow(kd, 8.0), 0.0, 10.0)/vpd*c1+clamp(pow(ks, 16.0), 0.0, 10.0)*c2,clamp(16.0/(dot(len,len)*2.2+1.0),0.0,1.0));	
}
/*
float n1(vec3 p) {
	return turb(vec3(p.xy, p.z));
}

vec3 ng(vec3 p) {
	vec3 eps=vec3(0.01, 0.0, 0.0);
	return normalize(vec3(n1(p+eps.xyz), n1(p+eps.yxz), n1(p+eps.yzx))-vec3(n1(p)));
}
*/
void main( void ) {
	//discard;
	
	vec2 position = ( (gl_FragCoord.xy-resolution.xy*0.5) / resolution.xy );
	
//	float t1 = turb(vec3(position.xy*64.0, fract(g_time/50.0)*50.0*0.42-8.0*mouse.x));
//	vec3 t1 = ng(vec3(position.xy*16.0, fract(g_time/50.0)*50.0*0.42-8.0*mouse.x));
//	gl_FragColor = vec4(t1*1.0);
//	return;
	
	
	vec3 kr = rotatexy(vec3(0.0, 0.0, 0.0), -g_time*0.162*0.45);
	origin = vec3(kr.x+g_time*0.0, kr.y, -2.0+g_time*0.0);
	origin.xy -= mouse.xy*8.0;
	ray = vec3(position.x, position.y, 1.0)*0.050;
	
	ray.yzx = rotatexy(ray.yzx, -1.37);// sin(g_time*0.1)*2.0);

    ray=normalize(ray);
	
	// ray.xzy = rotatexy(ray.xzy, time*0.01);
	
	//ray.xyz = rotatexy(ray, mouse.x*0.0);
	

	hitColor = vec4(vec3((1.0, 1.0, 1.240)*(position.y+0.5)), 1.0);
	
	
	// vec3
	

	vec3 acc=hitColor.xyz;

	hitPos = march(origin, ray, false);
	imoHit = imo;
	// hitPos = origin+ray*vc;	
	if (v < 0.8) {
		calcHitColor();
		acc = (hitColor.xyz*hitColor.w+acc.xyz*(1.0-hitColor.w))*0.40;
		if (true){// || imoHit==2){
		
			//acc=vec3(0.0);
		float kp=0.7;
		for (int k=0; k<2; k++) {
		// origin = hitPos+hitRef*0.020;
		// ray = hitRef*0.3;


		origin = hitPos-normalize(ray)*0.01;//+hitRef*0.020;
        ray = ray-(hitRef)*0.05;
		
		//origin = hitPos+ray*0.1;
		//ray = ray*0.5+hitNormal*0.5;
		//acc+=dot(hitRef,normalize(vec3(0.0, 0.0, 0.0)-hitPos));
        if (k==0) {
		    hitPos = march(origin, ray, true);
         } else {
            hitPos = march(origin, ray, false);
         }
		imoHit = imo;
		if (v < 0.8) {
			calcHitColor();
			hitColor.w*=kp;
         //   if (k==1) {
			    acc = hitColor.xyz*hitColor.w+acc.xyz*(1.0-hitColor.w);
           //     }
		}
			kp*=0.5;
		}
	}
	}
	
	
        frag = vec4(acc.xyz, 1.0);

   //     frag = -1.0/(1.0-frag);

  frag.r = pow(frag.r, 0.5);
  frag.g = pow(frag.g, 0.5);
  frag.b = pow(frag.b, 0.5);


  float lwhite2 = 2.0;
  frag = frag*(1.0+frag/lwhite2)/(1.0+frag);

}

/*
void main() {
  vec4 res = vec4(1.0);
  vec2 myUv = color.xy;
 // myUv *= 0.6+0.4*sin(g_time);
 myUv *= 1.0;
  float k=1.50;
  for (int i=0; i<3; i++) {
    res *= k*textureLod(tex, myUv*(0.2+i*0.576+0.0*sin(g_time*0.004+i*0.001)), 0.0);
    //k*=0.95;
  }
 // res.rgb *= (0.40-0.2*(sin(color.x*34.0+g_time*2.0)+cos(color.y*38.0+g_time)));

//  res.r = pow(res.r, 0.5);
//  res.g = pow(res.g, 0.5);
//  res.b = pow(res.b, 0.5);

  frag = res;
}


*/