<?xml version="1.0" encoding="utf-8"?>

<CustomShader version="5">
    <Parameters>
        <Parameter name = "windSnowLeafScale" target = "windSnowLeafScale" type = "float4" group="base"     defaultValue = "1.0 1.0 1.0 0.0"   minValue = "0.0 0.0 0.0 0.0"      maxValue = "1.0 1.0 1.0 10000.0"/>
    </Parameters>
    <UvUsages/>
    <Textures>
        <Texture name="mMaskMap" group="seasonal" defaultColorProfile="linearRGB"/>
    </Textures>
    <Variations>
        <Variation name = "billboard180" groups="base">
<![CDATA[
    #define BILLBOARD_180
]]>
        </Variation>
        <Variation name="SEASONAL_BILLBOARD180" groups="base seasonal">
            <UvUsages>
                <UvUsage textureName="baseMap"  uvType="uv0" uvScale="0.5"/>
            </UvUsages>
<![CDATA[
    #define SEASONAL
    /*

    TODO: blending based on mUVShift and mUVShift2

    Season states:
        cShared3 = 0 = summer
        cShared3 = 1 = autumn
        cShared3 = 2 = winter
        cShared3 = 3 = spring
        cShared3 = 4 = summer
    */
    #define BILLBOARD_180
    #define CHECKERBOARD_BLENDING
]]>
        </Variation>
    </Variations>
    <LodLevel startDistance="0">
        <CodeInjections>
            <CodeInjection position="CONFIG_DEFINES">
<![CDATA[
#if defined(SEASONAL)
    #define ALPHA_TESTED
#endif

#if defined(SHADING_RATE_IMAGE_ACTIVE) && !defined(SYSTEM_SHADING_RATE_REQUIRED)
#define SYSTEM_SHADING_RATE_REQUIRED
#endif
]]>
            </CodeInjection>
            <CodeInjection position="SAMPLERS">
