Added 17 new pixel shaders courtesy of hunterk porting and testing them.

This commit is contained in:
byuu 2019-10-05 13:44:51 +09:00
parent eaf33cb078
commit d37fb1c12e
90 changed files with 7894 additions and 0 deletions

View File

@ -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;
}

View File

@ -0,0 +1,8 @@
input
filter: nearest
program
fragment: AANN.fs
output
filter: nearest

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -0,0 +1,5 @@
program
vertex: crt-geom.vs
fragment: crt-geom.fs
modulo: 2

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -0,0 +1,13 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
void main() {
gl_Position = position;
vTexCoord = texCoord;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -0,0 +1,13 @@
#version 150
uniform sampler2D source[];
in Vertex {
vec2 vTexCoord;
};
out vec4 FragColor;
void main() {
FragColor = texture(source[0], vTexCoord);
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,13 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
void main() {
gl_Position = position;
vTexCoord = texCoord;
}

View File

@ -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);
}

View File

@ -0,0 +1,13 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
void main() {
gl_Position = position;
vTexCoord = texCoord;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -0,0 +1,13 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
void main() {
gl_Position = position;
vTexCoord = texCoord;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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" //
}

View File

@ -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);
}

View File

@ -0,0 +1,11 @@
input
filter: nearest
program
filter: nearest
height: 100%
fragment: pal-r57shell.fs
output
height: 0
filter: linear

View File

@ -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<Mwidth; ++i)
{
float4 res = texture(tex, uv);
float3 yuv = mul(RGB_to_YUV, res.xyz);
float a1 = alpha+(HueShift+2.5)*2.-yuv.x*ss*HueRotation;
float sig = yuv.x+dot(yuv.yz,sign(float2(sinn(a1),coss(a1))));
#ifdef USE_DELAY_LINE
float4 res1 = texture(tex, uv+sh);
float3 yuv1 = mul(RGB_to_YUV, res1.xyz);
float a2 = (HueShift+2.5)*2.+12012.0-alpha+yuv.x*ss*HueRotation;
float sig1 = yuv1.x+dot(yuv1.yz,sign(float2(sinn(a2),coss(a2))));
#endif
if (i < Ywidth)
ysum += sig;
#ifdef USE_DELAY_LINE
if (i < Uwidth)
usum += (sig+sig1)*sinn(alpha);
if (i < Vwidth)
vsum += (sig-sig1)*coss(alpha);
#else
if (i < Uwidth)
usum += sig*sinn(alpha);
if (i < Vwidth)
vsum += sig*coss(alpha);
#endif
alpha -= ss;
uv.x -= ustep;
}
float3 rgb = mul(float3(ysum+Brightness*Ywidth_static,usum,vsum), YUV_to_RGB);
#if defined(USE_GAMMA) && !defined(USE_COLORIMETRY)
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, Gamma/2.2);
#endif
#ifdef USE_COLORIMETRY
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, float3(Gamma, Gamma, Gamma));
#endif
#if (defined(USE_SCANLINES))
float2 q = (p*sourceSize[0].xy/sourceSize[0].xy)*float2(TV_Pixels*3.,size.y*2.);
#endif
#ifdef USE_SCANLINES
float scanlines = size.y * outputSize.z;
float top = fmod(q.y-0.5*scanlines*2.,2.);
float bottom = top+frac(scanlines)*2.;
float2 sw = saturate(min(float2(1.,2.),float2(bottom, bottom))
-max(float2(0.,1.),float2(top)))
+saturate(min(float2(3.,4.),float2(bottom, bottom))
-max(float2(2.,3.),float2(top)))
+floor(scanlines);
rgb = rgb*SCANLINE_MUL/(sw.x+sw.y);
/*
//old stupid method
float z =
#ifdef ANIMATE_SCANLINE
fmod(phase,2.0)+
#endif
0.5;
if (abs(fmod(q.y+0.5,2)-z)<0.5)
rgb *= dark_scanline;
*/
#endif
// size of pixel screen in texture coords:
//float output_pixel_size = sourceSize[0].x/(outputSize.x*sourceSize[0].x);
// correctness check
//if (fmod(p.x*output_pixel_size,2.0) < 1.0)
// rgb = float3(0.,0.,0.);
#ifdef USE_COLORIMETRY
float3 xyz1 = mul(RGB_to_XYZ,rgb);
float3 srgb = saturate(mul(XYZ_to_sRGB,xyz1));
float3 a1 = 12.92*srgb;
float3 a2 = 1.055*pow(srgb,float3(1./2.4))-0.055;
float3 ssrgb;
ssrgb.x = (srgb.x<0.0031308?a1.x:a2.x);
ssrgb.y = (srgb.y<0.0031308?a1.y:a2.y);
ssrgb.z = (srgb.z<0.0031308?a1.z:a2.z);
return ssrgb;
#else
return rgb;
#endif
}
// pos (left corner, sample size)
float4 monitor_sample(sampler2D tex, float2 p, float2 sample_)
{
// linear interpolation was...
// now other thing.
// http://imgur.com/m8Z8trV
// AT LAST IT WORKS!!!!
// going to check in retroarch...
float2 size = sourceSize[0].xy;
float2 next = float2(.25,1.)/size;
float2 f = frac(float2(4.,1.)*size*p);
sample_ *= float2(4.,1.)*size;
float2 l;
float2 r;
if (f.x+sample_.x < 1.)
{
l.x = f.x+sample_.x;
r.x = 0.;
}
else
{
l.x = 1.-f.x;
r.x = min(1.,f.x+sample_.x-1.);
}
if (f.y+sample_.y < 1.)
{
l.y = f.y+sample_.y;
r.y = 0.;
}
else
{
l.y = 1.-f.y;
r.y = min(1.,f.y+sample_.y-1.);
}
float3 top = mix(monitor(tex, p), monitor(tex, p+float2(next.x,0.)), r.x/(l.x+r.x));
float3 bottom = mix(monitor(tex, p+float2(0.,next.y)), monitor(tex, p+next), r.x/(l.x+r.x));
return float4(mix(top,bottom, r.y/(l.y+r.y)),1.0);
}
void main() {
#ifdef USE_SAMPLED
fragColor = vec4(monitor_sample(source[0], texCoord, outputSize.zw).rgb, 1.0);
#else
fragColor = float4(monitor(source[0], texCoord), 1.);
#endif
}

