//GL Engine Cg Shaders Be Here. -Nikolai
#define ENABLE_IBL

#ifndef CONDITIONAL_SHADER_COMPILATION
#define ENABLE_AGFBumpMap
#define ENABLE_AGFSphereEnvironmentMap
#define ENABLE_AGFDiffuseMap

#define ENABLE_ATTENUATION
#define ENABLE_SPOTLIGHTS
#define ENABLE_SPECULAR_HIGHLIGHTS
#define ENABLE_LIGHTING
#define ENABLE_FRAGMENT_LIGHTING
#define NUMBER_OF_LIGHTS 8
#define NUMBER_OF_ACTIVE_INFINITE_LIGHTS	3
#define NUMBER_OF_ACTIVE_SPOT_LIGHTS		3
#define NUMBER_OF_ACTIVE_POINT_LIGHTS		3
#define ENABLE_CLIPPING_PLANE
#define ENABLE_GL_SHADOWS 
#define ENABLE_GL_SOFT_SHADOWS
#define ENABLE_ROUGHNESS
#define ENABLE_AGFRoughnessMap
#define ENABLE_IBL_SPECULAR_HIGHLIGHTS
//#define SHADOW_TEXTURE_SIZE 2048
#endif

#define SHADOW_TEXTURE_SIZE 1024.0
//#define USING_TEXTURE_RECT 

#define cMult 0.0001002707309736288
#define aSubtract 0.2727272727272727

#define USE_3D_TEXTURE_FOR_IBL_SPECULAR_HIGHLIGHTS 1
#define ENABLE_ANGULAR_FALOFF 

float4 random_number(in float4 iClipPos)
{
float4 t = iClipPos;
float4 randVec=t;
float a = t.x + t.z*cMult + aSubtract - floor(t.x);	
a *= a;	
float b = t.y + a;
b -= floor(b);
float c = t.z + b;
c -= floor(c);
float d = c;
a += c*cMult + aSubtract - floor(a);
a *= a;
b +=	a;
b -= floor(b);
c += b;
c -= floor(c);	 
randVec = clamp(float4(a,b,c,d), float4(0, 0, 0, 0), float4(1, 1, 1, 1));
return randVec;
}

#ifdef ENABLE_GL_SHADOWS

#ifdef USING_TEXTURE_RECT
#define SHADOW_TEX			samplerRECT
#define SHADOW_LOOKUP(x,y) texRECT(x, y*float2(SHADOW_TEXTURE_SIZE, SHADOW_TEXTURE_SIZE))
#else
#define SHADOW_TEX			sampler2D
#define SHADOW_LOOKUP(x,y) tex2D(x, y)
#endif

#endif

	struct a2v
	{
		float4 vPosition : POSITION;
		float4 vColor: COLOR;
		float4 vNormal : NORMAL;
		float4 vTexCoord0 : TEXCOORD0;
		float4 vFaceNormal: TEXCOORD1;
		float4 vFaceTangent: TEXCOORD2;
		float4 vFaceBinormal: TEXCOORD3;
	};
	struct vertex2frag
	{
		float4 HPosition : POSITION;
		float4 fDiffuseColor : COLOR0;
		float4 fSpecularColor : COLOR1;
		float4 fTexCoord0 : TEXCOORD0;
		float4 fClipPosition : TEXCOORD1;

		float3 _t: TEXCOORD2;
		float3 _b: TEXCOORD3;
		float3 _n: TEXCOORD4;

		float3 vNormal: TEXCOORD5;
		float3 vEye: TEXCOORD6;
		float3 vPosition: TEXCOORD7;
	};
	struct vertex2fragX
	{
		float4 HPosition : POSITION;
		float4 fDiffuseColor : COLOR0;
		float4 fSpecularColor : COLOR1;

		float4 fBackDiffuseColor : BCOL0;
		float4 fBackSpecularColor : BCOL1;
		float4 fTexCoord0 : TEXCOORD0;
		float4 fClipPosition : TEXCOORD1;

		float3 _t: TEXCOORD2;
		float3 _b: TEXCOORD3;
		float3 _n: TEXCOORD4;

		float3 vNormal: TEXCOORD5;
		float3 vEye: TEXCOORD6;
		float3 vPosition: TEXCOORD7;
	};
	struct frag2buffer
	{
		float4 color: COLOR0;
		//float  depth: DEPTH;
	};
	struct Material 
	{
		float4	Ke;
		float4	Ka;
		float4	Kd;
		float4	Ks;
		float4	selfillum;
		float	shininess;
		float	reflectivity;
		float	opacity;
	};
	
	
	struct InfiniteLight
	{
		float3		diffuse;
		float3		specular;
		float4		position;
#ifdef ENABLE_GL_SHADOWS		
		float4		shadowFactor; //0 -number of texture divisions (reciproc) 1 - shadow softness (normalized) 2 - light source size (Raytracer gets the same thing)
		SHADOW_TEX	shadowMap;
		float4x4	worldToShadowMapMatrix;
		float4x4	shadowMapToWorldMatrix;
		float4x4    localShadowBufferToGlobalShadowBufferUVTransformationMatrix;
		float4		uvLocalShadowBoundaries;
#endif		
	};
	struct SpotLight
		{
		float3		diffuse;
		float3		specular;
		float4		position;
		
		float4		worldPosition;
		
		float4		direction;
		float4		angle_cos;
		float4		attenuation;

#ifdef ENABLE_GL_SHADOWS		
		float4		shadowFactor;
		SHADOW_TEX	shadowMap;
		float4x4	worldToShadowMapMatrix;
		float4x4	shadowMapToWorldMatrix;
		float4x4    localShadowBufferToGlobalShadowBufferUVTransformationMatrix;
		float4		uvLocalShadowBoundaries;
#endif		
		};
	
	struct PointLight
		{
		float3		diffuse;
		float3		specular;
		float4		position;

		float4		worldPosition;
		
		float4		attenuation;

#ifdef ENABLE_GL_SHADOWS		
		float4		shadowFactor;
		SHADOW_TEX	shadowMap;
		float4x4	worldToShadowMapMatrix[6];
		float4x4	shadowMapToWorldMatrix[6];
		float4x4    localShadowBufferToGlobalShadowBufferUVTransformationMatrix[6];
		float4		uvLocalShadowBoundaries[6];

#endif		
		};
#ifdef ENABLE_GL_SHADOWS	
	struct LightShadow
	{
		float4		lightSourceWorldPosition;
		float		screenSpaceRandomNumber;
		float4		shadowFactor;
		float4		angle_cos;
		SHADOW_TEX	shadowMap;
		float4x4	worldToShadowMapMatrix;
		float4x4	shadowMapToWorldMatrix;
		float4x4    localShadowBufferToGlobalShadowBufferUVTransformationMatrix;
		float4		uvLocalShadowBoundaries;
	};
#endif		
			
	
	
	
		
	struct Light 
	{
		float3		diffuse;
		float3		specular;
		float4		position;
		float4		direction;
		float4		angle_cos;
		float4		attenuation;
#ifdef ENABLE_GL_SHADOWS		
		float		shadowFactor;
		SHADOW_TEX	shadowMap;
		float4x4	worldToShadowMapMatrix[6];
		float4x4    localShadowBufferToGlobalShadowBufferUVTransformationMatrix[6];
#endif		
	};
//#define USE_TEXTURE_TRIG_FUNCTIONS
//#define ENABLE_GL_SOFT_SHADOWS

const float pi = 3.141592653589793238462;
#ifdef ENABLE_GL_SHADOWS

float gaussianShadowDepth(in sampler2D depthTex, in float2 UV)
{
	float2 texNorm = float2(1/SHADOW_TEXTURE_SIZE, 1/SHADOW_TEXTURE_SIZE);	
	float2 uv = UV;
	float2 uv00 = UV-texNorm*float2(1.0, 0.0);
	float2 uv01 = UV+texNorm*float2(1.0, 0.0);
	float2 uv10 = UV+texNorm*float2(0.0, 1.0);
	float2 uv11 = UV-texNorm*float2(0.0, 1.0);
	
	
	float2 uv200 = UV+texNorm*float2(-1.0, -1.0);
	float2 uv201 = UV+texNorm*float2(-1.0, +1.0);
	float2 uv210 = UV+texNorm*float2(+1.0, -1.0);
	float2 uv211 = UV+texNorm*float2(+1.0, +1.0);
	
	float totalDepth = 0.0;
	
	float depthInShadowBuffer;
	depthInShadowBuffer = tex2D(depthTex, uv).x;

	totalDepth += depthInShadowBuffer * 0.25;
		
	const float4 sideWeight = float4(0.125, 0.125, 0.125, 0.125);

	depthInShadowBuffer = tex2D(depthTex, uv00).x;
		totalDepth += depthInShadowBuffer * sideWeight.x;
		
	depthInShadowBuffer = tex2D(depthTex, uv01).x;
		totalDepth += depthInShadowBuffer * sideWeight.x;

	depthInShadowBuffer = tex2D(depthTex, uv10).x;
		totalDepth += depthInShadowBuffer * sideWeight.x;


	depthInShadowBuffer = tex2D(depthTex, uv11).x;
		totalDepth += depthInShadowBuffer * sideWeight.x;


	
	
	const float4 cornerWeight = float4(0.0625, 0.0625, 0.0625, 0.0625);
	
	depthInShadowBuffer = tex2D(depthTex, uv200).x;

		totalDepth += depthInShadowBuffer * cornerWeight.x;
		
	depthInShadowBuffer = tex2D(depthTex, uv201).x;

		totalDepth += depthInShadowBuffer * cornerWeight.x;
	
	depthInShadowBuffer = tex2D(depthTex, uv210).x;

		totalDepth += depthInShadowBuffer * cornerWeight.x;

	depthInShadowBuffer = tex2D(depthTex, uv211).x;

		totalDepth += depthInShadowBuffer * cornerWeight.x;

	return totalDepth;	
}

