diff --git a/data/resources/shaders/crt-lottes.glsl b/data/resources/shaders/crt-lottes.glsl index 8281c9acf..ed9494651 100644 --- a/data/resources/shaders/crt-lottes.glsl +++ b/data/resources/shaders/crt-lottes.glsl @@ -133,7 +133,7 @@ float3 ToLinear(float3 c) } float3 ToSrgb(float3 c) { - return pow(c, float3(1.0 / 2.2)); + return pow(c, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2)); } #else float ToLinear1(float c) diff --git a/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx b/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx new file mode 100644 index 000000000..02f21624b --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/CRT-NewPixie.fx @@ -0,0 +1,298 @@ +#include "ReShade.fxh" + +// newpixie CRT +// by Mattias Gustavsson +// adapted for slang by hunterk + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses - you may choose the one you like. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2016 Mattias Gustavsson +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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 float acc_modulate < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.01; + ui_label = "Accumulate Modulation [CRT-NewPixie]"; +> = 0.65; + + +texture2D tAccTex { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA8; }; +sampler sAccTex { Texture=tAccTex; }; + +//PASS 1 +float3 PrevColor(float4 pos : SV_Position, float2 uv : TEXCOORD0) : SV_Target +{ + return tex2D(ReShade::BackBuffer, uv).rgb; +} + +float4 PS_NewPixie_Accum(float4 pos : SV_Position, float2 uv : TEXCOORD0) : SV_Target +{ + float4 a = tex2D(sAccTex, uv.xy) * float4(acc_modulate,acc_modulate,acc_modulate,acc_modulate); + float4 b = tex2D(ReShade::BackBuffer, uv.xy); + return max( a, b * 0.96 ); +} + +//PASS 2 AND 3 +texture GaussianBlurTex { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA8; }; +sampler GaussianBlurSampler { Texture = GaussianBlurTex;}; + +uniform float blur_x < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 5.0; + ui_step = 0.25; + ui_label = "Horizontal Blur [CRT-NewPixie]"; +> = 1.0; + +uniform float blur_y < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 5.0; + ui_step = 0.25; + ui_label = "Vertical Blur [CRT-NewPixie]"; +> = 1.0; + +float4 PS_NewPixie_Blur(float4 pos : SV_Position, float2 uv_tx : TEXCOORD0) : SV_Target +{ + float2 blur = float2(blur_x, blur_y) * ReShade::PixelSize.xy; + float2 uv = uv_tx.xy; + float4 sum = tex2D( ReShade::BackBuffer, uv ) * 0.2270270270; + sum += tex2D(ReShade::BackBuffer, float2( uv.x - 4.0 * blur.x, uv.y - 4.0 * blur.y ) ) * 0.0162162162; + sum += tex2D(ReShade::BackBuffer, float2( uv.x - 3.0 * blur.x, uv.y - 3.0 * blur.y ) ) * 0.0540540541; + sum += tex2D(ReShade::BackBuffer, float2( uv.x - 2.0 * blur.x, uv.y - 2.0 * blur.y ) ) * 0.1216216216; + sum += tex2D(ReShade::BackBuffer, float2( uv.x - 1.0 * blur.x, uv.y - 1.0 * blur.y ) ) * 0.1945945946; + sum += tex2D(ReShade::BackBuffer, float2( uv.x + 1.0 * blur.x, uv.y + 1.0 * blur.y ) ) * 0.1945945946; + sum += tex2D(ReShade::BackBuffer, float2( uv.x + 2.0 * blur.x, uv.y + 2.0 * blur.y ) ) * 0.1216216216; + sum += tex2D(ReShade::BackBuffer, float2( uv.x + 3.0 * blur.x, uv.y + 3.0 * blur.y ) ) * 0.0540540541; + sum += tex2D(ReShade::BackBuffer, float2( uv.x + 4.0 * blur.x, uv.y + 4.0 * blur.y ) ) * 0.0162162162; + return sum; +} + +//PASS 4 +uniform int FCount < source = "framecount"; >; +texture tFrame < source = "crt-newpixie/crtframe.png"; > +{ + Width = 1024; + Height = 1024; + MipLevels = 1; +}; + +sampler sFrame { Texture = tFrame; AddressU = BORDER; AddressV = BORDER; MinFilter = LINEAR; MagFilter = LINEAR;}; + +uniform bool use_frame < + ui_type = "boolean"; + ui_label = "Use Frame Image [CRT-NewPixie]"; +> = false; + +uniform float curvature < + ui_type = "drag"; + ui_min = 0.0001; + ui_max = 4.0; + ui_step = 0.25; + ui_label = "Curvature [CRT-NewPixie]"; +> = 2.0; + +uniform bool wiggle_toggle < + ui_type = "boolean"; + ui_label = "Interference [CRT-NewPixie]"; +> = false; + +uniform bool scanroll < + ui_type = "boolean"; + ui_label = "Rolling Scanlines [CRT-NewPixie]"; +> = true; + +float3 tsample( sampler samp, float2 tc, float offs, float2 resolution ) +{ + tc = tc * float2(1.025, 0.92) + float2(-0.0125, 0.04); + float3 s = pow( abs( tex2D( samp, float2( tc.x, 1.0-tc.y ) ).rgb), float3( 2.2,2.2,2.2 ) ); + return s*float3(1.25,1.25,1.25); +} + +float3 filmic( float3 LinearColor ) +{ + float3 x = max( float3(0.0,0.0,0.0), LinearColor-float3(0.004,0.004,0.004)); + return (x*(6.2*x+0.5))/(x*(6.2*x+1.7)+0.06); +} + +float2 curve( float2 uv ) +{ + uv = (uv - 0.5);// * 2.0; + uv *= float2(0.925, 1.095); + uv *= curvature; + uv.x *= 1.0 + pow((abs(uv.y) / 4.0), 2.0); + uv.y *= 1.0 + pow((abs(uv.x) / 3.0), 2.0); + uv /= curvature; + uv += 0.5; + uv = uv *0.92 + 0.04; + return uv; +} + +float rand(float2 co){ return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453); } + +#define resolution ReShade::ScreenSize.xy +#define mod(x,y) (x-y*floor(x/y)) + +float4 PS_NewPixie_Final(float4 pos: SV_Position, float2 uv_tx : TEXCOORD0) : SV_Target +{ + // stop time variable so the screen doesn't wiggle + float time = mod(FCount, 849.0) * 36.0; + float2 uv = uv_tx.xy; + uv.y = 1.0 - uv_tx.y; + /* Curve */ + float2 curved_uv = lerp( curve( uv ), uv, 0.4 ); + float scale = -0.101; + float2 scuv = curved_uv*(1.0-scale)+scale/2.0+float2(0.003, -0.001); + + uv = scuv; + + /* Main color, Bleed */ + float3 col; + + float x = wiggle_toggle* sin(0.1*time+curved_uv.y*13.0)*sin(0.23*time+curved_uv.y*19.0)*sin(0.3+0.11*time+curved_uv.y*23.0)*0.0012; + float o =sin(uv_tx.y*1.5)/resolution.x; + x+=o*0.25; + // make time do something again + time = float(mod(FCount, 640) * 1); + col.r = tsample(ReShade::BackBuffer,float2(x+scuv.x+0.0009,scuv.y+0.0009),resolution.y/800.0, resolution ).x+0.02; + col.g = tsample(ReShade::BackBuffer,float2(x+scuv.x+0.0000,scuv.y-0.0011),resolution.y/800.0, resolution ).y+0.02; + col.b = tsample(ReShade::BackBuffer,float2(x+scuv.x-0.0015,scuv.y+0.0000),resolution.y/800.0, resolution ).z+0.02; + float i = clamp(col.r*0.299 + col.g*0.587 + col.b*0.114, 0.0, 1.0 ); + i = pow( 1.0 - pow(i,2.0), 1.0 ); + i = (1.0-i) * 0.85 + 0.15; + + /* Ghosting */ + float ghs = 0.15; + float3 r = tsample(GaussianBlurSampler, float2(x-0.014*1.0, -0.027)*0.85+0.007*float2( 0.35*sin(1.0/7.0 + 15.0*curved_uv.y + 0.9*time), + 0.35*sin( 2.0/7.0 + 10.0*curved_uv.y + 1.37*time) )+float2(scuv.x+0.001,scuv.y+0.001), + 5.5+1.3*sin( 3.0/9.0 + 31.0*curved_uv.x + 1.70*time),resolution).xyz*float3(0.5,0.25,0.25); + float3 g = tsample(GaussianBlurSampler, float2(x-0.019*1.0, -0.020)*0.85+0.007*float2( 0.35*cos(1.0/9.0 + 15.0*curved_uv.y + 0.5*time), + 0.35*sin( 2.0/9.0 + 10.0*curved_uv.y + 1.50*time) )+float2(scuv.x+0.000,scuv.y-0.002), + 5.4+1.3*sin( 3.0/3.0 + 71.0*curved_uv.x + 1.90*time),resolution).xyz*float3(0.25,0.5,0.25); + float3 b = tsample(GaussianBlurSampler, float2(x-0.017*1.0, -0.003)*0.85+0.007*float2( 0.35*sin(2.0/3.0 + 15.0*curved_uv.y + 0.7*time), + 0.35*cos( 2.0/3.0 + 10.0*curved_uv.y + 1.63*time) )+float2(scuv.x-0.002,scuv.y+0.000), + 5.3+1.3*sin( 3.0/7.0 + 91.0*curved_uv.x + 1.65*time),resolution).xyz*float3(0.25,0.25,0.5); + + col += float3(ghs*(1.0-0.299),ghs*(1.0-0.299),ghs*(1.0-0.299))*pow(clamp(float3(3.0,3.0,3.0)*r,float3(0.0,0.0,0.0),float3(1.0,1.0,1.0)),float3(2.0,2.0,2.0))*float3(i,i,i); + col += float3(ghs*(1.0-0.587),ghs*(1.0-0.587),ghs*(1.0-0.587))*pow(clamp(float3(3.0,3.0,3.0)*g,float3(0.0,0.0,0.0),float3(1.0,1.0,1.0)),float3(2.0,2.0,2.0))*float3(i,i,i); + col += float3(ghs*(1.0-0.114),ghs*(1.0-0.114),ghs*(1.0-0.114))*pow(clamp(float3(3.0,3.0,3.0)*b,float3(0.0,0.0,0.0),float3(1.0,1.0,1.0)),float3(2.0,2.0,2.0))*float3(i,i,i); + + /* Level adjustment (curves) */ + col *= float3(0.95,1.05,0.95); + col = clamp(col*1.3 + 0.75*col*col + 1.25*col*col*col*col*col,float3(0.0,0.0,0.0),float3(10.0,10.0,10.0)); + + /* Vignette */ + float vig = (0.1 + 1.0*16.0*curved_uv.x*curved_uv.y*(1.0-curved_uv.x)*(1.0-curved_uv.y)); + vig = 1.3*pow(vig,0.5); + col *= vig; + + time *= scanroll; + + /* Scanlines */ + float scans = clamp( 0.35+0.18*sin(6.0*time-curved_uv.y*resolution.y*1.5), 0.0, 1.0); + float s = pow(scans,0.9); + col = col * float3(s,s,s); + + /* Vertical lines (shadow mask) */ + col*=1.0-0.23*(clamp((mod(uv_tx.xy.x, 3.0))/2.0,0.0,1.0)); + + /* Tone map */ + col = filmic( col ); + + /* Noise */ + /*float2 seed = floor(curved_uv*resolution.xy*float2(0.5))/resolution.xy;*/ + float2 seed = curved_uv*resolution.xy;; + /* seed = curved_uv; */ + col -= 0.015*pow(float3(rand( seed +time ), rand( seed +time*2.0 ), rand( seed +time * 3.0 ) ), float3(1.5,1.5,1.5) ); + + /* Flicker */ + col *= (1.0-0.004*(sin(50.0*time+curved_uv.y*2.0)*0.5+0.5)); + + /* Clamp */ +// if(max(abs(uv.x-0.5),abs(uv.y-0.5))>0.5) +// col = float3(0.0,0.0,0.0); + +// if (curved_uv.x < 0.0 || curved_uv.x > 1.0) +// col *= 0.0; +// if (curved_uv.y < 0.0 || curved_uv.y > 1.0) +// col *= 0.0; + + uv = curved_uv; + + /* 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)); + 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 ) ); + + return float4( col, 1.0 ); +} + +technique CRTNewPixie +{ + pass PS_CRTNewPixie_Accum + { + VertexShader=PostProcessVS; + PixelShader=PS_NewPixie_Accum; + } + + pass PS_CRTNewPixie_SaveBuffer { + VertexShader=PostProcessVS; + PixelShader=PrevColor; + RenderTarget = tAccTex; + } + + pass PS_CRTNewPixie_Blur + { + VertexShader = PostProcessVS; + PixelShader = PS_NewPixie_Blur; + RenderTarget = GaussianBlurTex; + } + + pass PS_CRTNewPixie_Final + { + VertexShader = PostProcessVS; + PixelShader = PS_NewPixie_Final; + } +} diff --git a/data/resources/shaders/reshade/Shaders/CRTLottes2.fx b/data/resources/shaders/reshade/Shaders/CRTLottes2.fx new file mode 100644 index 000000000..dcf095355 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/CRTLottes2.fx @@ -0,0 +1,446 @@ +#include "ReShade.fxh" + +// +// PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER +// +// by Timothy Lottes +// +// This is more along the style of a really good CGA arcade monitor. +// With RGB inputs instead of NTSC. +// The shadow mask example has the mask rotated 90 degrees for less chromatic aberration. +// +// Left it unoptimized to show the theory behind the algorithm. +// +// It is an example what I personally would want as a display option for pixel art games. +// Please take and use, change, or whatever. +// + +#ifndef CRTS_DEBUG + #define CRTS_DEBUG 0 +#endif + +#ifndef CRTS_2_TAP + #define CRTS_2_TAP 0 +#endif + +uniform bool CRTS_WARP < + ui_type = "boolean"; + ui_label = "Enable Warping [CRT Lottes 2.0]"; +> = true; + +uniform float CRTS_WARP_X < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 512.0; + ui_label = "CRT Warping X [CRT Lottes 2.0]"; +> = 64.0; + +uniform float CRTS_WARP_Y < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 512.0; + ui_label = "CRT Warping Y [CRT Lottes 2.0]"; +> = 48.0; + +uniform bool CRTS_TONE < + ui_type = "boolean"; + ui_label = "Enable CRT Tonemapping [CRT Lottes 2.0]"; +> = true; + +uniform bool CRTS_CONTRAST < + ui_type = "boolean"; + ui_label = "Enable CRT Contrast [CRT Lottes 2.0]"; +> = false; + +uniform bool CRTS_SATURATION < + ui_type = "boolean"; + ui_label = "Enable CRT Saturation [CRT Lottes 2.0]"; +> = false; + +uniform int CRTS_MASK_TYPE < + ui_type = "combo"; + ui_items = "None\0Aperture Grille\0Aperture Grille (Lite)\0Shadow Mask\0"; + ui_label = "Mask Type [CRT Lottes 2.0]"; +> = 2; + +//-------------------------------------------------------------- +// Scanline thinness +// 0.50 = fused scanlines +// 0.70 = recommended default +// 1.00 = thinner scanlines (too thin) + +uniform float INPUT_THIN < + ui_type = "drag"; + ui_min = 0.5; + ui_max = 1.0; + ui_label = "Scanlines Thinnes [CRT Lottes 2.0]"; +> = 0.70; + +//-------------------------------------------------------------- +// Horizonal scan blur +// -3.0 = pixely +// -2.5 = default +// -2.0 = smooth +// -1.0 = too blurry + +uniform float INPUT_BLUR < + ui_type = "drag"; + ui_min = -3.0; + ui_max = 0.0; + ui_label = "Horizontal Scan Blur [CRT Lottes 2.0]"; +> = -2.5; + +//-------------------------------------------------------------- +// Shadow mask effect, ranges from, +// 0.25 = large amount of mask (not recommended, too dark) +// 0.50 = recommended default +// 1.00 = no shadow mask + +uniform float INPUT_MASK < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_label = "Shadow Mask Intensity [CRT Lottes 2.0]"; +> = 0.5; + +//-------------------------------------------------------------- + +uniform int INPUT_X < + ui_type = "drag"; + ui_min = 1; + ui_max = BUFFER_WIDTH; + ui_label = "Resolution Width [CRT Lottes 2.0]"; +> = 640; + +uniform int INPUT_Y < + ui_type = "drag"; + ui_min = 1; + ui_max = BUFFER_HEIGHT; + ui_label = "Resolution Height [CRT Lottes 2.0]"; +> = 480; + +//-------------------------------------------------------------- +// Setup the function which returns input image color + +void ToLinear(inout float3 color) +{ + float3 c1 = color.rgb / 12.92; + float3 c2 = pow((color.rgb + 0.055)/1.055, 2.4); + + color.r = (color.r <= 0.04045) ? c1.r : c2.r; + color.g = (color.g <= 0.04045) ? c1.g : c2.g; + color.b = (color.b <= 0.04045) ? c1.b : c2.b; +} + +void ToSRGB(inout float3 color) +{ + float3 c1 = color.rgb * 12.92; + float3 c2 = 1.055 * pow(color.rgb, 0.4166) - 0.055; + + color.r = (color.r < 0.0031308) ? c1.r : c2.r; + color.g = (color.g < 0.0031308) ? c1.g : c2.g; + color.b = (color.b < 0.0031308) ? c1.b : c2.b; +} + +float3 CrtsFetch(float2 uv) +{ + float3 color = tex2D(ReShade::BackBuffer, uv).rgb; + ToLinear(color); + return color; +} + +float4 CrtsTone( +float contrast, +float saturation, +float thin, +float mask) +{ + + mask = INPUT_MASK; + + if (CRTS_MASK_TYPE <= 0){ + mask=1.0; + } + + + if(CRTS_MASK_TYPE == 2){ + mask=0.5+INPUT_MASK*0.5; + } + + float4 ret; + float midOut=0.18/((1.5-thin)*(0.5*mask+0.5)); + float pMidIn=pow(0.18,contrast); + ret.x=contrast; + ret.y=((-pMidIn)+midOut)/((1.0-pMidIn)*midOut); + ret.z=((-pMidIn)*midOut+pMidIn)/(midOut*(-pMidIn)+midOut); + ret.w=contrast+saturation; + return ret; +} + +float3 CrtsMask(float2 pos,float dark) +{ + + if (CRTS_MASK_TYPE == 1){ + float3 m=dark; + float x=frac(pos.x*(1.0/3.0)); + if(x<(1.0/3.0))m.r=1.0; + else if(x<(2.0/3.0))m.g=1.0; + else m.b=1.0; + return m; + } else if (CRTS_MASK_TYPE == 2){ + float3 m=1.0; + float x=frac(pos.x*(1.0/3.0)); + if(x<(1.0/3.0))m.r=dark; + else if(x<(2.0/3.0))m.g=dark; + else m.b=dark; + return m; + } else if(CRTS_MASK_TYPE <= 0){ + return 1.0; + } else if(CRTS_MASK_TYPE >= 3){ + pos.x+=pos.y*3.0; + float3 m=dark; + float x=frac(pos.x*(1.0/6.0)); + if(x<(1.0/3.0))m.r=1.0; + else if(x<(2.0/3.0))m.g=1.0; + else m.b=1.0; + return m; + } else { + return 0.0; + } + } + + float3 CrtsFilter( +//-------------------------------------------------------------- + // SV_POSITION, fragCoord.xy + float2 ipos, +//-------------------------------------------------------------- + // inputSize / outputSize (in pixels) + float2 inputSizeDivOutputSize, +//-------------------------------------------------------------- + // 0.5 * inputSize (in pixels) + float2 halfInputSize, +//-------------------------------------------------------------- + // 1.0 / inputSize (in pixels) + float2 rcpInputSize, +//-------------------------------------------------------------- + // 1.0 / outputSize (in pixels) + float2 rcpOutputSize, +//-------------------------------------------------------------- + // 2.0 / outputSize (in pixels) + float2 twoDivOutputSize, +//-------------------------------------------------------------- + // inputSize.y + float inputHeight, +//-------------------------------------------------------------- + // Warp scanlines but not phosphor mask + // 0.0 = no warp + // 1.0/64.0 = light warping + // 1.0/32.0 = more warping + // Want x and y warping to be different (based on aspect) + float2 warp, +//-------------------------------------------------------------- + // Scanline thinness + // 0.50 = fused scanlines + // 0.70 = recommended default + // 1.00 = thinner scanlines (too thin) + // Shared with CrtsTone() function + float thin, +//-------------------------------------------------------------- + // Horizonal scan blur + // -3.0 = pixely + // -2.5 = default + // -2.0 = smooth + // -1.0 = too blurry + float blur, +//-------------------------------------------------------------- + // Shadow mask effect, ranges from, + // 0.25 = large amount of mask (not recommended, too dark) + // 0.50 = recommended default + // 1.00 = no shadow mask + // Shared with CrtsTone() function + float mask, +//-------------------------------------------------------------- + // Tonal curve parameters generated by CrtsTone() + float4 tone +//-------------------------------------------------------------- + ){ +//-------------------------------------------------------------- + #if (CRTS_DEBUG == 1) + float2 uv=ipos*rcpOutputSize; + // Show second half processed, and first half un-processed + if(uv.x<0.5) + { + // Force nearest to get squares + uv*=1.0/rcpInputSize; + uv=floor(uv)+float2(0.5,0.5); + uv*=rcpInputSize; + float3 color=CrtsFetch(uv); + return color; + } + #endif + + float2 pos; + float vin; + + if (CRTS_WARP){ + // Convert to {-1 to 1} range + pos=ipos*twoDivOutputSize-float2(1.0,1.0); + // Distort pushes image outside {-1 to 1} range + pos*=float2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y); + // TODO: Vignette needs optimization + vin=1.0-((1.0-saturate(pos.x*pos.x))*(1.0-saturate(pos.y*pos.y))); + vin=saturate((-vin)*inputHeight+inputHeight); + // Leave in {0 to inputSize} + pos=pos*halfInputSize+halfInputSize; + } else { + pos=ipos*inputSizeDivOutputSize; + } + + // Snap to center of first scanline + float y0=floor(pos.y-0.5)+0.5; + + #if (CRTS_2_TAP == 1) + // Using Inigo's "Improved Texture Interpolation" + // http://iquilezles.org/www/articles/texture/texture.htm + pos.x+=0.5; + float xi=floor(pos.x); + float xf=pos.x-xi; + xf=xf*xf*xf*(xf*(xf*6.0-15.0)+10.0); + float x0=xi+xf-0.5; + float2 p=float2(x0*rcpInputSize.x,y0*rcpInputSize.y); + // Coordinate adjusted bilinear fetch from 2 nearest scanlines + float3 colA=CrtsFetch(p); + p.y+=rcpInputSize.y; + float3 colB=CrtsFetch(p); + #else + // Snap to center of one of four pixels + float x0=floor(pos.x-1.5)+0.5; + // Inital UV position + float2 p=float2(x0*rcpInputSize.x,y0*rcpInputSize.y); + // Fetch 4 nearest texels from 2 nearest scanlines + float3 colA0=CrtsFetch(p); + p.x+=rcpInputSize.x; + float3 colA1=CrtsFetch(p); + p.x+=rcpInputSize.x; + float3 colA2=CrtsFetch(p); + p.x+=rcpInputSize.x; + float3 colA3=CrtsFetch(p); + p.y+=rcpInputSize.y; + float3 colB3=CrtsFetch(p); + p.x-=rcpInputSize.x; + float3 colB2=CrtsFetch(p); + p.x-=rcpInputSize.x; + float3 colB1=CrtsFetch(p); + p.x-=rcpInputSize.x; + float3 colB0=CrtsFetch(p); + #endif + + // Vertical filter + // Scanline intensity is using sine wave + // Easy filter window and integral used later in exposure + float off=pos.y-y0; + float pi2=6.28318530717958; + float hlf=0.5; + float scanA=cos(min(0.5, off *thin )*pi2)*hlf+hlf; + float scanB=cos(min(0.5,(-off)*thin+thin)*pi2)*hlf+hlf; + + #if (CRTS_2_TAP == 1) + if (CRTS_WARP){ + // Get rid of wrong pixels on edge + scanA*=vin; + scanB*=vin; + } + // Apply vertical filter + float3 color=(colA*scanA)+(colB*scanB); + #else + // Horizontal kernel is simple gaussian filter + float off0=pos.x-x0; + float off1=off0-1.0; + float off2=off0-2.0; + float off3=off0-3.0; + float pix0=exp2(blur*off0*off0); + float pix1=exp2(blur*off1*off1); + float pix2=exp2(blur*off2*off2); + float pix3=exp2(blur*off3*off3); + float pixT=rcp(pix0+pix1+pix2+pix3); + + if (CRTS_WARP){ + // Get rid of wrong pixels on edge + pixT*=vin; + } + scanA*=pixT; + scanB*=pixT; + // Apply horizontal and vertical filters + float3 color= + (colA0*pix0+colA1*pix1+colA2*pix2+colA3*pix3)*scanA + + (colB0*pix0+colB1*pix1+colB2*pix2+colB3*pix3)*scanB; + #endif + + // Apply phosphor mask + color*=CrtsMask(ipos,mask); + // Optional color processing + if (CRTS_TONE){ + // Tonal control, start by protecting from /0 + float peak=max(1.0/(256.0*65536.0),max(color.r,max(color.g,color.b))); + // Compute the ratios of {R,G,B} + float3 ratio=color*rcp(peak); + // Apply tonal curve to peak value + if (CRTS_CONTRAST){ + peak=pow(peak,tone.x); + } + peak=peak*rcp(peak*tone.y+tone.z); + // Apply saturation + if (CRTS_SATURATION){ + ratio=pow(ratio,float3(tone.w,tone.w,tone.w)); + } + // Reconstruct color + return ratio*peak; + } else { + return color; + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +void PS_CRTLottes2018(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 color : SV_Target0) +{ + color = tex2D(ReShade::BackBuffer, texcoord.xy); + + color.rgb=CrtsFilter( + vpos.xy, + float2(INPUT_X,INPUT_Y)/ReShade::ScreenSize.xy, + float2(INPUT_X,INPUT_Y)*0.5, + 1.0/float2(INPUT_X,INPUT_Y), + 1.0/ReShade::ScreenSize.xy, + 2.0/ReShade::ScreenSize.xy, + INPUT_Y, + float2(1.0/CRTS_WARP_X,1.0/CRTS_WARP_Y), + INPUT_THIN, + INPUT_BLUR, + INPUT_MASK, + CrtsTone(1.0,0.0,INPUT_THIN,INPUT_MASK)); + + ToSRGB(color.rgb); +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +technique CRTLottes2018 +{ + pass + { + VertexShader = PostProcessVS; + PixelShader = PS_CRTLottes2018; + } +} \ No newline at end of file diff --git a/data/resources/shaders/reshade/Shaders/FilmGrain2.fx b/data/resources/shaders/reshade/Shaders/FilmGrain2.fx new file mode 100644 index 000000000..8d3acf6b4 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/FilmGrain2.fx @@ -0,0 +1,149 @@ +/** + * Film Grain post-process shader v1.1 + * Martins Upitis (martinsh) devlog-martinsh.blogspot.com 2013 + * + * This work is licensed under a Creative Commons Attribution 3.0 Unported License. + * So you are free to share, modify and adapt it for your needs, and even use it for commercial use. + * + * Uses perlin noise shader by toneburst from http://machinesdontcare.wordpress.com/2009/06/25/3d-perlin-noise-sphere-vertex-shader-sourcecode/ + */ + +#include "ReShadeUI.fxh" + +uniform float grainamount < __UNIFORM_SLIDER_FLOAT1 + ui_min = 0.0; ui_max = 0.2; + ui_label = "Amount"; +> = 0.05; +uniform float coloramount < __UNIFORM_SLIDER_FLOAT1 + ui_min = 0.0; ui_max = 1.0; + ui_label = "Color Amount"; +> = 0.6; +uniform float lumamount < __UNIFORM_SLIDER_FLOAT1 + ui_min = 0.0; ui_max = 1.0; + ui_label = "Luminance Amount"; +> = 1.0; + +uniform float grainsize < __UNIFORM_SLIDER_FLOAT1 + ui_min = 1.5; ui_max = 2.5; + ui_label = "Grain Particle Size"; +> = 1.6; + +#include "ReShade.fxh" + +uniform float timer < source = "timer"; >; + +float4 rnm(in float2 tc) +{ + // A random texture generator, but you can also use a pre-computed perturbation texture + float noise = sin(dot(tc, float2(12.9898, 78.233))) * 43758.5453; + + float noiseR = frac(noise) * 2.0 - 1.0; + float noiseG = frac(noise * 1.2154) * 2.0 - 1.0; + float noiseB = frac(noise * 1.3453) * 2.0 - 1.0; + float noiseA = frac(noise * 1.3647) * 2.0 - 1.0; + + return float4(noiseR, noiseG, noiseB, noiseA); +} +float pnoise3D(in float3 p) +{ + // Perm texture texel-size + static const float permTexUnit = 1.0 / 256.0; + // Half perm texture texel-size + static const float permTexUnitHalf = 0.5 / 256.0; + + // Integer part + // Scaled so +1 moves permTexUnit texel and offset 1/2 texel to sample texel centers + float3 pi = permTexUnit * floor(p) + permTexUnitHalf; + // Fractional part for interpolation + float3 pf = frac(p); + + // Noise contributions from (x=0, y=0), z=0 and z=1 + float perm00 = rnm(pi.xy).a; + float3 grad000 = rnm(float2(perm00, pi.z)).rgb * 4.0 - 1.0; + float n000 = dot(grad000, pf); + float3 grad001 = rnm(float2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0; + float n001 = dot(grad001, pf - float3(0.0, 0.0, 1.0)); + + // Noise contributions from (x=0, y=1), z=0 and z=1 + float perm01 = rnm(pi.xy + float2(0.0, permTexUnit)).a; + float3 grad010 = rnm(float2(perm01, pi.z)).rgb * 4.0 - 1.0; + float n010 = dot(grad010, pf - float3(0.0, 1.0, 0.0)); + float3 grad011 = rnm(float2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0; + float n011 = dot(grad011, pf - float3(0.0, 1.0, 1.0)); + + // Noise contributions from (x=1, y=0), z=0 and z=1 + float perm10 = rnm(pi.xy + float2(permTexUnit, 0.0)).a; + float3 grad100 = rnm(float2(perm10, pi.z)).rgb * 4.0 - 1.0; + float n100 = dot(grad100, pf - float3(1.0, 0.0, 0.0)); + float3 grad101 = rnm(float2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0; + float n101 = dot(grad101, pf - float3(1.0, 0.0, 1.0)); + + // Noise contributions from (x=1, y=1), z=0 and z=1 + float perm11 = rnm(pi.xy + float2(permTexUnit, permTexUnit)).a; + float3 grad110 = rnm(float2(perm11, pi.z)).rgb * 4.0 - 1.0; + float n110 = dot(grad110, pf - float3(1.0, 1.0, 0.0)); + float3 grad111 = rnm(float2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0; + float n111 = dot(grad111, pf - float3(1.0, 1.0, 1.0)); + + // Blend contributions along x + float fade_x = pf.x * pf.x * pf.x * (pf.x * (pf.x * 6.0 - 15.0) + 10.0); + float4 n_x = lerp(float4(n000, n001, n010, n011), float4(n100, n101, n110, n111), fade_x); + + // Blend contributions along y + float fade_y = pf.y * pf.y * pf.y * (pf.y * (pf.y * 6.0 - 15.0) + 10.0); + float2 n_xy = lerp(n_x.xy, n_x.zw, fade_y); + + // Blend contributions along z + float fade_z = pf.z * pf.z * pf.z * (pf.z * (pf.z * 6.0 - 15.0) + 10.0); + float n_xyz = lerp(n_xy.x, n_xy.y, fade_z); + + // We're done, return the final noise value. + return n_xyz; +} + +float2 coordRot(in float2 tc, in float angle) +{ + float rotX = ((tc.x * 2.0 - 1.0) * BUFFER_ASPECT_RATIO * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle)); + float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * BUFFER_ASPECT_RATIO * sin(angle)); + rotX = ((rotX / BUFFER_ASPECT_RATIO) * 0.5 + 0.5); + rotY = rotY * 0.5 + 0.5; + + return float2(rotX, rotY); +} + +float4 main(float4 vpos : SV_Position, float2 texCoord : TexCoord) : SV_Target +{ + float3 rotOffset = float3(1.425, 3.892, 5.835); // Rotation offset values + float2 rotCoordsR = coordRot(texCoord, timer + rotOffset.x); + float3 noise = pnoise3D(float3(rotCoordsR * BUFFER_SCREEN_SIZE / grainsize, 0.0)).xxx; + + if (coloramount > 0) + { + float2 rotCoordsG = coordRot(texCoord, timer + rotOffset.y); + float2 rotCoordsB = coordRot(texCoord, timer + rotOffset.z); + noise.g = lerp(noise.r, pnoise3D(float3(rotCoordsG * BUFFER_SCREEN_SIZE / grainsize, 1.0)), coloramount); + noise.b = lerp(noise.r, pnoise3D(float3(rotCoordsB * BUFFER_SCREEN_SIZE / grainsize, 2.0)), coloramount); + } + + float3 col = tex2D(ReShade::BackBuffer, texCoord).rgb; + + const float3 lumcoeff = float3(0.299, 0.587, 0.114); + float luminance = lerp(0.0, dot(col, lumcoeff), lumamount); + float lum = smoothstep(0.2, 0.0, luminance); + lum += luminance; + + + noise = lerp(noise, 0.0, pow(lum, 4.0)); + col = col + noise * grainamount; + + return float4(col, 1.0); +} + +technique FilmGrain2 +{ + pass + { + VertexShader = PostProcessVS; + PixelShader = main; + } +} diff --git a/data/resources/shaders/reshade/Shaders/scanlines-abs.fx b/data/resources/shaders/reshade/Shaders/scanlines-abs.fx new file mode 100644 index 000000000..06c34c643 --- /dev/null +++ b/data/resources/shaders/reshade/Shaders/scanlines-abs.fx @@ -0,0 +1,77 @@ +/* + Scanlines Sine Absolute Value + An ultra light scanline shader + by RiskyJumps + license: public domain +*/ + +#include "ReShade.fxh" + +uniform float texture_sizeY < + ui_type = "drag"; + ui_min = 1.0; + ui_max = BUFFER_HEIGHT; + ui_label = "Scanlines Height [Scanlines-Absolute]"; +> = 240.0; + +uniform float amp < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 2.0; + ui_step = 0.05; + ui_label = "Amplitude [Scanlines-Absolute]"; +> = 1.25; + +uniform float phase < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 2.0; + ui_step = 0.05; + ui_label = "Phase [Scanlines-Absolute]"; +> = 0.0; + +uniform float lines_black < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 1.0; + ui_step = 0.05; + ui_label = "Lines Blacks [Scanlines-Absolute]"; +> = 0.0; + +uniform float lines_white < + ui_type = "drag"; + ui_min = 0.0; + ui_max = 2.0; + ui_step = 0.05; + ui_label = "Lines Whites [Scanlines-Absolute]"; +> = 1.0; + +#define freq 0.500000 +#define offset 0.000000 +#define pi 3.141592654 + +float4 PS_ScanlinesAbs(float4 pos : SV_POSITION, float2 tex : TEXCOORD0) : SV_TARGET +{ + float3 color = tex2D(ReShade::BackBuffer, tex).xyz; + float grid; + + float lines; + + float omega = 2.0 * pi * freq; // Angular frequency + float angle = tex.y * omega * texture_sizeY + phase; + + lines = sin(angle); + lines *= amp; + lines += offset; + lines = abs(lines) * (lines_white - lines_black) + lines_black; + color *= lines; + + return color.xyzz; +} + +technique ScanlinesAbs { + pass ScanlinesAbsolute{ + VertexShader = PostProcessVS; + PixelShader = PS_ScanlinesAbs; + } +} \ No newline at end of file diff --git a/data/resources/shaders/reshade/Textures/crt-newpixie/crtframe.png b/data/resources/shaders/reshade/Textures/crt-newpixie/crtframe.png new file mode 100644 index 000000000..9a467f019 Binary files /dev/null and b/data/resources/shaders/reshade/Textures/crt-newpixie/crtframe.png differ diff --git a/data/resources/shaders/reshade/source.txt b/data/resources/shaders/reshade/source.txt index 11c527f79..f97a2f2f6 100644 --- a/data/resources/shaders/reshade/source.txt +++ b/data/resources/shaders/reshade/source.txt @@ -1 +1,2 @@ -https://github.com/crosire/reshade-shaders \ No newline at end of file +https://github.com/crosire/reshade-shaders +https://github.com/Matsilagi/RSRetroArch/ diff --git a/data/resources/thirdparty.html b/data/resources/thirdparty.html index 906e36dfb..a64c1065a 100644 --- a/data/resources/thirdparty.html +++ b/data/resources/thirdparty.html @@ -71,7 +71,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

cubeb - https://github.com/mozilla/cubeb

-Copyright © 2011 Mozilla Foundation
+Copyright   2011 Mozilla Foundation
 
 Permission to use, copy, modify, and distribute this software for any
 purpose with or without fee is hereby granted, provided that the above
@@ -1624,7 +1624,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 The MIT License (MIT)
 
 Copyright (c) 2014-2021 Florian Bernd
-Copyright (c) 2014-2021 Joel Höner
+Copyright (c) 2014-2021 Joel H ner
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -1645,5 +1645,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
+Some shaders provided with the application are sourced from https://github.com/Matsilagi/RSRetroArch/.
+License details are included in the relevant shader source files, under resources\shaders\reshade. +