//-----------------------------------------------------------------------------
// Program Name: SL_Lighting
// Program Desc: Per pixel lighting functions.
// Program Type: Vertex/Pixel shader
// Language: CG
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void SL_TransformNormal(in float4x4 m, 
				   in float3 v, 
				   out float3 vOut)
{
	vOut = mul((float3x3)m, v);
}

//-----------------------------------------------------------------------------
void SL_TransformPosition(in float4x4 mWorldView, 
				   in float4 vPos, 
				   out float3 vOut)
{
	vOut = mul(mWorldView, vPos).xyz;
}

//-----------------------------------------------------------------------------
void SL_Light_Directional_Diffuse(
				   in float3 vNormal,
				   in float3 vNegLightDirView,
				   in float3 vDiffuseColour, 
				   in float3 vBaseColour, 
				   out float3 vOut)
{
	float3 vNormalView = normalize(vNormal);
	float nDotL = dot(vNormalView, vNegLightDirView);
	
	vOut = vBaseColour + vDiffuseColour * saturate(nDotL);
}

//-----------------------------------------------------------------------------
void SL_Light_Directional_DiffuseSpecular(
					in float3 vNormal,
					in float3 vViewPos,					
					in float3 vNegLightDirView,
					in float3 vDiffuseColour, 
					in float3 vSpecularColour, 
					in float fSpecularPower, 
					in float3 vBaseDiffuseColour,
					in float3 vBaseSpecularColour,					
					out float3 vOutDiffuse,
					out float3 vOutSpecular)
{
	vOutDiffuse  = vBaseDiffuseColour;
	vOutSpecular = vBaseSpecularColour;
	
	float3 vNormalView = normalize(vNormal);		
	float nDotL		   = dot(vNormalView, vNegLightDirView);			
	float3 vView       = -normalize(vViewPos);
	float3 vHalfWay    = normalize(vView + vNegLightDirView);
	float nDotH        = dot(vNormalView, vHalfWay);
	
	nDotL = max(nDotL, 0);
	vOutDiffuse  += vDiffuseColour * nDotL;		
	vOutSpecular += vSpecularColour * pow(saturate(nDotH), fSpecularPower);						
}


//the amount of light taken for ambient light (does not realy on direction)
//const float spotAmbientPart = 1;


//-----------------------------------------------------------------------------
void SL_Light_Ambient_Diffuse_Inner(
				    in float3 vNormal,
				    in float3 vLightView,
				    in float fLightDist,
				    in float3 vNegLightDirView,
				    in float3 vSpotParams,
				    in float3 vDiffuseColour, 
				    inout float3 vColorOut)
{
	float fLightDistInv = 1 / fLightDist;
	float nDotL = dot(vNormal, vLightView) * fLightDistInv;
	
	float fAtten = (1 - (fLightDist * vSpotParams.x));
	fAtten = fAtten * fAtten;

	float rho = dot(vNegLightDirView, vLightView) * fLightDistInv;
	float fSpotT = saturate((rho - vSpotParams.y) * vSpotParams.z);

	nDotL = step(0,nDotL) * (0.7 + (0.3 * nDotL));
	vColorOut += vDiffuseColour * 2* nDotL * fAtten * fSpotT;
	
	//if ((fLightDist < 150) && (rho < 0.85))
	//	vColorOut.x = 0.5;
}


//-----------------------------------------------------------------------------
void SL_Light_Ambient_Diffuse(
				    in float3 vNormal,
				    in float3 vViewPos,
				    in float3 vLightPosView,
				    in float3 vNegLightDirView,
				    in float3 vSpotParams,
				    in float3 vDiffuseColour, 
				    inout float3 vColorOut)
{
	float3 vLightView = vLightPosView - vViewPos;
	float fLightDist = length(vLightView);
	if (fLightDist * vSpotParams.x < 1)
	{
		SL_Light_Ambient_Diffuse_Inner(vNormal, vLightView, fLightDist,
				vNegLightDirView, vSpotParams, vDiffuseColour, vColorOut);
	}
}

//-----------------------------------------------------------------------------

void SL_Light_Segment_Texture_Ambient_Diffuse(
				    in float3 vNormal,
				    in float3 vViewPos,
				    in sampler2D dataTexture,
				    in float2 lightIndexLimit,
					in float4 lightBounds,
					in float invWidth,
					in float invHeight,
				    inout float3 vColorOut)
{
	float widthOffset = invWidth * 0.5;		
	float heightOffset = invHeight * 0.5;	
	
	float2 indexes = (vViewPos.xz - lightBounds.xy) * lightBounds.zw;
	indexes = clamp(indexes,0,8);
	int index = (int)indexes.x + (int)(indexes.y) * 9;
	widthOffset += invWidth * 3 * index;
	
	float4 indexBounds = tex2Dlod(dataTexture, float4(widthOffset,heightOffset,0,0));
	int toIndex = min(lightIndexLimit.y, indexBounds.x);
	for(int i = lightIndexLimit.x; i <= toIndex; ++i)
	{
		float heightCoord = heightOffset + invHeight * i;
		float4 dat1 = tex2Dlod(dataTexture, float4(widthOffset,heightCoord,0,0));
		
		float3 vLightView  = dat1.xyz - vViewPos;
		float fLightDist = length(vLightView);
		if (fLightDist * dat1.w < 1)
		{
			float4 dat2 = tex2Dlod(dataTexture, float4(widthOffset + invWidth,heightCoord,0,0));
			float4 dat3 = tex2Dlod(dataTexture, float4(widthOffset + invWidth * 2,heightCoord,0,0));
			SL_Light_Ambient_Diffuse_Inner(vNormal, vLightView, fLightDist, dat2.xyz, float3(dat1.w, dat2.w, dat3.w), dat3.xyz, vColorOut);
		}
	}
}


void SL_Light_Segment_Debug(
				    in float3 vNormal,
				    in float3 vViewPos,
				    in sampler2D dataTexture,
				    in float2 lightIndexLimit,
					in float4 lightBounds,
					in float invWidth,
					in float invHeight,
				    inout float3 vColorOut)
{
	float widthOffset = invWidth * 0.5;		
	float heightOffset = invHeight * 0.5;	
	
	float2 indexes = (vViewPos.xz - lightBounds.xy) * lightBounds.zw;
	indexes = clamp(indexes,0,8);
	int index = (int)indexes.x + (int)(indexes.y) * 9;
	float4 indexBounds = tex2Dlod(dataTexture, float4(widthOffset,heightOffset,0,0));

	float2 debugColors = vColorOut.xy * 0.5 + ((fmod(floor(indexes.xy),2) == 0) ? 0.1 : 0.2);
	vColorOut.xy =  debugColors;
	int toIndex = min(lightIndexLimit.y, indexBounds.x);
	vColorOut.z = (toIndex - lightIndexLimit.x) / 32;	
}