#define FOG


//------------------------------------

texture FurTexture;
sampler2D FurSampler = sampler_state
{
    texture = <FurTexture>;
    WrapS = Wrap;
    WrapT = Wrap;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

texture ColourTexture;
sampler2D ColourSampler = sampler_state
{
    texture = <ColourTexture>;
    WrapS = Wrap;        
    WrapT = Wrap;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

//------------------------------------ 

// transformations

float4x4 worldViewProj : WORLDVIEWPROJECTION;
float4x4 matModelView : MODELVIEWMATRIX;
float4x4 matWorld : WORLDMATRIX;
float4x4 matViewIT : VIEWINVERSETRANSPOSE;
float4x4 matView : VIEWMATRIX;

float FurLength;
float UVTexScale;
float UVFurScale;
float Layer; // 0 to 1 for the level

float3 gravity; // = float3( 0, -1, 0 );
float3 force;	// applied force
float3 normalNoise;

float3 cameraPos;	// camera in world-space
float4 lightPos;	// light in world-space

float4 fogColor; // = float4( 0, 0, 0, 1 );
float fogDensity;

uniform float kC, kL, kQ;


//------------------------------------

struct vertexInput 
{
    float3 position                 : POSITION;
    float3 normal                   : NORMAL;
    float2 texCoordDiffuse          : TEXCOORD0;
    float4 diffuse          	: COLOR;
};

 

struct vertexOutput 
{
    float4 HPOS     : POSITION;   
    float2 T0       : TEXCOORD0; // fur alpha
    float2 T1       : TEXCOORD1;
    float3 normal   : TEXCOORD2;
    float4 diffuse  : TEXCOORD3;
    float depth : TEXCOORD4;
    float3 lightVec : TEXCOORD5;
    float3 viewVec : TEXCOORD6;
    float3 worldPos : TEXCOORD7;
};



vertexOutput VS_TransformAndTexture( in vertexInput IN )
{
      vertexOutput OUT = (vertexOutput)0;
      float3 P = IN.position.xyz + (IN.normal * FurLength);
//      float3 P = IN.position.xyz + (IN.normal * FurLength + normalNoise);

      float4 Po = float4( P, 1.0 );

	float3 worldPos = mul( matWorld, Po ).xyz;
	OUT.worldPos = worldPos;

      float3 viewpos = mul( matModelView, Po ).xyz;	// in "view" coordinates
//      float3 viewpos = mul( matView, float4(worldPos,1.0) ).xyz;	// in "view" coordinates

    //Modify our normal so it faces the correct direction for lighting if we
    //want any lighting
    float3 normal = mul( (float3x3)matViewIT, IN.normal );
    normal = normalize( normal );
    OUT.normal = normal; // Output Normal

	float k =  pow(Layer, 3); // increase fast.. exponentially

	float3 displacement = force + gravity;
	displacement = mul( (float3x3)matViewIT, displacement );
//	displacement = mul( (float3x3)matWorld, displacement );
//	P += displacement * k;
	P += (normal * displacement) * k;
//      P += displacement * k * sin(IN.normal);
//      P += gravity * k * sin(IN.normal);
 
	OUT.HPOS = mul(worldViewProj, float4(P, 1.0f) ); // Output Vertice Position Data

	// if w is 1 its a point light, is 0 its a directional light
	float3 viewL = mul( matView, lightPos ).xyz;
	float3 L = viewL - (viewpos.xyz * lightPos.w);
	OUT.lightVec = normalize( L );

	float3 viewE = mul( matView, float4(cameraPos,1) ).xyz;
	OUT.viewVec = normalize( float3(matViewIT[0].w, matViewIT[1].w, matViewIT[2].w) - viewpos.xyz);

	OUT.T0 = IN.texCoordDiffuse * UVTexScale;
    OUT.T1 = IN.texCoordDiffuse * UVFurScale; 
	OUT.diffuse = IN.diffuse;

#ifdef FOG
	float3 dist = distance( viewE, viewpos.xyz );
	OUT.depth = dist.z;
#endif

    return OUT;
}


float4 PS_Textured( in vertexOutput IN ) : COLOR
{
   	float4 FinalColor = 0;

   	float4 FurTexel = tex2D( FurSampler, IN.T1 );    // Fur Texture - alpha is VERY IMPORTANT!
   	float4 ColorTexel = tex2D( ColourSampler, IN.T0 );

	//float3 vL = normalize( IN.lightVec );
	//float3 vV = normalize( IN.viewVec );
	//float3 vN = normalize( IN.normal );
	float3 vL = IN.lightVec;
	float3 vV = IN.viewVec;
	float3 vN = IN.normal;

	// Add shadow term. lower layers usually get less light
	float shadow = lerp( 0.4, 1, Layer );
    FurTexel *= shadow;

	// distance attenuation	
	float d = distance(lightPos.xyz,  IN.worldPos.xyz);
	float attenuation = 1.0 / (kC + kL*d + kQ*d*d);	

	float NdotL = max( 0, dot( vN, vL ) );

	float4 ambient = float4( 0.13, 0.13, 0.13, 1.0 );
	float4 diffuse = 0;
	float4 specular = 0;

	//if( NdotL > 0.0 )
	{
		ambient = ambient * FurTexel;
		
		// shadow term
		//float shadow = saturate( NdotL * 4 );
		//diffuse *= shadow;
		
		diffuse = FurTexel * ColorTexel * IN.diffuse * NdotL;
		
		//float3 vH = normalize( vV + vL );
		//specular = pow( saturate(dot(vH, vN)), 8.0 );	
		float3 vR = reflect( -vL, vN );
		specular = pow( saturate(dot(vR, vV)), 32.0 ) * FurTexel.a;
	}
	
//	FinalColor = (ambient + diffuse); // * attenuation;
	FinalColor = (ambient + diffuse + specular); // * attenuation;
	FinalColor.a = IN.diffuse.a * FurTexel.a;

#ifdef FOG
/*	// Apply linear fog
	if( IN.depth < fogEnd )
	{
		FinalColor = lerp( FinalColor, fogColor, (IN.depth-fogStart)/(fogEnd-fogStart) );
		FinalColor.a = IN.diffuse.a;
	}
	else
	{
		FinalColor = fogColor;
	}*/
	
	// Apply exp2 fog
	// fogFactor = exp(-(density * z)2)
	// final equation: fogFactor = exp2(density2 * z2 * 1.442695) 
	float fogFactor = exp( -fogDensity * fogDensity * IN.depth * IN.depth * 1.442695 );
	fogFactor = clamp( fogFactor, 0.0, 1.0 );
	FinalColor = mix( fogColor, FinalColor, fogFactor );
	FinalColor.a = IN.diffuse.a * diffuse.a;
#endif

      return FinalColor;       // Use texture colour
}


//---------------------------------------------------------------------------//
technique Technique_FurSimple
{   
    pass FurPass
    {		
		VertexProgram = compile arbvp1 VS_TransformAndTexture();
		FragmentProgram  = compile arbfp1 PS_Textured();
		//BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
		//AlphaBlendEnable = true;   
		//CullFaceEnable = false;
		//DepthTestEnable = true;
		//DepthMask = true;

    }
}
