// Maya_phong_fragment.cg
//
// This file cannot be directly compiled through CG... it first must be
// parsed to insert channel-specific instructions.
//
#include "Maya_Blends.cgh"
#include "Maya_EnvironmentMap.cgh"
#include "Maya_phong_connecters.cgh"

#if !defined (BLEND_MODE1)
// The blend function between layers 0 and 1: Default add
#define BLEND_MODE1 kBlendAdd 
#endif

#if !defined (ALPHA_LUMIANANCE)
// Use the alpha channel as luminance : Default off
#define ALPHA_LUMIANANCE 0		
#endif

// Explicit matrix to transform object space normal vector to world space
#if defined(OBJECT_NORMAL)
	uniform float4x4 objToWorldMatrix;
#endif

// already defined in the connecters header
//#if defined (LAYER_TWO) 
//	#define PASS_TEX1_UV 1
//#endif

///////////////////////////////////////////////////////////////////////////////////
struct MAYA_NormalInfoInput
{
	float3 wNormal;						// World space normal
	float faceMultiplier;				// Normal inversion (double-sided lighting, neg-determinants
	#if defined(BUMP_MAP)
		float4 wTangent;				// World space tangent
	#endif		
	#if defined(BUMP_MAP) || defined(OBJECT_NORMAL)
		float4 bumpTexUv;				// Normal map texcoords
		uniform float4	bumpTexMatrix0;
		uniform float4	bumpTexMatrix1; 
		sampler bumpTex;				// Normal map
	#endif	
};
///////////////////////////////////////////////////////////////////////////////////
//
// Procedure: MAYA_computeWorldSpaceNormal
// Description:
//      Compute the world space normal.
//
float3 MAYA_computeWorldSpaceNormal(MAYA_NormalInfoInput IN)
{
	float3 wBumpedNormal;

#if defined(BUMP_MAP)
	// Compute an orthonormal basis to transform from tangent space
	// to world space, and vice-versa.
	//
	float3 wTangent  = normalize(IN.wTangent.xyz);
	float3 wNormal   = normalize(IN.wNormal);
#if defined (BINORMAL_SIGN)
	float3 wBinormal = cross(wNormal, wTangent) * IN.wTangent.w;
#else
	float3 wBinormal = cross(wNormal, wTangent);
#endif

	// Translate and scale bump texture coordinates, by multiplying
	// the uvs by the bump texture matrix.
	//
	float2 placedBumpTexUv;
	float4 bumpTexUv = float4(IN.bumpTexUv.xy, 0.0, 1.0);
	placedBumpTexUv.x = dot(IN.bumpTexMatrix0, bumpTexUv);
	placedBumpTexUv.y = dot(IN.bumpTexMatrix1, bumpTexUv);

	// Fetch the bumped normal (in tangent space) from the bump texture.
	// The (... * 2 - 1) at the end is used to unpack the normal components,
	// from the [0,1] to [-1, 1] range.
	//
	float3 tBumpedNormal = normalize(tex2D(IN.bumpTex, placedBumpTexUv).xyz * 2.0 - 1.0);

	// Compute the world-space bumped normal by multiplying the tangent
	// space normal by the tangent space basis vectors.
	//

	#if defined(INVERT_TANGENT_SPACE_BASIS)
		wTangent		= -wTangent;
		tBumpedNormal  = -tBumpedNormal;
		wNormal		= -wNormal;

		#if !defined(TWO_SIDED_LIGHTING)	
			// Is transparent
			float flipBump = -IN.faceMultiplier;
		#else
			// Is opaque
			float flipBump = IN.faceMultiplier;
		#endif	

		wBumpedNormal =  tBumpedNormal.x * wTangent + 
						tBumpedNormal.y * wBinormal + 
						tBumpedNormal.z * wNormal * flipBump;
	#else
		 wBumpedNormal = IN.faceMultiplier * tBumpedNormal.x * wTangent + 
						 IN.faceMultiplier * tBumpedNormal.y * wBinormal + 
										  tBumpedNormal.z * wNormal;
	#endif	
	
	wBumpedNormal = normalize(wBumpedNormal);

#elif defined (OBJECT_NORMAL)

	// Translate and scale bump texture coordinates, by multiplying
	// the uvs by the bump texture matrix.
	//
	// [Should be moved to vertex program for efficiency]
	float4 bumpTexUv = float4(IN.bumpTexUv.xy, 0.0, 1.0);
	float2 placedBumpTexUv;
	placedBumpTexUv.x = dot(IN.bumpTexMatrix0, bumpTexUv);  
	placedBumpTexUv.y = dot(IN.bumpTexMatrix1, bumpTexUv);

	// Fetch the bumped normal (in object space) from the bump texture.
	// The (... * 2 - 1) at the end is used to unpack the normal components,
	// from the [0,1] to [-1, 1] range.
	//
	float3 oBumpedNormal = tex2D(IN.bumpTex, placedBumpTexUv).xyz * 2.0 - 1.0;

	// tranform the normal to world space.
	wBumpedNormal = normalize(mul(objToWorldMatrix, float4(oBumpedNormal, 0.0)).xyz);

#else 	
	// No bump map. Just pass through the normal as is
	wBumpedNormal = normalize(IN.wNormal);	
#endif // BUMP_MAP

	// Handle double sided lighting within the
	// program, as opposed to using the "normalMultiplier".
	// which is set externally.
	//
	// To support transparency and back-face lighting,
	// allow normal inversion.
	#if !defined(INVERT_TANGENT_SPACE_BASIS)
		wBumpedNormal = IN.faceMultiplier * wBumpedNormal;				
	#endif			
	return wBumpedNormal;
}

///////////////////////////////////////////////////////////////////////////////////
struct MAYA_ColorTxInfoInput
{
	#if defined(LIGHTANGLE_COLOR_UVS) || defined(CAMERA_ANGLE_COLOR_UVS) 	
	    #if defined(LIGHTANGLE_COLOR_UVS) 
            float LDotNsigned;          // Lookup is based on angle of light w.r.t normal
        #endif
        #if defined(CAMERA_ANGLE_COLOR_UVS) 	
            float3 wViewDir;            // Lookup is based on angle of camera w.r.t. normal
            float3 wBumpedNormal;       // Also sometimes mentioned as "facing ratio".
        #endif            
    #else
            float4 colorTexUv;          // Basic 2D texture lookup, with 2d transform applied
            float4 colorTexMatrix0;
            float4 colorTexMatrix1;
    #endif        
};
//
// Procedure: MAYA_computeColorTextureLookup
// Description:
//      Compute the coordinates for color texture lookups. 
//      Currently only 2D lookups are supported.
//
float2 MAYA_computeColorTextureLookup(MAYA_ColorTxInfoInput IN)
{
	// Apply the appropriate color texture lookup
	// then fetch the appropriate color texel.
	//
	float2 placedColorTexUv;

	// Use 0.5 for y to avoid filtering problems at the edges
	// of the texture. MUST use signed value so
	// that areas facing away from the light are also mapped
	// properly !
	//
	#if defined(LIGHTANGLE_COLOR_UVS) || defined(CAMERA_ANGLE_COLOR_UVS) 	
		#if defined(LIGHTANGLE_COLOR_UVS)
			placedColorTexUv.x = 0.5 * (IN.LDotNsigned+1.0); // This is from Maya's ramp shader
			placedColorTexUv.x = min( placedColorTexUv.x, 1.0 );
			placedColorTexUv.x = max( placedColorTexUv.x, 0.0 );
			placedColorTexUv.y = 0.5;
		#endif
		#if defined(CAMERA_ANGLE_COLOR_UVS)
			float EDotN = dot(IN.wViewDir, IN.wBumpedNormal);
			EDotN = max(EDotN, 0.001);
			placedColorTexUv.x = EDotN;
			placedColorTexUv.y = 0.5;
		#endif
	#else
		float4 colorTexUv = float4(IN.colorTexUv.xy, 0.0, 1.0);
		placedColorTexUv.x = dot(IN.colorTexMatrix0, IN.colorTexUv);
		placedColorTexUv.y = dot(IN.colorTexMatrix1, IN.colorTexUv);
	#endif	
	
	return placedColorTexUv;
}

