/***************************************************************************
 *                          Zanoza Modeler v3.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                 Copyright (c) 2002-2012 Zanoza Software.                *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler 3.x Color + Dual Diffuse Texture + Specular Map shader
 *--------------------------------------------------------------------------
 * @histroy: 24.04.2012. Created
 * @histroy: 31.08.2012. Damage support added
<[[
UserName = "Dual Diffuse+Spec"
Description = "Color, Dual Diffuse map and Specular map"
Version  = 1.6
Options  = SOLID SPECULAR TRANSITION DUSTCOLOR DIRTCOLOR SCRATCHCOLOR BURNCOLOR DIFFUSECOLOR2 DIFFUSECOLOR3 DIFFUSECOLOR4
Samplers = DETAIL DETAIL2 SPECMAP
ManualUV1 = v.vUV01.xy
ManualUV2 = v.vUV01.zw
ManualUV3 = v.vUV23.xy
ManualUV4 = v.vUV23.zw
EnvUV = v.vUVRefl.xy
WorldUV = v.vUVRefl.zw
AlphaRegister = 29

[DETAIL]
Variable = g_Diffuse
Register = 0
RegisterTrans = 1
Mask = R G B A RGB
Scale = 31.R
Level = 30.R
AngularLevel = 30.G

[DETAIL2]
Variable = g_Diffuse2
Register = 2
RegisterTrans = 3
Mask = R G B A RGB
Scale = 31.G
Level = 32.R
AngularLevel = 32.G

[SPECMAP]
Variable = g_SpecMap
Register = 4
RegisterTrans = 5
Mask = R G B A RGB
Scale = 31.B
Level = 30.B
AngularLevel = 30.A
	
[DUSTCOLOR]
Register    = 33

[DIRTCOLOR]
Register    = 34

[SCRATCHCOLOR]
Register    = 35

[BURNCOLOR]
Register    = 36

[DIFFUSECOLOR2]
Register    = 37

[DIFFUSECOLOR3]
Register    = 38

[DIFFUSECOLOR4]
Register    = 39

[ALPHABLEND]

[ALPHATEST]

[CUSTOM.1]
Name = MODE
Type = combo
Definition = DIFFUSE2_TOP_
Variants = Multiply = MULT, Add = ADD, Lerp = LERP

]]>
*/

#pragma pack_matrix( row_major ) 

struct VS_INPUT
{
    float4 vPosition        : POSITION;
    float4 vNormal          : NORMAL;
    float4 vColorDif        : COLOR0;
    float4 vUV01            : TEXCOORD0;
    float4 vUV23            : TEXCOORD1;
    float4 vDeformPosition  : TEXCOORD5;
    float4 vDeformNormal    : COLOR2;
    uint4  vBones           : BLENDINDICES;
    float4 vWeights         : BLENDWEIGHT;
};

struct VS_OUTPUT
{
    float4 vPosition  : POSITION;   //transformed position
    float4 vColorDif  : COLOR0;
    //precomputed stuff:
    float4 vNormal    : TEXCOORD0;  //world-space normal;
    float4 vViewer    : TEXCOORD1;  //camera-space position;
    float4 vUV01      : TEXCOORD2;
    float4 vUV23      : TEXCOORD3;
    float4 vUVRefl    : TEXCOORD4;
};

//----------------------------------------------------------------------
// globals:
//----------------------------------------------------------------------
#include "zmCommon.inl"

float4      g_alpha          : register(c29);  //[minlevel:testvalue, maxlevel, mapaffect, angular level]
float4      g_textureAmp     : register(c30);  //[diff amp, diff angular, spec amp, spec angular]
float4      g_textureScale   : register(c31);  //[diff scale, diff2 scale, spec scale, 0]
float4      g_textureAmp2    : register(c32);  //[diff2 amp, diff2 angular, 0, 0]
float4      g_dustColor      : register(c33);  //dust color r,g,b and level in .a
float4      g_dirtColor      : register(c34);  //dirt color r,g,b and level in .a
float4      g_scratchColor   : register(c35);  //scratch color r,g,b and level in .a
float4      g_burnColor      : register(c36);  //burn color r,g,b and level in .a
                                               //level of main diffuse is in g_colors[1].a;
