#define UBERSHADER

#if defined(_SHADERBUILDER_DEBUG)

//__________________________________________________________________________________________________

#pragma nu2_anchorPoint(attribute)

#pragma nu2_anchorPoint(varying)

struct FragmentOutput {
	float4 color[RENDER_TARGET_COUNT]	:COLOR0;
};

#if VERTEX_SHADER_VERSION>=20 && PIXEL_SHADER_VERSION >= 20
	#define STATIC static
#else
	#define STATIC
#endif

STATIC VertexInput		vin;
STATIC VertexOutput		vout;
STATIC FragmentOutput	fout;

#pragma nu2_anchorPoint(vs_local)

#pragma nu2_anchorPoint(fs_local)

#endif

//__________________________________________________________________________________________________

#define NO											0
#define YES											1

#define SURFACE_SMOOTH								0
#define SURFACE_NORMAL_MAP							1
#define SURFACE_PARALLAX_MAP						2
#define SURFACE_TANGENT_MAP							3
#define SURFACE_DISPLACEMENT_MAP					4
#define SURFACE_SELF_SHADOW_NORMAL_MAP				5

#define VTF_SMOOTH									0
#define VTF_NORMAL_MAP								1

#define DISABLE										0

#define COMBINE_OVER								1
#define COMBINE_ADD									2
#define COMBINE_SUBTRACT							3
#define COMBINE_MULTIPLY							4
#define COMBINE_BASE								5

#define LIGHTING_LAMBERT							1
#define LIGHTING_ENVMAP								2
#define LIGHTING_ANISO								3
#define LIGHTING_ANISO_WARD							4
#define LIGHTING_PHONG								5
#define LIGHTING_BRDF								6
#define LIGHTING_BRDF_PHONG							7
#define LIGHTING_SKIN								8
#define LIGHTING_EMISSIVE							9

#define LIGHTMAP_VERTEXLIT_PHONG					1
#define LIGHTMAP_VERTEXLIT_LAMBERT					2
#define LIGHTMAP_SMOOTH_LAMBERT						3
#define LIGHTMAP_SMOOTH_PHONG						4
#define LIGHTMAP_DIRECTIONAL_LAMBERT				5
#define LIGHTMAP_DIRECTIONAL_PHONG					6
#define LIGHTMAP_DIRECTIONAL_BRDF_LAMBERT			7
#define LIGHTMAP_DIRECTIONAL_BRDF_PHONG				8

#define FRESNEL_PERVERT_BRDF						1
#define FRESNEL_PERPIXEL_BRDF						2
#define FRESNEL_PERPIXEL							3

#define REFRACTION_DEFAULT							1
#define REFRACTION_WATER							2
#define REFRACTION_GLASS							3

#define ENVMAP_CUBE									1
#define ENVMAP_SPHERE								2
#define PS2_SHINEMAP								3
#define ENVMAP_CUBE_SM11							4

#define VERTEX_TRANSFORM							0
#define VERTEX_TRANSFORM_SKINNING					2
#define VERTEX_TRANSFORM_BLEND_ANIM_SKINNING_360	3
#define VERTEX_RAW									4
#define VERTEX_FETCH_DISPLACEMENT					5
#define CROSS_TANGENT_NORMAL						6
#define VERTEX_TRANSFORM_BLEND_ANIM_SKINNING		7
#define VERTEX_TRANSFORM_WATER						8
#define VERTEX_TRANSFORM_UNUSED2					11
#define VERTEX_TRANSFORM_UNUSED						12
#define VERTEX_FAST_BLEND							13

#define FROM_VS_RAW									0
#define FROM_VS_NORMALIZE							1
#define FROM_SURFACE_NORMAL							3
#define FROM_NORMAL_INCIDENT						4
#define FROM_DETAIL_SURFACE_NORMAL					5
#define FROM_VTF_NORMAL								6
#define FROM_SURFACE_AND_VTF_NORMALS				7

#define	VTF_SURFACE_SMOOTH                          0
#define	VTF_SURFACE_NORMAL_MAP                      1

#define UVSET_DEFAULT								1
#define UVSET_ANIMATION								2

#define MAX_VERTEX_GROUPS4							20 // effectively 20*4=80 vertex groups

#define FOG_LINEAR									1
#define FOG_EXPONENTIAL								2
#define FOG_EXPONENTIAL2							3
#define FOG_VERTEX_LINEAR							4
#define FOG_VERTEX_EXPONENTIAL						5
#define FOG_VERTEX_EXPONENTIAL2						6
#define FOG_VERTEX_CLAMP_EXPONENTIAL2				7
#define FOG_VERTEX_CLAMP_EXPONENTIAL2_PS3			8
#define FOG_VERTEX_PLANAR_EXPONENTIAL2				9

#define WATERCOEF_DEFAULT							1
#define WATERCOEF_AMPLITUDE							2

#if defined(HLSL_LANGUAGE)
#define iNliNE inline
#else
#define iNliNE
#endif

//__________________________________________________________________________________________________

string description = "Uber Shader v2.0";

// Forward function declarations
float3 projectModelToEyeSpace(float3 v);
float4 computeWorldPosition(float4x4 worldMtx);

#pragma nu2_anchorPoint(uniform) // uniforms are printed here


#define worldViewInverseTranspose	worldView
#define vs_viewInverseTranspose		vs_view


// Attribute declarations___________________________________________________________________________

#pragma nu2_declare(attribute, float4,	position,		semantic_position)		// position of the vertex in object space
#pragma nu2_declare(attribute, float4,	position1,		semantic_position1)
#pragma nu2_declare(attribute, half4,	normal,			semantic_normal)		// normal in object space
#pragma nu2_declare(attribute, half4,	tangent,		semantic_tangent)		// tangent in object space
#pragma nu2_declare(attribute, half4,	tangent2,		semantic_tangent1)		// layer 2 tangent in object space
#pragma nu2_declare(attribute, half3,	bitangent,		semantic_bitangent)		// bitangent in object space

#pragma nu2_declare(attribute, half2,	uvSet0, 		semantic_texcoord0)
#pragma nu2_declare(attribute, half2,	uvSet2, 		semantic_texcoord1)
#pragma nu2_declare(attribute, half4,	uvSet01, 		semantic_texcoord0)		// 2 uvsets in one attribute
#pragma nu2_declare(attribute, half4,	uvSet23, 		semantic_texcoord1)		// 2 uvsets in one attribute

#pragma nu2_declare(attribute, half4,	colorSet0, 		semantic_color0)
#pragma nu2_declare(attribute, half4,	colorSet1, 		semantic_color1)
#pragma nu2_declare(attribute, half4,	colorSet2, 		semantic_texcoord0)
#pragma nu2_declare(attribute, half4,	colorSet3, 		semantic_texcoord1)

#pragma nu2_declare(attribute, half4,	random,   		semantic_texcoord5)
#pragma nu2_declare(attribute, half3,	lightDirSet,   	semantic_texcoord6)
#pragma nu2_declare(attribute, half4,	lightColSet,   	semantic_texcoord7)

#pragma nu2_declare(attribute, half4,	blendWeight0,	semantic_blendWeight0)
#pragma nu2_declare(attribute, half4,	blendIndices0,	semantic_blendIndices0)
#pragma nu2_declare(attribute, half3,	blendOffsets0,	semantic_position1)

#pragma nu2_declare(attribute, int,		index,			semantic_index)

// Varying declarations____________________________________________________________________________

#pragma nu2_declare(varying, float4, varying_position, semantic_position)// vertex position in NDC in vertex shader only
#pragma nu2_declare(varying, float3, varying_eyePosition, default)		// vertex position in NDC in vertex shader only
#pragma nu2_declare(varying, float3, varying_modelPosition, default)    // untransformed vertex position in model space
#pragma nu2_declare(varying, float,  varying_world_y, default)          // y position in world space

#pragma nu2_declare(varying, float3, varying_normal, default)			// normal in eye space
#pragma nu2_declare(varying, float3, varying_tangent, default)			// tangent in eye space
#pragma nu2_declare(varying, float3, varying_tangent2, default)			// layer 2 tangent in eye space
#pragma nu2_declare(varying, float3, varying_bitangent, default)			// bitangent in eye space
#pragma nu2_declare(varying, float3, varying_worldReflection, default)	// rotated world reflection vector in world space (inacurate and wrong in some situations)
#pragma nu2_declare(varying, float3, varying_worldReflectionRot, default)// rotated world reflection vector in world space (inacurate and wrong in some situations)

#pragma nu2_declare(varying, float,  varying_VertexOpacity, default)

#pragma nu2_declare(varying, float2, varying_uvSet0, default)
#pragma nu2_declare(varying, float2, varying_uvSet1, default)
#pragma nu2_declare(varying, float2, varying_uvSet2, default)
#pragma nu2_declare(varying, float2, varying_uvSet3, default)
#pragma nu2_declare(varying, float2, varying_uvSet4, default)
#pragma nu2_declare(varying, float2, varying_uvSet5, default)
#pragma nu2_declare(varying, float2, varying_uvSet6, default)
#pragma nu2_declare(varying, float2, varying_uvSetN, default)			// this is a copy of the uvset matching SURFACE_UVSET: necessary on ps1.0 graphics
																		// cards which cannot use the same uvset on 2 different texture lookup
#pragma nu2_declare(varying, float3, varying_uvSetGlass, default)

#pragma nu2_declare(varying, float4, varying_colorSet0, semantic_colorx)
#pragma nu2_declare(varying, float4, varying_colorSet1, semantic_colorx)

#if PIXEL_SHADER_VERSION != 14
#else
	// ps_1_4 can only sample the color registers on the 2nd phase. Since we use varying_colorSet1 to store
	// the layer alphas, this makes it difficult to do the layer blending on the first phase.
	// Add some float1 declarations for layer opacities, that are packed into texcoords. I'm not making this
	// generic because packing these alpha into texcoords would waste the 2nd color interpolant
	#pragma nu2_declare(varying, float, varying_layer1alpha, default)
	#pragma nu2_declare(varying, float, varying_layer2alpha, default)
	#pragma nu2_declare(varying, float, varying_layer3alpha, default)
#endif
#pragma nu2_declare(varying, float4, varying_colorSet2, default)
#pragma nu2_declare(varying, float4, varying_colorSet3, default)

#pragma nu2_declare(varying, float3, varying_lightDirSet,   default)		// average light direction for prelit specular and bump fx.
#pragma nu2_declare(varying, float4, varying_lightColSet,   default)		// incident light colour for prelit specular and bump fx.

#pragma nu2_declare(varying, float4, varying_lightDir0, default)			// light direction in eye space
#pragma nu2_declare(varying, float4, varying_lightDir1, default)			// light direction in eye space
#pragma nu2_declare(varying, float4, varying_lightDir2, default)			// light direction in eye space

#pragma nu2_declare(varying, float4, varying_position2, default)			// fragment position in normalized device coordinates
#pragma nu2_declare(varying, float, varying_positionX, default)				// fragment position in normalized device coordinates
#pragma nu2_declare(varying, float, varying_positionY, default)				// fragment position in normalized device coordinates
#pragma nu2_declare(varying, float, varying_positionZ, default)				// fragment position in normalized device coordinates
#pragma nu2_declare(varying, float, varying_positionW, default)				// fragment position in normalized device coordinates
#pragma nu2_declare(varying, float, varying_positionOneOverW, default)		// fragment position in normalized device coordinates

#pragma nu2_declare(varying, float, varying_fog, semantic_fog)
#pragma nu2_declare(varying, float, varying_fogFactor, default)			// fog factor computed per vertex (value between 0.0 and 1.0)
#pragma nu2_declare(varying, float, varying_ps3FogParams, FOG)			// fog params (ps3)

#pragma nu2_declare(varying, float2, varying_shineMapCoord, default)

#pragma nu2_declare(varying, float4, varying_newClipPosition, default)
#pragma nu2_declare(varying, float4, varying_oldClipPosition, default)

#pragma nu2_declare(varying, float,  varying_eyeDistance, default)       // distance from the fragment to the eye position          

#pragma nu2_declare(varying, float,  varying_lodFactor, default)			// lod factor: 0 means no lod, 1 means the lod has been reached

#pragma nu2_declare(varying, float,  varying_waterAmplitude, default)	// water amplitude for use in fragment shader to modulate normal maps


#pragma nu2_declare(varying, float4, varying_wind, default)				// wind vector
#pragma nu2_declare(varying, float4, varying_plantParams, default)		// plant parameters

#pragma nu2_declare(varying, float4, varying_brdfData, default)			// incident vector in tangent space and sqrt(ndotv) in w component

#pragma nu2_declare(varying, float, varying_vertexFresnel, default)

// Local variables ____________________________________________________________________________

#pragma nu2_declare(vs_local, float4, vs_skinPosition, default)			// vertex in object space
#pragma nu2_declare(vs_local, float4, vs_eyePosition, default)			// vertex in eye space
#pragma nu2_declare(vs_local, half3, vs_normal, default)				// normal in eye space
#pragma nu2_declare(vs_local, half3, vs_tangent, default)				// tangent in eye space
#pragma nu2_declare(vs_local, half3, vs_tangent2, default)				// layer 2 tangent in eye space
#pragma nu2_declare(vs_local, half3, vs_bitangent, default)				// bitangent in eye space
#pragma nu2_declare(vs_local, half3, vs_bitangent2, default)			// layer 2 bitangent in eye space
#pragma nu2_declare(vs_local, half3, vs_incident, default)				// incident vector in eye space
#pragma nu2_declare(vs_local, half4, vs_brdfData, default)				// incident vector in tangent space and sqrt(ndotv) in w component
#pragma nu2_declare(vs_local, half3, vs_reflection, default)			// reflection vector in eye space
#pragma nu2_declare(vs_local, half3x3, vs_TBN, default)					// TBN matrix
#pragma nu2_declare(vs_local, half2, vs_uvSet0, default)
#pragma nu2_declare(vs_local, half2, vs_uvSet1, default)
#pragma nu2_declare(vs_local, half2, vs_uvSet2, default)
#pragma nu2_declare(vs_local, half2, vs_uvSet3, default)
#pragma nu2_declare(vs_local, int,   vs_skinMatrixOffset, default)		// offset used to access either current or previous frame skin matrices
#pragma nu2_declare(vs_local, half,  vs_randomSeed, default)			// random seed in [0; 1] per vertex
#pragma nu2_declare(vs_local, half,  vs_waterIndex, default)			// water index in [0; 32] per vertex
#pragma nu2_declare(vs_local, half,  vs_waterAmplitude, default)		// water amplitude in [0; 1] per vertex
#pragma nu2_declare(vs_local, half4, vs_waterCoef, default)				// water coef computed from waterTable, waterIndex and waterAmplitude
#pragma nu2_declare(vs_local, half4, vs_plantParams, default)			// plant parameters
#pragma nu2_declare(vs_local, half4x4, vs_worldViewInverseTranspose, default)	// this matrix is the same as the uniform worldViewInverseTranspose, except that it is computed in the vertex shader

#pragma nu2_declare(fs_local, half4, fs_surfaceNormal, default)
#pragma nu2_declare(fs_local, half3, fs_vtfNormal, default)
#pragma nu2_declare(fs_local, half2, fs_stOffset, default)
#pragma nu2_declare(fs_local, half,  fs_displacementHeight, default)	// TT Animation displacement map height value
#pragma nu2_declare(fs_local, half3, fs_nativeNormal, default)			// normalized normal in world space from the vertex shader
#pragma nu2_declare(fs_local, half3, fs_normal, default)				// normal in eye space, can come from normal map, been displaced, etc...
#pragma nu2_declare(fs_local, half3, fs_specularNormal, default)        // Blend between fs_nativeNormal and fs_normal used for specular lighting.
#pragma nu2_declare(fs_local, half3, fs_tangent, default)				// eye space
#pragma nu2_declare(fs_local, half3, fs_tangent2, default)				// eye space
#pragma nu2_declare(fs_local, half3, fs_bitangent, default)				// eye space
#pragma nu2_declare(fs_local, half3, fs_bitangent2, default)			// eye space
#pragma nu2_declare(fs_local, half3, fs_worldReflection, default)		// world space
#pragma nu2_declare(fs_local, half3, fs_lightDirSet, default)			// eye space
#pragma nu2_declare(fs_local, half4, fs_lightCol, default)			
#pragma nu2_declare(fs_local, half3x3, fs_TBN, default)
#pragma nu2_declare(fs_local, half4, fs_lightDir0, default)				// eye space
#pragma nu2_declare(fs_local, half4, fs_lightDir1, default)				// eye space
#pragma nu2_declare(fs_local, half4, fs_lightDir2, default)				// eye space
#pragma nu2_declare(fs_local, half4, fs_specLightDir0, default)			// eye space
#pragma nu2_declare(fs_local, half4, fs_specLightDir1, default)			// eye space
#pragma nu2_declare(fs_local, half4, fs_specLightDir2, default)			// eye space
#pragma nu2_declare(fs_local, half4, fs_layer0_color, default)
#pragma nu2_declare(fs_local, half,	 fs_layer1_alpha, default)			// alpha value for layer 1
#pragma nu2_declare(fs_local, half,	 fs_layer2_alpha, default)
#pragma nu2_declare(fs_local, half,  fs_layer3_alpha, default)
#pragma nu2_declare(fs_local, half4, fs_fog_color, default)
#pragma nu2_declare(fs_local, half3, fs_adjustedVertexColor, default)
#pragma nu2_declare(fs_local, half,  fs_blend2, default)				// blend factor for interpolating layer 1 and layer 2 normal and specular maps
#pragma nu2_declare(fs_local, half,  fs_vertexOpacity, default)			// per-vertex opacity that will fade out effects such as refraction and specular as well as surface colour
#pragma nu2_declare(fs_local, half,  fs_lightingIntensityFactor, default) // per-vertex scale factor for lighting to increase range and accuracy of lighting

#pragma nu2_declare(fs_local, half3, fs_incident, default)				// incident vector in eye space, from fragment to viewer
#pragma nu2_declare(fs_local, half2, fs_surfaceIncident, default)		// incident vector in tangent space, from fragment to viewer
#pragma nu2_declare(fs_local, half3, fs_surfaceIncident2, default)		// incident vector in layer 2 tangent space, from fragment to viewer
#pragma nu2_declare(fs_local, half4, fs_brdfData, default)				// incident vector in tangent space, from fragment to viewer, with sqrt(NdotV) in w component
#pragma nu2_declare(fs_local, half3, fs_lightmapNormal, default)		// normal used to blend lightmaps

#pragma nu2_declare(fs_local, float3, fs_pos, default)					// fragment position in normalized device coordinates after perspective division [-1; 1][-1; 1][0; 1]
#pragma nu2_declare(fs_local, half2, fs_vpos, default)					// fragment position in pixel units

#pragma nu2_declare(fs_local, half,  fs_dappleFactor, default)			// dapple factor computed from varying normal length.

#pragma nu2_declare(fs_local, half,  fs_fbm0, default)					// result of fractal fBm call on the current model position.

#pragma nu2_declare(fs_local, half,  fs_ldotn0raw, default)				// Ali precomputed dot product
#pragma nu2_declare(fs_local, half,  fs_ldotn1raw, default)				// Ali precomputed dot product
#pragma nu2_declare(fs_local, half,  fs_ldotn2raw, default)				// Ali precomputed dot product
#pragma nu2_declare(fs_local, half,  fs_ldotn0, default)				// Ali precomputed dot product
#pragma nu2_declare(fs_local, half,  fs_ldotn1, default)				// Ali precomputed dot product
#pragma nu2_declare(fs_local, half,  fs_ldotn2, default)				// Ali precomputed dot product

#pragma nu2_declare(fs_local, half,  fs_lodFactor, default)				// lod factor (1.0 if none)

#if !defined(MOTION_BLUR_PASS)
#include "fog.hlsl"
#endif

#include "hdr.hlsl"

struct AnisotropicSurfaceProperties
{
	half3	anisoBasis;
	half3	anisoBasisS;
	half	vdotb;
	half	vbf;
};

//__________________________________________________________________________________________________
// 
// Fragment shader functions...
//__________________________________________________________________________________________________


#if !defined(MOTION_BLUR_PASS)

#if defined(USE_SHADOWMAP) || defined(USE_FORWARD_DYNAMIC_LIGHTS)
// [ SHADOWMAPS] /////////////////////////////////////////////////////

#include "deferredFilterLighting.hlsl"

float GetShadowIntensity(float4 P, int lightIndex)
{
#if !defined(USE_SHADOWMAP) || defined(DONT_RECEIVE_SHADOW)

	return 0;

#else

	g_LightIndex = lightIndex;

	half outShadowIntensity = 0;

	// Calculate fragment position in view space
	half4 fragPosViewSpace = P;

	// Calculate fragment position in light space
	float4 fragPosLightSpace = 0;
	SoftShadowParams softShadowParams;
	if (lightIndex==0)
		fragPosLightSpace = ProjectToShadowMapCascade(fragPosViewSpace, softShadowParams);
	else
		fragPosLightSpace = ProjectToShadowMapCube(fragPosViewSpace, softShadowParams);

	// Compare fragment against the shadowmap
	if (lightIndex==0)
		outShadowIntensity = LookupShadowmap(fragPosLightSpace, fragPosViewSpace, softShadowParams);
	else
		outShadowIntensity = LookupShadowmapCube(fragPosLightSpace, fragPosViewSpace, softShadowParams);

	// Apply overall shadow intensity factor
	outShadowIntensity *= GetCommon().shadowFactors.x;

	// Attenuate shadow intensity
	outShadowIntensity *= CalculateViewSpaceAttenuation(fragPosViewSpace);

	return outShadowIntensity;
#endif
}

void ComputeDynamicLightingContribution(	half3 specularIntensity, 
											AnisotropicSurfaceProperties anisoSurfaceProperties,
											inout half shadowFactor, 
											out half3 outDiffuseLight, 
											out half3 outSpecularLight)
{
	outDiffuseLight  = 0;
	outSpecularLight = 0;

// The expression I really wanted is :
//
//	#if (!defined(DONT_RECEIVE_SHADOW) && defined(USE_SHADOWMAP)) || defined(USE_FORWARD_DYNAMIC_LIGHTS)
// 
// however this confuses our preprocessor, specifically it can't handle '(!'.

#if defined(USE_SHADOWMAP) || defined(USE_FORWARD_DYNAMIC_LIGHTS)
#if !defined(DONT_RECEIVE_SHADOW) || defined(USE_FORWARD_DYNAMIC_LIGHTS)

	#pragma nu2_use(varying, varying_positionX)
	#pragma nu2_use(varying, varying_positionY)
	#pragma nu2_use(varying, varying_positionW)

	#pragma nu2_use(uniform, fs_inverse_projection_xy)
	#pragma nu2_use(uniform, fs_frustum_params)
	#pragma nu2_use(uniform, specular_params)

	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_specularNormal)

	float2 pos = float2(varying_positionX, varying_positionY) / varying_positionW;

	float4 P = float4(varying_positionX, varying_positionY, varying_positionW, 1);
	P.xy = P.xy * fs_inverse_projection_xy.xy + fs_inverse_projection_xy.zw * varying_positionW;

	half2 uvCoords = pos.xy * half2(0.5, -0.5) + 0.5;

	float3 dynamicSurfaceColor = 0;
	shadowFactor = 1;

#if defined(USE_FORWARD_DYNAMIC_LIGHTS)

	half halfLambertFactor = 0;
	half diffuseMultiplier = 1.0f;

	#if (LIGHTING_MODEL == LIGHTING_SKIN)
		#pragma nu2_use(uniform, brdf_params)
		halfLambertFactor = specular_params.a;
		diffuseMultiplier = brdf_params.a;
	#endif

	// Directional light
	#if defined(USE_FORWARD_DIRECTIONAL_LIGHT)
	{
		float shadowIntensity = GetShadowIntensity(P, 0);

		float3 L = -g_Light.posDirRadius;

		half3 dirDiffuseLight = 0;
		half3 dirSpecularLight = 0;

		#if (LIGHTING_MODEL == LIGHTING_ANISO)
			ComputeLightingAnisotropic(	L, P, fs_normal, fs_specularNormal, 1-shadowIntensity, 
										g_Light,
										anisoSurfaceProperties,
										specular_params.r, specularIntensity, halfLambertFactor,
										dirDiffuseLight, dirSpecularLight);
		#else
			ComputeLighting(	L, P, fs_normal, fs_specularNormal, 1-shadowIntensity, 
								g_Light,
								specular_params.r, specularIntensity, halfLambertFactor,
								dirDiffuseLight, dirSpecularLight);
		#endif

		outDiffuseLight += dirDiffuseLight * diffuseMultiplier;
		outSpecularLight += dirSpecularLight;
	}
	#endif

	// Point light
	#if defined(USE_FORWARD_POINT_LIGHT)
	{
		float shadowIntensity = GetShadowIntensity(P, 1);

		half3 L = g_Light1.posDirRadius.xyz - P.xyz;

		// Normalise light direction
		half attenuationDistance = length(L);
		L = normalize(L);

		half attenuationFactor = 1.0;
		attenuationFactor *= saturate(attenuationDistance * g_Light1.posDirRadius.w + g_Light1.color.a);

		half3 pointDiffuseLight = 0;
		half3 pointSpecularLight = 0;
		
		#if (LIGHTING_MODEL == LIGHTING_ANISO)
			ComputeLightingAnisotropic(	L, P, fs_normal, fs_specularNormal, 1-shadowIntensity, 
										g_Light1,
										anisoSurfaceProperties,
										specular_params.r, specularIntensity, halfLambertFactor,
										pointDiffuseLight, pointSpecularLight);
		#else
			ComputeLighting(	L, P, fs_normal, fs_specularNormal, 1-shadowIntensity, 
								g_Light1,
								specular_params.r, specularIntensity, halfLambertFactor,
								pointDiffuseLight, pointSpecularLight);
		#endif

		outDiffuseLight += (pointDiffuseLight * attenuationFactor * diffuseMultiplier);
		outSpecularLight += (pointSpecularLight * attenuationFactor);
	}
	#endif

#elif defined(USE_SHADOWMAP)
	
	// LEGO supports shadow-only lights still

	#if !defined(DONT_RECEIVE_SHADOW)
	
		float3 L = -g_ShadowCommon.lightDirPos;

		float NL = dot(L, fs_normal);

		static const float threshold = 0.2;

		float shadowIntensity = 0;

		#if (LIGHTMAP_STAGE == DISABLE)
			if (NL<0)
			{
				shadowIntensity = GetCommon().shadowFactors.x * CalculateViewSpaceAttenuation(P);
			}
			else
			{
				shadowIntensity = max(GetShadowIntensity(P, 0), (1 - saturate(abs(NL) / threshold)) * GetCommon().shadowFactors.x);
			}
		#else
			// Don't do any self-shading on lightmapped geometry
			shadowIntensity = GetShadowIntensity(P, 0);
		#endif

		shadowFactor = 1 - shadowIntensity;

	#endif

#endif
#endif
#endif
}

// [ SHADOWMAPS] /////////////////////////////////////////////////////
#endif // USE_SHADOWMAP

//__________________________________________________________________________________________________

#if defined(LIGHTMAP_STAGE) && (LIGHTMAP_STAGE != DISABLE)
	#if (LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_PHONG)
		#if (PIXEL_SHADER_VERSION == 11 && defined(COMBINE_OP_0) && !defined(LAYER0_DIFFUSEENABLE))
		sampler2D lightmap0 : register(s1);
		#else
		sampler2D lightmap0 : register(s0);
		#endif
	//#elif (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_PHONG)
	#else 
		// We declare the lightmaps samplers even for vert-lit materials because when we encounter a lightmap display
		// list item we have no way of knowing whether we need to the textures or not, so we upload them every time.
		// Failing to do this will result in vert-lit materials having their diffuse/normal/specular maps replaced by
		// lightmaps (resulting in a tiled view of a lightmap)
		// This would no longer be required if we seperate the lightmap item which uploads the textures from the
		// instance data (offsets and mesh instance ID) AND if we made the lightmap items stored per clipitem
		// rather than per clipobject (half a clip object can be vert-lit and half texture-lit)
		sampler2D lightmap0 : register(s0);
		sampler2D lightmap1 : register(s1);
		sampler2D lightmap2 : register(s2);
	#endif
#endif

// Fixed lightmap directions (best 3 vectors to cover +Z hemi-sphere)
#define lmDir1 half3(	-0.4082482904,	-0.7071067811,	0.5773502691);
#define lmDir2 half3(	-0.4082482904,	0.7071067811,	0.5773502691);
#define lmDir3 half3(	0.8164965809,	0.0,			0.5773502691);

//__________________________________________________________________________________________________

#if (COMBINE_OP_1 != DISABLE)
iNliNE half4 combine1(in half4 src, in half4 dst)
{
	#if (COMBINE_OP_1 == COMBINE_OVER)
		#if defined(ALPHA_BLENDED)
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, dst.a + src.a - (dst.a * src.a));
		#else
//			return dst * (1.0 - src.a) + src * src.a;
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, 1.0);
		#endif
	#endif
	#if (COMBINE_OP_1 == COMBINE_ADD)
		return half4(dst.rgb + src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_1 == COMBINE_SUBTRACT)
		return half4(dst.rgb - src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_1 == COMBINE_MULTIPLY)
		half i = 1.0 - src.a;
		return half4(dst.rgb * (src.rgb * src.a + half3(i, i, i)), dst.a);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if (COMBINE_OP_2 != DISABLE)
