#ifndef PBR_LIT_PASS_INCLUDED
#define PBR_LIT_PASS_INCLUDED

#include "JR_Scene_PbrLight.hlsl"
#include "Assets/URP/Shader/HLSL/Environment/Sky&Fog/VolumetricFogForObject.hlsl"

float4 _BaseMap_ST;
half4 _BaseColor;
half _Cutoff;
half4 _SpecColor;
half _Metallic;
half _Roughness;
half _Emission;
half _normalScale;
half _detailNormalScale;
half _detailNormalTiling;
half _PomCount;
half _PomScale;
half4 _NightRainValue; // x:emission y:roughness z:color w:normal
half4 _BlendColor;
half _BlendIntensity;
half _BlendTexTilling;

TEXTURE2D(_BaseMap);            SAMPLER(sampler_BaseMap);
TEXTURE2D(_NormalMap);            SAMPLER(sampler_NormalMap);
TEXTURE2D(_PackMap);            SAMPLER(sampler_PackMap);
TEXTURE2D(_BlendTex);            SAMPLER(sampler_BlendTex);

#ifdef _DETAILNOMAL
TEXTURE2D(_DetailNormalMap);            SAMPLER(sampler_DetailNormalMap);
#endif

// Must match Universal ShaderGraph master node
struct SurfaceData
{
    half3 albedo;
    half3 specular;
    half  metallic;
    half  roughness;
    half3 normalTS;
    half3 normalBase;
    half3 emission;
    half  occlusion;
    half  alpha;
};

struct Attributes
{
    float4 positionOS   : POSITION;
    float3 normalOS     : NORMAL;
    float4 tangentOS    : TANGENT;
    half4 color         : COLOR;
    float2 texcoord     : TEXCOORD0;
    float2 lightmapUV   : TEXCOORD1;
    float2 texcoord3   : TEXCOORD2;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings
{
    float2 uv                       : TEXCOORD0;
    DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 1);

    float3 positionWS               : TEXCOORD2;

    float4 normalWS                 : TEXCOORD3;    // xyz: normal, w: viewDir.x
    float4 tangentWS                : TEXCOORD4;    // xyz: tangent, w: viewDir.y
    float4 bitangentWS              : TEXCOORD5;    // xyz: bitangent, w: viewDir.z

    float4 shadowCoord              : TEXCOORD7;
    float4 fogCoord                 : TEXCOORD8;
    float3 viewDirTS                : TEXCOORD9;
    half4 calaPos                   : TEXCOORD10;
    float2 DetailUv                   : TEXCOORD11;

    half4 color                     : COLOR;
    float4 positionCS               : SV_POSITION;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    UNITY_VERTEX_OUTPUT_STEREO
};

void InitializeInputData(Varyings input, half3 normalTS, half3 normalBase, out PbrInputData inputData)
{
    inputData = (PbrInputData)0;

    inputData.positionWS = input.positionWS;

    half3 viewDirWS = half3(input.normalWS.w, input.tangentWS.w, input.bitangentWS.w);
    inputData.normalWS = TransformTangentToWorld(normalTS,
        half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
    inputData.normalWS = normalize(inputData.normalWS);

    inputData.normalBase = TransformTangentToWorld(normalBase,
        half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
    inputData.normalBase = normalize(inputData.normalBase);

    viewDirWS = normalize(viewDirWS);
    inputData.viewDirectionWS = viewDirWS;

    inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);

    inputData.bakedGI = SAMPLE_GI(input.lightmapUV, input.vertexSH, inputData.normalWS);

    inputData.calaPos = input.calaPos;

#if defined(LIGHTMAP_ON) && defined(SHADOWS_SHADOWMASK)  
    inputData.bakedAtten = SampleShadowMask(input.lightmapUV);
#endif
}

half2 hash22(half2 p)
{
    p = (p * 3.04 + (_Time.y % 77) * 13 +  50.0);
    p = floor(p * 1024);
    half3 p3 = frac(half3(p.xyx) * half3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yzx+33.33);
    return frac((p3.xx+p3.yz)*p3.zy)*2 - 1;
}
half _angle;
inline void InitializeStandardLitSurfaceData(float2 uv, float2 uv3, half NdotL, out SurfaceData outSurfaceData)
{
    half4 albedoAlpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv);
#ifdef _ALPHATEST_ON
    clip(albedoAlpha.a - _Cutoff);
#endif
    outSurfaceData.alpha = albedoAlpha.a;

    half4 packValue = SAMPLE_TEXTURE2D(_PackMap, sampler_PackMap, uv);
    half4 specGloss = packValue.r;
    outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb * (1 - _NightRainValue.z);

    outSurfaceData.metallic = specGloss.r * _Metallic;
    outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h);
 
    outSurfaceData.roughness = packValue.g * _Roughness * (1 - _NightRainValue.y);
    half3 normal = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uv),_normalScale);
    normal.z = sqrt(1 - normal.x*normal.x - normal.y*normal.y);
    normal = normalize(normal);
    normal.xy += hash22(uv) * _NightRainValue.w;
    normal = normalize(normal);
    outSurfaceData.normalBase = normal;

