uniform sampler2D texture0;		// gdepth
uniform sampler2D rotMap;		// gnormals
uniform sampler2D normalTex;	// grandom

varying vec2 	texCoord1;
varying vec2 	texCoord;
varying vec2	VPOS;
uniform float 	contrast;
uniform float 	aorange;
uniform vec3 	shk[32];		// sphere kernel
uniform float 	aobias;
uniform mat4 	projTM;
uniform float 	aoscale;
uniform int  	numSamples;
uniform int	samplePerRay;
uniform float	farOffset;

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;
}

float invAOrange;
float curRange;

vec2 getScreenPos(vec4 pos)
{
	vec4 ppos;
	vec2 spos;
		
	// compute texture space pos
	ppos=projTM*pos;
	ppos=ppos/ppos.w;
	spos=vec2(1.0)-ppos.xy;
	return spos;
}

vec3 getEyePos(vec2 coords)
{
	vec3 pos;
	pos.z = texture2D(texture0, coords.xy).r;
	pos.xy=VPOS*-pos.z;
	return pos;
}

float testAO(in vec3 cPos/*, in float ofsSign,*/, vec3 samplePos) 
{
	// get sample pos
	//vec3 samplePos;
	vec2 screenCoords;
	float sampleDepth;
	float depthDist;
	float dist;
	vec3 diff;
	//float ofsSign=sign(dot(cNormal, sampleOfs));
	//vec3 ofsInc=(sampleOfs/*float(samplePerRay)*/)*ofsSign;
	//vec3 accSample=ofsInc;
	
	// raymarch occlusion 
	/*for(int i=0; i<samplePerRay; i++)
	{*/
		//samplePos=cPos+sampleOfs;//accSample;
		
		// project into screen space
		screenCoords=getScreenPos(vec4(samplePos,1.0));
		
		// get depth from occluder screen coords
		sampleDepth = texture2D(texture0, screenCoords).r;
		
		// return 1 if sample is occluded by depthBuffer
		depthDist = sampleDepth - samplePos.z;
		if(depthDist>0.0)
		{
			if(depthDist<curRange)
			{
				return 1.0;
			}
			else
			{
				// compute real distance
				vec3 eyepos=vec3(VPOS*-sampleDepth,sampleDepth);
				diff=cPos-eyepos;
				dist=length(diff)*invAOrange;
				
				// compute distance between sample and 
				return 1.0 - clamp(pow(dist, aoscale), 0.0,1.0);
			}
		}
	//	accSample+=ofsInc;
	//}
	return 0.0;
}

/*vec3 getsample(int i)
{
    vec2 mod_coord = mod(floor(gl_FragCoord.xy), pattern_size);
    float y = ((mod_coord.x + mod_coord.y*pattern_size)+0.5) / (pattern_size*pattern_size);
    float x = (float(i)+0.5)/float(numSamples);
    //return (texture2D(rotMap, vec2(x, y)).xyz-0.5)*2.0;
	
	vec3 rotSample = texture2D(rotMap, vec2(x, y)).rgb;
	rotSample = (2.0 * rotSample - 1.0);
	return rotSample;
}*/

void main(void)
{	
	float ao=0.0;
	float aoMinDist=farOffset-1500.0;
	float aoMaxDist=farOffset;
	vec3 centerPos=getEyePos(texCoord.xy);
	//float aoMinDist=farOffsetMin*2.0;
	if(-centerPos.z<aoMaxDist)
	{
		vec4 encoded=texture2D(normalTex,texCoord.st);
		vec4 centerNormal = decode(encoded);
		centerNormal.xyz=normalize(centerNormal.xyz);	
		centerNormal.xyz*=sign(dot(centerNormal.xyz,normalize(-centerPos))+0.2);// check if normal is opposed to view vector, in that case invert the normal (two sided trick)
		
		// create random rot matrix
		vec3 rotSample = texture2D(rotMap, texCoord1).rgb;
		rotSample = (2.0 * rotSample - 1.0);
		
		float occMul;
		vec3 vSample;
		vec4 prevCenterPos;
		vec2 reprojCoords;
		vec3 sample;
		float normalDot;
		//float rangeMul=mix(0.3,1.0,(samplePerRay-1.0)*0.125);
		
		/*if(-centerPos.z<farOffsetMin)
		{*/
			curRange=aorange-(centerPos.z*aorange/aoMaxDist);
			invAOrange=1.0/curRange;//rangeMul;
			float d=1.0;
			for(int i=0; i<numSamples; i++)
			{
				vSample = /*normalize(*/reflect(shk[i], rotSample);//);
				normalDot=dot(normalize(vSample), centerNormal.xyz);
				occMul=max(0.0,abs(normalDot) - aobias);
				if(occMul>0.0)
				{
				//	sample.xy=getScreenPos(vec4(centerPos,1.0))+(vSample.xy*curRange*d*sign(normalDot));
				//	sample.z=centerPos.z+(vSample.z*curRange*d*sign(normalDot));
					ao+=(testAO( centerPos, centerPos + (vSample*curRange*d*sign(normalDot)) )*occMul);
				}
				d*=0.75;
			}
		/*}
		else
		{
			float t=( clamp( (-centerPos.z-farOffsetMin)/(farOffset-farOffsetMin),0.0,1.0));
			float farRange=mix(aorange,aorange*2.0,t);
			invAOrange=0.3/farRange;//*rangeMul;
			curRange=farRange;
			for(int i=0; i<numSamples; i++)
			{
				vSample = normalize(reflect(shk[i], rotSample));
				normalDot=dot(vSample, centerNormal.xyz);
				occMul=max(0.0, abs(normalDot) - aobias);
				if(occMul>0.0)
					ao+=(testAO(centerPos,centerPos + (vSample*farRange*sign(normalDot)) )*occMul);
			}
		}*/
		
		// smooth basing on max distance
		ao=mix(ao,0.0,( clamp( (-centerPos.z-aoMinDist)/(aoMaxDist-aoMinDist),0.0,1.0) ));
	}
	gl_FragColor = vec4(ao/float(numSamples));
}