From 0ef58d965c6145c294ad2f70c179f050988e609b Mon Sep 17 00:00:00 2001 From: hunterk Date: Wed, 24 May 2017 16:11:48 -0500 Subject: [PATCH] add mame-ntsc-singlepass and artifact-colors shaders and presets --- ntsc/artifact-colors.slangp | 16 ++ ntsc/mame-ntsc-singlepass.slangp | 5 + .../artifact-colors/artifact-colors0.slang | 66 ++++++ .../artifact-colors/artifact-colors1.slang | 145 ++++++++++++ .../artifact-colors/artifact-colors2.slang | 167 ++++++++++++++ .../mame-ntsc/ntsc-mame-singlepass.slang | 209 ++++++++++++++++++ presets/c64-monitor.slangp | 24 ++ presets/ntsc-phosphorlut.slangp | 11 +- 8 files changed, 636 insertions(+), 7 deletions(-) create mode 100644 ntsc/artifact-colors.slangp create mode 100644 ntsc/mame-ntsc-singlepass.slangp create mode 100644 ntsc/shaders/artifact-colors/artifact-colors0.slang create mode 100644 ntsc/shaders/artifact-colors/artifact-colors1.slang create mode 100644 ntsc/shaders/artifact-colors/artifact-colors2.slang create mode 100644 ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang create mode 100644 presets/c64-monitor.slangp diff --git a/ntsc/artifact-colors.slangp b/ntsc/artifact-colors.slangp new file mode 100644 index 0000000..c6b9478 --- /dev/null +++ b/ntsc/artifact-colors.slangp @@ -0,0 +1,16 @@ +shaders = 3 + +shader0 = shaders/artifact-colors/artifact-colors0.slang +scale0 = 1.0 +scale_type0 = source +filter_linear0 = false + +shader1 = shaders/artifact-colors/artifact-colors1.slang +scale1 = 1.0 +scale_type1 = source +filter_linear1 = false + +shader2 = shaders/artifact-colors/artifact-colors2.slang +scale2 = 1.0 +scale_type2 = source +filter_linear2 = false \ No newline at end of file diff --git a/ntsc/mame-ntsc-singlepass.slangp b/ntsc/mame-ntsc-singlepass.slangp new file mode 100644 index 0000000..8c349d2 --- /dev/null +++ b/ntsc/mame-ntsc-singlepass.slangp @@ -0,0 +1,5 @@ +shaders = 1 + +shader0 = shaders/mame-ntsc/ntsc-mame-singlepass.slang +scale_type0 = source +scale0 = 1.0 \ No newline at end of file diff --git a/ntsc/shaders/artifact-colors/artifact-colors0.slang b/ntsc/shaders/artifact-colors/artifact-colors0.slang new file mode 100644 index 0000000..a241dbd --- /dev/null +++ b/ntsc/shaders/artifact-colors/artifact-colors0.slang @@ -0,0 +1,66 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float F_COL; +} params; + +#pragma parameter F_COL "F Col" 0.25 0.25 1.5 0.25 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +//Modulator + +//#define F_COL (1.0 / 4.0) // moved to parameter + +float tau = atan(1.0)*8.0; + +mat3 rgb2yiq = mat3(0.299, 0.596, 0.211, + 0.587,-0.274,-0.523, + 0.114,-0.322, 0.312); + +//Complex oscillator, Fo = Oscillator freq., Fs = Sample freq., n = Sample index +vec2 Oscillator(float Fo, float Fs, float n) +{ + float phase = (tau*Fo*floor(n))/Fs; + return vec2(cos(phase),sin(phase)); +} + +void main() +{ + float Fs = params.SourceSize.x; + float Fcol = Fs * params.F_COL; + float n = floor(vTexCoord.x * params.OutputSize.x); + + vec3 cRGB = texture(Source, vTexCoord.xy).rgb; + vec3 cYIQ = rgb2yiq * cRGB; + + vec2 cOsc = Oscillator(Fcol, Fs, n); + + float sig = cYIQ.x + dot(cOsc, cYIQ.yz); + + FragColor = vec4(sig,0.,0.,0.); +} \ No newline at end of file diff --git a/ntsc/shaders/artifact-colors/artifact-colors1.slang b/ntsc/shaders/artifact-colors/artifact-colors1.slang new file mode 100644 index 0000000..719eaaa --- /dev/null +++ b/ntsc/shaders/artifact-colors/artifact-colors1.slang @@ -0,0 +1,145 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float FIR_SIZE; + float F_COL; + float F_LUMA_LP; + float F_COL_BW; +} params; + +#pragma parameter FIR_SIZE "FIR Size" 29.0 1.0 50.0 1.0 +#pragma parameter F_COL "F Col" 0.25 0.25 1.5 0.25 +#pragma parameter F_LUMA_LP "F Luma LP" 0.16667 0.0001 0.333333 0.02 +#pragma parameter F_COL_BW "F Col BW" 50.0 10.0 200.0 1.0 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +#pragma format R16G16B16A16_SFLOAT +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +//Demodulator + +//#define F_COL (1.0 / 4.0) // moved to parameter +//#define F_LUMA_LP (1.0 / 6.0) // moved to parameter +//#define F_COL_BW (1.0 / 50.0) // moved to parameter + + +//#define FIR_SIZE 29 // moved to parameter + +float pi = 3.141592654;//atan(1.0)*4.0; +float tau = 6.283185308;//atan(1.0)*8.0; + +//Non-normalized texture sampling. +vec4 sample2D(sampler2D tex,vec2 resolution, vec2 uv) +{ + return texture(tex, uv / resolution); +} + +//Complex multiply +vec2 cmul(vec2 a, vec2 b) +{ + return vec2((a.x * b.x) - (a.y * b.y), (a.x * b.y) + (a.y * b.x)); +} + +float sinc(float x) +{ + return (x == 0.0) ? 1.0 : sin(x*pi)/(x*pi); +} + +//https://en.wikipedia.org/wiki/Window_function +float WindowBlackman(float a, int N, int i) +{ + float a0 = (1.0 - a) / 2.0; + float a1 = 0.5; + float a2 = a / 2.0; + + float wnd = a0; + wnd -= a1 * cos(2.0 * pi * (float(i) / float(N - 1))); + wnd += a2 * cos(4.0 * pi * (float(i) / float(N - 1))); + + return wnd; +} + +//FIR lowpass filter +//Fc = Cutoff freq., Fs = Sample freq., N = # of taps, i = Tap index +float Lowpass(float Fc, float Fs, int N, int i) +{ + float wc = (Fc/Fs); + + float wnd = WindowBlackman(0.16, N, i); + + return 2.0*wc * wnd * sinc(2.0*wc * float(i - N/2)); +} + +//FIR bandpass filter +//Fa/Fb = Low/High cutoff freq., Fs = Sample freq., N = # of taps, i = Tap index +float Bandpass(float Fa, float Fb, float Fs, int N, int i) +{ + float wa = (Fa/Fs); + float wb = (Fb/Fs); + + float wnd = WindowBlackman(0.16, N, i); + + return 2.0*(wb-wa) * wnd * (sinc(2.0*wb * float(i - N/2)) - sinc(2.0*wa * float(i - N/2))); +} + +//Complex oscillator, Fo = Oscillator freq., Fs = Sample freq., n = Sample index +vec2 Oscillator(float Fo, float Fs, float N) +{ + float phase = (tau*Fo*floor(N))/Fs; + return vec2(cos(phase),sin(phase)); +} + +void main() +{ + float Fs = params.SourceSize.x; + float Fcol = Fs * params.F_COL; + float Fcolbw = Fs * (1.0 / params.F_COL_BW); + float Flumlp = Fs * params.F_LUMA_LP; + float n = floor(vTexCoord.x * params.OutputSize.x); + + float y_sig = 0.0; + float iq_sig = 0.0; + + vec2 cOsc = Oscillator(Fcol, Fs, n); + + n += float(params.FIR_SIZE)/2.0; + + //Separate luma(Y) & chroma(IQ) signals + for(int i = 0;i < params.FIR_SIZE;i++) + { + int tpidx = int(params.FIR_SIZE) - i - 1; + float lp = Lowpass(Flumlp, Fs, int(params.FIR_SIZE), tpidx); + float bp = Bandpass(Fcol - Fcolbw, Fcol + Fcolbw, Fs, int(params.FIR_SIZE), tpidx); + + y_sig += sample2D(Source, params.SourceSize.xy, vec2(n - float(i), (vTexCoord.y * params.OutputSize.y))).r * lp; + iq_sig += sample2D(Source, params.SourceSize.xy, vec2(n - float(i), (vTexCoord.y * params.OutputSize.y))).r * bp; + } + + //Shift IQ signal down from Fcol to DC + vec2 iq_sig_mix = cmul(vec2(iq_sig, 0.), cOsc); + + FragColor = vec4(y_sig, iq_sig_mix, 0.); +} \ No newline at end of file diff --git a/ntsc/shaders/artifact-colors/artifact-colors2.slang b/ntsc/shaders/artifact-colors/artifact-colors2.slang new file mode 100644 index 0000000..b3c3cfb --- /dev/null +++ b/ntsc/shaders/artifact-colors/artifact-colors2.slang @@ -0,0 +1,167 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float FIR_SIZE; + float F_COL; + float SATURATION; + float BRIGHTNESS; + float F_LUMA_LP; + float HUE; +} params; + +#pragma parameter FIR_SIZE "FIR Size" 29.0 1.0 50.0 1.0 +#pragma parameter F_COL "F Col" 0.25 0.25 1.5 0.25 +#pragma parameter SATURATION "Saturation" 30.0 0.0 100.0 1.0 +#pragma parameter BRIGHTNESS "Brightness" 1.0 0.0 2.0 0.01 +#pragma parameter F_LUMA_LP "F Luma LP" 0.16667 0.0001 0.333333 0.02 +#pragma parameter HUE "Hue" 0.0 0.0 1.0 0.01 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Original; +layout(set = 0, binding = 4) uniform sampler2D Pass2; + +//Composite color artifact simulator +//Change Buf A to change the input image. + +//#define HUE 0.0 // moved to parameter +//#define SATURATION 30.0 // moved to parameter +//#define BRIGHTNESS 1.0 // moved to parameter + +#define COMPOSITE 0 //Composite demodulated image +#define RGB 1 //Raw RGB input image +#define LUMA 2 //Luma component +#define CHROMA 3 //Chroma component +#define SIGNAL 4 //Modulated image +#define SPLIT 5 //Left = Input RGB, Right = Output composite + +#define VIEW_MODE COMPOSITE + +//#define F_COL (1.0 / 4.0) // moved to parameter +//#define F_LUMA_LP (1.0 / 6.0) // moved to parameter + +//#define FIR_SIZE 29 // moved to parameter + +float pi = 3.141592654;//atan(1.0)*4.0; +float tau = 6.283185308;//atan(1.0)*8.0; + +mat3 yiq2rgb = mat3(1.000, 1.000, 1.000, + 0.956,-0.272,-1.106, + 0.621,-0.647, 1.703); + +//Angle -> 2D rotation matrix +mat2 rotate(float a) +{ + return mat2( cos(a), sin(a), + -sin(a), cos(a)); +} + +//Non-normalized texture sampling. +vec4 sample2D(sampler2D tex,vec2 resolution, vec2 uv) +{ + return texture(tex, uv / resolution); +} + +float sinc(float x) +{ + return (x == 0.0) ? 1.0 : sin(x*pi)/(x*pi); +} + +//https://en.wikipedia.org/wiki/Window_function +float WindowBlackman(float a, int N, int i) +{ + float a0 = (1.0 - a) / 2.0; + float a1 = 0.5; + float a2 = a / 2.0; + + float wnd = a0; + wnd -= a1 * cos(2.0 * pi * (float(i) / float(N - 1))); + wnd += a2 * cos(4.0 * pi * (float(i) / float(N - 1))); + + return wnd; +} + +//FIR lowpass filter +//Fc = Cutoff freq., Fs = Sample freq., N = # of taps, i = Tap index +float Lowpass(float Fc, float Fs, int N, int i) +{ + float wc = (Fc/Fs); + + float wnd = WindowBlackman(0.16, N, i); + + return 2.0*wc * wnd * sinc(2.0*wc * float(i - N/2)); +} + +void main() +{ + float Fs = params.SourceSize.x; + float Fcol = Fs * params.F_COL; + float Flumlp = Fs * params.F_LUMA_LP; + float n = floor(vTexCoord.x * params.OutputSize.x); + + vec2 uv = vTexCoord.xy * params.OutputSize.xy; + + float luma = sample2D(Source, params.SourceSize.xy, uv).r; + vec2 chroma = vec2(0.); + + //Filtering out unwanted high freqency content from the chroma(IQ) signal. + for(int i = 0;i < int(params.FIR_SIZE);i++) + { + int tpidx = int(params.FIR_SIZE) - i - 1; + float lp = Lowpass(Flumlp, Fs, int(params.FIR_SIZE), tpidx); + chroma += sample2D(Source, params.SourceSize.xy, uv - vec2(float(i) - params.FIR_SIZE / 2., 0.)).yz * lp; + } + + chroma *= rotate(tau * params.HUE); + + vec3 color = yiq2rgb * vec3(params.BRIGHTNESS * luma, chroma * params.SATURATION); + + #if(VIEW_MODE == COMPOSITE) + FragColor = vec4(color, 0.); + + #elif(VIEW_MODE == RGB) + FragColor = texture(Original, uv / params.SourceSize.xy); + + #elif(VIEW_MODE == LUMA) + FragColor = vec4(luma); + + #elif(VIEW_MODE == CHROMA) + FragColor = vec4(40.0*chroma+0.5,0.,0.); + + #elif(VIEW_MODE == SIGNAL) + FragColor = 0.5 * texture(Pass2, uv / params.SourceSize.xy).rrrr+0.25; + + #elif(VIEW_MODE == SPLIT) + if(uv.x < params.SourceSize.x/2.0) + { + FragColor = texture(Original, uv / params.SourceSize.xy); + } + else + { + FragColor = vec4(color, 0.); + } + #endif +} \ No newline at end of file diff --git a/ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang b/ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang new file mode 100644 index 0000000..e889c5f --- /dev/null +++ b/ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang @@ -0,0 +1,209 @@ +#version 450 + +// This is a port of the NTSC encode/decode shader pair in MAME and MESS, modified to use only +// one pass rather than an encode pass and a decode pass. It accurately emulates the sort of +// signal decimation one would see when viewing a composite signal, though it could benefit from a +// pre-pass to re-size the input content to more accurately reflect the actual size that would +// be incoming from a composite signal source. +// +// To encode the composite signal, I convert the RGB value to YIQ, then subsequently evaluate +// the standard NTSC composite equation. Four composite samples per RGB pixel are generated from +// the incoming linearly-interpolated texels. +// +// The decode pass implements a Fixed Impulse Response (FIR) filter designed by MAME/MESS contributor +// "austere" in matlab (if memory serves correctly) to mimic the behavior of a standard television set +// as closely as possible. The filter window is 83 composite samples wide, and there is an additional +// notch filter pass on the luminance (Y) values in order to strip the color signal from the luminance +// signal prior to processing. +// +// - UltraMoogleMan [8/2/2013] + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +// Useful Constants +const vec4 Zero = vec4(0.0); +const vec4 Half = vec4(0.5); +const vec4 One = vec4(1.0); +const vec4 Two = vec4(2.0); +const float Pi = 3.1415926535; +const float Pi2 = 6.283185307; + +// NTSC Constants +const vec4 A = vec4(0.5); +const vec4 B = vec4(0.5); +const float P = 1.0; +const float CCFrequency = 3.59754545; +const float YFrequency = 6.0; +const float IFrequency = 1.2; +const float QFrequency = 0.6; +const float NotchHalfWidth = 2.0; +const float ScanTime = 52.6; +const float MaxC = 2.1183; +const vec4 MinC = vec4(-1.1183); +const vec4 CRange = vec4(3.2366); + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +vec4 CompositeSample(vec2 UV) { + vec2 InverseRes = params.SourceSize.zw; + vec2 InverseP = vec2(P, 0.0) * InverseRes; + + // UVs for four linearly-interpolated samples spaced 0.25 texels apart + vec2 C0 = UV; + vec2 C1 = UV + InverseP * 0.25; + vec2 C2 = UV + InverseP * 0.50; + vec2 C3 = UV + InverseP * 0.75; + vec4 Cx = vec4(C0.x, C1.x, C2.x, C3.x); + vec4 Cy = vec4(C0.y, C1.y, C2.y, C3.y); + + vec3 Texel0 = texture(Source, C0).rgb; + vec3 Texel1 = texture(Source, C1).rgb; + vec3 Texel2 = texture(Source, C2).rgb; + vec3 Texel3 = texture(Source, C3).rgb; + + // Calculated the expected time of the sample. + vec4 T = A * Cy * vec4(params.SourceSize.x) * Two + B + Cx; + + const vec3 YTransform = vec3(0.299, 0.587, 0.114); + const vec3 ITransform = vec3(0.595716, -0.274453, -0.321263); + const vec3 QTransform = vec3(0.211456, -0.522591, 0.311135); + + float Y0 = dot(Texel0, YTransform); + float Y1 = dot(Texel1, YTransform); + float Y2 = dot(Texel2, YTransform); + float Y3 = dot(Texel3, YTransform); + vec4 Y = vec4(Y0, Y1, Y2, Y3); + + float I0 = dot(Texel0, ITransform); + float I1 = dot(Texel1, ITransform); + float I2 = dot(Texel2, ITransform); + float I3 = dot(Texel3, ITransform); + vec4 I = vec4(I0, I1, I2, I3); + + float Q0 = dot(Texel0, QTransform); + float Q1 = dot(Texel1, QTransform); + float Q2 = dot(Texel2, QTransform); + float Q3 = dot(Texel3, QTransform); + vec4 Q = vec4(Q0, Q1, Q2, Q3); + + vec4 W = vec4(Pi2 * CCFrequency * ScanTime); + vec4 Encoded = Y + I * cos(T * W) + Q * sin(T * W); + return (Encoded - MinC) / CRange; +} + +vec4 NTSCCodec(vec2 UV) +{ + vec2 InverseRes = params.SourceSize.zw; + vec4 YAccum = Zero; + vec4 IAccum = Zero; + vec4 QAccum = Zero; + float QuadXSize = params.SourceSize.x * 4.0; + float TimePerSample = ScanTime / QuadXSize; + + // Frequency cutoffs for the individual portions of the signal that we extract. + // Y1 and Y2 are the positive and negative frequency limits of the notch filter on Y. + // + float Fc_y1 = (CCFrequency - NotchHalfWidth) * TimePerSample; + float Fc_y2 = (CCFrequency + NotchHalfWidth) * TimePerSample; + float Fc_y3 = YFrequency * TimePerSample; + float Fc_i = IFrequency * TimePerSample; + float Fc_q = QFrequency * TimePerSample; + float Pi2Length = Pi2 / 82.0; + vec4 NotchOffset = vec4(0.0, 1.0, 2.0, 3.0); + vec4 W = vec4(Pi2 * CCFrequency * ScanTime); + for(float n = -41.0; n < 42.0; n += 4.0) + { + vec4 n4 = n + NotchOffset; + vec4 CoordX = UV.x + InverseRes.x * n4 * 0.25; + vec4 CoordY = vec4(UV.y); + vec2 TexCoord = vec2(CoordX.r, CoordY.r); + vec4 C = CompositeSample(TexCoord) * CRange + MinC; + vec4 WT = W * (CoordX + A * CoordY * Two * params.SourceSize.x + B); + + vec4 SincYIn1 = Pi2 * Fc_y1 * n4; + vec4 SincYIn2 = Pi2 * Fc_y2 * n4; + vec4 SincYIn3 = Pi2 * Fc_y3 * n4; + bvec4 notEqual = notEqual(SincYIn1, Zero); + vec4 SincY1 = sin(SincYIn1) / SincYIn1; + vec4 SincY2 = sin(SincYIn2) / SincYIn2; + vec4 SincY3 = sin(SincYIn3) / SincYIn3; + if(SincYIn1.x == 0.0) SincY1.x = 1.0; + if(SincYIn1.y == 0.0) SincY1.y = 1.0; + if(SincYIn1.z == 0.0) SincY1.z = 1.0; + if(SincYIn1.w == 0.0) SincY1.w = 1.0; + if(SincYIn2.x == 0.0) SincY2.x = 1.0; + if(SincYIn2.y == 0.0) SincY2.y = 1.0; + if(SincYIn2.z == 0.0) SincY2.z = 1.0; + if(SincYIn2.w == 0.0) SincY2.w = 1.0; + if(SincYIn3.x == 0.0) SincY3.x = 1.0; + if(SincYIn3.y == 0.0) SincY3.y = 1.0; + if(SincYIn3.z == 0.0) SincY3.z = 1.0; + if(SincYIn3.w == 0.0) SincY3.w = 1.0; + //vec4 IdealY = (2.0 * Fc_y1 * SincY1 - 2.0 * Fc_y2 * SincY2) + 2.0 * Fc_y3 * SincY3; + vec4 IdealY = (2.0 * Fc_y1 * SincY1 - 2.0 * Fc_y2 * SincY2) + 2.0 * Fc_y3 * SincY3; + vec4 FilterY = (0.54 + 0.46 * cos(Pi2Length * n4)) * IdealY; + + vec4 SincIIn = Pi2 * Fc_i * n4; + vec4 SincI = sin(SincIIn) / SincIIn; + if (SincIIn.x == 0.0) SincI.x = 1.0; + if (SincIIn.y == 0.0) SincI.y = 1.0; + if (SincIIn.z == 0.0) SincI.z = 1.0; + if (SincIIn.w == 0.0) SincI.w = 1.0; + vec4 IdealI = 2.0 * Fc_i * SincI; + vec4 FilterI = (0.54 + 0.46 * cos(Pi2Length * n4)) * IdealI; + + vec4 SincQIn = Pi2 * Fc_q * n4; + vec4 SincQ = sin(SincQIn) / SincQIn; + if (SincQIn.x == 0.0) SincQ.x = 1.0; + if (SincQIn.y == 0.0) SincQ.y = 1.0; + if (SincQIn.z == 0.0) SincQ.z = 1.0; + if (SincQIn.w == 0.0) SincQ.w = 1.0; + vec4 IdealQ = 2.0 * Fc_q * SincQ; + vec4 FilterQ = (0.54 + 0.46 * cos(Pi2Length * n4)) * IdealQ; + + YAccum = YAccum + C * FilterY; + IAccum = IAccum + C * cos(WT) * FilterI; + QAccum = QAccum + C * sin(WT) * FilterQ; + } + + float Y = YAccum.r + YAccum.g + YAccum.b + YAccum.a; + float I = (IAccum.r + IAccum.g + IAccum.b + IAccum.a) * 2.0; + float Q = (QAccum.r + QAccum.g + QAccum.b + QAccum.a) * 2.0; + + vec3 YIQ = vec3(Y, I, Q); + + vec3 OutRGB = 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))); + + return vec4(OutRGB, 1.0); +} + +void main() +{ + vec4 OutPixel = NTSCCodec(vTexCoord); + FragColor = vec4(OutPixel); +} \ No newline at end of file diff --git a/presets/c64-monitor.slangp b/presets/c64-monitor.slangp new file mode 100644 index 0000000..b8fde5e --- /dev/null +++ b/presets/c64-monitor.slangp @@ -0,0 +1,24 @@ +shaders = 4 + +shader0 = ../ntsc/shaders/artifact-colors/artifact-colors0.slang +scale0 = 1.0 +scale_type0 = source +filter_linear0 = false +alias0 = Pass1 + +shader1 = ../ntsc/shaders/artifact-colors/artifact-colors1.slang +scale1 = 1.0 +scale_type1 = source +filter_linear1 = false +alias1 = Pass2 + +shader2 = ../ntsc/shaders/artifact-colors/artifact-colors2.slang +scale2 = 1.0 +scale_type2 = source +filter_linear2 = false + +shader3 = ../crt/shaders/crt-geom.slang + +parameters = "F_COL;FIR_SIZE" +F_COL = 0.25 +FIR_SIZE = 29.00 \ No newline at end of file diff --git a/presets/ntsc-phosphorlut.slangp b/presets/ntsc-phosphorlut.slangp index 5f69df8..51d2454 100644 --- a/presets/ntsc-phosphorlut.slangp +++ b/presets/ntsc-phosphorlut.slangp @@ -50,10 +50,7 @@ parameters = "diffusion;PHOSPHOR_SCALE_X" diffusion = 0.6 PHOSPHOR_SCALE_X = 4.0 -textures = "Phosphors" -Phosphors = ../crt/shaders/phosphorlut/luts/rgb-shadowmask.png -//Phosphors = ../crt/shaders/phosphorlut/luts/cmy-shadowmask.png -//Phosphors = ../crt/shaders/phosphorlut/luts/rgb-aperture-grille.png -//Phosphors = ../crt/shaders/phosphorlut/luts/cmy-aperture-grille.png -//Phosphors = ../crt/shaders/phosphorlut/luts/rgb-slotmask.png -//Phosphors = ../crt/shaders/phosphorlut/luts/cmy-slotmask.png \ No newline at end of file +textures = "shadow;aperture;slot" +shadow = ../crt/shaders/phosphorlut/luts/shadowmask.png +aperture = ../crt/shaders/phosphorlut/luts/aperture-grille.png +slot = ../crt/shaders/phosphorlut/luts/slotmask.png \ No newline at end of file