#version 430 core

uniform sampler2D gb_diffuse;
uniform sampler2D gb_specular;
uniform sampler2D gb_normal;
uniform sampler2D gb_depth;
uniform sampler2D proj_tex;
uniform sampler2D shadowmap;
uniform vec2 viewport;

uniform mat4 TextureMatrix;
uniform mat4 ShadowMatrix;

in vec3 spot_pos;
in vec3 spot_dir;
in vec3 spot_params; // cone_angle, cone_cutoff_angle, radius
in vec3 spot_color;  // rgb*intensity

layout (location = 0) out vec4 frag_color;

#include <deferred/gbuffer_read_include.frag>

#include <shading_model/blinn_phong_model_include.frag>

float calculate_shadow(in vec4 pos)
{
	const float samples = 3.0;
	const float filterWidth = samples / 1024.0;
	const float stepSize = 2.0*filterWidth / samples;
	float count = 0.0;

	for (float i=-filterWidth; i < filterWidth; i+=stepSize)
	{
		for (float j=-filterWidth; j < filterWidth; j+=stepSize)
		{
			count += float(pos.z < texture(shadowmap, pos.xy + vec2(i,j)).x);
		}
	}
	return (count / (samples*samples))*0.75 + 0.25;
}

void main()
{
	vec2 uv = gl_FragCoord.xy * viewport;
	vec4 diff = texture(gb_diffuse, uv);
	vec4 spec = texture(gb_specular, uv);
	vec4 norm = texture(gb_normal, uv);
	float dpt = texture(gb_depth, uv).x;
	//vec3 pos = calc_position(uv, nd.w);
	vec3 pos = calc_position(uv, (dpt-0.5)*2.0);

	vec3 ld = spot_pos - pos;
	float len = length(ld);
	if ( len > spot_params.z ) discard;

	vec4 lpos = ShadowMatrix * vec4(pos, 1.0);
	lpos /= lpos.w;
	float shadow_term = calculate_shadow(lpos);

	ld = normalize(ld);

	vec3 n = normalize(norm.xyz);
	vec3 ed = normalize(-pos);

	float atten = 1.0 - pow(len / spot_params.z, 2.0);
	atten *= clamp( (dot(-ld, spot_dir) - spot_params.x) / (spot_params.y - spot_params.x), 0.0, 1.0 );
	shadow_term = mix(shadow_term, 1.0, smoothstep(0.75, 1.0, 1.0 - atten));

	vec3 terms = calculate_blinn_phong_model(n, ld, ed, 8.0) * atten * shadow_term;

	vec4 tpos = TextureMatrix * vec4(pos, 1.0);
	vec3 color = textureProj(proj_tex, tpos).xyz * spot_color * float(tpos.w < 0.0);
	
	frag_color.rgb = color*diff.rgb*terms.x + color*spec.rgb*(terms.y + terms.z);
	frag_color.a = terms.x;
}
