all repos — mgba @ 3be21bf5954d73b7714620fd8e389ff94ec68157

mGBA Game Boy Advance Emulator

res/shaders/fish.shader/fish.fs (view raw)

  1/*
  2   fish shader
  3   
  4   algorithm and original implementation by Miloslav "drummyfish" Ciz
  5   (tastyfish@seznam.cz)
  6
  7   Permission is hereby granted, free of charge, to any person obtaining a copy
  8   of this software and associated documentation files (the "Software"), to deal
  9   in the Software without restriction, including without limitation the rights
 10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11   copies of the Software, and to permit persons to whom the Software is
 12   furnished to do so, subject to the following conditions:
 13
 14   The above copyright notice and this permission notice shall be included in
 15   all copies or substantial portions of the Software.
 16
 17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23   THE SOFTWARE.
 24*/
 25
 26varying vec2 texCoord;
 27uniform sampler2D tex;
 28uniform vec2 texSize;
 29
 30uniform float similarity_threshold;
 31
 32vec4 texel_fetch(sampler2D t, ivec2 c)   // because GLSL TexelFetch is not supported
 33  {
 34    return texture2D(tex,   (2 * vec2(c) + vec2(1,1)) / (2 * texSize) );
 35  }
 36
 37float pixel_brightness(vec4 pixel)
 38  {
 39    return 0.21 * pixel.x + 0.72 * pixel.y + 0.07 * pixel.z;
 40  }
 41
 42bool pixel_is_brighter(vec4 pixel1, vec4 pixel2)
 43  {
 44    return pixel_brightness(pixel1) > pixel_brightness(pixel2);
 45  }
 46
 47vec3 pixel_to_yuv(vec4 pixel)
 48  {
 49    float y = 0.299 * pixel.x + 0.587 * pixel.y + 0.114 * pixel.z;
 50    return vec3(y, 0.492 * (pixel.z - y), 0.877 * (pixel.x - y));
 51  }
 52
 53bool yuvs_are_similar(vec3 yuv1, vec3 yuv2)
 54  {
 55    vec3 yuv_difference = abs(yuv1 - yuv2);
 56    return yuv_difference.x <= similarity_threshold && yuv_difference.y <= similarity_threshold && yuv_difference.z <= similarity_threshold;
 57  }
 58
 59bool pixels_are_similar(vec4 pixel1, vec4 pixel2)
 60  {
 61    vec3 yuv1 = pixel_to_yuv(pixel1);
 62    vec3 yuv2 = pixel_to_yuv(pixel2);
 63
 64    return yuvs_are_similar(yuv1, yuv2);
 65  }
 66
 67vec4 interpolate_nondiagonal(vec4 neighbour1, vec4 neighbour2)
 68  {
 69    if (pixels_are_similar(neighbour1,neighbour2))
 70      return mix(neighbour1,neighbour2,0.5);
 71    else
 72      return pixel_is_brighter(neighbour1, neighbour2) ? neighbour1 : neighbour2;
 73  }
 74
 75vec4 mix3(vec4 value1, vec4 value2, vec4 value3)
 76  {
 77    return (value1 + value2 + value3) / 3.0;
 78  }
 79
 80vec4 straight_line(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
 81  {
 82    return pixel_is_brighter(p2,p0) ? mix(p2,p3,0.5) : mix(p0,p1,0.5);
 83  }
 84
 85vec4 corner(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
 86  {
 87    return pixel_is_brighter(p1,p0) ? mix3(p1,p2,p3) : mix3(p0,p1,p2);
 88  }
 89
 90vec4 interpolate_diagonal(vec4 a, vec4 b, vec4 c, vec4 d)
 91  {
 92    // a b
 93    // c d
 94
 95    vec3 a_yuv = pixel_to_yuv(a);
 96    vec3 b_yuv = pixel_to_yuv(b);
 97    vec3 c_yuv = pixel_to_yuv(c);
 98    vec3 d_yuv = pixel_to_yuv(d);
 99
100    bool ad = yuvs_are_similar(a_yuv,d_yuv);
101    bool bc = yuvs_are_similar(b_yuv,c_yuv);
102    bool ab = yuvs_are_similar(a_yuv,b_yuv);
103    bool cd = yuvs_are_similar(c_yuv,d_yuv);
104    bool ac = yuvs_are_similar(a_yuv,c_yuv);
105    bool bd = yuvs_are_similar(b_yuv,d_yuv);
106
107    if (ad && cd && ab)                                          // all pixels are equal?
108      return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
109
110    else if (ac && cd && ! ab)                                   // corner 1?
111      return corner(b,a,d,c);
112    else if (bd && cd && ! ab)                                   // corner 2?
113      return corner(a,b,c,d);
114    else if (ac && ab && ! bd)                                   // corner 3?
115      return corner(d,c,b,a);
116    else if (ab && bd && ! ac)                                   // corner 4?
117      return corner(c,a,d,b);
118
119    else if (ad && (!bc || pixel_is_brighter(b,a)))              // diagonal line 1?
120      return mix(a,d,0.5);
121    else if (bc && (!ad || pixel_is_brighter(a,b)))              // diagonal line 2?
122      return mix(b,c,0.5);
123
124    else if (ab)                                                 // horizontal line 1?
125      return straight_line(a,b,c,d);
126    else if (cd)                                                 // horizontal line 2?
127      return straight_line(c,d,a,b);
128
129    else if (ac)                                                 // vertical line 1?
130      return straight_line(a,c,b,d);
131    else if (bd)                                                 // vertical line 2?
132      return straight_line(b,d,a,c);
133
134    return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
135  }
136
137void main()
138  {
139    ivec2 pixel_coords2 = ivec2(texCoord * texSize * 2);
140    ivec2 pixel_coords = pixel_coords2 / 2;
141
142    bool x_even = mod(pixel_coords2.x,2) == 0;
143    bool y_even = mod(pixel_coords2.y,2) == 0;
144
145    if (x_even)
146      {
147        if (y_even)
148          {
149
150            gl_FragColor = interpolate_diagonal(
151              texel_fetch(tex, pixel_coords + ivec2(-1,-1)),
152              texel_fetch(tex, pixel_coords + ivec2(0,-1)),
153              texel_fetch(tex, pixel_coords + ivec2(-1,0)),
154              texel_fetch(tex, pixel_coords + ivec2(0,0))
155              );
156
157          }
158        else
159          {
160            gl_FragColor = interpolate_nondiagonal
161              (
162                texel_fetch(tex, pixel_coords + ivec2(-1,0)),
163                texel_fetch(tex, pixel_coords)
164              );
165          }
166      }
167    else if (y_even)
168      {
169        gl_FragColor = interpolate_nondiagonal
170          (
171            texel_fetch(tex, pixel_coords + ivec2(0,-1)),
172            texel_fetch(tex, pixel_coords)
173          );
174      }
175    else
176      gl_FragColor = texel_fetch(tex, pixel_coords);
177  }