Created
May 21, 2016 05:51
-
-
Save SwooshyCueb/f8716456d93a1a21fb0bee376caddc3b to your computer and use it in GitHub Desktop.
Temporary location for glsl stuff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 420 compatibility | |
// Will insert lines here so make sure version is at the very top. | |
// No includes. | |
/******************************************************************************/ | |
/* GLSL Fragment Shader implementation of the SuperEagle 2x upscaler filter */ | |
/******************************************************************************/ | |
/* Copyright (C) 2016 Markus Kitsinger (SwooshyCueb) <root@swooshalicio.us> */ | |
/* */ | |
/* This implementation of the SuperEagle filter is subject to the terms of */ | |
/* Mozilla Public License, version 2.0. You can obtain a copy of this */ | |
/* license at http://mozilla.org/MPL/2.0/. */ | |
/******************************************************************************/ | |
/* The original SuperEagle filter implementation was created by */ | |
/* Derek Liauw Kie Fa (Kreed). It was released under the GPL license in 1999. */ | |
/* It can be found at https://vdnoort.home.xs4all.nl/emulation/2xsai/. */ | |
/******************************************************************************/ | |
// Mesa recently got complete OpenGL 4.2 support on intel graphics | |
// So we'll target 4.2 plus extensions | |
/* TODO: | |
* Replace gl_TexCoord, and anything else depricated in 4.2 | |
* Ensure shader works as intended when alpha values are used | |
*/ | |
#extension GL_ARB_texture_rectangle : enable | |
#extension GL_ARB_shading_language_420pack: enable | |
#extension GL_EXT_shader_image_load_store : enable | |
#extension GL_EXT_bindable_uniform : enable | |
const uint colorMask = uint(0xF7DEF7DE); | |
const uint lowPixelMask = uint(0x08210821); | |
const uint qcolorMask = uint(0xE79CE79C); | |
const uint qlowpixelMask = uint(0x18631863); | |
#ifdef DEBUG | |
vec4 c_black = vec4(0.0, 0.0, 0.0, 1.0); | |
vec4 c_white = vec4(1.0, 1.0, 1.0, 1.0); | |
vec4 c_red = vec4(1.0, 0.0, 0.0, 1.0); | |
vec4 c_green = vec4(0.0, 1.0, 0.0, 1.0); | |
vec4 c_blue = vec4(0.0, 0.0, 1.0, 1.0); | |
vec4 c_yellow = vec4(1.0, 1.0, 0.0, 1.0); | |
vec4 c_purple = vec4(1.0, 0.0, 1.0, 1.0); | |
vec4 c_indigo = vec4(0.0, 1.0, 1.0, 1.0); | |
#endif | |
uniform uvec2 src_size; | |
uniform uvec2 dst_size; | |
uniform sampler2D src_tex; | |
coherent writeonly uniform image2D dst_tex; | |
// If the destination texture | |
// isn't twice the size of the | |
// source texture, this shader | |
// will not work as intended. | |
//layout(origin_upper_left) | |
in vec4 gl_FragCoord; | |
highp vec2 coord = gl_TexCoord[0].st; | |
highp vec2 dst_pos_f = gl_FragCoord.xy; | |
ivec2 dst_pos_i = ivec2(dst_pos_f); | |
ivec2 dst_pos_o = ivec2(dst_pos_i.x, dst_size.y-dst_pos_i.y-1); | |
highp vec2 src_pos_f = vec2(coord.x * src_size.x, coord.y * src_size.y); | |
ivec2 src_pos_t = ivec2(src_pos_f); | |
highp vec2 dst_inv_size = vec2(1.0/float(dst_size.x), 1.0/float(dst_size.y)); | |
highp vec2 src_inv_size = vec2(1.0/float(src_size.x), 1.0/float(src_size.y)); | |
int magicnumber(vec4 A, vec4 B, vec4 C, vec4 D) { | |
ivec3 tmp = ivec3(0, 0, 0); | |
if (A == C) { | |
tmp.x = tmp.x + 1; | |
} else if (B == C) { | |
tmp.y = tmp.y + 1; | |
} | |
if (A == D) { | |
tmp.x = tmp.x + 1; | |
} else if (B == D) { | |
tmp.y = tmp.y + 1; | |
} | |
if (tmp.x <= 1) { | |
tmp.z = tmp.z + 1; | |
} | |
if (tmp.y <= 1) { | |
tmp.z = tmp.z - 1; | |
} | |
return tmp.z; | |
} | |
// Turn a vec4 color into a uint | |
highp uint reduce(vec4 color) { | |
return (uint(color.a*255.0) << uint(24)) | |
+ (uint(color.r*255.0) << uint(16)) | |
+ (uint(color.g*255.0) << uint(8)) | |
+ (uint(color.b*255.0)); | |
} | |
// Turn a uint into a vec4 color | |
highp vec4 unpack(uint c) { | |
highp vec4 ret; | |
ret.a = float((c & uint(0xFF000000)) >> 24); | |
ret.r = float((c & uint(0x00FF0000)) >> 16); | |
ret.g = float((c & uint(0x0000FF00)) >> 8); | |
ret.b = float(c & uint(0x000000FF)); | |
return ret/255.0; | |
} | |
highp vec4 smash2(vec4 A, vec4 B) { | |
if (A == B) { | |
return A; | |
} | |
uint rA = reduce(A); | |
uint rB = reduce(B); | |
return unpack(((rA & colorMask) >> 1) + ((rB & colorMask) >> 1) + | |
(rA & rB & lowPixelMask)); | |
} | |
highp vec4 smash4(vec4 A, vec4 B, vec4 C, vec4 D) { | |
uint rA = reduce(A); | |
uint rB = reduce(B); | |
uint rC = reduce(C); | |
uint rD = reduce(D); | |
return unpack((((rA & qcolorMask) >> 2) + ((rB & qcolorMask) >> 2) + | |
((rC & qcolorMask) >> 2) + ((rD & qcolorMask) >> 2)) + | |
((((rA & qlowpixelMask) + (rB & qlowpixelMask) + | |
(rC & qlowpixelMask) + (rD & qlowpixelMask)) >> 2) & qlowpixelMask)); | |
} | |
highp vec4 getpx(int x, int y) { | |
return texture2D(src_tex, coord + vec2(x * src_inv_size.x, -y * src_inv_size.y)); | |
} | |
void main() { | |
// Don't do anything if the pixel we're looking at is already taken care of | |
if ((mod(dst_pos_i.x, 2) != 0) || (mod(dst_pos_i.y, 2) != 0)) { | |
discard; | |
} | |
#ifdef DEBUG // Shows a few useful borders | |
if (dst_pos_i.x == 0 || dst_pos_i.y == 0 ) { | |
imageStore(dst_tex, dst_pos_o, c_green); | |
discard; | |
} else if (dst_pos_i.x == src_size.x-2 | |
|| dst_pos_i.y == src_size.y-2) { | |
imageStore(dst_tex, dst_pos_o, c_red); | |
discard; | |
} else if (dst_pos_i.x == dst_size.x-2 | |
|| dst_pos_i.y == dst_size.y-2) { | |
imageStore(dst_tex, dst_pos_o, c_indigo); | |
discard; | |
} | |
#endif | |
highp vec4 dst_px; | |
highp vec4 dst_px_E; | |
highp vec4 dst_px_N; | |
highp vec4 dst_px_NE; | |
// Fetch pixels from source texture | |
highp vec4 src_px = getpx( 0, 0); | |
highp vec4 src_px_N = getpx( 0, 1); | |
highp vec4 src_px_E = getpx( 1, 0); | |
highp vec4 src_px_S = getpx( 0, -1); | |
highp vec4 src_px_W = getpx(-1, 0); | |
highp vec4 src_px_NE = getpx( 1, 1); | |
highp vec4 src_px_SE = getpx( 1, -1); | |
highp vec4 src_px_NW = getpx(-1, 1); | |
highp vec4 src_px_NN = getpx( 0, 2); | |
highp vec4 src_px_EE = getpx( 2, 0); | |
highp vec4 src_px_NNE = getpx( 1, 2); | |
highp vec4 src_px_ENE = getpx( 2, 1); | |
// Do magic | |
// (Don't ask me how this works; I barely understand it myself) | |
if ((src_px_N == src_px_E) && (src_px != src_px_NE)) { | |
dst_px_E = dst_px_N = src_px_N; | |
if ((src_px_NW == src_px_N) || (src_px_E == src_px_SE)) { | |
dst_px = smash2(src_px_N, smash2(src_px_N, src_px)); | |
} else { | |
dst_px = smash2(src_px, src_px_E); | |
} | |
if ((src_px_E == src_px_EE) || (src_px_N == src_px_NN)) { | |
dst_px_NE = smash2(src_px_N, smash2(src_px_N, src_px_NE)); | |
} else { | |
dst_px_NE = smash2 (src_px_N, src_px_NE); | |
} | |
} else if ((src_px == src_px_NE) && (src_px_N != src_px_E)) { | |
dst_px_NE = dst_px = src_px; | |
if ((src_px_S == src_px) || (src_px_NE == src_px_ENE)) { | |
dst_px_E = smash2 (src_px, smash2 (src_px, src_px_E)); | |
} else { | |
dst_px_E = smash2 (src_px, src_px_E); | |
} | |
if ((src_px_NE == src_px_NNE) || (src_px_W == src_px)) { | |
dst_px_N = smash2 (src_px, smash2 (src_px, src_px_N)); | |
} else { | |
dst_px_N = smash2 (src_px_N, src_px_NE); | |
} | |
} else if (src_px == src_px_NE && src_px_N == src_px_E) { | |
int r = 0; | |
r += magicnumber(src_px_E, src_px, src_px_NW, src_px_NN); | |
r += magicnumber(src_px_E, src_px, src_px_W, src_px_S); | |
r += magicnumber(src_px_E, src_px, src_px_NNE, src_px_ENE); | |
r += magicnumber(src_px_E, src_px, src_px_SE, src_px_EE); | |
if (r > 0) { | |
dst_px_E = dst_px_N = src_px_N; | |
dst_px = dst_px_NE = smash2(src_px, src_px_E); | |
} else if (r < 0) { | |
dst_px_NE = dst_px = src_px; | |
dst_px_E = dst_px_N = smash2(src_px, src_px_E); | |
} else { | |
dst_px_NE = dst_px = src_px; | |
dst_px_E = dst_px_N = src_px_N; | |
} | |
} else { | |
dst_px_NE = dst_px = smash2(src_px_N, src_px_E); | |
dst_px_NE = smash4(src_px_NE, src_px_NE, src_px_NE, dst_px_NE); | |
dst_px = smash4(src_px, src_px, src_px, dst_px); | |
dst_px_N = dst_px_E = smash2(src_px, src_px_NE); | |
dst_px_N = smash4(src_px_N, src_px_N, src_px_N, dst_px_N); | |
dst_px_E = smash4(src_px_E, src_px_E, src_px_E, dst_px_E); | |
} | |
// Write pixels to destination texture | |
imageStore(dst_tex, dst_pos_o, dst_px); | |
imageStore(dst_tex, ivec2(dst_pos_o.x, dst_pos_o.y+1), dst_px_N); | |
imageStore(dst_tex, ivec2(dst_pos_o.x+1, dst_pos_o.y), dst_px_E); | |
imageStore(dst_tex, ivec2(dst_pos_o.x+1, dst_pos_o.y+1), dst_px_NE); | |
// No fragments | |
discard; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment