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

<CustomShader version="5">
    <Parameters>
        <Parameter name="fadeInOutStartEnd"                     target="fadeInOutStartEnd"                    group="base" type="float4" defaultValue="-5 0 70 75" />
        <Parameter name="cellSizeTerrainSizeScaleXZScaleY"      target="cellSizeTerrainSizeScaleXZScaleY"     group="base" type="float4" defaultValue="16 1024 2 255"/>
        <Parameter name="horizontalPosVarAtlasSizeAtlasOffset"  target="horizontalPosVarAtlasSizeAtlasOffset" group="base" type="float4"/>
        <Parameter name="texCoordOffsetAndScale"                target="texCoordOffsetAndScale"               group="base" type="float4"/>
        <Parameter name="sizeAndSizeVariance"                   target="sizeAndSizeVariance"                  group="base" type="float4"/>
        <Parameter name="snowScale"                             target="snowScale"                            group="base" type="float"  defaultValue="1.0" minValue = "0.0" maxValue = "1.0"/>
    </Parameters>
    <UvUsages>
        <UvUsage textureName="baseMap"   uvType="uv0"/>
        <UvUsage textureName="normalMap" uvType="uv0"/>
        <UvUsage textureName="glossMap"  uvType="uv0"/>
        <UvUsage textureName="alphaMap"  uvType="uv0"/>
    </UvUsages>
    <Textures>
        <Texture name = "alphaMap" group="alphaMap" defaultColorProfile = "linearRGB"/>
    </Textures>
    <VertexAttributes>
        <IgnoredVertexAttribute name="position" group="base"/>
        <IgnoredVertexAttribute name="normal"   group="base"/>
        <IgnoredVertexAttribute name="uv0"      group="base"/>
        <IgnoredVertexAttribute name="tangent"  group="base"/>
    </VertexAttributes>
    <Variations>
        <Variation name="ALPHA_MAP" groups="base alphaMap">
<![CDATA[
#define ALPHA_MAP
]]>
        </Variation>
    </Variations>
    <LodLevel startDistance="0">
        <CodeInjections>
            <CodeInjection position = "SHARED_START">