iNliNE half4 combine2(in half4 src, in half4 dst)
{
	#if (COMBINE_OP_2 == COMBINE_OVER)
		#if defined(ALPHA_BLENDED)
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, dst.a + src.a - (dst.a * src.a));
		#else
//			return dst * (1.0 - src.a) + src * src.a;
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, 1.0);
		#endif
	#endif
	#if (COMBINE_OP_2 == COMBINE_ADD)
		return half4(dst.rgb + src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_2 == COMBINE_SUBTRACT)
		return half4(dst.rgb - src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_2 == COMBINE_MULTIPLY)
		half i = 1.0 - src.a;
		return half4(dst.rgb * (src.rgb * src.a + half3(i, i, i)), dst.a);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if (COMBINE_OP_3 != DISABLE)
iNliNE half4 combine3(in half4 src, in half4 dst)
{
	#if (COMBINE_OP_3 == COMBINE_OVER)
		#if defined(ALPHA_BLENDED)
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, dst.a + src.a - (dst.a * src.a));
		#else
//			return dst * (1.0 - src.a) + src * src.a;
			return half4(dst.rgb * (1.0 - src.a) + src.rgb * src.a, 1.0);
		#endif
	#endif
	#if (COMBINE_OP_3 == COMBINE_ADD)
		return half4(dst.rgb + src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_3 == COMBINE_SUBTRACT)
		return half4(dst.rgb - src.rgb * src.a, dst.a);
	#endif
	#if (COMBINE_OP_3 == COMBINE_MULTIPLY)
		half i = 1.0 - src.a;
		return half4(dst.rgb * (src.rgb * src.a + half3(i, i, i)), dst.a);
	#endif
}

//__________________________________________________________________________________________________
#endif

iNliNE half4 multiLayerBlendingStage(out half4 albedo)
{
	#pragma nu2_use(uniform, layer0_diffuse)
	half4 surfaceColour;
	
	#if !defined(COMBINE_OP_0)
		surfaceColour = layer0_diffuse;
	#else
		#if defined(LAYER0_DIFFUSEENABLE)
			// Material coloured base layer
			//#if (PIXEL_SHADER_VERSION <= 14)
			//	surfaceColour = half4(1.0, 1.0, 1.0, layer0_diffuse.a);
			//#else
				surfaceColour = layer0_diffuse;
			//#endif
		#else
			// Diffuse textured base layer
			#pragma nu2_use(uniform, layer0_sampler)
			#pragma nu2_use(varying, * LAYER0_UVSET)

			#if defined(TEXTURE_ANIMATION_MAP)
				// Apply texture animation morphing
				#pragma nu2_use(uniform, texAnimMap_sampler)
				#pragma nu2_use(uniform, texAnimCurves_sampler)
				#pragma nu2_use(uniform, time)
				#pragma nu2_use(varying, varying_plantParams);

				half4 dmap = tex2D(texAnimMap_sampler, LAYER0_UVSET_VAL);
				half2 uv = half2(frac(time.x*dmap.a*varying_plantParams.r), dmap.b);
		
				half s = tex2D(texAnimCurves_sampler, uv).r;
				surfaceColour = tex2D(layer0_sampler, LAYER0_UVSET_VAL + dmap.rg*s) * layer0_diffuse;
			#else
				#if defined(USE_fs_stOffset)
					surfaceColour = tex2D(layer0_sampler, LAYER0_UVSET_VAL + fs_stOffset) * layer0_diffuse;
				#else
					surfaceColour = tex2D(layer0_sampler, LAYER0_UVSET_VAL) * layer0_diffuse;
				#endif

				#if defined(HDRALPHA_DIFFUSE)
					surfaceColour.rgb *= (1.0 + 5.0*surfaceColour.a);
					surfaceColour.a = 1.0;
				#endif
			#endif
		#endif

	#endif
	
	#if defined(CAR_PAINT)
		#pragma nu2_use(fs_local, fs_normal)
		#pragma nu2_use(fs_local, fs_incident)
		#pragma nu2_use(fs_local, fs_lightDir0)
		#pragma nu2_use(uniform, carpaint_tints)
		#pragma nu2_use(uniform, carpaint_params)
		half ndotl = saturate(dot(fs_normal, fs_lightDir0.xyz));
		half ndotv = abs( dot(fs_normal, fs_incident) );
		ndotl = pow( ndotl, carpaint_params.g );
		ndotv = pow( ndotv, carpaint_params.r );	
		half3 paintTint = lerp( lerp(carpaint_tints[0],carpaint_tints[1],ndotl), lerp(carpaint_tints[2],carpaint_tints[3],ndotl), ndotv );
		paintTint = paintTint * 2.0 - 1.0;
		surfaceColour.rgb += paintTint;
	#endif
	
	#if (COMBINE_OP_1 != DISABLE)
		#pragma nu2_use(uniform, layer1_diffuse)
		#pragma nu2_use(fs_local, fs_layer1_alpha)		
		#if defined(LAYER1_DIFFUSEENABLE)
			// Blend in material coloured layer 1
			half4 colorLayer1 = layer1_diffuse;
			half colorLayer1a = saturate(colorLayer1.a * fs_layer1_alpha);
		#else
			// Blend in diffuse textured layer 1
			#pragma nu2_use(uniform, layer1_sampler)
			#pragma nu2_use(varying, * LAYER1_UVSET)
			#if defined(USE_fs_stOffset)
				half4 colorLayer1 = tex2D(layer1_sampler, LAYER1_UVSET_VAL + fs_stOffset);
			#else
				half4 colorLayer1 = tex2D(layer1_sampler, LAYER1_UVSET_VAL);
			#endif

			half colorLayer1a = saturate(colorLayer1.a * layer1_diffuse.a * fs_layer1_alpha);
		#endif
		surfaceColour = combine1(half4(colorLayer1.rgb, colorLayer1a), surfaceColour);
	#endif

	#if (COMBINE_OP_2 != DISABLE)
		#pragma nu2_use(uniform, layer2_diffuse)
		#pragma nu2_use(fs_local, fs_layer2_alpha)		
		#if defined(LAYER2_DIFFUSEENABLE)
			// Blend in material coloured layer 2
			half4 colorLayer2 = layer2_diffuse;
			half colorLayer2a = saturate(colorLayer2.a * fs_layer2_alpha);
		#else
			// Blend in diffuse textured layer 2
			#pragma nu2_use(uniform, layer2_sampler)
			#pragma nu2_use(varying, * LAYER2_UVSET)
			#if defined(USE_fs_stOffset)
				half4 colorLayer2 = tex2D(layer2_sampler, LAYER2_UVSET_VAL + fs_stOffset);
			#else
				half4 colorLayer2 = tex2D(layer2_sampler, LAYER2_UVSET_VAL);
			#endif

			half colorLayer2a = saturate(colorLayer2.a * layer2_diffuse.a * fs_layer2_alpha);
		#endif
		surfaceColour = combine2(half4(colorLayer2.rgb, colorLayer2a), surfaceColour);
	#endif

	#if (COMBINE_OP_3 != DISABLE)
		#pragma nu2_use(uniform, layer3_diffuse)
		#pragma nu2_use(fs_local, fs_layer3_alpha)
		#if defined(LAYER3_DIFFUSEENABLE)
			// Blend in material coloured layer 3
			half4 colorLayer3 = layer3_diffuse;
			half colorLayer3a = saturate(colorLayer3.a * fs_layer3_alpha);
		#else
			// Blend in diffuse textured layer 3
			#pragma nu2_use(uniform, layer3_sampler)
			#pragma nu2_use(varying, * LAYER3_UVSET)
			#if defined(USE_fs_stOffset)
				half4 colorLayer3 = tex2D(layer3_sampler, LAYER3_UVSET_VAL + fs_stOffset);
			#else
				half4 colorLayer3 = tex2D(layer3_sampler, LAYER3_UVSET_VAL);
			#endif

			half colorLayer3a = saturate(colorLayer3.a * layer3_diffuse.a * fs_layer3_alpha);
		#endif
		surfaceColour = combine3(half4(colorLayer3.rgb, colorLayer3a), surfaceColour);
	#endif
	
	#if defined(DAPPLE)
		#pragma nu2_use(fs_local, fs_dappleFactor)
		surfaceColour.rgb *= fs_dappleFactor;
	#endif
	
	#if defined(FRACTAL)
		#pragma nu2_use(fs_local, fs_fbm0)
		#pragma nu2_use(uniform, fractal_params)
		surfaceColour.rgb *= (1.0 + fractal_params.a * fs_fbm0);
	#endif

	#if SURFACE_TYPE == SURFACE_DISPLACEMENT_MAP
		// Adjust final brightness based upon the displacement height.
		#pragma nu2_use(fs_local, fs_displacementHeight)
		surfaceColour.rgb *= (0.6 + fs_displacementHeight * 0.4);
	#endif
	
	#if (LIGHTMAP_STAGE != DISABLE) || defined(AMBIENT_OCCLUSION)

		// Grab the albedo before we factor in any vertex colour which may contain lighting information.
		albedo = surfaceColour;

		// Include the just vertex alpha.
		#pragma nu2_use(fs_local, fs_vertexOpacity)
		surfaceColour.a *= fs_vertexOpacity;
	#else
		// Factor in both the vertex colour and alpha.
		#pragma nu2_use(fs_local, fs_vertexOpacity)
		#pragma nu2_use(fs_local, fs_layer0_color)
		surfaceColour.rgb *= fs_layer0_color.rgb;

		// Grab the albedo before we factor in any vertex colour which may contain lighting information.
		// [UPDATE] For non-lightmapped and non-ambient occluded stuff, the vertex colour is effectively albedo, not lighting.
		// So we need to multiply it in here, so that deferred lighting works correctly for LEGO materials (which are vertex
		// coloured).
		albedo = surfaceColour;

		surfaceColour.a *= fs_vertexOpacity;
	#endif

	return surfaceColour;
}


//__________________________________________________________________________________________________

#if (LIGHTING_MODEL == LIGHTING_PHONG) || (LIGHTING_MODEL == LIGHTING_BRDF_PHONG) || (LIGHTING_MODEL == LIGHTING_SKIN)
iNliNE half3 phongSpecularStage()
{
	#if LIGHTING_LIGHTS_COUNT <= 0
		// there are no lights
		return half3(0.0, 0.0, 0.0);		
	#endif

	//#if (PIXEL_SHADER_VERSION <= 14)
	//	// pixel shader 1.1 - simulate the specular effect using the phong environment texture
	//	#pragma nu2_use(uniform, averageLightColor)
	//	#pragma nu2_use(varying, varying_worldReflectionRot)
	//	#pragma nu2_use(uniform, envmap_samplerCube)
	//	#pragma nu2_use(uniform, specular_params)
	//	half4 envTexel = texCUBE(envmap_samplerCube, varying_worldReflectionRot);
	//	return envTexel.rgb * specular_params.g * averageLightColor;
	//#endif

	//#if (PIXEL_SHADER_VERSION == 20 || PIXEL_SHADER_VERSION == 21)
	//	// pixel shader 2.0 - compute the specular effect using the average live light direction and colour
	//	#pragma nu2_use(uniform, averageLightColor)
	//	#pragma nu2_use(uniform, averageLightDir)
	//	#pragma nu2_use(uniform, specular_params)
	//	#pragma nu2_use(fs_local, fs_incident)
	//	#pragma nu2_use(fs_local, fs_specularNormal)

	//	half3 R2 = reflect(-averageLightDir.xyz, fs_specularNormal);

	//	half3 specularPhong = averageLightColor.rgb * pow(saturate(dot(fs_incident, R2)), specular_params.r);

	//	return specularPhong * specular_params.g;

	//#endif

	#if (PIXEL_SHADER_VERSION >= 30)

		#pragma nu2_use(uniform, specular_params)

		#if defined(ENABLE_SEPARATE_SPECULAR_LIGHTS)
			#pragma nu2_use(uniform, specLightColor0)
			#pragma nu2_use(uniform, specLightColor1)
			#pragma nu2_use(uniform, specLightColor2)
			#pragma nu2_use(fs_local, fs_specLightDir0)
			#pragma nu2_use(fs_local, fs_specLightDir1)
			#pragma nu2_use(fs_local, fs_specLightDir2)
		#else
			#pragma nu2_use(uniform, lightColor0)
			#pragma nu2_use(uniform, lightColor1)
			#pragma nu2_use(uniform, lightColor2)
			#pragma nu2_use(fs_local, fs_lightDir0)
			#pragma nu2_use(fs_local, fs_lightDir1)
			#pragma nu2_use(fs_local, fs_lightDir2)
			
			#define specLightColor0		lightColor0
			#define specLightColor1		lightColor1
			#define specLightColor2		lightColor2
			#define fs_specLightDir0	fs_lightDir0
			#define fs_specLightDir1	fs_lightDir1
			#define fs_specLightDir2	fs_lightDir2
		#endif

		#pragma nu2_use(fs_local, fs_incident)
		#pragma nu2_use(fs_local, fs_specularNormal)

		half3 specularPhong;
		half3 RI = reflect(fs_incident.xyz, fs_specularNormal);

		half4 dots = half4( dot(-fs_specLightDir0.xyz, RI), dot(-fs_specLightDir1.xyz, RI), dot(-fs_specLightDir2.xyz, RI), 1.0);
		
		dots = saturate(dots);
		dots = pow(dots,specular_params.r);

		#if (LIGHTING_LIGHTS_COUNT > 0)
			specularPhong = specLightColor0.rgb * (dots.x * specLightColor0.a);
		#endif

		#if (LIGHTING_LIGHTS_COUNT > 1)
			specularPhong += specLightColor1.rgb * (dots.y * specLightColor1.a);
		#endif

		#if (LIGHTING_LIGHTS_COUNT > 2)
			specularPhong += specLightColor2.rgb * (dots.z * specLightColor2.a);
		#endif
		
		return specularPhong * specular_params.g;
	
	#endif	
}

//__________________________________________________________________________________________________
#endif

#if (PIXEL_SHADER_VERSION <= 14) 
iNliNE bool lightingStageSM1( float fresnel, out half3 diffuseLight, out half3 specularLight, out half3 specularLightDE )
{
	diffuseLight	= 1;
	specularLight	= 0;
	specularLightDE = 0;
	bool lightingWasEnabled = false;

	//--------------------------------------------------------------------------------
	// Bump mapping
	//--------------------------------------------------------------------------------
	half bumpMapFactor = 1;

	#if SURFACE_TYPE == SURFACE_NORMAL_MAP
		
		lightingWasEnabled = true;

		#pragma nu2_use(fs_local, fs_surfaceNormal)
		// Note: The .z is compressed a lot more than the .xy. On next-gen we rely on the normal getting
		//		 renormalized to get back the precision.
		bumpMapFactor = saturate(1 - 0.5 * dot(fs_surfaceNormal.xy, fs_surfaceNormal.xy));
	#endif

	#if SURFACE_TYPE == SURFACE_SELF_SHADOW_NORMAL_MAP
		//#pragma nu2_use(fs_local, fs_surfaceNormal)
		//diffuseLight *= dot(fs_surfaceNormal, half3(1,1,1));
	#endif

	#if (LIGHTMAP_STAGE != DISABLE)
		//--------------------------------------------------------------------------------
		// Lightmapping
		//--------------------------------------------------------------------------------

		lightingWasEnabled = true;

		#if (LIGHTMAP_STAGE == LIGHTMAP_VERTEXLIT_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_VERTEXLIT_LAMBERT)
			// Vertex lit only - colour will be factored in below
			half3 lightmapCol = 1;
		#endif

		#if (LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_LAMBERT || LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_PHONG)
			#pragma nu2_use(varying, * LIGHTMAP_UVSET)
			#pragma nu2_use(uniform, lightmap0)
			// Read single RGB light-map
			half3 lightmapCol = tex2D(lightmap0, LIGHTMAP_UVSET_VAL).rgb;
		#endif
	
		// Apply bump mapping
		lightmapCol *= bumpMapFactor;

		// Here we account for the per-vertex colour and range of the lighting
		#pragma nu2_use(varying, varying_colorSet0)
		// Here we need the following :
		//		varying_colorSet0.rgb * varying_colorSet0.a * 10
		// However this doesn't map well to ps_1_4 instructions.
		// We can do this instead : 10 = 0.625 * 2 * 8
		// This maps to  _x2, _x8 and a multiply with 0.625 (which meets the [-1,1] literal requirement)
		// The x0.625 has been done in the vertex shader to save PS instructions.
		lightmapCol *= varying_colorSet0.rgb * (varying_colorSet0.a * 2);
		lightmapCol *= 8;

		// Add diffuse lighting
		diffuseLight = lightmapCol;

	#elif LIGHTING_MODEL != DISABLE

		// Apply bump mapping
		diffuseLight = bumpMapFactor;

	#endif

	return lightingWasEnabled;
}
#endif

//__________________________________________________________________________________________________

iNliNE void lightingStage( float fresnel, out half3 diffuseLight, out half3 specularLight, out half3 specularLightDE, out half shadowFactor,
						   out half3 albedoTweakDE, out half3 albedoTweakDES )
{
	diffuseLight	= 0;
	specularLight	= 0;
	specularLightDE = 0;
	shadowFactor	= 1;
	albedoTweakDE   = 0;
	albedoTweakDES  = 0;

	bool lightingWasEnabled = false;

	#if (LIGHTING_MODEL == LIGHTING_EMISSIVE)

		// Emissive lighting model; doesn't react to any kind of light (live, lightmap, dynamic or otherwise)
		diffuseLight = 1;

	#elif (PIXEL_SHADER_VERSION <= 14)

		if (lightingStageSM1(fresnel, diffuseLight, specularLight, specularLightDE))
		{
			lightingWasEnabled = true;
		}

	#else

		//--------------------------------------------------------------------------------
		// Lightmapping
		//--------------------------------------------------------------------------------
		#if (LIGHTMAP_STAGE == DISABLE)

			#if (LIGHTING_STAGE == DISABLE)
				// No lighting contribution
				diffuseLight = half3(1.0f, 1.0f, 1.0f);
			#endif

		#else

			lightingWasEnabled = true;

			#if (LIGHTMAP_STAGE == LIGHTMAP_VERTEXLIT_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_VERTEXLIT_LAMBERT)
				// Vertex lit only - colour will be factored in below
				half3 lightmapCol = half3(1,1,1);
			#endif

			#if (LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_LAMBERT || LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_PHONG)
				#pragma nu2_use(varying, * LIGHTMAP_UVSET)
				#pragma nu2_use(uniform, lightmap0)
				// Read single RGB light-map
				half3 lightmapCol = tex2D(lightmap0, LIGHTMAP_UVSET_VAL).rgb;
			#endif

			#if (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_PHONG)
				#pragma nu2_use(varying, * LIGHTMAP_UVSET)
				#pragma nu2_use(uniform, lightmap0)
				#pragma nu2_use(uniform, lightmap1)
				#pragma nu2_use(uniform, lightmap2)
				#pragma nu2_use(fs_local, fs_lightmapNormal)
	
				// Read directional lightmaps
				half3 lmcol1 = tex2D(lightmap0, LIGHTMAP_UVSET_VAL).rgb;
				half3 lmcol2 = tex2D(lightmap1, LIGHTMAP_UVSET_VAL).rgb;
				half3 lmcol3 = tex2D(lightmap2, LIGHTMAP_UVSET_VAL).rgb;
			
				half3 lightmapWeights = fs_lightmapNormal;

				#if (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_LAMBERT) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_PHONG)
					// Bias normal vector used for lighting (based upon view vector and smoothness)
					#pragma nu2_use(fs_local, fs_brdfData)
					#pragma nu2_use(uniform, brdf_params)
					lightmapWeights.xyz *= fs_brdfData.xyz * brdf_params.x;
				#endif
			
				// Calculate diffuse contribution
				half3 lightmapCol = lmcol1.rgb * lightmapWeights.x + lmcol2.rgb * lightmapWeights.y + lmcol3.rgb * lightmapWeights.z;
			#endif

			// Multiply light-map by vertex colour
			#pragma nu2_use(fs_local, fs_layer0_color)
			
			// Here we account for the per-vertex colour and range of the lighting
			#pragma nu2_use(fs_local, fs_lightingIntensityFactor)
			#pragma nu2_use(fs_local, fs_layer0_color)
			lightmapCol *= fs_layer0_color.rgb * fs_lightingIntensityFactor;

			#if (LIGHTMAP_STAGE == LIGHTMAP_SMOOTH_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_DIRECTIONAL_BRDF_PHONG) || (LIGHTMAP_STAGE == LIGHTMAP_VERTEXLIT_PHONG)
				#pragma nu2_use(uniform, specular_params)
				#pragma nu2_use(fs_local, fs_lightDirSet)
				#pragma nu2_use(fs_local, fs_lightCol)
				#pragma nu2_use(fs_local, fs_normal)
				
				float NdotH = saturate(dot(fs_normal, fs_lightDirSet.xyz));
				float SpecLightStr = pow( NdotH, specular_params.r ) * specular_params.g; // Raise to power and scale by pre-calculate 'energy conserving' factor
				half3 lightmapSpec = fs_lightCol.rgb * SpecLightStr;
				specularLight = lightmapSpec;
			#endif	
				
			// Add diffuse lighting
			diffuseLight = lightmapCol;

		#endif

		//--------------------------------------------------------------------------------
		// Diffuse lighting
		//--------------------------------------------------------------------------------
		#if (LIGHTING_MODEL == LIGHTING_LAMBERT) || (LIGHTING_MODEL == LIGHTING_PHONG) || (LIGHTING_MODEL == LIGHTING_WARD) || (LIGHTING_MODEL == LIGHTING_BRDF)
				
			// Lambertian diffuse lighting
			#if LIGHTING_LIGHTS_COUNT > 0
				lightingWasEnabled = true;
				#pragma nu2_use(uniform, lightColor0)
				#pragma nu2_use(fs_local, fs_ldotn0)
				diffuseLight += fs_ldotn0 * lightColor0.rgb;
			#endif

			#if LIGHTING_LIGHTS_COUNT > 1
				#pragma nu2_use(uniform, lightColor1)
				#pragma nu2_use(fs_local, fs_ldotn1)
				diffuseLight += fs_ldotn1 * lightColor1.rgb;
			#endif

			#if LIGHTING_LIGHTS_COUNT > 2
				#pragma nu2_use(uniform, lightColor2)
				#pragma nu2_use(fs_local, fs_ldotn2)
				diffuseLight += fs_ldotn2 * lightColor2.rgb;
			#endif

		#endif

		#if (LIGHTING_MODEL == LIGHTING_SKIN)
			// Skin diffuse lighting
			#pragma nu2_use(uniform, specular_params)
			#pragma nu2_use(uniform, brdf_params)
			half3 skinLight;

			#if LIGHTING_LIGHTS_COUNT > 0

				lightingWasEnabled = true;

				#pragma nu2_use(uniform, lightColor0)
				#pragma nu2_use(fs_local, fs_ldotn0)
				#pragma nu2_use(fs_local, fs_ldotn0raw)
				skinLight  = saturate( lightColor0.rgb * lerp(fs_ldotn0, fs_ldotn0raw * 0.5 + 0.5, specular_params.a) );
			#endif

			#if LIGHTING_LIGHTS_COUNT > 1
				#pragma nu2_use(uniform, lightColor1)
				#pragma nu2_use(fs_local, fs_ldotn1)
				#pragma nu2_use(fs_local, fs_ldotn1raw)
				skinLight += saturate( lightColor1.rgb * lerp(fs_ldotn1, fs_ldotn1raw * 0.5 + 0.5, specular_params.a) );
			#endif

			#if LIGHTING_LIGHTS_COUNT > 2
				#pragma nu2_use(uniform, lightColor2)
				#pragma nu2_use(fs_local, fs_ldotn2)
				#pragma nu2_use(fs_local, fs_ldotn2raw)
				skinLight += saturate( lightColor2.rgb * lerp(fs_ldotn2, fs_ldotn2raw * 0.5 + 0.5, specular_params.a) );
			#endif

			diffuseLight += skinLight * brdf_params.a;
 
		#endif

		//--------------------------------------------------------------------------------
		// Phong specular
		//--------------------------------------------------------------------------------
		#if (LIGHTING_MODEL == LIGHTING_PHONG) || (LIGHTING_MODEL == LIGHTING_BRDF_PHONG) || (LIGHTING_MODEL == LIGHTING_SKIN)
			lightingWasEnabled = true;
			specularLight += phongSpecularStage();
		#endif
		
		//--------------------------------------------------------------------------------
		// Ward lighting
		// Specular highlights that stretch in the T and B directions
		//--------------------------------------------------------------------------------
		#if (LIGHTING_MODEL == LIGHTING_WARD)
			#pragma nu2_use(uniform, specular_params)
			#pragma nu2_use(fs_local, fs_incident)
			#pragma nu2_use(fs_local, fs_normal)		
			#pragma nu2_use(fs_local, fs_tangent)
			#pragma nu2_use(fs_local, fs_bitangent)	
			
			#if defined(ENABLE_SEPARATE_SPECULAR_LIGHTS)
				#pragma nu2_use(uniform, specLightColor0)
				#pragma nu2_use(fs_local, fs_specLightDir0)
			#else
				#pragma nu2_use(uniform, lightColor0)
				#pragma nu2_use(fs_local, fs_lightDir0)
				
				#define specLightColor0		lightColor0
				#define fs_specLightDir0	fs_lightDir0
			#endif

			lightingWasEnabled = true;

			half3 Hn = normalize( fs_incident + fs_specLightDir0.xyz );
			half a = 0.3;
			half b = 0.1;
			half s = 0.8;
			half2 ab = half2(1/a,1/b);
			half2 top = half2( dot(Hn,fs_tangent), dot(Hn,fs_bitangent) );
			top = top * ab;
			half bottom = dot(Hn,fs_normal);
			half power = dot(top,top) / (bottom*bottom);
			half spec = (s / (4*3.142)) * (1/(a*b)) * pow( 2.718, -power );
			specularLight += specLightColor0.rgb * specular_params.g * spec * specLightColor0.a;		
		#endif
			
		//--------------------------------------------------------------------------------
		// Kajiya-Kay lighting
		// Treats surface normal as 'fin' direction for hair/fur
		//--------------------------------------------------------------------------------
		#if (LIGHTING_MODEL == LIGHTING_KAJIYAKAY)
			#pragma nu2_use(uniform, lightColor0)
			#pragma nu2_use(uniform, specular_params)
			#pragma nu2_use(fs_local, fs_lightDir0)
			#pragma nu2_use(fs_local, fs_incident)
			#pragma nu2_use(fs_local, fs_normal)
			#pragma nu2_use(fs_local, fs_tangent)
			
			lightingWasEnabled = true;

			half ldott = dot(fs_lightDir0.xyz, fs_tangent);
			half kajiyaKayDiffuse = clamp( sqrt(1.0-ldott*ldott), 0.0, 1.0);
			half phongDiffuse = clamp( dot(fs_lightDir0.xyz, fs_normal), 0.0, 1.0f);
			half diffuse = kajiyaKayDiffuse * 0.5 + phongDiffuse * 0.5;

			diffuseLight = lightColor0 * diffuse * fs_lightDir0.w;			

			half3 Hn = normalize( fs_lightDir0.xyz + fs_incident );
			half hdott = dot(Hn,fs_tangent);
			half specular = clamp( pow( sqrt( 1.0 - hdott*hdott ), specular_params.r * 10 ), 0.0, 1.0);
			specularLight += lightColor0.rgb * specular_params.g * specular * clamp( dot( fs_normal, fs_lightDir0.xyz ) * 30, 0.0, 1.0 ) * lightColor0.a; // Remove back facing specular
		#endif
		
		//--------------------------------------------------------------------------------
		// Anisotropic lighting
		// Simulates tangent aligned grooves (e.g. CD, brushed hair/fur such as that on a horse)
		//--------------------------------------------------------------------------------
		#if (LIGHTING_MODEL == LIGHTING_ANISO)
		
			lightingWasEnabled = true;

			// Common anisotropic initialisation code for both diffuse and specular components.
			half ldotb0,  ldotb1,  ldotb2,  ad0,  ad1,  ad2;
			half ldotb0s, ldotb1s, ldotb2s, ad0s, ad1s, ad2s;
			
			AnisotropicSurfaceProperties anisoSurfaceProperties;

			#pragma nu2_use(fs_local, fs_specularNormal)
		
			#pragma nu2_use(fs_local, fs_normal)
			#pragma nu2_use(fs_local, fs_incident)
			#if defined(ANISO_FLIP)
				#pragma nu2_use(fs_local, fs_tangent)
				anisoSurfaceProperties.anisoBasis = cross(fs_tangent, fs_normal);
				anisoSurfaceProperties.anisoBasisS = cross(fs_tangent, fs_specularNormal);
			#else
				#pragma nu2_use(fs_local, fs_bitangent)
				anisoSurfaceProperties.anisoBasis = cross(fs_bitangent, fs_normal);
				anisoSurfaceProperties.anisoBasisS = cross(fs_bitangent, fs_specularNormal);
			#endif
				
			#if defined(ENABLE_SEPARATE_SPECULAR_LIGHTS)

				#if LIGHTING_LIGHTS_COUNT > 0
					#pragma nu2_use(uniform, specLightColor0)
					#pragma nu2_use(fs_local, fs_specLightDir0)
				#endif

				#if LIGHTING_LIGHTS_COUNT > 1
					#pragma nu2_use(uniform, specLightColor1)
					#pragma nu2_use(fs_local, fs_specLightDir1)
				#endif

				#if LIGHTING_LIGHTS_COUNT > 2
					#pragma nu2_use(uniform, specLightColor2)
					#pragma nu2_use(fs_local, fs_specLightDir2)
				#endif

			#else

				#if LIGHTING_LIGHTS_COUNT > 0
					#pragma nu2_use(uniform,	lightColor0)
					#pragma nu2_use(fs_local,	fs_lightDir0)
					#define specLightColor0		lightColor0
					#define fs_specLightDir0	fs_lightDir0
				#endif

				#if LIGHTING_LIGHTS_COUNT > 1
					#pragma nu2_use(uniform,	lightColor1)
					#pragma nu2_use(fs_local,	fs_lightDir1)
					#define specLightColor1		lightColor1
					#define fs_specLightDir1	fs_lightDir1
				#endif

				#if LIGHTING_LIGHTS_COUNT > 2
					#pragma nu2_use(uniform,	lightColor2)
					#pragma nu2_use(fs_local,	fs_lightDir2)
					#define specLightColor2		lightColor2
					#define fs_specLightDir2	fs_lightDir2
				#endif

			#endif

			#if LIGHTING_LIGHTS_COUNT > 0
				#pragma nu2_use(uniform, lightColor0)
				#pragma nu2_use(fs_local, fs_lightDir0)
				#pragma nu2_use(fs_local, fs_ldotn0)

				ldotb0 = dot(fs_lightDir0.xyz, anisoSurfaceProperties.anisoBasis) * fs_lightDir0.w;
				ad0 = sqrt(1.0 - ldotb0 * ldotb0);
				ldotb0s = dot(fs_specLightDir0.xyz, anisoSurfaceProperties.anisoBasisS) * fs_specLightDir0.w;
				ad0s = sqrt(1.0 - ldotb0s * ldotb0s);
			#endif

			#if LIGHTING_LIGHTS_COUNT > 1
				#pragma nu2_use(uniform, lightColor1)
				#pragma nu2_use(fs_local, fs_lightDir1)
				#pragma nu2_use(fs_local, fs_ldotn1)

				ldotb1 = dot(fs_lightDir1.xyz, anisoSurfaceProperties.anisoBasis) * fs_lightDir1.w;
				ad1 = sqrt(1.0 - ldotb1 * ldotb1);
				ldotb1s = dot(fs_specLightDir1.xyz, anisoSurfaceProperties.anisoBasisS) * fs_specLightDir1.w;
				ad1s = sqrt(1.0 - ldotb1s * ldotb1s);
			#endif

			#if LIGHTING_LIGHTS_COUNT > 2
				#pragma nu2_use(uniform, lightColor2)
				#pragma nu2_use(fs_local, fs_lightDir2)
				#pragma nu2_use(fs_local, fs_ldotn2)

				ldotb2 = dot(fs_lightDir2.xyz, anisoSurfaceProperties.anisoBasis) * fs_lightDir2.w;
				ad2 = sqrt(1.0 - ldotb2 * ldotb2);
				ldotb2s = dot(fs_specLightDir2.xyz, anisoSurfaceProperties.anisoBasisS) * fs_specLightDir2.w;
				ad2s = sqrt(1.0 - ldotb2s * ldotb2s);
			#endif

			// Calculate the anisotropic diffuse component.
			#if (LIGHTMAP_STAGE == DISABLE)

				#if LIGHTING_LIGHTS_COUNT > 0
					#pragma nu2_use(fs_local, fs_ldotn0)
					diffuseLight += lightColor0 * ad0 * fs_ldotn0;
				#endif

				#if LIGHTING_LIGHTS_COUNT > 1
					#pragma nu2_use(fs_local, fs_ldotn1)
					diffuseLight += lightColor1 * ad1 * fs_ldotn1;
				#endif

				#if LIGHTING_LIGHTS_COUNT > 2
					#pragma nu2_use(fs_local, fs_ldotn2)
					diffuseLight += lightColor2 * ad2 * fs_ldotn2;
				#endif

			#endif

			// Calculate the anisotropic specular component.
			#pragma nu2_use(uniform, specular_params)
			half3 aniso = half3(0.0, 0.0, 0.0);
			anisoSurfaceProperties.vdotb = dot(fs_incident, anisoSurfaceProperties.anisoBasisS);
			anisoSurfaceProperties.vbf = sqrt(1.0 - (anisoSurfaceProperties.vdotb * anisoSurfaceProperties.vdotb));
			half base;

			#if LIGHTING_LIGHTS_COUNT > 0
				half ldotn0s = saturate(dot(fs_specLightDir0.xyz, fs_specularNormal)) * fs_specLightDir0.w;
				base = max(0.0000001, ad0s * anisoSurfaceProperties.vbf - (ldotb0s * anisoSurfaceProperties.vdotb));
				aniso += ldotn0s * specLightColor0.rgb * pow(base, specular_params.r) * specLightColor0.a;				
			#endif
			#if LIGHTING_LIGHTS_COUNT > 1
				half ldotn1s = saturate(dot(fs_specLightDir1.xyz, fs_specularNormal)) * fs_specLightDir1.w;
				base = max(0.0000001, ad1s * anisoSurfaceProperties.vbf - (ldotb1s * anisoSurfaceProperties.vdotb));
				aniso += ldotn1s * specLightColor1.rgb * pow(base, specular_params.r) * specLightColor1.a;				
			#endif
			#if LIGHTING_LIGHTS_COUNT > 2
				half ldotn2s = saturate(dot(fs_specLightDir2.xyz, fs_specularNormal)) * fs_specLightDir2.w;
				base = max(0.0000001, ad2s * anisoSurfaceProperties.vbf - (ldotb2s * anisoSurfaceProperties.vdotb));
				aniso += ldotn2s * specLightColor2.rgb * pow(base, specular_params.r) * specLightColor2.a;				
			#endif
			
			specularLight += aniso * specular_params.g;

			#if SURFACE_TYPE == SURFACE_DISPLACEMENT_MAP
				// Adjust specular brightness based upon the displacement height.
				#pragma nu2_use(fs_local, fs_displacementHeight)
				specularLight *= (0.6 + fs_displacementHeight * 0.4);
			#endif

		#else

			AnisotropicSurfaceProperties anisoSurfaceProperties;
			anisoSurfaceProperties.anisoBasis	= 0;
			anisoSurfaceProperties.anisoBasisS	= 0;
			anisoSurfaceProperties.vdotb		= 0;
			anisoSurfaceProperties.vbf			= 0;

		#endif
		
		//--------------------------------------------------------------------------------
		// Forward dynamic lights
		//--------------------------------------------------------------------------------
		#if defined(USE_SHADOWMAP) || defined(USE_FORWARD_DYNAMIC_LIGHTS)

			#pragma nu2_use(uniform, specular_params)
		
			half3 forwardDiffuseLight = 0;
			half3 forwardSpecularLight = 0;

			#if defined(USE_FORWARD_DYNAMIC_LIGHTS)
				lightingWasEnabled = true;
			#endif

			ComputeDynamicLightingContribution(	specular_params.g, 
												anisoSurfaceProperties,
												shadowFactor, 
												forwardDiffuseLight, 
												forwardSpecularLight);

			diffuseLight += forwardDiffuseLight;
			specularLight += forwardSpecularLight;

		#endif


		//--------------------------------------------------------------------------------
		// Ambient
		//--------------------------------------------------------------------------------
		#if LIGHTING_MODEL != DISABLE
			// Apply any ambient and glow to all active diffuse lighting models.
			#pragma nu2_use(uniform, sceneAmbientColor)
			#pragma nu2_use(uniform, ambientColor)

			lightingWasEnabled = true;

			diffuseLight += ambientColor.rgb + sceneAmbientColor.rgb;
		#endif

		half3 diffusePreEnvLight = diffuseLight;

		//--------------------------------------------------------------------------------
		// Diffuse environment map
		//--------------------------------------------------------------------------------
		#if defined(DIFFUSE_ENV)
			#pragma nu2_use(uniform, envRotation)
			#pragma nu2_use(uniform, diffenvmap_samplerCube)
			#pragma nu2_use(uniform, diffenv_params)
			#pragma nu2_use(fs_local, fs_normal)

			lightingWasEnabled = true;

			half3 worldNormal = mul((float3x3)envRotation, fs_normal);
			half3 diffuseEnvLight = texCUBE(diffenvmap_samplerCube, worldNormal).rgb * diffenv_params[0];

			#if defined(INCORPORATE_VERTEX_COLOURS)
				#pragma nu2_use(fs_local, fs_adjustedVertexColor)
				diffuseEnvLight *= fs_adjustedVertexColor;
			#endif

			#if defined(DEFERRED_MATERIAL) && defined(TT_ANIMATION)
				albedoTweakDE = diffuseEnvLight;
			#endif

			diffuseLight += diffuseEnvLight * diffusePreEnvLight;

		#endif

		//--------------------------------------------------------------------------------
		// Specular environment map
		//--------------------------------------------------------------------------------
		#if defined(DIFFUSE_ENV_SPECULAR)
			#pragma nu2_use(fs_local, fs_worldReflection)
			#pragma nu2_use(uniform, diffenvmap_samplerCube)
			#pragma nu2_use(uniform, diffenv_params)

			lightingWasEnabled = true;

			#if defined(DIFFUSE_ENV_FRESNEL)
				#pragma nu2_use(fs_local, fs_incident)
				#pragma nu2_use(fs_local, fs_specularNormal)
				half Fde = lerp(diffenv_params[2], 1.0, pow(1.0 - abs(dot(fs_specularNormal, fs_incident)), diffenv_params[3]));
				specularLightDE = texCUBE(diffenvmap_samplerCube, fs_worldReflection.rgb).rgb * Fde * diffenv_params[1];
			#else
				specularLightDE = texCUBE(diffenvmap_samplerCube, fs_worldReflection.rgb).rgb * diffenv_params[1];
			#endif

			#if defined(DEFERRED_MATERIAL) && defined(TT_ANIMATION)
				albedoTweakDES = specularLightDE;
			#endif
			
			specularLightDE *= diffusePreEnvLight;

			#if defined(INCORPORATE_VERTEX_COLOURS)
				#pragma nu2_use(fs_local, fs_adjustedVertexColor)
				specularLightDE *= fs_adjustedVertexColor;
			#endif
		#endif

		#if defined(INCORPORATE_VERTEX_COLOURS)
			#pragma nu2_use(fs_local, fs_adjustedVertexColor)
			specularLight *= fs_adjustedVertexColor;
		#endif

	#endif

	// If no light was enabled, then assume we're dealing with an 'unlit' material.
	// This is similar to what would be achieved by setting the lighting model to 'Emissive' and is
	// here primarily for dealing with existing scenes.
	if (!lightingWasEnabled)
	{
		diffuseLight = 1;
	}
}

