From 2a90a8805509a77e1e19bd0b6a0dc4e4e3c380fe Mon Sep 17 00:00:00 2001 From: Hyllian Date: Sat, 15 Jun 2024 11:02:30 -0300 Subject: [PATCH] Add crt-consumer and crt-cyclon. Update others. (#3223) - Add crt-consumer.glsl; - Add crt-cyclon.fx and its bezel.png texture; - Fix crt-newpixie.fx Frame adjust to game's aspect ratio; - Update others shaders to the new functions to get uniform values. --- .../shaders/dolphinfx/crt/CRT-CONSUMER.glsl | 780 ++++++++++++++++++ .../shaders/dolphinfx/crt/CRT-EASYMODE.glsl | 2 +- .../shaders/dolphinfx/crt/CRT-HYLLIAN.glsl | 2 +- .../dolphinfx/crt/ZFAST-CRT-COMPOSITE.glsl | 2 +- .../shaders/dolphinfx/edge-smoothing/XBR.glsl | 2 +- .../dolphinfx/pixel-art/PIXELLATE.glsl | 2 +- .../shaders/reshade/Shaders/CRT-NewPixie.fx | 5 +- .../shaders/reshade/Shaders/crt-cyclon.fx | 555 +++++++++++++ .../reshade/Textures/crt-cyclon/bezel.png | Bin 0 -> 7677 bytes 9 files changed, 1344 insertions(+), 6 deletions(-) create mode 100644 data/resources/shaders/dolphinfx/crt/CRT-CONSUMER.glsl create mode 100644 data/resources/shaders/reshade/Shaders/crt-cyclon.fx create mode 100644 data/resources/shaders/reshade/Textures/crt-cyclon/bezel.png diff --git a/data/resources/shaders/dolphinfx/crt/CRT-CONSUMER.glsl b/data/resources/shaders/dolphinfx/crt/CRT-CONSUMER.glsl new file mode 100644 index 000000000..0eeb87076 --- /dev/null +++ b/data/resources/shaders/dolphinfx/crt/CRT-CONSUMER.glsl @@ -0,0 +1,780 @@ +// Crt-Consumer + +// 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. + + + +/* +[configuration] + + +[OptionRangeFloat] +GUIName = Pre-Scale Sharpening +OptionName = PRE_SCALE +MinValue = 1.0 +MaxValue = 4.0 +StepAmount = 0.1 +DefaultValue = 1.5 + +[OptionRangeFloat] +GUIName = Convergence X +OptionName = blurx +MinValue = -4.0 +MaxValue = 4.0 +StepAmount = 0.05 +DefaultValue = 0.25 + +[OptionRangeFloat] +GUIName = Convergence Y +OptionName = blury +MinValue = -4.0 +MaxValue = 4.0 +StepAmount = 0.05 +DefaultValue = -0.1 + +[OptionRangeFloat] +GUIName = Curvature X +OptionName = warpx +MinValue = 0.0 +MaxValue = 0.12 +StepAmount = 0.01 +DefaultValue = 0.03 + +[OptionRangeFloat] +GUIName = Curvature Y +OptionName = warpy +MinValue = 0.0 +MaxValue = 0.12 +StepAmount = 0.01 +DefaultValue = 0.04 + +[OptionRangeFloat] +GUIName = Corner size +OptionName = corner +MinValue = 0.0 +MaxValue = 0.10 +StepAmount = 0.01 +DefaultValue = 0.03 + +[OptionRangeFloat] +GUIName = Border Smoothness +OptionName = smoothness +MinValue = 100.0 +MaxValue = 600.0 +StepAmount = 5.0 +DefaultValue = 400.0 + +[OptionRangeFloat] +GUIName = Interlacing Toggle +OptionName = inter +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 1.0 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Interlacing Downscale Scanlines +OptionName = Downscale +MinValue = 1.0 +MaxValue = 8.0 +StepAmount = 1. +DefaultValue = 2.0 + +[OptionRangeFloat] +GUIName = Beam low +OptionName = scanlow +MinValue = 1.0 +MaxValue = 15.0 +StepAmount = 1.0 +DefaultValue = 6.0 + +[OptionRangeFloat] +GUIName = Beam high +OptionName = scanhigh +MinValue = 1.0 +MaxValue = 15.0 +StepAmount = 1.0 +DefaultValue = 8.0 + +[OptionRangeFloat] +GUIName = Scanlines dark +OptionName = beamlow +MinValue = 0.5 +MaxValue = 2.5 +StepAmount = 0.0 +DefaultValue = 1.45 + +[OptionRangeFloat] +GUIName = Scanlines bright +OptionName = beamhigh +MinValue = 0.5 +MaxValue = 2.5 +StepAmount = 0.0 +DefaultValue = 1.05 + +[OptionRangeFloat] +GUIName = Protect White On Masks +OptionName = preserve +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 0.01 +DefaultValue = 0.98 + +[OptionRangeFloat] +GUIName = Bright boost dark pixels +OptionName = brightboost1 +MinValue = 0.0 +MaxValue = 3.0 +StepAmount = 0.05 +DefaultValue = 1.25 + +[OptionRangeFloat] +GUIName = Bright boost bright pixels +OptionName = brightboost2 +MinValue = 0.0 +MaxValue = 3.0 +StepAmount = 0.05 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Glow pixels per axis +OptionName = glow +MinValue = 1.0 +MaxValue = 6.0 +StepAmount = 1.0 +DefaultValue = 3.0 + +[OptionRangeFloat] +GUIName = Glow quality +OptionName = quality +MinValue = 0.25 +MaxValue = 4.0 +StepAmount = 0.05 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Glow intensity +OptionName = glow_str +MinValue = 0.0001 +MaxValue = 2.0 +StepAmount = 0.05 +DefaultValue = 0.3 + +[OptionRangeFloat] +GUIName = Add Noise +OptionName = nois +MinValue = 0.0 +MaxValue = 32.0 +StepAmount = 1.0 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Post Brightness +OptionName = postbr +MinValue = 0.0 +MaxValue = 2.5 +StepAmount = 0.02 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Palette Fixes. Sega, PUAE Atari ST dark colors +OptionName = palette_fix +MinValue = 0.0 +MaxValue = 2.0 +StepAmount = 1.0 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Mask Type +OptionName = Shadowmask +MinValue = -1.0 +MaxValue = 8.0 +StepAmount = 1. +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Mask Size +OptionName = masksize +MinValue = 1.0 +MaxValue = 2.0 +StepAmount = 1.0 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Mask dark +OptionName = MaskDark +MinValue = 0.0 +MaxValue = 2.0 +StepAmount = 0.1 +DefaultValue = 0.2 + +[OptionRangeFloat] +GUIName = Mask light +OptionName = MaskLight +MinValue = 0.0 +MaxValue = 2.0 +StepAmount = 0.1 +DefaultValue = 1.5 + +[OptionRangeFloat] +GUIName = Slot Mask Strength +OptionName = slotmask +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 0.05 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Slot Mask Width +OptionName = slotwidth +MinValue = 1.0 +MaxValue = 6.0 +StepAmount = 0.5 +DefaultValue = 2.0 + +[OptionRangeFloat] +GUIName = Slot Mask Height: 2x1 or 4x1 +OptionName = double_slot +MinValue = 1.0 +MaxValue = 2.0 +StepAmount = 1.0 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Slot Mask Size +OptionName = slotms +MinValue = 1.0 +MaxValue = 2.0 +StepAmount = 1.0 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Gamma Out +OptionName = GAMMA_OUT +MinValue = 0.0 +MaxValue = 4.0 +StepAmount = 0.05 +DefaultValue = 2.25 + +[OptionRangeFloat] +GUIName = Saturation +OptionName = sat +MinValue = 0.0 +MaxValue = 2.0 +StepAmount = 0.05 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Contrast, 1.0:Off +OptionName = contrast +MinValue = 0.00 +MaxValue = 2.00 +StepAmount = 0.05 +DefaultValue = 1.0 + +[OptionRangeFloat] +GUIName = Color Temperature % +OptionName = WP +MinValue = -100.0 +MaxValue = 100.0 +StepAmount = 5. +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Red-Green Tint +OptionName = rg +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Red-Blue Tint +OptionName = rb +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Green-Red Tint +OptionName = gr +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Green-Blue Tint +OptionName = gb +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Blue-Red Tint +OptionName = br +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Blue-Green Tint +OptionName = bg +MinValue = -1.0 +MaxValue = 1.0 +StepAmount = 0.005 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Vignette On/Off +OptionName = vignette +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 1.0 +DefaultValue = 0.0 + +[OptionRangeFloat] +GUIName = Vignette Power +OptionName = vpower +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 0.01 +DefaultValue = 0.15 + +[OptionRangeFloat] +GUIName = Vignette strength +OptionName = vstr +MinValue = 0.0 +MaxValue = 50.0 +StepAmount = 1.0 +DefaultValue = 40.0 + +[OptionRangeFloat] +GUIName = Switch off shader +OptionName = alloff +MinValue = 0.0 +MaxValue = 1.0 +StepAmount = 1.0 +DefaultValue = 0.0 + + +[/configuration] +*/ + +#define iTime (float(GetTime())/2.0) +#define iTimer (float(GetTime())/60.0) + +#define SourceSize (vec4(1.0/GetInvNativePixelSize(),GetInvNativePixelSize())) + +vec2 Warp(vec2 pos) +{ + pos = pos * 2.0 - 1.0; + pos *= vec2(1.0 + (pos.y * pos.y) * warpx, 1.0 + (pos.x * pos.x) * warpy); + return pos * 0.5 + 0.5; +} + +float sw(float y, float l) +{ + float beam = mix(scanlow, scanhigh, y); + float scan = mix(beamlow, beamhigh, l); + float ex = y * scan; + return exp2(-beam * ex * ex); +} + +vec3 mask(vec2 x, vec3 col, float l) +{ + x = floor(x / masksize); + + if (Shadowmask == 0.0) + { + float m = fract(x.x * 0.4999); + if (m < 0.4999) return vec3(1.0, MaskDark, 1.0); + else return vec3(MaskDark, 1.0, MaskDark); + } + + else if (Shadowmask == 1.0) + { + vec3 Mask = vec3(MaskDark, MaskDark, MaskDark); + float line = MaskLight; + float odd = 0.0; + + if (fract(x.x / 6.0) < 0.5) odd = 1.0; + if (fract((x.y + odd) / 2.0) < 0.5) line = MaskDark; + + float m = fract(x.x / 3.0); + if (m < 0.333) Mask.b = MaskLight; + else if (m < 0.666) Mask.g = MaskLight; + else Mask.r = MaskLight; + + Mask *= line; + return Mask; + } + + else if (Shadowmask == 2.0) + { + float m = fract(x.x*0.3333); + if (m < 0.3333) return vec3(MaskDark, MaskDark, MaskLight); + if (m < 0.6666) return vec3(MaskDark, MaskLight, MaskDark); + else return vec3(MaskLight, MaskDark, MaskDark); + } + + if (Shadowmask == 3.0) + { + float m = fract(x.x * 0.5); + if (m < 0.5) return vec3(1.0, 1.0, 1.0); + else return vec3(MaskDark, MaskDark, MaskDark); + } + + else if (Shadowmask == 4.0) + { + vec3 Mask = vec3(col.rgb); + float line = MaskLight; + float odd = 0.0; + + if (fract(x.x / 4.0) < 0.5) odd = 1.0; + if (fract((x.y + odd) / 2.0) < 0.5) line = MaskDark; + + float m = fract(x.x / 2.0); + if (m < 0.5) { Mask.r = 1.0; Mask.b = 1.0; } + else Mask.g = 1.0; + + Mask *= line; + return Mask; + } + + else if (Shadowmask == 5.0) + { + vec3 Mask = vec3(1.0, 1.0, 1.0); + + if (fract(x.x / 4.0) < 0.5) + { + if (fract(x.y / 3.0) < 0.666) + { + if (fract(x.x / 2.0) < 0.5) Mask = vec3(1.0, MaskDark, 1.0); + else Mask = vec3(MaskDark, 1.0, MaskDark); + } + else Mask *= l; + } + else if (fract(x.x / 4.0) >= 0.5) + { + if (fract(x.y / 3.0) > 0.333) + { + if (fract(x.x / 2.0) < 0.5) Mask = vec3(1.0, MaskDark, 1.0); + else Mask = vec3(MaskDark, 1.0, MaskDark); + } + else Mask *= l; + } + + return Mask; + } + + else if (Shadowmask == 6.0) + { + vec3 Mask = vec3(MaskDark, MaskDark, MaskDark); + if (fract(x.x / 6.0) < 0.5) + { + if (fract(x.y / 4.0) < 0.75) + { + if (fract(x.x / 3.0) < 0.3333) Mask.r = MaskLight; + else if (fract(x.x / 3.0) < 0.6666) Mask.g = MaskLight; + else Mask.b = MaskLight; + } + else Mask * l * 0.9; + } + else if (fract(x.x / 6.0) >= 0.5) + { + if (fract(x.y / 4.0) >= 0.5 || fract(x.y / 4.0) < 0.25) + { + if (fract(x.x / 3.0) < 0.3333) Mask.r = MaskLight; + else if (fract(x.x / 3.0) < 0.6666) Mask.g = MaskLight; + else Mask.b = MaskLight; + } + else Mask * l * 0.9; + } + return Mask; + } + + else if (Shadowmask == 7.0) + { + float m = fract(x.x * 0.3333); + + if (m < 0.3333) return vec3(MaskDark, MaskLight, MaskLight * col.b); //Cyan + if (m < 0.6666) return vec3(MaskLight * col.r, MaskDark, MaskLight); //Magenta + else return vec3(MaskLight, MaskLight * col.g, MaskDark); //Yellow + } + + else if (Shadowmask == 8.0) + { + vec3 Mask = vec3(MaskDark, MaskDark, MaskDark); + + float bright = MaskLight; + float left = 0.0; + if (fract(x.x / 6.0) < 0.5) left = 1.0; + + float m = fract(x.x / 3.0); + if (m < 0.333) Mask.b = 0.9; + else if (m < 0.666) Mask.g = 0.9; + else Mask.r = 0.9; + + if (mod(x.y, 2.0) == 1.0 && left == 1.0 || mod(x.y, 2.0) == 0.0 && left == 0.0) + Mask *= bright; + + return Mask; + } + + else return vec3(1.0, 1.0, 1.0); +} + +float SlotMask(vec2 pos, vec3 c) +{ + if (slotmask == 0.0) return 1.0; + + pos = floor(pos / slotms); + float mx = pow(max(max(c.r, c.g), c.b), 1.33); + float mlen = slotwidth * 2.0; + float px = fract(pos.x / mlen); + float py = floor(fract(pos.y / (2.0 * double_slot)) * 2.0 * double_slot); + float slot_dark = mix(1.0 - slotmask, 1.0 - 0.80 * slotmask, mx); + float slot = 1.0 + 0.7 * slotmask * (1.0 - mx); + + if (py == 0.0 && px < 0.5) slot = slot_dark; + else if (py == double_slot && px >= 0.5) slot = slot_dark; + + return slot; +} + +mat4 contrastMatrix(float contrast) +{ + float t = (1.0 - contrast) / 2.0; + + return mat4(contrast, 0, 0, 0, + 0, contrast, 0, 0, + 0, 0, contrast, 0, + t, t, t, 1); +} + +mat3 vign(float l) +{ +// vec2 vpos = vTexCoord; + vec2 vpos = GetCoordinates(); + vpos *= 1.0 - vpos.xy; + + float vig = vpos.x * vpos.y * vstr; + vig = min(pow(vig, vpower), 1.0); + if (vignette == 0.0) vig = 1.0; + + return mat3(vig, 0, 0, + 0, vig, 0, + 0, 0, vig); +} + +vec3 saturation(vec3 textureColor) +{ + float luminance = length(textureColor.rgb) * 0.5775; + + vec3 luminanceWeighting = vec3(0.4, 0.5, 0.1); + if (luminance < 0.5) luminanceWeighting.rgb = (luminanceWeighting.rgb * luminanceWeighting.rgb) + + (luminanceWeighting.rgb * luminanceWeighting.rgb); + + luminance = dot(textureColor.rgb, luminanceWeighting); + vec3 greyScaleColor = vec3(luminance, luminance, luminance); + + vec3 res = vec3(mix(greyScaleColor, textureColor.rgb, sat)); + return res; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +vec3 glow0 (vec2 texcoord, vec3 col) +{ + + // the more quality, the smaller the offset and better quality, less visible glow too + vec2 size = SourceSize.zw/quality; + + vec3 c01; + vec3 sum = vec3(0.0); + + // glow = pixels per axis, the more the slower! + + for (float x = -glow; x <= glow; x = x+1.0) + { + + // multiply texture, the more far away the less pronounced + float factor = 1.0/glow; + for (float y = -glow; y <= glow; y = y+1.0) + { + + vec2 offset = vec2(x, y) * size; + + c01 = SampleLocation(texcoord + offset).rgb*factor; c01 = c01*c01; + + sum += c01; + } + } + + return (glow_str * sum / (glow * glow )) ; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// + +float noise(vec2 co) +{ + return fract(sin(iTimer * dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +float corner0(vec2 coord) +{ + coord = (coord - vec2(0.5, 0.5)) * 1.0 + vec2(0.5, 0.5); + coord = min(coord, vec2(1.0, 1.0) - coord) * vec2(1.0, SourceSize.y / SourceSize.x); + + vec2 cdist = vec2(corner, corner); + coord = (cdist - min(coord, cdist)); + float dist = sqrt(dot(coord, coord)); + + return clamp((cdist.x - dist) * smoothness, 0.0, 1.0); +} + +const mat3 D65_to_XYZ = mat3( + 0.4306190, 0.2220379, 0.0201853, + 0.3415419, 0.7066384, 0.1295504, + 0.1783091, 0.0713236, 0.9390944); + +const mat3 XYZ_to_D65 = mat3( + 3.0628971, -0.9692660, 0.0678775, + -1.3931791, 1.8760108, -0.2288548, + -0.4757517, 0.0415560, 1.0693490); + +const mat3 D50_to_XYZ = mat3( + 0.4552773, 0.2323025, 0.0145457, + 0.3675500, 0.7077956, 0.1049154, + 0.1413926, 0.0599019, 0.7057489); + +const mat3 XYZ_to_D50 = mat3( + 2.9603944, -0.9787684, 0.0844874, + -1.4678519, 1.9161415, -0.2545973, + -0.4685105, 0.0334540, 1.4216174); + +void main() +{ + vec2 vTexCoord = GetCoordinates(); + vec2 pos = Warp(vTexCoord.xy); + vec2 tex_size = 1.0 / GetInvNativePixelSize(); + vec2 OutputSize = GetWindowSize(); + + + vec2 pC4 = (pos + 0.5/tex_size); + vec2 fp = fract(pos * tex_size); + if (inter < 0.5 && tex_size.y > 400.0){ fp.y = fract(pos.y * tex_size.y*1.0/Downscale);} + + vec4 res = vec4(1.0); + + if (alloff == 1.0) + res = SampleLocation(pC4); + else + { + + vec2 texel = pos * tex_size; + vec2 texel_floored = floor(texel); + + float scale = PRE_SCALE; + float region_range = 0.5 - 0.5 / scale; + + // Figure out where in the texel to sample to get correct pre-scaled bilinear. + // Uses the hardware bilinear interpolator to avoid having to sample 4 times manually. + + vec2 center_dist = fp - 0.5; + + vec2 fpp = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5; + + vec2 mod_texel = texel_floored + fpp; + vec2 coords = mod_texel / SourceSize.xy; + + vec3 sample1 = SampleLocation(vec2(coords.x + blurx*SourceSize.z, coords.y - blury*SourceSize.w)).rgb; + vec3 sample2 = SampleLocation(coords).rgb; + vec3 sample3 = SampleLocation(vec2(coords.x - blurx*SourceSize.z, coords.y + blury*SourceSize.w )).rgb; + + vec3 color = vec3(sample1.r * 0.5 + sample2.r * 0.5, + sample1.g * 0.25 + sample2.g * 0.5 + sample3.g * 0.25, + sample2.b * 0.5 + sample3.b * 0.5); + if (palette_fix != 0.0) + { + if (palette_fix == 1.0) color = color* 1.0667; + else if (palette_fix == 2.0) color = color * 2.0; + } + + //COLOR TEMPERATURE FROM GUEST.R-DR.VENOM + if (WP != 0.0) + { + vec3 warmer = D50_to_XYZ * color; + warmer = XYZ_to_D65 * warmer; + + vec3 cooler = D65_to_XYZ * color; + cooler = XYZ_to_D50 * cooler; + + float m = abs(WP) / 100.0; + vec3 comp = (WP < 0.0) ? cooler : warmer; + comp = clamp(comp, 0.0, 1.0); + + color = vec3(mix(color, comp, m)); + } + + mat3 hue = mat3 (1., rg, rb, //red tint + gr, 1., gb, //green tint + br, bg, 1.); //blue tint + + color = hue * color; + + color = (2.0*pow(color,vec3(2.8))) - pow(color,vec3(3.6)); + + float lum = color.r * 0.3 + color.g * 0.6 + color.b * 0.1; + + float f = fract(fp.y -0.5); + + if (inter > 0.5 && tex_size.y > 400.0) color = color; + else + {color = color * sw(f,lum) + color * sw (1.0-f,lum);} + + float lum1 = color.r * 0.3 + color.g * 0.6 + color.b * 0.1; + + + color *= mix(mask((vTexCoord * OutputSize.xy), color,lum1), vec3(1.0), lum1*preserve); + + + if (slotmask != 0.0) color *= SlotMask((vTexCoord * OutputSize.xy) * 1.0001, color); + + color *= mix(brightboost1, brightboost2, max(max(color.r, color.g), color.b)); + + + + color = pow(color,vec3(1.0 / GAMMA_OUT)); + if (glow_str != 0.0) color += glow0(coords,color); + + if (sat != 1.0) color = saturation(color); + if (corner != 0.0) color *= corner0(pC4); + if (nois != 0.0) color *= 1.0 + noise(coords * 2.0) / nois; + + color *= mix(1.0, postbr, lum); + res = vec4(color, 1.0); + if (contrast != 1.0) res = contrastMatrix(contrast) * res; + if (inter > 0.5 && SourceSize.y > 400.0 && fract(iTime) < 0.5) res = res * 0.95; + res.rgb *= vign(lum); + + } + + SetOutput(res); +} diff --git a/data/resources/shaders/dolphinfx/crt/CRT-EASYMODE.glsl b/data/resources/shaders/dolphinfx/crt/CRT-EASYMODE.glsl index 19a93a12e..76159328f 100644 --- a/data/resources/shaders/dolphinfx/crt/CRT-EASYMODE.glsl +++ b/data/resources/shaders/dolphinfx/crt/CRT-EASYMODE.glsl @@ -256,7 +256,7 @@ void main() float scan_weight = 1.0 - pow(cos(vTexCoord.y * 2.0 * PI * SourceSize.y) * 0.5 + 0.5, scan_beam) * GetOption(SCANLINE_STRENGTH); float mask = 1.0 - GetOption(MASK_STRENGTH); - vec2 mod_fac = floor(vTexCoord * GetResolution().xy * SourceSize.xy / (SourceSize.xy * vec2(GetOption(MASK_SIZE), GetOption(MASK_DOT_HEIGHT) * GetOption(MASK_SIZE)))); + vec2 mod_fac = floor(vTexCoord * GetWindowSize().xy * SourceSize.xy / (SourceSize.xy * vec2(GetOption(MASK_SIZE), GetOption(MASK_DOT_HEIGHT) * GetOption(MASK_SIZE)))); int dot_no = int(mod((mod_fac.x + mod(mod_fac.y, 2.0) * GetOption(MASK_STAGGER)) / GetOption(MASK_DOT_WIDTH), 3.0)); vec3 mask_weight; diff --git a/data/resources/shaders/dolphinfx/crt/CRT-HYLLIAN.glsl b/data/resources/shaders/dolphinfx/crt/CRT-HYLLIAN.glsl index f85f360f8..93513ffcc 100644 --- a/data/resources/shaders/dolphinfx/crt/CRT-HYLLIAN.glsl +++ b/data/resources/shaders/dolphinfx/crt/CRT-HYLLIAN.glsl @@ -502,7 +502,7 @@ void main() color = color_boost*GAMMA_OUT(color); - vec2 mask_coords =vTexCoord.xy * GetResolution().xy; + vec2 mask_coords =vTexCoord.xy * GetWindowSize().xy; mask_coords = mix(mask_coords.xy, mask_coords.yx, GetOption(VSCANLINES)); diff --git a/data/resources/shaders/dolphinfx/crt/ZFAST-CRT-COMPOSITE.glsl b/data/resources/shaders/dolphinfx/crt/ZFAST-CRT-COMPOSITE.glsl index 32f64f711..0f5beb338 100644 --- a/data/resources/shaders/dolphinfx/crt/ZFAST-CRT-COMPOSITE.glsl +++ b/data/resources/shaders/dolphinfx/crt/ZFAST-CRT-COMPOSITE.glsl @@ -168,7 +168,7 @@ else { } float steps; if (GetOption(TYPE) == 0.0) steps = 0.5; else steps = 0.3333; - float whichmask = fract(vTexCoord.x*GetResolution().x*steps); + float whichmask = fract(vTexCoord.x*GetWindowSize().x*steps); float mask = 1.0 + float(whichmask < steps) * (-GetOption(MASK_DARK)); colour.rgb = mix(mask*colour, colour, dot(colour.rgb,vec3(maskFade))); diff --git a/data/resources/shaders/dolphinfx/edge-smoothing/XBR.glsl b/data/resources/shaders/dolphinfx/edge-smoothing/XBR.glsl index 811b2f654..d8261d3a6 100644 --- a/data/resources/shaders/dolphinfx/edge-smoothing/XBR.glsl +++ b/data/resources/shaders/dolphinfx/edge-smoothing/XBR.glsl @@ -132,7 +132,7 @@ void main() { vec2 texCoord = GetCoordinates(); vec2 SourceSize = 1.0 / GetInvNativePixelSize(); - float aa_factor = 2.0* (1.0/GetResolution().x) * SourceSize.x; + float aa_factor = 2.0* (1.0/GetWindowSize().x) * SourceSize.x; vec4 edri, edr, edr_l, edr_u, px; // px = pixel, edr = edge detection rule vec4 irlv0, irlv1, irlv2l, irlv2u; diff --git a/data/resources/shaders/dolphinfx/pixel-art/PIXELLATE.glsl b/data/resources/shaders/dolphinfx/pixel-art/PIXELLATE.glsl index c10761680..48cdd50b1 100644 --- a/data/resources/shaders/dolphinfx/pixel-art/PIXELLATE.glsl +++ b/data/resources/shaders/dolphinfx/pixel-art/PIXELLATE.glsl @@ -34,7 +34,7 @@ void main() vec2 vTexCoord = GetCoordinates(); vec2 SourceSize = 1.0 / GetInvNativePixelSize(); vec2 texelSize = 1.0 / SourceSize.xy; - vec2 OutputSize = GetResolution().xy; + vec2 OutputSize = GetWindowSize().xy; vec2 range = vec2(abs(SourceSize.x / (OutputSize.x * SourceSize.x)), abs(SourceSize.y / (OutputSize.y * SourceSize.y))); range = range / 2.0 * 0.999; diff --git a/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx b/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx index 02f21624b..8d2bcfb2a 100644 --- a/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx +++ b/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx @@ -109,6 +109,8 @@ float4 PS_NewPixie_Blur(float4 pos : SV_Position, float2 uv_tx : TEXCOORD0) : SV //PASS 4 uniform int FCount < source = "framecount"; >; +uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >; + texture tFrame < source = "crt-newpixie/crtframe.png"; > { Width = 1024; @@ -261,7 +263,8 @@ float4 PS_NewPixie_Final(float4 pos: SV_Position, float2 uv_tx : TEXCOORD0) : SV /* Frame */ float2 fscale = float2( 0.026, -0.018);//float2( -0.018, -0.013 ); uv = float2(uv.x, 1.-uv.y); - float4 f= tex2D(sFrame,uv_tx.xy);//*((1.0)+2.0*fscale)-fscale-float2(-0.0, 0.005)); +// float4 f= tex2D(sFrame,uv_tx.xy);//*((1.0)+2.0*fscale)-fscale-float2(-0.0, 0.005)); + float4 f= tex2D(sFrame,(uv_tx-float2(0.5,0.5)) * BufferViewportRatio + float2(0.5,0.5));//*((1.0)+2.0*fscale)-fscale-float2(-0.0, 0.005)); f.xyz = lerp( f.xyz, float3(0.5,0.5,0.5), 0.5 ); float fvig = clamp( -0.00+512.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.2, 0.8 ); col = lerp( col, lerp( max( col, 0.0), pow( abs( f.xyz ), float3( 1.4,1.4,1.4 ) ) * fvig, f.w * f.w), float3( use_frame,use_frame,use_frame ) ); diff --git a/data/resources/shaders/reshade/Shaders/crt-cyclon.fx b/data/resources/shaders/reshade/Shaders/crt-cyclon.fx new file mode 100644 index 000000000..710f74746 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/crt-cyclon.fx @@ -0,0 +1,555 @@ +#include "ReShade.fxh" + + +// DariusG presents + +// 'crt-Cyclon' + +// Why? Because it's speedy! + +// A super-fast shader based on the magnificent crt-Geom, optimized for full speed +// on a Xiaomi Note 3 Pro cellphone (around 170(?) gflops gpu or so) + +// This shader uses parts from: +// crt-Geom (scanlines) +// Quillez (main filter) +// Grade (some primaries) +// Dogway's inverse Gamma +// Masks-slot-color handling, tricks etc are mine. + +// 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. + + + +uniform float SCANLINE < + ui_type = "drag"; + ui_min = 0.2; + ui_max = 0.6; + ui_step = 0.05; + ui_label = "Scanline Weight"; +> = 0.3; + +uniform float INTERLACE < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Interlacing On/Off"; +> = 1.0; + +uniform float bogus_msk < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.0; + ui_step = 0.0; + ui_label = " [ MASK SETTINGS ] "; +> = 0.0; + +uniform float M_TYPE < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Mask Type: -1:None, 0:CGWG, 1:RGB"; +> = 1.0; + +uniform float MSIZE < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 2.0; + ui_step = 1.0; + ui_label = "Mask Size"; +> = 1.0; + +uniform float SLOT < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Slot Mask On/Off"; +> = 1.0; + +uniform float SLOTW < + ui_type = "drag"; + ui_min = 2.0; + ui_max = 3.0; + ui_step = 1.0; + ui_label = "Slot Mask Width"; +> = 3.0; + +uniform float BGR < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Subpixels BGR/RGB"; +> = 0.0; + +uniform float Maskl < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Mask Brightness Dark"; +> = 0.3; + +uniform float Maskh < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Mask Brightness Bright"; +> = 0.75; + +uniform float bogus_geom < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.0; + ui_step = 0.0; + ui_label = " [ GEOMETRY SETTINGS ] "; +> = 0.0; + +uniform float bzl < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Bezel On/Off"; +> = 1.0; + +uniform float ambient < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Ambient Light"; +> = 0.40; + +uniform float zoomx < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.005; + ui_label = "Zoom Image X"; +> = 0.0; + +uniform float zoomy < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.005; + ui_label = "Zoom Image Y"; +> = 0.0; + +uniform float centerx < + ui_type = "drag"; + ui_min = -5.0; + ui_max = 5.0; + ui_step = 0.0; + ui_label = "Image Center X"; +> = 0.0; + +uniform float centery < + ui_type = "drag"; + ui_min = -5.0; + ui_max = 5.0; + ui_step = 0.05; + ui_label = "Image Center Y"; +> = 0.0; + +uniform float WARPX < + ui_type = "drag"; + ui_min = 0.00; + ui_max = 0.25; + ui_step = 0.01; + ui_label = "Curvature Horizontal"; +> = 0.02; + +uniform float WARPY < + ui_type = "drag"; + ui_min = 0.00; + ui_max = 0.25; + ui_step = 0.01; + ui_label = "Curvature Vertical"; +> = 0.01; + +uniform float vig < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Vignette On/Off"; +> = 1.0; + +uniform float bogus_col < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.0; + ui_step = 0.0; + ui_label = " [ COLOR SETTINGS ] "; +> = 0.0; + +uniform float BR_DEP < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.333; + ui_step = 0.01; + ui_label = "Scan/Mask Brightness Dependence"; +> = 0.2; + +uniform float c_space < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 3.0; + ui_step = 1.0; + ui_label = "Color Space: sRGB,PAL,NTSC-U,NTSC-J"; +> = 0.0; + +uniform float EXT_GAMMA < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "External Gamma In (Glow etc)"; +> = 0.0; + +uniform float SATURATION < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 2.0; + ui_step = 0.05; + ui_label = "Saturation"; +> = 1.0; + +uniform float BRIGHTNESS_ < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 2.0; + ui_step = 0.01; + ui_label = "Brightness, Sega fix:1.06"; +> = 1.0; + +uniform float BLACK < + ui_type = "drag"; + ui_min = -0.20; + ui_max = 0.20; + ui_step = 0.0; + ui_label = "Black Level"; +> = 0.0; + +uniform float RG < + ui_type = "drag"; + ui_min = -0.25; + ui_max = 0.25; + ui_step = 0.01; + ui_label = "Green <-to-> Red Hue"; +> = 0.0; + +uniform float RB < + ui_type = "drag"; + ui_min = 0.0; + ui_max = -0.25; + ui_step = 0.2; + ui_label = "Blue <-to-> Red Hue"; +> = 0.0; + +uniform float GB < + ui_type = "drag"; + ui_min = -0.25; + ui_max = 0.25; + ui_step = 0.01; + ui_label = "Blue <-to-> Green Hue"; +> = 0.0; + +uniform float bogus_con < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.0; + ui_step = 0.0; + ui_label = " [ CONVERGENCE SETTINGS ] "; +> = 0.0; + +uniform float C_STR < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 0.5; + ui_step = 0.05; + ui_label = "Convergence Overall Strength"; +> = 0.0; + +uniform float CONV_R < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Convergence Red X-Axis"; +> = 0.0; + +uniform float CONV_G < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Convergence Green X-axis"; +> = 0.0; + +uniform float CONV_B < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Convergence Blue X-Axis"; +> = 0.0; + +uniform float POTATO < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 1.0; + ui_label = "Potato Boost(Simple Gamma, adjust Mask)"; +> = 0.0; + + +#define blck ((1.0)/(1.0-BLACK)) +#define pi 3.1415926535897932384626433 + +uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >; +uniform float2 InternalPixelSize < source = "internal_pixel_size"; >; +uniform float2 NativePixelSize < source = "native_pixel_size"; >; +uniform float2 NormalizedInternalPixelSize < source = "normalized_internal_pixel_size"; >; +uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; +uniform float UpscaleMultiplier < source = "upscale_multiplier"; >; +uniform float2 ViewportSize < source = "viewportsize"; >; + + +uniform int FrameCount < source = "framecount"; >; +texture tBezel < source = "crt-cyclon/bezel.png"; > +{ + Width = BUFFER_WIDTH; + Height = BUFFER_HEIGHT; + MipLevels = 1; +}; + +sampler sBezel { Texture = tBezel; AddressU = BORDER; AddressV = BORDER; MinFilter = LINEAR; MagFilter = LINEAR;}; + +float3 Mask(float2 pos, float CGWG) +{ + float3 mask = float3(CGWG,CGWG,CGWG); + + +if (M_TYPE == 0.0){ + + if (POTATO == 1.0) { float pot = (1.0-CGWG)*sin(pos.x*pi)+CGWG; return float3(pot,pot,pot); } + else{ + float m = frac(pos.x*0.5); + + if (m<0.5) mask.rb = float2(1.0,1.0); + else mask.g = 1.0; + + return mask; + } +} + +if (M_TYPE == 1.0){ + + if (POTATO == 1.0) { float pot = (1.0-CGWG)*sin(pos.x*pi*0.6667)+CGWG; return float3(pot,pot,pot );} + else{ + float m = frac(pos.x*0.3333); + + if (m<0.3333) mask.rgb = (BGR == 0.0) ? float3(mask.r, mask.g, 1.0) : float3(1.0, mask.g, mask.b); + else if (m<0.6666) mask.g = 1.0; + else mask.rgb = (BGR == 0.0) ? float3(1.0, mask.g, mask.b) : float3(mask.r, mask.g, 1.0); + return mask; + } +} + else return float3(1.0,1.0,1.0); + +} + +float scanlineWeights(float distance, float3 color, float x) + { + // "wid" controls the width of the scanline beam, for each RGB + // channel The "weights" lines basically specify the formula + // that gives you the profile of the beam, i.e. the intensity as + // a function of distance from the vertical center of the + // scanline. In this case, it is gaussian if width=2, and + // becomes nongaussian for larger widths. Ideally this should + // be normalized so that the integral across the beam is + // independent of its width. That is, for a narrower beam + // "weights" should have a higher peak at the center of the + // scanline than for a wider beam. + float wid = SCANLINE + 0.15 * dot(color, float3(0.25-0.8*x, 0.25-0.8*x, 0.25-0.8*x)); //0.8 vignette strength + float weights = distance / wid; + return 0.4 * exp(-weights * weights ) / wid; + } + +#define pwr float3(1.0/((-1.0*SCANLINE+1.0)*(-0.8*CGWG+1.0))-1.2,1.0/((-1.0*SCANLINE+1.0)*(-0.8*CGWG+1.0))-1.2,1.0/((-1.0*SCANLINE+1.0)*(-0.8*CGWG+1.0))-1.2) +// Returns gamma corrected output, compensated for scanline+mask embedded gamma +float3 inv_gamma(float3 col, float3 power) +{ + float3 cir = col-1.0; + cir *= cir; + col = lerp(sqrt(col),sqrt(1.0-cir),power); + return col; +} + +// standard 6500k +static const float3x3 PAL = float3x3( +1.0740 , -0.0574 , -0.0119 , +0.0384 , 0.9699 , -0.0059 , +-0.0079 , 0.0204 , 0.9884 ); + +// standard 6500k +static const float3x3 NTSC = float3x3( +0.9318 , 0.0412 , 0.0217 , +0.0135 , 0.9711 , 0.0148 , +0.0055 , -0.0143 , 1.0085 ); + +// standard 8500k +static const float3x3 NTSC_J = float3x3( +0.9501 , -0.0431 , 0.0857 , +0.0265 , 0.9278 , 0.0432 , +0.0011 , -0.0206 , 1.3153 ); + +float3 slot(float2 pos) +{ + float h = frac(pos.x/SLOTW); + float v = frac(pos.y); + + float odd; + if (v<0.5) odd = 0.0; else odd = 1.0; + +if (odd == 0.0) + {if (h<0.5) return float3(0.5,0.5,0.5); else return float3(1.5,1.5,1.5);} + +else if (odd == 1.0) + {if (h<0.5) return float3(1.5,1.5,1.5); else return float3(0.5,0.5,0.5);} +} + +float2 Warp(float2 pos) +{ + pos = pos*2.0-1.0; + pos *= float2(1.0+pos.y*pos.y*WARPX, 1.0+pos.x*pos.x*WARPY); + pos = pos*0.5+0.5; + + return pos; +} + +uniform float2 BufferHeight < source = "bufferheight"; >; + +float4 CRT_CYCLON_PS(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD0) : SV_Target +{ + float4 SourceSize = float4(1.0 / (NormalizedInternalPixelSize * UpscaleMultiplier), NormalizedInternalPixelSize * UpscaleMultiplier); + float2 OutputSize = ViewportSize; + float2 scale = BufferViewportRatio.xy; + float2 warpcoords = (vTexCoord-float2(0.5,0.5)) * BufferViewportRatio + float2(0.5,0.5); + +// Hue matrix inside main() to avoid GLES error +float3x3 hue = float3x3( + 1.0, -RG, -RB, + RG, 1.0, -GB, + RB, GB, 1.0 +); +// zoom in and center screen for bezel + float2 pos = Warp((vTexCoord*float2(1.0-zoomx,1.0-zoomy)-float2(centerx,centery)/100.0)); + float4 bez = float4(0.0,0.0,0.0,0.0); +// if (bzl == 1.0) bez = tex2D(sBezel,vTexCoord*SourceSize.xy/OriginalSize.xy*0.97+float2(0.015,0.015)); +// if (bzl == 1.0) bez = tex2D(sBezel,vTexCoord*scale*0.97+float2(0.015,0.015)); + if (bzl == 1.0) bez = tex2D(sBezel,warpcoords*0.97+float2(0.015,0.015)); // This fix Bezel to adjust to Game's aspect ratio. + + bez.rgb = lerp(bez.rgb, float3(ambient,ambient,ambient),0.5); + + float2 bpos = pos; + float2 ps = SourceSize.zw; + float2 dx = float2(ps.x,0.0); +// Quilez + float2 ogl2 = pos*SourceSize.xy; + float2 i = floor(pos*SourceSize.xy) + 0.5; + float f = ogl2.y - i.y; + pos.y = (i.y + 4.0*f*f*f)*ps.y; // smooth + pos.x = lerp(pos.x, i.x*ps.x, 0.2); + +// Convergence + float3 res0 = tex2D(ReShade::BackBuffer,pos).rgb; + float resr = tex2D(ReShade::BackBuffer,pos + dx*CONV_R).r; + float resb = tex2D(ReShade::BackBuffer,pos + dx*CONV_B).b; + float resg = tex2D(ReShade::BackBuffer,pos + dx*CONV_G).g; + + float3 res = float3( res0.r*(1.0-C_STR) + resr*C_STR, + res0.g*(1.0-C_STR) + resg*C_STR, + res0.b*(1.0-C_STR) + resb*C_STR + ); +// Vignette + float x = 0.0; + if (vig == 1.0){ + x = vTexCoord.x*scale.x-0.5; +// x = vTexCoord.x-0.5; + x = x*x;} + + float l = dot(float3(BR_DEP,BR_DEP,BR_DEP),res); + + // Color Spaces + if(EXT_GAMMA != 1.0) res *= res; + if (c_space != 0.0) { + if (c_space == 1.0) res = mul(PAL,res); + if (c_space == 2.0) res = mul(NTSC,res); + if (c_space == 3.0) res = mul(NTSC_J,res); +// Apply CRT-like luminances + res /= float3(0.24,0.69,0.07); + res *= float3(0.29,0.6,0.11); + res = clamp(res,0.0,1.0); + } + float s = frac(bpos.y*SourceSize.y-0.5); +// handle interlacing + if (SourceSize.y > 400.0) + { + s = frac(bpos.y*SourceSize.y/2.0-0.5); +// if (INTERLACE == 1.0) s = mod(float(FrameCount),2.0) < 1.0 ? s: s+0.5; + if (INTERLACE == 1.0) s = (float(FrameCount) % 2.0) < 1.0 ? s: s+0.5; + } +// Calculate CRT-Geom scanlines weight and apply + float weight = scanlineWeights(s, res, x); + float weight2 = scanlineWeights(1.0-s, res, x); + res *= weight + weight2; + +// Masks + float2 xy = vTexCoord*OutputSize.xy*scale/MSIZE; +// float2 xy = vTexCoord*OutputSize.xy/MSIZE; + float CGWG = lerp(Maskl, Maskh, l); + res *= Mask(xy, CGWG); +// Apply slot mask on top of Trinitron-like mask + if (SLOT == 1.0) res *= lerp(slot(xy/2.0),float3(1.0,1.0,1.0),CGWG); + + if (POTATO == 0.0) res = inv_gamma(res,pwr); + else {res = sqrt(res); res *= lerp(1.3,1.1,l);} + +// Saturation + float lum = dot(float3(0.29,0.60,0.11),res); + res = lerp(float3(lum,lum,lum),res,SATURATION); + +// Brightness, Hue and Black Level + res *= BRIGHTNESS_; + res = mul(hue,res); + res -= float3(BLACK,BLACK,BLACK); + res *= blck; +// Apply bezel code, adapted from New-Pixie + if (bzl >0.0) + res.rgb = lerp(res.rgb, lerp(max(res.rgb, 0.0), pow( abs(bez.rgb), float3( 1.4,1.4,1.4 ) ), bez.w * bez.w), float3( 1.0,1.0,1.0 ) ); + + + return float4(res, 1.0); +} + + + +technique CRT_CYCLON +{ + pass PS_CRT_CYCLON + { + VertexShader = PostProcessVS; + PixelShader = CRT_CYCLON_PS; + } +} diff --git a/data/resources/shaders/reshade/Textures/crt-cyclon/bezel.png b/data/resources/shaders/reshade/Textures/crt-cyclon/bezel.png new file mode 100644 index 0000000000000000000000000000000000000000..e654d8ae8222baaf6bcd332abdb2f8054be5fede GIT binary patch literal 7677 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 literal 0 HcmV?d00001