[Scummvm-git-logs] scummvm-shaders master -> d52c8ecd1205332da616756fe4326bb47819d873

lotharsm noreply at scummvm.org
Sat Jan 7 23:40:44 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm-shaders' repo located at https://github.com/scummvm/scummvm-shaders .

Summary:
d52c8ecd12 SHADERS: Add some classics: hqx, sabr, scalefx, scalehq, xbrz, xsal, xsoft


Commit: d52c8ecd1205332da616756fe4326bb47819d873
    https://github.com/scummvm/scummvm-shaders/commit/d52c8ecd1205332da616756fe4326bb47819d873
Author: Lothar Serra Mari (mail at serra.me)
Date: 2023-01-08T00:40:06+01:00

Commit Message:
SHADERS: Add some classics: hqx, sabr, scalefx, scalehq, xbrz, xsal, xsoft

Changed paths:
  A base/hqx/hq2x-halphon.glslp
  A base/hqx/hq2x.glslp
  A base/hqx/hq3x.glslp
  A base/hqx/hq4x.glslp
  A base/hqx/resources/hq2x.png
  A base/hqx/resources/hq3x.png
  A base/hqx/resources/hq4x.png
  A base/hqx/shader-files/hq2x-halphon.glsl
  A base/hqx/shader-files/hqx-pass1.glsl
  A base/hqx/shader-files/hqx-pass2.glsl
  A base/hqx/single-pass/hq2x.glslp
  A base/hqx/single-pass/hq3x.glslp
  A base/hqx/single-pass/hq4x.glslp
  A base/hqx/single-pass/shader-files/hq2x.glsl
  A base/hqx/single-pass/shader-files/hq3x.glsl
  A base/hqx/single-pass/shader-files/hq4x.glsl
  A base/sabr/sabr-hybrid-deposterize.glslp
  A base/sabr/sabr.glslp
  A base/sabr/shaders/sabr-hybrid-deposterize.glsl
  A base/sabr/shaders/sabr-v3.0.glsl
  A base/scalefx/scalefx+rAA.glslp
  A base/scalefx/scalefx-hybrid.glslp
  A base/scalefx/scalefx.glslp
  A base/scalefx/shaders/scalefx-pass0.glsl
  A base/scalefx/shaders/scalefx-pass1.glsl
  A base/scalefx/shaders/scalefx-pass2.glsl
  A base/scalefx/shaders/scalefx-pass3.glsl
  A base/scalefx/shaders/scalefx-pass4-hybrid.glsl
  A base/scalefx/shaders/scalefx-pass4.glsl
  A base/scalehq/2xScaleHQ.glslp
  A base/scalehq/4xScaleHQ.glslp
  A base/scalehq/shaders/2xScaleHQ.glsl
  A base/scalehq/shaders/4xScaleHQ.glsl
  A base/scalenx/epx.glslp
  A base/scalenx/mmpx.glslp
  A base/scalenx/scale2x.glslp
  A base/scalenx/scale2xSFX.glslp
  A base/scalenx/scale2xplus.glslp
  A base/scalenx/scale3x.glslp
  A base/scalenx/shaders/epx.glsl
  A base/scalenx/shaders/mmpx.glsl
  A base/scalenx/shaders/scale2x.glsl
  A base/scalenx/shaders/scale2xSFX.glsl
  A base/scalenx/shaders/scale2xplus.glsl
  A base/scalenx/shaders/scale3x.glsl
  A base/scalenx/shaders/scale3xSFX.glsl
  A base/scanlines/shaders/res-independent-scanlines.glsl
  A base/scanlines/shaders/scanline-fract.glsl
  A base/scanlines/shaders/scanline.glsl
  A base/scanlines/shaders/scanlines-sine-abs.glsl
  A base/xbrz/4xbrz-linear.glslp
  A base/xbrz/5xbrz-linear.glslp
  A base/xbrz/6xbrz-linear.glslp
  A base/xbrz/shaders/4xbrz.glsl
  A base/xbrz/shaders/5xbrz.glsl
  A base/xbrz/shaders/6xbrz.glsl
  A base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass0.glsl
  A base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass1.glsl
  A base/xbrz/shaders/xbrz-freescale.glsl
  A base/xbrz/xbrz-freescale-multipass.glslp
  A base/xbrz/xbrz-freescale.glslp
  A base/xsal/2xsal-level2-crt.glslp
  A base/xsal/2xsal.glslp
  A base/xsal/4xsal-level2-crt.glslp
  A base/xsal/4xsal-level2-hq.glslp
  A base/xsal/4xsal-level2.glslp
  A base/xsal/shaders/2xsal-level2-hq.glsl
  A base/xsal/shaders/2xsal-level2-pass2.glsl
  A base/xsal/shaders/2xsal-level2.glsl
  A base/xsal/shaders/2xsal.glsl
  A base/xsoft/4xsoft.glslp
  A base/xsoft/4xsoftSdB.glslp
  A base/xsoft/shaders/4xsoft.glsl
  A base/xsoft/shaders/4xsoftSdB.glsl