//__________________________________________________________________________________________________

iNliNE void refractionSetupStage(inout half4 surfaceColour, inout half4 bbColour,
								 const in float fresnel, const in half refractMod, const in half edgeFresnel)
{
	#if REFRACTION_STAGE == REFRACTION_DEFAULT && PIXEL_SHADER_VERSION > 14

		#pragma nu2_use(uniform, refraction_kIndex)
		#pragma nu2_use(uniform, refraction_color)
		#pragma nu2_use(uniform, backBuffer_sampler)
		#pragma nu2_use(uniform, specular_params)
		#pragma nu2_use(varying, varying_positionX)
		#pragma nu2_use(varying, varying_positionY)
		#pragma nu2_use(fs_local, fs_normal)
		#pragma nu2_use(fs_local, fs_lodFactor)

		#if defined(_360_TARGET)
		#pragma nu2_use(uniform, fs_viewportScaleBias)
		#endif

		// Make a copy because we need this to be non-const
		float4 refraction_color_copy = refraction_color;

		// Compute the refractive displacement.
		half2 disp;

		#pragma nu2_use(varying, varying_positionW)
		half2 fragPos = half2(varying_positionX, varying_positionY) / varying_positionW;

		#if defined(HORIZONTAL_ONLY_REFRACTION)

			// We do this to avoid predicated tiling issues on 360.
			#pragma nu2_use(uniform, refraction_kIndex)
			#pragma nu2_use(fs_local, fs_nativeNormal)
			disp = edgeFresnel * refraction_kIndex * refractMod * fs_lodFactor * half2(-fs_normal.x + (fs_normal.y - fs_nativeNormal.y), 0.0);

			// Fade out refraction towards the edges of the screen to prevent off-backbuffer accesses and clamping.
			half adjPos;
			adjPos = fragPos.x * 0.5 + 0.5;
			disp.x *= min(smoothstep(0.0, 0.2, adjPos), 1.0 - smoothstep(0.8, 1.0, adjPos));

			#if defined(_360_TARGET)
				// Shift sample offset vertically by one half pixel to prevent bilinear sampling into unresolved tiles.
				#pragma nu2_use(uniform, fs_screenSize)
				disp.y -= 0.5 * fs_screenSize.w;
			#endif

		#else

			#if defined(HQ_REFRACTION)
				// HQ Refraction is currently only used by TT Animation. Clip refraction rendering for underfloor reflections.
				#pragma nu2_use(varying, varying_world_y)
				clip(varying_world_y);

				// This gives better results, since the observed refractive effect is now independent of the eye to refractive surface distance.
				#pragma nu2_use(varying, varying_eyeDistance)
				disp = (edgeFresnel * refraction_kIndex * fs_normal.xy * refractMod * fs_lodFactor) * 16.0 / varying_eyeDistance;

				// Fade out refraction towards the edges of the screen to prevent off-backbuffer accesses and clamping.
				half adjPos;
				adjPos = fragPos.x * 0.5 + 0.5;
				disp.x *= min(smoothstep(0.0, 0.2, adjPos), 1.0 - smoothstep(0.8, 1.0, adjPos));
				adjPos = fragPos.y * 0.5 + 0.5;
				disp.y *= min(smoothstep(0.0, 0.2, adjPos), 1.0 - smoothstep(0.8, 1.0, adjPos));
			#else
				disp = edgeFresnel * refraction_kIndex * fs_normal.xy * fs_lodFactor * refractMod;

				// This modulation factor reduces the problem of off-backbuffer fetches at the bottom of the screen.
				#if defined(BACKBUFFER_INVERTED)
					half modulation = smoothstep(0.0, 0.2, fragPos.y * 0.5 + 0.5);
				#else
					half modulation = smoothstep(0.0, 0.2, fragPos.y * -0.5 + 0.5);
				#endif
				disp.y *= modulation;
			#endif

			disp.x = -disp.x;

		#endif

		half2 baseTC = fragPos.xy * half2(0.5, -0.5) + 0.5;

		#if defined(_360_TARGET)
		disp *= fs_viewportScaleBias.zw;
		baseTC = baseTC * fs_viewportScaleBias.zw + fs_viewportScaleBias.xy;
		#endif

		// Perform the backbuffer look-up.
		#if defined(CHROMATIC_ABERRATION)
			// Include a bit of chromatic aberration.
			bbColour.r = tex2D(backBuffer_sampler, baseTC + disp       ).r;
			bbColour.g = tex2D(backBuffer_sampler, baseTC + disp * 0.97).g;
			bbColour.b = tex2D(backBuffer_sampler, baseTC + disp * 0.94).b;
		#else
			bbColour.rgb = tex2D(backBuffer_sampler, baseTC + disp).rgb;
		#endif

		#pragma nu2_use(uniform, exposure)
		bbColour.rgb = LDRToHDR( bbColour, false );
		
		// The refraction colour should be affected by fog.
		#if defined(FOG_STAGE)
			#pragma nu2_use(varying, varying_fogFactor)
			#pragma nu2_use(fs_local, fs_fog_color)
			refraction_color_copy.rgb = lerp(fs_fog_color.rgb, refraction_color_copy.rgb, varying_fogFactor);
		#endif

		// This is the final refraction alpha taking into account the material refraction alpha and the fresnel term.
		#if defined (SHADERTYPE_WATER)

			// Calculate refracted colour - blends between tinted backbuffer colour and constant refrative colour
			// NOTE: As refraction_color.a approaches 1 the refractive_colour.rgb is treated as a radiance value
			// rather than a colour/albedo. However this value is limited to the 0-1 range so is not HDR friendly.
			half3 refractedColour = lerp( bbColour, refraction_color_copy.rgb, refraction_color_copy.a );

			// Account for fresnel effect
			#if defined(FRESNEL_STAGE) && FRESNEL_STAGE != DISABLE
				refractedColour *= (1.0 - fresnel);
			#endif

			// Account for alpha of refractive material (e.g. it may not actually be refractive at this pixel)
			bbColour.rgb = lerp(bbColour.rgb, refractedColour, refractMod);

		#else
			#if !defined(FRESNEL_STAGE) || FRESNEL_STAGE == DISABLE
				half refAlpha = refraction_color_copy.a;
			#else
				// This reverse engineers the fresnel value to the stage before we shifted 
				// and scaled it to be between the constant fresnel value (fresnel.r) and 1.
				half fresnelOpacityBoost = (fresnel - fresnel_params.r) / (fresnel_params.g);

				// refAlpha is controlling whether the refraction colour is just modulating 
				// the background light, or whether it is adding a solid unlit colour (alib - Note: non HDR friendly)
				half refAlpha = min(1.0, refraction_color_copy.a * (1.0 + fresnelOpacityBoost));
			#endif
		
			// This tints the backbuffer with the refraction colour, modulated by refraction alpha.
			half3 refractedColour = refraction_color_copy.rgb * lerp(bbColour, half3(1.0, 1.0, 1.0), refAlpha);
		
			// This diminishes the effect of the above tint according to vertex alpha and the refraction alpha.
			// (alib - why is refAlpha included here? We've already calculated the colour of the transmitted light,
			// now we just need to lerp to decide how much of that was actually transmitted based on opacity)
			bbColour.rgb = lerp(bbColour, refractedColour.rgb, refAlpha * refractMod);

		#endif

		// Record the surface alpha value for the backbuffer combine stage.
		bbColour.a = surfaceColour.a;

		// Set the surface alpha to 1.0 so it picks up full specular effects.
		surfaceColour.a = 1.0;

	#elif REFRACTION_STAGE == REFRACTION_DEFAULT && PIXEL_SHADER_VERSION <= 14

		#pragma nu2_use(uniform, backBuffer_sampler)
		#pragma nu2_use(uniform, exposure)
		#pragma nu2_use(uniform, refraction_kIndex)
		#pragma nu2_use(varying, varying_uvSetGlass)

		half4 texCoords = varying_uvSetGlass.xyzz;

		half2 disp = 0;

		#if defined(FUNC_fs_computeVTFNormal) && FUNC_fs_computeVTFNormal == VTF_SURFACE_NORMAL_MAP
			#pragma nu2_use(fs_local, fs_vtfNormal)
			disp = fs_vtfNormal.xy;
			disp *= 2; // arbitrary
		#elif SURFACE_TYPE == SURFACE_NORMAL_MAP
			#pragma nu2_use(fs_local, fs_surfaceNormal)
			disp = fs_surfaceNormal.xy;
		#endif

		disp *= refraction_kIndex * refractMod;
		texCoords.xy += disp;

		bbColour.rgb = tex2Dproj(backBuffer_sampler, texCoords).rgb;

		bbColour.rgb = LDRToHDR( bbColour, false );

		#if defined (SHADERTYPE_WATER)
			#pragma nu2_use(uniform, refraction_color)

			// Calculate refracted colour - blends between tinted backbuffer colour and constant refrative colour
			// NOTE: As refraction_color.a approaches 1 the refractive_colour.rgb is treated as a radiance value
			// rather than a colour/albedo. However this value is limited to the 0-1 range so is not HDR friendly.
			half3 refractedColour = lerp( bbColour, refraction_color.rgb, refraction_color.a );

			// Account for alpha of refractive material (e.g. it may not actually be refractive at this pixel)
			bbColour.rgb = lerp(bbColour, refractedColour, refractMod);
		#endif

		// Record the surface alpha value for the backbuffer combine stage.
		bbColour.a = surfaceColour.a;

		// Set the surface alpha to 1.0 so it picks up full specular effects.
		surfaceColour.a = 1.0;

	#elif REFRACTION_STAGE == REFRACTION_WATER

		#pragma nu2_use(uniform, backBuffer_sampler)
		#pragma nu2_use(uniform, exposure)
		#pragma nu2_use(varying, varying_uvSetGlass)
		#pragma nu2_use(fs_local, fs_vertexOpacity)

		bbColour.rgb = tex2Dproj(backBuffer_sampler, varying_uvSetGlass.xyzz).rgb;
		bbColour.rgb = LDRToHDR( bbColour, false );
		bbColour.a = fs_vertexOpacity;
		surfaceColour.a = 1.0;

	#elif REFRACTION_STAGE == REFRACTION_GLASS

		#if PIXEL_SHADER_VERSION > 14
			#pragma nu2_use(uniform, backBuffer_sampler)
			#pragma nu2_use(uniform, fxAttributes)
			#pragma nu2_use(uniform, exposure)
			#pragma nu2_use(varying, varying_positionX)
			#pragma nu2_use(varying, varying_positionY)
			#pragma nu2_use(varying, varying_positionW)

			#pragma nu2_use(fs_local, fs_normal)
			#pragma nu2_use(fs_local, lod_factor)
			
			half2 fragPos = half2(varying_positionX, varying_positionY) / varying_positionW;

			bbColour.rgb = tex2D(backBuffer_sampler, (fragPos.xy * half2(0.5, -0.5) + 0.5) + fs_normal.xy * fxAttributes.x).rgb;
			bbColour.rgb = LDRToHDR( bbColour, false );
			bbColour.a = surfaceColour.a;
			surfaceColour.a = 1.0;
		#else
			#pragma nu2_use(uniform, backBuffer_sampler)
			#pragma nu2_use(uniform, exposure)
			#pragma nu2_use(varying, varying_uvSetGlass)

			bbColour.rgb = tex2Dproj(backBuffer_sampler, varying_uvSetGlass.xyzz).rgb;
			bbColour.rgb = LDRToHDR( bbColour, false );
			bbColour.a = surfaceColour.a;
			surfaceColour.a = 1.0;
		#endif

	#endif

	// alib - Removed as this causes 'ghosting', i.e. two refracted images. 
	// Not sure what this what this was intended to do.
	//surfaceColour.a = refractMod;
}


//__________________________________________________________________________________________________

iNliNE half4 reflectivityStage()
{
	half4 result = half4(1,1,1,1);

	#if defined(REFLECTIVITY_STAGE)
		#if defined (SPECULAR_SPECULARENABLE)
			// modulate reflectance with the specular colour
			#pragma nu2_use(uniform, specular_specular)
			result = half4(specular_specular, 1.0);
		#else
			// modulate reflectance with the specular map
			#pragma nu2_use(uniform, specular_sampler)
			#pragma nu2_use(varying, * SPECULAR_UVSET)
			#if defined(USE_fs_stOffset)
				result = tex2D(specular_sampler, SPECULAR_UVSET_VAL + fs_stOffset);
			#else
				result = tex2D(specular_sampler, SPECULAR_UVSET_VAL);
			#endif
		#endif
		
		#if defined(REFLECTIVITY_STAGE2)
			half4 result2;
			
			#if defined (SPECULAR_SPECULARENABLE2)
				// modulate reflectance with the specular2 colour
				#pragma nu2_use(uniform, specular2_specular)
				result2 = half4(specular2_specular, 1.0);
			#else
				// modulate reflectance with the specular 2 map
				#pragma nu2_use(uniform, specular2_sampler)
				#pragma nu2_use(varying, * LAYER1_UVSET)
				#if defined(USE_fs_stOffset)
					result2 = tex2D(specular2_sampler, LAYER1_UVSET_VAL + fs_stOffset);
				#else
					result2 = tex2D(specular2_sampler, LAYER1_UVSET_VAL);
				#endif
			#endif
			
			#pragma nu2_use(fs_local, fs_blend2)
			result = result * (1.0 - fs_blend2) + result2 * fs_blend2;
		#endif
		
		#if defined(FRACTAL)
			#pragma nu2_use(fs_local, fs_fbm0)
			#pragma nu2_use(uniform, surface_params2)
			result.rgb *= (1.0 + surface_params2[2] * fs_fbm0);
		#endif
	#endif
		
	return result;
}

//__________________________________________________________________________________________________

iNliNE float fresnelStage()
{
	#if !defined(FRESNEL_STAGE) || (FRESNEL_STAGE == DISABLE) 
		
		return 1.0;

	#elif PIXEL_SHADER_VERSION <= 14
		
		#pragma nu2_use(varying, varying_vertexFresnel)
		return varying_vertexFresnel;

	#else

		#pragma nu2_use(uniform, fresnel_params)
		float fresnelConst = fresnel_params.r;
		float invFresnelConst = fresnel_params.g;
		float fresnelPower = fresnel_params.b;
		float fresnelPowerX2 = fresnel_params.a;

		#if (FRESNEL_STAGE == FRESNEL_PERVERT_BRDF) || (FRESNEL_STAGE == FRESNEL_PERPIXEL_BRDF)
			#pragma nu2_use(fs_local, fs_brdfData)
			#pragma nu2_use(fs_local, fs_nativeNormal)
			#pragma nu2_use(fs_local, fs_surfaceNormal)
			float sqrRootVertexNdotV = fs_brdfData.w;
			float t = pow( sqrRootVertexNdotV, fresnelPowerX2 ); // Raise by twice the power as we interpolated the square root
			#if (FRESNEL_STAGE == FRESNEL_PERPIXEL_BRDF)
				// Tweak result based on how much more ndotv is with the per-pixel compared to the per-vertex normal
				float pixelNdotV = saturate( dot( fs_brdfData.xyz, fs_surfaceNormal ) );
				t = saturate( t - (pixelNdotV - fs_brdfData.z) ); 
			#endif
			return t * invFresnelConst + fresnelConst;
		#endif

		#if (FRESNEL_STAGE == FRESNEL_PERPIXEL)
			#pragma nu2_use(fs_local, fs_incident)
			#pragma nu2_use(fs_local, fs_specularNormal)
			#if defined (FRESNEL_EDGE_ALPHA)
				float ndotv = abs(dot(fs_specularNormal, fs_incident));
				return lerp(fresnelConst, 1.0, pow(ndotv, 1.0 / fresnelPower));
			#else
				float invndotv = 1.0 - abs(dot(fs_specularNormal, fs_incident));
				return lerp(fresnelConst, 1.0, pow(invndotv, fresnelPower));
			#endif
		#endif
	#endif
}

//__________________________________________________________________________________________________

iNliNE half fresnelAlphaStage(const in float fresnel)
{
	#if PIXEL_SHADER_VERSION <= 14
		return 1.0;
	#else
		#if defined(FRESNEL_EDGE_ALPHA)
//			#pragma nu2_use(fs_local, fs_incident)
//			#pragma nu2_use(fs_local, fs_specularNormal)
//			#pragma nu2_use(uniform, fresnel_params)
//			half ndotv = dot(fs_specularNormal, fs_incident);
//			half perpendicular = sqrt(1.0 - ndotv * ndotv);
//			return lerp(fresnel_params.r, 1.0, pow(max(0.001, 1.0 - perpendicular), fresnel_params.b));
			return fresnel;
		#else
			#if defined(FRESNEL_CENTRE_ALPHA) || defined(FRESNEL_FIN_ALPHA)
				return fresnel;
			#else
				return 1.0;
			#endif
		#endif
	#endif
}

//__________________________________________________________________________________________________

