1#version 130
2
3#define NTSC_CRT_GAMMA 2.5
4#define NTSC_MONITOR_GAMMA 2.0
5
6#define fetch_offset(offset, one_x) \
7   COMPAT_TEXTURE(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz
8
9#if defined(VERTEX)
10
11#if __VERSION__ >= 130
12#define COMPAT_VARYING out
13#define COMPAT_ATTRIBUTE in
14#define COMPAT_TEXTURE texture
15#else
16#define COMPAT_VARYING varying
17#define COMPAT_ATTRIBUTE attribute
18#define COMPAT_TEXTURE texture2D
19#endif
20
21#ifdef GL_ES
22#define COMPAT_PRECISION mediump
23#else
24#define COMPAT_PRECISION
25#endif
26
27COMPAT_ATTRIBUTE vec4 VertexCoord;
28COMPAT_ATTRIBUTE vec4 COLOR;
29COMPAT_ATTRIBUTE vec4 TexCoord;
30COMPAT_VARYING vec4 COL0;
31COMPAT_VARYING vec4 TEX0;
32
33uniform mat4 MVPMatrix;
34uniform COMPAT_PRECISION int FrameDirection;
35uniform COMPAT_PRECISION int FrameCount;
36uniform COMPAT_PRECISION vec2 OutputSize;
37uniform COMPAT_PRECISION vec2 TextureSize;
38uniform COMPAT_PRECISION vec2 InputSize;
39
40// vertex compatibility #defines
41#define vTexCoord TEX0.xy
42#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
43#define outsize vec4(OutputSize, 1.0 / OutputSize)
44
45void main()
46{
47    gl_Position = MVPMatrix * VertexCoord;
48    COL0 = COLOR;
49    TEX0.xy = TexCoord.xy - vec2(0.5 / SourceSize.x, 0.0); // Compensate for decimate-by-2.
50}
51
52#elif defined(FRAGMENT)
53
54#ifdef GL_ES
55#ifdef GL_FRAGMENT_PRECISION_HIGH
56precision highp float;
57#else
58precision mediump float;
59#endif
60#define COMPAT_PRECISION mediump
61#else
62#define COMPAT_PRECISION
63#endif
64
65#if __VERSION__ >= 130
66#define COMPAT_VARYING in
67#define COMPAT_TEXTURE texture
68out COMPAT_PRECISION vec4 FragColor;
69#else
70#define COMPAT_VARYING varying
71#define FragColor gl_FragColor
72#define COMPAT_TEXTURE texture2D
73#endif
74
75uniform COMPAT_PRECISION int FrameDirection;
76uniform COMPAT_PRECISION int FrameCount;
77uniform COMPAT_PRECISION vec2 OutputSize;
78uniform COMPAT_PRECISION vec2 TextureSize;
79uniform COMPAT_PRECISION vec2 InputSize;
80uniform sampler2D Texture;
81COMPAT_VARYING vec4 TEX0;
82
83// fragment compatibility #defines
84#define Source Texture
85#define vTexCoord TEX0.xy
86
87#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
88#define outsize vec4(OutputSize, 1.0 / OutputSize)
89
90// begin ntsc-rgbyuv
91const mat3 yiq2rgb_mat = mat3(
92   1.0, 0.956, 0.6210,
93   1.0, -0.2720, -0.6474,
94   1.0, -1.1060, 1.7046);
95
96vec3 yiq2rgb(vec3 yiq)
97{
98   return yiq * yiq2rgb_mat;
99}
100
101const mat3 yiq_mat = mat3(
102      0.2989, 0.5870, 0.1140,
103      0.5959, -0.2744, -0.3216,
104      0.2115, -0.5229, 0.3114
105);
106
107vec3 rgb2yiq(vec3 col)
108{
109   return col * yiq_mat;
110}
111// end ntsc-rgbyuv
112
113// begin ntsc-decode-filter-3phase
114#if __VERSION__ <= 150
115float luma_filter1 = -0.000012020;
116float luma_filter2 = -0.000022146;
117float luma_filter3 = -0.000013155;
118float luma_filter4 = -0.000012020;
119float luma_filter5 = -0.000049979;
120float luma_filter6 = -0.000113940;
121float luma_filter7 = -0.000122150;
122float luma_filter8 = -0.000005612;
123float luma_filter9 = 0.000170516;
124float luma_filter10 = 0.000237199;
125float luma_filter11 = 0.000169640;
126float luma_filter12 = 0.000285688;
127float luma_filter13 = 0.000984574;
128float luma_filter14 = 0.002018683;
129float luma_filter15 = 0.002002275;
130float luma_filter16 = -0.000909882;
131float luma_filter17 = -0.007049081;
132float luma_filter18 = -0.013222860;
133float luma_filter19 = -0.012606931;
134float luma_filter20 = 0.002460860;
135float luma_filter21 = 0.035868225;
136float luma_filter22 = 0.084016453;
137float luma_filter23 = 0.135563500;
138float luma_filter24 = 0.175261268;
139float luma_filter25 = 0.190176552;
140
141float chroma_filter1 = -0.000118847;
142float chroma_filter2 = -0.000271306;
143float chroma_filter3 = -0.000502642;
144float chroma_filter4 = -0.000930833;
145float chroma_filter5 = -0.001451013;
146float chroma_filter6 = -0.002064744;
147float chroma_filter7 = -0.002700432;
148float chroma_filter8 = -0.003241276;
149float chroma_filter9 = -0.003524948;
150float chroma_filter10 = -0.003350284;
151float chroma_filter11 = -0.002491729;
152float chroma_filter12 = -0.000721149;
153float chroma_filter13 = 0.002164659;
154float chroma_filter14 = 0.006313635;
155float chroma_filter15 = 0.011789103;
156float chroma_filter16 = 0.018545660;
157float chroma_filter17 = 0.026414396;
158float chroma_filter18 = 0.035100710;
159float chroma_filter19 = 0.044196567;
160float chroma_filter20 = 0.053207202;
161float chroma_filter21 = 0.061590275;
162float chroma_filter22 = 0.068803602;
163float chroma_filter23 = 0.074356193;
164float chroma_filter24 = 0.077856564;
165float chroma_filter25 = 0.079052396;
166#else
167#define TAPS 24
168const float luma_filter[TAPS + 1] = float[TAPS + 1](
169   -0.000012020,
170   -0.000022146,
171   -0.000013155,
172   -0.000012020,
173   -0.000049979,
174   -0.000113940,
175   -0.000122150,
176   -0.000005612,
177   0.000170516,
178   0.000237199,
179   0.000169640,
180   0.000285688,
181   0.000984574,
182   0.002018683,
183   0.002002275,
184   -0.000909882,
185   -0.007049081,
186   -0.013222860,
187   -0.012606931,
188   0.002460860,
189   0.035868225,
190   0.084016453,
191   0.135563500,
192   0.175261268,
193   0.190176552);
194
195const float chroma_filter[TAPS + 1] = float[TAPS + 1](
196   -0.000118847,
197   -0.000271306,
198   -0.000502642,
199   -0.000930833,
200   -0.001451013,
201   -0.002064744,
202   -0.002700432,
203   -0.003241276,
204   -0.003524948,
205   -0.003350284,
206   -0.002491729,
207   -0.000721149,
208   0.002164659,
209   0.006313635,
210   0.011789103,
211   0.018545660,
212   0.026414396,
213   0.035100710,
214   0.044196567,
215   0.053207202,
216   0.061590275,
217   0.068803602,
218   0.074356193,
219   0.077856564,
220   0.079052396);
221#endif
222// end ntsc-decode-filter-3phase
223
224void main()
225{
226// begin ntsc-pass2-decode
227	float one_x = 1.0 / SourceSize.x;
228	vec3 signal = vec3(0.0);
229#if __VERSION__ <= 130
230	float offset;
231	vec3 sums;
232
233	#define macro_loopz(c) offset = float(c) - 1.0; \
234		sums = fetch_offset(offset - 24., one_x) + fetch_offset(24. - offset, one_x); \
235		signal += sums * vec3(luma_filter##c, chroma_filter##c, chroma_filter##c);
236
237	// unrolling the loopz
238	macro_loopz(1)
239	macro_loopz(2)
240	macro_loopz(3)
241	macro_loopz(4)
242	macro_loopz(5)
243	macro_loopz(6)
244	macro_loopz(7)
245	macro_loopz(8)
246	macro_loopz(9)
247	macro_loopz(10)
248	macro_loopz(11)
249	macro_loopz(12)
250	macro_loopz(13)
251	macro_loopz(14)
252	macro_loopz(15)
253	macro_loopz(16)
254	macro_loopz(17)
255	macro_loopz(18)
256	macro_loopz(19)
257	macro_loopz(20)
258	macro_loopz(21)
259	macro_loopz(22)
260	macro_loopz(23)
261	macro_loopz(24)
262
263	signal += COMPAT_TEXTURE(Texture, TEX0.xy).xyz *
264		vec3(luma_filter25, chroma_filter25, chroma_filter25);
265#else
266	for (int i = 0; i < TAPS; i++)
267	{
268		float offset = float(i);
269
270		vec3 sums = fetch_offset(offset - float(TAPS), one_x) +
271			fetch_offset(float(TAPS) - offset, one_x);
272
273		signal += sums * vec3(luma_filter[i], chroma_filter[i], chroma_filter[i]);
274	}
275	signal += COMPAT_TEXTURE(Source, vTexCoord).xyz *
276		vec3(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS]);
277#endif
278// end ntsc-pass2-decode
279	vec3 rgb = yiq2rgb(signal);
280	FragColor = vec4(pow(rgb, vec3(NTSC_CRT_GAMMA / NTSC_MONITOR_GAMMA)), 1.0);
281}
282#endif
283