mirror of https://github.com/bsnes-emu/bsnes.git
Added 17 new pixel shaders courtesy of hunterk porting and testing them.
This commit is contained in:
parent
eaf33cb078
commit
d37fb1c12e
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
input
|
||||||
|
filter: nearest
|
||||||
|
|
||||||
|
program
|
||||||
|
fragment: AANN.fs
|
||||||
|
|
||||||
|
output
|
||||||
|
filter: nearest
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
program
|
||||||
|
vertex: crt-geom.vs
|
||||||
|
fragment: crt-geom.fs
|
||||||
|
modulo: 2
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
out Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = position;
|
||||||
|
vTexCoord = texCoord;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
uniform sampler2D source[];
|
||||||
|
|
||||||
|
in Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FragColor = texture(source[0], vTexCoord);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
out Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = position;
|
||||||
|
vTexCoord = texCoord;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
out Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = position;
|
||||||
|
vTexCoord = texCoord;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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));
|
||||||
|
}
|
|
@ -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
|
|
@ -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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
out Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = position;
|
||||||
|
vTexCoord = texCoord;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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" //
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
input
|
||||||
|
filter: nearest
|
||||||
|
|
||||||
|
program
|
||||||
|
filter: nearest
|
||||||
|
height: 100%
|
||||||
|
fragment: pal-r57shell.fs
|
||||||
|
|
||||||
|
output
|
||||||
|
height: 0
|
||||||
|
filter: linear
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
program
|
||||||
|
filter: nearest
|
||||||
|
wrap: edge
|
||||||
|
fragment: pixellate.fs
|
||||||
|
|
||||||
|
output
|
||||||
|
filter: nearest
|
|
@ -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));
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
program
|
||||||
|
filter: nearest
|
||||||
|
fragment: retro.fs
|
||||||
|
|
||||||
|
program
|
||||||
|
filter: nearest
|
||||||
|
fragment: gamma.fs
|
||||||
|
|
||||||
|
output
|
||||||
|
filter: nearest
|
||||||
|
width: 0
|
||||||
|
height: 0
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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));
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 150
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
out Vertex {
|
||||||
|
vec2 vTexCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = position;
|
||||||
|
vTexCoord = texCoord;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
input
|
||||||
|
filter: linear
|
||||||
|
|
||||||
|
program
|
||||||
|
fragment: sharp-bilinear.fs
|
||||||
|
|
||||||
|
output
|
||||||
|
filter: linear
|
|
@ -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);;
|
||||||
|
}
|
|
@ -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.);
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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.);
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue