3
uniform float display_sizeX <
7
ui_label = "Screen Width (NTSC)";
10
uniform float display_sizeY <
13
ui_max = BUFFER_HEIGHT;
14
ui_label = "Screen Height (NTSC)";
17
uniform bool bUseTwoPhase <
18
ui_label = "Use Two-Phase (NTSC)";
21
uniform bool bUseSVideo <
22
ui_label = "Use S-Video (NTSC)";
23
ui_tooltip = "Uses S-Video Cables instead of Composite.";
26
uniform float NTSC_DISPLAY_GAMMA <
31
ui_label = "NTSC Display Gamma (NTSC)";
34
uniform float NTSC_CRT_GAMMA <
39
ui_label = "NTSC CRT Gamma (NTSC)";
44
#define CHROMA_MOD_FREQ (PI / 3.0)
45
#define CHROMA_MOD_FREQ_TWO (4.0 * PI / 15.0)
49
#define ARTIFACTING 1.0
52
#define ARTIFACTING_SV 0.0
53
#define FRINGING_SV 0.0
55
#define display_size int2(display_sizeX,display_sizeY)
57
static const float3x3 mix_mat = float3x3(
58
BRIGHTNESS, ARTIFACTING, ARTIFACTING,
59
FRINGING, 2.0 * SATURATION, 0.0,
60
FRINGING, 0.0, 2.0 * SATURATION
63
static const float3x3 mix_mat_sv = float3x3(
64
BRIGHTNESS, ARTIFACTING_SV, ARTIFACTING_SV,
65
FRINGING_SV, 2.0 * SATURATION, 0.0,
66
FRINGING_SV, 0.0, 2.0 * SATURATION
69
static const float3x3 yiq2rgb_mat = float3x3(
71
1.0, -0.2720, -0.6474,
72
1.0, -1.1060, 1.7046);
74
float3 yiq2rgb(float3 yiq)
76
return mul(yiq2rgb_mat, yiq);
79
static const float3x3 yiq_mat = float3x3(
80
0.2989, 0.5870, 0.1140,
81
0.5959, -0.2744, -0.3216,
82
0.2115, -0.5229, 0.3114
85
float3 rgb2yiq(float3 col)
87
return mul(yiq_mat, col);
90
float fmod(float a, float b) {
91
float c = frac(abs(a / b)) * abs(b);
92
return (a < 0) ? -c : c;
98
Height = BUFFER_HEIGHT;
101
sampler s0 { Texture = target0_ntsc; };
103
uniform int framecount < source = "framecount"; >;
105
float4 NTSCStartPS( float4 pos : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
107
return tex2D(s0,texcoord);
110
float4 NTSCEncodePS( float4 pos : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
112
float3 col = tex2D(ReShade::BackBuffer, texcoord).rgb;
113
float3 yiq = rgb2yiq(col);
115
float2 pix_no = texcoord * display_size * float2( 4.0, 1.0 );
116
float2 one = 1.0 / ReShade::ScreenSize;
118
float chroma_phase = 0.6667 * PI * (fmod(pix_no.y, 3.0) + framecount);
119
float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ;
122
chroma_phase = PI * (fmod(pix_no.y, 2.0) + framecount);
123
mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ_TWO;
126
float i_mod = cos(mod_phase);
127
float q_mod = sin(mod_phase);
130
yiq.yz *= float2(i_mod, q_mod); // Modulate.
131
yiq = mul(mix_mat_sv,yiq); // Cross-talk.
132
yiq.yz *= float2(i_mod, q_mod); // Demodulate.
134
yiq.yz *= float2(i_mod, q_mod); // Modulate.
135
yiq = mul(mix_mat,yiq); // Cross-talk.
136
yiq.yz *= float2(i_mod, q_mod); // Demodulate.
139
return float4(yiq, 1.0);
142
float3 t2d(float2 texcoord)
144
return tex2D(s0,texcoord).rgb;
147
#define fixCoord (texcoord - float2( 0.5 * one_x, 0.0))
148
#define fetch_offset(offset, one_x) t2d(fixCoord + float2( (offset) * (one_x), 0.0))
150
float4 NTSCDecodePS( float4 pos : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
154
float luma_filter[33] = {
190
float chroma_filter[33] = {
226
luma_filter[0] = -0.000012020;
227
luma_filter[1] = -0.000022146;
228
luma_filter[2] = -0.000013155;
229
luma_filter[3] = -0.000012020;
230
luma_filter[4] = -0.000049979;
231
luma_filter[5] = -0.000113940;
232
luma_filter[6] = -0.000122150;
233
luma_filter[7] = -0.000005612;
234
luma_filter[8] = 0.000170516;
235
luma_filter[9] = 0.000237199;
236
luma_filter[10] = 0.000169640;
237
luma_filter[11] = 0.000285688;
238
luma_filter[12] = 0.000984574;
239
luma_filter[13] = 0.002018683;
240
luma_filter[14] = 0.002002275;
241
luma_filter[15] = -0.000909882;
242
luma_filter[16] = -0.007049081;
243
luma_filter[17] = -0.013222860;
244
luma_filter[18] = -0.012606931;
245
luma_filter[19] = 0.002460860;
246
luma_filter[20] = 0.035868225;
247
luma_filter[21] = 0.084016453;
248
luma_filter[22] = 0.135563500;
249
luma_filter[23] = 0.175261268;
250
luma_filter[24] = 0.190176552;
252
chroma_filter[0] = -0.000118847;
253
chroma_filter[1] = -0.000271306;
254
chroma_filter[2] = -0.000502642;
255
chroma_filter[3] = -0.000930833;
256
chroma_filter[4] = -0.001451013;
257
chroma_filter[5] = -0.002064744;
258
chroma_filter[6] = -0.002700432;
259
chroma_filter[7] = -0.003241276;
260
chroma_filter[8] = -0.003524948;
261
chroma_filter[9] = -0.003350284;
262
chroma_filter[10] = -0.002491729;
263
chroma_filter[11] = -0.000721149;
264
chroma_filter[12] = 0.002164659;
265
chroma_filter[13] = 0.006313635;
266
chroma_filter[14] = 0.011789103;
267
chroma_filter[15] = 0.018545660;
268
chroma_filter[16] = 0.026414396;
269
chroma_filter[17] = 0.035100710;
270
chroma_filter[18] = 0.044196567;
271
chroma_filter[19] = 0.053207202;
272
chroma_filter[20] = 0.061590275;
273
chroma_filter[21] = 0.068803602;
274
chroma_filter[22] = 0.074356193;
275
chroma_filter[23] = 0.077856564;
276
chroma_filter[24] = 0.079052396;
282
luma_filter[0] = -0.000205844;
283
luma_filter[1] = -0.000149453;
284
luma_filter[2] = -0.000051693;
285
luma_filter[3] = 0.000000000;
286
luma_filter[4] = -0.000066171;
287
luma_filter[5] = -0.000245058;
288
luma_filter[6] = -0.000432928;
289
luma_filter[7] = -0.000472644;
290
luma_filter[8] = -0.000252236;
291
luma_filter[9] = 0.000198929;
292
luma_filter[10] = 0.000687058;
293
luma_filter[11] = 0.000944112;
294
luma_filter[12] = 0.000803467;
295
luma_filter[13] = 0.000363199;
296
luma_filter[14] = 0.000013422;
297
luma_filter[15] = 0.000253402;
298
luma_filter[16] = 0.001339461;
299
luma_filter[17] = 0.002932972;
300
luma_filter[18] = 0.003983485;
301
luma_filter[19] = 0.003026683;
302
luma_filter[20] = -0.001102056;
303
luma_filter[21] = -0.008373026;
304
luma_filter[22] = -0.016897700;
305
luma_filter[23] = -0.022914480;
306
luma_filter[24] = -0.021642347;
307
luma_filter[25] = -0.008863273;
308
luma_filter[26] = 0.017271957;
309
luma_filter[27] = 0.054921920;
310
luma_filter[28] = 0.098342579;
311
luma_filter[29] = 0.139044281;
312
luma_filter[30] = 0.168055832;
313
luma_filter[31] = 0.178571429;
315
chroma_filter[0] = 0.001384762;
316
chroma_filter[1] = 0.001678312;
317
chroma_filter[2] = 0.002021715;
318
chroma_filter[3] = 0.002420562;
319
chroma_filter[4] = 0.002880460;
320
chroma_filter[5] = 0.003406879;
321
chroma_filter[6] = 0.004004985;
322
chroma_filter[7] = 0.004679445;
323
chroma_filter[8] = 0.005434218;
324
chroma_filter[9] = 0.006272332;
325
chroma_filter[10] = 0.007195654;
326
chroma_filter[11] = 0.008204665;
327
chroma_filter[12] = 0.009298238;
328
chroma_filter[13] = 0.010473450;
329
chroma_filter[14] = 0.011725413;
330
chroma_filter[15] = 0.013047155;
331
chroma_filter[16] = 0.014429548;
332
chroma_filter[17] = 0.015861306;
333
chroma_filter[18] = 0.017329037;
334
chroma_filter[19] = 0.018817382;
335
chroma_filter[20] = 0.020309220;
336
chroma_filter[21] = 0.021785952;
337
chroma_filter[22] = 0.023227857;
338
chroma_filter[23] = 0.024614500;
339
chroma_filter[24] = 0.025925203;
340
chroma_filter[25] = 0.027139546;
341
chroma_filter[26] = 0.028237893;
342
chroma_filter[27] = 0.029201910;
343
chroma_filter[28] = 0.030015081;
344
chroma_filter[29] = 0.030663170;
345
chroma_filter[30] = 0.031134640;
346
chroma_filter[31] = 0.031420995;
347
chroma_filter[32] = 0.031517031;
350
float one_x = 1.0 / ReShade::ScreenSize.x;
353
float3 signal = float3(0.0,0.0,0.0);
354
for (int i = 0; i < TAPS; i++)
356
float offset = float(i);
358
float3 sums = fetch_offset(offset - float(TAPS), one_x) +
359
fetch_offset(float(TAPS) - offset, one_x);
361
signal += sums * float3(luma_filter[i], chroma_filter[i], chroma_filter[i]);
363
signal += tex2D(s0, texcoord).xyz *
364
float3(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS]);
366
float3 rgb = yiq2rgb(signal);
367
return float4(rgb, 1.0);
370
float4 NTSCGaussPS( float4 pos : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
373
float2 pix_no = texcoord * display_size * float2( 4.0, 1.0 );
374
float2 one = 1.0 / ReShade::ScreenSize;
376
#define TEX(off) pow(tex2D(ReShade::BackBuffer, texcoord + float2(0.0, (off) * one.y)).rgb, float3(NTSC_CRT_GAMMA,NTSC_CRT_GAMMA,NTSC_CRT_GAMMA))
378
float3 frame0 = TEX(-2.0);
379
float3 frame1 = TEX(-1.0);
380
float3 frame2 = TEX(0.0);
381
float3 frame3 = TEX(1.0);
382
float3 frame4 = TEX(2.0);
384
float offset_dist = frac(pix_no.y) - 0.5;
385
float dist0 = 2.0 + offset_dist;
386
float dist1 = 1.0 + offset_dist;
387
float dist2 = 0.0 + offset_dist;
388
float dist3 = -1.0 + offset_dist;
389
float dist4 = -2.0 + offset_dist;
391
float3 scanline = frame0 * exp(-5.0 * dist0 * dist0);
392
scanline += frame1 * exp(-5.0 * dist1 * dist1);
393
scanline += frame2 * exp(-5.0 * dist2 * dist2);
394
scanline += frame3 * exp(-5.0 * dist3 * dist3);
395
scanline += frame4 * exp(-5.0 * dist4 * dist4);
397
return float4(pow(1.15 * scanline, float3(1.0 / NTSC_DISPLAY_GAMMA, 1.0 / NTSC_DISPLAY_GAMMA, 1.0 / NTSC_DISPLAY_GAMMA)), 1.0);
400
float4 NTSCFinalPS( float4 pos : SV_Position, float2 texcoord : TEXCOORD0) : SV_Target
402
return tex2D(ReShade::BackBuffer,texcoord);
406
technique NTSC_RetroArch
408
// first pass: encode s-video signal
411
RenderTarget = target0_ntsc;
413
VertexShader = PostProcessVS;
414
PixelShader = NTSCEncodePS;
417
// second pass: decode composite signal
420
VertexShader = PostProcessVS;
421
PixelShader = NTSCDecodePS;
423
// third pass: adds gaussian with scanlines
426
VertexShader = PostProcessVS;
427
PixelShader = NTSCGaussPS;
429
// final pass: decode composite signal
432
VertexShader = PostProcessVS;
433
PixelShader = NTSCFinalPS;