uniform sampler2D vsm;
uniform vec2      DepthRange;

#ifdef USE_VSM

float calc_vsm_shadow(in vec4 pos, in vec2 m)
{
#if 1
	float dist = pos.z*DepthRange.y;
	if ( dist <= m.x ) return 1.0;
	float variance = max(m.y - m.x*m.x, 0.00001);
	float d = dist - m.x;
	float p = float(dist <= m.x);
	float p_max = variance / (variance + d*d);
	//return smoothstep(0.6, 1.0, max(p, p_max));
	return smoothstep(0.6, 1.0, max(p_max, p));
#else
	float depth = pos.z*DepthRange.y;
	if ( depth <= m.x ) return 1.0;
	float variance = m.y - m.x*m.x;
	float d = m.x - depth;
	float p  = variance / (variance + d*d);
	return max(p, float(depth <= m.x) );
	//return smoothstep(0.6, 1.0, max(p, float(depth <= m.x)));
#endif
}

vec4 vsm_pcf(in vec2 pos)
{
	const float samples = 4.0; //5.0;
	const float filterWidth = samples/1024.0;
	const float stepSize = 2.0*filterWidth / samples;
	vec4 m = vec4( 0.0 );
	for (float i=-filterWidth; i < filterWidth; i+=stepSize)
	{
		for (float j=-filterWidth; j < filterWidth; j+=stepSize)
		{
			m += texture2D(vsm, pos.xy + vec2(i,j));
		}
	}
	return m / (samples*samples);
}

float vsm_shadow_first(in vec4 pos)
{
	//vec2 m = texture2D(vsm, pos.xy).xy;
	vec2 m = vsm_pcf(pos.xy).xy;
	return calc_vsm_shadow(pos, m);
}

float vsm_shadow_second(in vec4 pos)
{
	//vec2 m = texture2D(vsm, pos.xy).zw;
	vec2 m = vsm_pcf(pos.xy).zw;
	return calc_vsm_shadow(pos, m);
}

#else

float vsm_shadow_first(in vec4 pos)
{
	const float samples = 3.0;
	const float filterWidth = samples/1024.0;
	const float stepSize = 2.0*filterWidth / samples;
	float dist = pos.z*DepthRange.y;
	float count = 0.0;

	for (float i=-filterWidth; i < filterWidth; i+=stepSize)
	{
		for (float j=-filterWidth; j < filterWidth; j+=stepSize)
		{
			count += float( texture2D(vsm, pos.xy + vec2(i,j) ).x > dist );
		}
	}
	return count / (samples*samples);
}

float vsm_shadow_second(in vec4 pos)
{
	const float samples = 3.0;
	const float filterWidth = samples/1024.0;
	const float stepSize = 2.0*filterWidth / samples;
	float dist = pos.z*DepthRange.y;
	float count = 0.0;

	for (float i=-filterWidth; i < filterWidth; i+=stepSize)
	{
		for (float j=-filterWidth; j < filterWidth; j+=stepSize)
		{
			count += float( texture2D(vsm, pos.xy + vec2(i,j) ).z > dist );
		}
	}
	return count / (samples*samples);
}

#endif
