diff --git a/ntsc/ntsc-feather.slangp b/ntsc/ntsc-feather.slangp deleted file mode 100644 index 285359ed..00000000 --- a/ntsc/ntsc-feather.slangp +++ /dev/null @@ -1,6 +0,0 @@ -shaders = 1 -shader0 = shaders/ntsc-simple/ntsc-feather.slang -filter_linear0 = true - - - diff --git a/ntsc/ntsc-simple.slangp b/ntsc/ntsc-simple.slangp new file mode 100644 index 00000000..24b85b89 --- /dev/null +++ b/ntsc/ntsc-simple.slangp @@ -0,0 +1,7 @@ +shaders = 1 +shader0 = shaders/ntsc-simple/ntsc-simple.slang +filter_linear0 = "false" +scale_type_x0 = "source" +scale_x0 = "1.000000" +scale_type_y0 = "source" +scale_y0 = "1.000000" diff --git a/ntsc/shaders/ntsc-simple/ntsc-feather.slang b/ntsc/shaders/ntsc-simple/ntsc-feather.slang deleted file mode 100644 index f71b7f7c..00000000 --- a/ntsc/shaders/ntsc-simple/ntsc-feather.slang +++ /dev/null @@ -1,146 +0,0 @@ -#version 450 - - -layout(push_constant) uniform Push -{ - float MASK; - float COMPOSITE_LOWPASS; - float COL_BLEED; - float NTSC_COL; - -} params; - - -#pragma parameter MASK "Color Subcarrier Artifacts" 0.08 0.0 1.0 0.01 -#pragma parameter COMPOSITE_LOWPASS "Composite Lowpass" 0.8 0.0 2.0 0.05 -#pragma parameter COL_BLEED "Chroma Bleed" 1.4 0.0 2.0 0.05 -#pragma parameter NTSC_COL "NTSC Colors " 0.0 0.0 1.0 1.0 - -#define MASK params.MASK -#define COMPOSITE_LOWPASS params.COMPOSITE_LOWPASS -#define COL_BLEED params.COL_BLEED -#define NTSC_COL params.NTSC_COL -#define PI 3.141592 - -layout(std140, set = 0, binding = 0) uniform UBO -{ - mat4 MVP; - vec4 OutputSize; - vec4 OriginalSize; - vec4 SourceSize; - uint FrameCount; - -} global; - - -#define OutputSize global.OutputSize -#define SourceSize global.SourceSize -#define OriginalSize global.OriginalSize -#define FrameCount global.FrameCount - - -#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 * 1.0001; -} - - -#pragma stage fragment -layout(location = 0) in vec2 vTexCoord; -layout(location = 0) out vec4 FragColor; -layout(set = 0, binding = 2) uniform sampler2D Source; - - - -mat3 RGBtoYIQ = mat3( - 0.2989, 0.5870, 0.1140, - 0.5959, -0.2744, -0.3216, - 0.2115, -0.5229, 0.3114); - -mat3 YIQtoRGB = mat3( - 1.0, 0.956, 0.6210, - 1.0, -0.2720, -0.6474, - 1.0, -1.1060, 1.7046); - -const mat3 NTSC = mat3( - 1.8088923, -0.6480268, -0.0833558, - 0.4062922 , 0.6175271, -0.0038849, - -0.0025872, -0.103848 , 1.182318); - -#define Time sin(float(FrameCount)) - -float phase = OriginalSize.x<300.0 ? 4.0*PI/15.0 : PI/3.0; -#define SC MASK*sin(vTexCoord.x*SourceSize.x*phase)+1.0-MASK - -void main() -{ - - vec2 cent = floor(vTexCoord*SourceSize.xy)+0.5; - vec2 coords = cent*SourceSize.zw; - coords = vec2(mix(vTexCoord.x,coords.x,0.2),coords.y); - - vec3 res = texture(Source,coords).rgb; res *= RGBtoYIQ; - float onetexel = SourceSize.z*COMPOSITE_LOWPASS; - float bleed = SourceSize.z*COL_BLEED; - vec3 resr = texture(Source,coords-(vec2(2.0*bleed,0.0))).rgb; resr *= RGBtoYIQ; - vec3 resru = texture(Source,coords-(vec2(onetexel,0.0))).rgb; resru *= RGBtoYIQ; - vec3 resrr = texture(Source,coords-(vec2(3.0*bleed,0.0))).rgb; resrr *= RGBtoYIQ; - - vec3 resl = texture(Source,coords+(vec2(2.0*bleed,0.0))).rgb; resl *= RGBtoYIQ; - vec3 reslu = texture(Source,coords+(vec2(bleed,0.0))).rgb; reslu *= RGBtoYIQ; - vec3 resll = texture(Source,coords+(vec2(3.0*bleed,0.0))).rgb; resll *= RGBtoYIQ; - - //color bleed - res.gb += (resr.gb+resl.gb+resrr.gb+resll.gb+reslu.gb+resru.gb); res.gb /= 7.0; - //overall bluriness - res.r = (res.r + resru.r)/2.0; - - vec3 checker = texture(Source,vTexCoord - vec2(0.25/OriginalSize.x,0.0)).rgb; checker *= RGBtoYIQ; - vec3 checkerl = texture(Source,vTexCoord + vec2(0.1/OriginalSize.x,0.0)).rgb; checkerl *= RGBtoYIQ; - - float diff = res.g-checker.g; - float diffl = res.g-checkerl.g; - float ydiff = res.r-checker.r; - float ydiffl = res.r-checkerl.r; - - float x = mod(floor(vTexCoord.x*SourceSize.x),2.0); - float y = mod(floor(vTexCoord.y*SourceSize.y),2.0); - - -//Color subcarrier pattern - if (y == 0.0 && x == 0.0 && Time < 0.0 && diff > 0.0 || y == 0.0 && x == 1.0 && Time > 0.0 && diff > 0.0) - - res.b *= SC; // ok - - else if (y == 1.0 && x == 1.0 && Time < 0.0 && diff > 0.0 || y == 1.0 && x == 0.0 && Time > 0.0 && diff > 0.0) - - res.b *= SC; // ok - - else if (y == 0.0 && x == 0.0 && Time < 0.0 && ydiff < 0.0 || y == 0.0 && x == 1.0 && Time > 0.0 && ydiff < 0.0) - - res.r *= SC; // ok - - else if (y == 1.0 && x == 1.0 && Time < 0.0 && ydiff < 0.0 || y == 1.0 && x == 0.0 && Time > 0.0 && ydiff < 0.0) - res.r *= SC; // ok - - else if (y == 0.0 && x == 0.0 && Time < 0.0 && ydiffl < 0.0 || y == 0.0 && x == 1.0 && Time > 0.0 && ydiffl < 0.0) - - res.r *= SC; - - else if (y == 1.0 && x == 1.0 && Time < 0.0 && ydiffl < 0.0 || y == 1.0 && x == 0.0 && Time > 0.0 && ydiffl < 0.0) - res.r *= SC; - -//for testing -//if (ydiffl < 0.0) res = vec3(0.0); - -/// - res *= YIQtoRGB; - if (NTSC_COL == 1.0)res *= NTSC; - FragColor = vec4(res,1.0); -} diff --git a/ntsc/shaders/ntsc-simple/ntsc-simple.slang b/ntsc/shaders/ntsc-simple/ntsc-simple.slang new file mode 100644 index 00000000..6d1bc103 --- /dev/null +++ b/ntsc/shaders/ntsc-simple/ntsc-simple.slang @@ -0,0 +1,146 @@ +#version 450 +/* + Simple S-video like shader by DariusG 2023 + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. +*/ + +layout(push_constant) uniform Push +{ + float CHR_BLUR, L_BLUR, CHROMA_SATURATION, BRIGHTNESS, IHUE, QHUE; +} params; + + + +#pragma parameter CHR_BLUR "CHROMA RESOLUTION" 4.0 1.0 10.0 0.1 +#pragma parameter L_BLUR "LUMA RESOLUTION" 8.0 2.0 10.0 0.25 +#pragma parameter CHROMA_SATURATION "CHROMA SATURATION" 5.0 0.0 15.0 0.1 +#pragma parameter BRIGHTNESS "LUMA BRIGHTNESS" 0.55 0.0 2.0 0.01 +#pragma parameter IHUE "I SHIFT (blue to orange)" 0.0 -1.0 1.0 0.01 +#pragma parameter QHUE "Q SHIFT (green to purple)" 0.0 -1.0 1.0 0.01 + + + +#define CHR_BLUR params.CHR_BLUR +#define L_BLUR params.L_BLUR +#define CHROMA_SATURATION params.CHROMA_SATURATION +#define BRIGHTNESS params.BRIGHTNESS +#define IHUE params.IHUE +#define QHUE params.QHUE + + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; + +} global; + + +#define OutputSize global.OutputSize +#define SourceSize global.SourceSize +#define OriginalSize global.OriginalSize +#define FrameCount global.FrameCount + + +#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 * 1.0001; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define PI 3.14159265358979323846 +#define TAU 6.28318530717958647693 +#define FSC 3.57945*4.0 + +// Size of the decoding FIR filter +#define FIR_SIZE 20 + +// YIQ to RGB matrices +const mat3 yiq_to_rgb = mat3(1.000, 1.000, 1.000, + 0.956,-0.272,-1.106, + 0.621,-0.647, 1.703); + +const mat3 rgb_to_yiq = mat3(0.299, 0.596, 0.211, + 0.587,-0.274,-0.523, + 0.114,-0.322, 0.312); + +float blackman(float n, float N) { + float a0 = (1.0 - 0.16) / 2.0; + float a1 = 1.0 / 2.0; + float a2 = 0.16 / 2.0; + + return a0 - (a1 * cos((2.0 * PI * n) / N)) + (a2 * cos((4.0 * PI * n) / N)); +} + +void main() { +// moved due to GLES fix. +mat3 mix_mat = mat3( + 1.0, 0.0, 0.0, + IHUE, 1.0, 0.0, + QHUE, 0.0, 1.0 +); + + // Chroma decoder oscillator frequency + float fc = SourceSize.x*TAU; + + float counter = 0.0; + vec3 yiq = vec3(0.0); + +for (int d = -FIR_SIZE; d < FIR_SIZE; d++) { + + // LUMA encode + vec2 pos = vec2((vTexCoord.x + (float(d)/2.0/L_BLUR)*SourceSize.z), vTexCoord.y); + vec3 s = texture(Source, pos).rgb; + s = rgb_to_yiq*s; + // LUMA encode end + + // LUMA decode + // Apply Blackman window for smoother colors + float window = blackman(float(d/2 + 5), float(FIR_SIZE/2)); + yiq.r += s.r * BRIGHTNESS * window; + // LUMA decode end! + + // CHROMA encode + pos = vec2(vTexCoord.x + (float(d)/CHR_BLUR)*SourceSize.z, vTexCoord.y); + s = texture(Source, pos).rgb; + s = rgb_to_yiq*s; + s.yz *= vec2(cos(fc*vTexCoord.x+11.0*PI/60.0),sin(fc*vTexCoord.x+11.0*PI/60.0)); + // CHROMA encode end + + // CHROMA decode + // Apply Blackman window for smoother colors + window = blackman(float(d + FIR_SIZE), float(FIR_SIZE * 2 + 1)); + float wt = fc * (vTexCoord.x - float(d)*SourceSize.z); + yiq.yz += s.yz * vec2(cos(wt+11.0*PI/60.0), sin(wt+11.0*PI/60.0)) * window; + // CHROMA decode end! + + counter++; + } + + yiq.yz /= counter; + yiq.r /= counter/4.0; + + // Saturate chroma (IQ) + yiq.yz *= CHROMA_SATURATION; + // Control CHROMA Hue + yiq *= mix_mat; + // return to RGB + FragColor = vec4((yiq_to_rgb * yiq), 1.0); +}