#if defined(ENVMAP_STAGE)
iNliNE half3 envmapStage(const in half3 diffuseLight, const float fresnel, out half3 albedoTweakEnv)
{
	albedoTweakEnv = 0.0;

	#if ENVMAP_STAGE == DISABLE
		// envmap is disabled
		return half3(0.0, 0.0, 0.0);

	#elif ENVMAP_STAGE == ENVMAP_CUBE_SM11

		// pixel shader 1.1
		#pragma nu2_use(varying, varying_worldReflection)
		#pragma nu2_use(uniform, envmap_samplerCube)
		#pragma nu2_use(uniform, envmap_params)

		half4 envTexel = texCUBE(envmap_samplerCube, varying_worldReflection);
		return envTexel.rgb * envmap_params.g;

	#elif ENVMAP_STAGE == ENVMAP_CUBE
		// cubic style envmap
		// pixel shader 2.0 upwards
		#pragma nu2_use(uniform, envmap_samplerCube)
		#pragma nu2_use(uniform, envmap_params)
		#pragma nu2_use(fs_local, fs_worldReflection)
		#pragma nu2_use(fs_local, fs_layer0_color)
		
		half4 envTexel = texCUBE(envmap_samplerCube, fs_worldReflection.rgb );
		
		#if defined(HDRALPHA_ENVMAP)
			envTexel.rgb *= (1.0 + 10.0*(envTexel.a*envTexel.a));
		#endif

		envTexel.rgb *= (fresnel * envmap_params.g);
		#if defined(DEFERRED_MATERIAL) && defined(TT_ANIMATION)
			albedoTweakEnv = envTexel.rgb * envmap_params.r;
		#endif
		return envTexel.rgb * ((1.0 - envmap_params.r) + diffuseLight * envmap_params.r);
		
	#elif ENVMAP_STAGE == PS2_SHINEMAP
		// ps2 shinemap style envmap
		#pragma nu2_use(uniform, ps2_shinemap_sampler)
		#pragma nu2_use(varying, varying_shineMapCoord)
		#pragma nu2_use(uniform, envmap_params)
		half4 envTexel = tex2D(ps2_shinemap_sampler, varying_shineMapCoord);
		return envTexel.rgb * envmap_params.g;
	#elif ENVMAP_STAGE == ENVMAP_SPHERE
		// sphere style envmap
		#pragma nu2_use(uniform, ps2_shinemap_sampler)
		#pragma nu2_use(uniform, envmap_params)
		#pragma nu2_use(varying, varying_shineMapCoord)
		half4 envTexel = tex2D(ps2_shinemap_sampler, varying_shineMapCoord);
		return envTexel.rgb * envmap_params.g * diffuseLight * 2.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(FOG_STAGE)

half4 fogStage(half4 surfaceColour, half fogFactor)
{
	#pragma nu2_use(fs_local, fs_fog_color)
	return float4(lerp(fs_fog_color.rgb, surfaceColour.rgb, fogFactor), surfaceColour.a);
}

float calculateFogBlendFactor()
{
	#if PIXEL_SHADER_VERSION <= 14

		return 1.0;

	#elif FOG_STAGE == DISABLE
	
		return 1.0;
		
	#else
		#if FOG_STAGE == FOG_LINEAR

			#pragma nu2_use(uniform, fog_params)

			// If varying_position2 has been used elsewhere, reuse it here. 
			// This way we don't end up using both pos2 and posW
			#if defined(USE_varying_position2)
				half zFragEye = varying_position2.w;
			#else
				#pragma nu2_use(varying, varying_positionW)
				half zFragEye = varying_positionW;
			#endif

			return saturate((fog_params.x - zFragEye) / (fog_params.y - fog_params.x));

		#elif FOG_STAGE == FOG_EXPONENTIAL

			#pragma nu2_use(uniform, fog_params)

			// If varying_position2 has been used elsewhere, reuse it here. 
			// This way we don't end up using both pos2 and posW
			#if defined(USE_varying_position2)
				half zFragEye = varying_position2.w;
			#else
				#pragma nu2_use(varying, varying_positionW)
				half zFragEye = varying_positionW;
			#endif

			return exp(-zFragEye * fog_params.w);

		#elif FOG_STAGE == FOG_EXPONENTIAL2

			#pragma nu2_use(uniform, fog_params)

			// If varying_position2 has been used elsewhere, reuse it here. 
			// This way we don't end up using both pos2 and posW
			#if defined(USE_varying_position2)
				half zFragEye = varying_position2.w;
			#else
				#pragma nu2_use(varying, varying_positionW)
				half zFragEye = varying_positionW;
			#endif

			half dd = zFragEye* fog_params.w;
			return exp(-dd*dd);

		#elif FOG_STAGE == FOG_STAGE == FOG_VERTEX_CLAMP_EXPONENTIAL2

			#pragma nu2_use(varying, varying_fogFactor)
			return varying_fogFactor;

		#elif FOG_STAGE == FOG_VERTEX_PLANAR_EXPONENTIAL2

			#pragma nu2_use(varying, varying_fogFactor)
			return varying_fogFactor;

		#elif FOG_STAGE == FOG_VERTEX_CLAMP_EXPONENTIAL2_PS3

			#pragma nu2_use(varying, varying_ps3FogParams)
			return varying_ps3FogParams.y;

		#endif
	#endif
}

//__________________________________________________________________________________________________
#endif

half func_fs_compute_lodFactor()
{
	#if defined(LOD_SHADER)
	#pragma nu2_use(varying, varying_lodFactor)
	return varying_lodFactor;
	#else
	return 1.0;
	#endif
}

//__________________________________________________________________________________________________

#if defined(USE_fs_ldotn0)
void func_fs_compute_ldotn0(half FragmentOcclusion)
{
	#if LIGHTING_LIGHTS_COUNT > 0
	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_lightDir0)
	#pragma nu2_use(fs_local, fs_ldotn0raw)
	#pragma nu2_use(fs_local, fs_ldotn0)
	fs_ldotn0raw = dot(fs_lightDir0.xyz, fs_normal) * fs_lightDir0.w * FragmentOcclusion;
	fs_ldotn0 = saturate(fs_ldotn0raw);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_ldotn1)
void func_fs_compute_ldotn1(half FragmentOcclusion)
{
	#if LIGHTING_LIGHTS_COUNT > 1
	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_lightDir1)
	#pragma nu2_use(fs_local, fs_ldotn1raw)
	#pragma nu2_use(fs_local, fs_ldotn1)
	fs_ldotn1raw = dot(fs_lightDir1.xyz, fs_normal) * fs_lightDir1.w * FragmentOcclusion;
	fs_ldotn1 = saturate(fs_ldotn1raw);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_ldotn2)
void func_fs_compute_ldotn2(half FragmentOcclusion)
{
	#if LIGHTING_LIGHTS_COUNT > 2
	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_lightDir2)
	#pragma nu2_use(fs_local, fs_ldotn2raw)
	#pragma nu2_use(fs_local, fs_ldotn2)
	fs_ldotn2raw = dot(fs_lightDir2.xyz, fs_normal) * fs_lightDir2.w * FragmentOcclusion;
	fs_ldotn2 = saturate(fs_ldotn2raw);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_fog_color) && !defined(FUNC_fs_computeFogColor)
// default rule for fs_fog_color
#define FUNC_fs_computeFogColor YES
#endif

#if !defined(USE_fs_fog_color)
#elif FUNC_fs_computeFogColor == YES
iNliNE half4 func_fs_computeFogColor()
{
	#pragma nu2_use(uniform, fog_color)
	return fog_color;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_adjustedVertexColor)
iNliNE half3 func_fs_computeAdjustedVertexColor()
{
	#if defined(LAYER0_COLORSET)
		#pragma nu2_use(varying, varying_colorSet0)
		#if (PIXEL_SHADER_VERSION < 30) || defined(_PS3_TOOL)
			return varying_colorSet0 * COLOR_FACTOR; // Multiply here in PS to avoid VS output clamping issue in SM1.1 and SM2.0
		#else
			return varying_colorSet0;
		#endif

	#else
		return 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightDir0) && !defined(FUNC_fs_computeLightDir0)
// default rule for fs_lightDir0
#define FUNC_fs_computeLightDir0 YES
#endif

#if !defined(USE_fs_lightDir0)
#elif FUNC_fs_computeLightDir0 == YES
iNliNE half4 func_fs_computeLightDir0()
{
//	#pragma  nu2_use(varying, varying_lightDir0)
//	return normalize(varying_lightDir0);
	#pragma  nu2_use(uniform, lightPosition0)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * lightPosition0;
	#else
		return lightPosition0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightDir1) && !defined(FUNC_fs_computeLightDir1)
// default rule for fs_lightDir1
#define FUNC_fs_computeLightDir1 YES
#endif

#if !defined(USE_fs_lightDir1)
#elif FUNC_fs_computeLightDir1 == YES
iNliNE half4 func_fs_computeLightDir1()
{
//	#pragma nu2_use(varying, varying_lightDir1)
//	return normalize(varying_lightDir1);
	#pragma  nu2_use(uniform, lightPosition1)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * lightPosition1;
	#else
		return lightPosition1;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightDir2) && !defined(FUNC_fs_computeLightDir2)
// default rule for fs_lightDir2
#define FUNC_fs_computeLightDir2 YES
#endif

#if !defined(FUNC_fs_computeLightDir2)
#elif FUNC_fs_computeLightDir2 == YES
iNliNE half4 func_fs_computeLightDir2()
{
//	#pragma nu2_use(varying, varying_lightDir2)
//	return normalize(varying_lightDir2);
	#pragma  nu2_use(uniform, lightPosition2)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * lightPosition2;
	#else
		return lightPosition2;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_specLightDir0) && !defined(FUNC_fs_computeSpecLightDir0)
// default rule for fs_lightDir0
#define FUNC_fs_computeSpecLightDir0 YES
#endif

#if !defined(USE_fs_specLightDir0)
#elif FUNC_fs_computeSpecLightDir0 == YES
iNliNE half4 func_fs_computeSpecLightDir0()
{
	#pragma  nu2_use(uniform, specLightPosition0)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * specLightPosition0;
	#else
		return specLightPosition0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_specLightDir1) && !defined(FUNC_fs_computeSpecLightDir1)
// default rule for fs_lightDir1
#define FUNC_fs_computeSpecLightDir1 YES
#endif

#if !defined(USE_fs_specLightDir1)
#elif FUNC_fs_computeSpecLightDir1 == YES
iNliNE half4 func_fs_computeSpecLightDir1()
{
	#pragma  nu2_use(uniform, specLightPosition1)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * specLightPosition1;
	#else
		return specLightPosition1;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_specLightDir2) && !defined(FUNC_fs_computeSpecLightDir2)
// default rule for fs_lightDir2
#define FUNC_fs_computeSpecLightDir2 YES
#endif

#if !defined(USE_fs_specLightDir2)
#elif FUNC_fs_computeSpecLightDir2 == YES
iNliNE half4 func_fs_computeSpecLightDir2()
{
	#pragma  nu2_use(uniform, specLightPosition2)
	#if defined(ADJUSTED_LIGHTING_SUPPORTED)
		#pragma nu2_use(uniform, fs_lightingAdjust)
		return fs_lightingAdjust * specLightPosition2;
	#else
		return specLightPosition2;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightDirSet)
iNliNE half3 func_fs_computeLightDirSet()
{
	#pragma nu2_use(varying, varying_lightDirSet)
	return normalize(varying_lightDirSet.xyz);
}

//_________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightHalfVec)
iNliNE half3 func_fs_computeLightHalfVec()
{
	#pragma nu2_use(varying, varying_lightHalfVec)
	return normalize(varying_lightHalfVec.xyz);
}

//_________________________________________________________________________________________________
#endif

#if defined(USE_fs_lightCol)
iNliNE half4 func_fs_computeLightCol()
{
	#pragma nu2_use(varying, varying_lightColSet)
	return varying_lightColSet;
}

//_________________________________________________________________________________________________
#endif

#if defined(USE_fs_worldReflection)

// world reflection are always computed in the pixel shader by passing the normal
// from the vertex shader. This is to ease vertex shader workload (we are vertex bound in transformers)
iNliNE half3 func_fs_computeWorldReflection()
{
	#pragma nu2_use(uniform, envRotation)
	#pragma nu2_use(fs_local, fs_incident)
	#pragma nu2_use(fs_local, fs_specularNormal)
	
	// incident and reflection vectors are not normalized because
	// the worldReflection is going to be used to sample a cube map only.
	half3 reflection = reflect(fs_incident, fs_specularNormal);

	return -mul((float3x3)envRotation, reflection);
}

//_________________________________________________________________________________________________
#endif

#if defined(USE_fs_TBN) && !defined(FUNC_fs_computeTBN)
// default rule for USE_fs_TBN
#define FUNC_fs_computeTBN YES
#endif

#if defined(FUNC_fs_computeTBN) && FUNC_fs_computeTBN == YES
iNliNE half3x3 func_fs_computeTBN()
{
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_normal)
	return half3x3(fs_tangent, fs_bitangent, fs_normal);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_dappleFactor)
iNliNE half func_fs_computeDappleFactor()
{
	#pragma nu2_use(varying, varying_normal)
	return length(varying_normal.xyz);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_normal) && !defined(FUNC_fs_computeNormal)
	#if SURFACE_TYPE == SURFACE_DISPLACEMENT_MAP
		#define FUNC_fs_computeNormal FROM_SURFACE_NORMAL
	#else
		#if defined(FUNC_fs_computeVTFNormal) && FUNC_fs_computeVTFNormal == VTF_SURFACE_NORMAL_MAP
			#if SURFACE_TYPE == SURFACE_NORMAL_MAP || SURFACE_TYPE == SURFACE_PARALLAX_MAP
				#define FUNC_fs_computeNormal FROM_SURFACE_AND_VTF_NORMALS
			#else
				#define FUNC_fs_computeNormal FROM_VTF_NORMAL
			#endif
		#else
			// default rule on fs_normal
			#if SURFACE_TYPE == SURFACE_NORMAL_MAP || SURFACE_TYPE == SURFACE_PARALLAX_MAP || SURFACE_TYPE == SURFACE_SELF_SHADOW_NORMAL_MAP
				#define FUNC_fs_computeNormal FROM_SURFACE_NORMAL
			#else
				#define FUNC_fs_computeNormal FROM_VS_NORMALIZE
			#endif
		#endif
	#endif
#endif

#if !defined(FUNC_fs_computeNormal)
#elif FUNC_fs_computeNormal == FROM_VS_RAW
half3 func_fs_computeNormal()
{
	#pragma nu2_use(varying, varying_normal)
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the bitangent, not the normal.
		#pragma nu2_use(varying, varying_tangent)
		return normalize(cross(varying_tangent, varying_normal.xyz));
	#else
		return varying_normal.xyz;
	#endif
}

//_________________________________________________________________________________________________
#elif FUNC_fs_computeNormal == FROM_VS_NORMALIZE
half3 func_fs_computeNormal()
{
	#pragma nu2_use(varying, varying_normal)
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the bitangent, not the normal.
		#pragma nu2_use(varying, varying_tangent)
		return normalize(cross(varying_tangent, varying_normal.xyz));
	#else
		return normalize(varying_normal.xyz);
	#endif
}

//_________________________________________________________________________________________________
#elif FUNC_fs_computeNormal == FROM_SURFACE_NORMAL
half3 func_fs_computeNormal()
{
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_surfaceNormal)

	// [tangent, bitangent, normal] create a matrix that project from
	// tangent space to world space. We take the normal from the normal map, and project it
	// to world space.
	// No need to normalise as we're just projecting 
	return normalize(fs_surfaceNormal.x * fs_tangent + fs_surfaceNormal.y * fs_bitangent + fs_surfaceNormal.z * fs_nativeNormal.xyz);
}

//_________________________________________________________________________________________________
#elif FUNC_fs_computeNormal == FROM_DETAIL_SURFACE_NORMAL
half3 func_fs_computeNormal()
{
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_normal)
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_surfaceNormal)
	#pragma nu2_use(varying, * DETAIL_SURFACE_UVSET)
	#pragma nu2_use(uniform, detailSurface_sampler)
	
	half3 normal = normalize(
		fs_surfaceNormal.x * fs_tangent
		+ fs_surfaceNormal.y * fs_bitangent
		+ fs_surfaceNormal.z * fs_nativeNormal.xyz);

	half3 detailNormal = tex2D(detailSurface_sampler, DETAIL_SURFACE_UVSET_VAL).rgb * 2.0 - 1.0;
	return normalize(
		detailNormal.x * fs_tangent
		+ detailNormal.y * fs_bitangent
		+ detailNormal.z * normal);
}

//_________________________________________________________________________________________________
#elif FUNC_fs_computeNormal == FROM_VTF_NORMAL
half3 func_fs_computeNormal()
{
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_vtfNormal)
	
//	#pragma nu2_use(varying, varying_waterAmplitude)
//	return lerp(fs_nativeNormal.xyz, normalize(
//		  fs_vtfNormal.x * fs_tangent
//		+ fs_vtfNormal.y * fs_bitangent
//		+ fs_vtfNormal.z * fs_nativeNormal.xyz), varying_waterAmplitude);

	return normalize(
		  fs_vtfNormal.x * fs_tangent
		+ fs_vtfNormal.y * fs_bitangent
		+ fs_vtfNormal.z * fs_nativeNormal.xyz);
}

//_________________________________________________________________________________________________
#elif FUNC_fs_computeNormal == FROM_SURFACE_AND_VTF_NORMALS
half3 func_fs_computeNormal()
{
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_surfaceNormal)
	#pragma nu2_use(fs_local, fs_vtfNormal)
	
	half3 sNormal = fs_surfaceNormal.x * fs_tangent + fs_surfaceNormal.y * fs_bitangent + fs_surfaceNormal.z * fs_nativeNormal.xyz;
	half3 vNormal = fs_vtfNormal.x     * fs_tangent + fs_vtfNormal.y     * fs_bitangent + fs_vtfNormal.z     * fs_nativeNormal.xyz;
	
//	#pragma nu2_use(varying, varying_waterAmplitude)
//	vNormal = lerp(fs_nativeNormal.xyz, vNormal, varying_waterAmplitude);

	return normalize(sNormal + vNormal);
}

//_________________________________________________________________________________________________
#endif

#if defined(USE_fs_surfaceNormal) && !defined(FUNC_fs_computeSurfaceNormal)
// default rule for fs_surfaceNormal
#define FUNC_fs_computeSurfaceNormal SURFACE_TYPE
#endif

