diff --git a/crt/shaders/guest/advanced/afterglow0.slang b/crt/shaders/guest/advanced/afterglow0.slang index 8f15c8c..dfd02c4 100644 --- a/crt/shaders/guest/advanced/afterglow0.slang +++ b/crt/shaders/guest/advanced/afterglow0.slang @@ -84,7 +84,7 @@ void main() float w = 1.0; if ((color0.r + color0.g + color0.b < 5.0/255.0)) { w = 0.0; } - vec3 result = mix( max(mix(color, accumulate, 0.49 + vec3(PR, PG, PB))- 2.0/255.0, 0.0), color, w); + vec3 result = mix( max(mix(color, accumulate, 0.49 + vec3(PR, PG, PB))- 1.25/255.0, 0.0), color, w); FragColor = vec4(result, w); } \ No newline at end of file diff --git a/crt/shaders/guest/advanced/bloom_horizontal.slang b/crt/shaders/guest/advanced/bloom_horizontal.slang index 669806c..eb3147b 100644 --- a/crt/shaders/guest/advanced/bloom_horizontal.slang +++ b/crt/shaders/guest/advanced/bloom_horizontal.slang @@ -3,7 +3,7 @@ /* Gaussian blur - horizontal pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -30,17 +30,21 @@ layout(push_constant) uniform Push float SIZEHB; float SIGMA_HB; float BLOOMCUT_H; + float FINE_BLOOM; } params; #pragma parameter bogus_bloom "[ BLOOM/HALATION/(GLOW) PASS SETTINGS ]:" 0.0 0.0 1.0 1.0 -#pragma parameter SIZEHB " Horizontal Bloom/Halation/(Glow) Radius" 3.0 1.0 50.0 1.0 +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM + +#pragma parameter SIZEHB " Horizontal Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEHB params.SIZEHB -#pragma parameter SIGMA_HB " Horizontal Bloom/Halation/(Glow) Sigma" 0.75 0.25 15.0 0.05 +#pragma parameter SIGMA_HB " Horizontal Bloom/Halation Sigma" 0.75 0.25 15.0 0.025 #define SIGMA_HB params.SIGMA_HB -#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation/(Glow) Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_H params.BLOOMCUT_H layout(std140, set = 0, binding = 0) uniform UBO @@ -75,7 +79,7 @@ float gaussian(float x) void main() { - vec4 SourceSize1 = params.OriginalSize; + vec4 SourceSize1 = params.OriginalSize * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); float f = fract(SourceSize1.x * vTexCoord.x); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -90,7 +94,8 @@ void main() do { pixel = COMPAT_TEXTURE(LinearizePass, tex + n*dx); - w = max(gaussian(n+f) - BLOOMCUT_H, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_H >= 0.0) ? max(w - BLOOMCUT_H, 0.0) : (max(w + BLOOMCUT_H, 0.0)/(1.0 + BLOOMCUT_H)); pixel.a = max(max(pixel.r, pixel.g),pixel.b); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; diff --git a/crt/shaders/guest/advanced/bloom_vertical.slang b/crt/shaders/guest/advanced/bloom_vertical.slang index ed9fe64..d540fa1 100644 --- a/crt/shaders/guest/advanced/bloom_vertical.slang +++ b/crt/shaders/guest/advanced/bloom_vertical.slang @@ -3,7 +3,7 @@ /* Gaussian blur - vertical pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -30,16 +30,19 @@ layout(push_constant) uniform Push float SIZEVB; float SIGMA_VB; float BLOOMCUT_V; + float FINE_BLOOM; } params; +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM -#pragma parameter SIZEVB " Vertical Bloom/Halation/(Glow) Radius" 3.0 1.0 50.0 1.0 +#pragma parameter SIZEVB " Vertical Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEVB params.SIZEVB -#pragma parameter SIGMA_VB " Vertical Bloom/Halation/(Glow) Sigma" 0.60 0.25 15.0 0.05 +#pragma parameter SIGMA_VB " Vertical Bloom/Halation Sigma" 0.60 0.25 15.0 0.025 #define SIGMA_VB params.SIGMA_VB -#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation/(Glow) Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_V params.BLOOMCUT_V layout(std140, set = 0, binding = 0) uniform UBO @@ -76,7 +79,8 @@ void main() { vec4 SourceSize1 = params.SourceSize; SourceSize1.yw = params.OriginalSize.yw; - + SourceSize1 = SourceSize1 * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); + float f = fract(SourceSize1.y * vTexCoord.y); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -91,7 +95,8 @@ void main() do { pixel = COMPAT_TEXTURE(Source, tex + n*dy); - w = max(gaussian(n+f) - BLOOMCUT_V, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_V >= 0.0) ? max(w - BLOOMCUT_V, 0.0) : (max(w + BLOOMCUT_V, 0.0)/(1.0 + BLOOMCUT_V)); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; wsum = wsum + w; diff --git a/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang b/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang index ba2ea5c..9e90a57 100644 --- a/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang +++ b/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass1.slang @@ -48,19 +48,19 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bogus_filtering "[ FILTERING OPTIONS ]: " 0.0 0.0 1.0 1.0 -#pragma parameter HSHARPNESS " Horizontal Filter Range" 1.5 1.0 8.0 0.05 +#pragma parameter HSHARPNESS " Horizontal Filter Range" 1.75 1.0 8.0 0.05 #define HSHARPNESS params.HSHARPNESS -#pragma parameter SIGMA_HOR " Horizontal Blur Sigma" 0.90 0.1 7.0 0.05 +#pragma parameter SIGMA_HOR " Horizontal Blur Sigma" 0.85 0.1 7.0 0.05 #define SIGMA_HOR params.SIGMA_HOR -#pragma parameter S_SHARP " Substractive Sharpness" 0.9 0.0 2.0 0.10 +#pragma parameter S_SHARP " Substractive Sharpness" 1.4 0.0 3.0 0.10 #define S_SHARP params.S_SHARP #pragma parameter HSHARP " Sharpness Definition" 1.2 0.0 2.0 0.10 #define HSHARP params.HSHARP -#pragma parameter MAXS " Maximum Sharpness" 0.15 0.0 0.30 0.01 +#pragma parameter MAXS " Maximum Sharpness" 0.18 0.0 0.30 0.01 #define MAXS params.MAXS #pragma parameter HARNG " Substractive Sharpness Ringing" 0.4 0.0 4.0 0.10 diff --git a/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang b/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang index e9b61a0..fdf0a0c 100644 --- a/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang +++ b/crt/shaders/guest/advanced/crt-guest-advanced-ntsc-pass2.slang @@ -27,7 +27,7 @@ layout(push_constant) uniform Push { float IOS, OS, BLOOM, brightboost, brightboost1, gsl, scanline1, scanline2, beam_min, beam_max, beam_size, - h_sharp, s_sharp, warpX, warpY, glow, shadowMask, masksize, ring, no_scanlines; + h_sharp, s_sharp, warpX, warpY, glow, shadowMask, masksize, ring, no_scanlines, tds, clips, ssharp; } params; layout(std140, set = 0, binding = 0) uniform UBO @@ -47,12 +47,12 @@ layout(std140, set = 0, binding = 0) uniform UBO float intres; float prescalex; float c_shape; - float blendMode; float scangamma; - float rolling_scan; float sborder; float scan_falloff; float bloom_dist; + float bmask1; + float hmask1; } global; @@ -64,15 +64,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter gamma_c " Gamma correct" 1.0 0.50 2.0 0.025 #define gamma_c global.gamma_c // adjust brightness @@ -82,6 +88,9 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter brightboost1 " Bright Boost Bright Pixels" 1.10 0.25 3.00 0.025 #define brightboost1 params.brightboost1 // adjust brightness +#pragma parameter clips " Clip Saturated Color Beams" 0.0 -1.0 1.0 0.05 +#define clips params.clips // kinky effect + #pragma parameter bogus_scanline "[ SCANLINE OPTIONS ]: " 0.0 0.0 1.0 1.0 #pragma parameter gsl " Scanline Type" 0.0 -1.0 2.0 1.0 @@ -99,21 +108,24 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter beam_max " Scanline Shape Bright Pixels" 1.00 0.2 3.5 0.025 #define beam_max params.beam_max // bright area beam max - wide +#pragma parameter tds " Thinner Dark Scanlines" 0.0 0. 1.0 1.0 +#define tds params.tds // thinner dark scanlines + #pragma parameter beam_size " Increased Bright Scanline Beam" 0.60 0.0 1.0 0.05 #define beam_size params.beam_size // increased max. beam size #pragma parameter scans " Scanline Saturation / Mask Falloff" 0.50 -5.0 5.0 0.10 #define scans global.scans // scanline saturation -#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.05 +#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.025 #define scan_falloff global.scan_falloff // scanline falloff +#pragma parameter ssharp " Smart Sharpen Scanlines" 0.0 0.0 0.30 0.01 +#define ssharp params.ssharp + #pragma parameter scangamma " Scanline Gamma" 2.40 0.5 5.0 0.05 #define scangamma global.scangamma -#pragma parameter rolling_scan " Rolling Scanlines" 0.0 -1.0 1.0 0.01 -#define rolling_scan global.rolling_scan // rolling scanlines - #pragma parameter no_scanlines " No-scanline mode" 0.0 0.0 1.5 0.05 #define no_scanlines params.no_scanlines @@ -179,7 +191,7 @@ float st(float x) float st1(float x) { - return exp2(-7.0*x*x); + return exp2(-8.0*x*x); } float sw0(float x, float color, float scanline) @@ -205,6 +217,7 @@ float sw2(float x, float color, float scanline) float ex = x*tmp; return exp2(-scanline*ex*ex); } + vec2 Warp(vec2 pos) { @@ -227,6 +240,12 @@ vec3 gc(vec3 c) return c * mg/(mc + eps); } +vec3 plant (vec3 tar, float r) +{ + float t = max(max(tar.r,tar.g),tar.b) + 0.00001; + return tar * r / t; +} + void main() { @@ -308,9 +327,11 @@ void main() if (!interb) { // calculating scanlines + vec3 luma = vec3(0.2126, 0.7152, 0.0722); + float ssub = ssharp*max(abs(scolor1.x-scolor2.x), abs(dot(color1,luma)-dot(color2,luma))); - float shape1 = mix(scanline1, scanline2, f); - float shape2 = mix(scanline1, scanline2, 1.0-f); + float shape1 = mix(scanline1, scanline2 + ssub * scolor1.x * 35.0, f); + float shape2 = mix(scanline1, scanline2 + ssub * scolor2.x * 35.0, 1.0-f); float wt1 = st(f); float wt2 = st(1.0-f); @@ -326,13 +347,10 @@ if (!interb) vec3 cref1 = mix(sctmp, scolor1, beam_size); float creff1 = pow(max(max(cref1.r,cref1.g),cref1.b), scan_falloff); vec3 cref2 = mix(sctmp, scolor2, beam_size); float creff2 = pow(max(max(cref2.r,cref2.g),cref2.b), scan_falloff); + if (tds > 0.5) { shape1 = mix(scanline2, shape1, creff1); shape2 = mix(scanline2, shape2, creff2); } + float f1 = f; float f2 = 1.0-f; - - float scanpix = SourceSize.x/OutputSize.x; - - f1 = fract(f1 + rolling_scan*float(global.FrameCount)*scanpix); - f2 = 1.0 - f1; if (gsl < 0.5) { wf1 = sw0(f1,creff1,shape1); wf2 = sw0(f2,creff2,shape2);} else if (gsl == 1.0) { wf1 = sw1(f1,creff1,shape1); wf2 = sw1(f2,creff2,shape2);} else @@ -355,16 +373,20 @@ if (!interb) float scanpow2 = (scans > 0.0) ? 1.0 : pow(f2, 0.375); w1 = pow(w1, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref1, scanpow1))); w2 = pow(w2, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref2, scanpow2))); + + if (abs(clips) > 0.005) + { + sy = mc1; vec3 l1 = sqrt(w1*wt1); vec3 l2 = sqrt(w2*wt2); + one = (clips > 0.0) ? w1 : mix(w1, l1, sy); + float sat = 1.0001-min(min(cref1.r,cref1.g),cref1.b); + color1 = mix(color1, plant(pow(color1, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + sy = mc2; + sat = 1.0001-min(min(cref2.r,cref2.g),cref2.b); + one = (clips > 0.0) ? w2 : mix(w2, l2, sy); + color2 = mix(color2, plant(pow(color2, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + } color = (gc(color1)*w1 + gc(color2)*w2); - - if (abs(rolling_scan) > 0.005) - { - wt1 = st1(f); - wt2 = st1(1.0-f); - color00 = (color1*wt1 + color2*wt2)/(wt1+wt2); - color = gc(color00) * mix(w1+w2, w3.xxx, max(wf1,wf2)); - } color = min(color, 1.0); } diff --git a/crt/shaders/guest/advanced/crt-guest-advanced.slang b/crt/shaders/guest/advanced/crt-guest-advanced.slang index 9bacab6..3f231d6 100644 --- a/crt/shaders/guest/advanced/crt-guest-advanced.slang +++ b/crt/shaders/guest/advanced/crt-guest-advanced.slang @@ -27,7 +27,7 @@ layout(push_constant) uniform Push { float TATE, IOS, OS, BLOOM, brightboost, brightboost1, gsl, scanline1, scanline2, beam_min, beam_max, beam_size, - h_sharp, s_sharp, csize, bsize1, warpX, warpY, glow, spike, ring, no_scanlines; + h_sharp, s_sharp, csize, bsize1, warpX, warpY, glow, spike, ring, no_scanlines, tds, clips, ssharp; } params; layout(std140, set = 0, binding = 0) uniform UBO @@ -50,9 +50,10 @@ layout(std140, set = 0, binding = 0) uniform UBO float intres; float prescalex; float scan_falloff; - float rolling_scan; float bloom_dist; float scangamma; + float bmask1; + float hmask1; } global; @@ -64,15 +65,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter gamma_c " Gamma correct" 1.0 0.50 2.0 0.025 #define gamma_c global.gamma_c // adjust brightness @@ -82,6 +89,9 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter brightboost1 " Bright Boost Bright Pixels" 1.10 0.25 3.00 0.025 #define brightboost1 params.brightboost1 // adjust brightness +#pragma parameter clips " Clip Saturated Color Beams" 0.0 -1.0 1.0 0.05 +#define clips params.clips // kinky effect + #pragma parameter bogus_scanline "[ SCANLINE OPTIONS ]: " 0.0 0.0 1.0 1.0 #pragma parameter gsl " Scanline Type" 0.0 -1.0 2.0 1.0 @@ -99,20 +109,23 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter beam_max " Scanline Shape Bright Pixels" 1.00 0.2 3.5 0.025 #define beam_max params.beam_max // bright area beam max - wide +#pragma parameter tds " Thinner Dark Scanlines" 0.0 0. 1.0 1.0 +#define tds params.tds // thinner dark scanlines + #pragma parameter beam_size " Increased Bright Scanline Beam" 0.60 0.0 1.0 0.05 #define beam_size params.beam_size // increased max. beam size #pragma parameter scans " Scanline Saturation / Mask Falloff" 0.5 -5.0 5.0 0.10 #define scans global.scans // scanline saturation -#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.15 2.0 0.05 +#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.025 #define scan_falloff global.scan_falloff // scanline falloff #pragma parameter spike " Scanline Spike Removal" 1.0 0.0 2.0 0.10 #define spike params.spike -#pragma parameter rolling_scan " Rolling Scanlines" 0.0 -1.0 1.0 0.01 -#define rolling_scan global.rolling_scan // rolling scanlines +#pragma parameter ssharp " Smart Sharpen Scanlines" 0.0 0.0 0.30 0.01 +#define ssharp params.ssharp #pragma parameter scangamma " Scanline Gamma" 2.40 0.5 5.0 0.05 #define scangamma global.scangamma @@ -205,7 +218,7 @@ float st(float x) float st1(float x) { - return exp2(-7.0*x*x); + return exp2(-8.0*x*x); } float sw0(float x, float color, float scanline) @@ -254,6 +267,12 @@ vec3 gc(vec3 c) return c * mg/(mc + eps); } +vec3 plant (vec3 tar, float r) +{ + float t = max(max(tar.r,tar.g),tar.b) + 0.00001; + return tar * r / t; +} + void main() { @@ -469,8 +488,10 @@ if (!interb) { // calculating scanlines - float shape1 = mix(scanline1, scanline2, f); - float shape2 = mix(scanline1, scanline2, 1.0-f); + float ssub = ssharp*max(abs(scolor1.x-scolor2.x), abs(dot(color1,luma)-dot(color2,luma))); + + float shape1 = mix(scanline1, scanline2 + ssub * scolor1.x * 35.0, f); + float shape2 = mix(scanline1, scanline2 + ssub * scolor2.x * 35.0, 1.0-f); float wt1 = st(f); float wt2 = st(1.0-f); @@ -486,14 +507,11 @@ if (!interb) vec3 cref1 = mix(sctmp, scolor1, beam_size); float creff1 = pow(max(max(cref1.r,cref1.g),cref1.b), scan_falloff); vec3 cref2 = mix(sctmp, scolor2, beam_size); float creff2 = pow(max(max(cref2.r,cref2.g),cref2.b), scan_falloff); + if (tds > 0.5) { shape1 = mix(scanline2, shape1, creff1); shape2 = mix(scanline2, shape2, creff2); } + float f1 = f; float f2 = 1.0-f; - float scanpix = mix(SourceSize.x/OutputSize.x, SourceSize.y/OutputSize.y, float(notate)); - - f1 = fract(f1 + rolling_scan*float(global.FrameCount)*scanpix); - f2 = 1.0 - f1; - if (gsl < 0.5) { wf1 = sw0(f1,creff1,shape1); wf2 = sw0(f2,creff2,shape2);} else if (gsl == 1.0) { wf1 = sw1(f1,creff1,shape1); wf2 = sw1(f2,creff2,shape2);} else { wf1 = sw2(f1,creff1,shape1); wf2 = sw2(f2,creff2,shape2);} @@ -515,16 +533,20 @@ if (!interb) float scanpow2 = (scans > 0.0) ? 1.0 : pow(f2, 0.375); w1 = pow(w1, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref1, scanpow1))); w2 = pow(w2, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref2, scanpow2))); + + if (abs(clips) > 0.005) + { + sy = mc1; vec3 l1 = sqrt(w1*wt1); vec3 l2 = sqrt(w2*wt2); + one = (clips > 0.0) ? w1 : mix(w1, l1, sy); + float sat = 1.0001-min(min(cref1.r,cref1.g),cref1.b); + color1 = mix(color1, plant(pow(color1, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + sy = mc2; + sat = 1.0001-min(min(cref2.r,cref2.g),cref2.b); + one = (clips > 0.0) ? w2 : mix(w2, l2, sy); + color2 = mix(color2, plant(pow(color2, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + } color = (gc(color1)*w1 + gc(color2)*w2); - - if (abs(rolling_scan) > 0.005) - { - wt1 = st1(f); - wt2 = st1(1.0-f); - color00 = (color1*wt1 + color2*wt2)/(wt1+wt2); - color = gc(color00) * mix(w1+w2, w3.xxx, max(wf1,wf2)); - } color = min(color, 1.0); } @@ -537,6 +559,6 @@ if (!interb) float colmx = max(max(ctmp.r,ctmp.g),ctmp.b); if(!interb) color = pow( color, vec3(gamma_in/scangamma) ); - + FragColor = vec4(color, colmx); } diff --git a/crt/shaders/guest/advanced/deconvergence-ntsc.slang b/crt/shaders/guest/advanced/deconvergence-ntsc.slang index 0099eeb..6311894 100644 --- a/crt/shaders/guest/advanced/deconvergence-ntsc.slang +++ b/crt/shaders/guest/advanced/deconvergence-ntsc.slang @@ -40,7 +40,6 @@ layout(std140, set = 0, binding = 0) uniform UBO float bloom; float halation; float slotms; - float mclip; float mask_gamma; float gamma_out; float overscanX; @@ -77,6 +76,9 @@ layout(std140, set = 0, binding = 0) uniform UBO float smask_mit; float mask_zoom; float no_scanlines; + float bmask; + float bmask1; + float hmask1; } global; @@ -100,15 +102,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter brightboost " Bright Boost Dark Pixels" 1.40 0.25 10.0 0.05 #define brightboost params.brightboost // adjust brightness @@ -176,21 +184,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter masksize " CRT Mask Size" 1.0 1.0 4.0 1.0 #define masksize params.masksize // Mask Size -#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -4.0 4.0 1.0 +#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -5.0 5.0 1.0 #define mask_zoom global.mask_zoom // Mask Size +#pragma parameter mshift " (Transform to) Shadow Mask" 0.0 0.0 1.0 0.5 +#define mshift params.mshift // do the "shadow mask" + +#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 +#define mask_layout params.mask_layout // mask layout: RGB or BGR + #pragma parameter maskDark " Lottes maskDark" 0.5 0.0 2.0 0.05 #define maskDark params.maskDark // Dark "Phosphor" #pragma parameter maskLight " Lottes maskLight" 1.5 0.0 2.0 0.05 #define maskLight params.maskLight // Light "Phosphor" -#pragma parameter mshift " Mask Shift/Stagger" 0.0 -8.0 8.0 0.5 -#define mshift params.mshift // mask 'line' shift/stagger - -#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 -#define mask_layout params.mask_layout // mask layout: RGB or BGR - #pragma parameter mask_gamma " Mask gamma" 2.40 1.0 5.0 0.05 #define mask_gamma global.mask_gamma // Mask application gamma @@ -209,15 +217,15 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter slotms " Slot Mask Thickness" 1.0 1.0 4.0 1.0 #define slotms global.slotms // Slot Mask Thickness -#pragma parameter mclip " Keep Mask effect with clipping" 0.0 0.0 1.0 0.05 -#define mclip global.mclip // - #pragma parameter smoothmask " Smooth Masks in bright scanlines" 0.0 0.0 1.0 1.0 #define smoothmask global.smoothmask #pragma parameter smask_mit " Mitigate Slotmask Interaction" 0.0 0.0 1.0 0.05 #define smask_mit global.smask_mit +#pragma parameter bmask " Base (black) Mask strength" 0.0 0.0 0.25 0.01 +#define bmask global.bmask + #pragma parameter gamma_out " Gamma out" 1.95 1.0 5.0 0.05 #define gamma_out global.gamma_out // output gamma @@ -287,14 +295,7 @@ vec3 Mask(vec2 pos, float mx, float mb) vec3 mask = vec3(maskDark, maskDark, maskDark); vec3 one = vec3(1.0); - // No mask - if (shadowMask == -1.0) - { - mask = one; - } - - // Phosphor. - else if (shadowMask == 0.0) + if (shadowMask == 0.0) { float mc = 1.0 - max(maskstr, 0.0); pos.x = fract(pos.x*0.5); @@ -563,7 +564,7 @@ vec3 noise(vec3 v){ return v; } -void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) +void fetch_pixel (inout vec3 c, inout vec3 b, inout vec3 g, vec2 coord, vec2 bcoord) { float stepx = OutputSize.z; float stepy = OutputSize.w; @@ -589,8 +590,6 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) dy = posy * dy; } - // if (global.dctypex > 0.025 || global.dctypey > 0.025) ds *= sqrt(posx*posx*sign(global.dctypex) + posy*posy*sign(global.dctypey)); - vec2 rc = global.deconrr * dx + global.deconrry*dy; vec2 gc = global.deconrg * dx + global.deconrgy*dy; vec2 bc = global.deconrb * dx + global.deconrby*dy; @@ -607,8 +606,15 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) b1 = COMPAT_TEXTURE(BloomPass, bcoord + bc).b; d = vec3(r1, g1, b1); - b = clamp(mix(b, d, ds), 0.0, 1.0); -} + b = g = mix(b, d, min(ds,1.0)); + + r1 = COMPAT_TEXTURE(GlowPass, bcoord + rc).r; + g1 = COMPAT_TEXTURE(GlowPass, bcoord + gc).g; + b1 = COMPAT_TEXTURE(GlowPass, bcoord + bc).b; + + d = vec3(r1, g1, b1); + g = mix(g, d, min(ds,1.0)); +} void main() @@ -645,14 +651,15 @@ void main() // color and bloom fetching vec3 color = COMPAT_TEXTURE(Source,pos1).rgb; vec3 Bloom = COMPAT_TEXTURE(BloomPass, pos).rgb; - + vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; + if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(global.deconrgy) + abs(global.deconrb) + abs(global.deconrby)) > 0.2) - fetch_pixel(color, Bloom, pos1, pos); // deconvergence + fetch_pixel(color, Bloom, Glow, pos1, pos); // deconvergence float cm = igc(max(max(color.r,color.g),color.b)); float mx1 = COMPAT_TEXTURE(Source, pos1 ).a; float colmx = max(mx1, cm); - float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); + float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); if(interb) w3 = 1.0; vec2 dx = vec2(0.001, 0.0); float mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; @@ -665,7 +672,7 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob dx = vec2(global.OriginalSize.z, 0.0)*0.25; mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; mx2 = COMPAT_TEXTURE(Source, pos1 + dx).a; - float mb = 1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0); + float mb = (1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0)); vec3 one = vec3(1.0); @@ -673,36 +680,39 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob vec3 orig1 = color; vec3 cmask = one; - - vec2 maskcoord = gl_FragCoord.xy * 1.00001; - - vec2 scoord = maskcoord; - + vec3 cmask1 = one; + vec3 cmask2 = one; + // mask widths and mask dark compensate (fractional part) values - float mwidths[14] = float[14] (2.0, 3.0, 3.0, 3.0, 6.0, 2.4, 3.5, 2.4, 3.25, 3.5, 4.5, 4.25, 7.5, 6.25); float mwidth = mwidths[int(shadowMask)]; float mask_compensate = fract(mwidth); + +if (shadowMask > -0.5) +{ + vec2 maskcoord = gl_FragCoord.xy * 1.00001; + vec2 scoord = maskcoord; + mwidth = floor(mwidth) * masksize; float swidth = mwidth; bool zoomed = (abs(mask_zoom) > 0.75); float mscale = 1.0; vec2 maskcoord0 = maskcoord; maskcoord.y = floor(maskcoord.y/masksize); + float mwidth1 = max(mwidth + mask_zoom, 2.0); -if ( abs(mshift) > 0.75 ) +if ( mshift > 0.25 ) { - float stagg_lvl = 1.0; if (fract(abs(mshift)) > 0.25 && abs(mshift) > 1.25) stagg_lvl = 2.0; - float next_line = float(fract((maskcoord.y/stagg_lvl)*0.5) > 0.25); - maskcoord0.x = (mshift > -0.25) ? (maskcoord0.x + next_line * floor(mshift)) : (maskcoord0.x + floor(maskcoord.y / stagg_lvl) * floor(abs(mshift))); + float stagg_lvl = 1.0; if (fract(mshift) > 0.25) stagg_lvl = 2.0; + float next_line = float(floor(mod(maskcoord.y, 2.0*stagg_lvl)) < stagg_lvl); + maskcoord0.x = maskcoord0.x + next_line * 0.5 * mwidth1; } maskcoord = maskcoord0/masksize; if (mask_zoom >= 0.0) maskcoord = floor(maskcoord); if ( !zoomed ) - cmask*= Mask(maskcoord, mx, mb); + cmask*= Mask(floor(maskcoord), mx, mb); else{ - float mwidth1 = max(mwidth + mask_zoom, 2.0); mscale = mwidth1/mwidth; float mlerp = fract(maskcoord.x/mscale); float mcoord = floor(maskcoord.x/mscale); if (shadowMask == 12.0 && mask_zoom == -2.0) mcoord = ceil(maskcoord.x/mscale); @@ -718,15 +728,16 @@ else{ smask = SlotMask(scoord + vec2(sm_offset,0.0), mx, swidth); smask = clamp(smask + mix(smask_mit, 0.0, min(w3, pow(w3*max(max(orig1.r,orig1.g),orig1.b), 0.33333))), 0.0, 1.0); - + + cmask2 = cmask; cmask*=smask; - vec3 cmask1 = cmask; + cmask1 = cmask; - if (mask_bloom > 0.025) + if (abs(mask_bloom) > 0.025) { float maxbl = max(max(max(Bloom.r,Bloom.g),Bloom.b), mxg); - maxbl = maxbl * mix(1.0, 2.0-colmx, bloom_dist); - cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); + maxbl = maxbl * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + if (mask_bloom > 0.025) cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); else cmask = max(mix(cmask, cmask*(1.0-0.5*maxbl) + plant(pow(Bloom,0.35.xxx),maxbl), -mask_bloom),cmask); } color = pow(color, vec3(mask_gamma/gamma_in)); @@ -734,60 +745,61 @@ else{ color = min(color,1.0); color = pow(color, vec3(gamma_in/mask_gamma)); - cmask = min(cmask, 1.0); cmask1 = min(cmask1, 1.0); - - float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); +} + + float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); if(shadowMask < -0.5) dark_compensate = 1.0; float bb = mix(brightboost, brightboost1, mx) * dark_compensate; color*=bb; - vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; vec3 Ref = COMPAT_TEXTURE(LinearizePass, pos).rgb; float maxb = COMPAT_TEXTURE(BloomPass, pos).a; float vig = COMPAT_TEXTURE(PrePass0, clamp(pos, 0.0+0.5*global.OriginalSize.zw, 1.0-0.5*global.OriginalSize.zw)).a; vec3 Bloom1 = Bloom; + vec3 bcmask = mix(one, cmask, bmask1); + vec3 hcmask = mix(one, cmask, hmask1); -if (abs(bloom) > 0.025) -{ - if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); - Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); - Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); - Bloom1 = Bloom1 * mix(1.0, 2.0-colmx, bloom_dist); - color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); -} + if (abs(bloom) > 0.025) + { + if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); + Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); + Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); + Bloom1 = bcmask*Bloom1 * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); + } - color = min(color, mix(one, cmask1, mclip)); + if (!interb) color = declip(min(color,1.0), mix(1.0, w3, 0.6)); - if (!interb) color = declip(color, mix(1.0, w3, 0.6)); else w3 = 1.0; - if (halation > 0.01) { Bloom = mix(0.5*(Bloom + Bloom*Bloom), 0.75*Bloom*Bloom, colmx); - color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.6)*Bloom*halation; } + color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*halation; } else if (halation < -0.01) { float mbl = max(max(Bloom.r,Bloom.g),Bloom.b); Bloom = plant(Bloom + Ref + orig1 + Bloom*Bloom*Bloom, min(mbl*mbl,0.75)); - color = color + 2.0*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.5)*Bloom*(-halation); } + color = color + 2.0*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*(-halation); } + float w = 0.25 + 0.60*mix(w3, 1.0, sqrt(colmx)); - if (smoothmask > 0.5) { w3 = mix(1.0, w3, smoothstep(0.3, 0.6, mx1)); color = max(min(color/w3, 1.0)*w3, min(color,color*(1.0-w3))); } + if (smoothmask > 0.5) { color = min(color,1.0); color = max(min(color/w3, 1.0)*w3, min(orig1*bb,color*(1.0-w3))); } - if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, 0.7*colmx); + if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, colmx); else { maxb = max(max(Glow.r,Glow.g),Glow.b); - orig1 = plant(orig1 + 0.001*Ref, 1.0); + vec3 orig2 = plant(orig1 + 0.001*Ref, 1.0); Bloom = plant(Glow, 1.0); - Ref = abs(orig1-Bloom); - mx0 = max(max(orig1.g,orig1.g),orig1.b)-min(min(orig1.g,orig1.g),orig1.b); + Ref = abs(orig2-Bloom); + mx0 = max(max(orig2.g,orig2.g),orig2.b)-min(min(orig2.g,orig2.g),orig2.b); mx2 = max(max(Bloom.g,Bloom.g),Bloom.b)-min(min(Bloom.g,Bloom.g),Bloom.b); - Bloom = mix(maxb*min(Bloom,orig1), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); + Bloom = mix(maxb*min(Bloom,orig2), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); Glow = mix(global.m_glow_low*Glow, global.m_glow_high*Bloom, pow(colmx, global.m_glow_dist/gamma_in)); } - if (glow >= 0.0 && global.m_glow < 0.5) color = color + 0.5*Glow*glow; - else { if(global.m_glow > 0.5) cmask1 = max(mix(one, cmask1, global.m_glow_mask),0.0); color = color + abs(glow)*cmask1*Glow; } + if (global.m_glow < 0.5) { + if (glow >= 0.0) color = color + 0.5*Glow*glow; else color = color + abs(glow)*min(cmask2*cmask2,1.0)*Glow; } + else { cmask1 = clamp(mix(one, cmask1, global.m_glow_mask),0.0, 1.0); color = color + abs(glow)*cmask1*Glow; } color = min(color, 1.0); @@ -801,6 +813,9 @@ if (abs(bloom) > 0.025) if (global.noisetype < 0.5) color = mix(color, noise0, 0.25*abs(global.addnoised) * rc); else color = min(color * mix(1.0, 1.5*noise0.x, 0.5*abs(global.addnoised)), 1.0); } + + colmx = max(max(orig1.r,orig1.g),orig1.b); + color = color + bmask*mix(cmask2, 0.125*(1.0-colmx)*color, min(20.0*colmx, 1.0)); FragColor = vec4(color*vig*humbar(mix(pos.y, pos.x, global.bardir))*global.post_br*corner(pos0), 1.0); } diff --git a/crt/shaders/guest/advanced/deconvergence.slang b/crt/shaders/guest/advanced/deconvergence.slang index 50a8d82..e47878c 100644 --- a/crt/shaders/guest/advanced/deconvergence.slang +++ b/crt/shaders/guest/advanced/deconvergence.slang @@ -40,7 +40,6 @@ layout(std140, set = 0, binding = 0) uniform UBO float bloom; float halation; float slotms; - float mclip; float mask_gamma; float gamma_out; float overscanX; @@ -77,6 +76,9 @@ layout(std140, set = 0, binding = 0) uniform UBO float smask_mit; float mask_zoom; float no_scanlines; + float bmask; + float bmask1; + float hmask1; } global; #pragma parameter no_scanlines " No-scanline mode" 0.0 0.0 1.5 0.05 @@ -99,15 +101,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter brightboost " Bright Boost Dark Pixels" 1.40 0.25 10.0 0.05 #define brightboost params.brightboost // adjust brightness @@ -178,21 +186,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter masksize " CRT Mask Size" 1.0 1.0 4.0 1.0 #define masksize params.masksize // Mask Size -#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -4.0 4.0 1.0 +#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -5.0 5.0 1.0 #define mask_zoom global.mask_zoom // Mask Size +#pragma parameter mshift " (Transform to) Shadow Mask" 0.0 0.0 1.0 0.5 +#define mshift params.mshift // do the "shadow mask" + +#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 +#define mask_layout params.mask_layout // mask layout: RGB or BGR + #pragma parameter maskDark " Lottes maskDark" 0.5 0.0 2.0 0.05 #define maskDark params.maskDark // Dark "Phosphor" #pragma parameter maskLight " Lottes maskLight" 1.5 0.0 2.0 0.05 #define maskLight params.maskLight // Light "Phosphor" -#pragma parameter mshift " Mask Shift/Stagger" 0.0 -8.0 8.0 0.5 -#define mshift params.mshift // mask 'line' shift/stagger - -#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 -#define mask_layout params.mask_layout // mask layout: RGB or BGR - #pragma parameter mask_gamma " Mask gamma" 2.40 1.0 5.0 0.05 #define mask_gamma global.mask_gamma // Mask application gamma @@ -211,15 +219,15 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter slotms " Slot Mask Thickness" 1.0 1.0 4.0 1.0 #define slotms global.slotms // Slot Mask Thickness -#pragma parameter mclip " Keep Mask effect with clipping" 0.0 0.0 1.0 0.05 -#define mclip global.mclip // - #pragma parameter smoothmask " Smooth Masks in bright scanlines" 0.0 0.0 1.0 1.0 #define smoothmask global.smoothmask #pragma parameter smask_mit " Mitigate Slotmask Interaction" 0.0 0.0 1.0 0.05 #define smask_mit global.smask_mit +#pragma parameter bmask " Base (black) Mask strength" 0.0 0.0 0.25 0.01 +#define bmask global.bmask + #pragma parameter gamma_out " Gamma out" 2.4 1.0 5.0 0.05 #define gamma_out global.gamma_out // output gamma @@ -289,14 +297,7 @@ vec3 Mask(vec2 pos, float mx, float mb) vec3 mask = vec3(maskDark, maskDark, maskDark); vec3 one = vec3(1.0); - // No mask - if (shadowMask == -1.0) - { - mask = one; - } - - // Phosphor. - else if (shadowMask == 0.0) + if (shadowMask == 0.0) { float mc = 1.0 - max(maskstr, 0.0); pos.x = fract(pos.x*0.5); @@ -565,7 +566,7 @@ vec3 noise(vec3 v){ return v; } -void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) +void fetch_pixel (inout vec3 c, inout vec3 b, inout vec3 g, vec2 coord, vec2 bcoord) { float stepx = OutputSize.z; float stepy = OutputSize.w; @@ -591,8 +592,6 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) dy = posy * dy; } - // if (global.dctypex > 0.025 || global.dctypey > 0.025) ds *= sqrt(posx*posx*sign(global.dctypex) + posy*posy*sign(global.dctypey)); - vec2 rc = global.deconrr * dx + global.deconrry*dy; vec2 gc = global.deconrg * dx + global.deconrgy*dy; vec2 bc = global.deconrb * dx + global.deconrby*dy; @@ -609,8 +608,15 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) b1 = COMPAT_TEXTURE(BloomPass, bcoord + bc).b; d = vec3(r1, g1, b1); - b = clamp(mix(b, d, ds), 0.0, 1.0); -} + b = g = mix(b, d, min(ds,1.0)); + + r1 = COMPAT_TEXTURE(GlowPass, bcoord + rc).r; + g1 = COMPAT_TEXTURE(GlowPass, bcoord + gc).g; + b1 = COMPAT_TEXTURE(GlowPass, bcoord + bc).b; + + d = vec3(r1, g1, b1); + g = mix(g, d, min(ds,1.0)); +} void main() @@ -648,14 +654,15 @@ void main() // color and bloom fetching vec3 color = COMPAT_TEXTURE(Source,pos1).rgb; vec3 Bloom = COMPAT_TEXTURE(BloomPass, pos).rgb; + vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(global.deconrgy) + abs(global.deconrb) + abs(global.deconrby)) > 0.2) - fetch_pixel(color, Bloom, pos1, pos); // deconvergence + fetch_pixel(color, Bloom, Glow, pos1, pos); // deconvergence float cm = igc(max(max(color.r,color.g),color.b)); float mx1 = COMPAT_TEXTURE(Source, pos1 ).a; float colmx = max(mx1, cm); - float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); + float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); if(interb) w3 = 1.0; vec2 dx = mix(vec2(0.001, 0.0), vec2(0.0, 0.001), TATE); float mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; @@ -668,7 +675,7 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob dx = mix(vec2(global.OriginalSize.z, 0.0), vec2(0.0, global.OriginalSize.w), TATE) * 0.25; mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; mx2 = COMPAT_TEXTURE(Source, pos1 + dx).a; - float mb = 1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0); + float mb = (1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0)); vec3 one = vec3(1.0); @@ -676,36 +683,40 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob vec3 orig1 = color; vec3 cmask = one; - - vec2 maskcoord = gl_FragCoord.yx * 1.00001; - if (notate) maskcoord = maskcoord.yx; - vec2 scoord = maskcoord; - + vec3 cmask1 = one; + vec3 cmask2 = one; + // mask widths and mask dark compensate (fractional part) values - float mwidths[14] = float[14] (2.0, 3.0, 3.0, 3.0, 6.0, 2.4, 3.5, 2.4, 3.25, 3.5, 4.5, 4.25, 7.5, 6.25); float mwidth = mwidths[int(shadowMask)]; float mask_compensate = fract(mwidth); + +if (shadowMask > -0.5) +{ + vec2 maskcoord = gl_FragCoord.yx * 1.00001; + if (notate) maskcoord = maskcoord.yx; + vec2 scoord = maskcoord; + mwidth = floor(mwidth) * masksize; float swidth = mwidth; bool zoomed = (abs(mask_zoom) > 0.75); float mscale = 1.0; vec2 maskcoord0 = maskcoord; maskcoord.y = floor(maskcoord.y/masksize); + float mwidth1 = max(mwidth + mask_zoom, 2.0); -if ( abs(mshift) > 0.75 ) +if ( mshift > 0.25 ) { - float stagg_lvl = 1.0; if (fract(abs(mshift)) > 0.25 && abs(mshift) > 1.25) stagg_lvl = 2.0; - float next_line = float(fract((maskcoord.y/stagg_lvl)*0.5) > 0.25); - maskcoord0.x = (mshift > -0.25) ? (maskcoord0.x + next_line * floor(mshift)) : (maskcoord0.x + floor(maskcoord.y / stagg_lvl) * floor(abs(mshift))); + float stagg_lvl = 1.0; if (fract(mshift) > 0.25) stagg_lvl = 2.0; + float next_line = float(floor(mod(maskcoord.y, 2.0*stagg_lvl)) < stagg_lvl); + maskcoord0.x = maskcoord0.x + next_line * 0.5 * mwidth1; } maskcoord = maskcoord0/masksize; if (mask_zoom >= 0.0) maskcoord = floor(maskcoord); if ( !zoomed ) - cmask*= Mask(maskcoord, mx, mb); + cmask*= Mask(floor(maskcoord), mx, mb); else{ - float mwidth1 = max(mwidth + mask_zoom, 2.0); mscale = mwidth1/mwidth; float mlerp = fract(maskcoord.x/mscale); float mcoord = floor(maskcoord.x/mscale); if (shadowMask == 12.0 && mask_zoom == -2.0) mcoord = ceil(maskcoord.x/mscale); @@ -722,14 +733,15 @@ else{ smask = clamp(smask + mix(smask_mit, 0.0, min(w3, pow(w3*max(max(orig1.r,orig1.g),orig1.b), 0.33333))), 0.0, 1.0); + cmask2 = cmask; cmask*=smask; - vec3 cmask1 = cmask; + cmask1 = cmask; - if (mask_bloom > 0.025) + if (abs(mask_bloom) > 0.025) { float maxbl = max(max(max(Bloom.r,Bloom.g),Bloom.b), mxg); - maxbl = maxbl * mix(1.0, 2.0-colmx, bloom_dist); - cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); + maxbl = maxbl * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + if (mask_bloom > 0.025) cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); else cmask = max(mix(cmask, cmask*(1.0-0.5*maxbl) + plant(pow(Bloom,0.35.xxx),maxbl), -mask_bloom),cmask); } color = pow(color, vec3(mask_gamma/gamma_in)); @@ -737,60 +749,63 @@ else{ color = min(color,1.0); color = pow(color, vec3(gamma_in/mask_gamma)); - cmask = min(cmask, 1.0); + cmask = min(cmask, 1.0); cmask1 = min(cmask1, 1.0); +} - float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); + float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); if(shadowMask < -0.5) dark_compensate = 1.0; float bb = mix(brightboost, brightboost1, mx) * dark_compensate; color*=bb; vec3 Ref = COMPAT_TEXTURE(LinearizePass, pos).rgb; - vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; float maxb = COMPAT_TEXTURE(BloomPass, pos).a; float vig = COMPAT_TEXTURE(PrePass, clamp(pos, 0.0+0.5*global.OriginalSize.zw, 1.0-0.5*global.OriginalSize.zw)).a; vec3 Bloom1 = Bloom; + vec3 bcmask = mix(one, cmask, bmask1); + vec3 hcmask = mix(one, cmask, hmask1); -if (abs(bloom) > 0.025) -{ - if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); - Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); - Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); - Bloom1 = Bloom1 * mix(1.0, 2.0-colmx, bloom_dist); - color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); -} + if (abs(bloom) > 0.025) + { + if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); + Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); + Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); + Bloom1 = bcmask*Bloom1 * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); + } - color = min(color, mix(one, cmask1, mclip)); - - if (!interb) color = declip(color, mix(1.0, w3, 0.6)); else w3 = 1.0; + if (!interb) color = declip(min(color,1.0), mix(1.0, w3, 0.6)); if (halation > 0.01) { Bloom = mix(0.5*(Bloom + Bloom*Bloom), 0.75*Bloom*Bloom, colmx); - color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.6)*Bloom*halation; } + color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*halation; } else if (halation < -0.01) { float mbl = max(max(Bloom.r,Bloom.g),Bloom.b); Bloom = plant(Bloom + Ref + orig1 + Bloom*Bloom*Bloom, min(mbl*mbl,0.75)); - color = color + 2.0*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.5)*Bloom*(-halation); } + color = color + 2.0*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*(-halation); } + float w = 0.25 + 0.60*mix(w3, 1.0, sqrt(colmx)); - if (smoothmask > 0.5) { w3 = mix(1.0, w3, smoothstep(0.3, 0.6, mx1)); color = max(min(color/w3, 1.0)*w3, min(color,color*(1.0-w3))); } + if (smoothmask > 0.5) { color = min(color,1.0); color = max(min(color/w3, 1.0)*w3, min(orig1*bb,color*(1.0-w3))); } + - if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, 0.7*colmx); + if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, colmx); else { maxb = max(max(Glow.r,Glow.g),Glow.b); - orig1 = plant(orig1 + 0.001*Ref, 1.0); + vec3 orig2 = plant(orig1 + 0.001*Ref, 1.0); Bloom = plant(Glow, 1.0); - Ref = abs(orig1-Bloom); - mx0 = max(max(orig1.g,orig1.g),orig1.b)-min(min(orig1.g,orig1.g),orig1.b); + Ref = abs(orig2-Bloom); + mx0 = max(max(orig2.g,orig2.g),orig2.b)-min(min(orig2.g,orig2.g),orig2.b); mx2 = max(max(Bloom.g,Bloom.g),Bloom.b)-min(min(Bloom.g,Bloom.g),Bloom.b); - Bloom = mix(maxb*min(Bloom,orig1), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); + Bloom = mix(maxb*min(Bloom,orig2), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); Glow = mix(global.m_glow_low*Glow, global.m_glow_high*Bloom, pow(colmx, global.m_glow_dist/gamma_in)); } - - if (glow >= 0.0 && global.m_glow < 0.5) color = color + 0.5*Glow*glow; - else { if(global.m_glow > 0.5) cmask1 = max(mix(one, cmask1, global.m_glow_mask),0.0); color = color + abs(glow)*cmask1*Glow; } + + if (global.m_glow < 0.5) { + if (glow >= 0.0) color = color + 0.5*Glow*glow; else color = color + abs(glow)*min(cmask2*cmask2,1.0)*Glow; } + else { cmask1 = clamp(mix(one, cmask1, global.m_glow_mask),0.0, 1.0); color = color + abs(glow)*cmask1*Glow; } color = min(color, 1.0); @@ -805,5 +820,8 @@ if (abs(bloom) > 0.025) else color = min(color * mix(1.0, 1.5*noise0.x, 0.5*abs(global.addnoised)), 1.0); } + colmx = max(max(orig1.r,orig1.g),orig1.b); + color = color + bmask*mix(cmask2, 0.125*(1.0-colmx)*color, min(20.0*colmx, 1.0)); + FragColor = vec4(color*vig*humbar(mix(pos.y, pos.x, global.bardir))*global.post_br*corner(pos0), 1.0); } diff --git a/crt/shaders/guest/advanced/gaussian_horizontal.slang b/crt/shaders/guest/advanced/gaussian_horizontal.slang index 3388ff3..859f448 100644 --- a/crt/shaders/guest/advanced/gaussian_horizontal.slang +++ b/crt/shaders/guest/advanced/gaussian_horizontal.slang @@ -58,7 +58,7 @@ layout(push_constant) uniform Push #pragma parameter SIZEH " Horizontal Glow Radius" 6.0 1.0 50.0 1.0 #define SIZEH params.SIZEH -#pragma parameter SIGMA_H " Horizontal Glow Sigma" 1.20 0.20 15.0 0.10 +#pragma parameter SIGMA_H " Horizontal Glow Sigma" 1.20 0.20 15.0 0.05 #define SIGMA_H params.SIGMA_H diff --git a/crt/shaders/guest/advanced/gaussian_vertical.slang b/crt/shaders/guest/advanced/gaussian_vertical.slang index 29da738..024c116 100644 --- a/crt/shaders/guest/advanced/gaussian_vertical.slang +++ b/crt/shaders/guest/advanced/gaussian_vertical.slang @@ -35,7 +35,7 @@ layout(push_constant) uniform Push #pragma parameter SIZEV " Vertical Glow Radius" 6.0 1.0 50.0 1.0 #define SIZEV params.SIZEV -#pragma parameter SIGMA_V " Vertical Glow Sigma" 1.20 0.20 15.0 0.10 +#pragma parameter SIGMA_V " Vertical Glow Sigma" 1.20 0.20 15.0 0.05 #define SIGMA_V params.SIGMA_V layout(std140, set = 0, binding = 0) uniform UBO diff --git a/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade-old.slang b/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade-old.slang new file mode 100644 index 0000000..46bbdfd --- /dev/null +++ b/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade-old.slang @@ -0,0 +1,929 @@ +#version 450 + +layout(push_constant) uniform Push +{ + float g_gamma_in; + float g_gamma_out; + float g_signal_type; + float g_crtgamut; + float g_space_out; + float g_hue_degrees; + float g_I_SHIFT; + float g_Q_SHIFT; + float g_I_MUL; + float g_Q_MUL; + float g_lum_fix; + float g_vignette; + float g_vstr; + float g_vpower; + float g_sat; + float g_vibr; + float g_lum; + float g_cntrst; + float g_mid; + float g_lift; + float blr; + float blg; + float blb; + float wlr; + float wlg; + float wlb; + float rg; + float rb; + float gr; + float gb; + float br; + float bg; +} params; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float wp_temperature; + float g_satr; + float g_satg; + float g_satb; + float LUT_Size1; + float LUT1_toggle; + float LUT_Size2; + float LUT2_toggle; + float AS, asat; +} global; + +/* + Grade + > Ubershader grouping some monolithic color related shaders: + ::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT. + > and the addition of: + ::analogue color emulation, phosphor gamut, color space + TRC support, vibrance, HUE vs SAT, vignette (shared by Syh), black level, rolled gain and sigmoidal contrast. + + Author: Dogway + License: Public domain + + **Thanks to those that helped me out keep motivated by continuous feedback and bug reports: + **Syh, Nesguy, hunterk, and the libretro forum members. + + + ######################################...PRESETS...####################################### + ########################################################################################## + ### ### + ### PAL ### + ### Phosphor: EBU (#3) (or an EBU T3213 based CRT phosphor gamut) ### + ### WP: D65 (6504K) (in practice more like ~7500K) ### + ### TRC: 2.8 SMPTE-C Gamma ### + ### Saturation: -0.02 ### + ### ### + ### NTSC-U ### + ### Phosphor: P22/SMPTE-C (#1 #-1)(or a SMPTE-C based CRT phosphor gamut) ### + ### WP: D65 (6504K) (in practice more like ~7500K) ### + ### TRC: 2.22 SMPTE-C Gamma (in practice more like 2.35-2.55) ### + ### ### + ### NTSC-J (Default) ### + ### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ### + ### WP: 9300K+27MPCD (8942K) (CCT from x:0.281 y:0.311) ### + ### TRC: 2.22 SMPTE-C Gamma (in practice more like 2.35-2.55) ### + ### ### + ### *Despite the standard of 2.22, a more faithful approximation to CRT... ### + ### ...is to use a gamma (SMPTE-C type) with a value of 2.35-2.55. ### + ### ### + ### ### + ########################################################################################## + ########################################################################################## +*/ + +#pragma parameter AS " Afterglow Strength" 0.20 0.0 0.60 0.01 +#define AS global.AS +#pragma parameter asat " Afterglow saturation" 0.33 0.0 1.0 0.01 +#define asat global.asat + + +#pragma parameter g_gamma_in "Game Embedded Gamma" 2.222 1.80 3.0 0.05 +#pragma parameter g_gamma_out "CRT Electron Gun Gamma" 2.50 1.80 3.0 0.05 +#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 1.0 0.0 1.0 1.0 +#pragma parameter g_crtgamut "Phosphor (1:NTSC-U 2:NTSC-J 3:PAL)" 2.0 -4.0 3.0 1.0 +#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:DCI 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0 + +#pragma parameter g_hue_degrees "Hue" 0.0 -360.0 360.0 1.0 +#pragma parameter g_I_SHIFT "I/U Shift" 0.0 -0.2 0.2 0.01 +#pragma parameter g_Q_SHIFT "Q/V Shift" 0.0 -0.2 0.2 0.01 +#pragma parameter g_I_MUL "I/U Multiplier" 1.0 0.0 2.0 0.01 +#pragma parameter g_Q_MUL "Q/V Multiplier" 1.0 0.0 2.0 0.01 +#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0 +#pragma parameter g_vignette "Vignette Toggle" 1.0 0.0 1.0 1.0 +#pragma parameter g_vstr "Vignette Strength" 40.0 0.0 50.0 1.0 +#pragma parameter g_vpower "Vignette Power" 0.20 0.0 0.5 0.01 +#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01 +#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05 +#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01 +#pragma parameter wp_temperature "White Point" 6504.0 5004.0 12004.0 100.0 +#pragma parameter g_sat "Saturation" 0.0 -1.0 2.0 0.01 +#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05 +#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01 +#pragma parameter g_satg "Hue vs Sat Green" 0.0 -1.0 1.0 0.01 +#pragma parameter g_satb "Hue vs Sat Blue" 0.0 -1.0 1.0 0.01 +#pragma parameter g_lift "Black Level" 0.0 -0.5 0.5 0.01 +#pragma parameter blr "Black-Red Tint" 0.0 0.0 1.0 0.01 +#pragma parameter blg "Black-Green Tint" 0.0 0.0 1.0 0.01 +#pragma parameter blb "Black-Blue Tint" 0.0 0.0 1.0 0.01 +#pragma parameter wlr "White-Red Tint" 1.0 0.0 2.0 0.01 +#pragma parameter wlg "White-Green Tint" 1.0 0.0 2.0 0.01 +#pragma parameter wlb "White-Blue Tint" 1.0 0.0 2.0 0.01 +#pragma parameter rg "Red-Green Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter rb "Red-Blue Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter gr "Green-Red Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter gb "Green-Blue Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter br "Blue-Red Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter LUT_Size1 "LUT Size 1" 16.0 8.0 64.0 16.0 +#pragma parameter LUT1_toggle "LUT 1 Toggle" 0.0 0.0 1.0 1.0 +#pragma parameter LUT_Size2 "LUT Size 2" 64.0 0.0 64.0 16.0 +#pragma parameter LUT2_toggle "LUT 2 Toggle" 0.0 0.0 1.0 1.0 + +#define M_PI 3.1415926535897932384626433832795 +#define gamma_in params.g_gamma_in +#define gamma_out params.g_gamma_out +#define signal params.g_signal_type +#define crtgamut params.g_crtgamut +#define SPC params.g_space_out +#define hue_degrees params.g_hue_degrees +#define I_SHIFT params.g_I_SHIFT +#define Q_SHIFT params.g_Q_SHIFT +#define I_MUL params.g_I_MUL +#define Q_MUL params.g_Q_MUL +#define lum_fix params.g_lum_fix +#define vignette params.g_vignette +#define vstr params.g_vstr +#define vpower params.g_vpower +#define g_sat params.g_sat +#define vibr params.g_vibr +#define satr global.g_satr +#define satg global.g_satg +#define satb global.g_satb +#define lum params.g_lum +#define cntrst params.g_cntrst +#define mid params.g_mid +#define lift params.g_lift +#define blr params.blr +#define blg params.blg +#define blb params.blb +#define wlr params.wlr +#define wlg params.wlg +#define wlb params.wlb +#define rg params.rg +#define rb params.rb +#define gr params.gr +#define gb params.gb +#define br params.br +#define bg params.bg + +#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 StockPass; +layout(set = 0, binding = 4) uniform sampler2D AfterglowPass; +layout(set = 0, binding = 5) uniform sampler2D SamplerLUT1; +layout(set = 0, binding = 6) uniform sampler2D SamplerLUT2; + + +///////////////////////// Color Space Transformations ////////////////////////// + + + +vec3 XYZ_to_RGB(vec3 XYZ, float CSPC){ + + // to sRGB + const mat3x3 sRGB = mat3x3( + 3.24081254005432130, -0.969243049621582000, 0.055638398975133896, + -1.53730857372283940, 1.875966310501098600, -0.204007431864738460, + -0.49858659505844116, 0.041555050760507584, 1.057129383087158200); + + // to DCI-P3 -D65- + const mat3x3 DCIP3 = mat3x3( + 2.49339652061462400, -0.82948720455169680, 0.035850685089826584, + -0.93134605884552000, 1.76266026496887200, -0.076182708144187930, + -0.40269458293914795, 0.023624641820788383, 0.957014024257659900); + + // to Rec.2020 + const mat3x3 rec2020 = mat3x3( + 1.71660947799682620, -0.66668272018432620, 0.017642205581068993, + -0.35566213726997375, 1.61647748947143550, -0.042776308953762054, + -0.25336012244224550, 0.01576850563287735, 0.942228555679321300); + + // to AdobeRGB + const mat3x3 Adobe = mat3x3( + 2.0415899753570557, -0.96924000978469850, 0.013439999893307686, + -0.5650100111961365, 1.87597000598907470, -0.118359997868537900, + -0.3447299897670746, 0.04156000167131424, 1.015169978141784700); + + return (CSPC == 3.0) ? Adobe * XYZ : (CSPC == 2.0) ? rec2020 * XYZ : (CSPC == 1.0) ? DCIP3 * XYZ : sRGB * XYZ; +} + +vec3 RGB_to_XYZ(vec3 RGB, float CSPC){ + + // from sRGB + const mat3x3 sRGB = mat3x3( + 0.41241079568862915, 0.21264933049678802, 0.019331756979227066, + 0.35758456587791443, 0.71516913175582890, 0.119194857776165010, + 0.18045382201671600, 0.07218152284622192, 0.950390160083770800); + + // from DCI-P3 -D65- + const mat3x3 DCIP3 = mat3x3( + 0.48659050464630127, 0.22898375988006592, 0.00000000000000000, + 0.26566821336746216, 0.69173991680145260, 0.04511347413063049, + 0.19819043576717377, 0.07927616685628891, 1.04380297660827640); + + // from Rec.2020 + const mat3x3 rec2020 = mat3x3( + 0.63697350025177000, 0.24840137362480164, 0.00000000000000000, + 0.15294560790061950, 0.67799961566925050, 0.04253686964511871, + 0.11785808950662613, 0.03913172334432602, 1.06084382534027100); + + // from AdobeRGB + const mat3x3 Adobe = mat3x3( + 0.57666999101638790, 0.2973400056362152, 0.02703000046312809, + 0.18556000292301178, 0.6273599863052368, 0.07068999856710434, + 0.18822999298572540, 0.0752900019288063, 0.9913399815559387); + + return (CSPC == 3.0) ? Adobe * RGB : (CSPC == 2.0) ? rec2020 * RGB : (CSPC == 1.0) ? DCIP3 * RGB : sRGB * RGB; +} + + +vec3 XYZtoYxy(vec3 XYZ){ + + float XYZrgb = XYZ.r+XYZ.g+XYZ.b; + float Yxyg = (XYZrgb <= 0.0) ? 0.3805 : XYZ.r / XYZrgb; + float Yxyb = (XYZrgb <= 0.0) ? 0.3769 : XYZ.g / XYZrgb; + return vec3(XYZ.g, Yxyg, Yxyb); +} + +vec3 YxytoXYZ(vec3 Yxy){ + + float Xs = Yxy.r * (Yxy.g/Yxy.b); + float Xsz = (Yxy.r <= 0.0) ? 0.0 : 1.0; + vec3 XYZ = vec3(Xsz,Xsz,Xsz) * vec3(Xs, Yxy.r, (Xs/Yxy.g)-Xs-Yxy.r); + return XYZ; +} + +///////////////////////// White Point Mapping ///////////////////////// +// +// +// PAL: D65 NTSC-U: D65 NTSC-J: CCT NTSC-J NTSC-FCC: C +// PAL: 6504K NTSC-U: 6504K NTSC-J: 8942K NTSC-FCC: 6780K +// 0.3127 0.3290 0.3127 0.3290 0.281 0.311 0.310 0.316 + +vec3 wp_adjust(float temperature, vec3 color){ + + float temp3 = pow(10.,3.) / temperature; + float temp6 = pow(10.,6.) / pow(temperature, 2.); + float temp9 = pow(10.,9.) / pow(temperature, 3.); + + vec3 wp = vec3(1.); + + wp.x = (temperature <= 7000.) ? 0.244063 + 0.09911 * temp3 + 2.9678 * temp6 - 4.6070 * temp9 : \ + 0.237040 + 0.24748 * temp3 + 1.9018 * temp6 - 2.0064 * temp9 ; + + wp.y = -3.000 * pow(wp.x,2.) + 2.870 * wp.x - 0.275; + wp.z = 1. - wp.x - wp.y; + + const mat3x3 CAT02 = mat3x3( + 0.7328, 0.4296, -0.1624, + -0.70360, 1.6975, 0.0061, + 0.003, -0.0136, 0.9834); + + vec3 fw_trans = (vec3(wp.x/wp.y,1.,wp.z/wp.y) * CAT02) / (vec3(0.95045,1.,1.088917) * CAT02) ; + + return color.xyz * fw_trans.xyz ; + +} + +//////////////////////////////////////////////////////////////////////////////// + + +// Monitor Curve Functions: https://github.com/ampas/aces-dev +//---------------------------------------------------------------------- + + +float moncurve_f( float color, float gamma, float offs) +{ + // Forward monitor curve + color = clamp(color, 0.0, 1.0); + float fs = (( gamma - 1.0) / offs) * pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma); + float xb = offs / ( gamma - 1.0); + + color = ( color > xb) ? pow( ( color + offs) / ( 1.0 + offs), gamma) : color * fs; + return color; +} + + +vec3 moncurve_f_f3( vec3 color, float gamma, float offs) +{ + color.r = moncurve_f( color.r, gamma, offs); + color.g = moncurve_f( color.g, gamma, offs); + color.b = moncurve_f( color.b, gamma, offs); + return color.rgb; +} + + +float moncurve_r( float color, float gamma, float offs) +{ + // Reverse monitor curve + color = clamp(color, 0.0, 1.0); + float yb = pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma); + float rs = pow( ( gamma - 1.0) / offs, gamma - 1.0) * pow( ( 1.0 + offs) / gamma, gamma); + + color = ( color > yb) ? ( 1.0 + offs) * pow( color, 1.0 / gamma) - offs : color * rs; + return color; +} + + +vec3 moncurve_r_f3( vec3 color, float gamma, float offs) +{ + color.r = moncurve_r( color.r, gamma, offs); + color.g = moncurve_r( color.g, gamma, offs); + color.b = moncurve_r( color.b, gamma, offs); + return color.rgb; +} + + +//-------------------------- Luma Functions ---------------------------- + + +// Performs better in gamma encoded space +float contrast_sigmoid(float color, float cont, float pivot){ + + cont = pow(cont + 1., 3.); + + float knee = 1. / (1. + exp(cont * pivot)); + float shldr = 1. / (1. + exp(cont * (pivot - 1.))); + + color = (1. / (1. + exp(cont * (pivot - color))) - knee) / (shldr - knee); + + return color; +} + + +// Performs better in gamma encoded space +float contrast_sigmoid_inv(float color, float cont, float pivot){ + + cont = pow(cont - 1., 3.); + + float knee = 1. / (1. + exp (cont * pivot)); + float shldr = 1. / (1. + exp (cont * (pivot - 1.))); + + color = pivot - log(1. / (color * (shldr - knee) + knee) - 1.) / cont; + + return color; +} + + +float rolled_gain(float color, float gain){ + + float gx = abs(gain) + 0.001; + float anch = (gain > 0.0) ? 0.5 / (gx / 2.0) : 0.5 / gx; + color = (gain > 0.0) ? color * ((color - anch) / (1 - anch)) : color * ((1 - anch) / (color - anch)) * (1 - gain); + + return color; +} + + +vec4 rolled_gain_v4(vec4 color, float gain){ + + color.r = rolled_gain(color.r, gain); + color.g = rolled_gain(color.g, gain); + color.b = rolled_gain(color.b, gain); + + return vec4(color.rgb, 1.0); +} + + +float SatMask(float color_r, float color_g, float color_b) +{ + float max_rgb = max(color_r, max(color_g, color_b)); + float min_rgb = min(color_r, min(color_g, color_b)); + float msk = clamp((max_rgb - min_rgb) / (max_rgb + min_rgb), 0.0, 1.0); + return msk; +} + + +// This shouldn't be necessary but it seems some undefined values can +// creep in and each GPU vendor handles that differently. This keeps +// all values within a safe range +vec3 mixfix(vec3 a, vec3 b, float c) +{ + return (a.z < 1.0) ? mix(a, b, c) : a; +} + + +vec4 mixfix_v4(vec4 a, vec4 b, float c) +{ + return (a.z < 1.0) ? mix(a, b, c) : a; +} + + +//---------------------- Range Expansion/Compression ------------------- + + +// to Studio Swing/Broadcast Safe/SMPTE legal/Limited Range +vec3 PCtoTV(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing, bool rgb_in) +{ + col *= 255.; + Umax = (max_swing == 1.0) ? Umax * 224. : Umax * 239.; + Vmax = (max_swing == 1.0) ? Vmax * 224. : Vmax * 239.; + + col.x = (luma_swing == 1.0) ? ((col.x * 219.) / 255.) + 16. : col.x; + col.y = (rgb_in == true) ? ((col.y * 219.) / 255.) + 16. : (((col.y - 128.) * (Umax * 2.)) / 255.) + Umax; + col.z = (rgb_in == true) ? ((col.z * 219.) / 255.) + 16. : (((col.z - 128.) * (Vmax * 2.)) / 255.) + Vmax; + return col.xyz / 255.; +} + + +// to Full Swing/Full Range +vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing, bool rgb_in) +{ + col *= 255.; + Umax = (max_swing == 1.0) ? Umax * 224. : Umax * 239.; + Vmax = (max_swing == 1.0) ? Vmax * 224. : Vmax * 239.; + + float colx = (luma_swing == 1.0) ? ((col.x - 16.) / 219.) * 255. : col.x; + float coly = (rgb_in == true) ? ((col.y - 16.) / 219.) * 255. : (((col.y - Umax) / (Umax * 2.)) * 255.) + 128.; + float colz = (rgb_in == true) ? ((col.z - 16.) / 219.) * 255. : (((col.z - Vmax) / (Vmax * 2.)) * 255.) + 128.; + return vec3(colx,coly,colz) / 255.; +} + + +//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ + + +//--------------------- ITU-R BT.470/601 (M) (1953) -------------------- + + +// FCC (Sanctioned) YIQ matrix +vec3 RGB_FCC(vec3 col) + { + const mat3 conv_mat = mat3( + 0.299996928307425, 0.590001575542717, 0.110001496149858, + 0.599002392519453, -0.277301256521204, -0.321701135998249, + 0.213001700342824, -0.525101205289350, 0.312099504946526); + + return col.rgb * conv_mat; + } + +// FCC (Sanctioned) YIQ matrix (inverse) +vec3 FCC_RGB(vec3 col) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.946882217090069, 0.623556581986143, + 1.0000000, -0.274787646298978, -0.635691079187380, + 1.0000000, -1.108545034642030, 1.709006928406470); + + return col.rgb * conv_mat; + } + + +//--------------------- SMPTE RP 145 (C), 170M (1987) ------------------ + + +vec3 RGB_YIQ(vec3 col) + { + const mat3 conv_mat = mat3( + 0.2990, 0.5870, 0.1140, + 0.5959, -0.2746, -0.3213, + 0.2115, -0.5227, 0.3112); + + return col.rgb * conv_mat; + } + +vec3 YIQ_RGB(vec3 col) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.956, 0.619, + 1.0000000, -0.272, -0.647, + 1.0000000, -1.106, 1.703); + + return col.rgb * conv_mat; + } + +//----------------------- ITU-R BT.470/601 (B/G) ----------------------- + + +vec3 r601_YUV(vec3 RGB) + { + const mat3 conv_mat = mat3( + 0.299000, 0.587000, 0.114000, + -0.147407, -0.289391, 0.436798, + 0.614777, -0.514799, -0.099978); + + return RGB.rgb * conv_mat; + } + +vec3 YUV_r601(vec3 RGB) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.00000000000000000, 1.14025080204010000, + 1.0000000, -0.39393067359924316, -0.58080917596817020, + 1.0000000, 2.02839756011962900, -0.00000029356581166); + + return RGB.rgb * conv_mat; + } + +// Custom - not Standard +vec3 YUV_r709(vec3 YUV) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.0000000000000000, 1.14025092124938960, + 1.0000000, -0.2047683298587799, -0.33895039558410645, + 1.0000001, 2.0283975601196290, 0.00000024094399364); + + return YUV.rgb * conv_mat; + } + +// Custom - not Standard +vec3 r709_YUV(vec3 RGB) + { + const mat3 conv_mat = mat3( + 0.2126000, 0.715200, 0.0722000, + -0.1048118, -0.3525936, 0.4574054, + 0.6905498, -0.6272304, -0.0633194); + + return RGB.rgb * conv_mat; + } + + +//------------------------- SMPTE-240M Y’PbPr -------------------------- + + +// Umax 0.886 +// Vmax 0.700 +// RGB to YPbPr -full to limited range- with Rec.601 primaries +vec3 r601_YCC(vec3 RGB) + { + const mat3 conv_mat = mat3( + 0.299, 0.587, 0.114, + -0.16873589164785553047, -0.33126410835214446953, 0.500, + 0.500, -0.41868758915834522111, -0.08131241084165477889); + + return RGB.rgb * conv_mat; + } + +// YPbPr to RGB -limited to full range- with Rec.601 primaries +vec3 YCC_r601(vec3 YUV) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.000, 1.402, + 1.0000000, -0.34413628620102214651, -0.71413628620102214651, + 1.0000000, 1.772, 0.000); + + return YUV.rgb * conv_mat; + } + +// Umax 0.53890924768269023496443198965294 +// Vmax 0.63500127000254000508001016002032 +// RGB to YPbPr -full range in-gamut- with Rec.709 primaries +vec3 r709_YCC(vec3 RGB) + { + const mat3 conv_mat = mat3( + 0.2126, 0.7152, 0.0722, + -0.11457210605733994395, -0.38542789394266005605, 0.5000, + 0.5000, -0.45415290830581661163, -0.04584709169418338837); + + return RGB.rgb * conv_mat; + } + +// YPbPr to RGB -full range in-gamut- with Rec.709 primaries +vec3 YCC_r709(vec3 YUV) + { + const mat3 conv_mat = mat3( + 1.0000000, 0.00000000000000000000, 1.5748, + 1.0000000, -0.18732427293064876957, -0.46812427293064876957, + 1.0000000, 1.8556, 0.00000000000000000000); + + return YUV.rgb * conv_mat; + } + + +//------------------------- IPT -------------------------- + + +const mat3 LMS = +mat3( + 0.4002, 0.7076, -0.0808, +-0.2263, 1.1653, 0.0457, + 0.0, 0.0, 0.9182); + +const mat3 IPT = +mat3( + 0.4000, 0.4000, 0.2000, + 4.4550, -4.8510, 0.3960, + 0.8056, 0.3572, -1.1628); + + + +//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ + + +// ITU-R BT.470/601 (M) (proof of concept, actually never used) +// SMPTE 170M-1999 +// NTSC-FCC 1953 Standard Phosphor (use with temperature C: 6780K) +const mat3 NTSC_FCC_transform = +mat3( + 0.60699284076690670, 0.2989666163921356, 0.00000000000000000, + 0.17344850301742554, 0.5864211320877075, 0.06607561558485031, + 0.20057128369808197, 0.1146121546626091, 1.11746847629547120); + +// ITU-R BT.470/601 (M) +// Conrac 7211N19 CRT Phosphor +const mat3 Conrac_transform = +mat3( + 0.55842006206512450, 0.28580552339553833, 0.03517606481909752, + 0.20613566040992737, 0.63714659214019780, 0.09369802474975586, + 0.18589359521865845, 0.07704800367355347, 0.96004259586334230); + +// NTSC-J (use with D93 white point) +// Sony Trinitron KV-20M20 +const mat3 Sony20_20_transform = +mat3( + 0.33989441394805910, 0.18490256369113922, 0.019034087657928467, + 0.33497872948646545, 0.71182984113693240, 0.149544075131416320, + 0.22866378724575043, 0.10326752066612244, 1.143318891525268600); + +// SMPTE-C - Measured Average Phosphor (1979-1994) +const mat3 P22_transform = +mat3( + 0.4665636420249939, 0.25661000609397890, 0.005832045804709196, + 0.3039233088493347, 0.66820019483566280, 0.105618737637996670, + 0.1799621731042862, 0.07518967241048813, 0.977465748786926300); + +// SMPTE RP 145-1994 (SMPTE-C), 170M-1999 +// SMPTE-C - Standard Phosphor (Rec.601 NTSC) +const mat3 SMPTE_transform = +mat3( + 0.39354196190834045, 0.21238772571086884, 0.01874009333550930, + 0.36525884270668030, 0.70106136798858640, 0.11193416267633438, + 0.19164848327636720, 0.08655092865228653, 0.95824241638183590); + +// SMPTE RP 145-1994 (SMPTE-C), 170M-1999 +// NTSC-J - Standard Phosphor (https://web.archive.org/web/20130413104152/http://arib.or.jp/english/html/overview/doc/4-TR-B09v1_0.pdf) +const mat3 NTSC_J_transform = +mat3( + 0.39603787660598755, 0.22429330646991730, 0.02050681784749031, + 0.31201449036598206, 0.67417418956756590, 0.12814880907535553, + 0.24496731162071228, 0.10153251141309738, 1.26512730121612550); + +// ITU-R BT.470/601 (B/G) +// EBU Tech.3213-E PAL - Standard Phosphor for Studio Monitors +const mat3 EBU_transform = +mat3( + 0.43194326758384705, 0.22272075712680817, 0.020247340202331543, + 0.34123489260673523, 0.70600330829620360, 0.129433929920196530, + 0.17818950116634370, 0.07127580046653748, 0.938464701175689700); + + + + +//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ + + + + + +void main() +{ + + vec4 imgColor = texture(StockPass, vTexCoord.xy); + vec4 aftglow = texture(AfterglowPass, vTexCoord.xy); + + float w = 1.0-aftglow.w; + + float l = length(aftglow.rgb); + aftglow.rgb = AS*w*normalize(pow(aftglow.rgb + 0.01, vec3(asat)))*l; + + +// Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations. + float lum_exp = (lum_fix == 1.0) ? (255./239.) : 1.; + + // vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp; + vec3 src = imgColor.rgb * lum_exp; + +// Assumes framebuffer in Rec.601 with baked gamma +// make a YUV * NTSC Phosphor option too and a FCC * NTSC phosphor + vec3 col = (crtgamut == 3.0) ? r601_YUV(src) : \ + (crtgamut == 2.0) ? RGB_YIQ(src) : \ + (crtgamut == -3.0) ? RGB_FCC(src) : \ + (crtgamut == -4.0) ? RGB_FCC(src) : \ + RGB_YIQ(src) ; + + +// Clipping Logic / Gamut Limiting + vec2 UVmax = (crtgamut == 3.0) ? vec2(0.436798, 0.614777) : \ + (crtgamut == -4.0) ? vec2(0.599002392519453, 0.52510120528935) : \ + (crtgamut == -3.0) ? vec2(0.599002392519453, 0.52510120528935) : \ + vec2(0.5959, 0.5227) ; + + col = clamp(col.xyz, vec3(0.0, -UVmax.x, -UVmax.y), vec3(1.0, UVmax.x, UVmax.y)); + + + col = (crtgamut == 3.0) ? col : \ + (crtgamut == 2.0) ? col : \ + (crtgamut == -3.0) ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ + (crtgamut == -4.0) ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ + PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) ; + + +// YIQ/YUV Analogue Color Controls (HUE + Color Shift + Color Burst) + float hue_radians = hue_degrees * (M_PI / 180.0); + float hue = atan(col.z, col.y) + hue_radians; + float chroma = sqrt(col.z * col.z + col.y * col.y); + col = vec3(col.x, chroma * cos(hue), chroma * sin(hue)); + + col.y = (mod((col.y + 1.0) + I_SHIFT, 2.0) - 1.0) * I_MUL; + col.z = (mod((col.z + 1.0) + Q_SHIFT, 2.0) - 1.0) * Q_MUL; + + +// Back to RGB + col = (crtgamut == 3.0) ? col : \ + (crtgamut == 2.0) ? col : \ + (crtgamut == -3.0) ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ + (crtgamut == -4.0) ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ + TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) ; + + col = (crtgamut == 3.0) ? YUV_r601(col) : \ + (crtgamut == 2.0) ? YIQ_RGB(col) : \ + (crtgamut == -3.0) ? FCC_RGB(col) : \ + (crtgamut == -4.0) ? FCC_RGB(col) : \ + YIQ_RGB(col) ; + +// Gamut Limiting + col = r601_YCC(clamp(col, 0., 1.)); + col = (signal == 0.0) ? src : YCC_r601(clamp(col, vec3(0.0, -.886,-.700), vec3(1.0, .886,.700))); + + +// Developer baked CRT gamma (2.20 - 2.25) + col = moncurve_f_f3(col, gamma_in, 0.099); + +// CRT Phosphor Gamut + mat3 m_in; + + if (crtgamut == -4.0) { m_in = NTSC_FCC_transform; } else + if (crtgamut == -3.0) { m_in = Conrac_transform; } else + if (crtgamut == -2.0) { m_in = Sony20_20_transform; } else + if (crtgamut == -1.0) { m_in = SMPTE_transform; } else + if (crtgamut == 1.0) { m_in = P22_transform; } else + if (crtgamut == 2.0) { m_in = NTSC_J_transform; } else + if (crtgamut == 3.0) { m_in = EBU_transform; } + + vec3 gamut = m_in*col; + +// White Point Mapping + vec3 wp = (crtgamut == -4.0) ? wp_adjust(global.wp_temperature - (6404. - 6504.), gamut) : \ + (crtgamut == -3.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ + (crtgamut == -2.0) ? wp_adjust(global.wp_temperature - (7600. - 6504.), gamut) : \ + (crtgamut == -1.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ + (crtgamut == 1.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ + (crtgamut == 2.0) ? wp_adjust(global.wp_temperature - (7400. - 6504.), gamut) : \ + (crtgamut == 3.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ + wp_adjust(global.wp_temperature, gamut) ; + + vec3 adj = clamp(XYZ_to_RGB(wp, SPC), 0., 1.); + + +// Guest Emulated CRT Electron Gun gamma (2.35 - 2.50) (phosphor gamma brings it up back to ~2.222) + adj = moncurve_r_f3(crtgamut == 0.0 ? col : adj, pow(gamma_in, 2.) / gamma_out, 0.099); + + +// Look LUT - (in SPC space) + float red = (adj.r * (global.LUT_Size1 - 1.0) + 0.4999) / (global.LUT_Size1 * global.LUT_Size1); + float green = (adj.g * (global.LUT_Size1 - 1.0) + 0.4999) / global.LUT_Size1; + float blue1 = (floor(adj.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; + float blue2 = (ceil(adj.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; + float mixer = clamp(max((adj.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0); + vec3 color1 = texture(SamplerLUT1, vec2(blue1, green)).rgb; + vec3 color2 = texture(SamplerLUT1, vec2(blue2, green)).rgb; + vec3 vcolor = (global.LUT1_toggle == 0.0) ? adj : mixfix(color1, color2, mixer); + + + +// OETF - Opto-Electronic Transfer Function (Rec.709 does a Dim to Dark Surround adaptation) + vcolor = (SPC == 3.0) ? clamp(pow(vcolor, vec3(563./256.)), 0., 1.) : \ + (SPC == 2.0) ? moncurve_f_f3(vcolor, 2.20 + 0.022222, 0.0993) : \ + (SPC == 1.0) ? clamp(pow(vcolor, vec3(2.20 + 0.40)), 0., 1.) : \ + (SPC == 0.0) ? moncurve_f_f3(vcolor, 2.20 + 0.20, 0.0550) : \ + clamp(pow(pow(vcolor, vec3(1./1.019264)), vec3(2.20 + 0.20)), 0., 1.) ; + + + vcolor = RGB_to_XYZ(vcolor, SPC); + + +// Sigmoidal Contrast + vec3 Yxy = XYZtoYxy(vcolor); + float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0., 1.); + toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma; + float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid); + vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b); + vec3 XYZsrgb = clamp(XYZ_to_RGB(YxytoXYZ(contrast), SPC), 0., 1.); + contrast = (cntrst == 0.0) ? XYZ_to_RGB(vcolor, SPC) : XYZsrgb; + + +// Vignetting & Black Level + vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy); + + vpos *= 1.0 - vpos.xy; + float vig = vpos.x * vpos.y * vstr; + vig = min(pow(vig, vpower), 1.0); + contrast *= (vignette == 1.0) ? vig : 1.0; + + contrast += (lift / 20.0) * (1.0 - contrast); + + +// RGB Related Transforms + vec4 screen = vec4(max(contrast, 0.0), 1.0); + float sat = g_sat + 1.0; + + // r g b alpha ; alpha does nothing for our purposes + mat4 color = mat4(wlr, rg, rb, 0.0, //red tint + gr, wlg, gb, 0.0, //green tint + br, bg, wlb, 0.0, //blue tint + blr/20., blg/20., blb/20., 0.0); //black tint + + + vec3 coeff = (SPC == 3.0) ? vec3(0.29734000563621520, 0.62735998630523680, 0.07529000192880630) : \ + (SPC == 2.0) ? vec3(0.24840137362480164, 0.67799961566925050, 0.03913172334432602) : \ + (SPC == 1.0) ? vec3(0.22898375988006592, 0.69173991680145260, 0.07927616685628891) : \ + vec3(0.21264933049678802, 0.71516913175582890, 0.07218152284622192) ; + + + mat3 adjust = mat3((1.0 - sat) * coeff.x + sat, (1.0 - sat) * coeff.x, (1.0 - sat) * coeff.x, + (1.0 - sat) * coeff.y, (1.0 - sat) * coeff.y + sat, (1.0 - sat) * coeff.y, + (1.0 - sat) * coeff.z, (1.0 - sat) * coeff.z, (1.0 - sat) * coeff.z + sat); + + + screen = clamp(rolled_gain_v4(screen, clamp(lum, -0.49, 0.99)), 0., 1.); + screen = color * screen; + +// HUE vs SAT + vec3 src_h = RGB_to_XYZ(screen.rgb, SPC) * LMS; + src_h.x = src_h.x >= 0.0 ? pow(src_h.x, 0.43) : -pow(-src_h.x, 0.43); + src_h.y = src_h.y >= 0.0 ? pow(src_h.y, 0.43) : -pow(-src_h.y, 0.43); + src_h.z = src_h.z >= 0.0 ? pow(src_h.z, 0.43) : -pow(-src_h.z, 0.43); + + src_h.xyz *= IPT; + + float hue_at = atan(src_h.z, src_h.y); + chroma = sqrt(src_h.z * src_h.z + src_h.y * src_h.y); + + float hue_radians_r = -40.0 * (M_PI / 180.0); + float hue_r = chroma * cos(hue_at + hue_radians_r) * 2.; + + float hue_radians_g = 230.0 * (M_PI / 180.0); + float hue_g = chroma * cos(hue_at + hue_radians_g) * 2.; + + float hue_radians_b = 100.0 * (M_PI / 180.0); + float hue_b = chroma * cos(hue_at + hue_radians_b) * 2.; + + float msk = dot(clamp(vec3(hue_r, hue_g, hue_b), 0., 1.), vec3(satr, satg, satb)*(-1.)); + src_h = mixfix(screen.rgb, vec3(dot(coeff, screen.rgb)), msk); + + float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \ + 1.0 - (SatMask(src_h.x, src_h.y, src_h.z) * vibr) ; + + src_h = mixfix(src_h, clamp(adjust * src_h, 0., 1.), clamp(sat_msk, 0., 1.)); + + +// EOTF - Electro-Optical Transfer Function (Rec.709 does a Dim to Dark Surround adaptation) + vec3 TRC = (SPC == 3.0) ? clamp(pow(src_h, vec3(1./(563./256.))), 0., 1.) : \ + (SPC == 2.0) ? moncurve_r_f3(src_h, 2.20 + 0.022222, 0.0993) : \ + (SPC == 1.0) ? clamp(pow(src_h, vec3(1./(2.20 + 0.40))), 0., 1.) : \ + (SPC == 0.0) ? moncurve_r_f3(src_h, 2.20 + 0.20, 0.0550) : \ + clamp(pow(pow(src_h, vec3(1.019264)), vec3(1./(2.20 + 0.20))), 0., 1.) ; + + +// Technical LUT - (in SPC space) + float red_2 = (TRC.r * (global.LUT_Size2 - 1.0) + 0.4999) / (global.LUT_Size2 * global.LUT_Size2); + float green_2 = (TRC.g * (global.LUT_Size2 - 1.0) + 0.4999) / global.LUT_Size2; + float blue1_2 = (floor(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; + float blue2_2 = (ceil(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; + float mixer_2 = clamp(max((TRC.b - blue1_2) / (blue2_2 - blue1_2), 0.0), 0.0, 32.0); + vec3 color1_2 = texture(SamplerLUT2, vec2(blue1_2, green_2)).rgb; + vec3 color2_2 = texture(SamplerLUT2, vec2(blue2_2, green_2)).rgb; + vec3 LUT2_output = mixfix(color1_2, color2_2, mixer_2); + + LUT2_output = (global.LUT2_toggle == 0.0) ? TRC : LUT2_output; + + + FragColor = vec4(LUT2_output + aftglow.rgb, 1.0); +} \ No newline at end of file diff --git a/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade.slang b/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade.slang index 46bbdfd..ff4d485 100644 --- a/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade.slang +++ b/crt/shaders/guest/advanced/grade/pre-shaders-afterglow-grade.slang @@ -1,19 +1,41 @@ #version 450 +/* + Grade - CRT emulation and color manipulation shader + + Copyright (C) 2020-2023 Dogway (Jose Linares) + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + layout(push_constant) uniform Push { - float g_gamma_in; - float g_gamma_out; float g_signal_type; float g_crtgamut; float g_space_out; float g_hue_degrees; - float g_I_SHIFT; - float g_Q_SHIFT; - float g_I_MUL; - float g_Q_MUL; + float g_U_SHIFT; + float g_V_SHIFT; + float g_U_MUL; + float g_V_MUL; + float g_CRT_b; + float g_CRT_c; + float g_CRT_l; float g_lum_fix; - float g_vignette; float g_vstr; float g_vpower; float g_sat; @@ -43,10 +65,20 @@ layout(std140, set = 0, binding = 0) uniform UBO vec4 OriginalSize; vec4 OutputSize; uint FrameCount; + float g_vignette; + float g_Dark_to_Dim; + float g_GCompress; float wp_temperature; + float g_CRT_br; + float g_CRT_bg; + float g_CRT_bb; + float g_CRT_rf; + float g_CRT_sl; float g_satr; float g_satg; float g_satb; + float g_digital; + float g_analog; float LUT_Size1; float LUT1_toggle; float LUT_Size2; @@ -55,111 +87,122 @@ layout(std140, set = 0, binding = 0) uniform UBO } global; /* - Grade + Grade (16-06-2023) + > See settings decriptions at: https://forums.libretro.com/t/dogways-grading-shader-slang/27148/442 + > Ubershader grouping some monolithic color related shaders: ::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT. > and the addition of: ::analogue color emulation, phosphor gamut, color space + TRC support, vibrance, HUE vs SAT, vignette (shared by Syh), black level, rolled gain and sigmoidal contrast. - Author: Dogway - License: Public domain - **Thanks to those that helped me out keep motivated by continuous feedback and bug reports: **Syh, Nesguy, hunterk, and the libretro forum members. - ######################################...PRESETS...####################################### + #####################################...STANDARDS...###################################### ########################################################################################## ### ### ### PAL ### - ### Phosphor: EBU (#3) (or an EBU T3213 based CRT phosphor gamut) ### - ### WP: D65 (6504K) (in practice more like ~7500K) ### - ### TRC: 2.8 SMPTE-C Gamma ### + ### Phosphor: 470BG (#3) ### + ### WP: D65 (6504K) (in practice more like 7000K-7500K range) ### ### Saturation: -0.02 ### ### ### ### NTSC-U ### - ### Phosphor: P22/SMPTE-C (#1 #-1)(or a SMPTE-C based CRT phosphor gamut) ### - ### WP: D65 (6504K) (in practice more like ~7500K) ### - ### TRC: 2.22 SMPTE-C Gamma (in practice more like 2.35-2.55) ### + ### Phosphor: P22/SMPTE-C (#1 #-3)(or a SMPTE-C based CRT phosphor gamut) ### + ### WP: D65 (6504K) (in practice more like 7000K-7500K range) ### ### ### ### NTSC-J (Default) ### ### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ### - ### WP: 9300K+27MPCD (8942K) (CCT from x:0.281 y:0.311) ### - ### TRC: 2.22 SMPTE-C Gamma (in practice more like 2.35-2.55) ### - ### ### - ### *Despite the standard of 2.22, a more faithful approximation to CRT... ### - ### ...is to use a gamma (SMPTE-C type) with a value of 2.35-2.55. ### + ### WP: 9300K+27MPCD (8945K) (CCT from x:0.281 y:0.311)(in practice ~8500K)### ### ### ### ### ########################################################################################## ########################################################################################## */ + #pragma parameter AS " Afterglow Strength" 0.20 0.0 0.60 0.01 #define AS global.AS #pragma parameter asat " Afterglow saturation" 0.33 0.0 1.0 0.01 #define asat global.asat -#pragma parameter g_gamma_in "Game Embedded Gamma" 2.222 1.80 3.0 0.05 -#pragma parameter g_gamma_out "CRT Electron Gun Gamma" 2.50 1.80 3.0 0.05 -#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 1.0 0.0 1.0 1.0 -#pragma parameter g_crtgamut "Phosphor (1:NTSC-U 2:NTSC-J 3:PAL)" 2.0 -4.0 3.0 1.0 -#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:DCI 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0 +#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 1.0 0.0 1.0 1.0 +#pragma parameter g_crtgamut "Phosphor (-2:CRT-95s -1:P22-80s 1:P22-90s 2:NTSC-J 3:PAL)" 2.0 -3.0 3.0 1.0 +#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:P3-D65 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0 +#pragma parameter g_Dark_to_Dim "Dark to Dim adaptation" 1.0 0.0 1.0 1.0 +#pragma parameter g_GCompress "Gamut Compression" 1.0 0.0 1.0 1.0 -#pragma parameter g_hue_degrees "Hue" 0.0 -360.0 360.0 1.0 -#pragma parameter g_I_SHIFT "I/U Shift" 0.0 -0.2 0.2 0.01 -#pragma parameter g_Q_SHIFT "Q/V Shift" 0.0 -0.2 0.2 0.01 -#pragma parameter g_I_MUL "I/U Multiplier" 1.0 0.0 2.0 0.01 -#pragma parameter g_Q_MUL "Q/V Multiplier" 1.0 0.0 2.0 0.01 -#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0 -#pragma parameter g_vignette "Vignette Toggle" 1.0 0.0 1.0 1.0 -#pragma parameter g_vstr "Vignette Strength" 40.0 0.0 50.0 1.0 -#pragma parameter g_vpower "Vignette Power" 0.20 0.0 0.5 0.01 -#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01 -#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05 -#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01 -#pragma parameter wp_temperature "White Point" 6504.0 5004.0 12004.0 100.0 -#pragma parameter g_sat "Saturation" 0.0 -1.0 2.0 0.01 -#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05 -#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01 -#pragma parameter g_satg "Hue vs Sat Green" 0.0 -1.0 1.0 0.01 -#pragma parameter g_satb "Hue vs Sat Blue" 0.0 -1.0 1.0 0.01 -#pragma parameter g_lift "Black Level" 0.0 -0.5 0.5 0.01 -#pragma parameter blr "Black-Red Tint" 0.0 0.0 1.0 0.01 -#pragma parameter blg "Black-Green Tint" 0.0 0.0 1.0 0.01 -#pragma parameter blb "Black-Blue Tint" 0.0 0.0 1.0 0.01 -#pragma parameter wlr "White-Red Tint" 1.0 0.0 2.0 0.01 -#pragma parameter wlg "White-Green Tint" 1.0 0.0 2.0 0.01 -#pragma parameter wlb "White-Blue Tint" 1.0 0.0 2.0 0.01 -#pragma parameter rg "Red-Green Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter rb "Red-Blue Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter gr "Green-Red Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter gb "Green-Blue Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter br "Blue-Red Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005 -#pragma parameter LUT_Size1 "LUT Size 1" 16.0 8.0 64.0 16.0 -#pragma parameter LUT1_toggle "LUT 1 Toggle" 0.0 0.0 1.0 1.0 -#pragma parameter LUT_Size2 "LUT Size 2" 64.0 0.0 64.0 16.0 -#pragma parameter LUT2_toggle "LUT 2 Toggle" 0.0 0.0 1.0 1.0 +// Analogue controls +#pragma parameter g_analog "// ANALOG CONTROLS //" 0.0 0.0 1.0 1.0 +#pragma parameter wp_temperature "White Point" 8504.0 5004.0 12004.0 100.0 +#pragma parameter g_hue_degrees "CRT Hue" 0.0 -180.0 180.0 1.0 +#pragma parameter g_U_SHIFT "CRT U Shift" 0.0 -0.2 0.2 0.01 +#pragma parameter g_V_SHIFT "CRT V Shift" 0.0 -0.2 0.2 0.01 +#pragma parameter g_U_MUL "CRT U Multiplier" 1.0 0.0 2.0 0.01 +#pragma parameter g_V_MUL "CRT V Multiplier" 1.0 0.0 2.0 0.01 +#pragma parameter g_CRT_l "CRT Gamma" 2.50 2.30 2.60 0.01 +#pragma parameter g_CRT_b "CRT Brightness" 50.0 0.0 100.0 1.0 +#pragma parameter g_CRT_c "CRT Contrast" 50.0 0.0 100.0 1.0 +#pragma parameter g_CRT_br "CRT Beam Red" 1.0 0.0 1.2 0.01 +#pragma parameter g_CRT_bg "CRT Beam Green" 1.0 0.0 1.2 0.01 +#pragma parameter g_CRT_bb "CRT Beam Blue" 1.0 0.0 1.2 0.01 +#pragma parameter g_CRT_rf "CRT Lambert Refl. in %" 5.0 2.0 5.0 0.1 +#pragma parameter g_CRT_sl "Surround Luminance -nits-" 34.0 0.0 100.0 1.0 +#pragma parameter g_vignette "Vignette Toggle" 1.0 0.0 1.0 1.0 +#pragma parameter g_vstr "Vignette Strength" 50.0 0.0 50.0 1.0 +#pragma parameter g_vpower "Vignette Power" 0.50 0.0 0.5 0.01 -#define M_PI 3.1415926535897932384626433832795 -#define gamma_in params.g_gamma_in -#define gamma_out params.g_gamma_out +// Digital controls +#pragma parameter g_digital "// DIGITAL CONTROLS //" 0.0 0.0 1.0 1.0 +#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0 +#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01 +#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05 +#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01 +#pragma parameter g_sat "Saturation" 0.0 -1.0 1.0 0.01 +#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05 +#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01 +#pragma parameter g_satg "Hue vs Sat Green" 0.0 -1.0 1.0 0.01 +#pragma parameter g_satb "Hue vs Sat Blue" 0.0 -1.0 1.0 0.01 +#pragma parameter g_lift "Black Level" 0.0 -0.5 0.5 0.01 +#pragma parameter blr "Black-Red Tint" 0.0 0.0 1.0 0.01 +#pragma parameter blg "Black-Green Tint" 0.0 0.0 1.0 0.01 +#pragma parameter blb "Black-Blue Tint" 0.0 0.0 1.0 0.01 +#pragma parameter wlr "White-Red Tint" 1.0 0.0 2.0 0.01 +#pragma parameter wlg "White-Green Tint" 1.0 0.0 2.0 0.01 +#pragma parameter wlb "White-Blue Tint" 1.0 0.0 2.0 0.01 +#pragma parameter rg "Red-Green Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter rb "Red-Blue Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter gr "Green-Red Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter gb "Green-Blue Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter br "Blue-Red Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005 +#pragma parameter LUT_Size1 "LUT Size 1" 32.0 8.0 64.0 16.0 +#pragma parameter LUT1_toggle "LUT 1 Toggle" 0.0 0.0 1.0 1.0 +#pragma parameter LUT_Size2 "LUT Size 2" 64.0 0.0 64.0 16.0 +#pragma parameter LUT2_toggle "LUT 2 Toggle" 0.0 0.0 1.0 1.0 + +#define M_PI 3.1415926535897932384626433832795/180.0 +#define RW vec3(0.950457397565471, 1.0, 1.089436035930324) #define signal params.g_signal_type #define crtgamut params.g_crtgamut #define SPC params.g_space_out #define hue_degrees params.g_hue_degrees -#define I_SHIFT params.g_I_SHIFT -#define Q_SHIFT params.g_Q_SHIFT -#define I_MUL params.g_I_MUL -#define Q_MUL params.g_Q_MUL +#define U_SHIFT params.g_U_SHIFT +#define V_SHIFT params.g_V_SHIFT +#define U_MUL params.g_U_MUL +#define V_MUL params.g_V_MUL +#define CRT_l -(100000.*log((72981.-500000./(3.*max(2.3,params.g_CRT_l)))/9058.))/945461. #define lum_fix params.g_lum_fix -#define vignette params.g_vignette +#define vignette global.g_vignette +#define GCompress global.g_GCompress #define vstr params.g_vstr #define vpower params.g_vpower #define g_sat params.g_sat #define vibr params.g_vibr +#define beamr global.g_CRT_br +#define beamg global.g_CRT_bg +#define beamb global.g_CRT_bb #define satr global.g_satr #define satg global.g_satg #define satb global.g_satb @@ -201,147 +244,169 @@ layout(set = 0, binding = 5) uniform sampler2D SamplerLUT1; layout(set = 0, binding = 6) uniform sampler2D SamplerLUT2; + + + + ///////////////////////// Color Space Transformations ////////////////////////// +// 'D65' based +mat3 RGB_to_XYZ_mat(mat3 primaries) { + + vec3 T = RW * inverse(primaries); + + mat3 TB = mat3( + T.x, 0.0, 0.0, + 0.0, T.y, 0.0, + 0.0, 0.0, T.z); + + return TB * primaries; + } -vec3 XYZ_to_RGB(vec3 XYZ, float CSPC){ +vec3 RGB_to_XYZ(vec3 RGB, mat3 primaries) { - // to sRGB - const mat3x3 sRGB = mat3x3( - 3.24081254005432130, -0.969243049621582000, 0.055638398975133896, - -1.53730857372283940, 1.875966310501098600, -0.204007431864738460, - -0.49858659505844116, 0.041555050760507584, 1.057129383087158200); + return RGB * RGB_to_XYZ_mat(primaries); + } - // to DCI-P3 -D65- - const mat3x3 DCIP3 = mat3x3( - 2.49339652061462400, -0.82948720455169680, 0.035850685089826584, - -0.93134605884552000, 1.76266026496887200, -0.076182708144187930, - -0.40269458293914795, 0.023624641820788383, 0.957014024257659900); +vec3 XYZ_to_RGB(vec3 XYZ, mat3 primaries) { - // to Rec.2020 - const mat3x3 rec2020 = mat3x3( - 1.71660947799682620, -0.66668272018432620, 0.017642205581068993, - -0.35566213726997375, 1.61647748947143550, -0.042776308953762054, - -0.25336012244224550, 0.01576850563287735, 0.942228555679321300); - - // to AdobeRGB - const mat3x3 Adobe = mat3x3( - 2.0415899753570557, -0.96924000978469850, 0.013439999893307686, - -0.5650100111961365, 1.87597000598907470, -0.118359997868537900, - -0.3447299897670746, 0.04156000167131424, 1.015169978141784700); - - return (CSPC == 3.0) ? Adobe * XYZ : (CSPC == 2.0) ? rec2020 * XYZ : (CSPC == 1.0) ? DCIP3 * XYZ : sRGB * XYZ; -} - -vec3 RGB_to_XYZ(vec3 RGB, float CSPC){ - - // from sRGB - const mat3x3 sRGB = mat3x3( - 0.41241079568862915, 0.21264933049678802, 0.019331756979227066, - 0.35758456587791443, 0.71516913175582890, 0.119194857776165010, - 0.18045382201671600, 0.07218152284622192, 0.950390160083770800); - - // from DCI-P3 -D65- - const mat3x3 DCIP3 = mat3x3( - 0.48659050464630127, 0.22898375988006592, 0.00000000000000000, - 0.26566821336746216, 0.69173991680145260, 0.04511347413063049, - 0.19819043576717377, 0.07927616685628891, 1.04380297660827640); - - // from Rec.2020 - const mat3x3 rec2020 = mat3x3( - 0.63697350025177000, 0.24840137362480164, 0.00000000000000000, - 0.15294560790061950, 0.67799961566925050, 0.04253686964511871, - 0.11785808950662613, 0.03913172334432602, 1.06084382534027100); - - // from AdobeRGB - const mat3x3 Adobe = mat3x3( - 0.57666999101638790, 0.2973400056362152, 0.02703000046312809, - 0.18556000292301178, 0.6273599863052368, 0.07068999856710434, - 0.18822999298572540, 0.0752900019288063, 0.9913399815559387); - - return (CSPC == 3.0) ? Adobe * RGB : (CSPC == 2.0) ? rec2020 * RGB : (CSPC == 1.0) ? DCIP3 * RGB : sRGB * RGB; -} + return XYZ * inverse(RGB_to_XYZ_mat(primaries)); + } -vec3 XYZtoYxy(vec3 XYZ){ +vec3 XYZtoYxy(vec3 XYZ) { float XYZrgb = XYZ.r+XYZ.g+XYZ.b; float Yxyg = (XYZrgb <= 0.0) ? 0.3805 : XYZ.r / XYZrgb; float Yxyb = (XYZrgb <= 0.0) ? 0.3769 : XYZ.g / XYZrgb; return vec3(XYZ.g, Yxyg, Yxyb); -} + } -vec3 YxytoXYZ(vec3 Yxy){ +vec3 YxytoXYZ(vec3 Yxy) { float Xs = Yxy.r * (Yxy.g/Yxy.b); float Xsz = (Yxy.r <= 0.0) ? 0.0 : 1.0; vec3 XYZ = vec3(Xsz,Xsz,Xsz) * vec3(Xs, Yxy.r, (Xs/Yxy.g)-Xs-Yxy.r); return XYZ; -} + } + ///////////////////////// White Point Mapping ///////////////////////// // // -// PAL: D65 NTSC-U: D65 NTSC-J: CCT NTSC-J NTSC-FCC: C -// PAL: 6504K NTSC-U: 6504K NTSC-J: 8942K NTSC-FCC: 6780K -// 0.3127 0.3290 0.3127 0.3290 0.281 0.311 0.310 0.316 +// PAL: D65 NTSC-U: D65 NTSC-J: CCT 9300K+27MPCD +// PAL: 6503.512K NTSC-U: 6503.512K NTSC-J: ~8945.436K +// [x:0.31266142 y:0.3289589] [x:0.281 y:0.311] -vec3 wp_adjust(float temperature, vec3 color){ +// For NTSC-J there's not a common agreed value, measured consumer units span from 8229.87K to 8945.623K with accounts for 8800K as well. +// Recently it's been standardized to 9300K which is closer to what master monitors (and not consumer units) were (x=0.2838 y=0.2984) (~9177.98K) - float temp3 = pow(10.,3.) / temperature; - float temp6 = pow(10.,6.) / pow(temperature, 2.); - float temp9 = pow(10.,9.) / pow(temperature, 3.); +// "RGB to XYZ -> Temperature -> XYZ to RGB" joint matrix +vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) { + + float temp3 = 1000. / temperature; + float temp6 = 1000000. / pow(temperature, 2.); + float temp9 = 1000000000. / pow(temperature, 3.); vec3 wp = vec3(1.); - wp.x = (temperature <= 7000.) ? 0.244063 + 0.09911 * temp3 + 2.9678 * temp6 - 4.6070 * temp9 : \ - 0.237040 + 0.24748 * temp3 + 1.9018 * temp6 - 2.0064 * temp9 ; + wp.x = (temperature < 5500.) ? 0.244058 + 0.0989971 * temp3 + 2.96545 * temp6 - 4.59673 * temp9 : \ + (temperature < 8000.) ? 0.200033 + 0.9545630 * temp3 - 2.53169 * temp6 + 7.08578 * temp9 : \ + 0.237045 + 0.2437440 * temp3 + 1.94062 * temp6 - 2.11004 * temp9 ; - wp.y = -3.000 * pow(wp.x,2.) + 2.870 * wp.x - 0.275; + wp.y = -0.275275 + 2.87396 * wp.x - 3.02034 * pow(wp.x,2) + 0.0297408 * pow(wp.x,3); wp.z = 1. - wp.x - wp.y; - const mat3x3 CAT02 = mat3x3( - 0.7328, 0.4296, -0.1624, - -0.70360, 1.6975, 0.0061, - 0.003, -0.0136, 0.9834); + const mat3 CAT16 = mat3( + 0.401288,-0.250268, -0.002079, + 0.650173, 1.204414, 0.048952, + -0.051461, 0.045854, 0.953127); - vec3 fw_trans = (vec3(wp.x/wp.y,1.,wp.z/wp.y) * CAT02) / (vec3(0.95045,1.,1.088917) * CAT02) ; + vec3 VKV = (vec3(wp.x/wp.y,1.,wp.z/wp.y) * CAT16) / (RW * CAT16); - return color.xyz * fw_trans.xyz ; + mat3 VK = mat3( + VKV.x, 0.0, 0.0, + 0.0, VKV.y, 0.0, + 0.0, 0.0, VKV.z); + + mat3 CAM = CAT16 * (VK * inverse(CAT16)); + + mat3 mata = RGB_to_XYZ_mat(primaries); + mat3 matb = RGB_to_XYZ_mat(display); + + return RGB.rgb * ((mata * CAM) * inverse(matb)); + } -} //////////////////////////////////////////////////////////////////////////////// +// CRT EOTF Function +//---------------------------------------------------------------------- + +float EOTF_1886a(float color, float bl, float brightness, float contrast) { + + // Defaults: + // Black Level = 0.1 + // Brightness = 0 + // Contrast = 100 + + const float wl = 100.0; + float b = pow(bl, 1/2.4); + float a = pow(wl, 1/2.4)-b; + b = (brightness-50) / 250. + b/a; // -0.20 to +0.20 + a = contrast!=50 ? pow(2,(contrast-50)/50.) : 1.; // 0.50 to +2.00 + + const float Vc = 0.35; // Offset + float Lw = wl/100. * a; // White level + float Lb = min( b * a,Vc); // Black level + const float a1 = 2.6; // Shoulder gamma + const float a2 = 3.0; // Knee gamma + float k = Lw /pow(1 + Lb, a1); + float sl = k * pow(Vc + Lb, a1-a2); // Slope for knee gamma + + color = color >= Vc ? k * pow(color + Lb, a1 ) : sl * pow(color + Lb, a2 ); + return color; + } + +vec3 EOTF_1886a_f3( vec3 color, float BlackLevel, float brightness, float contrast) { + + color.r = EOTF_1886a( color.r, BlackLevel, brightness, contrast); + color.g = EOTF_1886a( color.g, BlackLevel, brightness, contrast); + color.b = EOTF_1886a( color.b, BlackLevel, brightness, contrast); + return color.rgb; + } + + + // Monitor Curve Functions: https://github.com/ampas/aces-dev //---------------------------------------------------------------------- -float moncurve_f( float color, float gamma, float offs) -{ +float moncurve_f( float color, float gamma, float offs) { + // Forward monitor curve - color = clamp(color, 0.0, 1.0); + color = clamp(color, 0.0, 1.0); float fs = (( gamma - 1.0) / offs) * pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma); float xb = offs / ( gamma - 1.0); color = ( color > xb) ? pow( ( color + offs) / ( 1.0 + offs), gamma) : color * fs; return color; -} + } -vec3 moncurve_f_f3( vec3 color, float gamma, float offs) -{ +vec3 moncurve_f_f3( vec3 color, float gamma, float offs) { + color.r = moncurve_f( color.r, gamma, offs); color.g = moncurve_f( color.g, gamma, offs); color.b = moncurve_f( color.b, gamma, offs); return color.rgb; -} + } -float moncurve_r( float color, float gamma, float offs) -{ +float moncurve_r( float color, float gamma, float offs) { + // Reverse monitor curve color = clamp(color, 0.0, 1.0); float yb = pow( offs * gamma / ( ( gamma - 1.0) * ( 1.0 + offs)), gamma); @@ -349,282 +414,257 @@ float moncurve_r( float color, float gamma, float offs) color = ( color > yb) ? ( 1.0 + offs) * pow( color, 1.0 / gamma) - offs : color * rs; return color; -} + } -vec3 moncurve_r_f3( vec3 color, float gamma, float offs) -{ +vec3 moncurve_r_f3( vec3 color, float gamma, float offs) { + color.r = moncurve_r( color.r, gamma, offs); color.g = moncurve_r( color.g, gamma, offs); color.b = moncurve_r( color.b, gamma, offs); return color.rgb; -} + } //-------------------------- Luma Functions ---------------------------- // Performs better in gamma encoded space -float contrast_sigmoid(float color, float cont, float pivot){ +float contrast_sigmoid(float color, float cont, float pivot) { cont = pow(cont + 1., 3.); - float knee = 1. / (1. + exp(cont * pivot)); + float knee = 1. / (1. + exp(cont * pivot)); float shldr = 1. / (1. + exp(cont * (pivot - 1.))); - color = (1. / (1. + exp(cont * (pivot - color))) - knee) / (shldr - knee); + color =(1. / (1. + exp(cont * (pivot - color))) - knee) / (shldr - knee); return color; -} + } // Performs better in gamma encoded space -float contrast_sigmoid_inv(float color, float cont, float pivot){ +float contrast_sigmoid_inv(float color, float cont, float pivot) { cont = pow(cont - 1., 3.); - float knee = 1. / (1. + exp (cont * pivot)); + float knee = 1. / (1. + exp (cont * pivot)); float shldr = 1. / (1. + exp (cont * (pivot - 1.))); color = pivot - log(1. / (color * (shldr - knee) + knee) - 1.) / cont; return color; -} + } -float rolled_gain(float color, float gain){ +float rolled_gain(float color, float gain) { - float gx = abs(gain) + 0.001; + float gx = abs(gain) + 0.001; float anch = (gain > 0.0) ? 0.5 / (gx / 2.0) : 0.5 / gx; - color = (gain > 0.0) ? color * ((color - anch) / (1 - anch)) : color * ((1 - anch) / (color - anch)) * (1 - gain); + color = (gain > 0.0) ? color * ((color - anch) / (1 - anch)) : color * ((1 - anch) / (color - anch)) * (1 - gain); return color; -} + } -vec4 rolled_gain_v4(vec4 color, float gain){ +vec3 rolled_gain_v3(vec3 color, float gain) { color.r = rolled_gain(color.r, gain); color.g = rolled_gain(color.g, gain); color.b = rolled_gain(color.b, gain); - return vec4(color.rgb, 1.0); -} + return color.rgb; + } -float SatMask(float color_r, float color_g, float color_b) -{ +float SatMask(float color_r, float color_g, float color_b) { + float max_rgb = max(color_r, max(color_g, color_b)); float min_rgb = min(color_r, min(color_g, color_b)); float msk = clamp((max_rgb - min_rgb) / (max_rgb + min_rgb), 0.0, 1.0); return msk; -} + } // This shouldn't be necessary but it seems some undefined values can // creep in and each GPU vendor handles that differently. This keeps // all values within a safe range -vec3 mixfix(vec3 a, vec3 b, float c) -{ +vec3 mixfix(vec3 a, vec3 b, float c) { return (a.z < 1.0) ? mix(a, b, c) : a; -} + } -vec4 mixfix_v4(vec4 a, vec4 b, float c) -{ +vec4 mixfix_v4(vec4 a, vec4 b, float c) { return (a.z < 1.0) ? mix(a, b, c) : a; -} + } -//---------------------- Range Expansion/Compression ------------------- + +//---------------------- Gamut Compression ------------------- -// to Studio Swing/Broadcast Safe/SMPTE legal/Limited Range -vec3 PCtoTV(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing, bool rgb_in) -{ - col *= 255.; - Umax = (max_swing == 1.0) ? Umax * 224. : Umax * 239.; - Vmax = (max_swing == 1.0) ? Vmax * 224. : Vmax * 239.; +// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress) +vec3 GamutCompression (vec3 rgb, float grey) { - col.x = (luma_swing == 1.0) ? ((col.x * 219.) / 255.) + 16. : col.x; - col.y = (rgb_in == true) ? ((col.y * 219.) / 255.) + 16. : (((col.y - 128.) * (Umax * 2.)) / 255.) + Umax; - col.z = (rgb_in == true) ? ((col.z * 219.) / 255.) + 16. : (((col.z - 128.) * (Vmax * 2.)) / 255.) + Vmax; - return col.xyz / 255.; -} + // Limit/Thres order is Cyan, Magenta, Yellow + vec3 beam = max(vec3(0.0),vec3(beamg,(beamb+beamr)/2,(beamr+beamg)/2)); + vec3 sat = max(vec3(0.0),vec3(satg, (satb +satr) /2,(satr +satg) /2)+1); // center at 1 + float temp = max(0,abs(global.wp_temperature-7000)-1000)/825.0+1; // center at 1 + vec3 WPD = global.wp_temperature < 7000 ? vec3(1,temp,(temp-1)/2+1) : vec3((temp-1)/2+1,temp,1); + sat = max(0.0,g_sat+1)*(sat*beam) * WPD; + mat2x3 LimThres = mat2x3( 0.100000,0.100000,0.100000, + 0.125000,0.125000,0.125000); + if (SPC < 1.0) { -// to Full Swing/Full Range -vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing, bool rgb_in) -{ - col *= 255.; - Umax = (max_swing == 1.0) ? Umax * 224. : Umax * 239.; - Vmax = (max_swing == 1.0) ? Vmax * 224. : Vmax * 239.; + LimThres = \ + crtgamut == 3.0 ? mat2x3( 0.000000,0.044065,0.000000, + 0.000000,0.095638,0.000000) : \ + crtgamut == 2.0 ? mat2x3( 0.006910,0.092133,0.000000, + 0.039836,0.121390,0.000000) : \ + crtgamut == 1.0 ? mat2x3( 0.018083,0.059489,0.017911, + 0.066570,0.105996,0.066276) : \ + crtgamut ==-1.0 ? mat2x3( 0.014947,0.098571,0.017911, + 0.060803,0.123793,0.066276) : \ + crtgamut ==-2.0 ? mat2x3( 0.004073,0.030307,0.012697, + 0.028222,0.083075,0.056029) : \ + crtgamut ==-3.0 ? mat2x3( 0.018424,0.053469,0.016841, + 0.067146,0.102294,0.064393) : LimThres; + } else if (SPC==1.0) { + + LimThres = \ + crtgamut == 3.0 ? mat2x3( 0.000000,0.234229,0.007680, + 0.000000,0.154983,0.042446) : \ + crtgamut == 2.0 ? mat2x3( 0.078526,0.108432,0.006143, + 0.115731,0.127194,0.037039) : \ + crtgamut == 1.0 ? mat2x3( 0.021531,0.237184,0.013466, + 0.072018,0.155438,0.057731) : \ + crtgamut ==-1.0 ? mat2x3( 0.051640,0.103332,0.013550, + 0.101092,0.125474,0.057912) : \ + crtgamut ==-2.0 ? mat2x3( 0.032717,0.525361,0.023928, + 0.085609,0.184491,0.075381) : \ + crtgamut ==-3.0 ? mat2x3( 0.000000,0.377522,0.043076, + 0.000000,0.172390,0.094873) : LimThres; + } + + // Amount of outer gamut to affect + vec3 th = 1.0-vec3(LimThres[1])*(0.4*sat+0.3); + + // Distance limit: How far beyond the gamut boundary to compress + vec3 dl = 1.0+vec3(LimThres[0])*sat; + + // Calculate scale so compression function passes through distance limit: (x=dl, y=1) + vec3 s = (vec3(1)-th)/sqrt(max(vec3(1.001), dl)-1.0); + + // Achromatic axis + float ac = max(rgb.x, max(rgb.y, rgb.z)); + + // Inverse RGB Ratios: distance from achromatic axis + vec3 d = ac==0.0?vec3(0.0):(ac-rgb)/abs(ac); + + // Compressed distance. Parabolic compression function: https://www.desmos.com/calculator/nvhp63hmtj + vec3 cd; + vec3 sf = s*sqrt(d-th+s*s/4.0)-s*sqrt(s*s/4.0)+th; + cd.x = (d.x < th.x) ? d.x : sf.x; + cd.y = (d.y < th.y) ? d.y : sf.y; + cd.z = (d.z < th.z) ? d.z : sf.z; + + // Inverse RGB Ratios to RGB + // and Mask with "luma" + return mix(rgb, ac-cd.xyz*abs(ac), pow(grey,1/params.g_CRT_l)); + } - float colx = (luma_swing == 1.0) ? ((col.x - 16.) / 219.) * 255. : col.x; - float coly = (rgb_in == true) ? ((col.y - 16.) / 219.) * 255. : (((col.y - Umax) / (Umax * 2.)) * 255.) + 128.; - float colz = (rgb_in == true) ? ((col.z - 16.) / 219.) * 255. : (((col.z - Vmax) / (Vmax * 2.)) * 255.) + 128.; - return vec3(colx,coly,colz) / 255.; -} //*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ -//--------------------- ITU-R BT.470/601 (M) (1953) -------------------- + +// Matrices in column-major -// FCC (Sanctioned) YIQ matrix -vec3 RGB_FCC(vec3 col) - { - const mat3 conv_mat = mat3( - 0.299996928307425, 0.590001575542717, 0.110001496149858, - 0.599002392519453, -0.277301256521204, -0.321701135998249, - 0.213001700342824, -0.525101205289350, 0.312099504946526); +//----------------------- Y'UV color model ----------------------- - return col.rgb * conv_mat; - } -// FCC (Sanctioned) YIQ matrix (inverse) -vec3 FCC_RGB(vec3 col) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.946882217090069, 0.623556581986143, - 1.0000000, -0.274787646298978, -0.635691079187380, - 1.0000000, -1.108545034642030, 1.709006928406470); +// 0-235 YUV PAL +// 0-235 YUV NTSC-J +// 16-235 YUV NTSC - return col.rgb * conv_mat; + +// Bymax 0.885515 +// Rymax 0.701088 +// R'G'B' full range to Decorrelated Intermediate (Y,B-Y,R-Y) +// Rows should sum to 0, except first one which sums 1 +const mat3 YByRy = + mat3( + 0.298912, 0.586603, 0.114485, + -0.298912,-0.586603, 0.885515, + 0.701088,-0.586603,-0.114485); + + +// Umax 0.435812284313725 +// Vmax 0.615857694117647 +// R'G'B' full to Y'UV limited +// YUV is defined with headroom and footroom (TV range), +// UV excursion is limited to Umax and Vmax +// Y excursion is limited to 16-235 for NTSC-U and 0-235 for PAL and NTSC-J +vec3 r601_YUV(vec3 RGB, float NTSC_U) { + + const float sclU = ((0.5*(235-16)+16)/255.); // This yields Luma grey at around 0.49216 or 125.5 in 8-bit + const float sclV = (240-16) /255. ; // This yields Chroma range at around 0.87843 or 224 in 8-bit + + mat3 conv_mat = mat3( + vec3(YByRy[0]), + vec3(sclU) * vec3(YByRy[1]), + vec3(sclV) * vec3(YByRy[2])); + +// -0.147111592156863 -0.288700692156863 0.435812284313725 +// 0.615857694117647 -0.515290478431373 -0.100567215686275 + + vec3 YUV = RGB.rgb * conv_mat; + YUV.x = NTSC_U==1.0 ? YUV.x * 219.0 + 16.0 : YUV.x * 235.0; + return vec3(YUV.x/255.0,YUV.yz); } -//--------------------- SMPTE RP 145 (C), 170M (1987) ------------------ +// Y'UV limited to R'G'B' full +vec3 YUV_r601(vec3 YUV, float NTSC_U) { +const mat3 conv_mat = mat3( + 1.0000000, -0.000000029378826483, 1.1383928060531616, + 1.0000000, -0.396552562713623050, -0.5800843834877014, + 1.0000000, 2.031872510910034000, 0.0000000000000000); -vec3 RGB_YIQ(vec3 col) - { - const mat3 conv_mat = mat3( - 0.2990, 0.5870, 0.1140, - 0.5959, -0.2746, -0.3213, - 0.2115, -0.5227, 0.3112); - - return col.rgb * conv_mat; - } - -vec3 YIQ_RGB(vec3 col) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.956, 0.619, - 1.0000000, -0.272, -0.647, - 1.0000000, -1.106, 1.703); - - return col.rgb * conv_mat; - } - -//----------------------- ITU-R BT.470/601 (B/G) ----------------------- - - -vec3 r601_YUV(vec3 RGB) - { - const mat3 conv_mat = mat3( - 0.299000, 0.587000, 0.114000, - -0.147407, -0.289391, 0.436798, - 0.614777, -0.514799, -0.099978); - - return RGB.rgb * conv_mat; - } - -vec3 YUV_r601(vec3 RGB) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.00000000000000000, 1.14025080204010000, - 1.0000000, -0.39393067359924316, -0.58080917596817020, - 1.0000000, 2.02839756011962900, -0.00000029356581166); - - return RGB.rgb * conv_mat; - } - -// Custom - not Standard -vec3 YUV_r709(vec3 YUV) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.0000000000000000, 1.14025092124938960, - 1.0000000, -0.2047683298587799, -0.33895039558410645, - 1.0000001, 2.0283975601196290, 0.00000024094399364); - - return YUV.rgb * conv_mat; - } - -// Custom - not Standard -vec3 r709_YUV(vec3 RGB) - { - const mat3 conv_mat = mat3( - 0.2126000, 0.715200, 0.0722000, - -0.1048118, -0.3525936, 0.4574054, - 0.6905498, -0.6272304, -0.0633194); - - return RGB.rgb * conv_mat; + YUV.x = (YUV.x - (NTSC_U == 1.0 ? 16.0/255.0 : 0.0 )) * (255.0/(NTSC_U == 1.0 ? 219.0 : 235.0)); + return YUV.xyz * conv_mat; } -//------------------------- SMPTE-240M Y’PbPr -------------------------- - - -// Umax 0.886 -// Vmax 0.700 -// RGB to YPbPr -full to limited range- with Rec.601 primaries -vec3 r601_YCC(vec3 RGB) - { - const mat3 conv_mat = mat3( - 0.299, 0.587, 0.114, - -0.16873589164785553047, -0.33126410835214446953, 0.500, - 0.500, -0.41868758915834522111, -0.08131241084165477889); - - return RGB.rgb * conv_mat; +// FP32 to 8-bit mid-tread uniform quantization +float Quantize8(float col) { + col = min(255.0,floor(col * 255.0 + 0.5)); + return col; } -// YPbPr to RGB -limited to full range- with Rec.601 primaries -vec3 YCC_r601(vec3 YUV) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.000, 1.402, - 1.0000000, -0.34413628620102214651, -0.71413628620102214651, - 1.0000000, 1.772, 0.000); - - return YUV.rgb * conv_mat; - } - -// Umax 0.53890924768269023496443198965294 -// Vmax 0.63500127000254000508001016002032 -// RGB to YPbPr -full range in-gamut- with Rec.709 primaries -vec3 r709_YCC(vec3 RGB) - { - const mat3 conv_mat = mat3( - 0.2126, 0.7152, 0.0722, - -0.11457210605733994395, -0.38542789394266005605, 0.5000, - 0.5000, -0.45415290830581661163, -0.04584709169418338837); - - return RGB.rgb * conv_mat; - } - -// YPbPr to RGB -full range in-gamut- with Rec.709 primaries -vec3 YCC_r709(vec3 YUV) - { - const mat3 conv_mat = mat3( - 1.0000000, 0.00000000000000000000, 1.5748, - 1.0000000, -0.18732427293064876957, -0.46812427293064876957, - 1.0000000, 1.8556, 0.00000000000000000000); - - return YUV.rgb * conv_mat; +vec3 Quantize8_f3(vec3 col) { + col.r = Quantize8(col.r); + col.g = Quantize8(col.g); + col.b = Quantize8(col.b); + return col.rgb; } -//------------------------- IPT -------------------------- + +//------------------------- LMS -------------------------- +// Hunt-Pointer-Estevez D65 cone response +// modification for IPT model const mat3 LMS = mat3( - 0.4002, 0.7076, -0.0808, --0.2263, 1.1653, 0.0457, - 0.0, 0.0, 0.9182); + 0.4002, 0.7075, -0.0807, +-0.2280, 1.1500, 0.0612, + 0.0000, 0.0000, 0.9184); const mat3 IPT = mat3( @@ -633,65 +673,99 @@ mat3( 0.8056, 0.3572, -1.1628); - //*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ -// ITU-R BT.470/601 (M) (proof of concept, actually never used) -// SMPTE 170M-1999 -// NTSC-FCC 1953 Standard Phosphor (use with temperature C: 6780K) -const mat3 NTSC_FCC_transform = -mat3( - 0.60699284076690670, 0.2989666163921356, 0.00000000000000000, - 0.17344850301742554, 0.5864211320877075, 0.06607561558485031, - 0.20057128369808197, 0.1146121546626091, 1.11746847629547120); - -// ITU-R BT.470/601 (M) -// Conrac 7211N19 CRT Phosphor -const mat3 Conrac_transform = -mat3( - 0.55842006206512450, 0.28580552339553833, 0.03517606481909752, - 0.20613566040992737, 0.63714659214019780, 0.09369802474975586, - 0.18589359521865845, 0.07704800367355347, 0.96004259586334230); - -// NTSC-J (use with D93 white point) -// Sony Trinitron KV-20M20 -const mat3 Sony20_20_transform = -mat3( - 0.33989441394805910, 0.18490256369113922, 0.019034087657928467, - 0.33497872948646545, 0.71182984113693240, 0.149544075131416320, - 0.22866378724575043, 0.10326752066612244, 1.143318891525268600); - -// SMPTE-C - Measured Average Phosphor (1979-1994) -const mat3 P22_transform = -mat3( - 0.4665636420249939, 0.25661000609397890, 0.005832045804709196, - 0.3039233088493347, 0.66820019483566280, 0.105618737637996670, - 0.1799621731042862, 0.07518967241048813, 0.977465748786926300); +//----------------------- Phosphor Gamuts ----------------------- +////// STANDARDS /////// // SMPTE RP 145-1994 (SMPTE-C), 170M-1999 // SMPTE-C - Standard Phosphor (Rec.601 NTSC) -const mat3 SMPTE_transform = -mat3( - 0.39354196190834045, 0.21238772571086884, 0.01874009333550930, - 0.36525884270668030, 0.70106136798858640, 0.11193416267633438, - 0.19164848327636720, 0.08655092865228653, 0.95824241638183590); - -// SMPTE RP 145-1994 (SMPTE-C), 170M-1999 -// NTSC-J - Standard Phosphor (https://web.archive.org/web/20130413104152/http://arib.or.jp/english/html/overview/doc/4-TR-B09v1_0.pdf) -const mat3 NTSC_J_transform = -mat3( - 0.39603787660598755, 0.22429330646991730, 0.02050681784749031, - 0.31201449036598206, 0.67417418956756590, 0.12814880907535553, - 0.24496731162071228, 0.10153251141309738, 1.26512730121612550); +// ILLUMINANT: D65->[0.31266142,0.3289589] +const mat3 SMPTE170M_ph = + mat3( + 0.630, 0.310, 0.155, + 0.340, 0.595, 0.070, + 0.030, 0.095, 0.775); // ITU-R BT.470/601 (B/G) -// EBU Tech.3213-E PAL - Standard Phosphor for Studio Monitors -const mat3 EBU_transform = -mat3( - 0.43194326758384705, 0.22272075712680817, 0.020247340202331543, - 0.34123489260673523, 0.70600330829620360, 0.129433929920196530, - 0.17818950116634370, 0.07127580046653748, 0.938464701175689700); +// EBU Tech.3213 PAL - Standard Phosphor for Studio Monitors +// ILLUMINANT: D65->[0.31266142,0.3289589] +const mat3 SMPTE470BG_ph = + mat3( + 0.640, 0.290, 0.150, + 0.330, 0.600, 0.060, + 0.030, 0.110, 0.790); + +// NTSC-J P22 +// Mix between averaging KV-20M20, KDS VS19, Dell D93, 4-TR-B09v1_0.pdf and Phosphor Handbook 'P22' +// ILLUMINANT: D93->[0.281000,0.311000] (CCT of 8945.436K) +// ILLUMINANT: D97->[0.285000,0.285000] (CCT of 9696K) for Nanao MS-2930s series (around 10000.0K for wp_adjust() daylight fit) +const mat3 P22_J_ph = + mat3( + 0.625, 0.280, 0.152, + 0.350, 0.605, 0.062, + 0.025, 0.115, 0.786); + + + +////// P22 /////// +// You can run any of these P22 primaries either through D65 or D93 indistinctly but typically these were D65 based. +// P22_80 is roughly the same as the old P22 gamut in Grade 2020. P22 1979-1994 meta measurement. +// ILLUMINANT: D65->[0.31266142,0.3289589] +const mat3 P22_80s_ph = + mat3( + 0.6470, 0.2820, 0.1472, + 0.3430, 0.6200, 0.0642, + 0.0100, 0.0980, 0.7886); + +// P22 improved with tinted phosphors (Use this for NTSC-U 16-bits, and above for 8-bits) +const mat3 P22_90s_ph = + mat3( + 0.6661, 0.3134, 0.1472, + 0.3329, 0.6310, 0.0642, + 0.0010, 0.0556, 0.7886); + +// RPTV (Rear Projection TV) for NTSC-U late 90s, early 00s +const mat3 RPTV_95s_ph = + mat3( + 0.640, 0.341, 0.150, + 0.335, 0.586, 0.070, + 0.025, 0.073, 0.780); + + +//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/ + + +//----------------------- Display Primaries ----------------------- + +// sRGB (IEC 61966-2-1) and ITU-R BT.709-6 (originally CCIR Rec.709) +const mat3 sRGB_prims = + mat3( + 0.640, 0.300, 0.150, + 0.330, 0.600, 0.060, + 0.030, 0.100, 0.790); + +// Adobe RGB (1998) +const mat3 Adobe_prims = + mat3( + 0.640, 0.210, 0.150, + 0.330, 0.710, 0.060, + 0.030, 0.080, 0.790); + +// BT-2020/BT-2100 (from 630nm, 532nm and 467nm) +const mat3 rec2020_prims = + mat3( + 0.707917792, 0.170237195, 0.131370635, + 0.292027109, 0.796518542, 0.045875976, + 0.000055099, 0.033244263, 0.822753389); + +// SMPTE RP 432-2 (DCI-P3) +const mat3 DCIP3_prims = + mat3( + 0.680, 0.265, 0.150, + 0.320, 0.690, 0.060, + 0.000, 0.045, 0.790); @@ -701,10 +775,11 @@ mat3( - void main() { +// Afterglow code for guest-advanced compatibility + vec4 imgColor = texture(StockPass, vTexCoord.xy); vec4 aftglow = texture(AfterglowPass, vTexCoord.xy); @@ -712,147 +787,58 @@ void main() float l = length(aftglow.rgb); aftglow.rgb = AS*w*normalize(pow(aftglow.rgb + 0.01, vec3(asat)))*l; - - + + // Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations. - float lum_exp = (lum_fix == 1.0) ? (255./239.) : 1.; - - // vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp; - vec3 src = imgColor.rgb * lum_exp; - -// Assumes framebuffer in Rec.601 with baked gamma -// make a YUV * NTSC Phosphor option too and a FCC * NTSC phosphor - vec3 col = (crtgamut == 3.0) ? r601_YUV(src) : \ - (crtgamut == 2.0) ? RGB_YIQ(src) : \ - (crtgamut == -3.0) ? RGB_FCC(src) : \ - (crtgamut == -4.0) ? RGB_FCC(src) : \ - RGB_YIQ(src) ; + float lum_exp = (lum_fix == 1.0) ? (255.0/239.0) : 1.0; + vec3 src = texture(StockPass, vTexCoord.xy).rgb * lum_exp; // Clipping Logic / Gamut Limiting - vec2 UVmax = (crtgamut == 3.0) ? vec2(0.436798, 0.614777) : \ - (crtgamut == -4.0) ? vec2(0.599002392519453, 0.52510120528935) : \ - (crtgamut == -3.0) ? vec2(0.599002392519453, 0.52510120528935) : \ - vec2(0.5959, 0.5227) ; + bool NTSC_U = crtgamut < 2.0; - col = clamp(col.xyz, vec3(0.0, -UVmax.x, -UVmax.y), vec3(1.0, UVmax.x, UVmax.y)); + vec2 UVmax = vec2(Quantize8(0.435812284313725), Quantize8(0.615857694117647)); + vec2 Ymax = NTSC_U ? vec2(16.0, 235.0) : vec2(0.0, 235.0); - col = (crtgamut == 3.0) ? col : \ - (crtgamut == 2.0) ? col : \ - (crtgamut == -3.0) ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ - (crtgamut == -4.0) ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ - PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0, false) ; +// Assumes framebuffer in Rec.601 full range with baked gamma +// Quantize to 8-bit to replicate CRT's circuit board arithmetics + vec3 col = clamp(Quantize8_f3(r601_YUV(src, NTSC_U ? 1.0 : 0.0)), vec3(Ymax.x, -UVmax.x, -UVmax.y), \ + vec3(Ymax.y, UVmax.x, UVmax.y))/255.0; - -// YIQ/YUV Analogue Color Controls (HUE + Color Shift + Color Burst) - float hue_radians = hue_degrees * (M_PI / 180.0); +// YUV Analogue Color Controls (HUE + Color Shift + Color Burst) + float hue_radians = hue_degrees * M_PI; float hue = atan(col.z, col.y) + hue_radians; - float chroma = sqrt(col.z * col.z + col.y * col.y); - col = vec3(col.x, chroma * cos(hue), chroma * sin(hue)); + float chroma = sqrt(col.z * col.z + col.y * col.y); // Euclidean Distance - col.y = (mod((col.y + 1.0) + I_SHIFT, 2.0) - 1.0) * I_MUL; - col.z = (mod((col.z + 1.0) + Q_SHIFT, 2.0) - 1.0) * Q_MUL; - - -// Back to RGB - col = (crtgamut == 3.0) ? col : \ - (crtgamut == 2.0) ? col : \ - (crtgamut == -3.0) ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ - (crtgamut == -4.0) ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) : \ - TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0, false) ; - - col = (crtgamut == 3.0) ? YUV_r601(col) : \ - (crtgamut == 2.0) ? YIQ_RGB(col) : \ - (crtgamut == -3.0) ? FCC_RGB(col) : \ - (crtgamut == -4.0) ? FCC_RGB(col) : \ - YIQ_RGB(col) ; - -// Gamut Limiting - col = r601_YCC(clamp(col, 0., 1.)); - col = (signal == 0.0) ? src : YCC_r601(clamp(col, vec3(0.0, -.886,-.700), vec3(1.0, .886,.700))); - - -// Developer baked CRT gamma (2.20 - 2.25) - col = moncurve_f_f3(col, gamma_in, 0.099); - -// CRT Phosphor Gamut - mat3 m_in; - - if (crtgamut == -4.0) { m_in = NTSC_FCC_transform; } else - if (crtgamut == -3.0) { m_in = Conrac_transform; } else - if (crtgamut == -2.0) { m_in = Sony20_20_transform; } else - if (crtgamut == -1.0) { m_in = SMPTE_transform; } else - if (crtgamut == 1.0) { m_in = P22_transform; } else - if (crtgamut == 2.0) { m_in = NTSC_J_transform; } else - if (crtgamut == 3.0) { m_in = EBU_transform; } - - vec3 gamut = m_in*col; - -// White Point Mapping - vec3 wp = (crtgamut == -4.0) ? wp_adjust(global.wp_temperature - (6404. - 6504.), gamut) : \ - (crtgamut == -3.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ - (crtgamut == -2.0) ? wp_adjust(global.wp_temperature - (7600. - 6504.), gamut) : \ - (crtgamut == -1.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ - (crtgamut == 1.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ - (crtgamut == 2.0) ? wp_adjust(global.wp_temperature - (7400. - 6504.), gamut) : \ - (crtgamut == 3.0) ? wp_adjust(global.wp_temperature - (6504. - 6504.), gamut) : \ - wp_adjust(global.wp_temperature, gamut) ; - - vec3 adj = clamp(XYZ_to_RGB(wp, SPC), 0., 1.); - - -// Guest Emulated CRT Electron Gun gamma (2.35 - 2.50) (phosphor gamma brings it up back to ~2.222) - adj = moncurve_r_f3(crtgamut == 0.0 ? col : adj, pow(gamma_in, 2.) / gamma_out, 0.099); + col.y = (mod((chroma * cos(hue) + 1.0) + U_SHIFT, 2.0) - 1.0) * U_MUL; + col.z = (mod((chroma * sin(hue) + 1.0) + V_SHIFT, 2.0) - 1.0) * V_MUL; +// Back to R'G'B' full + col = signal > 0.0 ? max(Quantize8_f3(YUV_r601(col.xyz, NTSC_U ? 1.0 : 0.0))/255.0, 0.0) : src; // Look LUT - (in SPC space) - float red = (adj.r * (global.LUT_Size1 - 1.0) + 0.4999) / (global.LUT_Size1 * global.LUT_Size1); - float green = (adj.g * (global.LUT_Size1 - 1.0) + 0.4999) / global.LUT_Size1; - float blue1 = (floor(adj.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; - float blue2 = (ceil(adj.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; - float mixer = clamp(max((adj.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0); + float red = (col.r * (global.LUT_Size1 - 1.0) + 0.4999) / (global.LUT_Size1 * global.LUT_Size1); + float green = (col.g * (global.LUT_Size1 - 1.0) + 0.4999) / global.LUT_Size1; + float blue1 = (floor(col.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; + float blue2 = (ceil(col.b * (global.LUT_Size1 - 1.0)) / global.LUT_Size1) + red; + float mixer = clamp(max((col.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0); vec3 color1 = texture(SamplerLUT1, vec2(blue1, green)).rgb; vec3 color2 = texture(SamplerLUT1, vec2(blue2, green)).rgb; - vec3 vcolor = (global.LUT1_toggle == 0.0) ? adj : mixfix(color1, color2, mixer); + vec3 vcolor = (global.LUT1_toggle == 0.0) ? col : mixfix(color1, color2, mixer); + + +// CRT EOTF. To Display Referred Linear: Undo developer baked CRT gamma (from 2.40 at default 0.1 CRT black level, to 2.60 at 0.0 CRT black level) + col = EOTF_1886a_f3(vcolor, CRT_l, params.g_CRT_b, params.g_CRT_c); + + +//_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +// \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \ -// OETF - Opto-Electronic Transfer Function (Rec.709 does a Dim to Dark Surround adaptation) - vcolor = (SPC == 3.0) ? clamp(pow(vcolor, vec3(563./256.)), 0., 1.) : \ - (SPC == 2.0) ? moncurve_f_f3(vcolor, 2.20 + 0.022222, 0.0993) : \ - (SPC == 1.0) ? clamp(pow(vcolor, vec3(2.20 + 0.40)), 0., 1.) : \ - (SPC == 0.0) ? moncurve_f_f3(vcolor, 2.20 + 0.20, 0.0550) : \ - clamp(pow(pow(vcolor, vec3(1./1.019264)), vec3(2.20 + 0.20)), 0., 1.) ; - - - vcolor = RGB_to_XYZ(vcolor, SPC); - - -// Sigmoidal Contrast - vec3 Yxy = XYZtoYxy(vcolor); - float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0., 1.); - toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma; - float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid); - vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b); - vec3 XYZsrgb = clamp(XYZ_to_RGB(YxytoXYZ(contrast), SPC), 0., 1.); - contrast = (cntrst == 0.0) ? XYZ_to_RGB(vcolor, SPC) : XYZsrgb; - - -// Vignetting & Black Level - vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy); - - vpos *= 1.0 - vpos.xy; - float vig = vpos.x * vpos.y * vstr; - vig = min(pow(vig, vpower), 1.0); - contrast *= (vignette == 1.0) ? vig : 1.0; - - contrast += (lift / 20.0) * (1.0 - contrast); - - -// RGB Related Transforms - vec4 screen = vec4(max(contrast, 0.0), 1.0); - float sat = g_sat + 1.0; +// HUE vs HUE + vec4 screen = vec4(max(col, 0.0), 1.0); // r g b alpha ; alpha does nothing for our purposes mat4 color = mat4(wlr, rg, rb, 0.0, //red tint @@ -860,23 +846,39 @@ void main() br, bg, wlb, 0.0, //blue tint blr/20., blg/20., blb/20., 0.0); //black tint - - vec3 coeff = (SPC == 3.0) ? vec3(0.29734000563621520, 0.62735998630523680, 0.07529000192880630) : \ - (SPC == 2.0) ? vec3(0.24840137362480164, 0.67799961566925050, 0.03913172334432602) : \ - (SPC == 1.0) ? vec3(0.22898375988006592, 0.69173991680145260, 0.07927616685628891) : \ - vec3(0.21264933049678802, 0.71516913175582890, 0.07218152284622192) ; + screen *= transpose(color); - mat3 adjust = mat3((1.0 - sat) * coeff.x + sat, (1.0 - sat) * coeff.x, (1.0 - sat) * coeff.x, - (1.0 - sat) * coeff.y, (1.0 - sat) * coeff.y + sat, (1.0 - sat) * coeff.y, - (1.0 - sat) * coeff.z, (1.0 - sat) * coeff.z, (1.0 - sat) * coeff.z + sat); +// CRT Phosphor Gamut (0.0 is sRGB/noop) + mat3 m_in; + + if (crtgamut == -3.0) { m_in = SMPTE170M_ph; } else + if (crtgamut == -2.0) { m_in = RPTV_95s_ph; } else + if (crtgamut == -1.0) { m_in = P22_80s_ph; } else + if (crtgamut == 1.0) { m_in = P22_90s_ph; } else + if (crtgamut == 2.0) { m_in = P22_J_ph; } else + if (crtgamut == 3.0) { m_in = SMPTE470BG_ph; } else + { m_in = sRGB_prims; } + + m_in = (global.LUT1_toggle == 0.0) ? m_in : sRGB_prims; + +// Display color space + mat3 m_ou; + + if (SPC == 1.0) { m_ou = DCIP3_prims; } else + if (SPC == 2.0) { m_ou = rec2020_prims; } else + if (SPC == 3.0) { m_ou = Adobe_prims; } else + { m_ou = sRGB_prims; } - screen = clamp(rolled_gain_v4(screen, clamp(lum, -0.49, 0.99)), 0., 1.); - screen = color * screen; +// White Point Mapping + col = wp_adjust(screen.rgb, global.wp_temperature, m_in, m_ou); -// HUE vs SAT - vec3 src_h = RGB_to_XYZ(screen.rgb, SPC) * LMS; + +// SAT + HUE vs SAT (in IPT space) + vec3 coeff = RGB_to_XYZ_mat(m_in)[1]; + + vec3 src_h = RGB_to_XYZ(screen.rgb, m_in) * LMS; src_h.x = src_h.x >= 0.0 ? pow(src_h.x, 0.43) : -pow(-src_h.x, 0.43); src_h.y = src_h.y >= 0.0 ? pow(src_h.y, 0.43) : -pow(-src_h.y, 0.43); src_h.z = src_h.z >= 0.0 ? pow(src_h.z, 0.43) : -pow(-src_h.z, 0.43); @@ -886,37 +888,87 @@ void main() float hue_at = atan(src_h.z, src_h.y); chroma = sqrt(src_h.z * src_h.z + src_h.y * src_h.y); - float hue_radians_r = -40.0 * (M_PI / 180.0); - float hue_r = chroma * cos(hue_at + hue_radians_r) * 2.; + // red 320º green 220º blue 100º + float hue_radians_r = 320.0 * M_PI; + float hue_r = cos(hue_at + hue_radians_r); - float hue_radians_g = 230.0 * (M_PI / 180.0); - float hue_g = chroma * cos(hue_at + hue_radians_g) * 2.; + float hue_radians_g = 220.0 * M_PI; + float hue_g = cos(hue_at + hue_radians_g); - float hue_radians_b = 100.0 * (M_PI / 180.0); - float hue_b = chroma * cos(hue_at + hue_radians_b) * 2.; + float hue_radians_b = 100.0 * M_PI; + float hue_b = cos(hue_at + hue_radians_b); - float msk = dot(clamp(vec3(hue_r, hue_g, hue_b), 0., 1.), vec3(satr, satg, satb)*(-1.)); - src_h = mixfix(screen.rgb, vec3(dot(coeff, screen.rgb)), msk); + float msk = dot(clamp(vec3(hue_r, hue_g, hue_b) * chroma * 2, 0.0, 1.0), -vec3(satr, satg, satb)); + src_h = mix(col, vec3(dot(coeff, col)), msk); float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \ - 1.0 - (SatMask(src_h.x, src_h.y, src_h.z) * vibr) ; + 1.0 - (SatMask(src_h.x, src_h.y, src_h.z) * vibr) ; - src_h = mixfix(src_h, clamp(adjust * src_h, 0., 1.), clamp(sat_msk, 0., 1.)); + float sat = g_sat + 1.0; + float msat = 1.0 - sat; + float msatx = msat * coeff.x; + float msaty = msat * coeff.y; + float msatz = msat * coeff.z; + + mat3 adjust = mat3(msatx + sat, msatx , msatx , + msaty , msaty + sat, msaty , + msatz , msatz , msatz + sat); -// EOTF - Electro-Optical Transfer Function (Rec.709 does a Dim to Dark Surround adaptation) - vec3 TRC = (SPC == 3.0) ? clamp(pow(src_h, vec3(1./(563./256.))), 0., 1.) : \ - (SPC == 2.0) ? moncurve_r_f3(src_h, 2.20 + 0.022222, 0.0993) : \ - (SPC == 1.0) ? clamp(pow(src_h, vec3(1./(2.20 + 0.40))), 0., 1.) : \ - (SPC == 0.0) ? moncurve_r_f3(src_h, 2.20 + 0.20, 0.0550) : \ - clamp(pow(pow(src_h, vec3(1.019264)), vec3(1./(2.20 + 0.20))), 0., 1.) ; + src_h = mix(src_h, adjust * src_h, clamp(sat_msk, 0.0, 1.0)); + src_h *= vec3(beamr,beamg,beamb); + + +// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress) + coeff = RGB_to_XYZ_mat(m_ou)[1]; + src_h = GCompress==1.0 ? clamp(GamutCompression(src_h, dot(coeff.xyz, src_h)), 0.0, 1.0) : clamp(src_h, 0.0, 1.0); + + +// Sigmoidal Luma Contrast under 'Yxy' decorrelated model (in gamma space) + vec3 Yxy = XYZtoYxy(RGB_to_XYZ(src_h, m_ou)); + float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0.0, 1.0); + toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma; + float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid); + vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b); + vec3 XYZsrgb = XYZ_to_RGB(YxytoXYZ(contrast), m_ou); + contrast = (cntrst == 0.0) ? src_h : XYZsrgb; + + +// Lift + Gain -PP Digital Controls- (Could do in Yxy but performance reasons) + src_h = clamp(rolled_gain_v3(contrast, clamp(lum, -0.49, 0.99)), 0.0, 1.0); + src_h += (lift / 20.0) * (1.0 - contrast); + + +// Vignetting (in linear space, so after EOTF^-1 it's power shaped; 0.5 thres converts to ~0.75) + vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy); + + vpos *= 1.0 - vpos.xy; + float vig = vpos.x * vpos.y * vstr; + vig = min(pow(vig, vpower), 1.0); + vig = vig >= 0.5 ? smoothstep(0,1,vig) : vig; + + src_h *= (vignette == 1.0) ? vig : 1.0; + + +// Dark to Dim adaptation OOTF; for 709, P3-D65 and 2020 + float DtD = global.g_Dark_to_Dim > 0.0 ? 1/0.9811 : 1.0; + +// EOTF^-1 - Inverted Electro-Optical Transfer Function + vec3 TRC = (SPC == 3.0) ? clamp(pow(src_h, vec3(1./ (563./256.))), 0., 1.) : \ + (SPC == 0.0) ? moncurve_r_f3(src_h, 2.20 + 0.20, 0.0550) : \ + clamp(pow( src_h, vec3(1./((2.20 + 0.20)*DtD))), 0., 1.) ; + + +// External Flare for Surround Illuminant 2700K (Soft White) at F0 (Lambertian reflectance); defines offset thus also black lift + vec3 Flare = 0.01 * (global.g_CRT_rf/5.0)*(0.049433*global.g_CRT_sl - 0.188367) * vec3(0.459993/0.410702,1.0,0.129305/0.410702); + TRC = global.g_CRT_sl > 0.0 ? min(TRC+Flare,1.0) : TRC; // Technical LUT - (in SPC space) - float red_2 = (TRC.r * (global.LUT_Size2 - 1.0) + 0.4999) / (global.LUT_Size2 * global.LUT_Size2); - float green_2 = (TRC.g * (global.LUT_Size2 - 1.0) + 0.4999) / global.LUT_Size2; - float blue1_2 = (floor(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; - float blue2_2 = (ceil(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; + float red_2 = (TRC.r * (global.LUT_Size2 - 1.0) + 0.4999) / (global.LUT_Size2 * global.LUT_Size2); + float green_2 = (TRC.g * (global.LUT_Size2 - 1.0) + 0.4999) / global.LUT_Size2; + float blue1_2 = (floor(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; + float blue2_2 = (ceil(TRC.b * (global.LUT_Size2 - 1.0)) / global.LUT_Size2) + red_2; float mixer_2 = clamp(max((TRC.b - blue1_2) / (blue2_2 - blue1_2), 0.0), 0.0, 32.0); vec3 color1_2 = texture(SamplerLUT2, vec2(blue1_2, green_2)).rgb; vec3 color2_2 = texture(SamplerLUT2, vec2(blue2_2, green_2)).rgb; @@ -926,4 +978,4 @@ void main() FragColor = vec4(LUT2_output + aftglow.rgb, 1.0); -} \ No newline at end of file +} diff --git a/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang b/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang index 15e4e90..aa5e07e 100644 --- a/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang +++ b/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang @@ -14,15 +14,18 @@ layout(std140, set = 0, binding = 0) uniform UBO float quality, ntsc_sat, cust_fringing, cust_artifacting, ntsc_bright, ntsc_scale, ntsc_fields, ntsc_phase, ntsc_cscale; } global; -#pragma parameter quality "NTSC Preset (Svideo=0 Composite=1 RF=2 Custom=-1)" 1.0 -1.0 2.0 1.0 -#pragma parameter ntsc_fields "NTSC Merge Fields" 0.0 0.0 1.0 1.0 -#pragma parameter ntsc_phase "NTSC Phase: Auto | 2 phase | 3 phase" 1.0 1.0 3.0 1.0 +#pragma parameter ntsc-row1 "------------------------------------------------" 0.0 0.0 1.0 1.0 +#pragma parameter quality "Values: Svideo = 0.0 | Composite = 1.0 | RF = 2.0" 0.0 0.0 1.0 1.0 +#pragma parameter cust_fringing "NTSC Fringing Value" 1.0 0.0 5.0 0.1 +#pragma parameter cust_artifacting "NTSC Artifacting Value" 1.0 0.0 5.0 0.1 +#pragma parameter ntsc-row2 "------------------------------------------------" 0.0 0.0 1.0 1.0 +#pragma parameter ntsc_fields "NTSC Merge Fields: Auto | NO | YES" -1.0 -1.0 1.0 1.0 +#pragma parameter ntsc_phase "NTSC Phase: Auto | 2 phase | 3 phase | Mixed" 1.0 1.0 4.0 1.0 #pragma parameter ntsc_scale "NTSC Resolution Scaling" 1.0 0.20 2.5 0.025 #pragma parameter ntsc_cscale "NTSC Chroma Scaling / Bleeding" 1.0 0.20 2.25 0.05 #pragma parameter ntsc_sat "NTSC Color Saturation" 1.0 0.0 2.0 0.01 #pragma parameter ntsc_bright "NTSC Brightness" 1.0 0.0 1.5 0.01 -#pragma parameter cust_fringing "NTSC Custom Fringing Value" 0.0 0.0 5.0 0.1 -#pragma parameter cust_artifacting "NTSC Custom Artifacting Value" 0.0 0.0 5.0 0.1 + #define PI 3.14159265 @@ -48,15 +51,17 @@ void main() vTexCoord = TexCoord; pix_no = TexCoord * global.SourceSize.xy * (res * global.OutputSize.xy / global.SourceSize.xy); phase = (global.ntsc_phase < 1.5) ? ((OriginalSize > 300.0) ? 2.0 : 3.0) : ((global.ntsc_phase > 2.5) ? 3.0 : 2.0); + if (global.ntsc_phase == 4.0) phase = 3.0; CHROMA_MOD_FREQ = (phase < 2.5) ? (4.0 * PI / 15.0) : (PI / 3.0); - ARTIFACTING = (global.quality > -0.5) ? global.quality : global.cust_artifacting; - FRINGING = (global.quality > -0.5) ? global.quality : global.cust_fringing; + ARTIFACTING = global.cust_artifacting; + FRINGING = global.cust_fringing; SATURATION = global.ntsc_sat; BRIGHTNESS = global.ntsc_bright; - - MERGE = (int(global.quality) == 2 || phase < 2.5) ? 0.0 : 1.0; - MERGE = (int(global.quality) == -1) ? global.ntsc_fields : MERGE; + MERGE = 0.0; + if (global.ntsc_fields == -1.0 && phase == 3.0) MERGE = 1.0; + else if (global.ntsc_fields == 0.0) MERGE = 0.0; + else if (global.ntsc_fields == 1.0) MERGE = 1.0; } #pragma stage fragment @@ -99,9 +104,19 @@ void main() { float res = global.ntsc_scale; vec3 col = texture(Source, vTexCoord).rgb; + vec3 yiq = rgb2yiq(col); float lum = yiq.x; - + +if (global.ntsc_phase == 4.0) +{ + vec2 dx = vec2(global.OriginalSize.z, 0.0); + vec3 c1 = texture(Source, vTexCoord - dx).rgb; + vec3 c2 = texture(Source, vTexCoord + dx).rgb; + c1 = rgb2yiq(c1); + c2 = rgb2yiq(c2); + yiq.x = mix(min(0.5*(yiq.x + max(c1.x,c2.x)), max(yiq.x , min(c1.x,c2.x))), yiq.x, 5.0*min(abs(c1.x-c2.x),1.0)); +} vec3 yiq2 = yiq; vec3 yiqs = yiq; vec3 yiqz = yiq; @@ -148,6 +163,11 @@ if (MERGE > 0.5) yiq.x = dot(yiqz, mix_mat[0]); // Cross-talk. } +if (global.ntsc_phase == 4.0) +{ + yiq.x = lum; yiq2.x = lum; +} + yiq = (MERGE < 0.5) ? yiq : 0.5*(yiq+yiq2); FragColor = vec4(yiq, lum); diff --git a/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang b/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang index d7e4336..9634189 100644 --- a/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang +++ b/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang @@ -19,8 +19,8 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter ntsc_cscale "NTSC Chroma Scaling / Bleeding" 1.0 0.20 2.25 0.05 #pragma parameter ntsc_scale "NTSC Resolution Scaling" 1.0 0.20 2.5 0.025 -#pragma parameter ntsc_phase "NTSC Phase: Auto | 2 phase | 3 phase" 1.0 1.0 3.0 1.0 -#pragma parameter ntsc_ring "NTSC Anti-Ringing" 0.0 0.0 1.0 1.0 +#pragma parameter ntsc_phase "NTSC Phase: Auto | 2 phase | 3 phase | Mixed" 1.0 1.0 4.0 1.0 +#pragma parameter ntsc_ring "NTSC Anti-Ringing" 0.5 0.0 1.0 0.10 #pragma stage vertex layout(location = 0) in vec4 Position; @@ -37,6 +37,8 @@ void main() 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 PrePass0; + vec3 fetch_offset(float offset, float one_x) { @@ -64,6 +66,7 @@ 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, @@ -100,7 +103,103 @@ const float luma_filter_2_phase[33] = float[33]( 0.168055832, 0.178571429); -const float chroma_filter_2_phase[33] = float[33]( + + +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.005909882, + -0.012049081, + -0.018222860, + -0.022606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.220176552); + +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); + + +const float chroma_filter_4_phase[33] = float[33]( + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -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 chroma_filter_2_phase[33] = float[33]( 0.001384762, 0.001678312, 0.002021715, @@ -135,68 +234,13 @@ const float chroma_filter_2_phase[33] = float[33]( 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 res = global.ntsc_scale; float OriginalSize = global.OriginalSize.x; float one_x = global.SourceSize.z / res; vec3 signal = vec3(0.0); float phase = (global.ntsc_phase < 1.5) ? ((OriginalSize > 300.0) ? 2.0 : 3.0) : ((global.ntsc_phase > 2.5) ? 3.0 : 2.0); + if (global.ntsc_phase == 4.0) { phase = 2.0; chroma_filter_2_phase = chroma_filter_4_phase; } + if(phase < 2.5) { @@ -283,7 +327,7 @@ void main() } - if (global.ntsc_ring > 0.5) + if (global.ntsc_ring > 0.05) { vec2 dx = vec2(global.OriginalSize.z / min(res, 1.0), 0.0); float a = texture(Source, vTexCoord - 1.5*dx).a; @@ -291,11 +335,14 @@ void main() float c = texture(Source, vTexCoord + 1.5*dx).a; float d = texture(Source, vTexCoord + 0.5*dx).a; float e = texture(Source, vTexCoord ).a; - signal.x = clamp(signal.x, min(min(min(a,b),min(c,d)),e), max(max(max(a,b),max(c,d)),e)); + signal.x = mix(signal.x, clamp(signal.x, min(min(min(a,b),min(c,d)),e), max(max(max(a,b),max(c,d)),e)), global.ntsc_ring); } + + vec3 orig = rgb2yiq(texture(PrePass0, vTexCoord).rgb); + signal.x = clamp(signal.x, -1.0, 1.0); vec3 rgb = signal; - FragColor = vec4(rgb, 1.0); + FragColor = vec4(rgb, orig.x); } diff --git a/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang b/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang index 30e41ae..07bc259 100644 --- a/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang +++ b/crt/shaders/guest/advanced/ntsc/ntsc-pass3.slang @@ -68,7 +68,8 @@ vec3 rgb2yiq(vec3 col) void main() { vec2 offsetx = vec2(0.5 * global.OriginalSize.z, 0.0); - vec2 texcoord = vTexCoord + vec2(0.25 * global.SourceSize.z, 0.0); + vec2 dx = vec2(0.25 * global.SourceSize.z, 0.0); + vec2 texcoord = vTexCoord + dx; vec3 l1 = texture(Source, texcoord + offsetx).xyz; vec3 l2 = texture(Source, texcoord - offsetx).xyz; @@ -76,7 +77,7 @@ void main() vec3 l4 = texture(Source, texcoord - 0.50*offsetx).xyz; vec3 ref = texture(Source, texcoord).xyz; - float lum1 = texture(NPass1, vTexCoord).a; + float lum1 = min(texture(Source, vTexCoord - dx).a, texture(Source, vTexCoord + dx).a); float lum2 = max(ref.x, 0.0); float dif = max(max(abs(l1.x-l2.x), abs(l1.y-l2.y)), max(abs(l1.z-l2.z), abs(l1.x*l1.x-l2.x*l2.x))); diff --git a/crt/shaders/guest/fast/bloom_horizontal.slang b/crt/shaders/guest/fast/bloom_horizontal.slang index 019af4c..eb3147b 100644 --- a/crt/shaders/guest/fast/bloom_horizontal.slang +++ b/crt/shaders/guest/fast/bloom_horizontal.slang @@ -3,7 +3,7 @@ /* Gaussian blur - horizontal pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,24 +23,28 @@ layout(push_constant) uniform Push { - vec4 SourceSize; + vec4 LinearizePassSize; vec4 OriginalSize; vec4 OutputSize; uint FrameCount; float SIZEHB; float SIGMA_HB; float BLOOMCUT_H; + float FINE_BLOOM; } params; -#pragma parameter bogus_glow "[ GLOW/BLOOM PASS SETTINGS ]:" 0.0 0.0 1.0 1.0 +#pragma parameter bogus_bloom "[ BLOOM/HALATION/(GLOW) PASS SETTINGS ]:" 0.0 0.0 1.0 1.0 -#pragma parameter SIZEHB " H. Bloom/Halation/Glow Radius" 4.0 1.0 30.0 1.0 +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM + +#pragma parameter SIZEHB " Horizontal Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEHB params.SIZEHB -#pragma parameter SIGMA_HB " Horizontal Bloom/Halation/Glow Sigma" 1.0 0.25 15.0 0.05 +#pragma parameter SIGMA_HB " Horizontal Bloom/Halation Sigma" 0.75 0.25 15.0 0.025 #define SIGMA_HB params.SIGMA_HB -#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation/(Glow) Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_H params.BLOOMCUT_H layout(std140, set = 0, binding = 0) uniform UBO @@ -75,7 +79,7 @@ float gaussian(float x) void main() { - vec4 SourceSize1 = params.OriginalSize; + vec4 SourceSize1 = params.OriginalSize * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); float f = fract(SourceSize1.x * vTexCoord.x); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -90,7 +94,8 @@ void main() do { pixel = COMPAT_TEXTURE(LinearizePass, tex + n*dx); - w = max(gaussian(n+f) - BLOOMCUT_H, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_H >= 0.0) ? max(w - BLOOMCUT_H, 0.0) : (max(w + BLOOMCUT_H, 0.0)/(1.0 + BLOOMCUT_H)); pixel.a = max(max(pixel.r, pixel.g),pixel.b); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; diff --git a/crt/shaders/guest/fast/bloom_vertical.slang b/crt/shaders/guest/fast/bloom_vertical.slang index f19278a..d540fa1 100644 --- a/crt/shaders/guest/fast/bloom_vertical.slang +++ b/crt/shaders/guest/fast/bloom_vertical.slang @@ -3,7 +3,7 @@ /* Gaussian blur - vertical pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,7 +21,6 @@ */ - layout(push_constant) uniform Push { vec4 SourceSize; @@ -31,16 +30,19 @@ layout(push_constant) uniform Push float SIZEVB; float SIGMA_VB; float BLOOMCUT_V; + float FINE_BLOOM; } params; +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM -#pragma parameter SIZEVB " V. Bloom/Halation/Glow Radius" 4.0 1.0 30.0 1.0 +#pragma parameter SIZEVB " Vertical Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEVB params.SIZEVB -#pragma parameter SIGMA_VB " Vertical Bloom/Halation/Glow Sigma" 1.0 0.25 15.0 0.05 +#pragma parameter SIGMA_VB " Vertical Bloom/Halation Sigma" 0.60 0.25 15.0 0.025 #define SIGMA_VB params.SIGMA_VB -#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation/(Glow) Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_V params.BLOOMCUT_V layout(std140, set = 0, binding = 0) uniform UBO @@ -75,8 +77,10 @@ float gaussian(float x) void main() { - vec4 SourceSize1 = vec4(params.SourceSize.x, params.OriginalSize.y, params.SourceSize.z, params.OriginalSize.w); - + vec4 SourceSize1 = params.SourceSize; + SourceSize1.yw = params.OriginalSize.yw; + SourceSize1 = SourceSize1 * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); + float f = fract(SourceSize1.y * vTexCoord.y); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -91,7 +95,8 @@ void main() do { pixel = COMPAT_TEXTURE(Source, tex + n*dy); - w = max(gaussian(n+f) - BLOOMCUT_V, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_V >= 0.0) ? max(w - BLOOMCUT_V, 0.0) : (max(w + BLOOMCUT_V, 0.0)/(1.0 + BLOOMCUT_V)); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; wsum = wsum + w; diff --git a/crt/shaders/guest/fast/crt-guest-advanced-pass2.slang b/crt/shaders/guest/fast/crt-guest-advanced-pass2.slang index 1bd5147..c1c732b 100644 --- a/crt/shaders/guest/fast/crt-guest-advanced-pass2.slang +++ b/crt/shaders/guest/fast/crt-guest-advanced-pass2.slang @@ -27,7 +27,7 @@ layout(push_constant) uniform Push { float brightboost, brightboost1, gsl, scanline1, scanline2, beam_min, beam_max, beam_size, - glow, vertmask, maskstr, inters, bloom, halation, scans, gamma_c, gamma_out, IOS, no_scanlines; + glow, maskstr, inters, bloom, halation, scans, gamma_c, gamma_out, IOS, no_scanlines, tds, clips, ssharp; } params; layout(std140, set = 0, binding = 0) uniform UBO @@ -51,7 +51,9 @@ layout(std140, set = 0, binding = 0) uniform UBO float scan_falloff; float overscanX; float overscanY; - float bloom_dist; + float bloom_dist; + float bmask1; + float hmask1; } global; #pragma parameter bogus_screen "[ SCREEN OPTIONS ]: " 0.0 0.0 1.0 1.0 @@ -99,15 +101,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom params.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation params.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter gamma_c " Gamma correct" 1.0 0.50 2.0 0.025 #define gamma_c params.gamma_c // adjust brightness @@ -117,6 +125,9 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter brightboost1 " Bright Boost Bright Pixels" 1.10 0.25 3.00 0.025 #define brightboost1 params.brightboost1 // adjust brightness +#pragma parameter clips " Clip Saturated Color Beams" 0.0 -1.0 1.0 0.05 +#define clips params.clips // kinky effect + #pragma parameter bogus_scanline "[ SCANLINE OPTIONS ]: " 0.0 0.0 1.0 1.0 #pragma parameter gsl " Scanline Type" 0.0 -1.0 2.0 1.0 @@ -134,18 +145,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter beam_max " Scanline Shape Bright Pixels" 1.00 0.2 3.5 0.025 #define beam_max params.beam_max // bright area beam max - wide +#pragma parameter tds " Thinner Dark Scanlines" 0.0 0. 1.0 1.0 +#define tds params.tds // thinner dark scanlines + #pragma parameter beam_size " Increased Bright Scanline Beam" 0.60 0.0 1.0 0.05 #define beam_size params.beam_size // increased max. beam size -#pragma parameter vertmask " Scanline Color Deconvergence" 0.0 -1.0 1.0 0.1 -#define vertmask params.vertmask // Scanline deconvergence colors - #pragma parameter scans " Scanline Saturation / Mask Falloff" 0.50 -5.0 5.0 0.10 #define scans params.scans // scanline saturation #pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.05 #define scan_falloff global.scan_falloff // scanline falloff +#pragma parameter ssharp " Smart Sharpen Scanlines" 0.0 0.0 0.30 0.01 +#define ssharp params.ssharp + #pragma parameter no_scanlines " No-scanline mode" 0.0 0.0 1.5 0.05 #define no_scanlines params.no_scanlines @@ -180,7 +194,12 @@ float st(float x) { return exp2(-10.0*x*x); } - + +float st1(float x) +{ + return exp2(-8.0*x*x); +} + float sw0(float x, float color, float scanline) { float tmp = mix(beam_min, beam_max, color); @@ -226,6 +245,12 @@ vec2 Warp(vec2 pos) return pos*0.5 + 0.5; } +vec3 plant (vec3 tar, float r) +{ + float t = max(max(tar.r,tar.g),tar.b) + 0.00001; + return tar * r / t; +} + void main() { @@ -296,8 +321,11 @@ void main() if (!interb) { - float shape1 = mix(scanline1, scanline2, f); - float shape2 = mix(scanline1, scanline2, 1.0-f); + vec3 luma = vec3(0.2126, 0.7152, 0.0722); + float ssub = ssharp*max(abs(scolor1.x-scolor2.x), abs(dot(color1,luma)-dot(color2,luma))); + + float shape1 = mix(scanline1, scanline2 + ssub * scolor1.x * 35.0, f); + float shape2 = mix(scanline1, scanline2 + ssub * scolor2.x * 35.0, 1.0-f); float wt1 = st(f); float wt2 = st(1.0-f); @@ -313,6 +341,8 @@ if (!interb) vec3 cref1 = mix(sctmp, scolor1, beam_size); float creff1 = pow(max(max(cref1.r,cref1.g),cref1.b), scan_falloff); vec3 cref2 = mix(sctmp, scolor2, beam_size); float creff2 = pow(max(max(cref2.r,cref2.g),cref2.b), scan_falloff); + if (tds > 0.5) { shape1 = mix(scanline2, shape1, creff1); shape2 = mix(scanline2, shape2, creff2); } + float f1 = f; float f2 = 1.0-f; @@ -337,6 +367,18 @@ if (!interb) float scanpow2 = (scans > 0.0) ? 1.0 : pow(f2, 0.375); w1 = pow(w1, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref1, scanpow1))); w2 = pow(w2, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref2, scanpow2))); + + if (abs(clips) > 0.005) + { + sy = mc1; vec3 l1 = sqrt(w1*wt1); vec3 l2 = sqrt(w2*wt2); + one = (clips > 0.0) ? w1 : mix(w1, l1, sy); + float sat = 1.0001-min(min(cref1.r,cref1.g),cref1.b); + color1 = mix(color1, plant(pow(color1, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + sy = mc2; + sat = 1.0001-min(min(cref2.r,cref2.g),cref2.b); + one = (clips > 0.0) ? w2 : mix(w2, l2, sy); + color2 = mix(color2, plant(pow(color2, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + } color = (gc(color1)*w1 + gc(color2)*w2); color = min(color, 1.0); diff --git a/crt/shaders/guest/fast/crt-guest-advanced-pass2f.slang b/crt/shaders/guest/fast/crt-guest-advanced-pass2f.slang index bc50661..abf4753 100644 --- a/crt/shaders/guest/fast/crt-guest-advanced-pass2f.slang +++ b/crt/shaders/guest/fast/crt-guest-advanced-pass2f.slang @@ -52,7 +52,8 @@ layout(std140, set = 0, binding = 0) uniform UBO float no_scanlines; float intres; float fcompat; - float smask_mit; + float smask_mit; + float ssharp; } global; #pragma parameter fcompat " Compatibility Mode (slower, use if glitchy)" 0.0 0.0 1.0 1.0 @@ -131,6 +132,9 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.05 #define scan_falloff global.scan_falloff // scanline falloff +#pragma parameter ssharp " Smart Sharpen Scanlines" 0.0 0.0 0.30 0.01 +#define ssharp global.ssharp + #pragma parameter no_scanlines " No-scanline mode" 0.0 0.0 1.5 0.05 #define no_scanlines global.no_scanlines @@ -461,7 +465,8 @@ vec3 Mask(vec2 pos, float mx, inout float swidth) } swidth*=masksize; - return mask; + float maskmin = min(min(mask.r,mask.g),mask.b); + return (mask - maskmin) * (1.0 + (maskboost-1.0)) + maskmin; } float SlotMask(vec2 pos, float m, float swidth) @@ -570,11 +575,11 @@ void main() float same4 = COMPAT_TEXTURE(PrePassDontChange,pc4+yy).a; float same5 = COMPAT_TEXTURE(PrePassDontChange,pc4+y2).a; - float refresh1 = 30.0; - float refresh2 = round(TEX0.y*29.0); + float refresh1 = 60.0; + float refresh2 = round(TEX0.y*59.0); - bool frames = (floor(mod(float(global.FrameCount), refresh1)) == refresh2); - bool not_same = (same2 + same3 + same4 + same5) > 0.25; + bool frames = (abs(floor(mod(float(global.FrameCount), refresh1)) - refresh2) < 0.001); + bool not_same = (same2 + same3 + same4 + same5) > 0.5; if ( not_same || frames || (interb && (no_scanlines < 0.025)) || global.fcompat > 0.5) @@ -645,8 +650,11 @@ if ( not_same || frames || (interb && (no_scanlines < 0.025)) || global.fcompat if (!interb) { - float shape1 = mix(scanline1, scanline2, f); - float shape2 = mix(scanline1, scanline2, 1.0-f); + vec3 luma = vec3(0.2126, 0.7152, 0.0722); + float ssub = ssharp*max(abs(scolor1.x-scolor2.x), abs(dot(color1,luma)-dot(color2,luma))); + + float shape1 = mix(scanline1, scanline2 + ssub * scolor1.x * 35.0, f); + float shape2 = mix(scanline1, scanline2 + ssub * scolor2.x * 35.0, 1.0-f); float wt1 = st(f); float wt2 = st(1.0-f); @@ -764,15 +772,16 @@ if(bloom > 0.025) color = color + bloom * Bloom1; } - color = min(color, mix(one, cmask, mclip)); if (!interb) color = declip(color, pow(w3,0.60)); if (halation > 0.025) { Bloom = mix(0.5*(Bloom + Bloom*Bloom), 0.75*Bloom*Bloom, colmx); color = color + 0.75*(0.75+maxb)*Bloom*(0.4+sqrt(colmx))*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.35 + 0.4*maxb)*halation; } - Glow = mix(Glow, 0.25*color, 0.7*colmx); + Glow = mix(Glow, 0.25*color, colmx); color = color + 0.5*glow*Glow; + + color = min(color, mix(one, cmask, mclip)); color = pow(color, vec3(1.0/gamma_out)); color = min(color, 1.0); diff --git a/crt/shaders/guest/fast/deconvergence-f.slang b/crt/shaders/guest/fast/deconvergence-f.slang index 06726a1..75bf2e9 100644 --- a/crt/shaders/guest/fast/deconvergence-f.slang +++ b/crt/shaders/guest/fast/deconvergence-f.slang @@ -40,7 +40,6 @@ layout(std140, set = 0, binding = 0) uniform UBO float bloom; float halation; float slotms; - float mclip; float mask_gamma; float gamma_out; float overscanX; @@ -70,6 +69,9 @@ layout(std140, set = 0, binding = 0) uniform UBO float smask_mit; float mask_zoom; float no_scanlines; + float bmask; + float bmask1; + float hmask1; } global; @@ -83,15 +85,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter brightboost " Bright Boost Dark Pixels" 1.40 0.25 10.0 0.05 #define brightboost params.brightboost // adjust brightness @@ -153,21 +161,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter masksize " CRT Mask Size" 1.0 1.0 4.0 1.0 #define masksize params.masksize // Mask Size -#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -4.0 4.0 1.0 +#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -5.0 5.0 1.0 #define mask_zoom global.mask_zoom // Mask Size +#pragma parameter mshift " (Transform to) Shadow Mask" 0.0 0.0 1.0 0.5 +#define mshift params.mshift // do the "shadow mask" + +#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 +#define mask_layout params.mask_layout // mask layout: RGB or BGR + #pragma parameter maskDark " Lottes maskDark" 0.5 0.0 2.0 0.05 #define maskDark params.maskDark // Dark "Phosphor" #pragma parameter maskLight " Lottes maskLight" 1.5 0.0 2.0 0.05 #define maskLight params.maskLight // Light "Phosphor" -#pragma parameter mshift " Mask Shift/Stagger" 0.0 -8.0 8.0 0.5 -#define mshift params.mshift // mask 'line' shift/stagger - -#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 -#define mask_layout params.mask_layout // mask layout: RGB or BGR - #pragma parameter mask_gamma " Mask gamma" 2.40 1.0 5.0 0.05 #define mask_gamma global.mask_gamma // Mask application gamma @@ -186,15 +194,15 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter slotms " Slot Mask Thickness" 1.0 1.0 4.0 1.0 #define slotms global.slotms // Slot Mask Thickness -#pragma parameter mclip " Keep Mask effect with clipping" 0.0 0.0 1.0 0.05 -#define mclip global.mclip // - #pragma parameter smoothmask " Smooth Masks in bright scanlines" 0.0 0.0 1.0 1.0 #define smoothmask global.smoothmask #pragma parameter smask_mit " Mitigate Slotmask Interaction" 0.0 0.0 1.0 0.05 #define smask_mit global.smask_mit +#pragma parameter bmask " Base (black) Mask strength" 0.0 0.0 0.25 0.01 +#define bmask global.bmask + #pragma parameter gamma_out " Gamma out" 2.4 1.0 5.0 0.05 #define gamma_out global.gamma_out // output gamma @@ -262,14 +270,7 @@ vec3 Mask(vec2 pos, float mx, float mb) vec3 mask = vec3(maskDark, maskDark, maskDark); vec3 one = vec3(1.0); - // No mask - if (shadowMask == -1.0) - { - mask = one; - } - - // Phosphor. - else if (shadowMask == 0.0) + if (shadowMask == 0.0) { float mc = 1.0 - max(maskstr, 0.0); pos.x = fract(pos.x*0.5); @@ -564,8 +565,6 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) dy = posy * dy; } - // if (global.dctypex > 0.025 || global.dctypey > 0.025) ds *= sqrt(posx*posx*sign(global.dctypex) + posy*posy*sign(global.dctypey)); - vec2 rc = global.deconrr * dx + global.deconrry*dy; vec2 gc = global.deconrg * dx + global.deconrgy*dy; vec2 bc = global.deconrb * dx + global.deconrby*dy; @@ -582,7 +581,7 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) b1 = COMPAT_TEXTURE(BloomPass, bcoord + bc).b; d = vec3(r1, g1, b1); - b = clamp(mix(b, d, ds), 0.0, 1.0); + b = mix(b, d, min(ds,1.0)); } void main() @@ -622,7 +621,7 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob float cm = igc(max(max(color.r,color.g),color.b)); float mx1 = COMPAT_TEXTURE(Source, pos1 ).a; float colmx = max(mx1, cm); - float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); + float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); if(interb) w3 = 1.0; vec2 dx = vec2(0.001, 0.0); float mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; @@ -635,7 +634,7 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob dx = vec2(global.OriginalSize.z, 0.0)*0.25; mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; mx2 = COMPAT_TEXTURE(Source, pos1 + dx).a; - float mb = 1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0); + float mb = (1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0)); vec3 one = vec3(1.0); @@ -643,36 +642,39 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob vec3 orig1 = color; vec3 cmask = one; - - vec2 maskcoord = gl_FragCoord.xy * 1.00001; - - vec2 scoord = maskcoord; - + vec3 cmask1 = one; + vec3 cmask2 = one; + // mask widths and mask dark compensate (fractional part) values - float mwidths[14] = float[14] (2.0, 3.0, 3.0, 3.0, 6.0, 2.4, 3.5, 2.4, 3.25, 3.5, 4.5, 4.25, 7.5, 6.25); float mwidth = mwidths[int(shadowMask)]; float mask_compensate = fract(mwidth); + +if (shadowMask > -0.5) +{ + vec2 maskcoord = gl_FragCoord.xy * 1.00001; + vec2 scoord = maskcoord; + mwidth = floor(mwidth) * masksize; float swidth = mwidth; bool zoomed = (abs(mask_zoom) > 0.75); float mscale = 1.0; vec2 maskcoord0 = maskcoord; maskcoord.y = floor(maskcoord.y/masksize); + float mwidth1 = max(mwidth + mask_zoom, 2.0); -if ( abs(mshift) > 0.75 ) +if ( mshift > 0.25 ) { - float stagg_lvl = 1.0; if (fract(abs(mshift)) > 0.25 && abs(mshift) > 1.25) stagg_lvl = 2.0; - float next_line = float(fract((maskcoord.y/stagg_lvl)*0.5) > 0.25); - maskcoord0.x = (mshift > -0.25) ? (maskcoord0.x + next_line * floor(mshift)) : (maskcoord0.x + floor(maskcoord.y / stagg_lvl) * floor(abs(mshift))); + float stagg_lvl = 1.0; if (fract(mshift) > 0.25) stagg_lvl = 2.0; + float next_line = float(floor(mod(maskcoord.y, 2.0*stagg_lvl)) < stagg_lvl); + maskcoord0.x = maskcoord0.x + next_line * 0.5 * mwidth1; } maskcoord = maskcoord0/masksize; if (mask_zoom >= 0.0) maskcoord = floor(maskcoord); if ( !zoomed ) - cmask*= Mask(maskcoord, mx, mb); + cmask*= Mask(floor(maskcoord), mx, mb); else{ - float mwidth1 = max(mwidth + mask_zoom, 2.0); mscale = mwidth1/mwidth; float mlerp = fract(maskcoord.x/mscale); float mcoord = floor(maskcoord.x/mscale); if (shadowMask == 12.0 && mask_zoom == -2.0) mcoord = ceil(maskcoord.x/mscale); @@ -688,15 +690,16 @@ else{ smask = SlotMask(scoord + vec2(sm_offset,0.0), mx, swidth); smask = clamp(smask + mix(smask_mit, 0.0, min(w3, pow(w3*max(max(orig1.r,orig1.g),orig1.b), 0.33333))), 0.0, 1.0); - + + cmask2 = cmask; cmask*=smask; - vec3 cmask1 = cmask; + cmask1 = cmask; - if (mask_bloom > 0.025) + if (abs(mask_bloom) > 0.025) { float maxbl = max(max(max(Bloom.r,Bloom.g),Bloom.b), mxg); - maxbl = maxbl * mix(1.0, 2.0-colmx, bloom_dist); - cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); + maxbl = maxbl * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + if (mask_bloom > 0.025) cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); else cmask = max(mix(cmask, cmask*(1.0-0.5*maxbl) + plant(pow(Bloom,0.35.xxx),maxbl), -mask_bloom),cmask); } color = pow(color, vec3(mask_gamma/gamma_in)); @@ -704,10 +707,10 @@ else{ color = min(color,1.0); color = pow(color, vec3(gamma_in/mask_gamma)); - cmask = min(cmask, 1.0); cmask1 = min(cmask1, 1.0); - - float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); +} + + float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); if(shadowMask < -0.5) dark_compensate = 1.0; float bb = mix(brightboost, brightboost1, mx) * dark_compensate; color*=bb; @@ -717,33 +720,34 @@ else{ float vig = COMPAT_TEXTURE(PrePass, clamp(pos, 0.0+0.5*global.OriginalSize.zw, 1.0-0.5*global.OriginalSize.zw)).a; vec3 Bloom1 = Bloom; + vec3 bcmask = mix(one, cmask, bmask1); + vec3 hcmask = mix(one, cmask, hmask1); -if (abs(bloom) > 0.025) -{ - if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); - Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); - Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); - Bloom1 = Bloom1 * mix(1.0, 2.0-colmx, bloom_dist); - color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); -} + if (abs(bloom) > 0.025) + { + if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); + Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); + Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); + Bloom1 = bcmask*Bloom1 * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); + } - color = min(color, mix(one, cmask1, mclip)); - - if (!interb) color = declip(color, mix(1.0, w3, 0.6)); else w3 = 1.0; + if (!interb) color = declip(min(color,1.0), mix(1.0, w3, 0.6)); if (halation > 0.01) { Bloom = mix(0.5*(Bloom + Bloom*Bloom), 0.75*Bloom*Bloom, colmx); - color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.6)*Bloom*halation; } + color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*halation; } else if (halation < -0.01) { float mbl = max(max(Bloom.r,Bloom.g),Bloom.b); Bloom = plant(Bloom + Ref + orig1 + Bloom*Bloom*Bloom, min(mbl*mbl,0.75)); - color = color + 2.0*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.5)*Bloom*(-halation); } + color = color + 2.0*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*(-halation); } - if (smoothmask > 0.5) { w3 = mix(1.0, w3, smoothstep(0.3, 0.6, mx1)); color = max(min(color/w3, 1.0)*w3, min(color,color*(1.0-w3))); } - Glow = mix(Glow, 0.25*color, 0.7*colmx); - if (glow >= 0.0) color = color + 0.5*Glow*glow; else { cmask*=cmask; cmask*=cmask; color = color + (-glow)*cmask*Glow; } + if (smoothmask > 0.5) { color = min(color,1.0); color = max(min(color/w3, 1.0)*w3, min(orig1*bb,color*(1.0-w3))); } + + Glow = mix(Glow, 0.25*color, colmx); + if (glow >= 0.0) color = color + 0.5*Glow*glow; else { cmask2*=cmask2; color = color + (-glow)*min(cmask2,1.0)*Glow; } color = min(color, 1.0); @@ -757,6 +761,9 @@ if (abs(bloom) > 0.025) if (global.noisetype < 0.5) color = mix(color, noise0, 0.25*abs(params.addnoised) * rc); else color = min(color * mix(1.0, 1.5*noise0.x, 0.5*abs(params.addnoised)),1.0); } + + colmx = max(max(orig1.r,orig1.g),orig1.b); + color = color + bmask*mix(cmask2, 0.125*(1.0-colmx)*color, min(20.0*colmx, 1.0)); FragColor = vec4(color*vig*humbar(mix(pos.y, pos.x, global.bardir))*global.post_br*corner(pos0), 1.0); } diff --git a/crt/shaders/guest/hd/afterglow0.slang b/crt/shaders/guest/hd/afterglow0.slang index 70e0b6b..1f92b60 100644 --- a/crt/shaders/guest/hd/afterglow0.slang +++ b/crt/shaders/guest/hd/afterglow0.slang @@ -87,7 +87,7 @@ void main() float w = 1.0; if ((color0.r + color0.g + color0.b < 5.0/255.0)) { w = 0.0; } - vec3 result = mix( max(mix(color, accumulate, 0.49 + vec3(PR, PG, PB))- 2.0/255.0, 0.0), color, w); + vec3 result = mix( max(mix(color, accumulate, 0.49 + vec3(PR, PG, PB))- 1.25/255.0, 0.0), color, w); FragColor = vec4(result, w); } \ No newline at end of file diff --git a/crt/shaders/guest/hd/bloom_horizontal.slang b/crt/shaders/guest/hd/bloom_horizontal.slang index 331702e..eb3147b 100644 --- a/crt/shaders/guest/hd/bloom_horizontal.slang +++ b/crt/shaders/guest/hd/bloom_horizontal.slang @@ -3,7 +3,7 @@ /* Gaussian blur - horizontal pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -23,24 +23,28 @@ layout(push_constant) uniform Push { - vec4 SourceSize; + vec4 LinearizePassSize; vec4 OriginalSize; vec4 OutputSize; uint FrameCount; float SIZEHB; float SIGMA_HB; float BLOOMCUT_H; + float FINE_BLOOM; } params; -#pragma parameter bogus_glow2 "[ BLOOM PASS SETTINGS ]:" 0.0 0.0 1.0 1.0 +#pragma parameter bogus_bloom "[ BLOOM/HALATION/(GLOW) PASS SETTINGS ]:" 0.0 0.0 1.0 1.0 -#pragma parameter SIZEHB " H. Bloom/Halation Radius" 4.0 1.0 30.0 1.0 +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM + +#pragma parameter SIZEHB " Horizontal Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEHB params.SIZEHB -#pragma parameter SIGMA_HB " Horizontal Bloom/Halation Sigma" 1.0 0.25 15.0 0.05 +#pragma parameter SIGMA_HB " Horizontal Bloom/Halation Sigma" 0.75 0.25 15.0 0.025 #define SIGMA_HB params.SIGMA_HB -#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_H " Horizontal Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_H params.BLOOMCUT_H layout(std140, set = 0, binding = 0) uniform UBO @@ -75,7 +79,7 @@ float gaussian(float x) void main() { - vec4 SourceSize1 = params.OriginalSize; + vec4 SourceSize1 = params.OriginalSize * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); float f = fract(SourceSize1.x * vTexCoord.x); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -90,7 +94,8 @@ void main() do { pixel = COMPAT_TEXTURE(LinearizePass, tex + n*dx); - w = max(gaussian(n+f) - BLOOMCUT_H, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_H >= 0.0) ? max(w - BLOOMCUT_H, 0.0) : (max(w + BLOOMCUT_H, 0.0)/(1.0 + BLOOMCUT_H)); pixel.a = max(max(pixel.r, pixel.g),pixel.b); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; diff --git a/crt/shaders/guest/hd/bloom_vertical.slang b/crt/shaders/guest/hd/bloom_vertical.slang index 58176dc..d540fa1 100644 --- a/crt/shaders/guest/hd/bloom_vertical.slang +++ b/crt/shaders/guest/hd/bloom_vertical.slang @@ -3,7 +3,7 @@ /* Gaussian blur - vertical pass, dynamic range, resizable - Copyright (C) 2020 - 2022 guest(r) - guest.r@gmail.com + Copyright (C) 2020 - 2023 guest(r) - guest.r@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,7 +21,6 @@ */ - layout(push_constant) uniform Push { vec4 SourceSize; @@ -31,16 +30,19 @@ layout(push_constant) uniform Push float SIZEVB; float SIGMA_VB; float BLOOMCUT_V; + float FINE_BLOOM; } params; +#pragma parameter FINE_BLOOM " Fine Bloom/Halation Sampling" 1.0 1.0 4.0 1.0 +#define FINE_BLOOM params.FINE_BLOOM -#pragma parameter SIZEVB " V. Bloom/Halation Radius" 4.0 1.0 30.0 1.0 +#pragma parameter SIZEVB " Vertical Bloom/Halation Radius" 3.0 1.0 50.0 1.0 #define SIZEVB params.SIZEVB -#pragma parameter SIGMA_VB " Vertical Bloom/Halation Sigma" 1.0 0.25 15.0 0.05 +#pragma parameter SIGMA_VB " Vertical Bloom/Halation Sigma" 0.60 0.25 15.0 0.025 #define SIGMA_VB params.SIGMA_VB -#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation Substract" 0.0 0.0 0.5 0.01 +#pragma parameter BLOOMCUT_V " Vertical Bloom/Halation Substract" 0.0 -0.5 0.5 0.05 #define BLOOMCUT_V params.BLOOMCUT_V layout(std140, set = 0, binding = 0) uniform UBO @@ -75,8 +77,10 @@ float gaussian(float x) void main() { - vec4 SourceSize1 = vec4(params.SourceSize.x, params.OriginalSize.y, params.SourceSize.z, params.OriginalSize.w); - + vec4 SourceSize1 = params.SourceSize; + SourceSize1.yw = params.OriginalSize.yw; + SourceSize1 = SourceSize1 * mix(1.0.xxxx, vec4(FINE_BLOOM, FINE_BLOOM, 1.0/FINE_BLOOM, 1.0/FINE_BLOOM), min(FINE_BLOOM-1.0,1.0)); + float f = fract(SourceSize1.y * vTexCoord.y); f = 0.5 - f; vec2 tex = floor(SourceSize1.xy * vTexCoord)*SourceSize1.zw + 0.5*SourceSize1.zw; @@ -91,7 +95,8 @@ void main() do { pixel = COMPAT_TEXTURE(Source, tex + n*dy); - w = max(gaussian(n+f) - BLOOMCUT_V, 0.0); + w = gaussian(n+f); + w = (BLOOMCUT_V >= 0.0) ? max(w - BLOOMCUT_V, 0.0) : (max(w + BLOOMCUT_V, 0.0)/(1.0 + BLOOMCUT_V)); pixel.a*=pixel.a*pixel.a; color = color + w * pixel; wsum = wsum + w; diff --git a/crt/shaders/guest/hd/crt-guest-advanced-hd-pass2.slang b/crt/shaders/guest/hd/crt-guest-advanced-hd-pass2.slang index 287f5dd..e26e962 100644 --- a/crt/shaders/guest/hd/crt-guest-advanced-hd-pass2.slang +++ b/crt/shaders/guest/hd/crt-guest-advanced-hd-pass2.slang @@ -27,7 +27,7 @@ layout(push_constant) uniform Push { float IOS, brightboost, brightboost1, gsl, scanline1, scanline2, beam_min, beam_max, beam_size, - glow, inters, bloom, halation, scans, gamma_c, no_scanlines, MAXS; + glow, inters, bloom, halation, scans, gamma_c, no_scanlines, MAXS, tds, clips, ssharp; } params; layout(std140, set = 0, binding = 0) uniform UBO @@ -58,6 +58,8 @@ layout(std140, set = 0, binding = 0) uniform UBO float overscanX; float overscanY; float bloom_dist; + float bmask1; + float hmask1; } global; #pragma parameter bogus_vfiltering "[ VERTICAL/INTERLACING FILTERING OPTIONS ]: " 0.0 0.0 1.0 1.0 @@ -125,15 +127,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom params.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation params.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter gamma_c " Gamma correct" 1.0 0.50 2.0 0.025 #define gamma_c params.gamma_c // adjust brightness @@ -143,6 +151,9 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter brightboost1 " Bright Boost Bright Pixels" 1.10 0.25 3.00 0.025 #define brightboost1 params.brightboost1 // adjust brightness +#pragma parameter clips " Clip Saturated Color Beams" 0.0 -1.0 1.0 0.05 +#define clips params.clips // kinky effect + #pragma parameter bogus_scanline "[ SCANLINE OPTIONS ]: " 0.0 0.0 1.0 1.0 #pragma parameter gsl " Scanline Type" 0.0 -1.0 2.0 1.0 @@ -160,18 +171,24 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter beam_max " Scanline Shape Bright Pixels" 1.00 0.2 3.5 0.025 #define beam_max params.beam_max // bright area beam max - wide +#pragma parameter tds " Thinner Dark Scanlines" 0.0 0. 1.0 1.0 +#define tds params.tds // thinner dark scanlines + #pragma parameter beam_size " Increased Bright Scanline Beam" 0.60 0.0 1.0 0.05 #define beam_size params.beam_size // increased max. beam size #pragma parameter scans " Scanline Saturation / Mask Falloff" 0.50 -5.0 5.0 0.10 #define scans params.scans // scanline saturation -#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.05 +#pragma parameter scan_falloff " Scanline Falloff" 1.0 0.10 2.0 0.025 #define scan_falloff global.scan_falloff // scanline falloff #pragma parameter scangamma " Scanline Gamma" 2.40 0.5 5.0 0.05 #define scangamma global.scangamma +#pragma parameter ssharp " Smart Sharpen Scanlines" 0.0 0.0 0.30 0.01 +#define ssharp params.ssharp + #pragma parameter no_scanlines " No-scanline mode" 0.0 0.0 1.5 0.05 #define no_scanlines params.no_scanlines @@ -209,7 +226,12 @@ float st(float x) { return exp2(-10.0*x*x); } - + +float st1(float x) +{ + return exp2(-8.0*x*x); +} + float sw0(float x, float color, float scanline) { float tmp = mix(beam_min, beam_max, color); @@ -233,7 +255,7 @@ float sw2(float x, float color, float scanline) float ex = x*tmp; return exp2(-scanline*ex*ex); } - + vec3 gc(vec3 c) { @@ -312,6 +334,12 @@ vec3 v_resample (vec2 tex0, vec4 Size) { return color; } +vec3 plant (vec3 tar, float r) +{ + float t = max(max(tar.r,tar.g),tar.b) + 0.00001; + return tar * r / t; +} + void main() { @@ -389,8 +417,11 @@ void main() if (!interb) { - float shape1 = mix(scanline1, scanline2, f); - float shape2 = mix(scanline1, scanline2, 1.0-f); + vec3 luma = vec3(0.2126, 0.7152, 0.0722); + float ssub = ssharp*max(abs(scolor1.x-scolor2.x), abs(dot(color1,luma)-dot(color2,luma))); + + float shape1 = mix(scanline1, scanline2 + ssub * scolor1.x * 35.0, f); + float shape2 = mix(scanline1, scanline2 + ssub * scolor2.x * 35.0, 1.0-f); float wt1 = st(f); float wt2 = st(1.0-f); @@ -406,6 +437,8 @@ if (!interb) vec3 cref1 = mix(sctmp, scolor1, beam_size); float creff1 = pow(max(max(cref1.r,cref1.g),cref1.b), scan_falloff); vec3 cref2 = mix(sctmp, scolor2, beam_size); float creff2 = pow(max(max(cref2.r,cref2.g),cref2.b), scan_falloff); + if (tds > 0.5) { shape1 = mix(scanline2, shape1, creff1); shape2 = mix(scanline2, shape2, creff2); } + float f1 = f; float f2 = 1.0-f; @@ -414,7 +447,7 @@ if (!interb) { wf1 = sw2(f1,creff1,shape1); wf2 = sw2(f2,creff2,shape2);} if ((wf1 + wf2) > 1.0) { float wtmp = 1.0/(wf1+wf2); wf1*=wtmp; wf2*=wtmp; } - + // Scanline saturation application vec3 w1 = vec3(wf1); vec3 w2 = vec3(wf2); @@ -430,7 +463,18 @@ if (!interb) float scanpow2 = (scans > 0.0) ? 1.0 : pow(f2, 0.375); w1 = pow(w1, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref1, scanpow1))); w2 = pow(w2, mix(2.0*abs(scans).xxx + 1.0, 1.0.xxx, mix(1.0.xxx, cref2, scanpow2))); - + + if (abs(clips) > 0.005) + { + sy = mc1; vec3 l1 = sqrt(w1*wt1); vec3 l2 = sqrt(w2*wt2); + one = (clips > 0.0) ? w1 : mix(w1, l1, sy); + float sat = 1.0001-min(min(cref1.r,cref1.g),cref1.b); + color1 = mix(color1, plant(pow(color1, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + sy = mc2; + sat = 1.0001-min(min(cref2.r,cref2.g),cref2.b); + one = (clips > 0.0) ? w2 : mix(w2, l2, sy); + color2 = mix(color2, plant(pow(color2, 0.70.xxx-0.325*sat),sy), pow(sat,0.3333)*one*abs(clips)); + } color = (gc(color1)*w1 + gc(color2)*w2); color = min(color, 1.0); diff --git a/crt/shaders/guest/hd/deconvergence-hd.slang b/crt/shaders/guest/hd/deconvergence-hd.slang index 6c29fca..b78f62e 100644 --- a/crt/shaders/guest/hd/deconvergence-hd.slang +++ b/crt/shaders/guest/hd/deconvergence-hd.slang @@ -40,7 +40,6 @@ layout(std140, set = 0, binding = 0) uniform UBO float bloom; float halation; float slotms; - float mclip; float mask_gamma; float gamma_out; float overscanX; @@ -78,6 +77,9 @@ layout(std140, set = 0, binding = 0) uniform UBO float smask_mit; float mask_zoom; float no_scanlines; + float bmask; + float bmask1; + float hmask1; } global; @@ -101,15 +103,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter bloom " Bloom Strength" 0.0 -2.0 2.0 0.05 #define bloom global.bloom // bloom effect -#pragma parameter mask_bloom " Mask Bloom" 0.0 0.0 2.0 0.05 +#pragma parameter mask_bloom " Mask Bloom" 0.0 -2.0 2.0 0.05 #define mask_bloom params.mask_bloom // bloom effect -#pragma parameter bloom_dist " Bloom Distribution" 0.0 0.0 3.0 0.05 +#pragma parameter bloom_dist " Bloom Distribution" 0.0 -2.0 3.0 0.05 #define bloom_dist global.bloom_dist // bloom effect distribution #pragma parameter halation " Halation Strength" 0.0 -2.0 2.0 0.025 #define halation global.halation // halation effect +#pragma parameter bmask1 " Bloom Mask Strength" 0.0 -1.0 1.0 0.025 +#define bmask1 global.bmask1 // bloom/halation mask strength + +#pragma parameter hmask1 " Halation Mask Strength" 0.5 0.0 1.0 0.025 +#define hmask1 global.hmask1 // bloom/halation mask strength + #pragma parameter brightboost " Bright Boost Dark Pixels" 1.40 0.25 10.0 0.05 #define brightboost params.brightboost // adjust brightness @@ -171,21 +179,21 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter masksize " CRT Mask Size" 1.0 1.0 4.0 1.0 #define masksize params.masksize // Mask Size -#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -4.0 4.0 1.0 +#pragma parameter mask_zoom " CRT Mask Zoom (+ mask width)" 0.0 -5.0 5.0 1.0 #define mask_zoom global.mask_zoom // Mask Size +#pragma parameter mshift " (Transform to) Shadow Mask" 0.0 0.0 1.0 0.5 +#define mshift params.mshift // do the "shadow mask" + +#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 +#define mask_layout params.mask_layout // mask layout: RGB or BGR + #pragma parameter maskDark " Lottes maskDark" 0.5 0.0 2.0 0.05 #define maskDark params.maskDark // Dark "Phosphor" #pragma parameter maskLight " Lottes maskLight" 1.5 0.0 2.0 0.05 #define maskLight params.maskLight // Light "Phosphor" -#pragma parameter mshift " Mask Shift/Stagger" 0.0 -8.0 8.0 0.5 -#define mshift params.mshift // mask 'line' shift/stagger - -#pragma parameter mask_layout " Mask Layout: RGB or BGR (check LCD panel) " 0.0 0.0 1.0 1.0 -#define mask_layout params.mask_layout // mask layout: RGB or BGR - #pragma parameter mask_gamma " Mask gamma" 2.40 1.0 5.0 0.05 #define mask_gamma global.mask_gamma // Mask application gamma @@ -204,15 +212,15 @@ layout(std140, set = 0, binding = 0) uniform UBO #pragma parameter slotms " Slot Mask Thickness" 1.0 1.0 4.0 1.0 #define slotms global.slotms // Slot Mask Thickness -#pragma parameter mclip " Keep Mask effect with clipping" 0.0 0.0 1.0 0.05 -#define mclip global.mclip // - #pragma parameter smoothmask " Smooth Masks in bright scanlines" 0.0 0.0 1.0 1.0 #define smoothmask global.smoothmask #pragma parameter smask_mit " Mitigate Slotmask Interaction" 0.0 0.0 1.0 0.05 #define smask_mit global.smask_mit +#pragma parameter bmask " Base (black) Mask strength" 0.0 0.0 0.25 0.01 +#define bmask global.bmask + #pragma parameter gamma_out " Gamma out" 1.75 1.0 5.0 0.05 #define gamma_out global.gamma_out // output gamma @@ -281,14 +289,7 @@ vec3 Mask(vec2 pos, float mx, float mb) vec3 mask = vec3(maskDark, maskDark, maskDark); vec3 one = vec3(1.0); - // No mask - if (shadowMask == -1.0) - { - mask = one; - } - - // Phosphor. - else if (shadowMask == 0.0) + if (shadowMask == 0.0) { float mc = 1.0 - max(maskstr, 0.0); pos.x = fract(pos.x*0.5); @@ -557,7 +558,7 @@ vec3 noise(vec3 v){ return v; } -void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) +void fetch_pixel (inout vec3 c, inout vec3 b, inout vec3 g, vec2 coord, vec2 bcoord) { float stepx = OutputSize.z; float stepy = OutputSize.w; @@ -583,8 +584,6 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) dy = posy * dy; } - // if (global.dctypex > 0.025 || global.dctypey > 0.025) ds *= sqrt(posx*posx*sign(global.dctypex) + posy*posy*sign(global.dctypey)); - vec2 rc = global.deconrr * dx + global.deconrry*dy; vec2 gc = global.deconrg * dx + global.deconrgy*dy; vec2 bc = global.deconrb * dx + global.deconrby*dy; @@ -601,8 +600,15 @@ void fetch_pixel (inout vec3 c, inout vec3 b, vec2 coord, vec2 bcoord) b1 = COMPAT_TEXTURE(BloomPass, bcoord + bc).b; d = vec3(r1, g1, b1); - b = clamp(mix(b, d, ds), 0.0, 1.0); -} + b = g = mix(b, d, min(ds,1.0)); + + r1 = COMPAT_TEXTURE(GlowPass, bcoord + rc).r; + g1 = COMPAT_TEXTURE(GlowPass, bcoord + gc).g; + b1 = COMPAT_TEXTURE(GlowPass, bcoord + bc).b; + + d = vec3(r1, g1, b1); + g = mix(g, d, min(ds,1.0)); +} void main() @@ -635,14 +641,15 @@ void main() // color and bloom fetching vec3 color = COMPAT_TEXTURE(Source,pos1).rgb; vec3 Bloom = COMPAT_TEXTURE(BloomPass, pos).rgb; + vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(global.deconrgy) + abs(global.deconrb) + abs(global.deconrby)) > 0.2) - fetch_pixel(color, Bloom, pos1, pos); // deconvergence + fetch_pixel(color, Bloom, Glow, pos1, pos); // deconvergence float cm = igc(max(max(color.r,color.g),color.b)); float mx1 = COMPAT_TEXTURE(Source, pos1 ).a; float colmx = max(mx1, cm); - float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); + float w3 = min((cm + 0.0001) / (colmx + 0.0005), 1.0); if(interb) w3 = 1.0; vec2 dx = vec2(0.001, 0.0); float mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; @@ -657,42 +664,45 @@ if ((abs(global.deconrr) + abs(global.deconrry) + abs(global.deconrg) + abs(glob dx = vec2(global.OriginalSize.z, 0.0)*0.25; mx0 = COMPAT_TEXTURE(Source, pos1 - dx).a; mx2 = COMPAT_TEXTURE(Source, pos1 + dx).a; - float mb = 1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0); + float mb = (1.0 - min(abs(mx0-mx2)/(0.5+mx1), 1.0)); // Apply Mask vec3 orig1 = color; vec3 cmask = one; - - vec2 maskcoord = gl_FragCoord.xy * 1.00001; - - vec2 scoord = maskcoord; - + vec3 cmask1 = one; + vec3 cmask2 = one; + // mask widths and mask dark compensate (fractional part) values - float mwidths[14] = float[14] (2.0, 3.0, 3.0, 3.0, 6.0, 2.4, 3.5, 2.4, 3.25, 3.5, 4.5, 4.25, 7.5, 6.25); float mwidth = mwidths[int(shadowMask)]; float mask_compensate = fract(mwidth); + +if (shadowMask > -0.5) +{ + vec2 maskcoord = gl_FragCoord.xy * 1.00001; + vec2 scoord = maskcoord; + mwidth = floor(mwidth) * masksize; float swidth = mwidth; bool zoomed = (abs(mask_zoom) > 0.75); float mscale = 1.0; vec2 maskcoord0 = maskcoord; maskcoord.y = floor(maskcoord.y/masksize); + float mwidth1 = max(mwidth + mask_zoom, 2.0); -if ( abs(mshift) > 0.75 ) +if ( mshift > 0.25 ) { - float stagg_lvl = 1.0; if (fract(abs(mshift)) > 0.25 && abs(mshift) > 1.25) stagg_lvl = 2.0; - float next_line = float(fract((maskcoord.y/stagg_lvl)*0.5) > 0.25); - maskcoord0.x = (mshift > -0.25) ? (maskcoord0.x + next_line * floor(mshift)) : (maskcoord0.x + floor(maskcoord.y / stagg_lvl) * floor(abs(mshift))); + float stagg_lvl = 1.0; if (fract(mshift) > 0.25) stagg_lvl = 2.0; + float next_line = float(floor(mod(maskcoord.y, 2.0*stagg_lvl)) < stagg_lvl); + maskcoord0.x = maskcoord0.x + next_line * 0.5 * mwidth1; } maskcoord = maskcoord0/masksize; if (mask_zoom >= 0.0) maskcoord = floor(maskcoord); if ( !zoomed ) - cmask*= Mask(maskcoord, mx, mb); + cmask*= Mask(floor(maskcoord), mx, mb); else{ - float mwidth1 = max(mwidth + mask_zoom, 2.0); mscale = mwidth1/mwidth; float mlerp = fract(maskcoord.x/mscale); float mcoord = floor(maskcoord.x/mscale); if (shadowMask == 12.0 && mask_zoom == -2.0) mcoord = ceil(maskcoord.x/mscale); @@ -708,15 +718,16 @@ else{ smask = SlotMask(scoord + vec2(sm_offset,0.0), mx, swidth); smask = clamp(smask + mix(smask_mit, 0.0, min(w3, pow(w3*max(max(orig1.r,orig1.g),orig1.b), 0.33333))), 0.0, 1.0); - + + cmask2 = cmask; cmask*=smask; - vec3 cmask1 = cmask; + cmask1 = cmask; - if (mask_bloom > 0.025) + if (abs(mask_bloom) > 0.025) { float maxbl = max(max(max(Bloom.r,Bloom.g),Bloom.b), mxg); - maxbl = maxbl * mix(1.0, 2.0-colmx, bloom_dist); - cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); + maxbl = maxbl * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + if (mask_bloom > 0.025) cmask = max(min(cmask + maxbl*mask_bloom, 1.0), cmask); else cmask = max(mix(cmask, cmask*(1.0-0.5*maxbl) + plant(pow(Bloom,0.35.xxx),maxbl), -mask_bloom),cmask); } color = pow(color, vec3(mask_gamma/gamma_in)); @@ -724,60 +735,61 @@ else{ color = min(color,1.0); color = pow(color, vec3(gamma_in/mask_gamma)); - cmask = min(cmask, 1.0); cmask1 = min(cmask1, 1.0); - - float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); +} + + float dark_compensate = mix(max( clamp( mix (mcut, maskstr, mx),0.0, 1.0) - 1.0 + mask_compensate, 0.0) + 1.0, 1.0, mx); if(shadowMask < -0.5) dark_compensate = 1.0; float bb = mix(brightboost, brightboost1, mx) * dark_compensate; color*=bb; - vec3 Glow = COMPAT_TEXTURE(GlowPass, pos).rgb; vec3 Ref = COMPAT_TEXTURE(LinearizePass, pos).rgb; float maxb = COMPAT_TEXTURE(BloomPass, pos).a; float vig = COMPAT_TEXTURE(PrePass, clamp(pos, 0.0+0.5*global.OriginalSize.zw, 1.0-0.5*global.OriginalSize.zw)).a; vec3 Bloom1 = Bloom; + vec3 bcmask = mix(one, cmask, bmask1); + vec3 hcmask = mix(one, cmask, hmask1); -if (abs(bloom) > 0.025) -{ - if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); - Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); - Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); - Bloom1 = Bloom1 * mix(1.0, 2.0-colmx, bloom_dist); - color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); -} + if (abs(bloom) > 0.025) + { + if (bloom < -0.01) Bloom1 = plant(Bloom, maxb); + Bloom1 = min(Bloom1*(orig1+color), max(0.5*(colmx + orig1 - color),0.001*Bloom1)); + Bloom1 = 0.5*(Bloom1 + mix(Bloom1, mix(colmx*orig1, Bloom1, 0.5), 1.0-color)); + Bloom1 = bcmask*Bloom1 * max(mix(1.0, 2.0-colmx, bloom_dist), 0.0); + color = pow(pow(color, vec3(mask_gamma/gamma_in)) + abs(bloom) * pow(Bloom1, vec3(mask_gamma/gamma_in)), vec3(gamma_in/mask_gamma)); + } - color = min(color, mix(one, cmask1, mclip)); - - if (!interb) color = declip(color, mix(1.0, w3, 0.6)); else w3 = 1.0; + if (!interb) color = declip(min(color,1.0), mix(1.0, w3, 0.6)); if (halation > 0.01) { Bloom = mix(0.5*(Bloom + Bloom*Bloom), 0.75*Bloom*Bloom, colmx); - color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.6)*Bloom*halation; } + color = color + 2.0*max((2.0*mix(maxb*maxb, maxb, colmx)-0.5*max(max(Ref.r,Ref.g),Ref.b)),0.25)*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*halation; } else if (halation < -0.01) { float mbl = max(max(Bloom.r,Bloom.g),Bloom.b); Bloom = plant(Bloom + Ref + orig1 + Bloom*Bloom*Bloom, min(mbl*mbl,0.75)); - color = color + 2.0*mix(1.0,w3,0.5*colmx)*mix(one,cmask,0.5)*Bloom*(-halation); } + color = color + 2.0*mix(1.0,w3,0.5*colmx)*hcmask*Bloom*(-halation); } + float w = 0.25 + 0.60*mix(w3, 1.0, sqrt(colmx)); - if (smoothmask > 0.5) { w3 = mix(1.0, w3, smoothstep(0.3, 0.6, mx1)); color = max(min(color/w3, 1.0)*w3, min(color,color*(1.0-w3))); } + if (smoothmask > 0.5) { color = min(color,1.0); color = max(min(color/w3, 1.0)*w3, min(orig1*bb,color*(1.0-w3))); } - if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, 0.7*colmx); + if (global.m_glow < 0.5) Glow = mix(Glow, 0.25*color, colmx); else { maxb = max(max(Glow.r,Glow.g),Glow.b); - orig1 = plant(orig1 + 0.001*Ref, 1.0); + vec3 orig2 = plant(orig1 + 0.001*Ref, 1.0); Bloom = plant(Glow, 1.0); - Ref = abs(orig1-Bloom); - mx0 = max(max(orig1.g,orig1.g),orig1.b)-min(min(orig1.g,orig1.g),orig1.b); + Ref = abs(orig2-Bloom); + mx0 = max(max(orig2.g,orig2.g),orig2.b)-min(min(orig2.g,orig2.g),orig2.b); mx2 = max(max(Bloom.g,Bloom.g),Bloom.b)-min(min(Bloom.g,Bloom.g),Bloom.b); - Bloom = mix(maxb*min(Bloom,orig1), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); + Bloom = mix(maxb*min(Bloom,orig2), w*mix(mix(Glow, max(max(Ref.g,Ref.g),Ref.b)*Glow, max(mx,mx0)), mix(color, Glow, mx2), max(mx0,mx2)*Ref), min(sqrt((1.10-mx0)*(0.10+mx2)),1.0)); Glow = mix(global.m_glow_low*Glow, global.m_glow_high*Bloom, pow(colmx, global.m_glow_dist/gamma_in)); } - if (glow >= 0.0 && global.m_glow < 0.5) color = color + 0.5*Glow*glow; - else { if(global.m_glow > 0.5) cmask1 = max(mix(one, cmask1, global.m_glow_mask),0.0); color = color + abs(glow)*cmask1*Glow; } + if (global.m_glow < 0.5) { + if (glow >= 0.0) color = color + 0.5*Glow*glow; else color = color + abs(glow)*min(cmask2*cmask2,1.0)*Glow; } + else { cmask1 = clamp(mix(one, cmask1, global.m_glow_mask),0.0, 1.0); color = color + abs(glow)*cmask1*Glow; } color = min(color, 1.0); @@ -791,6 +803,9 @@ if (abs(bloom) > 0.025) if (global.noisetype < 0.5) color = mix(color, noise0, 0.25*abs(global.addnoised) * rc); else color = min(color * mix(1.0, 1.5*noise0.x, 0.5*abs(global.addnoised)), 1.0); } + + colmx = max(max(orig1.r,orig1.g),orig1.b); + color = color + bmask*mix(cmask2, 0.125*(1.0-colmx)*color, min(20.0*colmx, 1.0)); FragColor = vec4(color*vig*humbar(mix(pos.y, pos.x, global.bardir))*global.post_br*corner(pos0), 1.0); } diff --git a/crt/shaders/guest/hd/gaussian_horizontal.slang b/crt/shaders/guest/hd/gaussian_horizontal.slang index d23c648..46340c2 100644 --- a/crt/shaders/guest/hd/gaussian_horizontal.slang +++ b/crt/shaders/guest/hd/gaussian_horizontal.slang @@ -58,7 +58,7 @@ layout(push_constant) uniform Push #pragma parameter SIZEH " Horizontal Glow Radius" 6.0 1.0 50.0 1.0 #define SIZEH params.SIZEH -#pragma parameter SIGMA_H " Horizontal Glow Sigma" 1.20 0.20 15.0 0.10 +#pragma parameter SIGMA_H " Horizontal Glow Sigma" 1.20 0.20 15.0 0.05 #define SIGMA_H params.SIGMA_H diff --git a/crt/shaders/guest/hd/gaussian_vertical.slang b/crt/shaders/guest/hd/gaussian_vertical.slang index 29da738..024c116 100644 --- a/crt/shaders/guest/hd/gaussian_vertical.slang +++ b/crt/shaders/guest/hd/gaussian_vertical.slang @@ -35,7 +35,7 @@ layout(push_constant) uniform Push #pragma parameter SIZEV " Vertical Glow Radius" 6.0 1.0 50.0 1.0 #define SIZEV params.SIZEV -#pragma parameter SIGMA_V " Vertical Glow Sigma" 1.20 0.20 15.0 0.10 +#pragma parameter SIGMA_V " Vertical Glow Sigma" 1.20 0.20 15.0 0.05 #define SIGMA_V params.SIGMA_V layout(std140, set = 0, binding = 0) uniform UBO