/***************************************************************************
 *                          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 + Bump + three Diffuse + Specular + EnvMap shader
 *--------------------------------------------------------------------------
 * @histroy: 30.08.2012. Created
<[[
UserName = "Bump+Triple Diffuse+Spec+Env"
Description = "Color, Bump, three Diffise, Specular and Env map"
Version  = 1.9.1
Options  = SOLID BUMP SPECULAR ENVIRONMENT FRESNEL TRANSITION EMISSIVECOLOR DUSTCOLOR DIRTCOLOR SCRATCHCOLOR BURNCOLOR DIFFUSECOLOR2 DIFFUSECOLOR3 DIFFUSECOLOR4
Samplers = BUMPMAP DETAIL DETAIL2 DETAIL3 SPECMAP ENVMAP MASK
ManualUV1 = v.vUV01.xy
ManualUV2 = v.vUV01.zw
ManualUV3 = v.vUV23.xy
ManualUV4 = v.vUV23.zw
EnvUV = vReflect.xy
WorldUV = v.vUVRefl.zw
AlphaRegister = 29

[BUMPMAP]
Variable = g_BumpMap
Register = 0
RegisterTrans = 10
Mask = RGB AGB GRB AG GA
Config = 33

[DETAIL]
Variable = g_Diffuse
Register = 1
RegisterTrans = 2
Mask = R G B A RGB
Config = 30

[DETAIL2]
Variable = g_Diffuse2
Register = 3
RegisterTrans = 8
Mask = R G B A RGB AGB GRB AG GA
Config = 31

[DETAIL3]
Variable = g_Diffuse3
Register = 4
RegisterTrans = 9
Mask = R G B A RGB AGB GRB AG GA
Config = 32

[SPECMAP]
Variable = g_SpecMap
Register = 5
RegisterTrans = 11
Mask = R G B A RGB
Config = 34

[ENVMAP]
Variable = g_Refl
Register = 6
Mask = RGB
Config = 35

[MASK]
Variable = g_Mask
Register = 7
Mask = R G B A RGB
Config = 44


[DUSTCOLOR]
Register    = 37

[DIRTCOLOR]
Register    = 38

[SCRATCHCOLOR]
Register    = 39

[BURNCOLOR]
Register    = 40

[DIFFUSECOLOR2]
Register    = 41

[DIFFUSECOLOR3]
Register    = 42

[DIFFUSECOLOR4]
Register    = 43

[ALPHABLEND]

[ALPHATEST]

[CUSTOM.1]
Name = Opacity Amplifier
Slot = 36.G
Type = float
Min = 0.0
Max = 1.0
Default = 0.2

[CUSTOM.2]
Name = Fresnel
Slot = 36.R
Type = float
Min = 0.001
Max = 0.3
Default = 0.2

[CUSTOM.3]
Name = MODE
Type = combo
Definition = DIFFUSE2_TOP_
Variants = Multiply = MULT, Add = ADD, Lerp = LERP, Overlay = OVERLAY, Mix = MIX, Displace = DISPLACE
;Default = Add

[CUSTOM.4]
Name = MODE2
Type = combo
Definition = DIFFUSE3_TOP_
Variants = Multiply = MULT, Add = ADD, Lerp = LERP, Overlay = OVERLAY, Displace = DISPLACE
;Default = Add


]]>
*/

#pragma pack_matrix( row_major ) 

struct VS_INPUT
{
    float4 vPosition        : POSITION;
    float4 vNormal          : NORMAL;
    float4 vTangent         : TANGENT;
    float4 vColorDif        : COLOR0;
    float4 vUV01            : TEXCOORD0;
    float4 vUV23            : TEXCOORD1;
    float4 vDeformPosition  : TEXCOORD5;
    float4 vDeformNormal    : COLOR2;
    uint4  vBones0          : BLENDINDICES0;
    uint4  vBones1          : BLENDINDICES1;
    float4 vWeights0        : BLENDWEIGHT0;
    float4 vWeights1        : BLENDWEIGHT1;
};

