uniform sampler2D depthpacked, normalmap, colormap;
uniform sampler2D reflectAmountTexture;
uniform sampler2D reflectionTexture;
uniform float amount;
uniform float blur_range;
uniform float randomDirection;
uniform float mixOut;
uniform bool reflectWholeScene;

float unpackFloatFromVec3i(const vec3 value){
	const vec3 bitSh = vec3( 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0);
	return(dot(value, bitSh));
}
vec3 packFloatToVec3i(const float value)
{
	const vec3 bitSh = vec3( 256.0 * 256.0, 256.0, 1.0);
	const vec3 bitMsk = vec3( 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
	vec3 res = fract(value * bitSh);
	res -= res.xxy * bitMsk;
	return res;
}

float getdepth(vec2 xy){
	float depth;
	vec3 col=texture2D(depthpacked,xy).xyz;
	if(col.x==0.0 && col.y==0.0 && col.z==0.0)
		depth=1000000000.0;
	else
		depth=unpackFloatFromVec3i(col);
	return depth;
}



void main()
{
	vec2 xy = gl_TexCoord[0].xy;
	float objRefAmount = 1.0;
	if(!reflectWholeScene)
		objRefAmount = texture2D(reflectAmountTexture,xy).r;
	vec4 colAtXY = texture2D(reflectionTexture,xy);

	if(objRefAmount <= 0.0 && !reflectWholeScene) {
		gl_FragColor = colAtXY;
	} else {
		vec4 nor = texture2D(normalmap,xy)-vec4(0.5);
		// eye normal
		vec3 viewDirection = vec3(0,0,1);
		vec3 L = normalize(nor.xyz);
		// fresnel equation
		vec3 halfwayDirection = normalize(L + viewDirection);
		float w = pow(2.0 - max(0.0, dot(halfwayDirection, viewDirection)), 5.0)*((1.0+amount)*500.0);
		w  = min(w,1.0);
		w  = max(w,0.0);

		float depth = getdepth(xy);
		if(depth >= 1000000000.0) {
			gl_FragColor = colAtXY;
		} else {

			int i;
			float res = 0.0;
			float counter = 0.0;
			vec2 xy2 = vec2(0);

			vec3 n = nor.xyz;
			vec4 c =vec4(0);
			//nor.xy /= 1+pow(nor.z,1.0);
			nor /= vec4(depth);
			xy2 = vec2(blur_range/1000000.0)*nor.xy; // *vec2(depth);
			float d;
			vec2 xy3;

			//vec2 randxy = vec2(xy2.x*1000.0,xy2.y*5000.0);
			float mult = 0.1/(depth*depth+0.1);
			float randx=sin(cos(dot(gl_FragCoord.xy*0.03 ,vec2(110021.9898,7088.2333))) * 43700158.5453)*0.0001*randomDirection*mult;
			float randy=cos(sin(dot(gl_FragCoord.xy*0.02 ,vec2(11101.98098,700.2333))) * 43101058.5453)*0.0001*randomDirection*mult;

			vec4 nn;

			for(i = 0 ; i < 16 ; i++) {
				xy3 = (xy2 )*pow(float(i),2.0)/20.0;
				xy2 += vec2(randx,randy);
				vec2 xy4 = xy + xy3;
				xy4.y = min(0.999,xy4.y);
				xy4.x = min(0.999,xy4.x);
				xy4.y = max(0.0001,xy4.y);
				xy4.x = max(0.0001,xy4.x);
				nn =  texture2D(normalmap,xy4)-vec4(0.5);
				if(distance(n,nn.xyz)>0.02)
					{
					d = getdepth(xy4);
					if(d >= depth){
						c += texture2D(colormap,xy4);
						counter+=1.0;
					}
				}
				else {
					counter+=1.0;
					c += colAtXY;
				}


			}

			c/=counter;

			vec4 fxCol = ((1.0-w)*colAtXY)+c*w*1.1;
			float m = mixOut*objRefAmount;
			m = min(1.0, m);
			m = max(0.0, m);
			gl_FragColor = fxCol * vec4(m) + vec4(1.0-m)*colAtXY;
		}
	}
}