#if !defined(FUNC_fs_computeSurfaceNormal)
#elif FUNC_fs_computeSurfaceNormal == SURFACE_NORMAL_MAP
iNliNE half4 func_fs_computeSurfaceNormal()
{
	#pragma nu2_use(uniform, surface_sampler)
	#pragma nu2_use(uniform, surface_params)
	#pragma nu2_use(varying, * SURFACE_UVSET)

	//	Sample the normal map
	half4 surfaceNormal = tex2D(surface_sampler, SURFACE_UVSET_VAL);

	#if defined(SWIZZLE_NORMAL_MAPS)
		surfaceNormal = surfaceNormal.agbr;
	#endif

	#if defined(DOUBLE_RANGE_NORMAL_MAP_1)
		surfaceNormal = surfaceNormal * half4(2,2,2,2) - half4(1,1,0,1);
	#else
		surfaceNormal = surfaceNormal * 2 - 1;
	#endif

	surfaceNormal.xy *= surface_params.r;
	
	#if defined(LOD_SHADER)
		#pragma nu2_use(varying, varying_lodFactor)
		surfaceNormal.xy *= varying_lodFactor;
	#endif
		
	#if (SURFACE_TYPE2 == SURFACE_NORMAL_MAP)
		#pragma nu2_use(uniform, surface2_sampler)
		#pragma nu2_use(uniform, surface_params2)
		#pragma nu2_use(varying, * LAYER1_UVSET)
		#pragma nu2_use(fs_local, fs_blend2)

		half4 surfaceNormal2 = tex2D(surface2_sampler, LAYER1_UVSET_VAL);

		#if defined(SWIZZLE_NORMAL_MAPS)
			surfaceNormal2 = surfaceNormal2.agbr;
		#endif

		#if defined(DOUBLE_RANGE_NORMAL_MAP_2)
			surfaceNormal2 = surfaceNormal2 * half4(2,2,2,2) - half4(1,1,0,1);
		#else
			surfaceNormal2 = surfaceNormal2 * 2 - 1;
		#endif

		surfaceNormal2.xy *= surface_params2.r;

		#if defined(LOD_SHADER)
		#pragma nu2_use(varying, varying_lodFactor)
		surfaceNormal2.xy *= varying_lodFactor;
		#endif

		surfaceNormal.xyz = lerp(surfaceNormal.xyz, surfaceNormal2.xyz, fs_blend2);
	#endif

	// We no longer normalize surfaceNormal here since func_fs_computeNormal() requires the un-normalized
	// value. We normalise instead after the func_fs_computeNormal() call.
	//surfaceNormal.xyz = normalize(surfaceNormal.xyz);
			
	return float4(surfaceNormal.xyz,1);
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeSurfaceNormal == SURFACE_SELF_SHADOW_NORMAL_MAP
iNliNE half4 func_fs_computeSurfaceNormal()
{
	#pragma nu2_use(uniform, surface_sampler)
	#pragma nu2_use(varying, * SURFACE_UVSET)

	//	Sample the normal map
	half4 surfaceNormal = tex2D(surface_sampler, SURFACE_UVSET_VAL);
				
	#if (SURFACE_TYPE2 == SURFACE_SELF_SHADOW_NORMAL_MAP)
		#pragma nu2_use(uniform, surface2_sampler)
		#pragma nu2_use(uniform, surface_params2)
		#pragma nu2_use(varying, * LAYER1_UVSET)
		#pragma nu2_use(fs_local, fs_blend2)

		half4 surfaceNormal2 = tex2D(surface2_sampler, LAYER1_UVSET_VAL);
	
		surfaceNormal.xyz = lerp(surfaceNormal.xyz, surfaceNormal2.xyz, fs_blend2);
	#endif

	return surfaceNormal;
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeSurfaceNormal == SURFACE_DISPLACEMENT_MAP
iNliNE half4 func_fs_computeSurfaceNormal()
{
	#pragma nu2_use(varying, * SURFACE_UVSET)
	#pragma nu2_use(fs_local, fs_incident)
	#pragma nu2_use(fs_local, fs_bitangent)
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_stOffset)
	#pragma nu2_use(fs_local, fs_displacementHeight)
	#pragma nu2_use(uniform, surface_params)
	#pragma nu2_use(uniform, surface_sampler)

	#if defined(ATI)
		int layers = 64;
	#else
		int layers = 128;
	#endif

	float invlayers = 1.0 / layers;
	int i;

	float3 Tn = cross(fs_bitangent, fs_nativeNormal);
	float vdotb = dot(fs_incident, fs_bitangent);
	float3 TanView = float3(dot(fs_incident, Tn), vdotb, abs(dot(fs_incident, fs_nativeNormal)) + 0.5);
	TanView = normalize(TanView);
	TanView /= TanView.z;
	#if defined(FLIP_PARALLAX)
		TanView.y -= surface_params.a;
	#else
		TanView.x += surface_params.a;
	#endif
	TanView.xy *= surface_params.b * -10.0;
	float3 TexCoord = float3(SURFACE_UVSET.x, SURFACE_UVSET.y, 0.0);
	TanView /= layers;

	float tdotv = abs(vdotb);
	float edgefade = 1.0;
	TanView.xy *= edgefade;
	float3 RayVec = TanView;

	#if defined(LAYER0_DIFFUSEENABLE)
		#pragma nu2_use(uniform, layer0_diffuse)
		float3 col = layer0_diffuse.rgb;
	#else
		#pragma nu2_use(uniform, layer0_sampler)
		#pragma nu2_use(varying, * LAYER0_UVSET)
		float3 col = tex2D(layer0_sampler, LAYER0_UVSET_VAL).rgb;
	#endif

	float maxh = 0.0;
	for (i = 0; i < layers; i++)
	{
		#if defined(SWIZZLE_PARALLAX_MAPS)
			float h = tex2D(surface_sampler, TexCoord.xy).r;
		#else
			float h = tex2D(surface_sampler, TexCoord.xy).a;
		#endif

		#if defined(LAYER0_DIFFUSEENABLE)
			float4 diff = layer0_diffuse;
		#else
			float4 diff = tex2D(layer0_sampler, TexCoord.xy);
		#endif

		float thispen = h - TexCoord.z;
		float thisheight = TexCoord.z + min(thispen, invlayers);

		if (thispen > 0.0)
		{
			maxh = thisheight;
			diff.a = (1.0 - thisheight);
		}

		col.rgb = col.rgb * (1.0 - diff.a) + diff.rgb * diff.a;

		TexCoord += RayVec;
	}

	half displacementHeight1 = maxh * edgefade;
	half2 stOffset1 = RayVec.xy * layers * maxh * edgefade;

	#if defined(SWIZZLE_PARALLAX_MAPS)
		float4 surfaceNormal1 =  tex2D(surface_sampler, SURFACE_UVSET_VAL + stOffset1).agbr * 2.0 - 1.0;
	#else
		float4 surfaceNormal1 =  tex2D(surface_sampler, SURFACE_UVSET_VAL + stOffset1) * 2.0 - 1.0;
	#endif
	surfaceNormal1.xy *= surface_params.r;

	#if (SURFACE_TYPE2 == SURFACE_DISPLACEMENT_MAP)

		#pragma nu2_use(varying, * LAYER1_UVSET)
		#pragma nu2_use(fs_local, fs_bitangent2)
		#pragma nu2_use(fs_local, fs_stOffset)
		#pragma nu2_use(fs_local, fs_blend2)
		#pragma nu2_use(uniform, surface2_sampler)
		#pragma nu2_use(uniform, surface_params2)

		Tn = cross(fs_bitangent2, fs_nativeNormal);
		vdotb = dot(fs_incident, fs_bitangent2);
		TanView = float3(dot(fs_incident, Tn), vdotb, abs(dot(fs_incident, fs_nativeNormal)) + 0.5);
		TanView = normalize(TanView);
		TanView /= TanView.z;
		TanView.x += surface_params.a;
		TanView.xy *= surface_params.b * -10.0;
		TexCoord = float3(LAYER1_UVSET.x, LAYER1_UVSET.y, 0.0);
		TanView /= layers;

		tdotv = abs(vdotb);
		edgefade = 1.0;
		TanView.xy *= edgefade;
		RayVec = TanView;

		#if defined(LAYER1_DIFFUSEENABLE)
			#pragma nu2_use(uniform, layer1_diffuse)
			col = layer1_diffuse.rgb;
		#else
			#pragma nu2_use(uniform, layer1_sampler)
			#pragma nu2_use(varying, * LAYER1_UVSET)
			col = tex2D(layer1_sampler, LAYER1_UVSET_VAL).rgb;
		#endif

		maxh = 0.0;
		for (i = 0; i < layers; i++)
		{
			#if defined(SWIZZLE_PARALLAX_MAPS)
				float h = tex2D(surface2_sampler, TexCoord.xy).r;
			#else
				float h = tex2D(surface2_sampler, TexCoord.xy).a;
			#endif

			#if defined(LAYER1_DIFFUSEENABLE)
				float4 diff = layer1_diffuse;
			#else
				float4 diff = tex2D(layer1_sampler, TexCoord.xy);
			#endif

			float thispen = h - TexCoord.z;
			float thisheight = TexCoord.z + min(thispen, invlayers);

			if (thispen > 0.0)
			{
				maxh = thisheight;
				diff.a = (1.0 - thisheight);
			}

			col.rgb = col.rgb * (1.0 - diff.a) + diff.rgb * diff.a;

			TexCoord += RayVec;
		}

		half displacementHeight2 = maxh * edgefade;
		half2 stOffset2 = RayVec.xy * layers * maxh * edgefade;

		#if defined(SWIZZLE_PARALLAX_MAPS)
			float4 surfaceNormal2 =  tex2D(surface2_sampler, LAYER1_UVSET_VAL + stOffset2).agbr * 2.0 - 1.0;
		#else
			float4 surfaceNormal2 =  tex2D(surface2_sampler, LAYER1_UVSET_VAL + stOffset2) * 2.0 - 1.0;
		#endif
		surfaceNormal2.xy *= surface_params2.r;

		fs_displacementHeight = lerp(displacementHeight1, displacementHeight2, fs_blend2);
		fs_stOffset = lerp(stOffset1, stOffset2, fs_blend2);
		float4 surfaceNormal = lerp(surfaceNormal1, surfaceNormal2, fs_blend2);
		return float4(surfaceNormal.xyz,1);

	#else

		fs_displacementHeight = displacementHeight1;
		fs_stOffset = stOffset1;
		return float4(surfaceNormal1.xyz,1);

	#endif
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeSurfaceNormal == SURFACE_PARALLAX_MAP
iNliNE half4 func_fs_computeSurfaceNormal()
{
	#pragma nu2_use(uniform, surface_sampler)
	#pragma nu2_use(uniform, surface_params)
	#pragma nu2_use(fs_local, fs_surfaceIncident)
	#pragma nu2_use(fs_local, fs_stOffset)
	#pragma nu2_use(varying, * SURFACE_UVSET)

	// Calculate parallax effect.
	#if defined(SWIZZLE_PARALLAX_MAPS)
		half h0 = tex2D(surface_sampler, SURFACE_UVSET_VAL).r;
	#else
		half h0 = tex2D(surface_sampler, SURFACE_UVSET_VAL).a;
	#endif


	// we take the opposite of offset.y because the y axis in the texture goes down,
	// whereas our vectors (e.g. fs_surfaceIncident) are defined in a coordinate system where
	// y axis goes up intituively
	half2 incident = half2(fs_surfaceIncident.x,-fs_surfaceIncident.y);
	
	half hsb = 2.0 * h0 + surface_params.a;
    fs_stOffset = hsb * surface_params.b * incident.xy;
  
	#if defined(SWIZZLE_PARALLAX_MAPS)
		half4 surfaceNormal =  tex2D(surface_sampler, SURFACE_UVSET_VAL + fs_stOffset).agbr * 2.0 - 1.0;
	#else
		half4 surfaceNormal =  tex2D(surface_sampler, SURFACE_UVSET_VAL + fs_stOffset) * 2.0 - 1.0;
	#endif

	surfaceNormal.xy *= surface_params.r;
	
	#pragma nu2_use(fs_local, fs_lodFactor)
	surfaceNormal.xy *= fs_lodFactor;
	
	#if (SURFACE_TYPE2 == SURFACE_PARALLAX_MAP)
		#pragma nu2_use(uniform, surface2_sampler)
		#pragma nu2_use(uniform, surface_params2)
		//#pragma nu2_use(fs_local, fs_surfaceIncident2)
		#pragma nu2_use(varying, * LAYER1_UVSET)
		#pragma nu2_use(fs_local, fs_blend2)
		
		// Calculate parallax effect.
		#if defined(SWIZZLE_PARALLAX_MAPS)
			half h02 = tex2D(surface2_sampler, LAYER1_UVSET_VAL).r;
		#else
			half h02 = tex2D(surface2_sampler, LAYER1_UVSET_VAL).a;
		#endif

		half hsb2 = 2.0 * h02 + surface_params.a;
		half2 stOffset2 = hsb2 * surface_params.g * incident.xy;
		
		#if defined(SWIZZLE_PARALLAX_MAPS)
			half4 surfaceNormal2 =  tex2D(surface2_sampler, LAYER1_UVSET_VAL + stOffset2).agbr * 2.0 - 1.0;
		#else
			half4 surfaceNormal2 =  tex2D(surface2_sampler, LAYER1_UVSET_VAL + stOffset2) * 2.0 - 1.0;
		#endif
		surfaceNormal2.xy *= surface_params2.r;
		
		#pragma nu2_use(fs_local, fs_lodFactor)
		surfaceNormal2.xy *= fs_lodFactor;

		fs_stOffset = lerp(fs_stOffset, stOffset2, fs_blend2);
		
		surfaceNormal.xyz = lerp(surfaceNormal.xyz, surfaceNormal2.xyz, fs_blend2);
	#endif
	
	// We no longer normalize surfaceNormal here since func_fs_computeNormal() requires the un-normalized
	// value. We normalise instead after the func_fs_computeNormal() call.
//	surfaceNormal.xyz = normalize(surfaceNormal.xyz);
	
	return float4(surfaceNormal.xyz,1);
}

//__________________________________________________________________________________________________
#else
iNliNE half4 func_fs_computeSurfaceNormal()
{
	return half4(0.0,0.0,1.0,1.0);
}

//__________________________________________________________________________________________________
#endif

#if !defined(FUNC_fs_computeVTFNormal)
#elif FUNC_fs_computeVTFNormal == VTF_SURFACE_NORMAL_MAP
iNliNE half3 func_fs_computeVTFNormal()
{
	#pragma nu2_use(fs_local, fs_vtfNormal)
	#pragma nu2_use(uniform, vtfNormal_sampler)
	#pragma nu2_use(uniform, vtf_kNormal)
	#pragma nu2_use(varying, * VTF_NORMAL_UVSET)

	//	Sample the normal map
	#if defined(SWIZZLE_NORMAL_MAPS)
		half4 vtfNormal = tex2D(vtfNormal_sampler, VTF_NORMAL_UVSET_VAL).agbr * 2.0 - 1.0;
	#else
		half4 vtfNormal = tex2D(vtfNormal_sampler, VTF_NORMAL_UVSET_VAL) * 2.0 - 1.0;
	#endif

	vtfNormal.xy *= vtf_kNormal;
	return vtfNormal.xyz;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_surfaceIncident)
iNliNE half2 func_fs_computeSurfaceIncident()
{
	#pragma nu2_use(fs_local, fs_incident)
//	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_tangent)
	#pragma nu2_use(fs_local, fs_bitangent)
//	return mul(half3x3(fs_tangent, fs_bitangent, fs_nativeNormal), fs_incident);
	return half2(dot(fs_tangent, fs_incident), dot(fs_bitangent, fs_incident));
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_surfaceIncident2)
iNliNE half3 func_fs_computeSurfaceIncident2()
{
	#pragma nu2_use(fs_local, fs_incident)
	#pragma nu2_use(fs_local, fs_nativeNormal)
	#pragma nu2_use(fs_local, fs_tangent2)
	#pragma nu2_use(fs_local, fs_bitangent2)
	return mul(half3x3(fs_tangent2, fs_bitangent2, fs_nativeNormal.xyz), fs_incident);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_tangent) && !defined(FUNC_fs_computeTangent)
// default rule for fs_tangent
#define FUNC_fs_computeTangent FROM_VS_NORMALIZE
#endif

#if !defined(FUNC_fs_computeTangent)
#elif FUNC_fs_computeTangent == FROM_VS_RAW
iNliNE half3 func_fs_computeTangent()
{
	#pragma nu2_use(varying, varying_tangent)
	return varying_tangent;
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeTangent == FROM_VS_NORMALIZE
iNliNE half3 func_fs_computeTangent()
{
	#pragma nu2_use(varying, varying_tangent)
	return normalize(varying_tangent);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_tangent2)
half3 func_fs_computeTangent2()
{
	#pragma nu2_use(varying, varying_tangent2)
	return normalize(varying_tangent2);
}
#endif

//__________________________________________________________________________________________________

#if defined(USE_fs_bitangent) && !defined(FUNC_fs_computeBitangent)
// default rule for fs_bitangent
#define FUNC_fs_computeBitangent FROM_VS_NORMALIZE
#endif

#if !defined(FUNC_fs_computeBitangent)
#elif FUNC_fs_computeBitangent == FROM_VS_RAW
iNliNE half3 func_fs_computeBitangent()
{
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the negated normal, not the bitangent.
		#pragma nu2_use(varying, varying_normal);
		return -normalize(varying_normal.xyz);
	#else
		#pragma nu2_use(varying, varying_bitangent)
		return varying_bitangent;
	#endif
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeBitangent == FROM_VS_NORMALIZE
iNliNE half3 func_fs_computeBitangent()
{
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the negated normal, not the bitangent.
		#pragma nu2_use(varying, varying_normal);
		return -normalize(varying_normal.xyz);
	#else
		#pragma nu2_use(varying, varying_bitangent)
		return normalize(varying_bitangent);
	#endif
}

//__________________________________________________________________________________________________
#elif FUNC_fs_computeBitangent == CROSS_TANGENT_NORMAL
iNliNE half3 func_fs_computeBitangent()
{
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the negated normal, not the bitangent.
		#pragma nu2_use(varying, varying_normal);
		return -normalize(varying_normal.xyz);
	#else
		#pragma nu2_use(varying, varying_tangent)
		#pragma nu2_use(fs_local, fs_nativeNormal)
		return normalize(cross(varying_tangent, fs_nativeNormal.xyz));
	#endif
}
//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_bitangent2)
half3 func_fs_computeBitangent2()
{
	#pragma nu2_use(varying, varying_tangent2)
	#pragma nu2_use(fs_local, fs_nativeNormal)

	return normalize(cross(varying_tangent2, fs_nativeNormal.xyz));
}
#endif

//__________________________________________________________________________________________________

#if defined(USE_fs_nativeNormal)
iNliNE half3 func_fs_computeNativeNormal()
{
	#pragma nu2_use(varying, varying_normal);
	#if defined(FRESNEL_FIN_ALPHA)
		// We return the bitangent, not the normal.
		#pragma nu2_use(varying, varying_tangent)
		return normalize(cross(varying_tangent, varying_normal.xyz));
	#else
		return normalize(varying_normal.xyz);
	#endif
}
//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_specularNormal)
iNliNE half3 func_fs_computeSpecularNormal()
{
	#pragma nu2_use(fs_local, fs_normal)
	#if defined(INDEPENDENT_SPECULAR) || (LIGHTING_MODEL == LIGHTING_SKIN)
		#pragma nu2_use(fs_local, fs_nativeNormal)
		#pragma nu2_use(uniform, brdf_params)
		#if (LIGHTING_MODEL == LIGHTING_SKIN)
			return normalize(lerp(fs_nativeNormal.xyz, fs_normal, 1.0 - brdf_params[2]));
		#else
			return normalize(lerp(fs_nativeNormal.xyz, fs_normal, brdf_params[2]));
		#endif
	#else
		return fs_normal;
	#endif
}
//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_incident)
iNliNE half3 func_fs_computeIncident()
{
	#pragma nu2_use(varying, varying_eyePosition)
	return normalize(-varying_eyePosition);
}
//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_brdfData)
iNliNE half4 func_fs_computeBRDFData()
{
	#pragma nu2_use(varying, varying_brdfData)
	return half4( varying_brdfData.xyz, varying_brdfData.w );
}
//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_vpos)
//half2 func_fs_computeVPos()
//{
//	// fs_pos is in range x=[-1, 1], y=[-1, 1], z=[0, 1]
//	// we shift (x,y) to [0, fs_screenSize] in pixels units
//	#pragma nu2_use(fs_local, fs_pos)
//	#pragma nu2_use(uniform, fs_screenSize)
//	// rounding is necessary on the 360
//	return round((fs_pos.xy * 0.5 + 0.5) * fs_screenSize);
//}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_pos)
iNliNE float3 func_fs_computePos()
{
	#pragma nu2_use(varying, varying_position2)
	return varying_position2.xyz / varying_position2.w;
}

//__________________________________________________________________________________________________
#endif


#if !defined(LAYER0_COLORSET)
iNliNE half4 func_fs_computeLayer0_color()
{
	#if (LIGHTING_STAGE == DISABLE)
	return COLOR_FACTOR;
	#else
	return 1.0;
	#endif
}

//__________________________________________________________________________________________________
#elif LAYER0_COLORSET == 0
iNliNE half4 func_fs_computeLayer0_color()
{
	#pragma nu2_use(varying, varying_colorSet0)
	#if (PIXEL_SHADER_VERSION < 30) || defined(_PS3_TOOL)
		return varying_colorSet0 * COLOR_FACTOR; // Multiply here in PS to avoid VS output clamping issue in SM1.1 and SM2.0
	#else
		return varying_colorSet0;
	#endif
}

//__________________________________________________________________________________________________
#elif LAYER0_COLORSET == 1
// Never used?
iNliNE half4 func_fs_computeLayer0_color()
{
	#pragma nu2_use(varying, varying_colorSet1)
	return varying_colorSet1;
}

//__________________________________________________________________________________________________
#elif LAYER0_COLORSET == 2
// Never used?
iNliNE half4 func_fs_computeLayer0_color()
{
	#pragma nu2_use(varying, varying_colorSet2)
	return varying_colorSet2;
}

//__________________________________________________________________________________________________
#elif LAYER0_COLORSET == 3
// Never used?
iNliNE half4 func_fs_computeLayer0_color()
{
	#pragma nu2_use(varying, varying_colorSet3)
	return varying_colorSet3;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_layer1_alpha)
iNliNE half func_fs_computeLayer1_alpha()
{
	#if defined (LAYER1_ALPHA)
		#if PIXEL_SHADER_VERSION > 14
			#pragma nu2_use(varying, *LAYER1_COLORSET)
			return LAYER1_COLORSET.r;
		#else
			#pragma nu2_use(varying, varying_layer1alpha)
			return varying_layer1alpha;
		#endif
	#else
		return 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_layer2_alpha)
iNliNE half func_fs_computeLayer2_alpha()
{
	#if defined (LAYER2_ALPHA)
		#if PIXEL_SHADER_VERSION > 14
			#pragma nu2_use(varying, *LAYER1_COLORSET)
			return LAYER1_COLORSET.g;
		#else
			#pragma nu2_use(varying, varying_layer2alpha)
			return varying_layer2alpha;
		#endif
	#else
		return 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_layer3_alpha)
iNliNE half func_fs_computeLayer3_alpha()
{
	#if defined (LAYER3_ALPHA)
		#if PIXEL_SHADER_VERSION > 14
			#pragma nu2_use(varying, *LAYER1_COLORSET)
			return LAYER1_COLORSET.b;
		#else
			#pragma nu2_use(varying, varying_layer3alpha)
			return varying_layer3alpha;
		#endif
	#else
		return 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_blend2)
half func_fs_computeBlend2()
{
	#pragma nu2_use(fs_local, fs_layer1_alpha)
	#if defined (SHADERTYPE_WATER)
		half result = fs_layer1_alpha; // Ignore material kOpacity[1] (layer1_diffuse.a)
	#else
		#pragma nu2_use(uniform, layer1_diffuse)
		half result = layer1_diffuse.a * fs_layer1_alpha;
	#endif
	#if !defined(LAYER1_DIFFUSEENABLE)
		#pragma nu2_use(uniform, layer1_sampler)
		#pragma nu2_use(varying, * LAYER1_UVSET)
		result *= tex2D(layer1_sampler, LAYER1_UVSET_VAL).a;
	#endif

	return saturate(result);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_vertexOpacity)
half func_fs_computeVertexOpacity()
{
#if defined(BEFORE_OPACITY_MOVED_TO_NORMALW)
	#pragma nu2_use(varying, varying_colorSet0)
	return varying_colorSet0.w;
#else
	#pragma nu2_use(varying, varying_VertexOpacity)
	return varying_VertexOpacity;
#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_fs_vertexOpacity)
half func_fs_computeLightingIntensityFactor()
{
	#if defined(BEFORE_OPACITY_MOVED_TO_NORMALW)
		// HDR brightness used to be stored in w component of normal. Divide by colour factor to
		// account for multiplication earlier on.
		#pragma nu2_use(fs_local, fs_nativeNormal)
		return fs_nativeNormal.w * (10.0 / COLOR_FACTOR);
	#else
		// HDR brightness stored in w component of colour. As colour has needlessly been
		// multiplied by COLOR_FACTOR we need to divide by it here (squared because both the
		// the rgb and w component have been doubled)
		#pragma nu2_use(fs_local, fs_layer0_color)
		return fs_layer0_color.w * (10.0 / (COLOR_FACTOR*COLOR_FACTOR));
	#endif
}

//__________________________________________________________________________________________________
#endif


#if defined(FRACTAL)

float gradperm(float x, float3 p)
{
	#pragma nu2_use(uniform, permgrad_sampler)
	float3 pg = tex2D(permgrad_sampler, float2(x, 0.5)).xyz * 2.0 - 1.0;
	return dot(pg, p);
}

float inoise(float3 p)
{
	#pragma nu2_use(uniform, perm_sampler)

	// Find the unit cube that contains the given point.
	float3 floorP = floor(p);

	// Find relative x,y,z of point in the cube.
	p -= floorP;

	// Compute fade curves for each of x,y,z.
	float3 f = p * p * p * (p * (p * 6.0 - 15.0) + 10.0);

	float3 modP = modf(floorP / 256.0f, floorP);
	float one = 1.0 / 256.0;

	// Hash the coordinates of the 8 cube corners.
	float4 AA = tex2D(perm_sampler, modP.xy) + modP.z;

	// Add the blended results from the 8 corners of the cube.
	return lerp(lerp(lerp(gradperm(AA.x,       p),                           gradperm(AA.z,       p + float3(-1.0,  0.0,  0.0)), f.x),
				     lerp(gradperm(AA.y,       p + float3( 0.0, -1.0,  0.0)), gradperm(AA.w,       p + float3(-1.0, -1.0,  0.0)), f.x), f.y),
			    lerp(lerp(gradperm(AA.x + one, p + float3( 0.0,  0.0, -1.0)), gradperm(AA.z + one, p + float3(-1.0,  0.0, -1.0)), f.x),
				     lerp(gradperm(AA.y + one, p + float3( 0.0, -1.0, -1.0)), gradperm(AA.w + one, p + float3(-1.0, -1.0, -1.0)), f.x), f.y), f.z);
}

float fBm(float3 p, float baseFrequency, float lacunarity, float gain)
{
	float sum = 0.0;

	float frequency = baseFrequency;
	float amplitude = 0.5;
	
	// A for loop! Fractals are only used on shader 3.0 and above.
	for (int i = 0; i < 5; i++)
	{
		// Accumulate 5 noise octaves.
		sum += inoise(p * frequency) * amplitude;
		frequency *= lacunarity;
		amplitude *= gain;
	}

	return sum;
}

void func_fs_compute_fbm0()
{
	#pragma nu2_use(fs_local, fs_fbm0)
	#pragma nu2_use(uniform, fractal_params)
	#pragma nu2_use(varying, varying_modelPosition)
	fs_fbm0 = fBm(varying_modelPosition, fractal_params.r, fractal_params.g, fractal_params.b);
}

#if defined(FRACTAL_BUMP)

float3 fBmGradient(float3 p, float baseFrequency, float lacunarity, float gain)
{
	#pragma nu2_use(fs_local, fs_fbm0)
	float eps = 0.1 / baseFrequency;
	#if defined(ATI)
		// ATI cards can't cope with the large instruction counts, so do simple bumpmapping from above.
		float fy = fBm(p + float3(0.0, eps, 0.0), baseFrequency, lacunarity, gain);
		return float3(0.0, fy - fs_fbm0, 0.0) / eps;
	#else
		// Nivdia cards can do proper 3D bumpmapping.
		float fx = fBm(p + float3(eps, 0.0, 0.0), baseFrequency, lacunarity, gain);
		float fy = fBm(p + float3(0.0, eps, 0.0), baseFrequency, lacunarity, gain);
		float fz = fBm(p + float3(0.0, 0.0, eps), baseFrequency, lacunarity, gain);
		return float3(fx - fs_fbm0, fy - fs_fbm0, fz - fs_fbm0) / eps;
	#endif
}

void func_fs_fractalBump()
{
	#pragma nu2_use(uniform, surface_params2)
	#pragma nu2_use(uniform, fractal_params)
	#pragma nu2_use(varying, varying_modelPosition)
	#pragma nu2_use(fs_local, fs_normal)
	fs_normal = fs_normal + surface_params2.g * fBmGradient(varying_modelPosition, fractal_params.r, fractal_params.g, fractal_params.b);
	fs_normal = normalize(fs_normal);
}

#endif // #if defined(FRACTAL_BUMP)

#endif // #if defined(FRACTAL)

//__________________________________________________________________________________________________

#endif // #if !defined(MOTION_BLUR_PASS)

//__________________________________________________________________________________________________
// 
// Vertex shader functions...
//__________________________________________________________________________________________________

#if defined(USE_varying_uvSetGlass)
void pipeuvSetGlass()
{
	#pragma nu2_use(varying, varying_uvSetGlass)

	#if REFRACTION_STAGE == REFRACTION_WATER
		#pragma nu2_use(attribute,	colorSet0)
		#pragma nu2_use(uniform,	fxAttributes)
		#pragma nu2_use(vs_local,	vs_waterCoef)
		
		varying_uvSetGlass.xy = varying_position.xy + vin.colorSet0.a * fxAttributes.w * vs_waterCoef.xy;
		varying_uvSetGlass.y = -varying_uvSetGlass.y;
		varying_uvSetGlass.z = varying_position.w;
		varying_uvSetGlass.xy = 0.5 * (varying_uvSetGlass.xy + varying_uvSetGlass.zz);
		varying_uvSetGlass.xy = 0.5 * (varying_uvSetGlass.xy + varying_position.w);
	#else
		#pragma nu2_use(uniform,	fxAttributes)
		#pragma nu2_use(uniform,	viewProj)
		#pragma nu2_use(vs_local,	vs_normal)

		varying_uvSetGlass.xy = varying_position.xy;
		varying_uvSetGlass.y = -varying_uvSetGlass.y;
		varying_uvSetGlass.z = varying_position.w;
		#if REFRACTION_STAGE != REFRACTION_DEFAULT
			half3 screenNormal = mul(vs_normal, viewProj); // seems odd - vs_normal has already had the view matrix applied.
			varying_uvSetGlass.xy += screenNormal.xy * fxAttributes.x;
		#endif
		varying_uvSetGlass.xy = 0.5 * (varying_uvSetGlass.xy + varying_position.w);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(VERTEX_GROUP)
void vertexGroupCompute()
{
	#pragma nu2_use(uniform, offsetTable)
	#pragma nu2_use(uniform, vertexGroupStates)
	#pragma nu2_use(attribute, normal)
	#pragma nu2_use(vs_local, vs_randomSeed)
	
	// dynamic offset geometry
	// the vertex group is encoded within normal.w
	// resolve the vertex group. it is normal.w * 255, but then
	// the vertex group states are packed by 4 in the half4 vertexGroupStates[20] array.
	
	half mgroup, ngroup;

	#if defined(PACKED_NORMAL)	
		#if (VERTEX_SHADER_VERSION == 11)
		mgroup = D3DCOLORtoUBYTE4(vin.normal).w;	// Was packed as D3DCOLOR
		#else
		mgroup = vin.normal.w * 255.0;
		#endif
	#else
	mgroup = vin.normal.w * 127.0;
	// NOTE THAT if there is more than 128 vertex group this shader code will break!
	// If the vertex group value is greater than 127 (vin.normal.w < 0), it should be
	// correctly computed using: 255.0 + vin.normal.w * 127.0
	#endif
	
	mgroup = round(mgroup);
	ngroup = modf(mgroup/4.0, mgroup);

	int vertexGroupState;
	if (ngroup >= 0.5 - 0.1)
	{
		if (ngroup >= 0.75 - 0.1)
			vertexGroupState = (int)vertexGroupStates[mgroup].a;
		else
			vertexGroupState = (int)vertexGroupStates[mgroup].b;
	}
	else
	{
		if (ngroup >= 0.25 - 0.1)
			vertexGroupState = (int)vertexGroupStates[mgroup].g;
		else
			vertexGroupState = (int)vertexGroupStates[mgroup].r;
	}

	if (vertexGroupState == 0.0)
		varying_position.z -= 100000.0; // force the vertex to be clipped away
	else
	{
		half2 stateOffset = offsetTable[vertexGroupState].xy;
		
		#if defined(USE_vs_uvSet0)
			vs_uvSet0 += stateOffset;
		#endif
		#if defined(USE_vs_uvSet1)
			vs_uvSet1 += stateOffset;
		#endif
		#if defined(USE_vs_uvSet2)
			vs_uvSet2 += stateOffset;
		#endif
		#if defined(USE_vs_uvSet3)
			vs_uvSet3 += stateOffset;
		#endif
	}
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lodFactor)
void pipeLodFactor()
{
	#pragma nu2_use(uniform, lodLimit)
	#pragma nu2_use(uniform, vs_projection_params)
	#pragma nu2_use(varying, varying_position)

	// TODO make xEye a shared resource to avoid redundant computation

	// backward projection
	half zEye = vs_projection_params.x / (1.0 - (varying_position.z/varying_position.w)*vs_projection_params.w);
//	varying_lodFactor = 1.0 - saturate(zEye / lodLimit);
	varying_lodFactor = saturate(1.3333 * (lodLimit - zEye) / lodLimit);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_eyeDistance)
void pipeEyeDistance()
{
	#pragma nu2_use(uniform, vs_projection_params)
	#pragma nu2_use(varying, varying_position)
	varying_eyeDistance = vs_projection_params.x / (1.0 - (varying_position.z / varying_position.w) * vs_projection_params.w);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_waterAmplitude)
void pipeWaterAmplitude()
{
	#pragma nu2_use(varying, varying_waterAmplitude)
	#pragma nu2_use(vs_local, vs_waterAmplitude)

	varying_waterAmplitude = vs_waterAmplitude;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightDir0)
void func_pipeLightDir0()
{
	#pragma nu2_use(uniform, vs_lightPosition0)
	#pragma nu2_use(varying, varying_lightDir0)
	varying_lightDir0 = vs_lightPosition0;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightDir1)
void func_pipeLightDir1()
{
	#pragma nu2_use(uniform, vs_lightPosition1)
	#pragma nu2_use(varying, varying_lightDir1)
	varying_lightDir1 = vs_lightPosition1;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightDir2)
void func_pipeLightDir2()
{
	#pragma nu2_use(uniform, vs_lightPosition2)
	#pragma nu2_use(varying, varying_lightDir2)
	varying_lightDir2 = vs_lightPosition2;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_normal)
iNliNE void func_pipeNormal()
{
	#pragma nu2_use(varying, varying_normal)
	#pragma nu2_use(vs_local, vs_normal)
	#pragma nu2_use(uniform, kTint)

	#if defined(DAPPLE)
		#pragma nu2_use(uniform, dappleLimit)
		#pragma nu2_use(uniform, vs_projection_params)
		#pragma nu2_use(varying, varying_position)

		half zEye = vs_projection_params.x / (1.0 - (varying_position.z / varying_position.w) * vs_projection_params.w);
		half dappleFactor = saturate(1.3333 * (dappleLimit - zEye) / dappleLimit);
		half3 unitNormal = normalize(vs_normal);

		varying_normal = lerp(unitNormal, vs_normal, dappleFactor);
	#else
		// w component stores opacity
		varying_normal = vs_normal.xyz;

	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_VertexOpacity)
iNliNE void func_pipeVertexOpacity()
{
	#pragma nu2_use(attribute, normal)
	#pragma nu2_use(varying, varying_VertexOpacity)
	#pragma nu2_use(uniform, kTint)

	// w component stores opacity
	varying_VertexOpacity = vin.normal.w * kTint.a;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_tangent)
iNliNE void func_pipeTangent()
{
	#pragma nu2_use(varying, varying_tangent)
	#pragma nu2_use(vs_local, vs_tangent)
	varying_tangent = vs_tangent;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_tangent2)
iNliNE void func_pipeTangent2()
{
	#pragma nu2_use(varying, varying_tangent2)
	#pragma nu2_use(vs_local, vs_tangent2)
	varying_tangent2 = vs_tangent2;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_bitangent)
iNliNE void func_pipeBitangent()
{
	#pragma nu2_use(varying, varying_bitangent)
	#pragma nu2_use(vs_local, vs_bitangent)
	varying_bitangent = vs_bitangent;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_brdfData)
iNliNE void func_pipeBRDFData()
{
	#pragma nu2_use(varying, varying_brdfData)
	#pragma nu2_use(vs_local, vs_brdfData)
	varying_brdfData = vs_brdfData;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_worldReflection)
iNliNE void func_pipeWorldReflection()
{
	#pragma nu2_use(uniform, vs_viewInverseTranspose)
	#pragma nu2_use(uniform, vs_view)
	#pragma nu2_use(vs_local, vs_reflection)
	varying_worldReflection = mul((float3x3)vs_viewInverseTranspose, vs_reflection);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_worldReflectionRot)
iNliNE void func_pipeWorldReflectionRot()
{
	#pragma nu2_use(varying, varying_worldReflectionRot)
	#pragma nu2_use(uniform, lightRotationMtx)
	#pragma nu2_use(vs_local, vs_reflection)

	varying_worldReflectionRot = mul(vs_reflection, (float3x3)lightRotationMtx);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_reflection)
iNliNE half3 func_computeReflection()
{
	#pragma nu2_use(vs_local, vs_incident)
	#pragma nu2_use(vs_local, vs_normal)

	return reflect(-vs_incident, vs_normal);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_incident)
iNliNE half3 func_computeIncident()
{
	#pragma nu2_use(vs_local, vs_eyePosition)
	return normalize(-vs_eyePosition.xyz);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_brdfData)
iNliNE half4 func_computeBRDFData()
{
	#pragma nu2_use(vs_local, vs_normal)
	#pragma nu2_use(vs_local, vs_tangent)
	#pragma nu2_use(vs_local, vs_bitangent)
	#pragma nu2_use(vs_local, vs_incident)
	#pragma nu2_use(uniform, brdf_params)
	
	// Transform incident vector into tangent space
	half3 TangentSpaceIncident;
	TangentSpaceIncident.x = dot(vs_incident,-vs_tangent);
	TangentSpaceIncident.y = dot(vs_incident,-vs_bitangent);
	TangentSpaceIncident.z = dot(vs_incident,vs_normal);

	// Transform into lightmap basis space
	half3 lmBasisVec1 = half3(	-0.4082482904,	-0.7071067811,	0.5773502691);
	half3 lmBasisVec2 = half3(	-0.4082482904,	0.7071067811,	0.5773502691);
	half3 lmBasisVec3 = half3(	0.8164965809,	0.0,			0.5773502691);
	half4 BRDFData = half4(0,0,0,0);
	BRDFData.x = dot(TangentSpaceIncident,lmBasisVec1);
	BRDFData.y = dot(TangentSpaceIncident,lmBasisVec2);
	BRDFData.z = dot(TangentSpaceIncident,lmBasisVec3);

	// Here we 'normalise' the view vector to ensure it won't significantly 
	// brighten or darken the lightmap weights (they must always sum to 1)
	half3 diag = half3(0.577,0.577,0.577);
	BRDFData.xyz -= diag * dot( BRDFData.xyz, diag );

	// Scale by 'smoothness' and add one so that this value can be multipled into
	// light-map weights directly (to result in weights = weights + offset*weights)
	// NOTE: The offset needs to be multiplied by the weights to preserve
	// any self-shadowing / occlusion effects
	//BRDFData.xyz *= brdf_params.x;
	BRDFData.xyz = BRDFData.xyz + half3(1.0,1.0,1.0);

	// BRDFData.z represents the per vertex N.L term. Interpolating this directly
	// will result in significant error and so we instead interpolate one minus
	// the square. This results in much less error when compared to interpolating 
	// the normal and performing the dot product per pixel, plus we have the bonus
	// that we have inverted the dot product in the vertex shader (which we would
	// otherwise need to do in the pixel shader to calculate fresnel effects).
#if (FRESNEL_STAGE == FRESNEL_PERVERT_BRDF) || (FRESNEL_STAGE == FRESNEL_PERPIXEL_BRDF)
	BRDFData.w = saturate( 1.0 - BRDFData.z*BRDFData.z ); 
#endif

	return BRDFData;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet0)
iNliNE void pipeUvSet0()
{
	#pragma nu2_use(vs_local, * varying_uvSet0_source)
	#pragma nu2_use(varying, varying_uvSet0)
	
	varying_uvSet0 = varying_uvSet0_source;

	#if FUNC_computeWorldPosition == VERTEX_TRANSFORM_WATER
		#pragma nu2_use(uniform, fxAttributes)
		#pragma nu2_use(vs_local, vs_waterCoef)
		varying_uvSet0.xy += (0.05f * fxAttributes.z * vs_waterCoef.xy);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet1)
iNliNE void pipeUvSet1()
{
	#pragma nu2_use(vs_local, * varying_uvSet1_source)
	#pragma nu2_use(varying, varying_uvSet1)
	
	varying_uvSet1 = varying_uvSet1_source;

	#if FUNC_computeWorldPosition == VERTEX_TRANSFORM_WATER
		#pragma nu2_use(uniform, fxAttributes)
		#pragma nu2_use(vs_local, vs_waterCoef)
		varying_uvSet1.xy += (0.05f * fxAttributes.z * vs_waterCoef.xy);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet2)
iNliNE void pipeUvSet2()
{
	#pragma nu2_use(vs_local, * varying_uvSet2_source)
	#pragma nu2_use(varying, varying_uvSet2)
	varying_uvSet2 = varying_uvSet2_source;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet3)
iNliNE void pipeUvSet3()
{
	#pragma nu2_use(vs_local, * varying_uvSet3_source)
	#pragma nu2_use(varying, varying_uvSet3)
	varying_uvSet3 = varying_uvSet3_source;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet4)
iNliNE void pipeUvSet4()
{
	#pragma nu2_use(vs_local, * varying_uvSet4_source)
	#pragma nu2_use(varying, varying_uvSet4)
	varying_uvSet4 = varying_uvSet4_source;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet5)
iNliNE void pipeUvSet5()
{
	#pragma nu2_use(vs_local, * varying_uvSet5_source)
	#pragma nu2_use(varying, varying_uvSet5)
	varying_uvSet5 = varying_uvSet5_source;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSet6)
iNliNE void pipeUvSet6()
{
	#pragma nu2_use(vs_local, * varying_uvSet6_source)
	#pragma nu2_use(varying, varying_uvSet6)
	varying_uvSet6 = varying_uvSet6_source;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_uvSetN) && defined(SURFACE_UVSET)
iNliNE void pipeUvSetN()
{
	#pragma nu2_use(varying, * SURFACE_UVSET)
	varying_uvSetN = SURFACE_UVSET;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightDirSet) && (VERTEX_SHADER_VERSION > 11)
iNliNE void pipeLightDirSet()
{
	#pragma nu2_use(attribute, lightDirSet)
	#pragma nu2_use(varying, varying_lightDirSet)
	#pragma nu2_use(vs_local, vs_incident)
	#define USE_projectModelToEyeSpace

	#if (VERTEX_SHADER_VERSION == 11)
		half3 vLightDirSet = vin.lightDirSet.zyx;	// was packed as D3DCOLOR
	#else
		half3 vLightDirSet = vin.lightDirSet.xyz;
	#endif
	varying_lightDirSet.xyz = vLightDirSet.xyz * 2.0 - 1.0;

#if defined(LMAPTODIFFUSEHACK)
		varying_lightDirSet.x=0;
		varying_lightDirSet.y=0;
		varying_lightDirSet.z=1;
#endif

	// Transform local space light direction to eye space
	varying_lightDirSet.xyz = projectModelToEyeSpace(varying_lightDirSet.xyz);

	// Calculate half vector (not as accurate as if it was done in pixel shader, can result in interpolation artifacts)
	varying_lightDirSet.xyz = normalize(varying_lightDirSet.xyz + vs_incident.xyz);
}


//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightHalfVec) && (VERTEX_SHADER_VERSION > 11)
iNliNE void pipeLightHalfVec()
{
	#pragma nu2_use(attribute, lightDirSet)
	#pragma nu2_use(varying, varying_lightDirSet)
	#pragma nu2_use(vs_local, vs_incident)
	#define USE_projectModelToEyeSpace

	#if (VERTEX_SHADER_VERSION == 11)
		half4 vLightDirSet = vin.lightDirSet.zyxw;	// was packed as D3DCOLOR
	#else
		half4 vLightDirSet = vin.lightDirSet;
	#endif
	varying_lightDirSet.xyz = vLightDirSet.xyz * 2.0 - 1.0;

	// Transform local space light direction to eye space
	varying_lightDirSet.xyz = projectModelToEyeSpace( varying_lightDirSet.xyz );

	// Calculate half vector
	varying_lightDirSet.xyz = normalize( varying_lightDirSet.xyz + vs_incident.xyz );
}


//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_lightColSet) && (VERTEX_SHADER_VERSION > 11)
iNliNE void pipeLightColSet()
{
	#pragma nu2_use(attribute, lightColSet)
	#pragma nu2_use(varying, varying_lightColSet)

#if defined(BEFORE_BAKED_SPECULAR_INTENSITY_FIX)
	// Mimick old broken code to avoid PC seeing a difference in old-data
	varying_lightColSet.rgb = vin.lightColSet.rgb * 2.0;
	varying_lightColSet.a = 1.0;
#else
	// Expand 8bit colour values using 8bit scalar stored in alpha
	varying_lightColSet.rgb = vin.lightColSet.rgb * vin.lightColSet.a * 10.0;
	varying_lightColSet.a = 1.0;
#endif

#if defined(LMAPTODIFFUSEHACK)
	varying_lightColSet.r=1;
	varying_lightColSet.gb=0.2f;
#endif

}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_colorSet0)
iNliNE void pipeColorSet0()
{
	#pragma nu2_use(attribute, colorSet0)
	#pragma nu2_use(varying, varying_colorSet0)
	#pragma nu2_use(uniform, kTint)
	
	#if (FUNC_computeWorldPosition == VERTEX_TRANSFORM_WATER)
		// We boost water alpha here, as a shader 1.1 compiler bug messes up the boost in the pixel shader.
		vin.colorSet0.a *= 1.5;
	#endif

	#if (PIXEL_SHADER_VERSION <= 14)
		
		#if (LIGHTING_MODEL != DISABLE)

			// Compute and apply the diffuse lighting in the vertex shader.
			#pragma nu2_use(vs_local, vs_normal)
			#pragma nu2_use(uniform, vs_ambientColor)
			#pragma nu2_use(uniform, vs_sceneAmbientColor)
			#pragma nu2_use(uniform, vs_lightPosition0)
			#pragma nu2_use(uniform, vs_lightPosition1)
			#pragma nu2_use(uniform, vs_lightPosition2)
			#pragma nu2_use(uniform, vs_lightColor0)
			#pragma nu2_use(uniform, vs_lightColor1)
			#pragma nu2_use(uniform, vs_lightColor2)

			half3 diffuseLight = vs_ambientColor.rgb + vs_sceneAmbientColor.rgb;
		
			#if LIGHTING_LIGHTS_COUNT > 0
				#if defined(ADJUSTED_LIGHTING_SUPPORTED)
					#pragma nu2_use(uniform, vs_lightingAdjust)
					diffuseLight += max(0, dot(vs_lightingAdjust.xyz * vs_lightPosition0.xyz, vs_normal)) * vs_lightColor0.rgb * vs_lightPosition0.w;
				#else
					diffuseLight += max(0, dot(vs_lightPosition0.xyz, vs_normal)) * vs_lightColor0.rgb * vs_lightPosition0.w;
				#endif
			#endif

			#if LIGHTING_LIGHTS_COUNT > 1
				#if defined(ADJUSTED_LIGHTING_SUPPORTED)
					#pragma nu2_use(uniform, vs_lightingAdjust)
					diffuseLight += max(0, dot(vs_lightingAdjust.xyz * vs_lightPosition1.xyz, vs_normal)) * vs_lightColor1.rgb * vs_lightPosition1.w;
				#else
					diffuseLight += max(0, dot(vs_lightPosition1.xyz, vs_normal)) * vs_lightColor1.rgb * vs_lightPosition1.w;
				#endif
			#endif

			#if LIGHTING_LIGHTS_COUNT > 2
				#if defined(ADJUSTED_LIGHTING_SUPPORTED)
					#pragma nu2_use(uniform, vs_lightingAdjust)
					diffuseLight += max(0, dot(vs_lightingAdjust.xyz * vs_lightPosition2.xyz, vs_normal)) * vs_lightColor2.rgb * vs_lightPosition2.w;
				#else
					diffuseLight += max(0, dot(vs_lightPosition2.xyz, vs_normal)) * vs_lightColor2.rgb * vs_lightPosition2.w;
				#endif
			#endif

			// Incandescent glow disabled now incandescence has been replaced with emissive flag.
//			#pragma nu2_use(uniform, vs_incandescentGlow)
//			diffuseLight = lerp(diffuseLight, half3(1.0, 1.0, 1.0), vs_incandescentGlow.rgb);

			varying_colorSet0 = saturate(vin.colorSet0 * half4(diffuseLight, 1.0));
			
			// Live-lit vertex shader 1.1 result - apply the COLOR_FACTOR in the pixel shader
			varying_colorSet0 = saturate(varying_colorSet0 * kTint);
			
		#else // (LIGHTING_MODEL != DISABLE)
		
			// Prelit vertex shader 1.1 result - apply the COLOR_FACTOR in the pixel shader
			varying_colorSet0 = saturate(vin.colorSet0 * kTint);

		#endif

		// colorSet0.a contains the lighting intensity factor for lightmapped surfaces.
		// This factor is meant to be multiplied by 10 on the pixel shader.
		// On ps_1_4 we can't do x10, so instead we do x2x8x0.625
		// x2 and x8 can be implemented as instruction and register modifiers.
		// The x0.625 would require an extra instruction and an extra constant.
		// Do it in the vertex shader instead.
		#if LIGHTMAP_STAGE != DISABLE
			varying_colorSet0.a *= 0.625;
		#endif

	#else // (PIXEL_SHADER_VERSION <= 14)

		#if (VERTEX_SHADER_VERSION < 30) || defined(_PS3_TOOL)
			// Vertex shader 2.0/2.0a result - apply the COLOR_FACTOR in the pixel shader
			varying_colorSet0 = saturate(vin.colorSet0 * kTint);
		#else
			// Vertex shader 3.0+ result - we can only apply the COLOR_FACTOR in the VS in SM3.0 due to VS output clamping on older shader models
			varying_colorSet0 = max(0.0, vin.colorSet0 * kTint * COLOR_FACTOR);
		#endif

	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_colorSet1)
iNliNE void pipeColorSet1()
{
	#pragma nu2_use(attribute, colorSet1)
	#pragma nu2_use(varying, varying_colorSet1)

	#if defined (HAS_BLENDSHAPE)
		#if defined(REFLECTIVITY_STAGE2) || (SURFACE_TYPE2 != SURFACE_SMOOTH)
			// Layer 2 FX maps are used with blendshapes - use the blendshape alpha stored in position.w.
			#pragma nu2_use(attribute, position)
			varying_colorSet1 = half4(vin.position.w, vin.colorSet1.gba);
		#else
			varying_colorSet1 = vin.colorSet1;
		#endif
	#else
		varying_colorSet1 = vin.colorSet1;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_colorSet2)
iNliNE void pipeColorSet2()
{
	#pragma nu2_use(attribute, colorSet2)
	#pragma nu2_use(varying, varying_colorSet2)
	varying_colorSet2 = vin.colorSet2;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_colorSet3)
iNliNE void pipeColorSet3()
{
	#pragma nu2_use(attribute, colorSet3) 
	#pragma nu2_use(varying, varying_colorSet3)
	varying_colorSet3 = vin.colorSet3;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_layer1alpha)
iNliNE void pipeLayer1alpha()
{
	#pragma nu2_use(attribute, colorSet1) 
	#pragma nu2_use(varying, varying_layer1alpha)
	varying_layer1alpha = vin.colorSet1.r;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_layer2alpha)
iNliNE void pipeLayer2alpha()
{
	#pragma nu2_use(attribute, colorSet1) 
	#pragma nu2_use(varying, varying_layer2alpha)
	varying_layer2alpha = vin.colorSet1.g;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_layer3alpha)
iNliNE void pipeLayer3alpha()
{
	#pragma nu2_use(attribute, colorSet1) 
	#pragma nu2_use(varying, varying_layer3alpha)
	varying_layer3alpha = vin.colorSet1.b;
}

//__________________________________________________________________________________________________
#endif


#if defined(USE_varying_shineMapCoord)
iNliNE void pipeShineMapCoord()
{
	#pragma nu2_use(uniform, ps2ShineMtx)
	#pragma nu2_use(uniform, fxAttributes)
	#pragma nu2_use(attribute, normal)
	#pragma nu2_use(uniform, world)

	#if (VERTEX_SHADER_VERSION == 11)
		half4 objectNormal = vin.normal.zyxw;
	#else
		half4 objectNormal = vin.normal;
	#endif
	half3 worldNormal = normalize(mul(objectNormal.xyz * 2.0 - 1.0, (float3x3)world));

	#if ENVMAP_STAGE == PS2_SHINEMAP
		worldNormal  *= fxAttributes.x;
	#endif

	varying_shineMapCoord = mul(float4(worldNormal, 1.0), ps2ShineMtx).xy;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_eyePosition)
iNliNE void pipeEyePosition()
{
	#pragma nu2_use(vs_local, vs_eyePosition)
	varying_eyePosition = vs_eyePosition.xyz;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_position2)
iNliNE void pipePosition2()
{
	#pragma nu2_use(varying, varying_position)
	varying_position2 = varying_position;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_positionX)
iNliNE void pipePositionX()
{
	#pragma nu2_use(varying, varying_position)
	varying_positionX = varying_position.x;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_positionY)
iNliNE void pipePositionY()
{
	#pragma nu2_use(varying, varying_position)
	varying_positionY = varying_position.y;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_positionZ)
iNliNE void pipePositionZ()
{
	#pragma nu2_use(varying, varying_position)
	varying_positionZ = varying_position.z;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_positionW)
iNliNE void pipePositionW()
{
	#pragma nu2_use(varying, varying_position)
	varying_positionW = varying_position.w;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_positionOneOverW)
iNliNE void pipePositionOneOverW()
{
	#pragma nu2_use(varying, varying_position)
	varying_positionOneOverW = 1.0 / varying_position.w;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_TBN)
iNliNE half3x3 func_computeTBN()
{
	#pragma nu2_use(vs_local, vs_tangent)
	#pragma nu2_use(vs_local, vs_bitangent)
	#pragma nu2_debug
	#pragma nu2_use(vs_local, vs_normal)
	#pragma nu2_use(vs_local, vs_TBN)
	return half3x3(vs_tangent, vs_bitangent, vs_normal);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_computeVertexSkin)
iNliNE half4 computeVertexSkin(
	const in float4 pos,
	const in float4x4 skinMatrix0, const in float4x4 skinMatrix1, const in float4x4 skinMatrix2,
	const in half w0, const in half w1, const in half w2)
{
	// SkinMatrix must be matrices that project directly from object space to world space
	float4 t0 = mul(pos, skinMatrix0);
	float4 t1 = mul(pos, skinMatrix1);
	float4 t2 = mul(pos, skinMatrix2);
	return t0*w0 + t1*w1 + t2*w2;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_computeVertexSkin4)
iNliNE half4 computeVertexSkin4(
	const in float4 pos,
    const in float4x4 skinMatrix0, const in float4x4 skinMatrix1, const in float4x4 skinMatrix2, const in float4x4 skinMatrix3,
    const in half4 weights)
{
	// SkinMatrix must be matrices that project directly from object space to world space
	float4 t0 = mul(pos, skinMatrix0);
	float4 t1 = mul(pos, skinMatrix1);
	float4 t2 = mul(pos, skinMatrix2);
	float4 t3 = mul(pos, skinMatrix3);
	return t0 * weights.x + t1 * weights.y + t2 * weights.z + t3 * weights.w;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_computeWind)
iNliNE half4 computeWind(const in float4 pos)
{
	#pragma nu2_use(uniform, wind_sampler)
	#pragma nu2_use(uniform, wind_params)

	half4 wind = 0.0;
	half wind_size = 256.0;
	
	// sample wind texture
	half4 t = half4(pos.xz+float2(wind_params.x, wind_params.x), 0.0f, 0.0f);
	half4 fn = tex2Dlod(wind_sampler, t);
	half4 tx, ty;
	ty = frac(fn);
	tx = (fn-ty)/128.0 - 1.0;
	ty = ty*2.0 - 1.0;

	// bilinear filtering
	half2 f = frac(t.xy*wind_size);
	half2 tA = lerp(float2(tx.x, ty.x), float2(tx.y, ty.y), f.x);
	half2 tB = lerp(float2(tx.z, ty.z), float2(tx.w, ty.w), f.x);
	wind.xz = lerp(tA, tB, f.y);
	wind.w = length(wind.xz);
	
	return wind;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_wind)
void pipeWind()
{
	#define USE_computeWind
	#pragma nu2_use(vs_local, vs_plantParams)
	#pragma nu2_use(uniform, world)
	#pragma nu2_use(uniform, wind_params)
	#pragma nu2_use(varying, varying_wind)

	float4 plant_position = {world._m30+vs_plantParams.x, 0.0f, world._m32+vs_plantParams.y, 0.0f};
	float4 worldpos = (mul(plant_position, world)+wind_params.y*0.5)/wind_params.y;

	varying_wind = computeWind(worldpos);
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_varying_plantParams)
void pipePlantParams()
{
	#pragma nu2_use(varying, varying_plantParams)
	#pragma nu2_use(vs_local, vs_plantParams)

	varying_plantParams = vs_plantParams;
	varying_plantParams.r = (varying_plantParams.r+5.0)/10.0;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_computeVertexWindOffset)
iNliNE float4 computeVertexWindOffset()
{
	#define USE_computeWind
	#pragma nu2_use(vs_local, vs_plantParams)
	#pragma nu2_use(uniform, world)
	#pragma nu2_use(uniform, wind_params)

	float4 plant_position = {world._m30+vs_plantParams.x, 0.0f, world._m32+vs_plantParams.y, 0.0f};
	float4 wind_map = 0.0;
	float4 offset = 0.0;
	float4 random_tangent = 0.0;
	float4 random_idle = {vs_plantParams.x, 0.0, vs_plantParams.y, 0.0};
	float fbend = vs_plantParams.z;
	float ftangent = vs_plantParams.w;

	// sample wind
	float4 worldpos = (mul(plant_position, world)+wind_params.y*0.5)/wind_params.y;
	wind_map = computeWind(worldpos);

	// motion regarding the wind
	offset.xz = wind_map.xz * fbend;
	offset.y = length(offset.xz)*(-0.25);
	offset.xz -= offset.xz*0.2;

	random_tangent.xz = cross(half3(wind_map.x, 0.0, wind_map.z), half3(0.0, 1.0, 0.0)) * wind_params.w*wind_map.w * ftangent * fbend;
	random_tangent.y = 0.0;

	// random motion
	random_idle = random_idle * fbend * wind_params.z;

	return (offset+random_idle+random_tangent);
}
#endif

#if defined(USE_computeVertexWindOffset2)
iNliNE half4 computeVertexWindOffset2()
{
	#define USE_computeWind
	#pragma nu2_use(vs_local, vs_plantParams)
	#pragma nu2_use(uniform, world)
	#pragma nu2_use(uniform, wind_params)
	#pragma nu2_use(uniform, wind_sampler)

	float4 plant_position = {world._m30+vs_plantParams.x, 0.0f, world._m32+vs_plantParams.y, 0.0f};
	float4 wind_map = 0.0;
	float4 offset = 0.0;
	half4 random = 0.0;
	half4 direction = {vs_plantParams.x*0.2, 0.0, vs_plantParams.y*0.2, 0.0};
	half fbend = vs_plantParams.z*2.0-1.0;
	half ftangent = vs_plantParams.w;

	// sample wind
	float4 worldpos = (mul(plant_position, world)+wind_params.y*0.5)/wind_params.y;
	wind_map = computeWind(worldpos);

	// motion regarding the wind
	offset.xz = direction.xz * wind_map.w * ftangent * cross(half3(direction.x, 0.0, direction.z), half3(wind_map.x, 0.0, wind_map.z)).y*dot(direction.xz, wind_map.xz);
	offset.y = wind_map.w * fbend;

	random.xz = direction.xz * wind_params.w * wind_map.w * ftangent * 0.25;
	random.y = wind_params.z * fbend * 0.25;

	return offset+random;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_computeVertexWindOffsetTree)
iNliNE float4 computeVertexWindOffsetTree()
{
	#define USE_computeWind
	#pragma nu2_use(vs_local, vs_plantParams)
	#pragma nu2_use(uniform, wind_params)
	#pragma nu2_use(uniform, world)

	float4 plant_position = {world._m30+vs_plantParams.x, 0.0f, world._m32+vs_plantParams.y, 0.0f};
	float4 wind_map = 0.0;
	float4 offset = 0.0;
	float fbend = vs_plantParams.z;
	float ftangent = vs_plantParams.w;
	
	// sample wind
	float4 worldpos = (mul(plant_position, world)+wind_params.y*0.5)/wind_params.y;
	wind_map = computeWind(worldpos);
	
	// motion regarding the wind
	offset.xz = wind_map.xz * wind_map.w * fbend;

	return offset;
}

//__________________________________________________________________________________________________
#endif

#if defined(FRACTAL)

iNliNE void func_pipeModelPosition()
{
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(varying, varying_modelPosition)
	varying_modelPosition.xyz = vin.position.xyz;
}

//__________________________________________________________________________________________________
#endif


#if defined(USE_vs_bitangent)
iNliNE half3 func_computeBitangent()
{
	#pragma nu2_use(uniform, bitangentFlip)
	#pragma nu2_use(vs_local, vs_tangent)
	#pragma nu2_use(vs_local, vs_normal)

	#if defined(FOUR_COMPONENT_TANGENTS)
		#pragma nu2_use(attribute, tangent)
		return vin.tangent.w * bitangentFlip * cross(vs_tangent, vs_normal);
	#else
		return bitangentFlip * cross(vs_tangent, vs_normal);
	#endif
}

//__________________________________________________________________________________________________
#endif


#if defined(USE_vs_tangent) && !defined(FUNC_computeTangent)
// default rule for vs_tangent
#define FUNC_computeTangent VERTEX_TRANSFORM
#endif

#if !defined(USE_vs_tangent)
#elif !defined(FUNC_computeTangent)
#elif FUNC_computeTangent == VERTEX_TRANSFORM
iNliNE half3 func_computeTangent()
{
//	#pragma nu2_use(uniform, bitangentFlip)
	#pragma nu2_use(attribute, tangent)
	#define USE_projectModelToEyeSpace

	#if (VERTEX_SHADER_VERSION == 11)
		half3 tangent = vin.tangent.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
	#else
		half3 tangent = vin.tangent.xyz * 2.0 - 1.0;
	#endif
//	return projectModelToEyeSpace(bitangentFlip * tangent);
	return projectModelToEyeSpace(tangent);
}
//__________________________________________________________________________________________________
#elif FUNC_computeTangent == VERTEX_TRANSFORM_SKINNING
iNliNE half3 func_computeTangent()
{
	#pragma nu2_use(uniform, skinMatrix)
	#pragma nu2_use(attribute, blendIndices0)
	#pragma nu2_use(attribute, blendWeight0)
	#pragma nu2_use(attribute, tangent)

	#if (VERTEX_SHADER_VERSION == 11)
		half3 tangent = vin.tangent.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
		half4 blendIndices0 = D3DCOLORtoUBYTE4(vin.blendIndices0);
		half4 blendWeight0 = vin.blendWeight0.zyxw;
	#else
		half3 tangent = vin.tangent.xyz * 2.0 - 1.0;
		half4 blendIndices0 = vin.blendIndices0;
		half4 blendWeight0 = vin.blendWeight0;
	#endif

	// 3-weight skinning should be sufficient even when vertex positions are 4-weight skinned
	half3 t0 = mul(tangent, (float3x3)skinMatrix[blendIndices0.x]);
	half3 t1 = mul(tangent, (float3x3)skinMatrix[blendIndices0.y]);
	half3 t2 = mul(tangent, (float3x3)skinMatrix[blendIndices0.z]);
	half3 t = normalize(t0 * blendWeight0.x + t1 * blendWeight0.y + t2 * (1.0 - blendWeight0.x - blendWeight0.y));

	#define USE_projectModelToEyeSpace
	return projectModelToEyeSpace(t);
}
//__________________________________________________________________________________________________
#elif FUNC_computeTangent == VERTEX_RAW
iNliNE half3 func_computeTangent()
{
	#pragma nu2_use(attribute, tangent)
	#if (VERTEX_SHADER_VERSION == 11)
		return vin.tangent.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
	#else
		return vin.tangent.xyz * 2.0 - 1.0;
	#endif

}

//__________________________________________________________________________________________________
#endif

#if !defined(USE_vs_tangent2)
#elif (FUNC_computeTangent == VERTEX_TRANSFORM)
iNliNE half3 func_computeTangent2()
{
//	#pragma nu2_use(uniform, bitangentFlip)
	#pragma nu2_use(attribute, tangent2)
	#define USE_projectModelToEyeSpace

	#if (VERTEX_SHADER_VERSION == 11)
		half3 tangent2 = vin.tangent2.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
	#else
		half3 tangent2 = vin.tangent2.xyz * 2.0 - 1.0;
	#endif
//	return projectModelToEyeSpace(bitangentFlip * tangent2);
	return projectModelToEyeSpace(tangent2);
}
//__________________________________________________________________________________________________
#elif (FUNC_computeTangent == VERTEX_TRANSFORM_SKINNING)
iNliNE half3 func_computeTangent2()
{
	#pragma nu2_use(uniform, skinMatrix)
	#pragma nu2_use(attribute, blendIndices0)
	#pragma nu2_use(attribute, blendWeight0)
	#pragma nu2_use(attribute, tangent2)

	#if (VERTEX_SHADER_VERSION == 11)
		half3 tangent2 = vin.tangent2.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
		half4 blendIndices0 = D3DCOLORtoUBYTE4(vin.blendIndices0);
		half4 blendWeight0 = vin.blendWeight0.zyxw;
	#else
		half3 tangent2 = vin.tangent2.xyz * 2.0 - 1.0;
		half4 blendIndices0 = vin.blendIndices0;
		half4 blendWeight0 = vin.blendWeight0;
	#endif

	// 3-weight skinning should be sufficient even when vertex positions are 4-weight skinned
	half3 t0 = mul(tangent2, (float3x3)skinMatrix[blendIndices0.x]);
	half3 t1 = mul(tangent2, (float3x3)skinMatrix[blendIndices0.y]);
	half3 t2 = mul(tangent2, (float3x3)skinMatrix[blendIndices0.z]);
	half3 t = normalize(t0 * blendWeight0.x + t1 * blendWeight0.y + t2 * (1.0 - blendWeight0.x - blendWeight0.y));

	#define USE_projectModelToEyeSpace
	return projectModelToEyeSpace(t);
}
//__________________________________________________________________________________________________
#elif (FUNC_computeTangent == VERTEX_RAW)
iNliNE half3 func_computeTangent2()
{
	#pragma nu2_use(attribute, tangent2)
	#if (VERTEX_SHADER_VERSION == 11)
		return vin.tangent2.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
	#else
		return vin.tangent2.xyz * 2.0 - 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_normal) && !defined(FUNC_computeNormal)
// default rule for vs_normal
#define FUNC_computeNormal VERTEX_TRANSFORM
#endif

#if !defined(USE_vs_normal)
#elif !defined(FUNC_computeNormal)
#elif FUNC_computeNormal == VERTEX_TRANSFORM
iNliNE half3 func_computeNormal()
{
	#pragma nu2_use(attribute, normal)
	#define USE_projectModelToEyeSpace

	#if (VERTEX_SHADER_VERSION == 11)
		half3 normal = vin.normal.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
		normal = normalize(normal);
	#else
		half3 normal = vin.normal.xyz * 2.0 - 1.0;
	#endif

	return projectModelToEyeSpace(normal);
}

//__________________________________________________________________________________________________
#elif FUNC_computeNormal == VERTEX_TRANSFORM_SKINNING
iNliNE half3 func_computeNormal()
{
	#pragma nu2_use(uniform, skinMatrix)
	#pragma nu2_use(attribute, blendIndices0)
	#pragma nu2_use(attribute, blendWeight0)
	#pragma nu2_use(attribute, normal)

	#if (VERTEX_SHADER_VERSION == 11)
		half3 normal = vin.normal.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
		half4 blendIndices0 = D3DCOLORtoUBYTE4(vin.blendIndices0);
		half4 blendWeight0 = vin.blendWeight0.zyxw;
	#else
		half3 normal = vin.normal.xyz * 2.0 - 1.0;
		half4 blendIndices0 = vin.blendIndices0;
		half4 blendWeight0 = vin.blendWeight0;
	#endif

	// 3-weight skinning should be sufficient even when vertex positions are 4-weight skinned
	half3 t0 = mul(normal, (float3x3)skinMatrix[blendIndices0.x]);
	half3 t1 = mul(normal, (float3x3)skinMatrix[blendIndices0.y]);
	half3 t2 = mul(normal, (float3x3)skinMatrix[blendIndices0.z]);
	half3 n = normalize(t0 * blendWeight0.x + t1 * blendWeight0.y + t2 * (1.0 - blendWeight0.x - blendWeight0.y));

	#define USE_projectModelToEyeSpace
	return projectModelToEyeSpace(n);
}

//__________________________________________________________________________________________________
#elif FUNC_computeNormal == VERTEX_RAW
iNliNE half3 func_computeNormal()
{
	#pragma nu2_use(attribute, normal)
	#if (VERTEX_SHADER_VERSION == 11)
		return vin.normal.zyx * 2.0 - 1.0;	// was packed as D3DCOLOR
	#else
		return vin.normal.xyz * 2.0 - 1.0;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_uvSet0) && !defined(FUNC_UVSET_0)
#define FUNC_UVSET_0 UVSET_DEFAULT
#endif

#if !defined(FUNC_UVSET_0)
half2 func_computeUvSet0()
{
	return half2(0,0);
}
#elif FUNC_UVSET_0 == UVSET_DEFAULT
half2 func_computeUvSet0()
{
	#if (UVSET_COUNT <= 1)
	#pragma nu2_use(attribute, uvSet0)
	return vin.uvSet0;
	#else
	#pragma nu2_use(attribute, uvSet01)
	return vin.uvSet01.xy;
	#endif
}
#elif FUNC_UVSET_0 == UVSET_ANIMATION
half2 func_computeUvSet0()
{
	#if (UVSET_COUNT <= 1)
		#pragma nu2_use(uniform, uvOffset01)
		#pragma nu2_use(attribute, uvSet0)
		return vin.uvSet0 + uvOffset01.xy;
	#else
		#pragma nu2_use(uniform, uvOffset01)
		#pragma nu2_use(attribute, uvSet01)
		return vin.uvSet01.xy + uvOffset01.xy;
	#endif
}
#endif

//__________________________________________________________________________________________________

#if defined (USE_vs_uvSet1) && !defined(FUNC_UVSET_1)
#define FUNC_UVSET_1 UVSET_DEFAULT
#endif

#if !defined(FUNC_UVSET_1)
half2 func_computeUvSet1()
{
	return half2(0,0);
}
#elif FUNC_UVSET_1 == UVSET_DEFAULT
half2 func_computeUvSet1()
{
	#pragma nu2_use(attribute, uvSet01)
	return vin.uvSet01.zw;
}

#elif FUNC_UVSET_1 == UVSET_ANIMATION
half2 func_computeUvSet1()
{
	#pragma nu2_use(uniform, uvOffset01)
	#pragma nu2_use(attribute, uvSet01)
	return vin.uvSet01.zw + uvOffset01.zw;
}
#endif

//__________________________________________________________________________________________________

#if defined(USE_vs_uvSet2) && !defined(FUNC_UVSET_2)
#define FUNC_UVSET_2 UVSET_DEFAULT
#endif

#if !defined(FUNC_UVSET_2)
half2 func_computeUvSet2()
{
	return half2(0,0);
}
#elif FUNC_UVSET_2 == UVSET_DEFAULT
half2 func_computeUvSet2()
{
	#if (UVSET_COUNT <= 3)
		#pragma nu2_use(attribute, uvSet2)
		return vin.uvSet2;
	#else
		#pragma nu2_use(attribute, uvSet23)
		return vin.uvSet23.xy;
	#endif
}

#elif FUNC_UVSET_2 == UVSET_ANIMATION
half2 func_computeUvSet2()
{
	#if (UVSET_COUNT <= 3)
		#pragma nu2_use(uniform, uvOffset23)
		#pragma nu2_use(attribute, uvSet2)
		return vin.uvSet2 + uvOffset23.xy;
	#else
		#pragma nu2_use(uniform, uvOffset23)
		#pragma nu2_use(attribute, uvSet23)
		return vin.uvSet23.xy + uvOffset23.xy;
	#endif
}
#endif

//__________________________________________________________________________________________________

#if defined (USE_vs_uvSet3) && !defined(FUNC_UVSET_3)
#define FUNC_UVSET_3 UVSET_DEFAULT
#endif

#if !defined(FUNC_UVSET_3)
half2 func_computeUvSet3()
{
	return half2(0,0);
}
#elif FUNC_UVSET_3 == UVSET_DEFAULT
half2 func_computeUvSet3()
{
	#pragma nu2_use(attribute, uvSet23)
	return vin.uvSet23.zw;
}

#elif FUNC_UVSET_3 == UVSET_ANIMATION
half2 func_computeUvSet3()
{
	#pragma nu2_use(uniform, uvOffset23)
	#pragma nu2_use(attribute, uvSet23)
	return vin.uvSet23.zw + uvOffset23.zw;
}

//__________________________________________________________________________________________________
#endif

#if defined (USE_vs_waterCoef) && !defined(FUNC_WATERCOEF)
#define FUNC_WATERCOEF WATERCOEF_DEFAULT
#endif

#if !defined(FUNC_WATERCOEF)
#elif FUNC_WATERCOEF == WATERCOEF_DEFAULT
iNliNE half4 func_computeWaterCoef()
{
	#pragma nu2_use(uniform, waterTable)
	#pragma nu2_use(vs_local, vs_waterIndex)
	return waterTable[vs_waterIndex];
}

#elif FUNC_WATERCOEF == WATERCOEF_AMPLITUDE
iNliNE half4 func_computeWaterCoef()
{
	#pragma nu2_use(uniform, waterTable)
	#pragma nu2_use(vs_local, vs_waterIndex)
	#pragma nu2_use(vs_local, vs_waterAmplitude)
	return waterTable[vs_waterIndex] * vs_waterAmplitude;
}

//__________________________________________________________________________________________________
#endif

#if defined (USE_vs_waterIndex)
iNliNE half func_computeWaterIndex()
{
	#pragma nu2_use(vs_local, vs_randomSeed)
	return vs_randomSeed * 31;
}

//__________________________________________________________________________________________________
#endif

#if defined (USE_vs_randomSeed)
iNliNE half func_computeRandomSeed()
{
	#if defined(FOUR_COMPONENT_TANGENTS)
		#pragma nu2_use(attribute, random)
		return random.x;
	#else
		#pragma nu2_use(attribute, tangent2)
		return vin.tangent2.w;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined (USE_vs_waterAmplitude)
iNliNE half func_computeWaterAmplitude()
{
	#if defined(FOUR_COMPONENT_TANGENTS)
		#pragma nu2_use(attribute, random)
		return random.y;
	#else
		#pragma nu2_use(attribute, tangent)
		#if (VERTEX_SHADER_VERSION == 11)
			half4 vTangent = vin.tangent.zyxw;	// was packed as D3DCOLOR
		#else
			half4 vTangent = vin.tangent;
		#endif
		return vTangent.w;
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined (USE_vs_plantParams)
iNliNE half4 func_computePlantParams()
{
	#pragma nu2_use(attribute, tangent2)
	half4 params;

	#if (VERTEX_SHADER_VERSION == 11)
		params = vin.tangent2.zyxw;	// was packed as D3DCOLOR
	#else
		params = vin.tangent2;
	#endif

	params.xy = params.xy * 10.0 - 5.0;
	params.w = params.w * 2.0 - 1.0;

	return params;
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_vs_worldViewInverseTranspose)
iNliNE half4x4 func_computeWorldViewInverseTranspose()
{
	#pragma nu2_use(uniform, world)
	#pragma nu2_use(uniform, vs_view)
	// we dont do inverse transpose to get rid of the scaling because world view
	// usually don't have such things. When they have (yes it happens), there is still the
	// possibility to normalize the result vector
	return mul(world, vs_view);
}
//__________________________________________________________________________________________________
#endif

// Set a default vertex transformation behaviour.
#if !defined(FUNC_computeWorldPosition)
#define FUNC_computeWorldPosition VERTEX_TRANSFORM
#endif


#if FUNC_computeWorldPosition == VERTEX_TRANSFORM
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(attribute, position)
	float4 positionH = float4(vin.position.xyz, 1.0);
	return mul(positionH, worldMtx);
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_TRANSFORM_SKINNING
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(uniform, skinMatrix)
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(attribute, blendIndices0)
	#pragma nu2_use(attribute, blendWeight0)
	#pragma nu2_use(vs_local, vs_skinPosition)
	#pragma nu2_use(vs_local, vs_skinMatrixOffset)

	#if (VERTEX_SHADER_VERSION == 11)
		// VGP 02May2007 : Compensate for lack of UBYTE4 on GeForce3/4
		half4 blendIndices0 = D3DCOLORtoUBYTE4(vin.blendIndices0);
		half4 blendWeight0 = vin.blendWeight0.zyxw;
	#else
		half4 blendIndices0 = vin.blendIndices0;
		half4 blendWeight0 = vin.blendWeight0;
	#endif

	float4 positionH = float4(vin.position.xyz, 1.0);
	
	// SkinMatrix projects from local space to local space
	#if defined(FOUR_WEIGHT_SKINNING)
		#define USE_computeVertexSkin4
		half4 i = blendIndices0 + float4(vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset);
		vs_skinPosition = computeVertexSkin4(positionH,
			skinMatrix[int(i.x)], skinMatrix[int(i.y)], skinMatrix[int(i.z)], skinMatrix[int(i.w)],
			blendWeight0);
	#else
		#define USE_computeVertexSkin
		half3 i = blendIndices0.xyz + float3(vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset);
		vs_skinPosition = computeVertexSkin(positionH,
			skinMatrix[int(i.x)], skinMatrix[int(i.y)], skinMatrix[int(i.z)],
			blendWeight0.x, blendWeight0.y, 1.0 - blendWeight0.x - blendWeight0.y);
	#endif

	return mul(vs_skinPosition, worldMtx);
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_TRANSFORM_BLEND_ANIM_SKINNING
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(uniform, skinMatrix)
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(attribute, blendIndices0)
	#pragma nu2_use(attribute, blendWeight0)
	#pragma nu2_use(attribute, blendOffsets0)
	#pragma nu2_use(vs_local, vs_skinPosition)
	#pragma nu2_use(vs_local, vs_skinMatrixOffset)

	// blended anim skinning
	// TO DO! *********************************************************

	float4 blendedVertex = float4(vin.position.xyz, 1.0);// + float4(vin.blendOffsets0.xyz, 0.0);

	#if defined(FOUR_WEIGHT_SKINNING)
		#define USE_computeVertexSkin4
		half4 i = vin.blendIndices0 + float4(vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset);
		vs_skinPosition = computeVertexSkin4(blendedVertex,
			skinMatrix[int(i.x)], skinMatrix[int(i.y)], skinMatrix[int(i.z)], skinMatrix[int(i.w)],
			vin.blendWeight0);
	#else
		#define USE_computeVertexSkin
		half3 i = vin.blendIndices0.xyz + float3(vs_skinMatrixOffset, vs_skinMatrixOffset, vs_skinMatrixOffset);
		vs_skinPosition = computeVertexSkin(blendedVertex,
			skinMatrix[int(i.x)], skinMatrix[int(i.y)], skinMatrix[int(i.z)],
			vin.blendWeight0.x, vin.blendWeight0.y, 1.0 - vin.blendWeight0.x - vin.blendWeight0.y);
	#endif

	return mul(vs_skinPosition, worldMtx);
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_FETCH_DISPLACEMENT
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(uniform, vertexFetch_sampler)
	#pragma nu2_use(uniform, vtf_kHeight)
	#pragma nu2_use(uniform, vtf_kOffset)
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(vs_local, *VERTEX_FETCH_UVSET)
	#pragma nu2_use(vs_local, vs_waterAmplitude)

	// Expects:
	//   G channel shifted right 1 texel
	//   B channel shifted down 1 texel
	//   A channel shifted right 1 texel and down 1 texel, i.e.
	//
	//   R G  =  Height(u, v    )  Height(u - 1, v    )
	//	 B A  =  Height(u, v - 1)  Height(u - 1, v - 1)

	float4 positionH = float4(vin.position.xyz, 1.0);
	float4 worldPosition = mul(positionH, worldMtx);

	const half textureSize = 256.0f;
	half2 f2 = frac(VERTEX_FETCH_UVSET_VAL * textureSize);
	half4 uv4 = half4(VERTEX_FETCH_UVSET_VAL, 0.0, 0.0);

	half4 t4 = tex2Dlod(vertexFetch_sampler, uv4);

	// This shouldn't be required, but the alpha read above doesn't seem to come out correctly.
	const half nextTexel = -1.0 / textureSize;
	t4.a = tex2Dlod(vertexFetch_sampler, uv4 + half4(nextTexel, nextTexel, 0.0, 0.0)).r;

	half2 t2 = lerp(t4.ga, t4.rb, f2.x);    // Interpolate top and bottom of texel in x
	half offset = lerp(t2.y, t2.x, f2.y);   // Interpolate last interpolation result in y
	
	#pragma nu2_use(attribute, normal)
	half3 worldNormal = normalize(mul(vin.normal.xyz * 2.0 - 1.0, (float3x3)world));

	worldPosition.xyz += worldNormal * ((offset + vtf_kOffset - 0.5) * vtf_kHeight * vs_waterAmplitude);

	return worldPosition;
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_TRANSFORM_WATER
// used for old-style water
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(vs_local, vs_waterCoef)

	float4 positionH = float4(vin.position.xyz, 1.0);
	return mul(positionH + half4(0.0, vs_waterCoef.w, 0.0, 0.0), worldMtx);
}

//__________________________________________________________________________________________________
#elif (FUNC_computeWorldPosition == VERTEX_TRANSFORM_UNUSED) || (FUNC_computeWorldPosition == VERTEX_TRANSFORM_UNUSED2)

iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	// Shouldn't get here. Use default behaviour in case it does.
	#pragma nu2_use(attribute, position)
	float4 positionH = float4(vin.position.xyz, 1.0);
	return mul(positionH, worldMtx);
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_FAST_BLEND
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	#pragma nu2_use(attribute, position)
	#pragma nu2_use(attribute, position1)
	#pragma nu2_use(uniform, vs_fastBlendWeights)

	// Interpolates between two input position streams...
	// project the vertex into clip space and pass it to the pixel shader
	float4 positionH = float4(vin.position.xyz, 1.0);
	return mul(lerp(positionH, vin.position1, vs_fastBlendWeights.x), worldMtx);
}

//__________________________________________________________________________________________________
#elif FUNC_computeWorldPosition == VERTEX_RAW
iNliNE float4 computeWorldPosition(float4x4 worldMtx)
{
	// No transform whatsoever
	#pragma nu2_use(attribute, position)

	#if defined(USE2DW)
		return vin.position.xyzw;
	#else
		return float4(vin.position.xyz, 1.0);
	#endif
}

//__________________________________________________________________________________________________
#endif

#if defined(USE_projectModelToEyeSpace)
iNliNE float3 projectModelToEyeSpace(float3 v)
{
	#if defined (_360_TARGET) || defined(_WINPC)
		#pragma nu2_use(vs_local, vs_worldViewInverseTranspose)
		return mul(v, (float3x3)vs_worldViewInverseTranspose);
	#else
		#pragma nu2_use(uniform, worldView)
		#pragma nu2_use(uniform, worldViewInverseTranspose)
		return mul(v, (float3x3)worldViewInverseTranspose);
	#endif
}

//__________________________________________________________________________________________________
#endif


#if defined(BUILD_VERTEX_SHADER)
//__________________________________________________________________________________________________
//
// THE VERTEX SHADER
//__________________________________________________________________________________________________

VertexOutput vertexProgram(VertexInput input) 
{
	vin = input;

	#pragma nu2_use(vs_local, vs_skinMatrixOffset)
	vs_skinMatrixOffset = 0;

	#if defined(USE_vs_worldViewInverseTranspose)
	vs_worldViewInverseTranspose = func_computeWorldViewInverseTranspose();
	#endif

	#if defined(USE_vs_normal)
	vs_normal = func_computeNormal();
	#endif
	
	#if defined(USE_vs_tangent)
	vs_tangent = func_computeTangent();
	#endif

	#if defined(USE_vs_tangent2)
	vs_tangent2 = func_computeTangent2();
	#endif

	#if defined(USE_vs_bitangent)
	vs_bitangent = func_computeBitangent();
	#endif

	#if defined(FUNC_computeTBN)
	vs_TBN = func_computeTBN();
	#endif

	#if defined(USE_vs_randomSeed)
	vs_randomSeed = func_computeRandomSeed();
	#endif
	
	#if defined(USE_vs_waterAmplitude)
	vs_waterAmplitude = func_computeWaterAmplitude();
	#endif
	
	#if defined(USE_vs_waterIndex)
	vs_waterIndex = func_computeWaterIndex();
	#endif
	
	#if defined(USE_vs_plantParams)
	vs_plantParams = func_computePlantParams();
	#endif
	
	#if defined(USE_vs_waterCoef)
	vs_waterCoef = func_computeWaterCoef();
	#endif
	
	#if defined(USE_vs_uvSet0)
	vs_uvSet0.xy = func_computeUvSet0();
	#endif

	#if defined(USE_vs_uvSet1)
	vs_uvSet1.xy = func_computeUvSet1();
	#endif

	#if defined(USE_vs_uvSet2)
	vs_uvSet2.xy = func_computeUvSet2();
	#endif

	#if defined(USE_vs_uvSet3)
	vs_uvSet3.xy = func_computeUvSet3();
	#endif
	
	// Always compute the world position.
	#pragma nu2_use(uniform, world)
	float4 worldPosition = computeWorldPosition(world);

	#if defined(REFLECTION_FADE)
		#pragma nu2_use(varying, varying_world_y)
		varying_world_y = worldPosition.y;
	#endif

	#if defined(USE_vs_eyePosition)
		#pragma nu2_use(uniform, vs_viewInverseTranspose)
		#pragma nu2_use(uniform, vs_view)

		#if defined(MOTION_BLUR_PASS)
			#pragma nu2_use(uniform, worldCamPos)

			// We shift the geometry slightly nearer the camera in the motion blur pass to overcome Z culling.
			float3 eyeShift = 0.05 * (worldCamPos.xyz - worldPosition.xyz);
			worldPosition.xyz += eyeShift;
		#endif

		vs_eyePosition = mul(worldPosition, vs_view);
	#endif

	#if defined(MOTION_BLUR_PASS) // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	#if defined(MOTION_BLUR_V2)
		#pragma nu2_use(uniform, projection)
	#else
		#pragma nu2_use(uniform, prevViewProj)
		#pragma nu2_use(varying, varying_newClipPosition)
	#endif
	#pragma nu2_use(uniform, viewProj)
	#pragma nu2_use(uniform, prevWorld)
	#pragma nu2_use(uniform, prevView)
	#pragma nu2_use(uniform, prevSkinMatrixOffset)
	#pragma nu2_use(uniform, blur_params)
	#pragma nu2_use(vs_local, vs_eyePosition)
	#pragma nu2_use(vs_local, vs_normal)
	#pragma nu2_use(varying, varying_position)
	#pragma nu2_use(varying, varying_positionX)
	#pragma nu2_use(varying, varying_positionY)
	#pragma nu2_use(varying, varying_positionW)
	#pragma nu2_use(varying, varying_oldClipPosition)

	// Use the character blur exposure value.
	float blurExposure = blur_params.y;

	#if defined(COMPUTE_PREVIOUS_WORLD_POS)
		vs_skinMatrixOffset = int(prevSkinMatrixOffset.x);
		float4 oldWorldPosition = computeWorldPosition(prevWorld);
		oldWorldPosition.xyz += eyeShift;
	#else
		float4 oldWorldPosition = worldPosition; 
	#endif

	#if defined(MOTION_BLUR_V2)
		float4 oldEyePosition = mul(oldWorldPosition, prevView);
		float3 eyeMotion = (vs_eyePosition.xyz - oldEyePosition.xyz) * blurExposure;
		varying_oldClipPosition = mul(vs_eyePosition, projection);

		// Choose a final eye position in the future or past of the static eye position based on the dot product between eye space motion and normal vectors.
		vs_eyePosition.xyz = (dot(eyeMotion, vs_normal) >= 0.0) ? (vs_eyePosition.xyz + eyeMotion) : (vs_eyePosition.xyz - eyeMotion);
		varying_position = mul(vs_eyePosition, projection);
	#else
		// Calculate the old and new eye space and clip space positions.
		varying_newClipPosition = mul(worldPosition, viewProj);

		float4 oldEyePosition = mul(oldWorldPosition, prevView);
		varying_oldClipPosition = mul(oldWorldPosition, prevViewProj);

		float4 displacement = (varying_newClipPosition - varying_oldClipPosition) * blurExposure;

		// Choose a final clip position in the future or past of the static clip position based on the dot product between eye space motion and normal vectors.
		float3 eyeMotion = vs_eyePosition.xyz - oldEyePosition.xyz;
		varying_position = (dot(eyeMotion, vs_normal) >= 0.0) ? (varying_newClipPosition + displacement) : (varying_newClipPosition - displacement);

		// Do Y flip and shutter fraction scale adjustment here to simplify motion vector calculation in the fragment shader.
		varying_oldClipPosition.xy *= float2(blurExposure, -blurExposure);
		varying_newClipPosition.xy *= float2(blurExposure, -blurExposure);
	#endif

	pipePositionX();
	pipePositionY();
	pipePositionW();

	#if defined(MOTION_BLUR_TEXTURED_ALPHA_CLIP) && defined(USE_varying_uvSet0)
		pipeUvSet0();
	#endif

	#if defined(_WINPC)
		varying_position.x += -1.0 * vs_screenSize.z * varying_position.w;
		varying_position.y +=  1.0 * vs_screenSize.w * varying_position.w;
	#endif

#if defined(TARGET_OS_MAC)
	varying_position.z = varying_position.z * 2.0 - varying_position.w;
#endif
    return vout;

	#else // !defined(MOTION_BLUR_PASS)  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	#pragma nu2_use(varying, varying_position)
	#if (FUNC_computeWorldPosition == VERTEX_RAW)
		// Pass through the world position.
		varying_position = worldPosition;
	#else
		// Project directly from world position to clip space - this must match the Z prepass shader method to avoid Z fighting.
		#pragma nu2_use(uniform, viewProj)
		varying_position = mul(worldPosition, viewProj);
	#endif
	
	#if defined(PERSPECTIVE_DIVIDE_IN_VERTEX_SHADER)
		// Make sure .w is 1. This helps with stereo 3D.
		varying_position /= varying_position.w;
		varying_position.w = 1;
	#endif

	#if defined(RENDER_FOR_SHADOW) 
	
		#if defined(GENERATE_DUAL_PARABOLOID_SHADOWMAP)
			#pragma nu2_use(uniform, vs_projection_params)

			float clippingZ = varying_position.z>0;

			float finalZ = length(varying_position.xyz);
			varying_position.xyz /= finalZ;
			varying_position.xy /= (varying_position.z + 1);
			varying_position.z = (finalZ - vs_projection_params.x) * vs_projection_params.w;
			varying_position.w = 1;

			//varying_position.xyz *= clippingZ;
			varying_position.w = clippingZ;

		#elif defined(GENERATE_CUBE_SHADOWMAP)
			//#pragma nu2_use(uniform, vs_projection_params)

			//varying_position.w = varying_position.z;
			//varying_position.z = length(varying_position.xyz) / 60.0 * varying_position.w;

		#endif

	#endif

	#if defined(FRACTAL)
	func_pipeModelPosition();
	#endif
	
	#if defined(USE_varying_position2)
	pipePosition2();
	#endif

	#if defined(USE_varying_positionX)
	pipePositionX();
	#endif

	#if defined(USE_varying_positionY)
	pipePositionY();
	#endif

	#if defined(USE_varying_positionZ)
	pipePositionZ();
	#endif

	#if defined(USE_varying_positionW)
	pipePositionW();
	#endif

	#if defined(USE_varying_positionOneOverW)
	pipePositionOneOverW();
	#endif

	#if defined(USE_varying_eyePosition)
	pipeEyePosition();
	#endif
	
	#if defined(USE_varying_waterAmplitude)
	pipeWaterAmplitude();
	#endif

	#if defined(USE_varying_lodFactor)
	pipeLodFactor();
	#endif

	#if defined(USE_varying_eyeDistance)
	pipeEyeDistance();
	#endif
		
	#if defined(USE_varying_lightColSet)
	pipeLightColSet();
	#endif

	#if defined(USE_varying_wind)
	pipeWind();
	#endif

	#if defined(USE_varying_plantParams)
	pipePlantParams();
	#endif

	#if defined(USE_vs_incident)
	vs_incident = func_computeIncident();
	#endif

	#if defined(USE_vs_brdfData)
	vs_brdfData = func_computeBRDFData();
	#endif

	#if defined(USE_vs_reflection)
	vs_reflection = func_computeReflection();
	#endif

	#if defined(USE_varying_lightDirSet)
	pipeLightDirSet();
	#endif

	#if defined(USE_varying_lightHalfVec)
	pipeLightHalfVec();
	#endif

	#if defined(VERTEX_GROUP)
	vertexGroupCompute();
	#endif

	#if defined(USE_varying_normal)
	func_pipeNormal();
	#endif
	#if defined(USE_varying_VertexOpacity)
	func_pipeVertexOpacity();
	#endif
	#if defined(USE_varying_tangent)
	func_pipeTangent();
	#endif
	#if defined(USE_varying_tangent2)
	func_pipeTangent2();
	#endif
	#if defined(USE_varying_bitangent)
	func_pipeBitangent();
	#endif
	#if defined(USE_varying_incident)
	func_pipeIncident();
	#endif
	#if defined(USE_varying_brdfData)
	func_pipeBRDFData();
	#endif
	#if defined(USE_varying_worldReflection)
	func_pipeWorldReflection();
	#endif
	#if defined(USE_varying_worldReflectionRot)
	func_pipeWorldReflectionRot();
	#endif

	#if defined(USE_varying_lightDir0)
	func_pipeLightDir0();
	#endif
	#if defined(USE_varying_lightDir1)
	func_pipeLightDir1();
	#endif
	#if defined(USE_varying_lightDir2)
	func_pipeLightDir2();
	#endif
	
	#if defined(USE_varying_uvSet0)
	pipeUvSet0();
	#endif
	#if defined(USE_varying_uvSet1)
	pipeUvSet1();
	#endif
	#if defined(USE_varying_uvSet2)
	pipeUvSet2();
	#endif
	#if defined(USE_varying_uvSet3)
	pipeUvSet3();
	#endif
	#if defined(USE_varying_uvSet4)
	pipeUvSet4();
	#endif
	#if defined(USE_varying_uvSet5)
	pipeUvSet5();
	#endif
	#if defined(USE_varying_uvSet6)
	pipeUvSet6();
	#endif

	#if defined(USE_varying_uvSetN)
	pipeUvSetN();
	#endif
	
	#if defined(USE_varying_colorSet0)
	pipeColorSet0();
	#endif
	#if defined(USE_varying_colorSet1)
	pipeColorSet1();
	#endif
	#if defined(USE_varying_colorSet2)
	pipeColorSet2();
	#endif
	#if defined(USE_varying_colorSet3)
	pipeColorSet3();
	#endif
	#if defined(USE_varying_layer1alpha)
	pipeLayer1alpha();
	#endif
	#if defined(USE_varying_layer2alpha)
	pipeLayer2alpha();
	#endif
	#if defined(USE_varying_layer3alpha)
	pipeLayer3alpha();
	#endif

	#if defined(USE_varying_shineMapCoord)
	pipeShineMapCoord();
	#endif

	#if defined(USE_varying_uvSetGlass)
	pipeuvSetGlass();
	#endif

	// Apply lightmap UV offset
	#if (LIGHTING_MODEL != LIGHTING_EMISSIVE) && (LIGHTMAP_STAGE != DISABLE) && (LIGHTMAP_STAGE != LIGHTMAP_VERTEXLIT_PHONG) && (LIGHTMAP_STAGE != LIGHTMAP_VERTEXLIT_LAMBERT)
		#pragma nu2_use(uniform, lightmapOffset)

		//#if (UVSET_COUNT > 3)
		//	#if defined(USE_vs_uvSet3)
		//		vs_uvSet3.xy = vs_uvSet3.xy * lightmapOffset.zw + lightmapOffset.xy;
		//	#endif
		//#elif (UVSET_COUNT > 2)
		//	#if defined(USE_vs_uvSet2)
		//		vs_uvSet2.xy = vs_uvSet2.xy * lightmapOffset.zw + lightmapOffset.xy;
		//	#endif
		//#elif (UVSET_COUNT > 1)
		//	#if defined(USE_vs_uvSet1)
		//		vs_uvSet1.xy = vs_uvSet1.xy * lightmapOffset.zw + lightmapOffset.xy;
		//	#endif
		//#elif (UVSET_COUNT > 0)
		//	#if defined(USE_vs_uvSet0)
		//		vs_uvSet0.xy = vs_uvSet0.xy * lightmapOffset.zw + lightmapOffset.xy;
		//	#endif
		//#endif

		LIGHTMAP_UVSET_VAL = LIGHTMAP_UVSET_VAL * lightmapOffset.zw + lightmapOffset.xy;

	#endif

	#if defined(FOG_STAGE)

		#pragma nu2_use(uniform, fog_params)	// {near, far, height, density}
		#pragma nu2_use(vs_local, vs_eyePosition)

		float fogFactor = 0;

		#if FOG_STAGE == FOG_VERTEX_LINEAR

			// TODO

		#elif FOG_STAGE == FOG_VERTEX_EXPONENTIAL

			fogFactor = exp(-length(vs_eyePosition.xyz) * fog_params.w);
			
		#elif FOG_STAGE == FOG_VERTEX_EXPONENTIAL2

			half dd = length(vs_eyePosition.xyz) * fog_params.w;
			fogFactor = exp(-dd * dd);

		#elif FOG_STAGE == FOG_VERTEX_CLAMP_EXPONENTIAL2

			half dist = max(0.0, length(vs_eyePosition.xyz) - fog_params.x);
			half dd = min((fog_params.y - fog_params.x), dist) * fog_params.w;
			fogFactor = exp(-dd * dd);
			
		#elif FOG_STAGE == FOG_VERTEX_CLAMP_EXPONENTIAL2_PS3

			fogFactor = min(varying_position.z, fog_params.y * varying_position.w);

		#elif FOG_STAGE == FOG_VERTEX_PLANAR_EXPONENTIAL2

			#pragma nu2_use(uniform, worldCamPos) // The w component contains the fog lower density multiplier
			#pragma nu2_use(vs_local, worldPosition)

			fogFactor = vs_fogVertexPlanarExponential2(worldPosition, vs_eyePosition.xyz);
		#endif

		#if PIXEL_SHADER_VERSION <= 14
			#pragma nu2_use(varying, varying_fog)
			varying_fog = fogFactor;
		#else
			#pragma nu2_use(varying, varying_fogFactor)
			varying_fogFactor = fogFactor;
		#endif

	#endif

	#if defined(USE_varying_vertexFresnel)

		#pragma nu2_use(varying, varying_vertexFresnel)
		#pragma nu2_use(uniform, vs_fresnel_params)
		#pragma nu2_use(vs_local, vs_incident)
		#pragma nu2_use(vs_local, vs_normal)

		float fresnelConst		= vs_fresnel_params.r;
		float invFresnelConst	= vs_fresnel_params.g;
		float fresnelPower		= vs_fresnel_params.b;
		float fresnelPowerX2	= vs_fresnel_params.a;

		#if defined (FRESNEL_EDGE_ALPHA)
			float ndotv = abs(dot(vs_normal, vs_incident));
			varying_vertexFresnel = lerp(fresnelConst, 1.0, pow(ndotv, 1.0 / fresnelPower));
		#else
			float invndotv = 1.0 - abs(dot(vs_normal, vs_incident));
			varying_vertexFresnel = lerp(fresnelConst, 1.0, pow(invndotv, fresnelPower));
		#endif

	#endif

#if defined(TARGET_OS_MAC)
	varying_position.z = varying_position.z * 2.0 - varying_position.w;
#endif
    return vout;

	#endif // #if !defined(MOTION_BLUR_PASS)
}

//__________________________________________________________________________________________________
#endif // defined(BUILD_VERTEX_SHADER)


#if defined(BUILD_PIXEL_SHADER)

#if defined(LMAPTODIFFUSEHACK)

// ------------------------------------------------------------------------------------------------
// Lightmap to Diffuse pixel shader
// ------------------------------------------------------------------------------------------------
FragmentOutput fragmentProgram_LightmapToDiffuse(VertexOutput input)
{
	vout = input;

	#pragma nu2_use(varying, * LIGHTMAP_UVSET)
	#pragma nu2_use(uniform, lightmap0)
	#pragma nu2_use(uniform, lightmap1)
	#pragma nu2_use(uniform, lightmap2)

	#pragma nu2_use(varying, varying_normal)
	#pragma nu2_use(varying, varying_tangent)
	#pragma nu2_use(varying, varying_bitangent)

	#pragma nu2_use(uniform, specular_params)
	#pragma nu2_use(varying, varying_lightDirSet)
	#pragma nu2_use(varying, varying_lightColSet)
	
	half4 TangentNormal = tex2D(lightmap1, LIGHTMAP_UVSET_VAL).rgba * 2 - 1;
	half3 Normal = normalize(varying_normal);
	half3 Tangent = normalize(varying_tangent);
	half3 Bitangent = normalize(varying_bitangent);
	half4 SpecularColour = tex2D(lightmap2, LIGHTMAP_UVSET_VAL).rgba;
	half3 WorldNormal = Tangent * TangentNormal.x + Bitangent * TangentNormal.y + Normal * TangentNormal.z;
	half4 LitAlbedo = tex2D(lightmap0, LIGHTMAP_UVSET_VAL).rgba;
	WorldNormal=normalize(WorldNormal);

	float NdotH = max(dot(WorldNormal, normalize(varying_lightDirSet.xyz) ), 0.0);
	float SpecLightStr = pow( NdotH, specular_params.r ) * specular_params.g; // Raise to power and scale by pre-calculate 'energy conserving' factor
//				float SpecLightStr = pow( NdotH, 20.0f) * 0.7f; // Raise to power and scale by pre-calculate 'energy conserving' factor
	half3 LightmapSpec = varying_lightColSet.rgb * SpecLightStr;

	LitAlbedo.rgb += SpecularColour.rgb*LightmapSpec;

	fout.color[0] = LitAlbedo;

	#if defined(NORMAL_OUTPUT)
		fout.color[NORMAL_OUTPUT] = float4(0.5, 0.5, 0.5, 1);
	#endif

	#if defined(ALBEDO_OUTPUT)
		fout.color[ALBEDO_OUTPUT] = half4(0,0,0,1);
	#endif

	#if defined(DEPTHRT_OUTPUT)
		fout.color[DEPTHRT_OUTPUT] = half4(0,0,0,0);
	#endif

	return fout;
}

#elif defined(MOTION_BLUR_PASS)

// ------------------------------------------------------------------------------------------------
// Motion blur pixel shader
// ------------------------------------------------------------------------------------------------
FragmentOutput fragmentProgram_MotionBlur(VertexOutput input)
{
	vout = input;

	#if defined(MOTION_BLUR_TEXTURED_ALPHA_CLIP)
		#pragma nu2_use(uniform, layer0_sampler)
		#pragma nu2_use(varying, * LAYER0_UVSET)
		float alpha = tex2D(layer0_sampler, LAYER0_UVSET_VAL).a;
	#else
		float alpha = 1.0;
	#endif

	#pragma nu2_use(uniform, colour_sampler)
	#pragma nu2_use(varying, varying_positionX)
	#pragma nu2_use(varying, varying_positionY)
	#pragma nu2_use(varying, varying_positionW)
	#pragma nu2_use(varying, varying_oldClipPosition)

	float2 rawPos = float2(varying_positionX, varying_positionY) / varying_positionW;
	float2 uv0 = rawPos * float2(1.0, -1.0) + 1.0;
	#if defined(MOTION_BLUR_V2)
		float2 motion = rawPos - varying_oldClipPosition.xy / varying_oldClipPosition.w;
		motion.y = -motion.y;
	#else
		#pragma nu2_use(varying, varying_newClipPosition)
		float2 motion = (varying_newClipPosition.xy / varying_newClipPosition.w) - (varying_oldClipPosition.xy / varying_oldClipPosition.w);
	#endif
	float2 uv = 0.5 * (uv0 - motion);

	// Blur by multisampling the colour in the backbuffer along the motion vector, unrolling the loop for efficiency.
	float4 c = tex2D(colour_sampler, uv);
	#if (MOTION_BLUR_SAMPLES >= 4)
		float2 d = motion / (MOTION_BLUR_SAMPLES - 1.0);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 8)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 12)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 16)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 20)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 24)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 28)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif
	#if (MOTION_BLUR_SAMPLES >= 32)
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
		uv += d; c += tex2D(colour_sampler, uv);
	#endif

	#if (MOTION_BLUR_SAMPLES > 1)
		fout.color[0] = float4(c.rgb / MOTION_BLUR_SAMPLES, alpha);
	#else
		fout.color[0] = float4(c.rgb, alpha);
	#endif

	return fout;
}