View File

@ -0,0 +1,7 @@
program
filter: nearest
wrap: edge
fragment: pixellate.fs
output
filter: nearest

View File

@ -0,0 +1,40 @@
#version 150
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 targetSize;
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
void main() {
vec2 texelSize = 1.0 * sourceSize[0].zw;
vec2 range = vec2(abs(dFdx(texCoord.x)), abs(dFdy(texCoord.y)));
range = range / 2.0 * 0.999;
float left = texCoord.x - range.x;
float top = texCoord.y + range.y;
float right = texCoord.x + range.x;
float bottom = texCoord.y - range.y;
vec4 topLeftColor = pow(texture(source[0], vec2(left, top)), vec4(2.2));
vec4 bottomRightColor = pow(texture(source[0], vec2(right, bottom)), vec4(2.2));
vec4 bottomLeftColor = pow(texture(source[0], vec2(left, bottom)), vec4(2.2));
vec4 topRightColor = pow(texture(source[0], vec2(right, top)), vec4(2.2));
vec2 border = clamp(round(texCoord / texelSize) * texelSize, vec2(left, bottom), vec2(right, top));
float totalArea = 4.0 * range.x * range.y;
vec4 averageColor;
averageColor = ((border.x - left) * (top - border.y) / totalArea) * topLeftColor;
averageColor += ((right - border.x) * (border.y - bottom) / totalArea) * bottomRightColor;
averageColor += ((border.x - left) * (border.y - bottom) / totalArea) * bottomLeftColor;
averageColor += ((right - border.x) * (top - border.y) / totalArea) * topRightColor;
fragColor = pow(averageColor, vec4(1.0/2.2));
}

View File

