[SMM] CRT filter

CRT filter, all credit to  Timothy Lottes - PD
Just for fun to see if it could be adapted, I'm not planning on fixing
issues
This commit is contained in:
getdls 2018-01-27 00:53:50 +01:00
parent 631116e4ee
commit 4c849d9d51
2 changed files with 287 additions and 0 deletions

View File

@ -0,0 +1,282 @@
#version 420
#extension GL_ARB_texture_gather : enable
#extension GL_ARB_separate_shader_objects : enable
// shader d2a97b2fb99411a5
// CRT filter - Just for fun, probably won't be fixing any issues..
layout(binding = 0) uniform sampler2D textureUnitPS0;// Tex0 addr 0xf4481800 res 768x384x1 dim 1 tm: 4 format 001a compSel: 0 1 2 3 mipView: 0x0 (num 0x1) sliceView: 0x0 (num 0x1) Sampler0 ClampX/Y/Z: 2 2 2 border: 1
layout(location = 0) in vec4 passParameterSem0;
layout(location = 0) out vec4 passPixelColor0;
uniform vec2 uf_fragCoordScale;
//
// 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.
//
//old contrasty, or just copy paste clarity
const float gamma = 0.95; // 1.0 is neutral
const float exposure = 1.2; // 1.0 is neutral, first lessen to avoid truncation prob around .25 for radeon.
const float vibrance = 0.175; // 0.0 is neutral
const float crushContrast = 0.01; // 0.0 is neutral. loss of shadow detail
//const float postExposure = 1.16; // 1.0 is neutral, then slightly raise exposure back up.
vec3 contrasty(vec3 colour) {
vec3 fColour = (colour.xyz);
fColour = clamp(exposure * fColour, 0.0, 1.0);
fColour = pow(fColour, vec3(1.0 / gamma));
float luminance = fColour.r*0.299 + fColour.g*0.587 + fColour.b*0.114;
float mn = min(min(fColour.r, fColour.g), fColour.b);
float mx = max(max(fColour.r, fColour.g), fColour.b);
float sat = (1.0 - (mx - mn)) * (1.0 - mx) * luminance * 5.0;
vec3 lightness = vec3((mn + mx) / 2.0);
// vibrance
fColour = mix(fColour, mix(fColour, lightness, -vibrance), sat);
fColour = max(vec3(0.0), fColour - vec3(crushContrast));
return fColour;
}
#define RGBA(r, g, b, a) vec4(float(r)/255.0, float(g)/255.0, float(b)/255.0, float(a)/255.0)
const vec3 kBackgroundColor = RGBA(0x00, 0x60, 0xb8, 0xff).rgb; // medium-blue sky
//const vec3 kBackgroundColor = RGBA(0xff, 0x00, 0xff, 0xff).rgb; // test magenta
//const vec3 kBackgroundColor = RGBA(0x50, 0x50, 0x50, 0xff).rgb;
// Emulated input resolution.
#if 1
// Fix resolution to set amount.
//768x384x1 // Note: 256x224 is the most common resolution of the SNES, and that of Super Mario World.
vec2 res = vec2(
textureSize(textureUnitPS0, 0).x / 1.0,
textureSize(textureUnitPS0, 0).y / 2.0
);
#else
// Optimize for resize.
vec2 res = textureSize(textureUnitPS0, 0) / 6.0;
#endif
// Hardness of scanline.
// -8.0 = soft
// -16.0 = medium
float sHardScan = -8.0;
// Hardness of pixels in scanline.
// -2.0 = soft
// -4.0 = hard
const float kHardPix = -2.0;
// Display warp.
// 0.0 = none
// 1.0 / 8.0 = extreme
const vec2 kWarp = vec2(1.0 / 64.0, 1.0 / 48.0);
//const vec2 kWarp = vec2(0);
// Amount of shadow mask.
float kMaskDark = 2.0;
float kMaskLight = 0.5;
//------------------------------------------------------------------------
/*
// sRGB to Linear.
// Assuing using sRGB typed textures this should not be needed.
float toLinear1(float c) {
return (c <= 0.04045) ?
(c / 12.92) :
pow((c + 0.055) / 1.055, 2.4);
}
vec3 toLinear(vec3 c) {
return vec3(toLinear1(c.r), toLinear1(c.g), toLinear1(c.b));
}
// Linear to sRGB.
// Assuing using sRGB typed textures this should not be needed.
float toSrgb1(float c) {
return(c < 0.0031308 ?
(c * 12.92) :
(1.055 * pow(c, 0.41666) - 0.055));
}
vec3 toSrgb(vec3 c) {
return vec3(toSrgb1(c.r), toSrgb1(c.g), toSrgb1(c.b));
}
*/
// Nearest emulated sample given floating point position and texel offset.
// Also zero's off screen.
vec4 fetch(vec2 pos, vec2 off)
{
pos = floor(pos * res + off) / res;
if (max(abs(pos.x - 0.5), abs(pos.y - 0.5)) > 0.5)
return vec4(vec3(0.0), 0.0);
//vec4 sampledColor = texture(textureUnitPS0, pos.xy, -16.0);
vec4 sampledColor = texture(textureUnitPS0, pos.xy,0);
sampledColor = vec4(
(sampledColor.rgb * sampledColor.a) +
(kBackgroundColor * (1.0 - sampledColor.a)),
1.0
);
return vec4(
//toLinear(sampledColor.rgb),
//sampledColor.a
sampledColor.rgba
);
}
// Distance in emulated pixels to nearest texel.
vec2 dist(vec2 pos) {
pos = pos * res;
return -((pos - floor(pos)) - vec2(0.5));
}
// 1D Gaussian.
float gaus(float pos, float scale) {
return exp2(scale * pos * pos);
}
// 3-tap Gaussian filter along horz line.
vec3 horz3(vec2 pos, float off)
{
vec3 b = fetch(pos, vec2(-1.0, off)).rgb;
vec3 c = fetch(pos, vec2(0.0, off)).rgb;
vec3 d = fetch(pos, vec2(+1.0, off)).rgb;
float dst = dist(pos).x;
// Convert distance to weight.
float scale = kHardPix;
float wb = gaus(dst - 1.0, scale);
float wc = gaus(dst + 0.0, scale);
float wd = gaus(dst + 1.0, scale);
// Return filtered sample.
return (b * wb + c * wc + d * wd) / (wb + wc + wd);
}
// 5-tap Gaussian filter along horz line.
vec3 horz5(vec2 pos, float off)
{
vec3 a = fetch(pos, vec2(-2.0, off)).rgb;
vec3 b = fetch(pos, vec2(-1.0, off)).rgb;
vec3 c = fetch(pos, vec2(0.0, off)).rgb;
vec3 d = fetch(pos, vec2(+1.0, off)).rgb;
vec3 e = fetch(pos, vec2(+2.0, off)).rgb;
float dst = dist(pos).x;
// Convert distance to weight.
float scale = kHardPix;
float wa = gaus(dst - 2.0, scale);
float wb = gaus(dst - 1.0, scale);
float wc = gaus(dst + 0.0, scale);
float wd = gaus(dst + 1.0, scale);
float we = gaus(dst + 2.0, scale);
// Return filtered sample.
return (a * wa + b * wb + c * wc + d * wd + e * we) / (wa + wb + wc + wd + we);
}
// Return scanline weight.
float scan(vec2 pos, float off) {
float dst = dist(pos).y;
return gaus(dst + off, sHardScan);
}
// Allow nearest three lines to effect pixel.
vec3 tri(vec2 pos)
{
vec3 a = horz3(pos, -1.0);
vec3 b = horz5(pos, 0.0);
vec3 c = horz3(pos, +1.0);
float wa = scan(pos, -1.0);
float wb = scan(pos, 0.0);
float wc = scan(pos, +1.0);
return a * wa + b * wb + c * wc;
}
// Distortion of scanlines, and end of screen alpha.
vec2 warp(vec2 pos)
{
pos = pos * 2.0 - 1.0;
pos *= vec2(
1.0 + (pos.y * pos.y) * kWarp.x,
1.0 + (pos.x * pos.x) * kWarp.y
);
return pos * 0.5 + 0.5;
}
// Shadow mask.
vec3 mask(vec2 pos)
{
pos.x += pos.y * 3.0;
vec3 mask = vec3(kMaskDark, kMaskDark, kMaskDark);
pos.x = fract(pos.x / 6.0);
if (pos.x < 0.333)
mask.r = kMaskLight;
else if (pos.x < 0.666)
mask.g = kMaskLight;
else
mask.b = kMaskLight;
return mask;
}
// Draw dividing bars.
float bar(float pos, float bar) {
pos -= bar;
return (pos * pos < 4.0) ? 0.0 : 1.0;
}
float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
}
int clampFI32(int v)
{
if( v == 0x7FFFFFFF )
return floatBitsToInt(1.0);
else if( v == 0xFFFFFFFF )
return floatBitsToInt(0.0);
return floatBitsToInt(clamp(intBitsToFloat(v), 0.0, 1.0));
}
float mul_nonIEEE(float a, float b){ if( a == 0.0 || b == 0.0 ) return 0.0; return a*b; }
void main()
{
vec4 R0f = vec4(0.0);
float backupReg0f, backupReg1f, backupReg2f, backupReg3f, backupReg4f;
vec4 PV0f = vec4(0.0), PV1f = vec4(0.0);
float PS0f = 0.0, PS1f = 0.0;
vec4 tempf = vec4(0.0);
float tempResultf;
int tempResulti;
ivec4 ARi = ivec4(0);
bool predResult = true;
vec3 cubeMapSTM;
int cubeMapFaceId;
R0f = passParameterSem0;
//R0f.xyzw = (texture(textureUnitPS0, R0f.xy).xyzw);
// export
//passPixelColor0 = vec4(R0f.x, R0f.y, R0f.z, R0f.w);
vec2 pos = warp(gl_FragCoord.xy / textureSize(textureUnitPS0, 0));//iResolution.xy);
vec4 unmodifiedColor = fetch(pos, vec2(0));
// Unmodified.
if (passPixelColor0.x > textureSize(textureUnitPS0, 0).x * 0.333)
{
passPixelColor0.rgb = contrasty(unmodifiedColor.rgb);
}
else
{
if (passPixelColor0.x > textureSize(textureUnitPS0, 0).x * 0.666) {
sHardScan = -12.0;
kMaskDark = kMaskLight = 1.0;
}
passPixelColor0.rgb = tri(pos) * mask(gl_FragCoord.xy);
}
//passPixelColor0.rgb *= bar(gl_FragCoord.x, textureSize(textureUnitPS0, 0).x * 0.333) * bar(gl_FragCoord.x, textureSize(textureUnitPS0, 0).x * 0.666);
//passPixelColor0 = vec4(
//toSrgb(passPixelColor0.rgb),
//1.0
//);
passPixelColor0 = vec4(passPixelColor0.rgb, 1.0);
}

View File

@ -0,0 +1,5 @@
[Definition]
titleIds = 000500001018DB00,000500001018DC00,000500001018DD00
name = "Super Mario Maker - CRT filter"
version = 2