#version 130
#define MAX_LIGHTS 8

varying vec3 lightDir[MAX_LIGHTS];
varying vec3 lightVec[MAX_LIGHTS];
varying vec3 eyeVec2;
varying vec4 shadowCoord[5];
varying vec3 normal, eyeVec;

uniform int  numLights;
uniform int  numSpotLights;
uniform bool textureMapped;
uniform bool normalMapped;
uniform bool specularMapped;
uniform bool lit;

uniform float textureMapScale;
uniform float normalMapScale;
uniform float specularMapScale;

uniform float specularity;
uniform float specularFactor;
uniform float normalFactor;

uniform sampler2D		textureMap;
uniform sampler2D		normalMap;
uniform sampler2D		specularMap;
uniform sampler2DShadow shadowMap[5];

float lookup(vec2 offset, int index)
{
	return shadow2DProj(shadowMap[index], vec4(shadowCoord[index].xy + offset * (1.0/4096.0) * shadowCoord[index].w, shadowCoord[index].z, shadowCoord[index].w)).r;
}

void main (void)
{
  if (!lit)
  {
	gl_FragColor = gl_FrontMaterial.diffuse;
	return;
  }

  float lambertTerm;
  float specular;
  
  vec4  final_color = vec4(0.0, 0.0, 0.0, 1.0);
  vec4  spec_color  = vec4(0.0, 0.0, 0.0, 1.0);
  vec3  normalVec   = normalize(normal);
  
  float shadow;
  float ambient = 0.25;
  int i;
  for (i=0; i < numLights; i++)
  {
	if (i < numSpotLights )
	{
	  vec2 shadowCoordWdivide = shadowCoord[i].st / shadowCoord[i].w;
	  shadow = 0.0;

	  if (  shadowCoordWdivide.s < 0.0 || shadowCoordWdivide.s > 1.0 ||
 			shadowCoordWdivide.t < 0.0 || shadowCoordWdivide.t > 1.0 || shadowCoord[i].w < 0.0 )
	   shadow = 0.0;
	  else
	  {
		vec2 offset = mod(gl_FragCoord.xy * 0.5, 1.0);
		offset.y += offset.x;
		if (offset.y > 1.0) offset.y = 0.0;

		shadow = (  lookup(offset + vec2(-1.5, 0.5), i) +
					lookup(offset + vec2( 0.5, 0.5), i) +
					lookup(offset + vec2(-1.5,-1.5), i) +
					lookup(offset + vec2( 0.5,-1.5), i) ) * 0.25;   
	/*	
		float x,y;			
		for (y = -1.5; y <= 1.5; y += 1.0)
		for (x = -1.5; x <= 1.5; x += 1.0)
			shadow += lookup(offset + vec2(x, y));

		shadow /= 16.0;
	*/				
	  }
  	  shadow *= max(1.0 - pow( length((shadowCoordWdivide.st - .5)*2.0), 4.0), 0.0);
	}
  
    vec3 L = normalize( lightDir[i] );
	vec3 lightVecNor = normalize( lightVec[i] );

	if ( normalMapped )
	{
		vec3 bump = 2.0 * texture2D(normalMap, gl_TexCoord[0].st * normalMapScale).rgb - 1.0;
		bump.xy *= normalFactor;
		bump = normalize(bump);
		lambertTerm = max(dot(lightVecNor, bump), 0.0);

		specular = pow(max(dot(reflect(-lightVecNor, bump), normalize(eyeVec2)), 0.0), specularity);
		
		if ( specularMapped )
		{
			specular *= texture2D(specularMap, gl_TexCoord[0].st * specularMapScale).r;
		}
		else
		{
			vec3 color = texture2D(textureMap, gl_TexCoord[0].st * textureMapScale).rgb;
			specular *= min(color.r, min(color.g,color.b));
		}
	}
	else
	{
		lambertTerm = max(dot(normalVec,L),0.0);

		specular = pow(max(dot(reflect(-L, normalVec ), normalize(eyeVec)), 0.0), specularity);

		if ( specularMapped )
		{
			specular *= texture2D(specularMap, gl_TexCoord[0].st * specularMapScale).r;
		}
	}

	float length2 = length(lightDir[i]);
	length2 *= length2;
	float att = 1.0/(1.0 + length2*0.000005);
	
	if (i < numSpotLights)
	{
		spec_color  += gl_LightSource[i].specular * specular * specularFactor * shadow;
		final_color += gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse * lambertTerm * att * shadow;
	}
	else
	{
		spec_color  += gl_LightSource[i].specular * specular * specularFactor;
		final_color += gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse * lambertTerm * att;
	}
	final_color += gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse * .01 * att;
  }
  
  //final_color += gl_FrontMaterial.diffuse * .25;
  
  if (textureMapped)
  	gl_FragColor = final_color * texture2D(textureMap,gl_TexCoord[0].st * textureMapScale) + spec_color;
  else
  	gl_FragColor = final_color + spec_color;
}