
float3 expand(float3 v)
{
	return v * 2 - 1;
}
float3 compress(float3 v)
{
	return ( v + 1 ) / 2;
}

float3 decodeNormal(float2 enc)
{
	float2 fenc = enc * 2 - 1;
	float3 n = float3( 0.f, 0.f, -( dot( fenc, fenc ) * 2 - 1 ) );
	n.xy = normalize( fenc ) * sqrt( 1 - n.z * n.z );
	return n;
}
float2 encodeNormal(float3 n)
{
	float2 enc = normalize( n.xy ) * ( sqrt( -n.z * 0.5 + 0.5 ) );
	enc = enc * 0.5 + 0.5;
	return enc;
}

float decodeDepth(float2 enc)
{
	return dot( enc, float2( 1.f, 1.f / 255.f ) );
}

float2 encodeDepth(float d)
{
	float2 enc = frac( float2( 1.f, 255.f ) * d );
	enc -= enc.y * float2( 1.f / 255.f, 1 / 255.f );
	return enc;
}

#define SKINVP( iterations ) \
	oPosition = float4( 0.f, 0.f, 0.f, 1.f ); \
	oNormal.xyz = float3( 0.f, 0.f, 0.f ); \
	oTangent = float3( 0.f, 0.f, 0.f ); \
	for( int i = 0; i < iterations; i += 1 ) \
	{ \
		float3x4 curMat = worldMatrix3x4Array[ blendIdx[i] ]; \
		oPosition.xyz += mul( curMat, position ) * blendWgt[i]; \
		oNormal.xyz += mul( (float3x3)curMat, normal ) * blendWgt[i]; \
		oTangent += mul( (float3x3)curMat, tangent.xyz ) * blendWgt[i]; \
	} \
	oPosition = mul( viewProj, oPosition ); \
	oNormal.xyz = mul( (float3x3)view, oNormal.xyz ); \
	oNormal.xyz = normalize( oNormal.xyz ); \
	oNormal.w = oPosition.w / farDistance; \
	oTangent.xyz = mul( (float3x3)view, oTangent.xyz ); \
	oTangent = normalize( oTangent.xyz ); \
	oBinormal = cross( oNormal.xyz, oTangent.xyz ) * tangent.w; \
	oUv1 = uv1; 
	
#define SKINVP_PARAMS \
					float4 position : POSITION, \
			                float3 normal	: NORMAL, \
			                float2 uv1	: TEXCOORD0, \
			                float4 tangent  : TANGENT0, \
			                uint4 blendIdx : BLENDINDICES, \
					out float4 oNormal      : TEXCOORD1, \
					out float3 oTangent     : TEXCOORD2, \
					out float3 oBinormal    : TEXCOORD3, \
			                out float4 oPosition    : POSITION, \
			                out float2 oUv1		: TEXCOORD0, \
			                uniform float4x4 viewProj, \
			                uniform float3x4 worldMatrix3x4Array[40], \
			                uniform float4x4 view, \
			                uniform float farDistance 
			                
