
	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 fColor : COLOR0;
		float4 fSpecularColor : COLOR1;
		float4 fTexCoord0 : TEXCOORD0;
		float4 fReflection : TEXCOORD1;
		float4 _t: TEXCOORD2;
		float4 _b: TEXCOORD3;
		float4 _n: TEXCOORD4;
		float3 fNormal: TEXCOORD5;
		float3 fEye: TEXCOORD6;
		float3 fPosition: TEXCOORD7;
	};
	struct vertex2fragX
	{
		float4 HPosition : POSITION;
		float4 fColor : COLOR0;
		float4 fBackColor : BCOL0;
		float4 fSpecularColor : COLOR1;
		float4 fTexCoord0 : TEXCOORD0;
		float4 fReflection : TEXCOORD1;
		float4 _t: TEXCOORD2;
		float4 _b: TEXCOORD3;
		float4 _n: TEXCOORD4;
		float3 fNormal: TEXCOORD5;
		float3 fEye: TEXCOORD6;
		float3 fPosition: TEXCOORD7;
	};
	struct frag2buffer
	{
		float4 color: COLOR0;
//		float4 extra_target1: COLOR1;
//		float4 extra_target2: COLOR2;
//		float4 extra_target3: COLOR3;
		float  depth: DEPTH;
	};
#define ENABLE_BUMP_MAPPING
	vertex2frag uvVertMain(in a2v app, 
		uniform float4x4 modelViewProj, 
		uniform float4x4 modelView)
	{
		vertex2frag vertOut;
		vertOut.HPosition = mul(modelViewProj, app.vPosition);
		vertOut.fPosition = mul(modelView,app.vPosition).xyz;
		float4 worldNormal=float4(app.vNormal.xyz, 0.0);
		float4 eyeNormal=mul(modelView, worldNormal);
		vertOut.fNormal =eyeNormal.xyz; //app.vNormal.xyz;
		vertOut.fTexCoord0 = app.vTexCoord0;
		
		float3 eyeFaceNormal;
		eyeFaceNormal = ((app.vFaceNormal).xyz);
		vertOut._n.xyz = normalize(eyeFaceNormal);
		//New way of tangents and binormals
		float3 eyeTangent, eyeBinormal;
		eyeTangent = ((app.vFaceTangent).xyz);
		eyeBinormal = ((app.vFaceBinormal).xyz);
		vertOut._t.xyz = (eyeTangent);
		vertOut._b.xyz = normalize(eyeBinormal);
		
		return vertOut;
	}
	vertex2fragX uvVertPaint(in a2v app, 
		uniform float4x4 modelViewProj)
	{
		vertex2fragX vertOut;
		vertOut.HPosition = mul(modelViewProj, app.vPosition);
		vertOut.fNormal = app.vNormal.xyz;
		vertOut.fTexCoord0 = app.vTexCoord0;
		vertOut.fColor = app.vColor;
		vertOut.fBackColor = app.vColor;
		vertOut._n = app.vFaceNormal;
		vertOut._t = app.vFaceTangent;
		//vertOut._b = app.vFaceBinormal;
		
		return vertOut;
	}
	frag2buffer uvFragMain(in vertex2frag interpolant, 
						   uniform sampler2D bump_gradient_texture, 
						   uniform float2 bumpTextureNormalizer, 
						   uniform float bumpStrength,
						   uniform float4 clippingPlane
						   )
	{
	frag2buffer fragOut;
	float clipSign = dot(clippingPlane.xyz, interpolant.fPosition.xyz)+clippingPlane.w;
	if (clipSign < 0) discard;//{
	float3 newNormal = interpolant.fNormal.xyz;
//#ifdef ENABLE_BUMP_MAPPING
if (bumpTextureNormalizer.x < 0.5 && length(interpolant._t)>0)//This means width of bump texture is > 2 -> bumps exist
	{
	float4 bumpLookup = tex2D(bump_gradient_texture, interpolant.fTexCoord0.xy);
	float3 bumpGradient;
	float x0,x1,y0,y1;
	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;
	bumpGradient.xyz = float3(-(x1-x0), -(y1-y0), 0);
	float3 normalDistortionTangentSpace = bumpGradient.xyz*2.0*bumpStrength*bumpLookup.a; //Alpha channel used to modulate bump strength
	float3 normalDistortionEyeSpace;
	float3 _t = normalize(interpolant._t);
	float3 _n = normalize(interpolant._n);
	float3 _b = normalize(cross(_n, _t));
	normalDistortionEyeSpace.x = _t.x * normalDistortionTangentSpace.x + _t.x * normalDistortionTangentSpace.y;//+ _n.x * normalDistortionTangentSpace.z;
	normalDistortionEyeSpace.y = _t.y * normalDistortionTangentSpace.x + _t.y * normalDistortionTangentSpace.y;// + _n.y * normalDistortionTangentSpace.z;
	normalDistortionEyeSpace.z = _t.z * normalDistortionTangentSpace.x + _t.z * normalDistortionTangentSpace.y;// + _n.z * normalDistortionTangentSpace.z;
	newNormal = newNormal + normalDistortionEyeSpace;
	}
//#endif	
	fragOut.color.rgb = (normalize(newNormal)+float3(1, 1, 1))*float3(0.5, 0.5, 0.5);
	//fragOut.color.rgb = float3(0, 1, 0);
	fragOut.color.a = 1.0;
	return  fragOut;
	}
