From 27b36311a1e5919e27e47351e059b293398fa5b8 Mon Sep 17 00:00:00 2001 From: hunterk Date: Thu, 2 Mar 2017 13:37:31 -0600 Subject: [PATCH] update scalefx shaders --- scalefx/scalefx-hybrid.slangp | 31 +++ scalefx/scalefx.slangp | 19 +- scalefx/shaders/old/scalefx-9x-old.slangp | 49 +++++ scalefx/shaders/old/scalefx-old.slangp | 21 ++ scalefx/shaders/old/scalefx-pass0.slang | 104 +++++++++ scalefx/shaders/old/scalefx-pass1.slang | 199 ++++++++++++++++++ scalefx/shaders/old/scalefx-pass2.slang | 171 +++++++++++++++ scalefx/shaders/old/scalefx-pass3.slang | 114 ++++++++++ scalefx/shaders/{ => old}/scalefx-pass7.slang | 0 scalefx/shaders/scalefx-pass0.slang | 47 +++-- scalefx/shaders/scalefx-pass1.slang | 138 +++--------- scalefx/shaders/scalefx-pass2.slang | 162 +++++++------- scalefx/shaders/scalefx-pass3.slang | 119 ++++++++--- scalefx/shaders/scalefx-pass4-hybrid.slang | 159 ++++++++++++++ scalefx/shaders/scalefx-pass4.slang | 114 ++++++++++ 15 files changed, 1195 insertions(+), 252 deletions(-) create mode 100644 scalefx/scalefx-hybrid.slangp create mode 100644 scalefx/shaders/old/scalefx-9x-old.slangp create mode 100644 scalefx/shaders/old/scalefx-old.slangp create mode 100644 scalefx/shaders/old/scalefx-pass0.slang create mode 100644 scalefx/shaders/old/scalefx-pass1.slang create mode 100644 scalefx/shaders/old/scalefx-pass2.slang create mode 100644 scalefx/shaders/old/scalefx-pass3.slang rename scalefx/shaders/{ => old}/scalefx-pass7.slang (100%) create mode 100644 scalefx/shaders/scalefx-pass4-hybrid.slang create mode 100644 scalefx/shaders/scalefx-pass4.slang diff --git a/scalefx/scalefx-hybrid.slangp b/scalefx/scalefx-hybrid.slangp new file mode 100644 index 0000000..bd32ea3 --- /dev/null +++ b/scalefx/scalefx-hybrid.slangp @@ -0,0 +1,31 @@ +shaders = 5 + +shader0 = shaders\scalefx-pass0.slang +filter_linear0 = false +scale_type0 = source +scale0 = 1.0 +float_framebuffer0 = true + +shader1 = shaders\scalefx-pass1.slang +filter_linear1 = false +scale_type1 = source +scale1 = 1.0 +float_framebuffer1 = true + +shader2 = shaders\scalefx-pass2.slang +filter_linear2 = false +scale_type2 = source +scale2 = 1.0 + +shader3 = shaders\scalefx-pass3.slang +filter_linear3 = false +scale_type3 = source +scale3 = 1.0 + +shader4 = shaders\scalefx-pass4-hybrid.slang +filter_linear4 = false +scale_type4 = source +scale4 = 3.0 + +parameters = "SFX_SAA" +SFX_SAA = "0.0" diff --git a/scalefx/scalefx.slangp b/scalefx/scalefx.slangp index 9e2b6b6..107b2e7 100644 --- a/scalefx/scalefx.slangp +++ b/scalefx/scalefx.slangp @@ -1,21 +1,28 @@ -shaders = 4 +shaders = 5 -shader0 = shaders/scalefx-pass0.slang +shader0 = shaders\scalefx-pass0.slang filter_linear0 = false scale_type0 = source scale0 = 1.0 +float_framebuffer0 = true -shader1 = shaders/scalefx-pass1.slang +shader1 = shaders\scalefx-pass1.slang filter_linear1 = false scale_type1 = source scale1 = 1.0 +float_framebuffer1 = true -shader2 = shaders/scalefx-pass2.slang +shader2 = shaders\scalefx-pass2.slang filter_linear2 = false scale_type2 = source scale2 = 1.0 -shader3 = shaders/scalefx-pass3.slang +shader3 = shaders\scalefx-pass3.slang filter_linear3 = false scale_type3 = source -scale3 = 3.0 +scale3 = 1.0 + +shader4 = shaders\scalefx-pass4.slang +filter_linear4 = false +scale_type4 = source +scale4 = 3.0 diff --git a/scalefx/shaders/old/scalefx-9x-old.slangp b/scalefx/shaders/old/scalefx-9x-old.slangp new file mode 100644 index 0000000..a97f1bc --- /dev/null +++ b/scalefx/shaders/old/scalefx-9x-old.slangp @@ -0,0 +1,49 @@ +shaders = 8 + +shader0 = scalefx-pass0.slang +filter_linear0 = false +scale_type0 = source +scale0 = 1.0 +alias0 = sfxp0 + +shader1 = scalefx-pass1.slang +filter_linear1 = false +scale_type1 = source +scale1 = 1.0 +alias1 = sfxp1 + +shader2 = scalefx-pass2.slang +filter_linear2 = false +scale_type2 = source +scale2 = 1.0 +alias2 = sfxp2 + +shader3 = scalefx-pass3.slang +filter_linear3 = false +scale_type3 = source +scale3 = 3.0 +alias3 = sfxp3 + +shader4 = scalefx-pass0.slang +filter_linear4 = false +scale_type4 = source +scale4 = 1.0 +alias4 = sfxp4 + +shader5 = scalefx-pass1.slang +filter_linear5 = false +scale_type5 = source +scale5 = 1.0 +alias5 = sfxp5 + +shader6 = scalefx-pass2.slang +filter_linear6 = false +scale_type6 = source +scale6 = 1.0 +alias6 = sfxp6 + +shader7 = scalefx-pass7.slang +filter_linear7 = false +scale_type7 = source +scale7 = 3.0 +alias7 = sfxp7 diff --git a/scalefx/shaders/old/scalefx-old.slangp b/scalefx/shaders/old/scalefx-old.slangp new file mode 100644 index 0000000..b407032 --- /dev/null +++ b/scalefx/shaders/old/scalefx-old.slangp @@ -0,0 +1,21 @@ +shaders = 4 + +shader0 = scalefx-pass0.slang +filter_linear0 = false +scale_type0 = source +scale0 = 1.0 + +shader1 = scalefx-pass1.slang +filter_linear1 = false +scale_type1 = source +scale1 = 1.0 + +shader2 = scalefx-pass2.slang +filter_linear2 = false +scale_type2 = source +scale2 = 1.0 + +shader3 = scalefx-pass3.slang +filter_linear3 = false +scale_type3 = source +scale3 = 3.0 diff --git a/scalefx/shaders/old/scalefx-pass0.slang b/scalefx/shaders/old/scalefx-pass0.slang new file mode 100644 index 0000000..b4a07e4 --- /dev/null +++ b/scalefx/shaders/old/scalefx-pass0.slang @@ -0,0 +1,104 @@ +#version 450 + +/* + ScaleFX - Pass 0 + by Sp00kyFox, 2016-03-30 + +Filter: Nearest +Scale: 1x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 0 prepares metric data for the next pass. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#pragma name sfxp0 + + +// Reference: http://www.compuphase.com/cmetric.htm +float eq(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 1 - sqrt(dot(c*d, d)) / 3; +} + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; +}; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; + + +#define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) + +void main() +{ + + /* grid metric + + A B C x y z + E F o w + */ + + + // read texels + vec3 A = TEX(-1,-1).rgb; + vec3 B = TEX( 0,-1).rgb; + vec3 C = TEX( 1,-1).rgb; + vec3 E = TEX( 0, 0).rgb; + vec3 F = TEX( 1, 0).rgb; + + // output + FragColor = vec4(eq(E,A), eq(E,B), eq(E,C), eq(E,F)); +} diff --git a/scalefx/shaders/old/scalefx-pass1.slang b/scalefx/shaders/old/scalefx-pass1.slang new file mode 100644 index 0000000..dc3c722 --- /dev/null +++ b/scalefx/shaders/old/scalefx-pass1.slang @@ -0,0 +1,199 @@ +#version 450 + +/* + ScaleFX - Pass 1 + by Sp00kyFox, 2016-03-30 + +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 resolves ambiguous configurations of corner candidates at pixel junctions. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#pragma name sfxp1 +#pragma parameter SFX_CLR "ScaleFX Color Thresh" 0.35 0.0 1.00 0.01 + +#ifdef PARAMETER_UNIFORM + uniform float SFX_CLR; +#else + #define SFX_CLR 0.35 +#endif + +const float THR = 1.0 - SFX_CLR; + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; +}; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; + + +#define LE(x, y) (1.0 - step(y, x)) +#define GE(x, y) (1.0 - step(x, y)) +#define LEQ(x, y) step(x, y) +#define GEQ(x, y) step(y, x) +#define NOT(x) (1.0 - (x)) + + +// corner strength +vec4 str(vec4 crn, vec4 ort){ + //return (crn > THR) ? max(2.0*crn - (ort + ort.wxyz), 0.0) : 0.0; + return GE(crn, vec4(THR)) * max(2.0*crn - (ort + ort.wxyz), vec4(0.0)); +} + +// corner dominance at junctions +vec4 dom(vec3 strx, vec3 stry, vec3 strz, vec3 strw){ + vec4 res; + res.x = max(2.0*strx.y - (strx.x + strx.z), 0.0); + res.y = max(2.0*stry.y - (stry.x + stry.z), 0.0); + res.z = max(2.0*strz.y - (strz.x + strz.z), 0.0); + res.w = max(2.0*strw.y - (strw.x + strw.z), 0.0); + return res; +} + +// necessary but not sufficient junction condition for orthogonal edges +float clear(vec2 crn, vec4 ort){ + //return all(crn.xyxy <= THR || crn.xyxy <= ort || crn.xyxy <= ort.wxyz); + vec4 res = LEQ(crn.xyxy, vec4(THR)) + LEQ(crn.xyxy, ort) + LEQ(crn.xyxy, ort.wxyz); + return min(res.x * res.y * res.z * res.w, 1.0); +} + + +void main() +{ + + /* grid metric pattern + + M A B C P x y z x y + N D E F Q o w w z + O G H I R + J K L + */ + + +#define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) + + + // metric data + vec4 A = TEX(-1,-1), B = TEX( 0,-1), C = TEX( 1,-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); + vec4 J = TEX(-1, 2), K = TEX( 0, 2), L = TEX( 1, 2); + vec4 M = TEX(-2,-1), N = TEX(-2, 0), O = TEX(-2, 1); + vec4 P = TEX( 2,-1), Q = TEX( 2, 0), R = TEX( 2, 1); + + + // corner strength + vec4 As = str(vec4(M.z, B.x, D.zx), vec4(A.yw, D.y, M.w)); + vec4 Bs = str(vec4(A.z, C.x, E.zx), vec4(B.yw, E.y, A.w)); + vec4 Cs = str(vec4(B.z, P.x, F.zx), vec4(C.yw, F.y, B.w)); + vec4 Ds = str(vec4(N.z, E.x, G.zx), vec4(D.yw, G.y, N.w)); + vec4 Es = str(vec4(D.z, F.x, H.zx), vec4(E.yw, H.y, D.w)); + vec4 Fs = str(vec4(E.z, Q.x, I.zx), vec4(F.yw, I.y, E.w)); + vec4 Gs = str(vec4(O.z, H.x, J.zx), vec4(G.yw, J.y, O.w)); + vec4 Hs = str(vec4(G.z, I.x, K.zx), vec4(H.yw, K.y, G.w)); + vec4 Is = str(vec4(H.z, R.x, L.zx), vec4(I.yw, L.y, H.w)); + + // 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 + //bvec4 jx = jDx != 0.0 && jDx + jDx.zwxy > jDx.yzwx + jDx.wxyz; + //bvec4 jy = jDy != 0.0 && jDy + jDy.zwxy > jDy.yzwx + jDy.wxyz; + //bvec4 jz = jDz != 0.0 && jDz + jDz.zwxy > jDz.yzwx + jDz.wxyz; + //bvec4 jw = jDw != 0.0 && jDw + jDw.zwxy > jDw.yzwx + jDw.wxyz; + + vec4 jx = GE(jDx, vec4(0.0)) * GE(jDx + jDx.zwxy, jDx.yzwx + jDx.wxyz); + vec4 jy = GE(jDy, vec4(0.0)) * GE(jDy + jDy.zwxy, jDy.yzwx + jDy.wxyz); + vec4 jz = GE(jDz, vec4(0.0)) * GE(jDz + jDz.zwxy, jDz.yzwx + jDz.wxyz); + vec4 jw = GE(jDw, vec4(0.0)) * GE(jDw + jDw.zwxy, jDw.yzwx + jDw.wxyz); + + // inject strength without creating new contradictions + //bvec4 res; + //res.x = jx.z || !(jx.y || jx.w) && (jSx.z != 0.0 && (jx.x || jSx.x + jSx.z > jSx.y + jSx.w)); + //res.y = jy.w || !(jy.z || jy.x) && (jSy.w != 0.0 && (jy.y || jSy.y + jSy.w > jSy.x + jSy.z)); + //res.z = jz.x || !(jz.w || jz.y) && (jSz.x != 0.0 && (jz.z || jSz.x + jSz.z > jSz.y + jSz.w)); + //res.w = jw.y || !(jw.x || jw.z) && (jSw.y != 0.0 && (jw.w || jSw.y + jSw.w > jSw.x + jSw.z)); + + vec4 res; + res.x = min(jx.z + (NOT(jx.y) * NOT(jx.w)) * (GE(jSx.z, 0.0) * (jx.x + GE(jSx.x + jSx.z, jSx.y + jSx.w))), 1.0); + res.y = min(jy.w + (NOT(jy.z) * NOT(jy.x)) * (GE(jSy.w, 0.0) * (jy.y + GE(jSy.y + jSy.w, jSy.x + jSy.z))), 1.0); + res.z = min(jz.x + (NOT(jz.w) * NOT(jz.y)) * (GE(jSz.x, 0.0) * (jz.z + GE(jSz.x + jSz.z, jSz.y + jSz.w))), 1.0); + res.w = min(jw.y + (NOT(jw.x) * NOT(jw.z)) * (GE(jSw.y, 0.0) * (jw.w + GE(jSw.y + jSw.w, jSw.x + jSw.z))), 1.0); + + + // single pixel & end of line detection + //res = res && (bvec4(jx.z, jy.w, jz.x, jw.y) || !(res.wxyz && res.yzwx)); + res = min(res * (vec4(jx.z, jy.w, jz.x, jw.y) + NOT(res.wxyz * res.yzwx)), vec4(1.0)); + + + // output + + vec4 clr; + clr.x = clear(vec2(D.z, E.x), vec4(A.w, E.y, D.wy)); + clr.y = clear(vec2(E.z, F.x), vec4(B.w, F.y, E.wy)); + clr.z = clear(vec2(H.z, I.x), vec4(E.w, I.y, H.wy)); + clr.w = clear(vec2(G.z, H.x), vec4(D.w, H.y, G.wy)); + + vec4 low = max(vec4(E.yw, H.y, D.w), vec4(THR)); + + vec4 hori = vec4(low.x < max(D.w, A.w), low.x < max(E.w, B.w), low.z < max(E.w, H.w), low.z < max(D.w, G.w)) * clr; // horizontal edges + vec4 vert = vec4(low.w < max(E.y, D.y), low.y < max(E.y, F.y), low.y < max(H.y, I.y), low.w < max(H.y, G.y)) * clr; // vertical edges + vec4 or = vec4(A.w < D.y, B.w <= F.y, H.w < I.y, G.w <= G.y); // orientation + + FragColor = (res + 2.0 * hori + 4.0 * vert + 8.0 * or) / 15.0; +} diff --git a/scalefx/shaders/old/scalefx-pass2.slang b/scalefx/shaders/old/scalefx-pass2.slang new file mode 100644 index 0000000..07d20f8 --- /dev/null +++ b/scalefx/shaders/old/scalefx-pass2.slang @@ -0,0 +1,171 @@ +#version 450 + +/* + ScaleFX - Pass 2 + by Sp00kyFox, 2016-03-30 + +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 determines which edge level is present and prepares tags for subpixel +output in the final pass. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#pragma name sfxp2 + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; +}; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; + + +// extract first bool4 from float4 - corners +bvec4 loadCorn(vec4 x){ + return bvec4(floor(mod(x*15 + 0.5, 2.0))); +} + +// extract second bool4 from float4 - horizontal edges +bvec4 loadHori(vec4 x){ + return bvec4(floor(mod(x*7.5 + 0.25, 2.0))); +} + +// extract third bool4 from float4 - vertical edges +bvec4 loadVert(vec4 x){ + return bvec4(floor(mod(x*3.75 + 0.125, 2.0))); +} + +// extract fourth bool4 from float4 - orientation +bvec4 loadOr(vec4 x){ + return bvec4(floor(mod(x*1.875 + 0.0625, 2.0))); +} + + + +void main() +{ + + /* grid corners mids + + B x y x + D E F w y + H w z z + */ + +#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); + + // 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); + + + // 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 = (Ec.x && Eo.x || lvl3x.x && Eo.y || lvl4x.x && Do.x || lvl6x.x && Fo.y) ? 5 : (Ec.x || 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 = (Ec.y && Eo.y || lvl3y.x && Eo.x || lvl4y.x && Fo.y || lvl6y.x && Do.x) ? 5 : (Ec.y || 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 = (Ec.z && Eo.z || lvl3z.x && Eo.w || lvl4z.x && Fo.z || lvl6z.x && Do.w) ? 7 : (Ec.z || 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 = (Ec.w && Eo.w || lvl3w.x && Eo.z || lvl4w.x && Do.w || lvl6w.x && Fo.z) ? 7 : (Ec.w || 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; + +} diff --git a/scalefx/shaders/old/scalefx-pass3.slang b/scalefx/shaders/old/scalefx-pass3.slang new file mode 100644 index 0000000..b75c3f1 --- /dev/null +++ b/scalefx/shaders/old/scalefx-pass3.slang @@ -0,0 +1,114 @@ +#version 450 + +/* + ScaleFX - Pass 3 + by Sp00kyFox, 2016-03-30 + +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 3 outputs subpixels based on previously calculated tags. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#pragma name sfxp3 + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; + vec4 SourceSize; +}; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; +layout(binding = 2) uniform sampler2D Original; + + + +// extract corners +vec4 loadCrn(vec4 x){ + return floor(mod(x*80.0 + 0.5, 9.0)); +} + +// extract mids +vec4 loadMid(vec4 x){ + return floor(mod(x*8.888888 + 0.055555, 9.0)); +} + + + +void main() +{ + + /* grid corners mids + + B x y x + D E F w y + H w z z + */ + + + // read data + vec4 E = 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 = texture(Original, vTexCoord + 1/SourceSize.xy * res); + +} diff --git a/scalefx/shaders/scalefx-pass7.slang b/scalefx/shaders/old/scalefx-pass7.slang similarity index 100% rename from scalefx/shaders/scalefx-pass7.slang rename to scalefx/shaders/old/scalefx-pass7.slang diff --git a/scalefx/shaders/scalefx-pass0.slang b/scalefx/shaders/scalefx-pass0.slang index b4a07e4..0591ce6 100644 --- a/scalefx/shaders/scalefx-pass0.slang +++ b/scalefx/shaders/scalefx-pass0.slang @@ -2,7 +2,7 @@ /* ScaleFX - Pass 0 - by Sp00kyFox, 2016-03-30 + by Sp00kyFox, 2017-03-01 Filter: Nearest Scale: 1x @@ -41,25 +41,15 @@ THE SOFTWARE. */ -#pragma name sfxp0 - - -// Reference: http://www.compuphase.com/cmetric.htm -float eq(vec3 A, vec3 B) +layout(push_constant) uniform Push { - float r = 0.5 * (A.r + B.r); - vec3 d = A - B; - vec3 c = vec3(2 + r, 4, 3 - r); - - return 1 - sqrt(dot(c*d, d)) / 3; -} - + vec4 SourceSize; +} params; layout(set = 0, binding = 0, std140) uniform UBO { mat4 MVP; - vec4 SourceSize; -}; +} global; #pragma stage vertex @@ -69,7 +59,7 @@ layout(location = 0) out vec2 vTexCoord; void main() { - gl_Position = MVP * Position; + gl_Position = global.MVP * Position; vTexCoord = TexCoord; } @@ -80,7 +70,16 @@ layout(location = 0) out vec4 FragColor; layout(binding = 1) uniform sampler2D Source; -#define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) +// 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() { @@ -92,13 +91,15 @@ void main() */ +#define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)).rgb + // read texels - vec3 A = TEX(-1,-1).rgb; - vec3 B = TEX( 0,-1).rgb; - vec3 C = TEX( 1,-1).rgb; - vec3 E = TEX( 0, 0).rgb; - vec3 F = TEX( 1, 0).rgb; + vec3 A = TEX(-1,-1); + vec3 B = TEX( 0,-1); + vec3 C = TEX( 1,-1); + vec3 E = TEX( 0, 0); + vec3 F = TEX( 1, 0); // output - FragColor = vec4(eq(E,A), eq(E,B), eq(E,C), eq(E,F)); + FragColor = vec4(dist(E,A), dist(E,B), dist(E,C), dist(E,F)); } diff --git a/scalefx/shaders/scalefx-pass1.slang b/scalefx/shaders/scalefx-pass1.slang index dc3c722..d2cc339 100644 --- a/scalefx/shaders/scalefx-pass1.slang +++ b/scalefx/shaders/scalefx-pass1.slang @@ -2,7 +2,7 @@ /* ScaleFX - Pass 1 - by Sp00kyFox, 2016-03-30 + by Sp00kyFox, 2017-03-01 Filter: Nearest Scale: 1x @@ -14,7 +14,7 @@ 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 resolves ambiguous configurations of corner candidates at pixel junctions. +Pass 1 calculates the strength of interpolation candidates. @@ -41,23 +41,22 @@ THE SOFTWARE. */ -#pragma name sfxp1 -#pragma parameter SFX_CLR "ScaleFX Color Thresh" 0.35 0.0 1.00 0.01 +layout(push_constant) uniform Push +{ + vec4 SourceSize; + float SFX_CLR; + float SFX_SAA; +} params; -#ifdef PARAMETER_UNIFORM - uniform float SFX_CLR; -#else - #define SFX_CLR 0.35 -#endif -const float THR = 1.0 - SFX_CLR; +#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 layout(set = 0, binding = 0, std140) uniform UBO { mat4 MVP; - vec4 SourceSize; -}; +} global; #pragma stage vertex @@ -67,7 +66,7 @@ layout(location = 0) out vec2 vTexCoord; void main() { - gl_Position = MVP * Position; + gl_Position = global.MVP * Position; vTexCoord = TexCoord; } @@ -78,34 +77,12 @@ layout(location = 0) out vec4 FragColor; layout(binding = 1) uniform sampler2D Source; -#define LE(x, y) (1.0 - step(y, x)) -#define GE(x, y) (1.0 - step(x, y)) -#define LEQ(x, y) step(x, y) -#define GEQ(x, y) step(y, x) -#define NOT(x) (1.0 - (x)) - - // corner strength -vec4 str(vec4 crn, vec4 ort){ - //return (crn > THR) ? max(2.0*crn - (ort + ort.wxyz), 0.0) : 0.0; - return GE(crn, vec4(THR)) * max(2.0*crn - (ort + ort.wxyz), vec4(0.0)); -} - -// corner dominance at junctions -vec4 dom(vec3 strx, vec3 stry, vec3 strz, vec3 strw){ - vec4 res; - res.x = max(2.0*strx.y - (strx.x + strx.z), 0.0); - res.y = max(2.0*stry.y - (stry.x + stry.z), 0.0); - res.z = max(2.0*strz.y - (strz.x + strz.z), 0.0); - res.w = max(2.0*strw.y - (strw.x + strw.z), 0.0); - return res; -} - -// necessary but not sufficient junction condition for orthogonal edges -float clear(vec2 crn, vec4 ort){ - //return all(crn.xyxy <= THR || crn.xyxy <= ort || crn.xyxy <= ort.wxyz); - vec4 res = LEQ(crn.xyxy, vec4(THR)) + LEQ(crn.xyxy, ort) + LEQ(crn.xyxy, ort.wxyz); - return min(res.x * res.y * res.z * res.w, 1.0); +float str(float d, vec2 a, vec2 b){ + float diff = a.x - a.y; + float wght1 = max(params.SFX_CLR - d, 0) / params.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 (params.SFX_SAA == 1 || 2*d < a.x + a.y) ? (wght1 * wght2) * (a.x * a.y) : 0; } @@ -114,86 +91,25 @@ void main() /* grid metric pattern - M A B C P x y z x y - N D E F Q o w w z - O G H I R - J K L + A B x y z x y + D E F o w w z + G H I */ #define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) - // metric data - vec4 A = TEX(-1,-1), B = TEX( 0,-1), C = TEX( 1,-1); + 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); - vec4 J = TEX(-1, 2), K = TEX( 0, 2), L = TEX( 1, 2); - vec4 M = TEX(-2,-1), N = TEX(-2, 0), O = TEX(-2, 1); - vec4 P = TEX( 2,-1), Q = TEX( 2, 0), R = TEX( 2, 1); - // corner strength - vec4 As = str(vec4(M.z, B.x, D.zx), vec4(A.yw, D.y, M.w)); - vec4 Bs = str(vec4(A.z, C.x, E.zx), vec4(B.yw, E.y, A.w)); - vec4 Cs = str(vec4(B.z, P.x, F.zx), vec4(C.yw, F.y, B.w)); - vec4 Ds = str(vec4(N.z, E.x, G.zx), vec4(D.yw, G.y, N.w)); - vec4 Es = str(vec4(D.z, F.x, H.zx), vec4(E.yw, H.y, D.w)); - vec4 Fs = str(vec4(E.z, Q.x, I.zx), vec4(F.yw, I.y, E.w)); - vec4 Gs = str(vec4(O.z, H.x, J.zx), vec4(G.yw, J.y, O.w)); - vec4 Hs = str(vec4(G.z, I.x, K.zx), vec4(H.yw, K.y, G.w)); - vec4 Is = str(vec4(H.z, R.x, L.zx), vec4(I.yw, L.y, H.w)); - - // 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 - //bvec4 jx = jDx != 0.0 && jDx + jDx.zwxy > jDx.yzwx + jDx.wxyz; - //bvec4 jy = jDy != 0.0 && jDy + jDy.zwxy > jDy.yzwx + jDy.wxyz; - //bvec4 jz = jDz != 0.0 && jDz + jDz.zwxy > jDz.yzwx + jDz.wxyz; - //bvec4 jw = jDw != 0.0 && jDw + jDw.zwxy > jDw.yzwx + jDw.wxyz; - - vec4 jx = GE(jDx, vec4(0.0)) * GE(jDx + jDx.zwxy, jDx.yzwx + jDx.wxyz); - vec4 jy = GE(jDy, vec4(0.0)) * GE(jDy + jDy.zwxy, jDy.yzwx + jDy.wxyz); - vec4 jz = GE(jDz, vec4(0.0)) * GE(jDz + jDz.zwxy, jDz.yzwx + jDz.wxyz); - vec4 jw = GE(jDw, vec4(0.0)) * GE(jDw + jDw.zwxy, jDw.yzwx + jDw.wxyz); - - // inject strength without creating new contradictions - //bvec4 res; - //res.x = jx.z || !(jx.y || jx.w) && (jSx.z != 0.0 && (jx.x || jSx.x + jSx.z > jSx.y + jSx.w)); - //res.y = jy.w || !(jy.z || jy.x) && (jSy.w != 0.0 && (jy.y || jSy.y + jSy.w > jSy.x + jSy.z)); - //res.z = jz.x || !(jz.w || jz.y) && (jSz.x != 0.0 && (jz.z || jSz.x + jSz.z > jSz.y + jSz.w)); - //res.w = jw.y || !(jw.x || jw.z) && (jSw.y != 0.0 && (jw.w || jSw.y + jSw.w > jSw.x + jSw.z)); - vec4 res; - res.x = min(jx.z + (NOT(jx.y) * NOT(jx.w)) * (GE(jSx.z, 0.0) * (jx.x + GE(jSx.x + jSx.z, jSx.y + jSx.w))), 1.0); - res.y = min(jy.w + (NOT(jy.z) * NOT(jy.x)) * (GE(jSy.w, 0.0) * (jy.y + GE(jSy.y + jSy.w, jSy.x + jSy.z))), 1.0); - res.z = min(jz.x + (NOT(jz.w) * NOT(jz.y)) * (GE(jSz.x, 0.0) * (jz.z + GE(jSz.x + jSz.z, jSz.y + jSz.w))), 1.0); - res.w = min(jw.y + (NOT(jw.x) * NOT(jw.z)) * (GE(jSw.y, 0.0) * (jw.w + GE(jSw.y + jSw.w, jSw.x + jSw.z))), 1.0); - - - // single pixel & end of line detection - //res = res && (bvec4(jx.z, jy.w, jz.x, jw.y) || !(res.wxyz && res.yzwx)); - res = min(res * (vec4(jx.z, jy.w, jz.x, jw.y) + NOT(res.wxyz * res.yzwx)), vec4(1.0)); - - - // output - - vec4 clr; - clr.x = clear(vec2(D.z, E.x), vec4(A.w, E.y, D.wy)); - clr.y = clear(vec2(E.z, F.x), vec4(B.w, F.y, E.wy)); - clr.z = clear(vec2(H.z, I.x), vec4(E.w, I.y, H.wy)); - clr.w = clear(vec2(G.z, H.x), vec4(D.w, H.y, G.wy)); - - vec4 low = max(vec4(E.yw, H.y, D.w), vec4(THR)); - - vec4 hori = vec4(low.x < max(D.w, A.w), low.x < max(E.w, B.w), low.z < max(E.w, H.w), low.z < max(D.w, G.w)) * clr; // horizontal edges - vec4 vert = vec4(low.w < max(E.y, D.y), low.y < max(E.y, F.y), low.y < max(H.y, I.y), low.w < max(H.y, G.y)) * clr; // vertical edges - vec4 or = vec4(A.w < D.y, B.w <= F.y, H.w < I.y, G.w <= G.y); // orientation - - FragColor = (res + 2.0 * hori + 4.0 * vert + 8.0 * or) / 15.0; + 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; } diff --git a/scalefx/shaders/scalefx-pass2.slang b/scalefx/shaders/scalefx-pass2.slang index 07d20f8..bf13103 100644 --- a/scalefx/shaders/scalefx-pass2.slang +++ b/scalefx/shaders/scalefx-pass2.slang @@ -2,7 +2,7 @@ /* ScaleFX - Pass 2 - by Sp00kyFox, 2016-03-30 + by Sp00kyFox, 2017-03-01 Filter: Nearest Scale: 1x @@ -14,8 +14,7 @@ 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 determines which edge level is present and prepares tags for subpixel -output in the final pass. +Pass 2 resolves ambiguous configurations of corner candidates at pixel junctions. @@ -42,14 +41,15 @@ THE SOFTWARE. */ -#pragma name sfxp2 - +layout(push_constant) uniform Push +{ + vec4 SourceSize; +} params; layout(set = 0, binding = 0, std140) uniform UBO { mat4 MVP; - vec4 SourceSize; -}; +} global; #pragma stage vertex @@ -59,7 +59,7 @@ layout(location = 0) out vec2 vTexCoord; void main() { - gl_Position = MVP * Position; + gl_Position = global.MVP * Position; vTexCoord = TexCoord; } @@ -68,104 +68,92 @@ void main() layout(location = 0) in vec2 vTexCoord; layout(location = 0) out vec4 FragColor; layout(binding = 1) uniform sampler2D Source; +layout(binding = 2) uniform sampler2D PassOutput0; -// extract first bool4 from float4 - corners -bvec4 loadCorn(vec4 x){ - return bvec4(floor(mod(x*15 + 0.5, 2.0))); +#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)); } -// extract second bool4 from float4 - horizontal edges -bvec4 loadHori(vec4 x){ - return bvec4(floor(mod(x*7.5 + 0.25, 2.0))); +// 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; } -// extract third bool4 from float4 - vertical edges -bvec4 loadVert(vec4 x){ - return bvec4(floor(mod(x*3.75 + 0.125, 2.0))); -} - -// extract fourth bool4 from float4 - orientation -bvec4 loadOr(vec4 x){ - return bvec4(floor(mod(x*1.875 + 0.0625, 2.0))); -} - - void main() { - /* grid corners mids + /* grid metric pattern - B x y x - D E F w y - H w z z + A B C x y z x y + D E F o w w z + G H I */ -#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); - - // 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); +#define TEXm(x, y) textureOffset(PassOutput0, vTexCoord, ivec2(x, y)) +#define TEXs(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) - // 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); + // 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); - // 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); + // 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); - // 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 = (Ec.x && Eo.x || lvl3x.x && Eo.y || lvl4x.x && Do.x || lvl6x.x && Fo.y) ? 5 : (Ec.x || 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 = (Ec.y && Eo.y || lvl3y.x && Eo.x || lvl4y.x && Fo.y || lvl6y.x && Do.x) ? 5 : (Ec.y || 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 = (Ec.z && Eo.z || lvl3z.x && Eo.w || lvl4z.x && Fo.z || lvl6z.x && Do.w) ? 7 : (Ec.z || 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 = (Ec.w && Eo.w || lvl3w.x && Eo.z || lvl4w.x && Do.w || lvl6w.x && Fo.z) ? 7 : (Ec.w || 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; + // 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); - // ouput - FragColor = (crn + 9 * mid) / 80; + // 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; } diff --git a/scalefx/shaders/scalefx-pass3.slang b/scalefx/shaders/scalefx-pass3.slang index b75c3f1..a8b56bf 100644 --- a/scalefx/shaders/scalefx-pass3.slang +++ b/scalefx/shaders/scalefx-pass3.slang @@ -2,10 +2,10 @@ /* ScaleFX - Pass 3 - by Sp00kyFox, 2016-03-30 + by Sp00kyFox, 2017-03-01 Filter: Nearest -Scale: 3x +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 @@ -14,7 +14,8 @@ 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 outputs subpixels based on previously calculated tags. +Pass 3 determines which edge level is present and prepares tags for subpixel +output in the final pass. @@ -41,14 +42,20 @@ THE SOFTWARE. */ -#pragma name sfxp3 +layout(push_constant) uniform Push +{ + vec4 SourceSize; + float SFX_SCN; +} params; + + +#pragma parameter SFX_SCN "ScaleFX Filter Corners" 1.0 0.0 1.0 1.0 layout(set = 0, binding = 0, std140) uniform UBO { mat4 MVP; - vec4 SourceSize; -}; +} global; #pragma stage vertex @@ -58,7 +65,7 @@ layout(location = 0) out vec2 vTexCoord; void main() { - gl_Position = MVP * Position; + gl_Position = global.MVP * Position; vTexCoord = TexCoord; } @@ -67,18 +74,26 @@ void main() layout(location = 0) in vec2 vTexCoord; layout(location = 0) out vec4 FragColor; layout(binding = 1) uniform sampler2D Source; -layout(binding = 2) uniform sampler2D Original; - -// extract corners -vec4 loadCrn(vec4 x){ - return floor(mod(x*80.0 + 0.5, 9.0)); +// extract first bool4 from float4 - corners +bvec4 loadCorn(vec4 x){ + return bvec4(floor(mod(x*15 + 0.5, 2))); } -// extract mids -vec4 loadMid(vec4 x){ - return floor(mod(x*8.888888 + 0.055555, 9.0)); +// 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))); } @@ -86,29 +101,83 @@ vec4 loadMid(vec4 x){ void main() { - /* grid corners mids + /* grid corners mids B x y x D E F w y H w z z */ +#define TEX(x, y) textureOffset(Source, vTexCoord, ivec2(x, y)) // read data - vec4 E = texture(Source, vTexCoord); + vec4 E = TEX( 0, 0); + vec4 D = TEX(-1, 0), D0 = TEX(-2, 0), D1 = TEX(-3, 0); + vec4 F = TEX( 1, 0), F0 = TEX( 2, 0), F1 = TEX( 3, 0); + vec4 B = TEX( 0,-1), B0 = TEX( 0,-2), B1 = TEX( 0,-3); + vec4 H = TEX( 0, 1), H0 = TEX( 0, 2), H1 = TEX( 0, 3); // extract data - vec4 crn = loadCrn(E); - vec4 mid = loadMid(E); + 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); - // 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)); + + // lvl1 corners (hori, vert) + bool lvl1x = Ec.x && (Dc.z || Bc.z || params.SFX_SCN == 1); + bool lvl1y = Ec.y && (Fc.w || Bc.w || params.SFX_SCN == 1); + bool lvl1z = Ec.z && (Fc.x || Hc.x || params.SFX_SCN == 1); + bool lvl1w = Ec.w && (Dc.y || Hc.y || params.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; - // output coordinate - 0 = E, 1 = D, 2 = D0, 3 = F, 4 = F0, 5 = B, 6 = B0, 7 = H, 8 = H0 - vec2 res = sp == 0 ? vec2(0,0) : sp == 1 ? vec2(-1,0) : sp == 2 ? vec2(-2,0) : sp == 3 ? vec2(1,0) : sp == 4 ? vec2(2,0) : sp == 5 ? vec2(0,-1) : sp == 6 ? vec2(0,-2) : sp == 7 ? vec2(0,1) : vec2(0,2); // ouput - FragColor = texture(Original, vTexCoord + 1/SourceSize.xy * res); + FragColor = (crn + 9 * mid) / 80; } diff --git a/scalefx/shaders/scalefx-pass4-hybrid.slang b/scalefx/shaders/scalefx-pass4-hybrid.slang new file mode 100644 index 0000000..9867a4d --- /dev/null +++ b/scalefx/shaders/scalefx-pass4-hybrid.slang @@ -0,0 +1,159 @@ +#version 450 + +/* + ScaleFX - Pass 4 + by Sp00kyFox, 2017-03-01 + +Filter: Nearest +Scale: 3x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 4 outputs subpixels based on previously calculated tags. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +layout(push_constant) uniform Push +{ + vec4 SourceSize; + float SFX_RAA; +} params; + + +#pragma parameter SFX_RAA "ScaleFX rAA Sharpness" 2.0 0.0 10.0 0.05 + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; +} global; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; +layout(binding = 2) uniform sampler2D Original; + + +// 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 = params.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 = texture(Source, vTexCoord); + + // determine subpixel + vec2 fc = fract(vTexCoord * params.SourceSize.xy); + vec2 fp = floor(3.0 * fc); + + // check adjacent pixels to prevent artifacts + vec4 hn = texture(Source, vTexCoord + vec2(fp.x - 1, 0) / params.SourceSize.xy); + vec4 vn = texture(Source, vTexCoord + vec2(0, fp.y - 1) / params.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); +} \ No newline at end of file diff --git a/scalefx/shaders/scalefx-pass4.slang b/scalefx/shaders/scalefx-pass4.slang new file mode 100644 index 0000000..630e0df --- /dev/null +++ b/scalefx/shaders/scalefx-pass4.slang @@ -0,0 +1,114 @@ +#version 450 + +/* + ScaleFX - Pass 4 + by Sp00kyFox, 2017-03-01 + +Filter: Nearest +Scale: 3x + +ScaleFX is an edge interpolation algorithm specialized in pixel art. It was +originally intended as an improvement upon Scale3x but became a new filter in +its own right. +ScaleFX interpolates edges up to level 6 and makes smooth transitions between +different slopes. The filtered picture will only consist of colours present +in the original. + +Pass 4 outputs subpixels based on previously calculated tags. + + + +Copyright (c) 2016 Sp00kyFox - ScaleFX@web.de + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +layout(push_constant) uniform Push +{ + vec4 SourceSize; +} params; + + +layout(set = 0, binding = 0, std140) uniform UBO +{ + mat4 MVP; +} global; + + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; +} + + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(binding = 1) uniform sampler2D Source; +layout(binding = 2) uniform sampler2D Original; + + +// extract corners +vec4 loadCrn(vec4 x){ + return floor(mod(x*80 + 0.5, 9)); +} + +// extract mids +vec4 loadMid(vec4 x){ + return floor(mod(x*8.888888 + 0.055555, 9)); +} + + +void main() +{ + + /* grid corners mids + + B x y x + D E F w y + H w z z + */ + + + // read data + vec4 E = texture(Source, vTexCoord); + + // extract data + vec4 crn = loadCrn(E); + vec4 mid = loadMid(E); + + // determine subpixel + vec2 fp = floor(3.0 * fract(vTexCoord * params.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 = texture(Original, vTexCoord + res / params.SourceSize.xy); +}