$input v_color0, v_texcoord0

// license:BSD-3-Clause
// copyright-holders:Ryan Holtz,ImJezze
//-----------------------------------------------------------------------------
// NTSC Decode Effect
//-----------------------------------------------------------------------------

#include "common.sh"

// Autos
uniform vec4 u_source_dims;

// User-supplied
uniform vec4 u_a_value;
uniform vec4 u_b_value;
uniform vec4 u_cc_value;
uniform vec4 u_o_value;
uniform vec4 u_scan_time;
uniform vec4 u_notch_width;
uniform vec4 u_y_freq_response;
uniform vec4 u_i_freq_response;
uniform vec4 u_q_freq_response;
uniform vec4 u_jitter_offset;

// Parametric
uniform vec4 u_jitter_amount;

// Samplers
SAMPLER2D(s_tex, 0);
SAMPLER2D(s_screen, 1);

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

void main()
{
	vec4 BaseTexel = texture2D(s_screen, v_texcoord0.xy);

	vec4 zero = vec4(0.0, 0.0, 0.0, 0.0);
	vec4 quarter = vec4(0.25, 0.25, 0.25, 0.25);
	vec4 onehalf = vec4(0.5, 0.5, 0.5, 0.5);
	vec4 one = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 two = vec4(2.0, 2.0, 2.0, 2.0);
	vec4 four = vec4(4.0, 4.0, 4.0, 4.0);
	int iSampleCount = 64;
	vec4 SampleCount = vec4(64.0, 64.0, 64.0, 64.0);
	vec4 HalfSampleCount = SampleCount / two;

	vec4 TimePerSample = u_scan_time.xxxx / (u_source_dims.xxxx * four);

	vec4 PI = vec4(3.1415927, 3.1415927, 3.1415927, 3.1415927);
	vec4 PI2 = vec4(6.2831854, 6.2831854, 6.2831854, 6.2831854);

	vec4 Fc_y1 = (u_cc_value.xxxx - u_notch_width.xxxx * onehalf) * TimePerSample;
	vec4 Fc_y2 = (u_cc_value.xxxx + u_notch_width.xxxx * onehalf) * TimePerSample;
	vec4 Fc_y3 = u_y_freq_response.xxxx * TimePerSample;
	vec4 Fc_i = u_i_freq_response.xxxx * TimePerSample;
	vec4 Fc_q = u_q_freq_response.xxxx * TimePerSample;
	vec4 Fc_i_2 = Fc_i * two;
	vec4 Fc_q_2 = Fc_q * two;
	vec4 Fc_y1_2 = Fc_y1 * two;
	vec4 Fc_y2_2 = Fc_y2 * two;
	vec4 Fc_y3_2 = Fc_y3 * two;
	vec4 Fc_i_pi2 = Fc_i * PI2;
	vec4 Fc_q_pi2 = Fc_q * PI2;
	vec4 Fc_y1_pi2 = Fc_y1 * PI2;
	vec4 Fc_y2_pi2 = Fc_y2 * PI2;
	vec4 Fc_y3_pi2 = Fc_y3 * PI2;
	vec4 PI2Length = PI2 / SampleCount;

	vec4 W = PI2 * u_cc_value.xxxx * u_scan_time.xxxx;
	vec4 WoPI = W / PI;

	vec4 HOffset = (u_b_value.xxxx + u_jitter_amount.xxxx * u_jitter_offset.xxxx) / WoPI;
	vec4 VScale = (u_a_value.xxxx * u_source_dims.yyyy) / WoPI;

	vec4 YAccum = zero;
	vec4 IAccum = zero;
	vec4 QAccum = zero;

	vec4 Cy = v_texcoord0.yyyy;
	vec4 VPosition = Cy;

	for (int i = 0; i < 64; i = i + 4)
	{
		vec4 n = vec4(i, i, i, i) - vec4(32.0, 32.0, 32.0, 32.0);
		vec4 n4 = n + vec4(0.0, 1.0, 2.0, 3.0);

		vec4 Cx = v_texcoord0.xxxx + (n4 * quarter) / u_source_dims.xxxx;
		vec4 HPosition = Cx;

		vec4 C = texture2D(s_tex, vec2(Cx.x, Cy.x));

		vec4 T = HPosition + HOffset + VPosition * VScale;
		vec4 WT = W * T + u_o_value.xxxx;

		vec4 SincKernel = vec4(0.54, 0.54, 0.54, 0.54) + vec4(0.46, 0.46, 0.46, 0.46) * cos(PI2Length * n4);

		vec4 SincYIn1 = Fc_y1_pi2 * n4;
		vec4 SincYIn2 = Fc_y2_pi2 * n4;
		vec4 SincYIn3 = Fc_y3_pi2 * n4;
		vec4 SincIIn = Fc_i_pi2 * n4;
		vec4 SincQIn = Fc_q_pi2 * n4;

		vec4 SincY1 = SincYIn1 != zero ? sin(SincYIn1) / SincYIn1 : one;
		vec4 SincY2 = SincYIn2 != zero ? sin(SincYIn2) / SincYIn2 : one;
		vec4 SincY3 = SincYIn3 != zero ? sin(SincYIn3) / SincYIn3 : one;

		vec4 IdealY = (Fc_y1_2 * SincY1 - Fc_y2_2 * SincY2) + Fc_y3_2 * SincY3;
		vec4 IdealI = Fc_i_2 * (SincIIn != zero ? sin(SincIIn) / SincIIn : one);
		vec4 IdealQ = Fc_q_2 * (SincQIn != zero ? sin(SincQIn) / SincQIn : one);

		vec4 FilterY = SincKernel * IdealY;
		vec4 FilterI = SincKernel * IdealI;
		vec4 FilterQ = SincKernel * IdealQ;

		YAccum = YAccum + C * FilterY;
		IAccum = IAccum + C * cos(WT) * FilterI;
		QAccum = QAccum + C * sin(WT) * FilterQ;
	}

	vec3 YIQ = vec3(
		(YAccum.r + YAccum.g + YAccum.b + YAccum.a),
		(IAccum.r + IAccum.g + IAccum.b + IAccum.a) * 2.0,
		(QAccum.r + QAccum.g + QAccum.b + QAccum.a) * 2.0);

	vec3 RGB = vec3(
		dot(YIQ, vec3(1.0, 0.956, 0.621)),
		dot(YIQ, vec3(1.0, -0.272, -0.647)),
		dot(YIQ, vec3(1.0, -1.106, 1.703)));

	// RGB obviously contains a NaN somewhere along the line! Returns black if vec4 etc. are included, white if just vec4(1.0)
	gl_FragColor = vec4(RGB, BaseTexel.a) * v_color0;
}