float4      g_diffuse2Color  : register(c37);  //diffuse2 color r,g,b and level in .a
float4      g_diffuse3Color  : register(c38);  //diffuse3 color r,g,b and level in .a
float4      g_diffuse4Color  : register(c39);  //diffuse4 color r,g,b and level in .a

// textures:
sampler     g_Diffuse        : register(s[0]);
sampler     g_DiffuseTrans   : register(s[1]);
sampler     g_Diffuse2       : register(s[2]);
sampler     g_Diffuse2Trans  : register(s[3]);
sampler     g_SpecMap        : register(s[4]);
sampler     g_SpecMapTrans   : register(s[5]);

#ifdef VERTEX_SHADER
VS_OUTPUT mainVS(in VS_INPUT v)
{
    VS_OUTPUT output = (VS_OUTPUT)0;
    output.vNormal = v.vNormal;
    float4 vTangent = (float4)0;
    output.vPosition = transformInput(v, output.vNormal, vTangent, output.vViewer);
    output.vColorDif = any(v.vColorDif.rgb) ? v.vColorDif : 1;

    output.vUV01 = v.vUV01;
    output.vUV23 = v.vUV23;
    output.vUVRefl.xy = (mul(output.vNormal.xyz, (float3x3)g_mView).xy+1)/2;
    output.vUVRefl.zw = v.vPosition.xz;

    return output;
}
#endif //VERTEX_SHADER

