/***************************************************************************
 *                         Zanoza Modeler v3.3.x                           *
 *     This is unpublished proprietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                 Copyright (c) 2002-2023 Zanoza Software.                *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler 3.3.x Color + Bump + SpecMap shader
 *--------------------------------------------------------------------------
 * @history: 27.08.2011. Created
 * @history: 31.08.2012. Damage support added
 * @history: 05.02.2023. Upgraded to DX11 engine
<[[
UserName = "Bump+Spec"
Description = "Color, Bump and Spec map"
Version  = 2.0.2
Engine = 11
Options  = SOLID BUMP SPECULAR TRANSITION EMISSIVECOLOR DUSTCOLOR DIRTCOLOR SCRATCHCOLOR BURNCOLOR DIFFUSECOLOR2 DIFFUSECOLOR3 DIFFUSECOLOR4
Samplers = BUMPMAP SPECMAP MASK
ManualUV1 = v.vUV01.xy
ManualUV2 = v.vUV01.zw
ManualUV3 = v.vUV23.xy
ManualUV4 = v.vUV23.zw
EnvUV = v.vUVRefl.xy
WorldUV = v.vUVRefl.zw

[BUMPMAP]
Variable = g_BumpMap
Register = 0
RegisterTrans = 1
Sampler = 0
Mask = RGB AGB GRB AG GA RG GR
Config = 30

[SPECMAP]
Variable = g_SpecMap
Register = 2
RegisterTrans = 3
Sampler = 1
Mask = R G B A RGB
Config = 31

[MASK]
Variable = g_Mask
Register = 4
RegisterTrans = 5
Sampler = 2
Mask = R G B A RGB
Config = 39

[DUSTCOLOR]
Register    = 32

[DIRTCOLOR]
Register    = 33

[SCRATCHCOLOR]
Register    = 34

[BURNCOLOR]
Register    = 35

[DIFFUSECOLOR2]
Register    = 36

[DIFFUSECOLOR3]
Register    = 37

[DIFFUSECOLOR4]
Register    = 38

[ALPHABLEND]

[ALPHATEST]


]]>
*/

#pragma pack_matrix( row_major ) 

struct VS_INPUT
{
    float4 vPosition        : SV_POSITION;
    float4 vNormal          : NORMAL;
    float4 vTangent         : TANGENT;
    float4 vColorDif        : COLOR0;
    float2 vUV0             : TEXCOORD0;
    float2 vUV1             : TEXCOORD1;
    float2 vUV2             : TEXCOORD2;
    float2 vUV3             : TEXCOORD3;
    float4 vDeformPosition  : TEXCOORD5;
    float4 vDeformNormal    : COLOR2;
    uint4  vBones0          : BLENDINDICES0;
    uint4  vBones1          : BLENDINDICES1;
    float4 vWeights0        : BLENDWEIGHT0;
    float4 vWeights1        : BLENDWEIGHT1;
};

struct VS_OUTPUT
{
    float4 vPosition  : SV_POSITION;//screen-space
    float4 vPos3D     : POSITION1;  //world-space
    float4 vColorDif  : COLOR0;
    //precomputed stuff:
    float4 vUV01      : TEXCOORD0;
    float4 vUV23      : TEXCOORD1;
    float4 vUVRefl    : TEXCOORD2;  //environment reflection;
    float4 vNormal    : TEXCOORD4;  //world-space normal;
    float4 vTangent   : TANGENT;
    float4 vViewer    : TEXCOORD5;  //camera-space position;
    float4 vBumpLit   : TEXCOORD6;  //tangent-space light;
    float4 vBumpViewer: TEXCOORD7;  //tangent-space position;
};

