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 }