#include "inout.hlsl"

// MATERIAL_TEXTUREMIXING_NORMAL	= 0
// MATERIAL_TEXTUREMIXING_ADD		= 1
// MATERIAL_TEXTUREMIXING_SUBTRACT	= 2
// MATERIAL_TEXTUREMIXING_MULTIPLY	= 3

#define NUM_LIGHTS 8
#define LIGHT_DIRECTIONAL	= 1;
#define LIGHT_POINT			= 2;
#define LIGHT_SPOT			= 3;

Texture2D ShaderTexture[5];//		: register(t0);
TextureCube ShaderCubeTexture;//	: register(t1);
SamplerState SampleTypeWrap		: register(s0);
SamplerState SampleTypeClamp	: register(s1);

cbuffer MaterialBuffer
{
	float	CC_fBrightness;
	int		CC_bHasTexture;
	int		CC_lTextureMixing;
	float	CC_fTextureStrength;

	float4	CS_colColor;
	int		CS_bHas;
	float	CS_fBrightness;
	float	CS_fPower;

	int		CN_bHas;

	int		CT_bHas;
	float	CT_fBrightness;

	int		CL_bHas;

	int		CE_bHas;

	int		CR_bHas;
	float4	Mat_Padding;
};

cbuffer LightBuffer
{
	float4	LIGHT_AmbientColor;
	float	LIGHT_AmbientStrength;
	float3	LIGHT_AmbientPadding;

	int		LIGHT_Count;
	float3	LIGHT_CountPadding;

	float4	LIGHT_Type[NUM_LIGHTS];
	float4	LIGHT_Position[NUM_LIGHTS];
	float4	LIGHT_Color[NUM_LIGHTS];
	float4	LIGHT_Intensity[NUM_LIGHTS];
	float4	LIGHT_Direction[NUM_LIGHTS];
	float4	LIGHT_AttRange[NUM_LIGHTS];
	float4	LIGHT_Cone[NUM_LIGHTS];

	bool	LIGHT_bUseShadow;
	float3	LIGHT_bUseShadowPadding;
};