struct VS_OUTPUT
{
    float4 vPosition  : POSITION;   //transformed position
    float4 vColor     : COLOR0;     //vertex color composition {ambient, diffuse, specular, 1}
    float4 vUV01      : TEXCOORD0;
    float4 vUV23      : TEXCOORD1;
    float4 vUVRefl    : TEXCOORD2;  //environment reflection;
    //precomputed stuff:
    float4 vNormal    : TEXCOORD4;  //world-space normal;
    float4 vViewer    : TEXCOORD5;  //camera-space position;
    float4 vBumpLit   : TEXCOORD6;  //tangent-space light;
    float4 vBumpViewer: TEXCOORD7;  //tangent-space position;
};

//----------------------------------------------------------------------
// globals:
//----------------------------------------------------------------------

#include "zmCommon.inl"

float4      g_alpha          : register(c29);  //[minlevel:testvalue, maxlevel, mapaffect, angular level]
float4      g_diffConfig     : register(c30);  //[level, angular, tiling.uv]
float4      g_diff2Config    : register(c31);  //[level, angular, tiling.uv]
float4      g_diff3Config    : register(c32);  //[level, angular, tiling.uv]
float4      g_bumpConfig     : register(c33);  //[level, angular, tiling.uv]
float4      g_specConfig     : register(c34);  //[level, angular, tiling.uv]
float4      g_envConfig      : register(c35);  //[level, angular, tiling.uv]
float4      g_environment    : register(c36);  //[fresnel, opacity strengthening, 0, 0]
float4      g_dustColor      : register(c37);  //dust color r,g,b and level in .a
float4      g_dirtColor      : register(c38);  //dirt color r,g,b and level in .a
float4      g_scratchColor   : register(c39);  //scratch color r,g,b and level in .a
float4      g_burnColor      : register(c40);  //burn color r,g,b and level in .a
                                               //level of main diffuse is in g_colors[1].a;
float4      g_diffuse2Color  : register(c41);  //diffuse2 color r,g,b and level in .a
float4      g_diffuse3Color  : register(c42);  //diffuse3 color r,g,b and level in .a
float4      g_diffuse4Color  : register(c43);  //diffuse4 color r,g,b and level in .a
float4      g_maskConfig     : register(c44);  //[level, angular, tiling.uv]