//----------------------------------------------------------------------
// globals:
//----------------------------------------------------------------------
#include "zmCommonBuffers.inl"
#include "zmCommonRoutines.inl"
cbuffer PrivateShadingBuffer : register(b2)
{
  float4      g_bumpConfig;//     : register(c30);  //[level, angular, tiling.uv]
  float4      g_specConfig;//     : register(c31);  //[level, angular, tiling.uv]
  float4      g_dustColor;//      : register(c32);  //dust color r,g,b and level in .a
  float4      g_dirtColor;//      : register(c33);  //dirt color r,g,b and level in .a
  float4      g_scratchColor;//   : register(c34);  //scratch color r,g,b and level in .a
  float4      g_burnColor;//      : register(c35);  //burn color r,g,b and level in .a
                                                    //level of main diffuse is in g_colors[1].a;
  float4      g_diffuse2Color;//  : register(c36);  //diffuse2 color r,g,b and level in .a
  float4      g_diffuse3Color;//  : register(c37);  //diffuse3 color r,g,b and level in .a
  float4      g_diffuse4Color;//  : register(c38);  //diffuse4 color r,g,b and level in .a
  float4      g_maskConfig;//     : register(c39);  //[level, angular, tiling.uv]
}

// textures:
texture2D   g_BumpMap        : register(t0);
texture2D   g_BumpMapTrans   : register(t1);
texture2D   g_SpecMap        : register(t2);
texture2D   g_SpecMapTrans   : register(t3);
texture2D   g_Mask           : register(t4);
texture2D   g_MaskTrans      : register(t5);

sampler     samplerBump      : register(s0);
sampler     samplerSpec      : register(s1);
sampler     samplerMask      : register(s2);

#ifdef VERTEX_SHADER
VS_OUTPUT mainVS(in VS_INPUT v)
{
    VS_OUTPUT output = (VS_OUTPUT)0;
    output.vNormal = v.vNormal;
    float3 t = v.vTangent.xyz;
    float3 fallbackTangent = cross(v.vNormal, float3(0, 1, 0.001));
    if (length(t) < 0.1) t = fallbackTangent;
    output.vTangent = float4(normalize(t), v.vTangent.w != 0 ? v.vTangent.w : 1.0);
    output.vPosition = transformInput(v, output.vPos3D, output.vNormal, output.vTangent, output.vViewer);
    output.vColorDif = any(v.vColorDif.rgb) ? v.vColorDif : 1;

    output.vUV01 = float4(v.vUV0.xy, v.vUV1.xy);
    output.vUV23 = float4(v.vUV2.xy, v.vUV3.xy);
    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] = output.vTangent.xyz;
    worldToTangentSpace[1] = normalize(cross(output.vTangent.xyz, output.vNormal.xyz)*(-output.vTangent.w));
    worldToTangentSpace[2] = output.vNormal.xyz;
    output.vBumpLit = float4(normalize(mul(worldToTangentSpace, -g_lightDir.xyz)), 1);
    output.vBumpViewer = float4(mul(worldToTangentSpace, output.vViewer.xyz), 1);

    return output;
}
#endif //VERTEX_SHADER

#ifdef GEOMETRY_SHADER
[maxvertexcount(3)]
void flatshadeGS(triangle VS_OUTPUT ptIn[3], inout TriangleStream<VS_OUTPUT> tristream)
{
  VS_OUTPUT gout;
  float4 vNorm = normalFromPoints(ptIn[0].vPos3D, ptIn[1].vPos3D, ptIn[2].vPos3D);
  [unroll]
  for (int i = 0; i < 3; i++)
  {
    gout = ptIn[i];
    gout.vNormal = lerp(ptIn[i].vNormal, vNorm, g_geomLevels.z); //adjust normal to flat-shaded (%)
    // bump-transformed light:
    //-----
    float3x3 worldToTangentSpace;
    worldToTangentSpace[0] = gout.vTangent.xyz;
    worldToTangentSpace[1] = normalize(cross(gout.vTangent.xyz, gout.vNormal.xyz)*(-gout.vTangent.w));
    worldToTangentSpace[2] = gout.vNormal.xyz;
    gout.vBumpLit = float4(normalize(mul(worldToTangentSpace, -g_lightDir.xyz)), 1);
    gout.vBumpViewer = float4(mul(worldToTangentSpace, gout.vViewer.xyz), 1);

    tristream.Append(gout);
  }
}
#endif //GEOMETRY_SHADER

