
// light direction (view space)
float4 lightDir ;

float4 I_a;   // ambient
float4 I_d;   // diffuse
float4 I_s; // specular

// material reflectivity
float4 k_a;// : MATERIALAMBIENT;   // ambient
float4 k_d;// : MATERIALDIFFUSE;    // diffuse
float4 k_s;// : MATERIALSPECULAR;    // specular
float  k_n;//   : MATERIALPOWER;       // power

texture Tex0;

// transformations
float4x4 World      : WORLD;
float4x4 View       : VIEW;
float4x4 Projection : PROJECTION;

struct VS_OUTPUT
{
    float4 Pos  : POSITION;
    float4 Diff : COLOR0;
    float4 Spec : COLOR1;
    float2 Tex  : TEXCOORD0;
    float3 Normal : TEXCOORD1;
};

VS_OUTPUT VS(
    float3 Pos  : POSITION, 
    float3 Norm : NORMAL, 
    float2 Tex  : TEXCOORD0)
{
	VS_OUTPUT Out;// = (VS_OUTPUT)0;

	float4x4 WorldView = mul(World, View);
    
//	float3 L = -lightDir;
	float3 L = -mul(float4(lightDir.xyz, 1), (float4x4)WorldView);  // position (view space)

//	float3 light = normalize( -lightDir.xyz );
//	float3 L = -mul( light, WorldView );


	float3 P = mul(float4(Pos, 1), (float4x3)WorldView);  // position (view space)
	float3 N = normalize(mul(Norm, (float3x3)WorldView)); // normal (view space)

	float3 R = normalize(2 * dot(N, L) * N - L);          // reflection vector (view space)
	float3 V = -normalize(P);                             // view direction (view space)

	Out.Pos  = mul(float4(P, 1), Projection);             // position (projected)
	Out.Diff = I_a * k_a + I_d * k_d * max(0, dot(N, L)); // diffuse + ambient
	Out.Spec = I_s * k_s * pow(max(0, dot(R, V)), k_n/1);   // specular
	Out.Normal = N;
	Out.Tex  = Tex;

	return Out;
}

VS_OUTPUT VS_shadow(
    float4 Pos  : POSITION, 
    float3 Norm : NORMAL, 
    float2 Tex  : TEXCOORD0)
{
	float4x4 WorldView = mul(World, View);
    float4x4 worldViewProj = mul( WorldView, Projection );
    VS_OUTPUT OUT;
	
//	float4 lightPos = float4( 2,7,0, 1 );
	float4 lightPos = lightDir;
	float4 PosW = mul( Pos, World );
	float4 dir = normalize( PosW-lightPos );
	float d = (float) (dot(Norm,-dir.xyz)>0);
	float4 newPos = float4( Pos.xyz + (dir.xyz*d*30) - Norm*0.01, Pos.w );
	OUT.Pos = mul( newPos, worldViewProj );
	
//	OUT.Diff = 0;
	float G = 1.0f/length( PosW-lightPos );
//	float G = saturate( 100.0f / length( newPos - Pos ) );
//	OUT.Diff = float4(1,1,1, G/4.0f );
	d = clamp(d,0,1);
	d *= d;
	d = (1-d)*0.3;
	OUT.Diff = float4( d,d,d,d );
	OUT.Spec = 0;
	OUT.Normal = 0;
	OUT.Tex = 0;
	return OUT;
	
	
/*	float4 p = Pos;
	float d = dot(normalize(Norm.xyz),float3(1,0,0));
	d = (float) (d<0.0);
	float4 n4 = float4(Norm,1);
	p = p + n4*d*1000 - mul(n4,0.01f);
	OUT.Pos = mul( mul(p,WorldView), Projection);	
	OUT.Diff = 0;
	OUT.Spec = 0;
	OUT.Normal = 0;
	OUT.Tex = 0;
	return OUT;*/
/*
	// hmm
	float4 lightPos = float4( 2,7,0, 1 );
//	lightPos = mul( lightPos, WorldView );
//	lightPos = mul( lightPos, View );
//	float4 lightPos = mul( lightDir, View );
//	float4 lightPos = float4( lightDir, 1);
	
	float ShadowExtrudeDist= 40;
	float GeomInset = 0.01;
	float4 PosW = mul(Pos,World);
	
	float4 Lvec = ( normalize( PosW - lightPos ));
	float ldn = dot( -Lvec.xyz, Norm.xyz );
	float4 inset_pos = float4(((PosW.xyz - (Norm * GeomInset)).xyz), PosW.w );
	float4 extrusion_vec = Lvec * ShadowExtrudeDist;
	float toggle = (float) (ldn < 0.0);
	
	float4 newPos = extrusion_vec*toggle + inset_pos;
	newPos = mul( newPos, View );
	
	OUT.Pos = mul( newPos, Projection );
	
	OUT.Diff = 0;
	OUT.Spec = 0;
	OUT.Normal = 0;
	OUT.Tex = 0;
	return OUT;
*/	
    
/*	
    
	float4 lightPos = float4( 190,190,-100, 1 );
    float3 N = mul( Norm.xyz, (float3x3)WorldView );
    float far = 100;
    float4 PosView = mul( Pos , WorldView);
    float4 lightView = mul(lightPos,WorldView);
//    float3 LightVecView = PosView - lightPos;
    float3 LightVecView = PosView - lightView;
    if( dot( N, -LightVecView ) < 0.0f )
    {
        if( PosView.z > lightView.z )
            PosView.xyz += LightVecView * ( far - PosView.z ) / LightVecView.z;
        else
            PosView = float4( LightVecView, 0.0f );

        // Transform the position from view space to homogeneous projection space
        PosView = mul( PosView, Projection );
    } else {
        PosView = mul( Pos, worldViewProj );
    }
    
    OUT.Pos = PosView;
	OUT.Diff = 0;
	OUT.Spec = 0;
	OUT.Normal = 0;
	OUT.Tex = 0;
	return OUT;
*/
}