// textures:
sampler     g_BumpMap        : register(s[0]);
sampler     g_Diffuse        : register(s[1]);
sampler     g_DiffuseTrans   : register(s[2]);
sampler     g_Diffuse2       : register(s[3]);
sampler     g_Diffuse3       : register(s[4]);
sampler     g_SpecMap        : register(s[5]);
sampler     g_Refl           : register(s[6]);
sampler     g_Mask           : register(s[7]);
sampler     g_Diffuse2Trans  : register(s[8]);
sampler     g_Diffuse3Trans  : register(s[9]);
sampler     g_BumpMapTrans   : register(s[10]);
sampler     g_SpecMapTrans   : register(s[11]);



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

    output.vUV01 = v.vUV01;
    output.vUV23 = v.vUV23;
    //bump-map reflection can mix this spehere-env uv mapping with bump-reflected env;
    output.vUVRefl.xy = (mul(output.vNormal.xyz, (float3x3)g_mView).xy+1)/2;
    output.vUVRefl.zw = v.vPosition.xz;

    // bump-transformed light:
    //-----
    float3x3 worldToTangentSpace;
    worldToTangentSpace[0] = vTangent.xyz;
    worldToTangentSpace[1] = normalize(cross(vTangent.xyz, output.vNormal.xyz)*(-v.vTangent.w));
    worldToTangentSpace[2] = output.vNormal.xyz;
    output.vBumpLit = normalize(float4(mul(worldToTangentSpace, -g_lightDir.xyz), 1));
    output.vBumpViewer = float4(mul(worldToTangentSpace, output.vViewer.xyz), 1);

    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);
    float2 vReflect      = v.vUVRefl.xy;
    float4 BUMPMAP_TEXEL = tex2D(BUMPMAP_SOURCE, BUMPMAP_UV_SOURCE*g_bumpConfig.zw);
    float4 DETAIL_TEXEL  = tex2D(DETAIL_SOURCE, DETAIL_UV_SOURCE*g_diffConfig.zw);
    float4 DETAIL2_TEXEL = tex2D(DETAIL2_SOURCE, DETAIL2_UV_SOURCE*g_diff2Config.zw);
    float4 DETAIL3_TEXEL = tex2D(DETAIL3_SOURCE, DETAIL3_UV_SOURCE*g_diff3Config.zw);
    float4 SPECMAP_TEXEL = tex2D(SPECMAP_SOURCE, SPECMAP_UV_SOURCE*g_bumpConfig.zw);
    float4 ENVMAP_TEXEL  = CONST_TEXEL;
    float4 VCOLOR_TEXEL  = v.vColor;
    float4 PERVERTEXCOLOR = lerp(1, VCOLOR_TEXEL, g_deform.z);
    float4 MASK_TEXEL    = tex2D(MASK_SOURCE, MASK_UV_SOURCE*g_maskConfig.zw)*g_maskConfig.x*(MASK_INPUT_MASK);
    DETAIL_TEXEL  = lerp(DETAIL_TEXEL,  tex2D(g_DiffuseTrans, DETAIL_UV_SOURCE*g_diffConfig.zw), DETAIL_TRANSITION);
    DETAIL2_TEXEL = lerp(DETAIL2_TEXEL, tex2D(g_Diffuse2Trans, DETAIL2_UV_SOURCE*g_diff2Config.zw), DETAIL2_TRANSITION);
    DETAIL3_TEXEL = lerp(DETAIL3_TEXEL, tex2D(g_Diffuse3Trans, DETAIL3_UV_SOURCE*g_diff3Config.zw), DETAIL3_TRANSITION);
    SPECMAP_TEXEL = lerp(SPECMAP_TEXEL, tex2D(g_SpecMapTrans, SPECMAP_UV_SOURCE*g_specConfig.zw),SPECMAP_TRANSITION);
    BUMPMAP_TEXEL = lerp(BUMPMAP_TEXEL, tex2D(g_BumpMapTrans, BUMPMAP_UV_SOURCE*g_bumpConfig.zw), BUMPMAP_TRANSITION);

    float3 normal = normalize(v.vNormal.xyz);
    float3 bumpNormal = normalize(2*(BUMPMAP_INPUT*BUMPMAP_INPUT_MASK)-1);
    float3 bumpLight = normalize(v.vBumpLit.xyz);

#ifdef DIFFUSE2_TOP_DISPLACE
    bumpNormal = normalize(bumpNormal + (((DETAIL2_INPUT)*2)-1)*g_diff2Config.x*(DETAIL2_INPUT_MASK));
#endif
#ifdef DIFFUSE3_TOP_DISPLACE
    bumpNormal = normalize(bumpNormal + (((DETAIL2_INPUT)*2)-1)*g_diff3Config.x*(DETAIL3_INPUT_MASK));
#endif
    
    //
    // regular vs bump-mapped normals and light:
    // float4 LightTemp is [non-bump diff, non-bump spec, bump-diff, bump spec]
    float4 specData = 0;
#ifdef SPECULAR_ENABLED
    specData.xy = float2(dot(-g_lightDir.xyz, normal), dot(normal, normalize(v.vViewer.xyz-g_lightDir.xyz)));
    specData.zw = float2(dot(bumpLight, bumpNormal), dot(bumpNormal, normalize(bumpLight+v.vBumpViewer.xyz)));
    float4 LightTemp = float4(
                    saturate(specData.x), 
                    lit(specData.x, specData.y, g_colors[2].a).z,
                    saturate(specData.z),
                    lit(specData.z, specData.w, g_colors[2].a).z); 
    
#else
    float4 LightTemp = float4(
                    saturate(dot(-g_lightDir.xyz, normal)), 
                    0,
                    saturate(dot(bumpLight, bumpNormal)),
                    0); 
