diff --git a/data/resources/shaders/reshade/Shaders/crt/crt-geo-zfast.fx b/data/resources/shaders/reshade/Shaders/crt/crt-geo-zfast.fx new file mode 100644 index 000000000..f9bb3418c --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/crt/crt-geo-zfast.fx @@ -0,0 +1,150 @@ +#include "ReShade.fxh" + +/* + zfast_crt_geo - A simple, fast CRT shader. + + Copyright (C) 2017 Greg Hogan (SoltanGris42) + Copyright (C) 2023 Jose Linares (Dogway) + + 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. + + +Notes: This shader does scaling with a weighted linear filter + based on the algorithm by IƱigo Quilez here: + https://iquilezles.org/articles/texture/ + but modified to be somewhat sharper. Then a scanline effect that varies + based on pixel brightness is applied along with a monochrome aperture mask. + This shader runs at ~60fps on the Chromecast HD (10GFlops) on a 1080p display. + (https://forums.libretro.com/t/android-googletv-compatible-shaders-nitpicky) + +Dogway: I modified zfast_crt.glsl shader to include screen curvature, + vignetting, round corners and phosphor*temperature. Horizontal pixel is left out + from the Quilez' algo (read above) to provide a more S-Video like horizontal blur. + The scanlines and mask are also now performed in the recommended linear light. + For this to run smoothly on GPU deprived platforms like the Chromecast and + older consoles, I had to remove several parameters and hardcode them into the shader. + Another POV is to run the shader on handhelds like the Switch or SteamDeck so they consume less battery. + +*/ + + +uniform float SCANLINE_WEIGHT < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 15.0; + ui_step = 0.5; + ui_label = "Scanline Amount"; +> = 7.0; + +uniform float MASK_DARK < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Mask Effect Amount"; +> = 0.5; + +uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; +uniform float BufferWidth < source = "bufferwidth"; >; +uniform float BufferHeight < source = "bufferheight"; >; + +sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=LINEAR;MinFilter=LINEAR;}; + +struct ST_VertexOut +{ + float2 invDims : TEXCOORD1; +}; + +// Vertex shader generating a triangle covering the entire screen +void VS_CRT_Geo_zFast(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS) +{ + texcoord.x = (id == 2) ? 2.0 : 0.0; + texcoord.y = (id == 1) ? 2.0 : 0.0; + position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); + + vVARS.invDims = NormalizedNativePixelSize; +} + + +#define MSCL (BufferHeight > 1499.0 ? 0.3333 : 0.5) +// This compensates the scanline+mask embedded gamma from the beam dynamics +#define pwr ((1.0/((-0.0325*SCANLINE_WEIGHT+1.0)*(-0.311*MASK_DARK+1.0))-1.2).xxx) + + + +// NTSC-J (D93) -> Rec709 D65 Joint Matrix (with D93 simulation) +// This is compensated for a linearization hack (RGB*RGB and then sqrt()) +static const float3x3 P22D93 = float3x3( + 1.00000, 0.00000, -0.06173, + 0.07111, 0.96887, -0.01136, + 0.00000, 0.08197, 1.07280); + + +// 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; +} + +float2 Warp(float2 pos) +{ + pos = pos*2.0-1.0; + pos *= float2(1.0 + (pos.y*pos.y)*0.0276, 1.0 + (pos.x*pos.x)*0.0414); + return pos*0.5 + 0.5; +} + + +float4 PS_CRT_Geo_zFast(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD0, in ST_VertexOut vVARS) : SV_Target +{ + float2 pos = vTexCoord; + float2 xy = Warp(pos); + + float2 corn = min(xy,1.0-xy); // This is used to mask the rounded + corn.x = 0.0001/corn.x; // corners later on + + pos *= (1.0 - pos.xy); + float vig = pos.x * pos.y * 46.0; + vig = min(sqrt(vig), 1.0); + + + // Of all the pixels that are mapped onto the texel we are + // currently rendering, which pixel are we currently rendering? + float ratio_scale = xy.y / NormalizedNativePixelSize.y - 0.5; + // Snap to the center of the underlying texel. + float i = floor(ratio_scale) + 0.5; + + // This is just like "Quilez Scaling" but sharper + float f = ratio_scale - i; + float Y = f*f; + float p = (i + 4.0*Y*f)*vVARS.invDims.y; + + float whichmask = floor(vTexCoord.x*BufferWidth)*(-MSCL); + float mask = 1.0 + float(frac(whichmask) < MSCL)*(-MASK_DARK); + float3 colour = tex2D(sBackBuffer, float2(xy.x,p)).rgb; + + colour = max(mul(P22D93 * vig, colour*colour), 0.0.xxx); + + float scanLineWeight = (1.5 - SCANLINE_WEIGHT*(Y - Y*Y)); + + if (corn.y <= corn.x || corn.x < 0.0001 ) + colour = 0.0.xxx; + + return float4(inv_gamma(colour.rgb*lerp(scanLineWeight*mask, 1.0, colour.r*0.26667+colour.g*0.26667+colour.b*0.26667),pwr),1.0); +} + + + +technique CRT_Geo_zFast +{ + pass + { + VertexShader = VS_CRT_Geo_zFast; + PixelShader = PS_CRT_Geo_zFast; + } +} diff --git a/data/resources/shaders/reshade/Shaders/crt/crt-hyllian-sinc.fx b/data/resources/shaders/reshade/Shaders/crt/crt-hyllian-sinc.fx new file mode 100644 index 000000000..0cd3d65d0 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/crt/crt-hyllian-sinc.fx @@ -0,0 +1,375 @@ +#include "ReShade.fxh" + +/* + Hyllian's CRT-sinc Shader + + Copyright (C) 2011-2024 Hyllian + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + + + +uniform int HFILTER_PROFILE < + ui_type = "combo"; + ui_items = "Custom\0Composite\0Composite Soft\0"; + ui_label = "H-FILTER PROFILE"; +> = 0; + +uniform float SHP < + ui_type = "drag"; + ui_min = 0.50; + ui_max = 1.0; + ui_step = 0.01; + ui_label = "CUSTOM H-FILTER SHARPNESS"; +> = 1.0; + +uniform bool CRT_ANTI_RINGING < + ui_type = "radio"; + ui_label = "ANTI RINGING"; +> = true; + +uniform bool SHARPNESS_HACK < + ui_type = "radio"; + ui_label = "SHARPNESS HACK"; +> = false; + +uniform float CRT_InputGamma < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 5.0; + ui_step = 0.1; + ui_label = "INPUT GAMMA"; +> = 2.4; + +uniform float CRT_OutputGamma < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 5.0; + ui_step = 0.05; + ui_label = "OUTPUT GAMMA"; +> = 2.2; + +uniform int MASK_LAYOUT < + ui_type = "combo"; + ui_items = "0-Off\0" + "1-Aperture Classic\0""2-Aperture1 RGB 1080p\0""3-Aperture2 RGB 1080p\0""4-Aperture1 RGB 4k\0""5-Aperture2 RGB 4k\0""6-Aperture3 RGB 4k\0" + "7-Shadow Classic\0""8-Shadow1 1080p\0""9-Shadow2 1080p\0""10-Shadow1 4k\0" + "11-Slot1 1080p\0""12-Slot2 1080p\0""13-Slot1 4k\0""14-Slot1 4k\0""15-Slot1 8k\0"; + ui_category = "CRT Mask"; + ui_label = "MASK LAYOUT"; +> = 1; + +uniform int MONITOR_SUBPIXELS < + ui_type = "combo"; + ui_items = "RGB\0BGR\0"; + ui_category = "CRT Mask"; + ui_label = "MONITOR SUBPIXELS LAYOUT"; +> = 0; + +uniform float BRIGHTBOOST < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 3.0; + ui_step = 0.05; + ui_label = "BRIGHTNESS BOOST"; +> = 1.0; + +uniform float BEAM_MIN_WIDTH < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.01; + ui_label = "MIN BEAM WIDTH"; +> = 0.86; + +uniform float BEAM_MAX_WIDTH < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.01; + ui_label = "MAX BEAM WIDTH"; +> = 1.0; + +uniform float SCANLINES_STRENGTH < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.01; + ui_label = "SCANLINES STRENGTH"; +> = 0.72; + +uniform int SCANLINES_SHAPE < + ui_type = "combo"; + ui_items = "Sinc\0Gaussian\0"; + ui_label = "SCANLINES SHAPE"; +> = 1.0; + +uniform float SCANLINES_CUTOFF < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1000.0; + ui_step = 1.0; + ui_label = "SCANLINES CUTOFF"; + ui_tooltip = "Max vertical native resolution above which scanlines are disabled."; +> = 390.0; + +uniform bool SCANLINES_HIRES < + ui_type = "radio"; + ui_label = "HIGH RESOLUTION SCANLINES"; +> = false; + +uniform float POST_BRIGHTNESS < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 3.0; + ui_step = 0.05; + ui_label = "POST-BRIGHTNESS"; +> = 1.00; + +uniform bool VSCANLINES < + ui_type = "radio"; + ui_label = "VERTICAL SCANLINES"; +> = false; + + +uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; +uniform float BufferWidth < source = "bufferwidth"; >; +uniform float BufferHeight < source = "bufferheight"; >; +uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >; +uniform float2 ViewportSize < source = "viewportsize"; >; +uniform float ViewportWidth < source = "viewportwidth"; >; +uniform float ViewportHeight < source = "viewportheight"; >; +uniform float UpscaleMultiplier < source = "upscale_multiplier"; >; + + +#include "../misc/include/mask.fxh" +#include "../misc/include/geom.fxh" + + +sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=POINT;MinFilter=POINT;}; + +texture2D tBackBufferLinear{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA16f;}; +sampler2D sBackBufferLinear{Texture=tBackBufferLinear;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; + +#define GAMMA_IN(color) pow(color, float3(CRT_InputGamma, CRT_InputGamma, CRT_InputGamma)) +#define GAMMA_OUT(color) pow(color, float3(1.0 / CRT_OutputGamma, 1.0 / CRT_OutputGamma, 1.0 / CRT_OutputGamma)) + +#define SCANLINES_STRENGTH (-0.16*SCANLINES_SHAPE+SCANLINES_STRENGTH) +#define CORNER_SMOOTHNESS (80.0*pow(CORNER_SMOOTHNESS,10.0)) + +#define pi 3.1415926535897932384626433832795 + +#define RADIUS 2.0 // No need for more than 2-taps + +float2 get_hfilter_profile() +{ + float2 hf_profile = float2(SHP, RADIUS); + + if (HFILTER_PROFILE == 1) hf_profile = float2(0.78, 2.0); // SNES composite + else if (HFILTER_PROFILE == 2) hf_profile = float2(0.65, 2.0); // Genesis composite + + return hf_profile; +} + +/* Some window functions for tests. */ +float4 sinc(float4 x) { return sin(pi*x)*(1.0/(pi*x+0.001.xxxx)); } +float4 hann_window(float4 x) { return 0.5 * ( 1.0 - cos( 0.5 * pi * ( x + 2.0 ) ) ); } +float4 blackman_window(float4 x) { return 0.42 - 0.5*cos(0.5*pi*(x+2.0)) + 0.08*cos(pi*(x+2.0)); } +float4 lanczos(float4 x, float a) { return sinc(x) * sinc(x / a); } +float4 blackman(float4 x, float a) { return sinc(x) * blackman_window(x); } +float4 hann(float4 x, float a) { return sinc(x) * hann_window(x); } + +float4 resampler4(float4 x, float2 hfp) +{ + return blackman(x * hfp.x, hfp.y); +} + + +#define wa (0.5*pi) +#define wb (pi) + +float3 resampler3(float3 x) +{ + float3 res; + + res.x = (x.x<=0.001) ? 1.0 : sin(x.x*wa)*sin(x.x*wb)/(wa*wb*x.x*x.x); + res.y = (x.y<=0.001) ? 1.0 : sin(x.y*wa)*sin(x.y*wb)/(wa*wb*x.y*x.y); + res.z = (x.z<=0.001) ? 1.0 : sin(x.z*wa)*sin(x.z*wb)/(wa*wb*x.z*x.z); + + return res; +} + +float3 get_scanlines(float3 d0, float3 d1, float3 color0, float3 color1) +{ + if (SCANLINES_SHAPE > 0.5) { + d0 = exp(-16.0*d0*d0); + d1 = exp(-16.0*d1*d1); + } + else { + d0 = clamp(2.0*d0, 0.0, 1.0); + d1 = clamp(2.0*d1, 0.0, 1.0); + d0 = resampler3(d0); + d1 = resampler3(d1); + } + + return (BRIGHTBOOST*(color0*d0+color1*d1)); +} + +float4 PS_BackBufferLinear(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target +{ +// float2 tc = (floor(vTexCoord / NormalizedNativePixelSize) + 0.5.xx) * NormalizedNativePixelSize; + + return float4(GAMMA_IN(tex2D(sBackBuffer, vTexCoord).rgb), 1.0); +} + +struct ST_VertexOut +{ + float2 sinangle : TEXCOORD1; + float2 cosangle : TEXCOORD2; + float3 stretch : TEXCOORD3; + float2 TextureSize : TEXCOORD4; +}; + + +// Vertex shader generating a triangle covering the entire screen +void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS) +{ + texcoord.x = (id == 2) ? 2.0 : 0.0; + texcoord.y = (id == 1) ? 2.0 : 0.0; + position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); + + // Screen centering + texcoord = texcoord - float2(centerx,centery)/100.0; + + float2 SourceSize = 1.0/NormalizedNativePixelSize; + float shp_hack = 1.0 + float(SHARPNESS_HACK); + + + // Precalculate a bunch of useful values we'll need in the fragment + // shader. + vVARS.sinangle = sin(float2(geom_x_tilt, geom_y_tilt)); + vVARS.cosangle = cos(float2(geom_x_tilt, geom_y_tilt)); + vVARS.stretch = maxscale(vVARS.sinangle, vVARS.cosangle); + vVARS.TextureSize = lerp(float2(shp_hack*SourceSize.x, SourceSize.y), float2(SourceSize.x, shp_hack*SourceSize.y), VSCANLINES); +} + + +float4 PS_CRT_Hyllian(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD0, in ST_VertexOut vVARS) : SV_Target +{ + float2 OutputSize = float2(BufferWidth, BufferHeight); + + float2 TextureSize = vVARS.TextureSize; + + float2 dx = lerp(float2(1.0/TextureSize.x, 0.0), float2(0.0, 1.0/TextureSize.y), VSCANLINES); + float2 dy = lerp(float2(0.0, 1.0/TextureSize.y), float2(1.0/TextureSize.x, 0.0), VSCANLINES); + + // Texture coordinates of the texel containing the active pixel. + float2 WarpedTexCoord = (geom_curvature == true) ? transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch) : vTexCoord; + + float cval = corner((WarpedTexCoord-0.5.xx) * BufferToViewportRatio + 0.5.xx); + + float2 pix_coord = WarpedTexCoord*TextureSize - 0.5.xx; + + float2 tc = ( (SCANLINES_HIRES == true) ? (lerp(float2(floor(pix_coord.x), pix_coord.y), float2(pix_coord.x, floor(pix_coord.y)), VSCANLINES) + float2(0.5, 0.5)) : (floor(pix_coord) + float2(0.5, 0.5)) )/TextureSize; + + float2 fp = lerp(frac(pix_coord), frac(pix_coord.yx), VSCANLINES); + + float3 c00 = tex2D(sBackBufferLinear, tc - dx).xyz; + float3 c01 = tex2D(sBackBufferLinear, tc ).xyz; + float3 c02 = tex2D(sBackBufferLinear, tc + dx).xyz; + float3 c03 = tex2D(sBackBufferLinear, tc + 2.0*dx).xyz; + + float3 c10, c11, c12, c13; + + if (SCANLINES_HIRES == false) + { + c10 = tex2D(sBackBufferLinear, tc - dx + dy).xyz; + c11 = tex2D(sBackBufferLinear, tc + dy).xyz; + c12 = tex2D(sBackBufferLinear, tc + dx + dy).xyz; + c13 = tex2D(sBackBufferLinear, tc + 2.0*dx + dy).xyz; + } + else { c10 = c00; c11 = c01; c12 = c02; c13 = c03;} + + float4x3 color_matrix0 = float4x3(c00, c01, c02, c03); + float4x3 color_matrix1 = float4x3(c10, c11, c12, c13); + + float2 hfp = get_hfilter_profile(); + + float4 weights = resampler4(float4(1.0+fp.x, fp.x, 1.0-fp.x, 2.0-fp.x), hfp); + + float3 color0 = mul(weights, color_matrix0)/dot(weights, 1.0.xxxx); + float3 color1 = mul(weights, color_matrix1)/dot(weights, 1.0.xxxx); + + // Get min/max samples + float3 min_sample0 = min(c01,c02); + float3 max_sample0 = max(c01,c02); + float3 min_sample1 = min(c11,c12); + float3 max_sample1 = max(c11,c12); + + // Anti-ringing + float3 aux = color0; + color0 = clamp(color0, min_sample0, max_sample0); + color0 = lerp(aux, color0, CRT_ANTI_RINGING); + aux = color1; + color1 = clamp(color1, min_sample1, max_sample1); + color1 = lerp(aux, color1, CRT_ANTI_RINGING); + + float pos0 = fp.y; + float pos1 = 1 - fp.y; + + float3 lum0 = lerp(BEAM_MIN_WIDTH.xxx, BEAM_MAX_WIDTH.xxx, color0); + float3 lum1 = lerp(BEAM_MIN_WIDTH.xxx, BEAM_MAX_WIDTH.xxx, color1); + + float3 d0 = SCANLINES_STRENGTH*pos0/(lum0*lum0+0.0000001.xxx); + float3 d1 = SCANLINES_STRENGTH*pos1/(lum1*lum1+0.0000001.xxx); + + float3 color = (vVARS.TextureSize.y <= SCANLINES_CUTOFF) ? get_scanlines(d0, d1, color0, color1) : tex2D(sBackBufferLinear, WarpedTexCoord.xy).xyz; + + color *= BRIGHTBOOST; + + color = GAMMA_OUT(color); + + float2 mask_coords =vTexCoord.xy * OutputSize.xy; + + mask_coords = lerp(mask_coords.xy, mask_coords.yx, VSCANLINES); + + color.rgb*=GAMMA_OUT(mask_weights(mask_coords, MASK_LAYOUT, MONITOR_SUBPIXELS, MASK_DARK_STRENGTH, MASK_LIGHT_STRENGTH)); + + float4 res = float4(POST_BRIGHTNESS*color, 1.0); + + res.rgb = res.rgb * cval.xxx; + + return float4(res.rgb, 1.0); +} + +technique CRT_Hyllian +{ + pass + { + VertexShader = PostProcessVS; + PixelShader = PS_BackBufferLinear; + RenderTarget = tBackBufferLinear; + } + pass + { + VertexShader = VS_CRT_Geom; + PixelShader = PS_CRT_Hyllian; + } +} diff --git a/data/resources/shaders/reshade/Shaders/interpolation/bicubic.fx b/data/resources/shaders/reshade/Shaders/interpolation/bicubic.fx index a0fe1312a..52dc150dd 100644 --- a/data/resources/shaders/reshade/Shaders/interpolation/bicubic.fx +++ b/data/resources/shaders/reshade/Shaders/interpolation/bicubic.fx @@ -32,15 +32,21 @@ uniform int BICUBIC_FILTER < ui_tooltip = "Bicubic: balanced. Catmull-Rom: sharp. B-Spline: blurred. Hermite: soft pixelized."; > = 0; +uniform float B_PRESCALE < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 8.0; + ui_step = 1.0; + ui_label = "Prescale factor"; +> = 1.0; uniform bool B_ANTI_RINGING < ui_type = "radio"; - ui_label = "Bicubic Anti-Ringing"; + ui_label = "Anti-Ringing"; > = false; uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; -uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >; -uniform float2 ViewportSize < source = "viewportsize"; >; +uniform float BufferWidth < source = "bufferwidth"; >; texture2D tBicubic_P0{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; sampler2D sBicubic_P0{Texture=tBicubic_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; @@ -89,9 +95,9 @@ float3 bicubic_ar(float fp, float3 C0, float3 C1, float3 C2, float3 C3) float4 PS_Bicubic_X(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target { // Both dimensions are unfiltered, so it looks for lores pixels. - float2 ps = NormalizedNativePixelSize; + float2 ps = NormalizedNativePixelSize/B_PRESCALE; float2 pos = uv_tx.xy/ps - float2(0.5, 0.0); - float2 tc = (floor(pos) + float2(0.5, 0.5)) * ps; + float2 tc = (floor(pos) + 0.5.xx) * ps; float2 fp = frac(pos); float3 C0 = tex2D(ReShade::BackBuffer, tc + ps*float2(-1.0, 0.0)).rgb; @@ -108,9 +114,9 @@ float4 PS_Bicubic_X(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Targ float4 PS_Bicubic_Y(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target { // One must be careful here. Horizontal dimension is already filtered, so it looks for x in hires. - float2 ps = float2(1.0/(ViewportSize.x*BufferToViewportRatio.x), NormalizedNativePixelSize.y); + float2 ps = float2(1.0/BufferWidth, NormalizedNativePixelSize.y/B_PRESCALE); float2 pos = uv_tx.xy/ps - float2(0.0, 0.5); - float2 tc = (floor(pos) + float2(0.5, 0.5)) * ps; + float2 tc = (floor(pos) + 0.5.xx) * ps; float2 fp = frac(pos); float3 C0 = tex2D(sBicubic_P0, tc + ps*float2(0.0, -1.0)).rgb; diff --git a/data/resources/shaders/reshade/Shaders/interpolation/lanczos3.fx b/data/resources/shaders/reshade/Shaders/interpolation/lanczos3.fx index 5d9069f89..f28929827 100644 --- a/data/resources/shaders/reshade/Shaders/interpolation/lanczos3.fx +++ b/data/resources/shaders/reshade/Shaders/interpolation/lanczos3.fx @@ -28,14 +28,22 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. http://www.gnu.org/copyleft/gpl.html */ +uniform float L3_PRESCALE < + ui_type = "drag"; + ui_min = 1.0; + ui_max = 8.0; + ui_step = 1.0; + ui_label = "Prescale factor"; +> = 1.0; + + uniform bool LANCZOS3_ANTI_RINGING < ui_type = "radio"; ui_label = "Lanczos3 Anti-Ringing"; > = true; uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; -uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >; -uniform float2 ViewportSize < source = "viewportsize"; >; +uniform float BufferWidth < source = "bufferwidth"; >; texture2D tLanczos3_P0{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;}; sampler2D sLanczos3_P0{Texture=tLanczos3_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;}; @@ -59,7 +67,7 @@ float3 lanczos3ar(float fp, float3 C0, float3 C1, float3 C2, float3 C3, float3 C float3 w1 = weight3(0.5 - fp * 0.5); float3 w2 = weight3(1.0 - fp * 0.5); - float sum = dot( w1, float3(1.,1.,1.)) + dot( w2, float3(1.,1.,1.)); + float sum = dot(w1, 1.0.xxx) + dot(w2, 1.0.xxx); w1 /= sum; w2 /= sum; @@ -83,9 +91,9 @@ float3 lanczos3ar(float fp, float3 C0, float3 C1, float3 C2, float3 C3, float3 C float4 PS_Lanczos3_X(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target { // Both dimensions are unfiltered, so it looks for lores pixels. - float2 ps = NormalizedNativePixelSize; + float2 ps = NormalizedNativePixelSize/L3_PRESCALE; float2 pos = uv_tx.xy/ps - float2(0.5, 0.0); - float2 tc = (floor(pos) + float2(0.5, 0.5)) * ps; + float2 tc = (floor(pos) + 0.5.xx) * ps; float2 fp = frac(pos); float3 C0 = tex2D(ReShade::BackBuffer, tc + ps*float2(-2.0, 0.0)).rgb; @@ -104,9 +112,9 @@ float4 PS_Lanczos3_X(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Tar float4 PS_Lanczos3_Y(float4 vpos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target { // One must be careful here. Horizontal dimension is already filtered, so it looks for x in hires. - float2 ps = float2(1.0/(ViewportSize.x*BufferToViewportRatio.x), NormalizedNativePixelSize.y); + float2 ps = float2(1.0/BufferWidth, NormalizedNativePixelSize.y/L3_PRESCALE); float2 pos = uv_tx.xy/ps - float2(0.0, 0.5); - float2 tc = (floor(pos) + float2(0.5, 0.5)) * ps; + float2 tc = (floor(pos) + 0.5.xx) * ps; float2 fp = frac(pos); float3 C0 = tex2D(sLanczos3_P0, tc + ps*float2(0.0, -2.0)).rgb; diff --git a/data/resources/shaders/reshade/Shaders/misc/geom.fx b/data/resources/shaders/reshade/Shaders/misc/geom.fx index 1fc96565a..0b610ca0a 100644 --- a/data/resources/shaders/reshade/Shaders/misc/geom.fx +++ b/data/resources/shaders/reshade/Shaders/misc/geom.fx @@ -170,14 +170,14 @@ sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BO #define PI 3.141592653589 #ifdef LINEAR_PROCESSING -# define TEX2D(c) pow(tex2D(sBackBuffer, (c)), float4(geom_target_gamma,geom_target_gamma,geom_target_gamma,geom_target_gamma)) +# define TEX2D(c) pow(tex2D(sBackBuffer, (c)), geom_target_gamma.xxxx) #else # define TEX2D(c) tex2D(sBackBuffer, (c)) #endif // aspect ratio #define aspect (geom_invert_aspect==true?float2(ViewportHeight/ViewportWidth,1.0):float2(1.0,ViewportHeight/ViewportWidth)) -#define overscan (float2(1.01,1.01)); +#define overscan (1.01.xx); struct ST_VertexOut @@ -189,105 +189,21 @@ struct ST_VertexOut }; -float vs_intersect(float2 xy, float2 sinangle, float2 cosangle) -{ - float A = dot(xy,xy) + geom_d*geom_d; - float B = 2.0*(geom_R*(dot(xy,sinangle)-geom_d*cosangle.x*cosangle.y)-geom_d*geom_d); - float C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y; - - return (-B-sqrt(B*B-4.0*A*C))/(2.0*A); -} - -float2 vs_bkwtrans(float2 xy, float2 sinangle, float2 cosangle) -{ - float c = vs_intersect(xy, sinangle, cosangle); - float2 point = (float2(c, c)*xy - float2(-geom_R, -geom_R)*sinangle) / float2(geom_R, geom_R); - float2 poc = point/cosangle; - - float2 tang = sinangle/cosangle; - float A = dot(tang, tang) + 1.0; - float B = -2.0*dot(poc, tang); - float C = dot(poc, poc) - 1.0; - - float a = (-B + sqrt(B*B - 4.0*A*C))/(2.0*A); - float2 uv = (point - a*sinangle)/cosangle; - float r = FIX(geom_R*acos(a)); - - return uv*r/sin(r/geom_R); -} - -float2 vs_fwtrans(float2 uv, float2 sinangle, float2 cosangle) -{ - float r = FIX(sqrt(dot(uv,uv))); - uv *= sin(r/geom_R)/r; - float x = 1.0-cos(r/geom_R); - float D = geom_d/geom_R + x*cosangle.x*cosangle.y+dot(uv,sinangle); - - return geom_d*(uv*cosangle-x*sinangle)/D; -} - -float3 vs_maxscale(float2 sinangle, float2 cosangle) -{ - float2 c = vs_bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle); - float2 a = float2(0.5,0.5)*aspect; - - float2 lo = float2(vs_fwtrans(float2(-a.x, c.y), sinangle, cosangle).x, - vs_fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect; - - float2 hi = float2(vs_fwtrans(float2(+a.x, c.y), sinangle, cosangle).x, - vs_fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect; - - return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y)); -} - -// Code snippet borrowed from crt-cyclon. (credits to DariusG) -float2 Warp(float2 pos) -{ - pos = pos*2.0 - 1.0; - pos *= float2(1.0 + pos.y*pos.y*0, 1.0 + pos.x*pos.x*0); - pos = pos*0.5 + 0.5; - - return pos; -} - - -// Vertex shader generating a triangle covering the entire screen -void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS) -{ - texcoord.x = (id == 2) ? 2.0 : 0.0; - texcoord.y = (id == 1) ? 2.0 : 0.0; - position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); - - // center screen - texcoord = Warp(texcoord - float2(centerx,centery)/100.0); - - float2 SourceSize = 1.0/NormalizedNativePixelSize; - - // Precalculate a bunch of useful values we'll need in the fragment - // shader. - vVARS.sinangle = sin(float2(geom_x_tilt, geom_y_tilt)); - vVARS.cosangle = cos(float2(geom_x_tilt, geom_y_tilt)); - vVARS.stretch = vs_maxscale(vVARS.sinangle, vVARS.cosangle); - vVARS.TextureSize = float2(SourceSize.x, SourceSize.y); -} - - - float intersect(float2 xy, float2 sinangle, float2 cosangle) { float A = dot(xy,xy) + geom_d*geom_d; float B, C; - B = 2.0*(geom_R*(dot(xy,sinangle) - geom_d*cosangle.x*cosangle.y) - geom_d*geom_d); - C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y; + B = 2.0*(geom_R*(dot(xy,sinangle) - geom_d*cosangle.x*cosangle.y) - geom_d*geom_d); + C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y; return (-B-sqrt(B*B - 4.0*A*C))/(2.0*A); } float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle) { - float c = intersect(xy, sinangle, cosangle); - float2 point = (float2(c, c)*xy - float2(-geom_R, -geom_R)*sinangle) / float2(geom_R, geom_R); + float c = intersect(xy, sinangle, cosangle); + float2 point = (c.xx*xy + geom_R.xx*sinangle) / geom_R.xx; float2 poc = point/cosangle; float2 tang = sinangle/cosangle; @@ -296,7 +212,7 @@ float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle) float C = dot(poc, poc) - 1.0; float a = (-B + sqrt(B*B - 4.0*A*C)) / (2.0*A); - float2 uv = (point - a*sinangle) / cosangle; + float2 uv = (point - a*sinangle) / cosangle; float r = FIX(geom_R*acos(a)); return uv*r/sin(r/geom_R); @@ -309,73 +225,91 @@ float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle) float x = 1.0 - cos(r/geom_R); float D; - D = geom_d/geom_R + x*cosangle.x*cosangle.y + dot(uv,sinangle); + D = geom_d/geom_R + x*cosangle.x*cosangle.y + dot(uv,sinangle); return geom_d*(uv*cosangle - x*sinangle)/D; } float3 maxscale(float2 sinangle, float2 cosangle) { - float2 c = bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle); - float2 a = float2(0.5, 0.5)*aspect; + float2 c = bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle); + float2 a = 0.5.xx*aspect; - float2 lo = float2(fwtrans(float2(-a.x, c.y), sinangle, cosangle).x, - fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect; - float2 hi = float2(fwtrans(float2(+a.x, c.y), sinangle, cosangle).x, - fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect; + float2 lo = float2(fwtrans(float2(-a.x, c.y), sinangle, cosangle).x, + fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect; + float2 hi = float2(fwtrans(float2(+a.x, c.y), sinangle, cosangle).x, + fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect; - return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y)); + return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y)); } float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch) { - coord = (coord - float2(0.5, 0.5))*aspect*stretch.z + stretch.xy; + coord = (coord - 0.5.xx)*aspect*stretch.z + stretch.xy; return (bkwtrans(coord, sinangle, cosangle) / - float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0)/aspect + float2(0.5, 0.5)); + float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0)/aspect + 0.5.xx); } + +// Vertex shader generating a triangle covering the entire screen +void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS) +{ + texcoord.x = (id == 2) ? 2.0 : 0.0; + texcoord.y = (id == 1) ? 2.0 : 0.0; + position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); + + // Screen centering + texcoord = texcoord - float2(centerx,centery)/100.0; + + float2 SourceSize = 1.0/NormalizedNativePixelSize; + + // Precalculate a bunch of useful values we'll need in the fragment + // shader. + vVARS.sinangle = sin(float2(geom_x_tilt, geom_y_tilt)); + vVARS.cosangle = cos(float2(geom_x_tilt, geom_y_tilt)); + vVARS.stretch = maxscale(vVARS.sinangle, vVARS.cosangle); + vVARS.TextureSize = float2(SourceSize.x, SourceSize.y); +} + + float corner(float2 coord) { - coord = min(coord, float2(1.0, 1.0) - coord) * aspect; - float2 cdist = float2(geom_cornersize, geom_cornersize); - coord = (cdist - min(coord, cdist)); - float dist = sqrt(dot(coord, coord)); + coord = min(coord, 1.0.xx - coord) * aspect; + float2 cdist = geom_cornersize.xx; + coord = (cdist - min(coord, cdist)); + float dist = sqrt(dot(coord, coord)); - return clamp((cdist.x - dist)*geom_cornersmooth, 0.0, 1.0); + return clamp((cdist.x - dist)*geom_cornersmooth, 0.0, 1.0); } -float fwidth(float value){ - return abs(ddx(value)) + abs(ddy(value)); +float fwidth(float value) +{ + return abs(ddx(value)) + abs(ddy(value)); } float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_VertexOut vVARS) : SV_Target { // Texture coordinates of the texel containing the active pixel. - float2 xy; + float2 xy = (geom_curvature == true) ? transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch) : vTexCoord; - if (geom_curvature == true) - xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch); - else - xy = vTexCoord; + float cval = corner((xy-0.5.xx) * BufferToViewportRatio + 0.5.xx); - float cval = corner((xy-float2(0.5,0.5)) * BufferToViewportRatio + float2(0.5,0.5)); - - float2 uv_ratio = frac((xy * vVARS.TextureSize - float2(0.5, 0.5)) / vVARS.TextureSize); + float2 uv_ratio = frac((xy * vVARS.TextureSize - 0.5.xx) / vVARS.TextureSize); float4 col = TEX2D(xy); #ifndef LINEAR_PROCESSING - col = pow(col , float4(geom_target_gamma, geom_target_gamma, geom_target_gamma, geom_target_gamma)); + col = pow(col, geom_target_gamma.xxxx); #endif col.rgb *= (geom_lum * step(0.0, uv_ratio.y)); - float3 mul_res = col.rgb * float3(cval, cval, cval); + float3 mul_res = col.rgb * cval.xxx; // Convert the image gamma for display on our output device. - mul_res = pow(mul_res, float3(1.0 / geom_monitor_gamma, 1.0 / geom_monitor_gamma, 1.0 / geom_monitor_gamma)); + mul_res = pow(mul_res, 1.0 / geom_monitor_gamma.xxx); return float4(mul_res, 1.0); } diff --git a/data/resources/shaders/reshade/Shaders/misc/include/geom.fxh b/data/resources/shaders/reshade/Shaders/misc/include/geom.fxh new file mode 100644 index 000000000..ff29bf771 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/misc/include/geom.fxh @@ -0,0 +1,225 @@ +#ifndef GEOM_PARAMS_H +#define GEOM_PARAMS_H + +/* + Geom Shader - a modified CRT-Geom without CRT features made to be appended/integrated + into any other shaders and provide curvature/warping/oversampling features. + + Adapted by Hyllian (2024). +*/ + + +/* + CRT-interlaced + + Copyright (C) 2010-2012 cgwg, Themaister and DOLLS + + 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. + + (cgwg gave their consent to have the original version of this shader + distributed under the GPL in this message: + + http://board.byuu.org/viewtopic.php?p=26075#p26075 + + "Feel free to distribute my shaders under the GPL. After all, the + barrel distortion code was taken from the Curvature shader, which is + under the GPL." + ) + This shader variant is pre-configured with screen curvature +*/ + + + +uniform bool geom_curvature < + ui_type = "radio"; + ui_category = "Geom Curvature"; + ui_label = "Geom Curvature Toggle"; +> = 1.0; + +uniform float geom_R < + ui_type = "drag"; + ui_min = 0.1; + ui_max = 10.0; + ui_step = 0.1; + ui_category = "Geom Curvature"; + ui_label = "Geom Curvature Radius"; +> = 2.0; + +uniform float geom_d < + ui_type = "drag"; + ui_min = 0.1; + ui_max = 3.0; + ui_step = 0.1; + ui_category = "Geom Curvature"; + ui_label = "Geom Distance"; +> = 1.5; + +uniform bool geom_invert_aspect < + ui_type = "radio"; + ui_category = "Geom Curvature"; + ui_label = "Geom Curvature Aspect Inversion"; +> = 0.0; + +uniform float geom_cornersize < + ui_type = "drag"; + ui_min = 0.001; + ui_max = 1.0; + ui_step = 0.005; + ui_category = "Geom Curvature"; + ui_label = "Geom Corner Size"; +> = 0.03; + +uniform float geom_cornersmooth < + ui_type = "drag"; + ui_min = 80.0; + ui_max = 2000.0; + ui_step = 100.0; + ui_category = "Geom Curvature"; + ui_label = "Geom Corner Smoothness"; +> = 1000.0; + +uniform float geom_x_tilt < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.05; + ui_category = "Geom Curvature"; + ui_label = "Geom Horizontal Tilt"; +> = 0.0; + +uniform float geom_y_tilt < + ui_type = "drag"; + ui_min = -1.0; + ui_max = 1.0; + ui_step = 0.05; + ui_category = "Geom Curvature"; + ui_label = "Geom Vertical Tilt"; +> = 0.0; + +uniform float geom_overscan_x < + ui_type = "drag"; + ui_min = -125.0; + ui_max = 125.0; + ui_step = 0.5; + ui_category = "Geom Curvature"; + ui_label = "Geom Horiz. Overscan %"; +> = 100.0; + +uniform float geom_overscan_y < + ui_type = "drag"; + ui_min = -125.0; + ui_max = 125.0; + ui_step = 0.5; + ui_category = "Geom Curvature"; + ui_label = "Geom Vert. Overscan %"; +> = 100.0; + +uniform float centerx < + ui_type = "drag"; + ui_min = -100.0; + ui_max = 100.0; + ui_step = 0.1; + ui_category = "Geom Curvature"; + ui_label = "Image Center X"; +> = 0.00; + +uniform float centery < + ui_type = "drag"; + ui_min = -100.0; + ui_max = 100.0; + ui_step = 0.1; + ui_category = "Geom Curvature"; + ui_label = "Image Center Y"; +> = 0.00; + + + +// Macros. +#define FIX(c) max(abs(c), 1e-5); + +// aspect ratio +#define aspect (geom_invert_aspect==true?float2(ViewportHeight/ViewportWidth,1.0):float2(1.0,ViewportHeight/ViewportWidth)) + + +float intersect(float2 xy, float2 sinangle, float2 cosangle) +{ + float A = dot(xy,xy) + geom_d*geom_d; + float B, C; + + B = 2.0*(geom_R*(dot(xy,sinangle) - geom_d*cosangle.x*cosangle.y) - geom_d*geom_d); + C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y; + + return (-B-sqrt(B*B - 4.0*A*C))/(2.0*A); +} + +float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle) +{ + float c = intersect(xy, sinangle, cosangle); + float2 point = (c.xx*xy + geom_R.xx*sinangle) / geom_R.xx; + float2 poc = point/cosangle; + float2 tang = sinangle/cosangle; + + float A = dot(tang, tang) + 1.0; + float B = -2.0*dot(poc, tang); + float C = dot(poc, poc) - 1.0; + + float a = (-B + sqrt(B*B - 4.0*A*C)) / (2.0*A); + float2 uv = (point - a*sinangle) / cosangle; + float r = FIX(geom_R*acos(a)); + + return uv*r/sin(r/geom_R); +} + +float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle) +{ + float r = FIX(sqrt(dot(uv, uv))); + uv *= sin(r/geom_R)/r; + float x = 1.0 - cos(r/geom_R); + float D; + + D = geom_d/geom_R + x*cosangle.x*cosangle.y + dot(uv,sinangle); + + return geom_d*(uv*cosangle - x*sinangle)/D; +} + +float3 maxscale(float2 sinangle, float2 cosangle) +{ + float2 c = bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle); + float2 a = 0.5.xx*aspect; + + float2 lo = float2(fwtrans(float2(-a.x, c.y), sinangle, cosangle).x, + fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect; + float2 hi = float2(fwtrans(float2(+a.x, c.y), sinangle, cosangle).x, + fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect; + + return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y)); +} + +float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch) +{ + coord = (coord - 0.5.xx)*aspect*stretch.z + stretch.xy; + + return (bkwtrans(coord, sinangle, cosangle) / + float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0)/aspect + 0.5.xx); +} + + +float corner(float2 coord) +{ + coord = min(coord, 1.0.xx - coord) * aspect; + float2 cdist = geom_cornersize.xx; + coord = (cdist - min(coord, cdist)); + float dist = sqrt(dot(coord, coord)); + + return clamp((cdist.x - dist)*geom_cornersmooth, 0.0, 1.0); +} + +float fwidth(float value) +{ + return abs(ddx(value)) + abs(ddy(value)); +} + +#endif // GEOM_PARAMS_H diff --git a/data/resources/shaders/reshade/Shaders/misc/include/mask.fxh b/data/resources/shaders/reshade/Shaders/misc/include/mask.fxh new file mode 100644 index 000000000..2fa70f661 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/misc/include/mask.fxh @@ -0,0 +1,242 @@ +#ifndef MASK_PARAMS_H +#define MASK_PARAMS_H + +uniform float MASK_DARK_STRENGTH < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.01; + ui_category = "CRT Mask"; + ui_label = "MASK DARK SUBPIXEL STRENGTH"; +> = 0.5; + +uniform float MASK_LIGHT_STRENGTH < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 6.0; + ui_step = 0.01; + ui_category = "CRT Mask"; + ui_label = "MASK LIGHT SUBPIXEL STRENGTH"; +> = 0.5; + +/* Mask code pasted from subpixel_masks.h. Masks 3 and 4 added. */ +float3 mask_weights(float2 coord, int phosphor_layout, float monitor_subpixels, float mask_light_str, float mask_dark_str){ + float3 weights = float3(1.,1.,1.); + float on = 1.+mask_light_str; +// float on = 1.; + float off = 1.-mask_dark_str; + float3 red = monitor_subpixels==1.0 ? float3(on, off, off) : float3(off, off, on ); + float3 green = float3(off, on, off); + float3 blue = monitor_subpixels==1.0 ? float3(off, off, on ) : float3(on, off, off); + float3 magenta = float3(on, off, on ); + float3 yellow = monitor_subpixels==1.0 ? float3(on, on, off) : float3(off, on, on ); + float3 cyan = monitor_subpixels==1.0 ? float3(off, on, on ) : float3(on, on, off); + float3 black = float3(off, off, off); + float3 white = float3(on, on, on ); + int w, z = 0; + + // This pattern is used by a few layouts, so we'll define it here + float3 aperture_weights = lerp(magenta, green, floor(coord.x % 2.0)); + + if(phosphor_layout == 0) return weights; + + else if(phosphor_layout == 1){ + // classic aperture for RGB panels; good for 1080p, too small for 4K+ + // aka aperture_1_2_bgr + weights = aperture_weights; + return weights; + } + + else if(phosphor_layout == 2){ + // Classic RGB layout; good for 1080p and lower + float3 bw3[3] = {red, green, blue}; +// float3 bw3[3] = float3[](black, yellow, blue); + + z = int(floor(coord.x % 3.0)); + + weights = bw3[z]; + return weights; + } + + else if(phosphor_layout == 3){ + // black and white aperture; good for weird subpixel layouts and low brightness; good for 1080p and lower + float3 bw3[3] = {black, white, black}; + + z = int(floor(coord.x % 3.0)); + + weights = bw3[z]; + return weights; + } + + else if(phosphor_layout == 4){ + // reduced TVL aperture for RGB panels. Good for 4k. + // aperture_2_4_rgb + + float3 big_ap_rgb[4] = {red, yellow, cyan, blue}; + + w = int(floor(coord.x % 4.0)); + + weights = big_ap_rgb[w]; + return weights; + } + + else if(phosphor_layout == 5){ + // black and white aperture; good for weird subpixel layouts and low brightness; good for 4k + float3 bw4[4] = {black, black, white, white}; + + z = int(floor(coord.x % 4.0)); + + weights = bw4[z]; + return weights; + } + + else if(phosphor_layout == 6){ + // aperture_1_4_rgb; good for simulating lower + float3 ap4[4] = {red, green, blue, black}; + + z = int(floor(coord.x % 4.0)); + + weights = ap4[z]; + return weights; + } + + else if(phosphor_layout == 7){ + // 2x2 shadow mask for RGB panels; good for 1080p, too small for 4K+ + // aka delta_1_2x1_bgr + float3 inverse_aperture = lerp(green, magenta, floor(coord.x % 2.0)); + weights = lerp(aperture_weights, inverse_aperture, floor(coord.y % 2.0)); + return weights; + } + + else if(phosphor_layout == 8){ + // delta_2_4x1_rgb + float3 delta[8] = { + red, yellow, cyan, blue, + cyan, blue, red, yellow + }; + + w = int(floor(coord.y % 2.0)); + z = int(floor(coord.x % 4.0)); + + weights = delta[4*w+z]; + return weights; + } + + else if(phosphor_layout == 9){ + // delta_1_4x1_rgb; dunno why this is called 4x1 when it's obviously 4x2 /shrug + float3 delta1[8] = { + red, green, blue, black, + blue, black, red, green + }; + + w = int(floor(coord.y % 2.0)); + z = int(floor(coord.x % 4.0)); + + weights = delta1[4*w+z]; + return weights; + } + + else if(phosphor_layout == 10){ + // delta_2_4x2_rgb + float3 delta[16] = { + red, yellow, cyan, blue, + red, yellow, cyan, blue, + cyan, blue, red, yellow, + cyan, blue, red, yellow + }; + + w = int(floor(coord.y % 4.0)); + z = int(floor(coord.x % 4.0)); + + weights = delta[4*w+z]; + return weights; + } + + else if(phosphor_layout == 11){ + // slot mask for RGB panels; looks okay at 1080p, looks better at 4K + float3 slotmask[24] = { + red, green, blue, red, green, blue, + red, green, blue, black, black, black, + red, green, blue, red, green, blue, + black, black, black, red, green, blue, + }; + + w = int(floor(coord.y % 4.0)); + z = int(floor(coord.x % 6.0)); + + // use the indexes to find which color to apply to the current pixel + weights = slotmask[6*w+z]; + return weights; + } + + else if(phosphor_layout == 12){ + // slot mask for RGB panels; looks okay at 1080p, looks better at 4K + float3 slotmask[24] = { + black, white, black, black, white, black, + black, white, black, black, black, black, + black, white, black, black, white, black, + black, black, black, black, white, black + }; + + w = int(floor(coord.y % 4.0)); + z = int(floor(coord.x % 6.0)); + + // use the indexes to find which color to apply to the current pixel + weights = slotmask[6*w+z]; + return weights; + } + + else if(phosphor_layout == 13){ + // based on MajorPainInTheCactus' HDR slot mask + float3 slot[32] = { + red, green, blue, black, red, green, blue, black, + red, green, blue, black, black, black, black, black, + red, green, blue, black, red, green, blue, black, + black, black, black, black, red, green, blue, black + }; + + w = int(floor(coord.y % 4.0)); + z = int(floor(coord.x % 8.0)); + + weights = slot[8*w+z]; + return weights; + } + + else if(phosphor_layout == 14){ + // same as above but for RGB panels + float3 slot2[40] = { + red, yellow, green, blue, blue, red, yellow, green, blue, blue , + black, green, green, blue, blue, red, red, black, black, black, + red, yellow, green, blue, blue, red, yellow, green, blue, blue , + red, red, black, black, black, black, green, green, blue, blue + }; + + w = int(floor(coord.y % 4.0)); + z = int(floor(coord.x % 10.0)); + + weights = slot2[10*w+z]; + return weights; + } + + else if(phosphor_layout == 15){ + // slot_3_7x6_rgb + float3 slot[84] = { + red, red, yellow, green, cyan, blue, blue, red, red, yellow, green, cyan, blue, blue, + red, red, yellow, green, cyan, blue, blue, red, red, yellow, green, cyan, blue, blue, + red, red, yellow, green, cyan, blue, blue, black, black, black, black, black, black, black, + red, red, yellow, green, cyan, blue, blue, red, red, yellow, green, cyan, blue, blue, + red, red, yellow, green, cyan, blue, blue, red, red, yellow, green, cyan, blue, blue, + black, black, black, black, black, black, black, black, red, red, yellow, green, cyan, blue + }; + + w = int(floor(coord.y % 6.0)); + z = int(floor(coord.x % 14.0)); + + weights = slot[14*w+z]; + return weights; + } + + else return weights; +} + +#endif // MASK_PARAMS_H diff --git a/data/resources/shaders/reshade/Textures/overlay/psx.jpg b/data/resources/shaders/reshade/Textures/overlay/psx.jpg index 8362110da..2663817fb 100644 Binary files a/data/resources/shaders/reshade/Textures/overlay/psx.jpg and b/data/resources/shaders/reshade/Textures/overlay/psx.jpg differ