uniform float4x4 modelViewProj : state.matrix.mvp;

//Warning: for CG_PROFILE_ARBFP1 we cannot use more than 2 lights ( probably not enough register count!!! )
#define MAX_LIGHT_COUNT 2



float3 getReflectedVector(float3 normalizedVector, float3 normalizedNormal)
{
	return normalizedNormal * 2.0 * dot(normalizedNormal, -normalizedVector) + normalizedVector;
}

float falloffFactor(float3 position, float3 lightPosition, float falloff )
{
	//to calculate falloff we use only falloff.x value and the formula below

	float dis =distance( position, lightPosition );
	float attenuation = pow( dis, falloff );
	
	return  1.0  / attenuation;
}

float getAngle(float3 vector1Normalized, float3 vector2Normalized)
{
	return  acos( dot( vector1Normalized, vector2Normalized ) );
}

float spotFactorCosFalloff(float angle)
{
	//TODO neni potreba pocitat znovu cos...staci nepocitat acos!!!
	
	return cos(angle);
}

float spotFactor(float angle, float beamWidth, float cutOffAngle)
{
	//formula according to VRML 97 spec
	
	if (angle >= cutOffAngle)
	{
        return 0.0;
	}
	
    if (angle <= beamWidth)
	{
        return 1.0;
	}
	
	return (angle - cutOffAngle) / (beamWidth - cutOffAngle);
}

float getCosAngle(float3 Nvector1, float3 Nvector2)
{
	return abs(dot( Nvector1, Nvector2 ));
}

float phongBRDF(float Pd, float Ps, float cosAngle, float exponent)
{
	//formula according to modified Phong reflectance model
	//Pd*(1/DT_PI) + Ps* ( (n+2)/2PI ) * (cos a)^n
	float one_div_PI=0.31830988618379067154;
	
	return Pd * one_div_PI + Ps * ( exponent+2 ) * 0.5 * one_div_PI *  pow( cosAngle, exponent );
}

float directIllumination(float cosAngleNL, float radiance, float Pd, float Ps, float cosAngleRE, float exponent)
{
	//cosAngleNL = kosinus uhlu mezi svetelnym paprskem a normalou povrchu
	//cosAngleRE = kosinus uhlu mezi idealnim odrazem a pozorovatelem
	
	return radiance* phongBRDF(Pd, Ps, cosAngleRE, exponent)* cosAngleNL;
}


struct VertexShaderOut 
{
	float4 oPosition : POSITION;
	float2 oTexCoord0: TEXCOORD0;
	float3 objectPos : TEXCOORD1;
	float3 oNormal   : TEXCOORD2;
};


VertexShaderOut GLphongLightingVs(float4 position : POSITION, float4 normal   : NORMAL, float2 texCoord0 : TEXCOORD0, uniform float4x4 modelMatrix )
{
	VertexShaderOut outData;
	outData.oPosition = mul( modelViewProj, position );
	
	//prevod pozice a normaly z Model space do World space
	outData.objectPos=mul(modelMatrix, position).xyz;

	normal.w = 0.0;	//vector, not a point
	outData.oNormal = mul(modelMatrix, normal).xyz;
	outData.oTexCoord0= texCoord0;
	
	return outData;
}

struct FragmentShaderOut 
{
	float4 color : COLOR;
};

FragmentShaderOut GLphongLightingFs(
	float2 texCoord0 : TEXCOORD0, 
	float3 position  : TEXCOORD1, 
	float3 normal    : TEXCOORD2, 
	uniform sampler2D texture0  : TEXUNIT0,
	uniform float3 radiance[ MAX_LIGHT_COUNT ], 
	uniform float3 lightPosition[ MAX_LIGHT_COUNT ], 
	uniform float3 eyePosition,
	uniform float3 lightDirection[ MAX_LIGHT_COUNT ],
	uniform float beamWidth[ MAX_LIGHT_COUNT ], 
	uniform float cutOffAngle[ MAX_LIGHT_COUNT ],
	uniform float3 Pd, 
	uniform float3 Ps, 
	uniform float  exponent,
	uniform float3 Pa,
	uniform float falloff[ MAX_LIGHT_COUNT ], 
	uniform float spotType[ MAX_LIGHT_COUNT ], 
	uniform float directional[ MAX_LIGHT_COUNT ], 
	uniform float fillLight[ MAX_LIGHT_COUNT ], 
	uniform float lightCount,
	uniform float useTexture)
{


	FragmentShaderOut outData;

	outData.color.rgb = float3(1,0,0);
	float3 finalRadiance = Pa;
	float3 partialRadiance = float3(0,0,0);
	float falloffVal = 1.0;
	float3 directionalVal = float3(1,1,1);
	float spot = 1.0;
 
	float3 normalNormalized = normalize(normal);
	float3 eyeVecNormalized = normalize(eyePosition - position);

	for ( int i=0; i<MAX_LIGHT_COUNT; ++i)	// CG_PROFILE_FP40 can iterate only over at compilation time known number !!!
	{
		if ( i < round(lightCount) ) //HACK to solve CG_PROFILE_FP40 FOR-CYKLE iterations limits
		{
			float3 lightVecNormalized = normalize(lightPosition[i] - position);
			float3 reflVecNormalized = normalize(getReflectedVector(lightVecNormalized, normalNormalized));
	
			float cosNL = getCosAngle(normalNormalized, lightVecNormalized);
			float cosRE = getCosAngle(eyeVecNormalized, reflVecNormalized );
		
			if ( dot(normalNormalized, lightVecNormalized)<0.0 )
			{
				cosNL=0.0;
			}
				
			partialRadiance.r	= directIllumination(cosNL, radiance[i].r, Pd.r, Ps.r, cosRE, exponent);
			partialRadiance.g	= directIllumination(cosNL, radiance[i].g, Pd.g, Ps.g, cosRE, exponent);
			partialRadiance.b	= directIllumination(cosNL, radiance[i].b, Pd.b, Ps.b, cosRE, exponent);
		
			spot=1.0;
		
		
			falloffVal = falloffFactor(position, lightPosition[i], falloff[i] );

			if (round(spotType[i])==1)	//use vrml spotlight?
			{
				float angleNL= getAngle(lightVecNormalized, normalize(lightDirection[i]));
				spot=spotFactor( angleNL, beamWidth[i] , cutOffAngle[i] );
			}
			else if  (round(spotType[i])==2)	//use basic spotlight?
			{
				spot = dot( lightVecNormalized, -normalize(lightDirection[i]) );

				if ( spot > 0 )
				{
					spot = pow ( spot, directional[i] );
				}
				else
				{
					spot = 0;
				}
			
			}
			finalRadiance += partialRadiance * ( spot * falloffVal );	
		}
		else
		{
			break;	//no more lights -> jump from for-cykle
		}
	}

	if ( round(useTexture) == 1)
	{
		//use texture
		outData.color = float4(   finalRadiance * tex2D(texture0, texCoord0), 1 );
	}
	else
	{
		//dont use texture
		outData.color = float4( finalRadiance, 1 );
	}
	
	return outData;
}