/*******************************************************************************************************************/
#define ID_DELTA 0.5
	float4 uvPaintLookupFaceID(uniform sampler2D faceIDTexture, float2 uv, float3 faceID, float4 yesResult, float4 noResult)
	{
		float4 result = noResult;
		float4 faceIDLookup = tex2D(faceIDTexture, uv);
		if ((faceIDLookup.r - faceID.x < ID_DELTA) &&
			(faceIDLookup.g - faceID.y < ID_DELTA) &&
			(faceIDLookup.b - faceID.z < ID_DELTA) &&
			(faceIDLookup.r - faceID.x > -ID_DELTA) &&
			(faceIDLookup.g - faceID.y > -ID_DELTA) &&
			(faceIDLookup.b - faceID.z > -ID_DELTA))
		{
			result = yesResult;
		}
		return result;
	}
	frag2buffer uvFragPaint_old(in vertex2frag interpolant, uniform sampler2D paintTexture, uniform sampler2D faceIDTexture, uniform float2 faceIDTextureNormalizer)
	{
		frag2buffer fragOut;
		float2 uv = interpolant.fTexCoord0.xy / interpolant.fTexCoord0.w;
		float4 paintResult = tex2D(paintTexture, uv);
		paintResult.a *= interpolant.fColor.a;
		fragOut.color = float4(0.0, 0.0, 0.0, 0.0);
		for (float du = -2.0; du < 2.5; du += 1.0)
		{
			for (float dv = -2.0; dv < 2.5; dv += 1.0)
			{
				fragOut.color = uvPaintLookupFaceID(faceIDTexture, uv + faceIDTextureNormalizer * float2(du, dv), interpolant.fNormal, paintResult, fragOut.color);
			}
		}
		//fragOut.color = faceIDLookup; // Debugging - to visualize the faceID map
		return fragOut;
	}
	frag2buffer uvFragPaint(in vertex2frag interpolant, uniform sampler2D paintTexture, uniform sampler2D faceIDTexture)
	{
		frag2buffer fragOut;
		fragOut.color = float4(0.0, 0.0, 0.0, 0.0);
		float2 uv = interpolant.fTexCoord0.xy / interpolant.fTexCoord0.w;
		if (uv.x <= 0.0 || uv.x >= 1.0 || uv.y <= 0.0 || uv.y >= 1.0)
			return fragOut;
		float4 paintLookup = tex2D(paintTexture, uv);
		paintLookup.a *= interpolant.fColor.a;
		float4 faceIDLookup = tex2D(faceIDTexture, uv);
		float faceID = faceIDLookup.r * 255.0 * 256.0 * 256.0 + faceIDLookup.g * 255.0 * 256.0 + faceIDLookup.b * 255.0;
		
		float testFaceID = interpolant.fNormal.x;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant.fNormal.y;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant.fNormal.z;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		
		testFaceID = interpolant._n.x;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._n.y;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._n.z;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._n.w;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		
		testFaceID = interpolant._t.x;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._t.y;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._t.z;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._t.w;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		
		testFaceID = interpolant._b.x;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._b.y;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._b.z;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		testFaceID = interpolant._b.w;
		if ((testFaceID - faceID < ID_DELTA) && (testFaceID - faceID > -ID_DELTA))
			fragOut.color = paintLookup;
		
		//fragOut.color = faceIDLookup; fragOut.color.a = 1.0; // Debugging - to visualize the faceID map
		//fragOut.color = paintLookup; // Debugging - ignore faceIDs
		// More debugging - view the paint fade value as a grayscale color
		/*fragOut.color.r = interpolant.fColor.a;
		fragOut.color.g = interpolant.fColor.a;
		fragOut.color.b = interpolant.fColor.a;
		fragOut.color.a = 1.0;*/
		
		// More debugging - visualize the difference between the faceID and the ID in the faceID map
		/*testFaceID = interpolant.fNormal.x - faceID;
		if (testFaceID < 0.0)
			testFaceID = -testFaceID;
		fragOut.color.r = testFaceID;
		fragOut.color.g = testFaceID;
		fragOut.color.b = testFaceID;
		fragOut.color.a = 1.0;*/
		
		return fragOut;
	}

