// G-Buffer data
uniform sampler2D bgl_DepthTexture;  // Depth texture  
uniform sampler2D randTexture; // Random texture
uniform sampler2D bgl_RenderedTexture; // Color texture 
uniform sampler2D light;

// Util vars
uniform int screenWidth;
uniform int screenHeight;

uniform bool renderColor;

float pw = 1.0/float(screenWidth);
float ph = 1.0/float(screenHeight);

uniform float lightDecrease;

float maxLightDecrease = 0.75;
float actualLightDecrease = lightDecrease * maxLightDecrease;

uniform float IgnoreLightXMin; // Used to ignore a part of the screen-view that doesnt show the light texture addition
uniform float IgnoreLightXMax;
uniform float IgnoreLightYMin;
uniform float IgnoreLightYMax;

float readDepth(in vec2 coord)
{  
    if (coord.x < 0.0|| coord.y < 0.0)
		return 1.0;

    float nearZ = 2.0;
    float farZ = 1000.0;
    float posZ = texture2D(bgl_DepthTexture, coord).x;

    return (2.0 * nearZ) / (nearZ + farZ - posZ * (farZ - nearZ));  
}   

vec3 readColor(in vec2 coord)  
{
	if(coord.x < IgnoreLightXMin || coord.x > IgnoreLightXMax || coord.y < IgnoreLightYMin || coord.y > IgnoreLightYMax)
	{
		return (texture2D(bgl_RenderedTexture, coord).xyz) + texture2D(light, coord).xyz;  
	}
	else
	{
		return (texture2D(bgl_RenderedTexture, coord).xyz);
	}
} 

float compareDepths(in float depth1, in float depth2,inout int far)  
{  

    float diff = (depth1 - depth2)*80.0; //depth difference (0-100)
    float gdisplace = 0.2; //gauss bell center
    float garea = 2.0; //gauss bell width 2

    //reduce left bell width to avoid self-shadowing
    if (diff<gdisplace){ 
    garea = 0.21;
    }else{
    far = 1;
    }
    float gauss = pow(2.7182,-2.0*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));

    return gauss;
}  

float calAO(float depth,float dw, float dh)  
{  
    float temp = 0.0;
    float temp2 = 0.0;
    float coordw = gl_TexCoord[0].x + dw/depth;
    float coordh = gl_TexCoord[0].y + dh/depth;
    float coordw2 = gl_TexCoord[0].x - dw/depth;
    float coordh2 = gl_TexCoord[0].y - dh/depth;

    if (coordw  < 1.0 && coordw  > 0.0 && coordh < 1.0 && coordh  > 0.0){
    vec2 coord = vec2(coordw , coordh);
    vec2 coord2 = vec2(coordw2, coordh2);
    int far = 0;
    temp = compareDepths(depth, readDepth(coord),far);

    //DEPTH EXTRAPOLATION:
    if (far > 0){
        temp2 = compareDepths(readDepth(coord2),depth,far);
        temp += (1.0-temp)*temp2; 
    }
    }
 
    return temp;  
}   
     
void main(void)  
{  
    //randomization texture:
    vec2 fres = vec2(screenWidth/256, screenHeight/256);
    vec4 random = texture2D(randTexture, gl_TexCoord[0].st*fres.xy);
    random = random*3.5-vec4(1.0);

    //initialize stuff:
	vec2 texturecoord = gl_TexCoord[0].xy;
    float depth = readDepth(texturecoord);  
    float ao = 0.0;

    for(int i=0; i<4; ++i) 
    {  
		//calculate color bleeding and ao:
		ao+=calAO(depth,  pw, ph);  
		ao+=calAO(depth,  pw, -ph);  
		ao+=calAO(depth,  -pw, ph);  
		ao+=calAO(depth,  -pw, -ph);

		ao+=calAO(depth,  pw*1.2, 0.0);  
		ao+=calAO(depth,  -pw*1.2, 0.0);  
		ao+=calAO(depth,  0.0, ph*1.2);  
		ao+=calAO(depth,  0.0, -ph*1.2);
     
		//sample jittering:
		pw += random.x*0.0002;
		ph += random.y*0.0002;

		//increase sampling area:
		pw *= 1.7;  
		ph *= 1.7;    
    }

    //final values, some adjusting:
    vec3 finalAO = vec3(1.0-(ao/32.0));

    if(renderColor)
    {
        gl_FragColor = vec4(readColor(gl_TexCoord[0].xy)*finalAO*1.0,1.0);  
    }
    else
    {
        gl_FragColor = vec4(finalAO*0.7,1.0) + texture2D(light, vec2(gl_TexCoord[0]));  
    }
}