float4x4 worldViewProj : WorldViewProjection;
float4x4 viewProj : ViewProjection;
float4x4 world : World;

#define BONEMODE_4x3 1

#include "..\generic.fx"
#include "..\mrt.fx"
#include "..\GameLights.fx"



float2 UVTranslate : UVTranslate;
float2 UVTranslate2ndLayer : UVTranslate2ndLayer;

float2 UVScale : UVScale;
float2 UVScale2ndLayer : UVScale2ndLayer;

float NormalScale :NormalScale;
float NormalScale2ndLayer :NormalScale2ndLayer;
float NormalAddScale : NormalAddScale;

float LayerBlend : LayerBlend;
float FinalColorModulate : FinalColorModulate;

float ReflectionOpacity : ReflectionOpacity;
float ReflectionDistortion : ReflectionDistortion;


float4 LightColor : LightColor;
float4 MidColor : MidColor;
float4 DarkColor : DarkColor;
    
float ColorMidpoint : ColorMidpoint;

float SpecularPower : SpecularPower;
float SpecularIntensity : SpecularIntensity;

float FresnelModulate : FresnelModulate;
float FresnelIndex : FresnelIndex;
float FresnelExponent : FresnelExponent;


texture MyDiffuseTexture : MyDiffuseTexture;
sampler DiffuseTextureSampler = sampler_state 
{
    texture = <MyDiffuseTexture>;
    AddressU  = WRAP;        
    AddressV  = WRAP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


texture bumpTexture : BumpTexture;
sampler BumpTextureSampler = sampler_state 
{
    texture = <bumpTexture>;
    AddressU  = WRAP;        
    AddressV  = WRAP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


texture NormalAddTexture : NormalAddTexture;
sampler NormalAddTextureSampler = sampler_state 
{
    texture = <NormalAddTexture>;
    AddressU  = WRAP;        
    AddressV  = WRAP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

texture ReflectionTexture : ReflectionTexture;
sampler ReflectionTextureSampler = sampler_state 
{
    texture = <ReflectionTexture>;
    AddressU  = CLAMP;
    AddressV  = CLAMP;
    AddressW  = CLAMP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


textureCUBE envTexture : EnvironmentTexture;
samplerCUBE EnvTextureSampler = sampler_state 
{
    texture = <envTexture>;
    AddressU  = CLAMP;        
    AddressV  = CLAMP;
    AddressW  = CLAMP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


float3 campos : CAMERAPOS;

struct vertexInputBoned {
    float4 position				: POSITION;
    float3 normal				: NORMAL;
    float2 texCoordDiffuse		: TEXCOORD0;
    float4 boneids              : BLENDINDICES;
    float4 boneweights          : BLENDWEIGHT;
    float4 tangent              : TANGENT;
};

struct vertexInputUnboned {
    float4 position				: POSITION;
    float3 normal				: NORMAL;
    float2 texCoordDiffuse		: TEXCOORD0;
    float4 tangent              : TANGENT;
};

struct vertexOutput {
    float4 hPosition		: POSITION;
    float2 texCoordDiffuse	: TEXCOORD0;
    float3 posWorld         : TEXCOORD1;
    float3 normWorld        : TEXCOORD2;
    float4 tanWorld         : TEXCOORD3;
    float4 screenPos        : TEXCOORD4;
};

vertexOutput VS_Shared(float4 pos, float3 norm, float3 tang, float tangw, float2 uv)
{
    vertexOutput OUT;

    OUT.normWorld = norm;
    OUT.posWorld = pos;
    OUT.tanWorld = float4(tang, tangw);
    OUT.texCoordDiffuse = uv;
    OUT.hPosition = mul( pos , viewProj);
    OUT.screenPos = mul( pos , viewProj);
    return OUT;
}

vertexOutput VS_TransformBoned(vertexInputBoned IN) 
{
    float4 pos;
    float3 norm;
    float3 tang;
    float weight4;
    weight4 = 1 - dot(IN.boneweights.xyz, float3(1,1,1));
    float4 weights = float4(IN.boneweights.xyz, weight4);
    
    float4 boneids = VS_ScaleBoneIDsFromD3DCOLOR(IN.boneids);
    VS_TransformBonesPNT_4(IN.position, pos, IN.normal, norm, IN.tangent, tang, boneids, weights, world);
    return VS_Shared(pos, norm, tang, IN.tangent.w, IN.texCoordDiffuse);
}

vertexOutput VS_TransformUnboned(vertexInputUnboned IN) 
{
    float4 pos;
    float3 norm;
    float3 tang;
    
    pos = mul(IN.position, world);
    norm = mul(IN.normal, world);
    tang = mul(IN.tangent.xyz, world);
    return VS_Shared(pos, norm, tang, IN.tangent.w, IN.texCoordDiffuse);
}


// Fresnel effect
void DoFresnel( inout float3 inOutColor, in float3 posWorld, in float3 normalWorld )
{
    
    float3 toCam = campos/10000 - posWorld/10000;  // floats out of range
    float nDotV = saturate( dot( normalize(normalWorld), normalize(toCam) ));
    
    float fresnel = FresnelIndex + (1.0f - FresnelIndex ) * pow( (1 - nDotV ), FresnelExponent);
    fresnel = saturate( fresnel );    

	// should be 2 techniques
	if( FresnelModulate < 0.0f )
    	inOutColor = lerp( inOutColor, inOutColor * (1-fresnel), -FresnelModulate );
   	else
   		inOutColor = lerp( inOutColor, inOutColor * fresnel, FresnelModulate );
     
}


PS_OUTPUT PS_TexturedNoSpecular( vertexOutput IN)
{
	matSettings.Reflectivity = 1;

	float3x3 tanmat;
	tanmat[0] = normalize(IN.tanWorld.xyz);
	tanmat[2] = normalize(IN.normWorld);
	tanmat[1] = normalize(cross(tanmat[2], tanmat[0])) * IN.tanWorld.w;

    float2 uvs = IN.texCoordDiffuse + UVTranslate;
    uvs *= UVScale;
    
    float2 uvs2ndLayer = IN.texCoordDiffuse + UVTranslate2ndLayer;
    uvs2ndLayer *= UVScale2ndLayer;

    float4 normalTexture = tex2D( BumpTextureSampler, uvs ) * 2 - 1;
    normalTexture.xy *= NormalScale;
    float3 normalWorld = mul(normalTexture.xyz, tanmat);
    normalWorld = normalize(normalWorld);

    float4 normalTexture2 = tex2D( BumpTextureSampler, uvs2ndLayer ) * 2 - 1;
    normalTexture2.xy *= NormalScale2ndLayer;
    float3 normalWorld2 = mul(normalTexture2.xyz, tanmat);
    normalWorld2 = normalize(normalWorld2);
    
    normalWorld = lerp( normalWorld, normalWorld2, LayerBlend );

    float3 eyeVecW = campos - IN.posWorld.xyz;
    float3 reflection = reflect(-eyeVecW, normalWorld);
    float4 envTex; // = texCUBE(EnvTextureSampler, reflection);

	float4 baseDiffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse ); 
    float4 diffuseTexture = tex2D( DiffuseTextureSampler, uvs );
    float4 diffuseTexture2 = tex2D( DiffuseTextureSampler, uvs2ndLayer );
    
    diffuseTexture =  lerp( diffuseTexture, diffuseTexture2, LayerBlend );
    
	diffuseTexture.xyz = lerp( LightColor, MidColor, min(1, diffuseTexture.x/ColorMidpoint) );
 	diffuseTexture.xyz = lerp( diffuseTexture.xyz, DarkColor, max(0, (diffuseTexture.x-ColorMidpoint)/(1.0f-ColorMidpoint)) );
   

    diffuseTexture.a = 1.0f;
    diffuseTexture *= LightColor.a;

	float2 reflectUV = (IN.screenPos.xy / (2*IN.screenPos.w) ) + 0.5f;

    reflectUV += (normalTexture.xy + normalTexture2.xy) * ReflectionDistortion; 
    float4 reflectionTexture = tex2D( ReflectionTextureSampler, reflectUV );
 
    float3 colorSum = 0;
    float3 specularSum = 0;
	AddLightsNoSpec(normalWorld, IN.posWorld, colorSum );
	
    float4 outColor;

	colorSum += matSettings.Ambient + ambientLevel;
    outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor.xyz += matSettings.Emissive;
    outColor.xyz *= colorSum * outColor.w;
    outColor.xyz += matSettings.Diffuse_Opacity* matSettings.Reflectivity * (specularSum * float3(60.4, 60.4, 60.4)/*matSettings.Specular_Power.xyz*/);
    
    outColor.xyz = lerp( outColor.xyz, reflectionTexture, ReflectionOpacity );    
    outColor.xyz *= FinalColorModulate;
       
   	outColor *= baseDiffuse.a; // puddles -> use alpha channel if present
   	
   	
    PS_OUTPUT Out;
    SetPSOutput( Out, outColor, float4( campos - IN.posWorld.xyz, 1) );
    return Out;
}

PS_OUTPUT PS_TexturedSpecular( vertexOutput IN)
{
	matSettings.Reflectivity = 1;

	float3x3 tanmat;
	tanmat[0] = normalize(IN.tanWorld.xyz);
	tanmat[2] = normalize(IN.normWorld);
	tanmat[1] = normalize(cross(tanmat[2], tanmat[0])) * IN.tanWorld.w;

    float2 uvs = IN.texCoordDiffuse + UVTranslate;
    uvs *= UVScale;
    
    float2 uvs2ndLayer = IN.texCoordDiffuse + UVTranslate2ndLayer;
    uvs2ndLayer *= UVScale2ndLayer;

    float4 normalTexture = tex2D( BumpTextureSampler, uvs ) * 2 - 1;
    normalTexture.xy *= NormalScale;
    float3 normalWorld = mul(normalTexture.xyz, tanmat);
    normalWorld = normalize(normalWorld);

    float4 normalTexture2 = tex2D( BumpTextureSampler, uvs2ndLayer ) * 2 - 1;
    normalTexture2.xy *= NormalScale2ndLayer;
    float3 normalWorld2 = mul(normalTexture2.xyz, tanmat);
    normalWorld2 = normalize(normalWorld2);
    
    normalWorld = lerp( normalWorld, normalWorld2, LayerBlend );

    float3 eyeVecW = campos - IN.posWorld.xyz;
    float3 reflection = reflect(-eyeVecW, normalWorld);
    float4 envTex; // = texCUBE(EnvTextureSampler, reflection);

	float4 baseDiffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse ); 
    float4 diffuseTexture = tex2D( DiffuseTextureSampler, uvs );
    float4 diffuseTexture2 = tex2D( DiffuseTextureSampler, uvs2ndLayer );
    
    diffuseTexture =  lerp( diffuseTexture, diffuseTexture2, LayerBlend );

    diffuseTexture.xyz = lerp( LightColor, MidColor, min(1, diffuseTexture.x/ColorMidpoint) );
 	diffuseTexture.xyz = lerp( diffuseTexture.xyz, DarkColor, max(0, (diffuseTexture.x-ColorMidpoint)/(1.0f-ColorMidpoint)) );
   

    diffuseTexture.a = 1.0f;
    diffuseTexture *= LightColor.a;

	float2 reflectUV = (IN.screenPos.xy / (2*IN.screenPos.w) ) + 0.5f;

    reflectUV += (normalTexture.xy + normalTexture2.xy) * ReflectionDistortion; 
    //float2 delta = (normalTexture.xy) * 0.2 * ReflectionDistortion;
    //reflectUV += float2( delta.x, -abs( delta.y ) );
    
    float4 reflectionTexture = tex2D( ReflectionTextureSampler, reflectUV );

    float3 colorSum = 0;
    float3 specularSum = 0;
	AddLights(normalWorld, IN.posWorld, colorSum, SpecularPower, eyeVecW, specularSum);
	
    float4 outColor;

	colorSum += matSettings.Ambient + ambientLevel;
    outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor.xyz += matSettings.Emissive;
    outColor.xyz *= colorSum * outColor.w;
    outColor.xyz += matSettings.Diffuse_Opacity* matSettings.Reflectivity * (specularSum * float3(60.4, 60.4, 60.4)/*matSettings.Specular_Power.xyz*/);
    
    outColor.xyz = lerp( outColor.xyz, reflectionTexture, ReflectionOpacity );    
    outColor.xyz *= FinalColorModulate;
       
   	outColor *= baseDiffuse.a; // puddles -> use alpha channel if present
    
     PS_OUTPUT Out;
    SetPSOutput( Out, outColor, float4( campos - IN.posWorld.xyz, 1) );
    return Out;
}


PS_OUTPUT PS_TexturedCubemap( vertexOutput IN)
{
	matSettings.Reflectivity = 1;

	float3x3 tanmat;
	tanmat[0] = normalize(IN.tanWorld.xyz);
	tanmat[2] = normalize(IN.normWorld);
	tanmat[1] = normalize(cross(tanmat[2], tanmat[0])) * IN.tanWorld.w;

    float2 uvs = IN.texCoordDiffuse + UVTranslate;
    uvs *= UVScale;
    
    float2 uvs2ndLayer = IN.texCoordDiffuse + UVTranslate2ndLayer;
    uvs2ndLayer *= UVScale2ndLayer;

    float4 normalTexture = tex2D( BumpTextureSampler, uvs ) * 2 - 1;
    normalTexture.xy *= NormalScale;
    float3 normalWorld = mul(normalTexture.xyz, tanmat);
    normalWorld = normalize(normalWorld);

    float4 normalTexture2 = tex2D( BumpTextureSampler, uvs2ndLayer ) * 2 - 1;
    normalTexture2.xy *= NormalScale2ndLayer;
    float3 normalWorld2 = mul(normalTexture2.xyz, tanmat);
    normalWorld2 = normalize(normalWorld2);
    
    normalWorld = lerp( normalWorld, normalWorld2, LayerBlend );

    float3 eyeVecW = campos - IN.posWorld.xyz;
    float3 reflection = reflect(-eyeVecW, normalWorld);
  
	float4 baseDiffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse ); 
    float4 diffuseTexture = tex2D( DiffuseTextureSampler, uvs );
    float4 diffuseTexture2 = tex2D( DiffuseTextureSampler, uvs2ndLayer );
    
    diffuseTexture =  lerp( diffuseTexture, diffuseTexture2, LayerBlend );

    diffuseTexture.xyz = lerp( LightColor, MidColor, min(1, diffuseTexture.x/ColorMidpoint) );
 	diffuseTexture.xyz = lerp( diffuseTexture.xyz, DarkColor, max(0, (diffuseTexture.x-ColorMidpoint)/(1.0f-ColorMidpoint)) );
   
    diffuseTexture.a = 1.0f;
    diffuseTexture *= LightColor.a;

	float2 reflectUV = (IN.screenPos.xy / (2*IN.screenPos.w) ) + 0.5f;

 	 float4 envTex = texCUBE(EnvTextureSampler, reflection);

    float3 colorSum = 0;
    float3 specularSum = 0;
	AddLights(normalWorld, IN.posWorld, colorSum, SpecularPower, eyeVecW, specularSum);
	
    float4 outColor;

	colorSum += matSettings.Ambient + ambientLevel;
    outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor.xyz += matSettings.Emissive;
    outColor.xyz *= colorSum * outColor.w;
    outColor.xyz += matSettings.Diffuse_Opacity* matSettings.Reflectivity * (specularSum * SpecularIntensity /*matSettings.Specular_Power.xyz*/);
    
    outColor.xyz = lerp( outColor.xyz, envTex, ReflectionOpacity );    
    outColor.xyz *= FinalColorModulate;
       
   	outColor *= baseDiffuse.a; // puddles -> use alpha channel if present
    
    DoFresnel( outColor.xyz, IN.posWorld, normalWorld );
    
    PS_OUTPUT Out;
    SetPSOutput( Out, outColor, float4( campos - IN.posWorld.xyz, 1) );
    return Out;
}

PS_OUTPUT PS_TexturedAddNormal( vertexOutput IN)
{
	matSettings.Reflectivity = 1;

	float3x3 tanmat;
	tanmat[0] = normalize(IN.tanWorld.xyz);
	tanmat[2] = normalize(IN.normWorld);
	tanmat[1] = normalize(cross(tanmat[2], tanmat[0])) * IN.tanWorld.w;

    float2 uvs = IN.texCoordDiffuse + UVTranslate;
    uvs *= UVScale;
    
    float2 uvs2ndLayer = IN.texCoordDiffuse + UVTranslate2ndLayer;
    uvs2ndLayer *= UVScale2ndLayer;

    float4 normalTexture = tex2D( BumpTextureSampler, uvs ) * 2 - 1;
    
   
   // float4 normalTextureAdd = tex2D( NormalAddTextureSampler, IN.texCoordDiffuse ) * 2 - 1;
    float4 normalTextureAdd = tex2D( NormalAddTextureSampler, IN.texCoordDiffuse ) * 2;
    normalTextureAdd -= (1/255.0f);
      
    normalTexture.xy *= NormalScale; 
    normalTextureAdd.xy *= NormalAddScale;    
    normalTexture += normalTextureAdd;
    
    
    float3 normalWorld = mul(normalTexture.xyz, tanmat);
    normalWorld = normalize(normalWorld);

    float4 normalTexture2 = tex2D( BumpTextureSampler, uvs2ndLayer ) * 2 - 1;
    normalTexture2.xy *= NormalScale2ndLayer;
    float3 normalWorld2 = mul(normalTexture2.xyz, tanmat);
    normalWorld2 = normalize(normalWorld2);

	
    normalWorld = lerp( normalWorld, normalWorld2, LayerBlend );
    
    float3 eyeVecW = campos - IN.posWorld.xyz;
    float3 reflection = reflect(-eyeVecW, normalWorld);
    float4 envTex; // = texCUBE(EnvTextureSampler, reflection);

	float4 baseDiffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse ); 
    float4 diffuseTexture = tex2D( DiffuseTextureSampler, uvs );
    float4 diffuseTexture2 = tex2D( DiffuseTextureSampler, uvs2ndLayer );
    
    diffuseTexture =  lerp( diffuseTexture, diffuseTexture2, LayerBlend );

	diffuseTexture.xyz = lerp( LightColor, MidColor, min(1, diffuseTexture.x/ColorMidpoint) );
 	diffuseTexture.xyz = lerp( diffuseTexture.xyz, DarkColor, max(0, (diffuseTexture.x-ColorMidpoint)/(1.0f-ColorMidpoint)) );
   

    diffuseTexture.a = 1.0f;
    diffuseTexture *= LightColor.a;

	float2 reflectUV = (IN.screenPos.xy / (2*IN.screenPos.w) ) + 0.5f;    
    reflectUV += (normalTexture.xy + normalTexture2.xy) * ReflectionDistortion; 
    float4 reflectionTexture = tex2D( ReflectionTextureSampler, reflectUV );

    
    float3 colorSum = 0;
    float3 specularSum = 0;
	//AddLightsNoSpec(normalWorld, IN.posWorld, colorSum );
	AddLights(normalWorld, IN.posWorld, colorSum, SpecularPower, eyeVecW, specularSum);

	
    float4 outColor;

	colorSum += matSettings.Ambient + ambientLevel;
    outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor.xyz += matSettings.Emissive;
    outColor.xyz *= colorSum * outColor.w;
    outColor.xyz += matSettings.Diffuse_Opacity* matSettings.Reflectivity * (specularSum * float3(60.4, 60.4, 60.4)/*matSettings.Specular_Power.xyz*/);
    
    outColor.xyz = lerp( outColor.xyz, reflectionTexture, ReflectionOpacity );
    outColor.xyz *= FinalColorModulate;
    
   	outColor *= baseDiffuse.a; // puddles -> use alpha channel if present
    
    PS_OUTPUT Out;
    SetPSOutput( Out, outColor, float4( campos - IN.posWorld.xyz, 1) );
    return Out;
}


//-----------------------------------
technique techSpecular
{
    pass p0 
    {		
		VertexShader = compile vs_3_0 VS_TransformUnboned();
		PixelShader  = compile ps_3_0 PS_TexturedSpecular();
    }
}

technique techNoSpecular
{
    pass p0 
    {		
		VertexShader = compile vs_3_0 VS_TransformUnboned();
		PixelShader  = compile ps_3_0 PS_TexturedNoSpecular();
    }
}

technique techAddNormal
{
    pass p0 
    {		
		VertexShader = compile vs_3_0 VS_TransformUnboned();
		PixelShader  = compile ps_3_0 PS_TexturedAddNormal();
    }
}


//-----------------------------------
technique techCubemap
{
    pass p0 
    {		
		VertexShader = compile vs_3_0 VS_TransformUnboned();
		PixelShader  = compile ps_3_0 PS_TexturedCubemap();
    }
}