#else //defined(MOTION_BLUR_PASS)

// ------------------------------------------------------------------------------------------------
// Standard pixel shader
// ------------------------------------------------------------------------------------------------
FragmentOutput fragmentProgram_Standard(VertexOutput input)
{
	vout = input;

	#if defined(NORMAL_OUTPUT)
		fout.color[NORMAL_OUTPUT] = float4(0.5, 0.5, 0.5, 1);
	#endif

	#if defined(ALBEDO_OUTPUT)
		fout.color[ALBEDO_OUTPUT] = half4(0,0,0,1);
	#endif

	#if defined(DEPTHRT_OUTPUT)
		fout.color[DEPTHRT_OUTPUT] = half4(0,0,0,0);
	#endif

	#if defined(USE_fs_lodFactor)
	fs_lodFactor = func_fs_compute_lodFactor();
	#endif
	#if defined(USE_fs_dappleFactor)
	fs_dappleFactor = func_fs_computeDappleFactor();
	#endif
	#if defined(USE_fs_pos)
	fs_pos = func_fs_computePos();
	#endif
//	#if defined(USE_fs_vpos)
//	fs_vpos = func_fs_computeVPos();
//	#endif
	#if defined(USE_fs_nativeNormal)
	fs_nativeNormal = func_fs_computeNativeNormal();
	#endif
	#if defined(USE_fs_incident)
	fs_incident = func_fs_computeIncident();
	#endif
	#if defined(USE_fs_brdfData)
	fs_brdfData = func_fs_computeBRDFData();
	#endif
	#if defined(USE_fs_tangent)
	fs_tangent = func_fs_computeTangent();
	#endif
	#if defined(USE_fs_tangent2)
	fs_tangent2 = func_fs_computeTangent2();
	#endif
	#if defined(USE_fs_bitangent)
	fs_bitangent = func_fs_computeBitangent();
	#endif
	#if defined(USE_fs_bitangent2)
	fs_bitangent2 = func_fs_computeBitangent2();
	#endif
	#if defined(USE_fs_surfaceIncident)
	fs_surfaceIncident = func_fs_computeSurfaceIncident();
	#endif
	#if defined(USE_fs_surfaceIncident2)
	fs_surfaceIncident2 = func_fs_computeSurfaceIncident2();
	#endif

	#if defined(USE_fs_lightDir0)
	fs_lightDir0 = func_fs_computeLightDir0();
	#endif
	#if defined(USE_fs_lightDir1)
	fs_lightDir1 = func_fs_computeLightDir1();
	#endif
	#if defined(USE_fs_lightDir2)
	fs_lightDir2 = func_fs_computeLightDir2();
	#endif

	#if defined(USE_fs_specLightDir0)
	fs_specLightDir0 = func_fs_computeSpecLightDir0();
	#endif
	#if defined(USE_fs_specLightDir1)
	fs_specLightDir1 = func_fs_computeSpecLightDir1();
	#endif
	#if defined(USE_fs_specLightDir2)
	fs_specLightDir2 = func_fs_computeSpecLightDir2();
	#endif

	#if defined(USE_fs_fog_color)
	fs_fog_color = func_fs_computeFogColor();
	#endif
	
	#if defined(USE_fs_layer0_color)
	fs_layer0_color = func_fs_computeLayer0_color();
	#endif
	#if defined(USE_fs_layer1_alpha)
	fs_layer1_alpha = func_fs_computeLayer1_alpha();
	#endif
	#if defined(USE_fs_layer2_alpha)
	fs_layer2_alpha = func_fs_computeLayer2_alpha();
	#endif
	#if defined(USE_fs_layer3_alpha)
	fs_layer3_alpha = func_fs_computeLayer3_alpha();
	#endif
	#if defined(USE_fs_blend2)
	fs_blend2 = func_fs_computeBlend2();
	#endif

	#if defined(USE_fs_vertexOpacity)
	fs_vertexOpacity = func_fs_computeVertexOpacity();
	#endif

	#if defined(USE_fs_lightingIntensityFactor)
	fs_lightingIntensityFactor = func_fs_computeLightingIntensityFactor();
	#endif	
	
	#if defined(USE_fs_adjustedVertexColor)
	fs_adjustedVertexColor = func_fs_computeAdjustedVertexColor();
	#endif
	
	#if defined(FUNC_fs_computeSurfaceNormal)
	fs_surfaceNormal = func_fs_computeSurfaceNormal();
	#endif
	#if defined(FUNC_fs_computeVTFNormal) && FUNC_fs_computeVTFNormal == VTF_SURFACE_NORMAL_MAP
	fs_vtfNormal = func_fs_computeVTFNormal();
	#endif

	half FragmentOcclusion = 1.0;

	#if PIXEL_SHADER_VERSION >= 30
		#if defined(USE_fs_lightmapNormal)
			fs_lightmapNormal = float3(0.333,0.333,0.333);
			#if SURFACE_TYPE == SURFACE_SELF_SHADOW_NORMAL_MAP
				#pragma nu2_use(fs_local, fs_surfaceNormal)
				// Use self-shadow normal map coeffecients directly
				fs_lightmapNormal = fs_surfaceNormal.xyz;
			#endif
			#if (SURFACE_TYPE == SURFACE_NORMAL_MAP) || (SURFACE_TYPE == SURFACE_PARALLAX_MAP)
				#pragma nu2_use(fs_local, fs_surfaceNormal)
				// Project tangent space normal onto light-map basis vectors
				half3 lmBasisVec1 = half3( -0.4082482904,	-0.7071067811,	0.5773502691);
				half3 lmBasisVec2 = half3( -0.4082482904,	 0.7071067811,	0.5773502691);
				half3 lmBasisVec3 = half3(  0.8164965809,	 0.0,			0.5773502691);
				fs_lightmapNormal.x = saturate( dot(fs_surfaceNormal,lmBasisVec1) );
				fs_lightmapNormal.y = saturate( dot(fs_surfaceNormal,lmBasisVec2) );
				fs_lightmapNormal.z = saturate( dot(fs_surfaceNormal,lmBasisVec3) );
				// Normalise to ensure consistant brightness
				fs_lightmapNormal *= fs_lightmapNormal;
				fs_lightmapNormal /= dot( fs_lightmapNormal, half3(1,1,1) );
			#endif
		#endif

		#if defined(FUNC_fs_computeSurfaceNormal)
			#if SURFACE_TYPE == SURFACE_SELF_SHADOW_NORMAL_MAP
				// Calculate occlusion
				FragmentOcclusion = dot( fs_surfaceNormal, half3(1,1,1) );
				// Our surface normal was read in the 'lightmap-basis' space
				// and so needs transforming into tangent space
				half3 lmBasisVec1 = half3(	-0.4082482904,	-0.7071067811,	0.5773502691);
				half3 lmBasisVec2 = half3(	-0.4082482904,	0.7071067811,	0.5773502691);
				half3 lmBasisVec3 = half3(	0.8164965809,	0.0,			0.5773502691);
				fs_surfaceNormal.xyz = lmBasisVec1*fs_surfaceNormal.x + lmBasisVec2*fs_surfaceNormal.y + lmBasisVec3*fs_surfaceNormal.z;
			#endif
		#endif
	#endif

	#if defined(FUNC_fs_computeNormal)
	fs_normal = func_fs_computeNormal();
	#endif

	#if PIXEL_SHADER_VERSION >= 20
		#if defined(FUNC_fs_computeSurfaceNormal)
			// We now normalise here instead of in func_fs_computeSurfaceNormal(), since func_fs_computeNormal() needed the un-normalized value.
			fs_surfaceNormal.xyz = normalize(fs_surfaceNormal.xyz);
		#endif
	#endif

	#if defined(USE_fs_specularNormal)
		#if (LIGHTING_MODEL == LIGHTING_SKIN)
			#pragma nu2_use(fs_local, fs_normal)
			fs_specularNormal = fs_normal;
			fs_normal = func_fs_computeSpecularNormal();
		#else
			fs_specularNormal = func_fs_computeSpecularNormal();
		#endif
	#endif
	#if defined(FRACTAL)
	func_fs_compute_fbm0();
	#endif
	#if defined(FRACTAL_BUMP)
	func_fs_fractalBump();
	#endif
	#if defined(FUNC_fs_computeTBN)
	fs_TBN = func_fs_computeTBN();
	#endif
	#if defined(USE_fs_worldReflection)
	fs_worldReflection = func_fs_computeWorldReflection();
	#endif
	#if defined(USE_fs_lightDirSet)
	fs_lightDirSet = func_fs_computeLightDirSet();
	#endif
	#if defined(USE_fs_lightHalfVec)
	fs_lightHalfVec = func_fs_computeLightHalfVec();
	#endif
	#if defined(USE_fs_lightCol)
	fs_lightCol = func_fs_computeLightCol();
	#endif
	#if defined(USE_fs_ldotn0)
	func_fs_compute_ldotn0(FragmentOcclusion);
	#endif
	#if defined(USE_fs_ldotn1)
	func_fs_compute_ldotn1(FragmentOcclusion);
	#endif
	#if defined(USE_fs_ldotn2)
	func_fs_compute_ldotn2(FragmentOcclusion);
	#endif

	// compute albedo
	half4 albedo;
	half4 surfaceColour = multiLayerBlendingStage(albedo);

	#pragma nu2_use(fs_local, fs_lodFactor)

	// Standard Lighting: the lighting equation assumes:
	//     half4(albedo.rgb * diffuseLight + specularLight, albedo.a)
	// (in practice, refraction comes in-between to tune the diffuse)
	const bool standardLighting = true;

	float fresnel = 1.0;
	half4 reflectivity = 1.0;

	#if defined(FLOOR_CLIP)
		#if defined(ADJUSTED_LIGHTING_SUPPORTED)
			#if defined(LIVE_LIT)
				// Clip out any normal geometry passing downwards through the floor (at y = 0)
				// and also any reflected geometry passing upwards through the floor. Only do
				// this for live-lit objects - presumed to be animated characters.
				#pragma nu2_use(fs_local, fs_lightingAdjust)
				#pragma nu2_use(varying, varying_world_y)
				clip(varying_world_y * fs_lightingAdjust.y);
			#endif
		#endif
	#endif

	half3 diffuseLight		= 0.0;
	half3 specularLight		= 0.0;
	half3 specularLightDE	= 0.0;
	half  shadowFactor		= 1;
	half4 bbColour			= 0.0;
	half3 albedoTweakDE     = 0.0;
	half3 albedoTweakDES    = 0.0;
	half3 albedoTweakEnv    = 0.0;

	if (standardLighting)
	{
		fresnel = fresnelStage();

		reflectivity = reflectivityStage();

		#if REFRACTION_STAGE != DISABLE
			// Scale all specular effects (and refraction control in alpha) by the vertex alpha.
			#pragma nu2_use(fs_local, fs_vertexOpacity)
			reflectivity *= fs_vertexOpacity;
		#endif

		// Compute lighting contributions
		lightingStage( fresnel, diffuseLight, specularLight, specularLightDE, shadowFactor, albedoTweakDE, albedoTweakDES );

		// Adjust specular contribution depending on fresnel, reflectivity and lod factor
		specularLight = ((specularLight * fresnel * fs_lodFactor + specularLightDE) * reflectivity.xyz);

		#if defined(ENVMAP_STAGE)
			specularLight += envmapStage(diffuseLight, fresnel, albedoTweakEnv) * reflectivity.xyz;
		#endif

		#if defined (FRESNEL_EDGE_ALPHA) || defined(FRESNEL_CENTRE_ALPHA) || defined(FRESNEL_FIN_ALPHA)
			surfaceColour.a *= fresnelAlphaStage(fresnel);
		#endif

		#if (REFRACTION_STAGE != DISABLE)
			// Do refraction setup on surfaceColour.
			#if defined (FRESNEL_EDGE_ALPHA)
				refractionSetupStage(surfaceColour, bbColour, fresnel, reflectivity.a, fresnel);
			#else
				refractionSetupStage(surfaceColour, bbColour, fresnel, reflectivity.a, 1.0);
			#endif
		#endif
			
		#if defined(LAQUERED_SURFACE_BRDF)
			diffuseLight *= 0.5 + 0.5*(1.0 - fresnel);
		#endif

		#if defined(LINEAR_SPACE_LIGHTING)
			float Gamma = 2.0;
			surfaceColour.rgb = pow( surfaceColour.rgb, Gamma );
			diffuseLight.rgb = pow( diffuseLight.rgb, Gamma );
		#endif

		#if defined(AMBIENT_OCCLUSION)
			#pragma nu2_use(fs_local, fs_layer0_color)
			diffuseLight  *= fs_layer0_color.rgb;
			specularLight *= fs_layer0_color.rgb;
		#endif

		// modulate surface colour by diffuse light contribution
		surfaceColour.rgb *= diffuseLight;

		#if defined(GLOW)
			#pragma nu2_use(uniform, incandescentGlow)

			#if (PIXEL_SHADER_VERSION <= 14)
				// Note: The brackets are important in the following statement.
				//		 They're there so the compiler can translate this to a _x8 instruction modifier.
				surfaceColour.rgb += 8 * (surfaceColour.rgb * incandescentGlow.a);
			#else
				surfaceColour.rgb *= (1.0 + 10.0*incandescentGlow.a);
			#endif
		#endif
	
		#if defined(LINEAR_SPACE_LIGHTING)
			surfaceColour.rgb = pow( surfaceColour.rgb, 1.0/Gamma );
		#endif
	}
	else
	{
		// non standard lighting models go here

	}


	#if defined (REFLECTION_FADE)
		// Applies a fade to green on geometry with negative y - presumed to be underfloor reflections (for TT Animation).
		#pragma nu2_use(varying, varying_world_y)
		#pragma nu2_use(uniform, carpaint_params)
		half3 fadeGreen = half3(0.162, 0.397, 0.078);
		#if defined(LIVE_LIT)
			// For live-lit objects (characters) use the reflection depth as specified in the cutscene .cfg
			half fadeOutDepth = carpaint_params.z;
		#else
			// For pre-lit objects (scenery) use scale up the reflection depth specified in the cutscene .cfg
			half fadeOutDepth = carpaint_params.z * 5.0;
		#endif
		half reflectionFade = saturate((fadeOutDepth + varying_world_y) / fadeOutDepth);
		half fadeFactor = max(step(0.0, varying_world_y), carpaint_params.x * pow(reflectionFade, carpaint_params.y));
		surfaceColour.rgb = lerp(fadeGreen, surfaceColour.rgb, fadeFactor);
	#endif


	// Refraction and fog...
	#if (REFRACTION_STAGE != DISABLE)

		// Apply fog before refraction to avoid effectively applying it twice (its already applied to bbColour)
		#if defined(FOG_STAGE)
			half fogFactor = calculateFogBlendFactor();
			surfaceColour = fogStage( surfaceColour, fogFactor );
		#endif

		// Apply refraction before specular, so that the specular effect isn't diminished
		surfaceColour.rgb = lerp(bbColour.rgb, surfaceColour.rgb, saturate(bbColour.a));

		// Apply fog-corrected specular (assumes fogFactor normally controls a linear lerp from surfaceColour to fogColour)
		#if defined(FOG_STAGE)
			surfaceColour.rgb += specularLight * fogFactor;
		#else
			surfaceColour.rgb += specularLight;
		#endif
	#else
	
		// Add in the specular
		surfaceColour.rgb += specularLight;

		// Apply fog
		#if defined(FOG_STAGE)
			surfaceColour = fogStage( surfaceColour, calculateFogBlendFactor() );
		#endif

	#endif

	// Convert HDR colour value to LDR to store in framebuffer
	#pragma nu2_use(uniform, exposure)
	surfaceColour = HDRToLDR( surfaceColour, false );
	
	// Apply LEGO shadow
	#if (LIGHTING_MODEL != LIGHTING_EMISSIVE)
		#if defined(USE_SHADOWMAP)
			surfaceColour.rgb *= shadowFactor;
		#endif
	#endif

	fout.color[0] = surfaceColour;

	// SM14 specific, on materials that don't do blending, set the output alpha to 1 to save
	// some pixel shader instructions (and make shaders compile)
	#if defined(FORCE_ALPHA_TO_ONE)
		#if (PIXEL_SHADER_VERSION <= 14)
			fout.color[0].a = 1;
		#endif
	#endif

	#if defined(NORMAL_OUTPUT)
		#if !defined(NORMAL_OUTPUT_IS_NULL)
			#pragma nu2_use(fs_local, fs_normal)

			// No reprojection
			{
				fout.color[NORMAL_OUTPUT].rg = fs_normal.xy * 0.5 + 0.5;
			}

		#endif
	#endif
	
	#if defined (DEFERRED_MATERIAL)
		#pragma nu2_use(uniform, specular_params)
		// Specular intensity in [0..20] range
		fout.color[NORMAL_OUTPUT].b = specular_params.g * specular_params.b * (reflectivity.r * fresnel);

		// Although albedo is 'unlit' we tweak the value for environmental and ambient occlusion contributions
		#if defined(TT_ANIMATION)
			// We only allow these additions for TT Animation since only they have a 16-bit albedo render target
			#if defined(DIFFUSE_ENV)
				albedo.rgb *= (1.0 + albedoTweakDE);
			#endif
			#if defined(DIFFUSE_ENV_SPECULAR)
				albedo.rgb += albedoTweakDES;
			#endif
			#if defined(ENVMAP_STAGE)
				albedo.rgb += albedoTweakEnv;
			#endif
		#endif
		#if defined(AMBIENT_OCCLUSION)
			#pragma nu2_use(fs_local, fs_layer0_color)
			albedo.rgb *= fs_layer0_color.rgb;
		#endif

		fout.color[ALBEDO_OUTPUT].rgb = albedo.rgb;

		#if defined(MRT_ALPHABLEND)
			fout.color[NORMAL_OUTPUT].a = fout.color[0].a;
			fout.color[ALBEDO_OUTPUT].a = fout.color[0].a;
		#endif

		#if (LIGHTING_MODEL == LIGHTING_EMISSIVE)
			fout.color[NORMAL_OUTPUT].xy = 0.5;
			fout.color[NORMAL_OUTPUT].b = 0;
			fout.color[ALBEDO_OUTPUT] = 0;
		#endif

	#endif

	#if defined(RENDER_FOR_SHADOW)
		
		fout.color[0].rgb = 1;

		#if defined(RENDER_FOR_SHADOW_ALPHATESTED)
			//fout.color[0].a = surfaceColour.a;
			fout.color[0].a = albedo.a;
		#else
			fout.color[0].a = 1;
		#endif

	#endif

	#if defined (DEPTHRT_OUTPUT)
		// If varying_position2 has been used elsewhere, reuse it here. 
		// This way we don't end up using both pos2 and posZ/W
		#if defined(USE_varying_position2)
			float depth = varying_position2.z / varying_position2.w;
		#else
			#pragma nu2_use(varying, varying_positionZ)
			#pragma nu2_use(varying, varying_positionW)
			float depth = varying_positionZ / varying_positionW;
		#endif
		
		{
			float iDepth = depth * 0xFFFFFF;

			float high;
			iDepth = modf(iDepth / (256.0 * 256.0), high);
			iDepth *= 256.0 * 256.0;
			high /= 0xFF;

			float med;
			iDepth = modf(iDepth / 256.0, med);
			med /= 0xFF;

			fout.color[DEPTHRT_OUTPUT].r = high;
			fout.color[DEPTHRT_OUTPUT].g = med;
			fout.color[DEPTHRT_OUTPUT].b = iDepth;

			#if defined(RENDER_FOR_SHADOW_ALPHATESTED)
			fout.color[DEPTHRT_OUTPUT].a = surfaceColour.a;
			#else
			fout.color[DEPTHRT_OUTPUT].a = 1.0;
			#endif
		}
	#endif //DEPTHRT_OUTPUT


	#if defined(LOW_COST_SHADER)

		#if defined(USE_fs_normal)
			fout.color[0].rgb = abs(fs_normal.z);
		#else
			fout.color[0].rgb = 1;
		#endif

		fout.color[0].a = surfaceColour.a;

		#if defined(NORMAL_OUTPUT)
			fout.color[NORMAL_OUTPUT] = float4(0.5, 0.5, 0.5, 1);
		#endif

		#if defined(ALBEDO_OUTPUT)
			fout.color[ALBEDO_OUTPUT] = half4(0,0,0,1);
		#endif

		#if defined(DEPTHRT_OUTPUT)
			fout.color[DEPTHRT_OUTPUT] = half4(0,0,0,0);
		#endif

	#endif

	return fout;
}

