float3 expand(float3 v)
{
	return (v - 0.5) * 2;
}

float4 doLighting(
	float3 position,
	float3 normal,
	float3 eyeDir,
	float exponent,
	float specularFactor,
	float3 lightDir,
	float4 lightPosition,
	float4 lightDiffuse,
	float4 lightSpecular,
	float4 lightAttenuation,
	float4 lightSpotlight,
	float3 lightSpotDir
) {
	float3 halfAngle = normalize(lightDir + eyeDir);

	float nDotL = dot(lightDir, normal);
	float nDotH = dot(halfAngle, normal);
	float4 lighting = lit(nDotL, nDotH, exponent);
	
	float attenuation = 1;
	#if ATTENUATION
	if (lightPosition.w != 0) {
		float distance = length(lightPosition.xyz - position);
		attenuation = 1.0 / (lightAttenuation.y + lightAttenuation.z * distance  + lightAttenuation.w * distance * distance);
	}
	#endif
	
	float spot = 1;
	if (!(lightSpotlight.x == 1 && lightSpotlight.y == 0 && lightSpotlight.z == 0 && lightSpotlight.w == 1)) {
		spot = saturate(
			(dot(lightDir, normalize(-lightSpotDir)) - lightSpotlight.y) /
			(lightSpotlight.x - lightSpotlight.y));
	}
	
	return attenuation * spot * (lightDiffuse * lighting.y + specularFactor * lightSpecular * lighting.z);
}

