all repos — mgba @ d119fc0fe312978802f5b5d30ecc24522108248f

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
 26precision highp float;
 27
 28varying vec2 texCoord;
 29uniform sampler2D tex;
 30uniform vec2 texSize;
 31
 32uniform float similarity_threshold;
 33
 34#define screen_res 240,160
 35
 36vec4 texel_fetch(sampler2D t, ivec2 c)   // because GLSL TexelFetch is not supported
 37  {
 38    return texture2D(tex,   (2 * vec2(c) + vec2(1,1)) / (2 * vec2(screen_res)) );
 39  }
 40
 41float pixel_brightness(vec4 pixel)
 42  {
 43    return 0.21 * pixel.x + 0.72 * pixel.y + 0.07 * pixel.z;
 44  }
 45
 46bool pixel_is_brighter(vec4 pixel1, vec4 pixel2)
 47  {
 48    return pixel_brightness(pixel1) > pixel_brightness(pixel2);
 49  }
 50
 51vec3 pixel_to_yuv(vec4 pixel)
 52  {
 53    float y = 0.299 * pixel.x + 0.587 * pixel.y + 0.114 * pixel.z;
 54    return vec3(y, 0.492 * (pixel.z - y), 0.877 * (pixel.x - y));
 55  }
 56
 57bool yuvs_are_similar(vec3 yuv1, vec3 yuv2)
 58  {
 59    vec3 yuv_difference = abs(yuv1 - yuv2);
 60    return yuv_difference.x <= similarity_threshold && yuv_difference.y <= similarity_threshold && yuv_difference.z <= similarity_threshold;
 61  }
 62
 63bool pixels_are_similar(vec4 pixel1, vec4 pixel2)
 64  {
 65    vec3 yuv1 = pixel_to_yuv(pixel1);
 66    vec3 yuv2 = pixel_to_yuv(pixel2);
 67
 68    return yuvs_are_similar(yuv1, yuv2);
 69  }
 70
 71vec4 interpolate_nondiagonal(vec4 neighbour1, vec4 neighbour2)
 72  {
 73    if (pixels_are_similar(neighbour1,neighbour2))
 74      return mix(neighbour1,neighbour2,0.5);
 75    else
 76      return pixel_is_brighter(neighbour1, neighbour2) ? neighbour1 : neighbour2;
 77  }
 78
 79vec4 mix3(vec4 value1, vec4 value2, vec4 value3)
 80  {
 81    return (value1 + value2 + value3) / 3.0;
 82  }
 83
 84vec4 straight_line(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
 85  {
 86    return pixel_is_brighter(p2,p0) ? mix(p2,p3,0.5) : mix(p0,p1,0.5);
 87  }
 88
 89vec4 corner(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
 90  {
 91    return pixel_is_brighter(p1,p0) ? mix3(p1,p2,p3) : mix3(p0,p1,p2);
 92  }
 93
 94vec4 interpolate_diagonal(vec4 a, vec4 b, vec4 c, vec4 d)
 95  {
 96    // a b
 97    // c d
 98
 99    vec3 a_yuv = pixel_to_yuv(a);
100    vec3 b_yuv = pixel_to_yuv(b);
101    vec3 c_yuv = pixel_to_yuv(c);
102    vec3 d_yuv = pixel_to_yuv(d);
103
104    bool ad = yuvs_are_similar(a_yuv,d_yuv);
105    bool bc = yuvs_are_similar(b_yuv,c_yuv);
106    bool ab = yuvs_are_similar(a_yuv,b_yuv);
107    bool cd = yuvs_are_similar(c_yuv,d_yuv);
108    bool ac = yuvs_are_similar(a_yuv,c_yuv);
109    bool bd = yuvs_are_similar(b_yuv,d_yuv);
110
111    if (ad && cd && ab)                                          // all pixels are equal?
112      return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
113
114    else if (ac && cd && ! ab)                                   // corner 1?
115      return corner(b,a,d,c);
116    else if (bd && cd && ! ab)                                   // corner 2?
117      return corner(a,b,c,d);
118    else if (ac && ab && ! bd)                                   // corner 3?
119      return corner(d,c,b,a);
120    else if (ab && bd && ! ac)                                   // corner 4?
121      return corner(c,a,d,b);
122
123    else if (ad && (!bc || pixel_is_brighter(b,a)))              // diagonal line 1?
124      return mix(a,d,0.5);
125    else if (bc && (!ad || pixel_is_brighter(a,b)))              // diagonal line 2?
126      return mix(b,c,0.5);
127
128    else if (ab)                                                 // horizontal line 1?
129      return straight_line(a,b,c,d);
130    else if (cd)                                                 // horizontal line 2?
131      return straight_line(c,d,a,b);
132
133    else if (ac)                                                 // vertical line 1?
134      return straight_line(a,c,b,d);
135    else if (bd)                                                 // vertical line 2?
136      return straight_line(b,d,a,c);
137
138    return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
139  }
140
141void main()
142  {
143    ivec2 pixel_coords2 = ivec2(texCoord * vec2(screen_res) * 2);
144    ivec2 pixel_coords = pixel_coords2 / 2;
145
146    bool x_even = mod(pixel_coords2.x,2) == 0;
147    bool y_even = mod(pixel_coords2.y,2) == 0;
148
149    if (x_even)
150      {
151        if (y_even)
152          {
153
154            gl_FragColor = interpolate_diagonal(
155              texel_fetch(tex, pixel_coords + ivec2(-1,-1)),
156              texel_fetch(tex, pixel_coords + ivec2(0,-1)),
157              texel_fetch(tex, pixel_coords + ivec2(-1,0)),
158              texel_fetch(tex, pixel_coords + ivec2(0,0))
159              );
160
161          }
162        else
163          {
164            gl_FragColor = interpolate_nondiagonal
165              (
166                texel_fetch(tex, pixel_coords + ivec2(-1,0)),
167                texel_fetch(tex, pixel_coords)
168              );
169          }
170      }
171    else if (y_even)
172      {
173        gl_FragColor = interpolate_nondiagonal
174          (
175            texel_fetch(tex, pixel_coords + ivec2(0,-1)),
176            texel_fetch(tex, pixel_coords)
177          );
178      }
179    else
180      gl_FragColor = texel_fetch(tex, pixel_coords);
181  }