#ifdef PIXEL_SHADER
//------------------------------------------------------------
//  PixelShader: generic color+Bump+SpecMap
//------------------------------------------------------------
float4 mainPS(in VS_OUTPUT v) : SV_TARGET
{
    float4 oColor;
    float4 CONST_TEXEL   = float4(1,1,1,1);
    float4 VCOLOR_TEXEL  = v.vColorDif;
    float4 PERVERTEXCOLOR = lerp(1, VCOLOR_TEXEL, g_colorBlend.x);
    float4 BUMPMAP_TEXEL = BUMPMAP_SOURCE.Sample(samplerBump, BUMPMAP_UV_SOURCE*g_bumpConfig.zw);
    float4 SPECMAP_TEXEL = SPECMAP_SOURCE.Sample(samplerSpec, SPECMAP_UV_SOURCE*g_specConfig.zw);
    float4 MASK_TEXEL    = MASK_SOURCE.Sample(samplerMask, MASK_UV_SOURCE*g_maskConfig.zw);
    MASK_TEXEL    = lerp(MASK_TEXEL,    g_MaskTrans.Sample(samplerMask, MASK_UV_SOURCE*g_maskConfig.zw), MASK_TRANSITION)*g_maskConfig.x*(MASK_INPUT_MASK);
    SPECMAP_TEXEL = lerp(SPECMAP_TEXEL, g_SpecMapTrans.Sample(samplerSpec, SPECMAP_UV_SOURCE*g_specConfig.zw), SPECMAP_TRANSITION);
    BUMPMAP_TEXEL = lerp(BUMPMAP_TEXEL, g_BumpMapTrans.Sample(samplerBump, 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);
    
    //
    // 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 correction of bumpmap
    oColor.a = lerp(saturate(dot(v.vViewer.xyz, normal)), saturate(dot(v.vBumpViewer.xyz, bumpNormal)), g_bumpConfig.x);
    
    float3 fSpecMapColor    = SPECMAP_INPUT;
    
    //
    // angular level on bump:
    if (g_bumpConfig.y >= 0)
      specData.x = lerp(1, oColor.a, g_bumpConfig.y)*g_bumpConfig.x;
    else
      specData.x = lerp(1, 1-oColor.a, abs(g_bumpConfig.y))*g_bumpConfig.x;
     
    //
    // angular level on spec:
    if (g_specConfig.y >= 0)
      specData.y = lerp(1, oColor.a, g_specConfig.y)*g_specConfig.x;
    else
      specData.y = lerp(1, 1-oColor.a, abs(g_specConfig.y))*g_specConfig.x;
    
    specData.ba = float2(lerp(LightTemp.x, LightTemp.z, specData.x), lerp(LightTemp.y, LightTemp.w, specData.x));
    
    //
    // 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 fSpecularColor = g_colors[2].rgb*(fSpecMapColor*(SPECMAP_INPUT_MASK)*specData.y)*saturate(specData.a + specData.a*(1+specData.b)*saturate(advShineOpac.g));

    //regular:
    oColor.rgb =
                // ambient: 
                (g_colors[0].rgb + 0.2*PERVERTEXCOLOR.rgb + 0.2*g_ambientLight.rgb)*g_ambientLight.rgb +
                // diffuse component:
                (fAdvancedDiffuseColor*PERVERTEXCOLOR.rgb*(1-fEffectColor.a) + fEffectColor.rgb*fEffectColor.a)*max((EMISSIVECOLOR_INPUT_MASK)*advShineOpac.r*2*g_colors[3].a, specData.b) +
                // matted:
                advShineOpac.r*(
                  // specular component:
                  fSpecularColor +
                  // emissive component:
                  g_colors[3].rgb*(EMISSIVECOLOR_INPUT_MASK)*g_colors[3].a
                );
                

#ifndef ALPHABLEND_ENABLED
    oColor.a = g_alpha.y;
#else
    if (g_alpha.w >= 0)
      oColor.a = lerp(1, oColor.a, g_alpha.w);
    else
      oColor.a = lerp(1, 1-oColor.a, abs(g_alpha.w));
    oColor.a = saturate(lerp(1, ALPHABLEND_INPUT, g_alpha.z)*ALPHABLEND_VERTEXCOLOR*oColor.a*g_alpha.y
# ifndef ALPHATEST_ENABLED
                        + advShineOpac.b + length(fSpecularColor)*0.5
# endif//ALPHATEST_ENABLED
                        );
#endif//ALPHABLEND_ENABLED

#ifdef ALPHATEST_ENABLED
    clip(oColor.a - g_alpha.x);
#endif//ALPHATEST_ENABLED

    return oColor;
}
#endif //PIXEL_SHADER

