//By EVOLVED
//www.evolved-software.com

//Un-Tweaks
   float4x4 World : World;
   float4x4 WorldVP : WorldViewProjection; 
   float4x4 ViewInv : ViewInverse;

//Tweaks
   float3 AmbientColor;
   float3 LightPosition;
   float3 LightColor;
   float LightRange;
   float HeightVal = 0.0025;

//Textures
   texture BaseTexture <string Name = "";>;	
   sampler BaseSampler = sampler_state 
      {
 	Texture = <BaseTexture>;
  	MagFilter = anisotropic;
	MinFilter = anisotropic;
	MipFilter = anisotropic;
	MaxAnisotropy = 8;
      };
   texture NormalMapTexture <string Name = "";>;
   sampler NormalMapSampler = sampler_state 
      {
 	Texture = <NormalMapTexture>;
  	MagFilter = anisotropic;
	MinFilter = anisotropic;
	MipFilter = anisotropic;
	MaxAnisotropy = 8;
      };
   texture HeightMapTexture <string Name = "";>;	
   sampler HeightMapSampler = sampler_state 
      {
 	Texture = <HeightMapTexture>;
  	MagFilter = anisotropic;
	MinFilter = anisotropic;
	MipFilter = anisotropic;
	MaxAnisotropy = 8;
      };

//Structs 
   struct Input
     {
 	float4 Pos : POSITION;
    	float2 UV : TEXCOORD; 
 	float3 Normal : NORMAL;
 	float3 Tangent : TANGENT;
     };
   struct Output
     {
 	float4 Pos : POSITION;
	float2 Tex : TEXCOORD0;
  	float3 TBNRow1 : TEXCOORD1; 
  	float3 TBNRow2 : TEXCOORD2; 
  	float3 TBNRow3 : TEXCOORD3;
 	float3 WorldPos : TEXCOORD4;
 	float3 ViewVec : TEXCOORD5;
 	float3 ViewDir : TEXCOORD6;
     };

//Vertex Shader
   Output VS(Input IN) 
      {
 	Output OUT;
	OUT.Pos = mul(IN.Pos, WorldVP);
 	OUT.Tex = IN.UV;
	float3 Normals = normalize(mul(IN.Normal, World)); 
	float3 Tangent = normalize(mul(IN.Tangent, World));
	OUT.TBNRow1 = Tangent;
	OUT.TBNRow2 = cross(Normals, Tangent);
	OUT.TBNRow3 = Normals;
	OUT.WorldPos = mul(IN.Pos, World); 
	OUT.ViewVec = ViewInv[3].xyz-OUT.WorldPos; 
	float3x3 WorldTBN = float3x3(OUT.TBNRow1, OUT.TBNRow2, OUT.TBNRow3);
	OUT.ViewDir = mul(OUT.ViewVec, transpose(WorldTBN));
	return OUT;
      }
 
//Pixel Shader
   float4 PS(Output IN)  : COLOR
      {
	float3 ViewDir = normalize(IN.ViewDir);
	ViewDir.xy = (ViewDir.xy/-ViewDir.z)*HeightVal;
        float Depth = 1.0-tex2D(HeightMapSampler, IN.Tex);
        float Height = 0.0;
        float Inc = 1.0/16.0;
	float2 Displace = IN.Tex;
        for(int i = 0; i < 16; i++ ) 
         {
          if(Height < Depth) 
           {
            Displace += ViewDir;
            Depth = 1.0-tex2D(HeightMapSampler, Displace);
            Height += Inc;
           }
        }
        float Weight = (1.0-tex2D(HeightMapSampler, Displace-ViewDir))-Height+Inc;  
        Weight = (Depth-Height)/((Depth-Height)-Weight);
        Displace = lerp(Displace, Displace-ViewDir, Weight);
	float3 Surface = pow(tex2D(BaseSampler, Displace), 2.2); 
	float3 NormalMap = tex2D(NormalMapSampler, Displace)*2.0-1.0;
	float3x3 WorldTBN = float3x3(IN.TBNRow1, IN.TBNRow2, IN.TBNRow3);
	float3 Normals = normalize(mul(NormalMap, WorldTBN));
	float3 ViewVec = normalize(IN.ViewVec);
	float3 LightVec = LightPosition-IN.WorldPos;
	float Attenuation = length(LightVec);
	LightVec /= Attenuation;
	float3 HalfVec = normalize(LightVec+ViewVec);
	float Light = max(dot(LightVec, Normals), 0.0);
	float Specular = pow(max(dot(HalfVec, Normals), 0.0), 64.0)*Light*2.0;
	float3 LightingColor = LightColor*(Light+Specular)*max(1.0/(Attenuation/LightRange)-1.0, 0.0);
	return float4(pow(Surface*(AmbientColor+LightingColor), 0.4545)*0.5, 1.0);
      }

//Techniques   
   technique Lighting
      {
 	pass p1
      {
 	vertexShader = compile vs_3_0 VS();
 	pixelShader  = compile ps_3_0 PS();
      }
      }