diff --git a/base/hqx/hq2x-halphon.glslp b/base/hqx/hq2x-halphon.glslp
new file mode 100644
index 0000000..29527ef
--- /dev/null
+++ b/base/hqx/hq2x-halphon.glslp
@@ -0,0 +1,9 @@
+shaders = 2
+
+shader0 = shader-files/hq2x-halphon.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
\ No newline at end of file
diff --git a/base/hqx/hq2x.glslp b/base/hqx/hq2x.glslp
new file mode 100644
index 0000000..d06cb40
--- /dev/null
+++ b/base/hqx/hq2x.glslp
@@ -0,0 +1,18 @@
+shaders = 2
+shader0 = shader-files/hqx-pass1.glsl
+shader1 = shader-files/hqx-pass2.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+
+filter_linear1 = false
+scale_type1 = source
+scale1 = 2.0
+
+textures = LUT
+LUT = resources/hq2x.png
+LUT_linear = false
+
+parameters = "SCALE"
+SCALE = 2.0
diff --git a/base/hqx/hq3x.glslp b/base/hqx/hq3x.glslp
new file mode 100644
index 0000000..692832e
--- /dev/null
+++ b/base/hqx/hq3x.glslp
@@ -0,0 +1,18 @@
+shaders = 2
+shader0 = shader-files/hqx-pass1.glsl
+shader1 = shader-files/hqx-pass2.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+
+filter_linear1 = false
+scale_type1 = source
+scale1 = 3.0
+
+textures = LUT
+LUT = resources/hq3x.png
+LUT_linear = false
+
+parameters = "SCALE"
+SCALE = 3.0
\ No newline at end of file
diff --git a/base/hqx/hq4x.glslp b/base/hqx/hq4x.glslp
new file mode 100644
index 0000000..ec5c536
--- /dev/null
+++ b/base/hqx/hq4x.glslp
@@ -0,0 +1,18 @@
+shaders = 2
+shader0 = shader-files/hqx-pass1.glsl
+shader1 = shader-files/hqx-pass2.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+
+filter_linear1 = false
+scale_type1 = source
+scale1 = 4.0
+
+textures = LUT
+LUT = resources/hq4x.png
+LUT_linear = false
+
+parameters = "SCALE"
+SCALE = 4.0
\ No newline at end of file
diff --git a/base/hqx/resources/hq2x.png b/base/hqx/resources/hq2x.png
new file mode 100644
index 0000000..a49c0f4
Binary files /dev/null and b/base/hqx/resources/hq2x.png differ
diff --git a/base/hqx/resources/hq3x.png b/base/hqx/resources/hq3x.png
new file mode 100644
index 0000000..6f5eb59
Binary files /dev/null and b/base/hqx/resources/hq3x.png differ
diff --git a/base/hqx/resources/hq4x.png b/base/hqx/resources/hq4x.png
new file mode 100644
index 0000000..18abeb3
Binary files /dev/null and b/base/hqx/resources/hq4x.png differ
diff --git a/base/hqx/shader-files/hq2x-halphon.glsl b/base/hqx/shader-files/hq2x-halphon.glsl
new file mode 100644
index 0000000..11ae494
--- /dev/null
+++ b/base/hqx/shader-files/hq2x-halphon.glsl
@@ -0,0 +1,221 @@
+#version 130
+
+// HQ2x
+// by Lior Halphon
+// ported to RetroArch's shader formats by hunterk
+
+/* Based on this (really good) article: http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html */
+
+/*
+MIT License
+
+Copyright (c) 2015-2016 Lior Halphon
+
+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 uResolution outsize.xy
+#define textureDimensions SourceSize.xy
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy * 1.0001;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+precision mediump int;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+/* The colorspace used by the HQnx filters is not really YUV, despite the algorithm description claims it is. It is
+   also not normalized. Therefore, we shall call the colorspace used by HQnx "HQ Colorspace" to avoid confusion. */
+vec3 rgb_to_hq_colospace(vec4 rgb)
+{
+    return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
+                 0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
+                -0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b);
+}
+
+bool is_different(vec4 a, vec4 b)
+{
+    vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b));
+    return diff.x > 0.188 || diff.y > 0.027 || diff.z > 0.031;
+}
+
+#define P(m, r) ((pattern & (m)) == (r))
+
+vec4 interp_2px(vec4 c1, float w1, vec4 c2, float w2)
+{
+    return (c1 * w1 + c2 * w2) / (w1 + w2);
+}
+
+vec4 interp_3px(vec4 c1, float w1, vec4 c2, float w2, vec4 c3, float w3)
+{
+    return (c1 * w1 + c2 * w2 + c3 * w3) / (w1 + w2 + w3);
+}
+
+vec4 scale(sampler2D image, vec2 coord)
+{
+    // o = offset, the width of a pixel
+    vec2 o = 1.0 / textureDimensions;
+    vec2 texCoord = coord;
+
+    /* We always calculate the top left pixel.  If we need a different pixel, we flip the image */
+
+    // p = the position within a pixel [0...1]
+    vec2 p = fract(texCoord * textureDimensions);
+
+    if (p.x > 0.5) o.x = -o.x;
+    if (p.y > 0.5) o.y = -o.y;
+
+    vec4 w0 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x, -o.y));
+    vec4 w1 = COMPAT_TEXTURE(image, texCoord + vec2(    0, -o.y));
+    vec4 w2 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x, -o.y));
+    vec4 w3 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x,    0));
+    vec4 w4 = COMPAT_TEXTURE(image, texCoord + vec2(    0,    0));
+    vec4 w5 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x,    0));
+    vec4 w6 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x,  o.y));
+    vec4 w7 = COMPAT_TEXTURE(image, texCoord + vec2(    0,  o.y));
+    vec4 w8 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x,  o.y));
+
+    int pattern = 0;
+    if (is_different(w0, w4)) pattern |= 1;
+    if (is_different(w1, w4)) pattern |= 2;
+    if (is_different(w2, w4)) pattern |= 4;
+    if (is_different(w3, w4)) pattern |= 8;
+    if (is_different(w5, w4)) pattern |= 16;
+    if (is_different(w6, w4)) pattern |= 32;
+    if (is_different(w7, w4)) pattern |= 64;
+    if (is_different(w8, w4)) pattern |= 128;
+
+    if ((P(0xbf,0x37) || P(0xdb,0x13)) && is_different(w1, w5))
+        return interp_2px(w4, 3.0, w3, 1.0);
+    if ((P(0xdb,0x49) || P(0xef,0x6d)) && is_different(w7, w3))
+        return interp_2px(w4, 3.0, w1, 1.0);
+    if ((P(0x0b,0x0b) || P(0xfe,0x4a) || P(0xfe,0x1a)) && is_different(w3, w1))
+        return w4;
+    if ((P(0x6f,0x2a) || P(0x5b,0x0a) || P(0xbf,0x3a) || P(0xdf,0x5a) ||
+         P(0x9f,0x8a) || P(0xcf,0x8a) || P(0xef,0x4e) || P(0x3f,0x0e) ||
+         P(0xfb,0x5a) || P(0xbb,0x8a) || P(0x7f,0x5a) || P(0xaf,0x8a) ||
+         P(0xeb,0x8a)) && is_different(w3, w1))
+        return interp_2px(w4, 3.0, w0, 1.0);
+    if (P(0x0b,0x08))
+        return interp_3px(w4, 2.0, w0, 1.0, w1, 1.0);
+    if (P(0x0b,0x02))
+        return interp_3px(w4, 2.0, w0, 1.0, w3, 1.0);
+    if (P(0x2f,0x2f))
+        return interp_3px(w4, 1.04, w3, 1.0, w1, 1.0);
+    if (P(0xbf,0x37) || P(0xdb,0x13))
+        return interp_3px(w4, 5.0, w1, 2.0, w3, 1.0);
+    if (P(0xdb,0x49) || P(0xef,0x6d))
+        return interp_3px(w4, 5.0, w3, 2.0, w1, 1.0);
+    if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
+        return interp_2px(w4, 3.0, w3, 1.0);
+    if (P(0x4b,0x09) || P(0x8b,0x89) || P(0x1f,0x19) || P(0x3b,0x19))
+        return interp_2px(w4, 3.0, w1, 1.0);
+    if (P(0x7e,0x2a) || P(0xef,0xab) || P(0xbf,0x8f) || P(0x7e,0x0e))
+        return interp_3px(w4, 2.0, w3, 3.0, w1, 3.0);
+    if (P(0xfb,0x6a) || P(0x6f,0x6e) || P(0x3f,0x3e) || P(0xfb,0xfa) ||
+        P(0xdf,0xde) || P(0xdf,0x1e))
+        return interp_2px(w4, 3.0, w0, 1.0);
+    if (P(0x0a,0x00) || P(0x4f,0x4b) || P(0x9f,0x1b) || P(0x2f,0x0b) ||
+        P(0xbe,0x0a) || P(0xee,0x0a) || P(0x7e,0x0a) || P(0xeb,0x4b) ||
+        P(0x3b,0x1b))
+        return interp_3px(w4, 2.0, w3, 1.0, w1, 1.0);
+    
+    return interp_3px(w4, 6.0, w3, 1.0, w1, 1.0);
+}
+
+void main()
+{
+	FragColor = scale(Source, vTexCoord);
+} 
+#endif
diff --git a/base/hqx/shader-files/hqx-pass1.glsl b/base/hqx/shader-files/hqx-pass1.glsl
new file mode 100644
index 0000000..401ac1d
--- /dev/null
+++ b/base/hqx/shader-files/hqx-pass1.glsl
@@ -0,0 +1,187 @@
+/*
+* Copyright (C) 2003 Maxim Stepin ( maxst at hiend3d.com )
+*
+* Copyright (C) 2010 Cameron Zemek ( grom at zeminvaders.net )
+*
+* Copyright (C) 2014 Jules Blok ( jules at aerix.nl )
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser 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
+*/
+
+// Compatibility #ifdefs needed for parameters
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+precision mediump float;
+#else
+#define COMPAT_PRECISION
+#endif
+
+// Parameter lines go here:
+#pragma parameter trY "Y Threshold" 48.0 0.0 255.0 1.0
+#pragma parameter trU "U Threshold" 7.0 0.0 255.0 1.0
+#pragma parameter trV "V Threshold" 6.0 0.0 255.0 1.0
+#ifdef PARAMETER_UNIFORM
+// All parameter floats need to have COMPAT_PRECISION in front of them
+uniform COMPAT_PRECISION float trY;
+uniform COMPAT_PRECISION float trU;
+uniform COMPAT_PRECISION float trV;
+#else
+#define trY 48.0
+#define trU 7.0
+#define trV 6.0
+#endif
+
+#ifdef GL_ES
+vec3 yuv_threshold = vec3(0.188235294, 0.02745098, 0.023529412);
+#else
+vec3 yuv_threshold = vec3(trY/255.0, trU/255.0, trV/255.0);
+#endif
+const mat3 yuv = mat3(0.299, -0.169, 0.5, 0.587, -0.331, -0.419, 0.114, 0.5, -0.081);
+const vec3 yuv_offset = vec3(0.0, 0.5, 0.5);
+
+bool diff(vec3 yuv1, vec3 yuv2) {
+	bvec3 res = greaterThan(abs((yuv1 + yuv_offset) - (yuv2 + yuv_offset)) , yuv_threshold);
+	return res.x || res.y || res.z;
+}
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	float	dx	=	SourceSize.z;
+	float	dy	=	SourceSize.w;
+	//   +----+----+----+
+	//   |    |    |    |
+	//   | w1 | w2 | w3 |
+	//   +----+----+----+
+	//   |    |    |    |
+	//   | w4 | w5 | w6 |
+	//   +----+----+----+
+	//   |    |    |    |
+	//   | w7 | w8 | w9 |
+	//   +----+----+----+
+	t1	=	vTexCoord.xxxy + vec4(-dx, 0, dx, -dy); //  w1 | w2 | w3;
+	t2	=	vTexCoord.xxxy + vec4(-dx, 0, dx,   0); //  w4 | w5 | w6;
+	t3	=	vTexCoord.xxxy + vec4(-dx, 0, dx,  dy); //  w7 | w8 | w9;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+	vec3	w1	=	yuv * COMPAT_TEXTURE(Source, t1.xw).rgb;
+	vec3	w2	=	yuv * COMPAT_TEXTURE(Source, t1.yw).rgb;
+	vec3	w3	=	yuv * COMPAT_TEXTURE(Source, t1.zw).rgb;
+
+	vec3	w4	=	yuv * COMPAT_TEXTURE(Source, t2.xw).rgb;
+	vec3	w5	=	yuv * COMPAT_TEXTURE(Source, t2.yw).rgb;
+	vec3	w6	=	yuv * COMPAT_TEXTURE(Source, t2.zw).rgb;
+
+	vec3	w7	=	yuv * COMPAT_TEXTURE(Source, t3.xw).rgb;
+	vec3	w8	=	yuv * COMPAT_TEXTURE(Source, t3.yw).rgb;
+	vec3	w9	=	yuv * COMPAT_TEXTURE(Source, t3.zw).rgb;
+
+	vec3	pattern_1	=	vec3(diff(w5, w1),	diff(w5, w2),	diff(w5, w3));
+	vec3	pattern_2	=	vec3(diff(w5, w4),	false,	diff(w5, w6));
+	vec3	pattern_3	=	vec3(diff(w5, w7),	diff(w5, w8),	diff(w5, w9));
+	vec4	cross		=	vec4(diff(w4, w2),	diff(w2, w6),	diff(w8, w4),	diff(w6, w8));
+	
+	vec2	index;
+	index.x	=	dot(pattern_1, vec3(1, 2, 4)) +
+				dot(pattern_2, vec3(8, 0, 16)) +
+				dot(pattern_3, vec3(32, 64, 128));
+	index.y	=	dot(cross, vec4(1, 2, 4, 8));
+	
+	FragColor	=	vec4(index / vec2(255.0, 15.0), 0.0, 1.0);
+} 
+#endif
diff --git a/base/hqx/shader-files/hqx-pass2.glsl b/base/hqx/shader-files/hqx-pass2.glsl
new file mode 100644
index 0000000..86de421
--- /dev/null
+++ b/base/hqx/shader-files/hqx-pass2.glsl
@@ -0,0 +1,144 @@
+/*
+* Copyright (C) 2003 Maxim Stepin ( maxst at hiend3d.com )
+*
+* Copyright (C) 2010 Cameron Zemek ( grom at zeminvaders.net )
+*
+* Copyright (C) 2014 Jules Blok ( jules at aerix.nl )
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser 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
+*/
+
+#pragma parameter SCALE "HQx Scale" 2.0 2.0 4.0 1.0
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D LUT;
+uniform sampler2D OrigTexture;
+COMPAT_VARYING vec4 TEX0;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float SCALE;
+#else
+#define SCALE 2.
+#endif
+
+#define Original OrigTexture
+
+void main()
+{
+	vec2 fp = fract(vTexCoord * SourceSize.xy);
+	vec2 quad = sign(-0.5 + fp);
+
+	float dx = SourceSize.z;
+	float dy = SourceSize.w;
+
+	vec3 p1 = COMPAT_TEXTURE(Original, vTexCoord).rgb;
+	vec3 p2 = COMPAT_TEXTURE(Original, vTexCoord + vec2(dx, dy) * quad).rgb;
+	vec3 p3 = COMPAT_TEXTURE(Original, vTexCoord + vec2(dx, 0.0) * quad).rgb;
+	vec3 p4 = COMPAT_TEXTURE(Original, vTexCoord + vec2(0.0, dy) * quad).rgb;
+
+	vec2 index = COMPAT_TEXTURE(Source, vTexCoord).xy * vec2(255.0, 15.0 * (SCALE * SCALE));
+	index.y += dot(floor(fp * SCALE), vec2(1.0, SCALE));
+
+	vec2 step = 1.0 / vec2(256.0, 16.0 * (SCALE * SCALE));
+	vec2 offset = step / 2.0;
+	vec4 weights = COMPAT_TEXTURE(LUT, index * step + offset);
+	float sum = dot(weights, vec4(1.0));
+	vec4 tmp = vec4(float((weights/sum).x), float((weights/sum).y), float((weights/sum).z), float((weights/sum).w));
+	vec3 res = tmp.x * p1.xyz;
+	res = res + tmp.y * p2.xyz;
+	res = res + tmp.z * p3.xyz;
+	res = res + tmp.w * p4.xyz;
+
+	FragColor = vec4(res.xyz, 1.0);
+} 
+#endif
\ No newline at end of file
diff --git a/base/hqx/single-pass/hq2x.glslp b/base/hqx/single-pass/hq2x.glslp
new file mode 100644
index 0000000..bbe66b9
--- /dev/null
+++ b/base/hqx/single-pass/hq2x.glslp
@@ -0,0 +1,10 @@
+shaders = 1
+shader0 = shader-files/hq2x.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
+
+textures = LUT
+LUT = ../resources/hq2x.png
+LUT_linear = false
diff --git a/base/hqx/single-pass/hq3x.glslp b/base/hqx/single-pass/hq3x.glslp
new file mode 100644
index 0000000..4c52c2b
--- /dev/null
+++ b/base/hqx/single-pass/hq3x.glslp
@@ -0,0 +1,10 @@
+shaders = 1
+shader0 = shader-files/hq3x.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 3.0
+
+textures = LUT
+LUT = ../resources/hq3x.png
+LUT_linear = false
diff --git a/base/hqx/single-pass/hq4x.glslp b/base/hqx/single-pass/hq4x.glslp
new file mode 100644
index 0000000..464295f
--- /dev/null
+++ b/base/hqx/single-pass/hq4x.glslp
@@ -0,0 +1,10 @@
+shaders = 1
+shader0 = shader-files/hq4x.glsl
+
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
+
+textures = LUT
+LUT = ../resources/hq4x.png
+LUT_linear = false
diff --git a/base/hqx/single-pass/shader-files/hq2x.glsl b/base/hqx/single-pass/shader-files/hq2x.glsl
new file mode 100644
index 0000000..2710b28
--- /dev/null
+++ b/base/hqx/single-pass/shader-files/hq2x.glsl
@@ -0,0 +1,434 @@
+// GLSL shader autogenerated by cg2glsl.py.
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord1;
+COMPAT_VARYING     vec4 _color1;
+COMPAT_VARYING     vec4 _position1;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _position1;
+    vec4 _color1;
+    vec2 _texCoord1;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+out_vertex _ret_0;
+input_dummy _IN1;
+vec4 _r0010;
+vec4 _v0010;
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    out_vertex _OUT;
+    vec2 _ps;
+    _v0010 = vec4(float(VertexCoord.x), float(VertexCoord.y), float(VertexCoord.z), float(VertexCoord.w));
+    _r0010 = _v0010.x*MVPMatrix[0];
+    _r0010 = _r0010 + _v0010.y*MVPMatrix[1];
+    _r0010 = _r0010 + _v0010.z*MVPMatrix[2];
+    _r0010 = _r0010 + _v0010.w*MVPMatrix[3];
+    _OUT._position1 = vec4(float(_r0010.x), float(_r0010.y), float(_r0010.z), float(_r0010.w));
+    _ps = 1.00000000E+00/TextureSize;
+    _OUT._t1 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(-_ps.y)));
+    _OUT._t2 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), 0.00000000E+00);
+    _OUT._t3 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(_ps.y)));
+    _ret_0._position1 = _OUT._position1;
+    _ret_0._color1 = COLOR;
+    _ret_0._texCoord1 = TexCoord.xy;
+    _ret_0._t1 = _OUT._t1;
+    _ret_0._t2 = _OUT._t2;
+    _ret_0._t3 = _OUT._t3;
+    VARps = _ps;
+    gl_Position = _OUT._position1;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+    TEX1 = _OUT._t1;
+    TEX2 = _OUT._t2;
+    TEX3 = _OUT._t3;
+    return;
+    COL0 = _ret_0._color1;
+    TEX0.xy = _ret_0._texCoord1;
+    TEX1 = _ret_0._t1;
+    TEX2 = _ret_0._t2;
+    TEX3 = _ret_0._t3;
+} 
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord;
+COMPAT_VARYING     vec4 _color;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _color;
+    vec2 _texCoord;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+vec4 _ret_0;
+float _TMP44;
+vec4 _TMP40;
+float _TMP39;
+float _TMP37;
+vec2 _TMP38;
+float _TMP36;
+float _TMP35;
+float _TMP34;
+float _TMP43;
+bool _TMP33;
+bool _TMP32;
+bool _TMP31;
+bool _TMP30;
+vec3 _TMP42;
+bool _TMP29;
+bool _TMP28;
+bool _TMP27;
+bool _TMP26;
+bool _TMP25;
+bool _TMP24;
+bool _TMP23;
+bool _TMP22;
+vec4 _TMP20;
+vec4 _TMP18;
+vec4 _TMP16;
+vec4 _TMP14;
+vec4 _TMP11;
+vec4 _TMP9;
+vec4 _TMP7;
+vec4 _TMP5;
+vec4 _TMP4;
+vec4 _TMP3;
+vec4 _TMP2;
+vec4 _TMP1;
+vec2 _TMP0;
+out_vertex _VAR1;
+uniform sampler2D Texture;
+input_dummy _IN1;
+uniform sampler2D LUT;
+vec2 _x0063;
+vec2 _val0065;
+vec2 _a0065;
+vec2 _c0069;
+vec2 _c0071;
+vec2 _c0073;
+vec3 _r0077;
+vec3 _v0077;
+vec3 _r0087;
+vec3 _v0087;
+vec3 _r0097;
+vec3 _v0097;
+vec3 _r0107;
+vec3 _v0107;
+vec3 _r0115;
+vec3 _v0115;
+vec3 _r0125;
+vec3 _v0125;
+vec3 _r0135;
+vec3 _v0135;
+vec3 _r0145;
+vec3 _v0145;
+vec3 _r0155;
+vec3 _v0155;
+bvec3 _res0163;
+vec3 _a0165;
+bvec3 _res0167;
+vec3 _a0169;
+bvec3 _res0171;
+vec3 _a0173;
+bvec3 _res0175;
+vec3 _a0177;
+bvec3 _res0179;
+vec3 _a0181;
+bvec3 _res0183;
+vec3 _a0185;
+bvec3 _res0187;
+vec3 _a0189;
+bvec3 _res0191;
+vec3 _a0193;
+bvec3 _res0195;
+vec3 _a0197;
+bvec3 _res0199;
+vec3 _a0201;
+bvec3 _res0203;
+vec3 _a0205;
+bvec3 _res0207;
+vec3 _a0209;
+vec3 _a0211;
+vec3 _a0213;
+vec3 _a0215;
+vec4 _a0217;
+vec2 _x0219;
+vec2 _c0223;
+vec3 _r0229;
+vec4 _v0229;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    vec2 _fp;
+    vec2 _quad;
+    vec3 _w1;
+    vec3 _w2;
+    vec3 _w3;
+    vec3 _w4;
+    vec3 _w5;
+    vec3 _w6;
+    vec3 _w7;
+    vec3 _w8;
+    vec3 _w9;
+    bvec4 _cross;
+    vec2 _index;
+    vec4 _weights;
+    float _sum;
+    bvec3 _TMP50[3];
+    _x0063 = TEX0.xy*TextureSize;
+    _fp = fract(_x0063);
+    _a0065 = -5.00000000E-01 + _fp;
+    _val0065 = vec2(float((_a0065.x > 0.00000000E+00)), float((_a0065.y > 0.00000000E+00)));
+    _TMP0 = _val0065 - vec2(float((_a0065.x < 0.00000000E+00)), float((_a0065.y < 0.00000000E+00)));
+    _quad = vec2(float(_TMP0.x), float(_TMP0.y));
+    _TMP1 = COMPAT_TEXTURE(Texture, TEX0.xy);
+    _c0069 = TEX0.xy + vec2(VARps.x, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP2 = COMPAT_TEXTURE(Texture, _c0069);
+    _c0071 = TEX0.xy + vec2(VARps.x, 0.00000000E+00)*vec2(float(_quad.x), float(_quad.y));
+    _TMP3 = COMPAT_TEXTURE(Texture, _c0071);
+    _c0073 = TEX0.xy + vec2(0.00000000E+00, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP4 = COMPAT_TEXTURE(Texture, _c0073);
+    _TMP5 = COMPAT_TEXTURE(Texture, TEX1.xw);
+    _v0077 = vec3(float(_TMP5.x), float(_TMP5.y), float(_TMP5.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.z = float(_TMP43);
+    _w1 = vec3(float(_r0077.x), float(_r0077.y), float(_r0077.z));
+    _TMP7 = COMPAT_TEXTURE(Texture, TEX1.yw);
+    _v0087 = vec3(float(_TMP7.x), float(_TMP7.y), float(_TMP7.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.z = float(_TMP43);
+    _w2 = vec3(float(_r0087.x), float(_r0087.y), float(_r0087.z));
+    _TMP9 = COMPAT_TEXTURE(Texture, TEX1.zw);
+    _v0097 = vec3(float(_TMP9.x), float(_TMP9.y), float(_TMP9.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.z = float(_TMP43);
+    _w3 = vec3(float(_r0097.x), float(_r0097.y), float(_r0097.z));
+    _TMP11 = COMPAT_TEXTURE(Texture, TEX2.xw);
+    _v0107 = vec3(float(_TMP11.x), float(_TMP11.y), float(_TMP11.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.z = float(_TMP43);
+    _w4 = vec3(float(_r0107.x), float(_r0107.y), float(_r0107.z));
+    _v0115 = vec3(float(_TMP1.x), float(_TMP1.y), float(_TMP1.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.z = float(_TMP43);
+    _w5 = vec3(float(_r0115.x), float(_r0115.y), float(_r0115.z));
+    _TMP14 = COMPAT_TEXTURE(Texture, TEX2.zw);
+    _v0125 = vec3(float(_TMP14.x), float(_TMP14.y), float(_TMP14.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.z = float(_TMP43);
+    _w6 = vec3(float(_r0125.x), float(_r0125.y), float(_r0125.z));
+    _TMP16 = COMPAT_TEXTURE(Texture, TEX3.xw);
+    _v0135 = vec3(float(_TMP16.x), float(_TMP16.y), float(_TMP16.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.z = float(_TMP43);
+    _w7 = vec3(float(_r0135.x), float(_r0135.y), float(_r0135.z));
+    _TMP18 = COMPAT_TEXTURE(Texture, TEX3.yw);
+    _v0145 = vec3(float(_TMP18.x), float(_TMP18.y), float(_TMP18.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.z = float(_TMP43);
+    _w8 = vec3(float(_r0145.x), float(_r0145.y), float(_r0145.z));
+    _TMP20 = COMPAT_TEXTURE(Texture, TEX3.zw);
+    _v0155 = vec3(float(_TMP20.x), float(_TMP20.y), float(_TMP20.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.z = float(_TMP43);
+    _w9 = vec3(float(_r0155.x), float(_r0155.y), float(_r0155.z));
+    _a0165 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w1 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0165);
+    _res0163 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP22 = _res0163.x || _res0163.y || _res0163.z;
+    _a0169 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0169);
+    _res0167 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP23 = _res0167.x || _res0167.y || _res0167.z;
+    _a0173 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w3 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0173);
+    _res0171 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP24 = _res0171.x || _res0171.y || _res0171.z;
+    _a0177 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0177);
+    _res0175 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP25 = _res0175.x || _res0175.y || _res0175.z;
+    _a0181 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0181);
+    _res0179 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP26 = _res0179.x || _res0179.y || _res0179.z;
+    _a0185 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w7 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0185);
+    _res0183 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP27 = _res0183.x || _res0183.y || _res0183.z;
+    _a0189 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0189);
+    _res0187 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP28 = _res0187.x || _res0187.y || _res0187.z;
+    _a0193 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w9 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0193);
+    _res0191 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP29 = _res0191.x || _res0191.y || _res0191.z;
+    _TMP50[0] = bvec3(_TMP22, _TMP23, _TMP24);
+    _TMP50[1] = bvec3(_TMP25, false, _TMP26);
+    _TMP50[2] = bvec3(_TMP27, _TMP28, _TMP29);
+    _a0197 = (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0197);
+    _res0195 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP30 = _res0195.x || _res0195.y || _res0195.z;
+    _a0201 = (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0201);
+    _res0199 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP31 = _res0199.x || _res0199.y || _res0199.z;
+    _a0205 = (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0205);
+    _res0203 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP32 = _res0203.x || _res0203.y || _res0203.z;
+    _a0209 = (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0209);
+    _res0207 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP33 = _res0207.x || _res0207.y || _res0207.z;
+    _cross = bvec4(_TMP30, _TMP31, _TMP32, _TMP33);
+    _a0211 = vec3(float(_TMP50[0].x), float(_TMP50[0].y), float(_TMP50[0].z));
+    _TMP43 = dot(vec3(float(_a0211.x), float(_a0211.y), float(_a0211.z)), vec3( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00));
+    _TMP34 = float(_TMP43);
+    _a0213 = vec3(float(_TMP50[1].x), float(_TMP50[1].y), float(_TMP50[1].z));
+    _TMP43 = dot(vec3(float(_a0213.x), float(_a0213.y), float(_a0213.z)), vec3( 8.00000000E+00, 0.00000000E+00, 1.60000000E+01));
+    _TMP35 = float(_TMP43);
+    _a0215 = vec3(float(_TMP50[2].x), float(_TMP50[2].y), float(_TMP50[2].z));
+    _TMP43 = dot(vec3(float(_a0215.x), float(_a0215.y), float(_a0215.z)), vec3( 3.20000000E+01, 6.40000000E+01, 1.28000000E+02));
+    _TMP36 = float(_TMP43);
+    _index.x = _TMP34 + _TMP35 + _TMP36;
+    _a0217 = vec4(float(_cross.x), float(_cross.y), float(_cross.z), float(_cross.w));
+    _TMP44 = dot(vec4(float(_a0217.x), float(_a0217.y), float(_a0217.z), float(_a0217.w)), vec4( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00, 8.00000000E+00));
+    _TMP37 = float(_TMP44);
+    _x0219 = _fp*2.00000000E+00;
+    _TMP38 = floor(_x0219);
+    _TMP39 = dot(_TMP38, vec2( 1.00000000E+00, 2.00000000E+00));
+    _index.y = float((float((_TMP37*4.00000000E+00)) + _TMP39));
+    _c0223 = vec2(float((_index*vec2( 3.90625000E-03, 1.56250000E-02) + vec2( 1.95312500E-03, 7.81250000E-03)).x), float((_index*vec2( 3.90625000E-03, 1.56250000E-02) + vec2( 1.95312500E-03, 7.81250000E-03)).y));
+    _TMP40 = COMPAT_TEXTURE(LUT, _c0223);
+    _weights = vec4(float(_TMP40.x), float(_TMP40.y), float(_TMP40.z), float(_TMP40.w));
+    _TMP44 = dot(vec4(float(_weights.x), float(_weights.y), float(_weights.z), float(_weights.w)), vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));
+    _sum = float(_TMP44);
+    _v0229 = vec4(float((_weights/_sum).x), float((_weights/_sum).y), float((_weights/_sum).z), float((_weights/_sum).w));
+    _r0229 = _v0229.x*_TMP1.xyz;
+    _r0229 = _r0229 + _v0229.y*_TMP2.xyz;
+    _r0229 = _r0229 + _v0229.z*_TMP3.xyz;
+    _r0229 = _r0229 + _v0229.w*_TMP4.xyz;
+    _ret_0 = vec4(_r0229.x, _r0229.y, _r0229.z, 1.00000000E+00);
+    FragColor = _ret_0;
+    return;
+} 
+#endif
diff --git a/base/hqx/single-pass/shader-files/hq3x.glsl b/base/hqx/single-pass/shader-files/hq3x.glsl
new file mode 100644
index 0000000..05e7512
--- /dev/null
+++ b/base/hqx/single-pass/shader-files/hq3x.glsl
@@ -0,0 +1,434 @@
+// GLSL shader autogenerated by cg2glsl.py.
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord1;
+COMPAT_VARYING     vec4 _color1;
+COMPAT_VARYING     vec4 _position1;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _position1;
+    vec4 _color1;
+    vec2 _texCoord1;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+out_vertex _ret_0;
+input_dummy _IN1;
+vec4 _r0010;
+vec4 _v0010;
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    out_vertex _OUT;
+    vec2 _ps;
+    _v0010 = vec4(float(VertexCoord.x), float(VertexCoord.y), float(VertexCoord.z), float(VertexCoord.w));
+    _r0010 = _v0010.x*MVPMatrix[0];
+    _r0010 = _r0010 + _v0010.y*MVPMatrix[1];
+    _r0010 = _r0010 + _v0010.z*MVPMatrix[2];
+    _r0010 = _r0010 + _v0010.w*MVPMatrix[3];
+    _OUT._position1 = vec4(float(_r0010.x), float(_r0010.y), float(_r0010.z), float(_r0010.w));
+    _ps = 1.00000000E+00/TextureSize;
+    _OUT._t1 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(-_ps.y)));
+    _OUT._t2 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), 0.00000000E+00);
+    _OUT._t3 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(_ps.y)));
+    _ret_0._position1 = _OUT._position1;
+    _ret_0._color1 = COLOR;
+    _ret_0._texCoord1 = TexCoord.xy;
+    _ret_0._t1 = _OUT._t1;
+    _ret_0._t2 = _OUT._t2;
+    _ret_0._t3 = _OUT._t3;
+    VARps = _ps;
+    gl_Position = _OUT._position1;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+    TEX1 = _OUT._t1;
+    TEX2 = _OUT._t2;
+    TEX3 = _OUT._t3;
+    return;
+    COL0 = _ret_0._color1;
+    TEX0.xy = _ret_0._texCoord1;
+    TEX1 = _ret_0._t1;
+    TEX2 = _ret_0._t2;
+    TEX3 = _ret_0._t3;
+} 
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord;
+COMPAT_VARYING     vec4 _color;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _color;
+    vec2 _texCoord;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+vec4 _ret_0;
+float _TMP44;
+vec4 _TMP40;
+float _TMP39;
+float _TMP37;
+vec2 _TMP38;
+float _TMP36;
+float _TMP35;
+float _TMP34;
+float _TMP43;
+bool _TMP33;
+bool _TMP32;
+bool _TMP31;
+bool _TMP30;
+vec3 _TMP42;
+bool _TMP29;
+bool _TMP28;
+bool _TMP27;
+bool _TMP26;
+bool _TMP25;
+bool _TMP24;
+bool _TMP23;
+bool _TMP22;
+vec4 _TMP20;
+vec4 _TMP18;
+vec4 _TMP16;
+vec4 _TMP14;
+vec4 _TMP11;
+vec4 _TMP9;
+vec4 _TMP7;
+vec4 _TMP5;
+vec4 _TMP4;
+vec4 _TMP3;
+vec4 _TMP2;
+vec4 _TMP1;
+vec2 _TMP0;
+out_vertex _VAR1;
+uniform sampler2D Texture;
+input_dummy _IN1;
+uniform sampler2D LUT;
+vec2 _x0063;
+vec2 _val0065;
+vec2 _a0065;
+vec2 _c0069;
+vec2 _c0071;
+vec2 _c0073;
+vec3 _r0077;
+vec3 _v0077;
+vec3 _r0087;
+vec3 _v0087;
+vec3 _r0097;
+vec3 _v0097;
+vec3 _r0107;
+vec3 _v0107;
+vec3 _r0115;
+vec3 _v0115;
+vec3 _r0125;
+vec3 _v0125;
+vec3 _r0135;
+vec3 _v0135;
+vec3 _r0145;
+vec3 _v0145;
+vec3 _r0155;
+vec3 _v0155;
+bvec3 _res0163;
+vec3 _a0165;
+bvec3 _res0167;
+vec3 _a0169;
+bvec3 _res0171;
+vec3 _a0173;
+bvec3 _res0175;
+vec3 _a0177;
+bvec3 _res0179;
+vec3 _a0181;
+bvec3 _res0183;
+vec3 _a0185;
+bvec3 _res0187;
+vec3 _a0189;
+bvec3 _res0191;
+vec3 _a0193;
+bvec3 _res0195;
+vec3 _a0197;
+bvec3 _res0199;
+vec3 _a0201;
+bvec3 _res0203;
+vec3 _a0205;
+bvec3 _res0207;
+vec3 _a0209;
+vec3 _a0211;
+vec3 _a0213;
+vec3 _a0215;
+vec4 _a0217;
+vec2 _x0219;
+vec2 _c0223;
+vec3 _r0229;
+vec4 _v0229;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    vec2 _fp;
+    vec2 _quad;
+    vec3 _w1;
+    vec3 _w2;
+    vec3 _w3;
+    vec3 _w4;
+    vec3 _w5;
+    vec3 _w6;
+    vec3 _w7;
+    vec3 _w8;
+    vec3 _w9;
+    bvec4 _cross;
+    vec2 _index;
+    vec4 _weights;
+    float _sum;
+    bvec3 _TMP50[3];
+    _x0063 = TEX0.xy*TextureSize;
+    _fp = fract(_x0063);
+    _a0065 = -5.00000000E-01 + _fp;
+    _val0065 = vec2(float((_a0065.x > 0.00000000E+00)), float((_a0065.y > 0.00000000E+00)));
+    _TMP0 = _val0065 - vec2(float((_a0065.x < 0.00000000E+00)), float((_a0065.y < 0.00000000E+00)));
+    _quad = vec2(float(_TMP0.x), float(_TMP0.y));
+    _TMP1 = COMPAT_TEXTURE(Texture, TEX0.xy);
+    _c0069 = TEX0.xy + vec2(VARps.x, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP2 = COMPAT_TEXTURE(Texture, _c0069);
+    _c0071 = TEX0.xy + vec2(VARps.x, 0.00000000E+00)*vec2(float(_quad.x), float(_quad.y));
+    _TMP3 = COMPAT_TEXTURE(Texture, _c0071);
+    _c0073 = TEX0.xy + vec2(0.00000000E+00, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP4 = COMPAT_TEXTURE(Texture, _c0073);
+    _TMP5 = COMPAT_TEXTURE(Texture, TEX1.xw);
+    _v0077 = vec3(float(_TMP5.x), float(_TMP5.y), float(_TMP5.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.z = float(_TMP43);
+    _w1 = vec3(float(_r0077.x), float(_r0077.y), float(_r0077.z));
+    _TMP7 = COMPAT_TEXTURE(Texture, TEX1.yw);
+    _v0087 = vec3(float(_TMP7.x), float(_TMP7.y), float(_TMP7.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.z = float(_TMP43);
+    _w2 = vec3(float(_r0087.x), float(_r0087.y), float(_r0087.z));
+    _TMP9 = COMPAT_TEXTURE(Texture, TEX1.zw);
+    _v0097 = vec3(float(_TMP9.x), float(_TMP9.y), float(_TMP9.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.z = float(_TMP43);
+    _w3 = vec3(float(_r0097.x), float(_r0097.y), float(_r0097.z));
+    _TMP11 = COMPAT_TEXTURE(Texture, TEX2.xw);
+    _v0107 = vec3(float(_TMP11.x), float(_TMP11.y), float(_TMP11.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.z = float(_TMP43);
+    _w4 = vec3(float(_r0107.x), float(_r0107.y), float(_r0107.z));
+    _v0115 = vec3(float(_TMP1.x), float(_TMP1.y), float(_TMP1.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.z = float(_TMP43);
+    _w5 = vec3(float(_r0115.x), float(_r0115.y), float(_r0115.z));
+    _TMP14 = COMPAT_TEXTURE(Texture, TEX2.zw);
+    _v0125 = vec3(float(_TMP14.x), float(_TMP14.y), float(_TMP14.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.z = float(_TMP43);
+    _w6 = vec3(float(_r0125.x), float(_r0125.y), float(_r0125.z));
+    _TMP16 = COMPAT_TEXTURE(Texture, TEX3.xw);
+    _v0135 = vec3(float(_TMP16.x), float(_TMP16.y), float(_TMP16.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.z = float(_TMP43);
+    _w7 = vec3(float(_r0135.x), float(_r0135.y), float(_r0135.z));
+    _TMP18 = COMPAT_TEXTURE(Texture, TEX3.yw);
+    _v0145 = vec3(float(_TMP18.x), float(_TMP18.y), float(_TMP18.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.z = float(_TMP43);
+    _w8 = vec3(float(_r0145.x), float(_r0145.y), float(_r0145.z));
+    _TMP20 = COMPAT_TEXTURE(Texture, TEX3.zw);
+    _v0155 = vec3(float(_TMP20.x), float(_TMP20.y), float(_TMP20.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.z = float(_TMP43);
+    _w9 = vec3(float(_r0155.x), float(_r0155.y), float(_r0155.z));
+    _a0165 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w1 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0165);
+    _res0163 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP22 = _res0163.x || _res0163.y || _res0163.z;
+    _a0169 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0169);
+    _res0167 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP23 = _res0167.x || _res0167.y || _res0167.z;
+    _a0173 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w3 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0173);
+    _res0171 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP24 = _res0171.x || _res0171.y || _res0171.z;
+    _a0177 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0177);
+    _res0175 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP25 = _res0175.x || _res0175.y || _res0175.z;
+    _a0181 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0181);
+    _res0179 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP26 = _res0179.x || _res0179.y || _res0179.z;
+    _a0185 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w7 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0185);
+    _res0183 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP27 = _res0183.x || _res0183.y || _res0183.z;
+    _a0189 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0189);
+    _res0187 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP28 = _res0187.x || _res0187.y || _res0187.z;
+    _a0193 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w9 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0193);
+    _res0191 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP29 = _res0191.x || _res0191.y || _res0191.z;
+    _TMP50[0] = bvec3(_TMP22, _TMP23, _TMP24);
+    _TMP50[1] = bvec3(_TMP25, false, _TMP26);
+    _TMP50[2] = bvec3(_TMP27, _TMP28, _TMP29);
+    _a0197 = (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0197);
+    _res0195 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP30 = _res0195.x || _res0195.y || _res0195.z;
+    _a0201 = (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0201);
+    _res0199 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP31 = _res0199.x || _res0199.y || _res0199.z;
+    _a0205 = (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0205);
+    _res0203 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP32 = _res0203.x || _res0203.y || _res0203.z;
+    _a0209 = (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0209);
+    _res0207 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP33 = _res0207.x || _res0207.y || _res0207.z;
+    _cross = bvec4(_TMP30, _TMP31, _TMP32, _TMP33);
+    _a0211 = vec3(float(_TMP50[0].x), float(_TMP50[0].y), float(_TMP50[0].z));
+    _TMP43 = dot(vec3(float(_a0211.x), float(_a0211.y), float(_a0211.z)), vec3( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00));
+    _TMP34 = float(_TMP43);
+    _a0213 = vec3(float(_TMP50[1].x), float(_TMP50[1].y), float(_TMP50[1].z));
+    _TMP43 = dot(vec3(float(_a0213.x), float(_a0213.y), float(_a0213.z)), vec3( 8.00000000E+00, 0.00000000E+00, 1.60000000E+01));
+    _TMP35 = float(_TMP43);
+    _a0215 = vec3(float(_TMP50[2].x), float(_TMP50[2].y), float(_TMP50[2].z));
+    _TMP43 = dot(vec3(float(_a0215.x), float(_a0215.y), float(_a0215.z)), vec3( 3.20000000E+01, 6.40000000E+01, 1.28000000E+02));
+    _TMP36 = float(_TMP43);
+    _index.x = _TMP34 + _TMP35 + _TMP36;
+    _a0217 = vec4(float(_cross.x), float(_cross.y), float(_cross.z), float(_cross.w));
+    _TMP44 = dot(vec4(float(_a0217.x), float(_a0217.y), float(_a0217.z), float(_a0217.w)), vec4( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00, 8.00000000E+00));
+    _TMP37 = float(_TMP44);
+    _x0219 = _fp*3.00000000E+00;
+    _TMP38 = floor(_x0219);
+    _TMP39 = dot(_TMP38, vec2( 1.00000000E+00, 3.00000000E+00));
+    _index.y = float((float((_TMP37*9.00000000E+00)) + _TMP39));
+    _c0223 = vec2(float((_index*vec2( 3.90625000E-03, 6.94274902E-03) + vec2( 1.95312500E-03, 3.47137451E-03)).x), float((_index*vec2( 3.90625000E-03, 6.94274902E-03) + vec2( 1.95312500E-03, 3.47137451E-03)).y));
+    _TMP40 = COMPAT_TEXTURE(LUT, _c0223);
+    _weights = vec4(float(_TMP40.x), float(_TMP40.y), float(_TMP40.z), float(_TMP40.w));
+    _TMP44 = dot(vec4(float(_weights.x), float(_weights.y), float(_weights.z), float(_weights.w)), vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));
+    _sum = float(_TMP44);
+    _v0229 = vec4(float((_weights/_sum).x), float((_weights/_sum).y), float((_weights/_sum).z), float((_weights/_sum).w));
+    _r0229 = _v0229.x*_TMP1.xyz;
+    _r0229 = _r0229 + _v0229.y*_TMP2.xyz;
+    _r0229 = _r0229 + _v0229.z*_TMP3.xyz;
+    _r0229 = _r0229 + _v0229.w*_TMP4.xyz;
+    _ret_0 = vec4(_r0229.x, _r0229.y, _r0229.z, 1.00000000E+00);
+    FragColor = _ret_0;
+    return;
+} 
+#endif
diff --git a/base/hqx/single-pass/shader-files/hq4x.glsl b/base/hqx/single-pass/shader-files/hq4x.glsl
new file mode 100644
index 0000000..3dac5a7
--- /dev/null
+++ b/base/hqx/single-pass/shader-files/hq4x.glsl
@@ -0,0 +1,434 @@
+// GLSL shader autogenerated by cg2glsl.py.
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord1;
+COMPAT_VARYING     vec4 _color1;
+COMPAT_VARYING     vec4 _position1;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _position1;
+    vec4 _color1;
+    vec2 _texCoord1;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+out_vertex _ret_0;
+input_dummy _IN1;
+vec4 _r0010;
+vec4 _v0010;
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    out_vertex _OUT;
+    vec2 _ps;
+    _v0010 = vec4(float(VertexCoord.x), float(VertexCoord.y), float(VertexCoord.z), float(VertexCoord.w));
+    _r0010 = _v0010.x*MVPMatrix[0];
+    _r0010 = _r0010 + _v0010.y*MVPMatrix[1];
+    _r0010 = _r0010 + _v0010.z*MVPMatrix[2];
+    _r0010 = _r0010 + _v0010.w*MVPMatrix[3];
+    _OUT._position1 = vec4(float(_r0010.x), float(_r0010.y), float(_r0010.z), float(_r0010.w));
+    _ps = 1.00000000E+00/TextureSize;
+    _OUT._t1 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(-_ps.y)));
+    _OUT._t2 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), 0.00000000E+00);
+    _OUT._t3 = TexCoord.xxxy + vec4(float(float(-_ps.x)), 0.00000000E+00, float(float(_ps.x)), float(float(_ps.y)));
+    _ret_0._position1 = _OUT._position1;
+    _ret_0._color1 = COLOR;
+    _ret_0._texCoord1 = TexCoord.xy;
+    _ret_0._t1 = _OUT._t1;
+    _ret_0._t2 = _OUT._t2;
+    _ret_0._t3 = _OUT._t3;
+    VARps = _ps;
+    gl_Position = _OUT._position1;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+    TEX1 = _OUT._t1;
+    TEX2 = _OUT._t2;
+    TEX3 = _OUT._t3;
+    return;
+    COL0 = _ret_0._color1;
+    TEX0.xy = _ret_0._texCoord1;
+    TEX1 = _ret_0._t1;
+    TEX2 = _ret_0._t2;
+    TEX3 = _ret_0._t3;
+} 
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+COMPAT_VARYING     vec2 VARps;
+COMPAT_VARYING     vec4 _t3;
+COMPAT_VARYING     vec4 _t2;
+COMPAT_VARYING     vec4 _t1;
+COMPAT_VARYING     vec2 _texCoord;
+COMPAT_VARYING     vec4 _color;
+struct input_dummy {
+    vec2 _video_size;
+    vec2 _texture_size;
+    vec2 _output_dummy_size;
+};
+struct out_vertex {
+    vec4 _color;
+    vec2 _texCoord;
+    vec4 _t1;
+    vec4 _t2;
+    vec4 _t3;
+    vec2 VARps;
+};
+vec4 _ret_0;
+float _TMP44;
+vec4 _TMP40;
+float _TMP39;
+float _TMP37;
+vec2 _TMP38;
+float _TMP36;
+float _TMP35;
+float _TMP34;
+float _TMP43;
+bool _TMP33;
+bool _TMP32;
+bool _TMP31;
+bool _TMP30;
+vec3 _TMP42;
+bool _TMP29;
+bool _TMP28;
+bool _TMP27;
+bool _TMP26;
+bool _TMP25;
+bool _TMP24;
+bool _TMP23;
+bool _TMP22;
+vec4 _TMP20;
+vec4 _TMP18;
+vec4 _TMP16;
+vec4 _TMP14;
+vec4 _TMP11;
+vec4 _TMP9;
+vec4 _TMP7;
+vec4 _TMP5;
+vec4 _TMP4;
+vec4 _TMP3;
+vec4 _TMP2;
+vec4 _TMP1;
+vec2 _TMP0;
+out_vertex _VAR1;
+uniform sampler2D Texture;
+input_dummy _IN1;
+uniform sampler2D LUT;
+vec2 _x0063;
+vec2 _val0065;
+vec2 _a0065;
+vec2 _c0069;
+vec2 _c0071;
+vec2 _c0073;
+vec3 _r0077;
+vec3 _v0077;
+vec3 _r0087;
+vec3 _v0087;
+vec3 _r0097;
+vec3 _v0097;
+vec3 _r0107;
+vec3 _v0107;
+vec3 _r0115;
+vec3 _v0115;
+vec3 _r0125;
+vec3 _v0125;
+vec3 _r0135;
+vec3 _v0135;
+vec3 _r0145;
+vec3 _v0145;
+vec3 _r0155;
+vec3 _v0155;
+bvec3 _res0163;
+vec3 _a0165;
+bvec3 _res0167;
+vec3 _a0169;
+bvec3 _res0171;
+vec3 _a0173;
+bvec3 _res0175;
+vec3 _a0177;
+bvec3 _res0179;
+vec3 _a0181;
+bvec3 _res0183;
+vec3 _a0185;
+bvec3 _res0187;
+vec3 _a0189;
+bvec3 _res0191;
+vec3 _a0193;
+bvec3 _res0195;
+vec3 _a0197;
+bvec3 _res0199;
+vec3 _a0201;
+bvec3 _res0203;
+vec3 _a0205;
+bvec3 _res0207;
+vec3 _a0209;
+vec3 _a0211;
+vec3 _a0213;
+vec3 _a0215;
+vec4 _a0217;
+vec2 _x0219;
+vec2 _c0223;
+vec3 _r0229;
+vec4 _v0229;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 TEX1;
+COMPAT_VARYING vec4 TEX2;
+COMPAT_VARYING vec4 TEX3;
+ 
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+void main()
+{
+    vec2 _fp;
+    vec2 _quad;
+    vec3 _w1;
+    vec3 _w2;
+    vec3 _w3;
+    vec3 _w4;
+    vec3 _w5;
+    vec3 _w6;
+    vec3 _w7;
+    vec3 _w8;
+    vec3 _w9;
+    bvec4 _cross;
+    vec2 _index;
+    vec4 _weights;
+    float _sum;
+    bvec3 _TMP50[3];
+    _x0063 = TEX0.xy*TextureSize;
+    _fp = fract(_x0063);
+    _a0065 = -5.00000000E-01 + _fp;
+    _val0065 = vec2(float((_a0065.x > 0.00000000E+00)), float((_a0065.y > 0.00000000E+00)));
+    _TMP0 = _val0065 - vec2(float((_a0065.x < 0.00000000E+00)), float((_a0065.y < 0.00000000E+00)));
+    _quad = vec2(float(_TMP0.x), float(_TMP0.y));
+    _TMP1 = COMPAT_TEXTURE(Texture, TEX0.xy);
+    _c0069 = TEX0.xy + vec2(VARps.x, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP2 = COMPAT_TEXTURE(Texture, _c0069);
+    _c0071 = TEX0.xy + vec2(VARps.x, 0.00000000E+00)*vec2(float(_quad.x), float(_quad.y));
+    _TMP3 = COMPAT_TEXTURE(Texture, _c0071);
+    _c0073 = TEX0.xy + vec2(0.00000000E+00, VARps.y)*vec2(float(_quad.x), float(_quad.y));
+    _TMP4 = COMPAT_TEXTURE(Texture, _c0073);
+    _TMP5 = COMPAT_TEXTURE(Texture, TEX1.xw);
+    _v0077 = vec3(float(_TMP5.x), float(_TMP5.y), float(_TMP5.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0077.x), float(_v0077.y), float(_v0077.z)));
+    _r0077.z = float(_TMP43);
+    _w1 = vec3(float(_r0077.x), float(_r0077.y), float(_r0077.z));
+    _TMP7 = COMPAT_TEXTURE(Texture, TEX1.yw);
+    _v0087 = vec3(float(_TMP7.x), float(_TMP7.y), float(_TMP7.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0087.x), float(_v0087.y), float(_v0087.z)));
+    _r0087.z = float(_TMP43);
+    _w2 = vec3(float(_r0087.x), float(_r0087.y), float(_r0087.z));
+    _TMP9 = COMPAT_TEXTURE(Texture, TEX1.zw);
+    _v0097 = vec3(float(_TMP9.x), float(_TMP9.y), float(_TMP9.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0097.x), float(_v0097.y), float(_v0097.z)));
+    _r0097.z = float(_TMP43);
+    _w3 = vec3(float(_r0097.x), float(_r0097.y), float(_r0097.z));
+    _TMP11 = COMPAT_TEXTURE(Texture, TEX2.xw);
+    _v0107 = vec3(float(_TMP11.x), float(_TMP11.y), float(_TMP11.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0107.x), float(_v0107.y), float(_v0107.z)));
+    _r0107.z = float(_TMP43);
+    _w4 = vec3(float(_r0107.x), float(_r0107.y), float(_r0107.z));
+    _v0115 = vec3(float(_TMP1.x), float(_TMP1.y), float(_TMP1.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0115.x), float(_v0115.y), float(_v0115.z)));
+    _r0115.z = float(_TMP43);
+    _w5 = vec3(float(_r0115.x), float(_r0115.y), float(_r0115.z));
+    _TMP14 = COMPAT_TEXTURE(Texture, TEX2.zw);
+    _v0125 = vec3(float(_TMP14.x), float(_TMP14.y), float(_TMP14.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0125.x), float(_v0125.y), float(_v0125.z)));
+    _r0125.z = float(_TMP43);
+    _w6 = vec3(float(_r0125.x), float(_r0125.y), float(_r0125.z));
+    _TMP16 = COMPAT_TEXTURE(Texture, TEX3.xw);
+    _v0135 = vec3(float(_TMP16.x), float(_TMP16.y), float(_TMP16.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0135.x), float(_v0135.y), float(_v0135.z)));
+    _r0135.z = float(_TMP43);
+    _w7 = vec3(float(_r0135.x), float(_r0135.y), float(_r0135.z));
+    _TMP18 = COMPAT_TEXTURE(Texture, TEX3.yw);
+    _v0145 = vec3(float(_TMP18.x), float(_TMP18.y), float(_TMP18.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0145.x), float(_v0145.y), float(_v0145.z)));
+    _r0145.z = float(_TMP43);
+    _w8 = vec3(float(_r0145.x), float(_r0145.y), float(_r0145.z));
+    _TMP20 = COMPAT_TEXTURE(Texture, TEX3.zw);
+    _v0155 = vec3(float(_TMP20.x), float(_TMP20.y), float(_TMP20.z));
+    _TMP43 = dot(vec3( 2.99072266E-01, 5.86914062E-01, 1.14013672E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.x = float(_TMP43);
+    _TMP43 = dot(vec3( -1.68945312E-01, -3.31054688E-01, 5.00000000E-01), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.y = float(_TMP43);
+    _TMP43 = dot(vec3( 5.00000000E-01, -4.18945312E-01, -8.09936523E-02), vec3(float(_v0155.x), float(_v0155.y), float(_v0155.z)));
+    _r0155.z = float(_TMP43);
+    _w9 = vec3(float(_r0155.x), float(_r0155.y), float(_r0155.z));
+    _a0165 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w1 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0165);
+    _res0163 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP22 = _res0163.x || _res0163.y || _res0163.z;
+    _a0169 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0169);
+    _res0167 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP23 = _res0167.x || _res0167.y || _res0167.z;
+    _a0173 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w3 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0173);
+    _res0171 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP24 = _res0171.x || _res0171.y || _res0171.z;
+    _a0177 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0177);
+    _res0175 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP25 = _res0175.x || _res0175.y || _res0175.z;
+    _a0181 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0181);
+    _res0179 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP26 = _res0179.x || _res0179.y || _res0179.z;
+    _a0185 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w7 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0185);
+    _res0183 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP27 = _res0183.x || _res0183.y || _res0183.z;
+    _a0189 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0189);
+    _res0187 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP28 = _res0187.x || _res0187.y || _res0187.z;
+    _a0193 = (_w5 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w9 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0193);
+    _res0191 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP29 = _res0191.x || _res0191.y || _res0191.z;
+    _TMP50[0] = bvec3(_TMP22, _TMP23, _TMP24);
+    _TMP50[1] = bvec3(_TMP25, false, _TMP26);
+    _TMP50[2] = bvec3(_TMP27, _TMP28, _TMP29);
+    _a0197 = (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0197);
+    _res0195 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP30 = _res0195.x || _res0195.y || _res0195.z;
+    _a0201 = (_w2 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0201);
+    _res0199 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP31 = _res0199.x || _res0199.y || _res0199.z;
+    _a0205 = (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w4 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0205);
+    _res0203 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP32 = _res0203.x || _res0203.y || _res0203.z;
+    _a0209 = (_w6 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01)) - (_w8 + vec3( 0.00000000E+00, 5.00000000E-01, 5.00000000E-01));
+    _TMP42 = abs(_a0209);
+    _res0207 = bvec3(_TMP42.x > 1.88232422E-01, _TMP42.y > 2.74505615E-02, _TMP42.z > 2.35290527E-02);
+    _TMP33 = _res0207.x || _res0207.y || _res0207.z;
+    _cross = bvec4(_TMP30, _TMP31, _TMP32, _TMP33);
+    _a0211 = vec3(float(_TMP50[0].x), float(_TMP50[0].y), float(_TMP50[0].z));
+    _TMP43 = dot(vec3(float(_a0211.x), float(_a0211.y), float(_a0211.z)), vec3( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00));
+    _TMP34 = float(_TMP43);
+    _a0213 = vec3(float(_TMP50[1].x), float(_TMP50[1].y), float(_TMP50[1].z));
+    _TMP43 = dot(vec3(float(_a0213.x), float(_a0213.y), float(_a0213.z)), vec3( 8.00000000E+00, 0.00000000E+00, 1.60000000E+01));
+    _TMP35 = float(_TMP43);
+    _a0215 = vec3(float(_TMP50[2].x), float(_TMP50[2].y), float(_TMP50[2].z));
+    _TMP43 = dot(vec3(float(_a0215.x), float(_a0215.y), float(_a0215.z)), vec3( 3.20000000E+01, 6.40000000E+01, 1.28000000E+02));
+    _TMP36 = float(_TMP43);
+    _index.x = _TMP34 + _TMP35 + _TMP36;
+    _a0217 = vec4(float(_cross.x), float(_cross.y), float(_cross.z), float(_cross.w));
+    _TMP44 = dot(vec4(float(_a0217.x), float(_a0217.y), float(_a0217.z), float(_a0217.w)), vec4( 1.00000000E+00, 2.00000000E+00, 4.00000000E+00, 8.00000000E+00));
+    _TMP37 = float(_TMP44);
+    _x0219 = _fp*4.00000000E+00;
+    _TMP38 = floor(_x0219);
+    _TMP39 = dot(_TMP38, vec2( 1.00000000E+00, 4.00000000E+00));
+    _index.y = float((float((_TMP37*1.60000000E+01)) + _TMP39));
+    _c0223 = vec2(float((_index*vec2( 3.90625000E-03, 3.90625000E-03) + vec2( 1.95312500E-03, 1.95312500E-03)).x), float((_index*vec2( 3.90625000E-03, 3.90625000E-03) + vec2( 1.95312500E-03, 1.95312500E-03)).y));
+    _TMP40 = COMPAT_TEXTURE(LUT, _c0223);
+    _weights = vec4(float(_TMP40.x), float(_TMP40.y), float(_TMP40.z), float(_TMP40.w));
+    _TMP44 = dot(vec4(float(_weights.x), float(_weights.y), float(_weights.z), float(_weights.w)), vec4( 1.00000000E+00, 1.00000000E+00, 1.00000000E+00, 1.00000000E+00));
+    _sum = float(_TMP44);
+    _v0229 = vec4(float((_weights/_sum).x), float((_weights/_sum).y), float((_weights/_sum).z), float((_weights/_sum).w));
+    _r0229 = _v0229.x*_TMP1.xyz;
+    _r0229 = _r0229 + _v0229.y*_TMP2.xyz;
+    _r0229 = _r0229 + _v0229.z*_TMP3.xyz;
+    _r0229 = _r0229 + _v0229.w*_TMP4.xyz;
+    _ret_0 = vec4(_r0229.x, _r0229.y, _r0229.z, 1.00000000E+00);
+    FragColor = _ret_0;
+    return;
+} 
+#endif
diff --git a/base/sabr/sabr-hybrid-deposterize.glslp b/base/sabr/sabr-hybrid-deposterize.glslp
new file mode 100644
index 0000000..af0aede
--- /dev/null
+++ b/base/sabr/sabr-hybrid-deposterize.glslp
@@ -0,0 +1,4 @@
+shaders = 1
+
+shader0 = "shaders/sabr-hybrid-deposterize.glsl"
+filter_linear0 = false
diff --git a/base/sabr/sabr.glslp b/base/sabr/sabr.glslp
new file mode 100644
index 0000000..9de651f
--- /dev/null
+++ b/base/sabr/sabr.glslp
@@ -0,0 +1,4 @@
+shaders = 1
+
+shader0 = shaders/sabr-v3.0.glsl
+filter_linear0 = false
diff --git a/base/sabr/shaders/sabr-hybrid-deposterize.glsl b/base/sabr/shaders/sabr-hybrid-deposterize.glsl
new file mode 100644
index 0000000..f46f176
--- /dev/null
+++ b/base/sabr/shaders/sabr-hybrid-deposterize.glsl
@@ -0,0 +1,462 @@
+/*
+	SABR v3.0 Shader
+	Joshua Street
+	
+	Portions of this algorithm were taken from Hyllian's 5xBR v3.7c
+	shader.
+	
+	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.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter minimum "Edge Thresh Min" 0.05 0.0 1.0 0.01
+#pragma parameter maximum "Edge Thresh Max" 0.08 0.0 1.0 0.01
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+COMPAT_VARYING vec2 tc;
+COMPAT_VARYING vec4 xyp_1_2_3;
+COMPAT_VARYING vec4 xyp_5_10_15;
+COMPAT_VARYING vec4 xyp_6_7_8;
+COMPAT_VARYING vec4 xyp_9_14_9;
+COMPAT_VARYING vec4 xyp_11_12_13;
+COMPAT_VARYING vec4 xyp_16_17_18;
+COMPAT_VARYING vec4 xyp_21_22_23;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	
+	float x = SourceSize.z;//1.0 / IN.texture_size.x;
+	float y = SourceSize.w;//1.0 / IN.texture_size.y;
+	
+	tc = TEX0.xy * vec2(1.0004, 1.0);
+	xyp_1_2_3    = tc.xxxy + vec4(      -x, 0.0,   x, -2.0 * y);
+	xyp_6_7_8    = tc.xxxy + vec4(      -x, 0.0,   x,       -y);
+	xyp_11_12_13 = tc.xxxy + vec4(      -x, 0.0,   x,      0.0);
+	xyp_16_17_18 = tc.xxxy + vec4(      -x, 0.0,   x,        y);
+	xyp_21_22_23 = tc.xxxy + vec4(      -x, 0.0,   x,  2.0 * y);
+	xyp_5_10_15  = tc.xyyy + vec4(-2.0 * x,  -y, 0.0,        y);
+	xyp_9_14_9   = tc.xyyy + vec4( 2.0 * x,  -y, 0.0,        y);
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+precision mediump int;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D Original;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 tc;
+COMPAT_VARYING vec4 xyp_1_2_3;
+COMPAT_VARYING vec4 xyp_5_10_15;
+COMPAT_VARYING vec4 xyp_6_7_8;
+COMPAT_VARYING vec4 xyp_9_14_9;
+COMPAT_VARYING vec4 xyp_11_12_13;
+COMPAT_VARYING vec4 xyp_16_17_18;
+COMPAT_VARYING vec4 xyp_21_22_23;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float minimum;
+uniform COMPAT_PRECISION float maximum;
+#else
+#define minimum 0.05
+#define maximum 0.08
+#endif
+
+/*
+	Constants
+*/
+/*
+	Inequation coefficients for interpolation
+Equations are in the form: Ay + Bx = C
+45, 30, and 60 denote the angle from x each line the cooeficient variable set builds
+*/
+const vec4 Ai  = vec4( 1.0, -1.0, -1.0,  1.0);
+const vec4 B45 = vec4( 1.0,  1.0, -1.0, -1.0);
+const vec4 C45 = vec4( 1.5,  0.5, -0.5,  0.5);
+const vec4 B30 = vec4( 0.5,  2.0, -0.5, -2.0);
+const vec4 C30 = vec4( 1.0,  1.0, -0.5,  0.0);
+const vec4 B60 = vec4( 2.0,  0.5, -2.0, -0.5);
+const vec4 C60 = vec4( 2.0,  0.0, -1.0,  0.5);
+
+const vec4 M45 = vec4(0.4, 0.4, 0.4, 0.4);
+const vec4 M30 = vec4(0.2, 0.4, 0.2, 0.4);
+const vec4 M60 = M30.yxwz;
+const vec4 Mshift = vec4(0.2);
+
+// Coefficient for weighted edge detection
+const float coef = 2.0;
+// Threshold for if luminance values are "equal"
+const vec4 threshold = vec4(0.32);
+
+// Conversion from RGB to Luminance (from GIMP)
+const vec3 lum = vec3(0.21, 0.72, 0.07);
+
+// Performs same logic operation as && for vectors
+bvec4 _and_(bvec4 A, bvec4 B) {
+	return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w);
+}
+
+// Performs same logic operation as || for vectors
+bvec4 _or_(bvec4 A, bvec4 B) {
+	return bvec4(A.x || B.x, A.y || B.y, A.z || B.z, A.w || B.w);
+}
+
+// Converts 4 3-color vectors into 1 4-value luminance vector
+vec4 lum_to(vec3 v0, vec3 v1, vec3 v2, vec3 v3) {
+	return vec4(dot(lum, v0), dot(lum, v1), dot(lum, v2), dot(lum, v3));
+}
+
+// Gets the difference between 2 4-value luminance vectors
+vec4 lum_df(vec4 A, vec4 B) {
+	return abs(A - B);
+}
+
+// Determines if 2 4-value luminance vectors are "equal" based on threshold
+bvec4 lum_eq(vec4 A, vec4 B) {
+	return lessThan(lum_df(A, B), threshold);
+}
+
+vec4 lum_wd(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) {
+	return lum_df(a, b) + lum_df(a, c) + lum_df(d, e) + lum_df(d, f) + 4.0 * lum_df(g, h);
+}
+
+// Gets the difference between 2 3-value rgb colors
+float c_df(vec3 c1, vec3 c2) {
+	vec3 df = abs(c1 - c2);
+	return df.r + df.g + df.b;
+}
+
+// luma-based edge detection
+float thresh(float thr1, float thr2 , float val) {
+ val = (val < thr1) ? 0.0 : val;
+ val = (val > thr2) ? 1.0 : val;
+ return val;
+}
+
+// averaged pixel intensity from 3 color channels
+float avg_intensity(vec4 pix) {
+ return dot(pix.rgb, vec3(0.2126, 0.7152, 0.0722));
+}
+
+vec4 get_pixel(sampler2D tex, vec2 coords, float dx, float dy) {
+ return COMPAT_TEXTURE(tex, coords + vec2(dx, dy));
+}
+
+// returns pixel color
+float IsEdge(sampler2D tex, vec2 coords){
+  float dxtex = SourceSize.z;
+  float dytex = SourceSize.w;
+  int k = -1;
+  float delta;
+
+  float pix[9];
+  // read neighboring pixel intensities
+  for (int i=-1; i<2; i++) {
+   for(int j=-1; j<2; j++) {
+    k++;
+    pix[k] = avg_intensity(get_pixel(tex, coords, float(i) * dxtex,
+                                          float(j) * dytex));
+   }
+  }
+  
+  // average color differences around neighboring pixels
+  float delta_lum = (abs(pix[1]-pix[7])+
+          abs(pix[5]-pix[3]) +
+          abs(pix[0]-pix[8])+
+          abs(pix[2]-pix[6])
+           )/4.;
+/*
+// RGB edge detection << more expensive 
+vec4 rgb_pix[9];	   
+  // read neighboring pixel intensities
+  for (int i=-1; i<2; i++) {
+   for(int j=-1; j<2; j++) {
+    k++;
+    rgb_pix[k] = (get_pixel(tex, coords, float(i) * dxtex,
+                                          float(j) * dytex));
+   }
+  }
+
+  // average color differences around neighboring pixels
+  float delta_r = (abs(rgb_pix[1].r-rgb_pix[7].r)+
+          abs(rgb_pix[5].r-rgb_pix[3].r) +
+          abs(rgb_pix[0].r-rgb_pix[8].r)+
+          abs(rgb_pix[2].r-rgb_pix[6].r)
+           )/4.;
+		   
+  float delta_g = (abs(rgb_pix[1].g-rgb_pix[7].g)+
+          abs(rgb_pix[5].g-rgb_pix[3].g) +
+          abs(rgb_pix[0].g-rgb_pix[8].g)+
+          abs(rgb_pix[2].g-rgb_pix[6].g)
+           )/4.;
+		   
+  float delta_b = (abs(rgb_pix[1].b-rgb_pix[7].b)+
+          abs(rgb_pix[5].b-rgb_pix[3].b) +
+          abs(rgb_pix[0].b-rgb_pix[8].b)+
+          abs(rgb_pix[2].b-rgb_pix[6].b)
+           )/4.;
+		   
+  float delta_rgb = max(delta_r, max(delta_g, delta_b));
+*/
+
+  return thresh(minimum, maximum,clamp(delta_lum,0.0,1.0));
+}
+
+float normpdf(in float x, in float sigma)
+{
+	return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;
+}
+
+vec4 Sharp(sampler2D tex, vec2 tc, vec4 xyp_1_2_3, vec4 xyp_5_10_15, vec4 xyp_6_7_8, vec4 xyp_9_14_9, vec4 xyp_11_12_13, vec4 xyp_16_17_18, vec4 xyp_21_22_23){
+/*
+Mask for algorithm
++-----+-----+-----+-----+-----+
+|     |  1  |  2  |  3  |     |
++-----+-----+-----+-----+-----+
+|  5  |  6  |  7  |  8  |  9  |
++-----+-----+-----+-----+-----+
+| 10  | 11  | 12  | 13  | 14  |
++-----+-----+-----+-----+-----+
+| 15  | 16  | 17  | 18  | 19  |
++-----+-----+-----+-----+-----+
+|     | 21  | 22  | 23  |     |
++-----+-----+-----+-----+-----+
+	*/
+	// Get mask values by performing texture lookup with the uniform sampler
+	vec3 P1  = COMPAT_TEXTURE(Source, xyp_1_2_3.xw   ).rgb;
+	vec3 P2  = COMPAT_TEXTURE(Source, xyp_1_2_3.yw   ).rgb;
+	vec3 P3  = COMPAT_TEXTURE(Source, xyp_1_2_3.zw   ).rgb;
+	
+	vec3 P6  = COMPAT_TEXTURE(Source, xyp_6_7_8.xw   ).rgb;
+	vec3 P7  = COMPAT_TEXTURE(Source, xyp_6_7_8.yw   ).rgb;
+	vec3 P8  = COMPAT_TEXTURE(Source, xyp_6_7_8.zw   ).rgb;
+	
+	vec3 P11 = COMPAT_TEXTURE(Source, xyp_11_12_13.xw).rgb;
+	vec3 P12 = COMPAT_TEXTURE(Source, xyp_11_12_13.yw).rgb;
+	vec3 P13 = COMPAT_TEXTURE(Source, xyp_11_12_13.zw).rgb;
+	
+	vec3 P16 = COMPAT_TEXTURE(Source, xyp_16_17_18.xw).rgb;
+	vec3 P17 = COMPAT_TEXTURE(Source, xyp_16_17_18.yw).rgb;
+	vec3 P18 = COMPAT_TEXTURE(Source, xyp_16_17_18.zw).rgb;
+	
+	vec3 P21 = COMPAT_TEXTURE(Source, xyp_21_22_23.xw).rgb;
+	vec3 P22 = COMPAT_TEXTURE(Source, xyp_21_22_23.yw).rgb;
+	vec3 P23 = COMPAT_TEXTURE(Source, xyp_21_22_23.zw).rgb;
+	
+	vec3 P5  = COMPAT_TEXTURE(Source, xyp_5_10_15.xy ).rgb;
+	vec3 P10 = COMPAT_TEXTURE(Source, xyp_5_10_15.xz ).rgb;
+	vec3 P15 = COMPAT_TEXTURE(Source, xyp_5_10_15.xw ).rgb;
+	
+	vec3 P9  = COMPAT_TEXTURE(Source, xyp_9_14_9.xy  ).rgb;
+	vec3 P14 = COMPAT_TEXTURE(Source, xyp_9_14_9.xz  ).rgb;
+	vec3 P19 = COMPAT_TEXTURE(Source, xyp_9_14_9.xw  ).rgb;
+	
+	// Store luminance values of each point in groups of 4
+	// so that we may operate on all four corners at once
+	vec4 p7  = lum_to(P7,  P11, P17, P13);
+	vec4 p8  = lum_to(P8,  P6,  P16, P18);
+	vec4 p11 = p7.yzwx;                      // P11, P17, P13, P7
+	vec4 p12 = lum_to(P12, P12, P12, P12);
+	vec4 p13 = p7.wxyz;                      // P13, P7,  P11, P17
+	vec4 p14 = lum_to(P14, P2,  P10, P22);
+	vec4 p16 = p8.zwxy;                      // P16, P18, P8,  P6
+	vec4 p17 = p7.zwxy;                      // P17, P13, P7,  P11
+	vec4 p18 = p8.wxyz;                      // P18, P8,  P6,  P16
+	vec4 p19 = lum_to(P19, P3,  P5,  P21);
+	vec4 p22 = p14.wxyz;                     // P22, P14, P2,  P10
+	vec4 p23 = lum_to(P23, P9,  P1,  P15);
+	
+	// Scale current texel coordinate to [0..1]
+	vec2 fp = fract(tc * SourceSize.xy);
+	
+	// Determine amount of "smoothing" or mixing that could be done on texel corners
+	vec4 ma45 = smoothstep(C45 - M45, C45 + M45, Ai * fp.y + B45 * fp.x);
+	vec4 ma30 = smoothstep(C30 - M30, C30 + M30, Ai * fp.y + B30 * fp.x);
+	vec4 ma60 = smoothstep(C60 - M60, C60 + M60, Ai * fp.y + B60 * fp.x);
+	vec4 marn = smoothstep(C45 - M45 + Mshift, C45 + M45 + Mshift, Ai * fp.y + B45 * fp.x);
+	
+	// Perform edge weight calculations
+	vec4 e45   = lum_wd(p12, p8, p16, p18, p22, p14, p17, p13);
+	vec4 econt = lum_wd(p17, p11, p23, p13, p7, p19, p12, p18);
+	vec4 e30   = lum_df(p13, p16);
+	vec4 e60   = lum_df(p8, p17);
+	
+	// Calculate rule results for interpolation
+	bvec4 r45_1   = _and_(notEqual(p12, p13), notEqual(p12, p17));
+	bvec4 r45_2   = _and_(not(lum_eq(p13, p7)), not(lum_eq(p13, p8)));
+	bvec4 r45_3   = _and_(not(lum_eq(p17, p11)), not(lum_eq(p17, p16)));
+	bvec4 r45_4_1 = _and_(not(lum_eq(p13, p14)), not(lum_eq(p13, p19)));
+	bvec4 r45_4_2 = _and_(not(lum_eq(p17, p22)), not(lum_eq(p17, p23)));
+	bvec4 r45_4   = _and_(lum_eq(p12, p18), _or_(r45_4_1, r45_4_2));
+	bvec4 r45_5   = _or_(lum_eq(p12, p16), lum_eq(p12, p8));
+	bvec4 r45     = _and_(r45_1, _or_(_or_(_or_(r45_2, r45_3), r45_4), r45_5));
+	bvec4 r30 = _and_(notEqual(p12, p16), notEqual(p11, p16));
+	bvec4 r60 = _and_(notEqual(p12, p8), notEqual(p7, p8));
+	
+	// Combine rules with edge weights
+	bvec4 edr45 = _and_(lessThan(e45, econt), r45);
+	bvec4 edrrn = lessThanEqual(e45, econt);
+	bvec4 edr30 = _and_(lessThanEqual(coef * e30, e60), r30);
+	bvec4 edr60 = _and_(lessThanEqual(coef * e60, e30), r60);
+	
+	// Finalize interpolation rules and cast to float (0.0 for false, 1.0 for true)
+	vec4 final45 = vec4(_and_(_and_(not(edr30), not(edr60)), edr45));
+	vec4 final30 = vec4(_and_(_and_(edr45, not(edr60)), edr30));
+	vec4 final60 = vec4(_and_(_and_(edr45, not(edr30)), edr60));
+	vec4 final36 = vec4(_and_(_and_(edr60, edr30), edr45));
+	vec4 finalrn = vec4(_and_(not(edr45), edrrn));
+	
+	// Determine the color to mix with for each corner
+	vec4 px = step(lum_df(p12, p17), lum_df(p12, p13));
+	
+	// Determine the mix amounts by combining the final rule result and corresponding
+	// mix amount for the rule in each corner
+	vec4 mac = final36 * max(ma30, ma60) + final30 * ma30 + final60 * ma60 + final45 * ma45 + finalrn * marn;
+	
+/*
+Calculate the resulting color by traversing clockwise and counter-clockwise around
+the corners of the texel
+
+Finally choose the result that has the largest difference from the texel's original
+color
+*/
+	vec3 res1 = P12;
+	res1 = mix(res1, mix(P13, P17, px.x), mac.x);
+	res1 = mix(res1, mix(P7, P13, px.y), mac.y);
+	res1 = mix(res1, mix(P11, P7, px.z), mac.z);
+	res1 = mix(res1, mix(P17, P11, px.w), mac.w);
+	
+	vec3 res2 = P12;
+	res2 = mix(res2, mix(P17, P11, px.w), mac.w);
+	res2 = mix(res2, mix(P11, P7, px.z), mac.z);
+	res2 = mix(res2, mix(P7, P13, px.y), mac.y);
+	res2 = mix(res2, mix(P13, P17, px.x), mac.x);
+	
+	return vec4(mix(res1, res2, step(c_df(P12, res1), c_df(P12, res2))), 1.0);
+}
+
+vec4 Smooth(sampler2D tex, vec2 tc){
+// single-pass gaussian blur from mrharicot https://www.shadertoy.com/view/XdfGDH
+		//declare stuff
+		const int mSize = 5;
+		int kSize = (mSize-1)/2;
+		float kernel[mSize];
+		vec3 final_colour = vec3(0.0);
+		
+		//create the 1-D kernel
+		float sigma = 5.0;
+		float Z = 0.0;
+		for (int j = 0; j <= kSize; ++j)
+		{
+			kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma);
+		}
+		
+		//get the normalization factor (as the gaussian has been clamped)
+		for (int j = 0; j < mSize; ++j)
+		{
+			Z += kernel[j];
+		}
+		
+		//read out the texels
+		for (int i=-kSize; i <= kSize; ++i)
+		{
+			for (int j=-kSize; j <= kSize; ++j)
+			{
+				final_colour += kernel[kSize+j]*kernel[kSize+i]*COMPAT_TEXTURE(Source, ((tc.xy * OutputSize.xy).xy+vec2(float(i),float(j))) / OutputSize.xy).rgb;
+			}
+		}
+				
+		return vec4(final_colour/(Z*Z), 1.0);
+}
+
+void main()
+{
+	float test = IsEdge(Source, tc);
+	vec4 hybrid = vec4(0.0);
+	hybrid = (test < 0.5) ? Smooth(Source, tc) : Sharp(Source, tc, xyp_1_2_3, xyp_5_10_15, xyp_6_7_8, xyp_9_14_9, xyp_11_12_13, xyp_16_17_18, xyp_21_22_23);
+//	vec4 hybrid = mix(Smooth, Sharp, test);
+   FragColor = hybrid;
+} 
+#endif
diff --git a/base/sabr/shaders/sabr-v3.0.glsl b/base/sabr/shaders/sabr-v3.0.glsl
new file mode 100644
index 0000000..632376f
--- /dev/null
+++ b/base/sabr/shaders/sabr-v3.0.glsl
@@ -0,0 +1,324 @@
+/*
+	SABR v3.0 Shader
+	Joshua Street
+	
+	Portions of this algorithm were taken from Hyllian's 5xBR v3.7c
+	shader.
+	
+	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.
+
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+COMPAT_VARYING vec2 tc;
+COMPAT_VARYING vec4 xyp_1_2_3;
+COMPAT_VARYING vec4 xyp_5_10_15;
+COMPAT_VARYING vec4 xyp_6_7_8;
+COMPAT_VARYING vec4 xyp_9_14_9;
+COMPAT_VARYING vec4 xyp_11_12_13;
+COMPAT_VARYING vec4 xyp_16_17_18;
+COMPAT_VARYING vec4 xyp_21_22_23;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+   	float x = SourceSize.z;//1.0 / IN.texture_size.x;
+	float y = SourceSize.w;//1.0 / IN.texture_size.y;
+	
+	tc = TEX0.xy * vec2(1.0004, 1.0);
+	xyp_1_2_3    = tc.xxxy + vec4(      -x, 0.0,   x, -2.0 * y);
+	xyp_6_7_8    = tc.xxxy + vec4(      -x, 0.0,   x,       -y);
+	xyp_11_12_13 = tc.xxxy + vec4(      -x, 0.0,   x,      0.0);
+	xyp_16_17_18 = tc.xxxy + vec4(      -x, 0.0,   x,        y);
+	xyp_21_22_23 = tc.xxxy + vec4(      -x, 0.0,   x,  2.0 * y);
+	xyp_5_10_15  = tc.xyyy + vec4(-2.0 * x,  -y, 0.0,        y);
+	xyp_9_14_9   = tc.xyyy + vec4( 2.0 * x,  -y, 0.0,        y);
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 tc;
+COMPAT_VARYING vec4 xyp_1_2_3;
+COMPAT_VARYING vec4 xyp_5_10_15;
+COMPAT_VARYING vec4 xyp_6_7_8;
+COMPAT_VARYING vec4 xyp_9_14_9;
+COMPAT_VARYING vec4 xyp_11_12_13;
+COMPAT_VARYING vec4 xyp_16_17_18;
+COMPAT_VARYING vec4 xyp_21_22_23;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+/*
+	Constants
+*/
+/*
+	Inequation coefficients for interpolation
+Equations are in the form: Ay + Bx = C
+45, 30, and 60 denote the angle from x each line the cooeficient variable set builds
+*/
+const vec4 Ai  = vec4( 1.0, -1.0, -1.0,  1.0);
+const vec4 B45 = vec4( 1.0,  1.0, -1.0, -1.0);
+const vec4 C45 = vec4( 1.5,  0.5, -0.5,  0.5);
+const vec4 B30 = vec4( 0.5,  2.0, -0.5, -2.0);
+const vec4 C30 = vec4( 1.0,  1.0, -0.5,  0.0);
+const vec4 B60 = vec4( 2.0,  0.5, -2.0, -0.5);
+const vec4 C60 = vec4( 2.0,  0.0, -1.0,  0.5);
+
+const vec4 M45 = vec4(0.4, 0.4, 0.4, 0.4);
+const vec4 M30 = vec4(0.2, 0.4, 0.2, 0.4);
+const vec4 M60 = M30.yxwz;
+const vec4 Mshift = vec4(0.2);
+
+// Coefficient for weighted edge detection
+const float coef = 2.0;
+// Threshold for if luminance values are "equal"
+const vec4 threshold = vec4(0.32);
+
+// Conversion from RGB to Luminance (from GIMP)
+const vec3 lum = vec3(0.21, 0.72, 0.07);
+
+// Performs same logic operation as && for vectors
+bvec4 _and_(bvec4 A, bvec4 B) {
+	return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w);
+}
+
+// Performs same logic operation as || for vectors
+bvec4 _or_(bvec4 A, bvec4 B) {
+	return bvec4(A.x || B.x, A.y || B.y, A.z || B.z, A.w || B.w);
+}
+
+// Converts 4 3-color vectors into 1 4-value luminance vector
+vec4 lum_to(vec3 v0, vec3 v1, vec3 v2, vec3 v3) {
+	return vec4(dot(lum, v0), dot(lum, v1), dot(lum, v2), dot(lum, v3));
+}
+
+// Gets the difference between 2 4-value luminance vectors
+vec4 lum_df(vec4 A, vec4 B) {
+	return abs(A - B);
+}
+
+// Determines if 2 4-value luminance vectors are "equal" based on threshold
+bvec4 lum_eq(vec4 A, vec4 B) {
+	return lessThan(lum_df(A, B), threshold);
+}
+
+vec4 lum_wd(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) {
+	return lum_df(a, b) + lum_df(a, c) + lum_df(d, e) + lum_df(d, f) + 4.0 * lum_df(g, h);
+}
+
+// Gets the difference between 2 3-value rgb colors
+float c_df(vec3 c1, vec3 c2) {
+	vec3 df = abs(c1 - c2);
+	return df.r + df.g + df.b;
+}
+
+void main()
+{
+/*
+Mask for algorithm
++-----+-----+-----+-----+-----+
+|     |  1  |  2  |  3  |     |
++-----+-----+-----+-----+-----+
+|  5  |  6  |  7  |  8  |  9  |
++-----+-----+-----+-----+-----+
+| 10  | 11  | 12  | 13  | 14  |
++-----+-----+-----+-----+-----+
+| 15  | 16  | 17  | 18  | 19  |
++-----+-----+-----+-----+-----+
+|     | 21  | 22  | 23  |     |
++-----+-----+-----+-----+-----+
+	*/
+	// Get mask values by performing texture lookup with the uniform sampler
+	vec3 P1  = COMPAT_TEXTURE(Source, xyp_1_2_3.xw   ).rgb;
+	vec3 P2  = COMPAT_TEXTURE(Source, xyp_1_2_3.yw   ).rgb;
+	vec3 P3  = COMPAT_TEXTURE(Source, xyp_1_2_3.zw   ).rgb;
+	
+	vec3 P6  = COMPAT_TEXTURE(Source, xyp_6_7_8.xw   ).rgb;
+	vec3 P7  = COMPAT_TEXTURE(Source, xyp_6_7_8.yw   ).rgb;
+	vec3 P8  = COMPAT_TEXTURE(Source, xyp_6_7_8.zw   ).rgb;
+	
+	vec3 P11 = COMPAT_TEXTURE(Source, xyp_11_12_13.xw).rgb;
+	vec3 P12 = COMPAT_TEXTURE(Source, xyp_11_12_13.yw).rgb;
+	vec3 P13 = COMPAT_TEXTURE(Source, xyp_11_12_13.zw).rgb;
+	
+	vec3 P16 = COMPAT_TEXTURE(Source, xyp_16_17_18.xw).rgb;
+	vec3 P17 = COMPAT_TEXTURE(Source, xyp_16_17_18.yw).rgb;
+	vec3 P18 = COMPAT_TEXTURE(Source, xyp_16_17_18.zw).rgb;
+	
+	vec3 P21 = COMPAT_TEXTURE(Source, xyp_21_22_23.xw).rgb;
+	vec3 P22 = COMPAT_TEXTURE(Source, xyp_21_22_23.yw).rgb;
+	vec3 P23 = COMPAT_TEXTURE(Source, xyp_21_22_23.zw).rgb;
+	
+	vec3 P5  = COMPAT_TEXTURE(Source, xyp_5_10_15.xy ).rgb;
+	vec3 P10 = COMPAT_TEXTURE(Source, xyp_5_10_15.xz ).rgb;
+	vec3 P15 = COMPAT_TEXTURE(Source, xyp_5_10_15.xw ).rgb;
+	
+	vec3 P9  = COMPAT_TEXTURE(Source, xyp_9_14_9.xy  ).rgb;
+	vec3 P14 = COMPAT_TEXTURE(Source, xyp_9_14_9.xz  ).rgb;
+	vec3 P19 = COMPAT_TEXTURE(Source, xyp_9_14_9.xw  ).rgb;
+	
+	// Store luminance values of each point in groups of 4
+	// so that we may operate on all four corners at once
+	vec4 p7  = lum_to(P7,  P11, P17, P13);
+	vec4 p8  = lum_to(P8,  P6,  P16, P18);
+	vec4 p11 = p7.yzwx;                      // P11, P17, P13, P7
+	vec4 p12 = lum_to(P12, P12, P12, P12);
+	vec4 p13 = p7.wxyz;                      // P13, P7,  P11, P17
+	vec4 p14 = lum_to(P14, P2,  P10, P22);
+	vec4 p16 = p8.zwxy;                      // P16, P18, P8,  P6
+	vec4 p17 = p7.zwxy;                      // P17, P13, P7,  P11
+	vec4 p18 = p8.wxyz;                      // P18, P8,  P6,  P16
+	vec4 p19 = lum_to(P19, P3,  P5,  P21);
+	vec4 p22 = p14.wxyz;                     // P22, P14, P2,  P10
+	vec4 p23 = lum_to(P23, P9,  P1,  P15);
+	
+	// Scale current texel coordinate to [0..1]
+	vec2 fp = fract(tc * SourceSize.xy);
+	
+	// Determine amount of "smoothing" or mixing that could be done on texel corners
+	vec4 ma45 = smoothstep(C45 - M45, C45 + M45, Ai * fp.y + B45 * fp.x);
+	vec4 ma30 = smoothstep(C30 - M30, C30 + M30, Ai * fp.y + B30 * fp.x);
+	vec4 ma60 = smoothstep(C60 - M60, C60 + M60, Ai * fp.y + B60 * fp.x);
+	vec4 marn = smoothstep(C45 - M45 + Mshift, C45 + M45 + Mshift, Ai * fp.y + B45 * fp.x);
+	
+	// Perform edge weight calculations
+	vec4 e45   = lum_wd(p12, p8, p16, p18, p22, p14, p17, p13);
+	vec4 econt = lum_wd(p17, p11, p23, p13, p7, p19, p12, p18);
+	vec4 e30   = lum_df(p13, p16);
+	vec4 e60   = lum_df(p8, p17);
+	
+	// Calculate rule results for interpolation
+	bvec4 r45_1   = _and_(notEqual(p12, p13), notEqual(p12, p17));
+	bvec4 r45_2   = _and_(not(lum_eq(p13, p7)), not(lum_eq(p13, p8)));
+	bvec4 r45_3   = _and_(not(lum_eq(p17, p11)), not(lum_eq(p17, p16)));
+	bvec4 r45_4_1 = _and_(not(lum_eq(p13, p14)), not(lum_eq(p13, p19)));
+	bvec4 r45_4_2 = _and_(not(lum_eq(p17, p22)), not(lum_eq(p17, p23)));
+	bvec4 r45_4   = _and_(lum_eq(p12, p18), _or_(r45_4_1, r45_4_2));
+	bvec4 r45_5   = _or_(lum_eq(p12, p16), lum_eq(p12, p8));
+	bvec4 r45     = _and_(r45_1, _or_(_or_(_or_(r45_2, r45_3), r45_4), r45_5));
+	bvec4 r30 = _and_(notEqual(p12, p16), notEqual(p11, p16));
+	bvec4 r60 = _and_(notEqual(p12, p8), notEqual(p7, p8));
+	
+	// Combine rules with edge weights
+	bvec4 edr45 = _and_(lessThan(e45, econt), r45);
+	bvec4 edrrn = lessThanEqual(e45, econt);
+	bvec4 edr30 = _and_(lessThanEqual(coef * e30, e60), r30);
+	bvec4 edr60 = _and_(lessThanEqual(coef * e60, e30), r60);
+	
+	// Finalize interpolation rules and cast to float (0.0 for false, 1.0 for true)
+	vec4 final45 = vec4(_and_(_and_(not(edr30), not(edr60)), edr45));
+	vec4 final30 = vec4(_and_(_and_(edr45, not(edr60)), edr30));
+	vec4 final60 = vec4(_and_(_and_(edr45, not(edr30)), edr60));
+	vec4 final36 = vec4(_and_(_and_(edr60, edr30), edr45));
+	vec4 finalrn = vec4(_and_(not(edr45), edrrn));
+	
+	// Determine the color to mix with for each corner
+	vec4 px = step(lum_df(p12, p17), lum_df(p12, p13));
+	
+	// Determine the mix amounts by combining the final rule result and corresponding
+	// mix amount for the rule in each corner
+	vec4 mac = final36 * max(ma30, ma60) + final30 * ma30 + final60 * ma60 + final45 * ma45 + finalrn * marn;
+	
+/*
+Calculate the resulting color by traversing clockwise and counter-clockwise around
+the corners of the texel
+
+Finally choose the result that has the largest difference from the texel's original
+color
+*/
+	vec3 res1 = P12;
+	res1 = mix(res1, mix(P13, P17, px.x), mac.x);
+	res1 = mix(res1, mix(P7, P13, px.y), mac.y);
+	res1 = mix(res1, mix(P11, P7, px.z), mac.z);
+	res1 = mix(res1, mix(P17, P11, px.w), mac.w);
+	
+	vec3 res2 = P12;
+	res2 = mix(res2, mix(P17, P11, px.w), mac.w);
+	res2 = mix(res2, mix(P11, P7, px.z), mac.z);
+	res2 = mix(res2, mix(P7, P13, px.y), mac.y);
+	res2 = mix(res2, mix(P13, P17, px.x), mac.x);
+	
+	FragColor = vec4(mix(res1, res2, step(c_df(P12, res1), c_df(P12, res2))), 1.0);
+} 
+#endif
diff --git a/base/scalefx/scalefx+rAA.glslp b/base/scalefx/scalefx+rAA.glslp
new file mode 100644
index 0000000..e48ee05
--- /dev/null
+++ b/base/scalefx/scalefx+rAA.glslp
@@ -0,0 +1,41 @@
+shaders = 8
+
+shader0 = shaders/scalefx-pass0.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+float_framebuffer0 = true
+
+shader1 = shaders/scalefx-pass1.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+float_framebuffer1 = true
+
+shader2 = shaders/scalefx-pass2.glsl
+filter_linear2 = false
+scale_type2 = source
+scale2 = 1.0
+
+shader3 = shaders/scalefx-pass3.glsl
+filter_linear3 = false
+scale_type3 = source
+scale3 = 1.0
+
+shader4 = shaders/scalefx-pass4.glsl
+filter_linear4 = false
+scale_type4 = source
+scale4 = 3.0
+
+shader5 = ../anti-aliasing/shaders/reverse-aa-post3x/reverse-aa-post3x-pass0.glsl
+filter_linear5 = false
+scale_type5 = source
+scale5 = 1.0
+
+shader6 = ../anti-aliasing/shaders/reverse-aa-post3x/reverse-aa-post3x-pass1.glsl
+filter_linear6 = false
+scale_type6 = source
+scale6 = 1.0
+
+shader7 = ../stock.glsl
+filter_linear7 = true
diff --git a/base/scalefx/scalefx-hybrid.glslp b/base/scalefx/scalefx-hybrid.glslp
new file mode 100644
index 0000000..c043858
--- /dev/null
+++ b/base/scalefx/scalefx-hybrid.glslp
@@ -0,0 +1,31 @@
+shaders = 5
+
+shader0 = shaders/scalefx-pass0.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+float_framebuffer0 = true
+
+shader1 = shaders/scalefx-pass1.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+float_framebuffer1 = true
+
+shader2 = shaders/scalefx-pass2.glsl
+filter_linear2 = false
+scale_type2 = source
+scale2 = 1.0
+
+shader3 = shaders/scalefx-pass3.glsl
+filter_linear3 = false
+scale_type3 = source
+scale3 = 1.0
+
+shader4 = shaders/scalefx-pass4-hybrid.glsl
+filter_linear4 = false
+scale_type4 = source
+scale4 = 3.0
+
+parameters = "SFX_SAA"
+SFX_SAA = "0.0"
diff --git a/base/scalefx/scalefx.glslp b/base/scalefx/scalefx.glslp
new file mode 100644
index 0000000..5706248
--- /dev/null
+++ b/base/scalefx/scalefx.glslp
@@ -0,0 +1,28 @@
+shaders = 5
+
+shader0 = shaders/scalefx-pass0.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+float_framebuffer0 = true
+
+shader1 = shaders/scalefx-pass1.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+float_framebuffer1 = true
+
+shader2 = shaders/scalefx-pass2.glsl
+filter_linear2 = false
+scale_type2 = source
+scale2 = 1.0
+
+shader3 = shaders/scalefx-pass3.glsl
+filter_linear3 = false
+scale_type3 = source
+scale3 = 1.0
+
+shader4 = shaders/scalefx-pass4.glsl
+filter_linear4 = false
+scale_type4 = source
+scale4 = 3.0
diff --git a/base/scalefx/shaders/scalefx-pass0.glsl b/base/scalefx/shaders/scalefx-pass0.glsl
new file mode 100644
index 0000000..bb97efc
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass0.glsl
@@ -0,0 +1,170 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	float dx = SourceSize.z, dy = SourceSize.w;
+
+	t1 = TEX0.xxxy + vec4(-dx, 0., dx, -dy);	// A, B, C
+	t2 = TEX0.xxxy + vec4(-dx, 0., dx,   0.);	// D, E, F
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+// 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
+	*/
+
+#ifdef GL_ES
+#define TEX(x) COMPAT_TEXTURE(Source, x)
+// read texels
+	vec3 A = TEX(t1.xw).rgb;
+	vec3 B = TEX(t1.yw).rgb;
+	vec3 C = TEX(t1.zw).rgb;
+	vec3 E = TEX(t2.yw).rgb;
+	vec3 F = TEX(t2.zw).rgb;
+#else
+#define TEX(x, y) textureOffset(Source, 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);
+#endif
+	// output
+	FragColor = vec4(dist(E,A), dist(E,B), dist(E,C), dist(E,F));
+} 
+#endif
diff --git a/base/scalefx/shaders/scalefx-pass1.glsl b/base/scalefx/shaders/scalefx-pass1.glsl
new file mode 100644
index 0000000..07423ad
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass1.glsl
@@ -0,0 +1,189 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter SFX_CLR "ScaleFX Threshold" 0.50 0.01 1.00 0.01
+#pragma parameter SFX_SAA "ScaleFX Filter AA" 1.00 0.00 1.00 1.00
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+	gl_Position = MVPMatrix * VertexCoord;
+	COL0 = COLOR;
+	TEX0.xy = TexCoord.xy;
+	float dx = SourceSize.z, dy = SourceSize.w;
+    
+	t1 = TEX0.xxxy + vec4(  -dx,   0., dx,  -dy);	// A, B, C
+	t2 = TEX0.xxxy + vec4(  -dx,   0., dx,    0.);	// D, E, F
+	t3 = TEX0.xxxy + vec4(  -dx,   0., dx,   dy);	// G, H, I
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float SFX_CLR;
+uniform COMPAT_PRECISION float SFX_SAA;
+#else
+#define SFX_CLR 0.5
+#define SFX_SAA 1.0
+#endif
+
+// 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
+	*/
+
+#ifdef GL_ES
+#define TEX(x) COMPAT_TEXTURE(Source, x)
+
+	// metric data
+	vec4 A = TEX(t1.xw), B = TEX(t1.yw);
+	vec4 D = TEX(t2.xw), E = TEX(t2.yw), F = TEX(t2.zw);
+	vec4 G = TEX(t3.xw), H = TEX(t3.yw), I = TEX(t3.zw);
+#else
+#define TEX(x, y) textureOffset(Source, 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);
+#endif
+
+	// 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;
+} 
+#endif
diff --git a/base/scalefx/shaders/scalefx-pass2.glsl b/base/scalefx/shaders/scalefx-pass2.glsl
new file mode 100644
index 0000000..5050a7d
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass2.glsl
@@ -0,0 +1,235 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	float dx = SourceSize.z, dy = SourceSize.w;
+	
+	t1 = TEX0.xxxy + vec4(  -dx,   0., dx,  -dy);	// A, B, C
+	t2 = TEX0.xxxy + vec4(  -dx,   0., dx,    0.);	// D, E, F
+	t3 = TEX0.xxxy + vec4(  -dx,   0., dx,   dy);	// G, H, I
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D PassPrev2Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#define PassOutput0 PassPrev2Texture
+
+#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
+	*/
+
+#ifdef GL_ES
+	#define TEXm(x) COMPAT_TEXTURE(PassOutput0, x)
+	#define TEXs(x) COMPAT_TEXTURE(Source, x)
+
+	// metric data
+	vec4 A = TEXm(t1.xw), B = TEXm(t1.yw);
+	vec4 D = TEXm(t2.xw), E = TEXm(t2.yw), F = TEXm(t2.zw);
+	vec4 G = TEXm(t3.xw), H = TEXm(t3.yw), I = TEXm(t3.zw);
+	
+	// strength data
+	vec4 As = TEXs(t1.xw), Bs = TEXs(t1.yw), Cs = TEXs(t1.zw);
+	vec4 Ds = TEXs(t2.xw), Es = TEXs(t2.yw), Fs = TEXs(t2.zw);
+	vec4 Gs = TEXs(t3.xw), Hs = TEXs(t3.yw), Is = TEXs(t3.zw);
+#else
+	#define TEXm(x, y) textureOffset(PassOutput0, vTexCoord, ivec2(x, y))
+	#define TEXs(x, y) textureOffset(Source, 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);
+#endif
+
+	// 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.;
+} 
+#endif
diff --git a/base/scalefx/shaders/scalefx-pass3.glsl b/base/scalefx/shaders/scalefx-pass3.glsl
new file mode 100644
index 0000000..a79daf5
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass3.glsl
@@ -0,0 +1,258 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter SFX_SCN "ScaleFX Filter Corners" 1.0 0.0 1.0 1.0
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	float dx = SourceSize.z, dy = SourceSize.w;
+    
+    t1 = TEX0.xxxy + vec4(-dx, -2.*dx, -3.*dx,     0.);	// D, D0, D1
+	t2 = TEX0.xxxy + vec4( dx,  2.*dx,  3.*dx,     0.);	// F, F0, F1
+	t3 = TEX0.xyyy + vec4(  0.,   -dy, -2.*dy, -3.*dy);	// B, B0, B1
+	t4 = TEX0.xyyy + vec4(  0.,    dy,  2.*dy,  3.*dy);	// H, H0, H1
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float SFX_SCN;
+#else
+#define SFX_SCN 1.0
+#endif
+
+// 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
+	*/
+#ifdef GL_ES
+#define TEX(x) COMPAT_TEXTURE(Source, x)
+
+	// read data
+	vec4 E = TEX(vTexCoord);
+	vec4 D = TEX(t1.xw), D0 = TEX(t1.yw), D1 = TEX(t1.zw);
+	vec4 F = TEX(t2.xw), F0 = TEX(t2.yw), F1 = TEX(t2.zw);
+	vec4 B = TEX(t3.xy), B0 = TEX(t3.xz), B1 = TEX(t3.xw);
+	vec4 H = TEX(t4.xy), H0 = TEX(t4.xz), H1 = TEX(t4.xw);
+#else
+#define TEX(x, y) textureOffset(Source, 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);
+#endif
+	// 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.;
+} 
+#endif
diff --git a/base/scalefx/shaders/scalefx-pass4-hybrid.glsl b/base/scalefx/shaders/scalefx-pass4-hybrid.glsl
new file mode 100644
index 0000000..c875f27
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass4-hybrid.glsl
@@ -0,0 +1,215 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter SFX_RAA "ScaleFX rAA Sharpness" 2.0 0.0 10.0 0.05
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D PassPrev5Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+#define Original PassPrev5Texture
+
+#ifdef PARAMETER_UNIFORM
+// All parameter floats need to have COMPAT_PRECISION in front of them
+uniform COMPAT_PRECISION float SFX_RAA;
+#else
+#define SFX_RAA 2.0
+#endif
+
+// 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.));
+}
+
+vec3 res2x(vec3 pre2, vec3 pre1, vec3 px, vec3 pos1, vec3 pos2)
+{
+	vec3 t, m;
+	mat4x3 pre = mat4x3(pre2, pre1,   px, pos1);
+	mat4x3 pos = mat4x3(pre1,   px, pos1, pos2);
+	mat4x3  df = pos - pre;
+	
+	m = mix(px, 1.-px, step(px, vec3(0.5)));	
+	m = SFX_RAA * min(m, min(abs(df[1]), abs(df[2])));
+	t = (7. * (df[1] + df[2]) - 3. * (df[0] + df[3])) / 16.;
+	t = clamp(t, -m, m);
+   
+	return t;
+}
+
+void main()
+{
+	/*	grid		corners		mids
+
+		  B		x   y	  	  x
+		D E F				w   y
+		  H		w   z	  	  z
+	*/
+
+
+	// read data
+	vec4 E = COMPAT_TEXTURE(Source, vTexCoord);
+
+	// determine subpixel
+	vec2 fc = fract(vTexCoord * SourceSize.xy);
+	vec2 fp = floor(3.0 * fc);
+	
+	// check adjacent pixels to prevent artifacts
+	vec4 hn = COMPAT_TEXTURE(Source, vTexCoord + vec2(fp.x - 1., 0.) / SourceSize.xy);
+	vec4 vn = COMPAT_TEXTURE(Source, vTexCoord + vec2(0., fp.y - 1.) / SourceSize.xy);
+
+	// extract data
+	vec4 crn = loadCrn(E), hc = loadCrn(hn), vc = loadCrn(vn);
+	vec4 mid = loadMid(E), hm = loadMid(hn), vm = loadMid(vn);
+
+	vec3 res = fp.y == 0. ? (fp.x == 0. ? vec3(crn.x, hc.y, vc.w) : fp.x == 1. ? vec3(mid.x, 0., vm.z) : vec3(crn.y, hc.x, vc.z)) : (fp.y == 1. ? (fp.x == 0. ? vec3(mid.w, hm.y, 0.) : fp.x == 1. ? vec3(0.) : vec3(mid.y, hm.w, 0.)) : (fp.x == 0. ? vec3(crn.w, hc.z, vc.x) : fp.x == 1. ? vec3(mid.z, 0., vm.x) : vec3(crn.z, hc.w, vc.y)));	
+	
+
+#define TEX(x, y) textureOffset(Original, vTexCoord, ivec2(x, y)).rgb
+
+	// reverseAA
+	vec3 E0 = TEX( 0, 0);
+	vec3 B0 = TEX( 0,-1), B1 = TEX( 0,-2), H0 = TEX( 0, 1), H1 = TEX( 0, 2);
+	vec3 D0 = TEX(-1, 0), D1 = TEX(-2, 0), F0 = TEX( 1, 0), F1 = TEX( 2, 0);
+
+	// output coordinate - 0 = E0, 1 = D0, 2 = D1, 3 = F0, 4 = F1, 5 = B0, 6 = B1, 7 = H0, 8 = H1
+	vec3 sfx = res.x == 1. ? D0 : res.x == 2. ? D1 : res.x == 3. ? F0 : res.x == 4. ? F1 : res.x == 5. ? B0 : res.x == 6. ? B1 : res.x == 7. ? H0 : H1;
+
+	// rAA weight
+	vec2 w = 2. * fc - 1.;
+	w.x = res.y == 0. ? w.x : 0.;
+	w.y = res.z == 0. ? w.y : 0.;
+
+	// rAA filter
+	vec3 t1 = res2x(D1, D0, E0, F0, F1);
+	vec3 t2 = res2x(B1, B0, E0, H0, H1);
+
+	vec3 a = min(min(min(min(B0,D0),E0),F0),H0);
+	vec3 b = max(max(max(max(B0,D0),E0),F0),H0);
+	vec3 raa = clamp(E0 + w.x*t1 + w.y*t2, a, b);
+
+	// hybrid output
+	FragColor = vec4((res.x != 0.) ? sfx : raa, 0.);	
+} 
+#endif
diff --git a/base/scalefx/shaders/scalefx-pass4.glsl b/base/scalefx/shaders/scalefx-pass4.glsl
new file mode 100644
index 0000000..564bcbb
--- /dev/null
+++ b/base/scalefx/shaders/scalefx-pass4.glsl
@@ -0,0 +1,179 @@
+#version 130
+
+/*
+	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 at 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.
+
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform COMPAT_PRECISION vec2 PassPrev5TextureSize;
+uniform COMPAT_PRECISION vec2 PassPrev5InputSize;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	
+	vec2 ps = 1.0/PassPrev5TextureSize;
+	float dx = ps.x, dy = ps.y;
+
+	t1 = TEX0.xxxy + vec4( 0., -dx, -2.*dx,     0.);	// E, D, D0
+	t2 = TEX0.xyxy + vec4(dx,   0,  2.*dx,     0.);	// F, F0
+	t3 = TEX0.xyxy + vec4( 0., -dy,     0., -2.*dy);	// B, B0
+	t4 = TEX0.xyxy + vec4( 0.,  dy,     0.,  2.*dy);	// H, H0
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D PassPrev5Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+// 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 = COMPAT_TEXTURE(Source, vTexCoord);
+
+	// extract data
+	vec4 crn = loadCrn(E);
+	vec4 mid = loadMid(E);
+
+	// determine subpixel
+	vec2 fp = floor(3.0 * fract(vTexCoord * SourceSize.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 = COMPAT_TEXTURE(PassPrev5Texture, vTexCoord + res / SourceSize.xy);
+} 
+#endif
diff --git a/base/scalehq/2xScaleHQ.glslp b/base/scalehq/2xScaleHQ.glslp
new file mode 100644
index 0000000..2018b13
--- /dev/null
+++ b/base/scalehq/2xScaleHQ.glslp
@@ -0,0 +1,6 @@
+shaders = 1
+
+shader0 = "shaders/2xScaleHQ.glsl"
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
diff --git a/base/scalehq/4xScaleHQ.glslp b/base/scalehq/4xScaleHQ.glslp
new file mode 100644
index 0000000..f3d739d
--- /dev/null
+++ b/base/scalehq/4xScaleHQ.glslp
@@ -0,0 +1,6 @@
+shaders = 1
+
+shader0 = "shaders/4xScaleHQ.glsl"
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
diff --git a/base/scalehq/shaders/2xScaleHQ.glsl b/base/scalehq/shaders/2xScaleHQ.glsl
new file mode 100644
index 0000000..ba1ac5d
--- /dev/null
+++ b/base/scalehq/shaders/2xScaleHQ.glsl
@@ -0,0 +1,162 @@
+/*
+   2xGLSLHqFilter shader
+   
+   Copyright (C) 2005 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy;
+   float x = 0.5 * SourceSize.z;
+   float y = 0.5 * SourceSize.w;
+   vec2 dg1 = vec2( x, y);
+   vec2 dg2 = vec2(-x, y);
+   vec2 dx = vec2(x, 0.0);
+   vec2 dy = vec2(0.0, y);
+   t1 = vec4(vTexCoord - dg1, vTexCoord - dy);
+   t2 = vec4(vTexCoord - dg2, vTexCoord + dx);
+   t3 = vec4(vTexCoord + dg1, vTexCoord + dy);
+   t4 = vec4(vTexCoord + dg2, vTexCoord - dx);
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+float mx = 0.325;      // start smoothing wt.
+float k = -0.250;      // wt. decrease factor
+float max_w = 0.25;    // max filter weight
+float min_w =-0.05;    // min filter weight
+float lum_add = 0.25;  // affects smoothing
+vec3 dt = vec3(1.0);
+
+void main()
+{
+   vec3 c00 = COMPAT_TEXTURE(Source, t1.xy).xyz; 
+   vec3 c10 = COMPAT_TEXTURE(Source, t1.zw).xyz; 
+   vec3 c20 = COMPAT_TEXTURE(Source, t2.xy).xyz; 
+   vec3 c01 = COMPAT_TEXTURE(Source, t4.zw).xyz; 
+   vec3 c11 = COMPAT_TEXTURE(Source, vTexCoord).xyz; 
+   vec3 c21 = COMPAT_TEXTURE(Source, t2.zw).xyz; 
+   vec3 c02 = COMPAT_TEXTURE(Source, t4.xy).xyz; 
+   vec3 c12 = COMPAT_TEXTURE(Source, t3.zw).xyz; 
+   vec3 c22 = COMPAT_TEXTURE(Source, t3.xy).xyz; 
+
+   float md1 = dot(abs(c00 - c22), dt);
+   float md2 = dot(abs(c02 - c20), dt);
+
+   float w1 = dot(abs(c22 - c11), dt) * md2;
+   float w2 = dot(abs(c02 - c11), dt) * md1;
+   float w3 = dot(abs(c00 - c11), dt) * md2;
+   float w4 = dot(abs(c20 - c11), dt) * md1;
+
+   float t1 = w1 + w3;
+   float t2 = w2 + w4;
+   float ww = max(t1, t2) + 0.0001;
+
+   c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);
+
+   float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);
+   float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);
+
+   w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);
+   w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);
+   w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);
+   w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);
+   FragColor = vec4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1.0);
+} 
+#endif
diff --git a/base/scalehq/shaders/4xScaleHQ.glsl b/base/scalehq/shaders/4xScaleHQ.glsl
new file mode 100644
index 0000000..620247f
--- /dev/null
+++ b/base/scalehq/shaders/4xScaleHQ.glsl
@@ -0,0 +1,177 @@
+/*
+   4xGLSLHqFilter shader
+   
+   Copyright (C) 2005 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy;
+   float x = 0.5 * SourceSize.z;
+   float y = 0.5 * SourceSize.w;
+   vec2 dg1 = vec2( x, y);
+   vec2 dg2 = vec2(-x, y);
+   vec2 sd1 = dg1 * 0.5;
+   vec2 sd2 = dg2 * 0.5;
+   vec2 ddx = vec2(x, 0.0);
+   vec2 ddy = vec2(0.0, y);
+   t1 = vec4(vTexCoord - sd1, vTexCoord - ddy);
+   t2 = vec4(vTexCoord - sd2, vTexCoord + ddx);
+   t3 = vec4(vTexCoord + sd1, vTexCoord + ddy);
+   t4 = vec4(vTexCoord + sd2, vTexCoord - ddx);
+   t5 = vec4(vTexCoord - dg1, vTexCoord - dg2);
+   t6 = vec4(vTexCoord + dg1, vTexCoord + dg2);
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+float mx = 1.0;      // start smoothing wt.
+float k = -1.10;      // wt. decrease factor
+float max_w = 0.75;    // max filter weight
+float min_w = 0.03;    // min filter weight
+float lum_add = 0.33;  // affects smoothing
+vec3 dt = vec3(1.0);
+
+void main()
+{
+   vec3 c  = COMPAT_TEXTURE(Source, vTexCoord).xyz;
+   vec3 i1 = COMPAT_TEXTURE(Source, t1.xy).xyz; 
+   vec3 i2 = COMPAT_TEXTURE(Source, t2.xy).xyz; 
+   vec3 i3 = COMPAT_TEXTURE(Source, t3.xy).xyz; 
+   vec3 i4 = COMPAT_TEXTURE(Source, t4.xy).xyz; 
+   vec3 o1 = COMPAT_TEXTURE(Source, t5.xy).xyz; 
+   vec3 o3 = COMPAT_TEXTURE(Source, t6.xy).xyz; 
+   vec3 o2 = COMPAT_TEXTURE(Source, t5.zw).xyz;
+   vec3 o4 = COMPAT_TEXTURE(Source, t6.zw).xyz;
+   vec3 s1 = COMPAT_TEXTURE(Source, t1.zw).xyz; 
+   vec3 s2 = COMPAT_TEXTURE(Source, t2.zw).xyz; 
+   vec3 s3 = COMPAT_TEXTURE(Source, t3.zw).xyz; 
+   vec3 s4 = COMPAT_TEXTURE(Source, t4.zw).xyz; 
+
+   float ko1=dot(abs(o1-c),dt);
+   float ko2=dot(abs(o2-c),dt);
+   float ko3=dot(abs(o3-c),dt);
+   float ko4=dot(abs(o4-c),dt);
+
+   float k1=min(dot(abs(i1-i3),dt),max(ko1,ko3));
+   float k2=min(dot(abs(i2-i4),dt),max(ko2,ko4));
+
+   float w1 = k2; if(ko3<ko1) w1*=ko3/ko1;
+   float w2 = k1; if(ko4<ko2) w2*=ko4/ko2;
+   float w3 = k2; if(ko1<ko3) w3*=ko1/ko3;
+   float w4 = k1; if(ko2<ko4) w4*=ko2/ko4;
+
+   c=(w1*o1+w2*o2+w3*o3+w4*o4+0.001*c)/(w1+w2+w3+w4+0.001);
+   w1 = k*dot(abs(i1-c)+abs(i3-c),dt)/(0.125*dot(i1+i3,dt)+lum_add);
+   w2 = k*dot(abs(i2-c)+abs(i4-c),dt)/(0.125*dot(i2+i4,dt)+lum_add);
+   w3 = k*dot(abs(s1-c)+abs(s3-c),dt)/(0.125*dot(s1+s3,dt)+lum_add);
+   w4 = k*dot(abs(s2-c)+abs(s4-c),dt)/(0.125*dot(s2+s4,dt)+lum_add);
+
+   w1 = clamp(w1+mx,min_w,max_w); 
+   w2 = clamp(w2+mx,min_w,max_w);
+   w3 = clamp(w3+mx,min_w,max_w); 
+   w4 = clamp(w4+mx,min_w,max_w);
+
+   FragColor = vec4((w1*(i1+i3)+w2*(i2+i4)+w3*(s1+s3)+w4*(s2+s4)+c)/(2.0*(w1+w2+w3+w4)+1.0), 1.0);
+} 
+#endif
diff --git a/base/scalenx/epx.glslp b/base/scalenx/epx.glslp
new file mode 100644
index 0000000..421f87c
--- /dev/null
+++ b/base/scalenx/epx.glslp
@@ -0,0 +1,6 @@
+shaders = 1
+
+shader0 = shaders/epx.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
diff --git a/base/scalenx/mmpx.glslp b/base/scalenx/mmpx.glslp
new file mode 100644
index 0000000..e6a7515
--- /dev/null
+++ b/base/scalenx/mmpx.glslp
@@ -0,0 +1,6 @@
+shaders = 1
+
+shader0 = shaders/mmpx.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
diff --git a/base/scalenx/scale2x.glslp b/base/scalenx/scale2x.glslp
new file mode 100644
index 0000000..04ed9ff
--- /dev/null
+++ b/base/scalenx/scale2x.glslp
@@ -0,0 +1,10 @@
+shaders = 2
+
+shader0 = shaders/scale2x.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/scalenx/scale2xSFX.glslp b/base/scalenx/scale2xSFX.glslp
new file mode 100644
index 0000000..125c3c2
--- /dev/null
+++ b/base/scalenx/scale2xSFX.glslp
@@ -0,0 +1,10 @@
+shaders = 2
+
+shader0 = shaders/scale2xSFX.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/scalenx/scale2xplus.glslp b/base/scalenx/scale2xplus.glslp
new file mode 100644
index 0000000..311a41b
--- /dev/null
+++ b/base/scalenx/scale2xplus.glslp
@@ -0,0 +1,10 @@
+shaders = 2
+
+shader0 = shaders/scale2xplus.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/scalenx/scale3x.glslp b/base/scalenx/scale3x.glslp
new file mode 100644
index 0000000..dee5a55
--- /dev/null
+++ b/base/scalenx/scale3x.glslp
@@ -0,0 +1,10 @@
+shaders = 2
+
+shader0 = shaders/scale3x.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 3.0
+scale_y0 = 3.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/scalenx/shaders/epx.glsl b/base/scalenx/shaders/epx.glsl
new file mode 100644
index 0000000..ce6b971
--- /dev/null
+++ b/base/scalenx/shaders/epx.glsl
@@ -0,0 +1,137 @@
+// EPX (Eric's Pixel Scaler)
+// based on the description from Wikipedia:
+// https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms#EPX/Scale2%C3%97/AdvMAME2%C3%97
+// adapted for glsl by hunterk
+// license GPL, I think
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 TEX0;
+// out variables go here as COMPAT_VARYING whatever
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+   gl_Position = MVPMatrix * VertexCoord;
+   TEX0.xy = TexCoord.xy;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+bool same(vec3 B, vec3 A0){
+   return all(equal(B, A0));
+}
+
+bool notsame(vec3 B, vec3 A0){
+   return any(notEqual(B, A0));
+}
+
+// sample with coordinate offsets
+#define TEX(c,d) COMPAT_TEXTURE(Source, vTexCoord.xy + vec2(c,d) * SourceSize.zw).rgb
+
+void main()
+{
+// The algorithm looks at the current pixel and the 4 surrounding cardinal pixels  
+// ___|_A_|___  
+// _C_|_P_|_B_
+//    | D |  
+
+// Our current pixel, P
+   vec3 P = TEX( 0., 0.);
+
+// Input pixels
+   vec3 A = TEX( 0., 1.);
+   vec3 B = TEX( 1., 0.);
+   vec3 D = TEX( 0.,-1.);
+   vec3 C = TEX(-1., 0.);
+   
+// Output: 2x2 grid. Default to the current pixel color (Nearest magnification)
+// ___one_|_two___
+//  three | four
+   vec3 one   = P;
+   vec3 two   = P;
+   vec3 three = P;
+   vec3 four  = P;
+
+// EPX algorithm rules:   
+// IF C==A AND C!=D AND A!=B => 1=A
+// IF A==B AND A!=C AND B!=D => 2=B
+// IF D==C AND D!=B AND C!=A => 3=C
+// IF B==D AND B!=A AND D!=C => 4=D
+
+   one   = (same(C, D) && notsame(C, A) && notsame(C, B)) ? C : P;
+   two   = (same(D, B) && notsame(D, C) && notsame(D, A)) ? D : P;
+   three = (same(A, C) && notsame(A, B) && notsame(A, D)) ? A : P;
+   four  = (same(B, A) && notsame(B, D) && notsame(B, C)) ? B : P;
+
+   vec2 px = fract(vTexCoord * SourceSize.xy);
+// split the texels into 4 and assign one of our output pixels to each
+   FragColor.rgb = (px.x < 0.5) ? (px.y < 0.5 ? one : three) : (px.y < 0.5 ? two : four);
+   FragColor.a = 1.0;
+} 
+#endif
diff --git a/base/scalenx/shaders/mmpx.glsl b/base/scalenx/shaders/mmpx.glsl
new file mode 100644
index 0000000..9f3b6a9
--- /dev/null
+++ b/base/scalenx/shaders/mmpx.glsl
@@ -0,0 +1,351 @@
+// MMPX
+// by Morgan McGuire and Mara Gagiu
+// https://casual-effects.com/research/McGuire2021PixelArt/
+// License: MIT
+// adapted for glsl by hunterk
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+   gl_Position = MVPMatrix * VertexCoord;
+   TEX0.xy = TexCoord.xy;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+float luma(vec3 col){
+   return dot(col, vec3(0.2126, 0.7152, 0.0722));
+}
+
+// I tried using a hash to speed these up but it didn't really help
+bool same(vec3 B, vec3 A0){
+   return all(equal(B, A0));
+}
+
+bool notsame(vec3 B, vec3 A0){
+   return any(notEqual(B, A0));
+}
+
+bool all_eq2(vec3 B, vec3 A0, vec3 A1) {
+    return (same(B,A0) && same(B,A1));
+}
+
+bool all_eq3(vec3 B, vec3 A0, vec3 A1, vec3 A2) {
+    return (same(B,A0) && same(B,A1) && same(B,A2));
+}
+
+bool all_eq4(vec3 B, vec3 A0, vec3 A1, vec3 A2, vec3 A3) {
+    return (same(B,A0) && same(B,A1) && same(B,A2) && same(B,A3));
+}
+
+bool any_eq3(vec3 B, vec3 A0, vec3 A1, vec3 A2) {
+   return (same(B,A0) || same(B,A1) || same(B,A2));
+}
+
+bool none_eq2(vec3 B, vec3 A0, vec3 A1) {
+   return (notsame(B,A0) && notsame(B,A1));
+}
+
+bool none_eq4(vec3 B, vec3 A0, vec3 A1, vec3 A2, vec3 A3) {
+   return (notsame(B,A0) && notsame(B,A1) && notsame(B,A2) && notsame(B,A3));
+}
+
+#define src(c,d) COMPAT_TEXTURE(Source, vTexCoord + vec2(c,d) * SourceSize.zw).rgb
+
+void main()
+{
+// these do nothing, but just for consistency with the original code...
+   float srcX = 0.;
+   float srcY = 0.;
+
+// Our current pixel
+   vec3 E = src(srcX+0.,srcY+0.);
+
+// Input: A-I central 3x3 grid
+   vec3 A = src(srcX-1.,srcY-1.);
+   vec3 B = src(srcX+0.,srcY-1.);
+   vec3 C = src(srcX+1.,srcY-1.);
+
+   vec3 D = src(srcX-1.,srcY+0.);
+   vec3 F = src(srcX+1.,srcY+0.);
+
+   vec3 G = src(srcX-1.,srcY+1.);
+   vec3 H = src(srcX+0.,srcY+1.);
+   vec3 I = src(srcX+1.,srcY+1.);
+
+// Default to Nearest magnification
+   vec3 J = E;
+   vec3 K = E;
+   vec3 L = E;
+   vec3 M = E;
+// Go ahead and put this here so we can use an early return on the next
+// line to save some cycles
+   FragColor = vec4(E, 1.0);
+   
+// Skip constant 3x3 centers and just use nearest-neighbor
+// them.  This gives a good speedup on spritesheets with
+// lots of padding and full screen images with large
+// constant regions such as skies.
+// EDIT: this is a wash for me, but we'll keep it around
+ if(same(E,A) && same(E,B) && same(E,C) && same(E,D) && same(E,F) && same(E,G) && same(E,H) && same(E,I)) return;
+
+// Read additional values at the tips of the diamond pattern
+   vec3 P  = src(srcX+0.,srcY-2.);
+   vec3 Q  = src(srcX-2.,srcY+0.);
+   vec3 R  = src(srcX+2.,srcY+0.);
+   vec3 S  = src(srcX+0.,srcY+2.);
+
+// Precompute luminances
+   float Bl = luma(B);
+   float Dl = luma(D);
+   float El = luma(E);
+   float Fl = luma(F);
+   float Hl = luma(H);
+
+// Round some corners and fill in 1:1 slopes, but preserve
+// sharp right angles.
+//
+// In each expression, the left clause is from
+// EPX and the others are new. EPX
+// recognizes 1:1 single-pixel lines because it
+// applies the rounding only to the LINE, and not
+// to the background (it looks at the mirrored
+// side).  It thus fails on thick 1:1 edges
+// because it rounds *both* sides and produces an
+// aliased edge shifted by 1 dst pixel.  (This
+// also yields the mushroom-shaped arrow heads,
+// where that 1-pixel offset runs up against the
+// 2-pixel aligned end; this is an inherent
+// problem with 2X in-palette scaling.)
+//
+// The 2nd clause clauses avoid *double* diagonal
+// filling on 1:1 slopes to prevent them becoming
+// aliased again. It does this by breaking
+// symmetry ties using luminance when working with
+// thick features (it allows thin and transparent
+// features to pass always).
+//
+// The 3rd clause seeks to preserve square corners
+// by considering the center value before
+// rounding.
+//
+// The 4th clause identifies 1-pixel bumps on
+// straight lines that are darker than their
+// background, such as the tail on a pixel art
+// "4", and prevents them from being rounded. This
+// corrects for asymmetry in this case that the
+// luminance tie breaker introduced.
+
+// .------------ 1st ------------.      .----- 2nd ---------.      .------ 3rd -----.      .--------------- 4th -----------------------.
+   if (((same(D,B) && notsame(D,H) && notsame(D,F))) && ((El>=Dl) || same(E,A)) && any_eq3(E,A,C,G) && ((El<Dl) || notsame(A,D) || notsame(E,P) || notsame(E,Q))) J=D;
+   if (((same(B,F) && notsame(B,D) && notsame(B,H))) && ((El>=Bl) || same(E,C)) && any_eq3(E,A,C,I) && ((El<Bl) || notsame(C,B) || notsame(E,P) || notsame(E,R))) K=B;
+   if (((same(H,D) && notsame(H,F) && notsame(H,B))) && ((El>=Hl) || same(E,G)) && any_eq3(E,A,G,I) && ((El<Hl) || notsame(G,H) || notsame(E,S) || notsame(E,Q))) L=H;
+   if (((same(F,H) && notsame(F,B) && notsame(F,D))) && ((El>=Fl) || same(E,I)) && any_eq3(E,C,G,I) && ((El<Fl) || notsame(I,H) || notsame(E,R) || notsame(E,S))) M=F;
+
+// Clean up disconnected line intersections.
+//
+// The first clause recognizes being on the inside
+// of a diagonal corner and ensures that the "foreground"
+// has been correctly identified to avoid
+// ambiguous cases such as this:
+//
+//  o#o#
+//  oo##
+//  o#o#
+//
+// where trying to fix the center intersection of
+// either the "o" or the "#" will leave the other
+// one disconnected. This occurs, for example,
+// when a pixel-art letter "B" or "R" is next to
+// another letter on the right.
+//
+// The second clause ensures that the pattern is
+// not a notch at the edge of a checkerboard
+// dithering pattern.
+// 
+// >
+//  .--------------------- 1st ------------------------.      .--------- 2nd -----------. 
+   if ((notsame(E,F) && all_eq4(E,C,I,D,Q) && all_eq2(F,B,H)) && notsame(F,src(srcX+3.,srcY))) K=M=F;
+   if ((notsame(E,D) && all_eq4(E,A,G,F,R) && all_eq2(D,B,H)) && notsame(D,src(srcX-3.,srcY))) J=L=D;
+   if ((notsame(E,H) && all_eq4(E,G,I,B,P) && all_eq2(H,D,F)) && notsame(H,src(srcX,srcY+3.))) L=M=H;
+   if ((notsame(E,B) && all_eq4(E,A,C,H,S) && all_eq2(B,D,F)) && notsame(B,src(srcX,srcY-3.))) J=K=B;
+
+// Remove tips of bright triangles on dark
+// backgrounds. The luminance tie breaker for 1:1
+// pixel lines leaves these as sticking up squared
+// off, which makes bright triangles and diamonds
+// look bad.
+   if ((Bl<El) && all_eq4(E,G,H,I,S) && none_eq4(E,A,D,C,F)) J=K=B;
+   if ((Hl<El) && all_eq4(E,A,B,C,P) && none_eq4(E,D,G,I,F)) L=M=H;
+   if ((Fl<El) && all_eq4(E,A,D,G,Q) && none_eq4(E,B,C,I,H)) K=M=F;
+   if ((Dl<El) && all_eq4(E,C,F,I,R) && none_eq4(E,B,A,G,H)) J=L=D;
+
+//////////////////////////////////////////////////////////////////////////////////
+// Do further neighborhood peeking to identify
+// 2:1 and 1:2 slopes of constant color.
+// The first clause of each rule identifies a 2:1 slope line
+// of consistent color.
+//
+// The second clause verifies that the line is separated from
+// every adjacent pixel on one side and not part of a more
+// complex pattern. Common subexpressions from the second clause
+// are lifted to an outer test on pairs of rules.
+// 
+// The actions taken by rules are unusual in that they extend
+// a color assigned by previous rules rather than drawing from
+// the original source image.
+//
+// The comments show a diagram of the local
+// neighborhood in which letters shown with the
+// same shape and color must match each other and
+// everything else without annotation must be
+// different from the solid colored, square
+// letters.
+   if (notsame(H,B)) { // Common subexpression
+                       // Above a 2:1 slope or -2:1 slope   â—¢ â—£
+                       // First:
+      if (notsame(H,A) && notsame(H,E) && notsame(H,C)) {
+                       // Second:
+                       //     P 
+                       //   â’¶ B C .
+                       // Q D 🄴 🅵 🆁
+                       //   🅶 🅷 I
+                       //     S
+         if (all_eq3(H,G,F,R) && none_eq2(H,D,src(srcX+2.,srcY-1.))) L=M;
+                       // Third:
+                       //     P 
+                       // . A B â’¸
+                       // 🆀 🅳 🄴 F R
+                       //   G 🅷 🅸
+                       //     S
+         if (all_eq3(H,I,D,Q) && none_eq2(H,F,src(srcX-2.,srcY-1.))) M=L;
+      }
+                        
+                       // Below a 2:1 (â—¤) or -2:1 (â—¥) slope (reflect the above 2:1 patterns vertically)
+      if (notsame(B,I) && notsame(B,G) && notsame(B,E)) {
+                       //     P 
+                       //   🅰 🅱 C
+                       // Q D 🄴 🅵 🆁
+                       //   â’¼ H I .
+                       //     S
+         if (all_eq3(B,A,F,R) && none_eq2(B,D,src(srcX+2.,srcY+1.))) J=K;
+                       //     P 
+                       //   A 🅱 🅲
+                       // 🆀 🅳 🄴 F R
+                       // . G H â’¾ 
+                       //     S
+         if (all_eq3(B,C,D,Q) && none_eq2(B,F,src(srcX-2.,srcY+1.))) K=J;
+      }
+   }
+
+   if (notsame(F,D)) { // Common subexpression
+                        
+                       // Right of a -1:2 (\) or -1:2 (/) slope (reflect the left 1:2 patterns horizontally)
+      if (notsame(D,I) && notsame(D,E) && notsame(D,C)) {
+                       //     P
+                       //   🅰 B Ⓒ
+                       // Q 🅳 🄴 F R
+                       //   G 🅷 I
+                       //     🆂 .
+         if (all_eq3(D,A,H,S) && none_eq2(D,B,src(srcX+1.,srcY+2.))) J=L;
+                       //     🅿 .
+                       //   A 🅱 C
+                       // Q 🅳 🄴 F R
+                       //   🅶 H Ⓘ
+                       //     S
+         if (all_eq3(D,G,B,P) && none_eq2(D,H,src(srcX+1.,srcY-2.))) L=J;
+      }
+                        
+                       // Left of a 1:2 (/) slope or -1:2 (\) slope (transpose the above 2:1 patterns)
+                       // Pull common none_eq subexpressions out
+
+      if (notsame(F,E) && notsame(F,A) && notsame(F,G)) {
+                       //     P     
+                       //   Ⓐ B 🅲   
+                       // Q D 🄴 🅵 R 
+                       //   G 🅷 I   
+                       //   . 🆂   
+         if (all_eq3(F,C,H,S) && none_eq2(F,B,src(srcX-1.,srcY+2.))) K=M;
+                       //   . 🅿
+                       //   A 🅱 C
+                       // Q D 🄴 🅵 R
+                       //   Ⓖ H 🅸
+                       //     S
+         if (all_eq3(F,I,B,P) && none_eq2(F,H,src(srcX-1.,srcY-2.))) M=K;
+      }
+   }
+
+// Determine which of our 4 output pixels we need to use
+   vec2 a = fract(vTexCoord * SourceSize.xy);
+   FragColor.rgb = (a.x < 0.5) ? (a.y < 0.5 ? J : L) : (a.y < 0.5 ? K : M);
+} 
+#endif
diff --git a/base/scalenx/shaders/scale2x.glsl b/base/scalenx/shaders/scale2x.glsl
new file mode 100644
index 0000000..99b34b8
--- /dev/null
+++ b/base/scalenx/shaders/scale2x.glsl
@@ -0,0 +1,163 @@
+/*
+	Scale2x
+
+Filter:	Nearest
+Scale:	2x
+
+Scale2x is real-time graphics effect able to increase the size of small bitmaps guessing the missing pixels without blurring the images.
+It was originally developed for the AdvanceMAME project in the year 2001 to improve the quality of old games with a low video resolution.
+
+Homepage: http://scale2x.sourceforge.net/
+Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni 
+License: GNU-GPL  
+
+*/
+
+#define saturate(c) clamp(c, 0.0, 1.0)
+#define lerp(a,b,c) mix(a,b,c)
+#define mul(a,b) (b*a)
+#define fmod(c,d) mod(c,d)
+#define frac(c) fract(c)
+#define tex2D(c,d) COMPAT_TEXTURE(c,d)
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+#define bool2 bvec2
+#define bool3 bvec3
+#define bool4 bvec4
+#define float2x2 mat2x2
+#define float3x3 mat3x3
+#define float4x4 mat4x4
+
+#define decal Source
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	float2 ps = float2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	t1 = TEX0.xyxy + float4(  0,-dy,-dx,  0);	// B, D
+	t2 = TEX0.xyxy + float4( dx,  0,  0, dy);	// F, H	
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+bool eq(float3 A, float3 B){
+	return (A==B);
+}
+
+bool neq(float3 A, float3 B){
+	return (A!=B);
+}
+
+void main()
+{
+	// subpixel determination
+	float2 fp = floor(2.0 * frac(vTexCoord*SourceSize.xy));
+
+	/*
+		  B		E0 E1
+		D E F		E2 E3
+		  H
+	*/
+
+	// reading the texels
+	float3 B = tex2D(decal, t1.xy).xyz;
+	float3 D = tex2D(decal, t1.zw).xyz;
+	float3 E = tex2D(decal, vTexCoord).xyz;
+	float3 F = tex2D(decal, t2.xy).xyz;
+	float3 H = tex2D(decal, t2.zw).xyz;
+
+	// rules
+	float3 E0 = eq(B,D) ? B : E;
+	float3 E1 = eq(B,F) ? B : E;
+	float3 E2 = eq(H,D) ? H : E;
+	float3 E3 = eq(H,F) ? H : E;
+
+	// general condition & subpixel output
+	FragColor = vec4(neq(B,H) && neq(D,F) ? (fp.y == 0. ? (fp.x == 0. ? E0 : E1) : (fp.x == 0. ? E2 : E3)) : E, 1.0);
+} 
+#endif
diff --git a/base/scalenx/shaders/scale2xSFX.glsl b/base/scalenx/shaders/scale2xSFX.glsl
new file mode 100644
index 0000000..1c9d0c8
--- /dev/null
+++ b/base/scalenx/shaders/scale2xSFX.glsl
@@ -0,0 +1,225 @@
+#version 130
+
+/*
+	Scale2xSFX
+	by Sp00kyFox, 2015
+
+Filter:	Nearest
+Scale:	2x
+
+Scale2SFX improves upon the original Scale2x (aka EPX) by avoiding the occurence of artifacts.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter YTR "SCALE2xSFX Y Threshold" 48.0 0.0 255.0 1.0
+#pragma parameter UTR "SCALE2xSFX U Threshold"  7.0 0.0 255.0 1.0
+#pragma parameter VTR "SCALE2xSFX V Threshold"  6.0 0.0 255.0 1.0
+
+#define saturate(c) clamp(c, 0.0, 1.0)
+#define lerp(a,b,c) mix(a,b,c)
+#define mul(a,b) (b*a)
+#define fmod(c,d) mod(c,d)
+#define frac(c) fract(c)
+#define tex2D(c,d) COMPAT_TEXTURE(c,d)
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+#define bool2 bvec2
+#define bool3 bvec3
+#define bool4 bvec4
+#define float2x2 mat2x2
+#define float3x3 mat3x3
+#define float4x4 mat4x4
+#define float4x3 mat4x3
+
+#define decal Source
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+   	float2 ps = float2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	t1 = TEX0.xxxy + float4(-dx,  0., dx,-dy);	// A, B, C
+	t2 = TEX0.xxxy + float4(-dx,  0., dx,  0.);	// D, E, F
+	t3 = TEX0.xxxy + float4(-dx,  0., dx, dy);	// G, H, I
+	t4 = TEX0.xyxy + float4(    0.,-2.*dy,-2.*dx,    0.);	// J, K
+	t5 = TEX0.xyxy + float4( 2.*dx,    0.,    0., 2.*dy);	// L, M
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float YTR;
+uniform COMPAT_PRECISION float UTR;
+uniform COMPAT_PRECISION float VTR;
+#else
+#define YTR 48.0
+#define UTR 7.0
+#define VTR 6.0
+#endif
+
+mat3 YUV  = mat3(0.299, -0.168736, 0.5, 0.587, -0.331264, -0.418688, 0.114, 0.5, -0.081312);	// transponed
+float3 thresh = float3(0.188235294, 0.02745098, 0.023529412);
+
+bool eq(float3 A, float3 B){
+	return (A==B);
+}
+
+bool neq(float3 A, float3 B){
+	return (A!=B);
+}
+
+void main()
+{
+	// subpixel determination
+	float2 fp = floor(2.0 * frac(vTexCoord*SourceSize.xy));
+
+	/*
+		    J
+		  A B C		E0 E1
+		K D E F L	E2 E3
+		  G H I
+		    M
+	*/
+
+	// reading the texels & colorspace conversion
+	float3 b = tex2D(decal, t1.yw).xyz;
+	float3 d = tex2D(decal, t2.xw).xyz;
+	float3 e = tex2D(decal, t2.yw).xyz;
+	float3 f = tex2D(decal, t2.zw).xyz;
+	float3 h = tex2D(decal, t3.yw).xyz;
+
+	float4x3 tmp = mul(float4x3(b,d,e,f), YUV);
+	float3 B = tmp[0], D = tmp[1], E = tmp[2], F = tmp[3], H = mul(h, YUV);
+
+	float3 A = tex2D(decal, t1.xw).xyz;
+	float3 C = tex2D(decal, t1.zw).xyz;
+	float3 G = tex2D(decal, t3.xw).xyz;
+	float3 I = tex2D(decal, t3.zw).xyz;
+
+	tmp = mul(float4x3(A,C,G,I), YUV);
+	A = tmp[0], C = tmp[1], G = tmp[2], I = tmp[3];
+
+	float3 J = tex2D(decal, t4.xy).xyz;
+	float3 K = tex2D(decal, t4.zw).xyz;
+	float3 L = tex2D(decal, t5.xy).xyz;
+	float3 M = tex2D(decal, t5.zw).xyz;
+
+	tmp = mul(float4x3(J,K,L,M), YUV);
+	J = tmp[0], K = tmp[1], L = tmp[2], M = tmp[3];
+
+
+
+	// parent condition
+	bool par0 = neq(B,F) && neq(D,H);
+	bool par1 = neq(B,D) && neq(F,H);
+
+	// equality checks
+	bool AE = eq(A,E), CE = eq(C,E), EG = eq(E,G), EI = eq(E,I);
+
+	// artifact prevention
+	bool art0 = CE || EG;
+	bool art1 = AE || EI;
+
+
+
+	// rules
+	float3 E0 = eq(B,D) && par0 && (!AE || art0 || eq(A,J) || eq(A,K)) ? 0.5*(b+d) : e;
+	float3 E1 = eq(B,F) && par1 && (!CE || art1 || eq(C,J) || eq(C,L)) ? 0.5*(b+f) : e;
+	float3 E2 = eq(D,H) && par1 && (!EG || art1 || eq(G,K) || eq(G,M)) ? 0.5*(h+d) : e;
+	float3 E3 = eq(F,H) && par0 && (!EI || art0 || eq(I,L) || eq(I,M)) ? 0.5*(h+f) : e;
+
+	// subpixel output
+	FragColor = vec4(fp.y == 0. ? (fp.x == 0. ? E0 : E1) : (fp.x == 0. ? E2 : E3), 1.0);
+} 
+#endif
diff --git a/base/scalenx/shaders/scale2xplus.glsl b/base/scalenx/shaders/scale2xplus.glsl
new file mode 100644
index 0000000..926ff1f
--- /dev/null
+++ b/base/scalenx/shaders/scale2xplus.glsl
@@ -0,0 +1,151 @@
+/*
+   Scale2xPlus shader 
+
+   - Copyright (C) 2007 guest(r) - guest.r at gmail.com
+
+   - License: GNU-GPL  
+
+
+   The Scale2x algorithm:
+
+   - Scale2x Homepage: http://scale2x.sourceforge.net/
+
+   - Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni 
+
+   - License: GNU-GPL  
+
+ */
+ 
+#define saturate(c) clamp(c, 0.0, 1.0)
+#define lerp(a,b,c) mix(a,b,c)
+#define mul(a,b) (b*a)
+#define fmod(c,d) mod(c,d)
+#define frac(c) fract(c)
+#define tex2D(c,d) COMPAT_TEXTURE(c,d)
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+#define bool2 bvec2
+#define bool3 bvec3
+#define bool4 bvec4
+#define float2x2 mat2x2
+#define float3x3 mat3x3
+#define float4x4 mat4x4
+
+#define decal Source
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy; // E
+   	float2 ps = float2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	t1 = TEX0.xyxy + float4(  0,-dy,-dx,  0);	// B, D
+	t2 = TEX0.xyxy + float4( dx,  0,  0, dy);	// F, H	
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+   float2 fp = frac(vTexCoord*SourceSize.xy);
+
+   // Reading the texels
+
+   float3 B = tex2D(decal, t1.xy).xyz;
+   float3 D = tex2D(decal, t1.zw).xyz;
+   float3 E = tex2D(decal, vTexCoord).xyz;
+   float3 F = tex2D(decal, t2.xy).xyz;
+   float3 H = tex2D(decal, t2.zw).xyz;
+
+   float3 E0 = D == B && B != H && D != F ? D : E;
+   float3 E1 = B == F && B != H && D != F ? F : E;
+   float3 E2 = D == H && B != H && D != F ? D : E;
+   float3 E3 = H == F && B != H && D != F ? F : E;
+
+   // Product interpolation
+   FragColor = float4((E3*fp.x+E2*(1.-fp.x))*fp.y+(E1*fp.x+E0*(1.-fp.x))*(1.-fp.y),1.);
+} 
+#endif
diff --git a/base/scalenx/shaders/scale3x.glsl b/base/scalenx/shaders/scale3x.glsl
new file mode 100644
index 0000000..35c17bc
--- /dev/null
+++ b/base/scalenx/shaders/scale3x.glsl
@@ -0,0 +1,178 @@
+/*
+	Scale3x
+
+Filter:	Nearest
+Scale:	3x
+
+Scale3x is real-time graphics effect able to increase the size of small bitmaps guessing the missing pixels without blurring the images.
+It was originally developed for the AdvanceMAME project in the year 2001 to improve the quality of old games with a low video resolution.
+
+Homepage: http://scale2x.sourceforge.net/
+Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni 
+License: GNU-GPL  
+
+*/
+
+#define saturate(c) clamp(c, 0.0, 1.0)
+#define lerp(a,b,c) mix(a,b,c)
+#define mul(a,b) (b*a)
+#define fmod(c,d) mod(c,d)
+#define frac(c) fract(c)
+#define tex2D(c,d) COMPAT_TEXTURE(c,d)
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+#define bool2 bvec2
+#define bool3 bvec3
+#define bool4 bvec4
+#define float2x2 mat2x2
+#define float3x3 mat3x3
+#define float4x4 mat4x4
+
+#define decal Source
+
+bool eq(float3 A, float3 B){
+	return (A==B);
+}
+
+bool neq(float3 A, float3 B){
+	return (A!=B);
+}
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	
+	float2 ps = float2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	t1 = TEX0.xxxy + float4(-dx,  0, dx,-dy);	// A, B, C
+	t2 = TEX0.xxxy + float4(-dx,  0, dx,  0);	// D, E, F
+	t3 = TEX0.xxxy + float4(-dx,  0, dx, dy);	// G, H, I
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+	// subpixel determination
+	float2 fp = floor(3.0 * frac(vTexCoord*SourceSize.xy));
+
+	/*
+		A B C		E0 E1 E2
+		D E F		E3 E4 E5
+		G H I		E6 E7 E8
+	*/
+
+	// reading the texels
+	float3 A = tex2D(decal, t1.xw).xyz;
+	float3 B = tex2D(decal, t1.yw).xyz;
+	float3 C = tex2D(decal, t1.zw).xyz;
+	float3 D = tex2D(decal, t2.xw).xyz;
+	float3 E = tex2D(decal, t2.yw).xyz;
+	float3 F = tex2D(decal, t2.zw).xyz;
+	float3 G = tex2D(decal, t3.xw).xyz;
+	float3 H = tex2D(decal, t3.yw).xyz;
+	float3 I = tex2D(decal, t3.zw).xyz;
+
+	// equality checks
+	bool eqBD = eq(B,D), eqBF = eq(B,F), eqHD = eq(H,D), eqHF = eq(H,F), neqEA = neq(E,A), neqEC = neq(E,C), neqEG = neq(E,G), neqEI = neq(E,I); 
+
+	// rules
+	float3 E0 = eqBD ? B : E;
+	float3 E1 = eqBD && neqEC || eqBF && neqEA ? B : E;
+	float3 E2 = eqBF ? B : E;
+	float3 E3 = eqBD && neqEG || eqHD && neqEA ? D : E;
+	float3 E5 = eqBF && neqEI || eqHF && neqEC ? F : E;
+	float3 E6 = eqHD ? H : E;
+	float3 E7 = eqHD && neqEI || eqHF && neqEG ? H : E;
+	float3 E8 = eqHF ? H : E;
+
+	// general condition & subpixel output
+	FragColor = vec4(neq(B,H) && neq(D,F) ? (fp.y == 0. ? (fp.x == 0. ? E0 : fp.x == 1. ? E1 : E2) : (fp.y == 1. ? (fp.x == 0. ? E3 : fp.x == 1. ? E : E5) : (fp.x == 0. ? E6 : fp.x == 1. ? E7 : E8))) : E, 1.0);
+} 
+#endif
diff --git a/base/scalenx/shaders/scale3xSFX.glsl b/base/scalenx/shaders/scale3xSFX.glsl
new file mode 100644
index 0000000..d7c2b62
--- /dev/null
+++ b/base/scalenx/shaders/scale3xSFX.glsl
@@ -0,0 +1,223 @@
+/*
+	Scale3xSFX
+	by Sp00kyFox, 2015
+
+Filter:	Nearest
+Scale:	3x
+
+Scale3SFX improves upon the original Scale3x by avoiding the occurence of artifacts and smoothing out 45° edges.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter YTR "SCALE2xSFX Y Threshold" 48.0 0.0 255.0 1.0
+#pragma parameter UTR "SCALE2xSFX U Threshold"  7.0 0.0 255.0 1.0
+#pragma parameter VTR "SCALE2xSFX V Threshold"  6.0 0.0 255.0 1.0
+
+#define saturate(c) clamp(c, 0.0, 1.0)
+#define lerp(a,b,c) mix(a,b,c)
+#define mul(a,b) (b*a)
+#define fmod(c,d) mod(c,d)
+#define frac(c) fract(c)
+#define tex2D(c,d) COMPAT_TEXTURE(c,d)
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+#define bool2 bvec2
+#define bool3 bvec3
+#define bool4 bvec4
+#define float2x2 mat2x2
+#define float3x3 mat3x3
+#define float4x4 mat4x4
+#define float4x3 mat4x3
+
+#define decal Source
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+
+	float2 ps = float2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	t1 = TEX0.xxxy + float4(-dx,  0., dx,-dy);	// A, B, C
+	t2 = TEX0.xxxy + float4(-dx,  0., dx,  0.);	// D, E, F
+	t3 = TEX0.xxxy + float4(-dx,  0., dx, dy);	// G, H, I
+	t4 = TEX0.xyxy + float4(    0.,-2.*dy,-2.*dx,    0.);	// J, K
+	t5 = TEX0.xyxy + float4( 2.*dx,    0.,    0., 2.*dy);	// L, M
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float YTR;
+uniform COMPAT_PRECISION float UTR;
+uniform COMPAT_PRECISION float VTR;
+#else
+#define YTR 48.0
+#define UTR 7.0
+#define VTR 6.0
+#endif
+
+const float3x3 YUV  = float3x3(0.299, -0.168736, 0.5, 0.587, -0.331264, -0.418688, 0.114, 0.5, -0.081312);	// transponed
+float3 thresh = float3(YTR, UTR, VTR)/255.0;
+
+bool3 eq(float3 A, float3 B){
+	return lessThanEqual(abs(A-B) , thresh);
+}
+
+bool3 neq(float3 A, float3 B){
+	return greaterThan(abs(A-B) , thresh);
+}
+
+void main()
+{
+	// subpixel determination
+	float2 fp = floor(2.0 * frac(vTexCoord*SourceSize.xy));
+
+	/*
+		    J
+		  A B C		E0 E1
+		K D E F L	E2 E3
+		  G H I
+		    M
+	*/
+
+	// reading the texels & colorspace conversion
+	float3 b = tex2D(decal, t1.yw).xyz;
+	float3 d = tex2D(decal, t2.xw).xyz;
+	float3 e = tex2D(decal, t2.yw).xyz;
+	float3 f = tex2D(decal, t2.zw).xyz;
+	float3 h = tex2D(decal, t3.yw).xyz;
+
+	float4x3 tmp = mul(float4x3(b,d,e,f), YUV);
+	float3 B = tmp[0], D = tmp[1], E = tmp[2], F = tmp[3], H = mul(h, YUV);
+
+	float3 A = tex2D(decal, t1.xw).xyz;
+	float3 C = tex2D(decal, t1.zw).xyz;
+	float3 G = tex2D(decal, t3.xw).xyz;
+	float3 I = tex2D(decal, t3.zw).xyz;
+
+	tmp = mul(float4x3(A,C,G,I), YUV);
+	A = tmp[0], C = tmp[1], G = tmp[2], I = tmp[3];
+
+	float3 J = tex2D(decal, t4.xy).xyz;
+	float3 K = tex2D(decal, t4.zw).xyz;
+	float3 L = tex2D(decal, t5.xy).xyz;
+	float3 M = tex2D(decal, t5.zw).xyz;
+
+	tmp = mul(float4x3(J,K,L,M), YUV);
+	J = tmp[0], K = tmp[1], L = tmp[2], M = tmp[3];
+
+	// parent condition
+	bool par0 = neq(B,F) == bool3(true) && neq(D,H) == bool3(true);
+	bool par1 = neq(B,D) == bool3(true) && neq(F,H) == bool3(true);
+
+	// equality checks
+	bool AE = eq(A,E) == bool3(true);
+	bool CE = eq(C,E) == bool3(true);
+	bool EG = eq(E,G) == bool3(true);
+	bool EI = eq(E,I) == bool3(true);
+
+	// artifact prevention
+	bool art0 = CE || EG;
+	bool art1 = AE || EI;
+
+	// rules
+	float3 E0 = eq(B,D) == bool3(true) && par0 == true && (AE == false || art0 == true || eq(A,J) == bool3(true) || eq(A,K) == bool3(true)) ? 0.5*(b+d) : e;
+	float3 E1 = eq(B,F) == bool3(true) && par1 == true && (CE == false || art1 == true || eq(C,J) == bool3(true) || eq(C,L) == bool3(true)) ? 0.5*(b+f) : e;
+	float3 E2 = eq(D,H) == bool3(true) && par1 == true && (EG == false || art1 == true || eq(G,K) == bool3(true) || eq(G,M) == bool3(true)) ? 0.5*(h+d) : e;
+	float3 E3 = eq(F,H) == bool3(true) && par0 == true && (EI == false || art0 == true || eq(I,L) == bool3(true) || eq(I,M) == bool3(true)) ? 0.5*(h+f) : e;
+
+	// subpixel output
+	FragColor = vec4(fp.y == 0. ? (fp.x == 0. ? E0 : E1) : (fp.x == 0. ? E2 : E3), 1.0);
+} 
+#endif
diff --git a/base/scanlines/shaders/res-independent-scanlines.glsl b/base/scanlines/shaders/res-independent-scanlines.glsl
new file mode 100644
index 0000000..ae281ba
--- /dev/null
+++ b/base/scanlines/shaders/res-independent-scanlines.glsl
@@ -0,0 +1,109 @@
+/*
+   based on scanline shader by:
+   Author: Themaister
+   License: Public domain
+*/
+
+#pragma parameter SCANLINE_SINE_COMP_B "Scanline Sine Comp B" 0.25 0.0 1.0 0.05
+#pragma parameter scanline_size "Scanline Scale" 4.0 1.0 20.0 1.0
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 omega;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+#define pi 3.141592654
+
+void main()
+{
+   gl_Position = MVPMatrix * VertexCoord;
+   TEX0.xy = TexCoord.xy;
+   omega = vec2(pi * OutputSize.x, 2.0 * pi * SourceSize.y);
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 omega;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float SCANLINE_SINE_COMP_B, scanline_size;
+#else
+#define SCANLINE_SINE_COMP_B 0.25
+#define scanline_size 4.0
+#endif
+
+void main()
+{
+   vec2 sine_comp = vec2(0.0, SCANLINE_SINE_COMP_B);
+   vec3 res = COMPAT_TEXTURE(Source, vTexCoord).xyz;
+   vec2 fragcoord = fract(floor(gl_FragCoord.xy * 1.0001) / scanline_size);
+   vec3 scanline = (fragcoord.y > 0.5)? res : vec3(0.0);//res * ((1. - 0.75 * SCANLINE_SINE_COMP_B) + dot(sine_comp * sin((fragcoord / scanline_size) * omega), vec2(1.0, 1.0)));
+   FragColor = vec4(scanline.x, scanline.y, scanline.z, 1.0);
+} 
+#endif
diff --git a/base/scanlines/shaders/scanline-fract.glsl b/base/scanlines/shaders/scanline-fract.glsl
new file mode 100644
index 0000000..5471a42
--- /dev/null
+++ b/base/scanlines/shaders/scanline-fract.glsl
@@ -0,0 +1,130 @@
+// Super-basic scanline shader
+// (looks bad at non-integer scales)
+// by hunterk
+// license: public domain
+
+// Parameter lines go here:
+#pragma parameter THICKNESS "Scanline Thickness" 2.0 1.0 12.0 1.0
+#pragma parameter DARKNESS "Scanline Darkness" 0.50 0.0 1.0 0.05
+#pragma parameter BRIGHTBOOST "Scanline Boost Bright" 1.1 1.0 1.2 0.1
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy * 1.0004;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+// All parameter floats need to have COMPAT_PRECISION in front of them
+uniform COMPAT_PRECISION float THICKNESS;
+uniform COMPAT_PRECISION float DARKNESS;
+uniform COMPAT_PRECISION float BRIGHTBOOST;
+#else
+#define THICKNESS 1.0
+#define DARKNESS 0.5
+#define BRIGHTBOOST 1.1
+#endif
+
+vec3 RGBtoYIQ(vec3 RGB){
+	const mat3 yiqmat = mat3(
+		0.2989, 0.5870, 0.1140,
+		0.5959, -0.2744, -0.3216,
+		0.2115, -0.5229, 0.3114);
+	return RGB * yiqmat;
+}
+
+vec3 YIQtoRGB(vec3 YIQ){
+	const mat3 rgbmat = mat3(
+		1.0, 0.956, 0.6210,
+		1.0, -0.2720, -0.6474,
+		1.0, -1.1060, 1.7046);
+	return YIQ * rgbmat;
+}
+
+void main()
+{
+	float lines = fract(vTexCoord.y * SourceSize.y);
+	float scale_factor = floor((OutputSize.y / InputSize.y) + 0.4999);
+	vec4 screen = COMPAT_TEXTURE(Source, vTexCoord);
+	screen.rgb = RGBtoYIQ(screen.rgb);
+	screen.r *= BRIGHTBOOST;
+	screen.rgb = YIQtoRGB(screen.rgb);
+
+    FragColor = (lines > (1.0 / scale_factor * THICKNESS)) ? screen : screen * vec4(1.0 - DARKNESS);
+} 
+#endif
diff --git a/base/scanlines/shaders/scanline.glsl b/base/scanlines/shaders/scanline.glsl
new file mode 100644
index 0000000..7186ba2
--- /dev/null
+++ b/base/scanlines/shaders/scanline.glsl
@@ -0,0 +1,107 @@
+// Parameter lines go here:
+#pragma parameter SCANLINE_BASE_BRIGHTNESS "Scanline Base Brightness" 0.95 0.0 1.0 0.01
+#pragma parameter SCANLINE_SINE_COMP_A "Grid Strength" 0.0 0.0 1.00 0.02
+#pragma parameter SCANLINE_SINE_COMP_B "Scanline Strength" 0.25 0.0 1.0 0.05
+#pragma parameter size "Grid size"  1.0 1.0 2.0 1.0
+#define pi 3.141592654
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 omega;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform COMPAT_PRECISION float size;
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+    omega = vec2(pi * size * OutputSize.x, 2.0 * pi * TextureSize.y);
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec2 omega;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutputSize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+// All parameter floats need to have COMPAT_PRECISION in front of them
+uniform COMPAT_PRECISION float SCANLINE_BASE_BRIGHTNESS;
+uniform COMPAT_PRECISION float SCANLINE_SINE_COMP_A;
+uniform COMPAT_PRECISION float SCANLINE_SINE_COMP_B;
+#else
+#define SCANLINE_BASE_BRIGHTNESS 0.95
+#define SCANLINE_SINE_COMP_A 0.0
+#define SCANLINE_SINE_COMP_B 0.15
+#endif
+
+void main()
+{
+   vec2 sine_comp = vec2(SCANLINE_SINE_COMP_A, SCANLINE_SINE_COMP_B);
+   vec3 res = COMPAT_TEXTURE(Source, vTexCoord).xyz;
+   vec3 scanline = res * (SCANLINE_BASE_BRIGHTNESS + dot(sine_comp * sin(vTexCoord * omega), vec2(1.0, 1.0)));
+   FragColor = vec4(scanline.x, scanline.y, scanline.z, 1.0);
+} 
+#endif
diff --git a/base/scanlines/shaders/scanlines-sine-abs.glsl b/base/scanlines/shaders/scanlines-sine-abs.glsl
new file mode 100644
index 0000000..2583358
--- /dev/null
+++ b/base/scanlines/shaders/scanlines-sine-abs.glsl
@@ -0,0 +1,137 @@
+/*
+    Scanlines Sine Absolute Value
+    An ultra light scanline shader
+    by RiskyJumps
+	license: public domain
+*/
+
+#pragma parameter amp          "Amplitude"      1.2500  0.000 2.000 0.05
+#pragma parameter phase        "Phase"          0.5000  0.000 2.000 0.05
+#pragma parameter lines_black  "Lines Blacks"   0.0000  0.000 1.000 0.05
+#pragma parameter lines_white  "Lines Whites"   1.0000  0.000 2.000 0.05
+ 
+#define freq             0.500000
+#define offset           0.000000
+#define pi               3.141592654
+
+#ifndef PARAMETER_UNIFORM
+#define amp              1.250000
+#define phase            0.500000
+#define lines_black      0.000000
+#define lines_white      1.000000
+#endif
+ 
+#if defined(VERTEX)
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+ 
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying
+#define COMPAT_ATTRIBUTE attribute
+#define COMPAT_TEXTURE texture2D
+#endif
+ 
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING float angle;
+ 
+vec4 _oPosition1;
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float amp;
+uniform COMPAT_PRECISION float phase;
+uniform COMPAT_PRECISION float lines_black;
+uniform COMPAT_PRECISION float lines_white;
+#endif
+ 
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+ 
+    float omega = 2.0 * pi * freq;              // Angular frequency
+    angle = TEX0.y * omega * TextureSize.y + phase;
+}
+ 
+#elif defined(FRAGMENT)
+ 
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+ 
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+ 
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING float angle;
+ 
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutputSize vec4(OutputSize, 1.0 / OutputSize)
+ 
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float amp;
+uniform COMPAT_PRECISION float phase;
+uniform COMPAT_PRECISION float lines_black;
+uniform COMPAT_PRECISION float lines_white;
+#endif
+ 
+void main()
+{
+    vec3 color = COMPAT_TEXTURE(Source, vTexCoord).xyz;
+    float grid;
+ 
+    float lines;
+ 
+    lines = sin(angle);
+    lines *= amp;
+    lines += offset;
+    lines = abs(lines);
+    lines *= lines_white - lines_black;
+    lines += lines_black;
+    color *= lines;
+ 
+    FragColor = vec4(color.xyz, 1.0);
+}
+#endif
\ No newline at end of file
diff --git a/base/xbrz/4xbrz-linear.glslp b/base/xbrz/4xbrz-linear.glslp
new file mode 100644
index 0000000..4c2b1b7
--- /dev/null
+++ b/base/xbrz/4xbrz-linear.glslp
@@ -0,0 +1,9 @@
+shaders = 2
+
+shader0 = shaders/4xbrz.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/xbrz/5xbrz-linear.glslp b/base/xbrz/5xbrz-linear.glslp
new file mode 100644
index 0000000..09da31e
--- /dev/null
+++ b/base/xbrz/5xbrz-linear.glslp
@@ -0,0 +1,9 @@
+shaders = 2
+
+shader0 = shaders/5xbrz.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 5.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/xbrz/6xbrz-linear.glslp b/base/xbrz/6xbrz-linear.glslp
new file mode 100644
index 0000000..337c008
--- /dev/null
+++ b/base/xbrz/6xbrz-linear.glslp
@@ -0,0 +1,9 @@
+shaders = 2
+
+shader0 = shaders/6xbrz.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 6.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/xbrz/shaders/4xbrz.glsl b/base/xbrz/shaders/4xbrz.glsl
new file mode 100644
index 0000000..2be698d
--- /dev/null
+++ b/base/xbrz/shaders/4xbrz.glsl
@@ -0,0 +1,427 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#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
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	vec2 ps = vec2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	 //  A1 B1 C1
+	// A0 A  B  C C4
+	// D0 D  E  F F4
+	// G0 G  H  I I4
+	 //  G5 H5 I5
+
+	t1 = vTexCoord.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
+	t2 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, -dy);    //  A  B  C
+	t3 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 0.0);    //  D  E  F
+	t4 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, dy);     //  G  H  I
+	t5 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 2.0*dy); // G5 H5 I5
+	t6 = vTexCoord.xyyy + vec4(-2.0*dx,-dy, 0.0, dy);  // A0 D0 G0
+	t7 = vTexCoord.xyyy + vec4( 2.0*dx,-dy, 0.0, dy);  // C4 F4 I4
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+	const float  one_sixth = 1.0 / 6.0;
+	const float  two_sixth = 2.0 / 6.0;
+	const float four_sixth = 4.0 / 6.0;
+	const float five_sixth = 5.0 / 6.0;
+
+	float reduce(const vec3 color)
+	{
+		return dot(color, vec3(65536.0, 256.0, 1.0));
+	}
+	
+	float DistYCbCr(const vec3 pixA, const 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, 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);
+	}
+	
+	bool IsBlendingNeeded(const ivec4 blend)
+	{
+		return any(notEqual(blend, ivec4(BLEND_NONE)));
+	}
+	
+	//---------------------------------------
+	// Input Pixel Mapping:    --|21|22|23|--
+	//                         19|06|07|08|09
+	//                         18|05|00|01|10
+	//                         17|04|03|02|11
+	//                         --|15|14|13|--
+	//
+	// Output Pixel Mapping: 20|21|22|23|24|25
+	//                       19|06|07|08|09|26
+	//                       18|05|00|01|10|27
+	//                       17|04|03|02|11|28
+	//                       16|15|14|13|12|29
+	//                       35|34|33|32|31|30
+
+void main()
+{
+vec2 f = fract(vTexCoord.xy * SourceSize.xy);
+
+	//---------------------------------------
+	// Input Pixel Mapping:  20|21|22|23|24
+	//                       19|06|07|08|09
+	//                       18|05|00|01|10
+	//                       17|04|03|02|11
+	//                       16|15|14|13|12
+  
+	vec3 src[25];
+  
+	src[21] = COMPAT_TEXTURE(Source, t1.xw).rgb;
+	src[22] = COMPAT_TEXTURE(Source, t1.yw).rgb;
+	src[23] = COMPAT_TEXTURE(Source, t1.zw).rgb;
+	src[ 6] = COMPAT_TEXTURE(Source, t2.xw).rgb;
+	src[ 7] = COMPAT_TEXTURE(Source, t2.yw).rgb;
+	src[ 8] = COMPAT_TEXTURE(Source, t2.zw).rgb;
+	src[ 5] = COMPAT_TEXTURE(Source, t3.xw).rgb;
+	src[ 0] = COMPAT_TEXTURE(Source, t3.yw).rgb;
+	src[ 1] = COMPAT_TEXTURE(Source, t3.zw).rgb;
+	src[ 4] = COMPAT_TEXTURE(Source, t4.xw).rgb;
+	src[ 3] = COMPAT_TEXTURE(Source, t4.yw).rgb;
+	src[ 2] = COMPAT_TEXTURE(Source, t4.zw).rgb;
+	src[15] = COMPAT_TEXTURE(Source, t5.xw).rgb;
+	src[14] = COMPAT_TEXTURE(Source, t5.yw).rgb;
+	src[13] = COMPAT_TEXTURE(Source, t5.zw).rgb;
+	src[19] = COMPAT_TEXTURE(Source, t6.xy).rgb;
+	src[18] = COMPAT_TEXTURE(Source, t6.xz).rgb;
+	src[17] = COMPAT_TEXTURE(Source, t6.xw).rgb;
+	src[ 9] = COMPAT_TEXTURE(Source, t7.xy).rgb;
+	src[10] = COMPAT_TEXTURE(Source, t7.xz).rgb;
+	src[11] = COMPAT_TEXTURE(Source, t7.xw).rgb;
+	
+		float v[9];
+		v[0] = reduce(src[0]);
+		v[1] = reduce(src[1]);
+		v[2] = reduce(src[2]);
+		v[3] = reduce(src[3]);
+		v[4] = reduce(src[4]);
+		v[5] = reduce(src[5]);
+		v[6] = reduce(src[6]);
+		v[7] = reduce(src[7]);
+		v[8] = reduce(src[8]);
+		
+		ivec4 blendResult = ivec4(BLEND_NONE);
+		
+		// Preprocess corners
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|--|07|08|--
+		//                    --|05|00|01|10
+		//                    --|04|03|02|11
+		//                    --|--|14|13|--
+		// Corner (1, 1)
+		if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false)
+		{
+			float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));
+			float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;
+			blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|06|07|--|--
+		//                    18|05|00|01|--
+		//                    17|04|03|02|--
+		//                    --|15|14|--|--
+		// Corner (0, 1)
+		if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false)
+		{
+			float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));
+			float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;
+			blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|--|22|23|--
+		//                    --|06|07|08|09
+		//                    --|05|00|01|10
+		//                    --|--|03|02|--
+		//                    --|--|--|--|--
+		// Corner (1, 0)
+		if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false)
+		{
+			float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));
+			float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;
+			blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|21|22|--|--
+		//                    19|06|07|08|--
+		//                    18|05|00|01|--
+		//                    --|04|03|--|--
+		//                    --|--|--|--|--
+		// Corner (0, 0)
+		if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false)
+		{
+			float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));
+			float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;
+			blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		vec3 dst[16];
+		dst[ 0] = src[0];
+		dst[ 1] = src[0];
+		dst[ 2] = src[0];
+		dst[ 3] = src[0];
+		dst[ 4] = src[0];
+		dst[ 5] = src[0];
+		dst[ 6] = src[0];
+		dst[ 7] = src[0];
+		dst[ 8] = src[0];
+		dst[ 9] = src[0];
+		dst[10] = src[0];
+		dst[11] = src[0];
+		dst[12] = src[0];
+		dst[13] = src[0];
+		dst[14] = src[0];
+		dst[15] = src[0];
+		
+		// Scale pixel
+		if (IsBlendingNeeded(blendResult) == true)
+		{
+			float dist_01_04 = DistYCbCr(src[1], src[4]);
+			float dist_03_08 = DistYCbCr(src[3], src[8]);
+			bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);
+			bool haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);
+			bool needBlend = (blendResult[2] != BLEND_NONE);
+			bool doLineBlend = (  blendResult[2] >= BLEND_DOMINANT ||
+							   ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+								 (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+								 (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false );
+			
+			vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];
+			dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);
+			dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);
+			dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);
+			dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);
+			dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);
+			
+			dist_01_04 = DistYCbCr(src[7], src[2]);
+			dist_03_08 = DistYCbCr(src[1], src[6]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);
+			needBlend = (blendResult[1] != BLEND_NONE);
+			doLineBlend = (  blendResult[1] >= BLEND_DOMINANT ||
+						  !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];
+			dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);
+			dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);
+			dst[ 8] = mix(dst[ 8], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);
+			dst[10] = mix(dst[10], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);
+			dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);
+
+			dist_01_04 = DistYCbCr(src[5], src[8]);
+			dist_03_08 = DistYCbCr(src[7], src[4]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);
+			needBlend = (blendResult[0] != BLEND_NONE);
+			doLineBlend = (  blendResult[0] >= BLEND_DOMINANT ||
+						  !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+							(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+							(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];
+			dst[ 0] = mix(dst[ 0], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);
+			dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);
+			dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[ 6] = mix(dst[ 6], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);
+			
+			
+			dist_01_04 = DistYCbCr(src[3], src[6]);
+			dist_03_08 = DistYCbCr(src[5], src[2]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);
+			needBlend = (blendResult[3] != BLEND_NONE);
+			doLineBlend = (  blendResult[3] >= BLEND_DOMINANT ||
+						  !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];
+			dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);
+			dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);
+			dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);
+			dst[14] = mix(dst[14], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);
+			dst[ 4] = mix(dst[ 4], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);
+			dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);
+		}
+		
+		vec3 res = mix( mix( mix( mix(dst[ 6], dst[ 7], step(0.25, f.x)), mix(dst[ 8], dst[ 9], step(0.75, f.x)), step(0.50, f.x)),
+		                             mix( mix(dst[ 5], dst[ 0], step(0.25, f.x)), mix(dst[ 1], dst[10], step(0.75, f.x)), step(0.50, f.x)), step(0.25, f.y)),
+		                        mix( mix( mix(dst[ 4], dst[ 3], step(0.25, f.x)), mix(dst[ 2], dst[11], step(0.75, f.x)), step(0.50, f.x)),
+		                             mix( mix(dst[15], dst[14], step(0.25, f.x)), mix(dst[13], dst[12], step(0.75, f.x)), step(0.50, f.x)), step(0.75, f.y)),
+		                                                                                                                                    step(0.50, f.y));
+								 
+   FragColor = vec4(res, 1.0);
+} 
+#endif
diff --git a/base/xbrz/shaders/5xbrz.glsl b/base/xbrz/shaders/5xbrz.glsl
new file mode 100644
index 0000000..5f79e00
--- /dev/null
+++ b/base/xbrz/shaders/5xbrz.glsl
@@ -0,0 +1,454 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#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
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	vec2 ps = vec2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	 //  A1 B1 C1
+	// A0 A  B  C C4
+	// D0 D  E  F F4
+	// G0 G  H  I I4
+	 //  G5 H5 I5
+
+	t1 = vTexCoord.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
+	t2 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, -dy);    //  A  B  C
+	t3 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 0.0);    //  D  E  F
+	t4 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, dy);     //  G  H  I
+	t5 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 2.0*dy); // G5 H5 I5
+	t6 = vTexCoord.xyyy + vec4(-2.0*dx,-dy, 0.0, dy);  // A0 D0 G0
+	t7 = vTexCoord.xyyy + vec4( 2.0*dx,-dy, 0.0, dy);  // C4 F4 I4
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+	const float  one_sixth = 1.0 / 6.0;
+	const float  two_sixth = 2.0 / 6.0;
+	const float four_sixth = 4.0 / 6.0;
+	const float five_sixth = 5.0 / 6.0;
+
+	float reduce(const vec3 color)
+	{
+		return dot(color, vec3(65536.0, 256.0, 1.0));
+	}
+	
+	float DistYCbCr(const vec3 pixA, const 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, 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);
+	}
+	
+	bool IsBlendingNeeded(const ivec4 blend)
+	{
+		return any(notEqual(blend, ivec4(BLEND_NONE)));
+	}
+	
+	//---------------------------------------
+	// Input Pixel Mapping:    --|21|22|23|--
+	//                         19|06|07|08|09
+	//                         18|05|00|01|10
+	//                         17|04|03|02|11
+	//                         --|15|14|13|--
+	//
+	// Output Pixel Mapping: 20|21|22|23|24|25
+	//                       19|06|07|08|09|26
+	//                       18|05|00|01|10|27
+	//                       17|04|03|02|11|28
+	//                       16|15|14|13|12|29
+	//                       35|34|33|32|31|30
+
+void main()
+{
+vec2 f = fract(vTexCoord.xy * SourceSize.xy);
+
+	//---------------------------------------
+	// Input Pixel Mapping:  20|21|22|23|24
+	//                       19|06|07|08|09
+	//                       18|05|00|01|10
+	//                       17|04|03|02|11
+	//                       16|15|14|13|12
+  
+	vec3 src[25];
+  
+	src[21] = COMPAT_TEXTURE(Source, t1.xw).rgb;
+	src[22] = COMPAT_TEXTURE(Source, t1.yw).rgb;
+	src[23] = COMPAT_TEXTURE(Source, t1.zw).rgb;
+	src[ 6] = COMPAT_TEXTURE(Source, t2.xw).rgb;
+	src[ 7] = COMPAT_TEXTURE(Source, t2.yw).rgb;
+	src[ 8] = COMPAT_TEXTURE(Source, t2.zw).rgb;
+	src[ 5] = COMPAT_TEXTURE(Source, t3.xw).rgb;
+	src[ 0] = COMPAT_TEXTURE(Source, t3.yw).rgb;
+	src[ 1] = COMPAT_TEXTURE(Source, t3.zw).rgb;
+	src[ 4] = COMPAT_TEXTURE(Source, t4.xw).rgb;
+	src[ 3] = COMPAT_TEXTURE(Source, t4.yw).rgb;
+	src[ 2] = COMPAT_TEXTURE(Source, t4.zw).rgb;
+	src[15] = COMPAT_TEXTURE(Source, t5.xw).rgb;
+	src[14] = COMPAT_TEXTURE(Source, t5.yw).rgb;
+	src[13] = COMPAT_TEXTURE(Source, t5.zw).rgb;
+	src[19] = COMPAT_TEXTURE(Source, t6.xy).rgb;
+	src[18] = COMPAT_TEXTURE(Source, t6.xz).rgb;
+	src[17] = COMPAT_TEXTURE(Source, t6.xw).rgb;
+	src[ 9] = COMPAT_TEXTURE(Source, t7.xy).rgb;
+	src[10] = COMPAT_TEXTURE(Source, t7.xz).rgb;
+	src[11] = COMPAT_TEXTURE(Source, t7.xw).rgb;
+	
+		float v[9];
+		v[0] = reduce(src[0]);
+		v[1] = reduce(src[1]);
+		v[2] = reduce(src[2]);
+		v[3] = reduce(src[3]);
+		v[4] = reduce(src[4]);
+		v[5] = reduce(src[5]);
+		v[6] = reduce(src[6]);
+		v[7] = reduce(src[7]);
+		v[8] = reduce(src[8]);
+		
+		ivec4 blendResult = ivec4(BLEND_NONE);
+		
+		// Preprocess corners
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|--|07|08|--
+		//                    --|05|00|01|10
+		//                    --|04|03|02|11
+		//                    --|--|14|13|--
+		// Corner (1, 1)
+		if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false)
+		{
+			float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));
+			float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;
+			blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|06|07|--|--
+		//                    18|05|00|01|--
+		//                    17|04|03|02|--
+		//                    --|15|14|--|--
+		// Corner (0, 1)
+		if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false)
+		{
+			float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));
+			float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;
+			blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|--|22|23|--
+		//                    --|06|07|08|09
+		//                    --|05|00|01|10
+		//                    --|--|03|02|--
+		//                    --|--|--|--|--
+		// Corner (1, 0)
+		if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false)
+		{
+			float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));
+			float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;
+			blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|21|22|--|--
+		//                    19|06|07|08|--
+		//                    18|05|00|01|--
+		//                    --|04|03|--|--
+		//                    --|--|--|--|--
+		// Corner (0, 0)
+		if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false)
+		{
+			float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));
+			float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;
+			blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		vec3 dst[25];
+		dst[ 0] = src[0];
+		dst[ 1] = src[0];
+		dst[ 2] = src[0];
+		dst[ 3] = src[0];
+		dst[ 4] = src[0];
+		dst[ 5] = src[0];
+		dst[ 6] = src[0];
+		dst[ 7] = src[0];
+		dst[ 8] = src[0];
+		dst[ 9] = src[0];
+		dst[10] = src[0];
+		dst[11] = src[0];
+		dst[12] = src[0];
+		dst[13] = src[0];
+		dst[14] = src[0];
+		dst[15] = src[0];
+		dst[16] = src[0];
+		dst[17] = src[0];
+		dst[18] = src[0];
+		dst[19] = src[0];
+		dst[20] = src[0];
+		dst[21] = src[0];
+		dst[22] = src[0];
+		dst[23] = src[0];
+		dst[24] = src[0];
+		
+		// Scale pixel
+		if (IsBlendingNeeded(blendResult) == true)
+		{
+			float dist_01_04 = DistYCbCr(src[1], src[4]);
+			float dist_03_08 = DistYCbCr(src[3], src[8]);
+			bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);
+			bool haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);
+			bool needBlend = (blendResult[2] != BLEND_NONE);
+			bool doLineBlend = (  blendResult[2] >= BLEND_DOMINANT ||
+							   ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+								 (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+								 (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false );
+			
+			vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];
+			dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);
+			dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);
+			dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);
+			dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);
+			dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[16] = mix(dst[16], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[24] = mix(dst[24], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			
+			dist_01_04 = DistYCbCr(src[7], src[2]);
+			dist_03_08 = DistYCbCr(src[1], src[6]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);
+			needBlend = (blendResult[1] != BLEND_NONE);
+			doLineBlend = (  blendResult[1] >= BLEND_DOMINANT ||
+						  !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);
+			dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[21] = mix(dst[21], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[22] = mix(dst[22], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);
+			dst[23] = mix(dst[23], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[24] = mix(dst[24], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);
+			dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+
+			dist_01_04 = DistYCbCr(src[5], src[8]);
+			dist_03_08 = DistYCbCr(src[7], src[4]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);
+			needBlend = (blendResult[0] != BLEND_NONE);
+			doLineBlend = (  blendResult[0] >= BLEND_DOMINANT ||
+						  !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+							(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+							(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[17] = mix(dst[17], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[18] = mix(dst[18], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);
+			dst[19] = mix(dst[19], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);
+			dst[21] = mix(dst[21], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[22] = mix(dst[22], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);
+			dst[23] = mix(dst[23], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[24] = mix(dst[24], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[16] = mix(dst[16], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			
+			
+			dist_01_04 = DistYCbCr(src[3], src[6]);
+			dist_03_08 = DistYCbCr(src[5], src[2]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);
+			needBlend = (blendResult[3] != BLEND_NONE);
+			doLineBlend = (  blendResult[3] >= BLEND_DOMINANT ||
+						  !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];
+			dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);
+			dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[16] = mix(dst[16], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);
+			dst[17] = mix(dst[17], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);
+			dst[18] = mix(dst[18], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);
+			dst[19] = mix(dst[19], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);			
+		}
+		
+		vec3 res = mix(           mix( dst[20], mix( mix(dst[21], dst[22], step(0.40, f.x)), mix(dst[23], dst[24], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),
+		                        mix( mix( mix( dst[19], mix( mix(dst[ 6], dst[ 7], step(0.40, f.x)), mix(dst[ 8], dst[ 9], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),
+		                                  mix( dst[18], mix( mix(dst[ 5], dst[ 0], step(0.40, f.x)), mix(dst[ 1], dst[10], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ), step(0.40, f.y)),
+		                             mix( mix( dst[17], mix( mix(dst[ 4], dst[ 3], step(0.40, f.x)), mix(dst[ 2], dst[11], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),
+		                                  mix( dst[16], mix( mix(dst[15], dst[14], step(0.40, f.x)), mix(dst[13], dst[12], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ), step(0.80, f.y)),
+		                                                                                                                                                                          step(0.60, f.y)),
+		                                                                                                                                                                          step(0.20, f.y));
+								 
+   FragColor = vec4(res, 1.0);
+} 
+#endif
diff --git a/base/xbrz/shaders/6xbrz.glsl b/base/xbrz/shaders/6xbrz.glsl
new file mode 100644
index 0000000..21ab078
--- /dev/null
+++ b/base/xbrz/shaders/6xbrz.glsl
@@ -0,0 +1,492 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#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
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy;
+	vec2 ps = vec2(SourceSize.z, SourceSize.w);
+	float dx = ps.x;
+	float dy = ps.y;
+
+	 //  A1 B1 C1
+	// A0 A  B  C C4
+	// D0 D  E  F F4
+	// G0 G  H  I I4
+	 //  G5 H5 I5
+
+	t1 = vTexCoord.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
+	t2 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, -dy);    //  A  B  C
+	t3 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 0.0);    //  D  E  F
+	t4 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, dy);     //  G  H  I
+	t5 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 2.0*dy); // G5 H5 I5
+	t6 = vTexCoord.xyyy + vec4(-2.0*dx,-dy, 0.0, dy);  // A0 D0 G0
+	t7 = vTexCoord.xyyy + vec4( 2.0*dx,-dy, 0.0, dy);  // C4 F4 I4
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+COMPAT_VARYING vec4 t7;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+	const float  one_sixth = 1.0 / 6.0;
+	const float  two_sixth = 2.0 / 6.0;
+	const float four_sixth = 4.0 / 6.0;
+	const float five_sixth = 5.0 / 6.0;
+
+	float reduce(const vec3 color)
+	{
+		return dot(color, vec3(65536.0, 256.0, 1.0));
+	}
+	
+	float DistYCbCr(const vec3 pixA, const 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, 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);
+	}
+	
+	bool IsBlendingNeeded(const ivec4 blend)
+	{
+		return any(notEqual(blend, ivec4(BLEND_NONE)));
+	}
+	
+	//---------------------------------------
+	// Input Pixel Mapping:    --|21|22|23|--
+	//                         19|06|07|08|09
+	//                         18|05|00|01|10
+	//                         17|04|03|02|11
+	//                         --|15|14|13|--
+	//
+	// Output Pixel Mapping: 20|21|22|23|24|25
+	//                       19|06|07|08|09|26
+	//                       18|05|00|01|10|27
+	//                       17|04|03|02|11|28
+	//                       16|15|14|13|12|29
+	//                       35|34|33|32|31|30
+
+void main()
+{
+vec2 f = fract(vTexCoord.xy * SourceSize.xy);
+
+	//---------------------------------------
+	// Input Pixel Mapping:  20|21|22|23|24
+	//                       19|06|07|08|09
+	//                       18|05|00|01|10
+	//                       17|04|03|02|11
+	//                       16|15|14|13|12
+  
+	vec3 src[25];
+  
+	src[21] = COMPAT_TEXTURE(Source, t1.xw).rgb;
+	src[22] = COMPAT_TEXTURE(Source, t1.yw).rgb;
+	src[23] = COMPAT_TEXTURE(Source, t1.zw).rgb;
+	src[ 6] = COMPAT_TEXTURE(Source, t2.xw).rgb;
+	src[ 7] = COMPAT_TEXTURE(Source, t2.yw).rgb;
+	src[ 8] = COMPAT_TEXTURE(Source, t2.zw).rgb;
+	src[ 5] = COMPAT_TEXTURE(Source, t3.xw).rgb;
+	src[ 0] = COMPAT_TEXTURE(Source, t3.yw).rgb;
+	src[ 1] = COMPAT_TEXTURE(Source, t3.zw).rgb;
+	src[ 4] = COMPAT_TEXTURE(Source, t4.xw).rgb;
+	src[ 3] = COMPAT_TEXTURE(Source, t4.yw).rgb;
+	src[ 2] = COMPAT_TEXTURE(Source, t4.zw).rgb;
+	src[15] = COMPAT_TEXTURE(Source, t5.xw).rgb;
+	src[14] = COMPAT_TEXTURE(Source, t5.yw).rgb;
+	src[13] = COMPAT_TEXTURE(Source, t5.zw).rgb;
+	src[19] = COMPAT_TEXTURE(Source, t6.xy).rgb;
+	src[18] = COMPAT_TEXTURE(Source, t6.xz).rgb;
+	src[17] = COMPAT_TEXTURE(Source, t6.xw).rgb;
+	src[ 9] = COMPAT_TEXTURE(Source, t7.xy).rgb;
+	src[10] = COMPAT_TEXTURE(Source, t7.xz).rgb;
+	src[11] = COMPAT_TEXTURE(Source, t7.xw).rgb;
+	
+		float v[9];
+		v[0] = reduce(src[0]);
+		v[1] = reduce(src[1]);
+		v[2] = reduce(src[2]);
+		v[3] = reduce(src[3]);
+		v[4] = reduce(src[4]);
+		v[5] = reduce(src[5]);
+		v[6] = reduce(src[6]);
+		v[7] = reduce(src[7]);
+		v[8] = reduce(src[8]);
+		
+		ivec4 blendResult = ivec4(BLEND_NONE);
+		
+		// Preprocess corners
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|--|07|08|--
+		//                    --|05|00|01|10
+		//                    --|04|03|02|11
+		//                    --|--|14|13|--
+		// Corner (1, 1)
+		if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false)
+		{
+			float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));
+			float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;
+			blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+
+		// Pixel Tap Mapping: --|--|--|--|--
+		//                    --|06|07|--|--
+		//                    18|05|00|01|--
+		//                    17|04|03|02|--
+		//                    --|15|14|--|--
+		// Corner (0, 1)
+		if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false)
+		{
+			float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));
+			float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;
+			blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|--|22|23|--
+		//                    --|06|07|08|09
+		//                    --|05|00|01|10
+		//                    --|--|03|02|--
+		//                    --|--|--|--|--
+		// Corner (1, 0)
+		if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false)
+		{
+			float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));
+			float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;
+			blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		// Pixel Tap Mapping: --|21|22|--|--
+		//                    19|06|07|08|--
+		//                    18|05|00|01|--
+		//                    --|04|03|--|--
+		//                    --|--|--|--|--
+		// Corner (0, 0)
+		if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false)
+		{
+			float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));
+			float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));
+			bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;
+			blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
+		}
+		
+		vec3 dst[36];
+		dst[ 0] = src[0];
+		dst[ 1] = src[0];
+		dst[ 2] = src[0];
+		dst[ 3] = src[0];
+		dst[ 4] = src[0];
+		dst[ 5] = src[0];
+		dst[ 6] = src[0];
+		dst[ 7] = src[0];
+		dst[ 8] = src[0];
+		dst[ 9] = src[0];
+		dst[10] = src[0];
+		dst[11] = src[0];
+		dst[12] = src[0];
+		dst[13] = src[0];
+		dst[14] = src[0];
+		dst[15] = src[0];
+		dst[16] = src[0];
+		dst[17] = src[0];
+		dst[18] = src[0];
+		dst[19] = src[0];
+		dst[20] = src[0];
+		dst[21] = src[0];
+		dst[22] = src[0];
+		dst[23] = src[0];
+		dst[24] = src[0];
+		dst[25] = src[0];
+		dst[26] = src[0];
+		dst[27] = src[0];
+		dst[28] = src[0];
+		dst[29] = src[0];
+		dst[30] = src[0];
+		dst[31] = src[0];
+		dst[32] = src[0];
+		dst[33] = src[0];
+		dst[34] = src[0];
+		dst[35] = src[0];
+		
+		// Scale pixel
+		if (IsBlendingNeeded(blendResult) == true)
+		{
+			float dist_01_04 = DistYCbCr(src[1], src[4]);
+			float dist_03_08 = DistYCbCr(src[3], src[8]);
+			bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);
+			bool haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);
+			bool needBlend = (blendResult[2] != BLEND_NONE);
+			bool doLineBlend = (  blendResult[2] >= BLEND_DOMINANT ||
+							   ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+								 (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+								 (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false );
+			
+			vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];
+			dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);
+			dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.500 : 1.000) : 0.000);
+			dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.000)) : 0.000);
+			dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[25] = mix(dst[25], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[26] = mix(dst[26], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[27] = mix(dst[27], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 1.000 : 0.000);
+			dst[28] = mix(dst[28], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[29] = mix(dst[29], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[30] = mix(dst[30], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.9711013910) : 0.000);
+			dst[31] = mix(dst[31], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[32] = mix(dst[32], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[33] = mix(dst[33], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 1.000 : 0.000);
+			dst[34] = mix(dst[34], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[35] = mix(dst[35], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			
+			dist_01_04 = DistYCbCr(src[7], src[2]);
+			dist_03_08 = DistYCbCr(src[1], src[6]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);
+			needBlend = (blendResult[1] != BLEND_NONE);
+			doLineBlend = (  blendResult[1] >= BLEND_DOMINANT ||
+						  !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );
+		
+			dist_01_04 = DistYCbCr(src[7], src[2]);
+			dist_03_08 = DistYCbCr(src[1], src[6]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);
+			needBlend = (blendResult[1] != BLEND_NONE);
+			doLineBlend = (  blendResult[1] >= BLEND_DOMINANT ||
+						  !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);
+			dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.500 : 1.000) : 0.000);
+			dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.000)) : 0.000);
+			dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[21] = mix(dst[21], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[22] = mix(dst[22], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 1.000 : 0.000);
+			dst[23] = mix(dst[23], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[24] = mix(dst[24], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[25] = mix(dst[25], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.9711013910) : 0.000);
+			dst[26] = mix(dst[26], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[27] = mix(dst[27], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[28] = mix(dst[28], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 1.000 : 0.000);
+			dst[29] = mix(dst[29], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[30] = mix(dst[30], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+
+			dist_01_04 = DistYCbCr(src[5], src[8]);
+			dist_03_08 = DistYCbCr(src[7], src[4]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);
+			needBlend = (blendResult[0] != BLEND_NONE);
+			doLineBlend = (  blendResult[0] >= BLEND_DOMINANT ||
+						  !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||
+							(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||
+							(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];
+			dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);
+			dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.500 : 1.000) : 0.000);
+			dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.000)) : 0.000);
+			dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[35] = mix(dst[35], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[16] = mix(dst[16], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[17] = mix(dst[17], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 1.000 : 0.000);
+			dst[18] = mix(dst[18], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[19] = mix(dst[19], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.9711013910) : 0.000);
+			dst[21] = mix(dst[21], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[22] = mix(dst[22], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[23] = mix(dst[23], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 1.000 : 0.000);
+			dst[24] = mix(dst[24], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[25] = mix(dst[25], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			
+			
+			dist_01_04 = DistYCbCr(src[3], src[6]);
+			dist_03_08 = DistYCbCr(src[5], src[2]);
+			haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);
+			haveSteepLine   = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);
+			needBlend = (blendResult[3] != BLEND_NONE);
+			doLineBlend = (  blendResult[3] >= BLEND_DOMINANT ||
+						  !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||
+							(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||
+							(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );
+			
+			blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];
+			dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);
+			dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.500 : 1.000) : 0.000);
+			dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.000)) : 0.000);
+			dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			dst[30] = mix(dst[30], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);
+			dst[31] = mix(dst[31], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.750 : 0.000);
+			dst[32] = mix(dst[32], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 1.000 : 0.000);
+			dst[33] = mix(dst[33], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[34] = mix(dst[34], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[35] = mix(dst[35], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.9711013910) : 0.000);
+			dst[16] = mix(dst[16], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.4236372243) : 0.000);
+			dst[17] = mix(dst[17], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.750 : 0.500)) : 0.05652034508) : 0.000);
+			dst[18] = mix(dst[18], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 1.000 : 0.000);
+			dst[19] = mix(dst[19], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);
+			dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);
+			
+		}
+		
+			vec3 res = mix( mix( mix( mix( mix( mix(dst[20], dst[21], step(one_sixth, f.x) ), dst[22], step(two_sixth, f.x) ), mix( mix(dst[23], dst[24], step(four_sixth, f.x) ), dst[25], step(five_sixth, f.x) ), step(0.50, f.x) ),
+		                                  mix( mix( mix(dst[19], dst[ 6], step(one_sixth, f.x) ), dst[ 7], step(two_sixth, f.x) ), mix( mix(dst[ 8], dst[ 9], step(four_sixth, f.x) ), dst[26], step(five_sixth, f.x) ), step(0.50, f.x) ), step(one_sixth, f.y) ),
+		                                  mix( mix( mix(dst[18], dst[ 5], step(one_sixth, f.x) ), dst[ 0], step(two_sixth, f.x) ), mix( mix(dst[ 1], dst[10], step(four_sixth, f.x) ), dst[27], step(five_sixth, f.x) ), step(0.50, f.x) ), step(two_sixth, f.y) ),
+		                        mix( mix( mix( mix( mix(dst[17], dst[ 4], step(one_sixth, f.x) ), dst[ 3], step(two_sixth, f.x) ), mix( mix(dst[ 2], dst[11], step(four_sixth, f.x) ), dst[28], step(five_sixth, f.x) ), step(0.50, f.x) ),
+		                                  mix( mix( mix(dst[16], dst[15], step(one_sixth, f.x) ), dst[14], step(two_sixth, f.x) ), mix( mix(dst[13], dst[12], step(four_sixth, f.x) ), dst[29], step(five_sixth, f.x) ), step(0.50, f.x) ), step(four_sixth, f.y) ),
+		                                  mix( mix( mix(dst[35], dst[34], step(one_sixth, f.x) ), dst[33], step(two_sixth, f.x) ), mix( mix(dst[32], dst[31], step(four_sixth, f.x) ), dst[30], step(five_sixth, f.x) ), step(0.50, f.x) ), step(five_sixth, f.y) ),
+		                     step(0.50, f.y) );
+								 
+   FragColor = vec4(res, 1.0);
+} 
+#endif
diff --git a/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass0.glsl b/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass0.glsl
new file mode 100644
index 0000000..5a01406
--- /dev/null
+++ b/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass0.glsl
@@ -0,0 +1,337 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy * 1.0001;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+// in variables go here as COMPAT_VARYING whatever
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+#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) COMPAT_TEXTURE(Source, coord + SourceSize.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(vTexCoord * SourceSize.xy) - vec2(0.5, 0.5);
+  vec2 coord = vTexCoord - pos * SourceSize.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;
+} 
+#endif
diff --git a/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass1.glsl b/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass1.glsl
new file mode 100644
index 0000000..0001c2d
--- /dev/null
+++ b/base/xbrz/shaders/xbrz-freescale-multipass/xbrz-freescale-pass1.glsl
@@ -0,0 +1,277 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy * 1.0001;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+uniform sampler2D PassPrev2Texture;
+uniform COMPAT_PRECISION vec2 PassPrev2TextureSize;
+COMPAT_VARYING vec4 TEX0;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+#define OriginalSize vec4(PassPrev2TextureSize, 1.0 / PassPrev2TextureSize)
+
+#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) COMPAT_TEXTURE(PassPrev2Texture, coord + OriginalSize.zw * vec2(x, y)).rgb
+
+void main()
+{
+  //---------------------------------------
+  // Input Pixel Mapping: -|B|-
+  //                      D|E|F
+  //                      -|H|-
+
+  vec2 scale = OutputSize.xy * OriginalSize.zw;
+  vec2 pos = fract(vTexCoord * OriginalSize.xy) - vec2(0.5, 0.5);
+  vec2 coord = vTexCoord - pos * OriginalSize.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(COMPAT_TEXTURE(Source, 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);
+} 
+#endif
diff --git a/base/xbrz/shaders/xbrz-freescale.glsl b/base/xbrz/shaders/xbrz-freescale.glsl
new file mode 100644
index 0000000..3cc9edd
--- /dev/null
+++ b/base/xbrz/shaders/xbrz-freescale.glsl
@@ -0,0 +1,375 @@
+/*
+   Hyllian's xBR-vertex code and texel mapping
+   
+   Copyright (C) 2011/2016 Hyllian - sergiogdb at 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.
+
+*/ 
+
+// This shader also uses code and/or concepts from xBRZ as it appears
+// in the Desmume source code. The license for which is as follows:
+
+// ****************************************************************************
+// * This file is part of the HqMAME project. It is distributed under         *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0          *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved          *
+// *                                                                          *
+// * Additionally and as a special exception, the author gives permission     *
+// * to link the code of this program with the MAME library (or with modified *
+// * versions of MAME that use the same license as MAME), and distribute      *
+// * linked combinations including the two. You must obey the GNU General     *
+// * Public License in all respects for all of the code used other than MAME. *
+// * If you modify this file, you may extend this exception to your version   *
+// * of the file, but you are not obligated to do so. If you do not wish to   *
+// * do so, delete this exception statement from your version.                *
+// ****************************************************************************
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+vec4 _oPosition1; 
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float WHATEVER;
+#else
+#define WHATEVER 0.0
+#endif
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    TEX0.xy = TexCoord.xy * 1.0001;
+}
+
+#elif defined(FRAGMENT)
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out COMPAT_PRECISION vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define OutSize vec4(OutputSize, 1.0 / OutputSize)
+
+#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) COMPAT_TEXTURE(Source, coord + SourceSize.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 scale = OutputSize.xy * SourceSize.zw;
+  vec2 pos = fract(vTexCoord * SourceSize.xy) - vec2(0.5, 0.5);
+  vec2 coord = vTexCoord - pos * SourceSize.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;
+  }
+
+  vec3 res = E;
+
+  // Pixel Tap Mapping: -|-|-|-|-
+  //                    -|-|B|C|-
+  //                    -|D|E|F|x
+  //                    -|G|H|I|x
+  //                    -|-|x|x|-
+  if(blendResult.z != BLEND_NONE)
+  {
+    float dist_F_G = DistYCbCr(F, G);
+    float dist_H_C = DistYCbCr(H, C);
+    bool doLineBlend = (blendResult.z == BLEND_DOMINANT ||
+                !((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))));
+
+    vec2 origin = vec2(0.0, 1.0 / sqrt(2.0));
+    vec2 direction = vec2(1.0, -1.0);
+    if(doLineBlend)
+    {
+      bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && neq(E,G) && neq(D,G);
+      bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && neq(E,C) && neq(B,C);
+      origin = haveShallowLine? vec2(0.0, 0.25) : vec2(0.0, 0.5);
+      direction.x += haveShallowLine? 1.0: 0.0;
+      direction.y -= haveSteepLine? 1.0: 0.0;
+    }
+
+    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: -|-|-|-|-
+  //                    -|A|B|-|-
+  //                    x|D|E|F|-
+  //                    x|G|H|I|-
+  //                    -|x|x|-|-
+  if(blendResult.w != BLEND_NONE)
+  {
+    float dist_H_A = DistYCbCr(H, A);
+    float dist_D_I = DistYCbCr(D, I);
+    bool doLineBlend = (blendResult.w == BLEND_DOMINANT ||
+                !((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))));
+
+    vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0);
+    vec2 direction = vec2(1.0, 1.0);
+    if(doLineBlend)
+    {
+      bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && neq(E,A) && neq(B,A);
+      bool haveSteepLine  = (STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && neq(E,I) && neq(F,I);
+      origin = haveShallowLine? vec2(-0.25, 0.0) : vec2(-0.5, 0.0);
+      direction.y += haveShallowLine? 1.0: 0.0;
+      direction.x += haveSteepLine? 1.0: 0.0;
+    }
+    origin = origin;
+    direction = direction;
+
+    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: -|-|x|x|-
+  //                    -|A|B|C|x
+  //                    -|D|E|F|x
+  //                    -|-|H|I|-
+  //                    -|-|-|-|-
+  if(blendResult.y != BLEND_NONE)
+  {
+    float dist_B_I = DistYCbCr(B, I);
+    float dist_F_A = DistYCbCr(F, A);
+    bool doLineBlend = (blendResult.y == BLEND_DOMINANT ||
+                !((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))));
+
+    vec2 origin = vec2(1.0 / sqrt(2.0), 0.0);
+    vec2 direction = vec2(-1.0, -1.0);
+
+    if(doLineBlend)
+    {
+      bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && neq(E,I) && neq(H,I);
+      bool haveSteepLine  = (STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && neq(E,A) && neq(D,A);
+      origin = haveShallowLine? vec2(0.25, 0.0) : vec2(0.5, 0.0);
+      direction.y -= haveShallowLine? 1.0: 0.0;
+      direction.x -= haveSteepLine? 1.0: 0.0;
+    }
+
+    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: -|x|x|-|-
+  //                    x|A|B|C|-
+  //                    x|D|E|F|-
+  //                    -|G|H|-|-
+  //                    -|-|-|-|-
+  if(blendResult.x != BLEND_NONE)
+  {
+    float dist_D_C = DistYCbCr(D, C);
+    float dist_B_G = DistYCbCr(B, G);
+    bool doLineBlend = (blendResult.x == BLEND_DOMINANT ||
+                !((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))));
+
+    vec2 origin = vec2(0.0, -1.0 / sqrt(2.0));
+    vec2 direction = vec2(-1.0, 1.0);
+    if(doLineBlend)
+    {
+      bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && neq(E,C) && neq(F,C);
+      bool haveSteepLine  = (STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && neq(E,G) && neq(H,G);
+      origin = haveShallowLine? vec2(0.0, -0.25) : vec2(0.0, -0.5);
+      direction.x -= haveShallowLine? 1.0: 0.0;
+      direction.y += haveSteepLine? 1.0: 0.0;
+    }
+
+    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);
+} 
+#endif
diff --git a/base/xbrz/xbrz-freescale-multipass.glslp b/base/xbrz/xbrz-freescale-multipass.glslp
new file mode 100644
index 0000000..4361d52
--- /dev/null
+++ b/base/xbrz/xbrz-freescale-multipass.glslp
@@ -0,0 +1,11 @@
+shaders = 2
+
+shader0 = shaders/xbrz-freescale-multipass/xbrz-freescale-pass0.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 1.0
+
+shader1 = shaders/xbrz-freescale-multipass/xbrz-freescale-pass1.glsl
+filter_linear1 = false
+scale_type1 = viewport
+scale1 = 1.0
diff --git a/base/xbrz/xbrz-freescale.glslp b/base/xbrz/xbrz-freescale.glslp
new file mode 100644
index 0000000..b25eddb
--- /dev/null
+++ b/base/xbrz/xbrz-freescale.glslp
@@ -0,0 +1,6 @@
+shaders = 1
+
+shader0 = shaders/xbrz-freescale.glsl
+filter_linear0 = false
+scale_type0 = viewport
+scale0 = 1.0
diff --git a/base/xsal/2xsal-level2-crt.glslp b/base/xsal/2xsal-level2-crt.glslp
new file mode 100644
index 0000000..a0317a1
--- /dev/null
+++ b/base/xsal/2xsal-level2-crt.glslp
@@ -0,0 +1,15 @@
+shaders = 2
+
+shader0 = shaders/2xsal-level2.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 2.0
+
+shader1 = ../crt/shaders/dotmask.glsl
+filter_linear1 = true
+scale_type1 = viewport
+scale1 = 1.0
+
+parameters = "maskDark; maskLight"
+maskDark  = 0.6
+maskLight = 1.4
diff --git a/base/xsal/2xsal.glslp b/base/xsal/2xsal.glslp
new file mode 100644
index 0000000..2d8b35a
--- /dev/null
+++ b/base/xsal/2xsal.glslp
@@ -0,0 +1,10 @@
+shaders = 2
+
+shader0 = shaders/2xsal.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = ../stock.glsl
+filter_linear1 = true
diff --git a/base/xsal/4xsal-level2-crt.glslp b/base/xsal/4xsal-level2-crt.glslp
new file mode 100644
index 0000000..3422a0d
--- /dev/null
+++ b/base/xsal/4xsal-level2-crt.glslp
@@ -0,0 +1,20 @@
+shaders = 3
+
+shader0 = shaders/2xsal-level2.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
+
+shader1 = shaders/2xsal-level2-pass2.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+ 
+shader2 = ../crt/shaders/dotmask.glsl
+filter_linear2 = true
+scale_type2 = viewport
+scale2 = 1.0
+
+parameters = "maskDark; maskLight"
+maskDark  = 0.6
+maskLight = 1.4
diff --git a/base/xsal/4xsal-level2-hq.glslp b/base/xsal/4xsal-level2-hq.glslp
new file mode 100644
index 0000000..04bb108
--- /dev/null
+++ b/base/xsal/4xsal-level2-hq.glslp
@@ -0,0 +1,14 @@
+shaders = 3
+
+shader0 = shaders/2xsal-level2-hq.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
+
+shader1 = shaders/2xsal-level2-pass2.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+
+shader2 = ../stock.glsl
+filter_linear2 = true
diff --git a/base/xsal/4xsal-level2.glslp b/base/xsal/4xsal-level2.glslp
new file mode 100644
index 0000000..406aea0
--- /dev/null
+++ b/base/xsal/4xsal-level2.glslp
@@ -0,0 +1,14 @@
+shaders = 3
+
+shader0 = shaders/2xsal-level2.glsl
+filter_linear0 = false
+scale_type0 = source
+scale0 = 4.0
+
+shader1 = shaders/2xsal-level2-pass2.glsl
+filter_linear1 = false
+scale_type1 = source
+scale1 = 1.0
+
+shader2 = ../stock.glsl
+filter_linear2 = true
diff --git a/base/xsal/shaders/2xsal-level2-hq.glsl b/base/xsal/shaders/2xsal-level2-hq.glsl
new file mode 100644
index 0000000..9697ac7
--- /dev/null
+++ b/base/xsal/shaders/2xsal-level2-hq.glsl
@@ -0,0 +1,167 @@
+/*
+    Copyright (C) 2016 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy * 1.00001;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    //vec2  texsize = IN.texture_size;
+    float dx      = 0.25*SourceSize.z;
+    float dy      = 0.25*SourceSize.w;
+    vec3  dt      = vec3(1.0, 1.0, 1.0);
+
+    vec4 yx = vec4(  dx,   dy,   -dx,   -dy);
+    vec4 xh = vec4(3.*dx,   dy, -3.*dx,   -dy);
+    vec4 yv = vec4(  dx, 3.*dy,   -dx, -3.*dy);
+    vec4 ox = 2.*yx; 
+
+    vec3 c11 = COMPAT_TEXTURE(Source, vTexCoord        ).xyz;
+    vec3 s00 = COMPAT_TEXTURE(Source, vTexCoord + yx.zw).xyz;
+    vec3 s20 = COMPAT_TEXTURE(Source, vTexCoord + yx.xw).xyz;
+    vec3 s22 = COMPAT_TEXTURE(Source, vTexCoord + yx.xy).xyz;
+    vec3 s02 = COMPAT_TEXTURE(Source, vTexCoord + yx.zy).xyz;
+    vec3 h00 = COMPAT_TEXTURE(Source, vTexCoord + xh.zw).xyz;
+    vec3 h20 = COMPAT_TEXTURE(Source, vTexCoord + xh.xw).xyz;
+    vec3 h22 = COMPAT_TEXTURE(Source, vTexCoord + xh.xy).xyz;
+    vec3 h02 = COMPAT_TEXTURE(Source, vTexCoord + xh.zy).xyz;
+    vec3 v00 = COMPAT_TEXTURE(Source, vTexCoord + yv.zw).xyz;
+    vec3 v20 = COMPAT_TEXTURE(Source, vTexCoord + yv.xw).xyz;
+    vec3 v22 = COMPAT_TEXTURE(Source, vTexCoord + yv.xy).xyz;
+    vec3 v02 = COMPAT_TEXTURE(Source, vTexCoord + yv.zy).xyz;
+    vec3 o00 = COMPAT_TEXTURE(Source, vTexCoord + ox.zw).xyz;
+    vec3 o20 = COMPAT_TEXTURE(Source, vTexCoord + ox.xw).xyz;
+    vec3 o22 = COMPAT_TEXTURE(Source, vTexCoord + ox.xy).xyz;
+    vec3 o02 = COMPAT_TEXTURE(Source, vTexCoord + ox.zy).xyz;
+
+    float m1 = 1.0/(dot(abs(s00 - s22), dt) + 0.00001);
+    float m2 = 1.0/(dot(abs(s02 - s20), dt) + 0.00001);
+    float h1 = 1.0/(dot(abs(s00 - h22), dt) + 0.00001);
+    float h2 = 1.0/(dot(abs(s02 - h20), dt) + 0.00001);
+    float h3 = 1.0/(dot(abs(h00 - s22), dt) + 0.00001);
+    float h4 = 1.0/(dot(abs(h02 - s20), dt) + 0.00001);
+    float v1 = 1.0/(dot(abs(s00 - v22), dt) + 0.00001);
+    float v2 = 1.0/(dot(abs(s02 - v20), dt) + 0.00001);
+    float v3 = 1.0/(dot(abs(v00 - s22), dt) + 0.00001);
+    float v4 = 1.0/(dot(abs(v02 - s20), dt) + 0.00001);
+
+    vec3 t1 = 0.5*(m1*(s00 + s22) + m2*(s02 + s20))/(m1 + m2);
+    vec3 t2 = 0.5*(h1*(s00 + h22) + h2*(s02 + h20) + h3*(h00 + s22) + h4*(h02 + s20))/(h1 + h2 + h3 + h4);
+    vec3 t3 = 0.5*(v1*(s00 + v22) + v2*(s02 + v20) + v3*(v00 + s22) + v4*(v02 + s20))/(v1 + v2 + v3 + v4);
+
+    float k00 = dot(abs(o00 - c11), dt) + 0.00001;
+    float k20 = dot(abs(o20 - c11), dt) + 0.00001;
+    float k22 = dot(abs(o22 - c11), dt) + 0.00001;
+    float k02 = dot(abs(o02 - c11), dt) + 0.00001;
+
+    float kr1 = min(dot(abs(s00 - s22), dt), dot(abs(o00 - o22), dt));
+    float kr2 = min(dot(abs(s02 - s20), dt), dot(abs(o20 - o02), dt));
+
+    float w1 = (k22 < k00) ? 0.0 : kr2;
+    float w2 = (k02 < k20) ? 0.0 : kr1;
+    float w3 = (k00 < k22) ? 0.0 : kr2;
+    float w4 = (k20 < k02) ? 0.0 : kr1; 
+
+    c11 = (w1*o00 + w2*o20 + w3*o22 + w4*o02 + 0.001*c11)/(w1 + w2 + w3 + w4 + 0.001);   
+
+    float k1 = 1.0/(dot(abs(t1 - c11), dt) + 0.00001);
+    float k2 = 1.0/(dot(abs(t2 - c11), dt) + 0.00001);
+    float k3 = 1.0/(dot(abs(t3 - c11), dt) + 0.00001);   
+
+
+    FragColor = vec4((k1*t1 + k2*t2 + k3*t3)/(k1 + k2 + k3), 1.0);
+} 
+#endif
diff --git a/base/xsal/shaders/2xsal-level2-pass2.glsl b/base/xsal/shaders/2xsal-level2-pass2.glsl
new file mode 100644
index 0000000..1dbdbe3
--- /dev/null
+++ b/base/xsal/shaders/2xsal-level2-pass2.glsl
@@ -0,0 +1,122 @@
+/*
+    Copyright (C) 2016 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy * 1.00001;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    vec2 texsize = SourceSize.xy;
+    float dx     = pow(texsize.x, -1.0) * 0.5;
+    float dy     = pow(texsize.y, -1.0) * 0.5;
+    vec3  dt     = vec3(1.0, 1.0, 1.0);
+
+    vec2 UL =    vTexCoord + vec2(-dx, -dy);
+    vec2 UR =    vTexCoord + vec2( dx, -dy);
+    vec2 DL =    vTexCoord + vec2(-dx,  dy);
+    vec2 DR =    vTexCoord + vec2( dx,  dy);
+
+    vec3 c00 = COMPAT_TEXTURE(Source, UL).xyz;
+    vec3 c20 = COMPAT_TEXTURE(Source, UR).xyz;
+    vec3 c02 = COMPAT_TEXTURE(Source, DL).xyz;
+    vec3 c22 = COMPAT_TEXTURE(Source, DR).xyz;
+
+    float m1 = dot(abs(c00 - c22), dt) + 0.001;
+    float m2 = dot(abs(c02 - c20), dt) + 0.001;
+
+    FragColor = vec4((m1*(c02 + c20) + m2*(c22 + c00))/(2.0*(m1 + m2)), 1.0);
+} 
+#endif
diff --git a/base/xsal/shaders/2xsal-level2.glsl b/base/xsal/shaders/2xsal-level2.glsl
new file mode 100644
index 0000000..b8df492
--- /dev/null
+++ b/base/xsal/shaders/2xsal-level2.glsl
@@ -0,0 +1,149 @@
+/*
+    Copyright (C) 2016 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+// out variables go here as COMPAT_VARYING whatever
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy * 1.00001;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+// in variables go here as COMPAT_VARYING whatever
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    vec2 tex = vTexCoord;   
+    //vec2 texsize = IN.texture_size;
+    float dx = 0.25*SourceSize.z;
+    float dy = 0.25*SourceSize.w;
+    vec3  dt = vec3(1.0, 1.0, 1.0);
+
+    vec4 yx = vec4(dx, dy, -dx, -dy);
+    vec4 xh = yx*vec4(3.0, 1.0, 3.0, 1.0);
+    vec4 yv = yx*vec4(1.0, 3.0, 1.0, 3.0);
+
+    vec3 c11 = COMPAT_TEXTURE(Source, tex        ).xyz;    
+    vec3 s00 = COMPAT_TEXTURE(Source, tex + yx.zw).xyz; 
+    vec3 s20 = COMPAT_TEXTURE(Source, tex + yx.xw).xyz; 
+    vec3 s22 = COMPAT_TEXTURE(Source, tex + yx.xy).xyz; 
+    vec3 s02 = COMPAT_TEXTURE(Source, tex + yx.zy).xyz;
+    vec3 h00 = COMPAT_TEXTURE(Source, tex + xh.zw).xyz; 
+    vec3 h20 = COMPAT_TEXTURE(Source, tex + xh.xw).xyz; 
+    vec3 h22 = COMPAT_TEXTURE(Source, tex + xh.xy).xyz; 
+    vec3 h02 = COMPAT_TEXTURE(Source, tex + xh.zy).xyz;
+    vec3 v00 = COMPAT_TEXTURE(Source, tex + yv.zw).xyz; 
+    vec3 v20 = COMPAT_TEXTURE(Source, tex + yv.xw).xyz; 
+    vec3 v22 = COMPAT_TEXTURE(Source, tex + yv.xy).xyz; 
+    vec3 v02 = COMPAT_TEXTURE(Source, tex + yv.zy).xyz;     
+
+    float m1 = 1.0/(dot(abs(s00 - s22), dt) + 0.00001);
+    float m2 = 1.0/(dot(abs(s02 - s20), dt) + 0.00001);
+    float h1 = 1.0/(dot(abs(s00 - h22), dt) + 0.00001);
+    float h2 = 1.0/(dot(abs(s02 - h20), dt) + 0.00001);
+    float h3 = 1.0/(dot(abs(h00 - s22), dt) + 0.00001);
+    float h4 = 1.0/(dot(abs(h02 - s20), dt) + 0.00001);
+    float v1 = 1.0/(dot(abs(s00 - v22), dt) + 0.00001);
+    float v2 = 1.0/(dot(abs(s02 - v20), dt) + 0.00001);
+    float v3 = 1.0/(dot(abs(v00 - s22), dt) + 0.00001);
+    float v4 = 1.0/(dot(abs(v02 - s20), dt) + 0.00001);
+
+    vec3 t1 = 0.5*(m1*(s00 + s22) + m2*(s02 + s20))/(m1 + m2);
+    vec3 t2 = 0.5*(h1*(s00 + h22) + h2*(s02 + h20) + h3*(h00 + s22) + h4*(h02 + s20))/(h1 + h2 + h3 + h4);
+    vec3 t3 = 0.5*(v1*(s00 + v22) + v2*(s02 + v20) + v3*(v00 + s22) + v4*(v02 + s20))/(v1 + v2 + v3 + v4);
+
+    float k1 = 1.0/(dot(abs(t1 - c11), dt) + 0.00001);
+    float k2 = 1.0/(dot(abs(t2 - c11), dt) + 0.00001);
+    float k3 = 1.0/(dot(abs(t3 - c11), dt) + 0.00001);
+
+    FragColor = vec4((k1*t1 + k2*t2 + k3*t3)/(k1 + k2 + k3), 1.0);
+} 
+#endif
diff --git a/base/xsal/shaders/2xsal.glsl b/base/xsal/shaders/2xsal.glsl
new file mode 100644
index 0000000..44a426d
--- /dev/null
+++ b/base/xsal/shaders/2xsal.glsl
@@ -0,0 +1,125 @@
+/*
+    Copyright (C) 2007 guest(r) - guest.r at 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.
+*/
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    gl_Position = MVPMatrix * VertexCoord;
+    COL0 = COLOR;
+    TEX0.xy = TexCoord.xy * 1.00001;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+// in variables go here as COMPAT_VARYING whatever
+
+// fragment compatibility #defines
+#define Source Texture
+#define vTexCoord TEX0.xy
+
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+void main()
+{
+    vec2 texsize = SourceSize.xy;
+    float dx     = pow(texsize.x, -1.0) * 0.25;
+    float dy     = pow(texsize.y, -1.0) * 0.25;
+    vec3  dt     = vec3(1.0, 1.0, 1.0);
+
+     
+    vec2 UL =    vTexCoord + vec2(-dx, -dy);
+    vec2 UR =    vTexCoord + vec2( dx, -dy);
+    vec2 DL =    vTexCoord + vec2(-dx,  dy);
+    vec2 DR =    vTexCoord + vec2( dx,  dy);
+    
+
+    vec3 c00 = COMPAT_TEXTURE(Source, UL).xyz;
+    vec3 c20 = COMPAT_TEXTURE(Source, UR).xyz;
+    vec3 c02 = COMPAT_TEXTURE(Source, DL).xyz;
+    vec3 c22 = COMPAT_TEXTURE(Source, DR).xyz;
+
+    float m1 = dot(abs(c00 - c22), dt) + 0.001;
+    float m2 = dot(abs(c02 - c20), dt) + 0.001;
+
+    FragColor = vec4((m1*(c02 + c20) + m2*(c22 + c00))/(2.0*(m1 + m2)), 1.0);
+} 
+#endif
diff --git a/base/xsoft/4xsoft.glslp b/base/xsoft/4xsoft.glslp
new file mode 100644
index 0000000..8318c07
--- /dev/null
+++ b/base/xsoft/4xsoft.glslp
@@ -0,0 +1,16 @@
+shaders = 3
+
+shader0 = ../stock.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = shaders/4xsoft.glsl
+filter_linear1 = false
+scale_type1 = source
+scale_x1 = 2.0
+scale_y1 = 2.0
+
+shader2 = ../stock.glsl
+filter_linear2 = true
diff --git a/base/xsoft/4xsoftSdB.glslp b/base/xsoft/4xsoftSdB.glslp
new file mode 100644
index 0000000..9d5c3a2
--- /dev/null
+++ b/base/xsoft/4xsoftSdB.glslp
@@ -0,0 +1,16 @@
+shaders = 3
+
+shader0 = ../stock.glsl
+filter_linear0 = false
+scale_type0 = source
+scale_x0 = 2.0
+scale_y0 = 2.0
+
+shader1 = shaders/4xsoftSdB.glsl
+filter_linear1 = false
+scale_type1 = source
+scale_x1 = 2.0
+scale_y1 = 2.0
+
+shader2 = ../stock.glsl
+filter_linear2 = true
diff --git a/base/xsoft/shaders/4xsoft.glsl b/base/xsoft/shaders/4xsoft.glsl
new file mode 100644
index 0000000..c17148c
--- /dev/null
+++ b/base/xsoft/shaders/4xsoft.glsl
@@ -0,0 +1,189 @@
+/*
+   Copyright (C) 2007 guest(r) - guest.r at 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.
+
+*/
+
+/*
+
+   The 4xSoft shader processes a gfx. surface and redraws it 4x finer.
+   
+   Note: set scaler to normal2x.
+
+*/
+
+// Parameter lines go here:
+#pragma parameter RESOLUTION_X "4xSoft Input Resolution X" 0.0 0.0 1920.0 1.0
+#pragma parameter RESOLUTION_Y "4xSoft Input Resolution Y" 0.0 0.0 1920.0 1.0
+#pragma parameter CONTRAST     "4xSoft Contrast"           3.0 0.0 10.0 0.1
+
+#define RESOLUTION_X_DEF SourceSize.x
+#define RESOLUTION_Y_DEF SourceSize.y
+
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+COMPAT_VARYING vec4 t1;
+COMPAT_VARYING vec4 t2;
+COMPAT_VARYING vec4 t3;
+COMPAT_VARYING vec4 t4;
+COMPAT_VARYING vec4 t5;
+COMPAT_VARYING vec4 t6;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+// vertex compatibility #defines
+#define vTexCoord TEX0.xy
+#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
+#define outsize vec4(OutputSize, 1.0 / OutputSize)
+
+#ifdef PARAMETER_UNIFORM
+uniform COMPAT_PRECISION float RESOLUTION_X;
+uniform COMPAT_PRECISION float RESOLUTION_Y;
+uniform COMPAT_PRECISION float CONTRAST;
+#else
+#define RESOLUTION_X 0.0
+#define RESOLUTION_Y 0.0
+#define CONTRAST 3.0
+#endif
+
+void main()




More information about the Scummvm-git-logs mailing list