Shader "SupGames/Mobile/PostProcessURP"
{
	Properties
	{
		[HideInInspector] _MainTex("Base (RGB)", 2D) = "white" {}
	}
	HLSLINCLUDE

	#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
	SAMPLER(sampler_LinearClamp);
	TEXTURE2D_X_FLOAT(_CameraDepthTexture);
	SAMPLER(sampler_CameraDepthTexture);

	uniform TEXTURE2D_X(_MainTex);
	SAMPLER(sampler_MainTex);
	uniform TEXTURE2D_X(_BloomHeightMipTex);
	uniform TEXTURE2D_X(_BloomTexLowMip);
	SAMPLER(sampler_BloomHeightMipTex);
	uniform TEXTURE2D_X(_LutTex2D);
	SAMPLER(sampler_LutTex2D);
	uniform TEXTURE3D(_LutTex3D);
	SAMPLER(sampler_LutTex3D);
	uniform TEXTURE2D_X(_MaskTex);
	SAMPLER(sampler_MaskTex);
	uniform TEXTURE2D_X(_BlurTex);
	SAMPLER(sampler_BlurTex);
	uniform half _LutAmount;
	uniform half4 _BloomThreshold;
	uniform half4 _BloomColor;
	uniform half _BloomAmount;
	uniform half _BlurAmount;
	uniform half _BloomDiffuse;
	uniform half _BloomClamp;
	uniform half _BloomScatter;
	uniform half _FxaaThresholdMin;
	uniform half _FxaaThreshold;
	uniform half _FxaaSharpness;
	uniform float4x4 _ViewProjM;
	uniform float4x4 _PrevViewProjM;
	uniform half _MotionBlurIntensity;
	uniform half _MotionBlurClamp;
	uniform half4 _MotionMask;
	uniform half _MotionMaskGradient;
	uniform half _LutDimension;
	uniform half4 _Color;
	uniform half _Contrast;
	uniform half _Brightness;
	uniform half _Saturation;
	uniform half _Exposure;
	uniform half _Gamma;
	uniform half _CentralFactor;
	uniform half _SideFactor;
	uniform half _Offset;
	uniform half _FishEye;
	uniform half _LensDistortion;
	uniform half4 _VignetteColor;
	uniform half _VignetteAmount;
	uniform half _VignetteSoftness;
	uniform half4 _MainTex_TexelSize;
	uniform half _TomemapExposure;
	
	uniform half4 _LGGLift;
	uniform half4 _LGGGamma;
	uniform half4 _LGGGain;

	struct appdata {
		half4 pos : POSITION;
		half2 uv : TEXCOORD0;
	};

	struct v2fb {
		half4 pos : SV_POSITION;
		half4 uv : TEXCOORD0;
		half4 uv1 : TEXCOORD1;
		half2 uv2 : TEXCOORD2;
	};
	struct v2f {
		half4 pos : SV_POSITION;
		half4 uv : TEXCOORD0;
		half4 uv1 : TEXCOORD1;
		half4 uv2 : TEXCOORD2;
		half2 uv3 : TEXCOORD3;
		float2 pixelHalfSize : TEXCOORD4;
		float4 fxaaConsolePosPos : TEXCOORD5;
		half2 projPos : TEXCOORD6;
		UNITY_VERTEX_OUTPUT_STEREO
	};

	v2fb vertBlurDown(appdata i)
	{
		v2fb o;
		UNITY_SETUP_INSTANCE_ID(i);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
		o.pos = mul(unity_MatrixVP, mul(unity_ObjectToWorld, half4(i.pos.xyz, 1.0h)));

		half2 offset = _MainTex_TexelSize.xy * (1 + _BloomDiffuse);

		i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
		o.uv = half4(i.uv - offset, i.uv + offset);
		o.uv1.xy = i.uv;
		o.uv1.zw = half2(0,0);
		o.uv2 = half2(0,0);
		return o;
	}

	half4 fragBlurDown(v2fb i) : SV_Target
	{
		UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
		
		half4 sum = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv1.xy) * 4;
		sum += SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.xy);
		sum += SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.xw);
		sum += SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.zw);
		sum += SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.zy);

		return sum * 0.125;
	}

	v2fb vertBlurUp(appdata i)
	{
		v2fb o;
		UNITY_SETUP_INSTANCE_ID(i);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
		o.pos = mul(unity_MatrixVP, mul(unity_ObjectToWorld, half4(i.pos.xyz, 1.0h)));

		_MainTex_TexelSize *= 0.5;

		half2 offset = _MainTex_TexelSize.xy * (1 + _BloomDiffuse);

		i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
		o.uv = half4(i.uv - offset, i.uv + offset);
		o.uv1.xy = i.uv + 2 * offset;
		o.uv1.zw = i.uv - 2 * offset;
		o.uv2.xy = i.uv;
		return o;
	}

	half4 fragBlurUp(v2fb i) : SV_Target
	{
		UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
		
		half4 lowMip = SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, i.uv.xy) * 2;
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, i.uv.xw) * 2;
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, i.uv.zw) * 2;
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, i.uv.zy) * 2;

		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, half2(i.uv1.x,i.uv2.y));
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, half2(i.uv1.z,i.uv2.y));
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, half2(i.uv2.x,i.uv1.y));
		lowMip += SAMPLE_TEXTURE2D_X(_BloomTexLowMip, sampler_LinearClamp, half2(i.uv2.x,i.uv1.w));

		lowMip *= 0.0833;

		half4 highMip = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv2);

		return lerp(highMip, lowMip, _BloomScatter);
	}

	v2f vert(appdata i)
	{
		v2f o;
		UNITY_SETUP_INSTANCE_ID(i);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
		o.pos = mul(unity_MatrixVP, mul(unity_ObjectToWorld, half4(i.pos.xyz, 1.0h)));
		float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
		o.uv.xy = uv;
		o.uv.zw = i.uv;
		o.uv1 = half4(o.uv.xy - _MainTex_TexelSize.xy, o.uv.xy + _MainTex_TexelSize.xy);
		o.uv2.x = o.uv.x - _Offset * _MainTex_TexelSize.x - 0.5h;
		o.uv2.y = o.uv.x + _Offset * _MainTex_TexelSize.x - 0.5h;
		o.uv2.zw = i.uv - 0.5h;
		o.uv3.xy = o.uv.xy - 0.5h;

		// fxaa.
		o.pixelHalfSize = 0.5/_ScreenParams.xy;
		o.fxaaConsolePosPos.xy = uv + o.pixelHalfSize;
		o.fxaaConsolePosPos.zw = uv - o.pixelHalfSize;

		// motion blur.
		float4 projPos = o.pos * 0.5;
        o.projPos = projPos.xy + projPos.w;

		return o;
	}

	half4 bloomPrefilter(half4 color)
	{
		color = min(_BloomClamp, color);

		// Thresholding
		half brightness = Max3(color.r, color.g, color.b);
		half ThresholdKnee = _BloomThreshold.x/2;
		half softness = clamp(brightness - _BloomThreshold.x + ThresholdKnee, 0.0, 2.0 * ThresholdKnee);
		softness = (softness * softness) / (4.0 * ThresholdKnee + 1e-4);
		half multiplier = max(brightness - _BloomThreshold.x, softness) / max(brightness, 1e-4);
		color *= multiplier;
		return color;
	}

	//
	// Quadratic color thresholding
	// curve = (threshold - knee, knee * 2, 0.25 / knee)
	//
	half4 QuadraticThreshold(half4 color)
	{
		color = clamp(color,0,_BloomClamp);
		half threshold = _BloomThreshold.x;
		half3 curve = _BloomThreshold.yzw;
		// Pixel brightness
		half br = Max3(color.r, color.g, color.b);

		// Under-threshold part: quadratic curve
		half rq = clamp(br - curve.x, 0.0, curve.y);
		rq = curve.z * rq * rq;

		// Combine and apply the brightness response curve.
		color *= max(rq, br - threshold) / max(br, 0.1);

		return color;
	}

	half4 fragBloomPrefilter(v2fb i) : SV_Target
	{
		UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
		
		half4 sum = QuadraticThreshold(SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv1.xy)) * 4;
		sum += QuadraticThreshold(SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.xy));
		sum += QuadraticThreshold(SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.xw));
		sum += QuadraticThreshold(SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.zw));
		sum += QuadraticThreshold(SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, i.uv.zy));

		return sum*0.125;
	}
	
	half rgb2luma(half3 rgb)
	{
		return dot(rgb, half3(0.299, 0.587, 0.114));
	}

	half4 fxaa(v2f i)
	{
		/*--------------------------------------------------------------------------*/
		half lumaNw = rgb2luma(SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.fxaaConsolePosPos.xy).rgb);
		half lumaSw = rgb2luma(SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.fxaaConsolePosPos.xw).rgb);
		half lumaNe = rgb2luma(SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.fxaaConsolePosPos.zy).rgb);
		half lumaSe = rgb2luma(SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.fxaaConsolePosPos.zw).rgb);
		/*--------------------------------------------------------------------------*/
		half4 rgbyM = SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.uv.xy);
		half lumaM = rgb2luma(rgbyM.xyz);
		/*--------------------------------------------------------------------------*/
		half lumaMaxNwSw = max(lumaNw, lumaSw);
		lumaNe += 1.0/384.0;
		half lumaMinNwSw = min(lumaNw, lumaSw);
		/*--------------------------------------------------------------------------*/
		half lumaMaxNeSe = max(lumaNe, lumaSe);
		half lumaMinNeSe = min(lumaNe, lumaSe);
		/*--------------------------------------------------------------------------*/
		half lumaMax = max(lumaMaxNeSe, lumaMaxNwSw);
		half lumaMin = min(lumaMinNeSe, lumaMinNwSw);
		/*--------------------------------------------------------------------------*/
		half lumaMaxScaled = lumaMax * _FxaaThreshold;
		/*--------------------------------------------------------------------------*/
		half lumaMinM = min(lumaMin, lumaM);
		half lumaMaxScaledClamped = max(_FxaaThresholdMin, lumaMaxScaled);
		half lumaMaxM = max(lumaMax, lumaM);
		half dirSwMinusNe = lumaSw - lumaNe;
		half lumaMaxSubMinM = lumaMaxM - lumaMinM;
		half dirSeMinusNw = lumaSe - lumaNw;
		if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbyM;
		/*--------------------------------------------------------------------------*/
		half2 dir;
		dir.x = dirSwMinusNe + dirSeMinusNw;
		dir.y = dirSwMinusNe - dirSeMinusNw;
		/*--------------------------------------------------------------------------*/
		half2 dir1 = normalize(dir.xy);
		half4 rgbyN1 = SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.uv.xy - dir1 * i.pixelHalfSize.xy);
		half4 rgbyP1 = SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.uv.xy + dir1 * i.pixelHalfSize.xy);
		/*--------------------------------------------------------------------------*/
		half dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * _FxaaSharpness;
		half2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0);
		/*--------------------------------------------------------------------------*/
		half4 rgbyN2 = SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.uv.xy - dir2 * 4 * i.pixelHalfSize.xy);
		half4 rgbyP2 = SAMPLE_TEXTURE2D_X(_MainTex,sampler_MainTex,i.uv.xy + dir2 * 4 * i.pixelHalfSize.xy);
		/*--------------------------------------------------------------------------*/
		half4 rgbyA = rgbyN1 + rgbyP1;
		half4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25);
		/*--------------------------------------------------------------------------*/
		bool twoTap = (rgbyB.w < lumaMin) || (rgbyB.w > lumaMax);
		if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5;
		return rgbyB;
		/*==========================================================================*/
	}

	half3 ACESFilm(half3 x)
	{
		half a = 2.51f;
		half b = 0.03f;
		half c = 2.43f;
		half d = 0.59f;
		half e = 0.14f;
		return saturate((x*(a*x+b))/(x*(c*x+d)+e));
	}

	//From  Next Generation Post Processing in Call of Duty: Advanced Warfare [Jimenez 2014]
	// http://advances.realtimerendering.com/s2014/index.html
	half InterleavedGradientNoise(half2 pixCoord)
	{
		const half3 magic = half3(0.06711056f, 0.00583715f, 52.9829189f);
		return frac(magic.z * frac(dot(pixCoord, magic.xy)));
	}
	
	float2 ClampVelocity(float2 velocity, float maxVelocity)
	{
		float len = length(velocity);
		return (len > 0.0) ? min(len, maxVelocity) * (velocity * rcp(len)) : 0.0;
	}

	// Per-pixel camera velocity
	float2 GetCameraVelocity(float4 uv)
	{
		float depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv.xy).r;

	#if UNITY_REVERSED_Z
		depth = 1.0 - depth;
	#endif

		depth = 2.0 * depth - 1.0;

		float3 viewPos = ComputeViewSpacePosition(uv.zw, depth, unity_CameraInvProjection);
		float4 worldPos = float4(mul(unity_CameraToWorld, float4(viewPos, 1.0)).xyz, 1.0);
		float4 prevPos = worldPos;

		float4 prevClipPos = mul(_PrevViewProjM, worldPos);
		float4 curClipPos = mul(_ViewProjM, worldPos);

		float2 prevPosCS = prevClipPos.xy / prevClipPos.w;
		float2 curPosCS = curClipPos.xy / curClipPos.w;

		return ClampVelocity(prevPosCS - curPosCS,0.2);
	}

	half3 GatherSample(half sampleNumber, half2 velocity, half invSampleCount, half2 centerUV, half randomVal, half velocitySign)
	{
		half  offsetLength = (sampleNumber + 0.5) + (velocitySign * (randomVal - 0.5));
		half2 sampleUV = centerUV + (offsetLength * invSampleCount) * velocity * velocitySign;
		return SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, sampleUV).xyz;
	}

	half4 DoMotionBlur(v2f input, half4 color, int iterations)
	{
		float2 uv = input.uv.xy;
		float len = saturate(pow(length((uv - _MotionMask.xy)*_MotionMask.zw),_MotionMaskGradient));
		
#ifdef MOTIONBLURMASK
		return (color + len)*0.5;
#endif
		float2 velocity = GetCameraVelocity(float4(uv, input.projPos)) * _MotionBlurIntensity * len;
		if (length(velocity) < 0.001) return color;
		float randomVal = InterleavedGradientNoise(uv * _ScreenParams.xy);
		float invSampleCount = rcp(iterations * 2.0);

		color = 0;

		UNITY_UNROLL
		for (int i = 0; i < iterations; i++)
		{
			color.xyz += GatherSample(i, velocity, invSampleCount, uv, randomVal, -1.0);
			color.xyz += GatherSample(i, velocity, invSampleCount, uv, randomVal,  1.0);
		}

		return color * invSampleCount;
	}

	half4 fragAll3D(v2f i) : SV_Target
	{
		UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
		half q = dot(i.uv2.zw, i.uv2.zw);
		half q2 = sqrt(q);
#ifdef DISTORTION
		half q3 = q * _LensDistortion * q2;
		i.uv.xy = (1.0h + q3) * i.uv3 + half2(0.5h, 0.5h);
#endif

#ifdef FXAA
		half4 c = fxaa(i);
#else
		half4 c = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv.xy);
