#version 400 

uniform mat4 displayProj;
uniform mat4 areaProj;
uniform mat4 model;

layout(location = IGLU_VERTEX)   in vec3 vertex;   // Sends vertex data from models here

uniform vec3 lightPos1, lightPos2, lookAt;

out  float drawThis;

// This is the actual code that is executed.
void main( void )
{ 
	// Approach that works for simple cases.  
	//    -> Here areaProj can be the matrix directly from Hunt & Johnson's paper
	//       [with the last line negated, i.e., not (-1, -1, -1, 1) but (1, 1, 1, -1)]
	//    -> areaProj can also include their proposed simple light matrix L (i.e., AP * L)
	// However, these 3 lines seem to break down when the front of the light (i.e., the
	// direction it points towards) does not face the 1st quadrant.  Either the sign flips,
	// or their proposed light matrix becomes singular (or both).
	/*
	vec4 wsPos   = model * vec4( vertex, 1.0f );
	vec4 projectedPos = areaProj * ( vec4( wsPos.xy, 0.0, 1.0 ) );  
	projectedPos /= projectedPos.w;
	*/
	
	// The above approach applies a gluLookAt()-like matrix to rotate the light around
	//    an "at" point, which defines the "front" side of the light, so that the vertices
	//    are at (1,0,0) and (0,1,0), as expected by the area projection matrix.
	
	// Some preliminaries to compute the canonical space 
	vec3 lightSurf = lightPos2-lightPos1;
	float lenLight = length( lightSurf );
	lightSurf      = normalize( lightSurf );
	vec3 outOfImg  = normalize( cross( lightSurf, lookAt-lightPos1 ) );
	
	// Compute the "forward" direction -- perpendicular to the light
	vec3 forward   = cross( outOfImg, lightSurf );
	
	// In this space, by definition the light runs from (1,0,0) to (0,1,0) and thus
	//    our forward direction goes in the (1,1,0) direction.  We can actually
	//    compute our x and y bases by adding these vectors.
	// We prescale them for the math described below.
	vec4 xVec      = vec4( normalize( forward + lightSurf ), 0.0f ) * 1.414213562 / lenLight;
	vec4 yVec      = vec4( normalize( forward - lightSurf ), 0.0f ) * 1.414213562 / lenLight;

	// Ok, transform this vertex into our new light space coordinate system
	//     First transform into world space, then apply our transform.
	//
	// lsPos = vec4( dot( wsPos-lightPos1, normalize( xVec ) ) * sqrt(2) / length(lightSurf),
	//               dot( wsPos-lightPos1, normalize( yVec ) ) * sqrt(2) / length(lightSurf),
    //               0.0,  // if in 3D, this changes to something similar.
    //               1.0 ) + 
    //               lightSpace-position-of-light1;  // defined for us as (0,1,0,0)
    // 
    // This is a basic projection by dot-products.  The multiplicative factors are to ensure
    //     the measure is consistent.  By definition, our light vertices are at (0,1,0) and (1,0,0)
    //     which means the distance between them is sqrt(2).  In world space, this may not be true;
    //     the light has been scaled by sqrt(2)/length(lightSurf).  We also scale other geometry.      
	vec4 wsPos   = model * vec4( vertex, 1.0f );
	vec4 lsPos   = vec4( dot( wsPos.xyz - lightPos1, xVec.xyz ),
	                     dot( wsPos.xyz - lightPos1, yVec.xyz ),
	                     0.0,
	                     1.0 ) + vec4( 0.0, 1.0, 0.0, 0.0 );

	vec4 projectedPos = areaProj * ( lsPos ); 
	projectedPos /= projectedPos.w;
	

	// This stuff shouldn't change no matter which of the two projection techniques above
	//    are used.
	drawThis     = 1.0;
	if ( (projectedPos.x + projectedPos.y) < 1 )  // Geometry passed the signularity.  Clip it.
		drawThis = -10000.0;                      //    Probably should actually use a clip plane, but
	gl_Position  = displayProj * projectedPos;    //    we'll just tell the frag shader to discard
	
}