﻿Shader "Hidden/High Definition Render Pipeline/SSCC"
{
    Properties
    {
        _MainTex("", any) = "" {}
    }

    HLSLINCLUDE

    #pragma target 4.5
    #pragma only_renderers d3d11 ps4 xboxone vulkan metal switch
    #pragma editor_sync_compilation

    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesFunctions.hlsl"
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"
	#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"

    TEXTURE2D_X(_MainTex);
    TEXTURE2D_X(_CameraNormalsTexture);
    TEXTURE2D_X(_GBufferTexture0);
    SAMPLER(sampler_LinearClamp);
    SAMPLER(sampler_PointClamp);

    CBUFFER_START(FrequentlyUpdatedUniforms)
    float4 _Input_TexelSize;
    float4 _UVToView;
	float4x4 unity_CameraProjection; //

	float _EffectIntensity;
	float _DistanceFade;

	float _CurvaturePixelRadius;
	float _CurvatureBrights;
	float _CurvatureDarks;

	float _CavityWorldRadius;
	float _CavityBrights;
	float _CavityDarks;
    CBUFFER_END

    struct Attributes
    {
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct Varyings
    {
        float4 positionCS : SV_POSITION;
        float2 uv         : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    };

    Varyings Vert(Attributes input)
    {
        Varyings output;
        UNITY_SETUP_INSTANCE_ID(input);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
        output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
        output.uv = GetNormalizedFullScreenTriangleTexCoord(input.vertexID);
		output.uv /= _RTHandleScale.xy; /////// only for HDRP
        return output;
    }

    ENDHLSL

    SubShader
    {
        Tags { "RenderPipeline" = "HDRenderPipeline" }
        LOD 100
        ZWrite Off ZTest Always Blend Off Cull Off

        Pass // 0
        {
            Name "Copy"

            HLSLPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag

            half4 Frag(Varyings input) : SV_Target 
			{
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
                return LOAD_TEXTURE2D_X(_MainTex, uint2(input.positionCS.xy));
            }
            ENDHLSL
        }

        Pass // 1
        {
            Name "Composite"

            ColorMask RGB

            HLSLPROGRAM
			#pragma multi_compile_local __ DEBUG_EFFECT DEBUG_NORMALS
			#pragma multi_compile_local __ ORTHOGRAPHIC_PROJECTION
			#pragma multi_compile_local __ NORMALS_RECONSTRUCT
			#pragma multi_compile_local CAVITY_SAMPLES_6 CAVITY_SAMPLES_8 CAVITY_SAMPLES_12
			#pragma multi_compile_local __ SATURATE_CAVITY

            #pragma vertex Vert
            #pragma fragment Composite_Frag

			//
			inline half4 FetchSceneColor(float2 uv) {
				uv *= _RTHandleScale.xy;//the scene color is special because it absolutely has to be scaled to the screen size by hdrp, unlike other hdrp buffers
				return SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv);
			}
			inline float FetchRawDepth(float2 uv) {
				//uv = clamp(uv, 0, 1 - _Input_TexelSize.xy * 0.5); // uv guard
				return SampleCameraDepth(uv);
			}
			inline float LinearizeDepth(float depth) {
				#if ORTHOGRAPHIC_PROJECTION
					#if UNITY_REVERSED_Z
						depth = 1 - depth;
					#endif
					float linearDepth = _ProjectionParams.y + depth * (_ProjectionParams.z - _ProjectionParams.y);
				#else
					float linearDepth = LinearEyeDepth(depth, _ZBufferParams);
				#endif
				return linearDepth;
			}
			inline float3 FetchViewPos(float2 uv) {
				float depth = LinearizeDepth(FetchRawDepth(uv));
				//return float3((uv * _UVToView.xy + _UVToView.zw) * depth, depth);
				float4 UVToView = float4(2 / unity_CameraProjection._m00, -2 / unity_CameraProjection._m11, -1 / unity_CameraProjection._m00, 1 / unity_CameraProjection._m11);
				#if ORTHOGRAPHIC_PROJECTION
					return float3((uv * UVToView.xy + UVToView.zw), depth);
				#else
					return float3((uv * UVToView.xy + UVToView.zw) * depth, depth);
				#endif
			}
			inline float3 MinDiff(float3 P, float3 Pr, float3 Pl) {
				float3 V1 = Pr - P;
				float3 V2 = P - Pl;
				return (dot(V1, V1) < dot(V2, V2)) ? V1 : V2;
			}
			inline float3 FetchViewNormals(float3 P, float2 uv) {
				#if NORMALS_RECONSTRUCT
					float c = FetchRawDepth(uv);
					half3 viewSpacePos_c = FetchViewPos(uv);
					// get data at 1 pixel offsets in each major direction
					half3 viewSpacePos_l = FetchViewPos(uv + float2(-1.0, 0.0) * _Input_TexelSize.xy);
					half3 viewSpacePos_r = FetchViewPos(uv + float2(+1.0, 0.0) * _Input_TexelSize.xy);
					half3 viewSpacePos_d = FetchViewPos(uv + float2(0.0, -1.0) * _Input_TexelSize.xy);
					half3 viewSpacePos_u = FetchViewPos(uv + float2(0.0, +1.0) * _Input_TexelSize.xy);
					half3 l = viewSpacePos_c - viewSpacePos_l;
					half3 r = viewSpacePos_r - viewSpacePos_c;
					half3 d = viewSpacePos_c - viewSpacePos_d;
					half3 u = viewSpacePos_u - viewSpacePos_c;
					half4 H = half4(
						FetchRawDepth(uv + float2(-1.0, 0.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(+1.0, 0.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(-2.0, 0.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(+2.0, 0.0) * _Input_TexelSize.xy)
					);
					half4 V = half4(
						FetchRawDepth(uv + float2(0.0, -1.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(0.0, +1.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(0.0, -2.0) * _Input_TexelSize.xy),
						FetchRawDepth(uv + float2(0.0, +2.0) * _Input_TexelSize.xy)
					);
					half2 he = abs((2 * H.xy - H.zw) - c);
					half2 ve = abs((2 * V.xy - V.zw) - c);
					half3 hDeriv = he.x < he.y ? l : r;
					half3 vDeriv = ve.x < ve.y ? d : u;
					float3 N = normalize(cross(hDeriv, vDeriv));
				#else
					float depth01 = FetchRawDepth(uv);
					if (depth01 == 1.0 || depth01 == 0.0) return 0; //HDRP doesn't clear it's gbuffer so we have to
					uint2 positionSS = uv * _Input_TexelSize.zw;
					NormalData normalData;
					DecodeFromNormalBuffer(positionSS, normalData);
					float3 N = normalize(TransformWorldToViewDir(normalData.normalWS));
					N = float3(N.x, -N.yz);
				#endif

				N = float3(N.x, -N.y, N.z);

				return N;
			}
			//
			#define SSCC_HDRP
			//#include "../../../Shaders/Shared.cginc"
			#include "Shared_HDRP.cginc"

			ENDHLSL
        }
    }

    Fallback Off
}