#endif

#ifdef MOTIONBLUR
		c = DoMotionBlur(i, c, 2);
#endif

#ifdef BLOOM
		half4 b = SAMPLE_TEXTURE2D_X(_BlurTex, sampler_BlurTex, i.uv.xy);
#endif

#ifdef CHROMA
		half r = dot(i.uv2.xw, i.uv2.xw);
#ifdef DISTORTION
		half2 r2 = (1.0h + r * _FishEye * sqrt(r) + q3) * i.uv2.xw + half2(0.5h, 0.5h);
#else
		half2 r2 = (1.0h + r * _FishEye * sqrt(r)) * i.uv2.xw + half2(0.5h, 0.5h);
#endif
		c.r = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, r2).r;

		r = dot(i.uv2.yw, i.uv2.yw);
#ifdef DISTORTION
		r2 = (1.0h - r * _FishEye * sqrt(r) + q3) * i.uv2.xw + half2(0.5h, 0.5h);
#else
		r2 = (1.0h - r * _FishEye * sqrt(r)) * i.uv2.yw + half2(0.5h, 0.5h);
#endif
		c.b = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, r2).b;
#endif

#ifdef SHARPEN
		c *= _CentralFactor;
		c -= SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv1.xy) * _SideFactor;
		c -= SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv1.xw) * _SideFactor;
		c -= SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv1.zy) * _SideFactor;
		c -= SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv1.zw) * _SideFactor;
