diff --git a/crt/phosphorlut.slangp b/crt/phosphorlut.slangp new file mode 100644 index 0000000..0777dc1 --- /dev/null +++ b/crt/phosphorlut.slangp @@ -0,0 +1,41 @@ +shaders = 5 + +shader0 = shaders/phosphorlut/scanlines-interlace-linearize.slang +alias0 = firstPass +scale0 = 2.0 +scale_type0 = source +srgb_framebuffer0 = true +filter_linear0 = false + +shader1 = ../blurs/blur5fast-vertical.slang +scale_type1 = source +scale1 = 1.0 +srgb_framebuffer1 = true +filter_linear1 = true +alias1 = blurPassV + +shader2 = ../blurs/blur5fast-horizontal.slang +alias2 = blurPass +filter_linear2 = true +scale2 = 1.0 +scale_type2 = source +srgb_framebuffer2 = true + +shader3 = shaders/phosphorlut/phosphorlut-pass0.slang +alias3 = phosphorPass +filter_linear3 = true +scale_type3 = source +scale_x3 = 4.0 +scale_y3 = 2.0 +srgb_framebuffer3 = true + +shader4 = shaders/phosphorlut/phosphorlut-pass1.slang +filter_linear4 = true + +textures = "Phosphors" +Phosphors = shaders/phosphorlut/luts/rgb-shadowmask.png +//Phosphors = shaders/phosphorlut/luts/cmy-shadowmask.png +//Phosphors = shaders/phosphorlut/luts/rgb-aperture-grille.png +//Phosphors = shaders/phosphorlut/luts/cmy-aperture-grille.png +//Phosphors = shaders/phosphorlut/luts/rgb-slotmask.png +//Phosphors = shaders/phosphorlut/luts/cmy-slotmask.png \ No newline at end of file diff --git a/crt/shaders/phosphorlut/luts/cmy-aperture-grille.png b/crt/shaders/phosphorlut/luts/cmy-aperture-grille.png new file mode 100644 index 0000000..27b0945 Binary files /dev/null and b/crt/shaders/phosphorlut/luts/cmy-aperture-grille.png differ diff --git a/crt/shaders/phosphorlut/luts/cmy-shadowmask.png b/crt/shaders/phosphorlut/luts/cmy-shadowmask.png new file mode 100644 index 0000000..a4463a7 Binary files /dev/null and b/crt/shaders/phosphorlut/luts/cmy-shadowmask.png differ diff --git a/crt/shaders/phosphorlut/luts/cmy-slotmask.png b/crt/shaders/phosphorlut/luts/cmy-slotmask.png new file mode 100644 index 0000000..baa953b Binary files /dev/null and b/crt/shaders/phosphorlut/luts/cmy-slotmask.png differ diff --git a/crt/shaders/phosphorlut/luts/rgb-aperture-grille.png b/crt/shaders/phosphorlut/luts/rgb-aperture-grille.png new file mode 100644 index 0000000..3d7861e Binary files /dev/null and b/crt/shaders/phosphorlut/luts/rgb-aperture-grille.png differ diff --git a/crt/shaders/phosphorlut/luts/rgb-shadowmask.png b/crt/shaders/phosphorlut/luts/rgb-shadowmask.png new file mode 100644 index 0000000..fd77612 Binary files /dev/null and b/crt/shaders/phosphorlut/luts/rgb-shadowmask.png differ diff --git a/crt/shaders/phosphorlut/luts/rgb-slotmask.png b/crt/shaders/phosphorlut/luts/rgb-slotmask.png new file mode 100644 index 0000000..2ad2549 Binary files /dev/null and b/crt/shaders/phosphorlut/luts/rgb-slotmask.png differ diff --git a/crt/shaders/phosphorlut/phosphorlut-pass0.slang b/crt/shaders/phosphorlut/phosphorlut-pass0.slang new file mode 100644 index 0000000..7c2c3db --- /dev/null +++ b/crt/shaders/phosphorlut/phosphorlut-pass0.slang @@ -0,0 +1,48 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float PHOSPHOR_SCALE_X; + float PHOSPHOR_SCALE_Y; +} params; + +#pragma parameter PHOSPHOR_SCALE_X "Phosphor Scale X" 2.0 1.0 12.0 1.0 +#pragma parameter PHOSPHOR_SCALE_Y "Phosphor Scale Y" 4.0 1.0 12.0 1.0 + +#define PHOSPHOR_SCALE_X params.PHOSPHOR_SCALE_X +#define PHOSPHOR_SCALE_Y params.PHOSPHOR_SCALE_Y + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Phosphors; +layout(set = 0, binding = 4) uniform sampler2D firstPass; + +void main() +{ + vec4 screen = vec4(texture(firstPass, vTexCoord).rgb, 1.0); + vec2 LUTeffectiveCoord = vec2(fract(vTexCoord.x * params.SourceSize.x / PHOSPHOR_SCALE_X), fract(vTexCoord.y * params.SourceSize.y / PHOSPHOR_SCALE_Y)); + vec4 phosphor_grid = vec4(texture(Phosphors, LUTeffectiveCoord).rgb, 1.0); + FragColor = screen * phosphor_grid; +} \ No newline at end of file diff --git a/crt/shaders/phosphorlut/phosphorlut-pass1.slang b/crt/shaders/phosphorlut/phosphorlut-pass1.slang new file mode 100644 index 0000000..6d10b64 --- /dev/null +++ b/crt/shaders/phosphorlut/phosphorlut-pass1.slang @@ -0,0 +1,52 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float diffusion; + float out_gamma; +} params; + +#pragma parameter diffusion "Halation Strength" 0.5 0.0 1.0 0.01 +#pragma parameter out_gamma "Display Gamma" 2.2 1.5 3.0 0.1 + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D firstPass; +layout(set = 0, binding = 3) uniform sampler2D blurPass; +layout(set = 0, binding = 4) uniform sampler2D phosphorPass; +//layout(set = 0, binding = 5) uniform sampler2D blurPassV; + +void main() +{ + vec3 scanlines = texture(firstPass, vTexCoord).rgb; +// vec3 blurV = texture(blurPassV, vTexCoord).rgb; + vec3 blurH = texture(blurPass, vTexCoord).rgb; + vec3 blurLines = (scanlines + blurH) / 2.0; + vec3 phosphors = texture(phosphorPass, vTexCoord).rgb; + vec3 glow = (phosphors + blurH) / 2.0; + vec3 halation = mix(blurLines, phosphors, params.diffusion); + //vec3 halation = 1.0 - (1.0 - phosphors) * (1.0 - blurLines); + halation = 1.0 - (1.0 - halation) * (1.0 - scanlines); + FragColor = vec4(pow(halation, vec3(1.0 / params.out_gamma)), 1.0); +} \ No newline at end of file diff --git a/crt/shaders/phosphorlut/scanlines-interlace-linearize.slang b/crt/shaders/phosphorlut/scanlines-interlace-linearize.slang new file mode 100644 index 0000000..9221bc0 --- /dev/null +++ b/crt/shaders/phosphorlut/scanlines-interlace-linearize.slang @@ -0,0 +1,67 @@ +#version 450 + +layout(push_constant) uniform Push +{ + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; + float percent; + float enable_480i; + float top_field_first; + float input_gamma; +} registers; + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; +} global; + +#pragma parameter input_gamma "CRT Gamma" 2.5 0.0 5.0 0.1 +#pragma parameter percent "Interlacing Scanline Bright %" 0.0 0.0 1.0 0.05 +#pragma parameter enable_480i "Enable 480i Mode" 1.0 0.0 1.0 1.0 +#pragma parameter top_field_first "Top Field First Enable" 0.0 0.0 1.0 1.0 + +/* + Interlacing + Author: hunterk + License: Public domain + + Note: This shader is designed to work with the typical interlaced output from an emulator, which displays both even and odd fields twice. + This shader will un-weave the image, resulting in a standard, alternating-field interlacing. +*/ + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() +{ + vec4 res = texture(Source, vTexCoord).rgba; + float y = 0.0; + float tick = registers.FrameCount; + + // assume anything with a vertical resolution greater than 400 lines is interlaced + if (registers.SourceSize.y > 400.0) + {y = registers.SourceSize.y * vTexCoord.y + (tick * registers.enable_480i) + registers.top_field_first;} + else + {y = 2.0 * registers.SourceSize.y * vTexCoord.y + registers.top_field_first;} + + if (mod(y, 1.99999) > 0.99999) + {res = res;} + else + {res = vec4(registers.percent) * res;} + FragColor = pow(res, vec4(registers.input_gamma)); +} \ No newline at end of file