//!HLSL

#include "ShadowHelpers.hlsl"
#include "fogHelper.hlsl"

// figure out how many textures we are blending
#if defined(FOUR_TEXTURES)
#define NUM_TEXTURES 4
#elif defined(THREE_TEXTURES)
#define NUM_TEXTURES 3
#elif defined(TWO_TEXTURES)
#define NUM_TEXTURES 2
#else
#define NUM_TEXTURES 1
#endif

#ifdef MATRIX_PALETTE
#define MAX_TRANSFORM_COUNT 48
#endif

#ifdef COLORIZE
// first value in ShipColors is opaque white
#define COLOR_COUNT 6
#endif

// single-channel spherical harmonics
float harmonics1 (
      float L00, float L1_1, float L10, float L11, 
      float L2_2, float L2_1, float L20, float L21, float L22,
      float3 n)
{
	const float c1 = 0.429043 ;
	const float c2 = 0.511664 ;
	const float c3 = 0.743125 ;
	const float c4 = 0.886227 ;
	const float c5 = 0.247708 ;
	
	float3 n2 = n*n;
	float xy = n.x*n.y;
	float yz = n.y*n.z;
	float xz = n.x*n.z;
  
	return c1*L22*(n2.x-n2.y) + c3*L20*n2.z + c4*L00 - c5*L20 
            + 2*c1*(L2_2*xy + L21*xz + L2_1*yz) 
            + 2*c2*(L11*n.x+L1_1*n.y+L10*n.z);
}

// this uses spherical harmonic coefficients derived from the blue channel of an outdoor cubemap to represent an approximation of sky hemisphere lighting. the multiplication by 0.45 normalizes the result to the 0..1 range.
float3 exampleHarmonicsBlue(float3 n)
{
	return harmonics1((1.25139f),
		(0.984037f),
		(0.0663701f),
		(0.195149f),
		(0.0846845f),
		(0.0708858f),
		(-0.30903f),
		(0.0420651f),
		(-0.154664f),
		n)*0.45;
}

// -----------------------------------------------------------------------------
// Vertex Shader
// -----------------------------------------------------------------------------
struct VSOutput
{
	float4 _position	: POSITION;
	float4 _color		: COLOR0;
	float4 _uvShadow	: TEXCOORD0;
	float4 _fogValue    : COLOR1;

#ifdef COLORIZE
	float3 _pieceColor  : TEXCOORD1;
#endif

	float2 _uv0			: TEXCOORD2;

#if NUM_TEXTURES > 1
	float2 _uv1			: TEXCOORD3;
#if NUM_TEXTURES > 2
	float2 _uv2			: TEXCOORD4;
#if NUM_TEXTURES > 3
	float2 _uv3         : TEXCOORD5;
#endif
#endif
#endif

};

