Add geom-overlay and fix other shaders. (#3245)

- Add geom-overlay.fx shader + psx.jpg texture;
- Add crt-consumer.fx and delete crt-consumer.glsl;
- Fix corner parameters from crt-geom.fx and geom.fx;
- Fix coords from super-xbr. Now it works with more aspect ratio options.
This commit is contained in:
Hyllian 2024-07-08 04:22:09 -03:00 committed by GitHub
parent 985b9f8a38
commit 22b273800e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 1283 additions and 839 deletions

View file

@ -1,780 +0,0 @@
// 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);
}

View file

@ -0,0 +1,797 @@
#include "ReShade.fxh"
/*
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.
*/
uniform float PRE_SCALE <
ui_type = "drag";
ui_min = 1.0;
ui_max = 4.0;
ui_step = 0.1;
ui_label = "Pre-Scale Sharpening";
> = 1.5;
uniform float blurx <
ui_type = "drag";
ui_min = -4.0;
ui_max = 4.0;
ui_step = 0.05;
ui_label = "Convergence X";
> = 0.25;
uniform float blury <
ui_type = "drag";
ui_min = -4.0;
ui_max = 4.0;
ui_step = 0.05;
ui_label = "Convergence Y";
> = -0.1;
uniform float warpx <
ui_type = "drag";
ui_min = 0.0;
ui_max = 0.12;
ui_step = 0.01;
ui_label = " Curvature X";
> = 0.03;
uniform float warpy <
ui_type = "drag";
ui_min = 0.0;
ui_max = 0.12;
ui_step = 0.01;
ui_label = " Curvature Y";
> = 0.04;
uniform float corner <
ui_type = "drag";
ui_min = 0.0;
ui_max = 0.10;
ui_step = 0.01;
ui_label = " Corner size";
> = 0.03;
uniform float smoothness <
ui_type = "drag";
ui_min = 100.0;
ui_max = 600.0;
ui_step = 5.0;
ui_label = " Border Smoothness";
> = 400.0;
uniform bool inter <
ui_type = "radio";
ui_label = "Interlacing Toggle";
> = true;
uniform float Downscale <
ui_type = "drag";
ui_min = 1.0;
ui_max = 8.0;
ui_step = 1.;
ui_label = "Interlacing Downscale Scanlines";
> = 2.0;
uniform float scanlow <
ui_type = "drag";
ui_min = 1.0;
ui_max = 15.0;
ui_step = 1.0;
ui_label = "Beam low";
> = 6.0;
uniform float scanhigh <
ui_type = "drag";
ui_min = 1.0;
ui_max = 15.0;
ui_step = 1.0;
ui_label = "Beam high";
> = 8.0;
uniform float beamlow <
ui_type = "drag";
ui_min = 0.5;
ui_max = 2.5;
ui_step = 0.0;
ui_label = "Scanlines dark";
> = 1.45;
uniform float beamhigh <
ui_type = "drag";
ui_min = 0.5;
ui_max = 2.5;
ui_step = 0.0;
ui_label = "Scanlines bright";
> = 1.05;
uniform float preserve <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "Protect White On Masks";
> = 0.98;
uniform float brightboost1 <
ui_type = "drag";
ui_min = 0.0;
ui_max = 3.0;
ui_step = 0.05;
ui_label = "Bright boost dark pixels";
> = 1.25;
uniform float brightboost2 <
ui_type = "drag";
ui_min = 0.0;
ui_max = 3.0;
ui_step = 0.05;
ui_label = "Bright boost bright pixels";
> = 1.0;
uniform float glow <
ui_type = "drag";
ui_min = 1.0;
ui_max = 6.0;
ui_step = 1.0;
ui_label = "Glow pixels per axis";
> = 3.0;
uniform float quality <
ui_type = "drag";
ui_min = 0.25;
ui_max = 4.0;
ui_step = 0.05;
ui_label = "Glow quality";
> = 1.0;
uniform float glow_str <
ui_type = "drag";
ui_min = 0.0001;
ui_max = 2.0;
ui_step = 0.05;
ui_label = "Glow intensity";
> = 0.3;
uniform float nois <
ui_type = "drag";
ui_min = 0.0;
ui_max = 32.0;
ui_step = 1.0;
ui_label = "Add Noise";
> = 0.0;
uniform float postbr <
ui_type = "drag";
ui_min = 0.0;
ui_max = 2.5;
ui_step = 0.02;
ui_label = "Post Brightness";
> = 1.0;
uniform float palette_fix <
ui_type = "drag";
ui_min = 0.0;
ui_max = 2.0;
ui_step = 1.0;
ui_label = "Palette Fixes. Sega, PUAE Atari ST dark colors";
> = 0.0;
uniform float Shadowmask <
ui_type = "drag";
ui_min = -1.0;
ui_max = 8.0;
ui_step = 1.;
ui_label = "Mask Type";
> = 0.0;
uniform float masksize <
ui_type = "drag";
ui_min = 1.0;
ui_max = 2.0;
ui_step = 1.0;
ui_label = "Mask Size";
> = 1.0;
uniform float MaskDark <
ui_type = "drag";
ui_min = 0.0;
ui_max = 2.0;
ui_step = 0.1;
ui_label = "Mask dark";
> = 0.2;
uniform float MaskLight <
ui_type = "drag";
ui_min = 0.0;
ui_max = 2.0;
ui_step = 0.1;
ui_label = "Mask light";
> = 1.5;
uniform float slotmask <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.05;
ui_label = "Slot Mask Strength";
> = 0.0;
uniform float slotwidth <
ui_type = "drag";
ui_min = 1.0;
ui_max = 6.0;
ui_step = 0.5;
ui_label = "Slot Mask Width";
> = 2.0;
uniform float double_slot <
ui_type = "drag";
ui_min = 1.0;
ui_max = 2.0;
ui_step = 1.0;
ui_label = "Slot Mask Height: 2x1 or 4x1";
> = 1.0;
uniform float slotms <
ui_type = "drag";
ui_min = 1.0;
ui_max = 2.0;
ui_step = 1.0;
ui_label = "Slot Mask Size";
> = 1.0;
uniform float GAMMA_OUT <
ui_type = "drag";
ui_min = 0.0;
ui_max = 4.0;
ui_step = 0.05;
ui_label = "Gamma Out";
> = 2.25;
uniform float sat <
ui_type = "drag";
ui_min = 0.0;
ui_max = 2.0;
ui_step = 0.05;
ui_label = "Saturation";
> = 1.0;
uniform float contrast <
ui_type = "drag";
ui_min = 0.00;
ui_max = 2.00;
ui_step = 0.05;
ui_label = "Contrast, 1.0:Off";
> = 1.0;
uniform float WP <
ui_type = "drag";
ui_min = -100.0;
ui_max = 100.0;
ui_step = 5.;
ui_label = "Color Temperature %";
> = 0.0;
uniform float rg <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Red-Green Tint";
> = 0.0;
uniform float rb <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Red-Blue Tint";
> = 0.0;
uniform float gr <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Green-Red Tint";
> = 0.0;
uniform float gb <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Green-Blue Tint";
> = 0.0;
uniform float br <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Blue-Red Tint";
> = 0.0;
uniform float bg <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Blue-Green Tint";
> = 0.0;
uniform bool vignette <
ui_type = "radio";
ui_label = "Vignette On/Off";
> = false;
uniform float vpower <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "Vignette Power";
> = 0.15;
uniform float vstr <
ui_type = "drag";
ui_min = 0.0;
ui_max = 50.0;
ui_step = 1.0;
ui_label = "Vignette strength";
> = 40.0;
uniform bool alloff <
ui_type = "radio";
ui_label = "Switch off shader";
> = false;
uniform float FrameCount < source = "framecount"; >;
uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
uniform float ViewportX < source = "viewportx"; >;
uniform float ViewportY < source = "viewporty"; >;
uniform float ViewportWidth < source = "viewportwidth"; >;
uniform float ViewportHeight < source = "viewportheight"; >;
uniform float2 ViewportOffset < source = "viewportoffset"; >;
uniform float BufferWidth < source = "bufferwidth"; >;
uniform float BufferHeight < source = "bufferheight"; >;
uniform float NativeWidth < source = "nativewidth"; >;
uniform float NativeHeight < source = "nativeheight"; >;
uniform float InternalWidth < source = "internalwidth"; >;
uniform float InternalHeight < source = "internalheight"; >;
sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
#define iTime (float(FrameCount)/2.0)
#define iTimer (float(FrameCount)/60.0)
#define SourceSize (float4(1.0/NormalizedNativePixelSize,NormalizedNativePixelSize))
#define OutputSize (ViewportSize*BufferToViewportRatio)
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);
return pos * 0.5 + 0.5;
}
float sw(float y, float l)
{
float beam = lerp(scanlow, scanhigh, y);
float scan = lerp(beamlow, beamhigh, l);
float ex = y * scan;
return exp2(-beam * ex * ex);
}
float3 mask(float2 x, float3 col, float l)
{
x = floor(x / masksize);
if (Shadowmask == 0.0)
{
float m = frac(x.x * 0.4999);
if (m < 0.4999) return float3(1.0, MaskDark, 1.0);
else return float3(MaskDark, 1.0, MaskDark);
}
else if (Shadowmask == 1.0)
{
float3 Mask = float3(MaskDark, MaskDark, MaskDark);
float line = MaskLight;
float odd = 0.0;
if (frac(x.x / 6.0) < 0.5) odd = 1.0;
if (frac((x.y + odd) / 2.0) < 0.5) line = MaskDark;
float m = frac(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 = frac(x.x*0.3333);
if (m < 0.3333) return float3(MaskDark, MaskDark, MaskLight);
if (m < 0.6666) return float3(MaskDark, MaskLight, MaskDark);
else return float3(MaskLight, MaskDark, MaskDark);
}
if (Shadowmask == 3.0)
{
float m = frac(x.x * 0.5);
if (m < 0.5) return float3(1.0, 1.0, 1.0);
else return float3(MaskDark, MaskDark, MaskDark);
}
else if (Shadowmask == 4.0)
{
float3 Mask = float3(col.rgb);
float line = MaskLight;
float odd = 0.0;
if (frac(x.x / 4.0) < 0.5) odd = 1.0;
if (frac((x.y + odd) / 2.0) < 0.5) line = MaskDark;
float m = frac(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)
{
float3 Mask = float3(1.0, 1.0, 1.0);
if (frac(x.x / 4.0) < 0.5)
{
if (frac(x.y / 3.0) < 0.666)
{
if (frac(x.x / 2.0) < 0.5) Mask = float3(1.0, MaskDark, 1.0);
else Mask = float3(MaskDark, 1.0, MaskDark);
}
else Mask *= l;
}
else if (frac(x.x / 4.0) >= 0.5)
{
if (frac(x.y / 3.0) > 0.333)
{
if (frac(x.x / 2.0) < 0.5) Mask = float3(1.0, MaskDark, 1.0);
else Mask = float3(MaskDark, 1.0, MaskDark);
}
else Mask *= l;
}
return Mask;
}
else if (Shadowmask == 6.0)
{
float3 Mask = float3(MaskDark, MaskDark, MaskDark);
if (frac(x.x / 6.0) < 0.5)
{
if (frac(x.y / 4.0) < 0.75)
{
if (frac(x.x / 3.0) < 0.3333) Mask.r = MaskLight;
else if (frac(x.x / 3.0) < 0.6666) Mask.g = MaskLight;
else Mask.b = MaskLight;
}
else Mask * l * 0.9;
}
else if (frac(x.x / 6.0) >= 0.5)
{
if (frac(x.y / 4.0) >= 0.5 || frac(x.y / 4.0) < 0.25)
{
if (frac(x.x / 3.0) < 0.3333) Mask.r = MaskLight;
else if (frac(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 = frac(x.x * 0.3333);
if (m < 0.3333) return float3(MaskDark, MaskLight, MaskLight * col.b); //Cyan
if (m < 0.6666) return float3(MaskLight * col.r, MaskDark, MaskLight); //Magenta
else return float3(MaskLight, MaskLight * col.g, MaskDark); //Yellow
}
else if (Shadowmask == 8.0)
{
float3 Mask = float3(MaskDark, MaskDark, MaskDark);
float bright = MaskLight;
float left = 0.0;
if (frac(x.x / 6.0) < 0.5) left = 1.0;
float m = frac(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 ((x.y % 2.0) == 1.0 && left == 1.0 || (x.y % 2.0) == 0.0 && left == 0.0)
Mask *= bright;
return Mask;
}
else return float3(1.0, 1.0, 1.0);
}
float SlotMask(float2 pos, float3 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 = frac(pos.x / mlen);
float py = floor(frac(pos.y / (2.0 * double_slot)) * 2.0 * double_slot);
float slot_dark = lerp(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;
}
float4x4 contrastMatrix(float contrast)
{
float t = (1.0 - contrast) / 2.0;
return float4x4(contrast, 0, 0, 0,
0, contrast, 0, 0,
0, 0, contrast, 0,
t, t, t, 1);
}
float3x3 vign(float l, float2 tex)
{
float2 vpos = tex;
vpos *= 1.0 - vpos.xy;
float vig = vpos.x * vpos.y * vstr;
vig = min(pow(vig, vpower), 1.0);
if (vignette == false) vig = 1.0;
return float3x3(vig, 0, 0,
0, vig, 0,
0, 0, vig);
}
float3 saturation(float3 textureColor)
{
float luminance = length(textureColor.rgb) * 0.5775;
float3 luminanceWeighting = float3(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);
float3 greyScaleColor = float3(luminance, luminance, luminance);
float3 res = float3(lerp(greyScaleColor, textureColor.rgb, sat));
return res;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
float3 glow0 (float2 texcoord, float3 col)
{
// the more quality, the smaller the offset and better quality, less visible glow too
float2 size = SourceSize.zw/quality;
float3 c01;
float3 sum = float3(0.0, 0.0, 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)
{
float2 offset = float2(x, y) * size;
c01 = tex2D(sBackBuffer, texcoord + offset).rgb*factor; c01 = c01*c01;
sum += c01;
}
}
return (glow_str * sum / (glow * glow )) ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
float noise(float2 co)
{
return frac(sin(iTimer * dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
}
float corner0(float2 coord)
{
coord = (coord - float2(0.5, 0.5)) * 1.0 + float2(0.5, 0.5);
coord = min(coord, float2(1.0, 1.0) - coord) * float2(1.0, SourceSize.y / SourceSize.x);
float2 cdist = float2(corner, corner);
coord = (cdist - min(coord, cdist));
float dist = sqrt(dot(coord, coord));
return clamp((cdist.x - dist) * smoothness, 0.0, 1.0);
}
static const float3x3 D65_to_XYZ = float3x3(
0.4306190, 0.2220379, 0.0201853,
0.3415419, 0.7066384, 0.1295504,
0.1783091, 0.0713236, 0.9390944);
static const float3x3 XYZ_to_D65 = float3x3(
3.0628971, -0.9692660, 0.0678775,
-1.3931791, 1.8760108, -0.2288548,
-0.4757517, 0.0415560, 1.0693490);
static const float3x3 D50_to_XYZ = float3x3(
0.4552773, 0.2323025, 0.0145457,
0.3675500, 0.7077956, 0.1049154,
0.1413926, 0.0599019, 0.7057489);
static const float3x3 XYZ_to_D50 = float3x3(
2.9603944, -0.9787684, 0.0844874,
-1.4678519, 1.9161415, -0.2545973,
-0.4685105, 0.0334540, 1.4216174);
float4 PS_CRT_CONSUMER(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD0) : SV_Target
{
float2 pos = Warp(vTexCoord.xy);
float2 tex_size = SourceSize.xy;
float2 pC4 = (pos + 0.5/tex_size);
float2 fp = frac(pos * tex_size);
if (inter == false && tex_size.y > 400.0){ fp.y = frac(pos.y * tex_size.y*1.0/Downscale);}
float4 res = float4(1.0, 1.0, 1.0, 1.0);
if (alloff == true)
res = tex2D(sBackBuffer, pC4);
else
{
float2 texel = pos * tex_size;
float2 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.
float2 center_dist = fp - 0.5;
float2 fpp = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;
float2 mod_texel = texel_floored + fpp;
float2 coords = mod_texel / SourceSize.xy;
float3 sample1 = tex2D(sBackBuffer, float2(coords.x + blurx*SourceSize.z, coords.y - blury*SourceSize.w)).rgb;
float3 sample2 = tex2D(sBackBuffer, coords).rgb;
float3 sample3 = tex2D(sBackBuffer, float2(coords.x - blurx*SourceSize.z, coords.y + blury*SourceSize.w )).rgb;
float3 color = float3(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)
{
float3 warmer = mul(color, D50_to_XYZ);
warmer = mul(warmer, XYZ_to_D65);
float3 cooler = mul(color, D65_to_XYZ);
cooler = mul(cooler, XYZ_to_D50);
float m = abs(WP) / 100.0;
float3 comp = (WP < 0.0) ? cooler : warmer;
comp = clamp(comp, 0.0, 1.0);
color = float3(lerp(color, comp, m));
}
float3x3 hue = float3x3 (1., rg, rb, //red tint
gr, 1., gb, //green tint
br, bg, 1.); //blue tint
color = mul(color, hue);
color = (2.0*pow(color,float3(2.8, 2.8, 2.8))) - pow(color,float3(3.6, 3.6, 3.6));
float lum = color.r * 0.3 + color.g * 0.6 + color.b * 0.1;
float f = frac(fp.y -0.5);
if (inter == true && 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 *= lerp(mask((vTexCoord * OutputSize.xy), color,lum1), float3(1.0, 1.0, 1.0), lum1*preserve);
if (slotmask != 0.0) color *= SlotMask((vTexCoord * OutputSize.xy) * 1.0001, color);
color *= lerp(brightboost1, brightboost2, max(max(color.r, color.g), color.b));
color = pow(color,float3(1.0 / GAMMA_OUT, 1.0 / GAMMA_OUT, 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 *= lerp(1.0, postbr, lum);
res = float4(color, 1.0);
if (contrast != 1.0) res = mul(res, contrastMatrix(contrast));
if (inter == true && SourceSize.y > 400.0 && frac(iTime) < 0.5) res = res * 0.95;
res.rgb = mul(res.rgb, vign(lum, vTexCoord));
}
return res;
}
technique CRT_CONSUMER
{
pass
{
VertexShader = PostProcessVS;
PixelShader = PS_CRT_CONSUMER;
}
}

View file

@ -52,16 +52,13 @@ uniform bool CURVATURE <
ui_category = "Curvature"; ui_category = "Curvature";
ui_type = "radio"; ui_type = "radio";
ui_label = "CRTGeom Curvature Toggle"; ui_label = "CRTGeom Curvature Toggle";
> = 1.0; > = true;
uniform float invert_aspect < uniform bool invert_aspect <
ui_type = "drag"; ui_type = "radio";
ui_category = "Curvature"; ui_category = "Curvature";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "CRTGeom Curvature Aspect Inversion"; ui_label = "CRTGeom Curvature Aspect Inversion";
> = 0.0; > = false;
uniform float R < uniform float R <
ui_type = "drag"; ui_type = "drag";
@ -93,8 +90,8 @@ uniform float cornersmooth <
uniform float x_tilt < uniform float x_tilt <
ui_type = "drag"; ui_type = "drag";
ui_category = "Curvature"; ui_category = "Curvature";
ui_min = -0.5; ui_min = -1.0;
ui_max = 0.5; ui_max = 1.0;
ui_step = 0.05; ui_step = 0.05;
ui_label = "CRTGeom Horizontal Tilt"; ui_label = "CRTGeom Horizontal Tilt";
> = 0.0; > = 0.0;
@ -102,8 +99,8 @@ uniform float x_tilt <
uniform float y_tilt < uniform float y_tilt <
ui_type = "drag"; ui_type = "drag";
ui_category = "Curvature"; ui_category = "Curvature";
ui_min = -0.5; ui_min = -1.0;
ui_max = 0.5; ui_max = 1.0;
ui_step = 0.05; ui_step = 0.05;
ui_label = "CRTGeom Vertical Tilt"; ui_label = "CRTGeom Vertical Tilt";
> = 0.0; > = 0.0;
@ -125,19 +122,19 @@ uniform float overscan_y <
> = 100.0; > = 100.0;
uniform float centerx < uniform float centerx <
ui_type = "drag"; ui_type = "drag";
ui_min = -9.99; ui_min = -100.0;
ui_max = 9.99; ui_max = 100.0;
ui_step = 0.01; ui_step = 0.1;
ui_label = "Image Center X"; ui_label = "Image Center X";
> = 0.00; > = 0.00;
uniform float centery < uniform float centery <
ui_type = "drag"; ui_type = "drag";
ui_min = -9.99; ui_min = -100.0;
ui_max = 9.99; ui_max = 100.0;
ui_step = 0.01; ui_step = 0.1;
ui_label = "Image Center Y"; ui_label = "Image Center Y";
> = 0.00; > = 0.00;
uniform float DOTMASK < uniform float DOTMASK <
@ -164,13 +161,10 @@ uniform float scanline_weight <
ui_label = "CRTGeom Scanline Weight"; ui_label = "CRTGeom Scanline Weight";
> = 0.3; > = 0.3;
uniform float vertical_scanlines < uniform bool vertical_scanlines <
ui_type = "drag"; ui_type = "radio";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "CRTGeom Vertical Scanlines"; ui_label = "CRTGeom Vertical Scanlines";
> = 0.0; > = false;
uniform float lum < uniform float lum <
ui_type = "drag"; ui_type = "drag";
@ -191,13 +185,15 @@ uniform float interlace_detect <
uniform float FrameCount < source = "framecount"; >; uniform float FrameCount < source = "framecount"; >;
uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >; uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 InternalPixelSize < source = "internal_pixel_size"; >; uniform float2 InternalPixelSize < source = "internal_pixel_size"; >;
uniform float2 NativePixelSize < source = "native_pixel_size"; >; uniform float2 NativePixelSize < source = "native_pixel_size"; >;
uniform float2 NormalizedInternalPixelSize < source = "normalized_internal_pixel_size"; >; uniform float2 NormalizedInternalPixelSize < source = "normalized_internal_pixel_size"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float UpscaleMultiplier < source = "upscale_multiplier"; >; uniform float UpscaleMultiplier < source = "upscale_multiplier"; >;
uniform float2 ViewportSize < source = "viewportsize"; >; uniform float2 ViewportSize < source = "viewportsize"; >;
uniform float ViewportWidth < source = "viewportwidth"; >;
uniform float ViewportHeight < source = "viewportheight"; >;
sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=POINT;MinFilter=POINT;}; sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=POINT;MinFilter=POINT;};
@ -222,7 +218,7 @@ sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BO
#endif #endif
// aspect ratio // aspect ratio
#define aspect (invert_aspect>0.5?float2(0.75,1.0):float2(1.0,0.75)) #define aspect (invert_aspect==true?float2(ViewportHeight/ViewportWidth,1.0):float2(1.0,ViewportHeight/ViewportWidth))
#define overscan (float2(1.01,1.01)); #define overscan (float2(1.01,1.01));
@ -311,7 +307,7 @@ void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, ou
texcoord = Warp(texcoord - float2(centerx,centery)/100.0); texcoord = Warp(texcoord - float2(centerx,centery)/100.0);
float2 SourceSize = 1.0/NormalizedNativePixelSize; float2 SourceSize = 1.0/NormalizedNativePixelSize;
float2 OutputSize = ViewportSize*BufferViewportRatio; float2 OutputSize = ViewportSize*BufferToViewportRatio;
// Precalculate a bunch of useful values we'll need in the fragment // Precalculate a bunch of useful values we'll need in the fragment
// shader. // shader.
@ -319,7 +315,7 @@ void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, ou
vVARS.cosangle = cos(float2(x_tilt, y_tilt)); vVARS.cosangle = cos(float2(x_tilt, y_tilt));
vVARS.stretch = vs_maxscale(vVARS.sinangle, vVARS.cosangle); vVARS.stretch = vs_maxscale(vVARS.sinangle, vVARS.cosangle);
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
{ {
vVARS.TextureSize = float2(SHARPER * SourceSize.x, SourceSize.y); vVARS.TextureSize = float2(SHARPER * SourceSize.x, SourceSize.y);
@ -350,7 +346,7 @@ float intersect(float2 xy, float2 sinangle, float2 cosangle)
float A = dot(xy,xy) + d*d; float A = dot(xy,xy) + d*d;
float B, C; float B, C;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
{ {
B = 2.0*(R*(dot(xy,sinangle) - d*cosangle.x*cosangle.y) - d*d); B = 2.0*(R*(dot(xy,sinangle) - d*cosangle.x*cosangle.y) - d*d);
C = d*d + 2.0*R*d*cosangle.x*cosangle.y; C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
@ -387,7 +383,7 @@ float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
float x = 1.0 - cos(r/R); float x = 1.0 - cos(r/R);
float D; float D;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
D = d/R + x*cosangle.x*cosangle.y + dot(uv,sinangle); D = d/R + x*cosangle.x*cosangle.y + dot(uv,sinangle);
else else
D = d/R + x*cosangle.y*cosangle.x + dot(uv,sinangle); D = d/R + x*cosangle.y*cosangle.x + dot(uv,sinangle);
@ -397,7 +393,7 @@ float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
float3 maxscale(float2 sinangle, float2 cosangle) float3 maxscale(float2 sinangle, float2 cosangle)
{ {
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
{ {
float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle); float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle);
float2 a = float2(0.5, 0.5)*aspect; float2 a = float2(0.5, 0.5)*aspect;
@ -464,13 +460,12 @@ float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch)
float corner(float2 coord) float corner(float2 coord)
{ {
coord = (coord - float2(0.5, 0.5)) * float2(overscan_x / 100.0, overscan_y / 100.0) + float2(0.5, 0.5);
coord = min(coord, float2(1.0, 1.0) - coord) * aspect; coord = min(coord, float2(1.0, 1.0) - coord) * aspect;
float2 cdist = float2(cornersize, cornersize); float2 cdist = float2(cornersize, cornersize);
coord = (cdist - min(coord, cdist)); coord = (cdist - min(coord, cdist));
float dist = sqrt(dot(coord, coord)); float dist = sqrt(dot(coord, coord));
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
return clamp((cdist.x - dist)*cornersmooth, 0.0, 1.0); return clamp((cdist.x - dist)*cornersmooth, 0.0, 1.0);
else else
return clamp((cdist.y - dist)*cornersmooth, 0.0, 1.0); return clamp((cdist.y - dist)*cornersmooth, 0.0, 1.0);
@ -508,17 +503,17 @@ float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_
// Texture coordinates of the texel containing the active pixel. // Texture coordinates of the texel containing the active pixel.
float2 xy; float2 xy;
if (CURVATURE > 0.5) if (CURVATURE == true)
xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch); xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch);
else else
xy = vTexCoord; xy = vTexCoord;
float cval = corner(xy); float cval = corner((xy-float2(0.5,0.5)) * BufferToViewportRatio + float2(0.5,0.5));
// Of all the pixels that are mapped onto the texel we are // Of all the pixels that are mapped onto the texel we are
// currently rendering, which pixel are we currently rendering? // currently rendering, which pixel are we currently rendering?
float2 ilvec; float2 ilvec;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
ilvec = float2(0.0, vVARS.ilfac.y * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0); ilvec = float2(0.0, vVARS.ilfac.y * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0);
else else
ilvec = float2(vVARS.ilfac.x * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0, 0.0); ilvec = float2(vVARS.ilfac.x * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0, 0.0);
@ -533,7 +528,7 @@ float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_
// of various neighbour texels in a scanline on the current // of various neighbour texels in a scanline on the current
// pixel. // pixel.
float4 coeffs; float4 coeffs;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
else else
coeffs = PI * float4(1.0 + uv_ratio.y, uv_ratio.y, 1.0 - uv_ratio.y, 2.0 - uv_ratio.y); coeffs = PI * float4(1.0 + uv_ratio.y, uv_ratio.y, 1.0 - uv_ratio.y, 2.0 - uv_ratio.y);
@ -551,7 +546,7 @@ float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_
// scanlines at the horizontal location of the current pixel, // scanlines at the horizontal location of the current pixel,
// using the Lanczos coefficients above. // using the Lanczos coefficients above.
float4 col, col2; float4 col, col2;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
{ {
col = clamp( col = clamp(
mul(coeffs, float4x4( mul(coeffs, float4x4(
@ -600,7 +595,7 @@ float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_
// Calculate the influence of the current and next scanlines on // Calculate the influence of the current and next scanlines on
// the current pixel. // the current pixel.
float4 weights, weights2; float4 weights, weights2;
if(vertical_scanlines < 0.5) if(vertical_scanlines == false)
{ {
weights = scanlineWeights(uv_ratio.y, col); weights = scanlineWeights(uv_ratio.y, col);
weights2 = scanlineWeights(1.0 - uv_ratio.y, col2); weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);

View file

@ -184,7 +184,9 @@ float3 super_xbr(float wp[6], float4 P0, float4 B, float4 C, float4 P1, float4
float4 PS_BackBufferY(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target float4 PS_BackBufferY(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{ {
float3 color = tex2D(ReShade::BackBuffer, vTexCoord.xy).rgb; float2 tc = (floor(vTexCoord / NormalizedNativePixelSize)+float2(0.5,0.5)) * NormalizedNativePixelSize;
float3 color = tex2D(ReShade::BackBuffer, tc).rgb;
return float4(color, luma(color)); return float4(color, luma(color));
} }

View file

@ -76,16 +76,16 @@ uniform float geom_cornersmooth <
uniform float geom_x_tilt < uniform float geom_x_tilt <
ui_type = "drag"; ui_type = "drag";
ui_min = -0.5; ui_min = -1.0;
ui_max = 0.5; ui_max = 1.0;
ui_step = 0.05; ui_step = 0.05;
ui_label = "Geom Horizontal Tilt"; ui_label = "Geom Horizontal Tilt";
> = 0.0; > = 0.0;
uniform float geom_y_tilt < uniform float geom_y_tilt <
ui_type = "drag"; ui_type = "drag";
ui_min = -0.5; ui_min = -1.0;
ui_max = 0.5; ui_max = 1.0;
ui_step = 0.05; ui_step = 0.05;
ui_label = "Geom Vertical Tilt"; ui_label = "Geom Vertical Tilt";
> = 0.0; > = 0.0;
@ -108,17 +108,17 @@ uniform float geom_overscan_y <
uniform float centerx < uniform float centerx <
ui_type = "drag"; ui_type = "drag";
ui_min = -9.99; ui_min = -100.0;
ui_max = 9.99; ui_max = 100.0;
ui_step = 0.01; ui_step = 0.1;
ui_label = "Image Center X"; ui_label = "Image Center X";
> = 0.00; > = 0.00;
uniform float centery < uniform float centery <
ui_type = "drag"; ui_type = "drag";
ui_min = -9.99; ui_min = -100.0;
ui_max = 9.99; ui_max = 100.0;
ui_step = 0.01; ui_step = 0.1;
ui_label = "Image Center Y"; ui_label = "Image Center Y";
> = 0.00; > = 0.00;
@ -147,9 +147,11 @@ uniform float geom_monitor_gamma <
> = 2.2; > = 2.2;
uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >; uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >; uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 ViewportSize < source = "viewportsize"; >; uniform float2 ViewportSize < source = "viewportsize"; >;
uniform float ViewportWidth < source = "viewportwidth"; >;
uniform float ViewportHeight < source = "viewportheight"; >;
sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=LINEAR;MinFilter=LINEAR;}; sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=LINEAR;MinFilter=LINEAR;};
@ -174,7 +176,7 @@ sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BO
#endif #endif
// aspect ratio // aspect ratio
#define aspect (geom_invert_aspect==true?float2(0.75,1.0):float2(1.0,0.75)) #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 (float2(1.01,1.01));
@ -259,8 +261,7 @@ void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, ou
// center screen // center screen
texcoord = Warp(texcoord - float2(centerx,centery)/100.0); texcoord = Warp(texcoord - float2(centerx,centery)/100.0);
// float2 SourceSize = 1.0/NormalizedNativePixelSize; float2 SourceSize = 1.0/NormalizedNativePixelSize;
float2 SourceSize = ViewportSize*BufferViewportRatio;
// Precalculate a bunch of useful values we'll need in the fragment // Precalculate a bunch of useful values we'll need in the fragment
// shader. // shader.
@ -336,7 +337,6 @@ float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch)
float corner(float2 coord) float corner(float2 coord)
{ {
coord = (coord - float2(0.5, 0.5)) * float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0) + float2(0.5, 0.5);
coord = min(coord, float2(1.0, 1.0) - coord) * aspect; coord = min(coord, float2(1.0, 1.0) - coord) * aspect;
float2 cdist = float2(geom_cornersize, geom_cornersize); float2 cdist = float2(geom_cornersize, geom_cornersize);
coord = (cdist - min(coord, cdist)); coord = (cdist - min(coord, cdist));
@ -360,7 +360,7 @@ float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_
else else
xy = vTexCoord; xy = vTexCoord;
float cval = corner(xy); 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 - float2(0.5, 0.5)) / vVARS.TextureSize);

View file

@ -0,0 +1,415 @@
#include "ReShade.fxh"
/*
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_label = "Geom Curvature Toggle";
ui_category = "Curvature";
ui_tooltip = "This shader only works with Aspect Ratio: Stretch to Fill.";
> = true;
uniform float geom_R <
ui_type = "drag";
ui_min = 0.1;
ui_max = 10.0;
ui_step = 0.1;
ui_label = "Geom Curvature Radius";
> = 10.0;
uniform float geom_d <
ui_type = "drag";
ui_min = 0.1;
ui_max = 10.0;
ui_step = 0.1;
ui_label = "Geom Distance";
> = 10.0;
uniform bool geom_invert_aspect <
ui_type = "radio";
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_label = "Geom Corner Size";
> = 0.006;
uniform float geom_cornersmooth <
ui_type = "drag";
ui_min = 80.0;
ui_max = 2000.0;
ui_step = 100.0;
ui_label = "Geom Corner Smoothness";
> = 200.0;
uniform float geom_x_tilt <
ui_type = "drag";
ui_min = -1.0;
ui_max = 1.0;
ui_step = 0.05;
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_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_label = "Geom Horiz. Overscan %";
> = 48.5;
uniform float geom_overscan_y <
ui_type = "drag";
ui_min = -125.0;
ui_max = 125.0;
ui_step = 0.5;
ui_label = "Geom Vert. Overscan %";
> = 64.5;
uniform float centerx <
ui_type = "drag";
ui_min = -100.0;
ui_max = 100.0;
ui_step = 0.1;
ui_label = "Image Center X";
> = 0.0;
uniform float centery <
ui_type = "drag";
ui_min = -100.0;
ui_max = 100.0;
ui_step = 0.1;
ui_label = "Image Center Y";
> = -8.8;
uniform float geom_lum <
ui_type = "drag";
ui_min = 0.5;
ui_max = 2.0;
ui_step = 0.01;
ui_label = "Geom Luminance";
> = 1.0;
uniform float geom_target_gamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "Geom Target Gamma";
> = 2.4;
uniform float geom_monitor_gamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "Geom Monitor Gamma";
> = 2.2;
uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
uniform float ViewportX < source = "viewportx"; >;
uniform float ViewportY < source = "viewporty"; >;
uniform float ViewportWidth < source = "viewportwidth"; >;
uniform float ViewportHeight < source = "viewportheight"; >;
uniform float2 ViewportOffset < source = "viewportoffset"; >;
sampler2D sBackBuffer{Texture=ReShade::BackBufferTex;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=LINEAR;MinFilter=LINEAR;};
texture tOverlay < source = "overlay/psx.jpg"; >
{
Width = BUFFER_WIDTH;
Height = BUFFER_HEIGHT;
MipLevels = 1;
};
sampler sOverlay { Texture = tOverlay; AddressU = BORDER; AddressV = BORDER; MinFilter = LINEAR; MagFilter = LINEAR;};
// Comment the next line to disable interpolation in linear gamma (and
// gain speed).
#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile; improves moire effect caused by scanlines+curvature
#define OVERSAMPLE
// Use the older, purely gaussian beam profile; uncomment for speed
//#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5);
#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))
#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));
struct ST_VertexOut
{
float2 sinangle : TEXCOORD1;
float2 cosangle : TEXCOORD2;
float3 stretch : TEXCOORD3;
float2 TextureSize : TEXCOORD4;
};
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));
}
// 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);
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;
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);
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 = float2(0.5, 0.5)*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 - float2(0.5, 0.5))*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));
}
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));
return clamp((cdist.x - dist)*geom_cornersmooth, 0.0, 1.0);
}
float fwidth(float value){
return abs(ddx(value)) + abs(ddy(value));
}
// 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;
}
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;
if (geom_curvature == true)
xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch);
else
xy = vTexCoord;
// center screen
xy = Warp(xy - float2(centerx,centery)/100.0);
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);
float4 col = TEX2D(xy);
#ifndef LINEAR_PROCESSING
col = pow(col , float4(geom_target_gamma, geom_target_gamma, geom_target_gamma, geom_target_gamma));
#endif
col.rgb *= (geom_lum * step(0.0, uv_ratio.y));
float3 mul_res = col.rgb * float3(cval, cval, cval);
// 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));
float4 overlay = tex2D(sOverlay, vTexCoord);
float2 top_left = (float2(ViewportX, ViewportY) - ViewportOffset)/ViewportSize;
float2 bottom_right = (float2(ViewportX + ViewportWidth, ViewportY + ViewportHeight) - ViewportOffset)/ViewportSize;
if (xy.x < top_left.x || xy.x > bottom_right.x || xy.y < top_left.y || xy.y > bottom_right.y)
mul_res = overlay.rgb;
return float4(mul_res, 1.0);
}
technique CRT_Geom
{
pass
{
VertexShader = VS_CRT_Geom;
PixelShader = PS_CRT_Geom;
}
}

View file

@ -0,0 +1,15 @@
# To Use
Choose Aspect Ratio: Stretch to Fill.
# Psx.jpg Credits
To the Author: SOQUEROEU.
The "psx.jpg" background was edited from the one obtained from "Soqueroeu TV Backgrounds 2.0" repository: https://github.com/soqueroeu/Soqueroeu-TV-Backgrounds_V2.0/tree/main.
The material is free to use according to the agreement below:
## AGREEMENT
This pack is free. You should not pay for anything related to this graphics pack and shader preset. You may distribute and reproduce part from this content, as long as you give credit to the authors involved. You may not profit from the sale of products that contain material in this package without the author's prior permission.

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB