#if DeclareUniqueCode

/***********************************************************************************************************
*
***********************************************************************************************************/
#if NbBonesPerVertex > 0
#define HasSkinning 1
#else 
#define HasSkinning 0
#endif
#define HasNormalMap HasShaderMap0
#define HasEnvMap HasShaderMap1
#define HasLightMap HasShaderMap2
#define HasFresnelMap HasShaderMap3

/***********************************************************************************************************
*
***********************************************************************************************************/
struct VS_INPUT
{
    float4 Pos          : POSITION;
#if NbUVSets > 0
    float2 TexCoord     : TEXCOORD0;
#endif
#if NbUVSets > 1
    float2 TexCoord2    : TEXCOORD1;
#endif
#if HasSkinning
    float4 BlendWeights : BLENDWEIGHT;
    float4 BlendIndices : BLENDINDICES;
#endif
    float4 Normal       : NORMAL;
#if HasBT
    float3 Binormal     : BINORMAL;
    float3 Tangent      : TANGENT;
#endif
#if HasVertexColor
    float4 Color        : COLOR;
#endif
};

/***********************************************************************************************************
*
***********************************************************************************************************/
#include "Uniforms.hlsl"
#include "Transforms.hlsl"
#include "Lighting.hlsl"
#include "Textures.hlsl"
#include "Shadow.hlsl"
#include "PhongTools.hlsl"
#include "Debug.hlsl"

/***********************************************************************************************************
*
***********************************************************************************************************/
float3 MaskedColor                  : ATTRIBUTE = float3(1.0, 1.0, 1.0);
float3 BuildingRenderingParameters  : ATTRIBUTE = float3(1.0, 0.0, 0.0);
float MotionBlurMaskParameter       : ATTRIBUTE < bool WarningWhenFailedToBeSet = false; > = float(0.0f);
float kFresnel                      : ATTRIBUTE < bool WarningWhenFailedToBeSet = false; > = 0.0f;
float3 TunnelColor                  : ATTRIBUTE < bool WarningWhenFailedToBeSet = false; > = float3(1.0f, 1.0f, 1.0f);
#if PhongIsolated && UseShader30
float4 GroundInfluence;
#endif

/***********************************************************************************************************
*
***********************************************************************************************************/
texture BaseMap     < string NTM = "Base"; >; 
texture GlossMap    < string NTM = "Gloss"; >;
texture NormalMap   < string NTM = "Shader"; int NTMIndex = 0; >;
texture EnvMap      < string NTM = "Shader"; int NTMIndex = 1; >;
texture LightMap    < string NTM = "Shader"; int NTMIndex = 2; >;
texture tFresnelMap < string NTM = "Shader"; int NTMIndex = 3; >;
texture DepthMap    < string NTM = "shader"; int NTMIndex = 7; bool hidden = true; >;

/***********************************************************************************************************
*
***********************************************************************************************************/
sampler BaseSampler     = sampler_state { Texture = (BaseMap); };
sampler NormalSampler   = sampler_state { Texture = (NormalMap); };
sampler GlossSampler    = sampler_state { Texture = (GlossMap); };
sampler LightSampler    = sampler_state { Texture = (LightMap); };
samplerCUBE EnvSampler  = sampler_state { Texture = (EnvMap); };
sampler DepthSampler    = sampler_state { Texture = (DepthMap); };
sampler sFresnelMap     = sampler_state { Texture = (tFresnelMap); ADDRESSU = CLAMP; ADDRESSV = CLAMP; };

/***********************************************************************************************************
*
***********************************************************************************************************/
void ComputeShininessFactorAndNormal(out half3 vOutNormal,
                                     out float fAlphaNormalMap, 
                                     float2 vTexCoord,
                                     float3 vInTangent, 
                                     float3 vInBinormal, 
                                     float3 vInNormal, 
                                     out float3 vNormalSampler)
{
#if HasNormalMap
    {
        float4 vNormalMap = tex2D(NormalSampler, vTexCoord, HasNormalMap);
        if(AGBNormalMap)
        {
            vNormalMap.rgba = vNormalMap.agbr;
        }
        float3 vTS_Normal = 255.0 / 128.0 * vNormalMap.rgb - 1;
        vNormalSampler.rgb = vTS_Normal;
        vOutNormal = vTS_Normal.r * vInTangent + vTS_Normal.g * vInBinormal + vTS_Normal.b * vInNormal;
        fAlphaNormalMap = vNormalMap.a;
    }
#else
    {
        vOutNormal = vInNormal;
        vNormalSampler = vOutNormal;
        fAlphaNormalMap = 0.0f;
    }
#endif
    vOutNormal = normalize(vOutNormal);
}

