diff --git a/crt/crt-geom.slang b/crt/crt-geom.slang index 88fdb57..5450aad 100644 --- a/crt/crt-geom.slang +++ b/crt/crt-geom.slang @@ -179,7 +179,6 @@ void main() #pragma stage fragment layout(location = 0) in vec2 vTexCoord; -layout(location = 1) in vec2 FragCoord; layout(location = 0) out vec4 FragColor; layout(set = 0, binding = 2) uniform sampler2D Source; diff --git a/ntsc/ntsc-256px-gauss-scanline.slangp b/ntsc/ntsc-256px-gauss-scanline.slangp new file mode 100644 index 0000000..1a38872 --- /dev/null +++ b/ntsc/ntsc-256px-gauss-scanline.slangp @@ -0,0 +1,26 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-composite-3phase.slang +shader1 = shaders/ntsc-pass2-3phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1024 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/ntsc-256px-svideo-gauss-scanline.slangp b/ntsc/ntsc-256px-svideo-gauss-scanline.slangp new file mode 100644 index 0000000..4348dc9 --- /dev/null +++ b/ntsc/ntsc-256px-svideo-gauss-scanline.slangp @@ -0,0 +1,26 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-svideo-3phase.slang +shader1 = shaders/ntsc-pass2-3phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1024 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/ntsc-256px-svideo.slangp b/ntsc/ntsc-256px-svideo.slangp new file mode 100644 index 0000000..663b7ed --- /dev/null +++ b/ntsc/ntsc-256px-svideo.slangp @@ -0,0 +1,18 @@ +shaders = 2 +shader0 = shaders/ntsc-pass1-svideo-3phase.slang +shader1 = shaders/ntsc-pass2-3phase-gamma.slang + +filter_linear0 = false +filter_linear1 = false + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1024 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + diff --git a/ntsc/ntsc-256px.slangp b/ntsc/ntsc-256px.slangp new file mode 100644 index 0000000..7e8d8a8 --- /dev/null +++ b/ntsc/ntsc-256px.slangp @@ -0,0 +1,18 @@ +shaders = 2 +shader0 = shaders/ntsc-pass1-composite-3phase.slang +shader1 = shaders/ntsc-pass2-3phase-gamma.slang + +filter_linear0 = false +filter_linear1 = false + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1024 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + diff --git a/ntsc/ntsc-320px-gauss-scanline.slangp b/ntsc/ntsc-320px-gauss-scanline.slangp new file mode 100644 index 0000000..e7ddf50 --- /dev/null +++ b/ntsc/ntsc-320px-gauss-scanline.slangp @@ -0,0 +1,26 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-composite-2phase.slang +shader1 = shaders/ntsc-pass2-2phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1280 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/ntsc-320px-svideo-gauss-scanline.slangp b/ntsc/ntsc-320px-svideo-gauss-scanline.slangp new file mode 100644 index 0000000..675cecf --- /dev/null +++ b/ntsc/ntsc-320px-svideo-gauss-scanline.slangp @@ -0,0 +1,26 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-svideo-2phase.slang +shader1 = shaders/ntsc-pass2-2phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1280 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/ntsc-320px-svideo.slangp b/ntsc/ntsc-320px-svideo.slangp new file mode 100644 index 0000000..2b4531f --- /dev/null +++ b/ntsc/ntsc-320px-svideo.slangp @@ -0,0 +1,18 @@ +shaders = 2 +shader0 = shaders/ntsc-pass1-svideo-2phase.slang +shader1 = shaders/ntsc-pass2-2phase-gamma.slang + +filter_linear0 = false +filter_linear1 = false + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1280 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + diff --git a/ntsc/ntsc-320px.slangp b/ntsc/ntsc-320px.slangp new file mode 100644 index 0000000..d2139fa --- /dev/null +++ b/ntsc/ntsc-320px.slangp @@ -0,0 +1,18 @@ +shaders = 2 +shader0 = shaders/ntsc-pass1-composite-2phase.slang +shader1 = shaders/ntsc-pass2-2phase-gamma.slang + +filter_linear0 = false +filter_linear1 = false + +scale_type_x0 = absolute +scale_type_y0 = source +scale_x0 = 1280 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + diff --git a/ntsc/ntsc-svideo.slangp b/ntsc/ntsc-svideo.slangp new file mode 100644 index 0000000..e3931cc --- /dev/null +++ b/ntsc/ntsc-svideo.slangp @@ -0,0 +1,25 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-svideo-3phase.slang +shader1 = shaders/ntsc-pass2-3phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type0 = source +scale_x0 = 4.0 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/ntsc.slangp b/ntsc/ntsc.slangp new file mode 100644 index 0000000..b8143e9 --- /dev/null +++ b/ntsc/ntsc.slangp @@ -0,0 +1,25 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-composite-3phase.slang +shader1 = shaders/ntsc-pass2-3phase.slang +shader2 = shaders/ntsc-gauss-pass.slang +shader3 = shaders/ntsc-stock.slang + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type0 = source +scale_x0 = 4.0 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/ntsc/shaders/ntsc-decode-filter-2phase.inc b/ntsc/shaders/ntsc-decode-filter-2phase.inc new file mode 100644 index 0000000..a549162 --- /dev/null +++ b/ntsc/shaders/ntsc-decode-filter-2phase.inc @@ -0,0 +1,70 @@ +#define TAPS 32 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000174844, + -0.000205844, + -0.000149453, + -0.000051693, + 0.000000000, + -0.000066171, + -0.000245058, + -0.000432928, + -0.000472644, + -0.000252236, + 0.000198929, + 0.000687058, + 0.000944112, + 0.000803467, + 0.000363199, + 0.000013422, + 0.000253402, + 0.001339461, + 0.002932972, + 0.003983485, + 0.003026683, + -0.001102056, + -0.008373026, + -0.016897700, + -0.022914480, + -0.021642347, + -0.008863273, + 0.017271957, + 0.054921920, + 0.098342579, + 0.139044281, + 0.168055832, + 0.178571429); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + 0.001384762, + 0.001678312, + 0.002021715, + 0.002420562, + 0.002880460, + 0.003406879, + 0.004004985, + 0.004679445, + 0.005434218, + 0.006272332, + 0.007195654, + 0.008204665, + 0.009298238, + 0.010473450, + 0.011725413, + 0.013047155, + 0.014429548, + 0.015861306, + 0.017329037, + 0.018817382, + 0.020309220, + 0.021785952, + 0.023227857, + 0.024614500, + 0.025925203, + 0.027139546, + 0.028237893, + 0.029201910, + 0.030015081, + 0.030663170, + 0.031134640, + 0.031420995, + 0.031517031); diff --git a/ntsc/shaders/ntsc-decode-filter-3phase.inc b/ntsc/shaders/ntsc-decode-filter-3phase.inc new file mode 100644 index 0000000..ed6b41c --- /dev/null +++ b/ntsc/shaders/ntsc-decode-filter-3phase.inc @@ -0,0 +1,54 @@ +#define TAPS 24 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000012020, + -0.000022146, + -0.000013155, + -0.000012020, + -0.000049979, + -0.000113940, + -0.000122150, + -0.000005612, + 0.000170516, + 0.000237199, + 0.000169640, + 0.000285688, + 0.000984574, + 0.002018683, + 0.002002275, + -0.000909882, + -0.007049081, + -0.013222860, + -0.012606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.190176552); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000118847, + -0.000271306, + -0.000502642, + -0.000930833, + -0.001451013, + -0.002064744, + -0.002700432, + -0.003241276, + -0.003524948, + -0.003350284, + -0.002491729, + -0.000721149, + 0.002164659, + 0.006313635, + 0.011789103, + 0.018545660, + 0.026414396, + 0.035100710, + 0.044196567, + 0.053207202, + 0.061590275, + 0.068803602, + 0.074356193, + 0.077856564, + 0.079052396); diff --git a/ntsc/shaders/ntsc-gauss-pass.slang b/ntsc/shaders/ntsc-gauss-pass.slang new file mode 100644 index 0000000..c3953a0 --- /dev/null +++ b/ntsc/shaders/ntsc-gauss-pass.slang @@ -0,0 +1,58 @@ +#version 450 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; +} global; + +#define NTSC_CRT_GAMMA 2.5 +#define NTSC_DISPLAY_GAMMA 2.1 + +#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; + vec2 pix_no = TexCoord * global.SourceSize.xy; + vec2 one = 1.0 / global.SourceSize.xy; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define TEX(off) pow(texture(Source, vTexCoord + vec2(0.0, (off) * vertex.one.y)).rgb, vec3(NTSC_CRT_GAMMA)) + + +void main() +{ + vec3 frame0 = TEX(-2.0); + vec3 frame1 = TEX(-1.0); + vec3 frame2 = TEX(0.0); + vec3 frame3 = TEX(1.0); + vec3 frame4 = TEX(2.0); + + float offset_dist = fract(vertex.pix_no.y) - 0.5; + float dist0 = 2.0 + offset_dist; + float dist1 = 1.0 + offset_dist; + float dist2 = 0.0 + offset_dist; + float dist3 = -1.0 + offset_dist; + float dist4 = -2.0 + offset_dist; + + vec3 scanline = frame0 * exp(-5.0 * dist0 * dist0); + scanline += frame1 * exp(-5.0 * dist1 * dist1); + scanline += frame2 * exp(-5.0 * dist2 * dist2); + scanline += frame3 * exp(-5.0 * dist3 * dist3); + scanline += frame4 * exp(-5.0 * dist4 * dist4); + +FragCoord = vec4(pow(1.15 * scanline, vec3(1.0 / NTSC_DISPLAY_GAMMA)), 1.0); +} diff --git a/ntsc/shaders/ntsc-param.inc b/ntsc/shaders/ntsc-param.inc new file mode 100644 index 0000000..f460b5a --- /dev/null +++ b/ntsc/shaders/ntsc-param.inc @@ -0,0 +1,28 @@ +#define PI 3.14159265 + +#if defined(TWO_PHASE) +#define CHROMA_MOD_FREQ (4.0 * PI / 15.0) +#elif defined(THREE_PHASE) +#define CHROMA_MOD_FREQ (PI / 3.0) +#endif + +#if defined(COMPOSITE) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 1.0 +#define FRINGING 1.0 +#elif defined(SVIDEO) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 0.0 +#define FRINGING 0.0 +#endif + +#if defined(COMPOSITE) || defined(SVIDEO) +mat3 mix_mat = mat3( + BRIGHTNESS, FRINGING, FRINGING, + ARTIFACTING, 2.0 * SATURATION, 0.0, + ARTIFACTING, 0.0, 2.0 * SATURATION +); +#endif + diff --git a/ntsc/shaders/ntsc-pass1-composite-2phase.slang b/ntsc/shaders/ntsc-pass1-composite-2phase.slang new file mode 100644 index 0000000..b0ac7fe --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-composite-2phase.slang @@ -0,0 +1,15 @@ +#include "ntsc-pass1-vertex.inc" +#define TWO_PHASE +#define COMPOSITE +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass1-encode-demodulate.inc" +} diff --git a/ntsc/shaders/ntsc-pass1-composite-3phase.slang b/ntsc/shaders/ntsc-pass1-composite-3phase.slang new file mode 100644 index 0000000..8104614 --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-composite-3phase.slang @@ -0,0 +1,15 @@ +#include "ntsc-pass1-vertex.inc" +#define THREE_PHASE +#define COMPOSITE +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass1-encode-demodulate.inc" +} diff --git a/ntsc/shaders/ntsc-pass1-encode-demodulate.inc b/ntsc/shaders/ntsc-pass1-encode-demodulate.inc new file mode 100644 index 0000000..145a0a7 --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-encode-demodulate.inc @@ -0,0 +1,19 @@ +vec3 col = texture(Source, vTexCoord).rgb; +vec3 yiq = rgb2yiq(col); + +#if defined(TWO_PHASE) +float chroma_phase = PI * (mod(vertex.pix_no.y, 2.0) + global.FrameCount); +#elif defined(THREE_PHASE) +float chroma_phase = 0.6667 * PI * (mod(pix_no.y, 3.0) + global.FrameCount); +#endif + +float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ; + +float i_mod = cos(mod_phase); +float q_mod = sin(mod_phase); + +yiq.yz *= vec2(i_mod, q_mod); // Modulate. +yiq *= mix_mat; // Cross-talk. +yiq.yz *= vec2(i_mod, q_mod); // Demodulate. +FragCoord = vec4(yiq, 1.0); + diff --git a/ntsc/shaders/ntsc-pass1-svideo-2phase.slang b/ntsc/shaders/ntsc-pass1-svideo-2phase.slang new file mode 100644 index 0000000..a0ffcce --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-svideo-2phase.slang @@ -0,0 +1,15 @@ +#include "ntsc-pass1-vertex.inc" +#define TWO_PHASE +#define SVIDEO +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass1-encode-demodulate.inc" +} diff --git a/ntsc/shaders/ntsc-pass1-svideo-3phase.slang b/ntsc/shaders/ntsc-pass1-svideo-3phase.slang new file mode 100644 index 0000000..34c06d4 --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-svideo-3phase.slang @@ -0,0 +1,15 @@ +#include "ntsc-pass1-vertex.inc" +#define THREE_PHASE +#define SVIDEO +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass1-encode-demodulate.inc" +} diff --git a/ntsc/shaders/ntsc-pass1-vertex.inc b/ntsc/shaders/ntsc-pass1-vertex.inc new file mode 100644 index 0000000..32532dc --- /dev/null +++ b/ntsc/shaders/ntsc-pass1-vertex.inc @@ -0,0 +1,21 @@ +#version 450 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; +} 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; + vec2 pix_no = TexCoord * global.SourceSize.xy * (global.OutputSize / global.SourceSize.zw); +} diff --git a/ntsc/shaders/ntsc-pass2-2phase-gamma.slang b/ntsc/shaders/ntsc-pass2-2phase-gamma.slang new file mode 100644 index 0000000..fd25379 --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-2phase-gamma.slang @@ -0,0 +1,21 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-2phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#define NTSC_CRT_GAMMA 2.5 +#define NTSC_MONITOR_GAMMA 2.0 + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(pow(rgb, NTSC_CRT_GAMMA / NTSC_MONITOR_GAMMA), 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-2phase-linear.slang b/ntsc/shaders/ntsc-pass2-2phase-linear.slang new file mode 100644 index 0000000..1da05ef --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-2phase-linear.slang @@ -0,0 +1,20 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-2phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#define NTSC_CRT_GAMMA 2.4 + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(pow(rgb, NTSC_CRT_GAMMA), 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-2phase.slang b/ntsc/shaders/ntsc-pass2-2phase.slang new file mode 100644 index 0000000..ab2f31e --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-2phase.slang @@ -0,0 +1,18 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-2phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(rgb, 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-3phase-gamma.slang b/ntsc/shaders/ntsc-pass2-3phase-gamma.slang new file mode 100644 index 0000000..3aec88c --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-3phase-gamma.slang @@ -0,0 +1,21 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-3phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#define NTSC_CRT_GAMMA 2.5 +#define NTSC_MONITOR_GAMMA 2.0 + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(pow(rgb, NTSC_CRT_GAMMA / NTSC_MONITOR_GAMMA), 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-3phase-linear.slang b/ntsc/shaders/ntsc-pass2-3phase-linear.slang new file mode 100644 index 0000000..3a68607 --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-3phase-linear.slang @@ -0,0 +1,20 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-3phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#define NTSC_CRT_GAMMA 2.4 + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(pow(rgb, NTSC_CRT_GAMMA), 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-3phase.slang b/ntsc/shaders/ntsc-pass2-3phase.slang new file mode 100644 index 0000000..0116246 --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-3phase.slang @@ -0,0 +1,18 @@ +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-3phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + texture(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ +#include "ntsc-pass2-decode.inc" +vec3 rgb = yiq2rgb(signal); +return vec4(rgb, 1.0); +} diff --git a/ntsc/shaders/ntsc-pass2-decode.inc b/ntsc/shaders/ntsc-pass2-decode.inc new file mode 100644 index 0000000..7214c8c --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-decode.inc @@ -0,0 +1,13 @@ +float one_x = 1.0 / global.SourceSize.x; +vec3 signal = vec3(0.0); +for (int i = 0; i < TAPS; i++) +{ + float offset = float(i); + + vec3 sums = fetch_offset(offset - float(TAPS), one_x) + + fetch_offset(float(TAPS) - offset, one_x); + + signal += sums * vec3(luma_filter[i], chroma_filter[i], chroma_filter[i]); +} +signal += texture(Source, vTexCoord).xyz * + vec3(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS]); diff --git a/ntsc/shaders/ntsc-pass2-vertex.inc b/ntsc/shaders/ntsc-pass2-vertex.inc new file mode 100644 index 0000000..f45dba2 --- /dev/null +++ b/ntsc/shaders/ntsc-pass2-vertex.inc @@ -0,0 +1,20 @@ +#version 450 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; +} 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 - vec2(0.5 / global.SourceSize.x, 0.0); // Compensate for decimate-by-2. +} diff --git a/ntsc/shaders/ntsc-rgbyuv.inc b/ntsc/shaders/ntsc-rgbyuv.inc new file mode 100644 index 0000000..ccf8fd3 --- /dev/null +++ b/ntsc/shaders/ntsc-rgbyuv.inc @@ -0,0 +1,21 @@ +mat3 yiq2rgb_mat = mat3( + 1.0, 1.0, 1.0, + 0.956, -0.2720, -1.1060, + 0.6210, -0.6474, 1.7046 +); + +vec3 yiq2rgb(vec3 yiq) +{ + return (yiq * yiq2rgb_mat); +} + +mat3 yiq_mat = mat3( + 0.2989, 0.5959, 0.2115, + 0.5870, -0.2744, -0.5229, + 0.1140, -0.3216, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return (col * yiq_mat); +} diff --git a/ntsc/shaders/ntsc-stock.slang b/ntsc/shaders/ntsc-stock.slang new file mode 100644 index 0000000..bd26cc9 --- /dev/null +++ b/ntsc/shaders/ntsc-stock.slang @@ -0,0 +1,30 @@ +#version 450 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; +} 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; + +void main() +{ +FragCoord = texture(Source, vTexCoord).rgba;