inline float depthLookup(in SHADOW_TEX shadowDepthTex, in float2 iUV, in float4 uvBoundaries)
{
	float depth=1.0;
#if 1	
	bool2 inside = (iUV == clamp(iUV, uvBoundaries.xy, uvBoundaries.zw));
	bool insideBoth = inside[0]&& inside[1];
	if (insideBoth)
		{
		depth = SHADOW_LOOKUP(shadowDepthTex, iUV).x;
		}
#else
	float2 UV = clamp(iUV, uvBoundaries.xy, uvBoundaries.zw);
	depth = SHADOW_LOOKUP(shadowDepthTex, UV).x;
#endif	
	
	return depth;
}
	
float findMinDepth(in SHADOW_TEX shadowDepthTex, in float2 iUV, in float texSpaceOffset,in float4 uvBoundaries)
{
	float2 texNorm = texSpaceOffset*float2(1.0/SHADOW_TEXTURE_SIZE, 1.0/SHADOW_TEXTURE_SIZE);
	float4 shadowTerm;
	float depthInShadowBuffer;
	float2 uv = iUV;
	float2 uv00 = iUV-texNorm*float2(1.0, 0.0);
	float2 uv01 = iUV+texNorm*float2(1.0, 0.0);
	float2 uv10 = iUV+texNorm*float2(0.0, 1.0);
	float2 uv11 = iUV-texNorm*float2(0.0, 1.0);
	
	
	float2 uv200 = iUV+texNorm*float2(-1.0, -1.0);
	float2 uv201 = iUV+texNorm*float2(-1.0, +1.0);
	float2 uv210 = iUV+texNorm*float2(+1.0, -1.0);
	float2 uv211 = iUV+texNorm*float2(+1.0, +1.0);
// 
// 	uv00 = clamp(uv00, uvBoundaries.xy, uvBoundaries.zw);
// 	uv01 = clamp(uv01, uvBoundaries.xy, uvBoundaries.zw);
// 	uv10 = clamp(uv10, uvBoundaries.xy, uvBoundaries.zw);
// 	uv11 = clamp(uv11, uvBoundaries.xy, uvBoundaries.zw);
// 	
// 	uv200 = clamp(uv200, uvBoundaries.xy, uvBoundaries.zw);
// 	uv201 = clamp(uv201, uvBoundaries.xy, uvBoundaries.zw);
// 	uv210 = clamp(uv210, uvBoundaries.xy, uvBoundaries.zw);
// 	uv211 = clamp(uv211, uvBoundaries.xy, uvBoundaries.zw);
// 
	
	shadowTerm = float4(0.0, 0.0, 0.0, 0.0);
	depthInShadowBuffer = 1.0;

	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv00, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv01, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv10, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv11, uvBoundaries));

	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv200, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv201, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv210, uvBoundaries));
	depthInShadowBuffer = min(depthInShadowBuffer, depthLookup(shadowDepthTex, uv211, uvBoundaries));
		
	return depthInShadowBuffer;
}
	