<![CDATA[
#if defined(FOLIAGE)
    #define SOFTWARE_INSTANCING 1
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "VS_INPUT">
<![CDATA[
    float3 terrainNormal;
    float3 blockPosition;
    float2 widthHeightScale;
    float rotAngle;
#if defined(SOFTWARE_INSTANCING)
    float atlasIndex;
#endif
    float3 blockPositionWorld;
]]>
            </CodeInjection>
            <CodeInjection position = "SAMPLERS">
<![CDATA[
#if defined(ALPHA_MAP)
    sampler2D alphaMap;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="CONFIG_DEFINES">
<![CDATA[
#if GPU_PROFILE <= GPU_PROFILE_HIGH
    #define NUM_SHADOW_MAP_SAMPLES 1
#endif
#if defined(FOLIAGE)
    #define DISTANCE_BLENDING
#endif
#if defined(ALPHA_MAP)
    #define ALPHA_TESTED
#endif
]]>
            </CodeInjection>
            <CodeInjection position="GET_POSITION_VS">
<![CDATA[
#if defined(FOLIAGE)
    float3 position = In.position.xyz; // get mesh XYZ
    position *= In.widthHeightScale.xyx;  // scale by widthScale & heightScale
    float plantRotation = In.rotAngle*3.1415926;
    position = rotateVectorToTerrainNormal(In, object, rotateFoliageVector(In, object, position, plantRotation), In.terrainNormal);
    float3 blockPos = In.blockPosition.xyz;
    blockPos *= object.cellSizeTerrainSizeScaleXZScaleY.xwx;
    position += blockPos; // add blockPositionX,Y,Z
    return position;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="GET_NORMAL_VS">
<![CDATA[
#if defined(FOLIAGE)
    #ifdef LIGHTING
        float3 normal = In.normal; // get mesh normal
        float plantRotation = In.rotAngle*3.1415926;
        return rotateVectorToTerrainNormal(In, object, rotateFoliageVector(In, object, normal, plantRotation), In.terrainNormal);
    #endif
#endif
]]>
            </CodeInjection>
            <CodeInjection position="GET_TANGENT_VS">
<![CDATA[
#if defined(FOLIAGE)
    #ifdef LIGHTING
        float3 tangent = In.tangent.xyz; // get mesh tangent
        float plantRotation = In.rotAngle*3.1415926;
        return rotateVectorToTerrainNormal(In, object, rotateFoliageVector(In, object, tangent, plantRotation), In.terrainNormal);
    #endif
#endif
]]>
            </CodeInjection>
            <CodeInjection position="GET_DEFAULT_TEXCOORDS_VS">
<![CDATA[
#if defined(FOLIAGE)
    return getFoliageTexCoords(In, object, In.texCoords2.xy, In.texCoords2.zw, 0, 0);
#endif
]]>
            </CodeInjection>
            <CodeInjection position="OBJECT_PARAMETERS">
<![CDATA[
    float4 fadeInOutStartEnd;
    float4 cellSizeTerrainSizeScaleXZScaleY;
#if defined(SOFTWARE_INSTANCING)
    float4 horizontalPosVarAtlasSizeAtlasOffset;
    float4 texCoordOffsetAndScale;
    float4 sizeAndSizeVariance;
#endif
    float snowScale;
]]>
            </CodeInjection>
            <CodeInjection position="VS_OUTPUT">
<![CDATA[
    float distanceBlendInverseAlphaAttr : TEXCOORDn;
]]>
            </CodeInjection>
            <CodeInjection position="VS_END">
<![CDATA[
#if defined(FOLIAGE)
    #if defined(DEPTH_VIS)
        float viewDirLength = length(lodViewpoint.xz - In.blockPositionWorld.xz);
        float positionOnFadeIn = (viewDirLength - object.fadeInOutStartEnd.x) / (object.fadeInOutStartEnd.y - object.fadeInOutStartEnd.x);
        float positionOnFadeOut = (viewDirLength - (object.fadeInOutStartEnd.z-6)) / (object.fadeInOutStartEnd.w - (object.fadeInOutStartEnd.z-6));
    #else
        float viewDirLength = length(In.blockPositionWorld.xz);
        float positionOnFadeIn = (viewDirLength - object.fadeInOutStartEnd.x) / (object.fadeInOutStartEnd.y - object.fadeInOutStartEnd.x);
        float positionOnFadeOut = (viewDirLength - object.fadeInOutStartEnd.z) / (object.fadeInOutStartEnd.w - object.fadeInOutStartEnd.z);
    #endif
    float alphaFadeIn = saturate(positionOnFadeIn);
    float alphaFadeOut = 1 - saturate(positionOnFadeOut);
    Out.distanceBlendInverseAlphaAttr = alphaFadeIn - alphaFadeOut;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="FILL_VERTEX_INPUT_VS">
<![CDATA[
#if defined(FOLIAGE)
    #if defined(SOFTWARE_INSTANCING)
        fillSoftInstancedFoliageVertexInput(In.vertexId, In, vertexTextureBuffer);
        getFoliageInstanceData(In.instanceId, instanceDataBuffer, object.horizontalPosVarAtlasSizeAtlasOffset.y, object.sizeAndSizeVariance, In.blockPosition, In.terrainNormal, In.rotAngle, In.widthHeightScale, In.atlasIndex);
        In.texCoords2 = object.texCoordOffsetAndScale;
    #else
        fillFoliageVertexInput(vertexAttributes, In);
        In.rotAngle = vertexAttributes.blendWeights.w;
        In.terrainNormal = vertexAttributes.texCoords1.xyz - 0.5;
        In.widthHeightScale = vertexAttributes.color.xy * 8;
        In.blockPosition = vertexAttributes.blendWeights.xyz;
        In.blockPosition.y += 0.5;
    #endif
    float3 blockPos = In.blockPosition.xyz;
    blockPos *= object.cellSizeTerrainSizeScaleXZScaleY.xwx;
    float3 worldBlockPos = mul(object.modelMatrix, float4(blockPos, 1)).xyz;
    In.blockPositionWorld = worldBlockPos;
#else
    // Regular mesh
    In.rotAngle = 0.0;
    In.terrainNormal = float3(0,1,0);
    In.widthHeightScale = 1.0;
    In.blockPosition = 0;
    In.blockPositionWorld = float3(object.modelMatrix[0][3], object.modelMatrix[1][3], object.modelMatrix[2][3]);
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "LIB_FUNCTION_FS">
<![CDATA[
float fitRangeFS(float mIn,float mOldMin,float mOldMax ,float mNewMin ,float mNewMax ){
    return (mNewMin + (mIn - mOldMin) * (mNewMax  - mNewMin ) / (mOldMax  - mOldMin));
}
// Season states:
// cShared3 = 0 = summer
// cShared3 = 1 = autumn
// cShared3 = 2 = winter
// cShared3 = 3 = spring
// cShared3 = 4 = summer
// cShared4 = 0 .. 1 = snow control
float getSnowMask(ObjectParameters& object, float3 mNormal, float mBackfaceScale){
    float NdotY = mNormal.y; // dot(mNormal, float3(0.0, 1.0, 0.0));
    NdotY = max(NdotY * mBackfaceScale, NdotY * (1.0-mBackfaceScale)) + mBackfaceScale;
    float mScale = object.snowScale*cShared4; 
    float mPow = fitRangeFS(mScale,0,1,50,1);
    float pi = 3.14159265359;
    mScale = sin(0.5*pi*mScale); // keep high values close to 1
    float mSnowMask = saturate(mScale*pow(NdotY,mPow));
    return mSnowMask;
}
]]>
            </CodeInjection>
            <CodeInjection position = "FS_GLOBALS">
<![CDATA[
    float  gSnowMask;
    bool   gIsSnowing;
    float3 gSnowDiffuse;
    float3 gSnowSpecular;
]]>
            </CodeInjection>
            <CodeInjection position = "START_FS">
<![CDATA[
    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.snowScale > 0.0;
]]>
            </CodeInjection>
            <CodeInjection position="POST_DIFFUSE_COLOR_FS">
<![CDATA[
    { // 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="GET_DISTANCE_BLEND_INVERSE_ALPHA_FS">
<![CDATA[
#if defined(FOLIAGE)
    return In.vs.distanceBlendInverseAlphaAttr;
#endif
]]>
            </CodeInjection>
            <CodeInjection position="ALPHA_FS">
<![CDATA[
#if defined(ALPHA_MAP)
    alpha = tex2D(alphaMap, ALBEDO_MAP_TEXCOORDS).r;
#endif
]]>
            </CodeInjection>
        </CodeInjections>
    </LodLevel>
</CustomShader>
