#version 400
#extension GL_EXT_gpu_shader4 : enable

#pragma IGLU_ENABLE BLENDING

in vec2 fragCoord;

uniform usampler2D voxels0, voxels1, voxels2, voxels3;

uniform float      intensity;
uniform vec4       esLightPos;
uniform float      maxAngle_L_V, minAngle_L_V;
uniform float      tan_fovy_2, aspect;

layout(location = 0) out vec4 outColor;


// Takes a few important vectors (eye-to-light, eye-to-frag) and computes epipolar coords
vec2 ComputeEpipolarVoxelCoordinates( vec3 EtoL, vec3 EtoF )
{
	// Compute the x-coordinate in the epipoloar map
	
	float eyeAngle = clamp( dot(EtoF,EtoL), -1.0f, 1.0f );
	float epiNDC_xCoord = (acos( eyeAngle ) - minAngle_L_V) / (maxAngle_L_V - minAngle_L_V);

	// Find a ortho normal basis, used to compute the epipolar angle
	vec3 up      = normalize( cross( EtoL, vec3(0,0,-1) ) );
	vec3 forward = cross( up, EtoL );
	vec2 angle = vec2( dot( forward, EtoF ), dot( up, EtoF ) );
	float epiPlaneAngle = atan( angle.y, angle.x );

	float epiNDC_yCoord = 0.5 * clamp( epiPlaneAngle/3.14159265358979, -1.0, 1.0 ) + 0.5;
	
	return vec2( 1.0-epiNDC_xCoord, epiNDC_yCoord );
}

// Takes a 2D location in screen space and returns an eye-space direction
vec3 DirectionFromPos( vec2 screenPos )
{
	vec3 dir;
	dir.x = tan_fovy_2 * ( 2.0*screenPos.x - 1.0 );
	dir.y = tan_fovy_2 * ( 1.0 - 2.0*screenPos.y );
	dir.x *= aspect;
	dir.z = -1;
	return normalize( dir );
}

void main(void)
{		
	// Compute a few important vectors based on light position and current frag onscreen
	vec3 EtoL = normalize( esLightPos.xyz );
	vec3 EtoF = DirectionFromPos( fragCoord.xy );
	
	// Now identify and look up the correct sample in the epipolar voxel buffer
	vec2 epiVoxelCoord = ComputeEpipolarVoxelCoordinates( EtoL, EtoF );
	
	// Count the number of shadowed voxels along the eye ray
	uvec4 bitsInShadow = uvec4( 0u );
	bitsInShadow += bitCount( texture( voxels0, epiVoxelCoord ) );
	bitsInShadow += bitCount( texture( voxels1, epiVoxelCoord ) );
	bitsInShadow += bitCount( texture( voxels2, epiVoxelCoord ) );
	bitsInShadow += bitCount( texture( voxels3, epiVoxelCoord ) );
	
	// Compute heat/color intenstiy to use for visualization
	float heat = intensity * float( bitsInShadow.x + bitsInShadow.y + bitsInShadow.z + bitsInShadow.w ) / 512.0;
	
	// Write the color out to the framebuffer
	outColor = vec4( 1.0, 1.0, 0.0, heat );
}	