@ -0,0 +1,31 @@
// Gamma Adjustment Shader
// Written by Themaister - based on byuu's bsnes gamma ramp code
#version 150
uniform sampler2D source[];
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
const float saturation = 1.0;
const float gamma = 1.0;
const float luminance = 1.2;
vec3 grayscale(vec3 col)
{
// Non-conventional way to do grayscale,
// but bSNES uses this as grayscale value.
return vec3(dot(col, vec3(0.3333)));
}
void main() {
vec3 res = texture(source[0], texCoord).xyz;
res = mix(grayscale(res), res, saturation); // Apply saturation
res = pow(res, vec3(gamma)); // Apply gamma
fragColor = vec4(clamp(res * luminance, 0.0, 1.0), 1.0);
}

View File

@ -0,0 +1,12 @@
program
filter: nearest
fragment: retro.fs
program
filter: nearest
fragment: gamma.fs
output
filter: nearest
width: 0
height: 0

View File

@ -0,0 +1,38 @@
// Retro v2 Shader
// Written by Hyllian / Jararaca
#version 150
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 targetSize;
// This value must be between 0.0 (totally black) and 1.0 (nearest neighbor)
#define PIXEL_SIZE 0.64
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
out vec3 E;
out vec2 fp;
out vec2 ps;
out vec2 f;
out vec3 res;
void main() {
// Reading the texel
vec3 E = pow(texture(source[0], texCoord).xyz, vec3(2.4));
vec2 fp = fract(texCoord.xy * sourceSize[0].xy);
vec2 ps = sourceSize[0].xy / targetSize.xy;
vec2 f = clamp(clamp(fp + 0.5*ps, 0.0, 1.0) - PIXEL_SIZE, vec2(0.0, 0.0), ps)/ps;
float max_coord = max(f.x, f.y);
vec3 res = mix(E*(1.04+fp.x*fp.y), E*0.36, max_coord);
fragColor = vec4(clamp( pow(res, vec3(1.0 / 2.2)), 0.0, 1.0 ), 1.0);
}

View File

@ -0,0 +1,61 @@
#version 150
#define dt vec3(1.0, 1.0, 1.0)
uniform sampler2D source[];
in vec3 c00;
in vec3 c10;
in vec3 c20;
in vec3 c01;
in vec3 c11;
in vec3 c21;
in vec3 c02;
in vec3 c12;
in vec3 c22;
in float d1;
in float d2;
in float hl;
in float vl;
in float k1;
in float k2;
in Vertex {
vec2 texCoord;
vec4 t1;
vec4 t2;
vec4 t3;
vec4 t4;
};
out vec4 fragColor;
void main(void) {
vec3 c00 = texture(source[0], t1.zw).xyz;
vec3 c10 = texture(source[0], t3.xy).xyz;
vec3 c20 = texture(source[0], t3.zw).xyz;
vec3 c01 = texture(source[0], t1.xy).xyz;
vec3 c11 = texture(source[0], texCoord).xyz;
vec3 c21 = texture(source[0], t2.xy).xyz;
vec3 c02 = texture(source[0], t2.zw).xyz;
vec3 c12 = texture(source[0], t4.xy).xyz;
vec3 c22 = texture(source[0], t4.zw).xyz;
float d1=dot(abs(c00 - c22), dt) + 0.0001;
float d2=dot(abs(c20 - c02), dt) + 0.0001;
float hl=dot(abs(c01 - c21), dt) + 0.0001;
float vl=dot(abs(c10 - c12), dt) + 0.0001;
float k1 = 0.5 * (hl + vl);
float k2 = 0.5 * (d1 + d2);
vec3 t1 = (hl * (c10 + c12) + vl * (c01 + c21) + k1 * c11) / (2.5 * (hl + vl));
vec3 t2 = (d1 * (c20 + c02) + d2 * (c00 + c22) + k2 * c11) / (2.5 * (d1 + d2));
k1 = dot(abs(t1 - c11), dt) + 0.0001;
k2 = dot(abs(t2 - c11), dt) + 0.0001;
fragColor = vec4((k1 * t2 + k2 * t1) / (k1 + k2), 1.0);
}

View File