float4 PS_Shadow( VS_OUTPUT IN): COLOR
{
	return IN.Diff;
	return float4(1,1,1,0.01);	
}


sampler Sampler = sampler_state
{
    Texture   = (Tex0);
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

float4 PS_ambient(
    float4 Diff : COLOR0,
    float4 Spec : COLOR1,
    float2 Tex  : TEXCOORD0,
    float3 Normal : TEXCOORD1 ) : COLOR
{
//	return float4(0,0,0,0);
	return tex2D(Sampler, Tex) * 0.3;
//	return float4(0.4,0,0,0.4)*Diff;
}

float4 PS(
    float4 Diff : COLOR0,
    float4 Spec : COLOR1,
    float2 Tex  : TEXCOORD0,
    float3 Normal : TEXCOORD1 ) : COLOR
{

/*	float3 light = mul(lightDir,View);
	float nldot = saturate( dot( Normal, light ) );
	Spec = pow( nldot, 16 );*/
//	Diff = float4(0,0,0,0);

	
//	return Diff;
//	return tex2D(Sampler, Tex) * ;
//	Spec *= length(c);
//	return float4(1,1,1,1);
	return tex2D(Sampler, Tex) * Diff + Spec;
}


technique Shadowed
{
	pass P0
	{
		// ambient pass
//		VertexShader = compile vs_2_0 VS_TransformAndTexture();
//		PixelShader  = compile ps_2_0 PS_Textured();
		VertexShader = compile vs_2_0 VS();
		PixelShader  = compile ps_2_0 PS_ambient();
        CullMode = none;
		StencilEnable = false;
		ZWriteEnable = true;
		ZFunc = LessEqual;
		ZEnable = true;
		TwoSidedStencilMode = false;
		AlphaBlendEnable = false;
		StencilWriteMask = 0;
		StencilFunc = Always;
	}
	
	pass P1
	{
		VertexShader = compile vs_2_0 VS_shadow();
		PixelShader  = compile ps_2_0 PS_Shadow();
		CullMode = None;
		
//		ColorWriteEnable = 0;
        AlphaBlendEnable = true;
//		SrcBlend = Zero;
		DestBlend = One;
/*	        SrcBlend = one;
        DestBlend = InvDestColor;/**/
        SrcBlend = SrcAlpha;
        
		ZWriteEnable = false;
		ZEnable = true;
		ZFunc = LessEqual;
		TwoSidedStencilMode = true;
		StencilEnable = true;
		StencilMask = 0xFFFFFFFF;
		StencilWriteMask = 0xFFFFFFFF;
		StencilRef = 1;
		Ccw_StencilFunc = Always;
		Ccw_StencilFail = Keep;
		Ccw_StencilZFail = Incr;
		Ccw_StencilPass = Keep;
		StencilFunc = Always;
		StencilFail = Keep;
		StencilZFail = Decr;
		StencilPass = Keep;
	}
	
	/*
	pass P1
	{
		VertexShader = compile vs_2_0 VS_shadow();
		PixelShader  = compile ps_2_0 PS_Shadow();
		CullMode = CW;
		
		AlphaBlendEnable = true;
		SrcBlend = Zero;
		DestBlend = One;
        
		ZWriteEnable = false;
		ZEnable = true;
		ZFunc = LessEqual;
		StencilEnable = true;
		StencilMask = 0xFFFFFFFF;
		StencilWriteMask = 0xFFFFFFFF;
		StencilRef = 1;
		StencilFunc = Always;
		StencilFail = Keep;
		StencilZFail = Incr;
		StencilPass = Keep;
	}
	pass P2
	{
		VertexShader = compile vs_2_0 VS_shadow();
		PixelShader  = compile ps_2_0 PS_Shadow();
		CullMode = CCW;
		
		AlphaBlendEnable = true;
		SrcBlend = Zero;
		DestBlend = One;
        
		ZWriteEnable = false;
		ZEnable = true;
		ZFunc = LessEqual;
		StencilEnable = true;
		StencilMask = 0xFFFFFFFF;
		StencilWriteMask = 0xFFFFFFFF;
		StencilRef = 0;
		StencilFunc = Always;
		StencilFail = Keep;
		StencilZFail = Decr;
		StencilPass = Keep;
	}
*/
	pass P3
	{
		VertexShader = compile vs_2_0 VS();
		PixelShader  = compile ps_2_0 PS();
		CullMode = CCW;
		ColorWriteEnable = 0xFFFFFFFF;
		
		ZEnable = true;
//		ZWriteEnable = false;
		ZFunc = Equal;
		StencilEnable = true;
		AlphaBlendEnable = true;
		BlendOp = Add;
		SrcBlend = One;
		DestBlend = One;
		StencilRef = 0;
		StencilFunc = Equal;
//		StencilFunc = GreaterEqual;
		StencilPass = Keep;
		StencilZFail = Keep;
		StencilFail = Keep;
	}
	
}

	

technique TVertexAndPixelShader
{
    pass P0
    {
        // shaders
        VertexShader = compile vs_2_0 VS();
        PixelShader  = compile ps_2_0 PS();
    }  
}
