1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
$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;
}
|