float4 c4e_PS(PIT_C4E input) : SV_TARGET
{
	float4 finalColor;
	float4 texColor;
	float4 lumColor;
	float4 normalColor;
	float3 normalNormal;
	float3 lightDir;
	float  lightStrength;
	float4 litColor;
	float3 reflection;
	float4 specular;

	float  bias;
	float2 projectTexCoord;
	float  depthValue;
	float  lightDepthValue;

	if (!CC_bHasTexture)
	{
		finalColor = input.color * CC_fBrightness;

		if (CN_bHas)
		{
			normalColor = ShaderTexture[1].Sample(SampleTypeWrap, input.tex);
			normalColor = (normalColor * 2.0f) - 1.0f;
			normalNormal = input.normal + normalColor.x * input.tangent + normalColor.y * input.binormal;
			normalNormal = normalize(normalNormal);
		}

	}
	else
	{
		texColor = ShaderTexture[0].Sample(SampleTypeWrap, input.tex);

		if (CN_bHas)
		{
			normalColor = ShaderTexture[1].Sample(SampleTypeWrap, input.tex);
			normalColor = (normalColor * 2.0f) - 1.0f;
			normalNormal = input.normal + normalColor.x * input.tangent + normalColor.y * input.binormal;
			normalNormal = normalize(normalNormal);
		}

		[forcecase]
		switch (CC_lTextureMixing)
		{
			case 0:
			{
				finalColor = texColor * CC_fTextureStrength + input.color * (1.0 - CC_fTextureStrength);
			}
			break;
			case 1:
			{
				finalColor = texColor * CC_fTextureStrength + input.color;
			}
			break;
			case 2:
			{
				finalColor = texColor * CC_fTextureStrength - input.color;
			}
			break;
			case 3:
			{
				finalColor = texColor * input.color;
			}
			break;
		}
	}

	litColor = float4(0.0f, 0.0f, 0.0f, 0.0f);
	specular = float4(0.0f, 0.0f, 0.0f, 0.0f);
	for (int i = 0; i < LIGHT_Count; i++)
	{
		lightDir = -LIGHT_Direction[i];

		if (LIGHT_Type[i].w == 1.0f)
		{
			if (!CN_bHas)
			{
				lightStrength = saturate(dot(input.normal, lightDir));
			}
			else
			{
				lightStrength = saturate(dot(normalNormal, lightDir));
			}

			if (lightStrength > 0.0f)
			{
				litColor += (LIGHT_Color[i] * LIGHT_Intensity[i].w * lightStrength);
				litColor = saturate(litColor);

				if (CS_bHas)
				{
					reflection = normalize(2 * lightStrength * input.normal - lightDir);
					specular = pow(saturate(dot(reflection, input.viewDirection)), CS_fPower);
					finalColor = saturate(finalColor + (specular * CS_colColor * CS_fBrightness * LIGHT_Intensity[i].w));
//					litColor = saturate(litColor + (specular * LIGHT_Color[i] * CS_fBrightness * LIGHT_Intensity[i].w));
				}
			}
		}
		if (LIGHT_Type[i].w == 2.0f)
		{
			float3 lightToPixelVec = LIGHT_Position[i] - input.worldPosition;
			float d = length(lightToPixelVec);

			if (d < LIGHT_AttRange[i].w)
			{
				lightToPixelVec /= d;
				float howMuchLight = 0.0f;

				if (!CN_bHas)
				{
					howMuchLight = saturate(dot(lightToPixelVec, input.normal));
				}
				else
				{
					howMuchLight = saturate(dot(lightToPixelVec, normalNormal));
				}


				if (howMuchLight > 0.0f)
				{	
					float4 pointColor = (LIGHT_Color[i] * LIGHT_Intensity[i].w * howMuchLight);
					float att = 1.0f / (LIGHT_AttRange[i].x + (LIGHT_AttRange[i].y * d) + (LIGHT_AttRange[i].z * (d*d)));

					litColor = litColor + (pointColor * att);
					litColor = saturate(litColor);

					if (CS_bHas)
					{
						reflection = normalize(2 * howMuchLight * input.normal - lightDir);
						specular = pow(saturate(dot(reflection, input.viewDirection)), CS_fPower);
						finalColor = saturate(finalColor + (specular * CS_colColor * CS_fBrightness * LIGHT_Intensity[i].w));
//						litColor = saturate(litColor + (specular * LIGHT_Color[i] * CS_fBrightness * LIGHT_Intensity[i].w));
					}
				}	
   			}	  
		}
		if (LIGHT_Type[i].w == 3.0f)
		{
			float3 lightToPixelVec = LIGHT_Position[i] - input.worldPosition;
			float d = length(lightToPixelVec);

			if (d < LIGHT_AttRange[i].w)
			{
				lightToPixelVec /= d; 
				float howMuchLight = saturate(dot(lightToPixelVec, input.normal));

				if (howMuchLight > 0.0f)
				{	
					float4 pointColor = (LIGHT_Color[i] * LIGHT_Intensity[i].w * howMuchLight);
					float att = 1.0f / (LIGHT_AttRange[i].x + (LIGHT_AttRange[i].y * d) + (LIGHT_AttRange[i].z * (d*d)));

//					litColor = litColor + (pointColor * att);
					float4 spotColor = litColor + (pointColor * att);
//					litColor *= pow(max(dot(lightToPixelVec, lightDir), 0.0f), LIGHT_Cone[i].w);
					spotColor *= pow(max(dot(lightToPixelVec, lightDir), 0.0f), 30.0f);
					litColor = saturate( (litColor + spotColor) );

					if (CS_bHas)
					{
						reflection = normalize(2 * howMuchLight * input.normal - lightDir);
						specular = pow(saturate(dot(reflection, input.viewDirection)), CS_fPower);
						finalColor = saturate(finalColor + (specular * CS_colColor * CS_fBrightness * LIGHT_Intensity[i].w));
//						litColor = saturate(litColor + (specular * LIGHT_Color[i] * CS_fBrightness * LIGHT_Intensity[i].w));
					}
				}
   			}
		}	

	} // lights

	if (CE_bHas)
	{
		finalColor = finalColor * ShaderTexture[3].Sample(SampleTypeWrap, input.texEnv);
	}

	if (CL_bHas)
	{
		lumColor = ShaderTexture[2].Sample(SampleTypeWrap, input.tex);
		finalColor = lumColor * finalColor + (LIGHT_AmbientColor * LIGHT_AmbientStrength);
	}
	else
	{
		finalColor = litColor * finalColor + (LIGHT_AmbientColor * LIGHT_AmbientStrength);
	}

	if (CR_bHas)
	{
		float3 incident = -input.viewDirection;
		float3 reflectionVector = reflect(incident, input.normal);
		float4 reflectionColor  = ShaderCubeTexture.Sample(SampleTypeWrap, reflectionVector);

		finalColor = finalColor + (reflectionColor / 7.0f);
//		finalColor = finalColor * reflectionColor;
//		finalColor = reflectionColor;
	}


	if (CT_bHas)
	{
		finalColor.a = CT_fBrightness;
	}
	else
	{
		finalColor.a = 1.0f;
	}

	if (LIGHT_bUseShadow)
	{
		bias = 0.001f;

		projectTexCoord.x =  input.lightViewPosition.x / input.lightViewPosition.w / 2.0f + 0.5f;
		projectTexCoord.y = -input.lightViewPosition.y / input.lightViewPosition.w / 2.0f + 0.5f;

		if ((saturate(projectTexCoord.x) == projectTexCoord.x) && (saturate(projectTexCoord.y) == projectTexCoord.y))
		{
			depthValue = ShaderTexture[4].Sample(SampleTypeClamp, projectTexCoord).r;
			lightDepthValue = input.lightViewPosition.z / input.lightViewPosition.w;
			lightDepthValue = lightDepthValue - bias;

			if (lightDepthValue > depthValue)
			{
				return finalColor * 0.2f;
//				return finalColor * LIGHT_AmbientStrength;
//				return LIGHT_AmbientColor;// * LIGHT_AmbientStrength;
			}
		}
	}


  return saturate(finalColor);
}