#ifdef _DETAILNOMAL
    float2 DetailUv;
    // DetailUv.x = cos(_angle)*uv3.x - sin(_angle)*uv3.y;
    // DetailUv.y = sin(_angle)*uv3.x +cos(_angle)*uv3.y;
    half3 detailNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, uv3 * _detailNormalTiling), _detailNormalScale*NdotL);
    // detailNormal.z = sqrt(1 - detailNormal.x*detailNormal.x - detailNormal.y*detailNormal.y);
    // detailNormal = normalize(detailNormal);
    // normal = normalize(lerp(normal,detailNormal,_normalLerp));
    normal.xy += detailNormal.xy;
#endif
    outSurfaceData.normalTS = normal;
    outSurfaceData.occlusion = 1;
#ifndef _ALPHATEST_ON
    outSurfaceData.emission = (packValue.b * _Emission + albedoAlpha.a * _NightRainValue.x) * outSurfaceData.albedo;
#else
    outSurfaceData.emission = packValue.b * _Emission * outSurfaceData.albedo;
#endif
}

///////////////////////////////////////////////////////////////////////////////
//                  Vertex and Fragment functions                            //
///////////////////////////////////////////////////////////////////////////////

// Used in Standard (Physically Based) shader
Varyings LitPassVertex(Attributes input)
{
    Varyings output = (Varyings)0;

    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, output);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

    VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
    VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
    half3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS;

    output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
    output.DetailUv = input.texcoord3;

    output.normalWS = half4(normalInput.normalWS, viewDirWS.x);
    output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y);
    output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z);

    OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV);
    OUTPUT_SH(output.normalWS.xyz, output.vertexSH);

    output.positionWS = vertexInput.positionWS;
    output.calaPos = VertCalaShadow(output.positionWS.xyzz, _DirX, _DirY);

    output.shadowCoord = GetShadowCoord(vertexInput);

    output.positionCS = vertexInput.positionCS;

#ifdef _POM_ON
    float3x3 WorldToTangent = float3x3(normalInput.tangentWS, normalInput.bitangentWS, normalInput.normalWS);
    output.viewDirTS = mul(WorldToTangent,viewDirWS);
#endif

    output.fogCoord = VolumetricFog_GetFogCoord(vertexInput.positionNDC, vertexInput.positionVS.z);
    output.color = input.color;

    return output;
}

half ComputePerPixelHeightDisplacement(half2 offset, half2 uv)
{
    return SAMPLE_TEXTURE2D(_PackMap, sampler_PackMap, offset + uv).a;
}

#include "Assets/URP/Shader/HLSL/Common/Function/Pom.hlsl"

// Used in Standard (Physically Based) shader
half4 LitPassFragment(Varyings input) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

#ifdef _POM_ON
    // Parallax Occlusion.
    float3 ParallaxOcclusionMapping_ViewDirUV = normalize(float3(input.viewDirTS.xy * _PomScale, input.viewDirTS.z));
    input.uv += ParallaxOcclusionMapping(_PomCount, ParallaxOcclusionMapping_ViewDirUV, input.uv);
#endif
    Light light = GetMainLight();
    half ndotl = dot(input.normalWS,light.direction);
    //return smoothstep(0,1,ndotl);
    SurfaceData surfaceData;
    InitializeStandardLitSurfaceData(input.uv, input.DetailUv, ndotl, surfaceData);

    PbrInputData inputData;
    InitializeInputData(input, surfaceData.normalTS, surfaceData.normalBase, inputData);

#ifdef _USE_Blend
    half3 N = inputData.normalBase;
    half3 BlendTex = SAMPLE_TEXTURE2D(_BlendTex, sampler_BlendTex, input.uv * _BlendTexTilling).rgb * _BlendColor.xyz;
    half BlendDir = N.y + _BlendIntensity;
    surfaceData.albedo.rgb = lerp(surfaceData.albedo.rgb,BlendTex,smoothstep(0,1,BlendDir)*input.color.a);
#endif

    half4 color = UniversalFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.roughness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);

    // color.rgb = VolumetricFog_GetFog(color.rgb, input.fogCoord);

    return color;
}

#endif