float4 shadowTermPCFGaussian(in SHADOW_TEX shadowDepthTex, in float2 iUV, in float texSpaceOffset, in float depthInShadowSpace, in float4 uvBoundaries)
{
	float2 texNorm = texSpaceOffset*float2(1.0/SHADOW_TEXTURE_SIZE, 1.0/SHADOW_TEXTURE_SIZE);
	float4 shadowTerm;
	float depthInShadowBuffer;
	float2 uv = iUV;
	float2 uv00 = iUV-texNorm*float2(1.0, 0.0);
	float2 uv01 = iUV+texNorm*float2(1.0, 0.0);
	float2 uv10 = iUV+texNorm*float2(0.0, 1.0);
	float2 uv11 = iUV-texNorm*float2(0.0, 1.0);
	
	
	float2 uv200 = iUV+texNorm*float2(-1.0, -1.0);
	float2 uv201 = iUV+texNorm*float2(-1.0, +1.0);
	float2 uv210 = iUV+texNorm*float2(+1.0, -1.0);
	float2 uv211 = iUV+texNorm*float2(+1.0, +1.0);

	uv00 = clamp(uv00, uvBoundaries.xy, uvBoundaries.zw);
	uv01 = clamp(uv01, uvBoundaries.xy, uvBoundaries.zw);
	uv10 = clamp(uv10, uvBoundaries.xy, uvBoundaries.zw);
	uv11 = clamp(uv11, uvBoundaries.xy, uvBoundaries.zw);
	
	uv200 = clamp(uv200, uvBoundaries.xy, uvBoundaries.zw);
	uv201 = clamp(uv201, uvBoundaries.xy, uvBoundaries.zw);
	uv210 = clamp(uv210, uvBoundaries.xy, uvBoundaries.zw);
	uv211 = clamp(uv211, uvBoundaries.xy, uvBoundaries.zw);

	
	shadowTerm = float4(0.0, 0.0, 0.0, 0.0);
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv, uvBoundaries);

 	float deltaS = depthInShadowBuffer - depthInShadowSpace;
 	float principalShadowTerm = 0.0;
 	
 	if (depthInShadowSpace > depthInShadowBuffer )
 		{
 		principalShadowTerm = 1.0;
 		}
 	
 	 
	if (principalShadowTerm > 0 || depthInShadowBuffer==1.0)
	{
		if (principalShadowTerm>0)
			{
			shadowTerm = shadowTerm + float4(0.25, 0.25, 0.25, 0.25);
//			totalWeight+=0.25;
			}
	const float4 sideWeight = float4(0.125, 0.125, 0.125, 0.125);
	
	
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv00, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + sideWeight;
		
//		totalWeight+=sideWeight.x;
		
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv01, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + sideWeight;

//		totalWeight+=sideWeight.x;
	
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv10, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + sideWeight;

//		totalWeight+=sideWeight.x;

	depthInShadowBuffer = depthLookup(shadowDepthTex, uv11, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + sideWeight;

//		totalWeight+=sideWeight.x;
	
	
	const float4 cornerWeight = float4(0.0625, 0.0625, 0.0625, 0.0625);
	
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv200, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + cornerWeight;

//		totalWeight+=cornerWeight.x;
		
	depthInShadowBuffer = depthLookup(shadowDepthTex, uv201, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + cornerWeight;

//		totalWeight+=cornerWeight.x;
	

	depthInShadowBuffer = depthLookup(shadowDepthTex, uv210, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + cornerWeight;

//		totalWeight+=cornerWeight.x;


	depthInShadowBuffer = depthLookup(shadowDepthTex, uv211, uvBoundaries);

	if (depthInShadowSpace > depthInShadowBuffer )
		shadowTerm = shadowTerm + cornerWeight;

//		totalWeight+=cornerWeight.x;

 	if (principalShadowTerm==0 && shadowTerm.x > sideWeight.x)
 		{
 		shadowTerm = shadowTerm + float4(0.25, 0.25, 0.25, 0.25);
	 //		totalWeight+=0.25;
 		}
	
	
	}

	return shadowTerm;

}
	
inline float4 EvaluateShadow(in float4 iGeomPointInWorldSpace, in LightShadow iLightSource)
	{
	float4 geomPointInShadowSpace = mul(iLightSource.worldToShadowMapMatrix,iGeomPointInWorldSpace);

	geomPointInShadowSpace.xyz = geomPointInShadowSpace.xyz*(1.0/geomPointInShadowSpace.w);
	geomPointInShadowSpace.xyz = (geomPointInShadowSpace.xyz+float3(1.0, 1.0, 1.0))*float3(0.5, 0.5, 0.5);
	
	float depthInShadowSpace =  geomPointInShadowSpace.z;
	
	float4 geomPointInGlobalShadowSpaceSource = float4(geomPointInShadowSpace.xy, 0, 1);
	float4 geomPointInGlobalShadowSpace = mul(iLightSource.localShadowBufferToGlobalShadowBufferUVTransformationMatrix, geomPointInGlobalShadowSpaceSource);

	float depthInShadowBuffer;
	float4 shadowTerm=float4(0, 0, 0, 0);
#ifdef ENABLE_GL_SOFT_SHADOWS
	//We need to compute penumbra size, approximate.
	float penumbraSize = 0.0; 
	//Estimating penumbra size, as described in http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
		//Point lights and spotlights, here we go.

		//Find out the point of shadow Caster.
		float occluderZ = SHADOW_LOOKUP(iLightSource.shadowMap, geomPointInGlobalShadowSpace.xy).x;
		float heisenbergShading = 0;
		if (occluderZ == 1.0)
			{
			//We might be in Penumbra;
			//Search the neighborhood
			occluderZ = findMinDepth(iLightSource.shadowMap, geomPointInGlobalShadowSpace.xy, 32*iLightSource.shadowFactor.x, iLightSource.uvLocalShadowBoundaries);
			}
		if (occluderZ < 1.0)
			{
			float4 occluderPointInShadowSpace = float4(geomPointInShadowSpace.xy, occluderZ,1);
			occluderPointInShadowSpace.xyz = (occluderPointInShadowSpace.xyz-float3(0.5, 0.5, 0.5))*float3(2.0, 2.0, 2.0);
			float4 occluderPointInWorldSpace = mul(iLightSource.shadowMapToWorldMatrix, occluderPointInShadowSpace);
			
			//Dont forget the perspective divide
			occluderPointInWorldSpace.xyz = occluderPointInWorldSpace.xyz*(1.0/occluderPointInWorldSpace.w);
			
			float penumbraWorldSize = 0.0; 
			if (iLightSource.lightSourceWorldPosition.w > 0.5)
				{	 

				float dReceiver = length(iGeomPointInWorldSpace.xyz - iLightSource.lightSourceWorldPosition.xyz);
				float dBlocker = length(occluderPointInWorldSpace.xyz - iLightSource.lightSourceWorldPosition.xyz);
				
				penumbraWorldSize = ((dReceiver - dBlocker) * iLightSource.shadowFactor.z) / dBlocker;		


				float zNear = iLightSource.angle_cos[2]; //1/tan(halfangle)
				
				float pS = (penumbraWorldSize*zNear)/dReceiver;
				penumbraSize = pS*iLightSource.shadowFactor.x*(SHADOW_TEXTURE_SIZE/2);
				}
			else
				{
				float dBlockerReceiverDistance = length(iGeomPointInWorldSpace.xyz - occluderPointInWorldSpace.xyz);
				penumbraSize = iLightSource.shadowFactor.z*dBlockerReceiverDistance*iLightSource.shadowFactor.x;
				}
				
			shadowTerm = shadowTermPCFGaussian(iLightSource.shadowMap, geomPointInGlobalShadowSpace.xy, penumbraSize, depthInShadowSpace, iLightSource.uvLocalShadowBoundaries);
	
 		//Probabilistic estimate.
 			heisenbergShading = iLightSource.screenSpaceRandomNumber; //Random Screen-space value.
			}
 	
 	if (heisenbergShading<shadowTerm.x)
 		{
 		shadowTerm = float4(1.0, 1.0, 1.0,1.0);
 		}
 	else
 		{
 		shadowTerm = float4(0.0,0.0, 0.0,0.0);
 		}


#else
	depthInShadowBuffer = SHADOW_LOOKUP(iLightSource.shadowMap, geomPointInGlobalShadowSpace.xy).x;
				
 	shadowTerm = float4(0.0, 0.0, 0.0, 0.0);
 	
 	if (depthInShadowSpace <= 1.0 && depthInShadowSpace > depthInShadowBuffer)
 		{
 		shadowTerm = float4(1.0, 1.0, 1.0, 1.0);
 		}
#endif
	
	
 
 	
 	if (depthInShadowSpace > 1.0 || geomPointInShadowSpace.x < 0.0 || geomPointInShadowSpace.x > 1.0 || geomPointInShadowSpace.y < 0.0 || geomPointInShadowSpace.y > 1.0)
 		{
 		shadowTerm = float4(0.0, 0.0, 0.0, 0.0);
 		}
 
  	if (depthInShadowSpace < 0.0)
  		{
  		shadowTerm = float4(0.0, 0.0, 0.0, 0.0);
  		}
  	
  	shadowTerm = shadowTerm * iLightSource.shadowFactor.w;
  		
	return	shadowTerm;
	}
	
	float4 EvaluateShadowTermForInfiniteLight(in float4 geomPointInWorldSpace, in InfiniteLight lightSource, in float iNoiseTexture)
	{
		LightShadow shadowData;
		shadowData.shadowFactor = lightSource.shadowFactor;
		shadowData.screenSpaceRandomNumber = iNoiseTexture;
		shadowData.shadowMap = lightSource.shadowMap;
		shadowData.worldToShadowMapMatrix = lightSource.worldToShadowMapMatrix;
		shadowData.shadowMapToWorldMatrix = lightSource.shadowMapToWorldMatrix;
#ifdef ENABLE_GL_SOFT_SHADOWS		
		shadowData.lightSourceWorldPosition = float4(0, 0, 0, 0);
		shadowData.uvLocalShadowBoundaries = lightSource.uvLocalShadowBoundaries;
#endif
		shadowData.localShadowBufferToGlobalShadowBufferUVTransformationMatrix = lightSource.localShadowBufferToGlobalShadowBufferUVTransformationMatrix;
		float4 shadowTerm = EvaluateShadow(geomPointInWorldSpace, shadowData);
		return shadowTerm;
	}
	
	float4 EvaluateShadowTermForSpotLight(in float4 geomPointInWorldSpace, in SpotLight lightSource, in float iNoiseTexture)
	{
		LightShadow shadowData;
		shadowData.shadowFactor = lightSource.shadowFactor;
		shadowData.shadowMap = lightSource.shadowMap;
		shadowData.screenSpaceRandomNumber = iNoiseTexture;
		shadowData.angle_cos = lightSource.angle_cos;
		shadowData.worldToShadowMapMatrix = lightSource.worldToShadowMapMatrix;
		shadowData.shadowMapToWorldMatrix = lightSource.shadowMapToWorldMatrix;
		shadowData.localShadowBufferToGlobalShadowBufferUVTransformationMatrix = lightSource.localShadowBufferToGlobalShadowBufferUVTransformationMatrix;
#ifdef ENABLE_GL_SOFT_SHADOWS		
		shadowData.lightSourceWorldPosition = lightSource.worldPosition;
		shadowData.uvLocalShadowBoundaries = lightSource.uvLocalShadowBoundaries;
#endif		
		float4 shadowTerm = EvaluateShadow(geomPointInWorldSpace, shadowData);
		return shadowTerm;
	}	

	float4 EvaluateShadowTermForPointLight(in float4 geomPointInWorldSpace, in PointLight lightSource, in float iNoiseTexture)
	{
		LightShadow shadowData;
		shadowData.shadowFactor = lightSource.shadowFactor;
		shadowData.shadowMap = lightSource.shadowMap;
		shadowData.screenSpaceRandomNumber = iNoiseTexture;
		shadowData.angle_cos[2] = 1.0;
#ifdef ENABLE_GL_SOFT_SHADOWS		
		shadowData.lightSourceWorldPosition = lightSource.worldPosition;
#endif		
		float4 shadowTerm;
		float4 finalShadowTerm=float4(0.0, 0.0, 0.0, 0.0);
		int s;
		for (s=0;s<6;s++)
			{
			shadowData.worldToShadowMapMatrix = lightSource.worldToShadowMapMatrix[s];
			shadowData.shadowMapToWorldMatrix = lightSource.shadowMapToWorldMatrix[s];
			shadowData.uvLocalShadowBoundaries = lightSource.uvLocalShadowBoundaries[s];
			shadowData.localShadowBufferToGlobalShadowBufferUVTransformationMatrix = lightSource.localShadowBufferToGlobalShadowBufferUVTransformationMatrix[s];
			shadowTerm = EvaluateShadow(geomPointInWorldSpace, shadowData);
			finalShadowTerm = finalShadowTerm + shadowTerm;
			}
		return finalShadowTerm;
	}	
#endif //of ENABLE_GL_SHADOWS
	void EvaluateInfiniteLight(	in float3			normal, 	
								in float3			ecPosition3,
								in InfiniteLight	lightSource,
								inout float3		diffuse, 
								inout float3		specular,
								inout float3		diffuseNoShadow,
								in float			shininess,
								in float4x4			iEyeToWorldMatrix,
								in float			iNoiseTexture) 
	{
		float nDotVP;
		float3 light = normalize(lightSource.position.xyz);

		float3 diffuse_coeff, specular_coeff;
		diffuse_coeff = lightSource.diffuse;
		specular_coeff = lightSource.specular;
		float brightness_factor=1.0;

#ifdef ENABLE_GL_SHADOWS
			float4 geomPointInEyeSpace = float4(-ecPosition3, 1.0);
			float4 geomPointInWorldSpace = mul(iEyeToWorldMatrix, geomPointInEyeSpace);

			float4 shadowTerm = EvaluateShadowTermForInfiniteLight(geomPointInWorldSpace, lightSource, iNoiseTexture);
 			if (shadowTerm.a > 0.1)
 				{
 				brightness_factor = 1.0f-shadowTerm.a;
 				}
#endif
		nDotVP = max (0.0, (dot(normal, light)));

		diffuseNoShadow += diffuse_coeff * nDotVP;

		diffuse_coeff *= brightness_factor;
		specular_coeff *= brightness_factor;
		diffuse += diffuse_coeff * nDotVP;
#ifdef ENABLE_SPECULAR_HIGHLIGHTS
		{
			float nDotHV, pf;
			float3 halfVect = normalize(light+normalize(ecPosition3));
			nDotHV = max (0.0, dot(normal, halfVect));
			pf = pow(nDotHV, shininess);
			specular += specular_coeff * pf;
		}
#endif
	}

	void EvaluateSpotLight(	in float3			normal, 	
							in float3			ecPosition3,
							in SpotLight		lightSource,
							inout float3		diffuse, 
							inout float3		specular,
							inout float3		diffuseNoShadow,
							in float			shininess,
							in float4x4			iEyeToWorldMatrix,
							in float			iNoiseTexture) 
	{
		float nDotVP;
		float3 light = normalize(lightSource.position.xyz + ecPosition3);
		float3 diffuse_coeff, specular_coeff;
		diffuse_coeff = lightSource.diffuse;
		specular_coeff = lightSource.specular;
		float brightness_factor=1.0;
#ifdef ENABLE_ATTENUATION
		float distance = length(lightSource.position.xyz + ecPosition3);
		if (lightSource.attenuation[0]>0.5)
			{
			float attenuation_factor = 1-smoothstep(lightSource.attenuation[1], lightSource.attenuation[2], distance);
			brightness_factor *= attenuation_factor;
			}
#endif
		float3 light_axis = -normalize(lightSource.direction.xyz - lightSource.position.xyz); //Should be already normalized in the app
		float angle_dot = dot(light, light_axis);

		float angular_brightness_value = 1.0f;
#ifdef ENABLE_ANGULAR_FALOFF				
		if (lightSource.attenuation[3]>0.0)
			{
			float faloff_power = lightSource.attenuation[3];
			float deltaAngle = (lightSource.angle_cos[3]-acos(angle_dot))/(lightSource.angle_cos[3]);
			
			float alpha = lightSource.angle_cos[3];
			float cos_alpha = lightSource.angle_cos[0];
			
			float offset = cos_alpha;
			float scale = 1.0/(1.0-cos_alpha);
			float x = (angle_dot-offset)*(scale);
			

			//This will generate an angular falloff, inherited from Lighting Effects spotlight. -Nikolai, 03/31/2011
			//faloff power is in range of 0.25 to 3.0
			//To see the shape of the resulting lobe, you can input this into http://wolframalpha.com
			// Plot [Cos[2 (Pi/4) (ArcCos[x]/(Pi/4))^0.25], {x, 0.707, 1}, {y, 0, 1}] (for total cone angle of Pi/2, and faloff_power of 0.25) (0.707 = cos (PI/4))
			float a = angle_dot;// cos_alpha+(1-cos_alpha)*x;
			float b = acos(a)*2.0;
			float c = b/(alpha*2.0);
			float d = pow(c, faloff_power);
			float e = d*alpha*2.0;
			float f = cos(e); 
			angular_brightness_value = f;
			if ((deltaAngle)<0.0)
				{
				angular_brightness_value = 0.0;
				}
			}
		else
			{
			angular_brightness_value=smoothstep(lightSource.angle_cos.r, lightSource.angle_cos.g, angle_dot);
			}
#else
		angular_brightness_value=smoothstep(lightSource.angle_cos.r, lightSource.angle_cos.g, angle_dot);
#endif
	
		brightness_factor *= angular_brightness_value;
			
		nDotVP = max (0.0, (dot(normal, light)));

		diffuseNoShadow += diffuse_coeff * brightness_factor* nDotVP;
#ifdef ENABLE_GL_SHADOWS
			float4 geomPointInEyeSpace = float4(-ecPosition3, 1.0);
			float4 geomPointInWorldSpace = mul(iEyeToWorldMatrix, geomPointInEyeSpace);

			float4 shadowTerm = EvaluateShadowTermForSpotLight(geomPointInWorldSpace, lightSource, iNoiseTexture);
 			if (shadowTerm.a > 0.1)
 				{
 				brightness_factor = 1.0f-shadowTerm.a;
 				}
#endif
		diffuse_coeff *= brightness_factor;
		specular_coeff *= brightness_factor;
		diffuse += diffuse_coeff * nDotVP;
#ifdef ENABLE_SPECULAR_HIGHLIGHTS
		float nDotHV, pf;
		float3 halfVect = normalize(light+normalize(ecPosition3));
		nDotHV = max (0.0, dot(normal, halfVect));
		pf = pow(nDotHV, shininess);
		specular += specular_coeff * pf;
#endif
	}


	void EvaluatePointLight(in float3			normal, 	
							in float3			ecPosition3,
							in PointLight		lightSource,
							inout float3		diffuse, 
							inout float3		specular,
							inout float3		diffuseNoShadow,
							in float			shininess,
							in float4x4			iEyeToWorldMatrix, 
							in float			iNoiseTexture) 
	{
		float nDotVP;
		float3 light = normalize(lightSource.position.xyz + ecPosition3);
		float3 diffuse_coeff, specular_coeff;
		diffuse_coeff = lightSource.diffuse;
		specular_coeff = lightSource.specular;
		float brightness_factor=1.0;
#ifdef ENABLE_ATTENUATION
		float distance = length(lightSource.position.xyz + ecPosition3);
		if (lightSource.attenuation[0]>0.5)
			{
			float attenuation_factor = 1-smoothstep(lightSource.attenuation[1], lightSource.attenuation[2], distance);
			brightness_factor *= attenuation_factor;
			}
#endif
		nDotVP = max (0.0, (dot(normal, light)));

		diffuseNoShadow += diffuse_coeff * brightness_factor* nDotVP;

#ifdef ENABLE_GL_SHADOWS
			float4 geomPointInEyeSpace = float4(-ecPosition3, 1.0);
			float4 geomPointInWorldSpace = mul(iEyeToWorldMatrix, geomPointInEyeSpace);

			float4 shadowTerm = EvaluateShadowTermForPointLight(geomPointInWorldSpace, lightSource, iNoiseTexture);
 			if (shadowTerm.a > 0.1)
 				{
 				brightness_factor = 1.0f-shadowTerm.a;
 				}
#endif
		diffuse_coeff *= brightness_factor;
		specular_coeff *= brightness_factor;
		diffuse += diffuse_coeff * nDotVP;
#ifdef ENABLE_SPECULAR_HIGHLIGHTS
		float nDotHV, pf;
		float3 halfVect = normalize(light+normalize(ecPosition3));
		nDotHV = max (0.0, dot(normal, halfVect));
		pf = pow(nDotHV, shininess);
		specular += specular_coeff * pf;
#endif
	}

/***********************************************************************/
float2 uvSPHERE(in float3 iSphereVector)
{
	float2 uv;
	uv.y = (acos(abs(iSphereVector.y))/pi);
	if (iSphereVector.y<0.0) uv.y = 1.0-uv.y;
	uv.x = (atan2(iSphereVector.x, iSphereVector.z)+pi)/(2.0*pi);
	return uv;
}
/***********************************************************************/

float4 xformTex2D(in sampler2D texture, in float4 homogeneousUV, in float4x4 uvMatrix)
{
	float4 xformedUV;
	xformedUV = mul(uvMatrix, homogeneousUV);
	return tex2D(texture, xformedUV.xy);
}

float4 xformTex3D(in sampler3D texture, in float4 homogeneousUV, in float4x4 uvMatrix)
{
	float4 xformedUV;
	xformedUV = mul(uvMatrix, homogeneousUV);
	return tex3D(texture, xformedUV.xyz);
}
/***********************************************************************/
float4 texSPHERE(in sampler2D sphereTex, in float4x4 textureMatrix, in float3 lookup_vector)
	{
	float2 index;
	float3 reflectDir;
	float4 sphereColor;
	index = uvSPHERE(lookup_vector);
	float4 homogeneousUVindex = float4(index, 0, 1);
	sphereColor = xformTex2D(sphereTex, homogeneousUVindex, textureMatrix);
	return sphereColor;
	}
	
float4 texSPHEREMULTI(in sampler3D sphereTex, in float4x4 textureMatrix, in float4 sliceAndScale, in float3 lookup_vector)
{
	float2 index;
	float3 reflectDir;
	float4 sphereColor;
	index = uvSPHERE(lookup_vector);
	float4 homogeneousUVindex = float4(index, 1, 1)*sliceAndScale;
	sphereColor = xformTex3D(sphereTex, homogeneousUVindex, textureMatrix);
	return sphereColor;
}
/***********************************************************************/


	

/***********************************************************************/
	vertex2fragX vertMain(in a2v app, 
		uniform float4x4 modelViewProj,
		uniform float4x4 modelView,
		uniform float4x4 modelViewIT,
		uniform float4x4 modelViewCamera,
		uniform float3	 normalMultiplier,
// #ifdef ENABLE_LIGHTING
// 		uniform Light    lights[NUMBER_OF_LIGHTS],
// #endif
		uniform Material material)
	{
		vertex2fragX vertOut;
		vertOut.HPosition = mul(modelViewProj, app.vPosition);


		vertOut.fClipPosition = mul(modelViewProj, app.vPosition);
		float3 ecPosition3 = (mul(modelView,app.vPosition).xyz);
#if 1
		float4 appNormal = app.vNormal;
		appNormal.w = 0.0;
		float3 normalVec = normalize(mul(modelViewIT,appNormal).xyz);
		normalVec = normalVec * normalMultiplier; //This will be used to flip the normal if necessary
#else
		float4 v1 = app.vPosition+app.vNormal;
		v1.w = 1.0;
		float3 ecPosition3_1 = (mul(modelView,v1).xyz);
		float3 normalVec = normalize(ecPosition3_1-ecPosition3);
		normalVec = normalVec * normalMultiplier; //This will be used to flip the normal if necessary
#endif		
#ifdef ENABLE_LIGHTING
#ifdef ENABLE_FRAGMENT_LIGHTING
		vertOut.fDiffuseColor.rgb = float3(1, 0, 0);
		vertOut.fBackDiffuseColor.rgb = float3(0, 0, 1);
#endif
#endif
		vertOut.fTexCoord0.xy = app.vTexCoord0.xy;
		vertOut.fTexCoord0.z = 0.0;

		vertOut.fTexCoord0.w = 1.0;

		vertOut._n = normalVec;//((mul(modelViewIT,app.vFaceNormal).xyz));
		vertOut._t = (mul(modelViewIT,app.vFaceTangent).xyz);
		vertOut._b = (mul(modelViewIT,app.vFaceBinormal).xyz);

		vertOut.vNormal = normalVec;
		vertOut.vEye = ecPosition3;
		vertOut.vPosition = mul(modelView,app.vPosition).xyz;
		return vertOut;
	}


/***********************************************************************/

frag2buffer fragMain(in vertex2frag interpolant
		,uniform sampler2D diffuse_texture
		,uniform sampler2D bump_gradient_texture
		,uniform sampler2D environment_texture
		,uniform float4	   environmentColor
		,uniform sampler2D reflectivity_texture
		,uniform float4x4 fmodelViewCamera
		,uniform float4x4 fmodelViewIT
#ifdef ENABLE_LIGHTING
		,uniform Light    lights[NUMBER_OF_LIGHTS]
#endif
#if NUMBER_OF_ACTIVE_INFINITE_LIGHTS > 0
		,uniform InfiniteLight	infiniteLights[NUMBER_OF_ACTIVE_INFINITE_LIGHTS]
#endif		
#if NUMBER_OF_ACTIVE_SPOT_LIGHTS > 0
		,uniform SpotLight	spotLights[NUMBER_OF_ACTIVE_SPOT_LIGHTS]
#endif		
#if NUMBER_OF_ACTIVE_POINT_LIGHTS > 0
		,uniform PointLight	pointLights[NUMBER_OF_ACTIVE_POINT_LIGHTS]
#endif		
		,uniform Material material
		,uniform float4 bumpTextureNormalizer
		,uniform float4x4 reflectionTransformationMatrix
		,uniform float4x4 sphericalHarmonicsTransformationMatrix
		,uniform sampler2D specular_intensity_texture
		,uniform sampler2D specular_exponent_texture
		,uniform sampler2D self_illumination_texture
		,uniform sampler2D object_opacity_texture
		,uniform sampler2D normal_map_texture
#if 0
		,uniform sampler2D IBLTexture
#endif		
		,uniform float4x4 diffuse_texture_matrix
		,uniform float4x4 bump_gradient_texture_matrix
		,uniform float4x4 reflectivity_texture_matrix
		,uniform float4x4 specular_intensity_texture_matrix
		,uniform float4x4 specular_exponent_texture_matrix
		,uniform float4x4 self_illumination_texture_matrix
		,uniform float4x4 object_opacity_texture_matrix
		,uniform float4x4 normal_map_texture_matrix
		,uniform float4x4 environment_texture_matrix
		,uniform float4 self_illumination_texture_range
#ifdef ENABLE_ROUGHNESS		
		,uniform sampler2D	roughness_texture
		,uniform float4x4	roughness_texture_matrix
		,uniform float4		roughness
#endif
#ifdef ENABLE_AGFSphereEnvironmentMap
		,uniform sampler1D acos_texture
		,uniform sampler2D atan2_texture
		,uniform sampler3D discreteShininess3DTex
#endif
#ifdef	ENABLE_IBL
		,uniform float4x4 sphericalHarmonicMatrixRed
		,uniform float4x4 sphericalHarmonicMatrixGreen
		,uniform float4x4 sphericalHarmonicMatrixBlue
#endif
		,uniform float bumpStrength
		,uniform float4 clippingPlane
		,uniform float4 textureSize
		,uniform float4x4	iEyeToWorldMatrix
		,uniform sampler2D	noiseTexture

#ifdef ENABLE_IBL_SPECULAR_HIGHLIGHTS
		,uniform float4		iGlobalAmbientColor				//alpha of iGlobalAmbientColor is used to piggyback the IBL intensity
#endif	
		)
	{
		frag2buffer fragOut;
		float4 diffuseColor = interpolant.fDiffuseColor;
		float4 specularColor = interpolant.fSpecularColor;
		float4 mainColor = float4(1.0, 1.0, 1.0, 1.0); //Set the opacity to 0, so if the diffuse texture is disabled, the material color will be used
		float3 newNormal = normalize(interpolant.vNormal);
		float3 materialSpecularColor;
		float3 materialDiffuseColor;
		float4 texLookup; //Temporary variable
		float4 finalColor = float4(0.0, 0.0, 0.0, 0.0);
		float4 UV = interpolant.fTexCoord0;
//		if (UV.z>0.5) discard;
//#if defined(SINGLE_PASS_SHADER) || defined(LIGHTING_PASS_SHADER)
#ifdef ENABLE_AGFSpecularColorMap
		//texLookup =  tex2D(specular_intensity_texture, interpolant.fTexCoord0.xy);
		texLookup =  xformTex2D(specular_intensity_texture, UV, specular_intensity_texture_matrix);
		materialSpecularColor = lerp(material.Ks.rgb, texLookup.rgb, texLookup.a);
#else
		materialSpecularColor =  material.Ks.rgb;
#endif	
#ifdef ENABLE_AGFDiffuseMap
		//texLookup = tex2D(diffuse_texture, interpolant.fTexCoord0.xy);
		texLookup = xformTex2D(diffuse_texture, UV, diffuse_texture_matrix);
		materialDiffuseColor = lerp(material.Kd.rgb, texLookup.rgb, texLookup.a);
#else
		materialDiffuseColor.rgb = material.Kd.rgb;
#endif
#ifdef ENABLE_LIGHTING
		//Modify Diffuse color by the material diffuse color. This will have effect on vertex-lighting mode only
		//Ambient term should be added here, but since our ambient light component is always 0, we skip it
		diffuseColor.rgb = (diffuseColor.rgb+material.Ke.rgb)*materialDiffuseColor;
		//Modify Specular color by the material specular color. This will have effect on vertex-lighting mode only
		specularColor.rgb = specularColor.rgb*materialSpecularColor;
#else 
		diffuseColor.rgb = materialDiffuseColor;
		specularColor.rgb = float3(0, 0, 0);
#endif
//Tangential basis. Needs to be there for bump maps and/or tangent-space normal maps
float3 _t = normalize(interpolant._t);
float3 _n = normalize(interpolant._n);
float3 _b = normalize(cross(_n, _t));
#ifdef ENABLE_AGFNormalMap
		//We will make sure that normal mapping and bump mapping cannot be enabled simultaneously
		//float4 normalMapLookup = tex2D(normal_map_texture, interpolant.fTexCoord0.xy);
		float4 normalMapLookup = xformTex2D(normal_map_texture, UV, normal_map_texture_matrix);
		normalMapLookup.xyz = (normalMapLookup.xyz-float3(0.5, 0.5, 0.5))*2;
		float normalMapAlpha = normalMapLookup.a;
		normalMapLookup.a = 0.0;
		//Normal maps are now tangential
		float3 tangentSpaceNormal = normalMapLookup.xyz;
		float3 eyeSpaceNormal;
		eyeSpaceNormal.x = _t.x * tangentSpaceNormal.x + _b.x * tangentSpaceNormal.y + _n.x * tangentSpaceNormal.z;
		eyeSpaceNormal.y = _t.y * tangentSpaceNormal.x + _b.y * tangentSpaceNormal.y + _n.y * tangentSpaceNormal.z;
		eyeSpaceNormal.z = _t.z * tangentSpaceNormal.x + _b.z * tangentSpaceNormal.y + _n.z * tangentSpaceNormal.z;

		if (dot(tangentSpaceNormal, tangentSpaceNormal)<2.5)//White color in normal maps disables it
			{
			newNormal = lerp(newNormal, normalize(eyeSpaceNormal), normalMapAlpha);
			}
#endif
#ifdef ENABLE_AGFBumpMap
		//float4 bumpLookup = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy);
		float4 bumpLookup = xformTex2D(bump_gradient_texture, UV, bump_gradient_texture_matrix);
		float3 bumpGradient;
#ifdef GPU_BUMP_GRADIENT_CALCULATION
		float x0,x1,y0,y1, xy0;
		xy0=bumpLookup.r;
#ifdef BUMP_CENTRAL_DIFFERENCE
//x0 = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy-bumpTextureNormalizer*float2(1.0, 0.0)).r;
//x1 = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy+bumpTextureNormalizer*float2(1.0, 0.0)).r;
//y0 = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy-bumpTextureNormalizer*float2(0.0, 1.0)).r;
//y1 = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy+bumpTextureNormalizer*float2(0.0, 1.0)).r;
x0 = xformTex2D(bump_gradient_texture, UV-bumpTextureNormalizer*float4(1.0, 0.0, 0.0, 0.0), bump_gradient_texture_matrix).r;
x1 = xformTex2D(bump_gradient_texture, UV+bumpTextureNormalizer*float4(1.0, 0.0, 0.0, 0.0), bump_gradient_texture_matrix).r;
y0 = xformTex2D(bump_gradient_texture, UV-bumpTextureNormalizer*float4(0.0, 1.0, 0.0, 0.0), bump_gradient_texture_matrix).r;
y1 = xformTex2D(bump_gradient_texture, UV+bumpTextureNormalizer*float4(0.0, 1.0, 0.0, 0.0), bump_gradient_texture_matrix).r;

bumpGradient.xyz = float3(-(x1-x0), -(y1-y0), 0);
#endif
#else
		bumpGradient = (bumpLookup.rgb - 0.5)*2.0; //In case of byte textures, stuff's shoved into [0, 1] range, we get it back to [-1, +1]
#endif
float3 normalDistortionTangentSpace = bumpGradient.xyz*2.0*bumpStrength*bumpLookup.a; //Alpha channel used to modulate bump strength
float3 normalDistortionEyeSpace;
normalDistortionEyeSpace.x = _t.x * normalDistortionTangentSpace.x + _b.x * normalDistortionTangentSpace.y;//+ _n.x * normalDistortionTangentSpace.z;
normalDistortionEyeSpace.y = _t.y * normalDistortionTangentSpace.x + _b.y * normalDistortionTangentSpace.y;// + _n.y * normalDistortionTangentSpace.z;
normalDistortionEyeSpace.z = _t.z * normalDistortionTangentSpace.x + _b.z * normalDistortionTangentSpace.y;// + _n.z * normalDistortionTangentSpace.z;
newNormal = normalize(newNormal + normalDistortionEyeSpace);
		//Okay, we got newNormal- normal distorted by the bump map
#endif	


		//Determine if triangle is front/back facing
		if (interpolant.fDiffuseColor.r > 0.5)//back-facing condition
		   newNormal = -newNormal;
		//Compute the lighting 
		float3 diff = float3(0.0, 0.0, 0.0);
		float3 spec = float3(0.0, 0.0, 0.0);
		int i;

float shininess = 90.0;		
#ifdef ENABLE_AGFSpecularExponentMap
		//texLookup = tex2D(specular_exponent_texture, interpolant.fTexCoord0.xy);
		texLookup = xformTex2D(specular_exponent_texture, UV, specular_exponent_texture_matrix);
		shininess = lerp(material.shininess, (1.0+180.0*texLookup.r), texLookup.a);
#else
		shininess = material.shininess;
#endif

	float3 materialAdjustedRoughnessSpecularColor = materialSpecularColor;
#ifdef ENABLE_ROUGHNESS
float roughnessValue = roughness.r;
#ifdef ENABLE_AGFRoughnessMap
		texLookup = xformTex2D(roughness_texture, UV,roughness_texture_matrix);
		roughnessValue = lerp(roughness.r, texLookup.r, texLookup.a); 
#endif	
	roughnessValue = roughnessValue*0.5f;
	
	float roughnessSigma = roughnessValue;
	
	float phongSigma = acos(exp(-1.0f/(2*shininess)));

	float newSigma = sqrt(phongSigma*phongSigma+roughnessSigma*roughnessSigma);
	
	shininess = (-1.0f/(2*log(cos(newSigma))));
	
	float specColorFadeout = phongSigma/newSigma;
	materialAdjustedRoughnessSpecularColor = materialSpecularColor*specColorFadeout.rrr*specColorFadeout.rrr;
#endif


#ifdef ENABLE_LIGHTING
#ifdef ENABLE_FRAGMENT_LIGHTING
	float3 diffNoShadowDummy=float3(0, 0, 0);
	float screenSpaceRandomNumber=0.0;
#ifdef ENABLE_GL_SOFT_SHADOWS	
	float3 clipNormalized;
	clipNormalized = (interpolant.fClipPosition.xyz+float3(1.0, 1.0, 1.0))*float3(0.5, 0.5, 0.5);
	float2 normTexLookup = clipNormalized.xy + clipNormalized.zz;
	screenSpaceRandomNumber = tex2D(noiseTexture,normTexLookup).x;
#endif
	
#if NUMBER_OF_ACTIVE_INFINITE_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_INFINITE_LIGHTS;i++)
			{
			infiniteLights[i].position = mul (fmodelViewCamera, infiniteLights[i].position);	
			EvaluateInfiniteLight(newNormal, -(interpolant.vEye), infiniteLights[i], diff, spec, diffNoShadowDummy, shininess,iEyeToWorldMatrix,screenSpaceRandomNumber);
			}
#endif		
#if NUMBER_OF_ACTIVE_SPOT_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_SPOT_LIGHTS;i++)
			{
			spotLights[i].worldPosition = spotLights[i].position;
			spotLights[i].position = mul (fmodelViewCamera, spotLights[i].position);	
			spotLights[i].direction = mul (fmodelViewCamera, spotLights[i].direction);	
			EvaluateSpotLight(newNormal, -(interpolant.vEye), spotLights[i], diff, spec, diffNoShadowDummy, shininess,iEyeToWorldMatrix,screenSpaceRandomNumber);
			}
#endif		
#if NUMBER_OF_ACTIVE_POINT_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_POINT_LIGHTS;i++)
			{
			pointLights[i].worldPosition = pointLights[i].position;
			pointLights[i].position = mul (fmodelViewCamera, pointLights[i].position);	
			EvaluatePointLight(newNormal, -(interpolant.vEye), pointLights[i], diff, spec, diffNoShadowDummy, shininess,iEyeToWorldMatrix,screenSpaceRandomNumber);
			}
#endif				
		
		
		
		//Ambient term should be added here, but since our ambient light component is always 0, we skip it
		diffuseColor.rgb = (diff+material.Ke.rgb)*materialDiffuseColor;
		specularColor.rgb = materialAdjustedRoughnessSpecularColor*spec;
#endif
#endif// of #ifdef ENABLE_LIGHTING 
#ifdef ZERO_LIGHTS
		//Special case for full-shaded mode with zero lights
		diffuseColor.rgb = (material.Ke.rgb)*materialDiffuseColor;
		specularColor.rgb = float3(0, 0, 0);
#endif 
		
#ifdef ENABLE_IBL
		//TODO: xinjul convert the normal in world coordinate
		float4 normal1 = newNormal.xyzz;
		normal1.w = 0.0;
		float4 normalIBL = mul(sphericalHarmonicsTransformationMatrix, normal1);
		normalIBL.w = 0.0;
		normalize(normalIBL);
		normalIBL.w = 1.0;
		float3   diffuse_intensity =  materialDiffuseColor ;
 		float3 diffuseIBL = {  diffuse_intensity.r * dot(normalIBL, mul(sphericalHarmonicMatrixRed, normalIBL)),
 							  diffuse_intensity.g * dot(normalIBL, mul(sphericalHarmonicMatrixGreen, normalIBL)),		
 							  diffuse_intensity.b * dot(normalIBL, mul(sphericalHarmonicMatrixBlue, normalIBL))
 							};
 		//diffuseIBL = texSPHERE(IBLTexture, normalIBL.xyz).rgb; //For Debugging env. orientation only - use tex sample instead of spherical harmonic
		diffuseColor.rgb += diffuseIBL;
#endif
		finalColor.rgb = diffuseColor.rgb+specularColor.rgb;
//#endif // of #ifdef SINGLE_PASS_SHADER...
		finalColor.a = material.opacity;
//#if defined(SINGLE_PASS_SHADER) || defined(ENVIRONMENT_PASS_SHADER)
#if defined(ENVIRONMENT_PASS_SHADER) || defined(OPACITY_SELF_ILLUM_PASS_SHADER)
finalColor = float4(0, 0, 0, 1);
#endif

float4 reflColor = environmentColor;
float4 iblSpecularHighlightsContribution = float4(0, 0, 0, 0);

		//Update the reflection vector
		float4 t_reflect;
		float3 reflectionVector;
		t_reflect.xyz = reflect(normalize(interpolant.vPosition.xyz), newNormal);
		t_reflect.w = 0;
#ifdef ENABLE_AGFSphereEnvironmentMap

		reflectionVector = mul(reflectionTransformationMatrix, t_reflect).xyz;
		texLookup = texSPHERE(environment_texture,environment_texture_matrix, reflectionVector);
		reflColor.rgb = lerp(environmentColor.rgb, texLookup.rgb, texLookup.a);
		//reflColor.rgb = float3(0, 0, 0);
		
		float texStep = 1.0/16.0;
		float texOffset = 1.0/(16.0*2);

#ifdef ENABLE_IBL_SPECULAR_HIGHLIGHTS
		reflectionVector = mul(reflectionTransformationMatrix, t_reflect).xyz;

		float3 minShinyColor;
		float3 maxShinyColor;
		float3 mediumShinyColor;

		texLookup=texSPHEREMULTI(discreteShininess3DTex, environment_texture_matrix, float4(1.0/9.0, 1.0/9.0, 2*texStep+texOffset, 1.0), reflectionVector);
		minShinyColor = lerp(environmentColor.rgb, texLookup.rgb, texLookup.a);

		texLookup=texSPHEREMULTI(discreteShininess3DTex, environment_texture_matrix, float4(1.0/1.0, 1.0/1.0, 0*texStep+texOffset, 1.0), reflectionVector);
		maxShinyColor = lerp(environmentColor.rgb, texLookup.rgb, texLookup.a);

		texLookup=texSPHEREMULTI(discreteShininess3DTex, environment_texture_matrix, float4(1.0/3.0, 1.0/3.0, 1*texStep+texOffset, 1.0), reflectionVector);
		mediumShinyColor = lerp(environmentColor.rgb, texLookup.rgb, texLookup.a);

		float lt = 0.0f;
		
		if (shininess<20.0)
			{
			lt = shininess/20.0f;
			iblSpecularHighlightsContribution.rgb = lerp(minShinyColor, mediumShinyColor, lt);
			}
		else
			{
			lt = (shininess-20.0f)/492.0f;
			iblSpecularHighlightsContribution.rgb = lerp(mediumShinyColor, maxShinyColor, lt);
			} 
		iblSpecularHighlightsContribution.rgb = iblSpecularHighlightsContribution.rgb*materialSpecularColor.rgb*iGlobalAmbientColor.a;
		iblSpecularHighlightsContribution.a = 0;
#endif	
		
		
#ifdef ENABLE_ROUGHNESS
		float4 color0 = reflColor.rgba;
		float4 color1 = texSPHEREMULTI(discreteShininess3DTex, environment_texture_matrix, float4(1.0, 1.0, 3*texStep+texOffset, 1.0), reflectionVector);
		float t = roughnessValue/0.1;
		float4 roughReflectionColor = lerp(color0, color1, t);
 		if (roughnessValue>0.1)
 			{
 			float texZ;
 			t = (roughnessValue-0.1)/0.9;
 			texZ = lerp(3*texStep+texOffset, 12*texStep+texOffset, t);
 			roughReflectionColor = texSPHEREMULTI(discreteShininess3DTex, environment_texture_matrix, float4(1.0/1.0, 1.0/1.0, texZ, 1.0), reflectionVector);
 			}
		
		reflColor.rgb = roughReflectionColor.rgb;
#endif		
		
		
		
		
#endif		
		reflColor.a = 0;
		
		
		
		
#ifdef ENABLE_AGFReflectivityMap
		float3 reflectivity;
		//texLookup = tex2D(reflectivity_texture, interpolant.fTexCoord0.xy);
		texLookup = xformTex2D(reflectivity_texture, UV,reflectivity_texture_matrix);
		reflectivity = lerp(material.reflectivity.rrr, texLookup.rgb, texLookup.a); //Default reflectivity is non-reflective, for now
		reflColor.rgb = reflColor.rgb*reflectivity;
#else
		reflColor.rgb = reflColor.rgb*material.reflectivity.rrr;
#endif

		finalColor = finalColor+ reflColor + iblSpecularHighlightsContribution;
		
#ifdef ENABLE_AGFSelfIlluminationMap
		float3 selfIlluminationColor;
		selfIlluminationColor = xformTex2D(self_illumination_texture, UV, self_illumination_texture_matrix).rgb;
		float3 rescaledSelfIlluminationColor;
		rescaledSelfIlluminationColor.r = lerp(self_illumination_texture_range[0],self_illumination_texture_range[1], selfIlluminationColor.r);
		rescaledSelfIlluminationColor.g = lerp(self_illumination_texture_range[0],self_illumination_texture_range[1], selfIlluminationColor.g);
		rescaledSelfIlluminationColor.b = lerp(self_illumination_texture_range[0],self_illumination_texture_range[1], selfIlluminationColor.b);
		finalColor.rgb = finalColor.rgb + rescaledSelfIlluminationColor.rgb;
#else
		finalColor.rgb = finalColor.rgb + material.selfillum.rgb;
#endif
		//float opacity = mainColor.a;

/******* OPACITY MANAGEMENT *******/
		
		float opacity=1.0;
#ifdef	ENABLE_AGFOpacityMap
		//texLookup = tex2D(object_opacity_texture, interpolant.fTexCoord0.xy);
		texLookup = xformTex2D(object_opacity_texture, UV, object_opacity_texture_matrix);		
#ifdef USE_ALPHA_FOR_OPACITY_MAP
		opacity = texLookup.a;
#else
		float3 perColorOpacity = lerp(material.opacity.rrr, texLookup.rgb, texLookup.a);
		//We have got to choose _SINGLE_ opacity value for GL framebuffer
		//We are choosing maximum of the 3
		float rg_maxopacity = max (perColorOpacity.r, perColorOpacity.g);
		opacity = max (rg_maxopacity, perColorOpacity.b); 
#endif
		finalColor.a = opacity;//*material.opacity;



#ifdef 	DISABLED_ENABLE_ENVIRONMENT_MAPPING
		float3 refractedRay;
		float4 t_refract;
		t_refract.xyz = refract(interpolant.vEye.xyz, newNormal, 1.0/1.45);
		t_refract.w = 0;
		refractedRay = mul(reflectionTransformationMatrix, t_refract).xyz;
		float4 refractedColor;
		refractedColor = texSPHERE(environment_texture, refractedRay);
		finalColor.rgb = (1-opacity)*refractedColor.rgb+opacity*finalColor.rgb;
		//finalColor.rgb = refractedColor.rgb;
		//finalColor.rgb = (refractedRay.rgb+float3(1, 1, 1))*0.5;
		opacity = 1.0;
#endif
#endif
//#endif // of defined(SINGLE_PASS_SHADER) || defined(ENVIRONMENT_PASS_SHADER)
#ifdef	ENABLE_CLIPPING_PLANE
		float clipSign = dot(clippingPlane.xyz, interpolant.vPosition.xyz)+clippingPlane.w;
		if (clipSign < 0) discard;
#endif
		if (finalColor.a == 0.0) discard;
		fragOut.color = finalColor;
#ifdef ENABLE_ALPHA_PREMULTIPLY
		fragOut.color.rgb = fragOut.color.rgb*fragOut.color.a;
#endif



		fragOut.color = clamp(fragOut.color, float4(0, 0, 0, 0), float4(1, 1, 1, 1));
//		fragOut.color.rgb=pow(fragOut.color.rgb, 1/2.2);
		return fragOut;
	}
	
#define STOCHASTIC_SHADOW_TRANSPARENCY	
frag2buffer shadowCasterMain(in vertex2frag interpolant
							,uniform Material	material
							,uniform float4x4	modelViewIT
							,uniform float4		clippingPlane
							,uniform sampler2D	noiseTexture
							,uniform sampler2D	object_opacity_texture
							,uniform float4x4	object_opacity_texture_matrix
							,uniform float4     meshShadowOpacity

)
{
	frag2buffer fragOut;
	fragOut.color = float4(0, 0, 0, 0);
	float4 UV = interpolant.fTexCoord0;
	float4 texLookup; //Temporary variable
#ifdef	ENABLE_CLIPPING_PLANE
	float clipSign = dot(clippingPlane.xyz, interpolant.vPosition.xyz)+clippingPlane.w;
	if (clipSign < 0) discard;
#endif
	
	float opacity=material.opacity;

#ifdef	ENABLE_AGFOpacityMap
		texLookup = xformTex2D(object_opacity_texture, UV, object_opacity_texture_matrix);		
#ifdef USE_ALPHA_FOR_OPACITY_MAP
		opacity = texLookup.a;
#else
		float3 perColorOpacity = lerp(material.opacity.rrr, texLookup.rgb, texLookup.a);
		//We have got to choose _SINGLE_ opacity value for GL framebuffer
		//We are choosing maximum of the 3
		float rg_maxopacity = max (perColorOpacity.r, perColorOpacity.g);
		opacity = max (rg_maxopacity, perColorOpacity.b); 
#endif
#endif
	
	float heisenbergShading = 0.5;
#ifdef STOCHASTIC_SHADOW_TRANSPARENCY	
	float3 clipNormalized;
	clipNormalized = (interpolant.fClipPosition.xyz+float3(1.0, 1.0, 1.0))*float3(0.5, 0.5, 0.5);
	float2 normTexLookup = clipNormalized.xy + clipNormalized.zz;
	float4 noiseVal = tex2D(noiseTexture,normTexLookup);
// 	float4 randArg;
// 	randArg.xyz = noiseVal.xyz*normalize(interpolant.vPosition.xyz);
// 	randArg.w = dot(noiseVal.xyz, normalize(interpolant.vPosition.xyz));
// 	heisenbergShading = random_number(noiseVal).x;
	heisenbergShading = noiseVal.r;
#endif
	
	opacity = opacity*meshShadowOpacity.r;
	
	if (opacity<heisenbergShading)
		discard;
		
	fragOut.color = float4(opacity, opacity, opacity, opacity);
	
	return fragOut;
}


frag2buffer shadowCatcherFragMain(in vertex2frag interpolant
					,uniform float4		environmentColor
					,uniform float4x4	fmodelViewCamera
					,uniform float4x4	fmodelViewIT
					,uniform float4x4   worldToUV
					,uniform Material	material
					,uniform float4		clippingPlane
#if NUMBER_OF_ACTIVE_INFINITE_LIGHTS > 0
					,uniform InfiniteLight	infiniteLights[NUMBER_OF_ACTIVE_INFINITE_LIGHTS]
#endif		
#if NUMBER_OF_ACTIVE_SPOT_LIGHTS > 0
					,uniform SpotLight		spotLights[NUMBER_OF_ACTIVE_SPOT_LIGHTS]
#endif		
#if NUMBER_OF_ACTIVE_POINT_LIGHTS > 0
					,uniform PointLight		pointLights[NUMBER_OF_ACTIVE_POINT_LIGHTS]
#endif	
					,uniform float4x4	iEyeToWorldMatrix
					,uniform float4		iGlobalAmbientColor
					,uniform sampler2D	noiseTexture
					,uniform float4x4   objectUVtoReflectionUV
					,uniform sampler2D   reflectionTexture
#ifdef	ENABLE_IBL
					,uniform float4x4 sphericalHarmonicMatrixRed
					,uniform float4x4 sphericalHarmonicMatrixGreen
					,uniform float4x4 sphericalHarmonicMatrixBlue
					,uniform float4x4 sphericalHarmonicsTransformationMatrix
#endif

#ifdef ENABLE_AGFDiffuseMap
					,uniform sampler2D	diffuse_texture
					,uniform float4x4	diffuse_texture_matrix
#endif

#ifdef ENABLE_AGFReflectivityMap
					,uniform sampler2D reflectivity_texture
					,uniform float4x4  reflectivity_texture_matrix
#endif

#ifdef ENABLE_AGFOpacityMap
					,uniform sampler2D object_opacity_texture
					,uniform float4x4  object_opacity_texture_matrix
#endif

#ifdef ENABLE_AGFSpecularColorMap
					,uniform sampler2D specular_intensity_texture
					,uniform float4x4  specular_intensity_texture_matrix
#endif					

#ifdef ENABLE_AGFBumpMap
					,uniform sampler2D bump_gradient_texture
					,uniform float4x4  bump_gradient_texture_matrix
					,uniform float bumpStrength
					,uniform float bumpTextureNormalizer
#endif

					)
	{
	frag2buffer fragOut;
	
	float3 newNormal = normalize(interpolant.vNormal);

	if (interpolant.fDiffuseColor.r > 0.5)//back-facing condition
		 newNormal = -newNormal;

	int i;
	
	float3 diff=float3(0, 0, 0);
	float3 spec=float3(0, 0, 0);
	float3 diffNoShadow=float3(0, 0, 0);
	float shininess=0.0f;
	float screenSpaceRandomNumber = 0.0;
	


#ifdef ENABLE_GL_SOFT_SHADOWS	
	float3 clipNormalized;
	clipNormalized = (interpolant.fClipPosition.xyz+float3(1.0, 1.0, 1.0))*float3(0.5, 0.5, 0.5);
	float2 normTexLookup = clipNormalized.xy + clipNormalized.zz;
    screenSpaceRandomNumber = tex2D(noiseTexture,normTexLookup).x;
#endif
	
#if NUMBER_OF_ACTIVE_INFINITE_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_INFINITE_LIGHTS;i++)
			{
			infiniteLights[i].position = mul (fmodelViewCamera, infiniteLights[i].position);	
			EvaluateInfiniteLight(newNormal, -(interpolant.vEye), infiniteLights[i], diff, spec, diffNoShadow, shininess,iEyeToWorldMatrix, screenSpaceRandomNumber);
			}
#endif		
#if NUMBER_OF_ACTIVE_SPOT_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_SPOT_LIGHTS;i++)
			{
			spotLights[i].worldPosition = spotLights[i].position;
			spotLights[i].position = mul (fmodelViewCamera, spotLights[i].position);	
			spotLights[i].direction = mul (fmodelViewCamera, spotLights[i].direction);	
			EvaluateSpotLight(newNormal, -(interpolant.vEye), spotLights[i], diff, spec, diffNoShadow, shininess,iEyeToWorldMatrix, screenSpaceRandomNumber);
			}
#endif		
#if NUMBER_OF_ACTIVE_POINT_LIGHTS > 0
		for (i=0;i<NUMBER_OF_ACTIVE_POINT_LIGHTS;i++)
			{
			pointLights[i].worldPosition = pointLights[i].position;
			pointLights[i].position = mul (fmodelViewCamera, pointLights[i].position);	
			EvaluatePointLight(newNormal, -(interpolant.vEye), pointLights[i], diff, spec, diffNoShadow, shininess,iEyeToWorldMatrix, screenSpaceRandomNumber);
			}
#endif	

#ifdef ENABLE_IBL
		float4 normal1 = newNormal.xyzz;
		normal1.w = 0.0;
		float4 normalIBL = mul(sphericalHarmonicsTransformationMatrix, normal1);
		normalIBL.w = 0.0;
		normalize(normalIBL);
		normalIBL.w = 1.0;
 		float3 diffuseIBL = { dot(normalIBL, mul(sphericalHarmonicMatrixRed, normalIBL)),
 							  dot(normalIBL, mul(sphericalHarmonicMatrixGreen, normalIBL)),		
 							  dot(normalIBL, mul(sphericalHarmonicMatrixBlue, normalIBL))
 							};
		diff += diffuseIBL;
		diffNoShadow += diffuseIBL;
#endif

	diff+=iGlobalAmbientColor.rgb;
	diffNoShadow+=iGlobalAmbientColor.rgb;
	float intensityWithShadows = diff.x + diff.y + diff.z;
	float intensityNoShadows = diffNoShadow.x + diffNoShadow.y + diffNoShadow.z;

	float ratio = 1.0;
	if (intensityNoShadows > 1e-6) 
		{
		ratio = intensityWithShadows / intensityNoShadows;
		}
							
	if (ratio < 0.0f) 
		{
		ratio = 0.0f;
		}

	if (ratio > 1.0f) 
		{
		ratio = 1.0f;
		}
	float4 geomPointInEyeSpace = float4(interpolant.vEye, 1.0);
	float4 geomPointInWorldSpace = mul(iEyeToWorldMatrix, geomPointInEyeSpace);

	float4 UV =  mul(worldToUV,geomPointInWorldSpace);
	UV.z = 0.0f;
	UV.w = 1.0f;	
	float4 texLookup;

	float4 shadowedColor;
	float4 blendedColor;
	float4 reflectedColor;

	float3 materialDiffuseColor = material.Kd.rgb;;

	float reflectivity = material.reflectivity;

	float4 reflectedColorFactor;
	reflectedColorFactor.rgb = material.Ks.rgb;
	reflectedColorFactor.a = 1.0;
	
	float opacity = material.opacity;

#ifdef ENABLE_AGFDiffuseMap
	texLookup = xformTex2D(diffuse_texture, UV, diffuse_texture_matrix);
	materialDiffuseColor = lerp(material.Kd.rgb, texLookup.rgb, texLookup.a);
#endif

#ifdef ENABLE_AGFOpacityMap
	texLookup = xformTex2D(object_opacity_texture, UV, object_opacity_texture_matrix);
	opacity = texLookup.r; 
#endif	
	
#ifdef ENABLE_AGFReflectivityMap
	texLookup = xformTex2D(reflectivity_texture, UV, reflectivity_texture_matrix);
	reflectivity = lerp(material.reflectivity.rrr, texLookup.rgb, texLookup.a).r; 
#endif

#ifdef ENABLE_AGFSpecularColorMap
	texLookup =  xformTex2D(specular_intensity_texture, UV, specular_intensity_texture_matrix);
	reflectedColorFactor.rgb = lerp(material.Ks.rgb, texLookup.rgb, texLookup.a);
#endif

	shadowedColor.rgb =  materialDiffuseColor;
	shadowedColor.a = (1.0-ratio)*opacity;
	
	if (shadowedColor.a<=0.00001)
		{
		shadowedColor = float4(0, 0, 0, 0);
		}
		
	float4 reflectionUV = interpolant.fTexCoord0;
	reflectionUV.z = 0.0f;
	reflectionUV.w = 1.0f;
	texLookup = xformTex2D(reflectionTexture, reflectionUV, objectUVtoReflectionUV);
	reflectedColor = texLookup;
	float reflectedOpacity = reflectedColor.a*reflectivity;
	
	reflectedColor = reflectedColor*reflectedColorFactor;
	reflectedColor.a = reflectedOpacity;

	blendedColor = lerp(reflectedColor, shadowedColor, (1.0f-reflectedColor.a));
	blendedColor.a = 1.0f - (1.0f-reflectedColor.a)*(1.0f-shadowedColor.a);
	
	fragOut.color = blendedColor;
	
	fragOut.color = clamp(fragOut.color, float4(0, 0, 0, 0), float4(1, 1, 1, 1));
	
 	if (UV.x < 0|| UV.x > 1 || UV.y < 0 || UV.y > 1)
 		{
 		fragOut.color = float4(0, 0, 0, 0);
 		}
 	
 //	fragOut.color.rgb = reflectedColorFactor.rgb;
//	fragOut.color.a = 1;
	return fragOut;
	}
	
	
	
frag2buffer shadowCatcherFragMainDEBUG(in vertex2frag interpolant)
	{
	frag2buffer fragOut;
	 fragOut.color.rgb =  float3(1, 0, 0);
 	fragOut.color.a =1.0f;

	return fragOut;
	}
	
vertex2fragX vertMainDEBUG(in a2v app, 
						   uniform float4x4 modelViewProj)
	{
		vertex2fragX vertOut;
		vertOut.HPosition = mul(modelViewProj, app.vPosition);
		return vertOut;
	}