slang-shaders/crt/shaders/crt-Cyclon.slang

340 lines
9.9 KiB
Plaintext
Raw Normal View History

#version 450
/*
DariusG presents
'crt-Cyclon'
Why? Because it's speedy!
A super-fast shader based on the magnificent crt-Geom, optimized for full speed
on a Xiaomi Note 3 Pro cellphone (around 170(?) gflops gpu or so)
This shader uses parts from:
crt-Geom (scanlines)
Quillez (main filter)
Grade (some primaries)
Dogway's inverse Gamma
Masks-slot-color handling, tricks etc are mine.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
*/
layout(push_constant) uniform Push
{
float SCANLINE,INTERLACE,M_TYPE,MSIZE,SLOT,SLOTW,BGR,Maskl,Maskh,C_STR,CONV_R,CONV_G,CONV_B,
WARPX,WARPY,CORNER,B_SMOOTH,PAL_NTSC,BR_DEP,c_space,EXT_GAMMA;
} params;
// Parameter lines go here:
#pragma parameter SCANLINE "Scanline Weight" 0.25 0.15 0.6 0.05
#pragma parameter INTERLACE "Interlacing On/Off" 1.0 0.0 1.0 1.0
#pragma parameter bogus_msk " [ MASK SETTINGS ] " 0.0 0.0 0.0 0.0
#pragma parameter M_TYPE "Mask Type: -1:None, 0:CGWG, 1:RGB" 0.0 -1.0 1.0 1.0
#pragma parameter MSIZE "Mask Size" 1.0 1.0 2.0 1.0
#pragma parameter SLOT "Slot Mask On/Off" 0.0 0.0 1.0 1.0
#pragma parameter SLOTW "Slot Mask Width" 2.0 2.0 3.0 1.0
#pragma parameter BGR "Subpixels BGR/RGB" 0.0 0.0 1.0 1.0
#pragma parameter Maskl "Mask Brightness Dark" 0.3 0.0 1.0 0.05
#pragma parameter Maskh "Mask Brightness Bright" 0.75 0.0 1.0 0.05
#pragma parameter bogus_con " [ CONVERGENCE SETTINGS ] " 0.0 0.0 0.0 0.0
#pragma parameter C_STR "Convergence Overall Strength" 0.0 0.0 1.0 0.05
#pragma parameter CONV_R "Convergence Red X-Axis" 0.0 -1.0 1.0 0.05
#pragma parameter CONV_G "Convergence Green Y-axis" 0.0 -1.0 1.0 0.05
#pragma parameter CONV_B "Convergence Blue X-Axis" 0.0 -1.0 1.0 0.05
#pragma parameter bogus_geom " [ GEOMETRY SETTINGS ] " 0.0 0.0 0.0 0.0
#pragma parameter WARPX "Curvature Horizontal" 0.032 0.00 0.25 0.01
#pragma parameter WARPY "Curvature Vertical" 0.042 0.00 0.25 0.01
#pragma parameter CORNER "Corner Round" 0.02 0.0 0.25 0.01
#pragma parameter B_SMOOTH "Border Smoothness" 300.0 100.0 1000.0 25.0
#pragma parameter PAL_NTSC "PAL-NTSC Aspect: Amiga,MD-SNES" 0.0 0.0 2.0 1.0
#pragma parameter bogus_col " [ COLOR SETTINGS ] " 0.0 0.0 0.0 0.0
#pragma parameter BR_DEP "Scan/Mask Brightness Dependence" 0.266 0.0 0.333 0.01
#pragma parameter c_space "Color Space: sRGB,PAL,NTSC-U,NTSC-J" 0.0 0.0 3.0 1.0
#pragma parameter EXT_GAMMA "External Gamma In (Glow etc)" 0.0 0.0 1.0 1.0
#pragma parameter SATURATION "Saturation" 1.0 0.0 2.0 0.01
#pragma parameter BRIGHTNESS "Brightness, Sega fix:1.06" 1.0 0.0 2.0 0.01
#pragma parameter BLACK "Black Level" 0.0 -0.20 0.20 0.01
#pragma parameter RG "Green <-to-> Red Hue" 0.0 -0.25 0.25 0.01
#pragma parameter RB "Blue <-to-> Red Hue" 0.0 -0.25 0.25 0.01
#pragma parameter GB "Blue <-to-> Green Hue" 0.0 -0.25 0.25 0.01
#pragma parameter POTATO "Potato Boost(Simple Gamma, adjust Mask)" 0.0 0.0 1.0 1.0
#define M_TYPE params.M_TYPE
#define BGR params.BGR
#define MSIZE params.MSIZE
#define Maskl params.Maskl
#define Maskh params.Maskh
#define C_STR params.C_STR
#define CONV_R params.CONV_R
#define CONV_G params.CONV_G
#define CONV_B params.CONV_B
#define SCANLINE params.SCANLINE
#define INTERLACE params.INTERLACE
#define WARPX params.WARPX
#define WARPY params.WARPY
#define SLOT params.SLOT
#define SLOTW params.SLOTW
#define c_space params.c_space
#define CORNER params.CORNER
#define B_SMOOTH params.B_SMOOTH
#define BR_DEP params.BR_DEP
#define EXT_GAMMA params.EXT_GAMMA
#define PAL_NTSC params.PAL_NTSC
#define pi 3.1415926535897932384626433
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
float BLACK, RG, RB, GB, POTATO,SATURATION,BRIGHTNESS;
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
} global;
#define RG global.RG
#define RB global.RB
#define GB global.GB
#define BLACK global.BLACK
#define POTATO global.POTATO
#define SATURATION global.SATURATION
#define BRIGHTNESS global.BRIGHTNESS
#define SourceSize global.SourceSize
#define OriginalSize global.OriginalSize
#define OutputSize global.OutputSize
#define FrameCount global.FrameCount
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
layout(location = 1) out vec2 scale;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord * 1.0001;
scale = SourceSize.xy/OriginalSize.xy;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(location = 1) in vec2 scale;
layout(set = 0, binding = 1) uniform sampler2D Source;
///////////////////////////////////////////////////////////////////////////////////////////////
vec3 Mask(vec2 pos, float CGWG)
{
vec3 mask = vec3(CGWG);
if (M_TYPE == 0.0){
if (POTATO == 1.0) return vec3( (1.0-CGWG)*sin(pos.x*pi)+CGWG) ;
else{
float m = fract(pos.x*0.5);
if (m<0.5) mask.rb = vec2(1.0);
else mask.g = 1.0;
return mask;}
}
if (M_TYPE == 1.0){
if (POTATO == 1.0) return vec3( (1.0-CGWG)*sin(pos.x*pi*0.6667)+CGWG) ;
else{
float m = fract(pos.x*0.3333);
if (m<0.3333) BGR == 0.0 ? mask.b = 1.0 : mask.r = 1.0;
else if (m<0.6666) mask.g = 1.0;
else BGR == 0.0 ? mask.r = 1.0 : mask.b = 1.0;
return mask;
}
}
else return vec3(1.0);
}
vec3 scanlineWeights(float distance, vec3 color)
{
// "wid" controls the width of the scanline beam, for each RGB
// channel The "weights" lines basically specify the formula
// that gives you the profile of the beam, i.e. the intensity as
// a function of distance from the vertical center of the
// scanline. In this case, it is gaussian if width=2, and
// becomes nongaussian for larger widths. Ideally this should
// be normalized so that the integral across the beam is
// independent of its width. That is, for a narrower beam
// "weights" should have a higher peak at the center of the
// scanline than for a wider beam.
vec3 wid = SCANLINE + 0.15 * pow(color, vec3(3.0));
vec3 weights = vec3(distance / wid);
return 0.4 * exp(-weights * weights ) / wid;
}
#define pwr vec3(1.0/((-0.8*SCANLINE+1.0)*(-0.8*(1.0-CGWG)+1.0))-1.2)
// Returns gamma corrected output, compensated for scanline+mask embedded gamma
vec3 inv_gamma(vec3 col, vec3 power)
{
vec3 cir = col-1.0;
cir *= cir;
col = mix(sqrt(col),sqrt(1.0-cir),power);
return col;
}
// standard 6774k
mat3 PAL = mat3(
1.1515, -0.1099, -0.0033,
0.0914, 0.9177, -0.0043,
0.0039, -0.0071, 1.0901
);
// standard 6774k
mat3 NTSC = mat3(
0.8870, 0.0451, 0.0566,
-0.0800, 1.0368, 0.0361,
0.0053, -0.1196, 1.2320
);
// standard 9300k
mat3 NTSC_J = mat3(
0.8800, 0.0020, 0.1054,
-0.0071, 0.9351, 0.0658,
0.0198, -0.0797, 1.3533
);
vec3 slot(vec2 pos)
{
float h = fract(pos.x/SLOTW);
float v = fract(pos.y);
float odd;
if (v<0.5) odd = 0.0; else odd = 1.0;
if (odd == 0.0)
{if (h<0.5) return vec3(0.5); else return vec3(1.5);}
else if (odd == 1.0)
{if (h<0.5) return vec3(1.5); else return vec3(0.5);}
}
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);
pos = pos*0.5+0.5;
return pos;
}
float corner(vec2 coord)
{
coord = min(coord, vec2(1.0)-coord) * vec2(1.0, 0.75);
vec2 cdist = vec2(CORNER);
coord = cdist - min(coord,cdist);
float dist = sqrt(dot(coord,coord));
return clamp((cdist.x-dist)*B_SMOOTH,0.0, 1.0);
}
void main()
{
mat3 hue = mat3(
1.0, -RG, -RB,
RG, 1.0, -GB,
RB, GB, 1.0
);
vec2 pos = Warp(vTexCoord*scale); vec2 cpos=pos;
pos /=scale; // blurry
if (PAL_NTSC != 0.0){
if(PAL_NTSC == 1.0) pos.y /=1.2; // Amiga 256 to 200
pos.y += 0.005; // re-center
if(PAL_NTSC == 2.0) pos.y /=1.0714; // MD-SNES 240 to 224
}
vec2 bpos = pos;
vec2 dx = vec2(SourceSize.z,0.0);
vec2 dy = vec2(0.0,OutputSize.w);
vec2 ogl2 = pos*SourceSize.xy;
vec2 i = floor(pos*SourceSize.xy) + 0.5;
float f = ogl2.y - i.y;
pos.y = (i.y + 4.0*f*f*f)*SourceSize.w; // smooth
pos.x = mix(pos.x, i.x*SourceSize.z, 0.2);
vec3 res0 = texture(Source,pos).rgb;
vec3 resr = texture(Source,pos + dx*CONV_R).rgb;
vec3 resb = texture(Source,pos + dx*CONV_B).rgb;
vec3 resg = texture(Source,pos + dy*CONV_G).rgb;
vec3 res = vec3( res0.r*(1.0-C_STR) + resr.r*C_STR,
res0.g*(1.0-C_STR) + resg.g*C_STR,
res0.b*(1.0-C_STR) + resb.b*C_STR
);
float l = dot(vec3(BR_DEP),res);
if(EXT_GAMMA != 1.0) res *= res;
if (c_space != 0.0) {
if (c_space == 1.0) res *= PAL;
if (c_space == 2.0) res *= NTSC;
if (c_space == 3.0) res *= NTSC_J;
res = clamp(res,0.0,1.0);
}
float s = fract(bpos.y*SourceSize.y-0.5);
// handle interlacing
if (OriginalSize.y > 400.0)
{
s = fract(bpos.y*SourceSize.y/2.0-0.5);
if (INTERLACE == 1.0) s = mod(float(FrameCount),2.0) < 1.0 ? s: s+0.5;
}
vec3 weight = scanlineWeights(s, res);
vec3 weight2 = scanlineWeights(1.0-s, res);
res *= weight + weight2;
vec2 xy = vTexCoord*OutputSize.xy*scale/MSIZE;
float CGWG = mix(Maskl, Maskh, l);
res *= Mask(xy, CGWG);
if (SLOT == 1.0) res *= mix(slot(xy/2.0),vec3(1.0),CGWG);
if (POTATO == 0.0) res = inv_gamma(res,pwr);
else res = sqrt(res);
float lum = dot(vec3(0.29,0.60,0.11),res);
res = mix(vec3(lum),res,SATURATION);
res *= BRIGHTNESS;
res *= hue;
res -= vec3(BLACK);
res *= vec3(1.0)/vec3(1.0-BLACK);
if (CORNER !=0.0) res *= corner(cpos);
FragColor = vec4(res,1.0);
}