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

<CustomShader version="5">
    <Parameters>
        <Parameter name = "windSnowLeafScale" target = "windSnowLeafScale" type = "float3" group = "base" defaultValue = "1.0 1.0 1.0"     minValue = "0.0 0.0 0.0"        maxValue = "1.0 1.0 1.0"/>
        <Parameter name = "markerPosScaleRot" target = "markerPosScaleRot" type = "float4" group = "base" defaultValue = "0.0 0.0 0.0 0.0" minValue = "-5.0 -1.0 0.0 0.0"  maxValue = "5.0 10.0 5.0 6.2832"/>
        <Parameter name = "markerColorScale"  target = "markerColorScale"  type = "float4" group = "base" defaultValue = "1.0 0.0 0.0 1.0" minValue = "0.0 0.0 0.0 0.0"    maxValue = "1.0 1.0 1.0 1.0"/>
    </Parameters>
    <UvUsages/>
    <Textures>
        <Texture name = "mMarker"       group="base"           defaultColorProfile = "sRGB"      defaultFilename = "$data/shared/default_alpha.png"/>
        <Texture name = "mParallaxMap"  group="customParallax" defaultColorProfile = "linearRGB" defaultFilename = "$data/maps/textures/shared/default_height.png"/>
    </Textures>
    <Variations>
        <Variation name = "customParallax" groups="base customParallax">
<![CDATA[
    #define CUSTOM_PARALLAX
]]>
        </Variation>
    </Variations>
    <LodLevel startDistance="0">
        <CodeInjections>
            <CodeInjection position="SHARED_START">
<![CDATA[
#if defined(CUSTOM_PARALLAX)
    #define PARALLAX_MAP
#endif
]]>
            </CodeInjection>
            <CodeInjection position="OBJECT_PARAMETERS">
<![CDATA[
/*
    windSnowLeafScale.r - wind
    windSnowLeafScale.g - snow
    windSnowLeafScale.b - leaf
*/
float3 windSnowLeafScale;
/*
    markerPosScaleRot.x - horizontal uv offset ( in most cases should be 0.0 )
    markerPosScaleRot.y - vertical uv offset
    markerPosScaleRot.z - uv scale
    markerPosScaleRot.w - uv rotation around the trunk
*/
float4 markerPosScaleRot;
/*
    markerColorScale.rgb - multiplied with mMarker.rgb
    markerColorScale.a   - erosion value from mMarker.rgb
*/
float4 markerColorScale;

]]>
            </CodeInjection>
            <CodeInjection position="LIB_FUNCTION_VS">
<![CDATA[
float3 getTrunkAnimationOffset(VS_INPUT In, ObjectParameters& object, float mTime, float3 windDirection,float windStrength){
    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 * mTime + treeVarSeed + 0.1)*0.3);

    float normalizedTreeY = In.position.y/30;
    float trunkOffsetScale = (1*max(windStrength-0.1,0)/0.9 + sin( 1.5 * mTime + treeVarSeed)*0.7*windStrength)*normalizedTreeY*normalizedTreeY;
    float3 trunkOffset = trunkMoveDirection.xyz * trunkOffsetScale;
    return trunkOffset;
}
]]>
            </CodeInjection>
            <CodeInjection position="VS_OUTPUT">
<![CDATA[
    float3 localPosition : TEXCOORDn;
]]>
            </CodeInjection>
            <CodeInjection position="POST_SET_TEXCOORDS_VS">
<![CDATA[
    Out.localPosition = In.position.xyz;
]]>
            </CodeInjection>
            <CodeInjection position="POST_GET_WORLD_POSE_VS">
<![CDATA[
    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) {
        // current pos
        worldPosition += getTrunkAnimationOffset(In,object,cTime_s,windDirection,windStrength);
        // previous pos
        prevWorldPosition += getTrunkAnimationOffset(In,object,cPrevTime_s,windDirection,windStrength);
    }
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "SAMPLERS">
<![CDATA[
    sampler2D mMarker;
#if defined(CUSTOM_PARALLAX)
    sampler2D mParallaxMap;
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "GET_BUMP_HEIGHT_AT_WITH_GRAD_FS">
<![CDATA[
#if defined(CUSTOM_PARALLAX)
    return tex2Dgrad(mParallaxMap, float3(uv, layer), gradX, gradY).r;
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "GET_BUMP_HEIGHT_AT_FS">
<![CDATA[
#if defined(CUSTOM_PARALLAX)
    return tex2D(mParallaxMap, float3(uv, layer)).r;
#endif
]]>
            </CodeInjection>
            <CodeInjection position = "GET_BUMP_HEIGHT_TEXTURE_SIZE_FS">
<![CDATA[
#if defined(CUSTOM_PARALLAX)
    return tex2DSize(mParallaxMap, 0);
#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
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;
}
]]>
            </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.windSnowLeafScale.z > 0.0;
]]>
            </CodeInjection>
            <CodeInjection position = "POST_DIFFUSE_COLOR_FS">
<![CDATA[
    if (object.markerPosScaleRot.z > 0) {
        float2 projSide = float2(cos(-object.markerPosScaleRot.w),sin(-object.markerPosScaleRot.w));

        float2 projNormal = float2(-projSide.y, projSide.x);
        if (dot(projNormal, In.vs.localPosition.xz) > 0) {

            float2 markerUv = float2(
                dot(In.vs.localPosition.xz, projSide),
                In.vs.localPosition.y);

            float worldToUv = 1.0/object.markerPosScaleRot.z;

            markerUv *= worldToUv;
            markerUv += 0.5;
            markerUv -= object.markerPosScaleRot.xy * worldToUv;

            if (all(markerUv > 0) && all(markerUv < 1)) {
                float4 mMarkerMap = tex2D(mMarker, markerUv);
                diffuseColor.rgb = lerp(diffuseColor.rgb, mMarkerMap.xyz * object.markerColorScale.rgb, saturate(mMarkerMap.w - (1-object.markerColorScale.a)));
            }
        }
    }
    { // 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="FINAL_POS_FS">
<![CDATA[
#if defined(DEBUG_SHOW_CUSTOM1)
    // NEED FOR LOD BAKING
    oColor.xyz *= 0.0001;
    oColor.xyz += diffuseColor;
#endif
]]>
            </CodeInjection>
        </CodeInjections>
    </LodLevel>
</CustomShader>
