From fa3321fbd79a860602186a62f5fb105c5623fd5e Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Fri, 21 May 2021 19:09:55 +0200 Subject: [PATCH 1/3] crt-geom: add vertical mode, tate preset --- crt/crt-geom-tate.slangp | 17 +++ crt/shaders/crt-geom.slang | 239 ++++++++++++++++++++++++++----------- 2 files changed, 185 insertions(+), 71 deletions(-) create mode 100644 crt/crt-geom-tate.slangp diff --git a/crt/crt-geom-tate.slangp b/crt/crt-geom-tate.slangp new file mode 100644 index 0000000..4c3ff5e --- /dev/null +++ b/crt/crt-geom-tate.slangp @@ -0,0 +1,17 @@ +shaders = 1 + +shader0 = shaders/crt-geom.slang +filter_linear0 = false + +CRTgamma = "2.2" +CURVATURE = "1.0" +d = "1.5" +R = "1.8" +y_tilt = "-0.15" +cornersize = "0.0155" +invert_aspect = "0.0" +DOTMASK = "0.0" +scanline_weight = "0.3" +lum = "0.07" +vertical_scanlines = "1.0" +interlace_detect = "0.0" diff --git a/crt/shaders/crt-geom.slang b/crt/shaders/crt-geom.slang index 2e09d13..a8e2e64 100644 --- a/crt/shaders/crt-geom.slang +++ b/crt/shaders/crt-geom.slang @@ -17,32 +17,37 @@ layout(push_constant) uniform Push float SHARPER; float scanline_weight; float CURVATURE; - float interlace_detect; + float interlace_detect; float lum; - float xsize, ysize; + float invert_aspect; + float vertical_scanlines; + float xsize; + float ysize; } registers; layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; vec4 OutputSize; - vec4 SourceSize; + vec4 SourceSize; } global; #pragma parameter CRTgamma "CRTGeom Target Gamma" 2.4 0.1 5.0 0.1 #pragma parameter monitorgamma "CRTGeom Monitor Gamma" 2.2 0.1 5.0 0.1 #pragma parameter d "CRTGeom Distance" 1.5 0.1 3.0 0.1 #pragma parameter CURVATURE "CRTGeom Curvature Toggle" 1.0 0.0 1.0 1.0 +#pragma parameter invert_aspect "CRTGeom Curvature Aspect Inversion" 0.0 0.0 1.0 1.0 #pragma parameter R "CRTGeom Curvature Radius" 2.0 0.1 10.0 0.1 #pragma parameter cornersize "CRTGeom Corner Size" 0.03 0.001 1.0 0.005 #pragma parameter cornersmooth "CRTGeom Corner Smoothness" 1000.0 80.0 2000.0 100.0 #pragma parameter x_tilt "CRTGeom Horizontal Tilt" 0.0 -0.5 0.5 0.05 #pragma parameter y_tilt "CRTGeom Vertical Tilt" 0.0 -0.5 0.5 0.05 -#pragma parameter overscan_x "CRTGeom Horiz. Overscan %" 100.0 -125.0 125.0 1.0 -#pragma parameter overscan_y "CRTGeom Vert. Overscan %" 100.0 -125.0 125.0 1.0 -#pragma parameter DOTMASK "CRTGeom Dot Mask Strength" 0.3 0.0 1.0 0.05 +#pragma parameter overscan_x "CRTGeom Horiz. Overscan %" 100.0 -125.0 125.0 0.5 +#pragma parameter overscan_y "CRTGeom Vert. Overscan %" 100.0 -125.0 125.0 0.5 +#pragma parameter DOTMASK "CRTGeom Dot Mask Toggle" 0.3 0.0 0.3 0.3 #pragma parameter SHARPER "CRTGeom Sharpness" 1.0 1.0 3.0 1.0 #pragma parameter scanline_weight "CRTGeom Scanline Weight" 0.3 0.1 0.5 0.05 +#pragma parameter vertical_scanlines "CRTGeom Vertical Scanlines" 0.0 0.0 1.0 1.0 #pragma parameter lum "CRTGeom Luminance" 0.0 0.0 1.0 0.01 #pragma parameter interlace_detect "CRTGeom Interlacing Simulation" 1.0 0.0 1.0 1.0 @@ -96,7 +101,7 @@ vec4 SourceSize = vec4(width.x, height.x, width.y, height.y); #endif // aspect ratio -vec2 aspect = vec2(1.0, 0.75); +vec2 aspect = vec2(registers.invert_aspect > 0.5 ? (0.75, 1.0) : (1.0, 0.75)); vec2 overscan = vec2(1.01, 1.01); #pragma stage vertex @@ -172,15 +177,29 @@ void main() sinangle = sin(vec2(registers.x_tilt, registers.y_tilt)); cosangle = cos(vec2(registers.x_tilt, registers.y_tilt)); stretch = maxscale(); - TextureSize = vec2(registers.SHARPER * SourceSize.x, SourceSize.y); - ilfac = vec2(1.0, clamp(floor(SourceSize.y/200.0), 1.0, 2.0)); + if(registers.vertical_scanlines < 0.5) + { + TextureSize = vec2(registers.SHARPER * SourceSize.x, SourceSize.y); + + ilfac = vec2(1.0, clamp(floor(SourceSize.y/(registers.interlace_detect > 0.5 ? 200.0 : 1000)), 1.0, 2.0)); - // The size of one texel, in texture-coordinates. - one = ilfac / TextureSize; + // The size of one texel, in texture-coordinates. + one = ilfac / TextureSize; - // Resulting X pixel-coordinate of the pixel we're drawing. - mod_factor = vTexCoord.x * SourceSize.x * global.OutputSize.x / SourceSize.x; + // Resulting X pixel-coordinate of the pixel we're drawing. + mod_factor = vTexCoord.x * SourceSize.x * global.OutputSize.x / SourceSize.x; + }else{ + TextureSize = vec2(SourceSize.x, registers.SHARPER * SourceSize.y); + + ilfac = vec2(clamp(floor(SourceSize.x/(registers.interlace_detect > 0.5 ? 200.0 : 1000)), 1.0, 2.0), 1.0); + + // The size of one texel, in texture-coordinates. + one = ilfac / TextureSize; + + // Resulting X pixel-coordinate of the pixel we're drawing. + mod_factor = vTexCoord.y * SourceSize.y * global.OutputSize.y / SourceSize.y; + } } #pragma stage fragment @@ -198,9 +217,17 @@ layout(set = 0, binding = 2) uniform sampler2D Source; float intersect(vec2 xy) { float A = dot(xy,xy) + registers.d*registers.d; - float B = 2.0*(registers.R*(dot(xy,sinangle) - registers.d*cosangle.x*cosangle.y) - registers.d*registers.d); - float C = registers.d*registers.d + 2.0*registers.R*registers.d*cosangle.x*cosangle.y; - + float B, C; + + if(registers.vertical_scanlines < 0.5) + { + B = 2.0*(registers.R*(dot(xy,sinangle) - registers.d*cosangle.x*cosangle.y) - registers.d*registers.d); + C = registers.d*registers.d + 2.0*registers.R*registers.d*cosangle.x*cosangle.y; + }else{ + B = 2.0*(registers.R*(dot(xy,sinangle) - registers.d*cosangle.y*cosangle.x) - registers.d*registers.d); + C = registers.d*registers.d + 2.0*registers.R*registers.d*cosangle.y*cosangle.x; + } + return (-B-sqrt(B*B - 4.0*A*C))/(2.0*A); } @@ -227,22 +254,40 @@ vec2 fwtrans(vec2 uv) float r = FIX(sqrt(dot(uv, uv))); uv *= sin(r/registers.R)/r; float x = 1.0 - cos(r/registers.R); - float D = registers.d/registers.R + x*cosangle.x*cosangle.y + dot(uv,sinangle); + float D; + + if(registers.vertical_scanlines < 0.5) + D = registers.d/registers.R + x*cosangle.x*cosangle.y + dot(uv,sinangle); + else + D = registers.d/registers.R + x*cosangle.y*cosangle.x + dot(uv,sinangle); return registers.d*(uv*cosangle - x*sinangle)/D; } vec3 maxscale() { - vec2 c = bkwtrans(-registers.R * sinangle / (1.0 + registers.R/registers.d*cosangle.x*cosangle.y)); - vec2 a = vec2(0.5, 0.5)*aspect; + if(registers.vertical_scanlines < 0.5) + { + vec2 c = bkwtrans(-registers.R * sinangle / (1.0 + registers.R/registers.d*cosangle.x*cosangle.y)); + vec2 a = vec2(0.5, 0.5)*aspect; - vec2 lo = vec2(fwtrans(vec2(-a.x, c.y)).x, - fwtrans(vec2( c.x, -a.y)).y)/aspect; - vec2 hi = vec2(fwtrans(vec2(+a.x, c.y)).x, - fwtrans(vec2( c.x, +a.y)).y)/aspect; + vec2 lo = vec2(fwtrans(vec2(-a.x, c.y)).x, + fwtrans(vec2( c.x, -a.y)).y)/aspect; + vec2 hi = vec2(fwtrans(vec2(+a.x, c.y)).x, + fwtrans(vec2( c.x, +a.y)).y)/aspect; - return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y)); + return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y)); + }else{ + vec2 c = bkwtrans(-registers.R * sinangle / (1.0 + registers.R/registers.d*cosangle.y*cosangle.x)); + vec2 a = vec2(0.5, 0.5)*aspect; + + vec2 lo = vec2(fwtrans(vec2(-a.y, c.x)).y, + fwtrans(vec2( c.y, -a.x)).x)/aspect; + vec2 hi = vec2(fwtrans(vec2(+a.y, c.x)).y, + fwtrans(vec2( c.y, +a.x)).x)/aspect; + + return vec3((hi+lo)*aspect*0.5,max(hi.y-lo.y, hi.x-lo.x)); + } } // Calculate the influence of a scanline on the current pixel. @@ -263,17 +308,19 @@ vec4 scanlineWeights(float distance, vec4 color) // independent of its width. That is, for a narrower beam // "weights" should have a higher peak at the center of the // scanline than for a wider beam. -#ifdef USEGAUSSIAN - vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0)); - vec4 weights = vec4(distance / wid); - return (registers.lum + 0.4) * exp(-weights * weights) / wid; -#else - vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0)); - vec4 weights = vec4(distance / registers.scanline_weight); - return (registers.lum + 1.4) * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid); -#endif + #ifdef USEGAUSSIAN + vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0)); + vec4 weights = vec4(distance / wid); + + return (registers.lum + 0.4) * exp(-weights * weights) / wid; + #else + vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0)); + vec4 weights = vec4(distance / registers.scanline_weight); + + return (registers.lum + 1.4) * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid); + #endif } - + vec2 transform(vec2 coord) { coord = (coord - vec2(0.5, 0.5))*aspect*stretch.z + stretch.xy; @@ -281,7 +328,7 @@ vec2 transform(vec2 coord) return (bkwtrans(coord) / vec2(registers.overscan_x / 100.0, registers.overscan_y / 100.0)/aspect + vec2(0.5, 0.5)); } - + float corner(vec2 coord) { coord = (coord - vec2(0.5)) * vec2(registers.overscan_x / 100.0, registers.overscan_y / 100.0) + vec2(0.5, 0.5); @@ -290,9 +337,12 @@ float corner(vec2 coord) coord = (cdist - min(coord, cdist)); float dist = sqrt(dot(coord, coord)); - return clamp((cdist.x - dist)*registers.cornersmooth, 0.0, 1.0); + if(registers.vertical_scanlines < 0.5) + return clamp((cdist.x - dist)*registers.cornersmooth, 0.0, 1.0); + else + return clamp((cdist.y - dist)*registers.cornersmooth, 0.0, 1.0); } - + void main() { // Here's a helpful diagram to keep in mind while trying to @@ -319,16 +369,19 @@ void main() // Texture coordinates of the texel containing the active pixel. vec2 xy; if (registers.CURVATURE > 0.5) - xy = transform(vTexCoord); + xy = transform(vTexCoord); else - xy = vTexCoord; + xy = vTexCoord; float cval = corner(xy); // Of all the pixels that are mapped onto the texel we are // currently rendering, which pixel are we currently rendering? - - vec2 ilvec = vec2(0.0, ilfac.y * registers.interlace_detect > 1.5 ? mod(float(registers.FrameCount), 2.0) : 0.0); + vec2 ilvec; + if(registers.vertical_scanlines < 0.5) + ilvec = vec2(0.0, ilfac.y * registers.interlace_detect > 1.5 ? mod(float(registers.FrameCount), 2.0) : 0.0); + else + ilvec = vec2(ilfac.x * registers.interlace_detect > 1.5 ? mod(float(registers.FrameCount), 2.0) : 0.0, 0.0); vec2 ratio_scale = (xy * TextureSize - vec2(0.5, 0.5) + ilvec) / ilfac; vec2 uv_ratio = fract(ratio_scale); @@ -339,7 +392,11 @@ void main() // Calculate Lanczos scaling coefficients describing the effect // of various neighbour texels in a scanline on the current // pixel. - vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); + vec4 coeffs; + if(registers.vertical_scanlines < 0.5) + coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); + else + coeffs = PI * vec4(1.0 + uv_ratio.y, uv_ratio.y, 1.0 - uv_ratio.y, 2.0 - uv_ratio.y); // Prevent division by zero. coeffs = FIX(coeffs); @@ -353,24 +410,47 @@ void main() // Calculate the effective colour of the current and next // scanlines at the horizontal location of the current pixel, // using the Lanczos coefficients above. - vec4 col = clamp( - mat4( - TEX2D(xy + vec2(-one.x, 0.0)), - TEX2D(xy), - TEX2D(xy + vec2(one.x, 0.0)), - TEX2D(xy + vec2(2.0 * one.x, 0.0)) - ) * coeffs, - 0.0, 1.0 - ); - vec4 col2 = clamp( - mat4( - TEX2D(xy + vec2(-one.x, one.y)), - TEX2D(xy + vec2(0.0, one.y)), - TEX2D(xy + one), - TEX2D(xy + vec2(2.0 * one.x, one.y)) - ) * coeffs, - 0.0, 1.0 - ); + vec4 col, col2; + if(registers.vertical_scanlines < 0.5) + { + col = clamp( + mat4( + TEX2D(xy + vec2(-one.x, 0.0)), + TEX2D(xy), + TEX2D(xy + vec2(one.x, 0.0)), + TEX2D(xy + vec2(2.0 * one.x, 0.0)) + ) * coeffs, + 0.0, 1.0 + ); + col2 = clamp( + mat4( + TEX2D(xy + vec2(-one.x, one.y)), + TEX2D(xy + vec2(0.0, one.y)), + TEX2D(xy + one), + TEX2D(xy + vec2(2.0 * one.x, one.y)) + ) * coeffs, + 0.0, 1.0 + ); + }else{ + col = clamp( + mat4( + TEX2D(xy + vec2(0.0, -one.y)), + TEX2D(xy), + TEX2D(xy + vec2(0.0, one.y)), + TEX2D(xy + vec2(0.0, 2.0 * one.y)) + ) * coeffs, + 0.0, 1.0 + ); + col2 = clamp( + mat4( + TEX2D(xy + vec2(one.x, -one.y)), + TEX2D(xy + vec2(one.x, 0.0)), + TEX2D(xy + one), + TEX2D(xy + vec2(one.x, 2.0 * one.y)) + ) * coeffs, + 0.0, 1.0 + ); + } #ifndef LINEAR_PROCESSING col = pow(col , vec4(registers.CRTgamma)); @@ -379,18 +459,35 @@ void main() // Calculate the influence of the current and next scanlines on // the current pixel. - vec4 weights = scanlineWeights(uv_ratio.y, col); - vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2); + vec4 weights, weights2; + if(registers.vertical_scanlines < 0.5) + { + weights = scanlineWeights(uv_ratio.y, col); + weights2 = scanlineWeights(1.0 - uv_ratio.y, col2); -#ifdef OVERSAMPLE - float filter_ = fwidth(ratio_scale.y); - uv_ratio.y = uv_ratio.y + 1.0/3.0*filter_; - weights = (weights + scanlineWeights(uv_ratio.y, col))/3.0; - weights2 = (weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2))/3.0; - uv_ratio.y = uv_ratio.y - 2.0/3.0*filter_; - weights = weights + scanlineWeights(abs(uv_ratio.y), col)/3.0; - weights2 = weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2)/3.0; -#endif + #ifdef OVERSAMPLE + float filter_ = fwidth(ratio_scale.y); + uv_ratio.y = uv_ratio.y + 1.0/3.0*filter_; + weights = (weights + scanlineWeights(uv_ratio.y, col))/3.0; + weights2 = (weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2))/3.0; + uv_ratio.y = uv_ratio.y - 2.0/3.0*filter_; + weights = weights + scanlineWeights(abs(uv_ratio.y), col)/3.0; + weights2 = weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2)/3.0; + #endif + }else{ + weights = scanlineWeights(uv_ratio.x, col); + weights2 = scanlineWeights(1.0 - uv_ratio.x, col2); + + #ifdef OVERSAMPLE + float filter_ = fwidth(ratio_scale.x); + uv_ratio.x = uv_ratio.x + 1.0/3.0*filter_; + weights = (weights + scanlineWeights(uv_ratio.x, col))/3.0; + weights2 = (weights2 + scanlineWeights(abs(1.0 - uv_ratio.x), col2))/3.0; + uv_ratio.x = uv_ratio.x - 2.0/3.0*filter_; + weights = weights + scanlineWeights(abs(uv_ratio.x), col)/3.0; + weights2 = weights2 + scanlineWeights(abs(1.0 - uv_ratio.x), col2)/3.0; + #endif + } vec3 mul_res = (col * weights + col2 * weights2).rgb * vec3(cval); From 8a59989df4a6b3e7a3d8eaf3d2b6c105a76b3449 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sat, 22 May 2021 15:16:23 +0200 Subject: [PATCH 2/3] ntsc-adaptive-tate, smart-morph additions --- ntsc/ntsc-adaptive-tate.slangp | 14 ++ .../ntsc-adaptive-tate/ntsc-tate-pass1.slang | 87 +++++++ .../ntsc-adaptive-tate/ntsc-tate-pass2.slang | 220 ++++++++++++++++++ .../crt-geom-ntsc-composite-sharp-tate.slangp | 78 +++++++ presets/crt-geom-ntsc-composite-sharp.slangp | 77 ++++++ warp/shaders/smart-morph.slang | 40 +++- 6 files changed, 506 insertions(+), 10 deletions(-) create mode 100644 ntsc/ntsc-adaptive-tate.slangp create mode 100644 ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang create mode 100644 ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang create mode 100644 presets/crt-geom-ntsc-composite-sharp-tate.slangp create mode 100644 presets/crt-geom-ntsc-composite-sharp.slangp diff --git a/ntsc/ntsc-adaptive-tate.slangp b/ntsc/ntsc-adaptive-tate.slangp new file mode 100644 index 0000000..47462ae --- /dev/null +++ b/ntsc/ntsc-adaptive-tate.slangp @@ -0,0 +1,14 @@ +shaders = 2 + +shader0 = shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang +scale_type0 = source +scale_x0 = 1.0 +filter_linear0 = false +scale_y0 = 4.0 +float_framebuffer0 = true + +shader1 = shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang +scale_type1 = source +scale_x1 = 1.0 +scale_y1 = 0.5 +filter_linear1 = false diff --git a/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang new file mode 100644 index 0000000..3549f7e --- /dev/null +++ b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang @@ -0,0 +1,87 @@ +#version 450 + +// NTSC-Adaptive +// based on Themaister's NTSC shader + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; + float quality, bw; +} global; + +#pragma parameter quality "Quality (Composite = 0, Svideo = 1)" 0.0 0.0 1.0 1.0 +#pragma parameter bw "Black and White" 0.0 0.0 1.0 1.0 + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out vec2 pix_no; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; + pix_no = TexCoord * global.SourceSize.xy * (global.OutputSize.xy / global.SourceSize.xy); +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in vec2 pix_no; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define PI 3.14159265 +float phase = (global.OriginalSize.y > 300.0) ? 2.0 : 3.0; + + +#define mix_mat mat3(BRIGHTNESS, FRINGING, FRINGING, ARTIFACTING, 2.0 * SATURATION, 0.0, ARTIFACTING, 0.0, 2.0 * SATURATION) + +const mat3 yiq2rgb_mat = mat3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +vec3 yiq2rgb(vec3 yiq) +{ + return yiq * yiq2rgb_mat; +} + +const mat3 yiq_mat = mat3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return col * yiq_mat; +} + +void main() +{ + float CHROMA_MOD_FREQ = (phase < 2.5) ? (4.0 * PI / 15.0) : (PI / 3.0); + float ARTIFACTING = 1.0 - global.quality; + float FRINGING = 1.0 - global.quality; + float SATURATION = 1.0 - global.bw; + // prevent some very slight clipping that happens at 1.0 + const float BRIGHTNESS = 0.95; + vec3 col = texture(Source, vTexCoord).rgb; + vec3 yiq = rgb2yiq(col); + + float chroma_phase = (phase < 2.5) ? PI * (mod(pix_no.x, 2.0) + mod(global.FrameCount, 2.)) : 0.6667 * PI * (mod(pix_no.x, 3.0) + mod(global.FrameCount, 2.)); + + float mod_phase = chroma_phase + pix_no.y * 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. + FragColor = vec4(yiq, 1.0); +} diff --git a/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang new file mode 100644 index 0000000..c20ffa4 --- /dev/null +++ b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang @@ -0,0 +1,220 @@ +#version 450 + +// NTSC-Adaptive +// based on Themaister's NTSC shader + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + float linearize; +} global; + +#pragma parameter linearize "Linearize Output Gamma" 0.0 0.0 1.0 1.0 + +#define fetch_offset(offset, one_y) \ + texture(Source, vTexCoord + vec2(0.0, (offset) * (one_y))).xyz + +#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.0, 0.5 / global.SourceSize.y); // Compensate for decimate-by-2. +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +const mat3 yiq2rgb_mat = mat3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +vec3 yiq2rgb(vec3 yiq) +{ + return yiq * yiq2rgb_mat; +} + +const mat3 yiq_mat = mat3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return col * yiq_mat; +} + +const int TAPS_2_phase = 32; +const float luma_filter_2_phase[33] = float[33]( + -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_2_phase[33] = float[33]( + 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); + +const int TAPS_3_phase = 24; +const float luma_filter_3_phase[25] = float[25]( + -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_3_phase[25] = float[25]( + -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); + +void main() +{ + float phase = (global.OriginalSize.y > 300.0) ? 2.0 : 3.0; + float one_y = global.SourceSize.w; + vec3 signal = vec3(0.0); + + if(phase < 2.5) + { + for (int i = 0; i < TAPS_2_phase; i++) + { + float offset = float(i); + + vec3 sums = fetch_offset(offset - float(TAPS_2_phase), one_y) + + fetch_offset(float(TAPS_2_phase) - offset, one_y); + signal += sums * vec3(luma_filter_2_phase[i], chroma_filter_2_phase[i], chroma_filter_2_phase[i]); + } + signal += texture(Source, vTexCoord).xyz * + vec3(luma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase]); + } + else if(phase > 2.5) + { + for (int i = 0; i < TAPS_3_phase; i++) + { + float offset = float(i); + + vec3 sums = fetch_offset(offset - float(TAPS_3_phase), one_y) + + fetch_offset(float(TAPS_3_phase) - offset, one_y); + signal += sums * vec3(luma_filter_3_phase[i], chroma_filter_3_phase[i], chroma_filter_3_phase[i]); + } + signal += texture(Source, vTexCoord).xyz * + vec3(luma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase]); + } + + vec3 rgb = yiq2rgb(signal); + FragColor = vec4(rgb, 1.0); + if(global.linearize < 0.5) return; + else FragColor = pow(FragColor, vec4(2.2)); +} diff --git a/presets/crt-geom-ntsc-composite-sharp-tate.slangp b/presets/crt-geom-ntsc-composite-sharp-tate.slangp new file mode 100644 index 0000000..ce07e5c --- /dev/null +++ b/presets/crt-geom-ntsc-composite-sharp-tate.slangp @@ -0,0 +1,78 @@ +shaders = "6" +shader0 = "../misc/ntsc-colors.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" +scale_type_x0 = "source" +scale_x0 = "1.000000" +scale_type_y0 = "source" +scale_y0 = "1.000000" +shader1 = "../ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang" +filter_linear1 = "false" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "1.000000" +scale_type_y1 = "source" +scale_y1 = "4.000000" +shader2 = "../ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang" +filter_linear2 = "false" +wrap_mode2 = "clamp_to_border" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "false" +srgb_framebuffer2 = "false" +scale_type_x2 = "source" +scale_x2 = "1.000000" +scale_type_y2 = "source" +scale_y2 = "0.500000" +shader3 = "../warp/shaders/smart-morph.slang" +wrap_mode3 = "clamp_to_border" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "false" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../sharpen/shaders/fast-sharpen.slang" +wrap_mode4 = "clamp_to_border" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "false" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "1.000000" +scale_type_y4 = "source" +scale_y4 = "1.000000" +shader5 = "../crt/shaders/crt-geom.slang" +wrap_mode5 = "clamp_to_border" +mipmap_input5 = "false" +alias5 = "" +float_framebuffer5 = "false" +srgb_framebuffer5 = "false" + +intensity = "0.0" +quality = "0.0" +SM_RANGE = "2.0" +SM_PWR = "0.7" +CONTR = "0.15" + +CRTgamma = "2.2" +CURVATURE = "1.0" +d = "1.5" +R = "1.8" +cornersize = "0.0155" +y_tilt = "-0.05" +scanline_weight = "0.25" +DOTMASK = "0.0" +lum = "0.15" +interlace_detect = "0.0" +vertical_scanlines = "1.0" diff --git a/presets/crt-geom-ntsc-composite-sharp.slangp b/presets/crt-geom-ntsc-composite-sharp.slangp new file mode 100644 index 0000000..b7d0cd5 --- /dev/null +++ b/presets/crt-geom-ntsc-composite-sharp.slangp @@ -0,0 +1,77 @@ +shaders = "6" +shader0 = "../misc/ntsc-colors.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" +scale_type_x0 = "source" +scale_x0 = "1.000000" +scale_type_y0 = "source" +scale_y0 = "1.000000" +shader1 = "../ntsc/shaders/ntsc-adaptive/ntsc-pass1.slang" +filter_linear1 = "false" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "4.000000" +scale_type_y1 = "source" +scale_y1 = "1.000000" +shader2 = "../ntsc/shaders/ntsc-adaptive/ntsc-pass2.slang" +filter_linear2 = "false" +wrap_mode2 = "clamp_to_border" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "false" +srgb_framebuffer2 = "false" +scale_type_x2 = "source" +scale_x2 = "0.500000" +scale_type_y2 = "source" +scale_y2 = "1.000000" +shader3 = "../warp/shaders/smart-morph.slang" +wrap_mode3 = "clamp_to_border" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "false" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../sharpen/shaders/fast-sharpen.slang" +wrap_mode4 = "clamp_to_border" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "false" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "1.000000" +scale_type_y4 = "source" +scale_y4 = "1.000000" +shader5 = "../crt/shaders/crt-geom.slang" +wrap_mode5 = "clamp_to_border" +mipmap_input5 = "false" +alias5 = "" +float_framebuffer5 = "false" +srgb_framebuffer5 = "false" + +intensity = "0.0" +quality = "0.0" +SM_RANGE = "1.0" +SM_PWR = "0.7" +CONTR = "0.15" + +CRTgamma = "2.2" +CURVATURE = "1.0" +d = "1.5" +R = "1.8" +cornersize = "0.0155" +y_tilt = "-0.05" +scanline_weight = "0.25" +DOTMASK = "0.0" +lum = "0.15" +interlace_detect = "0.0" diff --git a/warp/shaders/smart-morph.slang b/warp/shaders/smart-morph.slang index 9ebd244..a298a3f 100644 --- a/warp/shaders/smart-morph.slang +++ b/warp/shaders/smart-morph.slang @@ -22,10 +22,11 @@ layout(push_constant) uniform Push vec4 OriginalSize; vec4 OutputSize; uint FrameCount; - float SM_MODE, SM_PWR, SM_STRMIN, SM_STRMAX, SM_CUTLO, SM_CUTHI, SM_DEBUG; + float SM_MODE, SM_RANGE, SM_PWR, SM_STRMIN, SM_STRMAX, SM_CUTLO, SM_CUTHI, SM_DEBUG; } params; #pragma parameter SM_MODE "SmartMorph Dilation / Erosion" 0.0 0.0 1.0 1.0 // Switches between dilation and erosion (line thinning or thickening). +#pragma parameter SM_RANGE "SmartMorph Range 0-multi 1-hor 2-vert" 0.0 0.0 2.0 1.0 // Switches between all directions / horizontal only / vertical only. #pragma parameter SM_PWR "SmartMorph Luma Exponent" 0.5 0.0 10.0 0.1 // range: [0.0, +inf) - Raises d by the exponent of PWR. Smaller values for stronger morphing. #pragma parameter SM_STRMIN "SmartMorph MIN Strength" 0.0 0.0 1.0 0.01 // range: [0.0, STRMAX] - Minimal strength to apply #pragma parameter SM_STRMAX "SmartMorph MAX Strength" 1.0 0.0 1.0 0.01 // range: [STRMIN, 1.0] - Maximal strength to apply. @@ -68,20 +69,39 @@ void main() vec3 E = TEX( 0., 0.).rgb; vec3 F = TEX( 1., 0.).rgb; vec3 H = TEX( 0., 1.).rgb; + vec3 res; - vec4 b = mul( mat4x3(B, D, H, F), y_weights ); float e = dot(E, y_weights); - float di = 0.0; - if(params.SM_MODE > 0.5){ - di = min(min(b.x, b.y), min(b.z, min(b.w, e))); - } - else{ - di = max(max(b.x, b.y), max(b.z, max(b.w, e))); - } + if (params.SM_RANGE == 2.0){ + vec2 b = mul( mat2x3(B, H), y_weights ); + if(params.SM_MODE > 0.5) + di = max(b.x, b.y); + else + di = min(b.x, b.y); + + res = (di==b.y) ? B : H; + } + else if (params.SM_RANGE == 1.0){ + vec2 b = mul( mat2x3(D,F), y_weights ); + if(params.SM_MODE > 0.5) + di = max(b.x, b.y); + else + di = min(b.x, b.y); + + res = (di==b.y) ? D : F; + } + else{ + vec4 b = mul( mat4x3(B, D, H, F), y_weights ); + if(params.SM_MODE > 0.5) + di = min(min(b.x, b.y), min(b.z, min(b.w, e))); + else + di = max(max(b.x, b.y), max(b.z, max(b.w, e))); + + res = (di==b.x) ? B : (di==b.y) ? D : (di==b.z) ? H : F; + } - vec3 res = (di==b.x) ? B : (di==b.y) ? D : (di==b.z) ? H : F; di = abs(e-di); float str = (di<=params.SM_CUTLO) ? params.SM_STRMIN : (di>=params.SM_CUTHI) ? params.SM_STRMAX : smoothstep( 0.0, 1.0, pow((di-params.SM_CUTLO)/(params.SM_CUTHI-params.SM_CUTLO), params.SM_PWR) ) * (params.SM_STRMAX-params.SM_STRMIN) + params.SM_STRMIN; From c2b113411fdcf62e7cbcff32ab93186e494e9589 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sat, 22 May 2021 15:21:57 +0200 Subject: [PATCH 3/3] Update crt-geom.slang --- crt/shaders/crt-geom.slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crt/shaders/crt-geom.slang b/crt/shaders/crt-geom.slang index a8e2e64..c7c446c 100644 --- a/crt/shaders/crt-geom.slang +++ b/crt/shaders/crt-geom.slang @@ -44,7 +44,7 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter y_tilt "CRTGeom Vertical Tilt" 0.0 -0.5 0.5 0.05 #pragma parameter overscan_x "CRTGeom Horiz. Overscan %" 100.0 -125.0 125.0 0.5 #pragma parameter overscan_y "CRTGeom Vert. Overscan %" 100.0 -125.0 125.0 0.5 -#pragma parameter DOTMASK "CRTGeom Dot Mask Toggle" 0.3 0.0 0.3 0.3 +#pragma parameter DOTMASK "CRTGeom Dot Mask Strength" 0.3 0.0 1.0 0.05 #pragma parameter SHARPER "CRTGeom Sharpness" 1.0 1.0 3.0 1.0 #pragma parameter scanline_weight "CRTGeom Scanline Weight" 0.3 0.1 0.5 0.05 #pragma parameter vertical_scanlines "CRTGeom Vertical Scanlines" 0.0 0.0 1.0 1.0