/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 LightView;
float4x4 LightProjection;
static const float SHADOW_EPSILON = 0.0005f;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float g_fRandom;
float g_fAlpha;
float3 EyePos;
float3 g_LightPos;
float3 g_LightColor;
float3 g_ShadowColor;
float3 g_Color;
float FrameDivide;
float g_Shadows;
float g_fReflection;

float g_WaterX;
float g_WaterZ;

int FrameX;
int FrameY;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct VertexOut
{
    float4 Pos      : POSITION;
    float3 Normal    : TEXCOORD0;
    float2 TexUV     : TEXCOORD1;
    float3 toEyeT    : TEXCOORD2;
    float3 lightDirT : TEXCOORD3;
    float3 toEyeL    : TEXCOORD4;
    float3 lightDirL : TEXCOORD5;
    float4 projtex   : TEXCOORD6;
    float2 Depth     : TEXCOORD7;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
texture g_MeshTexture;
sampler MeshTextureSampler = sampler_state
{
    Texture = <g_MeshTexture>;
    MinFilter = NONE;
    MagFilter = NONE;
    AddressU = WRAP;
    AddressV = WRAP;
};
texture g_MeshTexture2;
sampler MeshTextureSampler2 = sampler_state
{
    Texture = <g_MeshTexture2>;
    MinFilter = NONE;
    MagFilter = NONE;
    MipFilter = NONE;
    AddressU = WRAP;
    AddressV = WRAP;
};
texture g_HudTexture;
sampler HudTextureSampler = sampler_state
{
    Texture = <g_HudTexture>;
    MinFilter = POINT;
    MagFilter = POINT;
    AddressU = CLAMP;
    AddressV = CLAMP;
};
texture g_EnvMap;
sampler EnvMapSampler = sampler_state
{
    Texture = <g_EnvMap>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};
texture g_ShadowMap;
sampler ShadowMapSampler = sampler_state
{
    Texture = <g_ShadowMap>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = POINT;
    AddressU = CLAMP;
    AddressV = CLAMP;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
VertexOut StandardVS(float4 Pos : POSITION,      float3 Normal : NORMAL, float2 tex : TEXCOORD0,
		     float3 tangentL : TANGENT0, float3 binormalL : BINORMAL0)
{
	VertexOut Vert = (VertexOut)0;
	
	float4x4 Transform;
	Pos = mul(Pos, World);

	Normal = normalize(mul(Normal, World));
	tangentL = normalize(mul(tangentL,World));
	binormalL = normalize(mul(binormalL,World));

	Vert.Normal = Normal;
	Transform = mul(LightView, LightProjection);
	Vert.projtex = mul(Pos, Transform);		

	Transform = mul(View, Projection);
	Vert.Pos = mul(Pos, Transform);
        Vert.Depth = Vert.Pos.zw;

	tex.x /= FrameDivide;
	tex.y /= FrameDivide;
	tex.x += (1/FrameDivide) * FrameX;
	tex.y += (1/FrameDivide) * FrameY;
	Vert.TexUV = tex;

	float3x3 TBN;
	TBN[0] = tangentL;
	TBN[1] = binormalL;
	TBN[2] = Normal;
		
	float3x3 toTangentSpace = transpose(TBN);

	float3 toEyeL = normalize(EyePos - Pos);
	Vert.toEyeL = toEyeL;
	Vert.toEyeT = mul(toEyeL, toTangentSpace);
	float3 lightDirL = normalize(g_LightPos - Pos);
	Vert.lightDirL = lightDirL;
	Vert.lightDirT = normalize(mul(lightDirL, toTangentSpace));
	
	return Vert;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroPlusPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	// shadow projection //
	float2 ShadowTexC = 0.5 * (ProjTex.xy / ProjTex.w) + float2( 0.5, 0.5 );
	ShadowTexC.y = 1.0f - ShadowTexC.y;
	float2 texelpos = 1024 * ShadowTexC;
   	float s0 = (tex2D(ShadowMapSampler, ShadowTexC.xy).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s1 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,0)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;
	float s2 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(0,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s3 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float LightAmount = lerp( lerp(s0,s1,frac(texelpos.x)),
				  lerp(s2,s3,frac(texelpos.x)),
				  frac(texelpos.y));
	
	// Fade Shadows //
	LightAmount = min(1,LightAmount+g_Shadows);
	LightAmount += max(((Depth.x-300)/(Depth.y/2)),0);
	LightAmount = min(max(LightAmount,0),1);

	// Normal Calculations //
	float intensityL = dot(lightDirL, normalW);

	float4 Texture = tex2D(MeshTextureSampler,texuv);

	// Lit Surface //
	float3 Highlight = max((LightAmount * intensityL),0);
	Highlight *= g_LightColor;
	
	// Depth //
	//float DepthColor = max(min((Depth.x-100)/(Depth.y*1.05f),1),0); 

	// Shadow Surface //
	float3 Shaded = min((1-intensityL) + (1-LightAmount),1);
	Shaded *= g_ShadowColor;
	
	Texture.rgb = (Highlight+Shaded) * Texture.rgb;
	Texture.a *= g_fAlpha;
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroPlusDistPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	// shadow projection //
	float2 ShadowTexC = 0.5 * (ProjTex.xy / ProjTex.w) + float2( 0.5, 0.5 );
	ShadowTexC.y = 1.0f - ShadowTexC.y;
	float2 texelpos = 1024 * ShadowTexC;
   	float s0 = (tex2D(ShadowMapSampler, ShadowTexC.xy).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s1 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,0)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;
	float s2 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(0,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s3 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float LightAmount = lerp( lerp(s0,s1,frac(texelpos.x)),
				  lerp(s2,s3,frac(texelpos.x)),
				  frac(texelpos.y));
	
	// Fade Shadows //
	LightAmount = min(1,LightAmount+g_Shadows);
	LightAmount += max(((Depth.x-300)/(Depth.y/2)),0);
	LightAmount = min(max(LightAmount,0),1);

	// Normal Calculations //
	float intensityL = dot(lightDirL, normalW);

	float4 Texture = tex2D(MeshTextureSampler2,texuv);

	// Lit Surface //
	float3 Highlight = max((LightAmount * intensityL),0);
	Highlight *= g_LightColor;
	
	// Depth //
	//float DepthColor = max(min((Depth.x-100)/(Depth.y*1.05f),1),0); 

	// Shadow Surface //
	float3 Shaded = min((1-intensityL) + (1-LightAmount),1);
	Shaded *= g_ShadowColor;
	
	Texture.rgb = (Highlight+Shaded) * Texture.rgb;
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroStreetWetPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	// shadow projection //
	float2 ShadowTexC = 0.5 * (ProjTex.xy / ProjTex.w) + float2( 0.5, 0.5 );
	ShadowTexC.y = 1.0f - ShadowTexC.y;
	float2 texelpos = 1024 * ShadowTexC;
   	float s0 = (tex2D(ShadowMapSampler, ShadowTexC.xy).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s1 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,0)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;
	float s2 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(0,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s3 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float LightAmount = lerp( lerp(s0,s1,frac(texelpos.x)),
				  lerp(s2,s3,frac(texelpos.x)),
				  frac(texelpos.y));
	
	// Fade Shadows //
	LightAmount = min(1,LightAmount+g_Shadows);
	LightAmount += max(((Depth.x-300)/(Depth.y/2)),0);
	LightAmount = min(max(LightAmount,0),1);

	// Normal Calculations //
	float intensityL = dot(lightDirL, normalW);

	float4 Texture = tex2D(MeshTextureSampler,texuv);

	// reflection //
	float3 envMapTex = reflect(toEyeL,normalW) + (Texture.rgb)/2;
	float3 reflectColor = texCUBE(EnvMapSampler, envMapTex)*g_fReflection;
	Texture.rgb -= g_fReflection;
	Texture.rgb += reflectColor;

	// Lit Surface //
	float3 Highlight = max((LightAmount * intensityL),0);
	Highlight *= g_LightColor;
	
	// Shadow Surface //
	float3 Shaded = min((1-intensityL) + (1-LightAmount),1);
	Shaded *= g_ShadowColor;

	Texture.rgb = (Highlight+Shaded) * Texture.rgb;

	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroBuildingPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	float4 Texture = tex2D(MeshTextureSampler,texuv);
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroHitPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	float4 Texture = tex2D(MeshTextureSampler,texuv);
	Texture.rgb *= float3(2,0.3,0.3);
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroCleanPS(float3 normalW   : TEXCOORD0,
			float3 texuv     : TEXCOORD1) : COLOR
{
	float4 Texture = tex2D(MeshTextureSampler2,texuv);
	Texture.rgb *= g_LightColor;
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroEffectPS(float3 texuv     : TEXCOORD1) : COLOR
{
	float4 Texture = tex2D(MeshTextureSampler,texuv);
	if (Texture.r == 0 && Texture.g == 0 && Texture.b == 0)
	{	
	Texture.r = 1-Texture.r;
	Texture.g = 1-Texture.g;
	Texture.b = 1-Texture.b;
	}
	Texture.rgb = (Texture.r + Texture.g + Texture.b)/3;
	Texture.rgb *= (g_Color*1);
	Texture.rgb *= g_fAlpha*2;
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroWaterPS(float3 normalW   : TEXCOORD0,
		float3 texuv     : TEXCOORD1,
		float3 toEyeT    : TEXCOORD2,
		float3 lightDirT : TEXCOORD3,
		float3 toEyeL    : TEXCOORD4,
		float3 lightDirL : TEXCOORD5,
		float4 ProjTex   : TEXCOORD6,
		float2 Depth     : TEXCOORD7) : COLOR
{
	// shadow projection //
	float2 ShadowTexC = 0.5 * (ProjTex.xy / ProjTex.w) + float2( 0.5, 0.5 );
	ShadowTexC.y = 1.0f - ShadowTexC.y;
	float2 texelpos = 1024 * ShadowTexC;
   	float s0 = (tex2D(ShadowMapSampler, ShadowTexC.xy).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s1 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,0)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;
	float s2 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(0,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float s3 = (tex2D(ShadowMapSampler, ShadowTexC.xy + float2(1.0f/1024,1.0f/1024)).r + SHADOW_EPSILON < (ProjTex.z / ProjTex.w)) ? 0.0f : 1.0f;		
	float LightAmount = lerp( lerp(s0,s1,frac(texelpos.x)),
				  lerp(s2,s3,frac(texelpos.x)),
				  frac(texelpos.y));

	// Fade Shadows //
	LightAmount = min(1,LightAmount+g_Shadows);
	LightAmount += max(((Depth.x-300)/(Depth.y/2)),0);
	LightAmount = min(max(LightAmount,0),1);

	float2 UV1 = texuv.xy;
	float2 UV2 = texuv.xy;
	UV1.x += g_WaterX;
	UV2.y += g_WaterZ;
	UV1.xy *= 50;
	UV2.xy *= 50;
	float4 Texture = tex2D(MeshTextureSampler,UV1);
	Texture += tex2D(MeshTextureSampler,UV2);
	float3 Shade = Texture / 2;
	Texture.rgb *= LightAmount;
	Texture.rgb += (1-LightAmount) * Shade;

	Texture.a = 0.7f;
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 RetroWaterFloorPS(float3 texuv     : TEXCOORD1) : COLOR
{
	float2 UV1 = texuv.xy;
	float2 UV2 = texuv.xy;
	UV1.xy *= 50;
	UV2.xy *= 50;
	float4 Texture = tex2D(MeshTextureSampler,UV1);
	return float4(Texture);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 HudPS(float2 Tex : TEXCOORD0 ) : COLOR
{
    float4 SceneColor;
    SceneColor.rgb = tex2D(HudTextureSampler, Tex.xy).rgb;
    SceneColor.a = (SceneColor.r + SceneColor.g + SceneColor.b) / 2;
    SceneColor.a *= g_fAlpha;
    return float4(SceneColor);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 HudPSAlpha(float2 Tex : TEXCOORD0 ) : COLOR
{
    float4 SceneColor; 
    SceneColor = tex2D(HudTextureSampler, Tex.xy);
    SceneColor.a *= g_fAlpha;
    return float4(SceneColor);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
float4 HudPSEffect(float2 Tex : TEXCOORD0 ) : COLOR
{
    float4 SceneColor; 
    SceneColor = tex2D(HudTextureSampler, Tex.xy);
    SceneColor.rgb += g_Color.rgb;
    SceneColor.a *= g_fAlpha;
    SceneColor.a = max(SceneColor.a,0);
    return float4(SceneColor);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
technique Retro
{  
   pass P0 // USED AS DEFAULT
   {
	PixelShader = compile ps_2_0 RetroPlusPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
   pass P1 // USED FOR GETTING HIT
   {
	PixelShader = compile ps_2_0 RetroHitPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
   pass P2 // USED FOR OUTLINE
   {
	PixelShader = compile ps_2_0 RetroEffectPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaBlendEnable = TRUE;
	ZWriteEnable = FALSE;
	SrcBlend = SrcColor;
	DestBlend = One;
	
   }
   pass P3 // USED FOR ECHO
   {
	PixelShader = compile ps_2_0 RetroEffectPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaBlendEnable = TRUE;
	ZWriteEnable = FALSE;
	SrcBlend = SrcColor;
	DestBlend = One;
   }
   pass P4 // USED FOR BACKGROUND
   {
	PixelShader = compile ps_2_0 RetroCleanPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = TRUE;
	ZWriteEnable = TRUE;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
	SrcBlend = SrcAlpha;
	DestBlend = InvSrcAlpha;
   }
   pass P5 // USED FOR BUILDINGS
   {
	PixelShader = compile ps_2_0 RetroBuildingPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
   pass P6 // USED FOR WETSTREETS
   {
	PixelShader = compile ps_2_0 RetroStreetWetPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
  pass P7 // USED FOR BUILDINGS AT A DISTANCE
   {
	PixelShader = compile ps_2_0 RetroPlusDistPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
 pass P8 // WATER
   {
	PixelShader = compile ps_2_0 RetroWaterPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaBlendEnable = TRUE;
	ZWriteEnable = FALSE;
	SrcBlend = SrcColor;
	DestBlend = DestColor;
   }
 pass P9 // WATER - FLOOR
   {
	PixelShader = compile ps_2_0 RetroWaterFloorPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaTestEnable = true;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
	CullMode = CCW;
   }
 pass P10 // USED TO FADE IN/OUT OBJS
   {
	PixelShader = compile ps_2_0 RetroPlusPS();
        VertexShader = compile vs_2_0 StandardVS();
	AlphaBlendEnable = true;
	SrcBlend = SrcAlpha;
	DestBlend = InvSrcAlpha;
	CullMode = CCW;
   }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
technique HUDTechnique
{  
    pass P0 // RGB COMBO ALPHA
    {
        //VertexShader = compile vs_2_0 StandardVS();
	PixelShader = compile ps_2_0 HudPS();
	AlphaTestEnable = true;
	AlphaBlendEnable = FALSE;
	AlphaRef = 100;
	AlphaFunc = GreaterEqual;
    }
    pass P1 // DDS ALPHA
    {
        //VertexShader = compile vs_2_0 StandardVS();
	PixelShader = compile ps_2_0 HudPSAlpha();
	//AlphaTestEnable = true;
 	AlphaBlendEnable = true;
	//AlphaRef = 100;
	//AlphaFunc = GreaterEqual;
    }
   pass P2 // DDS EFFECT
    {
        //VertexShader = compile vs_2_0 StandardVS();
	PixelShader = compile ps_2_0 HudPSEffect();
	//AlphaTestEnable = true;
 	AlphaBlendEnable = true;
	//AlphaRef = 100;
	//AlphaFunc = GreaterEqual;
    }
}