<![CDATA[
#if defined(SEASONAL)
    sampler2D mMaskMap;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="OBJECT_PARAMETERS">
<![CDATA[
/*
    windSnowLeafScale.r - wind intensity
    windSnowLeafScale.g - snow intensity
    windSnowLeafScale.b - leaf alpha
    windSnowLeafScale.a - (treePos.x + treePos.y + treePos.z) should be > 0.0
*/
    float4 windSnowLeafScale;
]]>
            </CodeInjection>
            <CodeInjection position="LIB_FUNCTION_VS">
<![CDATA[
float fitRange(float mIn,float mOldMin,float mOldMax ,float mNewMin ,float mNewMax ){
    return (mNewMin + (mIn - mOldMin) * (mNewMax  - mNewMin ) / (mOldMax  - mOldMin));
}
]]>
            </CodeInjection>
            <CodeInjection position="VS_OUTPUT">
<![CDATA[
#if defined(SEASONAL)
    float3 randTintBranchDistance : TEXCOORDn;
    float4 texCoordsWinter        : TEXCOORDn;
    float4 texCoordsSpring        : TEXCOORDn;
    float4 texCoordsSummer        : TEXCOORDn;
    float4 texCoordsAutumn        : TEXCOORDn;
    float4 texCoordsMask          : TEXCOORDn;
#endif
#if defined(BILLBOARD_180)
    float  texCoords2Weight     : TEXCOORDn;
    float2 texCoords2           : TEXCOORDn;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="POST_GET_WORLD_POSE_VS">
<![CDATA[
float3 upVector     = float3(object.modelMatrix[0][1], object.modelMatrix[1][1], object.modelMatrix[2][1]);
float3 camToPos     = float3(object.modelMatrix[0][3], object.modelMatrix[1][3], object.modelMatrix[2][3]);
#if defined(DEPTH_VIS)
// orthographic projection, so vector from camera is just viewspace(0,0,-1)
camToPos = -float3(invViewMatrix[0][2], invViewMatrix[1][2], invViewMatrix[2][2]);
#endif

#if defined(BILLBOARD_180)
    float mUVShift;
    float mUVShift2;
    {
        float3 mProjectCamToPos      = normalize(camToPos -upVector*dot(upVector,camToPos));
        float3 mProjectedWorldNormal = normalize(worldNormal -upVector*dot(upVector,worldNormal));

        float3 camCross     = cross( mProjectCamToPos, mProjectedWorldNormal );
        float mEyeAngle     = acos(clamp(-dot( mProjectCamToPos, mProjectedWorldNormal), -1.0, 1.0));
        float mUVShiftTileF = 8.0 * 0.5 * mEyeAngle / 3.1415926535897932384626433832795;
        if (camCross.y > 0) {
            mUVShiftTileF *= -1;
        }
        float mUVShiftTile1 = floor(mUVShiftTileF);
        mUVShift            = mUVShiftTile1/8.0;
    #if defined(CHECKERBOARD_BLENDING)
        Out.texCoords2Weight = floor(saturate(2*(mUVShiftTileF-mUVShiftTile1) - 0.5)*4);
    #else
        Out.texCoords2Weight = saturate(2*(mUVShiftTileF-mUVShiftTile1) - 0.5);
    #endif
        mUVShift2           = mUVShift + 1.0/8.0;
    }
    #if defined(SEASONAL)
        mUVShift  = frac(mUVShift)*0.5;
        mUVShift2 = frac(mUVShift2)*0.5;
    #endif
#endif

float3 sideVector   = normalize(cross(camToPos, upVector));

// Wind animation
float windXMovement = 0;
float3 windDirection;
windDirection.xz = normalize(float2(cShared1, cShared2));
windDirection.y = 0;
float windStrength = cShared0*object.windSnowLeafScale.x;
#if !defined(DEPTH_VIS) // avoid shadow artefacts by not animating in the shadow map
if (windStrength > 0.0001) {
    float3 treePos = float3(object.modelMatrix[0][3] + invViewMatrix[0][3],
                            object.modelMatrix[1][3] + invViewMatrix[1][3],
                            object.modelMatrix[2][3] + invViewMatrix[2][3]);
    float3 windSideDirection = cross(float3(0,1,0), windDirection);
    float treeVarSeed = treePos.x + treePos.y + treePos.z;

    float3 trunkMoveDirection = windDirection;
    trunkMoveDirection = normalize(trunkMoveDirection + windSideDirection*sin(0.9 * cTime_s + treeVarSeed + 0.1)*0.3);

    float normalizedTreeY = In.position.y/30;
    float trunkOffsetScale = (1*max(windStrength-0.1,0)/0.9 + sin( 1.5 * cTime_s + treeVarSeed)*0.7*windStrength)*normalizedTreeY*normalizedTreeY;
    float3 trunkOffset = trunkMoveDirection.xyz * trunkOffsetScale;

    windXMovement = dot(trunkOffset, sideVector);
}
#endif

// Allow scaling
float xScale = length(float3(object.modelMatrix[0][0], object.modelMatrix[1][0], object.modelMatrix[2][0]));
float xPos = In.position.x*xScale;
float xOffset = xPos+windXMovement;

#if defined(DEPTH_VIS)
// restore camToPos as the object center
camToPos = float3(object.modelMatrix[0][3], object.modelMatrix[1][3], object.modelMatrix[2][3]);
#endif
worldPosition = camToPos + sideVector*xOffset + upVector*In.position.y;
prevWorldPosition = worldPosition;

#if defined(DEPTH_VIS)
    worldPosition -= float3(invViewMatrix[0][2], invViewMatrix[1][2], invViewMatrix[2][2])*In.position.y*0.5;    // ~45 degree tilt of the billboard to avoid self-shadowing
#endif
]]>
            </CodeInjection>
            <CodeInjection position="POST_GET_NORMALS_VS">
<![CDATA[
{
    float3 tangent      = getTangent(In, object);
    float tangentSide   = In.tangent.w;
    float3 bitangent    = getBitangent(In, object);
    float3 normal       = getNormal(In, object);

    normal      = float3(0,0,1);
    tangent     = float3(1,0,0);
    tangentSide = 1;

    worldNormal.xyz  = float3(invViewMatrix[0][2], 0, invViewMatrix[2][2]);
    worldNormal     = normalize(worldNormal);

    worldTangent.xyz = float3(invViewMatrix[0][0], 0, invViewMatrix[2][0]);
    worldTangent    = normalize(worldTangent);

    worldBitangent  = normalize(cross(worldNormal.xyz, worldTangent.xyz)*tangentSide);
}
]]>
            </CodeInjection>
            <CodeInjection position="VS_END">
<![CDATA[
{
#if defined(SHADING_RATE_IMAGE_ACTIVE) && defined(SYSTEM_SHADING_RATE_REQUIRED)
Out.shadingRate = SHADING_RATE_1X1;
#endif
}
]]>
            </CodeInjection>
            <CodeInjection position="POST_SET_TEXCOORDS_VS">
<![CDATA[
#if defined(SEASONAL)
    {
        float3 treePos = float3(object.modelMatrix[0][3] + invViewMatrix[0][3],
                                object.modelMatrix[1][3] + invViewMatrix[1][3],
                                object.modelMatrix[2][3] + invViewMatrix[2][3]);
        float treePosSum = (object.windSnowLeafScale.w > 0) ? object.windSnowLeafScale.w : (abs(treePos.x) + abs(treePos.y) + abs(treePos.z));
        treePosSum = ceil(10.0 * treePosSum)/10.0;
        float x = 0.10812 * treePosSum;
        float y = 0.21237 * treePosSum;
        Out.randTintBranchDistance.x = abs(frac(x) - 0.5) * 2; // 0-1 range triangle wave
        Out.randTintBranchDistance.y = abs(frac(y) - 0.5) * 2;
        Out.randTintBranchDistance.z = 0.0;
    }
    float2 mUV = getDefaultTexCoords(In, object);
    Out.texCoordsWinter.xy = mUV*float2(0.5,0.5) + float2(0.5,0.0);
    Out.texCoordsWinter.zw = Out.texCoordsWinter.xy;
    Out.texCoordsSpring.xy = mUV*float2(0.5,0.5) + float2(0.0,0.5);
    Out.texCoordsSpring.zw = Out.texCoordsSpring.xy;
    Out.texCoordsSummer.xy = mUV*float2(0.5,0.5) + float2(0.5,0.5);
    Out.texCoordsSummer.zw = Out.texCoordsSummer.xy;
    Out.texCoordsAutumn.xy = mUV*float2(0.5,0.5) + float2(0.0,0.0);
    Out.texCoordsAutumn.zw = Out.texCoordsAutumn.xy;
    Out.texCoordsMask.xy = mUV;
    Out.texCoordsMask.zw = Out.texCoordsMask.xy;
    // Default trasition Summer to Autumn
    Out.defaultTexCoords = Out.texCoordsSummer.xy;
#endif
#if defined(BILLBOARD_180)
    Out.texCoords2 = Out.defaultTexCoords;
    Out.texCoords2.x += mUVShift2;
    Out.defaultTexCoords.x += mUVShift;
    #if defined(SEASONAL)
        Out.texCoordsWinter.z += mUVShift2;
        Out.texCoordsSpring.z += mUVShift2;
        Out.texCoordsSummer.z += mUVShift2;
        Out.texCoordsAutumn.z += mUVShift2;
        Out.texCoordsMask.z   += mUVShift2*2;
        Out.texCoordsWinter.x += mUVShift;
        Out.texCoordsSpring.x += mUVShift;
        Out.texCoordsSummer.x += mUVShift;
        Out.texCoordsAutumn.x += mUVShift;
        Out.texCoordsMask.x   += mUVShift*2;
    #endif
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "LIB_FUNCTION_FS">
<![CDATA[
// Season states:
// cShared3 = 0 = summer
// cShared3 = 1 = autumn
// cShared3 = 2 = winter
// cShared3 = 3 = spring
// cShared3 = 4 = summer
// cShared4 = 0 .. 1 = snow control
/*
    0.00 = June      - fully spring green
    0.33 = July      -
    0.66 = August    - fully dark green
    1.00 = September - half green/orange
    1.33 = October   - fully orange
    1.66 = November  - half lost leaves
    2.00 = December  - almost no leaves
    2.33 = January   - no leaves
    2.66 = February  - no leaves
    3.00 = March     - small leaves
    3.33 = April     -
    3.66 = May       - fully spring green
*/
float getSnowMask(ObjectParameters& object, float3 mNormal, float mBackfaceScale){
    float snowLevel = min(cShared4, 1);
    float mTransition = snowLevel*snowLevel*snowLevel; // pow(cShared4,3);
    float NdotY = mNormal.y; // dot(mNormal, float3(0.0, 1.0, 0.0));
    NdotY = max(NdotY * mBackfaceScale, NdotY * (1.0-mBackfaceScale)) + mBackfaceScale;
    float mSnowMask = object.windSnowLeafScale.y*mTransition*saturate(NdotY);
    return mSnowMask;
    //return mSnowMask * 0.75 + 0.25;
}
// simplifed smoothstep
// remaps the values of x between a and b to the range [0, 1], and clamps values outside this range
float linearstepFS(float a, float b, float x){
    return saturate((x - a)/(b - a));
}
float fitRangeFS(float mIn,float mOldMin,float mOldMax ,float mNewMin ,float mNewMax ){
    return (mNewMin + (mIn - mOldMin) * (mNewMax  - mNewMin ) / (mOldMax  - mOldMin));
}
]]>
            </CodeInjection>
            <CodeInjection position = "FS_GLOBALS">
<![CDATA[
    float  gSnowMask;
    bool   gIsSnowing;
    float3 gSnowDiffuse;
    float3 gSnowSpecular;
#if defined(BILLBOARD_180)
    #if defined(CHECKERBOARD_BLENDING)
        bool blendScale;
        float2 maskDdx;
        float2 maskDdy;
        float2 defaultDdx;
        float2 defaultDdy;
    #else
        float blendScale;
    #endif
#endif
#if defined(SEASONAL)
    float gSeason;              // current season 0,1,2,3,4
    float gBranchesMask;        // 0..1   stencil-style mask only for branches
    float gLeavesMask;          // 0..1   stencil-style mask only for leaves
    float gLeavesGrow;          // 0.5..1 radial growing gradient mask only for leaves
    float gLeavesRand;          // 0..1   random value per leaf
    float gAlpha;               // alpha channel
#endif
]]>
            </CodeInjection>
            <CodeInjection position="START_FS">
<![CDATA[
#if defined(BILLBOARD_180)
    {
    #if defined(CHECKERBOARD_BLENDING)
        float2 pixelPosFloor = floor(viewportSize.xy * (In.vs.screenPos.xy/In.vs.screenPosW + 0.5));
        float2 blockPixelPos = fmod(pixelPosFloor, 2);
        // This will in 2x2 pixel block indices:
        // 1 2
        // 3 0
        float pixelIndex = fmod(blockPixelPos.x + 2*blockPixelPos.y + 1, 4);
        // texCoords2Weight: 0-4 means blending out 0: all visible, 4: nothing visible
        globals.blendScale = pixelIndex < In.vs.texCoords2Weight;

        globals.maskDdx = ddx(In.vs.texCoordsMask.xy);
        globals.maskDdy = ddy(In.vs.texCoordsMask.xy);
        globals.defaultDdx = ddx(In.vs.defaultTexCoords);
        globals.defaultDdy = ddy(In.vs.defaultTexCoords);
    #else
        globals.blendScale = In.vs.texCoords2Weight;
    #endif
    }
#endif
#if defined(SEASONAL)
    #if defined(BILLBOARD_180) && defined(CHECKERBOARD_BLENDING) && 0
        float3 mMask = tex2Dgrad(mMaskMap, globals.blendScale ? In.vs.texCoordsMask.zw   : In.vs.texCoordsMask.xy, globals.maskDdx, globals.maskDdy).xyz;
    #else
        #if defined(ALBEDO_MAP)
            float3 mMask = tex2D(mMaskMap, In.vs.texCoordsMask.xy).xyz;
        #else
            float3 mMask = float3(0,0,0);
        #endif
    #endif
    // ----
    globals.gAlpha      = 1.0;
    {
        float scale1    = saturate(cShared3); // 0..1
        float scale2    = 1-saturate(cShared3-2.0); // 2..3
        float offset    = 0.4*In.vs.randTintBranchDistance.x * scale1*scale2; // time offset
        globals.gSeason = max(cShared3 - offset,0.0); // current season
    }
    // ----
    globals.gBranchesMask = mMask.x;
    globals.gLeavesGrow   = mMask.y;
    // bring grow from 0.5..1.0 to 1.0..1.0 range (stencil-style)
    globals.gLeavesMask    = clamp(2*globals.gLeavesGrow,0.0,1.0);
    globals.gLeavesRand    = mMask.z;
#endif
    globals.gSnowDiffuse  = float3(0.7300,0.7668,0.8356);
    globals.gSnowSpecular = float3(0.1922,0.8706,0.0000);
    globals.gSnowMask  = 0.0;
    globals.gIsSnowing = cShared4 > 0.0 && object.windSnowLeafScale.y > 0.0;
]]>
            </CodeInjection>
            <CodeInjection position="POST_DIFFUSE_COLOR_FS">
<![CDATA[
#if defined(BILLBOARD_180) && !defined(SEASONAL)
    #if defined(ALBEDO_MAP)
        float4 combinedDiffuseAlpha = lerp(tex2D(baseMap, ALBEDO_MAP_TEXCOORDS), tex2D(baseMap, In.vs.texCoords2), globals.blendScale);
        diffuseColor.xyz = combinedDiffuseAlpha.xyz;
    #endif
#endif
#if defined(SEASONAL)
    // compute transition between seasons
    float mColorLeavesTransition = 0.0;
    float mTransition = 0.0;
    // ----
    #if defined(BILLBOARD_180) && defined(CHECKERBOARD_BLENDING) && 0
        float3 mColorBranches = tex2Dgrad(baseMap, globals.blendScale ? In.vs.texCoordsWinter.zw : In.vs.texCoordsWinter.xy, globals.defaultDdx, globals.defaultDdy).rgb;
        float3 mColorSpring   = tex2Dgrad(baseMap, globals.blendScale ? In.vs.texCoordsSpring.zw : In.vs.texCoordsSpring.xy, globals.defaultDdx, globals.defaultDdy).rgb;
        float3 mColorSummer   = tex2Dgrad(baseMap, globals.blendScale ? In.vs.texCoordsSummer.zw : In.vs.texCoordsSummer.xy, globals.defaultDdx, globals.defaultDdy).rgb;
        float3 mColorAutumn   = tex2Dgrad(baseMap, globals.blendScale ? In.vs.texCoordsAutumn.zw : In.vs.texCoordsAutumn.xy, globals.defaultDdx, globals.defaultDdy).rgb;
    #else
        #if defined(ALBEDO_MAP)
            float3 mColorBranches = tex2D(baseMap,  In.vs.texCoordsWinter.xy).rgb;
            float3 mColorSpring   = tex2D(baseMap,  In.vs.texCoordsSpring.xy).rgb;
            float3 mColorSummer   = tex2D(baseMap,  In.vs.texCoordsSummer.xy).rgb;
            float3 mColorAutumn   = tex2D(baseMap,  In.vs.texCoordsAutumn.xy).rgb;
        #else
            float3 mColorBranches = float3(0,0,0);
            float3 mColorSpring   = float3(0,0,0);
            float3 mColorSummer   = float3(0,0,0);
            float3 mColorAutumn   = float3(0,0,0);
        #endif
    #endif
    mColorSpring = lerp( mColorSpring, float3(0.335,0.620,0.049), 0.30*In.vs.randTintBranchDistance.y );
    mColorSummer = lerp( mColorSummer, float3(0.026,0.097,0.029), 0.30*In.vs.randTintBranchDistance.y );
    mColorAutumn = lerp( mColorAutumn, float3(0.981,0.000,0.000), 0.40*In.vs.randTintBranchDistance.y );
    // ----
    float3 mColorLeaves = mColorSummer;
    float  mLeavesMaskTansition  = globals.gLeavesRand*saturate((2.0*globals.gLeavesGrow));
    float  mLeavesMask  = globals.gLeavesMask;
    /*

        0.0..0.7 Spring to Summer (only color)
        0.7..1.5 Summer to Autumn (only color)
        1.5..2.1 Autumn to Winter (losing leaves)
        2.1..2.6 Winter (no leaves)
        2.6..4.0 Winter to Spring (growing leaves)

    */
    {
        // 0.00 = June      - fully spring green
        // 0.33 = July      -
        // 0.66 = August    - fully dark green
        mTransition = fitRangeFS(globals.gSeason,0.0,0.70,0.00,1.00);
        mColorLeavesTransition = mTransition*linearstepFS(mTransition+0.1,mTransition,mLeavesMaskTansition);
        // color of the leaves
        mColorLeaves = lerp(mColorSpring, mColorSummer, mColorLeavesTransition);
        // combine it with branches
        diffuseColor = lerp(mColorBranches,mColorLeaves,mLeavesMask);
        globals.gAlpha = globals.gBranchesMask + globals.gLeavesGrow;
    }
    if ( globals.gSeason >= 0.70 && globals.gSeason < 1.50 ) {
        // 0.66 = August    - fully dark green
        // 1.00 = September - half green/orange
        // 1.33 = October   - fully orange
        mTransition = fitRangeFS(globals.gSeason,0.7,1.50,0.00,1.00);
        mColorLeavesTransition = mTransition*linearstepFS(mTransition+0.1,mTransition,mLeavesMaskTansition);
        // color of the leaves
        mColorLeaves = lerp(mColorSummer, mColorAutumn, mColorLeavesTransition);
        // combine it with branches
        diffuseColor = lerp(mColorBranches,mColorLeaves,mLeavesMask);
    } else if ( globals.gSeason >= 1.50  && globals.gSeason < 2.1 ) {
        // 1.66 = Novemner  - half lost leaves
        // 2.00 = December  - almost no leaves
        // 2.33 = January   - no leaves
        mTransition = fitRangeFS(globals.gSeason,1.5,2.1,0.00,1.00);
        // color of the leaves
        mColorLeaves = mColorAutumn;
        float autumnToWinter = (1-mTransition) < 0.95*globals.gLeavesRand;
        globals.gAlpha = lerp(globals.gBranchesMask + globals.gLeavesGrow, globals.gBranchesMask, autumnToWinter);
        autumnToWinter = (1 - autumnToWinter)*globals.gLeavesMask;

        diffuseColor = lerp(mColorBranches,mColorLeaves,autumnToWinter);
    } else if ( globals.gSeason >= 2.1 && globals.gSeason < 2.6 ) {
        // 2.33 = January   - no leaves
        // 2.66 = February  - no leaves
        // 3.00 = March     - small leaves
        diffuseColor   = mColorBranches;
        globals.gAlpha = globals.gBranchesMask;
    } else if ( globals.gSeason >= 2.6 && globals.gSeason <= 4.0 ) {
        // 3.00 = March     - small leaves
        // 3.33 = April     -
        // 3.66 = May       - fully spring green
        mTransition    = fitRangeFS(globals.gSeason,2.6,4.0,0.00,1.00);
        // color of the leaves
        mColorLeaves = mColorSpring;
        float winterToSpring = mTransition <= 1-globals.gLeavesGrow + 0.45*globals.gLeavesRand;
        globals.gAlpha = lerp(globals.gBranchesMask + globals.gLeavesGrow, globals.gBranchesMask, winterToSpring);
        winterToSpring = (1 - winterToSpring)*globals.gLeavesMask;
        // combine it with branches
        diffuseColor = lerp(mColorBranches,mColorLeaves,winterToSpring);
    }
#endif
    { // Snow mixing code
        if (globals.gIsSnowing){
            // pixelShader normal computed before this point, right after PARALLAX_MAPPING_FS
            globals.gSnowMask = getSnowMask(object,normal,-0.05);
            diffuseColor.rgb = lerp( diffuseColor.rgb, globals.gSnowDiffuse.rgb, globals.gSnowMask );
        }
    }
]]>
            </CodeInjection>
            <CodeInjection position = "POST_GLOSS_COLOR_FS">
<![CDATA[
    { // Snow mixing code
        if (globals.gIsSnowing){
            float3 mPbrMapValues = lerp( float3(1-roughness,bakedAO,metalness), globals.gSnowSpecular, globals.gSnowMask );
            roughness = 1-mPbrMapValues.x;
            bakedAO   = mPbrMapValues.y;
            metalness = mPbrMapValues.z;
        }
    }
]]>
            </CodeInjection>
            <CodeInjection position="ALPHA_FS">
<![CDATA[
#if defined(BILLBOARD_180) && !defined(SEASONAL)
   #if defined(ALBEDO_MAP)
        alpha = combinedDiffuseAlpha.w;
    #endif
#endif
#if defined(SEASONAL)
    alpha = globals.gAlpha;
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "GET_UNNORMALIZED_TANGENT_SPACE_NORMAL_FS">
<![CDATA[
#if defined(BILLBOARD_180)
    #if defined( NORMAL_MAP )
        #if defined(SEASONAL)
            //return lerp(tex2D(normalMap, In.vs.texCoordsMask.xy).xyz, tex2D(normalMap, In.vs.texCoordsMask.zw).xyz, globals.blendScale) - 0.5;
            return tex2D(normalMap, In.vs.texCoordsMask.xy) - 0.5;
        #else
            return lerp(tex2D(normalMap, In.vs.defaultTexCoords).xyz, tex2D(normalMap, In.vs.texCoords2).xyz, globals.blendScale) - 0.5;
        #endif
    #endif
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "GET_TANGENT_SPACE_NORMAL_FS">
<![CDATA[
#if defined(BILLBOARD_180)
    #if defined( NORMAL_MAP )
        return normalize(getUnnormalizedTangentSpaceNormal(In, globals, object));
    #endif
#endif
]]>
            </CodeInjection>
            <CodeInjection position="POST_GET_LIGHTING_FS">
<![CDATA[
{
    float NdotL = dot(normal, lightDir);
    if (NdotL < 0) {
        NdotL = -NdotL*0.35;
    }
    NdotL = min(NdotL, 1);
    float3 lighting = atten*NdotL * (diffuseShading + specularShading) * lightColor;
    return lighting;
}
]]>
            </CodeInjection>
            <CodeInjection position="FINAL_POS_FS">
<![CDATA[
{
#if defined(DEBUG_SHOW_CUSTOM1)
    oColor.xyz *= 0.0001;
    #if defined(SEASONAL)
        oColor.xyz += In.vs.randTintBranchDistance.x;
    #endif
#endif
}
]]>
            </CodeInjection>
        </CodeInjections>
    </LodLevel>
</CustomShader>
