#version 150 core

in vec2 ioFragTexCoords;

out vec3 outColor;

uniform sampler2D uPositions;
uniform sampler2D uNormals;
uniform sampler2D uNoise;

uniform float uRadius;
uniform float uBias;
uniform float uPower;
uniform int uSampleCount;
uniform vec3 uSamples[64];
uniform mat4 uProjection;

void main() {
	vec2 noise_scale = textureSize(uPositions, 0) / 2.0;

	vec3 position = texture(uPositions, ioFragTexCoords).xyz;
	vec3 normal = normalize(texture(uNormals, ioFragTexCoords)).rgb;
	vec3 random_vector = normalize(texture(uNoise, ioFragTexCoords * noise_scale).xyz);

	vec3 tangent = normalize(random_vector - normal * dot(random_vector, normal));
	vec3 bitangent = cross(normal, tangent);
	mat3 TBN = mat3 (tangent, bitangent, normal);

	float occlusion = 0.0;
	for (int i = 0; i < uSampleCount; ++i) {
		vec3 sample = TBN * uSamples[i];
		sample = position + sample * uRadius;

		vec4 offset = vec4(sample, 1.0);
		offset = uProjection * offset;
		offset.xyz /= offset.w;
		offset.xyz = offset.xyz * 0.5 + 0.5;
		float sample_depth = texture(uPositions, offset.xy).z;

		float range_check = smoothstep(0.0, 1.0, uRadius / abs(position.z - sample_depth));
		occlusion += (sample_depth >= sample.z + uBias ? 1.0 : 0.0) * range_check; 
	}

	occlusion = pow(1.0 - (occlusion / uSampleCount), uPower);
	outColor = vec3(occlusion);	
}
