mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-22 07:41:31 +11:00
add mame-ntsc-singlepass and artifact-colors shaders and presets
This commit is contained in:
parent
8ed075bc7f
commit
0ef58d965c
16
ntsc/artifact-colors.slangp
Normal file
16
ntsc/artifact-colors.slangp
Normal file
|
@ -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
|
5
ntsc/mame-ntsc-singlepass.slangp
Normal file
5
ntsc/mame-ntsc-singlepass.slangp
Normal file
|
@ -0,0 +1,5 @@
|
|||
shaders = 1
|
||||
|
||||
shader0 = shaders/mame-ntsc/ntsc-mame-singlepass.slang
|
||||
scale_type0 = source
|
||||
scale0 = 1.0
|
66
ntsc/shaders/artifact-colors/artifact-colors0.slang
Normal file
66
ntsc/shaders/artifact-colors/artifact-colors0.slang
Normal file
|
@ -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.);
|
||||
}
|
145
ntsc/shaders/artifact-colors/artifact-colors1.slang
Normal file
145
ntsc/shaders/artifact-colors/artifact-colors1.slang
Normal file
|
@ -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.);
|
||||
}
|
167
ntsc/shaders/artifact-colors/artifact-colors2.slang
Normal file
167
ntsc/shaders/artifact-colors/artifact-colors2.slang
Normal file
|
@ -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
|
||||
}
|
209
ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang
Normal file
209
ntsc/shaders/mame-ntsc/ntsc-mame-singlepass.slang
Normal file
|
@ -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);
|
||||
}
|
24
presets/c64-monitor.slangp
Normal file
24
presets/c64-monitor.slangp
Normal file
|
@ -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
|
|
@ -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
|
||||
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
|
Loading…
Reference in a new issue