
Shader "Hidden/BlurShadowmap" {
	Properties
	{
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Bloom ("Bloom (RGB)", 2D) = "black" {}
	}
	
	CGINCLUDE
	#include "UnityCG.cginc"

	half4 _TexelSize;

	struct v2f_tap
	{
		float4 pos : SV_POSITION;
		half2 uv20 : TEXCOORD0;
		half2 uv21 : TEXCOORD1;
		half2 uv22 : TEXCOORD2;
		half2 uv23 : TEXCOORD3;
	};			

	v2f_tap vert4Tap ( appdata_img v )
	{
		v2f_tap o;
		o.pos = v.vertex;

		o.uv20 = v.texcoord + _TexelSize.xy;				
		o.uv21 = v.texcoord + _TexelSize.xy * half2(-0.5, -0.5);	
		o.uv22 = v.texcoord + _TexelSize.xy * half2( 0.5, -0.5);		
		o.uv23 = v.texcoord + _TexelSize.xy * half2(-0.5,  0.5);		

		return o; 
	}

	// TODO: consolidate with the above, but make sure both area and dir shadows work
	v2f_tap vert4TapDir ( appdata_img v )
	{
		v2f_tap o;
		o.pos = UnityObjectToClipPos(v.vertex);

		o.uv20 = v.texcoord + _TexelSize.xy;				
		o.uv21 = v.texcoord + _TexelSize.xy * half2(-0.5, -0.5);	
		o.uv22 = v.texcoord + _TexelSize.xy * half2( 0.5, -0.5);		
		o.uv23 = v.texcoord + _TexelSize.xy * half2(-0.5,  0.5);		

		return o; 
	}

	float4 _ZParams;
	float _ESMExponent;
	Texture2D _Shadowmap;
	SamplerComparisonState sampler_Shadowmap;

	// To get a sampler, which doesn't do comparison
	Texture2D _ShadowmapDummy;
	SamplerState sampler_ShadowmapDummy;

	#define VSM 1

	float4 fragDownsampleFromShadowmapFormat ( v2f_tap i ) : SV_Target
	{
		float4 z;
		z.r = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv20).r;
		z.g = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv21).r;
		z.b = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv22).r;
		z.a = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv23).r;

		// The texture contains just 0. But we need to sample it somewhere for Unity to initialize the corresponding sampler.
		z.r += _ShadowmapDummy.Sample(sampler_ShadowmapDummy, 0).a;

		#if UNITY_REVERSED_Z
			z = 1.0 - z;
		#endif

		// Transform to linear z, 0 at near, 1 at far
		z = z * 2 - 1;
		z = _ZParams.x * (z + 1.0) / (z + _ZParams.y);	

	#if VSM
		// TODO: this is wrong. We can't average/blur z values before converting to VSM.
		// This doesn't affect m, but affects m * m, so I should swap those two lines.
		float m = dot(z, 0.25);
		return float4(m, m * m, 0, 0);
	#else
		z = exp(_ESMExponent * z);
		return dot(z, 0.25);
	#endif
	}

	sampler2D _DirShadowmap;

	float4 fragDownsampleFromShadowmapFormatDir ( v2f_tap i ) : SV_Target
	{
		float4 z;
		z.r = tex2D (_DirShadowmap, i.uv20).r;
		z.g = tex2D (_DirShadowmap, i.uv21).r;
		z.b = tex2D (_DirShadowmap, i.uv22).r;
		z.a = tex2D (_DirShadowmap, i.uv23).r;

		// return z.r;

		// Transform to linear z, 0 at near, 1 at far
		// z = z * 2 - 1;
		// z = _ZParams.x * (z + 1.0) / (z + _ZParams.y);	

	#if 1
		// float m = dot(z, 0.25);
		// return float4(m, m * m, 0, 0);
		float4 z2 = z * z;
		return float4(dot(z, 0.25), dot(z2, 0.25), 0, 0);
	#else
		//z = exp(_ESMExponent * z);
		z = exp(40.0 * z);
		return dot(z, 0.25);
	#endif
	}

	sampler2D _MainTex;

	float4 fragDownsample ( v2f_tap i ) : SV_Target
	{		
		float4 color = tex2D (_MainTex, i.uv20);
		color += tex2D (_MainTex, i.uv21);
		color += tex2D (_MainTex, i.uv22);
		color += tex2D (_MainTex, i.uv23);
		return color * 0.25;
	}

	struct v2f
	{
		float4 pos : SV_POSITION;
		half2 uv : TEXCOORD0;
		half2 offs : TEXCOORD1;
	};

	float _BlurSize;

	v2f vertBlurHorizontal (appdata_img v)
	{
		v2f o;

		o.pos = UnityObjectToClipPos(v.vertex);
		//o.pos = v.vertex;
		
		o.uv = v.texcoord;
		o.offs = _TexelSize.xy * half2(1.0, 0.0) * _BlurSize;

		return o; 
	}
	
	v2f vertBlurVertical (appdata_img v)
	{
		v2f o;

		o.pos = UnityObjectToClipPos(v.vertex);
		//o.pos = v.vertex;
		
		o.uv = v.texcoord;
		o.offs = _TexelSize.xy * half2(0.0, 1.0) * _BlurSize;
		 
		return o; 
	}	

	float4 fragBlur8(v2f i) : SV_Target
	{
		//half2 coords = i.uv.xy;
		half2 coords = i.uv.xy - i.offs * 5.0;  
		
		float4 color = 0;
		for(int k = 0; k < 11; k++)  
		{
			color += tex2D(_MainTex, coords);
			coords += i.offs;
		}
		return color/11.0;
	}	
					
	ENDCG
	
	SubShader {
	  ZTest Off Cull Off ZWrite Off Blend Off

	// 0
	Pass 
	{ 
		CGPROGRAM
		#pragma vertex vert4Tap
		#pragma fragment fragDownsampleFromShadowmapFormat
		ENDCG	 
	}

	// 1
	Pass 
	{ 
		CGPROGRAM
		#pragma vertex vert4Tap
		#pragma fragment fragDownsample
		ENDCG	 
	}

	// 2
	Pass {
		ZTest Always
		Cull Off
		
		CGPROGRAM 
		
		#pragma vertex vertBlurVertical
		#pragma fragment fragBlur8
		
		ENDCG 
		}	
		
	// 3
	Pass {		
		ZTest Always
		Cull Off
				
		CGPROGRAM
		
		#pragma vertex vertBlurHorizontal
		#pragma fragment fragBlur8
		
		ENDCG
		}

	// 4
	Pass 
	{ 
		CGPROGRAM
		#pragma vertex vert4TapDir
		#pragma fragment fragDownsampleFromShadowmapFormatDir
		ENDCG	 
	}

	// 5
	Pass 
	{ 
		CGPROGRAM
		#pragma vertex vert4TapDir
		#pragma fragment fragDownsample
		ENDCG	 
	}

	}	

	FallBack Off
}
