Mercurial > repos > blastem
comparison shaders/xBRZ.f.glsl @ 2495:d437b8e8ba62
Add xBRZ and bandlimit pixel footprint shaders ported by hunterk
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 28 Apr 2024 23:22:37 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2494:b62580dc6f30 | 2495:d437b8e8ba62 |
---|---|
1 // xBRZ freescale | |
2 // based on : | |
3 | |
4 /* | |
5 Hyllian's xBR-vertex code and texel mapping | |
6 | |
7 Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com | |
8 | |
9 Permission is hereby granted, free of charge, to any person obtaining a copy | |
10 of this software and associated documentation files (the "Software"), to deal | |
11 in the Software without restriction, including without limitation the rights | |
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
13 copies of the Software, and to permit persons to whom the Software is | |
14 furnished to do so, subject to the following conditions: | |
15 | |
16 The above copyright notice and this permission notice shall be included in | |
17 all copies or substantial portions of the Software. | |
18 | |
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
25 THE SOFTWARE. | |
26 | |
27 */ | |
28 | |
29 // This shader also uses code and/or concepts from xBRZ as it appears | |
30 // in the Desmume source code. The license for which is as follows: | |
31 | |
32 // **************************************************************************** | |
33 // * This file is part of the HqMAME project. It is distributed under * | |
34 // * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * | |
35 // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * | |
36 // * * | |
37 // * Additionally and as a special exception, the author gives permission * | |
38 // * to link the code of this program with the MAME library (or with modified * | |
39 // * versions of MAME that use the same license as MAME), and distribute * | |
40 // * linked combinations including the two. You must obey the GNU General * | |
41 // * Public License in all respects for all of the code used other than MAME. * | |
42 // * If you modify this file, you may extend this exception to your version * | |
43 // * of the file, but you are not obligated to do so. If you do not wish to * | |
44 // * do so, delete this exception statement from your version. * | |
45 // **************************************************************************** | |
46 // ported to blastem shader format by hunterk | |
47 | |
48 uniform sampler2D textures[2]; | |
49 uniform mediump vec2 texsize; | |
50 varying mediump vec2 texcoord; | |
51 | |
52 #define BLEND_NONE 0 | |
53 #define BLEND_NORMAL 1 | |
54 #define BLEND_DOMINANT 2 | |
55 #define LUMINANCE_WEIGHT 1.0 | |
56 #define EQUAL_COLOR_TOLERANCE 30.0/255.0 | |
57 #define STEEP_DIRECTION_THRESHOLD 2.2 | |
58 #define DOMINANT_DIRECTION_THRESHOLD 3.6 | |
59 | |
60 // this is usually handled automatically but blastem doesn't expose output size? | |
61 #define scale vec2(10.0, 10.0) | |
62 | |
63 mediump float DistYCbCr(vec3 pixA, vec3 pixB) | |
64 { | |
65 const vec3 w = vec3(0.2627, 0.6780, 0.0593); | |
66 const float scaleB = 0.5 / (1.0 - w.b); | |
67 const float scaleR = 0.5 / (1.0 - w.r); | |
68 vec3 diff = pixA - pixB; | |
69 float Y = dot(diff.rgb, w); | |
70 float Cb = scaleB * (diff.b - Y); | |
71 float Cr = scaleR * (diff.r - Y); | |
72 | |
73 return sqrt(((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr)); | |
74 } | |
75 | |
76 bool IsPixEqual(const vec3 pixA, const vec3 pixB) | |
77 { | |
78 return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); | |
79 } | |
80 | |
81 mediump float get_left_ratio(vec2 center, vec2 origin, vec2 direction, vec2 scale_) | |
82 { | |
83 vec2 P0 = center - origin; | |
84 vec2 proj = direction * (dot(P0, direction) / dot(direction, direction)); | |
85 vec2 distv = P0 - proj; | |
86 vec2 orth = vec2(-direction.y, direction.x); | |
87 float side = sign(dot(P0, orth)); | |
88 float v = side * length(distv * scale_); | |
89 | |
90 // return step(0, v); | |
91 return smoothstep(-sqrt(2.0)/2.0, sqrt(2.0)/2.0, v); | |
92 } | |
93 | |
94 #define eq(a,b) (a == b) | |
95 #define neq(a,b) (a != b) | |
96 | |
97 #define P(x,y) texture2D(textures[0], coord + (1.0 / texsize) * vec2(x, y)).rgb | |
98 | |
99 void main() | |
100 { | |
101 //--------------------------------------- | |
102 // Input Pixel Mapping: -|x|x|x|- | |
103 // x|A|B|C|x | |
104 // x|D|E|F|x | |
105 // x|G|H|I|x | |
106 // -|x|x|x|- | |
107 | |
108 vec2 pos = fract(texcoord * texsize.xy) - vec2(0.5, 0.5); | |
109 vec2 coord = texcoord - pos * (1.0 / texsize.xy); | |
110 | |
111 vec3 A = P(-1,-1); | |
112 vec3 B = P( 0,-1); | |
113 vec3 C = P( 1,-1); | |
114 vec3 D = P(-1, 0); | |
115 vec3 E = P( 0, 0); | |
116 vec3 F = P( 1, 0); | |
117 vec3 G = P(-1, 1); | |
118 vec3 H = P( 0, 1); | |
119 vec3 I = P( 1, 1); | |
120 | |
121 // blendResult Mapping: x|y| | |
122 // w|z| | |
123 ivec4 blendResult = ivec4(BLEND_NONE,BLEND_NONE,BLEND_NONE,BLEND_NONE); | |
124 | |
125 // Preprocess corners | |
126 // Pixel Tap Mapping: -|-|-|-|- | |
127 // -|-|B|C|- | |
128 // -|D|E|F|x | |
129 // -|G|H|I|x | |
130 // -|-|x|x|- | |
131 if (!((eq(E,F) && eq(H,I)) || (eq(E,H) && eq(F,I)))) | |
132 { | |
133 float dist_H_F = DistYCbCr(G, E) + DistYCbCr(E, C) + DistYCbCr(P(0,2), I) + DistYCbCr(I, P(2,0)) + (4.0 * DistYCbCr(H, F)); | |
134 float dist_E_I = DistYCbCr(D, H) + DistYCbCr(H, P(1,2)) + DistYCbCr(B, F) + DistYCbCr(F, P(2,1)) + (4.0 * DistYCbCr(E, I)); | |
135 bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_H_F) < dist_E_I; | |
136 blendResult.z = ((dist_H_F < dist_E_I) && neq(E,F) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; | |
137 } | |
138 | |
139 | |
140 // Pixel Tap Mapping: -|-|-|-|- | |
141 // -|A|B|-|- | |
142 // x|D|E|F|- | |
143 // x|G|H|I|- | |
144 // -|x|x|-|- | |
145 if (!((eq(D,E) && eq(G,H)) || (eq(D,G) && eq(E,H)))) | |
146 { | |
147 float dist_G_E = DistYCbCr(P(-2,1) , D) + DistYCbCr(D, B) + DistYCbCr(P(-1,2), H) + DistYCbCr(H, F) + (4.0 * DistYCbCr(G, E)); | |
148 float dist_D_H = DistYCbCr(P(-2,0) , G) + DistYCbCr(G, P(0,2)) + DistYCbCr(A, E) + DistYCbCr(E, I) + (4.0 * DistYCbCr(D, H)); | |
149 bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_H) < dist_G_E; | |
150 blendResult.w = ((dist_G_E > dist_D_H) && neq(E,D) && neq(E,H)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; | |
151 } | |
152 | |
153 // Pixel Tap Mapping: -|-|x|x|- | |
154 // -|A|B|C|x | |
155 // -|D|E|F|x | |
156 // -|-|H|I|- | |
157 // -|-|-|-|- | |
158 if (!((eq(B,C) && eq(E,F)) || (eq(B,E) && eq(C,F)))) | |
159 { | |
160 float dist_E_C = DistYCbCr(D, B) + DistYCbCr(B, P(1,-2)) + DistYCbCr(H, F) + DistYCbCr(F, P(2,-1)) + (4.0 * DistYCbCr(E, C)); | |
161 float dist_B_F = DistYCbCr(A, E) + DistYCbCr(E, I) + DistYCbCr(P(0,-2), C) + DistYCbCr(C, P(2,0)) + (4.0 * DistYCbCr(B, F)); | |
162 bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_B_F) < dist_E_C; | |
163 blendResult.y = ((dist_E_C > dist_B_F) && neq(E,B) && neq(E,F)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; | |
164 } | |
165 | |
166 // Pixel Tap Mapping: -|x|x|-|- | |
167 // x|A|B|C|- | |
168 // x|D|E|F|- | |
169 // -|G|H|-|- | |
170 // -|-|-|-|- | |
171 if (!((eq(A,B) && eq(D,E)) || (eq(A,D) && eq(B,E)))) | |
172 { | |
173 float dist_D_B = DistYCbCr(P(-2,0), A) + DistYCbCr(A, P(0,-2)) + DistYCbCr(G, E) + DistYCbCr(E, C) + (4.0 * DistYCbCr(D, B)); | |
174 float dist_A_E = DistYCbCr(P(-2,-1), D) + DistYCbCr(D, H) + DistYCbCr(P(-1,-2), B) + DistYCbCr(B, F) + (4.0 * DistYCbCr(A, E)); | |
175 bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_D_B) < dist_A_E; | |
176 blendResult.x = ((dist_D_B < dist_A_E) && neq(E,D) && neq(E,B)) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; | |
177 } | |
178 | |
179 vec3 res = E; | |
180 | |
181 // Pixel Tap Mapping: -|-|-|-|- | |
182 // -|-|B|C|- | |
183 // -|D|E|F|x | |
184 // -|G|H|I|x | |
185 // -|-|x|x|- | |
186 if(blendResult.z != BLEND_NONE) | |
187 { | |
188 float dist_F_G = DistYCbCr(F, G); | |
189 float dist_H_C = DistYCbCr(H, C); | |
190 bool doLineBlend = (blendResult.z == BLEND_DOMINANT || | |
191 !((blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || (blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || | |
192 (IsPixEqual(G, H) && IsPixEqual(H, I) && IsPixEqual(I, F) && IsPixEqual(F, C) && !IsPixEqual(E, I)))); | |
193 | |
194 vec2 origin = vec2(0.0, 1.0 / sqrt(2.0)); | |
195 vec2 direction = vec2(1.0, -1.0); | |
196 if(doLineBlend) | |
197 { | |
198 bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_F_G <= dist_H_C) && neq(E,G) && neq(D,G); | |
199 bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_H_C <= dist_F_G) && neq(E,C) && neq(B,C); | |
200 origin = haveShallowLine? vec2(0.0, 0.25) : vec2(0.0, 0.5); | |
201 direction.x += haveShallowLine? 1.0: 0.0; | |
202 direction.y -= haveSteepLine? 1.0: 0.0; | |
203 } | |
204 | |
205 vec3 blendPix = mix(H,F, step(DistYCbCr(E, F), DistYCbCr(E, H))); | |
206 res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); | |
207 } | |
208 | |
209 // Pixel Tap Mapping: -|-|-|-|- | |
210 // -|A|B|-|- | |
211 // x|D|E|F|- | |
212 // x|G|H|I|- | |
213 // -|x|x|-|- | |
214 if(blendResult.w != BLEND_NONE) | |
215 { | |
216 float dist_H_A = DistYCbCr(H, A); | |
217 float dist_D_I = DistYCbCr(D, I); | |
218 bool doLineBlend = (blendResult.w == BLEND_DOMINANT || | |
219 !((blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || (blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || | |
220 (IsPixEqual(A, D) && IsPixEqual(D, G) && IsPixEqual(G, H) && IsPixEqual(H, I) && !IsPixEqual(E, G)))); | |
221 | |
222 vec2 origin = vec2(-1.0 / sqrt(2.0), 0.0); | |
223 vec2 direction = vec2(1.0, 1.0); | |
224 if(doLineBlend) | |
225 { | |
226 bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_H_A <= dist_D_I) && neq(E,A) && neq(B,A); | |
227 bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_D_I <= dist_H_A) && neq(E,I) && neq(F,I); | |
228 origin = haveShallowLine? vec2(-0.25, 0.0) : vec2(-0.5, 0.0); | |
229 direction.y += haveShallowLine? 1.0: 0.0; | |
230 direction.x += haveSteepLine? 1.0: 0.0; | |
231 } | |
232 origin = origin; | |
233 direction = direction; | |
234 | |
235 vec3 blendPix = mix(H,D, step(DistYCbCr(E, D), DistYCbCr(E, H))); | |
236 res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); | |
237 } | |
238 | |
239 // Pixel Tap Mapping: -|-|x|x|- | |
240 // -|A|B|C|x | |
241 // -|D|E|F|x | |
242 // -|-|H|I|- | |
243 // -|-|-|-|- | |
244 if(blendResult.y != BLEND_NONE) | |
245 { | |
246 float dist_B_I = DistYCbCr(B, I); | |
247 float dist_F_A = DistYCbCr(F, A); | |
248 bool doLineBlend = (blendResult.y == BLEND_DOMINANT || | |
249 !((blendResult.x != BLEND_NONE && !IsPixEqual(E, I)) || (blendResult.z != BLEND_NONE && !IsPixEqual(E, A)) || | |
250 (IsPixEqual(I, F) && IsPixEqual(F, C) && IsPixEqual(C, B) && IsPixEqual(B, A) && !IsPixEqual(E, C)))); | |
251 | |
252 vec2 origin = vec2(1.0 / sqrt(2.0), 0.0); | |
253 vec2 direction = vec2(-1.0, -1.0); | |
254 | |
255 if(doLineBlend) | |
256 { | |
257 bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_B_I <= dist_F_A) && neq(E,I) && neq(H,I); | |
258 bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_F_A <= dist_B_I) && neq(E,A) && neq(D,A); | |
259 origin = haveShallowLine? vec2(0.25, 0.0) : vec2(0.5, 0.0); | |
260 direction.y -= haveShallowLine? 1.0: 0.0; | |
261 direction.x -= haveSteepLine? 1.0: 0.0; | |
262 } | |
263 | |
264 vec3 blendPix = mix(F,B, step(DistYCbCr(E, B), DistYCbCr(E, F))); | |
265 res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); | |
266 } | |
267 | |
268 // Pixel Tap Mapping: -|x|x|-|- | |
269 // x|A|B|C|- | |
270 // x|D|E|F|- | |
271 // -|G|H|-|- | |
272 // -|-|-|-|- | |
273 if(blendResult.x != BLEND_NONE) | |
274 { | |
275 float dist_D_C = DistYCbCr(D, C); | |
276 float dist_B_G = DistYCbCr(B, G); | |
277 bool doLineBlend = (blendResult.x == BLEND_DOMINANT || | |
278 !((blendResult.w != BLEND_NONE && !IsPixEqual(E, C)) || (blendResult.y != BLEND_NONE && !IsPixEqual(E, G)) || | |
279 (IsPixEqual(C, B) && IsPixEqual(B, A) && IsPixEqual(A, D) && IsPixEqual(D, G) && !IsPixEqual(E, A)))); | |
280 | |
281 vec2 origin = vec2(0.0, -1.0 / sqrt(2.0)); | |
282 vec2 direction = vec2(-1.0, 1.0); | |
283 if(doLineBlend) | |
284 { | |
285 bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_D_C <= dist_B_G) && neq(E,C) && neq(F,C); | |
286 bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_B_G <= dist_D_C) && neq(E,G) && neq(H,G); | |
287 origin = haveShallowLine? vec2(0.0, -0.25) : vec2(0.0, -0.5); | |
288 direction.x -= haveShallowLine? 1.0: 0.0; | |
289 direction.y += haveSteepLine? 1.0: 0.0; | |
290 } | |
291 | |
292 vec3 blendPix = mix(D,B, step(DistYCbCr(E, B), DistYCbCr(E, D))); | |
293 res = mix(res, blendPix, get_left_ratio(pos, origin, direction, scale)); | |
294 } | |
295 | |
296 gl_FragColor = vec4(res, 1.0); | |
297 } |