#endif

#ifdef BLOOM
		c += b * _BloomAmount;
#endif

#ifdef LUT
		c = lerp(c, SAMPLE_TEXTURE3D(_LutTex3D, sampler_LutTex3D, c.rgb * 0.9375h + 0.03125h), _LutAmount);
#endif

#if LIFTGAMMAGAIN
		// Lift, gamma, gain
		half3 color = c.xyz * _LGGGain.xyz + _LGGLift.xyz;
		color = sign(color) * pow(abs(color), _LGGGamma.xyz);
		c = half4( color.xyz,c.w);
#endif

// tonemap
#ifdef TONEMAP
		c.xyz = AcesTonemap(unity_to_ACES(c.xyz * _TomemapExposure));
#endif

#ifdef FILTER
		c.rgb = (c.rgb - 0.5f) * _Contrast + _Brightness;
		c.rgb = lerp(dot(c.rgb, half3(0.3h, 0.587h, 0.114h)), c.rgb, _Saturation);
		c.rgb *= (pow(2, _Exposure) - _Gamma) * _Color.rgb;
#endif
		c.rgb = lerp(_VignetteColor.rgb, c.rgb, smoothstep(_VignetteAmount, _VignetteSoftness, q2));
		return c;
	}

	ENDHLSL


	Subshader
	{
		Pass //0
		{
		  ZTest Always Cull Off ZWrite Off
		  Fog { Mode off }
		  HLSLPROGRAM
		  #pragma vertex vertBlurDown
		  #pragma fragment fragBlurDown
		  ENDHLSL
		}
		Pass //1
		{
		  ZTest Always Cull Off ZWrite Off
		  Fog { Mode off }
		  HLSLPROGRAM
		  #pragma vertex vertBlurDown
		  #pragma fragment fragBlurDown
		  ENDHLSL
		}
		Pass //2
		{
		  ZTest Always Cull Off ZWrite Off
		  Fog { Mode off }
		  HLSLPROGRAM
		  #pragma vertex vert
		  #pragma fragment fragAll3D
		  #pragma multi_compile_local __ BLOOM
		//   #pragma multi_compile_local __ BLUR
		  #pragma multi_compile_local __ FXAA
		//   #pragma multi_compile_local __ MOTIONBLUR
		//   #pragma multi_compile_local __ MOTIONBLURMASK
		//   #pragma multi_compile_local __ CHROMA
		//   #pragma multi_compile_local __ LUT
		  #pragma multi_compile_local __ LIFTGAMMAGAIN 
		  #pragma multi_compile_local __ TONEMAP
		//   #pragma multi_compile_local __ TONEMAP_UNITY
		  #pragma multi_compile_local __ FILTER
		//   #pragma multi_compile_local __ SHARPEN
		//   #pragma multi_compile_local __ DISTORTION
		  ENDHLSL
		}

		Pass //3
		{
		  ZTest Always Cull Off ZWrite Off
		  Fog { Mode off }
		  HLSLPROGRAM
		  #pragma vertex vertBlurDown
		  #pragma fragment fragBloomPrefilter
		  ENDHLSL
		}

		Pass //4
		{
		  ZTest Always Cull Off ZWrite Off
		  Fog { Mode off }
		  HLSLPROGRAM
		  #pragma vertex vertBlurUp
		  #pragma fragment fragBlurUp
		  ENDHLSL
		}

	}
	Fallback off
}