// This program is exactly the same as the specular-only VP.
void defaultDeferred_vp(
                                	float4 position : POSITION,
			                float3 normal	: NORMAL,
			                float2 uv1	: TEXCOORD0,
			                float4 tangent  : TANGENT0,

					out float4 oNormal      : TEXCOORD1,
					out float3 oTangent     : TEXCOORD2,
					out float3 oBinormal    : TEXCOORD3,
			                out float4 oPosition    : POSITION,
			                out float2 oUv1		: TEXCOORD0,

			                uniform float4x4 worldViewProj,
			                uniform float4x4 worldView,
			                uniform float farDistance )
{
	oPosition = mul( worldViewProj, position );
	oNormal.xyz = normalize( mul( (float3x3)worldView, normal.xyz ) );
	oNormal.w = oPosition.w / farDistance;
	oTangent = normalize( mul( (float3x3)worldView, tangent.xyz ) );
	oBinormal = cross( oNormal.xyz, oTangent.xyz ) * tangent.w;
	// pass the main uvs straight through unchanged
	oUv1 = uv1;
}
void defaultDeferredSkinning_vp(
					float4 blendWgt : BLENDWEIGHT,
                                	SKINVP_PARAMS
			                )
{
	SKINVP(4)
}
void defaultDeferredSkinningThree_vp(
					float3 blendWgt : BLENDWEIGHT,
                                	SKINVP_PARAMS
			                )
{
	SKINVP(3)
}
void defaultDeferredSkinningOne_vp(
					float1 blendWgt : BLENDWEIGHT,
                                	SKINVP_PARAMS
			                )
{
	SKINVP(1)
}
void defaultDeferred_fp(	float2 uv1 : TEXCOORD0,
				float4 normal : TEXCOORD1,
				float3 tangent     : TEXCOORD2,
				float3 binormal    : TEXCOORD3,
				
				//out float4 oDepthBuf : COLOR0,
				//out float4 oNormalBuf : COLOR1,
				//out float4 oDiffuseBuf : COLOR2,
				//out float4 oSpecularBuf : COLOR3,
				out float4 oDepthAndNormalBuf : COLOR0,
				out float4 oDiffuseBuf : COLOR1,
				out float4 oSpecularBuf : COLOR2,
				
				uniform sampler2D normalMap : register(s0),
				uniform sampler2D diffuseCol : register(s1),
				uniform sampler2D specularCol : register(s2),
				uniform float exponent )
{
//	oDepthBuf.yzw = float3( 0.f, 0.f, 0.f );
//	oNormalBuf.zw = float2( 0.f, 0.f );
	// Get bump map vector, expand from range-compressed
	oDiffuseBuf = tex2D( diffuseCol, uv1 );
	if( oDiffuseBuf.w < 0.01f ) discard;
	float3 nMap = expand( tex2D( normalMap, uv1 ).xyz );
//	oNormalBuf.xy = encodeNormal( normalize( tangent * nMap.x + binormal * nMap.y + normal.xyz * nMap.z ) );
	oDepthAndNormalBuf.zw = encodeNormal( normalize( tangent * nMap.x + binormal * nMap.y + normal.xyz * nMap.z ) );
	
//	oDepthBuf.x = normal.w;
	oDepthAndNormalBuf.xy = encodeDepth( normal.w );

	oSpecularBuf = tex2D( specularCol, uv1 );
	oSpecularBuf.w = exponent / 256;
}

void scrollUvDeferred_fp(	float2 uv1 : TEXCOORD0,
				float4 normal : TEXCOORD1,
				float3 tangent     : TEXCOORD2,
				float3 binormal    : TEXCOORD3,
				
				//out float4 oDepthBuf : COLOR0,
				//out float4 oNormalBuf : COLOR1,
				//out float4 oDiffuseBuf : COLOR2,
				//out float4 oSpecularBuf : COLOR3,
				out float4 oDepthAndNormalBuf : COLOR0,
				out float4 oDiffuseBuf : COLOR1,
				out float4 oSpecularBuf : COLOR2,
				
				uniform sampler2D normalMap : register(s0),
				uniform sampler2D diffuseCol : register(s1),
				uniform sampler2D specularCol : register(s2),
				uniform float exponent,
				uniform float2 uvScale,
				uniform float normalUScroll,
				uniform float normalVScroll,
				uniform float diffuseUScroll,
				uniform float diffuseVScroll,
				uniform float specularUScroll,
				uniform float specularVScroll )
{
//	oDepthBuf.yzw = float3( 0.f, 0.f, 0.f );
//	oNormalBuf.zw = float2( 0.f, 0.f );
	// Get bump map vector, expand from range-compressed
	oDiffuseBuf = tex2D( diffuseCol, float2( uv1.x + diffuseUScroll, uv1.y + diffuseVScroll ) * uvScale );
	if( oDiffuseBuf.w < 0.01f ) discard;
	float3 nMap = expand( tex2D( normalMap, float2( uv1.x + normalUScroll, uv1.y + normalVScroll )  * uvScale ).xyz  );
//	oNormalBuf.xy = encodeNormal( normalize( tangent * nMap.x + binormal * nMap.y + normal.xyz * nMap.z ) );
	oDepthAndNormalBuf.zw = encodeNormal( normalize( tangent * nMap.x + binormal * nMap.y + normal.xyz * nMap.z ) );

//	oDepthBuf.r = normal.w;
	oDepthAndNormalBuf.xy = encodeDepth( normal.w );
	
	oSpecularBuf = tex2D( specularCol, float2( uv1.x + specularUScroll, uv1.y + specularVScroll )  * uvScale );
	oSpecularBuf.w = exponent / 256;
}

