#version 330 core
// Based on devmaster.net's SSAO routine
// http://devmaster.net/posts/3095/shader-effects-screen-space-ambient-occlusion

in vec2 UV;
uniform sampler2D texture0;  // normals
uniform sampler2D texture1;  // positions
uniform sampler2D texture2;  // colors
out vec4 color;

const float kScale = float(2.0);
const float kBias = float(0.9);
const float kIntensity = float(4.0);
const vec2 kSampleRad = vec2(10.0) / vec2(768.0, 768.0);

float rand(vec2 co){
	return (fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453) - 0.5);
}

vec2 getRnd(vec2 uv) {
	return normalize(vec2(rand(uv.xy + uv.yy * uv.xx),
	                      rand(uv.yx + uv.xy + vec2(0.546,-0.516)))
	                );
}

float aofactor(vec2 poscoord, vec2 rndcoord, vec3 p, vec3 normal) {
	vec3 diff = texture(texture1, poscoord + rndcoord).xyz - p;
	vec3 v = normalize(diff);
	float d = length(diff) * kScale;
	return kIntensity * max(0.0, (dot(normal, v) - kBias)) / (1.0 + d);
}

void main(){
	vec2 samples[4];
	samples[0] = vec2( 1.0,  0.0);
	samples[1] = vec2(-1.0,  0.0);
	samples[2] = vec2( 0.0,  1.0);
	samples[3] = vec2( 0.0, -1.0);
	vec3 p = texture(texture1, UV).xyz;
	vec3 n = normalize(texture(texture0, UV).xyz);
	vec2 rand = getRnd(UV + p.xy * n.xz);

	float ao = float(0.0);
	const int kIterations = 4;
	for ( int i = 0; i < kIterations; i++ ) {
		vec2 coord1 = reflect(samples[i], rand) * kSampleRad;
		vec2 coord2 = vec2(coord1.x * 0.707 - coord1.y * 0.707,
		                   coord1.x * 0.707 + coord1.y * 0.707) * kSampleRad;
		ao += aofactor(UV, coord1 * 0.25, p, n);
		ao += aofactor(UV, coord2 * 0.50, p, n);
		ao += aofactor(UV, coord1 * 0.75, p, n);
		ao += aofactor(UV, coord2, p, n);
	}
	ao /= (float(kIterations) * 4.0);
	color = vec4(vec3(1.0 - ao), 1.0);
	color = color * texture(texture2, UV);
}
