
#define FOG
//#define PARABOLOID
//#define ATTENUATION

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

texture ColorTexture;
sampler2D ColorSampler = sampler_state
{
    texture = <ColorTexture>;
    WrapS = Wrap;        
//    WrapS = Mirror;//Wrap;        
    WrapT = Wrap;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

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


 

// transformations

uniform float4x4 worldViewProj : WORLDVIEWPROJECTION;
uniform float4x4 view : MODELVIEW;
uniform float4x4 viewI : VIEWINVERSE;
uniform float4x4 viewIT : VIEWINVERSETRANSPOSE;
uniform float4x4 WorldXf : WORLD;
uniform float4x4 W2C: WORLDTOCAMERA;

float3 cameraPos;
float4 lightPos;
float kC, kL, kQ;   // attenuation de la lumire (constante, linéaire, quadratique)

float useSpecular = 0;
float specularLevel = 64.0;

float4 fogColor;
float fogDensity;
float fogStart;
float fogEnd;



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

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

 

struct vertexOutput 
{
    float4 position	: POSITION;   
    float2 uv		: TEXCOORD0;
    float3 normal   : TEXCOORD1;
    float3 lightVec	: TEXCOORD2;
    float3 viewVec	: TEXCOORD3;
    float4 diffuse	: TEXCOORD4;
	float  depth	: TEXCOORD5;
    float3 worldPos	: TEXCOORD6;
};



vertexOutput VS_DiffuseSpecular( in vertexInput IN )
{
    vertexOutput OUT = (vertexOutput)0;

	OUT.position = mul( worldViewProj, float4(IN.position, 1) ); 

//	float4 pos = mul( viewIT, IN.position );
//	OUT.worldPos = pos.xyz;
    float4 Po = float4( IN.position, 1);
    float3 worldpos = mul(WorldXf, Po).xyz;	// in "world" coordinates
    float3 viewpos = mul(view, Po).xyz;	// in "view" coordinates
	OUT.worldPos = worldpos;

	float4 Nn = IN.normal;
    OUT.normal = mul(viewIT, Nn).xyz;

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

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

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

#ifdef FLIPY
	OUT.uv = float2( IN.uv.x, 1.0-IN.uv.y );
#else
	OUT.uv = IN.uv;
#endif

	OUT.diffuse = IN.diffuse;


    return OUT;
}


float4 PS_DiffuseSpecular( in vertexOutput IN ) : COLOR
{
	float4 FinalColor = 0;
	float4 diffuseTexel = tex2D( ColorSampler, IN.uv );


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

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

	float NdotL = max( dot( vN, vL ), 0 );
	
	float4 ambient = 0;
	float4 diffuse = 0;
	float4 specular = 0;
	float2 texcoord = 0;

	//if( NdotL > 0.0 )
	{
		ambient = ambient * diffuseTexel;
		diffuse = diffuseTexel * IN.diffuse * NdotL;

		//float3 vH = normalize( vV + vL );
		//specular = pow( saturate(dot(vH, vN)), specularLevel );	
		float3 vR = reflect( -vL, vN );
		specular = pow( saturate(dot(vR, vV)), specularLevel );
	}

	if( useSpecular ==  0 )
		FinalColor = (ambient + diffuse);
	else
		FinalColor = (ambient + diffuse + specular);
#ifdef ATTENUATION
	FinalColor *= attenuation;
#endif
	FinalColor.a = IN.diffuse.a * diffuseTexel.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 * diffuseTexel.a;
#endif
	
	return FinalColor;
}



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

#ifdef ATTENUATION
	// distance attenuation	
	float d = distance(lightPos.xyz,  IN.worldPos.xyz);
	float attenuation = 1.0 / (kC + kL*d + kQ*d*d);	
#endif
	
	float4 diffuseTexel = tex2D( ColorSampler, IN.uv );

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

	float NdotL = max( dot( vN, vL ), 0 );
	
	// Wrap lighting
	float wrap = 0.13;
	float scatterWidth = 0.35;
	float4 scatterColor = float4(0.0, 0.0, 0.0, 1.0);
	float NdotL_wrap = (NdotL + wrap) / (1.0 + wrap); // wrap lighting

	float4 ambient = 0;//{0.1, 0.1, 0.1, 0.0};	
	float4 diffuse = 0;
	float4 specular = 0;

	//if( NdotL > 0.0 )
	{
		ambient = ambient * diffuseTexel;
	
		diffuse = diffuseTexel * IN.diffuse;
	
		// shadow term
		//float shadow = saturate( NdotL_wrap * 4 );
		//diffuse *= shadow;

		diffuse = diffuse * NdotL_wrap;
		diffuse += (scatterWidth * scatterColor);

		//float3 vR = reflect(-vV, vN);
		//specular = pow( saturate(dot(vR, vL)), specularLevel );
		float3 vR = reflect( -vL, vN );
		specular = pow( saturate(dot(vR, vV)), specularLevel );
	}
	
	if( useSpecular ==  0 )
		FinalColor = (ambient + diffuse);
	else
		FinalColor = (ambient + diffuse + specular);
#ifdef ATTENUATION
	FinalColor *= attenuation;
#endif
	FinalColor.a = IN.diffuse.a * diffuseTexel.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 * diffuseTexel.a;
#endif

	return FinalColor;
}


//---------------------------------------------------------------------------//
technique Technique_DiffuseSpecular
{   
    pass Pass_DiffuseSpecular
    {		
		VertexProgram = compile arbvp1 VS_DiffuseSpecular();
		FragmentProgram  = compile arbfp1 PS_DiffuseSpecular();

/*		//BlendEnable = true;
		//BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
		CullFaceEnable = true;
		CullFace = back;
		DepthTestEnable = true;
		DepthFunc = LEqual;
		DepthMask = true;*/
	}
}

//---------------------------------------------------------------------------//
technique Technique_DiffuseSpecularWrap
{
    pass Pass_DiffuseSpecularWrap
    {		
		VertexProgram = compile arbvp1 VS_DiffuseSpecular();
		FragmentProgram  = compile arbfp1 PS_DiffuseSpecularWrap();
		//GeometryProgram = null;

/*		//BlendEnable = true;
		//BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
		CullFaceEnable = true;
		CullFace = back;
		DepthTestEnable = true;
		DepthFunc = LEqual;
		DepthMask = true;*/
    }
}