@ -0,0 +1,36 @@
#version 150
in vec4 position;
in vec2 texCoord;
uniform vec4 sourceSize[];
in vec2 ps;
in float dx;
in float dy;
out Vertex {
vec2 texCoord;
vec4 t1;
vec4 t2;
vec4 t3;
vec4 t4;
} vertexOut;
void main() {
vec2 ps = vec2(1.0/sourceSize[0].x, 1.0/sourceSize[0].y);
float dx = ps.x * 0.5;
float dy = ps.y * 0.5;
gl_Position = position;
vertexOut.texCoord = texCoord;
vertexOut.t1.xy = texCoord + vec2(-dx, 0);
vertexOut.t2.xy = texCoord + vec2( dx, 0);
vertexOut.t3.xy = texCoord + vec2( 0, -dy);
vertexOut.t4.xy = texCoord + vec2( 0, dy);
vertexOut.t1.zw = texCoord + vec2(-dx, -dy);
vertexOut.t2.zw = texCoord + vec2(-dx, dy);
vertexOut.t3.zw = texCoord + vec2( dx, -dy);
vertexOut.t4.zw = texCoord + vec2( dx, dy);
}

View File

@ -0,0 +1,51 @@
input
filter: nearest
program
filter: nearest
format: rgba16f
width: 100%
height: 100%
vertex: scalefx-pass0.vs
fragment: scalefx-pass0.fs
program
filter: nearest
format: rgba16f
width: 100%
height: 100%
vertex: scalefx-pass1.vs
fragment: scalefx-pass1.fs
program
filter: nearest
width: 100%
height: 100%
vertex: scalefx-pass2.vs
fragment: scalefx-pass2.fs
program
filter: nearest
width: 100%
height: 100%
vertex: scalefx-pass3.vs
fragment: scalefx-pass3.fs
program
filter: nearest
width: 300%
height: 300%
vertex: scalefx-pass4.vs
fragment: scalefx-pass4.fs
program
filter: nearest
height: 200%
width: 200%
vertex: advanced-aa.vs
fragment: advanced-aa.fs
output
height: 0
width: 0
filter: linear

View File

@ -0,0 +1,83 @@
#version 150
/*
ScaleFX - Pass 0
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 0 prepares metric data for the next 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.
*/
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 targetSize;
in Vertex {
vec2 vTexCoord;
};
out vec4 FragColor;
// Reference: http://www.compuphase.com/cmetric.htm
float dist(vec3 A, vec3 B)
{
float r = 0.5 * (A.r + B.r);
vec3 d = A - B;
vec3 c = vec3(2 + r, 4, 3 - r);
return sqrt(dot(c*d, d)) / 3;
}
void main() {
/* grid metric
A B C x y z
E F o w
*/
#define TEX(x, y) textureOffset(source[0], vTexCoord, ivec2(x, y)).rgb
// read texels
vec3 A = TEX(-1,-1);
vec3 B = TEX( 0,-1);
vec3 C = TEX( 1,-1);
vec3 E = TEX( 0, 0);
vec3 F = TEX( 1, 0);
// output
FragColor = vec4(dist(E,A), dist(E,B), dist(E,C), dist(E,F));
}

View File

@ -0,0 +1,13 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
void main() {
gl_Position = position;
vTexCoord = texCoord;
}

View File

@ -0,0 +1,88 @@
#version 150
/*
ScaleFX - Pass 1
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 1 calculates the strength of interpolation candidates.
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_CLR 0.5
#define SFX_SAA 1.0
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 targetSize;
in Vertex {
vec2 vTexCoord;
};
out vec4 FragColor;
// corner strength
float str(float d, vec2 a, vec2 b){
float diff = a.x - a.y;
float wght1 = max(SFX_CLR - d, 0) / SFX_CLR;
float wght2 = clamp((1-d) + (min(a.x, b.x) + a.x > 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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -0,0 +1,8 @@
input
filter: linear
program
fragment: sharp-bilinear.fs
output
filter: linear

View File

@ -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);;
}

View File

@ -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.);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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.);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

251
shaders/xBRZ.shader/fxaa.fs Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
/*
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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
/*
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);
}