void main_triplanar_reference_fp(
	float3 position: TEXCOORD0,
	float4 normalAndFogVal: TEXCOORD1, 
	float3 eyePos: TEXCOORD2,
	
	#if LIGHT0
	uniform float4 lightPosition0,
	uniform float4 spotlightDir0,
	uniform float4 lightDiffuse0,
	uniform float4 lightSpecular0,
	uniform float4 lightAttenuation0,
	uniform float4 lightSpotlight0,
	#endif
	#if LIGHT1
	uniform float4 lightPosition1,
	uniform float4 spotlightDir1,
	uniform float4 lightDiffuse1,
	uniform float4 lightSpecular1,
	uniform float4 lightAttenuation1,
	uniform float4 lightSpotlight1,
	#endif
	#if LIGHT2
	uniform float4 lightPosition2,
	uniform float4 spotlightDir2,
	uniform float4 lightDiffuse2,
	uniform float4 lightSpecular2,
	uniform float4 lightAttenuation2,
	uniform float4 lightSpotlight2,
	#endif
	
    uniform float4x4 world,
	uniform float exponent,
	uniform float texScale,
	uniform float plateauSize,
	uniform float transitionSpeed,

	#if FOGLINEAR || FOGEXPONENTIAL || FOGEXPONENTIAL2
	uniform float4 fogColour,
	#endif
	
	uniform float4 ambient,
	uniform sampler2D texFromX: register(s0),
	uniform sampler2D texFromXNormal: register(s1),
	uniform sampler2D texFromY: register(s2),
	uniform sampler2D texFromYNormal: register(s3),
	uniform sampler2D texFromZ: register(s4),
	uniform sampler2D texFromZNormal: register(s5),
					
	out float4 oColor: COLOR
){
	
	float3 unitNormal = normalize(normalAndFogVal.xyz);
	float3 eyeDir = normalize(eyePos - position);
		
	// Ported from http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html
	float3 blendWeights = abs(unitNormal);
	blendWeights = blendWeights - plateauSize;
	blendWeights = pow(max(blendWeights, 0), transitionSpeed);
	blendWeights /= (blendWeights.x + blendWeights.y + blendWeights.z ).xxx;
	// Move the planar mapping a bit according to the normal length to avoid bad looking skirts.
	float nLength = length(normalAndFogVal.xyz - 1.0);
	float2 coord1 = (position.yz + nLength) * texScale;
	float2 coord2 = (position.zx + nLength) * texScale;
	float2 coord3 = (position.xy + nLength) * texScale;
	
	float4 col1 = tex2D(texFromX, coord1);
	float4 col2 = tex2D(texFromY, coord2);
	float4 col3 = tex2D(texFromZ, coord3);
	float4 textColour = float4(col1.xyz * blendWeights.x +
		col2.xyz * blendWeights.y +
		col3.xyz * blendWeights.z, 1);
	
	// Normal Mapping
	#if LIGHTNORMALMAPPING
	float3 tangent = float3(1, 0, 0);
	float3 binormal = normalize(cross(tangent, unitNormal));
	tangent = normalize(cross(unitNormal, binormal));
	float3x3 TBN = float3x3(tangent, binormal, unitNormal);
	float3 eyeDir2 = normalize(mul(TBN, eyeDir));
	float3 bumpFetch1 = expand(tex2D(texFromXNormal, coord1).rgb);
    float3 bumpFetch2 = expand(tex2D(texFromYNormal, coord2).rgb);
    float3 bumpFetch3 = expand(tex2D(texFromZNormal, coord3).rgb);
	float3 normal2 = bumpFetch1.xyz * blendWeights.x +  
		bumpFetch2.xyz * blendWeights.y +  
		bumpFetch3.xyz * blendWeights.z;
	#else
	float3 eyeDir2 = eyeDir;
	float3 normal2 = unitNormal;
	#endif
	
	#if USESPECULARMAP
	float specularFactor = textColour.a;
	#else
	float specularFactor = 1.0;
	#endif
	
	// Light
	float4 lightContribution = float4(0, 0, 0, 0);
	#if LIGHT0
	float3 lightSpotDir0 = mul(world, spotlightDir0).xyz;
	float3 lightDir0 = normalize(lightPosition0.xyz - position * lightPosition0.w);
	#if LIGHTNORMALMAPPING
	float3 lightSpotDir02 = normalize(mul(TBN, lightSpotDir0));
	float3 lightDir02 = normalize(mul(TBN, lightDir0));
	#else
	float3 lightSpotDir02 = lightSpotDir0;
	float3 lightDir02 = lightDir0;
	#endif
	lightContribution += doLighting(position, normal2, eyeDir2, exponent, specularFactor, lightDir02, lightPosition0, lightDiffuse0, lightSpecular0, lightAttenuation0, lightSpotlight0, lightSpotDir02);
	#endif
	
	#if LIGHT1
	float3 lightSpotDir1 = mul(world, spotlightDir1).xyz;
	float3 lightDir1 = normalize(lightPosition1.xyz - position * lightPosition1.w);
	#if LIGHTNORMALMAPPING
	float3 lightSpotDir12 = normalize(mul(TBN, lightSpotDir1));
	float3 lightDir12 = normalize(mul(TBN, lightDir1));
	#else
	float3 lightSpotDir12 = lightSpotDir1;
	float3 lightDir12 = lightDir1;
	#endif
	lightContribution += doLighting(position, normal2, eyeDir2, exponent, specularFactor, lightDir12, lightPosition1, lightDiffuse1, lightSpecular1, lightAttenuation1, lightSpotlight1, lightSpotDir12);
	#endif
	
	#if LIGHT2
	float3 lightSpotDir2 = mul(world, spotlightDir2).xyz;
	float3 lightDir2 = normalize(lightPosition2.xyz - position * lightPosition2.w);
	#if LIGHTNORMALMAPPING
	float3 lightSpotDir22 = normalize(mul(TBN, lightSpotDir2));
	float3 lightDir22 = normalize(mul(TBN, lightDir2));
	#else
	float3 lightSpotDir22 = lightSpotDir2;
	float3 lightDir22 = lightDir2;
	#endif
	lightContribution += doLighting(position, normal2, eyeDir2, exponent, specularFactor, lightDir22, lightPosition2, lightDiffuse2, lightSpecular2, lightAttenuation2, lightSpotlight2, lightSpotDir22);
	#endif
	
	oColor = saturate(textColour * (lightContribution + ambient));
	#if FOGLINEAR || FOGEXPONENTIAL || FOGEXPONENTIAL2
	oColor = lerp(oColor, fogColour, normalAndFogVal.w);
	#endif
	
}