#version 150 //GL 3.2

#define M_PI 3.14159265358979323846

#define ZEYE_DIFF_DISCONTINUITY 0.01

#include <hostdefs>
#line 11
#include "data/shader/ubo.glsl"
#line 13

#if NSPP == 1u
	uniform sampler2D gbuf_depth;
#else
	uniform sampler2DMS gbuf_depth;
#endif



in vec2 v0f, v1f, v2f;

out vec4 frag_color;



vec3 unproject( vec2 pixel,float z_screen, vec4 viewport )
{
	vec3 vert_screen = vec3( pixel, z_screen );
	vec4 vert_ndc = vec4(
		vec3( (2.0*vert_screen.xy-viewport.xy)/viewport.zw, 2.0*vert_screen.z ) - vec3(1.0),
		1.0
	);
	vec4 vert_wld = matr_PV_inv * vert_ndc;
	vert_wld /= vert_wld.w;
	return vert_wld.xyz;
}

bool tri_point_intersect( vec2 v0,vec2 e01,vec2 e02, vec2 pt )
{
	vec2 test = pt - v0;

	float dot00 = dot( e02, e02  );
	float dot01 = dot( e02, e01  );
	float dot02 = dot( e02, test );
	float dot11 = dot( e01, e01  );
	float dot12 = dot( e01, test );

	float denom = dot00*dot11 - dot01*dot01;
	float u = ( dot11*dot02 - dot01*dot12 ) / denom;
	float v = ( dot00*dot12 - dot01*dot02 ) / denom;

	return u>=-0.0 && v>=-0.0 && u+v<=1.0;
}

float compute_visibility( float z_screen )
{
	vec3 pos_world = unproject( gl_FragCoord.xy,z_screen, viewport );
	vec3 L = normalize( light_pos_xyzw.xyz - pos_world );

	float proj_dist = pos_world.z / L.z;
	vec2 proj_pos = pos_world.xy - L.xy*proj_dist;

	return tri_point_intersect( v0f,v1f-v0f,v2f-v0f, proj_pos ) ? 0.0 : 1.0;
}

void main()
{
	ivec2 coord = ivec2(gl_FragCoord.xy);

	#if NSPP == 1u

		float z_screen = texelFetch( gbuf_depth, coord, 0 ).r;
		float vis = compute_visibility(z_screen);

	#else

		float zs_screen[NSPP];
		for ( int k=0; k<int(NSPP); ++k ) zs_screen[k] = texelFetch( gbuf_depth, coord, k ).r;

		float z_screen_avg = 0.0;
		for ( int k=0; k<int(NSPP); ++k ) z_screen_avg += zs_screen[k];
		z_screen_avg *= 1.0/NSPP;

		float max_abs_diff = 0.0;
		for ( int k=0; k<int(NSPP); ++k )
		{
			float abs_diff = abs( zs_screen[k] - z_screen_avg );
			max_abs_diff = max( max_abs_diff, abs_diff );
		}

		//|dzₛ/dzₑ| = |fn/(n-f) z⁻²|
		float zscreen_diff_discontinuity = clip_far * clip_near;
		zscreen_diff_discontinuity /= ( clip_near - clip_far ) * z_screen_avg*z_screen_avg;
		zscreen_diff_discontinuity *= -ZEYE_DIFF_DISCONTINUITY;

		float vis;
		if ( max_abs_diff > zscreen_diff_discontinuity )
		{
			//Pixel contains a depth discontinuity.  Testing the average position would give the
			//	wrong result.  Test positions per-sample instead.
			vis = 0.0;
			for ( int k=0; k<int(NSPP); ++k )
			{
				vis += compute_visibility( zs_screen[k] );
			}
			vis *= 1.0/NSPP;
		}
		else
		{
			//Pixel doesn't contain a depth discontinuity.  Testing individual positions could give
			//	the wrong result (partial coverage at edges, would could not be filled in by
			//	neighbors, resulting in cracks).  So do a single test on the average position.  This
			//	is also cheaper, though not AA.
			vis = compute_visibility(z_screen_avg);
		}

	#endif

	frag_color = vec4( vis,vis,vis, 1 );
}