///////////////////////////////////////////////////////////////////////////////////
struct MAYA_BaseInfoInput
{
#if defined(INTENSITY_ANGLE_COLOR_UVS)
    float4 intensityAngleColor;
#else    
	#if defined(CONSTANT_COLOR)
	    // Constant colour
        float4 constantColor;
    #else
        // Sampler lookup
        sampler colorTex;         
		float3 lookupVector;
        //float2 placedColorTexUv;
        #if defined(PASS_TEX1_UV)
			// Sampler lookup
			sampler colorTex2; 
			float3 lookupVector2;
			//float2 placedColorTexUv2;
	#endif
	#if defined(PASS_TEX1_ALPHA_UV)
		sampler alphaTex2;
		float2 placedAlphaTexUv2;
	#else
			float passAlpha2;
        #endif
    #endif
    #if defined(COLOR_PER_VERTEX)
        float4 colorPerVertex;		
	    #if defined(COLOR_PER_VERTEX_MASK)
            float colorPerVertexMask;
        #endif
    #endif
#endif    
};

//
// Procedure: MAYA_computeBaseColor
// Description:
//      Compute the base color. Value may be computed externally based on
//      lighting; a constant colour or texture lookup; and may be
//      affected by colour per vertex.
//
///////////////////////////////////////////////////////////////////////////////////
float4 MAYA_computeBaseColor(MAYA_BaseInfoInput IN, out float4 previousColor)
{
    float4 baseColor = float4(0,0,0,1);

#if defined(INTENSITY_ANGLE_COLOR_UVS)
	// Color is based on light intensity. Skip color computation.
	baseColor = IN.intensityAngleColor; // float4(1, 1, 1, 1);
#else

	#if defined(CONSTANT_COLOR)
		baseColor = IN.constantColor;
	#else
		// Switch on whether to lookup using environment mapping or not.
		// Crap. Must do switching in compiler, since you can't do run time seting of a sampler
		// to the correct type. Sigh.
		//
		#if (defined(PASS_TEX0_ENV_SPHERE) || defined(PASS_TEX0_ENV_CUBE))
		  #if defined(PASS_TEX0_ENV_SPHERE)
				baseColor = MAYA_environmentLookup(IN.lookupVector, IN.colorTex, kEnvironmentSphere);		
		  #else
				baseColor = MAYA_environmentLookup(IN.lookupVector, IN.colorTex, kEnvironmentCube);		
		  #endif
		#else
			//baseColor = tex2D(IN.colorTex, IN.placedColorTexUv);
			baseColor = tex2D(IN.colorTex, IN.lookupVector.xy);
		#endif			
		
		#if defined(PASS_TEX1_UV)		
			float4 color2;
			// Note that we are forced to do things this way since the compiler complains that
			// we are changing the interpretation of a sampler otherwise. So can't do a
			// conditional if-else.
			#if (defined(PASS_TEX1_ENV_SPHERE) || defined(PASS_TEX1_ENV_CUBE))
				#if defined(PASS_TEX1_ENV_SPHERE) 
					color2 = MAYA_environmentLookup(IN.lookupVector2, IN.colorTex2, kEnvironmentSphere );
				#else
					color2 = MAYA_environmentLookup(IN.lookupVector2, IN.colorTex2, kEnvironmentCube );
				#endif
			#else
				//color2 = tex2D(IN.colorTex2, IN.placedColorTexUv2);
				color2 = tex2D(IN.colorTex2, IN.lookupVector2.xy);
			#endif
			#if defined(PASS_TEX1_ALPHA_UV)
				float4 layerAlphaColor = float4( tex2D(IN.alphaTex2, IN.placedAlphaTexUv2).xyz, 1.0);
				float layerAlpha = MAYA_computeLuminance( layerAlphaColor.xyz );
				color2.a *= layerAlpha;
			#else										
			// Pre-multiply by pass alpha.
			color2.a *= IN.passAlpha2;
			#endif
			
			// Need to switch on blending factor.
			// Note that CPV blending occurs after layered blending
			MAYA_computeLayeredBlend( baseColor, color2, BLEND_MODE1, ALPHA_LUMIANANCE);
		#endif
	#endif		

	#if defined(COLOR_PER_VERTEX)		
	
		#if defined(OPACITY_IN_COLOR_ALPHA)
			previousColor = baseColor;
		#endif
		
		// Using mapped / unmapped mask
		#if defined(COLOR_PER_VERTEX_MASK)
			float4 mask = IN.colorPerVertexMask.rrrr;
			float4 invMask = float4(1.0, 1.0, 1.0, 1.0) - mask;
			#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
				baseColor = (IN.colorPerVertex * mask) + (baseColor * invMask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
				baseColor = baseColor + (IN.colorPerVertex * mask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
				baseColor = baseColor - (IN.colorPerVertex * mask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
				baseColor = baseColor * (IN.colorPerVertex * mask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
				baseColor = baseColor / (IN.colorPerVertex * mask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
				baseColor = 0.5 * (baseColor + (IN.colorPerVertex * mask));
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
				baseColor = (baseColor * (IN.colorPerVertex * mask)) * 2.0;
			#endif
		#else	
			#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
				baseColor = IN.colorPerVertex;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
				baseColor = baseColor + IN.colorPerVertex;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
				baseColor = baseColor - IN.colorPerVertex;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
				baseColor = baseColor * IN.colorPerVertex;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
				baseColor = baseColor / IN.colorPerVertex;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
				baseColor = 0.5 * (baseColor + IN.colorPerVertex);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
				baseColor = (baseColor * IN.colorPerVertex) * 2.0;
			#endif
		#endif	// COLOR_PER_VERTEX_MASK

	#endif
#endif	
    return baseColor;
}

///////////////////////////////////////////////////////////////////////////////////
struct MAYA_DiffuseInfoInput
{
#if defined(CONSTANT_DIFFUSE)
	float constantDiffuse;
#else
	float4 diffuseTexUv;
	float4 diffuseTexMatrix0;
	float4 diffuseTexMatrix1;
	sampler diffuseTex;
#endif
};
//
// Procedure: MAYA_computeDiffuseCoef
// Description:
//		Compute Maya's diffuse coefficient
//
float MAYA_computeDiffuseCoef(MAYA_DiffuseInfoInput IN)
{
	float diffuseCoef;
	
#if defined(CONSTANT_DIFFUSE)
	diffuseCoef = IN.constantDiffuse;
#else
	// Apply placement texture matrix and fetch from diffuse texture.
	// Note that only the alpha is taken in consideration.
	//
	float2 placedDiffuseTexUv;
	float4 diffuseTexUv = float4(IN.diffuseTexUv.xy, 0.0, 1.0);
	placedDiffuseTexUv.x = dot(IN.diffuseTexMatrix0, diffuseTexUv);
	placedDiffuseTexUv.y = dot(IN.diffuseTexMatrix1, diffuseTexUv);
	diffuseCoef = tex2D(IN.diffuseTex, placedDiffuseTexUv).a;
#endif	
	return diffuseCoef;
}

///////////////////////////////////////////////////////////////////////////////////
//
struct MAYA_SpecularInfoInput1
{
	float3 attenuatedLightColor;
	float RDotV;
	float specularExp;
	float4 specValues;
	#if defined(COLOR_PER_VERTEX_SPECULAR)
		float4 colorPerVertex;
		#if defined(COLOR_PER_VERTEX_MASK)		
			float colorPerVertexMask;
		#endif
	#endif
};
//
// Procedure: MAYA_computePhongSpecular
// Description:
//		Compute Maya's Phong specular colour component
//
float3 MAYA_computePhongSpecular(MAYA_SpecularInfoInput1 IN)
{
	float3 specularColor;
	
	// Regular non-colour per vertex case
	#if !defined(COLOR_PER_VERTEX_SPECULAR)
			specularColor = IN.attenuatedLightColor * IN.specValues.rgb * pow(IN.RDotV, IN.specularExp);

	// Specular CPV case
	#else
		float specPower = pow(IN.RDotV, IN.specularExp);

		#if defined(COLOR_PER_VERTEX_MASK)
		
			float4 mask = IN.colorPerVertexMask.rrrr;
			float4 invMask = float4(1.0, 1.0, 1.0, 1.0) - mask;

			#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
				specularColor = (IN.colorPerVertex.rgb * mask.rgb * IN.attenuatedLightColor.rgb) * (specPower * invMask);
			#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
				specularColor = (IN.specValues.rgb + IN.colorPerVertex.rgb * mask.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
				specularColor = (IN.specValues.rgb - IN.colorPerVertex.rgb * mask.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
				specularColor = (IN.specValues.rgb * IN.colorPerVertex.rgb * mask.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
				specularColor = (IN.specValues.rgb / (IN.colorPerVertex.rgb * mask.rgb)) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
				specularColor = (0.5 * (IN.specValues.rgb + (IN.colorPerVertex.rgb * mask.rgb))) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
				specularColor = (IN.specValues.rgb * IN.colorPerVertex.rgb * mask.rgb) * IN.attenuatedLightColor.rgb * specPower * 2.0;
			#endif
		#else
			#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
				specularColor = IN.colorPerVertex.rgb * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
				specularColor = (IN.specValues.rgb + IN.colorPerVertex.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
				specularColor = (IN.specValues.rgb - IN.colorPerVertex.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
				specularColor = (IN.specValues.rgb * IN.colorPerVertex.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
				specularColor = (IN.specValues.rgb / IN.colorPerVertex.rgb) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
				specularColor = (0.5 * (IN.specValues.rgb + IN.colorPerVertex.rgb)) * IN.attenuatedLightColor.rgb * specPower;
			#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
				specularColor = (IN.specValues.rgb * IN.colorPerVertex.rgb) * IN.attenuatedLightColor.rgb * specPower * 2.0;
			#endif
		#endif

	#endif // Specular CPV
	
	return specularColor;
}

///////////////////////////////////////////////////////////////////////////////////
//
// Procedure: MAYA_computeBlinnSpecular
// Description:
//		Compute Maya's Blinn specular colour component
//
struct MAYA_SpecularInfoInput // Input data to compute specular
{
	float3 wBumpedNormal;
	float3 wLightDir;
	float3 attenuatedLightColor;
	float3 wViewDir;
	float eccentricity;
#if defined(REFLECTED_SPECULAR)
	float specularity;	
#else
	float specularRollOff;
#endif	
	float4 specValues;
	float LDotN;
	float cosne;
};
float3 MAYA_computeBlinnSpecular(MAYA_SpecularInfoInput IN)
{
	float3 specularColor = float3(0,0,0);

	// Compute the Blinn specular component
	//
	float3 wHalfAngleDir = normalize(IN.wLightDir + IN.wViewDir);
	float coseh  = dot(wHalfAngleDir, IN.wViewDir);
	float cosnh  = dot(wHalfAngleDir, IN.wBumpedNormal);
	float eccSM1 = IN.eccentricity * IN.eccentricity - 1.0;

	// Protection against division by zero
	float cosne = max( IN.cosne, 0.0001 );
	coseh = max( coseh, 0.0001 );
	cosnh = max( cosnh, 0.0001 );

#if defined(REFLECTED_SPECULAR)
	if( (eccSM1 > -0.0001) && (eccSM1 < 0.0001) )	eccSM1 = 0.0001;
	eccSM1 = 1.0 / eccSM1;
	
	float Dd = (eccSM1 + 1.0f) / ( eccSM1 + cosnh * cosnh );
#else
	float Dd = (eccSM1 + 1.0f) / ( 1.0 + eccSM1 * cosnh * cosnh );
#endif
	Dd    = Dd * Dd;
	cosnh = 2 * cosnh;

	float Gg;
	if (cosne < IN.LDotN) 
		Gg = (cosne*cosnh < coseh) ? (cosnh / coseh) : (1.0f / cosne);
	else 
		Gg = (IN.LDotN*cosnh < coseh) ? ((IN.LDotN * cosnh) / (coseh * cosne)) : (1.0f / cosne);

	float Ff = 0.0f;
	
#if defined(REFLECTED_SPECULAR)
	Ff = IN.specularity;
#else
	// Fresnel calculation.
	coseh = 1.0f - coseh;
	coseh = coseh * coseh * coseh;
	Ff = coseh + (1.0f - coseh) * IN.specularRollOff;
#endif

	// Ensure the specularCoefficient to be always positive.
	//
	float specularCoefficient = max(Dd * Gg * Ff, 0);
	specularColor = specularCoefficient * IN.attenuatedLightColor * IN.specValues.rgb;

	return specularColor;
}

///////////////////////////////////////////////////////////////////////////////////
//
// Procedure: MAYA_computeTranslucence
// Description:
//		Compute translucence
//
struct MAYA_translucenceInfo
{
    float3              wLightDir;
    float3              wViewDir;
	float				LDotNsigned;
	float				LDotN;
	uniform float		translucence;
	uniform float		translucenceFocus;
	uniform float		translucenceDepth;
};
float MAYA_computeTranslucence(MAYA_translucenceInfo IN)
{
	float tlBright = 0.0;

	// Forward scatter is not considered yet.
	//
	float translFade = 0.15;
	float translMinAngle = -1.0 * (1.0+translFade) * IN.translucenceDepth * 10.0;
	if (IN.LDotNsigned > translMinAngle)
	{
		translFade = translFade - translMinAngle;
		translFade = max(translFade, 1.0 );

		tlBright = IN.translucence; 
		if (IN.translucenceFocus > 0.0)
		{
			float LDotE = -dot(IN.wLightDir, IN.wViewDir);
			LDotE = (LDotE + 1.0) * 0.5;
			LDotE = min(LDotE, 1.0);
			LDotE = max(LDotE, 0.0);
			
			// subtract from 1.00001 so there is still a light at 1.0
			float tFocus = IN.translucenceFocus /(1.00001-IN.translucenceFocus);
			tlBright = IN.translucence * pow( LDotE, tFocus );			
		}

		if( IN.LDotNsigned < (translMinAngle + translFade) )
			tlBright *= (IN.LDotN - translMinAngle) / translFade;
	}
	return tlBright;
}

///////////////////////////////////////////////////////////////////////////////////
//
// Procedure: MAYA_lookupTexturedTransparency
// Description:
//		Compute textured transparency
//
struct MAYA_TranspLookupInfo // Structure to pass over generalized data. To convert to interface.
{
	uniform sampler transpTex;
	#if defined(CAMERA_ANGLE_TRANSP_UVS)
		float EDotN;
	#else
		float4 transpTexUv;
		uniform float4 transpTexMatrix0;
		uniform float4 transpTexMatrix1;
	#endif
};
float3 MAYA_lookupTexturedTransparency(MAYA_TranspLookupInfo IN)
{
	// Apply the placement transparency/opacity texture lookup, 
	// then fetch the appropriate texel.
	//
	float2 placedTranspTexUv;

	#if defined(CAMERA_ANGLE_TRANSP_UVS)
		placedTranspTexUv.x = IN.EDotN;
		placedTranspTexUv.y = 0.5;	
	#else
		float4 transpTexUv = float4(IN.transpTexUv.xy, 0.0, 1.0);
		placedTranspTexUv.x = dot(IN.transpTexMatrix0, transpTexUv);
		placedTranspTexUv.y = dot(IN.transpTexMatrix1, transpTexUv);
	#endif		

	// The transparency color is encoded in the transparency texture's RGB,
	// and the opacity is stored in the transparency texture's alpha.
	// This mode allows colored transparency.
	//
	float4 transpColor = tex2D(IN.transpTex, placedTranspTexUv);
	return (1.0 - transpColor.rgb);
}

///////////////////////////////////////////////////////////////////////////////////
//
// Procedure: MAYA_computePerVertexAlpha
// Description:
//		Compute fragment opacity based per vertex alpha input.
//		As alpha may not exist, a mask 'bit' must also be sent over
//		to test with.
//
float3 MAYA_computePerVertexAlpha(float alphaValue,
							      float alphaBit,
							      float3 opacityColorIn)
{
	float3 colorPerVertexAlpha = float3(alphaValue, alphaValue, alphaValue);
	float3 opacityColor = float3(1,1,1);

	#if defined(COLOR_PER_VERTEX_MASK)	
		float aInvMask = 1.0 - alphaBit;

		#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
			opacityColor = (colorPerVertexAlpha * alphaBit) + (opacityColorIn.rgb * aInvMask);
		#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
			opacityColor = (opacityColorIn.rgb + colorPerVertexAlpha * alphaBit);
		#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
			opacityColor = (opacityColorIn.rgb - colorPerVertexAlpha * alphaBit) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
			opacityColor = (opacityColorIn.rgb * colorPerVertexAlpha * alphaBit) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
			opacityColor = (opacityColorIn.rgb / (colorPerVertexAlpha * alphaBit)) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
			opacityColor = (0.5 * (opacityColorIn.rgb + (colorPerVertexAlpha * alphaBit))) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
			opacityColor = (opacityColorIn.rgb * colorPerVertexAlpha * alphaBit) * 2.0;				
		#endif
	#else
		#if defined(COLOR_PER_VERTEX_OPERATOR_replace)
			opacityColor = colorPerVertexAlpha;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_add)
			opacityColor = (opacityColorIn.rgb + colorPerVertexAlpha) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_subtract)
			opacityColor = (opacityColorIn.rgb - colorPerVertexAlpha) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate)
			opacityColor = (opacityColorIn.rgb * colorPerVertexAlpha) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_divide)
			opacityColor = (opacityColorIn.rgb / colorPerVertexAlpha) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_average)
			opacityColor = (0.5 * (opacityColorIn.rgb + colorPerVertexAlpha)) ;
		#elif defined(COLOR_PER_VERTEX_OPERATOR_modulate2x)
			opacityColor = (opacityColorIn.rgb * colorPerVertexAlpha) * 2.0;
		#endif
	#endif
	return opacityColor;
}

///////////////////////////////////////////////////////////////////////////////////
//
// Description: Compute the final output color
//
float4 MAYA_computeFinalColor(float3 diffuseAndAmbientValue, 
                              float3 specularValue, 
                              float3 opacityValue)
{
    // To match standard hardware fixed-function pipeline specular, allow the option of modulating
    // speculary by opacity.
	#if defined(SPECULAR_IS_AFFECTED_BY_OPACITY)
		float4 finalColor = float4(opacityValue * (diffuseAndAmbientValue + specularValue), 1);
	#else	
		float4 finalColor = float4(opacityValue * diffuseAndAmbientValue + specularValue, 1);
	#endif
	return finalColor;	
}

///////////////////////


// Uniforms common to projective light textures or shadow maps.
// 
#if defined(PROJ_LIGHT_TEXTURE) || defined(SHADOW_MAP)

#define UNIFORM_WORLD_TO_PROJECTIVE_LIGHT_MATRIX		\
			, uniform float4  worldToProjLightMatrix0,	\
			uniform float4  worldToProjLightMatrix1,	\
			uniform float4  worldToProjLightMatrix2,	\
			uniform float4  worldToProjLightMatrix3

#else // (! (defined(PROJ_LIGHT_TEXTURE) || defined(SHADOW_MAP))

#define UNIFORM_WORLD_TO_PROJECTIVE_LIGHT_MATRIX

#endif // PROJ_LIGHT_TEXTURE || SHADOW_MAP


// Uniforms specific to shadow map.
//
#if defined(SHADOW_MAP)

#define UNIFORM_SHADOW_MAP_TEXTURE						\
			, uniform sampler shadowTex					\
			, uniform float3 shadowColor

#else // !defined(SHADOW_MAP)

#define UNIFORM_SHADOW_MAP_TEXTURE

#endif // SHADOW_MAP


// Uniforms specific to projective light texture.
//
#if defined(PROJ_LIGHT_TEXTURE)

#define UNIFORM_PROJ_LIGHT_TEXTURE						\
			, uniform sampler lightColorTex,			\
			uniform float lightIntensity,				\
			uniform float lightScale

#else // !defined(PROJ_LIGHT_TEXTURE)

#define UNIFORM_PROJ_LIGHT_TEXTURE

#endif // PROJ_LIGHT_TEXTURE

#if defined(BOUNDED_LIGHT)			
	#define UNIFORM_LIGHT_BOUNDS		\
			, uniform float3  wCorner1,	\
			uniform float3  wCorner2,	\
			uniform float3  wCorner3,	\
			uniform float3  wCorner4,	\
			uniform float3  wSpotDir	\
			UNIFORM_WORLD_TO_PROJECTIVE_LIGHT_MATRIX	\
			UNIFORM_SHADOW_MAP_TEXTURE					
#else
	#define UNIFORM_LIGHT_BOUNDS
#endif

// Uniforms specific to a given light type. Only one of these
// (POINT_LIGHT, SPOT_LIGHT, DIR_LIGHT, AMBIENT_LIGHT) should
// be enabled within a compile.
//
#if defined(POINT_LIGHT)

#define LIGHT_SPECIFIC_UNIFORMS					\
			, uniform float3  wLightPos			\
			UNIFORM_LIGHT_BOUNDS				\
            , uniform float4  lightDecayCoeff            

#elif defined(SPOT_LIGHT)

#define LIGHT_SPECIFIC_UNIFORMS							\
			, uniform float3  wLightPos,				\
            uniform float4  lightDecayCoeff,			\
			uniform float3  wSpotDir,					\
			uniform float	cosPenumbra,				\
			uniform float   cosUmbra,					\
			uniform float	radialDropOff				\
			UNIFORM_WORLD_TO_PROJECTIVE_LIGHT_MATRIX	\
			UNIFORM_SHADOW_MAP_TEXTURE					\
			UNIFORM_PROJ_LIGHT_TEXTURE


#elif defined(DIR_LIGHT)

#define LIGHT_SPECIFIC_UNIFORMS							\
			, uniform float3  wLightDir					\
			UNIFORM_WORLD_TO_PROJECTIVE_LIGHT_MATRIX	\
			UNIFORM_SHADOW_MAP_TEXTURE					


#elif defined(AMBIENT_LIGHT)

#define LIGHT_SPECIFIC_UNIFORMS					\
			,									\
			uniform float3  wLightPos,			\
			uniform float	ambientShade

#endif // Light-specific uniforms


//
// Main fragment program
//
float4 main(MAYA_phong_vert2frag   IN,
			uniform float4  gWorldEyePos,
#if !defined(TWO_SIDED_LIGHTING)						
			uniform float	normalMultiplier,	// -1 if normal needs to be inverted, 1 otherwise.
#endif			
			uniform float3	lightColor		// pre-multiplied by intensity.
			LIGHT_SPECIFIC_UNIFORMS
			
#if defined(CONSTANT_COLOR)
			, uniform float4	constantColor
#else
			, uniform sampler colorTex
			, uniform float4	colorTexMatrix0
			, uniform float4	colorTexMatrix1

			// Need to add these in for cube mapping.			
			//uniform float3 worldToCubeRotationMatrix0,
			//uniform float3 worldToCubeRotationMatrix1,
			//uniform float3 worldToCubeRotationMatrix2,
			
#if defined (PASS_TEX1_UV)
			, uniform sampler	pass2Tex
			, uniform float4	pass2TexMatrix0
			, uniform float4	pass2TexMatrix1
#endif
#if defined (PASS_TEX1_ALPHA_UV)
			, uniform sampler2D pass2AlphaTex
			, uniform float4	pass2AlphaTexMatrix0
			, uniform float4	pass2AlphaTexMatrix1
#else			
			, uniform float		pass2TexAlpha
#endif

#endif			
#if defined(CONSTANT_DIFFUSE)
			, uniform float	constantDiffuse
#else
			, uniform sampler diffuseTex
			, uniform float4	diffuseTexMatrix0
			, uniform float4	diffuseTexMatrix1
#endif
#if defined(CONSTANT_SPECULAR)
			, uniform float4 constantSpecular
#else
			, uniform sampler specTex
			, uniform float4	specTexMatrix0
			, uniform float4	specTexMatrix1
#endif
#if defined(BUMP_MAP) || defined (OBJECT_NORMAL)
			, uniform sampler bumpTex
			, uniform float4	bumpTexMatrix0,
			uniform float4	bumpTexMatrix1
#endif // BUMP_MAP || OBJECT_NORMAL

	#if defined(CONSTANT_TRANSPARENCY)
			, uniform float3 constantTransparency // Allow for colored transparency
	#else
			, uniform sampler transpTex
			, uniform float4	transpTexMatrix0
			, uniform float4	transpTexMatrix1
	#endif			
	
	#if defined(COMPUTE_TRANSLUCENCE)
			, uniform float		translucence
			, uniform float		translucenceFocus
			, uniform float		translucenceDepth
	#endif
	
	#if defined(BLINN_SHADING_MODEL)
			, uniform float		eccentricity
			, uniform float		specularRollOff
		#if defined(REFLECTED_SPECULAR)
			, uniform float		specularity
		#endif	
	#endif
	

			) : COLOR
{     
	// Compute the unnormalized light direction vector, expressed
    // in world space.
    //

#if defined(POINT_LIGHT) || defined(SPOT_LIGHT) || defined(AMBIENT_LIGHT)
    float3 wLightVector = (wLightPos - IN.wPosition.xyz).xyz;
    float3 wLightDir = normalize(wLightVector);
    
	#if defined(BOUNDED_LIGHT)
		float3 wLightVector1 = (wCorner1 - IN.wPosition.xyz).xyz;
		float3 wLightVector2 = (wCorner2 - IN.wPosition.xyz).xyz;
		float3 wLightVector3 = (wCorner3 - IN.wPosition.xyz).xyz;
		float3 wLightVector4 = (wCorner4 - IN.wPosition.xyz).xyz;

	    float3 wLightDir1 = normalize(wLightVector1);
	    float3 wLightDir2 = normalize(wLightVector2);
	    float3 wLightDir3 = normalize(wLightVector3);
	    float3 wLightDir4 = normalize(wLightVector4);

		// Analytic computation for a polygon
		float3 light_vector1 = acos( dot( wLightDir1, wLightDir2 )) * cross(wLightDir1, wLightDir2);
		float3 light_vector2 = acos( dot( wLightDir2, wLightDir3 )) * cross(wLightDir2, wLightDir3);
		float3 light_vector3 = acos( dot( wLightDir3, wLightDir4 )) * cross(wLightDir3, wLightDir4);
		float3 light_vector4 = acos( dot( wLightDir4, wLightDir1 )) * cross(wLightDir4, wLightDir1);
	#endif    
#elif defined(DIR_LIGHT)
	// do nothing. wLightDir is read from the uniform.
#endif // (POINT_LIGHT || SPOT_LIGHT || AMBIENT_LIGHT)

    // Calculate view direction in world space,
	// from point to eye.
    //
    float3 wViewDir = normalize(gWorldEyePos.xyz - IN.wPosition.xyz);

#if defined(TWO_SIDED_LIGHTING)
	float faceMultiplier = IN.frontColor.x > 0.3 ? 1.0 : -1.0;
#else
	float faceMultiplier = normalMultiplier;
#endif	

	///////////////////////////////////////////////////////////
	// Compute proper world space normal
	///////////////////////////////////////////////////////////
	MAYA_NormalInfoInput normin;
#if !defined(OBJECT_NORMAL)	
	normin.wNormal = IN.wNormal;
#endif	
	normin.faceMultiplier = faceMultiplier;
	#if defined(BUMP_MAP)
		normin.wTangent = IN.wTangent;
	#endif		
	#if defined(BUMP_MAP) || defined(OBJECT_NORMAL)
		normin.bumpTexUv = IN.bumpTexUv;
		normin.bumpTexMatrix0 = bumpTexMatrix0;
		normin.bumpTexMatrix1 = bumpTexMatrix1;
		normin.bumpTex = bumpTex;
	#endif	
	float3 wBumpedNormal = MAYA_computeWorldSpaceNormal( normin );

    // Compute (L dot N) :
    float LDotN = dot(wLightDir, wBumpedNormal);    
    float LDotNsigned = LDotN;
    
#if defined(POINT_LIGHT) 
	#if defined(BOUNDED_LIGHT)
		float LDotN1 = dot(wLightDir1, wBumpedNormal);    
		float LDotNsigned1 = LDotN1;
		LDotN1 = max(LDotN1, 0);

		float LDotN2 = dot(wLightDir2, wBumpedNormal);    
		float LDotNsigned2 = LDotN2;
		LDotN2 = max(LDotN2, 0);

		float LDotN3 = dot(wLightDir3, wBumpedNormal);    
		float LDotNsigned3 = LDotN3;
		LDotN3 = max(LDotN3, 0);

		float LDotN4 = dot(wLightDir4, wBumpedNormal);    
		float LDotNsigned4 = LDotN4;
		LDotN4 = max(LDotN4, 0);
	#endif		
#endif
    
#if !defined(AMBIENT_LIGHT)
    LDotN = max(LDotN, 0);
#endif // not ambient light

#if defined(SHADOW_MAP) || defined(PROJ_LIGHT_TEXTURE)
	// Transform the world space position into proj light space.
	// This is required for shadow maps or projective light texture
	// look-ups.
	//
	float4 projTexCoords;

	float4 pos = float4(IN.wPosition.xyz, 1);
	projTexCoords.x = dot(pos, worldToProjLightMatrix0);
	projTexCoords.y = dot(pos, worldToProjLightMatrix1);
	projTexCoords.z = dot(pos, worldToProjLightMatrix2);
	projTexCoords.w = dot(pos, worldToProjLightMatrix3);		
#endif // (SHADOW_MAP || PROJ_LIGHT_TEXTURE)


#if defined(PROJ_LIGHT_TEXTURE)
	// This is a spot light, where the light color comes from a 
	// projective texture. Fetch the color from that texture.
	//
	float2 projLightTexCoords = projTexCoords.xy / projTexCoords.w;
	projLightTexCoords = (projLightTexCoords - 0.5) * lightScale + 0.5;
	float3 attenuatedLightColor = lightIntensity * 
		tex2D(lightColorTex, projLightTexCoords).xyz ;
#else
	float3 attenuatedLightColor = lightColor;
#endif // PROJ_LIGHT_TEXTURE

#if defined(SHADOW_MAP)
	// Do the shadow distance comparison, to find out if the
	// current fragment is shadowed or not.
	float inShadow = tex2Dproj(shadowTex, projTexCoords);
	
	// Test code for multi-sampling a shadow map. Results are very poor.
	//float value = tex2Dproj(shadowTex, projTexCoords + float4(0.02, 0.02, 0 ,0));	
	//value += tex2Dproj(shadowTex, projTexCoords + float4(-0.02, 0.02, 0 ,0));	
	//value += tex2Dproj(shadowTex, projTexCoords + float4(0.02, -0.02, 0 ,0));	
	//value += tex2Dproj(shadowTex, projTexCoords + float4(-0.02, -0.02, 0,0));		
	//float inShadow = 0.25 * value;
	
	// Color the shadowed areas
	if (inShadow < 0.001)
		attenuatedLightColor.rgb = attenuatedLightColor * shadowColor;
	else
		attenuatedLightColor.rgb = attenuatedLightColor;
#endif // SHADOW_MAP

	// The attenuation is a dividing factor used to attenuate
	// the light source contribution.
	//
	float attenuation = 1;

#if defined(POINT_LIGHT) || defined(SPOT_LIGHT)
	// Compute the distance-from-light-source attenuation.
	// 
	float wLightDistance = length(wLightVector);

	// The following line could be optimized.
    attenuation = lightDecayCoeff.x + 
                lightDecayCoeff.y * wLightDistance + 
                lightDecayCoeff.z * wLightDistance * wLightDistance +
				lightDecayCoeff.w * wLightDistance * wLightDistance * wLightDistance;
				
	// Add special attenuation code for bounded lights ? [***]
        
	// Do not allow the light to have an attenuation factor greater than
	// 1, since this would make the light source appear too bright.
	//
    attenuation = max(attenuation, 1);    
#endif // (POINT_LIGHT || SPOT_LIGHT) distance-based attenuation.


	float spotRadialIntensity = 1;
#if defined(SPOT_LIGHT)
	// Compute the spot light's radial attenuation.
	// The spot cone of influence is divided into
	// two regions: the penumbra (outer region) and
	// umbra (inner region).
	// NOTE: at this point the penumbra angle is assumed
	// to be positive, and both the umbra and penumbra angle
	// are assumed to be greater than 0.
	//
	float SdotL = dot(wLightDir, wSpotDir);
	
	if (SdotL < cosPenumbra)
	{
		// The angle is larger than the total angle,
		// therefore it's outside of the cone.
		//
		spotRadialIntensity = 0;
	} 
	else
	{
		// Make an exponential decay over the inner region.
		//
		spotRadialIntensity = pow(SdotL, radialDropOff);

		if (SdotL < cosUmbra)
		{
			// Linearly interpolate between
			// the penumbra and umbra angle.
			//
			spotRadialIntensity = spotRadialIntensity * 
				(SdotL - cosPenumbra) / (cosUmbra - cosPenumbra);
		}
	}
#endif // SPOT_LIGHT

#if defined	(BOUNDED_LIGHT)
	#if defined(LIGHT_SHAPE_RECTANGLE)
	// Use this to clip the light against a hard plane. If we had volumes,
	// we could do volume level clipping as well with multiple planes.
	float SdotL = dot(wLightDir, wSpotDir);
	if (SdotL < 0)
		spotRadialIntensity = 0;
	#endif
#endif

    //
    // Compute attenuated light colour
    //
	attenuatedLightColor = attenuatedLightColor * spotRadialIntensity / attenuation;

    // Compute the base colour
    //
    MAYA_BaseInfoInput baseinput;
	float4 previousColor;
    #if defined(INTENSITY_ANGLE_COLOR_UVS)
        baseinput.intensityAngleColor = float4(1,1,1,1);
    #else    
	    #if defined(CONSTANT_COLOR)
	        // Constant colour
            baseinput.constantColor = constantColor;
        #else
            //
	        // Apply the appropriate color texture lookup
	        // then fetch the appropriate color texel.
	        //
            MAYA_ColorTxInfoInput ctinput;
	        #if defined(LIGHTANGLE_COLOR_UVS) || defined(CAMERA_ANGLE_COLOR_UVS) 	
	            #if defined(LIGHTANGLE_COLOR_UVS) 
                    ctinput.LDotNsigned = LDotNsigned;
                #endif
                #if defined(CAMERA_ANGLE_COLOR_UVS) 	
                    ctinput.wViewDir = wViewDir;         
                    ctinput.wBumpedNormal = wBumpedNormal;       
                #endif
            #else
                ctinput.colorTexUv = IN.colorTexUv;
                ctinput.colorTexMatrix0 = colorTexMatrix0;
                ctinput.colorTexMatrix1 = colorTexMatrix1;
            #endif    

			// Compute first texture lookup
			//

			#if defined(PASS_TEX0_ENV_SPHERE) 				
				baseinput.lookupVector = reflect(-wViewDir, wBumpedNormal); 
				//baseinput.lookupVector = wBumpedNormal * dot(wBumpedNormal, wViewDir) * 2.0 - wViewDir;
			#elif defined(PASS_TEX0_ENV_CUBE)
				float3 lookupVector;
				#if defined(PASS_NORMAL0_LOOKUP)
					baseinput.lookupVector = wBumpedNormal; 
				#else // #if defined(PASS_REFLECTION0_LOOKUP)
					baseinput.lookupVector = reflect(-wViewDir, wBumpedNormal); 
				#endif					
			#else
				baseinput.lookupVector = float3( MAYA_computeColorTextureLookup( ctinput ), 0.0 );
			#endif
			// Send first texture
            baseinput.colorTex = colorTex;

			// Compute second texture lookup
			//
			#if defined(PASS_TEX1_UV)
				#if  defined(PASS_TEX1_ENV_SPHERE)
					baseinput.lookupVector2 = reflect(-wViewDir, wBumpedNormal); 
				#elif defined(PASS_TEX1_ENV_CUBE)
					#if defined(PASS_NORMAL1_LOOKUP)
						baseinput.lookupVector2 = wBumpedNormal; 
					#else // #if defined(PASS_REFLECTION1_LOOKUP)
						baseinput.lookupVector2 = reflect(-wViewDir, wBumpedNormal); 
					#endif					
				#else
					// Extract uvs from packed float4.
					float2 placedColorTexUv;
					float4 tempUV = float4(IN.pass2TexUv.xy, 0.0, 1.0);
					placedColorTexUv.x = dot(pass2TexMatrix0, tempUV);
					placedColorTexUv.y = dot(pass2TexMatrix1, tempUV);
					baseinput.lookupVector2 = float3( placedColorTexUv, 0.0 );
				#endif
				// Send second texture
				baseinput.colorTex2 = pass2Tex;
			#endif
			
			// Compute alpha blend texture lookup
			//
			#if defined(PASS_TEX1_ALPHA_UV)
				// Extract uvs from packed float4.
				float4 tempUV2 = float4(IN.pass2TexUv.zw, 0.0, 1.0);
				placedColorTexUv.x = dot(pass2AlphaTexMatrix0, tempUV2);
				placedColorTexUv.y = dot(pass2AlphaTexMatrix1, tempUV2);
				baseinput.alphaTex2 = pass2AlphaTex;
				baseinput.placedAlphaTexUv2 = placedColorTexUv;
			#else
				baseinput.passAlpha2 = pass2TexAlpha;
			#endif

        #endif
        #if defined(COLOR_PER_VERTEX)
            baseinput.colorPerVertex = IN.colorPerVertex;
	        #if defined(COLOR_PER_VERTEX_MASK)
                baseinput.colorPerVertexMask = IN.colorPerVertexMask;
            #endif
        #endif
    #endif        
    float4 baseColor = MAYA_computeBaseColor( baseinput, previousColor );

	float3 diffuseAndAmbientColor;

//*** AMBIENT
#if defined(AMBIENT_LIGHT)
	////////////////////////////////////////////////////////////////////
	// Compute ambient only
	////////////////////////////////////////////////////////////////////

#if defined( COLOR_PER_VERTEX_AMBIENT )
	// Ambient color has been calculated in a separate ambient pass
	// which takes into account colour per vertex data.
	//
	diffuseAndAmbientColor = float3(0,0,0);
#else
	// Perform the ambient light's diffuse computation. Note that ambient
	// lights do not contribute to a specular component.
	//
	ambientShade = ambientShade * (LDotN - 1.0);
	float3 diffuseAndAmbientFactor = float3(lightColor * (1.0 + ambientShade).xxx);

	#if defined(INTENSITY_ANGLE_COLOR_UVS)
		float2 intensityLookup;
		intensityLookup.x = (diffuseAndAmbientFactor.x + diffuseAndAmbientFactor.y + diffuseAndAmbientFactor.z) / 3.0;
		intensityLookup.x = min(1.0, intensityLookup.x);
		intensityLookup.y = 0.5;
		diffuseAndAmbientColor = tex2D(colorTex, intensityLookup).xyz;
	#else
		diffuseAndAmbientColor = baseColor.rgb * diffuseAndAmbientFactor;
	#endif			
#endif
	float3  specularColor = float3(0,0,0);

//*** NON AMBIENT
#else
	////////////////////////////////////////////////////////////////////
	// Compute diffuse
	////////////////////////////////////////////////////////////////////
	//
	// Compute the diffuse coefficient
	//
	MAYA_DiffuseInfoInput dinput;
	#if defined(CONSTANT_DIFFUSE)
		dinput.constantDiffuse = constantDiffuse;
	#else
		dinput.diffuseTexUv = IN.diffuseTexUv;
		dinput.diffuseTexMatrix0 = diffuseTexMatrix0;
		dinput.diffuseTexMatrix1 = diffuseTexMatrix1;
		dinput.diffuseTex = diffuseTex;
	#endif
	float diffuseCoef = MAYA_computeDiffuseCoef(dinput);

	//
	// Compute the diffuse component
	//
	// Base diffuse factor.
#if defined(POINT_LIGHT)
	#if defined	(BOUNDED_LIGHT)

		#if defined(LIGHT_SHAPE_RECTANGLE)
			float diffuseFactor;

			// Note that spot direction doesn't really play any part in the direction of
			// the hilite, so is basically ignored here. It's the lights position, and 
			// dimensions which play the main factor.
			//
			// Point lights to get the spread.
			float NdotS = dot( wBumpedNormal, wSpotDir );
			diffuseFactor = (LDotN + LDotN1 + LDotN2 + LDotN3 + LDotN4) /5.0 * diffuseCoef;
			
			// Integration to handle dimensions. Fills in the center
			float light_val = dot( wBumpedNormal, light_vector1) + dot( wBumpedNormal, light_vector2 ) + 
								 dot( wBumpedNormal, light_vector3)  + dot( wBumpedNormal, light_vector4 );			
			diffuseFactor += light_val / (2.0 * 3.14159) * diffuseCoef;
		#else
			// Use this if not using the shape.
			float diffuseFactor = 2.0 * LDotN * max( dot(wLightDir, wSpotDir), 0.0);
			diffuseFactor += LDotN1 * max( dot(wLightDir1, wSpotDir), 0.0);
			diffuseFactor += LDotN2 * max( dot(wLightDir2, wSpotDir), 0.0);
			diffuseFactor += LDotN3 * max( dot(wLightDir3, wSpotDir), 0.0);
			diffuseFactor += LDotN4 * max( dot(wLightDir4, wSpotDir), 0.0);
			diffuseFactor *= diffuseCoef / 4.0;
		#endif
	#else		
		float diffuseFactor = diffuseCoef * LDotN;
	#endif		
#else		
	float diffuseFactor = diffuseCoef * LDotN;
#endif
	
	// Compute translucency if required.
	//
	#if defined(COMPUTE_TRANSLUCENCE)		
	if (translucence > 0.0)
	{
	    MAYA_translucenceInfo translinput;
	    translinput.LDotNsigned = LDotNsigned;
	    translinput.LDotN = LDotN;
	    translinput.wViewDir = wViewDir;
	    translinput.wLightDir = wLightDir;
	    translinput.translucence = translucence;
	    translinput.translucenceFocus = translucenceFocus;
	    translinput.translucenceDepth = translucenceDepth;
    	
	    float tlBright = MAYA_computeTranslucence( translinput );
	    diffuseFactor += tlBright;
	}
	#endif		

	#if defined(INTENSITY_ANGLE_COLOR_UVS) // Brightness
		float2 intensityLookup;
		attenuatedLightColor *= diffuseFactor;
		intensityLookup.x = (attenuatedLightColor.x + attenuatedLightColor.y + attenuatedLightColor.z) / 3.0;
		intensityLookup.x = min(1.0, intensityLookup.x);
		intensityLookup.y = 0.5;
		diffuseAndAmbientColor = tex2D(colorTex, intensityLookup).xyz;
	#else
		diffuseAndAmbientColor = attenuatedLightColor * baseColor.rgb * diffuseFactor;
	#endif	

	////////////////////////////////////////////////////////////////////
	// Compute specular
	////////////////////////////////////////////////////////////////////

	// Apply the placement specular color/exponent texture matrix, 
	// to the corresponding texture coordinates, then fetch the 
	// appropriate texel.
	//
	float	cosne = dot(wViewDir, wBumpedNormal);	
	float3  specularColor = float3(0,0,0);
	
	#if defined(CONSTANT_SPECULAR)
		float4 specValues = float4(constantSpecular.rgb, 1.0);
    #else
		float2	placedSpecTexUv;
		
		#if defined(REFLECTED_SPECULAR)
			float3	refVector = (cosne + cosne) * wBumpedNormal - wViewDir;
			float	LDotR = dot(wLightDir, refVector);
			float	specTexUv = 0.5f * (LDotR + 1.0);

			placedSpecTexUv.x = specTexUv * specTexUv * specTexUv;
			placedSpecTexUv.y = 0.5f;
		#else
			float4 specTexUv = float4(IN.specTexUv.xy, 0.0, 1.0);
			placedSpecTexUv.x = dot(specTexMatrix0, specTexUv);
			placedSpecTexUv.y = dot(specTexMatrix1, specTexUv);
		#endif

		float4 specValues = tex2D(specTex, placedSpecTexUv);
	#endif
	
#if defined(BLINN_SHADING_MODEL)
	//
	// Compute Blinn specular shading
	//		
	#if defined(POINT_LIGHT)
		#if defined	(BOUNDED_LIGHT)
			float3 specularColor2 = float3(0,0,0);
			float count = 0;
			
			MAYA_SpecularInfoInput specin;
			specin.wBumpedNormal = wBumpedNormal;
			specin.attenuatedLightColor = attenuatedLightColor;
			specin.wViewDir = wViewDir;
			specin.eccentricity = eccentricity;
			#if defined(REFLECTED_SPECULAR)
				specin.specularity = specularity;
			#else
				specin.specularRollOff = specularRollOff;
			#endif	
			specin.specValues = specValues;
			specin.cosne = cosne;

			specin.LDotN = max( LDotN, 0.001 );
			specin.wLightDir = wLightDir;
			specularColor2 += MAYA_computeBlinnSpecular( specin );
			count +=1 ;
			
			specin.LDotN = max( LDotN1, 0.001 );
			specin.wLightDir = wLightDir1;
			specularColor2 += MAYA_computeBlinnSpecular( specin );
			count +=1 ;

			specin.LDotN = max( LDotN2, 0.001 );
			specin.wLightDir = wLightDir2;
			specularColor2 += MAYA_computeBlinnSpecular( specin );
			count +=1 ;

			specin.LDotN = max( LDotN3, 0.001 );
			specin.wLightDir = wLightDir3;
			specularColor2 += MAYA_computeBlinnSpecular( specin );
			count +=1 ;

			specin.LDotN = max( LDotN4, 0.001 );
			specin.wLightDir = wLightDir4;
			specularColor2 += MAYA_computeBlinnSpecular( specin );
			count +=1 ;

			if (count > 0)
				specularColor2 = specularColor2 / count;
			specularColor = specularColor2;			
		#else
			MAYA_SpecularInfoInput specin;
			specin.wBumpedNormal = wBumpedNormal;
			specin.wLightDir = wLightDir;
			specin.attenuatedLightColor = attenuatedLightColor;
			specin.wViewDir = wViewDir;
			specin.eccentricity = eccentricity;
			#if defined(REFLECTED_SPECULAR)
				specin.specularity = specularity;
			#else
				specin.specularRollOff = specularRollOff;
			#endif	
			specin.specValues = specValues;
			specin.LDotN = max( LDotN, 0.001 );
			specin.cosne = cosne;
			specularColor = MAYA_computeBlinnSpecular( specin );
		#endif
	#else		
		MAYA_SpecularInfoInput specin;
		specin.wBumpedNormal = wBumpedNormal;
		specin.wLightDir = wLightDir;
		specin.attenuatedLightColor = attenuatedLightColor;
		specin.wViewDir = wViewDir;
		specin.eccentricity = eccentricity;
		#if defined(REFLECTED_SPECULAR)
			specin.specularity = specularity;
		#else
			specin.specularRollOff = specularRollOff;
		#endif	
		specin.specValues = specValues;
		specin.LDotN = max( LDotN, 0.001 );
		specin.cosne = cosne;
		specularColor = MAYA_computeBlinnSpecular( specin );
	#endif		
#else 
	//
	// Compute Phong specular shading
	//
	// - Clamp [R dot V] to the [0.001,1] range.
    // (Note: we don't clamp to [0,1] because
	// potential floating-point innaccuracies could
	// cause the value to become negative.
	// - R = light's reflection direction (R).
	//
	float3 wReflectDir = reflect(-wLightDir, wBumpedNormal);
    float RDotV = dot(wReflectDir, wViewDir);
    RDotV = max(RDotV, 0.001);    
	//if ( RDotV > 0.001 ) -- Doing this creates a clear circular band artifact.
	{
	    // Compute the specular exponent
	    #if defined(CONSTANT_SPECULAR)
			// The specular exponent is encoded in the alpha
			// of the specular color.
			float specularExp = constantSpecular.a; 
		#else				
			// The specular exponent (encoded in the alpha of the spec texture)
			// needs to be converted from the [0,1] to the [0,128] range.
			//
			float specularExp = specValues.a * 128;
		#endif	
	
		MAYA_SpecularInfoInput1 specin;
		specin.attenuatedLightColor = attenuatedLightColor;
		specin.RDotV = RDotV;
		specin.specularExp = specularExp;
		specin.specValues = specValues ;
		#if defined(COLOR_PER_VERTEX_SPECULAR)
			specin.colorPerVertex = IN.colorPerVertex;
			#if defined(COLOR_PER_VERTEX_MASK)		
				specin.colorPerVertexMask = IN.colorPerVertexMask;
			#endif
		#endif	
		
#if defined(POINT_LIGHT)
	#if defined	(BOUNDED_LIGHT)

		specularColor = float3(0.0, 0.0, 0.0);
		float3 specularColor2;

		float factor1 = dot( wBumpedNormal, wLightDir ); // cos(N,L)
		float factor2 = dot ( wLightDir, wSpotDir );  // cos(L,LD)
		float specFactor = factor1*factor2;
		
		float count = 1.0;		
		//specin.specularExp = specularExp * 2.2;
		specularColor2 = MAYA_computePhongSpecular(specin);		
		specularColor = specularColor2 ;

		specin.specularExp = specularExp;
		wReflectDir = reflect(-wLightDir1, wBumpedNormal);
		specin.RDotV = max( dot(wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(normalize(-wLightDir1 + -wLightDir2), wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir , wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(-wLightDir2, wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir , wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(normalize(-wLightDir2 + -wLightDir3), wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir , wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(-wLightDir3, wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(normalize(-wLightDir3 + -wLightDir4), wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir , wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(-wLightDir4, wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		wReflectDir = reflect(normalize(-wLightDir1 + -wLightDir4), wBumpedNormal);
		specin.RDotV = max( dot( wReflectDir , wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		

		#if defined(MORE_LIGHT_SAMPLES)
		wReflectDir = reflect(normalize(-wLightDir1 + -wLightDir), wBumpedNormal);
		specin.RDotV = max( dot(wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		
		wReflectDir = reflect(normalize(-wLightDir2 + -wLightDir), wBumpedNormal);
		specin.RDotV = max( dot(wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		
		wReflectDir = reflect(normalize(-wLightDir3 + -wLightDir), wBumpedNormal);
		specin.RDotV = max( dot(wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		
		wReflectDir = reflect(normalize(-wLightDir4 + -wLightDir), wBumpedNormal);
		specin.RDotV = max( dot(wReflectDir, wViewDir), 0.001);
		specularColor2 = MAYA_computePhongSpecular(specin);
		specularColor += specularColor2;
		count += 1.0;		
		#endif

		specularColor = specularColor / count;		
		//specularColor = specularColor * specFactor;

	#else
		specularColor = MAYA_computePhongSpecular(specin);			
	#endif		
#else
	specularColor = MAYA_computePhongSpecular(specin);
#endif
	}

#endif // BLINN_SHADING_MODEL

#endif // AMBIENT_LIGHT

	////////////////////////////////////////////////////////////////////
	// Compute transparency
	////////////////////////////////////////////////////////////////////
	float3 opacityColor;

	// The transparency texel can be interpreted in two different ways:
#if defined(OPACITY_IN_COLOR_ALPHA)
	// The opacity is encoded in the base color texture's alpha.
	// This mode is frequently used to combine the base color and
	// transparency in one texture.
	//
    #if defined(COLOR_PER_VERTEX)	
	    opacityColor = previousColor.aaa;
    #else	
	    opacityColor = baseColor.aaa;
    #endif	
	
#else	// TRANSP_IN_TRANSP_RGB

	#if defined(CONSTANT_TRANSPARENCY)
		// Passthrough constant transparency information
		//
		opacityColor = constantTransparency;

	#else
		MAYA_TranspLookupInfo input2;
		#if defined(CAMERA_ANGLE_TRANSP_UVS)		
		    float EDotN = dot(wViewDir, wBumpedNormal);
			EDotN = max(EDotN, 0.001);
			input2.EDotN = EDotN;
		#else
			input2.transpTexUv = IN.transpTexUv;
			input2.transpTexMatrix0 = transpTexMatrix0;
			input2.transpTexMatrix1 = transpTexMatrix1;
		#endif			
		input2.transpTex = transpTex;
		
		opacityColor = MAYA_lookupTexturedTransparency( input2 );
	#endif
#endif // OPACITY_IN_COLOR_ALPHA

#if defined(COLOR_PER_VERTEX)	
	// Get opacity based in incoming per-vertex alpha.
	float alphaValue = IN.colorPerVertex.a;		
	#if defined(COLOR_PER_VERTEX_MASK)	
		float alphaBit= IN.colorPerVertexMask.r;
	#else		
		float alphaBit = 1.0;
	#endif
	opacityColor = MAYA_computePerVertexAlpha(alphaValue, alphaBit, opacityColor);
#endif

	// Collect everything together to get the final colour.
	//
	float4 finalColor = MAYA_computeFinalColor(diffuseAndAmbientColor, specularColor, opacityColor);
	return finalColor;
}