#ifdef PIXEL_SHADER
//------------------------------------------------------------
//  PixelShader: generic Dif+Bump+SpecMap+Refl;
//------------------------------------------------------------
float4 mainPS(in VS_OUTPUT v) : COLOR0
{
    float4 oColor;
    float4 CONST_TEXEL   = float4(1,1,1,1);
    float4 VCOLOR_TEXEL  = v.vColorDif;
    float4 DETAIL_TEXEL  = tex2D(DETAIL_SOURCE, DETAIL_UV_SOURCE/g_textureScale.x);
    float4 DETAIL2_TEXEL = tex2D(DETAIL2_SOURCE, DETAIL2_UV_SOURCE/g_textureScale.y);
    float4 SPECMAP_TEXEL = tex2D(SPECMAP_SOURCE, SPECMAP_UV_SOURCE/g_textureScale.z);
    DETAIL_TEXEL = lerp(DETAIL_TEXEL, tex2D(g_DiffuseTrans, DETAIL_UV_SOURCE/g_textureScale.x), DETAIL_TRANSITION);
    DETAIL2_TEXEL = lerp(DETAIL2_TEXEL, tex2D(g_Diffuse2Trans, DETAIL2_UV_SOURCE/g_textureScale.y), DETAIL2_TRANSITION);
    SPECMAP_TEXEL = lerp(SPECMAP_TEXEL, tex2D(g_SpecMapTrans, SPECMAP_UV_SOURCE/g_textureScale.z), SPECMAP_TRANSITION);

    float3 light = -g_lightDir.xyz;
    float4 Temp   = float4(1,1,0,saturate(dot(v.vViewer.xyz, v.vNormal.xyz))); 
    
#ifdef SPECULAR_ENABLED
    float3 normal = normalize(v.vNormal.xyz);
    float3 halfSpec = normalize(light + v.vViewer.xyz);
    Temp.xy = float2(dot(normal, light), dot(normal, halfSpec));
    float4 LitCoef = lit(Temp.x, Temp.y, g_colors[2].a);
#else
    float4 LitCoef = float4(1, saturate(dot(light, v.vNormal.xyz)), 0, 0);
#endif //SPECULAR_ENABLED
    // alter diffuse light factor by ambient illumitaion addon:
    LitCoef.y = saturate(LitCoef.y + (g_ambientLight.r + g_ambientLight.g + g_ambientLight.b)/3);

    float3 fDiffuse1Color   = (DETAIL_INPUT)DETAIL_MASK;
    float3 fDiffuse2Color   = (DETAIL2_INPUT)DETAIL2_MASK;
    float3 fSpecMapColor    = (SPECMAP_INPUT)SPECMAP_MASK;
    //diffuse1 angular:
    if (g_textureAmp.y >= 0)
      Temp.x = lerp(1, Temp.w, g_textureAmp.y)*g_textureAmp.x*(DETAIL_INPUT_MASK);
    else
      Temp.x = lerp(1, 1-Temp.w, abs(g_textureAmp.y))*g_textureAmp.x*(DETAIL_INPUT_MASK);
    //diffuse2 angular:
    if (g_textureAmp2.y >= 0)
      Temp.y = lerp(1, Temp.w, g_textureAmp2.y)*g_textureAmp2.x*(DETAIL2_INPUT_MASK);
    else
      Temp.y = lerp(1, 1-Temp.w, abs(g_textureAmp2.y))*g_textureAmp2.x*(DETAIL2_INPUT_MASK);

    float3 fDetailColor = 
#if defined(DIFFUSE2_TOP_MULT)
      lerp(1, fDiffuse1Color, Temp.x)*lerp(1, fDiffuse2Color, Temp.y);
#elif defined(DIFFUSE2_TOP_LERP)
      lerp(1, fDiffuse1Color*Temp.x + fDiffuse2Color*Temp.y, saturate(Temp.x+Temp.y));
#else
      lerp(1, fDiffuse1Color, Temp.x) + fDiffuse2Color*Temp.y;
#endif

    //specmap angular:
    if (g_textureAmp.w >= 0)
      Temp.z = lerp(1, Temp.w, g_textureAmp.w)*g_textureAmp.z;
    else
      Temp.z = lerp(1, 1-Temp.w, abs(g_textureAmp.w))*g_textureAmp.z;
    
    //
    // advanced diffuse color, and shine/opacity overload controllers:
    ADVANCED_COLOR_DIFFUSELEVEL(fAdvColorLevels)
    ADVANCED_COLOR_DIFFUSEVAR(fAdvancedDiffuseColor, fAdvColorLevels)
    ADVANCED_COLOR_EFFECTLEVELS(fEffectLevels)
    ADVANCED_COLOR_EFFECTVAR(fEffectColor, fEffectLevels)
    ADVANCED_COLOR_OPTIONS(advShineOpac, fEffectLevels, fAdvColorLevels)

    oColor.rgb =
                // ambient: 
                (g_colors[0].rgb + 0.2*v.vColorDif.rgb + 0.8*fDetailColor*g_ambientLight.rgb)*g_ambientLight.rgb +
                // diffuse component:
                (fAdvancedDiffuseColor*v.vColorDif.rgb*fDetailColor*(1-fEffectColor.a) + fEffectColor.rgb*fEffectColor.a)*max(g_colors[3].a, LitCoef.y) +
                // matted:
                advShineOpac.r*(
                  // specular component:
                  g_colors[2].rgb*(fSpecMapColor*(SPECMAP_INPUT_MASK)*Temp.z)*(LitCoef.z + LitCoef.z*(1+LitCoef.y)*saturate(advShineOpac.g)) +
                  // emissive component:
                  g_colors[3].rgb*g_colors[3].a
                );

#ifdef ALPHABLEND_ENABLED
    if (g_alpha.w >= 0)
      Temp.z = lerp(1, Temp.w, g_alpha.w);
    else
      Temp.z = lerp(1, 1-Temp.w, abs(g_alpha.w));
    oColor.a = saturate(lerp(1, ALPHABLEND_INPUT, g_alpha.z)*ALPHABLEND_VERTEXCOLOR*Temp.z*g_alpha.y + advShineOpac.b);
#else
    oColor.a = g_alpha.y;
#endif//ALPHABLEND_ENABLED
#ifdef ALPHATEST_ENABLED
    clip(oColor.a - g_alpha.x);
#endif//ALPHATEST_ENABLED
    return oColor;
}
#endif //PIXEL_SHADER