#endif

// ------------------------------------------------------------------------------------------------
// Pixel shader entry point
// ------------------------------------------------------------------------------------------------
FragmentOutput fragmentProgram(VertexOutput input)
{
	#if defined(LMAPTODIFFUSEHACK)

		return fragmentProgram_LightmapToDiffuse(input);

	#elif defined(MOTION_BLUR_PASS)

		return fragmentProgram_MotionBlur(input);

	#else

		return fragmentProgram_Standard(input);

	#endif
}

//__________________________________________________________________________________________________
#endif // defined(BUILD_PIXEL_SHADER)

#if defined (BUILD_EFFECT)
technique TECHNIQUE_BUILTSHADER
{
    pass p0 
    {
		#if VERTEX_SHADER_VERSION == 30
		VertexShader = compile vs_3_0 vertexProgram();
		#elif VERTEX_SHADER_VERSION == 21
		VertexShader = compile vs_2_a vertexProgram();
		#elif VERTEX_SHADER_VERSION == 20
		VertexShader = compile vs_2_0 vertexProgram();
		#elif VERTEX_SHADER_VERSION == 11
		VertexShader = compile vs_1_1 vertexProgram();
		#endif

		#if PIXEL_SHADER_VERSION == 30
		PixelShader  = compile ps_3_0 fragmentProgram();
		#elif PIXEL_SHADER_VERSION == 21
		PixelShader  = compile ps_2_a fragmentProgram();
		#elif PIXEL_SHADER_VERSION == 20
		PixelShader  = compile ps_2_0 fragmentProgram();
		#elif PIXEL_SHADER_VERSION == 11
		PixelShader  = compile ps_1_1 fragmentProgram();
		#endif
    }
}

//__________________________________________________________________________________________________
#endif

// Dummy comment to get rid of old cached shaders on PC
// And again

