uniform sampler greyArea		: register(s0);
uniform sampler splat0			: register(s1);
uniform sampler splat1			: register(s2);
uniform sampler diffusemap[4];
uniform sampler patch[4];
uniform sampler horizon;
uniform sampler shadow;

static const float LOS_THRESHOLD = 0.75f;
static const float LOS_DARKENING = 0.60f;
static const float SHADOW_FACTOR = 0.90f;

extern uniform float worldSize;
extern uniform float sunElevation;
extern uniform float4 losTint; 

struct VS_INPUT 
{
	float2 uv0							: TEXCOORD0;
	float4 shadowUV						: TEXCOORD1;
	float2 terrainUV					: TEXCOORD2;
};

float4 main_ps( VS_INPUT input ) : COLOR0
{
	float4 outColor = float4(0, 0, 0, 0);
	float4 tempColor = float4(0, 0, 0, 0);

	float4 splatValues0 = tex2D(splat0, input.terrainUV);
	float4 splatValues1 = tex2D(splat1, input.terrainUV);
		
	float fSum =	splatValues0.a + splatValues0.r + splatValues0.g + splatValues0.b +
					splatValues1.a + splatValues1.r + splatValues1.g + splatValues1.b;
	
	// the individual color channels are used to store the blending factors ("weight") of each texture		
	// they should always add up to 1.f
	outColor += tex2D( diffusemap[0], input.uv0 ) * splatValues0.a/fSum ;
	outColor += tex2D( diffusemap[1], input.uv0 ) * splatValues0.b/fSum ;
	outColor += tex2D( diffusemap[2], input.uv0 ) * splatValues0.g/fSum ;
	outColor += tex2D( diffusemap[3], input.uv0 ) * splatValues0.r/fSum ;

	outColor += tex2D( patch[0], input.uv0 ) * splatValues1.a/fSum ;
	outColor += tex2D( patch[1], input.uv0 ) * splatValues1.b/fSum ;
	outColor += tex2D( patch[2], input.uv0 ) * splatValues1.g/fSum ;
	outColor += tex2D( patch[3], input.uv0 ) * splatValues1.r/fSum ;
	
	float offset = 1/worldSize;
	
	float blockSide = 3.0f;
	
	// Ashwin please review : rakehsj
	float fOneTileOffset = 4*offset;
	
	float4 tempGrey = float4( 0.0f, 0.0f, 0.0f, 0.0f );
	float2 tempGreyAreaUV = float2( input.terrainUV.x-fOneTileOffset-blockSide*offset, input.terrainUV.y-blockSide*offset );

	for( int i = 0; i < blockSide; i ++ )
		for(int j = 0; j < blockSide; j ++ )
			tempGrey += tex2D( greyArea, float2(tempGreyAreaUV.x + j*offset, tempGreyAreaUV.y + i*offset) );

	tempGrey /= blockSide*blockSide;

#ifndef FUZZY_LOS 	
	if( tempGrey.r < LOS_THRESHOLD )
	{
		outColor.rgb *= losTint.rgb;	
	}
#else
	// tempGrey:0.5->1.0	
	outColor *= lerp( 2*losTint-1, 1, tempGrey.r);
#endif

	float fTheta = tex2D( horizon, input.terrainUV ).r;	// horizon elevation

	// this factor does something similar to Ambient Occlusion
	float fDeltaElevation = fTheta - sunElevation;
	outColor *= lerp( 1.0, 0.4, 2*saturate(fDeltaElevation) );
	
	// to reduce shadow doubling , we take closer spaced samples
	offset /= 3;
	
	float fHCenter = fTheta;
	
	float4 fHSamples = float4(
						tex2D( horizon, input.terrainUV.xy + float2(-offset,0) ).r,
						tex2D( horizon, input.terrainUV.xy + float2(offset, 0) ).r,
						tex2D( horizon, input.terrainUV.xy + float2(0,-offset) ).r,
						tex2D( horizon, input.terrainUV.xy + float2(0, offset) ).r	);

	float fVisibility = ( fHCenter > sunElevation ) ? SHADOW_FACTOR : 1.f;

	fVisibility += ( fHSamples.r > sunElevation ) ? SHADOW_FACTOR : 1.f;
	fVisibility += ( fHSamples.g > sunElevation ) ? SHADOW_FACTOR : 1.f;
	fVisibility += ( fHSamples.b > sunElevation ) ? SHADOW_FACTOR : 1.f;
	fVisibility += ( fHSamples.a > sunElevation ) ? SHADOW_FACTOR : 1.f;
	   
	fVisibility /= 5.0f;
	
	return outColor * fVisibility;
}