#endif //SPECULAR_ENABLED
    // alter diffuse light factor by ambient illumitaion addon:
    LightTemp.x = saturate(LightTemp.x + (g_ambientLight.r + g_ambientLight.g + g_ambientLight.b)/3);
    LightTemp.z = saturate(LightTemp.z + (g_ambientLight.r + g_ambientLight.g + g_ambientLight.b)/3);


    //
    //angular level (.z - final (after angular level), .w - initial)
    float4 Temp   = float4(1,1,1,
                           lerp(saturate(dot(v.vViewer.xyz, normal)), saturate(dot(v.vBumpViewer, bumpNormal)), g_bumpConfig.x));
    //bump angular:
    if (g_bumpConfig.y >= 0)
      Temp.z = lerp(1, Temp.w, g_bumpConfig.y)*g_bumpConfig.x;
    else
      Temp.z = lerp(1, 1-Temp.w, abs(g_bumpConfig.y))*g_bumpConfig.x;

    float3 fDiffuse1Color   = DETAIL_INPUT;
    float3 fDiffuse2Color   = DETAIL2_INPUT;
    float3 fDiffuse3Color   = DETAIL3_INPUT;
    float3 fSpecMapColor    = SPECMAP_INPUT;

	//detail #1 and #2 angular:
    if (g_diffConfig.y >= 0)
      Temp.x = lerp(1, Temp.z, g_diffConfig.y)*g_diffConfig.x*(DETAIL_INPUT_MASK);
    else
      Temp.x = lerp(1, 1-Temp.z, abs(g_diffConfig.y))*g_diffConfig.x*(DETAIL_INPUT_MASK);
    if (g_diff2Config.y >= 0)
      Temp.y = lerp(1, Temp.z, g_diff2Config.y)*g_diff2Config.x*(DETAIL2_INPUT_MASK);
    else
      Temp.y = lerp(1, 1-Temp.z, abs(g_diff2Config.y))*g_diff2Config.x*(DETAIL2_INPUT_MASK);

    //
    // 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)
    
    float3 fFinalDiffuseColor = fAdvancedDiffuseColor*PERVERTEXCOLOR.rgb*fDiffuse1Color;

    fFinalDiffuseColor = 
#if defined(DIFFUSE2_TOP_MULT)
      lerp(1, fFinalDiffuseColor, Temp.x)*lerp(1, fDiffuse2Color, Temp.y);
#elif defined(DIFFUSE2_TOP_MIX)
      lerp(1, fFinalDiffuseColor*Temp.x + fDiffuse2Color*Temp.y, saturate(Temp.x+Temp.y));
#elif defined(DIFFUSE2_TOP_LERP)
      lerp(lerp(1, fFinalDiffuseColor, Temp.x), fDiffuse2Color, Temp.y);
#elif defined(DIFFUSE2_TOP_OVERLAY)
      saturate(lerp(1, fFinalDiffuseColor, Temp.x)*(0.5+lerp(0.5, fDiffuse2Color, Temp.y)));
#elif defined(DIFFUSE2_TOP_DISPLACE)
      lerp(1, fFinalDiffuseColor, Temp.x);
#else
      lerp(1, fFinalDiffuseColor, Temp.x) + fDiffuse2Color*Temp.y;
#endif


    // diffuse 3 angular:
    if (g_diff3Config.y >= 0)
      Temp.x = lerp(1, Temp.z, g_diff3Config.y)*g_diff3Config.x*(DETAIL3_INPUT_MASK);
    else
      Temp.x = lerp(1, 1-Temp.z, abs(g_diff3Config.y))*g_diff3Config.x*(DETAIL3_INPUT_MASK);

    fFinalDiffuseColor =
#if defined(DIFFUSE3_TOP_MULT)
      fFinalDiffuseColor*lerp(1, fDiffuse3Color, Temp.x);
#elif defined(DIFFUSE3_TOP_LERP)
      lerp(fFinalDiffuseColor, fDiffuse3Color, Temp.x);