/***********************************************************************************************************
*
***********************************************************************************************************/
float3 GetEnvironmentReflectedEye(float3 vWS_ReflectedEye)
{
    return float3(-vWS_ReflectedEye.x, vWS_ReflectedEye.z, vWS_ReflectedEye.y);
}

/***********************************************************************************************************
*
***********************************************************************************************************/
float3 ComputeEnvironmentLighting(float3 vWS_ReflectedEye)
{
    float3 vEnvironmentLighting = (float3)0;
#if HasEnvMap
    {
        float3 vCubeMapSampling = GetEnvironmentReflectedEye(vWS_ReflectedEye);
        float4 vEnvMap = texCUBE(EnvSampler, vCubeMapSampling.xyz);
        vEnvironmentLighting = vEnvMap.rgb;
    }
#endif
    return vEnvironmentLighting;
}

/***********************************************************************************************************
*
***********************************************************************************************************/
void ComputeFresnel(out float kFresnelCoeff, out float3 kFresnelLighting, float NdotV)
{
    float fIntensity = (LightColor.r+LightColor.g+LightColor.b) / 3.0f;
#if HasFresnelMap
    kFresnelCoeff = tex1D(sFresnelMap, 1.0-NdotV, HasFresnelMap).r;
#else
    kFresnelCoeff = pow(1.0f - NdotV, 8.0f) * kFresnel;
#endif
    kFresnelLighting = kFresnelCoeff * fIntensity;
}

/***********************************************************************************************************
*
***********************************************************************************************************/
float GetMaterialPower()
{
    const float fMin = 4.0;
    return(fMin + 128.0 * MaterialPower / (128.0 - fMin));
}

#else

/***********************************************************************************************************
*
***********************************************************************************************************/
#ifndef UseShader30
#define UseShader30 1
#endif
#if UseShader30
#define VS_OUTPUT VS_OUTPUT_30
#define VSMain VSMain30
#define PSMainBlendColor PSMainBlendColor30
#define PSMain PSMain30
#else
#define VSMain VSMain20
#define PSMainBlendColor PSMainBlendColor20
#define PSMain PSMain20
#endif
#if UseMultipleRenderTarget > 1 && UseShader30
#define UseMotionBlurMask 1
#else
#define UseMotionBlurMask 0
#endif
#if UseMultipleRenderTarget && UseShader30
#define UseOutputDepth 1
#else
#define UseOutputDepth 0
#endif
#if UseMotionBlurMask
#define PS_OUTPUT PSOutput3Color
#else
#define PS_OUTPUT PSOutput
#endif
#ifndef UseLodVersion
#define UseLodVersion 0
#endif

/***********************************************************************************************************
*
***********************************************************************************************************/
struct VS_OUTPUT
{
    float4 Pos              : POSITION;
    float3 TexCoord         : TEXCOORD0;
    float2 TexCoord2        : TEXCOORD1;
    float4 WorldPos         : TEXCOORD2;
    float3 Normal           : TEXCOORD3_centroid;   
#if UseShader30 && !UseLodVersion
    float3 Tangent          : TEXCOORD4;
    float3 Binormal         : TEXCOORD5;
#else
    float3 Ambiant          : TEXCOORD4;
#endif
    float4 TransformPos     : TEXCOORD6;
#if PhongIsolated && UseShader30    
	float4 PrecalcGround    : TEXCOORD7;
#endif
#if HasVertexColor
    float4 Color            : COLOR0;
#endif
};

/***********************************************************************************************************
*
***********************************************************************************************************/
VS_OUTPUT VSMain(VS_INPUT In)
{
    VS_OUTPUT Out = (VS_OUTPUT)0;
#if NbUVSets > 0
    Out.TexCoord.xy = GetUV(In.TexCoord.xy, TexTransformBase, HasBaseMapTransform);
#endif
#if NbUVSets > 1
    Out.TexCoord2 = GetUV(In.TexCoord2, TexTransformBase, HasLightMap);
#endif

    float4x3 WorldTransform = GetWorldTransform(In);
    float3 vWorldPos = mul(In.Pos, WorldTransform);
    float4x4 WorldViewProjTransform = GetWorldViewProjTransform(In);
    Out.Pos = mul(In.Pos, WorldViewProjTransform);
    Out.TransformPos = Out.Pos;
    Out.Normal = normalize(mul(In.Normal, (float3x3)WorldTransform));
#if HasBT && UseShader30 && !UseLodVersion
    Out.Tangent = normalize(mul(In.Tangent, (float3x3)WorldTransform));
    Out.Binormal = normalize(mul(In.Binormal, (float3x3)WorldTransform));
#endif
#if !UseShader30    
    Out.Ambiant = ComputeAmbientLighting(Out.Normal) * AmbiantFresnelScale.x;
#endif
    Out.WorldPos.xyz = vWorldPos;

#if HasVertexColor
    Out.Color = In.Color;
#endif

    float fEyeDist = length(vWorldPos - EyePos);    
    Out.WorldPos.w = saturate((fEyeDist - FogDistanceAndLength.x) / (FogDistanceAndLength.y));
    
#if PhongIsolated && UseShader30  
    // Calculate BlendFactor    
    // Here we take directly the World Matrix to avoid Animation Wrong Translation
    Out.PrecalcGround.x = floor(GroundInfluence.x) / 255.0f;
    Out.PrecalcGround.y = frac(GroundInfluence.x);
    Out.PrecalcGround.z = GroundInfluence.y;
    Out.PrecalcGround.w = 0.25f + 0.75f * ((Out.WorldPos.z - World._43 + GroundInfluence.z) * GroundInfluence.w);
#endif

    return Out;
}