void prePassAmbientZ_vp( float4 position : POSITION,
			 float2 uv1	: TEXCOORD0,
			 float4 tangent  : TANGENT0,
			
			 out float4 oPosition : POSITION,
			 out float2 oUv1 : TEXCOORD0,
			 uniform float4x4 worldViewProj )
{
	oPosition = mul( worldViewProj, position );
	oUv1 = uv1;
}


#define SKINVP_PRE( iterations ) \
	oPosition = float4( 0.f, 0.f, 0.f, 1.f ); \
	for( int i = 0; i < iterations; i += 1 ) \
	{ \
		oPosition.xyz += mul( worldMatrix3x4Array[ blendIdx[i] ], position ) * blendWgt[i]; \
	} \
	oPosition = mul( viewProj, oPosition ); \
	oUv1 = uv1; 
	
#define SKINVP_PRE_PARAMS \
	float4 position : POSITION, \
	float2 uv1	: TEXCOORD0, \
	uint4 blendIdx : BLENDINDICES, \
	out float4 oPosition    : POSITION, \
	out float2 oUv1		: TEXCOORD0, \
	uniform float4x4 viewProj, \
	uniform float3x4 worldMatrix3x4Array[40] 

void prePassAmbientZSkinnedOne_vp( float1 blendWgt : BLENDWEIGHT,
				   SKINVP_PRE_PARAMS )
{
	SKINVP_PRE( 1 )
}

void prePassAmbientZSkinnedThree_vp( float3 blendWgt : BLENDWEIGHT,
				     SKINVP_PRE_PARAMS )
{
	SKINVP_PRE( 3 )
}

void prePassAmbientZSkinnedFour_vp( float4 blendWgt : BLENDWEIGHT,
				    SKINVP_PRE_PARAMS )
{
	SKINVP_PRE( 4 )
}

void prePassAmbientZ_fp( float2 uv1 : TEXCOORD,
			 float3 normal : TEXCOORD1,
			 out float4 color : COLOR,
			 uniform float4 ambient,
			 uniform sampler2D diffuseCol )
{
	float4 diff = tex2D( diffuseCol, uv1 );
	if( diff.w < 0.01f ) discard;
	color = diff * ambient;
}

void prePassAmbientZAnim_fp( float2 uv1 : TEXCOORD,
			     float3 normal : TEXCOORD1,
			     out float4 color : COLOR,
			     uniform sampler2D diffuseCol,
			     uniform float4 sourceAmbientColor,
			     uniform float4 destAmbientColor,
			     uniform float ambientFactor )
{
	float4 diff = tex2D( diffuseCol, uv1 );
	if( diff.w < 0.01f ) discard;
	color = lerp( sourceAmbientColor, destAmbientColor, (ambientFactor + 1.f ) / 2 ) * diff;	
}

void prePassAmbientZScrollUv_fp( float2 uv1 : TEXCOORD0,
				float3 normal : TEXCOORD1,
				out float4 color : COLOR,
				uniform sampler2D diffuseCol,
				uniform float4 ambient,
				uniform float2 uvScale,
				uniform float diffuseUScroll,
				uniform float diffuseVScroll )
{
	float4 diff = tex2D( diffuseCol, float2( uv1.x + diffuseUScroll, uv1.y + diffuseVScroll ) * uvScale );
	if( diff.w < 0.01f ) discard;
	color = diff * ambient;
}