#elif defined(DIFFUSE3_TOP_OVERLAY)
      saturate(fFinalDiffuseColor*(0.5+lerp(0.5, fDiffuse3Color, Temp.x)));
#elif defined(DIFFUSE3_TOP_DISPLACE)
      fFinalDiffuseColor;
#else
      fFinalDiffuseColor + fDiffuse3Color*Temp.x;
#endif

    //
    // environment UV computation is wrong in tangent space (vBumpReflect); 
    // however it's suitable at the moment, since I reduce affection (Temp.z)
    // when bump-map normal pointing around (0,0,1)
    //
    float2 vBumpReflect   = (reflect(bumpNormal, v.vBumpViewer.xyz).xy + 1)/2;
    vReflect              = lerp(vReflect, vBumpReflect, Temp.z*(1-saturate(bumpNormal.z)));
            
    ENVMAP_TEXEL          = tex2D(ENVMAP_SOURCE, ENVMAP_UV_SOURCE*g_envConfig.zw);
    
    float3 fEnvironColor = (ENVMAP_INPUT*(ENVMAP_INPUT_MASK));
    
    // Temp.x is a diffuse level (with respect to bump level/angular)
    Temp.x = lerp(LightTemp.x, LightTemp.z, Temp.z); 
     
    //
    // angular level on env:
    if (g_envConfig.y >= 0)
      Temp.z = lerp(1, Temp.w, g_envConfig.y);
    else
      Temp.z = lerp(1, 1-Temp.w, abs(g_envConfig.y));

    // fresnel reflection
    specData.w = (1-Temp.x)*(1-Temp.x);
    specData.w = specData.w*specData.w;
    specData.w = saturate(mad(specData.w*(1-Temp.x), 1-saturate(g_environment.x), g_environment.x));
    fEnvironColor = fEnvironColor*saturate(Temp.z*g_envConfig.x+(0.5 + g_envConfig.x)*specData.w);

    //
    // angular level on spec:
    if (g_specConfig.y >= 0)
      Temp.z = lerp(1, Temp.w, g_specConfig.y)*g_specConfig.x;
    else
      Temp.z = lerp(1, 1-Temp.w, abs(g_specConfig.y))*g_specConfig.x;

    // specular level (with respect to bump level/angular)
    Temp.y = lerp(LightTemp.y, LightTemp.w, Temp.z); 

    float3 fSpecularColor = g_colors[2].rgb*(fSpecMapColor*(SPECMAP_INPUT_MASK)*Temp.z)*(Temp.y + Temp.y*(1+Temp.x)*saturate(advShineOpac.g));
    
    //regular:
    oColor.rgb =
                // ambient: 
                (g_colors[0].rgb + 0.2*PERVERTEXCOLOR.rgb + 0.8*fFinalDiffuseColor*g_ambientLight.rgb)*g_ambientLight.rgb +
                // diffuse component:
                (fFinalDiffuseColor*(1-fEffectColor.a) + fEffectColor.rgb*fEffectColor.a)*max((EMISSIVECOLOR_INPUT_MASK)*advShineOpac.r*4*g_colors[3].a, Temp.x) +
                // matted:
                advShineOpac.r*(
                  // specular component:
                  fSpecularColor +
                  // reflection component:
                  fEnvironColor +
                  // emissive component:
                  g_colors[3].rgb*(EMISSIVECOLOR_INPUT_MASK)*g_colors[3].a
                );
                

#ifdef ALPHABLEND_ENABLED
    if (g_alpha.w >= 0)
      Temp.x = lerp(1, Temp.w, g_alpha.w);
    else
      Temp.x = lerp(1, 1-Temp.w, abs(g_alpha.w));
    oColor.a = saturate(lerp(1, ALPHABLEND_INPUT, g_alpha.z)*ALPHABLEND_VERTEXCOLOR*Temp.x*g_alpha.y +
                        (length(fEnvironColor) + length(fSpecularColor))*g_environment.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

