uniform sampler2D texture0;	// depth texture
uniform sampler2D rotMap;	// rotation normal map
uniform sampler2D normalTex;	// rotation normal map

//uniform vec2 camerarange; 	// near and far camera range
//uniform vec2 screensize;	// screen width and height
varying vec2 	texCoord;
varying vec2	texCoord1;
uniform vec3 	shk[8];		// sphere kernel

uniform float	wFar;

float aoCap = 1.0;
float aoMultiplier=1.0;
float depthTolerance=0.0;
uniform float aorange;//= 300.0;// units in space the AO effect extends to (this gets divided by the camera far range

float invAOrange=1.0/aorange;//0.005;	//1/aorange;	

uniform float contrast;
float falloff = 0.000002;
float strength = 1.0;

/*float lerp(float a, float b, float t)
{
	return ((b-a)*t)+a;
}*/

vec4 decode(vec4 enc)
{
    vec2 fenc = enc.xy*4.0-2.0;
    float f = dot(fenc,fenc);
    float g = sqrt(1.0-f/4.0);
    vec4 n;
    n.xy = fenc.xy*g;
    n.z = 1.0-f/2.0;
	n.w=enc.w;
    return n;
}

vec3 mirror( vec3 vDir, vec3 vPlane ) 
{
	return vDir - 2.0 * vPlane * dot(vPlane,vDir);
}

float compareDepths( in float depth1, in float depth2 ) 
{
	float distance=depth1-depth2;
/*	float valid=step(falloff,distance);
	return valid * (1.0-smoothstep(falloff,strength,distance));
	*/
	float dscaled=distance*invAOrange;
	float valid=(clamp(abs(dscaled),0.0,1.0)+clamp(dscaled,0.0,1.0))*0.5;
	return 1.0-mix(clamp(-distance*10.0,0.0,1.0),0.55,valid);
}

void main(void)
{	
	float depth = -texture2D(texture0, texCoord.xy).r;
	
	// get normal
	vec4 encoded=texture2D(normalTex,texCoord.st);
	vec4 normal = decode(encoded);
	
	float d;
	float 	aoscale=1.5,
			aoscale2=1.2;//1.5*0.8;
	float ao=0.0;

	float scale=/*aorange/depth; //*/clamp((depth-aorange),0.0,1.0)*clamp((depth*0.0001),0.0,0.4)+0.6;
	float farscale=scale*3000.0;
	float scale2=scale*2.0;

	// create random rot matrix
	vec3 rotSample = texture2D(rotMap, texCoord1).rgb;
	rotSample = (2.0 * rotSample - 1.0);
	
	//aorange=200.0;///scale;
	vec4 occNormal;
	for(int i=0; i<8; i++)
	{
		vec3 vSample = reflect(shk[i], rotSample)*scale;
		vSample.z*=farscale;	// far plane
		
		// if the ray is outside the hemisphere then change direction
		vec2 sample = texCoord.xy + /*sign(dot(vSample,normal.xyz) )*/vSample.xy;
		//occNormal=decode(texture2D(normalTex,sample));
		d=-texture2D( texture0, sample ).r;
		ao+=/*(1.0-dot(occNormal.xyz,normal.xyz));*/compareDepths(depth+vSample.z,d)*aoscale;
			
		sample = texCoord.xy + /*sign(dot(vSample,normal.xyz) )*/vSample.xy*scale2;
		//occNormal=decode(texture2D(normalTex,sample));
		d=-texture2D( texture0, sample).r;
		ao+=/*(1.0-dot(occNormal.xyz,normal.xyz));*/compareDepths(depth+vSample.z,d)*aoscale2;		
	}

	ao/=16.0;/*24.0;*/
	ao=1.0-(ao*clamp(depth,0.0,1.0));
		
	// brightness & conttrast (default brightness=0.0, contrast=1.0)
	
	ao = ((ao-0.5)*contrast) + 0.5;
	//ao+=0.5;
	ao=clamp(ao,0.0,1.0);
	
	gl_FragColor = vec4(ao);
}



///////////////////////////////////////////////////////////

//noise producing function to reduce banding (got it from someone else´s shader):
float rand(vec2 co){

        return 0.5+(fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453))*0.5;

}


#define NUM_SAMPLES 8

void main()
{    
	float sum = 0.0;
	/*float zFar = 80.0;
	float zNear = 0.5;
*/
	float prof = texture2D(texture0, texCoord.st).x;
	//prof = zFar * zNear / (prof * (zFar - zNear) - zFar);  //linearize z sample

	//vec3 norm = normalize(vec3(texture2D(normal,gl_TexCoord[0].st).xyz)*2.0-vec3(1.0));
	vec3 norm=readNormal(texCoord.st);

	int hf = NUM_SAMPLES/2;

	//calculate sampling rates:
	float incx = (1.0/160.0)*aorange;//8 is the radius 
	float incy = (1.0/120.0)*aorange;

	for(int i=-hf; i < hf; i++){
		  for(int j=-hf; j < hf; j++){
	 
		  vec2 coords = vec2(i*incx,j*incy)/-prof;

		  float prof2 = texture2D(texture0,texCoord.st+coords*rand(texCoord)).x;

		  if (prof2>prof){

			   vec3 norm2 = readNormal(texCoord.st+coords*rand(texCoord));//normalize(vec3(texture2D(normal,gl_TexCoord[0].st+coords*rand(gl_TexCoord[0])).xyz)*2.0-vec3(1.0)); 
			   
			   //calculate approximate pixel distance:
			   vec3 dist = vec3(coords,prof-prof2);

			   //calculate normal and sampling direction coherence:
			   float coherence = dot(normalize(-coords),normalize(vec2(norm2.xy)));

			   //if there is coherence, calculate occlusion:
			   if (coherence > 0){
				  //approximate form factor:
				  float pformfactor = 0.5*((1.0-dot(norm,norm2)))/(3.1416*pow(abs(length(dist*4)),2.0)+0.5);//4 is depthscale
				  sum += clamp(pformfactor*contrast,0.0,1.0);//2 is ao intensity; 
			   }
			   
		  }
	   }
	}

	float occlusion = 1.0-(sum/NUM_SAMPLES);
	gl_FragColor = vec4(occlusion,occlusion,occlusion,1.0);
}