#version 400

// Tells the OpenGL/IGLU program to enable the depth test when using this shader
#pragma IGLU_ENABLE  DEPTH_TEST

// Information from the vertex shader about the eye-space location
//    of this fragment we're working on
in vec4 esFragPos;
in vec4 esFragNormal;
in float fragMatlID;

// Where to store the color we compute
out vec4 result;

// Asked to use a Lambertian shading scheme?
uniform float useLambertian;  

// Bias for shadow map
uniform float sMapBias;

// Location of the light, relative to the eye
uniform vec4 esLightPos;     

// Information about the near & far planes for the shadow map's projection
uniform float nearDist, farDist;

// Our shadow map texture.  Layer 0 = positive z-hemisphere, layer 1 = negative
uniform sampler2DArrayShadow shadowTex;  

// The buffer containing our material information
uniform samplerBuffer  matlInfoTex;

// A function to query our paraboloid shadow map, based on an light and
//     fragment position (both must be in same coordinate space)
float IsIlluminatedByOmniLight( vec3 lightPos, vec3 fragPos )
{
	vec3 toVert = fragPos - lightPos;
	float dist = length( toVert );
	toVert = normalize( toVert );
	
	// The [0..1] z-value to compare against the shadow map
	float z_persp = 0.5 * ((nearDist+farDist)*-dist+(2*nearDist*farDist))/(dist*(nearDist-farDist)) + 0.5;
	
	// Compute the coordinates in the + & - hemi-paraboloids
	vec2 posMap = vec2(toVert.xy)/(toVert.z+1);
	vec2 negMap = vec2(toVert.xy)/(toVert.z-1);
	
	// Select if we're using the + or - hemi-paraboloid.
	bool usePos = dot(posMap,posMap) < dot(negMap,negMap);
	
	// Compute the actual [-1..1] position in the shadow map we need to compare against
	//posMap.x = 0.5*posMap.x - 0.5;
	//negMap.x = 0.5*negMap.x + 0.5;
	
	// Now map this into texture space (i.e., [0..1])
	posMap = 0.5*posMap + 0.5;
	negMap = 0.5*negMap + 0.5;
	
	// Lookup the value
	return texture(shadowTex, vec4( usePos ? vec3(posMap, 0) : vec3(negMap, 1), z_persp+sMapBias ));
}


// This is the actual code that is executed.
void main( void )
{	
	// Look up data about this particular fragment's material
	int matlIdx     = 4 * int(fragMatlID+0.5);
	vec4 matlInfo   = texelFetch( matlInfoTex, matlIdx+1 );  // Get diffuse color
	
	// Query the shadow map to determine if we're lit
	float isLit     = IsIlluminatedByOmniLight( esLightPos.xyz, esFragPos.xyz );
	
	// Find simple vectors for basic shading
	vec3 toLight = normalize( esLightPos.xyz - esFragPos.xyz);
	vec3 toEye   = normalize( -esFragPos.xyz );
	
	// Figure out the Lambertian color (if shadowed, set to 0)
	vec3 lambert = isLit * useLambertian * max( 0.0f, dot( normalize(esFragNormal.xyz), toLight ) ) * matlInfo.xyz;
	
	// Figure out the ambient color (if shadowed, set to 0)
	vec3 ambient = isLit * (1.0-useLambertian) * matlInfo.xyz;
	
	// The ambient & lambertian terms we computed above are mutually
	//    independent, so we simply add them together, giving us a correct
	//    answer, no matter which display approach the user has chosen.
	result = vec4( lambert + ambient, 1.0f );
}