diff --git a/shaders/AANN.shader/AANN.fs b/shaders/AANN.shader/AANN.fs new file mode 100644 index 00000000..29792966 --- /dev/null +++ b/shaders/AANN.shader/AANN.fs @@ -0,0 +1,93 @@ +#version 150 + +// AntiAliased Nearest Neighbor +// by jimbo1qaz and wareya +// Licensed MIT + +precision highp float; + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize[]; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define NOT(fl) (1-fl) +#define YES(fl) fl + +vec4 vpow(vec4 n, float e) +{ + return vec4(pow(n.x, e), pow(n.y, e), pow(n.z, e), pow(n.w, e)); +} + +vec4 getLQV(vec3 mine) { + return vec4 + ( mine.r + , mine.g + , mine.b + , mine.r*0.2989 + mine.g*0.5870 + mine.b*0.1140); +} +vec3 fromLQV(vec4 mine) { + float f = mine.w/(mine.r*0.2989 + mine.g*0.5870 + mine.b*0.1140); + return vec3(mine.rgb)*f; +} + +vec3 percent(float ssize, float tsize, float coord) { + float minfull = (coord*tsize - 0.5) /tsize*ssize; + float maxfull = (coord*tsize + 0.5) /tsize*ssize; + + float realfull = floor(maxfull); + + if (minfull > realfull) { + return vec3(1, (realfull+0.5)/ssize, (realfull+0.5)/ssize); + } + + return vec3( + (maxfull - realfull) / (maxfull - minfull), + (realfull-0.5) / ssize, + (realfull+0.5) / ssize + ); +} + + +void main() { + float cheapsrgb = 2.1; + float gamma = 3.0; + vec3 xstuff = percent(sourceSize[0].x, targetSize[0].x, texCoord.x); + vec3 ystuff = percent(sourceSize[0].y, targetSize[0].y, texCoord.y); + + float xkeep = xstuff[0]; + float ykeep = ystuff[0]; + + // get points to interpolate across, in linear rgb + vec4 a = getLQV(vpow(texture(source[0],vec2(xstuff[1],ystuff[1])), cheapsrgb).rgb); + vec4 b = getLQV(vpow(texture(source[0],vec2(xstuff[2],ystuff[1])), cheapsrgb).rgb); + vec4 c = getLQV(vpow(texture(source[0],vec2(xstuff[1],ystuff[2])), cheapsrgb).rgb); + vec4 d = getLQV(vpow(texture(source[0],vec2(xstuff[2],ystuff[2])), cheapsrgb).rgb); + + // use perceptual gamma for luminance component + a.w = pow(a.w, 1/gamma); + b.w = pow(b.w, 1/gamma); + c.w = pow(c.w, 1/gamma); + d.w = pow(d.w, 1/gamma); + + // interpolate + vec4 gammaLQVresult = + NOT(xkeep)*NOT(ykeep)*a + + YES(xkeep)*NOT(ykeep)*b + + NOT(xkeep)*YES(ykeep)*c + + YES(xkeep)*YES(ykeep)*d; + + // change luminance gamma back to linear + vec4 LQVresult = gammaLQVresult; + LQVresult.w = pow(gammaLQVresult.w, gamma); + + // convert back to srgb; lqv -> lrgb -> srgb + vec4 c1 = vpow(vec4(fromLQV(LQVresult), 1), 1/cheapsrgb); + + fragColor = c1; +} diff --git a/shaders/AANN.shader/manifest.bml b/shaders/AANN.shader/manifest.bml new file mode 100644 index 00000000..d9d50d5d --- /dev/null +++ b/shaders/AANN.shader/manifest.bml @@ -0,0 +1,8 @@ +input + filter: nearest + +program + fragment: AANN.fs + +output + filter: nearest \ No newline at end of file diff --git a/shaders/CRT-Geom.shader/crt-geom.fs b/shaders/CRT-Geom.shader/crt-geom.fs new file mode 100644 index 00000000..08a671e5 --- /dev/null +++ b/shaders/CRT-Geom.shader/crt-geom.fs @@ -0,0 +1,297 @@ +#version 150 + +/* + 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 +*/ + +//#define INTERLACED + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +uniform int phase; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +// Comment the next line to disable interpolation in linear gamma (and gain speed). +#define LINEAR_PROCESSING + +// Enable screen curvature. +#define CURVATURE + +// Enable 3x oversampling of the beam profile +#define OVERSAMPLE + +// Use the older, purely gaussian beam profile +//#define USEGAUSSIAN + +// vertex params // + + // gamma of simulated CRT +#define CRTgamma 2.4 + // gamma of display monitor (typically 2.2 is correct) +#define monitorgamma 2.2 + // overscan (e.g. 1.02 for 2% overscan) +#define overscan vec2(1.0 , 1.0)//(0.93 , 0.915) + // aspect ratio +#define aspect vec2(1.0, 0.75) + // lengths are measured in units of (approximately) the width of the monitor + // simulated distance from viewer to monitor +#define d 2.0 + // radius of curvature +#define R 2.0 + // tilt angle in radians + // (behavior might be a bit wrong if both components are nonzero) +#define angle vec2(0.0,-0.0) + // size of curved corners +#define cornersize 0.02 + // border smoothness parameter + // decrease if borders are too aliased +#define cornersmooth 80.0 + +#define sinangle sin(angle) +#define cosangle cos(angle) +#define stretch maxscale() +#define ilfac vec2(1.0, floor(sourceSize[0].y / 200.0)) +#define one (ilfac / sourceSize[0].xy) +#define mod_factor (texCoord.x * targetSize.x) + +// END of vertex params // + +// Macros. +#define FIX(c) max(abs(c), 1e-5); +#define PI 3.141592653589 + +#ifdef LINEAR_PROCESSING +# define TEX2D(c) pow(texture(source[0], (c)), vec4(CRTgamma)) +#else +# define TEX2D(c) texture(source[0], (c)) +#endif + +#define FIX(c) max(abs(c), 1e-5); + +float intersect(vec2 xy) +{ + float A = dot(xy,xy)+d*d; + float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d); + float C = d*d + 2.0*R*d*cosangle.x*cosangle.y; + return (-B-sqrt(B*B-4.0*A*C))/(2.0*A); +} + +vec2 bkwtrans(vec2 xy) +{ + float c = intersect(xy); + vec2 point = vec2(c)*xy; + point -= vec2(-R)*sinangle; + point /= vec2(R); + vec2 tang = sinangle/cosangle; + vec2 poc = point/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); + vec2 uv = (point-a*sinangle)/cosangle; + float r = R*acos(a); + return uv*r/sin(r/R); +} + +vec2 fwtrans(vec2 uv) +{ + float r = FIX(sqrt(dot(uv,uv))); + uv *= sin(r/R)/r; + float x = 1.0-cos(r/R); + float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle); + return d*(uv*cosangle-x*sinangle)/D; +} + +vec3 maxscale() +{ + vec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y)); + vec2 a = vec2(0.5,0.5)*aspect; + vec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x, + fwtrans(vec2(c.x,-a.y)).y)/aspect; + vec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x, + fwtrans(vec2(c.x,+a.y)).y)/aspect; + return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y)); +} + +vec2 transform(vec2 coord) +{ + coord = (coord-vec2(0.5))*aspect*stretch.z+stretch.xy; + return (bkwtrans(coord)/overscan/aspect+vec2(0.5)); +} + +float corner(vec2 coord) +{ + coord = (coord - vec2(0.5)) * overscan + vec2(0.5); + coord = min(coord, vec2(1.0)-coord) * aspect; + vec2 cdist = vec2(cornersize); + coord = (cdist - min(coord,cdist)); + float dist = sqrt(dot(coord,coord)); + return clamp((cdist.x-dist)*cornersmooth,0.0, 1.0); +} + +// Calculate the influence of a scanline on the current pixel. +// +// 'distance' is the distance in texture coordinates from the current +// pixel to the scanline in question. +// 'color' is the colour of the scanline at the horizontal location of +// the current pixel. +vec4 scanlineWeights(float distance, vec4 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. +#ifdef USEGAUSSIAN + vec4 wid = 0.3 + 0.1 * pow(color, vec4(3.0)); + vec4 weights = vec4(distance / wid); + return 0.4 * exp(-weights * weights) / wid; +#else + vec4 wid = 2.0 + 2.0 * pow(color, vec4(4.0)); + vec4 weights = vec4(distance / 0.3); + return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid); +#endif +} + +void main() +{ + + // Here's a helpful diagram to keep in mind while trying to + // understand the code: + // + // | | | | | + // ------------------------------- + // | | | | | + // | 01 | 11 | 21 | 31 | <-- current scanline + // | | @ | | | + // ------------------------------- + // | | | | | + // | 02 | 12 | 22 | 32 | <-- next scanline + // | | | | | + // ------------------------------- + // | | | | | + // + // Each character-cell represents a pixel on the output + // surface, "@" represents the current pixel (always somewhere + // in the bottom half of the current scan-line, or the top-half + // of the next scanline). The grid of lines represents the + // edges of the texels of the underlying texture. + + // Texture coordinates of the texel containing the active pixel. +#ifdef CURVATURE + vec2 xy = transform(texCoord); +#else + vec2 xy = texCoord; +#endif + float cval = corner(xy); + + // Of all the pixels that are mapped onto the texel we are + // currently rendering, which pixel are we currently rendering? +#ifdef INTERLACED + vec2 ilvec = vec2(0.0,ilfac.y > 1.5 ? mod(float(phase),2.0) : 0.0); +#else + vec2 ilvec = vec2(0.0,ilfac.y); +#endif + vec2 ratio_scale = (xy * sourceSize[0].xy - vec2(0.5) + ilvec)/ilfac; +#ifdef OVERSAMPLE + float filter_ = sourceSize[0].y / targetSize.y; +#endif + vec2 uv_ratio = fract(ratio_scale); + + // Snap to the center of the underlying texel. + xy = (floor(ratio_scale)*ilfac + vec2(0.5) - ilvec) / sourceSize[0].xy; + + // Calculate Lanczos scaling coefficients describing the effect + // of various neighbour texels in a scanline on the current + // pixel. + vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); + + // Prevent division by zero. + coeffs = FIX(coeffs); + + // Lanczos2 kernel. + coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs); + + // Normalize. + coeffs /= dot(coeffs, vec4(1.0)); + + // Calculate the effective colour of the current and next + // scanlines at the horizontal location of the current pixel, + // using the Lanczos coefficients above. + vec4 col = clamp(mat4( + TEX2D(xy + vec2(-one.x, 0.0)), + TEX2D(xy), + TEX2D(xy + vec2(one.x, 0.0)), + TEX2D(xy + vec2(2.0 * one.x, 0.0))) * coeffs, + 0.0, 1.0); + vec4 col2 = clamp(mat4( + TEX2D(xy + vec2(-one.x, one.y)), + TEX2D(xy + vec2(0.0, one.y)), + TEX2D(xy + one), + TEX2D(xy + vec2(2.0 * one.x, one.y))) * coeffs, + 0.0, 1.0); + +#ifndef LINEAR_PROCESSING + col = pow(col , vec4(CRTgamma)); + col2 = pow(col2, vec4(CRTgamma)); +#endif + + // Calculate the influence of the current and next scanlines on + // the current pixel. + vec4 weights = scanlineWeights(uv_ratio.y, col); + vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2); +#ifdef OVERSAMPLE + uv_ratio.y =uv_ratio.y+1.0/3.0*filter_; + weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0; + weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0; + uv_ratio.y =uv_ratio.y-2.0/3.0*filter_; + weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0; + weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0; +#endif + vec3 mul_res = (col * weights + col2 * weights2).rgb * vec3(cval); + + // dot-mask emulation: + // Output pixels are alternately tinted green and magenta. + vec3 dotMaskWeights = mix( + vec3(1.0, 0.7, 1.0), + vec3(0.7, 1.0, 0.7), + floor(mod(mod_factor, 2.0)) + ); + + mul_res *= dotMaskWeights; + + // Convert the image gamma for display on our output device. + mul_res = pow(mul_res, vec3(1.0 / monitorgamma)); + + // Color the texel. + fragColor = vec4(mul_res, 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Geom.shader/crt-geom.vs b/shaders/CRT-Geom.shader/crt-geom.vs new file mode 100644 index 00000000..30b48eee --- /dev/null +++ b/shaders/CRT-Geom.shader/crt-geom.vs @@ -0,0 +1,121 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; +in vec4 sourceSize[]; +in vec4 targetSize; + +out Vertex { + vec2 texCoord; +} vertexOut; + +float CRTgamma; +float monitorgamma; +vec2 overscan; +vec2 aspect; +float d; +float R; +float cornersize; +float cornersmooth; + +vec3 stretch; +vec2 sinangle; +vec2 cosangle; + +vec2 one; +float mod_factor; +vec2 ilfac; + +#define FIX(c) max(abs(c), 1e-5); + +float intersect(vec2 xy) +{ + float A = dot(xy,xy)+d*d; + float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d); + float C = d*d + 2.0*R*d*cosangle.x*cosangle.y; + return (-B-sqrt(B*B-4.0*A*C))/(2.0*A); +} + +vec2 bkwtrans(vec2 xy) +{ + float c = intersect(xy); + vec2 point = vec2(c)*xy; + point -= vec2(-R)*sinangle; + point /= vec2(R); + vec2 tang = sinangle/cosangle; + vec2 poc = point/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); + vec2 uv = (point-a*sinangle)/cosangle; + float r = R*acos(a); + return uv*r/sin(r/R); +} + +vec2 fwtrans(vec2 uv) +{ + float r = FIX(sqrt(dot(uv,uv))); + uv *= sin(r/R)/r; + float x = 1.0-cos(r/R); + float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle); + return d*(uv*cosangle-x*sinangle)/D; +} + +vec3 maxscale() +{ + vec2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y)); + vec2 a = vec2(0.5,0.5)*aspect; + vec2 lo = vec2(fwtrans(vec2(-a.x,c.y)).x, + fwtrans(vec2(c.x,-a.y)).y)/aspect; + vec2 hi = vec2(fwtrans(vec2(+a.x,c.y)).x, + fwtrans(vec2(c.x,+a.y)).y)/aspect; + return vec3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y)); +} + +void main() +{ + + // START of parameters + + // gamma of simulated CRT + CRTgamma = 2.4; + // gamma of display monitor (typically 2.2 is correct) + monitorgamma = 2.2; + // overscan (e.g. 1.02 for 2% overscan) + overscan = vec2(0.99,0.99); + // aspect ratio + aspect = vec2(1.0, 0.75); + // lengths are measured in units of (approximately) the width of the monitor + // simulated distance from viewer to monitor + d = 2.0; + // radius of curvature + R = 2.0; + // tilt angle in radians + // (behavior might be a bit wrong if both components are nonzero) + const vec2 angle = vec2(0.0,-0.0); + // size of curved corners + cornersize = 0.03; + // border smoothness parameter + // decrease if borders are too aliased + cornersmooth = 80.0; + + // END of parameters + +vertexOut.texCoord = texCoord.xy; +gl_Position = position; + + // Precalculate a bunch of useful values we'll need in the fragment + // shader. + sinangle = sin(angle); + cosangle = cos(angle); + stretch = maxscale(); + + ilfac = vec2(1.0,floor(sourceSize[0].y/200.0)); + + // The size of one texel, in texture-coordinates. + one = ilfac / sourceSize[0].xy; + + // Resulting X pixel-coordinate of the pixel we're drawing. + mod_factor = texCoord.x * targetSize.x; +} \ No newline at end of file diff --git a/shaders/CRT-Geom.shader/curvature.fs b/shaders/CRT-Geom.shader/curvature.fs new file mode 100644 index 00000000..22386c8c --- /dev/null +++ b/shaders/CRT-Geom.shader/curvature.fs @@ -0,0 +1,21 @@ +#version 150 +#define distortion 0.08 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +vec2 radialDistortion(vec2 coord) { + vec2 cc = coord - vec2(0.5); + float dist = dot(cc, cc) * distortion; + return coord + cc * (1.0 - dist) * dist; +} + +void main(void) { + fragColor = texture(source[0], radialDistortion(texCoord)); +} diff --git a/shaders/CRT-Geom.shader/manifest.bml b/shaders/CRT-Geom.shader/manifest.bml new file mode 100644 index 00000000..8315f31c --- /dev/null +++ b/shaders/CRT-Geom.shader/manifest.bml @@ -0,0 +1,5 @@ +program + vertex: crt-geom.vs + fragment: crt-geom.fs + modulo: 2 + diff --git a/shaders/CRT-Glow.shader/blur_horiz.fs b/shaders/CRT-Glow.shader/blur_horiz.fs new file mode 100644 index 00000000..d532e704 --- /dev/null +++ b/shaders/CRT-Glow.shader/blur_horiz.fs @@ -0,0 +1,32 @@ +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// Higher value, more centered glow. +// Lower values might need more taps. +#define GLOW_FALLOFF 0.35 +#define TAPS 4 + +#define kernel(x) exp(-GLOW_FALLOFF * (x) * (x)) + +void main() { + vec3 col = vec3(0.0); + float dx = 4.0 * sourceSize[0].z; // Mipmapped + + float k_total = 0.0; + for (int i = -TAPS; i <= TAPS; i++) + { + float k = kernel(i); + k_total += k; + col += k * texture(source[0], vTexCoord + vec2(float(i) * dx, 0.0)).rgb; + } + + FragColor = vec4(col / k_total, 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/blur_horiz.vs b/shaders/CRT-Glow.shader/blur_horiz.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/CRT-Glow.shader/blur_horiz.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/blur_vert.fs b/shaders/CRT-Glow.shader/blur_vert.fs new file mode 100644 index 00000000..c904efdf --- /dev/null +++ b/shaders/CRT-Glow.shader/blur_vert.fs @@ -0,0 +1,32 @@ +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// Higher value, more centered glow. +// Lower values might need more taps. +#define GLOW_FALLOFF 0.35 +#define TAPS 4 + +#define kernel(x) exp(-GLOW_FALLOFF * (x) * (x)) + +void main() { + vec3 col = vec3(0.0); + float dy = sourceSize[0].w; + + float k_total = 0.0; + for (int i = -TAPS; i <= TAPS; i++) + { + float k = kernel(i); + k_total += k; + col += k * texture(source[0], vTexCoord + vec2(0.0, float(i) * dy)).rgb; + } + + FragColor = vec4(col / k_total, 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/blur_vert.vs b/shaders/CRT-Glow.shader/blur_vert.vs new file mode 100644 index 00000000..1f08237b --- /dev/null +++ b/shaders/CRT-Glow.shader/blur_vert.vs @@ -0,0 +1,13 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/gauss_horiz.fs b/shaders/CRT-Glow.shader/gauss_horiz.fs new file mode 100644 index 00000000..1d20dd91 --- /dev/null +++ b/shaders/CRT-Glow.shader/gauss_horiz.fs @@ -0,0 +1,33 @@ +#version 150 + +#define INV_SQRT_2_PI 0.38 // Doesn't have to be accurate. + +#define HORIZ_GAUSS_WIDTH 0.5 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; + float data_pix_no; + float data_one; +}; + +out vec4 FragColor; + +void main() { + float texel = floor(data_pix_no); + float phase = data_pix_no - texel; + float base_phase = phase - 0.5; + vec2 tex = vec2((texel + 0.5) * sourceSize[0].z, vTexCoord.y); + + vec3 col = vec3(0.0); + for (int i = -2; i <= 2; i++) + { + float phase = base_phase - float(i); + float g = INV_SQRT_2_PI * exp(-0.5 * phase * phase / (HORIZ_GAUSS_WIDTH * HORIZ_GAUSS_WIDTH)) / HORIZ_GAUSS_WIDTH; + col += texture(source[0], tex + vec2(float(i) * data_one, 0.0)).rgb * g; + } + + FragColor = vec4(col, 1.0); +} diff --git a/shaders/CRT-Glow.shader/gauss_horiz.vs b/shaders/CRT-Glow.shader/gauss_horiz.vs new file mode 100644 index 00000000..0be7ad1d --- /dev/null +++ b/shaders/CRT-Glow.shader/gauss_horiz.vs @@ -0,0 +1,20 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; + float data_pix_no; + float data_one; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; + + data_pix_no = vTexCoord.x * sourceSize[0].x; + data_one = sourceSize[0].z; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/gauss_vert.fs b/shaders/CRT-Glow.shader/gauss_vert.fs new file mode 100644 index 00000000..01cf7af9 --- /dev/null +++ b/shaders/CRT-Glow.shader/gauss_vert.fs @@ -0,0 +1,49 @@ +#version 150 + +#define BOOST 1.0 +#define CRT_GEOM_BEAM 1 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; + vec2 data_pix_no; + float data_one; +}; + +out vec4 FragColor; + +vec3 beam(vec3 color, float dist) +{ +#if CRT_GEOM_BEAM + vec3 wid = 2.0 + 2.0 * pow(color, vec3(4.0)); + vec3 weights = vec3(abs(dist) * 3.333333333); + + return 2.0 * color * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid); +#else + float reciprocal_width = 4.0; + vec3 x = dist * reciprocal_width; + + return 2.0 * color * exp(-0.5 * x * x) * reciprocal_width; +#endif +} + +void main() { + vec2 texel = floor(data_pix_no); + float phase = data_pix_no.y - texel.y; + vec2 tex = vec2(texel + 0.5) * sourceSize[0].zw; + + vec3 top = texture(source[0], tex + vec2(0.0, 0 * data_one)).rgb; + vec3 bottom = texture(source[0], tex + vec2(0.0, 1 * data_one)).rgb; + + float dist0 = phase; + float dist1 = 1.0 - phase; + + vec3 scanline = vec3(0.0); + + scanline += beam(top, dist0); + scanline += beam(bottom, dist1); + + FragColor = vec4(BOOST * scanline * 0.869565217391304, 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/gauss_vert.vs b/shaders/CRT-Glow.shader/gauss_vert.vs new file mode 100644 index 00000000..78d20239 --- /dev/null +++ b/shaders/CRT-Glow.shader/gauss_vert.vs @@ -0,0 +1,20 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; + vec2 data_pix_no; + float data_one; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; + + data_pix_no = vTexCoord.xy * sourceSize[0].xy - vec2(0.0, 0.5); + data_one = sourceSize[0].w; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/lanczos_horiz.fs b/shaders/CRT-Glow.shader/lanczos_horiz.fs new file mode 100644 index 00000000..5ac2f3e2 --- /dev/null +++ b/shaders/CRT-Glow.shader/lanczos_horiz.fs @@ -0,0 +1,13 @@ +#version 150 + +uniform sampler2D source[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +void main() { + FragColor = texture(source[0], vTexCoord); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/lanczos_horiz.vs b/shaders/CRT-Glow.shader/lanczos_horiz.vs new file mode 100644 index 00000000..d95f0fcd --- /dev/null +++ b/shaders/CRT-Glow.shader/lanczos_horiz.vs @@ -0,0 +1,15 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/linearize.fs b/shaders/CRT-Glow.shader/linearize.fs new file mode 100644 index 00000000..9d4a652f --- /dev/null +++ b/shaders/CRT-Glow.shader/linearize.fs @@ -0,0 +1,15 @@ +#version 150 + +#define INPUT_GAMMA 2.2 + +uniform sampler2D source[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +void main() { + FragColor = pow(texture(source[0], vTexCoord), vec4(INPUT_GAMMA)); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/linearize.vs b/shaders/CRT-Glow.shader/linearize.vs new file mode 100644 index 00000000..d95f0fcd --- /dev/null +++ b/shaders/CRT-Glow.shader/linearize.vs @@ -0,0 +1,15 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/manifest.bml b/shaders/CRT-Glow.shader/manifest.bml new file mode 100644 index 00000000..bb865dad --- /dev/null +++ b/shaders/CRT-Glow.shader/manifest.bml @@ -0,0 +1,54 @@ +input + filter: nearest + +program + format: srgb8 + filter: nearest + vertex: linearize.vs + fragment: linearize.fs + +program + format: srgb8 + filter: nearest + height: 25% + width: 100% + vertex: gauss_horiz.vs + fragment: gauss_horiz.fs + +program + format: srgb8 + filter: nearest + vertex: gauss_vert.vs + fragment: gauss_vert.fs + +program + format: srgb8 + filter: nearest + height: 100% + width: 100% + vertex: threshold.vs + fragment: threshold.fs + +program + format: srgb8 + filter: linear + height: 25% + width: 25% + vertex: blur_horiz.vs + fragment: blur_horiz.fs + +program + format: srgb8 + filter: linear + height: 100% + width: 100% + vertex: blur_vert.vs + fragment: blur_vert.fs + +program + filter: linear + vertex: resolve.vs + fragment: resolve.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/resolve.fs b/shaders/CRT-Glow.shader/resolve.fs new file mode 100644 index 00000000..de32ec58 --- /dev/null +++ b/shaders/CRT-Glow.shader/resolve.fs @@ -0,0 +1,28 @@ +#version 150 + +#define BLOOM_STRENGTH 0.25 +#define OUTPUT_GAMMA 2.2 + +uniform sampler2D source[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// For debugging +#define BLOOM_ONLY 0 + +#define CRT_PASS source[3] + +void main() { +#if BLOOM_ONLY + vec3 source = BLOOM_STRENGTH * texture(source[0], vTexCoord).rgb; +#else + vec3 source_ = 1.15 * texture(CRT_PASS, vTexCoord).rgb; + vec3 bloom = texture(source[0], vTexCoord).rgb; + source_ += BLOOM_STRENGTH * bloom; +#endif + FragColor = vec4(pow(clamp(source_, 0.0, 1.0), vec3(1.0 / OUTPUT_GAMMA)), 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/resolve.vs b/shaders/CRT-Glow.shader/resolve.vs new file mode 100644 index 00000000..1f08237b --- /dev/null +++ b/shaders/CRT-Glow.shader/resolve.vs @@ -0,0 +1,13 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/threshold.fs b/shaders/CRT-Glow.shader/threshold.fs new file mode 100644 index 00000000..e4de6f87 --- /dev/null +++ b/shaders/CRT-Glow.shader/threshold.fs @@ -0,0 +1,19 @@ +#version 150 + +#define GLOW_WHITEPOINT 1.0 +#define GLOW_ROLLOFF 3.0 + +uniform sampler2D source[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +void main() { + vec3 color = 1.15 * texture(source[0], vTexCoord).rgb; + vec3 factor = clamp(color / GLOW_WHITEPOINT, 0.0, 1.0); + + FragColor = vec4(pow(factor, vec3(GLOW_ROLLOFF)), 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Glow.shader/threshold.vs b/shaders/CRT-Glow.shader/threshold.vs new file mode 100644 index 00000000..1f08237b --- /dev/null +++ b/shaders/CRT-Glow.shader/threshold.vs @@ -0,0 +1,13 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Lottes.shader/bloompass.fs b/shaders/CRT-Lottes.shader/bloompass.fs new file mode 100644 index 00000000..3a64ec42 --- /dev/null +++ b/shaders/CRT-Lottes.shader/bloompass.fs @@ -0,0 +1,306 @@ +#version 150 + +// 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. + +#define hardScan -8.0 +#define hardPix -3.0 +#define warpX 0.031 +#define warpY 0.041 +#define maskDark 0.5 +#define maskLight 1.5 +#define scaleInLinearGamma 1.0 +#define shadowMask 3.0 +#define brightBoost 1.0 +#define hardBloomPix -1.5 +#define hardBloomScan -2.0 +#define bloomAmount 0.4 +#define shape 2.0 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +//Uncomment to reduce instructions with simpler linearization +//(fixes HD3000 Sandy Bridge IGP) +//#define SIMPLE_LINEAR_GAMMA +#define DO_BLOOM 1 + +// ------------- // + +// sRGB to Linear. +// Assuming using sRGB typed textures this should not be needed. +#ifdef SIMPLE_LINEAR_GAMMA +float ToLinear1(float c) +{ + return c; +} +vec3 ToLinear(vec3 c) +{ + return c; +} +vec3 ToSrgb(vec3 c) +{ + return pow(c, vec3(1.0 / 2.2)); +} +#else +float ToLinear1(float c) +{ + if (scaleInLinearGamma == 0) + return c; + + return(c<=0.04045) ? c/12.92 : pow((c + 0.055)/1.055, 2.4); +} + +vec3 ToLinear(vec3 c) +{ + if (scaleInLinearGamma==0) + return c; + + return vec3(ToLinear1(c.r), ToLinear1(c.g), ToLinear1(c.b)); +} + +// Linear to sRGB. +// Assuming using sRGB typed textures this should not be needed. +float ToSrgb1(float c) +{ + if (scaleInLinearGamma == 0) + return c; + + return(c<0.0031308 ? c*12.92 : 1.055*pow(c, 0.41666) - 0.055); +} + +vec3 ToSrgb(vec3 c) +{ + if (scaleInLinearGamma == 0) + return c; + + return vec3(ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b)); +} +#endif + + + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=(floor(pos*sourceSize[0].xy+off)+vec2(0.5,0.5))/sourceSize[0].xy; +#ifdef SIMPLE_LINEAR_GAMMA + return ToLinear(brightBoost * pow(texture(source[0],pos.xy).rgb, vec3(2.2))); +#else + return ToLinear(brightBoost * texture(source[0],pos.xy).rgb); +#endif +} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos) +{ + pos = pos*sourceSize[0].xy; + + return -((pos - floor(pos)) - vec2(0.5)); +} + +// 1D Gaussian. +float Gaus(float pos, float scale) +{ + return exp2(scale*pow(abs(pos), shape)); +} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos, float off) +{ + vec3 b = Fetch(pos, vec2(-1.0, off)); + vec3 c = Fetch(pos, vec2( 0.0, off)); + vec3 d = Fetch(pos, vec2( 1.0, off)); + float dst = Dist(pos).x; + + // Convert distance to weight. + float scale = hardPix; + 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)); + vec3 b = Fetch(pos,vec2(-1.0, off)); + vec3 c = Fetch(pos,vec2( 0.0, off)); + vec3 d = Fetch(pos,vec2( 1.0, off)); + vec3 e = Fetch(pos,vec2( 2.0, off)); + + float dst = Dist(pos).x; + // Convert distance to weight. + float scale = hardPix; + 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); +} + +// 7-tap Gaussian filter along horz line. +vec3 Horz7(vec2 pos,float off) +{ + vec3 a = Fetch(pos, vec2(-3.0, off)); + vec3 b = Fetch(pos, vec2(-2.0, off)); + vec3 c = Fetch(pos, vec2(-1.0, off)); + vec3 d = Fetch(pos, vec2( 0.0, off)); + vec3 e = Fetch(pos, vec2( 1.0, off)); + vec3 f = Fetch(pos, vec2( 2.0, off)); + vec3 g = Fetch(pos, vec2( 3.0, off)); + + float dst = Dist(pos).x; + // Convert distance to weight. + float scale = hardBloomPix; + float wa = Gaus(dst - 3.0, scale); + float wb = Gaus(dst - 2.0, scale); + float wc = Gaus(dst - 1.0, scale); + float wd = Gaus(dst + 0.0, scale); + float we = Gaus(dst + 1.0, scale); + float wf = Gaus(dst + 2.0, scale); + float wg = Gaus(dst + 3.0, scale); + + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we+f*wf+g*wg)/(wa+wb+wc+wd+we+wf+wg); +} + +// Return scanline weight. +float Scan(vec2 pos, float off) +{ + float dst = Dist(pos).y; + + return Gaus(dst + off, hardScan); +} + +// Return scanline weight for bloom. +float BloomScan(vec2 pos, float off) +{ + float dst = Dist(pos).y; + + return Gaus(dst + off, hardBloomScan); +} + +// 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; +} + +// Small bloom. +vec3 Bloom(vec2 pos) +{ + vec3 a = Horz5(pos,-2.0); + vec3 b = Horz7(pos,-1.0); + vec3 c = Horz7(pos, 0.0); + vec3 d = Horz7(pos, 1.0); + vec3 e = Horz5(pos, 2.0); + + float wa = BloomScan(pos,-2.0); + float wb = BloomScan(pos,-1.0); + float wc = BloomScan(pos, 0.0); + float wd = BloomScan(pos, 1.0); + float we = BloomScan(pos, 2.0); + + return a*wa+b*wb+c*wc+d*wd+e*we; +} + +// 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)*warpX, 1.0 + (pos.x*pos.x)*warpY); + + return pos*0.5 + 0.5; +} + +// Shadow mask. +vec3 Mask(vec2 pos) +{ + vec3 mask = vec3(maskDark, maskDark, maskDark); + + // Very compressed TV style shadow mask. + if (shadowMask == 1.0) + { + float line = maskLight; + float odd = 0.0; + + if (fract(pos.x*0.166666666) < 0.5) odd = 1.0; + if (fract((pos.y + odd) * 0.5) < 0.5) line = maskDark; + + pos.x = fract(pos.x*0.333333333); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + mask*=line; + } + + // Aperture-grille. + else if (shadowMask == 2.0) + { + pos.x = fract(pos.x*0.333333333); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + // Stretched VGA style shadow mask (same as prior shaders). + else if (shadowMask == 3.0) + { + pos.x += pos.y*3.0; + pos.x = fract(pos.x*0.166666666); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + // VGA style shadow mask. + else if (shadowMask == 4.0) + { + pos.xy = floor(pos.xy*vec2(1.0, 0.5)); + pos.x += pos.y*3.0; + pos.x = fract(pos.x*0.166666666); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + return mask; +} + +void main() { + FragColor = vec4(Bloom(vTexCoord)*bloomAmount, 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Lottes.shader/bloompass.vs b/shaders/CRT-Lottes.shader/bloompass.vs new file mode 100644 index 00000000..d95f0fcd --- /dev/null +++ b/shaders/CRT-Lottes.shader/bloompass.vs @@ -0,0 +1,15 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/CRT-Lottes.shader/manifest.bml b/shaders/CRT-Lottes.shader/manifest.bml new file mode 100644 index 00000000..13050c81 --- /dev/null +++ b/shaders/CRT-Lottes.shader/manifest.bml @@ -0,0 +1,18 @@ +input + filter: nearest + +program + filter: nearest + format: srgb8 + height: 100% + width: 100% + vertex: bloompass.vs + fragment: bloompass.fs + +program + filter: nearest + vertex: scanpass.vs + fragment: scanpass.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/CRT-Lottes.shader/scanpass.fs b/shaders/CRT-Lottes.shader/scanpass.fs new file mode 100644 index 00000000..5f14f70d --- /dev/null +++ b/shaders/CRT-Lottes.shader/scanpass.fs @@ -0,0 +1,317 @@ +#version 150 + +// 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. + +#define hardScan -8.0 +#define hardPix -3.0 +#define warpX 0.031 +#define warpY 0.041 +#define maskDark 0.5 +#define maskLight 1.5 +#define scaleInLinearGamma 1.0 +#define shadowMask 3.0 +#define brightBoost 1.0 +#define hardBloomPix -1.5 +#define hardBloomScan -2.0 +#define bloomAmount 0.4 +#define shape 2.0 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 outputSize; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +//Uncomment to reduce instructions with simpler linearization +//(fixes HD3000 Sandy Bridge IGP) +//#define SIMPLE_LINEAR_GAMMA +#define DO_BLOOM 1 + +// ------------- // + +// sRGB to Linear. +// Assuming using sRGB typed textures this should not be needed. +#ifdef SIMPLE_LINEAR_GAMMA +float ToLinear1(float c) +{ + return c; +} +vec3 ToLinear(vec3 c) +{ + return c; +} +vec3 ToSrgb(vec3 c) +{ + return pow(c, vec3(1.0 / 2.2)); +} +#else +float ToLinear1(float c) +{ + if (scaleInLinearGamma == 0) + return c; + + return(c<=0.04045) ? c/12.92 : pow((c + 0.055)/1.055, 2.4); +} + +vec3 ToLinear(vec3 c) +{ + if (scaleInLinearGamma==0) + return c; + + return vec3(ToLinear1(c.r), ToLinear1(c.g), ToLinear1(c.b)); +} + +// Linear to sRGB. +// Assuming using sRGB typed textures this should not be needed. +float ToSrgb1(float c) +{ + if (scaleInLinearGamma == 0) + return c; + + return(c<0.0031308 ? c*12.92 : 1.055*pow(c, 0.41666) - 0.055); +} + +vec3 ToSrgb(vec3 c) +{ + if (scaleInLinearGamma == 0) + return c; + + return vec3(ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b)); +} +#endif + + + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=(floor(pos*sourceSize[0].xy+off)+vec2(0.5,0.5))/sourceSize[0].xy; +#ifdef SIMPLE_LINEAR_GAMMA + return ToLinear(brightBoost * pow(texture(source[1],pos.xy).rgb, vec3(2.2))); +#else + return ToLinear(brightBoost * texture(source[1],pos.xy).rgb); +#endif +} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos) +{ + pos = pos*sourceSize[0].xy; + + return -((pos - floor(pos)) - vec2(0.5)); +} + +// 1D Gaussian. +float Gaus(float pos, float scale) +{ + return exp2(scale*pow(abs(pos), shape)); +} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos, float off) +{ + vec3 b = Fetch(pos, vec2(-1.0, off)); + vec3 c = Fetch(pos, vec2( 0.0, off)); + vec3 d = Fetch(pos, vec2( 1.0, off)); + float dst = Dist(pos).x; + + // Convert distance to weight. + float scale = hardPix; + 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)); + vec3 b = Fetch(pos,vec2(-1.0, off)); + vec3 c = Fetch(pos,vec2( 0.0, off)); + vec3 d = Fetch(pos,vec2( 1.0, off)); + vec3 e = Fetch(pos,vec2( 2.0, off)); + + float dst = Dist(pos).x; + // Convert distance to weight. + float scale = hardPix; + 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); +} + +// 7-tap Gaussian filter along horz line. +vec3 Horz7(vec2 pos,float off) +{ + vec3 a = Fetch(pos, vec2(-3.0, off)); + vec3 b = Fetch(pos, vec2(-2.0, off)); + vec3 c = Fetch(pos, vec2(-1.0, off)); + vec3 d = Fetch(pos, vec2( 0.0, off)); + vec3 e = Fetch(pos, vec2( 1.0, off)); + vec3 f = Fetch(pos, vec2( 2.0, off)); + vec3 g = Fetch(pos, vec2( 3.0, off)); + + float dst = Dist(pos).x; + // Convert distance to weight. + float scale = hardBloomPix; + float wa = Gaus(dst - 3.0, scale); + float wb = Gaus(dst - 2.0, scale); + float wc = Gaus(dst - 1.0, scale); + float wd = Gaus(dst + 0.0, scale); + float we = Gaus(dst + 1.0, scale); + float wf = Gaus(dst + 2.0, scale); + float wg = Gaus(dst + 3.0, scale); + + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we+f*wf+g*wg)/(wa+wb+wc+wd+we+wf+wg); +} + +// Return scanline weight. +float Scan(vec2 pos, float off) +{ + float dst = Dist(pos).y; + + return Gaus(dst + off, hardScan); +} + +// Return scanline weight for bloom. +float BloomScan(vec2 pos, float off) +{ + float dst = Dist(pos).y; + + return Gaus(dst + off, hardBloomScan); +} + +// 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; +} + +// Small bloom. +vec3 Bloom(vec2 pos) +{ + vec3 a = Horz5(pos,-2.0); + vec3 b = Horz7(pos,-1.0); + vec3 c = Horz7(pos, 0.0); + vec3 d = Horz7(pos, 1.0); + vec3 e = Horz5(pos, 2.0); + + float wa = BloomScan(pos,-2.0); + float wb = BloomScan(pos,-1.0); + float wc = BloomScan(pos, 0.0); + float wd = BloomScan(pos, 1.0); + float we = BloomScan(pos, 2.0); + + return a*wa+b*wb+c*wc+d*wd+e*we; +} + +// 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)*warpX, 1.0 + (pos.x*pos.x)*warpY); + + return pos*0.5 + 0.5; +} + +// Shadow mask. +vec3 Mask(vec2 pos) +{ + vec3 mask = vec3(maskDark, maskDark, maskDark); + + // Very compressed TV style shadow mask. + if (shadowMask == 1.0) + { + float line = maskLight; + float odd = 0.0; + + if (fract(pos.x*0.166666666) < 0.5) odd = 1.0; + if (fract((pos.y + odd) * 0.5) < 0.5) line = maskDark; + + pos.x = fract(pos.x*0.333333333); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + mask*=line; + } + + // Aperture-grille. + else if (shadowMask == 2.0) + { + pos.x = fract(pos.x*0.333333333); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + // Stretched VGA style shadow mask (same as prior shaders). + else if (shadowMask == 3.0) + { + pos.x += pos.y*3.0; + pos.x = fract(pos.x*0.166666666); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + // VGA style shadow mask. + else if (shadowMask == 4.0) + { + pos.xy = floor(pos.xy*vec2(1.0, 0.5)); + pos.x += pos.y*3.0; + pos.x = fract(pos.x*0.166666666); + + if (pos.x < 0.333) mask.r = maskLight; + else if (pos.x < 0.666) mask.g = maskLight; + else mask.b = maskLight; + } + + return mask; +} + +void main() { + vec2 pos = Warp(vTexCoord); + vec3 outColor = Tri(pos).rgb; + + if (shadowMask > 0.0) + outColor.rgb *= Mask(vTexCoord.xy * outputSize.xy * 1.000001); +#ifdef DO_BLOOM + //Add Bloom + outColor.rgb += mix( vec3(0.0), texture(source[0], pos).rgb, bloomAmount); +#endif + + FragColor = vec4(ToSrgb(outColor.rgb), 1.0); +} \ No newline at end of file diff --git a/shaders/CRT-Lottes.shader/scanpass.vs b/shaders/CRT-Lottes.shader/scanpass.vs new file mode 100644 index 00000000..d95f0fcd --- /dev/null +++ b/shaders/CRT-Lottes.shader/scanpass.vs @@ -0,0 +1,15 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/GTU.shader/GTU-pass1.fs b/shaders/GTU.shader/GTU-pass1.fs new file mode 100644 index 00000000..53707f3a --- /dev/null +++ b/shaders/GTU.shader/GTU-pass1.fs @@ -0,0 +1,52 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + + +#define RGB_to_YIQ mat3x3( 0.299 , 0.595716 , 0.211456 , 0.587 , -0.274453 , -0.522591 , 0.114 , -0.321263 , 0.311135 ) +#define YIQ_to_RGB mat3x3( 1.0 , 1.0 , 1.0 , 0.9563 , -0.2721 , -1.1070 , 0.6210 , -0.6474 , 1.7046 ) +#define LEVELS(C) clamp((C -16/ 255.0)*255.0/(235.0-16.0),0.0,1.0) + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; +out vec4 fragColor; + + +void main() { + vec3 c=texture2D(source[0], texCoord.xy).xyz; +#ifdef TV_COLOR_LEVELS + c=LEVELS(c); +#endif +#ifdef COMPOSITE_CONNECTION + c=RGB_to_YIQ*c; +#endif + fragColor = vec4(c, 1.0); +} diff --git a/shaders/GTU.shader/GTU-pass2.fs b/shaders/GTU.shader/GTU-pass2.fs new file mode 100644 index 00000000..40c7c531 --- /dev/null +++ b/shaders/GTU.shader/GTU-pass2.fs @@ -0,0 +1,77 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + + + +#define YIQ_to_RGB mat3x3( 1.0 , 1.0 , 1.0 , 0.9563 , -0.2721 , -1.1070 , 0.6210 , -0.6474 , 1.7046 ) + + + + +#define pi 3.14159265358 +#define a(x) abs(x) +#define d(x,b) (pi*b*min(a(x)+0.5,1.0/b)) +#define e(x,b) (pi*b*min(max(a(x)-0.5,-1.0/b),1.0/b)) +#define STU(x,b) ((d(x,b)+sin(d(x,b))-e(x,b)-sin(e(x,b)))/(2.0*pi)) +#define X(i) (offset-(i)) + +#define GETC (texture(source[0], vec2(texCoord.x - X*sourceSize[0].z,texCoord.y)).xyz) + +#ifdef COMPOSITE_CONNECTION +#define VAL vec3((c.x*STU(X,(SIGNAL_RESOLUTION*sourceSize[0].z))),(c.y*STU(X,(SIGNAL_RESOLUTION_I*sourceSize[0].z))),(c.z*STU(X,(SIGNAL_RESOLUTION_Q*sourceSize[0].z)))) +#else +#define VAL (c*STU(X,(SIGNAL_RESOLUTION*sourceSize[0].z))) +#endif //COMPOSITE_CONNECTION + +#define PROCESS(i) X=X(i);c=GETC;tempColor+=VAL; + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; +out vec4 fragColor; + + +void main() { + + float offset = fract((texCoord.x * sourceSize[0].x) - 0.5); + vec3 tempColor = vec3(0.0); + float X; + vec3 c; + PROCESS(-6)PROCESS(-5)PROCESS(-4)PROCESS(-3)PROCESS(-2)PROCESS(-1)PROCESS( 0) + PROCESS( 7)PROCESS( 6)PROCESS( 5)PROCESS( 4)PROCESS( 3)PROCESS( 2)PROCESS( 1) + + +#ifdef COMPOSITE_CONNECTION + tempColor=clamp(YIQ_to_RGB*tempColor,0.0,1.0); +#endif + tempColor=clamp(pow(tempColor,vec3(TV_DISPLAY_GAMMA)),0.0,1.0); + fragColor = vec4(tempColor,1.0); +} diff --git a/shaders/GTU.shader/GTU-pass2.vs b/shaders/GTU.shader/GTU-pass2.vs new file mode 100644 index 00000000..22981154 --- /dev/null +++ b/shaders/GTU.shader/GTU-pass2.vs @@ -0,0 +1,46 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + +in vec4 position; +in vec2 texCoord; + +out Vertex{ + vec2 texCoord; +}vertexOut; + +void main(void){ + +#ifdef CROP_OVERSCAN + gl_Position=position; + gl_Position.x/=(224.0/240.0); +#else + gl_Position=position; +#endif + + vertexOut.texCoord=texCoord; +} diff --git a/shaders/GTU.shader/GTU-pass3.fs b/shaders/GTU.shader/GTU-pass3.fs new file mode 100644 index 00000000..582fc20f --- /dev/null +++ b/shaders/GTU.shader/GTU-pass3.fs @@ -0,0 +1,63 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + + + +#define pi 3.14159265358 +#define a(x) abs(x) +#define d(x,b) (pi*b*min(a(x)+0.5,1.0/b)) +#define e(x,b) (pi*b*min(max(a(x)-0.5,-1.0/b),1.0/b)) +#define STU(x,b) ((d(x,b)+sin(d(x,b))-e(x,b)-sin(e(x,b)))/(2.0*pi)) +#define X(i) (offset-(i)) + +#define GETC (texture(source[0], vec2(texCoord.x - X*sourceSize[0].z,texCoord.y)).xyz) +#define VAL (c*STU(X,(TV_HORIZONTAL_RESOLUTION*sourceSize[0].z))) + +#define PROCESS(i) X=X(i);c=GETC;tempColor+=VAL; + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; +out vec4 fragColor; + + +void main() { + + float offset = fract((texCoord.x * sourceSize[0].x) - 0.5); + vec3 tempColor = vec3(0.0); + float X; + vec3 c; + PROCESS(-6)PROCESS(-5)PROCESS(-4)PROCESS(-3)PROCESS(-2)PROCESS(-1)PROCESS( 0) + PROCESS( 7)PROCESS( 6)PROCESS( 5)PROCESS( 4)PROCESS( 3)PROCESS( 2)PROCESS( 1) + + // tempColor=pow(tempColor,vec3(1.0/2.2)); + fragColor = vec4(tempColor,1.0); +} diff --git a/shaders/GTU.shader/GTU-pass4.fs b/shaders/GTU.shader/GTU-pass4.fs new file mode 100644 index 00000000..d26bbf1d --- /dev/null +++ b/shaders/GTU.shader/GTU-pass4.fs @@ -0,0 +1,78 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + + + +#define SCANLINE_WIDTH (1.5*sourceSize[0].y/TV_VERTICAL_RESOLUTION) + +uniform sampler2D source[]; +uniform sampler2D texture[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; +out vec4 fragColor; + + +#define GAMMAOUT(c0) (pow(c0, vec3(1.0/OUTPUTG2))) +#define pi 3.14159265358 +#define GAUSS(x,w) ((sqrt(2.0) / (w)) * (exp((-2.0 * pi * (x) * (x)) / ((w) * (w))))) +#define Y(j) (offset.y-(j)) +#define a(x) abs(x) +#define d(x,b) (pi*b*min(a(x)+0.5,1.0/b)) +#define e(x,b) (pi*b*min(max(a(x)-0.5,-1.0/b),1.0/b)) +#define STU(x,b) ((d(x,b)+sin(d(x,b))-e(x,b)-sin(e(x,b)))/(2.0*pi)) + +#define SOURCE(j) vec2(texCoord.x,texCoord.y - Y(j)*sourceSize[0].w) +#define C(j) (texture2D(source[0], SOURCE(j)).xyz) + +#ifdef NO_SCANLINES +#define VAL(j) (C(j)*STU(Y(j),(TV_VERTICAL_RESOLUTION*sourceSize[0].w))) +#else +#define VAL(j) (C(j)*GAUSS(Y(j),SCANLINE_WIDTH)) +#endif + + + +void main() { + + vec2 offset = fract((texCoord.xy * sourceSize[0].xy) - 0.5); + vec3 tempColor = vec3(0.0); + + tempColor+=VAL(-3.0); + tempColor+=VAL(-2.0); + tempColor+=VAL(-1.0); + tempColor+=VAL(0.0); + tempColor+=VAL(1.0); + tempColor+=VAL(2.0); + tempColor+=VAL(3.0); + tempColor+=VAL(4.0); + + fragColor = vec4(pow(tempColor,vec3(1.0/OUTPUT_DISPLAY_GAMMA)), 1.0); +} \ No newline at end of file diff --git a/shaders/GTU.shader/GTU-pass4.vs b/shaders/GTU.shader/GTU-pass4.vs new file mode 100644 index 00000000..1d0270f3 --- /dev/null +++ b/shaders/GTU.shader/GTU-pass4.vs @@ -0,0 +1,46 @@ +#version 150 + +//////////////////////////////////////////////////////// +// GTU version 0.40 +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// SETTINGS +//////////////////////////////////////////////////////// + +//#define CROP_OVERSCAN +#define TV_COLOR_LEVELS +//#define COMPOSITE_CONNECTION +//#define NO_SCANLINES +#define TV_HORIZONTAL_RESOLUTION 400.0 +#define TV_VERTICAL_RESOLUTION 300.0 +#define SIGNAL_RESOLUTION 280.0 +#define SIGNAL_RESOLUTION_I 83.0 +#define SIGNAL_RESOLUTION_Q 25.0 +#define TV_DISPLAY_GAMMA 2.4 +#define OUTPUT_DISPLAY_GAMMA 2.2 + +//////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////// + +in vec4 position; +in vec2 texCoord; + +out Vertex{ + vec2 texCoord; +}vertexOut; + +void main(void){ + +#ifdef CROP_OVERSCAN + gl_Position=position; + gl_Position.y/=(224.0/240.0); +#else + gl_Position=position; +#endif + + vertexOut.texCoord=texCoord; +} diff --git a/shaders/GTU.shader/manifest.bml b/shaders/GTU.shader/manifest.bml new file mode 100644 index 00000000..23c46cfb --- /dev/null +++ b/shaders/GTU.shader/manifest.bml @@ -0,0 +1,28 @@ +program + width: 100% + height: 100% + format: rgba32f + filter: nearest + wrap: edge + fragment: GTU-pass1.fs +program + height: 100% + format: rgba32f + filter: nearest + wrap: edge + vertex: GTU-pass2.vs + fragment: GTU-pass2.fs +program + height: 100% + format: rgba32f + filter: nearest + wrap: edge + fragment: GTU-pass3.fs +program + format: rgba8 + filter: nearest + wrap: edge + vertex: GTU-pass4.vs + fragment: GTU-pass4.fs +output + filter: nearest \ No newline at end of file diff --git a/shaders/LCD-cgwg.shader/lcd-grid.fs b/shaders/LCD-cgwg.shader/lcd-grid.fs new file mode 100644 index 00000000..930c43c0 --- /dev/null +++ b/shaders/LCD-cgwg.shader/lcd-grid.fs @@ -0,0 +1,88 @@ +#version 150 + +#in red +#in green +#in blue +#in gain +#in gamma +#in blacklevel +#in ambient +#in BGR + +#define outgamma 2.2 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define fetch_offset(coord,offset) (pow(vec3(gain) * texelFetchOffset(source[0], (coord), 0, (offset)).rgb + vec3(blacklevel), vec3(gamma)) + vec3(ambient)) + +// integral of (1 - x^2 - x^4 + x^6)^2 +const float coeffs_x[] = float[](1.0, -2.0/3.0, -1.0/5.0, 4.0/7.0, -1.0/9.0, -2.0/11.0, 1.0/13.0); +// integral of (1 - 2x^4 + x^6)^2 +const float coeffs_y[] = float[](1.0, 0.0, -4.0/5.0, 2.0/7.0, 4.0/9.0, -4.0/11.0, 1.0/13.0); +float intsmear_func(float z, float coeffs[7]) +{ + float z2 = z*z; + float zn = z; + float ret = 0.0; + for (int i = 0; i < 7; i++) { + ret += zn*coeffs[i]; + zn *= z2; + } + return ret; +} +float intsmear(float x, float dx, float d, float coeffs[7]) +{ + float zl = clamp((x-dx*0.5)/d,-1.0,1.0); + float zh = clamp((x+dx*0.5)/d,-1.0,1.0); + return d * ( intsmear_func(zh,coeffs) - intsmear_func(zl,coeffs) )/dx; +} + +void main() +{ + vec2 texelSize = 1.0 / sourceSize[0].xy; + vec2 range = sourceSize[0].xy / (targetSize.xy * sourceSize[0].xy); + + vec3 cred = pow(red, vec3(outgamma)); + vec3 cgreen = pow(green, vec3(outgamma)); + vec3 cblue = pow(blue, vec3(outgamma)); + + ivec2 tli = ivec2(floor(texCoord/texelSize-vec2(0.4999))); + + vec3 lcol, rcol; + float subpix = (texCoord.x/texelSize.x - 0.4999 - float(tli.x))*3.0; + float rsubpix = range.x/texelSize.x * 3.0; + lcol = vec3(intsmear(subpix+1.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix ,rsubpix, 1.5, coeffs_x), + intsmear(subpix-1.0,rsubpix, 1.5, coeffs_x)); + rcol = vec3(intsmear(subpix-2.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix-3.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix-4.0,rsubpix, 1.5, coeffs_x)); +#ifdef BGR + lcol.rgb = lcol.bgr; + rcol.rgb = rcol.bgr; +#endif + float tcol, bcol; + subpix = texCoord.y/texelSize.y - 0.4999 - float(tli.y); + rsubpix = range.y/texelSize.y; + tcol = intsmear(subpix ,rsubpix, 0.63, coeffs_y); + bcol = intsmear(subpix-1.0,rsubpix, 0.63, coeffs_y); + + vec3 topLeftColor = fetch_offset(tli, ivec2(0,0)) * lcol * vec3(tcol); + vec3 bottomRightColor = fetch_offset(tli, ivec2(1,1)) * rcol * vec3(bcol); + vec3 bottomLeftColor = fetch_offset(tli, ivec2(0,1)) * lcol * vec3(bcol); + vec3 topRightColor = fetch_offset(tli, ivec2(1,0)) * rcol * vec3(tcol); + + vec3 averageColor = topLeftColor + bottomRightColor + bottomLeftColor + topRightColor; + + averageColor = mat3x3(cred, cgreen, cblue) * averageColor; + + fragColor = vec4(pow(averageColor,vec3(1.0/outgamma)),0.0); +} diff --git a/shaders/LCD-cgwg.shader/manifest.bml b/shaders/LCD-cgwg.shader/manifest.bml new file mode 100644 index 00000000..b908e2f3 --- /dev/null +++ b/shaders/LCD-cgwg.shader/manifest.bml @@ -0,0 +1,23 @@ +settings + persistence: 0.5 + red: vec3(1,0,0) + green: vec3(0,1,0) + blue: vec3(0,0,1) + gain: 1.0 + gamma: 3.0 + blacklevel: 0.05 + ambient: 0.0 + BGR + +input + history: 8 + filter: nearest + +program + fragment: motion-blur.fs + filter: nearest + width: 100% + height: 100% + +program + fragment: lcd-grid.fs \ No newline at end of file diff --git a/shaders/LCD-cgwg.shader/motion-blur.fs b/shaders/LCD-cgwg.shader/motion-blur.fs new file mode 100644 index 00000000..cd439ab2 --- /dev/null +++ b/shaders/LCD-cgwg.shader/motion-blur.fs @@ -0,0 +1,23 @@ +#version 150 + +uniform sampler2D source[]; +uniform sampler2D history[]; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +void main() { + vec4 color = pow(texture(history[7], texCoord).rgba, vec4(2.2)); + color = (color + pow(texture(history[6], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[5], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[4], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[3], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[2], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[1], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(history[0], texCoord).rgba, vec4(2.2))) / 2.0; + color = (color + pow(texture(source[0], texCoord).rgba, vec4(2.2))) / 2.0; + fragColor = pow(color, vec4(1.0 / 2.2)); +} \ No newline at end of file diff --git a/shaders/MDAPT-Dedithering.shader/manifest.bml b/shaders/MDAPT-Dedithering.shader/manifest.bml new file mode 100644 index 00000000..06fc8373 --- /dev/null +++ b/shaders/MDAPT-Dedithering.shader/manifest.bml @@ -0,0 +1,24 @@ +program + width: 100% + height: 100% + filter: nearest + fragment: mdapt-pass1.fs + wrap: edge +program + width: 100% + height: 100% + filter: nearest + fragment: mdapt-pass2.fs + wrap: edge +program + width: 100% + height: 100% + filter: nearest + fragment: mdapt-pass3.fs + wrap: edge +program + width: 100% + height: 100% + filter: nearest + fragment: mdapt-pass4.fs + wrap: edge \ No newline at end of file diff --git a/shaders/MDAPT-Dedithering.shader/mdapt-pass1.fs b/shaders/MDAPT-Dedithering.shader/mdapt-pass1.fs new file mode 100644 index 00000000..0a9ee787 --- /dev/null +++ b/shaders/MDAPT-Dedithering.shader/mdapt-pass1.fs @@ -0,0 +1,200 @@ +// This is a port of the original CG shader to the quark format +// the original shader can be found here : +// https://github.com/libretro/common-shaders/tree/master/dithering/mdapt-4p + +/* + Merge Dithering and Pseudo Transparency Shader v1.5 - Pass 1 + by Sp00kyFox, 2013 + + Finds specific patterns and tags their central pixel. + +*/ +#version 150 +//#define HORI +//#define VERT +#define dtt vec3(65536,255,1) +#define eq_threshold 5.0 + + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +in Vertex{ + vec2 texCoord; +}; + +out vec4 fragColor; + +float reduce(vec3 color) +{ + return dot(color, dtt); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (A == B); +} + +float remapTo01(float v, float low, float high) +{ + return clamp((v - low)/(high-low),0.0,1.0); +} + + +void main(void) { + vec2 pos = texCoord*sourceSize[0].xy; // pos = pixel position + vec2 dir = sign(pos); // dir = pixel direction + + vec2 g1 = dir*vec2(sourceSize[0].z,0.0); + vec2 g2 = dir*vec2(0.0,sourceSize[0].w);; + + /* + U3 + UUL U2 UUR + ULL UL U1 UR URR + L3 L2 L1 C R1 R2 R3 + DLL DL D1 DR DRR + DDL D2 DDR + D3 + */ + + vec3 c = texture(source[0], texCoord).xyz; + vec3 l1 = texture(source[0], texCoord - g1).xyz; + vec3 l2 = texture(source[0], texCoord - 2*g1).xyz; + vec3 r1 = texture(source[0], texCoord + g1).xyz; + vec3 r2 = texture(source[0], texCoord + 2*g1).xyz; + vec3 u1 = texture(source[0], texCoord - g2).xyz; + vec3 u2 = texture(source[0], texCoord - 2*g2).xyz; + vec3 d1 = texture(source[0], texCoord + g2).xyz; + vec3 d2 = texture(source[0], texCoord + 2*g2).xyz; + vec3 ul = texture(source[0], texCoord - g1 - g2).xyz; + vec3 ur = texture(source[0], texCoord + g1 - g2).xyz; + vec3 dl = texture(source[0], texCoord - g1 + g2).xyz; + vec3 dr = texture(source[0], texCoord + g1 + g2).xyz; + + vec3 ull = texture(source[0], texCoord - 2*g1 - g2).xyz; + vec3 uul = texture(source[0], texCoord - g1 - 2*g2).xyz; + vec3 uur = texture(source[0], texCoord + g1 - 2*g2).xyz; + vec3 urr = texture(source[0], texCoord + 2*g1 - g2).xyz; + vec3 drr = texture(source[0], texCoord + 2*g1 + g2).xyz; + vec3 ddr = texture(source[0], texCoord + g1 + 2*g2).xyz; + vec3 ddl = texture(source[0], texCoord - g1 + 2*g2).xyz; + vec3 dll = texture(source[0], texCoord - 2*g1 + g2).xyz; + + vec3 l3 = texture(source[0], texCoord - 3*g1).xyz; + vec3 r3 = texture(source[0], texCoord + 3*g1).xyz; + vec3 u3 = texture(source[0], texCoord - 3*g2).xyz; + vec3 d3 = texture(source[0], texCoord + 3*g2).xyz; + + float C = reduce( c ); + + float L1 = reduce( l1 ); float U1 = reduce( u1 ); + float L2 = reduce( l2 ); float U2 = reduce( u2 ); + float R1 = reduce( r1 ); float D1 = reduce( d1 ); + float R2 = reduce( r2 ); float D2 = reduce( d2 ); + + float UL = reduce( ul ); float L3 = reduce( l3 ); + float UR = reduce( ur ); float R3 = reduce( r3 ); + float DL = reduce( dl ); float U3 = reduce( u3 ); + float DR = reduce( dr ); float D3 = reduce( d3 ); + + float ULL = reduce( ull ); float DRR = reduce( drr ); + float UUL = reduce( uul ); float DDR = reduce( ddr ); + float UUR = reduce( uur ); float DDL = reduce( ddl ); + float URR = reduce( urr ); float DLL = reduce( dll ); + + /* + tag values: + 0 nothing + + checkerboard pattern + 9 DL + 8 DR + 7 UR + 6 UL + 5 full + + horizontal two-line checkerboard + 4 bottom line + 3 upper line + + vertical two-line checkerboard + 2 left line + 1 right line + + one line dither + -1 horizontal + -2 vertical + */ + + float type=0; + + // checkerboard pattern + if(!eq(C,D1) && !eq(C,U1) && !eq(C,L1) && !eq(C,R1)) + { + if(eq(C,UL)) + { + if(eq(C,UR)) + { + if(eq(C,DR)) + { + if(eq(C,DL)) + type = 5; + else if(!eq(D1,L1) || eq(D1,DL)) + type = 9; + } + else + { + if(eq(C,DL) && (!eq(D1,R1) || eq(D1,DR))) + type = 8; + } + } + else + { + if(eq(C,DR) && eq(C,DL) && (!eq(U1,R1) || eq(U1,UR))) + type = 7; + } + } + else if(eq(C,UR) && eq(C,DR) && eq(C,DL) && (!eq(U1,L1) || eq(U1,UL))) + type = 6; + } + // horizontal two-line checkerboard + else if(eq(C,L2) && eq(C,R2) && eq(C,UL) && eq(C,UR) && !eq(C,L1) && !eq(C,R1) && !eq(C,ULL) && !eq(C,U1) && !eq(C,URR)) + { + type = 4; + } + else if(eq(C,L2) && eq(C,R2) && eq(C,DL) && eq(C,DR) && !eq(C,L1) && !eq(C,R1) && !eq(C,DLL) && !eq(C,D1) && !eq(C,DRR)) + { + type = 3; + } + // vertical two-line checkerboard + else if(eq(C,U2) && eq(C,D2) && eq(C,UR) && eq(C,DR) && !eq(C,U1) && !eq(C,D1) && !eq(C,R1) && !eq(C,UUR) && !eq(C,DDR)) + { + type = 2; + } + else if(eq(C,U2) && eq(C,D2) && eq(C,UL) && eq(C,DL) && !eq(C,U1) && !eq(C,D1) && !eq(C,L1) && !eq(C,UUL) && !eq(C,DDL)) + { + type = 1; + } +#ifdef HORI + // horizontal one line dither + else if(eq(C,L2) && eq(C,R2) && eq(L1,R1) && !eq(C,L1) && !eq(C,L3) && !eq(C,R3)) + type = -1; +#endif +#ifdef VERT + // vertical one line dither + else if(eq(C,U2) && eq(C,D2) && eq(U1,D1) && !eq(C,U1) && !eq(C,U3) && !eq(C,D3)) + type = -2; +#endif + + fragColor=vec4(c, remapTo01(type+2, 0, 15)); + +} + + + diff --git a/shaders/MDAPT-Dedithering.shader/mdapt-pass2.fs b/shaders/MDAPT-Dedithering.shader/mdapt-pass2.fs new file mode 100644 index 00000000..ffdfcfbc --- /dev/null +++ b/shaders/MDAPT-Dedithering.shader/mdapt-pass2.fs @@ -0,0 +1,161 @@ +// This is a port of the original CG shader to the quark format +// the original shader can be found here : +// https://github.com/libretro/common-shaders/tree/master/dithering/mdapt-4p + +/* + Merge Dithering and Pseudo Transparency Shader v1.5 - Pass 1 + by Sp00kyFox, 2013 + + Finds specific patterns and tags their central pixel. + +*/ + +#version 150 +// Radius of the area where the algorithm looks for other detected pixels. +#define rad 2 + +// Minimal count of detection pixels in search area to be rated as valid. +#define minimum 3 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +in Vertex{ + vec2 texCoord; +}; + +out vec4 fragColor; + +float remapTo01(float v, float low, float high) +{ + return clamp((v - low)/(high-low),0.0,1.0); +} + +float remapFrom01(float v, float low, float high) +{ + return round(mix(low, high, v)); +} + +void main(void) { + vec2 pos = texCoord*sourceSize[0].xy; // pos = pixel position + vec2 dir = sign(pos); // dir = pixel direction + + vec2 g1 = dir*vec2(sourceSize[0].z,0.0); + vec2 g2 = dir*vec2(0.0,sourceSize[0].w); + + vec4 CC = texture(source[0], texCoord).xyzw; + + float C = remapFrom01(CC.w, 0, 15) - 2; + + if(C == 0){ + fragColor=CC; + return; + } + + /* + tag values: + 0 nothing + + checkerboard pattern + 9 DL + 8 DR + 7 UR + 6 UL + 5 full + + horizontal two-line checkerboard + 4 bottom line + 3 upper line + + vertical two-line checkerboard + 2 left line + 1 right line + + one line dither + -1 horizontal + -2 vertical + */ + + int hits = 0; + + if(C > 0) + { +// for(int x=-rad; x<=rad; x++) +// { +// for(int y=-rad; y<=rad; y++) +// { +// hits += ((remapFrom01(texture(source[0], texCoord + (x*g1) + (y*g2)).x, 0, 15) - 2) > 0) ? 1 : 0; +// } +// } + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + (-2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + (-1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 0*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + (-2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + (-1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 0*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + (-2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + (-1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 0*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + (-2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + (-1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 0*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + (-2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + (-1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 0*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 1*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 2*g2)).w, 0, 15) - 2) > 0) ? 1 : 0; + } + else + { +// for(int x=-rad; x<=rad; x++) +// { +// for(int y=-rad; y<=rad; y++) +// { +// hits += ((remapFrom01(texture(source[0], texCoord + (x*g1) + (y*g2)).x, 0, 15) - 2) == C) ? 1 : 0; +// } +// } + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + (-2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + (-1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 0*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-2*g1) + ( 2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + (-2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + (-1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 0*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + (-1*g1) + ( 2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + (-2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + (-1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 0*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 0*g1) + ( 2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + (-2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + (-1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 0*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 1*g1) + ( 2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + (-2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + (-1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 0*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 1*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + hits += ((remapFrom01(texture(source[0], texCoord + ( 2*g1) + ( 2*g2)).w, 0, 15) - 2) == C) ? 1 : 0; + fragColor=CC; + return; + } + + if(hits < minimum) + fragColor=vec4(CC.xyz, remapTo01(2, 0, 15)); + else + fragColor=CC; +} + + + diff --git a/shaders/MDAPT-Dedithering.shader/mdapt-pass3.fs b/shaders/MDAPT-Dedithering.shader/mdapt-pass3.fs new file mode 100644 index 00000000..122e7dbb --- /dev/null +++ b/shaders/MDAPT-Dedithering.shader/mdapt-pass3.fs @@ -0,0 +1,175 @@ +// This is a port of the original CG shader to the quark format +// the original shader can be found here : +// https://github.com/libretro/common-shaders/tree/master/dithering/mdapt-4p + +/* + Merge Dithering and Pseudo Transparency Shader v1.5 - Pass 3 + by Sp00kyFox, 2013 + + Tags the rest of the detected pattern from pass 1. + +*/ + +#version 150 +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +in Vertex{ + vec2 texCoord; +}; + +out vec4 fragColor; + +float remapTo01(float v, float low, float high) +{ + return clamp((v - low)/(high-low),0.0,1.0); +} + +float remapFrom01(float v, float low, float high) +{ + return round(mix(low, high, v)); +} +void main(void) { + vec2 pos = texCoord*sourceSize[0].xy; // pos = pixel position + vec2 dir = sign(pos); // dir = pixel direction + + vec2 g1 = dir*vec2(sourceSize[0].z,0.0); + vec2 g2 = dir*vec2(0.0,sourceSize[0].w); + /* + U2 + UL U1 UR + L2 L1 xC R1 R2 + DL D1 DR + D2 + */ + + vec4 xC = texture(source[0], texCoord).xyzw; + vec4 xL1 = texture(source[0], texCoord - g1).xyzw; + vec4 xL2 = texture(source[0], texCoord - 2*g1).xyzw; + vec4 xR1 = texture(source[0], texCoord + g1).xyzw; + vec4 xR2 = texture(source[0], texCoord + 2*g1).xyzw; + vec4 xU1 = texture(source[0], texCoord - g2).xyzw; + vec4 xU2 = texture(source[0], texCoord - 2*g2).xyzw; + vec4 xD1 = texture(source[0], texCoord + g2).xyzw; + vec4 xD2 = texture(source[0], texCoord + 2*g2).xyzw; + vec4 xUL = texture(source[0], texCoord - g1 - g2).xyzw; + vec4 xUR = texture(source[0], texCoord + g1 - g2).xyzw; + vec4 xDL = texture(source[0], texCoord - g1 + g2).xyzw; + vec4 xDR = texture(source[0], texCoord + g1 + g2).xyzw; + + float C = remapFrom01(xC.w, 0, 15) - 2; + float L1 = remapFrom01(xL1.w, 0, 15) - 2; + float L2 = remapFrom01(xL2.w, 0, 15) - 2; + float R1 = remapFrom01(xR1.w, 0, 15) - 2; + float R2 = remapFrom01(xR2.w, 0, 15) - 2; + float U1 = remapFrom01(xU1.w, 0, 15) - 2; + float U2 = remapFrom01(xU2.w, 0, 15) - 2; + float D1 = remapFrom01(xD1.w, 0, 15) - 2; + float D2 = remapFrom01(xD2.w, 0, 15) - 2; + float UL = remapFrom01(xUL.w, 0, 15) - 2; + float UR = remapFrom01(xUR.w, 0, 15) - 2; + float DL = remapFrom01(xDL.w, 0, 15) - 2; + float DR = remapFrom01(xDR.w, 0, 15) - 2; + + /* + tag values: + 0 nothing + + checkerboard pattern + 9 DL + 8 DR + 7 UR + 6 UL + 5 full + + horizontal two-line checkerboard + 4 bottom line + 3 upper line + + vertical two-line checkerboard + 2 left line + 1 right line + + one line dither + -1 horizontal + -2 vertical + */ + + // checkerboard pattern + if(U1 == 5 || D1 == 5 || L1 == 5 || R1 == 5 || UL == 5 || UR == 5 || DR == 5 || DL == 5) + { + fragColor=vec4(xC.xyz, remapTo01(5+2, 0, 15)); + return ; + } + if(U1 == 6 || L1 == 6 || UL == 6 || UR == 6 || DL == 6) // UL + { + fragColor=vec4(xC.xyz, remapTo01(6+2, 0, 15)); + return ; + } + + if(U1 == 7 || R1 == 7 || UL == 7 || UR == 7 || DR == 7) // UR + { + fragColor=vec4(xC.xyz, remapTo01(7+2, 0, 15)); + return ; + } + + if(D1 == 8 || R1 == 8 || UR == 8 || DR == 8 || DL == 8) // DR + { + fragColor=vec4(xC.xyz, remapTo01(8+2, 0, 15)); + return ; + } + + if(D1 == 9 || L1 == 9 || UL == 9 || DR == 9 || DL == 9) // DL + { + fragColor=vec4(xC.xyz, remapTo01(9+2, 0, 15)); + return ; + } + + // horizontal two-line checkerboard + if (L2 == 4 || L1 == 4 || R1 == 4 || R2 == 4 || DL == 4 || D1 == 4 || DR == 4) + { + fragColor=vec4(xC.xyz, remapTo01(4+2, 0, 15)); + return ; + } + if (L2 == 3 || L1 == 3 || R1 == 3 || R2 == 3 || UL == 3 || U1 == 3 || UR == 3) + { + fragColor=vec4(xC.xyz, remapTo01(3+2, 0, 15)); + return ; + } + + // vertical two-line checkerboard + if (U2 == 2 || U1 == 2 || D1 == 2 || D2 == 2 || UL == 2 || L1 == 2 || DL == 2) + { + fragColor=vec4(xC.xyz, remapTo01(2+2, 0, 15)); + return ; + } + if (U2 == 1 || U1 == 1 || D1 == 1 || D2 == 1 || UR == 1 || R1 == 1 || DR == 1) + { + fragColor=vec4(xC.xyz, remapTo01(1+2, 0, 15)); + return ; + } + + if(C > 0){ + fragColor=xC; + return ; + } + + // horizontal one line dither + if (L2 == -1 || L1 == -1 || R1 == -1 || R2 == -1) + { + fragColor=vec4(xC.xyz, remapTo01(-1+2, 0, 15)); + return ; + } + + // vertical one line dither + if (U2 == -2 || U1 == -2 || D1 == -2 || D2 == -2) + { + fragColor=vec4(xC.xyz, remapTo01(-2+2, 0, 15)); + return; + } + + fragColor=xC; +} + + + diff --git a/shaders/MDAPT-Dedithering.shader/mdapt-pass4.fs b/shaders/MDAPT-Dedithering.shader/mdapt-pass4.fs new file mode 100644 index 00000000..9a0d79ef --- /dev/null +++ b/shaders/MDAPT-Dedithering.shader/mdapt-pass4.fs @@ -0,0 +1,192 @@ +// This is a port of the original CG shader to the quark format +// the original shader can be found here : +// https://github.com/libretro/common-shaders/tree/master/dithering/mdapt-4p + +/* + Merge Dithering and Pseudo Transparency Shader v1.5 - Pass 4 + by Sp00kyFox, 2013 + + Blends tagged pixels with tagged neighbors. + +*/ + +#version 150 +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +in Vertex{ + vec2 texCoord; +}; + +out vec4 fragColor; + +bool eq(vec4 A, vec4 B) +{ + return (A.x == B.x && A.y == B.y && A.z == B.z); +} + +float remapFrom01(float v, float low, float high) +{ + return round(mix(low, high, v)); +} + + +vec3 merge3(vec4 C, vec4 A, vec4 B, float tag) +{ + if(A.w == tag) + { + if(B.w == tag) + return 0.5*C.xyz + 0.25*(A.xyz + B.xyz); + else + return 0.5*(C.xyz + A.xyz); + } + else if(B.w == tag) + return 0.5*(C.xyz + B.xyz); + else + return C.xyz; +} + +vec3 merge9(vec4 C, vec4 UL, vec4 UR, vec4 DL, vec4 DR, vec4 U1, vec4 D1, vec4 L1, vec4 R1) +{ + //return 0.25*C.xyz + 0.0625*(UL.xyz + UR.xyz + DR.xyz + DL.xyz) + 0.125*(L1.xyz + R1.xyz + D1.xyz + U1.xyz); + + vec3 B = vec3(0.0); + vec3 W = vec3(0.0); + float cntB = 0; + float cntW = 0; + + if(UL.w > 0 || eq(UL,C) || (D1.w > 0 && eq(UL,D1)) || (R1.w > 0 && eq(UL,R1)) ) + { + B = B+UL.xyz; + cntB++; + } + if(UR.w > 0 || eq(UR,C) || (D1.w > 0 && eq(UR,D1)) || (L1.w > 0 && eq(UR,L1)) ) + { + B = B+UR.xyz; + cntB++; + } + if(DL.w > 0 || eq(DL,C) || (U1.w > 0 && eq(DL,U1)) || (R1.w > 0 && eq(DL,R1)) ) + { + B = B+DL.xyz; + cntB++; + } + if(DR.w > 0 || eq(DR,C) || (U1.w > 0 && eq(DR,U1)) || (L1.w > 0 && eq(DR,L1)) ) + { + B = B+DR.xyz; + cntB++; + } + if(U1.w > 0 || eq(U1,C) || (D1.w > 0 && eq(U1,D1)) ) + { + W = W+U1.xyz; + cntW++; + } + if(D1.w > 0 || eq(D1,C) || (U1.w > 0 && eq(D1,U1)) ) + { + W = W+D1.xyz; + cntW++; + } + if(L1.w > 0 || eq(L1,C) || (R1.w > 0 && eq(L1,R1)) ) + { + W = W+L1.xyz; + cntW++; + } + if(R1.w > 0 || eq(R1,C) || (L1.w > 0 && eq(R1,L1)) ) + { + W = W+R1.xyz; + cntW++; + } + + if(cntB == 0) + { + if(cntW == 0) + return C.xyz; + else + return 0.5*C.xyz + (1/(cntW*2))*W; + } + if(cntW == 0) + return 0.5*C.xyz + (1/(cntB*2))*B; + else + return 0.25*C.xyz + (1/(cntB*4))*B + (1/(cntW*2))*W; +} +void main(void) { + vec2 pos = texCoord*sourceSize[0].xy; // pos = pixel position + vec2 dir = sign(pos); // dir = pixel direction + + vec2 g1 = dir*vec2(sourceSize[0].z,0.0); + vec2 g2 = dir*vec2(0.0,sourceSize[0].w); + + /* + UL U1 UR + L1 C R1 + DL D1 DR + */ + + vec4 C = texture(source[0], texCoord).xyzw; + vec4 L1 = texture(source[0], texCoord - g1).xyzw; + vec4 R1 = texture(source[0], texCoord + g1).xyzw; + vec4 U1 = texture(source[0], texCoord - g2).xyzw; + vec4 D1 = texture(source[0], texCoord + g2).xyzw; + vec4 UL = texture(source[0], texCoord - g1 - g2).xyzw; + vec4 UR = texture(source[0], texCoord + g1 - g2).xyzw; + vec4 DL = texture(source[0], texCoord - g1 + g2).xyzw; + vec4 DR = texture(source[0], texCoord + g1 + g2).xyzw; + + + C.w = remapFrom01(C.w, 0, 15) - 2; + L1.w = remapFrom01(L1.w, 0, 15) - 2; + R1.w = remapFrom01(R1.w, 0, 15) - 2; + U1.w = remapFrom01(U1.w, 0, 15) - 2; + D1.w = remapFrom01(D1.w, 0, 15) - 2; + UL.w = remapFrom01(UL.w, 0, 15) - 2; + UR.w = remapFrom01(UR.w, 0, 15) - 2; + DL.w = remapFrom01(DL.w, 0, 15) - 2; + DR.w = remapFrom01(DR.w, 0, 15) - 2; + + /* + tag values: + 0 nothing + + checkerboard pattern + 9 DL + 8 DR + 7 UR + 6 UL + 5 full + + horizontal two-line checkerboard + 4 bottom line + 3 upper line + + vertical two-line checkerboard + 2 left line + 1 right line + + one line dither + -1 horizontal + -2 vertical + */ + + + // checkerboard pattern + if(C.w > 0){ + fragColor=vec4(merge9(C,UL,UR,DL,DR,U1,D1,L1,R1),0); + return; + } + // horizontal one line dither + if(C.w == -1){ + fragColor=vec4(merge3(C,L1,R1,-1),0); + return; + } + + // vertical one line dither + if(C.w == -2){ + fragColor=vec4(merge3(C,U1,D1,-2),0); + return; + } + + fragColor=vec4(C.xyz, 1.0); + +} + + + diff --git a/shaders/NTSC-MAME.shader/mame-ntsc.fs b/shaders/NTSC-MAME.shader/mame-ntsc.fs new file mode 100644 index 00000000..13f182cd --- /dev/null +++ b/shaders/NTSC-MAME.shader/mame-ntsc.fs @@ -0,0 +1,229 @@ +#version 150 + +// This is a port of the NTSC encode/decode shader pair in MAME and MESS, modified to use only +// one pass rather than an encode pass and a decode pass. It accurately emulates the sort of +// signal decimation one would see when viewing a composite signal, though it could benefit from a +// pre-pass to re-size the input content to more accurately reflect the actual size that would +// be incoming from a composite signal source. +// +// To encode the composite signal, I convert the RGB value to YIQ, then subsequently evaluate +// the standard NTSC composite equation. Four composite samples per RGB pixel are generated from +// the incoming linearly-interpolated texels. +// +// The decode pass implements a Fixed Impulse Response (FIR) filter designed by MAME/MESS contributor +// "austere" in matlab (if memory serves correctly) to mimic the behavior of a standard television set +// as closely as possible. The filter window is 83 composite samples wide, and there is an additional +// notch filter pass on the luminance (Y) values in order to strip the color signal from the luminance +// signal prior to processing. +// +// Yes, this code could greatly use some cleaning up. + +// ported from UltraMoogleMan's "Full MAME/MESS Shader Pipe" shadertoy: https://www.shadertoy.com/view/ldf3Rf +// license: presumably MAME's license at the time, which was noncommercial + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// Useful Constants +const vec4 Zero = vec4(0.0); +const vec4 Half = vec4(0.5); +const vec4 One = vec4(1.0); +const vec4 Two = vec4(2.0); +const vec3 Gray = vec3(0.3, 0.59, 0.11); +const float Pi = 3.1415926535; +const float Pi2 = 6.283185307; + +// NTSC Constants +const vec4 A = vec4(0.5); +const vec4 A2 = vec4(1.0); +const vec4 B = vec4(0.5); +const float P = 1.0; +const float CCFrequency = 3.59754545; +const float NotchUpperFrequency = 5.59754545; //3.59754545 + 2.0; +const float NotchLowerFrequency = 1.59754545; //3.59754545 - 2.0; +const float YFrequency = 6.0; +const float IFrequency = 1.2; +const float QFrequency = 0.6; +const float NotchHalfWidth = 2.0; +const float ScanTime = 52.6; +const float Pi2ScanTime = 330.4955471482;// 6.283185307 * 52.6; +const float MaxC = 2.1183; +const vec4 YTransform = vec4(0.299, 0.587, 0.114, 0.0); +const vec4 ITransform = vec4(0.595716, -0.274453, -0.321263, 0.0); +const vec4 QTransform = vec4(0.211456, -0.522591, 0.311135, 0.0); +const vec3 YIQ2R = vec3(1.0, 0.956, 0.621); +const vec3 YIQ2G = vec3(1.0, -0.272, -0.647); +const vec3 YIQ2B = vec3(1.0, -1.106, 1.703); +const vec4 MinC = vec4(-1.1183); +const vec4 CRange = vec4(3.2366); +const vec4 InvCRange = vec4(1.0/3.2366); +const float Pi2Length = Pi2 / 63.0; +const vec4 NotchOffset = vec4(0.0, 1.0, 2.0, 3.0); +vec4 W = vec4(Pi2 * CCFrequency * ScanTime); + +// Color Convolution Constants +const vec3 RedMatrix = vec3(1.0, 0.0, 0.0); +const vec3 GrnMatrix = vec3(0.0, 1.0, 0.0); +const vec3 BluMatrix = vec3(0.0, 0.0, 1.0); +const vec3 DCOffset = vec3(0.0, 0.0, 0.0); +const vec3 ColorScale = vec3(0.95, 0.95, 0.95); +const float Saturation = 1.4; + +// Deconverge Constants +const vec3 ConvergeX = vec3(-0.4, 0.0, 0.2); +const vec3 ConvergeY = vec3( 0.0, -0.4, 0.2); +const vec3 RadialConvergeX = vec3(1.0, 1.0, 1.0); +const vec3 RadialConvergeY = vec3(1.0, 1.0, 1.0); + +// Scanline/Pincushion Constants +const float PincushionAmount = 0.015; +const float CurvatureAmount = 0.015; +//const float ScanlineAmount = 0.175; <- move to parameter +const float ScanlineScale = 1.0; +const float ScanlineHeight = 1.0; +const float ScanlineBrightScale = 1.0; +const float ScanlineBrightOffset = 0.0; +const float ScanlineOffset = 0.0; +const vec3 Floor = vec3(0.05, 0.05, 0.05); + +// 60Hz Bar Constants +const float SixtyHertzRate = (60.0 / 59.97 - 1.0); // Difference between NTSC and line frequency +const float SixtyHertzScale = 0.1; + +vec4 CompositeSample(vec2 UV, vec2 InverseRes) { + vec2 InverseP = vec2(P, 0.0) * InverseRes; + + // UVs for four linearly-interpolated samples spaced 0.25 texels apart + vec2 C0 = UV; + vec2 C1 = UV + InverseP * 0.25; + vec2 C2 = UV + InverseP * 0.50; + vec2 C3 = UV + InverseP * 0.75; + vec4 Cx = vec4(C0.x, C1.x, C2.x, C3.x); + vec4 Cy = vec4(C0.y, C1.y, C2.y, C3.y); + + vec4 Texel0 = texture(source[0], C0); + vec4 Texel1 = texture(source[0], C1); + vec4 Texel2 = texture(source[0], C2); + vec4 Texel3 = texture(source[0], C3); + + float Frequency = CCFrequency; + //Frequency = Frequency;// Uncomment for bad color sync + (sin(UV.y * 2.0 - 1.0) / CCFrequency) * 0.001; + + // Calculated the expected time of the sample. + vec4 T = A2 * Cy * vec4(sourceSize[0].y) + B + Cx; + vec4 W = vec4(Pi2ScanTime * Frequency); + vec4 TW = T * W; + vec4 Y = vec4(dot(Texel0, YTransform), dot(Texel1, YTransform), dot(Texel2, YTransform), dot(Texel3, YTransform)); + vec4 I = vec4(dot(Texel0, ITransform), dot(Texel1, ITransform), dot(Texel2, ITransform), dot(Texel3, ITransform)); + vec4 Q = vec4(dot(Texel0, QTransform), dot(Texel1, QTransform), dot(Texel2, QTransform), dot(Texel3, QTransform)); + + vec4 Encoded = Y + I * cos(TW) + Q * sin(TW); + return (Encoded - MinC) * InvCRange; +} + +vec4 NTSCCodec(vec2 UV, vec2 InverseRes) +{ + vec4 YAccum = Zero; + vec4 IAccum = Zero; + vec4 QAccum = Zero; + float QuadXSize = sourceSize[0].x * 4.0; + float TimePerSample = ScanTime / QuadXSize; + + // Frequency cutoffs for the individual portions of the signal that we extract. + // Y1 and Y2 are the positive and negative frequency limits of the notch filter on Y. + // Y3 is the center of the frequency response of the Y filter. + // I is the center of the frequency response of the I filter. + // Q is the center of the frequency response of the Q filter. + float Fc_y1 = NotchLowerFrequency * TimePerSample; + float Fc_y2 = NotchUpperFrequency * TimePerSample; + float Fc_y3 = YFrequency * TimePerSample; + float Fc_i = IFrequency * TimePerSample; + float Fc_q = QFrequency * TimePerSample; + float Pi2Fc_y1 = Fc_y1 * Pi2; + float Pi2Fc_y2 = Fc_y2 * Pi2; + float Pi2Fc_y3 = Fc_y3 * Pi2; + float Pi2Fc_i = Fc_i * Pi2; + float Pi2Fc_q = Fc_q * Pi2; + float Fc_y1_2 = Fc_y1 * 2.0; + float Fc_y2_2 = Fc_y2 * 2.0; + float Fc_y3_2 = Fc_y3 * 2.0; + float Fc_i_2 = Fc_i * 2.0; + float Fc_q_2 = Fc_q * 2.0; + vec4 CoordY = vec4(UV.y); + + // 83 composite samples wide, 4 composite pixels per texel + for(float n = -31.0; n < 32.0; n += 4.0) + { + vec4 n4 = n + NotchOffset; + vec4 CoordX = UV.x + InverseRes.x * n4 * 0.25; + vec2 TexCoord = vec2(CoordX.x, CoordY.x); + vec4 C = CompositeSample(TexCoord, InverseRes) * CRange + MinC; + vec4 WT = W * (CoordX + A2 * CoordY * sourceSize[0].y + B); + vec4 Cosine = 0.54 + 0.46 * cos(Pi2Length * n4); + + vec4 SincYIn1 = Pi2Fc_y1 * n4; + vec4 SincYIn2 = Pi2Fc_y2 * n4; + vec4 SincYIn3 = Pi2Fc_y3 * n4; + vec4 SincY1 = sin(SincYIn1) / SincYIn1; + vec4 SincY2 = sin(SincYIn2) / SincYIn2; + vec4 SincY3 = sin(SincYIn3) / SincYIn3; + + // These zero-checks could be made more efficient if WebGL supported mix(vec4, vec4, bvec4) + // Unfortunately, the universe hates us + if(SincYIn1.x == 0.0) SincY1.x = 1.0; + if(SincYIn1.y == 0.0) SincY1.y = 1.0; + if(SincYIn1.z == 0.0) SincY1.z = 1.0; + if(SincYIn1.w == 0.0) SincY1.w = 1.0; + if(SincYIn2.x == 0.0) SincY2.x = 1.0; + if(SincYIn2.y == 0.0) SincY2.y = 1.0; + if(SincYIn2.z == 0.0) SincY2.z = 1.0; + if(SincYIn2.w == 0.0) SincY2.w = 1.0; + if(SincYIn3.x == 0.0) SincY3.x = 1.0; + if(SincYIn3.y == 0.0) SincY3.y = 1.0; + if(SincYIn3.z == 0.0) SincY3.z = 1.0; + if(SincYIn3.w == 0.0) SincY3.w = 1.0; + vec4 IdealY = (Fc_y1_2 * SincY1 - Fc_y2_2 * SincY2) + Fc_y3_2 * SincY3; + vec4 FilterY = Cosine * IdealY; + + vec4 SincIIn = Pi2Fc_i * n4; + vec4 SincI = sin(SincIIn) / SincIIn; + if (SincIIn.x == 0.0) SincI.x = 1.0; + if (SincIIn.y == 0.0) SincI.y = 1.0; + if (SincIIn.z == 0.0) SincI.z = 1.0; + if (SincIIn.w == 0.0) SincI.w = 1.0; + vec4 IdealI = Fc_i_2 * SincI; + vec4 FilterI = Cosine * IdealI; + + vec4 SincQIn = Pi2Fc_q * n4; + vec4 SincQ = sin(SincQIn) / SincQIn; + if (SincQIn.x == 0.0) SincQ.x = 1.0; + if (SincQIn.y == 0.0) SincQ.y = 1.0; + if (SincQIn.z == 0.0) SincQ.z = 1.0; + if (SincQIn.w == 0.0) SincQ.w = 1.0; + vec4 IdealQ = Fc_q_2 * SincQ; + vec4 FilterQ = Cosine * IdealQ; + + YAccum += C * FilterY; + IAccum += C * cos(WT) * FilterI; + QAccum += C * sin(WT) * FilterQ; + } + + float Y = dot(YAccum, One); + float I = dot(IAccum, One) * 2.0; + float Q = dot(QAccum, One) * 2.0; + + vec3 YIQ = vec3(Y, I, Q); + vec3 OutRGB = vec3(dot(YIQ, YIQ2R), dot(YIQ, YIQ2G), dot(YIQ, YIQ2B)); + + return vec4(OutRGB, 1.0); +} + +void main() { + FragColor = vec4(NTSCCodec(vTexCoord, sourceSize[0].zw)); +} \ No newline at end of file diff --git a/shaders/NTSC-MAME.shader/mame-ntsc.vs b/shaders/NTSC-MAME.shader/mame-ntsc.vs new file mode 100644 index 00000000..1f08237b --- /dev/null +++ b/shaders/NTSC-MAME.shader/mame-ntsc.vs @@ -0,0 +1,13 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/NTSC-MAME.shader/mame-postproc.fs b/shaders/NTSC-MAME.shader/mame-postproc.fs new file mode 100644 index 00000000..e3819397 --- /dev/null +++ b/shaders/NTSC-MAME.shader/mame-postproc.fs @@ -0,0 +1,208 @@ +#version 150 + +// This is a port of the NTSC encode/decode shader pair in MAME and MESS, modified to use only +// one pass rather than an encode pass and a decode pass. It accurately emulates the sort of +// signal decimation one would see when viewing a composite signal, though it could benefit from a +// pre-pass to re-size the input content to more accurately reflect the actual size that would +// be incoming from a composite signal source. +// +// To encode the composite signal, I convert the RGB value to YIQ, then subsequently evaluate +// the standard NTSC composite equation. Four composite samples per RGB pixel are generated from +// the incoming linearly-interpolated texels. +// +// The decode pass implements a Fixed Impulse Response (FIR) filter designed by MAME/MESS contributor +// "austere" in matlab (if memory serves correctly) to mimic the behavior of a standard television set +// as closely as possible. The filter window is 83 composite samples wide, and there is an additional +// notch filter pass on the luminance (Y) values in order to strip the color signal from the luminance +// signal prior to processing. +// +// Yes, this code could greatly use some cleaning up. + +// ported from UltraMoogleMan's "Full MAME/MESS Shader Pipe" shadertoy: https://www.shadertoy.com/view/ldf3Rf +// license: presumably MAME's license at the time, which was noncommercial + +#define scanlines 0.0 +#define scandark 0.175 +#define deconverge 0.0 +#define pincushion 0.0 +#define hertzroll 0.0 + +// Useful Constants +const vec4 Zero = vec4(0.0); +const vec4 Half = vec4(0.5); +const vec4 One = vec4(1.0); +const vec4 Two = vec4(2.0); +const vec3 Gray = vec3(0.3, 0.59, 0.11); +const float Pi = 3.1415926535; +const float Pi2 = 6.283185307; + +// NTSC Constants +const vec4 A = vec4(0.5); +const vec4 A2 = vec4(1.0); +const vec4 B = vec4(0.5); +const float P = 1.0; +const float CCFrequency = 3.59754545; +const float NotchUpperFrequency = 5.59754545; //3.59754545 + 2.0; +const float NotchLowerFrequency = 1.59754545; //3.59754545 - 2.0; +const float YFrequency = 6.0; +const float IFrequency = 1.2; +const float QFrequency = 0.6; +const float NotchHalfWidth = 2.0; +const float ScanTime = 52.6; +const float Pi2ScanTime = 330.4955471482;// 6.283185307 * 52.6; +const float MaxC = 2.1183; +const vec4 YTransform = vec4(0.299, 0.587, 0.114, 0.0); +const vec4 ITransform = vec4(0.595716, -0.274453, -0.321263, 0.0); +const vec4 QTransform = vec4(0.211456, -0.522591, 0.311135, 0.0); +const vec3 YIQ2R = vec3(1.0, 0.956, 0.621); +const vec3 YIQ2G = vec3(1.0, -0.272, -0.647); +const vec3 YIQ2B = vec3(1.0, -1.106, 1.703); +const vec4 MinC = vec4(-1.1183); +const vec4 CRange = vec4(3.2366); +const vec4 InvCRange = vec4(1.0/3.2366); +const float Pi2Length = Pi2 / 63.0; +const vec4 NotchOffset = vec4(0.0, 1.0, 2.0, 3.0); +vec4 W = vec4(Pi2 * CCFrequency * ScanTime); + +// Color Convolution Constants +const vec3 RedMatrix = vec3(1.0, 0.0, 0.0); +const vec3 GrnMatrix = vec3(0.0, 1.0, 0.0); +const vec3 BluMatrix = vec3(0.0, 0.0, 1.0); +const vec3 DCOffset = vec3(0.0, 0.0, 0.0); +const vec3 ColorScale = vec3(0.95, 0.95, 0.95); +const float Saturation = 1.4; + +// Deconverge Constants +const vec3 ConvergeX = vec3(-0.4, 0.0, 0.2); +const vec3 ConvergeY = vec3( 0.0, -0.4, 0.2); +const vec3 RadialConvergeX = vec3(1.0, 1.0, 1.0); +const vec3 RadialConvergeY = vec3(1.0, 1.0, 1.0); + +// Scanline/Pincushion Constants +const float PincushionAmount = 0.015; +const float CurvatureAmount = 0.015; +//const float ScanlineAmount = 0.175; <- move to parameter +const float ScanlineScale = 1.0; +const float ScanlineHeight = 1.0; +const float ScanlineBrightScale = 1.0; +const float ScanlineBrightOffset = 0.0; +const float ScanlineOffset = 0.0; +const vec3 Floor = vec3(0.05, 0.05, 0.05); + +// 60Hz Bar Constants +const float SixtyHertzRate = (60.0 / 59.97 - 1.0); // Difference between NTSC and line frequency +const float SixtyHertzScale = 0.1; + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +uniform int phase; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +vec4 ColorConvolution(vec2 UV, vec2 InverseRes) +{ + vec3 InPixel = texture(source[0], UV).rgb; + + // Color Matrix + float RedValue = dot(InPixel, RedMatrix); + float GrnValue = dot(InPixel, GrnMatrix); + float BluValue = dot(InPixel, BluMatrix); + vec3 OutColor = vec3(RedValue, GrnValue, BluValue); + + // DC Offset & Scale + OutColor = (OutColor * ColorScale) + DCOffset; + + // Saturation + float Luma = dot(OutColor, Gray); + vec3 Chroma = OutColor - Luma; + OutColor = (Chroma * Saturation) + Luma; + + return vec4(OutColor, 1.0); +} + +vec4 Deconverge(vec2 UV) +{ + vec2 InverseRes = 1.0 / sourceSize[0].xy; + vec2 InverseSrcRes = 1.0 / sourceSize[0].xy; + + vec3 CoordX = UV.x * RadialConvergeX; + vec3 CoordY = UV.y * RadialConvergeY; + + CoordX += ConvergeX * InverseRes.x - (RadialConvergeX - 1.0) * 0.5; + CoordY += ConvergeY * InverseRes.y - (RadialConvergeY - 1.0) * 0.5; + + float RedValue = ColorConvolution(vec2(CoordX.x, CoordY.x), InverseSrcRes).r; + float GrnValue = ColorConvolution(vec2(CoordX.y, CoordY.y), InverseSrcRes).g; + float BluValue = ColorConvolution(vec2(CoordX.z, CoordY.z), InverseSrcRes).b; + + if (deconverge > 0.5) return vec4(RedValue, GrnValue, BluValue, 1.0); + else return vec4(texture(source[0], UV)); +} + +vec4 ScanlinePincushion(vec2 UV) +{ + vec4 InTexel = Deconverge(UV); + + vec2 PinUnitCoord = UV * Two.xy - One.xy; + float PincushionR2 = pow(length(PinUnitCoord), 2.0); + vec2 PincushionCurve = PinUnitCoord * PincushionAmount * PincushionR2; + vec2 BaseCoord = UV; + vec2 ScanCoord = UV; + + BaseCoord *= One.xy - PincushionAmount * 0.2; // Warning: Magic constant + BaseCoord += PincushionAmount * 0.1; + BaseCoord += PincushionCurve; + + ScanCoord *= One.xy - PincushionAmount * 0.2; // Warning: Magic constant + ScanCoord += PincushionAmount * 0.1; + ScanCoord += PincushionCurve; + + vec2 CurveClipUnitCoord = UV * Two.xy - One.xy; + float CurvatureClipR2 = pow(length(CurveClipUnitCoord), 2.0); + vec2 CurvatureClipCurve = CurveClipUnitCoord * CurvatureAmount * CurvatureClipR2; + vec2 ScreenClipCoord = UV; + ScreenClipCoord -= Half.xy; + ScreenClipCoord *= One.xy - CurvatureAmount * 0.2; // Warning: Magic constant + ScreenClipCoord += Half.xy; + ScreenClipCoord += CurvatureClipCurve; + + if (pincushion > 0.5){ + // -- Alpha Clipping -- + if (BaseCoord.x < 0.0) return vec4(0.0, 0.0, 0.0, 1.0); + if (BaseCoord.y < 0.0) return vec4(0.0, 0.0, 0.0, 1.0); + if (BaseCoord.x > 1.0) return vec4(0.0, 0.0, 0.0, 1.0); + if (BaseCoord.y > 1.0) return vec4(0.0, 0.0, 0.0, 1.0); + } + + // -- Scanline Simulation -- + float InnerSine = ScanCoord.y * sourceSize[0].y * ScanlineScale; + float ScanBrightMod = sin(InnerSine * Pi + ScanlineOffset * sourceSize[0].y); + float ScanBrightness = mix(1.0, (pow(ScanBrightMod * ScanBrightMod, ScanlineHeight) * ScanlineBrightScale + 1.0) * 0.5, scandark); + vec3 ScanlineTexel = InTexel.rgb * ScanBrightness; + + // -- Color Compression (increasing the floor of the signal without affecting the ceiling) -- + ScanlineTexel = Floor + (One.xyz - Floor) * ScanlineTexel; + if (scanlines > 0.5) return vec4(ScanlineTexel, 1.0); + else return vec4(InTexel); +} + +vec4 SixtyHertz(vec2 UV) +{ + vec4 InPixel = ScanlinePincushion(UV); + float Milliseconds = float(phase) * 15.0; + float TimeStep = fract(Milliseconds * SixtyHertzRate); + float BarPosition = 1.0 - fract(-UV.y + TimeStep) * SixtyHertzScale; + vec4 OutPixel = InPixel * BarPosition; + if (hertzroll > 0.5) return OutPixel; + else return InPixel; +} + +void main() { + vec4 OutPixel = SixtyHertz(vTexCoord.xy); + FragColor = OutPixel; +} \ No newline at end of file diff --git a/shaders/NTSC-MAME.shader/mame-postproc.vs b/shaders/NTSC-MAME.shader/mame-postproc.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/NTSC-MAME.shader/mame-postproc.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/NTSC-MAME.shader/manifest.bml b/shaders/NTSC-MAME.shader/manifest.bml new file mode 100644 index 00000000..37b893a7 --- /dev/null +++ b/shaders/NTSC-MAME.shader/manifest.bml @@ -0,0 +1,20 @@ +input + filter: linear + +program + filter: linear + height: 100% + width: 100% + vertex: mame-ntsc.vs + fragment: mame-ntsc.fs + +program + filter: linear + modulo: 270.0 + vertex: mame-postproc.vs + fragment: mame-postproc.fs + +output + height: 0 + width: 0 + filter: linear \ No newline at end of file diff --git a/shaders/NTSC.shader/gaussian-scanlines.fs b/shaders/NTSC.shader/gaussian-scanlines.fs new file mode 100644 index 00000000..949a01ab --- /dev/null +++ b/shaders/NTSC.shader/gaussian-scanlines.fs @@ -0,0 +1,48 @@ +// Gaussian Scanlines +// +// adapted from NTSC Shader - written by Hans-Kristian Arntzen +// License: GPLv3 +// pulled from git://github.com/libretro/common-shaders.git on 08/05/2013 + +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +uniform int phase; + +#define DISPLAY_GAMMA 2.1 +#define CRT_GAMMA 2.5 +#define one (sourceSize[0]) //this is set to 1.0 / sourceSize[0] in the original version, but I think this looks better +#define pix_no texCoord.y * sourceSize[0] +#define TEX(off) pow(texture(source[0], texCoord - vec2(0.0, (off) * one.y)).rgb, vec3(CRT_GAMMA)) + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +void main() { + +vec3 frame0 = TEX(-2.0); +vec3 frame1 = TEX(-1.0); +vec3 frame2 = TEX(0.0); +vec3 frame3 = TEX(1.0); +vec3 frame4 = TEX(2.0); + +float offset_dist = fract(pix_no.y) - 0.5; +float dist0 = 2.0 + offset_dist; +float dist1 = 1.0 + offset_dist; +float dist2 = 0.0 + offset_dist; +float dist3 = -1.0 + offset_dist; +float dist4 = -2.0 + offset_dist; + +vec3 scanline = frame0 * exp(-5.0 * dist0 * dist0); + scanline += frame1 * exp(-5.0 * dist1 * dist1); + scanline += frame2 * exp(-5.0 * dist2 * dist2); + scanline += frame3 * exp(-5.0 * dist3 * dist3); + scanline += frame4 * exp(-5.0 * dist4 * dist4); + +fragColor = vec4(pow(1.15 * scanline, vec3(1.0 / DISPLAY_GAMMA)), 1.0); +} \ No newline at end of file diff --git a/shaders/NTSC.shader/manifest.bml b/shaders/NTSC.shader/manifest.bml new file mode 100644 index 00000000..0201bed6 --- /dev/null +++ b/shaders/NTSC.shader/manifest.bml @@ -0,0 +1,26 @@ +input + filter: nearest + format: rgba16f + +program + filter: nearest + format: rgba16f + width: 400% + height: 100% + modulo: 2 + fragment: ntsc-pass1.fs + +program + filter: nearest + format: rgba16f + width: 50% + height: 100% + fragment: ntsc-pass2.fs + +program + filter: linear + width: 100% + height: 100% + +output + filter: nearest \ No newline at end of file diff --git a/shaders/NTSC.shader/ntsc-pass1.fs b/shaders/NTSC.shader/ntsc-pass1.fs new file mode 100644 index 00000000..92d872c0 --- /dev/null +++ b/shaders/NTSC.shader/ntsc-pass1.fs @@ -0,0 +1,103 @@ +// NTSC Shader - written by Hans-Kristian Arntzen +// License: GPLv3 +// pulled from git://github.com/libretro/common-shaders.git on 01/30/2014 + +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; +uniform int phase; + +// uniforms added for compatibility +out vec3 col; +out float mod_phase; +out float chroma_phase; + +#define THREE_PHASE +#define COMPOSITE + +// #include "ntsc-param.inc" // +#define PI 3.14159265 + +#if defined(TWO_PHASE) +#define CHROMA_MOD_FREQ (4.0 * PI / 15.0) +#elif defined(THREE_PHASE) +#define CHROMA_MOD_FREQ (PI / 3.0) +#endif + +#if defined(COMPOSITE) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 1.0 +#define FRINGING 1.0 +#elif defined(SVIDEO) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 0.0 +#define FRINGING 0.0 +#endif + +#if defined(COMPOSITE) || defined(SVIDEO) +mat3 mix_mat = mat3( + BRIGHTNESS, FRINGING, FRINGING, + ARTIFACTING, 2.0 * SATURATION, 0.0, + ARTIFACTING, 0.0, 2.0 * SATURATION +); +#endif +// END "ntsc-param.inc" // + +// moved from vertex +#define pix_no (texCoord.xy * sourceSize[0].xy * (targetSize.xy / sourceSize[0].xy)) + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +mat3 yiq2rgb_mat = mat3( + 1.0, 1.0, 1.0, + 0.956, -0.2720, -1.1060, + 0.6210, -0.6474, 1.7046 +); + +vec3 yiq2rgb(vec3 yiq) +{ + return (yiq * yiq2rgb_mat); +} + +mat3 yiq_mat = mat3( + 0.2989, 0.5959, 0.2115, + 0.5870, -0.2744, -0.5229, + 0.1140, -0.3216, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return (col * yiq_mat); +} + +void main() { +// #include "ntsc-pass1-encode-demodulate.inc" // +vec3 col = texture(source[0], texCoord).rgb; +vec3 yiq = rgb2yiq(col); + +#if defined(TWO_PHASE) +float chroma_phase = PI * (mod(pix_no.y, 2.0) + phase); +#elif defined(THREE_PHASE) +float chroma_phase = 0.6667 * PI * (mod(pix_no.y, 3.0) + phase); +#endif + +float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ; + +float i_mod = cos(mod_phase); +float q_mod = sin(mod_phase); + +yiq.yz *= vec2(i_mod, q_mod); // Modulate +yiq *= mix_mat; // Cross-talk +yiq.yz *= vec2(i_mod, q_mod); // Demodulate + +fragColor = vec4(yiq, 1.0); +// END "ntsc-pass1-encode-demodulate.inc" // +} \ No newline at end of file diff --git a/shaders/NTSC.shader/ntsc-pass2.fs b/shaders/NTSC.shader/ntsc-pass2.fs new file mode 100644 index 00000000..b8c292bf --- /dev/null +++ b/shaders/NTSC.shader/ntsc-pass2.fs @@ -0,0 +1,252 @@ +// NTSC Shader - written by Hans-Kristian Arntzen +// License: GPLv3 +// pulled from git://github.com/libretro/common-shaders.git on 01/30/2014 + +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +#define THREE_PHASE //options here include THREE_PHASE, TWO_PHASE or OLD_THREE_PHASE +#define GAMMA_CORRECTION //comment to disable gamma correction, usually because higan's gamma correction is enabled or you have another shader already doing it +#define CRT_GAMMA 2.5 +#define DISPLAY_GAMMA 2.1 + +#if defined OLD_THREE_PHASE +#define TAPS 24 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000071070, + -0.000032816, + 0.000128784, + 0.000134711, + -0.000226705, + -0.000777988, + -0.000997809, + -0.000522802, + 0.000344691, + 0.000768930, + 0.000275591, + -0.000373434, + 0.000522796, + 0.003813817, + 0.007502825, + 0.006786001, + -0.002636726, + -0.019461182, + -0.033792479, + -0.029921972, + 0.005032552, + 0.071226466, + 0.151755921, + 0.218166470, + 0.243902439); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + 0.001845562, + 0.002381606, + 0.003040177, + 0.003838976, + 0.004795341, + 0.005925312, + 0.007242534, + 0.008757043, + 0.010473987, + 0.012392365, + 0.014503872, + 0.016791957, + 0.019231195, + 0.021787070, + 0.024416251, + 0.027067414, + 0.029682613, + 0.032199202, + 0.034552198, + 0.036677005, + 0.038512317, + 0.040003044, + 0.041103048, + 0.041777517, + 0.042004791); +#endif + +#if defined(THREE_PHASE) +// #include "ntsc-decode-filter-3phase.inc" // +#define TAPS 24 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000012020, + -0.000022146, + -0.000013155, + -0.000012020, + -0.000049979, + -0.000113940, + -0.000122150, + -0.000005612, + 0.000170516, + 0.000237199, + 0.000169640, + 0.000285688, + 0.000984574, + 0.002018683, + 0.002002275, + -0.000909882, + -0.007049081, + -0.013222860, + -0.012606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.190176552); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000118847, + -0.000271306, + -0.000502642, + -0.000930833, + -0.001451013, + -0.002064744, + -0.002700432, + -0.003241276, + -0.003524948, + -0.003350284, + -0.002491729, + -0.000721149, + 0.002164659, + 0.006313635, + 0.011789103, + 0.018545660, + 0.026414396, + 0.035100710, + 0.044196567, + 0.053207202, + 0.061590275, + 0.068803602, + 0.074356193, + 0.077856564, + 0.079052396); +// END "ntsc-decode-filter-3phase.inc" // + +#elif defined(TWO_PHASE) +// #include "ntsc-decode-filter-3phase.inc" // +#define TAPS 24 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000012020, + -0.000022146, + -0.000013155, + -0.000012020, + -0.000049979, + -0.000113940, + -0.000122150, + -0.000005612, + 0.000170516, + 0.000237199, + 0.000169640, + 0.000285688, + 0.000984574, + 0.002018683, + 0.002002275, + -0.000909882, + -0.007049081, + -0.013222860, + -0.012606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.190176552); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000118847, + -0.000271306, + -0.000502642, + -0.000930833, + -0.001451013, + -0.002064744, + -0.002700432, + -0.003241276, + -0.003524948, + -0.003350284, + -0.002491729, + -0.000721149, + 0.002164659, + 0.006313635, + 0.011789103, + 0.018545660, + 0.026414396, + 0.035100710, + 0.044196567, + 0.053207202, + 0.061590275, + 0.068803602, + 0.074356193, + 0.077856564, + 0.079052396); +// END "ntsc-decode-filter-3phase.inc" // +#endif + +// #include ntsc-rgbyuv.inc // +mat3 yiq2rgb_mat = mat3( + 1.0, 1.0, 1.0, + 0.956, -0.2720, -1.1060, + 0.6210, -0.6474, 1.7046 +); + +vec3 yiq2rgb(vec3 yiq) +{ + return (yiq * yiq2rgb_mat); +} + +mat3 yiq_mat = mat3( + 0.2989, 0.5959, 0.2115, + 0.5870, -0.2744, -0.5229, + 0.1140, -0.3216, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return (col * yiq_mat); +} +// END ntsc-rgbyuv.inc // + +// fixCoord moved from vertex +#define fixCoord (texCoord - vec2(0.5 / sourceSize[0].x, 0.0)) // Compensate for decimate-by-2. + +#define fetch_offset(offset, one_x) \ +texture(source[0], fixCoord + vec2((offset) * (one_x), 0.0)).xyz + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +void main() { +// #include "ntsc-pass2-decode.inc" // +float one_x = 1.0 / sourceSize[0].x; +vec3 signal = vec3(0.0); + +for (int i = 0; i < TAPS; i++) +{ + float offset = float(i); + vec3 sums = fetch_offset(offset - float(TAPS), one_x) + + fetch_offset(float(TAPS) - offset, one_x); + + signal += sums * vec3(luma_filter[i], chroma_filter[i], chroma_filter[i]); +} + +signal += texture(source[0], fixCoord).xyz * vec3(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS]); + +// END "ntsc-pass2-decode.inc" // + + vec3 rgb = yiq2rgb(signal); + +#ifdef GAMMA_CORRECTION + vec3 gamma = vec3(CRT_GAMMA / DISPLAY_GAMMA); + rgb = pow(rgb, gamma.rgb); +#endif + +fragColor = vec4(rgb, 1.0); +} \ No newline at end of file diff --git a/shaders/PAL-Composite.shader/manifest.bml b/shaders/PAL-Composite.shader/manifest.bml new file mode 100644 index 00000000..74d15e71 --- /dev/null +++ b/shaders/PAL-Composite.shader/manifest.bml @@ -0,0 +1,11 @@ +input + filter: nearest + +program + filter: nearest + height: 100% + fragment: pal-r57shell.fs + +output + height: 0 + filter: linear \ No newline at end of file diff --git a/shaders/PAL-Composite.shader/pal-r57shell.fs b/shaders/PAL-Composite.shader/pal-r57shell.fs new file mode 100644 index 00000000..d7f50edf --- /dev/null +++ b/shaders/PAL-Composite.shader/pal-r57shell.fs @@ -0,0 +1,368 @@ +#version 150 + +// NES PAL composite signal simulation for RetroArch +// shader by r57shell +// thanks to feos & HardWareMan & NewRisingSun + +// also TV subpixels and scanlines + +// LICENSE: PUBLIC DOMAIN + +// NOTE: for nice TV subpixels and scanlines I recommend to +// disable this features here and apply CRT-specialized shader. + +// Quality considerations + +// there are three main options: +// USE_RAW (R), USE_DELAY_LINE (D), USE_COLORIMETRY (C) +// here is table of quality in decreasing order: +// RDC, RD, RC, DC, D, C + +// compatibility macros +#define float2 vec2 +#define float3 vec3 +#define float4 vec4 +#define frac(c) fract(c) +#define saturate(c) clamp(c, 0.0, 1.0) +#define fmod(x,y) mod(x,y) +#define mul(x,y) (y*x) +#define float2x2 mat2 +#define float3x3 mat3 +#define float4x4 mat4 +#define bool2 bvec2 +#define bool3 bvec3 +#define bool4 bvec4 +#define static + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 outputSize; +uniform int phase; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +// TWEAKS start + +// use delay line technique +// without delay line technique, color would interleave +// to avoid this, set HueRotation to zero. +#define USE_DELAY_LINE + +// use this if you need to swap even/odd V sign. +// sign of V changes each scanline +// so if some scanline is positive, then next is negative +// and if you want to match picture +// to actual running PAL NES on TV +// you may want to have this option, to change signs +// if they don't match +//#define SWAP_VSIGN + +// rough simulation of scanlines +// better if you use additional shader instead +// if you still use it, make sure that SizeY +// is at least twice lower than output height +#define USE_SCANLINES // FIXME: scanlines are broken and I'm too lazy to fix it right now + +// to change gamma of virtual TV from 2.2 to something else +#define USE_GAMMA + +// use sampled version. it's much more slower version of shader. +// because it is computing x4 more values. NOT RECOMMENDED. +//#define USE_SAMPLED + +#ifndef PARAMETER_UNIFORM +// NTSC standard gamma = 2.2 +// PAL standard gamma = 2.8 +// according to many sources, very unlikely gamma of TV is 2.8 +// most likely gamma of PAL TV is in range 2.4-2.5 +const float Gamma_static = 2.8; // gamma of virtual TV + +const float Brightness_static = 0.25; +const float Contrast_static = 1.1; +const float Saturation_static = 1.1; + +const int + Ywidth_static = 12, + Uwidth_static = 23, + Vwidth_static = 23; + +#define Brightness Brightness_static +#define Gamma Gamma_static + +#define Ywidth Ywidth_static +#define Uwidth Uwidth_static +#define Vwidth Vwidth_static + +#define SCANLINE_MUL (sw.x*dark_scanline+sw.y) + +int Mwidth = int(max(float(Ywidth), max(float(Uwidth), float(Vwidth)))); + +// correct one is -2.5 +// works only with USE_RAW +const float HueShift = -2.5; + +// rotation of hue due to luma level. +const float HueRotation = 2.; + +// touch this only if you know what you doing +const float Phase_Y = 2.; // fmod(341*10,12) +const float Phase_One = 0.; // alternating phases. +const float Phase_Two = 8.; + +// screen size, scanlines = y*2; y one field, and y other field. +const int SizeX = 256; +const int SizeY = 240; + +// count of pixels of virtual TV. +// value close to 1000 produce small artifacts +const int TV_Pixels = 400; + +const float dark_scanline = 0.5; // half +#endif + +// this is using following matrixes. +// it provides more scientific approach +// by conversion into linear XYZ space +// and back to sRGB. +// it's using Gamma setting too. +// define USE_GAMMA is not required. +#define USE_COLORIMETRY + +const float3x3 RGB_to_XYZ = +mat3( + 0.4306190, 0.3415419, 0.1783091, + 0.2220379, 0.7066384, 0.0713236, + 0.0201853, 0.1295504, 0.9390944 +); + +const float3x3 XYZ_to_sRGB = +mat3( + 3.2406, -1.5372, -0.4986, + -0.9689, 1.8758, 0.0415, + 0.0557, -0.2040, 1.0570 +); + +// TWEAKS end + +const float YUV_u = 0.492; +const float YUV_v = 0.877; + +const mat3 RGB_to_YUV = +mat3( + float3( 0.299, 0.587, 0.114), //Y + float3(-0.299,-0.587, 0.886)*YUV_u, //B-Y + float3( 0.701,-0.587,-0.114)*YUV_v //R-Y +); + +#ifdef USE_DELAY_LINE +const float comb_line = 1.; +#else +const float comb_line = 2.; +#endif + +static const float Voltage_0 = 0.518; +static const float Voltage_1 = 1.962; +static const float DeltaV = (Voltage_1-Voltage_0); + +float RGB_y = Contrast_static/Ywidth_static/DeltaV; +float RGB_u = comb_line*Contrast_static*Saturation_static/YUV_u/Uwidth_static/DeltaV; +float RGB_v = comb_line*Contrast_static*Saturation_static/YUV_v/Vwidth_static/DeltaV; + +mat3 YUV_to_RGB = +mat3( + float3(1., 1., 1.)*RGB_y, + float3(0., -0.114/0.587, 1.)*RGB_u, + float3(1., -0.299/0.587, 0.)*RGB_v +); + +const float pi = 3.1415926535897932384626433832795; + +float sinn(float x) +{ + return sin(/*fmod(x,24)*/x*(pi*2./24.)); +} + +float coss(float x) +{ + return cos(/*fmod(x,24)*/x*(pi*2./24.)); +} + +float3 monitor(sampler2D tex, float2 p) +{ + float2 size = sourceSize[0].xy;//float2(SizeX,SizeY); + // align vertical coord to center of texel + float2 uv = float2( + + p.x, + + (floor(p.y*sourceSize[0].y)+0.5)/sourceSize[0].y); +#ifdef USE_DELAY_LINE + float2 sh = (sourceSize[0].xy/sourceSize[0].xy/size)*float2(14./10.,-1.0); +#endif + float2 pc = uv*sourceSize[0].xy/sourceSize[0].xy*size*float2(10.,1.); + float alpha = dot(floor(float2(pc.x,pc.y)),float2(2.,Phase_Y*2.)); + alpha += Phase_One*2.; + + // 1/size.x of screen in uv coords = sourceSize[0].x/sourceSize[0].x/size.x; + // then 1/10*size.x of screen: + float ustep = sourceSize[0].x/sourceSize[0].x/size.x/10.; + + float border = sourceSize[0].x/sourceSize[0].x; + float ss = 2.0; +#ifdef SWAP_VSIGN +#define PAL_SWITCH(A) A < 1. +#else +#define PAL_SWITCH(A) A > 1. +#endif + if (PAL_SWITCH(fmod(uv.y*sourceSize[0].y/sourceSize[0].y*size.y,2.0))) + { + // cos(pi-alpha) = -cos(alpha) + // sin(pi-alpha) = sin(alpha) + // pi - alpha + alpha = -alpha+12012.0; + ss = -2.0; + } + + float ysum = 0., usum = 0., vsum = 0.; + for (int i=0; i min(a.y, b.y) + a.y ? diff : -diff), 0, 1); + return (SFX_SAA == 1 || 2*d < a.x + a.y) ? (wght1 * wght2) * (a.x * a.y) : 0; +} + +void main() { +/* grid metric pattern + + A B x y z x y + D E F o w w z + G H I + */ + + +#define TEX(x, y) textureOffset(source[0], vTexCoord, ivec2(x, y)) + + // metric data + vec4 A = TEX(-1,-1), B = TEX( 0,-1); + vec4 D = TEX(-1, 0), E = TEX( 0, 0), F = TEX( 1, 0); + vec4 G = TEX(-1, 1), H = TEX( 0, 1), I = TEX( 1, 1); + + // corner strength + vec4 res; + res.x = str(D.z, vec2(D.w, E.y), vec2(A.w, D.y)); + res.y = str(F.x, vec2(E.w, E.y), vec2(B.w, F.y)); + res.z = str(H.z, vec2(E.w, H.y), vec2(H.w, I.y)); + res.w = str(H.x, vec2(D.w, H.y), vec2(G.w, G.y)); + + FragColor = res; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass1.vs b/shaders/ScaleFX.shader/scalefx-pass1.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass1.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass2.fs b/shaders/ScaleFX.shader/scalefx-pass2.fs new file mode 100644 index 00000000..35006f98 --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass2.fs @@ -0,0 +1,135 @@ +#version 150 + +/* + ScaleFX - Pass 2 + by Sp00kyFox, 2017-03-01 + +Filter: Nearest +Scale: 1x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 2 resolves ambiguous configurations of corner candidates at pixel junctions. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +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. + +*/ + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +#define LE(x, y) (1 - step(y, x)) +#define GE(x, y) (1 - step(x, y)) +#define LEQ(x, y) step(x, y) +#define GEQ(x, y) step(y, x) +#define NOT(x) (1 - (x)) + +// corner dominance at junctions +vec4 dom(vec3 x, vec3 y, vec3 z, vec3 w){ + return 2 * vec4(x.y, y.y, z.y, w.y) - (vec4(x.x, y.x, z.x, w.x) + vec4(x.z, y.z, z.z, w.z)); +} + +// necessary but not sufficient junction condition for orthogonal edges +float clear(vec2 crn, vec2 a, vec2 b){ + return (crn.x >= max(min(a.x, a.y), min(b.x, b.y))) && (crn.y >= max(min(a.x, b.y), min(b.x, a.y))) ? 1 : 0; +} + +void main() { + /* grid metric pattern + + A B C x y z x y + D E F o w w z + G H I + */ + + +#define TEXm(x, y) textureOffset(source[1], vTexCoord, ivec2(x, y)) +#define TEXs(x, y) textureOffset(source[0], vTexCoord, ivec2(x, y)) + + + // metric data + vec4 A = TEXm(-1,-1), B = TEXm( 0,-1); + vec4 D = TEXm(-1, 0), E = TEXm( 0, 0), F = TEXm( 1, 0); + vec4 G = TEXm(-1, 1), H = TEXm( 0, 1), I = TEXm( 1, 1); + + // strength data + vec4 As = TEXs(-1,-1), Bs = TEXs( 0,-1), Cs = TEXs( 1,-1); + vec4 Ds = TEXs(-1, 0), Es = TEXs( 0, 0), Fs = TEXs( 1, 0); + vec4 Gs = TEXs(-1, 1), Hs = TEXs( 0, 1), Is = TEXs( 1, 1); + + // strength & dominance junctions + vec4 jSx = vec4(As.z, Bs.w, Es.x, Ds.y), jDx = dom(As.yzw, Bs.zwx, Es.wxy, Ds.xyz); + vec4 jSy = vec4(Bs.z, Cs.w, Fs.x, Es.y), jDy = dom(Bs.yzw, Cs.zwx, Fs.wxy, Es.xyz); + vec4 jSz = vec4(Es.z, Fs.w, Is.x, Hs.y), jDz = dom(Es.yzw, Fs.zwx, Is.wxy, Hs.xyz); + vec4 jSw = vec4(Ds.z, Es.w, Hs.x, Gs.y), jDw = dom(Ds.yzw, Es.zwx, Hs.wxy, Gs.xyz); + + + // majority vote for ambiguous dominance junctions + vec4 zero4 = vec4(0); + vec4 jx = min(GE(jDx, zero4) * (LEQ(jDx.yzwx, zero4) * LEQ(jDx.wxyz, zero4) + GE(jDx + jDx.zwxy, jDx.yzwx + jDx.wxyz)), 1); + vec4 jy = min(GE(jDy, zero4) * (LEQ(jDy.yzwx, zero4) * LEQ(jDy.wxyz, zero4) + GE(jDy + jDy.zwxy, jDy.yzwx + jDy.wxyz)), 1); + vec4 jz = min(GE(jDz, zero4) * (LEQ(jDz.yzwx, zero4) * LEQ(jDz.wxyz, zero4) + GE(jDz + jDz.zwxy, jDz.yzwx + jDz.wxyz)), 1); + vec4 jw = min(GE(jDw, zero4) * (LEQ(jDw.yzwx, zero4) * LEQ(jDw.wxyz, zero4) + GE(jDw + jDw.zwxy, jDw.yzwx + jDw.wxyz)), 1); + + + // inject strength without creating new contradictions + vec4 res; + res.x = min(jx.z + NOT(jx.y) * NOT(jx.w) * GE(jSx.z, 0) * (jx.x + GE(jSx.x + jSx.z, jSx.y + jSx.w)), 1); + res.y = min(jy.w + NOT(jy.z) * NOT(jy.x) * GE(jSy.w, 0) * (jy.y + GE(jSy.y + jSy.w, jSy.x + jSy.z)), 1); + res.z = min(jz.x + NOT(jz.w) * NOT(jz.y) * GE(jSz.x, 0) * (jz.z + GE(jSz.x + jSz.z, jSz.y + jSz.w)), 1); + res.w = min(jw.y + NOT(jw.x) * NOT(jw.z) * GE(jSw.y, 0) * (jw.w + GE(jSw.y + jSw.w, jSw.x + jSw.z)), 1); + + + // single pixel & end of line detection + res = min(res * (vec4(jx.z, jy.w, jz.x, jw.y) + NOT(res.wxyz * res.yzwx)), 1); + + + // output + + vec4 clr; + clr.x = clear(vec2(D.z, E.x), vec2(D.w, E.y), vec2(A.w, D.y)); + clr.y = clear(vec2(F.x, E.z), vec2(E.w, E.y), vec2(B.w, F.y)); + clr.z = clear(vec2(H.z, I.x), vec2(E.w, H.y), vec2(H.w, I.y)); + clr.w = clear(vec2(H.x, G.z), vec2(D.w, H.y), vec2(G.w, G.y)); + + vec4 h = vec4(min(D.w, A.w), min(E.w, B.w), min(E.w, H.w), min(D.w, G.w)); + vec4 v = vec4(min(E.y, D.y), min(E.y, F.y), min(H.y, I.y), min(H.y, G.y)); + + vec4 or = GE(h + vec4(D.w, E.w, E.w, D.w), v + vec4(E.y, E.y, H.y, H.y)); // orientation + vec4 hori = LE(h, v) * clr; // horizontal edges + vec4 vert = GE(h, v) * clr; // vertical edges + +FragColor = (res + 2 * hori + 4 * vert + 8 * or) / 15; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass2.vs b/shaders/ScaleFX.shader/scalefx-pass2.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass2.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass3.fs b/shaders/ScaleFX.shader/scalefx-pass3.fs new file mode 100644 index 00000000..fb6eba75 --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass3.fs @@ -0,0 +1,155 @@ +#version 150 + +/* + ScaleFX - Pass 3 + by Sp00kyFox, 2017-03-01 + +Filter: Nearest +Scale: 1x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 3 determines which edge level is present and prepares tags for subpixel +output in the final pass. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +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. + +*/ + +#define SFX_SCN 1.0 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// extract first bool4 from float4 - corners +bvec4 loadCorn(vec4 x){ + return bvec4(floor(mod(x*15 + 0.5, 2))); +} + +// extract second bool4 from float4 - horizontal edges +bvec4 loadHori(vec4 x){ + return bvec4(floor(mod(x*7.5 + 0.25, 2))); +} + +// extract third bool4 from float4 - vertical edges +bvec4 loadVert(vec4 x){ + return bvec4(floor(mod(x*3.75 + 0.125, 2))); +} + +// extract fourth bool4 from float4 - orientation +bvec4 loadOr(vec4 x){ + return bvec4(floor(mod(x*1.875 + 0.0625, 2))); +} + +void main() { +/* grid corners mids + + B x y x + D E F w y + H w z z + */ + +#define TEX(x, y) textureOffset(source[0], vTexCoord, ivec2(x, y)) + + // read data + vec4 E = TEX( 0, 0); + vec4 D = TEX(-1, 0), D0 = TEX(-2, 0), D1 = TEX(-3, 0); + vec4 F = TEX( 1, 0), F0 = TEX( 2, 0), F1 = TEX( 3, 0); + vec4 B = TEX( 0,-1), B0 = TEX( 0,-2), B1 = TEX( 0,-3); + vec4 H = TEX( 0, 1), H0 = TEX( 0, 2), H1 = TEX( 0, 3); + + // extract data + bvec4 Ec = loadCorn(E), Eh = loadHori(E), Ev = loadVert(E), Eo = loadOr(E); + bvec4 Dc = loadCorn(D), Dh = loadHori(D), Do = loadOr(D), D0c = loadCorn(D0), D0h = loadHori(D0), D1h = loadHori(D1); + bvec4 Fc = loadCorn(F), Fh = loadHori(F), Fo = loadOr(F), F0c = loadCorn(F0), F0h = loadHori(F0), F1h = loadHori(F1); + bvec4 Bc = loadCorn(B), Bv = loadVert(B), Bo = loadOr(B), B0c = loadCorn(B0), B0v = loadVert(B0), B1v = loadVert(B1); + bvec4 Hc = loadCorn(H), Hv = loadVert(H), Ho = loadOr(H), H0c = loadCorn(H0), H0v = loadVert(H0), H1v = loadVert(H1); + + + // lvl1 corners (hori, vert) + bool lvl1x = Ec.x && (Dc.z || Bc.z || SFX_SCN == 1); + bool lvl1y = Ec.y && (Fc.w || Bc.w || SFX_SCN == 1); + bool lvl1z = Ec.z && (Fc.x || Hc.x || SFX_SCN == 1); + bool lvl1w = Ec.w && (Dc.y || Hc.y || SFX_SCN == 1); + + // lvl2 mid (left, right / up, down) + bvec2 lvl2x = bvec2((Ec.x && Eh.y) && Dc.z, (Ec.y && Eh.x) && Fc.w); + bvec2 lvl2y = bvec2((Ec.y && Ev.z) && Bc.w, (Ec.z && Ev.y) && Hc.x); + bvec2 lvl2z = bvec2((Ec.w && Eh.z) && Dc.y, (Ec.z && Eh.w) && Fc.x); + bvec2 lvl2w = bvec2((Ec.x && Ev.w) && Bc.z, (Ec.w && Ev.x) && Hc.y); + + // lvl3 corners (hori, vert) + bvec2 lvl3x = bvec2(lvl2x.y && (Dh.y && Dh.x) && Fh.z, lvl2w.y && (Bv.w && Bv.x) && Hv.z); + bvec2 lvl3y = bvec2(lvl2x.x && (Fh.x && Fh.y) && Dh.w, lvl2y.y && (Bv.z && Bv.y) && Hv.w); + bvec2 lvl3z = bvec2(lvl2z.x && (Fh.w && Fh.z) && Dh.x, lvl2y.x && (Hv.y && Hv.z) && Bv.x); + bvec2 lvl3w = bvec2(lvl2z.y && (Dh.z && Dh.w) && Fh.y, lvl2w.x && (Hv.x && Hv.w) && Bv.y); + + // lvl4 corners (hori, vert) + bvec2 lvl4x = bvec2((Dc.x && Dh.y && Eh.x && Eh.y && Fh.x && Fh.y) && (D0c.z && D0h.w), (Bc.x && Bv.w && Ev.x && Ev.w && Hv.x && Hv.w) && (B0c.z && B0v.y)); + bvec2 lvl4y = bvec2((Fc.y && Fh.x && Eh.y && Eh.x && Dh.y && Dh.x) && (F0c.w && F0h.z), (Bc.y && Bv.z && Ev.y && Ev.z && Hv.y && Hv.z) && (B0c.w && B0v.x)); + bvec2 lvl4z = bvec2((Fc.z && Fh.w && Eh.z && Eh.w && Dh.z && Dh.w) && (F0c.x && F0h.y), (Hc.z && Hv.y && Ev.z && Ev.y && Bv.z && Bv.y) && (H0c.x && H0v.w)); + bvec2 lvl4w = bvec2((Dc.w && Dh.z && Eh.w && Eh.z && Fh.w && Fh.z) && (D0c.y && D0h.x), (Hc.w && Hv.x && Ev.w && Ev.x && Bv.w && Bv.x) && (H0c.y && H0v.z)); + + // lvl5 mid (left, right / up, down) + bvec2 lvl5x = bvec2(lvl4x.x && (F0h.x && F0h.y) && (D1h.z && D1h.w), lvl4y.x && (D0h.y && D0h.x) && (F1h.w && F1h.z)); + bvec2 lvl5y = bvec2(lvl4y.y && (H0v.y && H0v.z) && (B1v.w && B1v.x), lvl4z.y && (B0v.z && B0v.y) && (H1v.x && H1v.w)); + bvec2 lvl5z = bvec2(lvl4w.x && (F0h.w && F0h.z) && (D1h.y && D1h.x), lvl4z.x && (D0h.z && D0h.w) && (F1h.x && F1h.y)); + bvec2 lvl5w = bvec2(lvl4x.y && (H0v.x && H0v.w) && (B1v.z && B1v.y), lvl4w.y && (B0v.w && B0v.x) && (H1v.y && H1v.z)); + + // lvl6 corners (hori, vert) + bvec2 lvl6x = bvec2(lvl5x.y && (D1h.y && D1h.x), lvl5w.y && (B1v.w && B1v.x)); + bvec2 lvl6y = bvec2(lvl5x.x && (F1h.x && F1h.y), lvl5y.y && (B1v.z && B1v.y)); + bvec2 lvl6z = bvec2(lvl5z.x && (F1h.w && F1h.z), lvl5y.x && (H1v.y && H1v.z)); + bvec2 lvl6w = bvec2(lvl5z.y && (D1h.z && D1h.w), lvl5w.x && (H1v.x && H1v.w)); + + + // subpixels - 0 = E, 1 = D, 2 = D0, 3 = F, 4 = F0, 5 = B, 6 = B0, 7 = H, 8 = H0 + + vec4 crn; + crn.x = (lvl1x && Eo.x || lvl3x.x && Eo.y || lvl4x.x && Do.x || lvl6x.x && Fo.y) ? 5 : (lvl1x || lvl3x.y && !Eo.w || lvl4x.y && !Bo.x || lvl6x.y && !Ho.w) ? 1 : lvl3x.x ? 3 : lvl3x.y ? 7 : lvl4x.x ? 2 : lvl4x.y ? 6 : lvl6x.x ? 4 : lvl6x.y ? 8 : 0; + crn.y = (lvl1y && Eo.y || lvl3y.x && Eo.x || lvl4y.x && Fo.y || lvl6y.x && Do.x) ? 5 : (lvl1y || lvl3y.y && !Eo.z || lvl4y.y && !Bo.y || lvl6y.y && !Ho.z) ? 3 : lvl3y.x ? 1 : lvl3y.y ? 7 : lvl4y.x ? 4 : lvl4y.y ? 6 : lvl6y.x ? 2 : lvl6y.y ? 8 : 0; + crn.z = (lvl1z && Eo.z || lvl3z.x && Eo.w || lvl4z.x && Fo.z || lvl6z.x && Do.w) ? 7 : (lvl1z || lvl3z.y && !Eo.y || lvl4z.y && !Ho.z || lvl6z.y && !Bo.y) ? 3 : lvl3z.x ? 1 : lvl3z.y ? 5 : lvl4z.x ? 4 : lvl4z.y ? 8 : lvl6z.x ? 2 : lvl6z.y ? 6 : 0; + crn.w = (lvl1w && Eo.w || lvl3w.x && Eo.z || lvl4w.x && Do.w || lvl6w.x && Fo.z) ? 7 : (lvl1w || lvl3w.y && !Eo.x || lvl4w.y && !Ho.w || lvl6w.y && !Bo.x) ? 1 : lvl3w.x ? 3 : lvl3w.y ? 5 : lvl4w.x ? 2 : lvl4w.y ? 8 : lvl6w.x ? 4 : lvl6w.y ? 6 : 0; + + vec4 mid; + mid.x = (lvl2x.x && Eo.x || lvl2x.y && Eo.y || lvl5x.x && Do.x || lvl5x.y && Fo.y) ? 5 : lvl2x.x ? 1 : lvl2x.y ? 3 : lvl5x.x ? 2 : lvl5x.y ? 4 : (Ec.x && Dc.z && Ec.y && Fc.w) ? ( Eo.x ? Eo.y ? 5 : 3 : 1) : 0; + mid.y = (lvl2y.x && !Eo.y || lvl2y.y && !Eo.z || lvl5y.x && !Bo.y || lvl5y.y && !Ho.z) ? 3 : lvl2y.x ? 5 : lvl2y.y ? 7 : lvl5y.x ? 6 : lvl5y.y ? 8 : (Ec.y && Bc.w && Ec.z && Hc.x) ? (!Eo.y ? !Eo.z ? 3 : 7 : 5) : 0; + mid.z = (lvl2z.x && Eo.w || lvl2z.y && Eo.z || lvl5z.x && Do.w || lvl5z.y && Fo.z) ? 7 : lvl2z.x ? 1 : lvl2z.y ? 3 : lvl5z.x ? 2 : lvl5z.y ? 4 : (Ec.z && Fc.x && Ec.w && Dc.y) ? ( Eo.z ? Eo.w ? 7 : 1 : 3) : 0; + mid.w = (lvl2w.x && !Eo.x || lvl2w.y && !Eo.w || lvl5w.x && !Bo.x || lvl5w.y && !Ho.w) ? 1 : lvl2w.x ? 5 : lvl2w.y ? 7 : lvl5w.x ? 6 : lvl5w.y ? 8 : (Ec.w && Hc.y && Ec.x && Bc.z) ? (!Eo.w ? !Eo.x ? 1 : 5 : 7) : 0; + + + // ouput + FragColor = (crn + 9 * mid) / 80; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass3.vs b/shaders/ScaleFX.shader/scalefx-pass3.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass3.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass4.fs b/shaders/ScaleFX.shader/scalefx-pass4.fs new file mode 100644 index 00000000..fb815b9c --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass4.fs @@ -0,0 +1,88 @@ +#version 150 + +/* + ScaleFX - Pass 4 + by Sp00kyFox, 2017-03-01 + +Filter: Nearest +Scale: 3x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 4 outputs subpixels based on previously calculated tags. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +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. + +*/ + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 vTexCoord; +}; + +out vec4 FragColor; + +// extract corners +vec4 loadCrn(vec4 x){ + return floor(mod(x*80 + 0.5, 9)); +} + +// extract mids +vec4 loadMid(vec4 x){ + return floor(mod(x*8.888888 + 0.055555, 9)); +} + +void main() { +/* grid corners mids + + B x y x + D E F w y + H w z z + */ + + + // read data + vec4 E = texture(source[0], vTexCoord); + + // extract data + vec4 crn = loadCrn(E); + vec4 mid = loadMid(E); + + // determine subpixel + vec2 fp = floor(3.0 * fract(vTexCoord * sourceSize[0].xy)); + float sp = fp.y == 0 ? (fp.x == 0 ? crn.x : fp.x == 1 ? mid.x : crn.y) : (fp.y == 1 ? (fp.x == 0 ? mid.w : fp.x == 1 ? 0 : mid.y) : (fp.x == 0 ? crn.w : fp.x == 1 ? mid.z : crn.z)); + + // output coordinate - 0 = E, 1 = D, 2 = D0, 3 = F, 4 = F0, 5 = B, 6 = B0, 7 = H, 8 = H0 + vec2 res = sp == 0 ? vec2(0,0) : sp == 1 ? vec2(-1,0) : sp == 2 ? vec2(-2,0) : sp == 3 ? vec2(1,0) : sp == 4 ? vec2(2,0) : sp == 5 ? vec2(0,-1) : sp == 6 ? vec2(0,-2) : sp == 7 ? vec2(0,1) : vec2(0,2); + + // ouput + FragColor = texture(source[4], vTexCoord + res / sourceSize[0].xy); +} \ No newline at end of file diff --git a/shaders/ScaleFX.shader/scalefx-pass4.vs b/shaders/ScaleFX.shader/scalefx-pass4.vs new file mode 100644 index 00000000..18707b1e --- /dev/null +++ b/shaders/ScaleFX.shader/scalefx-pass4.vs @@ -0,0 +1,16 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; + +out Vertex { + vec2 vTexCoord; +}; + +uniform vec4 targetSize; +uniform vec4 sourceSize[]; + +void main() { + gl_Position = position; + vTexCoord = texCoord; +} \ No newline at end of file diff --git a/shaders/Sharp-Bilinear.shader/manifest.bml b/shaders/Sharp-Bilinear.shader/manifest.bml new file mode 100644 index 00000000..f04d6106 --- /dev/null +++ b/shaders/Sharp-Bilinear.shader/manifest.bml @@ -0,0 +1,8 @@ +input + filter: linear + +program + fragment: sharp-bilinear.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/Sharp-Bilinear.shader/sharp-bilinear.fs b/shaders/Sharp-Bilinear.shader/sharp-bilinear.fs new file mode 100644 index 00000000..4d19fa38 --- /dev/null +++ b/shaders/Sharp-Bilinear.shader/sharp-bilinear.fs @@ -0,0 +1,33 @@ +#version 150 + +// Sharp Bilinear +// Author: Themaister +// License: Public Domain + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +void main() { +float prescale = floor(targetSize.y / sourceSize[0].y); + vec2 texel = texCoord.xy * sourceSize[0].xy; + vec2 texel_floored = floor(texel); + vec2 s = fract(texel); + float region_range = 0.5 - 0.5 / prescale; + + // 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 = s - 0.5; + vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * prescale + 0.5; + + vec2 mod_texel = texel_floored + f; + + fragColor = texture(source[0], mod_texel / sourceSize[0].xy);; +} \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/custom-jinc2-sharper.fs b/shaders/xBR-mode7-480p.shader/custom-jinc2-sharper.fs new file mode 100644 index 00000000..bff93c68 --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/custom-jinc2-sharper.fs @@ -0,0 +1,166 @@ +#version 150 + +/* + Hyllian's jinc windowed-jinc 2-lobe sharper with anti-ringing Shader + + Copyright (C) 2011-2014 Hyllian/Jararaca - sergiogdb@gmail.com + + 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 sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define JINC2_WINDOW_SINC 0.42 +#define JINC2_SINC 0.92 +#define JINC2_AR_STRENGTH 1.0 + +#define mul(a,b) (b*a) + + + /* + This is an approximation of Jinc(x)*Jinc(x*r1/r2) for x < 2.5, + where r1 and r2 are the first two zeros of jinc function. + For a jinc 2-lobe best approximation, use A=0.5 and B=0.825. + */ + +// A=0.5, B=0.825 is the best jinc approximation for x<2.5. if B=1.0, it's a lanczos filter. +// Increase A to get more blur. Decrease it to get a sharper picture. +// B = 0.825 to get rid of dithering. Increase B to get a fine sharpness, though dithering returns. + +#define halfpi 1.5707963267948966192313216916398 +#define pi 3.1415926535897932384626433832795 +#define wa (JINC2_WINDOW_SINC*pi) +#define wb (JINC2_SINC*pi) + +const vec3 Y = vec3(0.299, 0.587, 0.114); + +float df(float A, float B) +{ + return abs(A-B); +} + +// Calculates the distance between two points +float d(vec2 pt1, vec2 pt2) +{ + vec2 v = pt2 - pt1; + return sqrt(dot(v,v)); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +vec4 resampler(vec4 x) +{ + vec4 res; + res = (x == vec4(0.0, 0.0, 0.0, 0.0)) ? vec4(wa*wb) : sin(x*wa)*sin(x*wb)/(x*x); + return res; +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[6] +#define FragColor fragColor + +void main(void) { + vec3 color; + mat4x4 weights; + + vec2 dx = vec2(1.0, 0.0); + vec2 dy = vec2(0.0, 1.0); + + vec2 pc = vTexCoord * SourceSize.xy; + + vec2 tc = (floor(pc-vec2(0.5,0.5))+vec2(0.5,0.5)); + + weights[0] = resampler(vec4(d(pc, tc -dx -dy), d(pc, tc -dy), d(pc, tc +dx -dy), d(pc, tc+2.0*dx -dy))); + weights[1] = resampler(vec4(d(pc, tc -dx ), d(pc, tc ), d(pc, tc +dx ), d(pc, tc+2.0*dx ))); + weights[2] = resampler(vec4(d(pc, tc -dx +dy), d(pc, tc +dy), d(pc, tc +dx +dy), d(pc, tc+2.0*dx +dy))); + weights[3] = resampler(vec4(d(pc, tc -dx+2.0*dy), d(pc, tc +2.0*dy), d(pc, tc +dx+2.0*dy), d(pc, tc+2.0*dx+2.0*dy))); + + //weights[0][0] = weights[0][3] = weights[3][0] = weights[3][3] = 0.0; + + dx = dx / SourceSize.xy; + dy = dy / SourceSize.xy; + tc = tc / SourceSize.xy; + + // reading the texels + + vec3 c00 = texture(Source, tc -dx -dy).xyz; + vec3 c10 = texture(Source, tc -dy).xyz; + vec3 c20 = texture(Source, tc +dx -dy).xyz; + vec3 c30 = texture(Source, tc+2.0*dx -dy).xyz; + vec3 c01 = texture(Source, tc -dx ).xyz; + vec3 c11 = texture(Source, tc ).xyz; + vec3 c21 = texture(Source, tc +dx ).xyz; + vec3 c31 = texture(Source, tc+2.0*dx ).xyz; + vec3 c02 = texture(Source, tc -dx +dy).xyz; + vec3 c12 = texture(Source, tc +dy).xyz; + vec3 c22 = texture(Source, tc +dx +dy).xyz; + vec3 c32 = texture(Source, tc+2.0*dx +dy).xyz; + vec3 c03 = texture(Source, tc -dx+2.0*dy).xyz; + vec3 c13 = texture(Source, tc +2.0*dy).xyz; + vec3 c23 = texture(Source, tc +dx+2.0*dy).xyz; + vec3 c33 = texture(Source, tc+2.0*dx+2.0*dy).xyz; + + + + color = mul(weights[0], mat4x3(c00, c10, c20, c30)); + color+= mul(weights[1], mat4x3(c01, c11, c21, c31)); + color+= mul(weights[2], mat4x3(c02, c12, c22, c32)); + color+= mul(weights[3], mat4x3(c03, c13, c23, c33)); + color = color/(dot(mul(weights, vec4(1.)), vec4(1.))); + + + + // Anti-ringing + // Get min/max samples + pc = vTexCoord; + c00 = texture(Source, pc ).xyz; + c11 = texture(Source, pc +dx ).xyz; + c21 = texture(Source, pc -dx ).xyz; + c12 = texture(Source, pc +dy).xyz; + c22 = texture(Source, pc -dy).xyz; + + + vec3 min_sample = min4(c11, c21, c12, c22); + vec3 max_sample = max4(c11, c21, c12, c22); + min_sample = min(min_sample, c00); + max_sample = max(max_sample, c00); + + vec3 aux = color; + + color = clamp(color, min_sample, max_sample); + color = mix(aux, color, JINC2_AR_STRENGTH); + + FragColor = vec4(color, 1.); +} \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/manifest.bml b/shaders/xBR-mode7-480p.shader/manifest.bml new file mode 100644 index 00000000..746ec3bb --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/manifest.bml @@ -0,0 +1,27 @@ +program + width: 100% + height: 100% + filter: nearest + fragment: super-2xbr-3d-pass0.fs + +program + width: 100% + height: 100% + filter: nearest + fragment: super-2xbr-3d-pass1.fs + +program + width: 100% + height: 100% + filter: nearest + vertex: super-2xbr-3d-pass2.vs + fragment: super-2xbr-3d-pass2.fs + +program + width: 200% + height: 200% + filter: nearest + fragment: custom-jinc2-sharper.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass0.fs b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass0.fs new file mode 100644 index 00000000..6fe79dd9 --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass0.fs @@ -0,0 +1,236 @@ +#version 150 + +/* + + ******* Super XBR 3D Shader - pass0 ******* + + Copyright (c) 2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define XBR_EDGE_STR 0.6 +#define XBR_WEIGHT 1.0 +#define XBR_ANTI_RINGING 1.0 + +#define mul(a,b) (b*a) + +#define XBR_RES 2.0 + +#define wp1 2.0 +#define wp2 1.0 +#define wp3 -1.0 +#define wp4 4.0 +#define wp5 -1.0 +#define wp6 1.0 + +#define weight1 (XBR_WEIGHT*1.29633/10.0) +#define weight2 (XBR_WEIGHT*1.75068/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + if (any(lessThan(fract(vTexCoord.xy*SourceSize.xy/XBR_RES) , vec2(0.5,0.5)))) + { + FragColor = texture(Source, vTexCoord); + return; + } + else + { + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES) + vec2(0.5, 0.5))*XBR_RES/SourceSize.xy; + + vec2 g1 = vec2(XBR_RES/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, XBR_RES/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -g1 -g2).xyz; + vec3 P1 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 P2 = texture(Source, vTexCoord -g1+2.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +2.0*g1+2.0*g2).xyz; + + vec3 B = texture(Source, vTexCoord -g2).xyz; + vec3 C = texture(Source, vTexCoord +g1-g2).xyz; + vec3 D = texture(Source, vTexCoord -g1 ).xyz; + vec3 E = texture(Source, vTexCoord ).xyz; + vec3 F = texture(Source, vTexCoord +g1 ).xyz; + vec3 G = texture(Source, vTexCoord -g1+g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1+g2).xyz; + + vec3 F4 = texture(Source, vTexCoord +2.0*g1 ).xyz; + vec3 I4 = texture(Source, vTexCoord +g2+2.0*g1 ).xyz; + vec3 H5 = texture(Source, vTexCoord +2.0*g2 ).xyz; + vec3 I5 = texture(Source, vTexCoord +2.0*g2+g1 ).xyz; + + vec3 F6 = texture(Source, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Source, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Source, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Source, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Source, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Source, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Source, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Source, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz == f0.yzw) && (h0.xyz == h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + // doesn't seem to be used anywhere, so commenting for performance +// bool ir_lv1 = (((e!=f) && (e!=h)) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : E; + + FragColor = vec4(color, 1.0); + } +} \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass1.fs b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass1.fs new file mode 100644 index 00000000..4fd2b3d6 --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass1.fs @@ -0,0 +1,214 @@ +#version 150 + +/* + + ******* Super XBR 3D Shader - pass1 ******* + + Copyright (c) 2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +const float XBR_EDGE_STR = 0.0; +const float XBR_WEIGHT = 0.0; +const float XBR_ANTI_RINGING = 0.0; + +#define mul(a,b) (b*a) + +#define wp1 8.0 +#define wp2 0.0 +#define wp3 0.0 +#define wp4 0.0 +#define wp5 0.0 +#define wp6 0.0 + +#define XBR_RES 2.0 + +#define weight1 (XBR_WEIGHT*1.75068/10.0) +#define weight2 (XBR_WEIGHT*1.29633/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[1] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + vec2 dir = fract(vTexCoord*SourceSize.xy/XBR_RES) - vec2(0.5,0.5); + if ((dir.x*dir.y)>0.0){ FragColor = texture(Source, vTexCoord); + return;} + else{ + + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES) + vec2(0.5, 0.5))*XBR_RES/SourceSize.xy; + + vec2 g1 = vec2((XBR_RES/2.0)/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, (XBR_RES/2.0)/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -3.0*g1 ).xyz; + vec3 P1 = texture(Source, vTexCoord -3.0*g2).xyz; + vec3 P2 = texture(Source, vTexCoord +3.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +3.0*g1 ).xyz; + + vec3 B = texture(Source, vTexCoord -2.0*g1 -g2).xyz; + vec3 C = texture(Source, vTexCoord -g1 -2.0*g2).xyz; + vec3 D = texture(Source, vTexCoord -2.0*g1 +g2).xyz; + vec3 E = texture(Source, vTexCoord -g1 ).xyz; + vec3 F = texture(Source, vTexCoord -g2).xyz; + vec3 G = texture(Source, vTexCoord -g1 +2.0*g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1 ).xyz; + + vec3 F4 = texture(Source, vTexCoord +g1 -2.0*g2).xyz; + vec3 I4 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 H5 = texture(Source, vTexCoord +g1 +2.0*g2).xyz; + vec3 I5 = texture(Source, vTexCoord +2.0*g1 +g2).xyz; + + vec3 A = texture(Source, vTexCoord).xyz; + + g1 *= 2.0; + g2 *= 2.0; + + vec3 F6 = texture(Original, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Original, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Original, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Original, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Original, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Original, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Original, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Original, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz==f0.yzw) && (h0.xyz==h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : A; + + FragColor = vec4(color, 1.0); + } +} \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.fs b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.fs new file mode 100644 index 00000000..2e4cf5c4 --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.fs @@ -0,0 +1,227 @@ +#version 150 + +/* + + ******* Super XBR Shader - pass2 ******* This pass is optional. + + Copyright (c) 2015 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +const float XBR_EDGE_STR = 0.6; +const float XBR_WEIGHT = 1.0; +const float XBR_ANTI_RINGING = 1.0; + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +// vec4 t1; +// vec4 t2; +// vec4 t3; +// vec4 t4; +}; + +out vec4 fragColor; + +#define mul(a,b) (b*a) + +#define XBR_RES 2.0 + +#define wp1 1.0 +#define wp2 0.0 +#define wp3 2.0 +#define wp4 3.0 +#define wp5 -2.0 +#define wp6 1.0 + +#define XBR_RES 2.0 + +#define weight1 (XBR_WEIGHT*1.29633/10.0) +#define weight2 (XBR_WEIGHT*1.75068/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[2] +#define FragColor fragColor + +void main(void) { + float dx = SourceSize.z; + float dy = SourceSize.w; + vec4 t1 = vTexCoord.xyxy + vec4(-2.0*dx, -2.0*dy, dx, dy); + vec4 t2 = vTexCoord.xyxy + vec4( -dx, -2.0*dy, 0, dy); + vec4 t3 = vTexCoord.xyxy + vec4(-2.0*dx, -dy, dx, 0); + vec4 t4 = vTexCoord.xyxy + vec4( -dx, -dy, 0, 0); + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES) + vec2(0.5, 0.5))*XBR_RES/SourceSize.xy; + + vec2 g1 = vec2(XBR_RES/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, XBR_RES/SourceSize.y); + + vec3 P0 = texture(Source, t1.xy).xyz; + vec3 P1 = texture(Source, t1.zy).xyz; + vec3 P2 = texture(Source, t1.xw).xyz; + vec3 P3 = texture(Source, t1.zw).xyz; + + vec3 B = texture(Source, t2.xy).xyz; + vec3 C = texture(Source, t2.zy).xyz; + vec3 H5 = texture(Source, t2.xw).xyz; + vec3 I5 = texture(Source, t2.zw).xyz; + + vec3 D = texture(Source, t3.xy).xyz; + vec3 F4 = texture(Source, t3.zy).xyz; + vec3 G = texture(Source, t3.xw).xyz; + vec3 I4 = texture(Source, t3.zw).xyz; + + vec3 E = texture(Source, t4.xy).xyz; + vec3 F = texture(Source, t4.zy).xyz; + vec3 H = texture(Source, t4.xw).xyz; + vec3 I = texture(Source, t4.zw).xyz; + + vec3 A = texture(Source, vTexCoord).xyz; + + vec3 F6 = texture(Original, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Original, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Original, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Original, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Original, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Original, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Original, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Original, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz==f0.yzw) && (h0.xyz==h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : A; + + FragColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.vs b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.vs new file mode 100644 index 00000000..92323126 --- /dev/null +++ b/shaders/xBR-mode7-480p.shader/super-2xbr-3d-pass2.vs @@ -0,0 +1,29 @@ +#version 150 + +in vec4 position; +in vec2 texCoord; +in vec4 sourceSize[]; +in vec4 targetSize; + +out Vertex { + vec2 texCoord; +// vec4 t1; +// vec4 t2; +// vec4 t3; +// vec4 t4; +} vertexOut; + +#define SourceSize sourceSize[0] + +void main() +{ + vertexOut.texCoord = texCoord.xy * 1.0001; + gl_Position = position; + + float dx = SourceSize.z; + float dy = SourceSize.w; +// vertexOut.t1 = texCoord.xyxy + vec4(-2.0*dx, -2.0*dy, dx, dy); +// vertexOut.t2 = texCoord.xyxy + vec4( -dx, -2.0*dy, 0, dy); +// vertexOut.t3 = texCoord.xyxy + vec4(-2.0*dx, -dy, dx, 0); +// vertexOut.t4 = texCoord.xyxy + vec4( -dx, -dy, 0, 0); // dunno why this doesn't want to carry over, but whatever +} \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/custom-jinc2-sharper.fs b/shaders/xBR-mode7-960p.shader/custom-jinc2-sharper.fs new file mode 100644 index 00000000..bff93c68 --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/custom-jinc2-sharper.fs @@ -0,0 +1,166 @@ +#version 150 + +/* + Hyllian's jinc windowed-jinc 2-lobe sharper with anti-ringing Shader + + Copyright (C) 2011-2014 Hyllian/Jararaca - sergiogdb@gmail.com + + 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 sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define JINC2_WINDOW_SINC 0.42 +#define JINC2_SINC 0.92 +#define JINC2_AR_STRENGTH 1.0 + +#define mul(a,b) (b*a) + + + /* + This is an approximation of Jinc(x)*Jinc(x*r1/r2) for x < 2.5, + where r1 and r2 are the first two zeros of jinc function. + For a jinc 2-lobe best approximation, use A=0.5 and B=0.825. + */ + +// A=0.5, B=0.825 is the best jinc approximation for x<2.5. if B=1.0, it's a lanczos filter. +// Increase A to get more blur. Decrease it to get a sharper picture. +// B = 0.825 to get rid of dithering. Increase B to get a fine sharpness, though dithering returns. + +#define halfpi 1.5707963267948966192313216916398 +#define pi 3.1415926535897932384626433832795 +#define wa (JINC2_WINDOW_SINC*pi) +#define wb (JINC2_SINC*pi) + +const vec3 Y = vec3(0.299, 0.587, 0.114); + +float df(float A, float B) +{ + return abs(A-B); +} + +// Calculates the distance between two points +float d(vec2 pt1, vec2 pt2) +{ + vec2 v = pt2 - pt1; + return sqrt(dot(v,v)); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +vec4 resampler(vec4 x) +{ + vec4 res; + res = (x == vec4(0.0, 0.0, 0.0, 0.0)) ? vec4(wa*wb) : sin(x*wa)*sin(x*wb)/(x*x); + return res; +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[6] +#define FragColor fragColor + +void main(void) { + vec3 color; + mat4x4 weights; + + vec2 dx = vec2(1.0, 0.0); + vec2 dy = vec2(0.0, 1.0); + + vec2 pc = vTexCoord * SourceSize.xy; + + vec2 tc = (floor(pc-vec2(0.5,0.5))+vec2(0.5,0.5)); + + weights[0] = resampler(vec4(d(pc, tc -dx -dy), d(pc, tc -dy), d(pc, tc +dx -dy), d(pc, tc+2.0*dx -dy))); + weights[1] = resampler(vec4(d(pc, tc -dx ), d(pc, tc ), d(pc, tc +dx ), d(pc, tc+2.0*dx ))); + weights[2] = resampler(vec4(d(pc, tc -dx +dy), d(pc, tc +dy), d(pc, tc +dx +dy), d(pc, tc+2.0*dx +dy))); + weights[3] = resampler(vec4(d(pc, tc -dx+2.0*dy), d(pc, tc +2.0*dy), d(pc, tc +dx+2.0*dy), d(pc, tc+2.0*dx+2.0*dy))); + + //weights[0][0] = weights[0][3] = weights[3][0] = weights[3][3] = 0.0; + + dx = dx / SourceSize.xy; + dy = dy / SourceSize.xy; + tc = tc / SourceSize.xy; + + // reading the texels + + vec3 c00 = texture(Source, tc -dx -dy).xyz; + vec3 c10 = texture(Source, tc -dy).xyz; + vec3 c20 = texture(Source, tc +dx -dy).xyz; + vec3 c30 = texture(Source, tc+2.0*dx -dy).xyz; + vec3 c01 = texture(Source, tc -dx ).xyz; + vec3 c11 = texture(Source, tc ).xyz; + vec3 c21 = texture(Source, tc +dx ).xyz; + vec3 c31 = texture(Source, tc+2.0*dx ).xyz; + vec3 c02 = texture(Source, tc -dx +dy).xyz; + vec3 c12 = texture(Source, tc +dy).xyz; + vec3 c22 = texture(Source, tc +dx +dy).xyz; + vec3 c32 = texture(Source, tc+2.0*dx +dy).xyz; + vec3 c03 = texture(Source, tc -dx+2.0*dy).xyz; + vec3 c13 = texture(Source, tc +2.0*dy).xyz; + vec3 c23 = texture(Source, tc +dx+2.0*dy).xyz; + vec3 c33 = texture(Source, tc+2.0*dx+2.0*dy).xyz; + + + + color = mul(weights[0], mat4x3(c00, c10, c20, c30)); + color+= mul(weights[1], mat4x3(c01, c11, c21, c31)); + color+= mul(weights[2], mat4x3(c02, c12, c22, c32)); + color+= mul(weights[3], mat4x3(c03, c13, c23, c33)); + color = color/(dot(mul(weights, vec4(1.)), vec4(1.))); + + + + // Anti-ringing + // Get min/max samples + pc = vTexCoord; + c00 = texture(Source, pc ).xyz; + c11 = texture(Source, pc +dx ).xyz; + c21 = texture(Source, pc -dx ).xyz; + c12 = texture(Source, pc +dy).xyz; + c22 = texture(Source, pc -dy).xyz; + + + vec3 min_sample = min4(c11, c21, c12, c22); + vec3 max_sample = max4(c11, c21, c12, c22); + min_sample = min(min_sample, c00); + max_sample = max(max_sample, c00); + + vec3 aux = color; + + color = clamp(color, min_sample, max_sample); + color = mix(aux, color, JINC2_AR_STRENGTH); + + FragColor = vec4(color, 1.); +} \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/manifest.bml b/shaders/xBR-mode7-960p.shader/manifest.bml new file mode 100644 index 00000000..ca3d312a --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/manifest.bml @@ -0,0 +1,30 @@ +program + width: 100% + height: 100% + filter: nearest + fragment: super-4xbr-3d-pass0.fs + +program + width: 100% + height: 100% + filter: nearest + fragment: super-4xbr-3d-pass1.fs + +program + width: 100% + height: 100% + filter: nearest + fragment: super-4xbr-3d-pass2.fs + +program + width: 100% + height: 100% + filter: nearest + fragment: super-4xbr-3d-pass3.fs + +program + filter: nearest + fragment: custom-jinc2-sharper.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass0.fs b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass0.fs new file mode 100644 index 00000000..b776db96 --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass0.fs @@ -0,0 +1,236 @@ +#version 150 + +/* + + ******* Super 4XBR 3D Shader - pass0 ******* + + Copyright (c) 2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define XBR_EDGE_STR 2.0 +#define XBR_WEIGHT 1.0 +#define XBR_ANTI_RINGING 1.0 + +#define mul(a,b) (b*a) + +#define wp1 2.0 +#define wp2 1.0 +#define wp3 -1.0 +#define wp4 4.0 +#define wp5 -1.0 +#define wp6 1.0 + +#define XBR_RES 4.0 + +#define weight1 (XBR_WEIGHT*1.29633/10.0) +#define weight2 (XBR_WEIGHT*1.75068/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + if (any(lessThan(fract(vTexCoord*SourceSize.xy/XBR_RES) , vec2(0.5,0.5)))) + { + FragColor = texture(Source, vTexCoord); + return; + } + else + { + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES) + vec2(0.5, 0.5))*XBR_RES*SourceSize.zw; + + vec2 g1 = vec2(XBR_RES/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, XBR_RES/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -g1 -g2).xyz; + vec3 P1 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 P2 = texture(Source, vTexCoord -g1+2.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +2.0*g1+2.0*g2).xyz; + + vec3 B = texture(Source, vTexCoord -g2).xyz; + vec3 C = texture(Source, vTexCoord +g1-g2).xyz; + vec3 D = texture(Source, vTexCoord -g1 ).xyz; + vec3 E = texture(Source, vTexCoord ).xyz; + vec3 F = texture(Source, vTexCoord +g1 ).xyz; + vec3 G = texture(Source, vTexCoord -g1+g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1+g2).xyz; + + vec3 F4 = texture(Source, vTexCoord +2.0*g1 ).xyz; + vec3 I4 = texture(Source, vTexCoord +g2+2.0*g1 ).xyz; + vec3 H5 = texture(Source, vTexCoord +2.0*g2 ).xyz; + vec3 I5 = texture(Source, vTexCoord +2.0*g2+g1 ).xyz; + + vec3 F6 = texture(Source, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Source, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Source, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Source, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Source, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Source, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Source, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Source, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz == f0.yzw) && (h0.xyz == h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + //bool ir_lv1 = (((e!=f) && (e!=h)) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : E; + + FragColor = vec4(color, 1.0); + } +} \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass1.fs b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass1.fs new file mode 100644 index 00000000..d9bd7620 --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass1.fs @@ -0,0 +1,227 @@ +#version 150 + +/* + + ******* Super 4XBR 3D Shader - pass1 ******* + + Copyright (c) 2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +const float XBR_EDGE_STR = 0.0; +const float XBR_WEIGHT = 0.0; +const float XBR_ANTI_RINGING = 0.0; + +#define mul(a,b) (b*a) + +#define wp1 8.0 +#define wp2 0.0 +#define wp3 0.0 +#define wp4 0.0 +#define wp5 0.0 +#define wp6 0.0 + +#define XBR_RES 4.0 + +#define weight1 (XBR_WEIGHT*1.75068/10.0) +#define weight2 (XBR_WEIGHT*1.29633/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[1] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + vec2 dir = fract(vTexCoord*SourceSize.xy/XBR_RES) - vec2(0.5,0.5); + if ((dir.x*dir.y)>0.0){ FragColor = texture(Source, vTexCoord); + return;} + else{ + + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES) + vec2(0.5, 0.5))*XBR_RES*SourceSize.zw; + + vec2 g1 = vec2((XBR_RES/2.0)/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, (XBR_RES/2.0)/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -3.0*g1 ).xyz; + vec3 P1 = texture(Source, vTexCoord -3.0*g2).xyz; + vec3 P2 = texture(Source, vTexCoord +3.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +3.0*g1 ).xyz; + + vec3 B = texture(Source, vTexCoord -2.0*g1 -g2).xyz; + vec3 C = texture(Source, vTexCoord -g1 -2.0*g2).xyz; + vec3 D = texture(Source, vTexCoord -2.0*g1 +g2).xyz; + vec3 E = texture(Source, vTexCoord -g1 ).xyz; + vec3 F = texture(Source, vTexCoord -g2).xyz; + vec3 G = texture(Source, vTexCoord -g1 +2.0*g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1 ).xyz; + + vec3 F4 = texture(Source, vTexCoord +g1 -2.0*g2).xyz; + vec3 I4 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 H5 = texture(Source, vTexCoord +g1 +2.0*g2).xyz; + vec3 I5 = texture(Source, vTexCoord +2.0*g1 +g2).xyz; + + vec3 A = texture(Source, vTexCoord).xyz; + + g1 *= 2.0; + g2 *= 2.0; + + vec3 F6 = texture(Original, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Original, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Original, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Original, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Original, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Original, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Original, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Original, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz==f0.yzw) && (h0.xyz==h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + //bool ir_lv1 = (((e!=f) && (e!=h)) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : A; + + FragColor = vec4(color, 1.0); + } +} \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass2.fs b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass2.fs new file mode 100644 index 00000000..8bfd2127 --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass2.fs @@ -0,0 +1,233 @@ +#version 150 + +/* + + ******* Super 4XBR Shader - pass2 ******* + + Copyright (c) 2015 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +const float XBR_EDGE_STR = 0.0; +const float XBR_WEIGHT = 0.0; +const float XBR_ANTI_RINGING = 0.0; + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define mul(a,b) (b*a) + +#define wp1 2.0 +#define wp2 1.0 +#define wp3 -1.0 +#define wp4 4.0 +#define wp5 -1.0 +#define wp6 1.0 + +#define XBR_RES2 2.0 + +#define weight1 (XBR_WEIGHT*1.29633/10.0) +#define weight2 (XBR_WEIGHT*1.75068/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[2] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + if (any(lessThan(fract(vTexCoord*SourceSize.xy/XBR_RES2),vec2(0.5,0.5)))){ FragColor = texture(Source, vTexCoord); return;} + + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES2) + vec2(0.5, 0.5))*XBR_RES2*SourceSize.zw; + + vec2 g1 = vec2(XBR_RES2/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, XBR_RES2/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -g1 -g2).xyz; + vec3 P1 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 P2 = texture(Source, vTexCoord -g1+2.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +2.0*g1+2.0*g2).xyz; + + vec3 B = texture(Source, vTexCoord -g2).xyz; + vec3 C = texture(Source, vTexCoord +g1-g2).xyz; + vec3 D = texture(Source, vTexCoord -g1 ).xyz; + vec3 E = texture(Source, vTexCoord ).xyz; + vec3 F = texture(Source, vTexCoord +g1 ).xyz; + vec3 G = texture(Source, vTexCoord -g1+g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1+g2).xyz; + + vec3 F4 = texture(Source,vTexCoord +2.0*g1 ).xyz; + vec3 I4 = texture(Source,vTexCoord +g2+2.0*g1 ).xyz; + vec3 H5 = texture(Source,vTexCoord +2.0*g2 ).xyz; + vec3 I5 = texture(Source,vTexCoord +2.0*g2+g1 ).xyz; + + vec3 F6 = texture(Source, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Source, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Source, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Source, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Source, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Source, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Source, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Source, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz==f0.yzw) && (h0.xyz==h0.yzw)); + + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + //bool ir_lv1 = (((e!=f) && (e!=h)) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : E; + + FragColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass3.fs b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass3.fs new file mode 100644 index 00000000..ef742c8e --- /dev/null +++ b/shaders/xBR-mode7-960p.shader/super-4xbr-3d-pass3.fs @@ -0,0 +1,237 @@ +#version 150 + +/* + + ******* Super 4XBR Shader - pass3 ******* + + Copyright (c) 2015 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +const float XBR_EDGE_STR = 0.0; +const float XBR_WEIGHT = 0.0; +const float XBR_ANTI_RINGING = 0.0; + +uniform sampler2D source[]; +uniform sampler2D frame[]; +uniform sampler2D pixmap[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define mul(a,b) (b*a) + +#define wp1 8.0 +#define wp2 0.0 +#define wp3 0.0 +#define wp4 0.0 +#define wp5 0.0 +#define wp6 0.0 + +#define XBR_RES2 2.0 + +#define weight1 (XBR_WEIGHT*1.75068/10.0) +#define weight2 (XBR_WEIGHT*1.29633/10.0/2.0) + +const vec3 Y = vec3(.2126, .7152, .0722); + +const vec3 dtt = vec3(65536.,255.,1.); + +vec4 reduce4(vec3 A, vec3 B, vec3 C, vec3 D) +{ + return mul(mat4x3(A, B, C, D), dtt); +} + +float RGBtoYUV(vec3 color) +{ + return dot(color, Y); +} + +float df(float A, float B) +{ + return abs(A-B); +} + +bool eq(float A, float B) +{ + return (df(A, B) < 15.0); +} + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + +float d_wd(float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3) +{ + return (wp1*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp2*(df(d2,d3) + df(d0,d1)) + wp3*(df(d1,d3) + df(d0,d2)) + wp4*df(d1,d2) + wp5*(df(c0,c2) + df(e1,e3)) + wp6*(df(b0,b1) + df(f2,f3))); +} + +float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4) +{ + return ( wp4*(df(i1,i2)+df(i3,i4)) + wp1*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp3*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4))); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +#define vTexCoord (texCoord * 1.0001) +#define SourceSize sourceSize[0] +#define Source source[0] +#define Original source[3] +#define FragColor fragColor + +void main(void) { + //Skip pixels on wrong grid + vec2 dir = fract(vTexCoord*SourceSize.xy/XBR_RES2) - vec2(0.5,0.5); + if ((dir.x*dir.y)>0.0){ FragColor = texture(Source, vTexCoord); + return;} + else{ + + vec2 tex = (floor(vTexCoord*SourceSize.xy/XBR_RES2) + vec2(0.5, 0.5))*XBR_RES2*SourceSize.zw; + + vec2 g1 = vec2((XBR_RES2/2.0)/SourceSize.x, 0.0); + vec2 g2 = vec2(0.0, (XBR_RES2/2.0)/SourceSize.y); + + vec3 P0 = texture(Source, vTexCoord -3.0*g1 ).xyz; + vec3 P1 = texture(Source, vTexCoord -3.0*g2).xyz; + vec3 P2 = texture(Source, vTexCoord +3.0*g2).xyz; + vec3 P3 = texture(Source, vTexCoord +3.0*g1 ).xyz; + + vec3 B = texture(Source, vTexCoord -2.0*g1 -g2).xyz; + vec3 C = texture(Source, vTexCoord -g1 -2.0*g2).xyz; + vec3 D = texture(Source, vTexCoord -2.0*g1 +g2).xyz; + vec3 E = texture(Source, vTexCoord -g1 ).xyz; + vec3 F = texture(Source, vTexCoord -g2).xyz; + vec3 G = texture(Source, vTexCoord -g1 +2.0*g2).xyz; + vec3 H = texture(Source, vTexCoord +g2).xyz; + vec3 I = texture(Source, vTexCoord +g1 ).xyz; + + vec3 F4 = texture(Source, vTexCoord +g1 -2.0*g2).xyz; + vec3 I4 = texture(Source, vTexCoord +2.0*g1 -g2).xyz; + vec3 H5 = texture(Source, vTexCoord +g1 +2.0*g2).xyz; + vec3 I5 = texture(Source, vTexCoord +2.0*g1 +g2).xyz; + + vec3 A = texture(Source, vTexCoord).xyz; + + g1 *= 2.0; + g2 *= 2.0; + + vec3 F6 = texture(Original, tex +g1+0.25*g1+0.25*g2).xyz; + vec3 F7 = texture(Original, tex +g1+0.25*g1-0.25*g2).xyz; + vec3 F8 = texture(Original, tex +g1-0.25*g1-0.25*g2).xyz; + vec3 F9 = texture(Original, tex +g1-0.25*g1+0.25*g2).xyz; + + vec3 H6 = texture(Original, tex +0.25*g1+0.25*g2+g2).xyz; + vec3 H7 = texture(Original, tex +0.25*g1-0.25*g2+g2).xyz; + vec3 H8 = texture(Original, tex -0.25*g1-0.25*g2+g2).xyz; + vec3 H9 = texture(Original, tex -0.25*g1+0.25*g2+g2).xyz; + + vec4 f0 = reduce4(F6, F7, F8, F9); + vec4 h0 = reduce4(H6, H7, H8, H9); + + bool block_3d = ((f0.xyz == f0.yzw) && (h0.xyz == h0.yzw)); + + float b = RGBtoYUV( B ); + float c = RGBtoYUV( C ); + float d = RGBtoYUV( D ); + float e = RGBtoYUV( E ); + float f = RGBtoYUV( F ); + float g = RGBtoYUV( G ); + float h = RGBtoYUV( H ); + float i = RGBtoYUV( I ); + + float i4 = RGBtoYUV( I4 ); float p0 = RGBtoYUV( P0 ); + float i5 = RGBtoYUV( I5 ); float p1 = RGBtoYUV( P1 ); + float h5 = RGBtoYUV( H5 ); float p2 = RGBtoYUV( P2 ); + float f4 = RGBtoYUV( F4 ); float p3 = RGBtoYUV( P3 ); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Calc edgeness in diagonal directions. */ + float d_edge = (d_wd( d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 )); + + /* Calc edgeness in horizontal/vertical directions. */ + float hv_edge = (hv_wd(f, i, e, h, c, i5, b, h5) - hv_wd(e, f, h, i, d, f4, g, i4)); + + float limits = XBR_EDGE_STR + 0.000001; + float edge_strength = smoothstep(0.0, limits, abs(d_edge)); + + /* Filter weights. Two taps only. */ + vec4 w1 = vec4(-weight1, weight1+0.5, weight1+0.5, -weight1); + vec4 w2 = vec4(-weight2, weight2+0.25, weight2+0.25, -weight2); + + /* Filtering and normalization in four direction generating four colors. */ + vec3 c1 = mul(w1, mat4x3( P2, H, F, P1 )); + vec3 c2 = mul(w1, mat4x3( P0, E, I, P3 )); + vec3 c3 = mul(w2, mat4x3(D+G, E+H, F+I, F4+I4)); + vec3 c4 = mul(w2, mat4x3(C+B, F+E, I+H, I5+H5)); + + //bool ir_lv1 = (((e!=f) && (e!=h)) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + + /* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */ + vec3 color = mix(mix(c1, c2, step(0.0, d_edge)), mix(c3, c4, step(0.0, hv_edge)), 1. - edge_strength); + +/* + P1 + |P0|B |C |P1| C F4 |a0|b1|c2|d3| + |D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2| + |G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4| + |P2|H5|I5|P3| D H I5 |d0|e1|f2|g3| + G H5 + P2 +*/ + + /* Anti-ringing code. */ + vec3 min_sample = min4( E, F, H, I ) + (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + vec3 max_sample = max4( E, F, H, I ) - (1.-XBR_ANTI_RINGING)*mix((P2-H)*(F-P1), (P0-E)*(I-P3), step(0.0, d_edge)); + + color = clamp(color, min_sample, max_sample); + + color = (block_3d) ? color : A; + + FragColor = vec4(color, 1.0); + } +} \ No newline at end of file diff --git a/shaders/xBRZ.shader/fxaa.fs b/shaders/xBRZ.shader/fxaa.fs new file mode 100644 index 00000000..71702f10 --- /dev/null +++ b/shaders/xBRZ.shader/fxaa.fs @@ -0,0 +1,251 @@ +#version 150 + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +/** + * @license + * Copyright (c) 2011 NVIDIA Corporation. All rights reserved. + * + * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED + * *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS + * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA + * OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS + * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY + * OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* +FXAA_PRESET - Choose compile-in knob preset 0-5. +------------------------------------------------------------------------------ +FXAA_EDGE_THRESHOLD - The minimum amount of local contrast required + to apply algorithm. + 1.0/3.0 - too little + 1.0/4.0 - good start + 1.0/8.0 - applies to more edges + 1.0/16.0 - overkill +------------------------------------------------------------------------------ +FXAA_EDGE_THRESHOLD_MIN - Trims the algorithm from processing darks. + Perf optimization. + 1.0/32.0 - visible limit (smaller isn't visible) + 1.0/16.0 - good compromise + 1.0/12.0 - upper limit (seeing artifacts) +------------------------------------------------------------------------------ +FXAA_SEARCH_STEPS - Maximum number of search steps for end of span. +------------------------------------------------------------------------------ +FXAA_SEARCH_THRESHOLD - Controls when to stop searching. + 1.0/4.0 - seems to be the best quality wise +------------------------------------------------------------------------------ +FXAA_SUBPIX_TRIM - Controls sub-pixel aliasing removal. + 1.0/2.0 - low removal + 1.0/3.0 - medium removal + 1.0/4.0 - default removal + 1.0/8.0 - high removal + 0.0 - complete removal +------------------------------------------------------------------------------ +FXAA_SUBPIX_CAP - Insures fine detail is not completely removed. + This is important for the transition of sub-pixel detail, + like fences and wires. + 3.0/4.0 - default (medium amount of filtering) + 7.0/8.0 - high amount of filtering + 1.0 - no capping of sub-pixel aliasing removal +*/ + +#ifndef FXAA_PRESET + #define FXAA_PRESET 5 +#endif +#if (FXAA_PRESET == 3) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/16.0) + #define FXAA_SEARCH_STEPS 16 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +#if (FXAA_PRESET == 4) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 24 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +#if (FXAA_PRESET == 5) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 32 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif + +#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM)) + +// Return the luma, the estimation of luminance from rgb inputs. +// This approximates luma using one FMA instruction, +// skipping normalization and tossing out blue. +// FxaaLuma() will range 0.0 to 2.963210702. +float FxaaLuma(vec3 rgb) { + return rgb.y * (0.587/0.299) + rgb.x; +} + +vec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) { + return (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b); +} + +vec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) { + float x = pos.x + float(off.x) * rcpFrame.x; + float y = pos.y + float(off.y) * rcpFrame.y; + return texture(tex, vec2(x, y)); +} + +// pos is the output of FxaaVertexShader interpolated across screen. +// xy -> actual texture position {0.0 to 1.0} +// rcpFrame should be a uniform equal to {1.0/frameWidth, 1.0/frameHeight} +vec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame) +{ + vec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz; + vec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz; + vec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz; + vec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz; + vec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz; + + float lumaN = FxaaLuma(rgbN); + float lumaW = FxaaLuma(rgbW); + float lumaM = FxaaLuma(rgbM); + float lumaE = FxaaLuma(rgbE); + float lumaS = FxaaLuma(rgbS); + float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE))); + float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE))); + + float range = rangeMax - rangeMin; + if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD)) + { + return rgbM; + } + + vec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS; + + float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25; + float rangeL = abs(lumaL - lumaM); + float blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE; + blendL = min(FXAA_SUBPIX_CAP, blendL); + + vec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz; + vec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz; + vec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz; + vec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz; + rgbL += (rgbNW + rgbNE + rgbSW + rgbSE); + rgbL *= vec3(1.0/9.0); + + float lumaNW = FxaaLuma(rgbNW); + float lumaNE = FxaaLuma(rgbNE); + float lumaSW = FxaaLuma(rgbSW); + float lumaSE = FxaaLuma(rgbSE); + + float edgeVert = + abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) + + abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) + + abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE)); + float edgeHorz = + abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) + + abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) + + abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE)); + + bool horzSpan = edgeHorz >= edgeVert; + float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x; + + if(!horzSpan) + { + lumaN = lumaW; + lumaS = lumaE; + } + + float gradientN = abs(lumaN - lumaM); + float gradientS = abs(lumaS - lumaM); + lumaN = (lumaN + lumaM) * 0.5; + lumaS = (lumaS + lumaM) * 0.5; + + if (gradientN < gradientS) + { + lumaN = lumaS; + lumaN = lumaS; + gradientN = gradientS; + lengthSign *= -1.0; + } + + vec2 posN; + posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5); + posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0); + + gradientN *= FXAA_SEARCH_THRESHOLD; + + vec2 posP = posN; + vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y); + float lumaEndN = lumaN; + float lumaEndP = lumaN; + bool doneN = false; + bool doneP = false; + posN += offNP * vec2(-1.0, -1.0); + posP += offNP * vec2( 1.0, 1.0); + + for(int i = 0; i < FXAA_SEARCH_STEPS; i++) { + if(!doneN) + { + lumaEndN = FxaaLuma(texture(tex, posN.xy).xyz); + } + if(!doneP) + { + lumaEndP = FxaaLuma(texture(tex, posP.xy).xyz); + } + + doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN); + doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN); + + if(doneN && doneP) + { + break; + } + if(!doneN) + { + posN -= offNP; + } + if(!doneP) + { + posP += offNP; + } + } + + float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y; + float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y; + bool directionN = dstN < dstP; + lumaEndN = directionN ? lumaEndN : lumaEndP; + + if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0)) + { + lengthSign = 0.0; + } + + + float spanLength = (dstP + dstN); + dstN = directionN ? dstN : dstP; + float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign; + vec3 rgbF = texture(tex, vec2( + pos.x + (horzSpan ? 0.0 : subPixelOffset), + pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz; + return FxaaLerp3(rgbL, rgbF, blendL); +} + +void main() { + fragColor = vec4(FxaaPixelShader(texCoord, source[0], vec2(sourceSize[0].z, sourceSize[0].w)), 1.0) * 1.0; +} \ No newline at end of file diff --git a/shaders/xBRZ.shader/manifest.bml b/shaders/xBRZ.shader/manifest.bml new file mode 100644 index 00000000..f7d4084f --- /dev/null +++ b/shaders/xBRZ.shader/manifest.bml @@ -0,0 +1,17 @@ +input + filter: nearest + +program + filter: nearest + fragment: xBRZ-Freescale-p0.fs + +program + filter: nearest + fragment: xBRZ-Freescale-p1.fs + +program + filter: linear + fragment: fxaa.fs + +output + filter: linear \ No newline at end of file diff --git a/shaders/xBRZ.shader/xBRZ-Freescale-p0.fs b/shaders/xBRZ.shader/xBRZ-Freescale-p0.fs new file mode 100644 index 00000000..dc02091c --- /dev/null +++ b/shaders/xBRZ.shader/xBRZ-Freescale-p0.fs @@ -0,0 +1,265 @@ +#version 150 + +// xBRZ freescale +// based on : + +// 4xBRZ shader - Copyright (C) 2014-2016 DeSmuME team +// +// This file 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 file 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 the this software. If not, see . + + +/* + Hyllian's xBR-vertex code and texel mapping + + Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define BLEND_NONE 0 +#define BLEND_NORMAL 1 +#define BLEND_DOMINANT 2 +#define LUMINANCE_WEIGHT 1.0 +#define EQUAL_COLOR_TOLERANCE 30.0/255.0 +#define STEEP_DIRECTION_THRESHOLD 2.2 +#define DOMINANT_DIRECTION_THRESHOLD 3.6 + +float DistYCbCr(vec3 pixA, vec3 pixB) +{ + const vec3 w = vec3(0.2627, 0.6780, 0.0593); + const float scaleB = 0.5 / (1.0 - w.b); + const float scaleR = 0.5 / (1.0 - w.r); + vec3 diff = pixA - pixB; + float Y = dot(diff.rgb, w); + float Cb = scaleB * (diff.b - Y); + float Cr = scaleR * (diff.r - Y); + + return sqrt(((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr)); +} + +bool IsPixEqual(const vec3 pixA, const vec3 pixB) +{ + return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); +} + +float get_left_ratio(vec2 center, vec2 origin, vec2 direction, vec2 scale) +{ + vec2 P0 = center - origin; + vec2 proj = direction * (dot(P0, direction) / dot(direction, direction)); + vec2 distv = P0 - proj; + vec2 orth = vec2(-direction.y, direction.x); + float side = sign(dot(P0, orth)); + float v = side * length(distv * scale); + +// return step(0, v); + return smoothstep(-sqrt(2.0)/2.0, sqrt(2.0)/2.0, v); +} + +#define eq(a,b) (a == b) +#define neq(a,b) (a != b) + +#define P(x,y) texture(source[0], coord + sourceSize[0].zw * vec2(x, y)).rgb + +void main() { + //--------------------------------------- + // Input Pixel Mapping: -|x|x|x|- + // x|A|B|C|x + // x|D|E|F|x + // x|G|H|I|x + // -|x|x|x|- + + vec2 pos = fract(texCoord * sourceSize[0].xy) - vec2(0.5, 0.5); + vec2 coord = texCoord - pos * sourceSize[0].zw; + + vec3 A = P(-1,-1); + vec3 B = P( 0,-1); + vec3 C = P( 1,-1); + vec3 D = P(-1, 0); + vec3 E = P( 0, 0); + vec3 F = P( 1, 0); + vec3 G = P(-1, 1); + vec3 H = P( 0, 1); + vec3 I = P( 1, 1); + + // blendResult Mapping: x|y| + // w|z| + ivec4 blendResult = ivec4(BLEND_NONE,BLEND_NONE,BLEND_NONE,BLEND_NONE); + + // Preprocess corners + // Pixel Tap Mapping: -|-|-|-|- + // -|-|B|C|- + // -|D|E|F|x + // -|G|H|I|x + // -|-|x|x|- + if (!((eq(E,F) && eq(H,I)) || (eq(E,H) && eq(F,I)))) + { + float dist_H_F = DistYCbCr(G, E) + DistYCbCr(E, C) + DistYCbCr(P(0,2), I) + DistYCbCr(I, P(2,0)) + (4.0 * DistYCbCr(H, F)); + float dist_E_I = DistYCbCr(D, H) + DistYCbCr(H, P(1,2)) + DistYCbCr(B, F) + DistYCbCr(F, P(2,1)) + (4.0 * DistYCbCr(E, I)); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_H_F) < dist_E_I; + blendResult.z = ((dist_H_F < dist_E_I) && neq(E,F) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + + // Pixel Tap Mapping: -|-|-|-|- + // -|A|B|-|- + // x|D|E|F|- + // x|G|H|I|- + // -|x|x|-|- + if (!((eq(D,E) && eq(G,H)) || (eq(D,G) && eq(E,H)))) + { + float dist_G_E = DistYCbCr(P(-2,1) , D) + DistYCbCr(D, B) + DistYCbCr(P(-1,2), H) + DistYCbCr(H, F) + (4.0 * DistYCbCr(G, E)); + float dist_D_H = DistYCbCr(P(-2,0) , G) + DistYCbCr(G, P(0,2)) + DistYCbCr(A, E) + DistYCbCr(E, I) + (4.0 * DistYCbCr(D, H)); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_H) < dist_G_E; + blendResult.w = ((dist_G_E > dist_D_H) && neq(E,D) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: -|-|x|x|- + // -|A|B|C|x + // -|D|E|F|x + // -|-|H|I|- + // -|-|-|-|- + if (!((eq(B,C) && eq(E,F)) || (eq(B,E) && eq(C,F)))) + { + float dist_E_C = DistYCbCr(D, B) + DistYCbCr(B, P(1,-2)) + DistYCbCr(H, F) + DistYCbCr(F, P(2,-1)) + (4.0 * DistYCbCr(E, C)); + float dist_B_F = DistYCbCr(A, E) + DistYCbCr(E, I) + DistYCbCr(P(0,-2), C) + DistYCbCr(C, P(2,0)) + (4.0 * DistYCbCr(B, F)); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_B_F) < dist_E_C; + blendResult.y = ((dist_E_C > dist_B_F) && neq(E,B) && neq(E,F)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: -|x|x|-|- + // x|A|B|C|- + // x|D|E|F|- + // -|G|H|-|- + // -|-|-|-|- + if (!((eq(A,B) && eq(D,E)) || (eq(A,D) && eq(B,E)))) + { + float dist_D_B = DistYCbCr(P(-2,0), A) + DistYCbCr(A, P(0,-2)) + DistYCbCr(G, E) + DistYCbCr(E, C) + (4.0 * DistYCbCr(D, B)); + float dist_A_E = DistYCbCr(P(-2,-1), D) + DistYCbCr(D, H) + DistYCbCr(P(-1,-2), B) + DistYCbCr(B, F) + (4.0 * DistYCbCr(A, E)); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_B) < dist_A_E; + blendResult.x = ((dist_D_B < dist_A_E) && neq(E,D) && neq(E,B)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + fragColor = vec4(blendResult); + + // Pixel Tap Mapping: -|-|-|-|- + // -|-|B|C|- + // -|D|E|F|x + // -|G|H|I|x + // -|-|x|x|- + if(blendResult.z == BLEND_DOMINANT || (blendResult.z == BLEND_NORMAL && + !((blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || (blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || + (IsPixEqual(G, H) && IsPixEqual(H, I) && IsPixEqual(I, F) && IsPixEqual(F, C) && !IsPixEqual(E, I))))) + { + fragColor.z += 4.0; + + float dist_F_G = DistYCbCr(F, G); + float dist_H_C = DistYCbCr(H, C); + + if((STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && neq(E,G) && neq(D,G)) + fragColor.z += 16.0; + + if((STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && neq(E,C) && neq(B,C)) + fragColor.z += 64.0; + } + + // Pixel Tap Mapping: -|-|-|-|- + // -|A|B|-|- + // x|D|E|F|- + // x|G|H|I|- + // -|x|x|-|- + if(blendResult.w == BLEND_DOMINANT || (blendResult.w == BLEND_NORMAL && + !((blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || (blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || + (IsPixEqual(A, D) && IsPixEqual(D, G) && IsPixEqual(G, H) && IsPixEqual(H, I) && !IsPixEqual(E, G))))) + { + fragColor.w += 4.0; + + float dist_H_A = DistYCbCr(H, A); + float dist_D_I = DistYCbCr(D, I); + + if((STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && neq(E,A) && neq(B,A)) + fragColor.w += 16.0; + + if((STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && neq(E,I) && neq(F,I)) + fragColor.w += 64.0; + } + + // Pixel Tap Mapping: -|-|x|x|- + // -|A|B|C|x + // -|D|E|F|x + // -|-|H|I|- + // -|-|-|-|- + if(blendResult.y == BLEND_DOMINANT || (blendResult.y == BLEND_NORMAL && + !((blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || (blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || + (IsPixEqual(I, F) && IsPixEqual(F, C) && IsPixEqual(C, B) && IsPixEqual(B, A) && !IsPixEqual(E, C))))) + { + fragColor.y += 4.0; + + float dist_B_I = DistYCbCr(B, I); + float dist_F_A = DistYCbCr(F, A); + + if((STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && neq(E,I) && neq(H,I)) + fragColor.y += 16.0; + + if((STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && neq(E,A) && neq(D,A)) + fragColor.y += 64.0; + } + + // Pixel Tap Mapping: -|x|x|-|- + // x|A|B|C|- + // x|D|E|F|- + // -|G|H|-|- + // -|-|-|-|- + if(blendResult.x == BLEND_DOMINANT || (blendResult.x == BLEND_NORMAL && + !((blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || (blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || + (IsPixEqual(C, B) && IsPixEqual(B, A) && IsPixEqual(A, D) && IsPixEqual(D, G) && !IsPixEqual(E, A))))) + { + fragColor.x += 4.0; + + float dist_D_C = DistYCbCr(D, C); + float dist_B_G = DistYCbCr(B, G); + + if((STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && neq(E,C) && neq(F,C)) + fragColor.x += 16.0; + + if((STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && neq(E,G) && neq(H,G)) + fragColor.x += 64.0; + } +fragColor /= 255.0; +} \ No newline at end of file diff --git a/shaders/xBRZ.shader/xBRZ-Freescale-p1.fs b/shaders/xBRZ.shader/xBRZ-Freescale-p1.fs new file mode 100644 index 00000000..c312294f --- /dev/null +++ b/shaders/xBRZ.shader/xBRZ-Freescale-p1.fs @@ -0,0 +1,204 @@ +#version 150 + +// xBRZ freescale +// based on : + +// 4xBRZ shader - Copyright (C) 2014-2016 DeSmuME team +// +// This file 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 file 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 the this software. If not, see . + + +/* + Hyllian's xBR-vertex code and texel mapping + + Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com + + 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. + +*/ + +uniform sampler2D source[]; +uniform vec4 sourceSize[]; +uniform vec4 targetSize; + +in Vertex { + vec2 texCoord; +}; + +out vec4 fragColor; + +#define BLEND_NONE 0 +#define BLEND_NORMAL 1 +#define BLEND_DOMINANT 2 +#define LUMINANCE_WEIGHT 1.0 +#define EQUAL_COLOR_TOLERANCE 30.0/255.0 +#define STEEP_DIRECTION_THRESHOLD 2.2 +#define DOMINANT_DIRECTION_THRESHOLD 3.6 + +float DistYCbCr(vec3 pixA, vec3 pixB) +{ + const vec3 w = vec3(0.2627, 0.6780, 0.0593); + const float scaleB = 0.5 / (1.0 - w.b); + const float scaleR = 0.5 / (1.0 - w.r); + vec3 diff = pixA - pixB; + float Y = dot(diff.rgb, w); + float Cb = scaleB * (diff.b - Y); + float Cr = scaleR * (diff.r - Y); + + return sqrt(((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr)); +} + +bool IsPixEqual(const vec3 pixA, const vec3 pixB) +{ + return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); +} + +float get_left_ratio(vec2 center, vec2 origin, vec2 direction, vec2 scale) +{ + vec2 P0 = center - origin; + vec2 proj = direction * (dot(P0, direction) / dot(direction, direction)); + vec2 distv = P0 - proj; + vec2 orth = vec2(-direction.y, direction.x); + float side = sign(dot(P0, orth)); + float v = side * length(distv * scale); + +// return step(0, v); + return smoothstep(-sqrt(2.0)/2.0, sqrt(2.0)/2.0, v); +} + +#define eq(a,b) (a == b) +#define neq(a,b) (a != b) + +#define P(x,y) texture(source[1], coord + sourceSize[1].zw * vec2(x, y)).rgb + +void main() { + //--------------------------------------- + // Input Pixel Mapping: -|B|- + // D|E|F + // -|H|- + + vec2 scale = targetSize.xy * sourceSize[1].zw; + vec2 pos = fract(texCoord * sourceSize[1].xy) - vec2(0.5, 0.5); + vec2 coord = texCoord - pos * sourceSize[1].zw; + + vec3 B = P( 0,-1); + vec3 D = P(-1, 0); + vec3 E = P( 0, 0); + vec3 F = P( 1, 0); + vec3 H = P( 0, 1); + + vec4 info = floor(texture(source[0], coord) * 255.0 + 0.5); + + // info Mapping: x|y| + // w|z| + + vec4 blendResult = floor(mod(info, 4.0)); + vec4 doLineBlend = floor(mod(info / 4.0, 4.0)); + vec4 haveShallowLine = floor(mod(info / 16.0, 4.0)); + vec4 haveSteepLine = floor(mod(info / 64.0, 4.0)); + + vec3 res = E; + + // Pixel Tap Mapping: -|-|- + // -|E|F + // -|H|- + + if(blendResult.z > BLEND_NONE) + { + vec2 origin = vec2(0.0, 1.0 / sqrt(2.0)); + vec2 direction = vec2(1.0, -1.0); + if(doLineBlend.z > 0.0) + { + origin = haveShallowLine.z > 0.0? vec2(0.0, 0.25) : vec2(0.0, 0.5); + direction.x += haveShallowLine.z; + direction.y -= haveSteepLine.z; + } + + vec3 blendPix = mix(H,F, step(DistYCbCr(E, F), DistYCbCr(E, H))); + res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); + } + + // Pixel Tap Mapping: -|-|- + // D|E|- + // -|H|- + if(blendResult.w > BLEND_NONE) + { + vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0); + vec2 direction = vec2(1.0, 1.0); + if(doLineBlend.w > 0.0) + { + origin = haveShallowLine.w > 0.0? vec2(-0.25, 0.0) : vec2(-0.5, 0.0); + direction.y += haveShallowLine.w; + direction.x += haveSteepLine.w; + } + + vec3 blendPix = mix(H,D, step(DistYCbCr(E, D), DistYCbCr(E, H))); + res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); + } + + // Pixel Tap Mapping: -|B|- + // -|E|F + // -|-|- + if(blendResult.y > BLEND_NONE) + { + vec2 origin = vec2(1.0 / sqrt(2.0), 0.0); + vec2 direction = vec2(-1.0, -1.0); + + if(doLineBlend.y > 0.0) + { + origin = haveShallowLine.y > 0.0? vec2(0.25, 0.0) : vec2(0.5, 0.0); + direction.y -= haveShallowLine.y; + direction.x -= haveSteepLine.y; + } + + vec3 blendPix = mix(F,B, step(DistYCbCr(E, B), DistYCbCr(E, F))); + res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); + } + + // Pixel Tap Mapping: -|B|- + // D|E|- + // -|-|- + if(blendResult.x > BLEND_NONE) + { + vec2 origin = vec2(0.0, -1.0 / sqrt(2.0)); + vec2 direction = vec2(-1.0, 1.0); + if(doLineBlend.x > 0.0) + { + origin = haveShallowLine.x > 0.0? vec2(0.0, -0.25) : vec2(0.0, -0.5); + direction.x -= haveShallowLine.x; + direction.y += haveSteepLine.x; + } + + vec3 blendPix = mix(D,B, step(DistYCbCr(E, B), DistYCbCr(E, D))); + res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); + } + +fragColor = vec4(res, 1.0); +} \ No newline at end of file