vertex2fragX paintMaskVertex(in a2v app, 
	uniform float4x4 modelViewProj,
	uniform float4x4 modelView,
	uniform float4x4 modelViewIT,
	uniform float4x4 textureTransform, 
	uniform float2 uivScreenSize, 
	uniform float4 uivTextureSize)
	{
	vertex2fragX vertOut;
	// uivTextureSize's 3rd and 4th component are used to pass normal vector fade thresholds.
	float fadeMinThreshold=uivTextureSize[2];
	float fadeMaxThreshold=uivTextureSize[3];
	vertOut.HPosition = mul(modelViewProj, app.vPosition);
	vertOut.fPosition = mul(modelView,app.vPosition).xyz;
	float3 normalVec; 
	float3 ecPosition3 = (mul(modelView,app.vPosition).xyz);
	float4 v1 = app.vPosition+app.vNormal;
	v1.w = 1.0;
	float3 ecPosition3_1 = (mul(modelView,v1).xyz);
	normalVec = normalize(ecPosition3_1-ecPosition3);
	float paintFaloff = abs(normalVec.z); //DOT(NORMAL, EYE)
	float paintFalloffTransfer=1.0-smoothstep(fadeMaxThreshold, fadeMinThreshold, paintFaloff);
	float4 P = app.vPosition;
	P.w = 1.0;
	float4 P1T = app.vPosition+app.vFaceTangent*0.5*0.01;
	P1T.w = 1.0;
	float4 P1B = app.vPosition+app.vFaceBinormal*0.5*0.01;
	P1B.w = 1.0;
	float4 P0T = app.vPosition-app.vFaceTangent*0.5*0.01;
	P0T.w = 1.0;
	float4 P0B = app.vPosition-app.vFaceBinormal*0.5*0.01;
	P0B.w = 1.0;
	//float4 projP = mul(modelViewProj, P);
	float4 projP0T = mul(modelViewProj, P0T);
	float4 projP0B = mul(modelViewProj, P0B);
	float4 projP1T = mul(modelViewProj, P1T);
	float4 projP1B = mul(modelViewProj, P1B);
	float2 pP0T = projP0T.xy/projP0T.w;
	float2 pP1T = projP1T.xy/projP1T.w;
	float2 pP0B = projP0B.xy/projP0B.w;
	float2 pP1B = projP1B.xy/projP1B.w;
	float2 dSdu = (pP1T-pP0T)*float2(100*0.5, 100*0.5)*(uivScreenSize/uivTextureSize.xx);
	float2 dSdv = (pP1B-pP0B)*float2(100*0.5, 100*0.5)*(uivScreenSize/uivTextureSize.yy);
//	float4 tu = mul(modelViewIT, app.vFaceTangent);
//	float4 tv = mul(modelViewIT, app.vFaceBinormal);
//	dSdu = tu.xy/tu.w;
//	dSdv = tv.xy/tv.w;
	//Compute eigenvalues;
	float a = dSdu.x;
	float b = dSdv.x;
	float c = dSdu.y;
	float d = dSdv.y;
	float sqD = sqrt((a-d)*(a-d)+4*b*c);
	float lambda_min = abs((a+d-sqD)*0.5);
	float temp_swap = lambda_min;
	float lambda_max = abs((a+d+sqD)*0.5);
	if (lambda_min>lambda_max)
		{
		lambda_min = lambda_max;
		lambda_max = temp_swap;
		}
	float factor = 0;
	float threshold_factor = 4.0;
	float3 heatmap_color = float3(1, 0, 0);
	if (lambda_max<1)
	{	//Oversample case:
		factor = 1/lambda_min;
		heatmap_color = float3(1, 0, 0);
	}
	if (lambda_min>1)
	{	//Undersample case:
		factor = lambda_max;
		heatmap_color = float3(0, 0, 1);
	}
	float t = (factor-1)/(threshold_factor-1);
	float transfer_t;
	transfer_t = smoothstep(0.5, 1.0, t);
	float combined_metric_t = 1.0 - (1.0-transfer_t)*(1.0-paintFalloffTransfer);
	float3 metric = lerp(float3(1, 1, 1), heatmap_color, combined_metric_t);
	//metric.rg = (P1.xy+float2(1, 1))*(float2(0.5, 0.5));
	//metric.b = 0;
	vertOut.fColor = metric.rgbr;
	vertOut.fBackColor =  metric.rgbr;
	return vertOut;
	}