/***********************************************************************************************************
*
***********************************************************************************************************/
PS_OUTPUT PSMainBlendColor(VS_OUTPUT In, float4 fColorBlend) 
{
    PS_OUTPUT sOut = (PS_OUTPUT)1;
    float4 vBaseSampler  = tex2D(BaseSampler, In.TexCoord, HasBaseMap);

#if SHADOWPASS==1
    sOut.vColor0 = float4(  In.TransformPos.z / In.TransformPos.w + fShadowDepthOffset, 0.0f, 0.0f, vBaseSampler.w);
#else // SHADOWPASS == 1

    float4 vColor = 1;    
    float4 vGlossSampler = tex2D(GlossSampler, In.TexCoord, HasGlossMap, float4(0.0, 0.0, 0.0, 0.0));

    float fAlphaNormalMap = 0.0f;
#if UseShader30 && !UseLodVersion
    float3 vEmissiveLighting = MaterialEmissive;
    half3 vNormal;
    float3 vNormalSampler = (float4)0;
    ComputeShininessFactorAndNormal(vNormal, fAlphaNormalMap, In.TexCoord, In.Tangent, In.Binormal, In.Normal, vNormalSampler);
    float3 vAmbientLighting = ComputeAmbientLighting(vNormal) * AmbiantFresnelScale.x;
#else
    half3 vNormal = In.Normal;
    float3 vNormalSampler = 0;
    float3 vAmbientLighting = In.Ambiant;
#endif
    
    // Shininess
#if UseShader30
#if UseNewChannel
#if HasGlossMap
    half fShininessFactor = vGlossSampler.b;
#else
    half fShininessFactor = 1.0f;
#endif // HasGlossMap
#else // UseNewChannel
#if HasNormalMap
    half fShininessFactor = fAlphaNormalMap;
#else
    half fShininessFactor = 1.0f;
#endif // HasNormalMap
#endif // UseNewChannel
#else // UseShader30
    half fShininessFactor = 0.0f;
#endif // UseShader30
    
    float3 vDiffuseLighting = 0;
    float3 vSpecularLighting = 0;
    float3 vFromEye = normalize(In.WorldPos - EyePos);
    float3 vReflectedEye = reflect(vFromEye, vNormal);
    float NdotL = dot(vNormal, -LightDir);

#if HasBaseMap
#if UseShader30
    NdotL = ComputeStandardLighting(NdotL,In.WorldPos.xyz,In.TransformPos.w);
#else
    NdotL = ComputeStandardLightingWithoutShadow(NdotL,In.WorldPos.xyz,In.TransformPos.w);
#endif
#else
    NdotL = max(NdotL, 0.0f);
#endif  

#if UseShader30
    ComputeDiffuseAndSpecularLighting(vDiffuseLighting, vSpecularLighting, NdotL, vReflectedEye, GetMaterialPower()*fShininessFactor);
#else
    ComputeDiffuseAndSpecularLighting(vDiffuseLighting, vSpecularLighting, NdotL, vReflectedEye, GetMaterialPower());
#endif

#if UseShader30
    float3 vFresnelLighting = float3(1.0f,1.0f,1.0f);
    float fFresnelCoeff = 0.0f;
#if HasEnvMap //Because fresnel modulate env map
    ComputeFresnel(fFresnelCoeff, vFresnelLighting, abs(dot(-vFromEye,vNormal)));
#endif
    float3 vEnvironmentLighting = ComputeEnvironmentLighting(vReflectedEye) * vFresnelLighting;    
    // Ground influence color
    vBaseSampler.rgb = lerp( fColorBlend.xyz , vBaseSampler.rgb , fColorBlend.w );
#else
    float3 vEnvironmentLighting = float3(0.0f, 0.0f, 0.0f); 
#endif

    float4 vShadowSampler  = tex2D(LightSampler, In.TexCoord2, HasLightMap);

    // Color mask
#if UseNewChannel    
#if HasGlossMap
    vBaseSampler.rgb *= lerp(float3(1.0, 1.0, 1.0), MaskedColor.rgb, vGlossSampler.a);
#else
    vBaseSampler.rgb *= lerp(float3(1.0, 1.0, 1.0), MaskedColor.rgb, fAlphaNormalMap);
#endif
#else  
    vBaseSampler.rgb *= lerp(float3(1.0, 1.0, 1.0), MaskedColor.rgb, vGlossSampler.g);
#endif

#if UseNewChannel
    float fFresnelMap = vGlossSampler.r;
#else
    float fFresnelMap = vGlossSampler.a;
#endif

#if UseShader30
    float3 vNonSpecularLighting = vEmissiveLighting + lerp(vDiffuseLighting, vEnvironmentLighting, fFresnelCoeff * fFresnelMap) * MaterialDiffuse + vAmbientLighting;
#else
    float3 vNonSpecularLighting = MaterialEmissive + vDiffuseLighting * MaterialDiffuse + vAmbientLighting;
#endif

#if HasVertexColor
#if HasNormalMap
    vBaseSampler.rgb *= lerp(float3(1.0, 1.0, 1.0), In.Color.rgb, fAlphaNormalMap);
#else
	vBaseSampler.rgb *= In.Color;
#endif
#endif

#if UseNewChannel
    float fSpecularMap = vGlossSampler.g;
#else
    float fSpecularMap = vGlossSampler.r;
#endif

    vColor.rgb = 
        vBaseSampler.rgb *  vNonSpecularLighting + 
        (fSpecularMap * vSpecularLighting  + vNonSpecularLighting * vEnvironmentLighting.rgb * fFresnelMap) * MaterialSpecular;

#if HasLightMap
    vColor.rgb *= vShadowSampler.rgb;
#endif
#if UseShader30
    vColor.a = lerp(vBaseSampler.a * MaterialDiffuse.a, vBaseSampler.a * 1.0f, fFresnelCoeff);
#else
    vColor.a = vBaseSampler.a * MaterialDiffuse.a;
#endif
    // Add Fog
#if NOT_GB_VIEWER    
    vColor.rgb = vColor.rgb * TunnelColor;
    vColor.rgb = lerp(vColor.rgb, FogColor, In.WorldPos.w);
#endif

#if UseShader30
#if UseOutputDepth
    sOut.vColor1.r = In.TransformPos.z / In.TransformPos.w;
    sOut.vColor1.a = vColor.a;
#endif
#if UseMotionBlurMask
	sOut.vColor2 = UpdateMask(MotionBlurMaskParameter, 0.0f);
#endif
#endif

#if ShowDebugValue
    float3 vColorSampler = vBaseSampler.rgb;
    float3 vDetailSampler = float3(0.0f,0.0f,0.0f);
    float3 vGlowSampler = float3(0.0f,0.0f,0.0f);
    float3 vSpecSampler = vGlossSampler.rgb;
    float3 vFullDetail = float3(0.0f,0.0f,0.0f);
#if UseShader30
    float3 vVertexNormal = normalize(In.Normal);
    float3 vCubeSampler = vEnvironmentLighting.rgb;
#else
    float3 vVertexNormal = vNormal;
    float3 vFresnelLighting = float3(0.0f,0.0f,0.0f);
    float fFresnelCoeff = 0.0f;
    float3 vCubeSampler = float3(0.0f,0.0f,0.0f);
#endif
    float fOcclusion = 0.0f;
    sOut.vColor0 = float4(DebugValues(vColor.rgb),vColor.a);
#else // ShowDebugValue
    sOut.vColor0 = vColor;
#endif // ShowDebugValue
#endif // SHADOWPASS == 1
    return sOut;
}

/***********************************************************************************************************
*
***********************************************************************************************************/
PS_OUTPUT PSMain(VS_OUTPUT In)
{
#if PhongIsolated && UseShader30    
    // Do the clamp in pixel shader to avoid some graphic bug with vertex interpolation
    In.PrecalcGround.w = clamp(In.PrecalcGround.w, 0.25f, 1.0f);
    return PSMainBlendColor(In, In.PrecalcGround);
#else
    return PSMainBlendColor(In, float4(0.0f, 0.0f, 0.0f, 1.0f));
#endif
}

/***********************************************************************************************************
*
***********************************************************************************************************/
#undef VS_OUTPUT
#undef VSMain
#undef PSMainBlendColor
#undef PSMain
#undef UseMotionBlurMask
#undef UseOutputDepth
#undef PS_OUTPUT
#undef UseLodVersion

#endif //DeclareUniqueCode
