/***************************************************************************
 *                          Zanoza Modeler v3.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 shaders common routines
 *--------------------------------------------------------------------------
 * @histroy: 12.09.2011. Created
 * @histroy: 21.01.2023. Remastered for common routines only file
<[[
Version  = 2.0.2
Engine = 11
]]>
 */

#define ADVANCED_COLOR_DIFFUSELEVEL(_v) float4 _v = float4( \
	g_diffuse2Color.a*(DIFFUSECOLOR2_INPUT_MASK), \
	g_diffuse3Color.a*(DIFFUSECOLOR3_INPUT_MASK), \
	g_diffuse4Color.a*(DIFFUSECOLOR4_INPUT_MASK), 0);

#define ADVANCED_COLOR_DIFFUSEVAR(_v, _a) float3 _v = ((g_colors[1].rgb*(1 - _a.r) + g_diffuse2Color.rgb*_a.r)*(1 - _a.g) + g_diffuse3Color.rgb*_a.g)*(1 - _a.b) + g_diffuse4Color.rgb*_a.b;

#define ADVANCED_COLOR_EFFECTLEVELS(_v) float4 _v = float4(g_dustColor.a*g_effectLevels.r*(DUSTCOLOR_INPUT_MASK), \
	g_scratchColor.a*g_effectLevels.g*(SCRATCHCOLOR_INPUT_MASK), \
	g_dirtColor.a*g_effectLevels.b*(DIRTCOLOR_INPUT_MASK), \
	g_burnColor.a*g_effectLevels.a*(BURNCOLOR_INPUT_MASK));

#define ADVANCED_COLOR_EFFECTVAR(_v, _e) float4 _v = float4(((g_dustColor.rgb*_e.r*(1-_e.g) + \
	g_scratchColor.rgb*_e.g)*(1-_e.b) + \
	g_dirtColor.rgb*_e.b)*(1-_e.a) + g_burnColor.rgb*_e.a, \
	saturate(dot(_e.rgba, 1)));

#define ADVANCED_COLOR_OPTIONS(_v, _f, _a) float4 _v = (float4)0; \
	_v.r = saturate(1-dot(_f, float4(DUSTCOLOR_MATTED, SCRATCHCOLOR_MATTED, DIRTCOLOR_MATTED, BURNCOLOR_MATTED)) - \
			dot(_a, float4(DIFFUSECOLOR2_MATTED, DIFFUSECOLOR3_MATTED, DIFFUSECOLOR4_MATTED, 0))); \
	_v.g = dot(_f, float4(DUSTCOLOR_GLOSSY, SCRATCHCOLOR_GLOSSY, DIRTCOLOR_GLOSSY, BURNCOLOR_GLOSSY)) + \
			dot(_a, float4(DIFFUSECOLOR2_GLOSSY, DIFFUSECOLOR3_GLOSSY, DIFFUSECOLOR4_GLOSSY, 0)); \
	_v.b = dot(_f, float4(DUSTCOLOR_OPAQUE, SCRATCHCOLOR_OPAQUE, DIRTCOLOR_OPAQUE, BURNCOLOR_OPAQUE)) + \
			dot(_a, float4(DIFFUSECOLOR2_OPAQUE, DIFFUSECOLOR3_OPAQUE, DIFFUSECOLOR4_OPAQUE, 4));

#ifdef GEOMETRY_SHADER
//
// evaluates normal from cross-product on three points. Generally, for flat-shading purpose;
float4 normalFromPoints(in float4 pt0, in float4 pt1, in float4 pt2) : NORMAL
{
  float4 v1 = pt2 - pt0;
  float4 v2 = pt1 - pt0;
  return float4(normalize(cross(v2.xyz, v1.xyz)),1);
}
#endif //GEOMETRY_SHADER

#ifdef VERTEX_SHADER

float4x4 blendAddMatrix(float3x4 trans, float weight)
{
  float3x4 m = trans*weight;
  m[0][3] = m[1][3] = m[2][3] = 0;
  return float4x4(m, float4(trans[0].w*weight, trans[1].w*weight, trans[2].w*weight, 1));
}


//
// common vertex transformation function. 
// respects deformation and transformation tweening;
//
float4 transformInput(in VS_INPUT v, inout float4 vPos3D, inout float4 vNorm, inout float4 vTangent, inout float4 vView) : POSITION
{
  float4x4 mTransform = (float4x4)0;
  if (g_deform.y > 0.01)
  {
    float4 weights0 = {v.vWeights0.x*g_deform.y, v.vWeights0.y*g_deform.y, v.vWeights0.z*g_deform.y, v.vWeights0.w*g_deform.y};
    float4 weights1 = {v.vWeights1.x*g_deform.y, v.vWeights1.y*g_deform.y, v.vWeights1.z*g_deform.y, 
                        (1 - v.vWeights0.x - v.vWeights0.y - v.vWeights0.z - v.vWeights0.w - v.vWeights1.x - v.vWeights1.y - v.vWeights1.z)*g_deform.y};
    mTransform += blendAddMatrix(g_animMat[v.vBones0.x], weights0.x);
    mTransform += blendAddMatrix(g_animMat[v.vBones0.y], weights0.y);
    mTransform += blendAddMatrix(g_animMat[v.vBones0.z], weights0.z);
    mTransform += blendAddMatrix(g_animMat[v.vBones0.w], weights0.w);
    mTransform += blendAddMatrix(g_animMat[v.vBones1.x], weights1.x);
    mTransform += blendAddMatrix(g_animMat[v.vBones1.y], weights1.y);
    mTransform += blendAddMatrix(g_animMat[v.vBones1.z], weights1.z);
    mTransform += blendAddMatrix(g_animMat[v.vBones1.w], weights1.w);
  }
  else
    mTransform[0][0] = mTransform[1][1] = mTransform[2][2] = mTransform[3][3] = 1;
    

  // [optionally] deformed position:
  vPos3D = float4(v.vPosition.xyz + g_deform.x*v.vDeformPosition.xyz, 1);
  // [optionally] transformed position:
  vPos3D = float4(mul(float4(mul(vPos3D, (float4x3)mTransform),1), (float4x3)g_mWorld),1);

  vView = float4(normalize(g_viewPosition.xyz - vPos3D.xyz)*g_viewPosition.w, 1);
  // position in camera space:
  float4 vPosScreen = float4(mul(vPos3D, (float4x3)g_mView),1);
  // position on screen:
  vPosScreen = mul(vPosScreen, g_mProj);

  // [optionally] deformed normal:
  vNorm = vNorm + g_deform.x*any(v.vDeformNormal.xyz)*float4(v.vDeformNormal.xyz*4-float3(2,2,2), 0);
  // transformed normal:
  vNorm.xyz = mul(mul(vNorm.xyz, (float3x3)mTransform), (float3x3)g_mWorld);
  // transformed tangent:
  vTangent = float4(mul(mul(vTangent.xyz, (float3x3)mTransform), (float3x3)g_mWorld), vTangent.w);

  return vPosScreen;
}

#endif //VERTEX_SHADER
