#version 330 core

in vec2 UV;
in vec2 ray;
uniform float timestamp;
uniform mat4 viewProjectionInverseMatrix;  // inv(proj * view)
uniform mat4 depthMVP;
uniform vec3 eye;
uniform sampler2D target;      // Target colors
uniform sampler2D targetdepth; // target depth buffer
uniform sampler2D lightdepth;  // Depth buffer from light p.o.v.

const int Nsamples = 128;

out vec4 ocolor;

vec3 position() {
  vec4 clipSpaceLocation;
  clipSpaceLocation.xy = UV * 2.0 - 1.0;
  clipSpaceLocation.z = texture(targetdepth, UV).r * 2.0 - 1.0;
  clipSpaceLocation.w = 1.0f;
  vec4 homogenousLocation = viewProjectionInverseMatrix * clipSpaceLocation;
  return homogenousLocation.xyz / homogenousLocation.w;
}

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

float occlusion(vec3 pos) {
	vec4 candidate = depthMVP * vec4(pos, 1.0);
	return 1.0 * float(texture(lightdepth, candidate.xy * .5 + 0.5).r < candidate.z * .5 + .5);
}

void main() {
	vec3 targetPos = position();
	vec3 source = eye;
	vec3 ray = targetPos - source;

	// Sample along the ray
	float of = 0.0; // occlusion factor
	vec3 prevpos = vec3(0.0);
	for (int i = 0; i < Nsamples; i++) {
		vec3 pos = source + rand(UV.yx + prevpos.xz + vec2(UV.x + .001 * timestamp, 0.1 + float(i))) * ray;
		prevpos = pos;
		of += occlusion(pos);
	}

//texture(target, UV).xyz
	float shadow = 1.0 - of / float(Nsamples);
	ocolor = vec4(vec3(shadow * shadow * shadow * shadow), 1.0); // * texture(target, UV);
	ocolor.xyz = ocolor.xyz * texture(target, UV).xyz;
	//ocolor = texture(target, UV);
}