frag2buffer paintMaskFrag(in vertex2frag interpolant,
						  uniform float2 textureSize, 
						  uniform float2 viewportSize,
						  uniform float4 clippingPlane)
	{
	frag2buffer fragOut;
	float clipSign = dot(clippingPlane.xyz, interpolant.fPosition.xyz)+clippingPlane.w;
	if (clipSign < 0) discard;
	fragOut.color = interpolant.fColor;
	fragOut.color.a  =  1.0f;//float4(1, 0,0, 1);
	return fragOut;
	}
	
///////////////////////////////////////////////////////////////////////////////////////////	
	
vertex2frag depthVertMain(in a2v app, 
		uniform float4x4 modelViewProj, 
		uniform float4x4 modelView)
	{
		vertex2frag vertOut;
		vertOut.HPosition = mul(modelViewProj, app.vPosition);
		vertOut.fPosition = mul(modelView,app.vPosition).xyz;
		vertOut.fReflection=mul(modelViewProj, app.vPosition);
		vertOut.fNormal = app.vNormal.xyz;
		vertOut.fTexCoord0 = app.vTexCoord0;
		

		return vertOut;
	}

	frag2buffer depthFragMain(in vertex2frag interpolant, 
						   uniform sampler2D bump_gradient_texture, 
						   uniform float2 bumpTextureNormalizer, 
						   uniform float bumpStrength,
						   uniform float4 clippingPlane
						   )
	{
	frag2buffer fragOut;
	float clipSign = dot(clippingPlane.xyz, interpolant.fPosition.xyz)+clippingPlane.w;
	if (clipSign < 0) discard;

	float4 clipCoord = interpolant.fReflection;
	clipCoord = clipCoord/clipCoord.w;
	float depth = (clipCoord.z+1.0)*0.5;

	fragOut.color.rgb = depth.rrr;
	fragOut.color.a = 1.0;
	return  fragOut;
	}