VSOutput VSMain(float4 vPosition : POSITION,
	            float3 vNormal : NORMAL,
	            float2 vUV0 : TEXCOORD0,
#if NUM_TEXTURES > 1
	            float2 vUV1 : TEXCOORD1,
#if NUM_TEXTURES > 2
	            float2 vUV2 : TEXCOORD2,
#if NUM_TEXTURES > 3
		        float2 vUV3 : TEXCOORD3,
#endif
#endif
#endif

#ifdef MATRIX_PALETTE

#if NUM_TEXTURES == 1
		        float2 vBlendInfo : TEXCOORD1,
#elif NUM_TEXTURES == 2
		        float2 vBlendInfo : TEXCOORD2,
#elif NUM_TEXTURES == 3
		        float2 vBlendInfo : TEXCOORD3,
#else
		        float2 vBlendInfo : TEXCOORD4,
#endif

				uniform float4x4 blendTransforms[MAX_TRANSFORM_COUNT],
#endif

#ifdef COLORIZE
			    float4 vColor : COLOR,
				uniform float4 ShipColors[COLOR_COUNT],
#endif

		        uniform float4x4 modelViewProjection,
		        uniform float4x4 modelWorld,
		        uniform float4x4 shadowTextureWorldTransform,

		        uniform float4 sunColor,
		        uniform float3 sunDirectionObject,

				uniform float3 pointLightDiffuseColors[POINT_LIGHT_COUNT],
				uniform float3 pointLightPositions[POINT_LIGHT_COUNT],
				uniform float3 pointLightAttenuations[POINT_LIGHT_COUNT],		
				uniform float pointLightCount,

				uniform float4 fogColor,
				uniform float2 fogParams
 #ifdef OCEANDEPTH
 				,
 				uniform float3 oceanDepthRange,
				uniform float4 oceanDepthColor
#endif
				,
				uniform float  id


					)  
{
	VSOutput ret;

	// position
	//
	float4 vObjectPos;
#ifdef MATRIX_PALETTE
	int index = vBlendInfo.x;
	vObjectPos = mul(blendTransforms[index], vPosition);
#else

	vObjectPos = vPosition;

#endif

	ret._position = mul(modelViewProjection, vObjectPos);

	// normal
	//
	float3 vObjectNormal;

#ifdef MATRIX_PALETTE

	vObjectNormal = mul((float3x3)blendTransforms[index], vNormal); 

#else	

	vObjectNormal = vNormal;

#endif
	vObjectNormal = normalize(vObjectNormal);

	// colorizing
	//
#ifdef COLORIZE

	ret._pieceColor.xyz = ShipColors[round(vColor.w*255)].xyz;

#endif

	// lighting
	//
	float fLightContrib = saturate(dot(vObjectNormal, sunDirectionObject));

	float3 vBattLightColor = calcBatLightColor( vObjectPos.xyz, vObjectNormal, pointLightDiffuseColors, 
											   pointLightPositions, pointLightAttenuations, pointLightCount );

	ret._color.xyz = vBattLightColor + sunColor.xyz*fLightContrib;
	ret._color.w = exampleHarmonicsBlue(vObjectNormal);

	// uvs
	//
	ret._uv0 = vUV0;
#if NUM_TEXTURES > 1
	ret._uv1 = vUV1;
#if NUM_TEXTURES > 2
	ret._uv2 = vUV2;
#if NUM_TEXTURES > 3
	ret._uv3 = vUV3;
#endif
#endif
#endif

	// shadow uv
	//

	float4 vWorldPos = mul (modelWorld, vObjectPos);

	ret._uvShadow.xyz = calcShadowUVs(shadowTextureWorldTransform, vWorldPos);
	ret._uvShadow.w = FiveBitID( id );

	// fog
	//
#ifdef OCEANDEPTH
 	ret._fogValue = getFogValueWorldSpace(fogColor, fogParams,
 									ret._position, vWorldPos, oceanDepthRange, oceanDepthColor);
#else
 	ret._fogValue = getFogValue(fogColor, fogParams,
 								ret._position);
#endif 
	return ret;
}

// -----------------------------------------------------------------------------
// Pixel Shader
// -----------------------------------------------------------------------------

float4 PSMain(VSOutput vertex,
						  uniform sampler2D samplerDiffuse0,
#if NUM_TEXTURES > 1
						  uniform sampler2D samplerDiffuse1,
#if NUM_TEXTURES > 2
						  uniform sampler2D samplerDiffuse2,
#if NUM_TEXTURES > 3
						  uniform sampler2D samplerDiffuse3,
#endif
#endif
#endif
						  uniform sampler2D samplerShadow,
						  uniform float3 sunAmbient,
						  uniform float2 shadowSampleScale
						  ) : COLOR0
{
	// modulate the layered textures
	//
	float4 vFinalColor = tex2D(samplerDiffuse0, vertex._uv0);

#if NUM_TEXTURES > 1
	vFinalColor *= tex2D(samplerDiffuse1, vertex._uv1);
#if NUM_TEXTURES > 2
	vFinalColor *= tex2D(samplerDiffuse2, vertex._uv2);
#if NUM_TEXTURES > 3
	vFinalColor *= tex2D(samplerDiffuse3, vertex._uv3);
#endif
#endif
#endif

#ifdef COLORIZE

	vFinalColor.xyz *= vertex._pieceColor.xyz;

#endif

	// light it
	//
	float fShadowed = 1.0 - isShadowedPref( vertex._uvShadow, samplerShadow, vertex._uvShadow.z, shadowSampleScale, vertex._uvShadow.w );
	float ambientFactor = vertex._color.w*1.4; //increase the ambient slightly so the resulting image's intensity roughly matches what it was when we had constant ambient (so artists don't have to readjust ambient light values)
	float3 vLightColor = (fShadowed * vertex._color.xyz + sunAmbient*ambientFactor);

	vFinalColor.xyz *= vLightColor;

	// fog it
	//
	vFinalColor = getFogColor(vFinalColor, vertex._fogValue);
		

	return vFinalColor;
}
