@thenick775/mgba-wasm 2.4.0 → 2.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mgba.d.ts +483 -11
- package/dist/mgba.data +3480 -0
- package/dist/mgba.js +2 -13272
- package/dist/mgba.wasm +0 -0
- package/dist/mgba.wasm.map +1 -1
- package/dist/mgba.wrapper.js +14 -0
- package/package.json +5 -3
package/dist/mgba.data
ADDED
|
@@ -0,0 +1,3480 @@
|
|
|
1
|
+
varying vec2 texCoord;
|
|
2
|
+
uniform sampler2D tex;
|
|
3
|
+
uniform vec2 texSize;
|
|
4
|
+
uniform vec2 outputSize;
|
|
5
|
+
|
|
6
|
+
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
|
7
|
+
precision highp float;
|
|
8
|
+
#else
|
|
9
|
+
precision mediump float;
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
void main() {
|
|
13
|
+
vec3 c = texture2D(tex, texCoord).rgb;
|
|
14
|
+
|
|
15
|
+
// gamma-ish shaping the original shader intended
|
|
16
|
+
c = pow(c * vec3(0.8), vec3(1.8)) + vec3(0.16);
|
|
17
|
+
|
|
18
|
+
// Stripe mask aligned to OUTPUT pixels (stable across scale factors)
|
|
19
|
+
float x = mod(floor(gl_FragCoord.x), 3.0);
|
|
20
|
+
vec3 maskX =
|
|
21
|
+
(x < 0.5) ? vec3(0.2, 0.2, 1.0) :
|
|
22
|
+
(x < 1.5) ? vec3(0.2, 1.0, 0.2) :
|
|
23
|
+
vec3(1.0, 0.2, 0.2);
|
|
24
|
+
|
|
25
|
+
float y = mod(floor(gl_FragCoord.y), 4.0);
|
|
26
|
+
vec3 maskY = (y < 3.5) ? vec3(1.0) : vec3(0.8);
|
|
27
|
+
|
|
28
|
+
c *= (maskX * maskY);
|
|
29
|
+
|
|
30
|
+
gl_FragColor = vec4(c, 1.0);
|
|
31
|
+
}
|
|
32
|
+
[shader]
|
|
33
|
+
name=AGB-001
|
|
34
|
+
author=endrift
|
|
35
|
+
description=A glorious recreation of the original Game Boy Advance
|
|
36
|
+
passes=1
|
|
37
|
+
|
|
38
|
+
[pass.0]
|
|
39
|
+
fragmentShader=agb001.fs
|
|
40
|
+
blend=1
|
|
41
|
+
width=-3
|
|
42
|
+
height=-4
|
|
43
|
+
varying vec2 texCoord;
|
|
44
|
+
uniform sampler2D tex;
|
|
45
|
+
uniform float reflectionBrightness;
|
|
46
|
+
uniform vec2 reflectionDistance;
|
|
47
|
+
uniform float lightBrightness;
|
|
48
|
+
|
|
49
|
+
const float speed = 2.0;
|
|
50
|
+
const float decay = 2.0;
|
|
51
|
+
const float coeff = 2.5;
|
|
52
|
+
|
|
53
|
+
void main() {
|
|
54
|
+
float sp = pow(speed, lightBrightness);
|
|
55
|
+
float dc = pow(decay, -lightBrightness);
|
|
56
|
+
float s = (sp - dc) / (sp + dc);
|
|
57
|
+
vec2 radius = (texCoord.st - vec2(0.5, 0.5)) * vec2(coeff * s);
|
|
58
|
+
radius = pow(abs(radius), vec2(4.0));
|
|
59
|
+
vec3 bleed = vec3(0.12, 0.14, 0.19);
|
|
60
|
+
bleed += (dot(radius, radius) + vec3(0.02, 0.03, 0.05)) * vec3(0.14, 0.18, 0.2);
|
|
61
|
+
|
|
62
|
+
vec4 color = texture2D(tex, texCoord);
|
|
63
|
+
color.rgb += pow(bleed, pow(vec3(lightBrightness), vec3(-0.5)));
|
|
64
|
+
|
|
65
|
+
vec4 reflection = texture2D(tex, texCoord - reflectionDistance);
|
|
66
|
+
color.rgb += reflection.rgb * reflectionBrightness;
|
|
67
|
+
color.a = 1.0;
|
|
68
|
+
gl_FragColor = color;
|
|
69
|
+
}
|
|
70
|
+
varying vec2 texCoord;
|
|
71
|
+
uniform sampler2D tex;
|
|
72
|
+
uniform vec2 texSize;
|
|
73
|
+
|
|
74
|
+
const vec3 kArrayX0 = vec3(0.2, 0.2, 1.0);
|
|
75
|
+
const vec3 kArrayX1 = vec3(0.2, 1.0, 0.2);
|
|
76
|
+
const vec3 kArrayX2 = vec3(1.0, 0.2, 0.2);
|
|
77
|
+
const vec3 kArrayY0 = vec3(1.0, 1.0, 1.0);
|
|
78
|
+
const vec3 kArrayY1 = vec3(1.0, 1.0, 1.0);
|
|
79
|
+
const vec3 kArrayY2 = vec3(1.0, 1.0, 1.0);
|
|
80
|
+
const vec3 kArrayY3 = vec3(0.9, 0.9, 0.9);
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
void main() {
|
|
84
|
+
vec4 color = texture2D(tex, texCoord);
|
|
85
|
+
// WebGL1-safe: precomputed constant LUTs (no runtime array writes)
|
|
86
|
+
color.rgb = pow(color.rgb, vec3(1.6, 1.6, 1.6));
|
|
87
|
+
int xi = int(mod(texCoord.s * texSize.x * 3.0, 3.0));
|
|
88
|
+
vec3 ax = (xi == 0) ? kArrayX0 : ((xi == 1) ? kArrayX1 : kArrayX2);
|
|
89
|
+
int yi = int(mod(texCoord.t * texSize.y * 4.0, 4.0));
|
|
90
|
+
vec3 ay = (yi == 0) ? kArrayY0 : ((yi == 1) ? kArrayY1 : ((yi == 2) ? kArrayY2 : kArrayY3));
|
|
91
|
+
color.rgb *= ax;
|
|
92
|
+
color.rgb *= ay;
|
|
93
|
+
color.a = 0.8;
|
|
94
|
+
gl_FragColor = color;
|
|
95
|
+
}
|
|
96
|
+
[shader]
|
|
97
|
+
name=AGS-001
|
|
98
|
+
author=endrift
|
|
99
|
+
description=A pristine recreation of the illuminated Game Boy Advance SP
|
|
100
|
+
passes=2
|
|
101
|
+
|
|
102
|
+
[pass.0]
|
|
103
|
+
fragmentShader=ags001.fs
|
|
104
|
+
blend=1
|
|
105
|
+
width=-3
|
|
106
|
+
height=-4
|
|
107
|
+
|
|
108
|
+
[pass.1]
|
|
109
|
+
fragmentShader=ags001-light.fs
|
|
110
|
+
width=-3
|
|
111
|
+
height=-4
|
|
112
|
+
|
|
113
|
+
[pass.1.uniform.lightBrightness]
|
|
114
|
+
type=float
|
|
115
|
+
default=1
|
|
116
|
+
readableName=Light brightness
|
|
117
|
+
|
|
118
|
+
[pass.1.uniform.reflectionBrightness]
|
|
119
|
+
type=float
|
|
120
|
+
default=0.07
|
|
121
|
+
readableName=Reflection brightness
|
|
122
|
+
|
|
123
|
+
[pass.1.uniform.reflectionDistance]
|
|
124
|
+
type=float2
|
|
125
|
+
default[0]=0
|
|
126
|
+
default[1]=0.025
|
|
127
|
+
readableName=Reflection distance
|
|
128
|
+
// Shader that replicates the LCD Colorspace from a Nintendo DS Lite --
|
|
129
|
+
varying vec2 texCoord;
|
|
130
|
+
varying mat4 profile;
|
|
131
|
+
uniform sampler2D tex;
|
|
132
|
+
uniform vec2 texSize;
|
|
133
|
+
|
|
134
|
+
const float target_gamma = 2.2;
|
|
135
|
+
const float display_gamma = 2.2;
|
|
136
|
+
|
|
137
|
+
void main() {
|
|
138
|
+
// bring out our stored luminance value
|
|
139
|
+
float lum = profile[3].w;
|
|
140
|
+
|
|
141
|
+
// our adjustments need to happen in linear gamma
|
|
142
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma)).rgba;
|
|
143
|
+
|
|
144
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
145
|
+
screen = profile * screen;
|
|
146
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
147
|
+
}
|
|
148
|
+
uniform int color_mode;
|
|
149
|
+
attribute vec4 position;
|
|
150
|
+
varying vec2 texCoord;
|
|
151
|
+
varying mat4 profile;
|
|
152
|
+
|
|
153
|
+
const mat4 DSL_sRGB = mat4(
|
|
154
|
+
0.93, 0.025, 0.008, 0.0, //red channel
|
|
155
|
+
0.14, 0.90, -0.03, 0.0, //green channel
|
|
156
|
+
-0.07, 0.075, 1.022, 0.0, //blue channel
|
|
157
|
+
0.0, 0.0, 0.0, 0.935 //alpha channel
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const mat4 DSL_DCI = mat4(
|
|
161
|
+
0.76, 0.055, 0.0225, 0.0, //red channel
|
|
162
|
+
0.27, 0.875, 0.0225, 0.0, //green channel
|
|
163
|
+
-0.03, 0.07, 0.955, 0.0, //blue channel
|
|
164
|
+
0.0, 0.0, 0.0, 0.97 //alpha channel
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const mat4 DSL_Rec2020 = mat4(
|
|
168
|
+
0.585, 0.09, 0.0225, 0.0, //red channel
|
|
169
|
+
0.3725, 0.825, 0.035, 0.0, //green channel
|
|
170
|
+
0.0425, 0.085, 0.9425, 0.0, //blue channel
|
|
171
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
void main() {
|
|
175
|
+
if (color_mode == 1) profile = DSL_sRGB;
|
|
176
|
+
else if (color_mode == 2) profile = DSL_DCI;
|
|
177
|
+
else if (color_mode == 3) profile = DSL_Rec2020;
|
|
178
|
+
|
|
179
|
+
gl_Position = position;
|
|
180
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
181
|
+
}
|
|
182
|
+
[shader]
|
|
183
|
+
name=Nintendo DS Lite Color
|
|
184
|
+
author=Pokefan531 and hunterk
|
|
185
|
+
description=Shader that replicates the LCD Colorspace from a Nintendo DS Lite.
|
|
186
|
+
passes=1
|
|
187
|
+
|
|
188
|
+
[pass.0]
|
|
189
|
+
fragmentShader=dslite-color.fs
|
|
190
|
+
vertexShader=dslite-color.vs
|
|
191
|
+
blend=1
|
|
192
|
+
width=-1
|
|
193
|
+
height=-1
|
|
194
|
+
|
|
195
|
+
[pass.0.uniform.color_mode]
|
|
196
|
+
type=int
|
|
197
|
+
default=1
|
|
198
|
+
min=1
|
|
199
|
+
max=3
|
|
200
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
201
|
+
/*
|
|
202
|
+
fish shader
|
|
203
|
+
|
|
204
|
+
algorithm and original implementation by Miloslav "drummyfish" Ciz
|
|
205
|
+
(tastyfish@seznam.cz)
|
|
206
|
+
|
|
207
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
208
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
209
|
+
in the Software without restriction, including without limitation the rights
|
|
210
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
211
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
212
|
+
furnished to do so, subject to the following conditions:
|
|
213
|
+
|
|
214
|
+
The above copyright notice and this permission notice shall be included in
|
|
215
|
+
all copies or substantial portions of the Software.
|
|
216
|
+
|
|
217
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
218
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
219
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
220
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
221
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
222
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
223
|
+
THE SOFTWARE.
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
uniform sampler2D tex;
|
|
227
|
+
uniform vec2 texSize;
|
|
228
|
+
varying vec2 texCoord;
|
|
229
|
+
|
|
230
|
+
uniform float similarity_threshold;
|
|
231
|
+
|
|
232
|
+
vec4 texel_fetch(sampler2D t, ivec2 c) // because GLSL TexelFetch is not supported
|
|
233
|
+
{
|
|
234
|
+
return texture2D(t, (2.0 * vec2(c) + vec2(1.0,1.0)) / (2.0 * texSize));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
float pixel_brightness(vec4 pixel)
|
|
238
|
+
{
|
|
239
|
+
return 0.21 * pixel.x + 0.72 * pixel.y + 0.07 * pixel.z;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
bool pixel_is_brighter(vec4 pixel1, vec4 pixel2)
|
|
243
|
+
{
|
|
244
|
+
return pixel_brightness(pixel1) > pixel_brightness(pixel2);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
vec3 pixel_to_yuv(vec4 pixel)
|
|
248
|
+
{
|
|
249
|
+
float y = 0.299 * pixel.x + 0.587 * pixel.y + 0.114 * pixel.z;
|
|
250
|
+
return vec3(y, 0.492 * (pixel.z - y), 0.877 * (pixel.x - y));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
bool yuvs_are_similar(vec3 yuv1, vec3 yuv2)
|
|
254
|
+
{
|
|
255
|
+
vec3 yuv_difference = abs(yuv1 - yuv2);
|
|
256
|
+
return yuv_difference.x <= similarity_threshold && yuv_difference.y <= similarity_threshold && yuv_difference.z <= similarity_threshold;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
bool pixels_are_similar(vec4 pixel1, vec4 pixel2)
|
|
260
|
+
{
|
|
261
|
+
vec3 yuv1 = pixel_to_yuv(pixel1);
|
|
262
|
+
vec3 yuv2 = pixel_to_yuv(pixel2);
|
|
263
|
+
|
|
264
|
+
return yuvs_are_similar(yuv1, yuv2);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
vec4 interpolate_nondiagonal(vec4 neighbour1, vec4 neighbour2)
|
|
268
|
+
{
|
|
269
|
+
if (pixels_are_similar(neighbour1,neighbour2))
|
|
270
|
+
return mix(neighbour1,neighbour2,0.5);
|
|
271
|
+
else
|
|
272
|
+
return pixel_is_brighter(neighbour1, neighbour2) ? neighbour1 : neighbour2;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
vec4 mix3(vec4 value1, vec4 value2, vec4 value3)
|
|
276
|
+
{
|
|
277
|
+
return (value1 + value2 + value3) / 3.0;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
vec4 straight_line(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
|
|
281
|
+
{
|
|
282
|
+
return pixel_is_brighter(p2,p0) ? mix(p2,p3,0.5) : mix(p0,p1,0.5);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
vec4 corner(vec4 p0, vec4 p1, vec4 p2, vec4 p3)
|
|
286
|
+
{
|
|
287
|
+
return pixel_is_brighter(p1,p0) ? mix3(p1,p2,p3) : mix3(p0,p1,p2);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
vec4 interpolate_diagonal(vec4 a, vec4 b, vec4 c, vec4 d)
|
|
291
|
+
{
|
|
292
|
+
// a b
|
|
293
|
+
// c d
|
|
294
|
+
|
|
295
|
+
vec3 a_yuv = pixel_to_yuv(a);
|
|
296
|
+
vec3 b_yuv = pixel_to_yuv(b);
|
|
297
|
+
vec3 c_yuv = pixel_to_yuv(c);
|
|
298
|
+
vec3 d_yuv = pixel_to_yuv(d);
|
|
299
|
+
|
|
300
|
+
bool ad = yuvs_are_similar(a_yuv,d_yuv);
|
|
301
|
+
bool bc = yuvs_are_similar(b_yuv,c_yuv);
|
|
302
|
+
bool ab = yuvs_are_similar(a_yuv,b_yuv);
|
|
303
|
+
bool cd = yuvs_are_similar(c_yuv,d_yuv);
|
|
304
|
+
bool ac = yuvs_are_similar(a_yuv,c_yuv);
|
|
305
|
+
bool bd = yuvs_are_similar(b_yuv,d_yuv);
|
|
306
|
+
|
|
307
|
+
if (ad && cd && ab) // all pixels are equal?
|
|
308
|
+
return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
|
|
309
|
+
|
|
310
|
+
else if (ac && cd && ! ab) // corner 1?
|
|
311
|
+
return corner(b,a,d,c);
|
|
312
|
+
else if (bd && cd && ! ab) // corner 2?
|
|
313
|
+
return corner(a,b,c,d);
|
|
314
|
+
else if (ac && ab && ! bd) // corner 3?
|
|
315
|
+
return corner(d,c,b,a);
|
|
316
|
+
else if (ab && bd && ! ac) // corner 4?
|
|
317
|
+
return corner(c,a,d,b);
|
|
318
|
+
|
|
319
|
+
else if (ad && (!bc || pixel_is_brighter(b,a))) // diagonal line 1?
|
|
320
|
+
return mix(a,d,0.5);
|
|
321
|
+
else if (bc && (!ad || pixel_is_brighter(a,b))) // diagonal line 2?
|
|
322
|
+
return mix(b,c,0.5);
|
|
323
|
+
|
|
324
|
+
else if (ab) // horizontal line 1?
|
|
325
|
+
return straight_line(a,b,c,d);
|
|
326
|
+
else if (cd) // horizontal line 2?
|
|
327
|
+
return straight_line(c,d,a,b);
|
|
328
|
+
|
|
329
|
+
else if (ac) // vertical line 1?
|
|
330
|
+
return straight_line(a,c,b,d);
|
|
331
|
+
else if (bd) // vertical line 2?
|
|
332
|
+
return straight_line(b,d,a,c);
|
|
333
|
+
|
|
334
|
+
return( mix(mix(a,b,0.5), mix(c,d,0.5), 0.5) );
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
void main()
|
|
338
|
+
{
|
|
339
|
+
ivec2 pixel_coords2 = ivec2(vec2(texCoord) * vec2(texSize) * 2.0);
|
|
340
|
+
ivec2 pixel_coords = pixel_coords2 / 2;
|
|
341
|
+
|
|
342
|
+
bool x_even = (pixel_coords2.x - (pixel_coords2.x / 2) * 2) == 0;
|
|
343
|
+
bool y_even = (pixel_coords2.y - (pixel_coords2.y / 2) * 2) == 0;
|
|
344
|
+
|
|
345
|
+
if (x_even)
|
|
346
|
+
{
|
|
347
|
+
if (y_even)
|
|
348
|
+
{
|
|
349
|
+
|
|
350
|
+
gl_FragColor = interpolate_diagonal(
|
|
351
|
+
texel_fetch(tex, pixel_coords + ivec2(-1,-1)),
|
|
352
|
+
texel_fetch(tex, pixel_coords + ivec2(0,-1)),
|
|
353
|
+
texel_fetch(tex, pixel_coords + ivec2(-1,0)),
|
|
354
|
+
texel_fetch(tex, pixel_coords + ivec2(0,0))
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
}
|
|
358
|
+
else
|
|
359
|
+
{
|
|
360
|
+
gl_FragColor = interpolate_nondiagonal
|
|
361
|
+
(
|
|
362
|
+
texel_fetch(tex, pixel_coords + ivec2(-1,0)),
|
|
363
|
+
texel_fetch(tex, pixel_coords)
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
else if (y_even)
|
|
368
|
+
{
|
|
369
|
+
gl_FragColor = interpolate_nondiagonal
|
|
370
|
+
(
|
|
371
|
+
texel_fetch(tex, pixel_coords + ivec2(0,-1)),
|
|
372
|
+
texel_fetch(tex, pixel_coords)
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
else
|
|
376
|
+
gl_FragColor = texel_fetch(tex, pixel_coords);
|
|
377
|
+
}
|
|
378
|
+
[shader]
|
|
379
|
+
name=fish
|
|
380
|
+
author=Drummyfish
|
|
381
|
+
description=Attempts to keep thin lines thin.
|
|
382
|
+
passes=1
|
|
383
|
+
|
|
384
|
+
[pass.0]
|
|
385
|
+
fragmentShader=fish.fs
|
|
386
|
+
integerScaling=1
|
|
387
|
+
|
|
388
|
+
[pass.0.uniform.similarity_threshold]
|
|
389
|
+
type=float
|
|
390
|
+
default=0.2
|
|
391
|
+
readableName=Similarity Threshold
|
|
392
|
+
min=0
|
|
393
|
+
max=1
|
|
394
|
+
// Shader that replicates the LCD Colorspace from a Gameboy Micro (OXY-001) --
|
|
395
|
+
varying vec2 texCoord;
|
|
396
|
+
varying mat4 profile;
|
|
397
|
+
uniform sampler2D tex;
|
|
398
|
+
uniform vec2 texSize;
|
|
399
|
+
|
|
400
|
+
const float target_gamma = 2.2;
|
|
401
|
+
const float display_gamma = 2.2;
|
|
402
|
+
|
|
403
|
+
void main() {
|
|
404
|
+
// bring out our stored luminance value
|
|
405
|
+
float lum = profile[3].w;
|
|
406
|
+
|
|
407
|
+
// our adjustments need to happen in linear gamma
|
|
408
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma)).rgba;
|
|
409
|
+
|
|
410
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
411
|
+
screen = profile * screen;
|
|
412
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
413
|
+
}
|
|
414
|
+
uniform int color_mode;
|
|
415
|
+
attribute vec4 position;
|
|
416
|
+
varying vec2 texCoord;
|
|
417
|
+
varying mat4 profile;
|
|
418
|
+
|
|
419
|
+
const mat4 GBM_sRGB = mat4(
|
|
420
|
+
0.8025, 0.10, 0.1225, 0.0, //red channel
|
|
421
|
+
0.31, 0.6875, 0.1125, 0.0, //green channel
|
|
422
|
+
-0.1125, 0.2125, 0.765, 0.0, //blue channel
|
|
423
|
+
0.0, 0.0, 0.0, 0.9 //alpha channel
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
const mat4 GBM_DCI = mat4(
|
|
427
|
+
0.6675, 0.125, 0.13, 0.0, //red channel
|
|
428
|
+
0.3825, 0.675, 0.1475, 0.0, //green channel
|
|
429
|
+
-0.05, 0.20, 0.7225, 0.0, //blue channel
|
|
430
|
+
0.0, 0.0, 0.0, 0.96 //alpha channel
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const mat4 GBM_Rec2020 = mat4(
|
|
434
|
+
0.525, 0.15, 0.13, 0.0, //red channel
|
|
435
|
+
0.43, 0.65, 0.155, 0.0, //green channel
|
|
436
|
+
0.045, 0.20, 0.715, 0.0, //blue channel
|
|
437
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
void main() {
|
|
441
|
+
if (color_mode == 1) profile = GBM_sRGB;
|
|
442
|
+
else if (color_mode == 2) profile = GBM_DCI;
|
|
443
|
+
else if (color_mode == 3) profile = GBM_Rec2020;
|
|
444
|
+
|
|
445
|
+
gl_Position = position;
|
|
446
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
447
|
+
}
|
|
448
|
+
[shader]
|
|
449
|
+
name=GB Micro Color
|
|
450
|
+
author=Pokefan531 and hunterk
|
|
451
|
+
description=Shader that replicates the LCD Colorspace from a Gameboy Micro (OXY-001).
|
|
452
|
+
passes=1
|
|
453
|
+
|
|
454
|
+
[pass.0]
|
|
455
|
+
fragmentShader=gb-micro-color.fs
|
|
456
|
+
vertexShader=gb-micro-color.vs
|
|
457
|
+
blend=1
|
|
458
|
+
width=-1
|
|
459
|
+
height=-1
|
|
460
|
+
|
|
461
|
+
[pass.0.uniform.color_mode]
|
|
462
|
+
type=int
|
|
463
|
+
default=1
|
|
464
|
+
min=1
|
|
465
|
+
max=3
|
|
466
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
467
|
+
// Shader that replicates the LCD Colorspace from Gameboy Advance --
|
|
468
|
+
varying vec2 texCoord;
|
|
469
|
+
varying mat4 profile;
|
|
470
|
+
uniform sampler2D tex;
|
|
471
|
+
uniform vec2 texSize;
|
|
472
|
+
|
|
473
|
+
uniform float darken_screen;
|
|
474
|
+
const float target_gamma = 2.0;
|
|
475
|
+
const float display_gamma = 2.0;
|
|
476
|
+
|
|
477
|
+
void main() {
|
|
478
|
+
// bring out our stored luminance value
|
|
479
|
+
float lum = profile[3].w;
|
|
480
|
+
|
|
481
|
+
// our adjustments need to happen in linear gamma
|
|
482
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma + darken_screen)).rgba;
|
|
483
|
+
|
|
484
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
485
|
+
screen = profile * screen;
|
|
486
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
487
|
+
}
|
|
488
|
+
uniform int color_mode;
|
|
489
|
+
attribute vec4 position;
|
|
490
|
+
varying vec2 texCoord;
|
|
491
|
+
varying mat4 profile;
|
|
492
|
+
|
|
493
|
+
const mat4 GBA_sRGB = mat4(
|
|
494
|
+
0.80, 0.135, 0.195, 0.0, //red channel
|
|
495
|
+
0.275, 0.64, 0.155, 0.0, //green channel
|
|
496
|
+
-0.075, 0.225, 0.65, 0.0, //blue channel
|
|
497
|
+
0.0, 0.0, 0.0, 0.93 //alpha channel
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
const mat4 GBA_DCI = mat4(
|
|
501
|
+
0.685, 0.16, 0.20, 0.0, //red channel
|
|
502
|
+
0.34, 0.629, 0.19, 0.0, //green channel
|
|
503
|
+
-0.025, 0.211, 0.61, 0.0, //blue channel
|
|
504
|
+
0.0, 0.0, 0.0, 0.975 //alpha channel
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
const mat4 GBA_Rec2020 = mat4(
|
|
508
|
+
0.555, 0.1825, 0.20, 0.0, //red channel
|
|
509
|
+
0.395, 0.61, 0.195, 0.0, //green channel
|
|
510
|
+
0.05, 0.2075, 0.605, 0.0, //blue channel
|
|
511
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
void main() {
|
|
515
|
+
if (color_mode == 1) profile = GBA_sRGB;
|
|
516
|
+
else if (color_mode == 2) profile = GBA_DCI;
|
|
517
|
+
else if (color_mode == 3) profile = GBA_Rec2020;
|
|
518
|
+
|
|
519
|
+
gl_Position = position;
|
|
520
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
521
|
+
}
|
|
522
|
+
[shader]
|
|
523
|
+
name=GBA Color
|
|
524
|
+
author=Pokefan531 and hunterk
|
|
525
|
+
description=Modifies the color output to simulate the GBA LCD characteristics.
|
|
526
|
+
passes=1
|
|
527
|
+
|
|
528
|
+
[pass.0]
|
|
529
|
+
fragmentShader=gba-color.fs
|
|
530
|
+
vertexShader=gba-color.vs
|
|
531
|
+
blend=1
|
|
532
|
+
width=-1
|
|
533
|
+
height=-1
|
|
534
|
+
|
|
535
|
+
[pass.0.uniform.darken_screen]
|
|
536
|
+
type=float
|
|
537
|
+
default=0.5
|
|
538
|
+
min=0
|
|
539
|
+
max=1
|
|
540
|
+
readableName=Darken Screen
|
|
541
|
+
|
|
542
|
+
[pass.0.uniform.color_mode]
|
|
543
|
+
type=int
|
|
544
|
+
default=1
|
|
545
|
+
min=1
|
|
546
|
+
max=3
|
|
547
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
548
|
+
// Shader that replicates the LCD Colorspace from Gameboy Color --
|
|
549
|
+
varying vec2 texCoord;
|
|
550
|
+
varying mat4 profile;
|
|
551
|
+
uniform sampler2D tex;
|
|
552
|
+
uniform vec2 texSize;
|
|
553
|
+
|
|
554
|
+
uniform float lighten_screen;
|
|
555
|
+
const float target_gamma = 2.2;
|
|
556
|
+
const float display_gamma = 2.2;
|
|
557
|
+
|
|
558
|
+
void main() {
|
|
559
|
+
// bring out our stored luminance value
|
|
560
|
+
float lum = profile[3].w;
|
|
561
|
+
|
|
562
|
+
// our adjustments need to happen in linear gamma
|
|
563
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma - lighten_screen)).rgba;
|
|
564
|
+
|
|
565
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
566
|
+
screen = profile * screen;
|
|
567
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
568
|
+
}
|
|
569
|
+
uniform int color_mode;
|
|
570
|
+
attribute vec4 position;
|
|
571
|
+
varying vec2 texCoord;
|
|
572
|
+
varying mat4 profile;
|
|
573
|
+
|
|
574
|
+
const mat4 GBC_sRGB = mat4(
|
|
575
|
+
0.905, 0.10, 0.1575, 0.0, //red channel
|
|
576
|
+
0.195, 0.65, 0.1425, 0.0, //green channel
|
|
577
|
+
-0.10, 0.25, 0.70, 0.0, //blue channel
|
|
578
|
+
0.0, 0.0, 0.0, 0.91 //alpha channel
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const mat4 GBC_DCI = mat4(
|
|
582
|
+
0.76, 0.125, 0.16, 0.0, //red channel
|
|
583
|
+
0.27, 0.6375, 0.18, 0.0, //green channel
|
|
584
|
+
-0.03, 0.2375, 0.66, 0.0, //blue channel
|
|
585
|
+
0.0, 0.0, 0.0, 0.97 //alpha channel
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
const mat4 GBC_Rec2020 = mat4(
|
|
589
|
+
0.61, 0.155, 0.16, 0.0, //red channel
|
|
590
|
+
0.345, 0.615, 0.1875, 0.0, //green channel
|
|
591
|
+
0.045, 0.23, 0.6525, 0.0, //blue channel
|
|
592
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
void main() {
|
|
596
|
+
if (color_mode == 1) profile = GBC_sRGB;
|
|
597
|
+
else if (color_mode == 2) profile = GBC_DCI;
|
|
598
|
+
else if (color_mode == 3) profile = GBC_Rec2020;
|
|
599
|
+
|
|
600
|
+
gl_Position = position;
|
|
601
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
602
|
+
}
|
|
603
|
+
[shader]
|
|
604
|
+
name=GBC Color
|
|
605
|
+
author=Pokefan531 and hunterk
|
|
606
|
+
description=Modifies the color output to simulate the GBA LCD characteristics.
|
|
607
|
+
passes=1
|
|
608
|
+
|
|
609
|
+
[pass.0]
|
|
610
|
+
fragmentShader=gbc-color.fs
|
|
611
|
+
vertexShader=gbc-color.vs
|
|
612
|
+
blend=1
|
|
613
|
+
width=-1
|
|
614
|
+
height=-1
|
|
615
|
+
|
|
616
|
+
[pass.0.uniform.lighten_screen]
|
|
617
|
+
type=float
|
|
618
|
+
default=1.0
|
|
619
|
+
min=0
|
|
620
|
+
max=1
|
|
621
|
+
readableName=External Lighten Screen
|
|
622
|
+
|
|
623
|
+
[pass.0.uniform.color_mode]
|
|
624
|
+
type=int
|
|
625
|
+
default=1
|
|
626
|
+
min=1
|
|
627
|
+
max=3
|
|
628
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
629
|
+
/**
|
|
630
|
+
* This shader creates a backlight bleeding effect,
|
|
631
|
+
* and an internal reflection or ghosting effect.
|
|
632
|
+
*/
|
|
633
|
+
|
|
634
|
+
varying vec2 texCoord;
|
|
635
|
+
uniform sampler2D tex;
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Determines the color of the backlight bleed.
|
|
639
|
+
* Lower values produce less, dimmer light.
|
|
640
|
+
* Higher values produce brighter or more colorful light.
|
|
641
|
+
* You'll normally want each of these numbers to be close
|
|
642
|
+
* to 1, and not normally lower than 0.
|
|
643
|
+
*/
|
|
644
|
+
uniform vec3 LightColor;
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Affects the shape of the backlight bleed glow.
|
|
648
|
+
* Lower values cause the light bleed to fade out quickly
|
|
649
|
+
* from the edges.
|
|
650
|
+
* Higher values cause the light bleed to fade out more
|
|
651
|
+
* softly and gradually toward the center.
|
|
652
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
653
|
+
*/
|
|
654
|
+
uniform float LightSoftness;
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Lower values result in a less visible or intense
|
|
658
|
+
* backlight bleed.
|
|
659
|
+
* Higher values make the backlight bleed more pronounced.
|
|
660
|
+
* You'll normally want this to be a number close to 0,
|
|
661
|
+
* and not normally higher than 1.
|
|
662
|
+
*/
|
|
663
|
+
uniform float LightIntensity;
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Lower values cause the internal reflection or ghosting
|
|
667
|
+
* effect to be less visible.
|
|
668
|
+
* Higher values cause the effect to be brighter and more
|
|
669
|
+
* visible.
|
|
670
|
+
* You'll normally want this to be a number close to 0,
|
|
671
|
+
* and not normally higher than 1.
|
|
672
|
+
*/
|
|
673
|
+
uniform float ReflectionBrightness;
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Lower values have the internal reflection or ghosting
|
|
677
|
+
* effect appear offset by a lesser distance.
|
|
678
|
+
* Higher values have the effect offset by a greater
|
|
679
|
+
* distance.
|
|
680
|
+
* You'll normally want each of these numbers to be close
|
|
681
|
+
* to 0, and not normally higher than 1.
|
|
682
|
+
*/
|
|
683
|
+
uniform vec2 ReflectionDistance;
|
|
684
|
+
|
|
685
|
+
#define M_PI 3.1415926535897932384626433832795
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Helper to compute backlight bleed intensity
|
|
689
|
+
* for a texCoord input.
|
|
690
|
+
*/
|
|
691
|
+
float getLightIntensity(vec2 coord) {
|
|
692
|
+
vec2 coordCentered = coord - vec2(0.5, 0.5);
|
|
693
|
+
float coordDistCenter = (
|
|
694
|
+
length(coordCentered) / sqrt(0.5)
|
|
695
|
+
);
|
|
696
|
+
vec2 coordQuadrant = vec2(
|
|
697
|
+
1.0 - (1.5 * min(coord.x, 1.0 - coord.x)),
|
|
698
|
+
1.0 - (1.5 * min(coord.y, 1.0 - coord.y))
|
|
699
|
+
);
|
|
700
|
+
float lightIntensityEdges = (
|
|
701
|
+
pow(coordQuadrant.x, 5.0) +
|
|
702
|
+
pow(coordQuadrant.y, 5.0)
|
|
703
|
+
);
|
|
704
|
+
float lightIntensity = (
|
|
705
|
+
(1.0 - LightSoftness) * lightIntensityEdges +
|
|
706
|
+
LightSoftness * coordDistCenter
|
|
707
|
+
);
|
|
708
|
+
return clamp(lightIntensity, 0.0, 1.0);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Helper to convert an intensity value into a white
|
|
713
|
+
* gray color with that intensity. A radial distortion
|
|
714
|
+
* effect with subtle chromatic abberation is applied that
|
|
715
|
+
* makes it look a little more like a real old or cheap
|
|
716
|
+
* backlight, and also helps to reduce color banding.
|
|
717
|
+
*/
|
|
718
|
+
vec3 getWhiteVector(float intensity) {
|
|
719
|
+
const float DeformAmount = 0.0025;
|
|
720
|
+
vec2 texCoordCentered = texCoord - vec2(0.5, 0.5);
|
|
721
|
+
float radians = atan(texCoordCentered.y, texCoordCentered.x);
|
|
722
|
+
float rot = pow(2.0, 4.0 + floor(6.0 * length(texCoordCentered)));
|
|
723
|
+
float deformRed = cos(rot * radians + (2.0 / 3.0 * M_PI));
|
|
724
|
+
float deformGreen = cos(rot * radians);
|
|
725
|
+
float deformBlue = cos(rot * radians + (4.0 / 3.0 * M_PI));
|
|
726
|
+
return clamp(vec3(
|
|
727
|
+
intensity + (deformRed * DeformAmount),
|
|
728
|
+
intensity + (deformGreen * DeformAmount),
|
|
729
|
+
intensity + (deformBlue * DeformAmount)
|
|
730
|
+
), 0.0, 1.0);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
void main() {
|
|
734
|
+
vec3 colorSource = texture2D(tex, texCoord).rgb;
|
|
735
|
+
vec3 lightWhiteVector = getWhiteVector(getLightIntensity(texCoord));
|
|
736
|
+
vec3 colorLight = LightColor * lightWhiteVector;
|
|
737
|
+
vec3 colorReflection = texture2D(tex, texCoord - ReflectionDistance).rgb;
|
|
738
|
+
vec3 colorResult = (
|
|
739
|
+
colorSource +
|
|
740
|
+
(colorLight * LightIntensity) +
|
|
741
|
+
(colorReflection * ReflectionBrightness)
|
|
742
|
+
);
|
|
743
|
+
gl_FragColor = vec4(
|
|
744
|
+
colorResult,
|
|
745
|
+
1.0
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* This shader imitates the GameBoy Color subpixel
|
|
750
|
+
* arrangement.
|
|
751
|
+
*/
|
|
752
|
+
|
|
753
|
+
varying vec2 texCoord;
|
|
754
|
+
uniform sampler2D tex;
|
|
755
|
+
uniform vec2 texSize;
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Adds a base color to everything.
|
|
759
|
+
* Lower values make black colors darker.
|
|
760
|
+
* Higher values make black colors lighter.
|
|
761
|
+
* You'll normally want each of these numbers to be close
|
|
762
|
+
* to 0, and not normally higher than 1.
|
|
763
|
+
*/
|
|
764
|
+
uniform vec3 BaseColor;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Modifies the contrast or saturation of the image.
|
|
768
|
+
* Lower values make the image more gray and higher values
|
|
769
|
+
* make it more colorful.
|
|
770
|
+
* A value of 1 represents a normal, baseline level of
|
|
771
|
+
* contrast.
|
|
772
|
+
* You'll normally want this to be somewhere around 1.
|
|
773
|
+
*/
|
|
774
|
+
uniform float SourceContrast;
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Modifies the luminosity of the image.
|
|
778
|
+
* Lower values make the image darker and higher values make
|
|
779
|
+
* it lighter.
|
|
780
|
+
* A value of 1 represents normal, baseline luminosity.
|
|
781
|
+
* You'll normally want this to be somewhere around 1.
|
|
782
|
+
*/
|
|
783
|
+
uniform float SourceLuminosity;
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Lower values look more like a sharp, unshaded image.
|
|
787
|
+
* Higher values look more like an LCD display with subpixels.
|
|
788
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
789
|
+
*/
|
|
790
|
+
uniform float SubpixelBlendAmount;
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Lower values make subpixels darker.
|
|
794
|
+
* Higher values make them lighter and over-bright.
|
|
795
|
+
* A value of 1 represents a normal, baseline gamma value.
|
|
796
|
+
* You'll normally want this to be somewhere around 1.
|
|
797
|
+
*/
|
|
798
|
+
uniform float SubpixelGamma;
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Higher values allow subpixels to be more blended-together
|
|
802
|
+
* and brighter.
|
|
803
|
+
* Lower values keep subpixel colors more separated.
|
|
804
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
805
|
+
*/
|
|
806
|
+
uniform float SubpixelColorBleed;
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Determines the distance between subpixels.
|
|
810
|
+
* Lower values put the red, green, and blue subpixels
|
|
811
|
+
* within a single pixel closer together.
|
|
812
|
+
* Higher values put them farther apart.
|
|
813
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
814
|
+
*/
|
|
815
|
+
uniform float SubpixelSpread;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Determines the vertical offset of subpixels within
|
|
819
|
+
* a pixel.
|
|
820
|
+
* Lower values put the red, green, and blue subpixels
|
|
821
|
+
* within a single pixel higher up.
|
|
822
|
+
* Higher values put them further down.
|
|
823
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
824
|
+
*/
|
|
825
|
+
uniform float SubpixelVerticalOffset;
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Lower values make the subpixels horizontally thinner,
|
|
829
|
+
* and higher values make them thicker.
|
|
830
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
831
|
+
*/
|
|
832
|
+
uniform float SubpixelLightWidth;
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Lower values make the subpixels vertically taller,
|
|
836
|
+
* and higher values make them shorter.
|
|
837
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
838
|
+
*/
|
|
839
|
+
uniform float SubpixelLightHeight;
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Lower values make the subpixels sharper and more
|
|
843
|
+
* individually distinct.
|
|
844
|
+
* Higher values add an increasingly intense glowing
|
|
845
|
+
* effect around each subpixel.
|
|
846
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
847
|
+
*/
|
|
848
|
+
uniform float SubpixelLightGlow;
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Scale the size of pixels up or down.
|
|
852
|
+
* Useful for looking at larger than 8x8 subpixel sizes.
|
|
853
|
+
* You'll normally want this number to be exactly 1,
|
|
854
|
+
* meaning that every group of 3 subpixels corresponds
|
|
855
|
+
* to one pixel in the display.
|
|
856
|
+
*/
|
|
857
|
+
uniform float SubpixelScale;
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* GBC subpixels are roughly rectangular shaped, but
|
|
861
|
+
* with a rectangular gap in the lower-right corner.
|
|
862
|
+
* Lower values make the lower-right gap in each GBC
|
|
863
|
+
* subpixel less distinct. A value of 0 results in no
|
|
864
|
+
* gap being shown at all.
|
|
865
|
+
* Higher values make the gap more distinct.
|
|
866
|
+
* You'll normally want this to be a number from 0 to 1.
|
|
867
|
+
*/
|
|
868
|
+
uniform float SubpixelTabHeight;
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* The following three uniforms decide the base colors
|
|
872
|
+
* of each of the subpixels.
|
|
873
|
+
*
|
|
874
|
+
* Default subpixel colors are based on this resource:
|
|
875
|
+
* https://gbcc.dev/technology/
|
|
876
|
+
* R: #FF7145 (1.00, 0.44, 0.27)
|
|
877
|
+
* G: #C1D650 (0.75, 0.84, 0.31)
|
|
878
|
+
* B: #3BCEFF (0.23, 0.81, 1.00)
|
|
879
|
+
*/
|
|
880
|
+
uniform vec3 SubpixelColorRed; // vec3(1.00, 0.38, 0.22);
|
|
881
|
+
uniform vec3 SubpixelColorGreen; // vec3(0.60, 0.88, 0.30);
|
|
882
|
+
uniform vec3 SubpixelColorBlue; // vec3(0.23, 0.65, 1.00);
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Helper to get luminosity of an RGB color.
|
|
886
|
+
* Used with HCL color space related code.
|
|
887
|
+
*/
|
|
888
|
+
float getColorLumosity(in vec3 rgb) {
|
|
889
|
+
return (
|
|
890
|
+
(rgb.r * (5.0 / 16.0)) +
|
|
891
|
+
(rgb.g * (9.0 / 16.0)) +
|
|
892
|
+
(rgb.b * (2.0 / 16.0))
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Helper to convert RGB color to HCL. (Hue, Chroma, Luma)
|
|
898
|
+
*/
|
|
899
|
+
vec3 convertRgbToHcl(in vec3 rgb) {
|
|
900
|
+
float xMin = min(rgb.r, min(rgb.g, rgb.b));
|
|
901
|
+
float xMax = max(rgb.r, max(rgb.g, rgb.b));
|
|
902
|
+
float c = xMax - xMin;
|
|
903
|
+
float l = getColorLumosity(rgb);
|
|
904
|
+
float h = mod((
|
|
905
|
+
c == 0 ? 0.0 :
|
|
906
|
+
xMax == rgb.r ? ((rgb.g - rgb.b) / c) :
|
|
907
|
+
xMax == rgb.g ? ((rgb.b - rgb.r) / c) + 2.0 :
|
|
908
|
+
xMax == rgb.b ? ((rgb.r - rgb.g) / c) + 4.0 :
|
|
909
|
+
0.0
|
|
910
|
+
), 6.0);
|
|
911
|
+
return vec3(h, c, l);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Helper to convert HCL color to RGB. (Hue, Chroma, Luma)
|
|
916
|
+
*/
|
|
917
|
+
vec3 convertHclToRgb(in vec3 hcl) {
|
|
918
|
+
vec3 rgb;
|
|
919
|
+
float h = mod(hcl.x, 6.0);
|
|
920
|
+
float c = hcl.y;
|
|
921
|
+
float l = hcl.z;
|
|
922
|
+
float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
|
|
923
|
+
if(h <= 1.0) {
|
|
924
|
+
rgb = vec3(c, x, 0.0);
|
|
925
|
+
}
|
|
926
|
+
else if(h <= 2.0) {
|
|
927
|
+
rgb = vec3(x, c, 0.0);
|
|
928
|
+
}
|
|
929
|
+
else if(h <= 3.0) {
|
|
930
|
+
rgb = vec3(0.0, c, x);
|
|
931
|
+
}
|
|
932
|
+
else if(h <= 4.0) {
|
|
933
|
+
rgb = vec3(0.0, x, c);
|
|
934
|
+
}
|
|
935
|
+
else if(h <= 5.0) {
|
|
936
|
+
rgb = vec3(x, 0.0, c);
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
rgb = vec3(c, 0.0, x);
|
|
940
|
+
}
|
|
941
|
+
float lRgb = getColorLumosity(rgb);
|
|
942
|
+
float m = l - lRgb;
|
|
943
|
+
return clamp(vec3(m, m, m) + rgb, 0.0, 1.0);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Helper to check if a point is contained within
|
|
948
|
+
* a rectangular area.
|
|
949
|
+
*/
|
|
950
|
+
bool getPointInRect(
|
|
951
|
+
vec2 point,
|
|
952
|
+
vec2 rectTopLeft,
|
|
953
|
+
vec2 rectBottomRight
|
|
954
|
+
) {
|
|
955
|
+
return (
|
|
956
|
+
point.x >= rectTopLeft.x &&
|
|
957
|
+
point.y >= rectTopLeft.y &&
|
|
958
|
+
point.x <= rectBottomRight.x &&
|
|
959
|
+
point.y <= rectBottomRight.y
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Helper to get the nearest offset vector from a
|
|
965
|
+
* point to a line segment.
|
|
966
|
+
* (The length of this offset vector is the nearest
|
|
967
|
+
* distance from the point to the line segment.)
|
|
968
|
+
* Thank you to https://stackoverflow.com/a/1501725
|
|
969
|
+
*/
|
|
970
|
+
vec2 getPointLineDistance(
|
|
971
|
+
vec2 point,
|
|
972
|
+
vec2 line0,
|
|
973
|
+
vec2 line1
|
|
974
|
+
) {
|
|
975
|
+
vec2 lineDelta = line0 - line1;
|
|
976
|
+
float lineLengthSq = dot(lineDelta, lineDelta);
|
|
977
|
+
if(lineLengthSq <= 0) {
|
|
978
|
+
return line0 - point;
|
|
979
|
+
}
|
|
980
|
+
float t = (
|
|
981
|
+
dot(point - line0, line1 - line0) / lineLengthSq
|
|
982
|
+
);
|
|
983
|
+
vec2 projection = (
|
|
984
|
+
line0 + clamp(t, 0.0, 1.0) * (line1 - line0)
|
|
985
|
+
);
|
|
986
|
+
return projection - point;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Helper to get the nearest offset vector from a
|
|
991
|
+
* point to a rectangle.
|
|
992
|
+
* Returns (0, 0) for points within the rectangle.
|
|
993
|
+
*/
|
|
994
|
+
vec2 getPointRectDistance(
|
|
995
|
+
vec2 point,
|
|
996
|
+
vec2 rectTopLeft,
|
|
997
|
+
vec2 rectBottomRight
|
|
998
|
+
) {
|
|
999
|
+
if(getPointInRect(point, rectTopLeft, rectBottomRight)) {
|
|
1000
|
+
return vec2(0.0, 0.0);
|
|
1001
|
+
}
|
|
1002
|
+
vec2 rectTopRight = vec2(rectBottomRight.x, rectTopLeft.y);
|
|
1003
|
+
vec2 rectBottomLeft = vec2(rectTopLeft.x, rectBottomRight.y);
|
|
1004
|
+
vec2 v0 = getPointLineDistance(point, rectTopLeft, rectTopRight);
|
|
1005
|
+
vec2 v1 = getPointLineDistance(point, rectBottomLeft, rectBottomRight);
|
|
1006
|
+
vec2 v2 = getPointLineDistance(point, rectTopLeft, rectBottomLeft);
|
|
1007
|
+
vec2 v3 = getPointLineDistance(point, rectTopRight, rectBottomRight);
|
|
1008
|
+
float v0LengthSq = dot(v0, v0);
|
|
1009
|
+
float v1LengthSq = dot(v1, v1);
|
|
1010
|
+
float v2LengthSq = dot(v2, v2);
|
|
1011
|
+
float v3LengthSq = dot(v3, v3);
|
|
1012
|
+
float minLengthSq = min(
|
|
1013
|
+
min(v0LengthSq, v1LengthSq),
|
|
1014
|
+
min(v2LengthSq, v3LengthSq)
|
|
1015
|
+
);
|
|
1016
|
+
if(minLengthSq == v0LengthSq) {
|
|
1017
|
+
return v0;
|
|
1018
|
+
}
|
|
1019
|
+
else if(minLengthSq == v1LengthSq) {
|
|
1020
|
+
return v1;
|
|
1021
|
+
}
|
|
1022
|
+
else if(minLengthSq == v2LengthSq) {
|
|
1023
|
+
return v2;
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
return v3;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Helper to get the nearest offset vector from a
|
|
1032
|
+
* point to a subpixel.
|
|
1033
|
+
* GBC subpixels are roughly rectangular in shape,
|
|
1034
|
+
* but have a rectangular gap in their bottom-left
|
|
1035
|
+
* corner.
|
|
1036
|
+
* Returns (0, 0) for points within the subpixel.
|
|
1037
|
+
*/
|
|
1038
|
+
vec2 getPointSubpixelDistance(
|
|
1039
|
+
vec2 point,
|
|
1040
|
+
vec2 subpixelCenter,
|
|
1041
|
+
vec2 subpixelSizeHalf
|
|
1042
|
+
) {
|
|
1043
|
+
float rectLeft = subpixelCenter.x - subpixelSizeHalf.x;
|
|
1044
|
+
float rectRight = subpixelCenter.x + subpixelSizeHalf.x;
|
|
1045
|
+
float rectTop = subpixelCenter.y - subpixelSizeHalf.y;
|
|
1046
|
+
float rectBottom = subpixelCenter.y + subpixelSizeHalf.y;
|
|
1047
|
+
vec2 offsetLeft = getPointRectDistance(
|
|
1048
|
+
point,
|
|
1049
|
+
vec2(rectLeft, rectTop + SubpixelTabHeight),
|
|
1050
|
+
vec2(subpixelCenter.x, rectBottom)
|
|
1051
|
+
);
|
|
1052
|
+
vec2 offsetRight = getPointRectDistance(
|
|
1053
|
+
point,
|
|
1054
|
+
vec2(subpixelCenter.x, rectTop),
|
|
1055
|
+
vec2(rectRight, rectBottom)
|
|
1056
|
+
);
|
|
1057
|
+
float offsetLeftLengthSq = dot(offsetLeft, offsetLeft);
|
|
1058
|
+
float offsetRightLengthSq = dot(offsetRight, offsetRight);
|
|
1059
|
+
if(offsetLeftLengthSq <= offsetRightLengthSq) {
|
|
1060
|
+
return offsetLeft;
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
return offsetRight;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Helper to get the intensity of light from a
|
|
1069
|
+
* subpixel.
|
|
1070
|
+
* The pixelPosition argument represents a
|
|
1071
|
+
* fragment's position within a pixel.
|
|
1072
|
+
* Spread represents the subpixel's horizontal
|
|
1073
|
+
* position within the pixel.
|
|
1074
|
+
*/
|
|
1075
|
+
float getSubpixelIntensity(
|
|
1076
|
+
vec2 pixelPosition,
|
|
1077
|
+
float spread
|
|
1078
|
+
) {
|
|
1079
|
+
vec2 subpixelCenter = vec2(
|
|
1080
|
+
0.5 + (spread * SubpixelSpread),
|
|
1081
|
+
1.0 - SubpixelVerticalOffset
|
|
1082
|
+
);
|
|
1083
|
+
vec2 subpixelSizeHalf = 0.5 * vec2(
|
|
1084
|
+
SubpixelLightWidth,
|
|
1085
|
+
SubpixelLightHeight
|
|
1086
|
+
);
|
|
1087
|
+
vec2 offset = getPointSubpixelDistance(
|
|
1088
|
+
pixelPosition,
|
|
1089
|
+
subpixelCenter,
|
|
1090
|
+
subpixelSizeHalf
|
|
1091
|
+
);
|
|
1092
|
+
if(SubpixelLightGlow <= 0) {
|
|
1093
|
+
return dot(offset, offset) <= 0.0 ? 1.0 : 0.0;
|
|
1094
|
+
}
|
|
1095
|
+
else {
|
|
1096
|
+
float dist = length(offset);
|
|
1097
|
+
float glow = max(0.0,
|
|
1098
|
+
1.0 - (dist / SubpixelLightGlow)
|
|
1099
|
+
);
|
|
1100
|
+
return glow;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* Helper to apply SubpixelColorBleed to the intensity
|
|
1106
|
+
* value computed for a fragment and subpixel.
|
|
1107
|
+
* Subpixel color bleed allows subpixel colors to be
|
|
1108
|
+
* more strongly coerced to more accurately represent
|
|
1109
|
+
* the underlying pixel color.
|
|
1110
|
+
*/
|
|
1111
|
+
float applySubpixelBleed(
|
|
1112
|
+
float subpixelIntensity,
|
|
1113
|
+
float colorSourceChannel
|
|
1114
|
+
) {
|
|
1115
|
+
return subpixelIntensity * (
|
|
1116
|
+
SubpixelColorBleed +
|
|
1117
|
+
((1.0 - SubpixelColorBleed) * colorSourceChannel)
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
void main() {
|
|
1122
|
+
// Get base color of the pixel, adjust based on
|
|
1123
|
+
// contrast and luminosity settings.
|
|
1124
|
+
vec3 colorSource = texture2D(tex, texCoord).rgb;
|
|
1125
|
+
vec3 colorSourceHcl = convertRgbToHcl(colorSource);
|
|
1126
|
+
vec3 colorSourceAdjusted = convertHclToRgb(vec3(
|
|
1127
|
+
colorSourceHcl.x,
|
|
1128
|
+
colorSourceHcl.y * SourceContrast,
|
|
1129
|
+
colorSourceHcl.z * SourceLuminosity
|
|
1130
|
+
));
|
|
1131
|
+
// Determine how much each subpixel's light should
|
|
1132
|
+
// affect this fragment.
|
|
1133
|
+
vec2 pixelPosition = (
|
|
1134
|
+
mod(texCoord * texSize * SubpixelScale, 1.0)
|
|
1135
|
+
);
|
|
1136
|
+
float subpixelIntensityRed = applySubpixelBleed(
|
|
1137
|
+
getSubpixelIntensity(pixelPosition, -1.0),
|
|
1138
|
+
colorSourceAdjusted.r
|
|
1139
|
+
);
|
|
1140
|
+
float subpixelIntensityGreen = applySubpixelBleed(
|
|
1141
|
+
getSubpixelIntensity(pixelPosition, +0.0),
|
|
1142
|
+
colorSourceAdjusted.g
|
|
1143
|
+
);
|
|
1144
|
+
float subpixelIntensityBlue = applySubpixelBleed(
|
|
1145
|
+
getSubpixelIntensity(pixelPosition, +1.0),
|
|
1146
|
+
colorSourceAdjusted.b
|
|
1147
|
+
);
|
|
1148
|
+
vec3 subpixelLightColor = SubpixelGamma * (
|
|
1149
|
+
(subpixelIntensityRed * SubpixelColorRed) +
|
|
1150
|
+
(subpixelIntensityGreen * SubpixelColorGreen) +
|
|
1151
|
+
(subpixelIntensityBlue * SubpixelColorBlue)
|
|
1152
|
+
);
|
|
1153
|
+
// Compute final color
|
|
1154
|
+
vec3 colorResult = clamp(
|
|
1155
|
+
subpixelLightColor * colorSourceAdjusted, 0.0, 1.0
|
|
1156
|
+
);
|
|
1157
|
+
vec3 colorResultBlended = (
|
|
1158
|
+
((1.0 - SubpixelBlendAmount) * colorSourceAdjusted) +
|
|
1159
|
+
(SubpixelBlendAmount * colorResult)
|
|
1160
|
+
);
|
|
1161
|
+
colorResultBlended = BaseColor + (
|
|
1162
|
+
(colorResultBlended * (vec3(1.0, 1.0, 1.0) - BaseColor))
|
|
1163
|
+
);
|
|
1164
|
+
gl_FragColor = vec4(
|
|
1165
|
+
colorResultBlended,
|
|
1166
|
+
1.0
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
This is free and unencumbered software released into the public domain.
|
|
1170
|
+
|
|
1171
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
1172
|
+
distribute this software, either in source code form or as a compiled
|
|
1173
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
1174
|
+
means.
|
|
1175
|
+
|
|
1176
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
1177
|
+
of this software dedicate any and all copyright interest in the
|
|
1178
|
+
software to the public domain. We make this dedication for the benefit
|
|
1179
|
+
of the public at large and to the detriment of our heirs and
|
|
1180
|
+
successors. We intend this dedication to be an overt act of
|
|
1181
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
1182
|
+
software under copyright law.
|
|
1183
|
+
|
|
1184
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
1185
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
1186
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
1187
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
1188
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
1189
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
1190
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
1191
|
+
|
|
1192
|
+
For more information, please refer to <http://unlicense.org/>
|
|
1193
|
+
[shader]
|
|
1194
|
+
name=gbc-lcd
|
|
1195
|
+
author=Sophie Kirschner
|
|
1196
|
+
description=Imitates the GameBoy Color LCD screen subpixel arrangement, with an optional backlight effect.
|
|
1197
|
+
passes=2
|
|
1198
|
+
|
|
1199
|
+
[pass.0]
|
|
1200
|
+
integerScaling=1
|
|
1201
|
+
fragmentShader=gbc-lcd.fs
|
|
1202
|
+
blend=1
|
|
1203
|
+
|
|
1204
|
+
[pass.1]
|
|
1205
|
+
fragmentShader=gbc-lcd-light.fs
|
|
1206
|
+
|
|
1207
|
+
[pass.0.uniform.BaseColor]
|
|
1208
|
+
type=float3
|
|
1209
|
+
default[0]=0.130
|
|
1210
|
+
default[1]=0.128
|
|
1211
|
+
default[2]=0.101
|
|
1212
|
+
readableName=Screen base color
|
|
1213
|
+
|
|
1214
|
+
[pass.0.uniform.SubpixelColorRed]
|
|
1215
|
+
type=float3
|
|
1216
|
+
default[0]=1.00
|
|
1217
|
+
default[1]=0.38
|
|
1218
|
+
default[2]=0.22
|
|
1219
|
+
readableName=Red subpixel color
|
|
1220
|
+
|
|
1221
|
+
[pass.0.uniform.SubpixelColorGreen]
|
|
1222
|
+
type=float3
|
|
1223
|
+
default[0]=0.60
|
|
1224
|
+
default[1]=0.88
|
|
1225
|
+
default[2]=0.30
|
|
1226
|
+
readableName=Green subpixel color
|
|
1227
|
+
|
|
1228
|
+
[pass.0.uniform.SubpixelColorBlue]
|
|
1229
|
+
type=float3
|
|
1230
|
+
default[0]=0.23
|
|
1231
|
+
default[1]=0.65
|
|
1232
|
+
default[2]=1.00
|
|
1233
|
+
readableName=Blue subpixel color
|
|
1234
|
+
|
|
1235
|
+
[pass.0.uniform.SourceContrast]
|
|
1236
|
+
type=float
|
|
1237
|
+
default=0.85
|
|
1238
|
+
readableName=Screen contrast
|
|
1239
|
+
|
|
1240
|
+
[pass.0.uniform.SourceLuminosity]
|
|
1241
|
+
type=float
|
|
1242
|
+
default=0.88
|
|
1243
|
+
readableName=Screen luminosity
|
|
1244
|
+
|
|
1245
|
+
[pass.0.uniform.SubpixelBlendAmount]
|
|
1246
|
+
type=float
|
|
1247
|
+
default=1.0
|
|
1248
|
+
readableName=Subpixel effect amount
|
|
1249
|
+
|
|
1250
|
+
[pass.0.uniform.SubpixelColorBleed]
|
|
1251
|
+
type=float
|
|
1252
|
+
default=0.31
|
|
1253
|
+
readableName=Subpixel color bleeding
|
|
1254
|
+
|
|
1255
|
+
[pass.0.uniform.SubpixelSpread]
|
|
1256
|
+
type=float
|
|
1257
|
+
default=0.333
|
|
1258
|
+
readableName=Subpixel spread X
|
|
1259
|
+
|
|
1260
|
+
[pass.0.uniform.SubpixelVerticalOffset]
|
|
1261
|
+
type=float
|
|
1262
|
+
default=0.48
|
|
1263
|
+
readableName=Subpixel offset Y
|
|
1264
|
+
|
|
1265
|
+
[pass.0.uniform.SubpixelGamma]
|
|
1266
|
+
type=float
|
|
1267
|
+
default=1.040
|
|
1268
|
+
readableName=Subpixel brightness
|
|
1269
|
+
|
|
1270
|
+
[pass.0.uniform.SubpixelLightWidth]
|
|
1271
|
+
type=float
|
|
1272
|
+
default=0.220
|
|
1273
|
+
readableName=Subpixel width
|
|
1274
|
+
|
|
1275
|
+
[pass.0.uniform.SubpixelLightHeight]
|
|
1276
|
+
type=float
|
|
1277
|
+
default=0.850
|
|
1278
|
+
readableName=Subpixel height
|
|
1279
|
+
|
|
1280
|
+
[pass.0.uniform.SubpixelLightGlow]
|
|
1281
|
+
type=float
|
|
1282
|
+
default=0.195
|
|
1283
|
+
readableName=Subpixel glow size
|
|
1284
|
+
|
|
1285
|
+
[pass.0.uniform.SubpixelTabHeight]
|
|
1286
|
+
type=float
|
|
1287
|
+
default=0.175
|
|
1288
|
+
readableName=Subpixel tab shaping
|
|
1289
|
+
|
|
1290
|
+
[pass.0.uniform.SubpixelScale]
|
|
1291
|
+
type=float
|
|
1292
|
+
default=1.0
|
|
1293
|
+
readableName=Subpixel scale
|
|
1294
|
+
|
|
1295
|
+
[pass.1.uniform.LightColor]
|
|
1296
|
+
type=float3
|
|
1297
|
+
default[0]=1.000
|
|
1298
|
+
default[1]=0.968
|
|
1299
|
+
default[2]=0.882
|
|
1300
|
+
readableName=Backlight color
|
|
1301
|
+
|
|
1302
|
+
[pass.1.uniform.LightIntensity]
|
|
1303
|
+
type=float
|
|
1304
|
+
default=0.06
|
|
1305
|
+
readableName=Backlight intensity
|
|
1306
|
+
|
|
1307
|
+
[pass.1.uniform.LightSoftness]
|
|
1308
|
+
type=float
|
|
1309
|
+
default=0.67
|
|
1310
|
+
readableName=Backlight softness
|
|
1311
|
+
|
|
1312
|
+
[pass.1.uniform.ReflectionDistance]
|
|
1313
|
+
type=float2
|
|
1314
|
+
default[0]=0
|
|
1315
|
+
default[1]=0.025
|
|
1316
|
+
readableName=Internal reflection distance
|
|
1317
|
+
|
|
1318
|
+
[pass.1.uniform.ReflectionBrightness]
|
|
1319
|
+
type=float
|
|
1320
|
+
default=0.032
|
|
1321
|
+
readableName=Internal reflection brightness
|
|
1322
|
+
/* MIT License
|
|
1323
|
+
*
|
|
1324
|
+
* Copyright (c) 2015-2023 Lior Halphon
|
|
1325
|
+
*
|
|
1326
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1327
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
1328
|
+
* in the Software without restriction, including without limitation the rights
|
|
1329
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1330
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
1331
|
+
* furnished to do so, subject to the following conditions:
|
|
1332
|
+
*
|
|
1333
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
1334
|
+
* copies or substantial portions of the Software.
|
|
1335
|
+
*
|
|
1336
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1337
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1338
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1339
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1340
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1341
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1342
|
+
* SOFTWARE.
|
|
1343
|
+
*/
|
|
1344
|
+
/* Based on this (really good) article: http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html */
|
|
1345
|
+
|
|
1346
|
+
/* The colorspace used by the HQnx filters is not really YUV, despite the algorithm description claims it is. It is
|
|
1347
|
+
also not normalized. Therefore, we shall call the colorspace used by HQnx "HQ Colorspace" to avoid confusion. */
|
|
1348
|
+
|
|
1349
|
+
varying vec2 texCoord;
|
|
1350
|
+
uniform sampler2D tex;
|
|
1351
|
+
uniform vec2 texSize;
|
|
1352
|
+
|
|
1353
|
+
float _bit(float v, int i)
|
|
1354
|
+
{
|
|
1355
|
+
// v is an integer value stored as float
|
|
1356
|
+
float p = exp2(float(i)); // 2^i, GLSL ES 1.00-friendly
|
|
1357
|
+
return floor(mod(floor(v / p), 2.0));
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
bool _matchMask(float pattern, int mask, int ref)
|
|
1361
|
+
{
|
|
1362
|
+
// (pattern & mask) == ref, implemented without bitwise ops.
|
|
1363
|
+
float m = float(mask);
|
|
1364
|
+
float r = float(ref);
|
|
1365
|
+
float mism = 0.0;
|
|
1366
|
+
for (int i = 0; i < 8; ++i)
|
|
1367
|
+
{
|
|
1368
|
+
float mb = _bit(m, i);
|
|
1369
|
+
if (mb > 0.5)
|
|
1370
|
+
{
|
|
1371
|
+
float pb = _bit(pattern, i);
|
|
1372
|
+
float rb = _bit(r, i);
|
|
1373
|
+
mism += abs(pb - rb);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
return mism < 0.5;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
vec3 rgb_to_hq_colospace(vec4 rgb)
|
|
1380
|
+
{
|
|
1381
|
+
return vec3(
|
|
1382
|
+
0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
|
|
1383
|
+
0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
|
|
1384
|
+
-0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
bool is_different(vec4 a, vec4 b)
|
|
1389
|
+
{
|
|
1390
|
+
vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b));
|
|
1391
|
+
return diff.x > 0.018 || diff.y > 0.002 || diff.z > 0.005;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// WebGL1: no bitwise ops in GLSL ES 1.00
|
|
1395
|
+
|
|
1396
|
+
vec4 interp_2px(vec4 c1, float w1, vec4 c2, float w2)
|
|
1397
|
+
{
|
|
1398
|
+
return (c1 * w1 + c2 * w2) / (w1 + w2);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
vec4 interp_3px(vec4 c1, float w1, vec4 c2, float w2, vec4 c3, float w3)
|
|
1402
|
+
{
|
|
1403
|
+
return (c1 * w1 + c2 * w2 + c3 * w3) / (w1 + w2 + w3);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
vec4 scale(sampler2D image, vec2 position, vec2 input_resolution)
|
|
1407
|
+
{
|
|
1408
|
+
// o = offset, the width of a pixel
|
|
1409
|
+
vec2 o = vec2(1.0, 1.0) / input_resolution;
|
|
1410
|
+
|
|
1411
|
+
/* We always calculate the top left pixel. If we need a different pixel, we flip the image */
|
|
1412
|
+
|
|
1413
|
+
// p = the position within a pixel [0...1]
|
|
1414
|
+
vec2 p = fract(position * input_resolution);
|
|
1415
|
+
|
|
1416
|
+
if (p.x > 0.5) o.x = -o.x;
|
|
1417
|
+
if (p.y > 0.5) o.y = -o.y;
|
|
1418
|
+
|
|
1419
|
+
vec4 w0 = texture2D(image, position + vec2( -o.x, -o.y));
|
|
1420
|
+
vec4 w1 = texture2D(image, position + vec2( 0.0, -o.y));
|
|
1421
|
+
vec4 w2 = texture2D(image, position + vec2( o.x, -o.y));
|
|
1422
|
+
vec4 w3 = texture2D(image, position + vec2( -o.x, 0.0));
|
|
1423
|
+
vec4 w4 = texture2D(image, position + vec2( 0.0, 0.0));
|
|
1424
|
+
vec4 w5 = texture2D(image, position + vec2( o.x, 0.0));
|
|
1425
|
+
vec4 w6 = texture2D(image, position + vec2( -o.x, o.y));
|
|
1426
|
+
vec4 w7 = texture2D(image, position + vec2( 0.0, o.y));
|
|
1427
|
+
vec4 w8 = texture2D(image, position + vec2( o.x, o.y));
|
|
1428
|
+
|
|
1429
|
+
float pattern = 0.0;
|
|
1430
|
+
if (is_different(w0, w4)) pattern += 1.0;
|
|
1431
|
+
if (is_different(w1, w4)) pattern += 2.0;
|
|
1432
|
+
if (is_different(w2, w4)) pattern += 4.0;
|
|
1433
|
+
if (is_different(w3, w4)) pattern += 8.0;
|
|
1434
|
+
if (is_different(w5, w4)) pattern += 16.0;
|
|
1435
|
+
if (is_different(w6, w4)) pattern += 32.0;
|
|
1436
|
+
if (is_different(w7, w4)) pattern += 64.0;
|
|
1437
|
+
if (is_different(w8, w4)) pattern += 128.0;
|
|
1438
|
+
|
|
1439
|
+
// NOTE: hex literals (0x..) are not GLSL ES 1.00. Converted to decimal.
|
|
1440
|
+
|
|
1441
|
+
if ((_matchMask(pattern, 191, 55) || _matchMask(pattern, 219, 19)) && is_different(w1, w5))
|
|
1442
|
+
{
|
|
1443
|
+
return interp_2px(w4, 3.0, w3, 1.0);
|
|
1444
|
+
}
|
|
1445
|
+
if ((_matchMask(pattern, 219, 73) || _matchMask(pattern, 239, 109)) && is_different(w7, w3))
|
|
1446
|
+
{
|
|
1447
|
+
return interp_2px(w4, 3.0, w1, 1.0);
|
|
1448
|
+
}
|
|
1449
|
+
if ((_matchMask(pattern, 11, 11) || _matchMask(pattern, 254, 74) || _matchMask(pattern, 254, 26)) && is_different(w3, w1))
|
|
1450
|
+
{
|
|
1451
|
+
return w4;
|
|
1452
|
+
}
|
|
1453
|
+
if ((_matchMask(pattern, 111, 42) || _matchMask(pattern, 91, 10) || _matchMask(pattern, 191, 58) || _matchMask(pattern, 223, 90) ||
|
|
1454
|
+
_matchMask(pattern, 159, 138) || _matchMask(pattern, 207, 138) || _matchMask(pattern, 239, 78) || _matchMask(pattern, 63, 14) ||
|
|
1455
|
+
_matchMask(pattern, 251, 90) || _matchMask(pattern, 187, 138) || _matchMask(pattern, 127, 90) || _matchMask(pattern, 175, 138) ||
|
|
1456
|
+
_matchMask(pattern, 235, 138)) && is_different(w3, w1))
|
|
1457
|
+
{
|
|
1458
|
+
return interp_2px(w4, 3.0, w0, 1.0);
|
|
1459
|
+
}
|
|
1460
|
+
if (_matchMask(pattern, 11, 8))
|
|
1461
|
+
{
|
|
1462
|
+
return interp_3px(w4, 2.0, w0, 1.0, w1, 1.0);
|
|
1463
|
+
}
|
|
1464
|
+
if (_matchMask(pattern, 11, 2))
|
|
1465
|
+
{
|
|
1466
|
+
return interp_3px(w4, 2.0, w0, 1.0, w3, 1.0);
|
|
1467
|
+
}
|
|
1468
|
+
if (_matchMask(pattern, 47, 47))
|
|
1469
|
+
{
|
|
1470
|
+
return interp_3px(w4, 4.0, w3, 1.0, w1, 1.0);
|
|
1471
|
+
}
|
|
1472
|
+
if (_matchMask(pattern, 191, 55) || _matchMask(pattern, 219, 19))
|
|
1473
|
+
{
|
|
1474
|
+
return interp_3px(w4, 5.0, w1, 2.0, w3, 1.0);
|
|
1475
|
+
}
|
|
1476
|
+
if (_matchMask(pattern, 219, 73) || _matchMask(pattern, 239, 109))
|
|
1477
|
+
{
|
|
1478
|
+
return interp_3px(w4, 5.0, w3, 2.0, w1, 1.0);
|
|
1479
|
+
}
|
|
1480
|
+
if (_matchMask(pattern, 27, 3) || _matchMask(pattern, 79, 67) || _matchMask(pattern, 139, 131) || _matchMask(pattern, 107, 67))
|
|
1481
|
+
{
|
|
1482
|
+
return interp_2px(w4, 3.0, w3, 1.0);
|
|
1483
|
+
}
|
|
1484
|
+
if (_matchMask(pattern, 75, 9) || _matchMask(pattern, 139, 137) || _matchMask(pattern, 31, 25) || _matchMask(pattern, 59, 25))
|
|
1485
|
+
{
|
|
1486
|
+
return interp_2px(w4, 3.0, w1, 1.0);
|
|
1487
|
+
}
|
|
1488
|
+
if (_matchMask(pattern, 126, 42) || _matchMask(pattern, 239, 171) || _matchMask(pattern, 191, 143) || _matchMask(pattern, 126, 14))
|
|
1489
|
+
{
|
|
1490
|
+
return interp_3px(w4, 2.0, w3, 3.0, w1, 3.0);
|
|
1491
|
+
}
|
|
1492
|
+
if (_matchMask(pattern, 251, 106) || _matchMask(pattern, 111, 110) || _matchMask(pattern, 63, 62) || _matchMask(pattern, 251, 250) ||
|
|
1493
|
+
_matchMask(pattern, 223, 222) || _matchMask(pattern, 223, 30))
|
|
1494
|
+
{
|
|
1495
|
+
return interp_2px(w4, 3.0, w0, 1.0);
|
|
1496
|
+
}
|
|
1497
|
+
if (_matchMask(pattern, 10, 0) || _matchMask(pattern, 79, 75) || _matchMask(pattern, 159, 27) || _matchMask(pattern, 47, 11) ||
|
|
1498
|
+
_matchMask(pattern, 190, 10) || _matchMask(pattern, 238, 10) || _matchMask(pattern, 126, 10) || _matchMask(pattern, 235, 75) ||
|
|
1499
|
+
_matchMask(pattern, 59, 27))
|
|
1500
|
+
{
|
|
1501
|
+
return interp_3px(w4, 2.0, w3, 1.0, w1, 1.0);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
return interp_3px(w4, 6.0, w3, 1.0, w1, 1.0);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
void main()
|
|
1508
|
+
{
|
|
1509
|
+
gl_FragColor = scale(tex, texCoord, texSize);
|
|
1510
|
+
}
|
|
1511
|
+
[shader]
|
|
1512
|
+
name=hq2x
|
|
1513
|
+
author=Lior Halphon
|
|
1514
|
+
description="High Quality" 2x scaling
|
|
1515
|
+
passes=1
|
|
1516
|
+
|
|
1517
|
+
[pass.0]
|
|
1518
|
+
fragmentShader=hq2x.fs
|
|
1519
|
+
blend=0
|
|
1520
|
+
width=-2
|
|
1521
|
+
height=-2
|
|
1522
|
+
/*
|
|
1523
|
+
LCD Shader
|
|
1524
|
+
|
|
1525
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
1526
|
+
|
|
1527
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1528
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1529
|
+
in the Software without restriction, including without limitation the rights
|
|
1530
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1531
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1532
|
+
furnished to do so, subject to the following conditions:
|
|
1533
|
+
The above copyright notice and this permission notice shall be included in
|
|
1534
|
+
all copies or substantial portions of the Software.
|
|
1535
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1536
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1537
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1538
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1539
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1540
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1541
|
+
THE SOFTWARE.
|
|
1542
|
+
*/
|
|
1543
|
+
|
|
1544
|
+
uniform sampler2D tex;
|
|
1545
|
+
uniform vec2 texSize;
|
|
1546
|
+
varying vec2 texCoord;
|
|
1547
|
+
|
|
1548
|
+
uniform float boundBrightness;
|
|
1549
|
+
|
|
1550
|
+
void main()
|
|
1551
|
+
{
|
|
1552
|
+
vec4 color = texture2D(tex, texCoord);
|
|
1553
|
+
|
|
1554
|
+
if (int(mod(texCoord.s * texSize.x * 3.0, 3.0)) == 0 ||
|
|
1555
|
+
int(mod(texCoord.t * texSize.y * 3.0, 3.0)) == 0)
|
|
1556
|
+
{
|
|
1557
|
+
color.rgb *= vec3(1.0, 1.0, 1.0) * boundBrightness;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
gl_FragColor = color;
|
|
1561
|
+
}
|
|
1562
|
+
[shader]
|
|
1563
|
+
name=LCD
|
|
1564
|
+
author=Dominus Iniquitatis
|
|
1565
|
+
description=Simple LCD emulation.
|
|
1566
|
+
passes=1
|
|
1567
|
+
|
|
1568
|
+
[pass.0]
|
|
1569
|
+
fragmentShader=lcd.fs
|
|
1570
|
+
blend=1
|
|
1571
|
+
width=-3
|
|
1572
|
+
height=-3
|
|
1573
|
+
|
|
1574
|
+
[pass.0.uniform.boundBrightness]
|
|
1575
|
+
type=float
|
|
1576
|
+
readableName=Bound brightness
|
|
1577
|
+
default=0.9
|
|
1578
|
+
min=0.0
|
|
1579
|
+
max=1.0
|
|
1580
|
+
[shader]
|
|
1581
|
+
name=Motion Blur
|
|
1582
|
+
author=Dominus Iniquitatis
|
|
1583
|
+
description=Simple motion blur.
|
|
1584
|
+
passes=1
|
|
1585
|
+
|
|
1586
|
+
[pass.0]
|
|
1587
|
+
fragmentShader=motion_blur.fs
|
|
1588
|
+
blend=1
|
|
1589
|
+
width=-1
|
|
1590
|
+
height=-1
|
|
1591
|
+
|
|
1592
|
+
[pass.0.uniform.amount]
|
|
1593
|
+
type=float
|
|
1594
|
+
readableName=Amount
|
|
1595
|
+
default=0.3
|
|
1596
|
+
min=0.0
|
|
1597
|
+
max=1.0
|
|
1598
|
+
/*
|
|
1599
|
+
Motion Blur Shader
|
|
1600
|
+
|
|
1601
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
1602
|
+
|
|
1603
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1604
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1605
|
+
in the Software without restriction, including without limitation the rights
|
|
1606
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1607
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1608
|
+
furnished to do so, subject to the following conditions:
|
|
1609
|
+
The above copyright notice and this permission notice shall be included in
|
|
1610
|
+
all copies or substantial portions of the Software.
|
|
1611
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1612
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1613
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1614
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1615
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1616
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1617
|
+
THE SOFTWARE.
|
|
1618
|
+
*/
|
|
1619
|
+
|
|
1620
|
+
uniform sampler2D tex;
|
|
1621
|
+
uniform vec2 texSize;
|
|
1622
|
+
varying vec2 texCoord;
|
|
1623
|
+
|
|
1624
|
+
uniform float amount;
|
|
1625
|
+
|
|
1626
|
+
void main()
|
|
1627
|
+
{
|
|
1628
|
+
vec4 color = texture2D(tex, texCoord);
|
|
1629
|
+
color.a = 1.0 - amount;
|
|
1630
|
+
|
|
1631
|
+
gl_FragColor = color;
|
|
1632
|
+
}
|
|
1633
|
+
[shader]
|
|
1634
|
+
name=Nintendo DS Color
|
|
1635
|
+
author=Pokefan531 and hunterk
|
|
1636
|
+
description=Shader that replicates the LCD Colorspace from a Nintendo DS Phat.
|
|
1637
|
+
passes=1
|
|
1638
|
+
|
|
1639
|
+
[pass.0]
|
|
1640
|
+
fragmentShader=nds-color.fs
|
|
1641
|
+
vertexShader=nds-color.vs
|
|
1642
|
+
blend=1
|
|
1643
|
+
width=-1
|
|
1644
|
+
height=-1
|
|
1645
|
+
|
|
1646
|
+
[pass.0.uniform.color_mode]
|
|
1647
|
+
type=int
|
|
1648
|
+
default=1
|
|
1649
|
+
min=1
|
|
1650
|
+
max=3
|
|
1651
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
1652
|
+
// Shader that replicates the LCD Colorspace from a Nintendo DS Phat --
|
|
1653
|
+
varying vec2 texCoord;
|
|
1654
|
+
varying mat4 profile;
|
|
1655
|
+
uniform sampler2D tex;
|
|
1656
|
+
uniform vec2 texSize;
|
|
1657
|
+
|
|
1658
|
+
const float target_gamma = 2.2;
|
|
1659
|
+
const float display_gamma = 2.2;
|
|
1660
|
+
|
|
1661
|
+
void main() {
|
|
1662
|
+
// bring out our stored luminance value
|
|
1663
|
+
float lum = profile[3].w;
|
|
1664
|
+
|
|
1665
|
+
// our adjustments need to happen in linear gamma
|
|
1666
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma)).rgba;
|
|
1667
|
+
|
|
1668
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
1669
|
+
screen = profile * screen;
|
|
1670
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
1671
|
+
}
|
|
1672
|
+
uniform int color_mode;
|
|
1673
|
+
attribute vec4 position;
|
|
1674
|
+
varying vec2 texCoord;
|
|
1675
|
+
varying mat4 profile;
|
|
1676
|
+
|
|
1677
|
+
const mat4 NDS_sRGB = mat4(
|
|
1678
|
+
0.835, 0.10, 0.105, 0.0, //red channel
|
|
1679
|
+
0.27, 0.6375, 0.175, 0.0, //green channel
|
|
1680
|
+
-0.105, 0.2625, 0.72, 0.0, //blue channel
|
|
1681
|
+
0.0, 0.0, 0.0, 0.905 //alpha channel
|
|
1682
|
+
);
|
|
1683
|
+
|
|
1684
|
+
const mat4 NDS_DCI = mat4(
|
|
1685
|
+
0.70, 0.125, 0.12, 0.0, //red channel
|
|
1686
|
+
0.34, 0.625, 0.20, 0.0, //green channel
|
|
1687
|
+
-0.04, 0.25, 0.68, 0.0, //blue channel
|
|
1688
|
+
0.0, 0.0, 0.0, 0.96 //alpha channel
|
|
1689
|
+
);
|
|
1690
|
+
|
|
1691
|
+
const mat4 NDS_Rec2020 = mat4(
|
|
1692
|
+
0.555, 0.1475, 0.1175, 0.0, //red channel
|
|
1693
|
+
0.39, 0.6075, 0.2075, 0.0, //green channel
|
|
1694
|
+
0.055, 0.245, 0.675, 0.0, //blue channel
|
|
1695
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
1696
|
+
);
|
|
1697
|
+
|
|
1698
|
+
void main() {
|
|
1699
|
+
if (color_mode == 1) profile = NDS_sRGB;
|
|
1700
|
+
else if (color_mode == 2) profile = NDS_DCI;
|
|
1701
|
+
else if (color_mode == 3) profile = NDS_Rec2020;
|
|
1702
|
+
|
|
1703
|
+
gl_Position = position;
|
|
1704
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
1705
|
+
}
|
|
1706
|
+
[shader]
|
|
1707
|
+
name=NSO GBA Color
|
|
1708
|
+
author=Pokefan531 and hunterk
|
|
1709
|
+
description=Shader that replicates the Nintendo Switch Online's GBA color filter.
|
|
1710
|
+
passes=1
|
|
1711
|
+
|
|
1712
|
+
[pass.0]
|
|
1713
|
+
fragmentShader=nso-gba-color.fs
|
|
1714
|
+
vertexShader=nso-gba-color.vs
|
|
1715
|
+
blend=1
|
|
1716
|
+
width=-1
|
|
1717
|
+
height=-1
|
|
1718
|
+
|
|
1719
|
+
[pass.0.uniform.darken_screen]
|
|
1720
|
+
type=float
|
|
1721
|
+
default=0.8
|
|
1722
|
+
min=0
|
|
1723
|
+
max=1
|
|
1724
|
+
readableName=Darken Screen
|
|
1725
|
+
|
|
1726
|
+
[pass.0.uniform.color_mode]
|
|
1727
|
+
type=int
|
|
1728
|
+
default=1
|
|
1729
|
+
min=1
|
|
1730
|
+
max=3
|
|
1731
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
1732
|
+
// Shader that replicates the LCD Colorspace from Gameboy Advance --
|
|
1733
|
+
varying vec2 texCoord;
|
|
1734
|
+
varying mat4 profile;
|
|
1735
|
+
uniform sampler2D tex;
|
|
1736
|
+
uniform vec2 texSize;
|
|
1737
|
+
|
|
1738
|
+
uniform float darken_screen;
|
|
1739
|
+
const float target_gamma = 2.2;
|
|
1740
|
+
const float display_gamma = 2.2;
|
|
1741
|
+
|
|
1742
|
+
void main() {
|
|
1743
|
+
// bring out our stored luminance value
|
|
1744
|
+
float lum = profile[3].w;
|
|
1745
|
+
|
|
1746
|
+
// our adjustments need to happen in linear gamma
|
|
1747
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma + darken_screen)).rgba;
|
|
1748
|
+
|
|
1749
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
1750
|
+
screen = profile * screen;
|
|
1751
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
1752
|
+
}
|
|
1753
|
+
uniform int color_mode;
|
|
1754
|
+
attribute vec4 position;
|
|
1755
|
+
varying vec2 texCoord;
|
|
1756
|
+
varying mat4 profile;
|
|
1757
|
+
|
|
1758
|
+
const mat4 GBA_sRGB = mat4(
|
|
1759
|
+
0.865, 0.0575, 0.0575, 0.0, //red channel
|
|
1760
|
+
0.1225, 0.925, 0.1225, 0.0, //green channel
|
|
1761
|
+
0.0125, 0.0125, 0.82, 0.0, //blue channel
|
|
1762
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
1763
|
+
);
|
|
1764
|
+
|
|
1765
|
+
const mat4 GBA_DCI = mat4(
|
|
1766
|
+
0.72, 0.0875, 0.0725, 0.0, //red channel
|
|
1767
|
+
0.2675, 0.9, 0.185, 0.0, //green channel
|
|
1768
|
+
0.0125, 0.0125, 0.7425, 0.0, //blue channel
|
|
1769
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
1770
|
+
);
|
|
1771
|
+
|
|
1772
|
+
const mat4 GBA_Rec2020 = mat4(
|
|
1773
|
+
0.57, 0.115, 0.0725, 0.0, //red channel
|
|
1774
|
+
0.3825, 0.8625, 0.195, 0.0, //green channel
|
|
1775
|
+
0.0475, 0.0225, 0.7325, 0.0, //blue channel
|
|
1776
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
1777
|
+
);
|
|
1778
|
+
|
|
1779
|
+
void main() {
|
|
1780
|
+
if (color_mode == 1) profile = GBA_sRGB;
|
|
1781
|
+
else if (color_mode == 2) profile = GBA_DCI;
|
|
1782
|
+
else if (color_mode == 3) profile = GBA_Rec2020;
|
|
1783
|
+
|
|
1784
|
+
gl_Position = position;
|
|
1785
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
1786
|
+
}
|
|
1787
|
+
[shader]
|
|
1788
|
+
name=NSO GBC Color
|
|
1789
|
+
author=Pokefan531 and hunterk
|
|
1790
|
+
description=Shader that replicates the Nintendo Switch Online's GBC color filter.
|
|
1791
|
+
passes=1
|
|
1792
|
+
|
|
1793
|
+
[pass.0]
|
|
1794
|
+
fragmentShader=nso-gbc-color.fs
|
|
1795
|
+
vertexShader=nso-gbc-color.vs
|
|
1796
|
+
blend=1
|
|
1797
|
+
width=-1
|
|
1798
|
+
height=-1
|
|
1799
|
+
|
|
1800
|
+
[pass.0.uniform.lighten_screen]
|
|
1801
|
+
type=float
|
|
1802
|
+
default=0.0
|
|
1803
|
+
min=0
|
|
1804
|
+
max=1
|
|
1805
|
+
readableName=Lighten Screen
|
|
1806
|
+
|
|
1807
|
+
[pass.0.uniform.color_mode]
|
|
1808
|
+
type=int
|
|
1809
|
+
default=1
|
|
1810
|
+
min=1
|
|
1811
|
+
max=3
|
|
1812
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
1813
|
+
// Shader that replicates the Nintendo Switch Online's GBC color filter --
|
|
1814
|
+
varying vec2 texCoord;
|
|
1815
|
+
varying mat4 profile;
|
|
1816
|
+
uniform sampler2D tex;
|
|
1817
|
+
uniform vec2 texSize;
|
|
1818
|
+
|
|
1819
|
+
uniform float lighten_screen;
|
|
1820
|
+
|
|
1821
|
+
void main() {
|
|
1822
|
+
// bring out our stored luminance value
|
|
1823
|
+
float lum = profile[3].w;
|
|
1824
|
+
|
|
1825
|
+
// our adjustments need to happen in linear gamma
|
|
1826
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(1.24, 0.8, 0.7, 1.0)).rgba;
|
|
1827
|
+
|
|
1828
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
1829
|
+
screen = profile * screen;
|
|
1830
|
+
gl_FragColor = pow(screen, vec4(1.0));
|
|
1831
|
+
}
|
|
1832
|
+
uniform int color_mode;
|
|
1833
|
+
attribute vec4 position;
|
|
1834
|
+
varying vec2 texCoord;
|
|
1835
|
+
varying mat4 profile;
|
|
1836
|
+
|
|
1837
|
+
const mat4 GBC_sRGB = mat4(
|
|
1838
|
+
0.84, 0.105, 0.15, 0.0, //red channel
|
|
1839
|
+
0.265, 0.67, 0.30, 0.0, //green channel
|
|
1840
|
+
0.0, 0.24, 0.525, 0.0, //blue channel
|
|
1841
|
+
0.175, 0.18, 0.18, 0.85 //alpha channel
|
|
1842
|
+
);
|
|
1843
|
+
|
|
1844
|
+
const mat4 GBC_DCI = mat4(
|
|
1845
|
+
0.84, 0.105, 0.15, 0.0, //red channel
|
|
1846
|
+
0.265, 0.67, 0.30, 0.0, //green channel
|
|
1847
|
+
0.0, 0.24, 0.525, 0.0, //blue channel
|
|
1848
|
+
0.175, 0.18, 0.18, 1.0 //alpha channel
|
|
1849
|
+
);
|
|
1850
|
+
|
|
1851
|
+
const mat4 GBC_Rec2020 = mat4(
|
|
1852
|
+
0.84, 0.105, 0.15, 0.0, //red channel
|
|
1853
|
+
0.265, 0.67, 0.30, 0.0, //green channel
|
|
1854
|
+
0.0, 0.24, 0.525, 0.0, //blue channel
|
|
1855
|
+
0.175, 0.18, 0.18, 1.0 //alpha channel
|
|
1856
|
+
);
|
|
1857
|
+
|
|
1858
|
+
void main() {
|
|
1859
|
+
if (color_mode == 1) profile = GBC_sRGB;
|
|
1860
|
+
else if (color_mode == 2) profile = GBC_DCI;
|
|
1861
|
+
else if (color_mode == 3) profile = GBC_Rec2020;
|
|
1862
|
+
|
|
1863
|
+
gl_Position = position;
|
|
1864
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
1865
|
+
}
|
|
1866
|
+
[shader]
|
|
1867
|
+
name=OmniScale
|
|
1868
|
+
author=Lior Halphon
|
|
1869
|
+
description=Resolution-indepedent scaler inspired by the hqx family scalers
|
|
1870
|
+
passes=1
|
|
1871
|
+
|
|
1872
|
+
[pass.0]
|
|
1873
|
+
fragmentShader=omniscale.fs
|
|
1874
|
+
blend=0
|
|
1875
|
+
/* MIT License
|
|
1876
|
+
*
|
|
1877
|
+
* Copyright (c) 2015-2023 Lior Halphon
|
|
1878
|
+
*
|
|
1879
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1880
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
1881
|
+
* in the Software without restriction, including without limitation the rights
|
|
1882
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1883
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
1884
|
+
* furnished to do so, subject to the following conditions:
|
|
1885
|
+
*
|
|
1886
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
1887
|
+
* copies or substantial portions of the Software.
|
|
1888
|
+
*
|
|
1889
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1890
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1891
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1892
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1893
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1894
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1895
|
+
* SOFTWARE.
|
|
1896
|
+
*/
|
|
1897
|
+
/* OmniScale is derived from the pattern based design of HQnx, but with the following general differences:
|
|
1898
|
+
- The actual output calculating was completely redesigned as resolution independent graphic generator. This allows
|
|
1899
|
+
scaling to any factor.
|
|
1900
|
+
- HQnx approximations that were good enough for a 2x/3x/4x factor were refined, creating smoother gradients.
|
|
1901
|
+
- "Quarters" can be interpolated in more ways than in the HQnx filters
|
|
1902
|
+
- If a pattern does not provide enough information to determine the suitable scaling interpolation, up to 16 pixels
|
|
1903
|
+
per quarter are sampled (in contrast to the usual 9) in order to determine the best interpolation.
|
|
1904
|
+
*/
|
|
1905
|
+
|
|
1906
|
+
varying vec2 texCoord;
|
|
1907
|
+
uniform sampler2D tex;
|
|
1908
|
+
uniform vec2 texSize;
|
|
1909
|
+
uniform vec2 outputSize;
|
|
1910
|
+
|
|
1911
|
+
float _bit(float v, int i)
|
|
1912
|
+
{
|
|
1913
|
+
// v is an integer value stored as float
|
|
1914
|
+
float p = exp2(float(i)); // 2^i, GLSL ES 1.00-friendly
|
|
1915
|
+
return floor(mod(floor(v / p), 2.0));
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
bool _matchMask(float pattern, int mask, int ref)
|
|
1919
|
+
{
|
|
1920
|
+
// (pattern & mask) == ref, implemented without bitwise ops.
|
|
1921
|
+
float m = float(mask);
|
|
1922
|
+
float r = float(ref);
|
|
1923
|
+
float mism = 0.0;
|
|
1924
|
+
for (int i = 0; i < 15; ++i)
|
|
1925
|
+
{
|
|
1926
|
+
float mb = _bit(m, i);
|
|
1927
|
+
if (mb > 0.5)
|
|
1928
|
+
{
|
|
1929
|
+
float pb = _bit(pattern, i);
|
|
1930
|
+
float rb = _bit(r, i);
|
|
1931
|
+
mism += abs(pb - rb);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
return mism < 0.5;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
/* We use the same colorspace as the HQ algorithms. */
|
|
1938
|
+
vec3 rgb_to_hq_colospace(vec4 rgb)
|
|
1939
|
+
{
|
|
1940
|
+
return vec3(
|
|
1941
|
+
0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
|
|
1942
|
+
0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
|
|
1943
|
+
-0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
bool is_different(vec4 a, vec4 b)
|
|
1948
|
+
{
|
|
1949
|
+
vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b));
|
|
1950
|
+
return diff.x > 0.018 || diff.y > 0.002 || diff.z > 0.005;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
// WebGL1: no bitwise ops in GLSL ES 1.00
|
|
1954
|
+
|
|
1955
|
+
vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
|
|
1956
|
+
{
|
|
1957
|
+
// o = offset, the width of a pixel
|
|
1958
|
+
vec2 o = vec2(1.0, 1.0) / input_resolution;
|
|
1959
|
+
|
|
1960
|
+
/* We always calculate the top left quarter. If we need a different quarter, we flip our co-ordinates */
|
|
1961
|
+
|
|
1962
|
+
// p = the position within a pixel [0...1]
|
|
1963
|
+
vec2 p = fract(position * input_resolution);
|
|
1964
|
+
|
|
1965
|
+
if (p.x > 0.5)
|
|
1966
|
+
{
|
|
1967
|
+
o.x = -o.x;
|
|
1968
|
+
p.x = 1.0 - p.x;
|
|
1969
|
+
}
|
|
1970
|
+
if (p.y > 0.5)
|
|
1971
|
+
{
|
|
1972
|
+
o.y = -o.y;
|
|
1973
|
+
p.y = 1.0 - p.y;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
vec4 w0 = texture2D(image, position + vec2(-o.x, -o.y));
|
|
1977
|
+
vec4 w1 = texture2D(image, position + vec2( 0.0, -o.y));
|
|
1978
|
+
vec4 w2 = texture2D(image, position + vec2( o.x, -o.y));
|
|
1979
|
+
vec4 w3 = texture2D(image, position + vec2(-o.x, 0.0));
|
|
1980
|
+
vec4 w4 = texture2D(image, position + vec2( 0.0, 0.0));
|
|
1981
|
+
vec4 w5 = texture2D(image, position + vec2( o.x, 0.0));
|
|
1982
|
+
vec4 w6 = texture2D(image, position + vec2(-o.x, o.y));
|
|
1983
|
+
vec4 w7 = texture2D(image, position + vec2( 0.0, o.y));
|
|
1984
|
+
vec4 w8 = texture2D(image, position + vec2( o.x, o.y));
|
|
1985
|
+
|
|
1986
|
+
float pattern = 0.0;
|
|
1987
|
+
if (is_different(w0, w4)) pattern += 1.0;
|
|
1988
|
+
if (is_different(w1, w4)) pattern += 2.0;
|
|
1989
|
+
if (is_different(w2, w4)) pattern += 4.0;
|
|
1990
|
+
if (is_different(w3, w4)) pattern += 8.0;
|
|
1991
|
+
if (is_different(w5, w4)) pattern += 16.0;
|
|
1992
|
+
if (is_different(w6, w4)) pattern += 32.0;
|
|
1993
|
+
if (is_different(w7, w4)) pattern += 64.0;
|
|
1994
|
+
if (is_different(w8, w4)) pattern += 128.0;
|
|
1995
|
+
|
|
1996
|
+
// NOTE: hex literals (0x..) are not GLSL ES 1.00. Converted to decimal.
|
|
1997
|
+
|
|
1998
|
+
if ((_matchMask(pattern, 191, 55) || _matchMask(pattern, 219, 19)) && is_different(w1, w5))
|
|
1999
|
+
{
|
|
2000
|
+
return mix(w4, w3, 0.5 - p.x);
|
|
2001
|
+
}
|
|
2002
|
+
if ((_matchMask(pattern, 219, 73) || _matchMask(pattern, 239, 109)) && is_different(w7, w3))
|
|
2003
|
+
{
|
|
2004
|
+
return mix(w4, w1, 0.5 - p.y);
|
|
2005
|
+
}
|
|
2006
|
+
if ((_matchMask(pattern, 11, 11) || _matchMask(pattern, 254, 74) || _matchMask(pattern, 254, 26)) && is_different(w3, w1))
|
|
2007
|
+
{
|
|
2008
|
+
return w4;
|
|
2009
|
+
}
|
|
2010
|
+
if ((_matchMask(pattern, 111, 42) || _matchMask(pattern, 91, 10) || _matchMask(pattern, 191, 58) || _matchMask(pattern, 223, 90) ||
|
|
2011
|
+
_matchMask(pattern, 159, 138) || _matchMask(pattern, 207, 138) || _matchMask(pattern, 239, 78) || _matchMask(pattern, 63, 14) ||
|
|
2012
|
+
_matchMask(pattern, 251, 90) || _matchMask(pattern, 187, 138) || _matchMask(pattern, 127, 90) || _matchMask(pattern, 175, 138) ||
|
|
2013
|
+
_matchMask(pattern, 235, 138)) && is_different(w3, w1))
|
|
2014
|
+
{
|
|
2015
|
+
return mix(w4, mix(w4, w0, 0.5 - p.x), 0.5 - p.y);
|
|
2016
|
+
}
|
|
2017
|
+
if (_matchMask(pattern, 11, 8))
|
|
2018
|
+
{
|
|
2019
|
+
return mix(mix(w0 * 0.375 + w1 * 0.25 + w4 * 0.375, w4 * 0.5 + w1 * 0.5, p.x * 2.0), w4, p.y * 2.0);
|
|
2020
|
+
}
|
|
2021
|
+
if (_matchMask(pattern, 11, 2))
|
|
2022
|
+
{
|
|
2023
|
+
return mix(mix(w0 * 0.375 + w3 * 0.25 + w4 * 0.375, w4 * 0.5 + w3 * 0.5, p.y * 2.0), w4, p.x * 2.0);
|
|
2024
|
+
}
|
|
2025
|
+
if (_matchMask(pattern, 47, 47))
|
|
2026
|
+
{
|
|
2027
|
+
float dist = length(p - vec2(0.5));
|
|
2028
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
|
2029
|
+
if (dist < 0.5 - pixel_size / 2.0)
|
|
2030
|
+
{
|
|
2031
|
+
return w4;
|
|
2032
|
+
}
|
|
2033
|
+
vec4 r;
|
|
2034
|
+
if (is_different(w0, w1) || is_different(w0, w3))
|
|
2035
|
+
{
|
|
2036
|
+
r = mix(w1, w3, p.y - p.x + 0.5);
|
|
2037
|
+
}
|
|
2038
|
+
else
|
|
2039
|
+
{
|
|
2040
|
+
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
if (dist > 0.5 + pixel_size / 2.0)
|
|
2044
|
+
{
|
|
2045
|
+
return r;
|
|
2046
|
+
}
|
|
2047
|
+
return mix(w4, r, (dist - 0.5 + pixel_size / 2.0) / pixel_size);
|
|
2048
|
+
}
|
|
2049
|
+
if (_matchMask(pattern, 191, 55) || _matchMask(pattern, 219, 19))
|
|
2050
|
+
{
|
|
2051
|
+
float dist = p.x - 2.0 * p.y;
|
|
2052
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
|
2053
|
+
if (dist > pixel_size / 2.0)
|
|
2054
|
+
{
|
|
2055
|
+
return w1;
|
|
2056
|
+
}
|
|
2057
|
+
vec4 r = mix(w3, w4, p.x + 0.5);
|
|
2058
|
+
if (dist < -pixel_size / 2.0)
|
|
2059
|
+
{
|
|
2060
|
+
return r;
|
|
2061
|
+
}
|
|
2062
|
+
return mix(r, w1, (dist + pixel_size / 2.0) / pixel_size);
|
|
2063
|
+
}
|
|
2064
|
+
if (_matchMask(pattern, 219, 73) || _matchMask(pattern, 239, 109))
|
|
2065
|
+
{
|
|
2066
|
+
float dist = p.y - 2.0 * p.x;
|
|
2067
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
|
2068
|
+
if (dist > pixel_size / 2.0)
|
|
2069
|
+
{
|
|
2070
|
+
return w3;
|
|
2071
|
+
}
|
|
2072
|
+
vec4 r = mix(w1, w4, p.x + 0.5);
|
|
2073
|
+
if (dist < -pixel_size / 2.0)
|
|
2074
|
+
{
|
|
2075
|
+
return r;
|
|
2076
|
+
}
|
|
2077
|
+
return mix(r, w3, (dist + pixel_size / 2.0) / pixel_size);
|
|
2078
|
+
}
|
|
2079
|
+
if (_matchMask(pattern, 191, 143) || _matchMask(pattern, 126, 14))
|
|
2080
|
+
{
|
|
2081
|
+
float dist = p.x + 2.0 * p.y;
|
|
2082
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
|
2083
|
+
|
|
2084
|
+
if (dist > 1.0 + pixel_size / 2.0)
|
|
2085
|
+
{
|
|
2086
|
+
return w4;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
vec4 r;
|
|
2090
|
+
if (is_different(w0, w1) || is_different(w0, w3))
|
|
2091
|
+
{
|
|
2092
|
+
r = mix(w1, w3, p.y - p.x + 0.5);
|
|
2093
|
+
}
|
|
2094
|
+
else
|
|
2095
|
+
{
|
|
2096
|
+
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
if (dist < 1.0 - pixel_size / 2.0)
|
|
2100
|
+
{
|
|
2101
|
+
return r;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size);
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
if (_matchMask(pattern, 126, 42) || _matchMask(pattern, 239, 171))
|
|
2108
|
+
{
|
|
2109
|
+
float dist = p.y + 2.0 * p.x;
|
|
2110
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
|
2111
|
+
|
|
2112
|
+
if (dist > 1.0 + pixel_size / 2.0)
|
|
2113
|
+
{
|
|
2114
|
+
return w4;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
vec4 r;
|
|
2118
|
+
|
|
2119
|
+
if (is_different(w0, w1) || is_different(w0, w3))
|
|
2120
|
+
{
|
|
2121
|
+
r = mix(w1, w3, p.y - p.x + 0.5);
|
|
2122
|
+
}
|
|
2123
|
+
else
|
|
2124
|
+
{
|
|
2125
|
+
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
if (dist < 1.0 - pixel_size / 2.0)
|
|
2129
|
+
{
|
|
2130
|
+
return r;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size);
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
if (_matchMask(pattern, 27, 3) || _matchMask(pattern, 79, 67) || _matchMask(pattern, 139, 131) || _matchMask(pattern, 107, 67))
|
|
2137
|
+
{
|
|
2138
|
+
return mix(w4, w3, 0.5 - p.x);
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
if (_matchMask(pattern, 75, 9) || _matchMask(pattern, 139, 137) || _matchMask(pattern, 31, 25) || _matchMask(pattern, 59, 25))
|
|
2142
|
+
{
|
|
2143
|
+
return mix(w4, w1, 0.5 - p.y);
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
if (_matchMask(pattern, 251, 106) || _matchMask(pattern, 111, 110) || _matchMask(pattern, 63, 62) || _matchMask(pattern, 251, 250) ||
|
|
2147
|
+
_matchMask(pattern, 223, 222) || _matchMask(pattern, 223, 30))
|
|
2148
|
+
{
|
|
2149
|
+
return mix(w4, w0, (1.0 - p.x - p.y) / 2.0);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
if (_matchMask(pattern, 79, 75) || _matchMask(pattern, 159, 27) || _matchMask(pattern, 47, 11) ||
|
|
2153
|
+
_matchMask(pattern, 190, 10) || _matchMask(pattern, 238, 10) || _matchMask(pattern, 126, 10) || _matchMask(pattern, 235, 75) ||
|
|
2154
|
+
_matchMask(pattern, 59, 27))
|
|
2155
|
+
{
|
|
2156
|
+
float dist = p.x + p.y;
|
|
2157
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
|
2158
|
+
|
|
2159
|
+
if (dist > 0.5 + pixel_size / 2.0)
|
|
2160
|
+
{
|
|
2161
|
+
return w4;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
vec4 r;
|
|
2165
|
+
if (is_different(w0, w1) || is_different(w0, w3))
|
|
2166
|
+
{
|
|
2167
|
+
r = mix(w1, w3, p.y - p.x + 0.5);
|
|
2168
|
+
}
|
|
2169
|
+
else
|
|
2170
|
+
{
|
|
2171
|
+
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
if (dist < 0.5 - pixel_size / 2.0)
|
|
2175
|
+
{
|
|
2176
|
+
return r;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size);
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
if (_matchMask(pattern, 11, 1))
|
|
2183
|
+
{
|
|
2184
|
+
return mix(mix(w4, w3, 0.5 - p.x), mix(w1, (w1 + w3) / 2.0, 0.5 - p.x), 0.5 - p.y);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
if (_matchMask(pattern, 11, 0))
|
|
2188
|
+
{
|
|
2189
|
+
return mix(mix(w4, w3, 0.5 - p.x), mix(w1, w0, 0.5 - p.x), 0.5 - p.y);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
float dist = p.x + p.y;
|
|
2193
|
+
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
|
2194
|
+
|
|
2195
|
+
if (dist > 0.5 + pixel_size / 2.0)
|
|
2196
|
+
{
|
|
2197
|
+
return w4;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
/* We need more samples to "solve" this diagonal */
|
|
2201
|
+
vec4 x0 = texture2D(image, position + vec2(-o.x * 2.0, -o.y * 2.0));
|
|
2202
|
+
vec4 x1 = texture2D(image, position + vec2(-o.x , -o.y * 2.0));
|
|
2203
|
+
vec4 x2 = texture2D(image, position + vec2( 0.0 , -o.y * 2.0));
|
|
2204
|
+
vec4 x3 = texture2D(image, position + vec2( o.x , -o.y * 2.0));
|
|
2205
|
+
vec4 x4 = texture2D(image, position + vec2(-o.x * 2.0, -o.y ));
|
|
2206
|
+
vec4 x5 = texture2D(image, position + vec2(-o.x * 2.0, 0.0 ));
|
|
2207
|
+
vec4 x6 = texture2D(image, position + vec2(-o.x * 2.0, o.y ));
|
|
2208
|
+
|
|
2209
|
+
if (is_different(x0, w4)) pattern += exp2(8.0);
|
|
2210
|
+
if (is_different(x1, w4)) pattern += exp2(9.0);
|
|
2211
|
+
if (is_different(x2, w4)) pattern += exp2(10.0);
|
|
2212
|
+
if (is_different(x3, w4)) pattern += exp2(11.0);
|
|
2213
|
+
if (is_different(x4, w4)) pattern += exp2(12.0);
|
|
2214
|
+
if (is_different(x5, w4)) pattern += exp2(13.0);
|
|
2215
|
+
if (is_different(x6, w4)) pattern += exp2(14.0);
|
|
2216
|
+
|
|
2217
|
+
float diagonal_bias = -7.0;
|
|
2218
|
+
for (int i = 0; i < 15; ++i)
|
|
2219
|
+
{
|
|
2220
|
+
diagonal_bias += _bit(pattern, i);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
if (diagonal_bias <= 0.0)
|
|
2224
|
+
{
|
|
2225
|
+
vec4 r = mix(w1, w3, p.y - p.x + 0.5);
|
|
2226
|
+
if (dist < 0.5 - pixel_size / 2.0)
|
|
2227
|
+
{
|
|
2228
|
+
return r;
|
|
2229
|
+
}
|
|
2230
|
+
return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
return w4;
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
void main()
|
|
2237
|
+
{
|
|
2238
|
+
gl_FragColor = scale(tex, texCoord, texSize, outputSize);
|
|
2239
|
+
}
|
|
2240
|
+
[shader]
|
|
2241
|
+
name=Pixelate
|
|
2242
|
+
author=endrift
|
|
2243
|
+
description=Only scale up the screen at an integer ratio
|
|
2244
|
+
passes=1
|
|
2245
|
+
|
|
2246
|
+
[pass.0]
|
|
2247
|
+
blend=1
|
|
2248
|
+
integerScaling=1
|
|
2249
|
+
[shader]
|
|
2250
|
+
name=Scale2x
|
|
2251
|
+
author=singron
|
|
2252
|
+
description=AdvanceMAME's Scale2x algorithm
|
|
2253
|
+
passes=1
|
|
2254
|
+
|
|
2255
|
+
[pass.0]
|
|
2256
|
+
fragmentShader=scale2x.fs
|
|
2257
|
+
blend=1
|
|
2258
|
+
width=-2
|
|
2259
|
+
height=-2
|
|
2260
|
+
/* Shader implementation of Scale2x is adapted from https://gist.github.com/singron/3161079 */
|
|
2261
|
+
varying vec2 texCoord;
|
|
2262
|
+
uniform sampler2D tex;
|
|
2263
|
+
uniform vec2 texSize;
|
|
2264
|
+
|
|
2265
|
+
void main() {
|
|
2266
|
+
// o = offset, the width of a pixel
|
|
2267
|
+
vec2 o = 1.0 / texSize;
|
|
2268
|
+
|
|
2269
|
+
// texel arrangement
|
|
2270
|
+
// A B C
|
|
2271
|
+
// D E F
|
|
2272
|
+
// G H I
|
|
2273
|
+
vec4 B = texture2D(tex, texCoord + vec2( 0.0, o.y));
|
|
2274
|
+
vec4 D = texture2D(tex, texCoord + vec2( -o.x, 0.0));
|
|
2275
|
+
vec4 E = texture2D(tex, texCoord + vec2( 0.0, 0.0));
|
|
2276
|
+
vec4 F = texture2D(tex, texCoord + vec2( o.x, 0.0));
|
|
2277
|
+
vec4 H = texture2D(tex, texCoord + vec2( 0.0, -o.y));
|
|
2278
|
+
vec2 p = texCoord * texSize;
|
|
2279
|
+
// p = the texCoord within a pixel [0...1]
|
|
2280
|
+
p = fract(p);
|
|
2281
|
+
if (p.x > .5) {
|
|
2282
|
+
if (p.y > .5) {
|
|
2283
|
+
// Top Right
|
|
2284
|
+
gl_FragColor = B == F && B != D && F != H ? F : E;
|
|
2285
|
+
} else {
|
|
2286
|
+
// Bottom Right
|
|
2287
|
+
gl_FragColor = H == F && D != H && B != F ? F : E;
|
|
2288
|
+
}
|
|
2289
|
+
} else {
|
|
2290
|
+
if (p.y > .5) {
|
|
2291
|
+
// Top Left
|
|
2292
|
+
gl_FragColor = D == B && B != F && D != H ? D : E;
|
|
2293
|
+
} else {
|
|
2294
|
+
// Bottom Left
|
|
2295
|
+
gl_FragColor = D == H && D != B && H != F ? D : E;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
[shader]
|
|
2300
|
+
name=Scale4x
|
|
2301
|
+
author=singron, endrift
|
|
2302
|
+
description=AdvanceMAME's Scale4x algorithm
|
|
2303
|
+
passes=1
|
|
2304
|
+
|
|
2305
|
+
[pass.0]
|
|
2306
|
+
fragmentShader=scale4x.fs
|
|
2307
|
+
blend=1
|
|
2308
|
+
width=-4
|
|
2309
|
+
height=-4
|
|
2310
|
+
/* Shader implementation of Scale2x is adapted from https://gist.github.com/singron/3161079 */
|
|
2311
|
+
varying vec2 texCoord;
|
|
2312
|
+
uniform sampler2D tex;
|
|
2313
|
+
uniform vec2 texSize;
|
|
2314
|
+
|
|
2315
|
+
vec4 scale2x(vec4 pixels[5], vec2 p) {
|
|
2316
|
+
// texel arrangement
|
|
2317
|
+
// x 0 x
|
|
2318
|
+
// 1 2 3
|
|
2319
|
+
// x 4 x
|
|
2320
|
+
// p = the texCoord within a pixel [0...1]
|
|
2321
|
+
p = fract(p);
|
|
2322
|
+
if (p.x > .5) {
|
|
2323
|
+
if (p.y > .5) {
|
|
2324
|
+
// Top Right
|
|
2325
|
+
return pixels[0] == pixels[3] && pixels[0] != pixels[1] && pixels[3] != pixels[4] ? pixels[3] : pixels[2];
|
|
2326
|
+
} else {
|
|
2327
|
+
// Bottom Right
|
|
2328
|
+
return pixels[4] == pixels[3] && pixels[1] != pixels[4] && pixels[0] != pixels[3] ? pixels[3] : pixels[2];
|
|
2329
|
+
}
|
|
2330
|
+
} else {
|
|
2331
|
+
if (p.y > .5) {
|
|
2332
|
+
// Top Left
|
|
2333
|
+
return pixels[1] == pixels[0] && pixels[0] != pixels[3] && pixels[1] != pixels[4] ? pixels[1] : pixels[2];
|
|
2334
|
+
} else {
|
|
2335
|
+
// Bottom Left
|
|
2336
|
+
return pixels[1] == pixels[4] && pixels[1] != pixels[0] && pixels[4] != pixels[3] ? pixels[1] : pixels[2];
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
vec4 scaleNeighborhood(vec2 p, vec2 x, vec2 o) {
|
|
2342
|
+
vec4 neighborhood[5];
|
|
2343
|
+
neighborhood[0] = texture2D(tex, texCoord + x + vec2( 0.0, o.y));
|
|
2344
|
+
neighborhood[1] = texture2D(tex, texCoord + x + vec2(-o.x, 0.0));
|
|
2345
|
+
neighborhood[2] = texture2D(tex, texCoord + x + vec2( 0.0, 0.0));
|
|
2346
|
+
neighborhood[3] = texture2D(tex, texCoord + x + vec2( o.x, 0.0));
|
|
2347
|
+
neighborhood[4] = texture2D(tex, texCoord + x + vec2( 0.0, -o.y));
|
|
2348
|
+
return scale2x(neighborhood, p + x * texSize);
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
void main() {
|
|
2352
|
+
// o = offset, the width of a pixel
|
|
2353
|
+
vec2 o = 1.0 / texSize;
|
|
2354
|
+
|
|
2355
|
+
vec2 p = texCoord * texSize;
|
|
2356
|
+
vec4 pixels[5];
|
|
2357
|
+
pixels[0] = scaleNeighborhood(p, vec2( 0.0, o.y / 2.0), o);
|
|
2358
|
+
pixels[1] = scaleNeighborhood(p, vec2(-o.x / 2.0, 0.0), o);
|
|
2359
|
+
pixels[2] = scaleNeighborhood(p, vec2( 0.0, 0.0), o);
|
|
2360
|
+
pixels[3] = scaleNeighborhood(p, vec2( o.x / 2.0, 0.0), o);
|
|
2361
|
+
pixels[4] = scaleNeighborhood(p, vec2( 0.0, -o.y / 2.0), o);
|
|
2362
|
+
gl_FragColor = scale2x(pixels, p * 2.0);
|
|
2363
|
+
}
|
|
2364
|
+
[shader]
|
|
2365
|
+
name=Scanlines
|
|
2366
|
+
author=Dominus Iniquitatis
|
|
2367
|
+
description=Simple scanlines.
|
|
2368
|
+
passes=1
|
|
2369
|
+
|
|
2370
|
+
[pass.0]
|
|
2371
|
+
fragmentShader=scanlines.fs
|
|
2372
|
+
blend=1
|
|
2373
|
+
width=-2
|
|
2374
|
+
height=-2
|
|
2375
|
+
|
|
2376
|
+
[pass.0.uniform.lineBrightness]
|
|
2377
|
+
type=float
|
|
2378
|
+
readableName=Line brightness
|
|
2379
|
+
default=0.5
|
|
2380
|
+
min=0.0
|
|
2381
|
+
max=1.0
|
|
2382
|
+
/*
|
|
2383
|
+
Scanlines Shader
|
|
2384
|
+
|
|
2385
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
2386
|
+
|
|
2387
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2388
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2389
|
+
in the Software without restriction, including without limitation the rights
|
|
2390
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2391
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2392
|
+
furnished to do so, subject to the following conditions:
|
|
2393
|
+
The above copyright notice and this permission notice shall be included in
|
|
2394
|
+
all copies or substantial portions of the Software.
|
|
2395
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2396
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2397
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2398
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2399
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2400
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2401
|
+
THE SOFTWARE.
|
|
2402
|
+
*/
|
|
2403
|
+
|
|
2404
|
+
uniform sampler2D tex;
|
|
2405
|
+
uniform vec2 texSize;
|
|
2406
|
+
varying vec2 texCoord;
|
|
2407
|
+
|
|
2408
|
+
uniform float lineBrightness;
|
|
2409
|
+
|
|
2410
|
+
void main() {
|
|
2411
|
+
vec4 color = texture2D(tex, texCoord);
|
|
2412
|
+
|
|
2413
|
+
// Compute the Y coordinate in pixel space
|
|
2414
|
+
float y = texCoord.y * texSize.y;
|
|
2415
|
+
|
|
2416
|
+
// Use floor and mod to get even/odd row
|
|
2417
|
+
if (mod(floor(y), 2.0) < 1.0) {
|
|
2418
|
+
color.rgb *= lineBrightness;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
gl_FragColor = color;
|
|
2422
|
+
}
|
|
2423
|
+
[shader]
|
|
2424
|
+
name=Soften
|
|
2425
|
+
author=Dominus Iniquitatis
|
|
2426
|
+
description=Soft image blurring.
|
|
2427
|
+
passes=1
|
|
2428
|
+
|
|
2429
|
+
[pass.0]
|
|
2430
|
+
fragmentShader=soften.fs
|
|
2431
|
+
blend=1
|
|
2432
|
+
width=-1
|
|
2433
|
+
height=-1
|
|
2434
|
+
|
|
2435
|
+
[pass.0.uniform.amount]
|
|
2436
|
+
type=float
|
|
2437
|
+
readableName=Amount
|
|
2438
|
+
default=0.5
|
|
2439
|
+
min=0.0
|
|
2440
|
+
max=1.0
|
|
2441
|
+
/*
|
|
2442
|
+
Soften Shader
|
|
2443
|
+
|
|
2444
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
2445
|
+
|
|
2446
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2447
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2448
|
+
in the Software without restriction, including without limitation the rights
|
|
2449
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2450
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2451
|
+
furnished to do so, subject to the following conditions:
|
|
2452
|
+
The above copyright notice and this permission notice shall be included in
|
|
2453
|
+
all copies or substantial portions of the Software.
|
|
2454
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2455
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2456
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2457
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2458
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2459
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2460
|
+
THE SOFTWARE.
|
|
2461
|
+
*/
|
|
2462
|
+
|
|
2463
|
+
uniform sampler2D tex;
|
|
2464
|
+
uniform vec2 texSize;
|
|
2465
|
+
varying vec2 texCoord;
|
|
2466
|
+
|
|
2467
|
+
uniform float amount;
|
|
2468
|
+
|
|
2469
|
+
vec2 GetTexelSize()
|
|
2470
|
+
{
|
|
2471
|
+
return vec2(1.0 / texSize.x, 1.0 / texSize.y);
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
void main()
|
|
2475
|
+
{
|
|
2476
|
+
vec4 color = texture2D(tex, texCoord);
|
|
2477
|
+
|
|
2478
|
+
vec4 northColor = texture2D(tex, texCoord + vec2(0.0, GetTexelSize().y));
|
|
2479
|
+
vec4 southColor = texture2D(tex, texCoord - vec2(0.0, GetTexelSize().y));
|
|
2480
|
+
vec4 eastColor = texture2D(tex, texCoord + vec2(GetTexelSize().x, 0.0));
|
|
2481
|
+
vec4 westColor = texture2D(tex, texCoord - vec2(GetTexelSize().x, 0.0));
|
|
2482
|
+
|
|
2483
|
+
if (abs(length(color) - length(northColor)) > 0.0)
|
|
2484
|
+
{
|
|
2485
|
+
color = mix(color, northColor, amount / 4.0);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (abs(length(color) - length(southColor)) > 0.0)
|
|
2489
|
+
{
|
|
2490
|
+
color = mix(color, southColor, amount / 4.0);
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
if (abs(length(color) - length(eastColor)) > 0.0)
|
|
2494
|
+
{
|
|
2495
|
+
color = mix(color, eastColor, amount / 4.0);
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
if (abs(length(color) - length(westColor)) > 0.0)
|
|
2499
|
+
{
|
|
2500
|
+
color = mix(color, westColor, amount / 4.0);
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
gl_FragColor = color;
|
|
2504
|
+
}
|
|
2505
|
+
[shader]
|
|
2506
|
+
name=GBA SP 101 Color
|
|
2507
|
+
author=Pokefan531 and hunterk
|
|
2508
|
+
description=Shader that replicates the LCD Colorspace from a Gameboy SP 101 (backlit version).
|
|
2509
|
+
passes=1
|
|
2510
|
+
|
|
2511
|
+
[pass.0]
|
|
2512
|
+
fragmentShader=sp101-color.fs
|
|
2513
|
+
vertexShader=sp101-color.vs
|
|
2514
|
+
blend=1
|
|
2515
|
+
width=-1
|
|
2516
|
+
height=-1
|
|
2517
|
+
|
|
2518
|
+
[pass.0.uniform.color_mode]
|
|
2519
|
+
type=int
|
|
2520
|
+
default=1
|
|
2521
|
+
min=1
|
|
2522
|
+
max=3
|
|
2523
|
+
readableName=Color Profile (1=sRGB, 2=DCI, 3=Rec2020)
|
|
2524
|
+
// Shader that replicates the LCD Colorspace from a Gameboy SP 101 (backlit version) --
|
|
2525
|
+
varying vec2 texCoord;
|
|
2526
|
+
varying mat4 profile;
|
|
2527
|
+
uniform sampler2D tex;
|
|
2528
|
+
uniform vec2 texSize;
|
|
2529
|
+
|
|
2530
|
+
const float target_gamma = 2.2;
|
|
2531
|
+
const float display_gamma = 2.2;
|
|
2532
|
+
|
|
2533
|
+
void main() {
|
|
2534
|
+
// bring out our stored luminance value
|
|
2535
|
+
float lum = profile[3].w;
|
|
2536
|
+
|
|
2537
|
+
// our adjustments need to happen in linear gamma
|
|
2538
|
+
vec4 screen = pow(texture2D(tex, texCoord), vec4(target_gamma)).rgba;
|
|
2539
|
+
|
|
2540
|
+
screen = clamp(screen * lum, 0.0, 1.0);
|
|
2541
|
+
screen = profile * screen;
|
|
2542
|
+
gl_FragColor = pow(screen, vec4(1.0 / display_gamma));
|
|
2543
|
+
}
|
|
2544
|
+
uniform int color_mode;
|
|
2545
|
+
attribute vec4 position;
|
|
2546
|
+
varying vec2 texCoord;
|
|
2547
|
+
varying mat4 profile;
|
|
2548
|
+
|
|
2549
|
+
const mat4 SP1_sRGB = mat4(
|
|
2550
|
+
0.96, 0.0325, 0.001, 0.0, //red channel
|
|
2551
|
+
0.11, 0.89, -0.03, 0.0, //green channel
|
|
2552
|
+
-0.07, 0.0775, 1.029, 0.0, //blue channel
|
|
2553
|
+
0.0, 0.0, 0.0, 0.935 //alpha channel
|
|
2554
|
+
);
|
|
2555
|
+
|
|
2556
|
+
const mat4 SP1_DCI = mat4(
|
|
2557
|
+
0.805, 0.0675, 0.017, 0.0, //red channel
|
|
2558
|
+
0.24, 0.86, 0.02, 0.0, //green channel
|
|
2559
|
+
-0.045, 0.0725, 0.963, 0.0, //blue channel
|
|
2560
|
+
0.0, 0.0, 0.0, 0.955 //alpha channel
|
|
2561
|
+
);
|
|
2562
|
+
|
|
2563
|
+
const mat4 SP1_Rec2020 = mat4(
|
|
2564
|
+
0.625, 0.10, 0.015, 0.0, //red channel
|
|
2565
|
+
0.35, 0.82, 0.0325, 0.0, //green channel
|
|
2566
|
+
0.025, 0.08, 0.9525, 0.0, //blue channel
|
|
2567
|
+
0.0, 0.0, 0.0, 1.0 //alpha channel
|
|
2568
|
+
);
|
|
2569
|
+
|
|
2570
|
+
void main() {
|
|
2571
|
+
if (color_mode == 1) profile = SP1_sRGB;
|
|
2572
|
+
else if (color_mode == 2) profile = SP1_DCI;
|
|
2573
|
+
else if (color_mode == 3) profile = SP1_Rec2020;
|
|
2574
|
+
|
|
2575
|
+
gl_Position = position;
|
|
2576
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
2577
|
+
}
|
|
2578
|
+
[shader]
|
|
2579
|
+
name=TV Mode
|
|
2580
|
+
author=Dominus Iniquitatis
|
|
2581
|
+
description=Scanlines along with a subtle blurring.
|
|
2582
|
+
passes=1
|
|
2583
|
+
|
|
2584
|
+
[pass.0]
|
|
2585
|
+
fragmentShader=tv.fs
|
|
2586
|
+
blend=1
|
|
2587
|
+
width=-2
|
|
2588
|
+
height=-2
|
|
2589
|
+
|
|
2590
|
+
[pass.0.uniform.lineBrightness]
|
|
2591
|
+
type=float
|
|
2592
|
+
readableName=Line brightness
|
|
2593
|
+
default=0.75
|
|
2594
|
+
min=0.0
|
|
2595
|
+
max=1.0
|
|
2596
|
+
|
|
2597
|
+
[pass.0.uniform.blurring]
|
|
2598
|
+
type=float
|
|
2599
|
+
readableName=Blurring
|
|
2600
|
+
default=1.0
|
|
2601
|
+
min=0.0
|
|
2602
|
+
max=1.0
|
|
2603
|
+
/*
|
|
2604
|
+
TV Mode Shader
|
|
2605
|
+
|
|
2606
|
+
Copyright (C) 2022 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
2607
|
+
|
|
2608
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2609
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2610
|
+
in the Software without restriction, including without limitation the rights
|
|
2611
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2612
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2613
|
+
furnished to do so, subject to the following conditions:
|
|
2614
|
+
The above copyright notice and this permission notice shall be included in
|
|
2615
|
+
all copies or substantial portions of the Software.
|
|
2616
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2617
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2618
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2619
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2620
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2621
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2622
|
+
THE SOFTWARE.
|
|
2623
|
+
*/
|
|
2624
|
+
|
|
2625
|
+
uniform sampler2D tex;
|
|
2626
|
+
uniform vec2 texSize;
|
|
2627
|
+
varying vec2 texCoord;
|
|
2628
|
+
|
|
2629
|
+
uniform float lineBrightness;
|
|
2630
|
+
uniform float blurring;
|
|
2631
|
+
|
|
2632
|
+
void main()
|
|
2633
|
+
{
|
|
2634
|
+
vec4 c = texture2D(tex, texCoord);
|
|
2635
|
+
vec4 n = texture2D(tex, texCoord + vec2(1.0 / texSize.x * 0.5, 0.0));
|
|
2636
|
+
|
|
2637
|
+
vec4 color = mix(c, (c + n) / 2.0, blurring);
|
|
2638
|
+
color.a = c.a;
|
|
2639
|
+
|
|
2640
|
+
if (int(mod(texCoord.t * texSize.y * 2.0, 2.0)) == 0)
|
|
2641
|
+
{
|
|
2642
|
+
color.rgb *= lineBrightness;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
gl_FragColor = color;
|
|
2646
|
+
}
|
|
2647
|
+
[shader]
|
|
2648
|
+
name=VBA Pixelate
|
|
2649
|
+
author=Dominus Iniquitatis
|
|
2650
|
+
description=VisualBoyAdvance-style pixelation.
|
|
2651
|
+
passes=1
|
|
2652
|
+
|
|
2653
|
+
[pass.0]
|
|
2654
|
+
fragmentShader=vba_pixelate.fs
|
|
2655
|
+
blend=1
|
|
2656
|
+
width=-2
|
|
2657
|
+
height=-2
|
|
2658
|
+
|
|
2659
|
+
[pass.0.uniform.boundBrightness]
|
|
2660
|
+
type=float
|
|
2661
|
+
readableName=Bound brightness
|
|
2662
|
+
default=0.5
|
|
2663
|
+
min=0.0
|
|
2664
|
+
max=1.0
|
|
2665
|
+
/*
|
|
2666
|
+
VBA Pixelate Shader
|
|
2667
|
+
|
|
2668
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
2669
|
+
|
|
2670
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2671
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2672
|
+
in the Software without restriction, including without limitation the rights
|
|
2673
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2674
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2675
|
+
furnished to do so, subject to the following conditions:
|
|
2676
|
+
The above copyright notice and this permission notice shall be included in
|
|
2677
|
+
all copies or substantial portions of the Software.
|
|
2678
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2679
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2680
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2681
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2682
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2683
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2684
|
+
THE SOFTWARE.
|
|
2685
|
+
*/
|
|
2686
|
+
|
|
2687
|
+
uniform sampler2D tex;
|
|
2688
|
+
uniform vec2 texSize;
|
|
2689
|
+
varying vec2 texCoord;
|
|
2690
|
+
|
|
2691
|
+
uniform float boundBrightness;
|
|
2692
|
+
|
|
2693
|
+
void main()
|
|
2694
|
+
{
|
|
2695
|
+
vec4 color = texture2D(tex, texCoord);
|
|
2696
|
+
|
|
2697
|
+
float x = floor(texCoord.s * texSize.x);
|
|
2698
|
+
float y = floor(texCoord.t * texSize.y);
|
|
2699
|
+
|
|
2700
|
+
bool onVerticalLine = mod(x, 2.0) == 0.0;
|
|
2701
|
+
bool onHorizontalLine = mod(y, 2.0) == 0.0;
|
|
2702
|
+
|
|
2703
|
+
if (onVerticalLine || onHorizontalLine)
|
|
2704
|
+
{
|
|
2705
|
+
color.rgb *= boundBrightness;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
gl_FragColor = color;
|
|
2709
|
+
}[shader]
|
|
2710
|
+
name=Vignette
|
|
2711
|
+
author=Dominus Iniquitatis
|
|
2712
|
+
description=Configurable vignette effect.
|
|
2713
|
+
passes=1
|
|
2714
|
+
|
|
2715
|
+
[pass.0]
|
|
2716
|
+
fragmentShader=vignette.fs
|
|
2717
|
+
blend=1
|
|
2718
|
+
width=-1
|
|
2719
|
+
height=-1
|
|
2720
|
+
|
|
2721
|
+
[pass.0.uniform.intensity]
|
|
2722
|
+
type=float
|
|
2723
|
+
readableName=Intensity
|
|
2724
|
+
default=1.0
|
|
2725
|
+
min=0.0
|
|
2726
|
+
max=1.0
|
|
2727
|
+
/*
|
|
2728
|
+
Vignette Shader
|
|
2729
|
+
|
|
2730
|
+
Copyright (C) 2017 Dominus Iniquitatis - zerosaiko@gmail.com
|
|
2731
|
+
|
|
2732
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2733
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2734
|
+
in the Software without restriction, including without limitation the rights
|
|
2735
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2736
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2737
|
+
furnished to do so, subject to the following conditions:
|
|
2738
|
+
The above copyright notice and this permission notice shall be included in
|
|
2739
|
+
all copies or substantial portions of the Software.
|
|
2740
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2741
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2742
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2743
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2744
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2745
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2746
|
+
THE SOFTWARE.
|
|
2747
|
+
*/
|
|
2748
|
+
|
|
2749
|
+
uniform sampler2D tex;
|
|
2750
|
+
uniform vec2 texSize;
|
|
2751
|
+
varying vec2 texCoord;
|
|
2752
|
+
|
|
2753
|
+
uniform float intensity;
|
|
2754
|
+
|
|
2755
|
+
void main()
|
|
2756
|
+
{
|
|
2757
|
+
vec4 color = texture2D(tex, texCoord);
|
|
2758
|
+
color = mix(color, vec4(0.0, 0.0, 0.0, 1.0), length(texCoord - 0.5) * intensity);
|
|
2759
|
+
|
|
2760
|
+
gl_FragColor = color;
|
|
2761
|
+
}
|
|
2762
|
+
[shader]
|
|
2763
|
+
name=Wii U
|
|
2764
|
+
author=Prof. 9
|
|
2765
|
+
description=Uses the color palette from the Wii U Virtual Console. Enable bilinear filtering to further mimic Wii U output.
|
|
2766
|
+
passes=1
|
|
2767
|
+
|
|
2768
|
+
[pass.0]
|
|
2769
|
+
fragmentShader=wiiu.fs
|
|
2770
|
+
blend=1
|
|
2771
|
+
width=-4
|
|
2772
|
+
height=-4
|
|
2773
|
+
varying vec2 texCoord;
|
|
2774
|
+
uniform sampler2D tex;
|
|
2775
|
+
uniform vec2 texSize;
|
|
2776
|
+
|
|
2777
|
+
float wiiuLut31(float x) {
|
|
2778
|
+
int i = int(floor(x * 31.0 + 0.5));
|
|
2779
|
+
|
|
2780
|
+
if (i < 0) i = 0;
|
|
2781
|
+
if (i > 31) i = 31;
|
|
2782
|
+
|
|
2783
|
+
if (i == 0) return 0.0 / 255.0;
|
|
2784
|
+
if (i == 1) return 6.0 / 255.0;
|
|
2785
|
+
if (i == 2) return 12.0 / 255.0;
|
|
2786
|
+
if (i == 3) return 18.0 / 255.0;
|
|
2787
|
+
if (i == 4) return 24.0 / 255.0;
|
|
2788
|
+
if (i == 5) return 31.0 / 255.0;
|
|
2789
|
+
if (i == 6) return 37.0 / 255.0;
|
|
2790
|
+
if (i == 7) return 43.0 / 255.0;
|
|
2791
|
+
if (i == 8) return 49.0 / 255.0;
|
|
2792
|
+
if (i == 9) return 55.0 / 255.0;
|
|
2793
|
+
if (i == 10) return 61.0 / 255.0;
|
|
2794
|
+
if (i == 11) return 67.0 / 255.0;
|
|
2795
|
+
if (i == 12) return 73.0 / 255.0;
|
|
2796
|
+
if (i == 13) return 79.0 / 255.0;
|
|
2797
|
+
if (i == 14) return 86.0 / 255.0;
|
|
2798
|
+
if (i == 15) return 92.0 / 255.0;
|
|
2799
|
+
if (i == 16) return 98.0 / 255.0;
|
|
2800
|
+
if (i == 17) return 104.0 / 255.0;
|
|
2801
|
+
if (i == 18) return 111.0 / 255.0;
|
|
2802
|
+
if (i == 19) return 117.0 / 255.0;
|
|
2803
|
+
if (i == 20) return 123.0 / 255.0;
|
|
2804
|
+
if (i == 21) return 129.0 / 255.0;
|
|
2805
|
+
if (i == 22) return 135.0 / 255.0;
|
|
2806
|
+
if (i == 23) return 141.0 / 255.0;
|
|
2807
|
+
if (i == 24) return 148.0 / 255.0;
|
|
2808
|
+
if (i == 25) return 154.0 / 255.0;
|
|
2809
|
+
if (i == 26) return 159.0 / 255.0;
|
|
2810
|
+
if (i == 27) return 166.0 / 255.0;
|
|
2811
|
+
if (i == 28) return 172.0 / 255.0;
|
|
2812
|
+
if (i == 29) return 178.0 / 255.0;
|
|
2813
|
+
if (i == 30) return 184.0 / 255.0;
|
|
2814
|
+
// i == 31
|
|
2815
|
+
return 191.0 / 255.0;
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
void main() {
|
|
2819
|
+
vec4 color = texture2D(tex, texCoord);
|
|
2820
|
+
|
|
2821
|
+
color.r = wiiuLut31(color.r);
|
|
2822
|
+
color.g = wiiuLut31(color.g);
|
|
2823
|
+
color.b = wiiuLut31(color.b);
|
|
2824
|
+
|
|
2825
|
+
gl_FragColor = color;
|
|
2826
|
+
}
|
|
2827
|
+
[shader]
|
|
2828
|
+
name=xBR-lv2
|
|
2829
|
+
author=Hyllian
|
|
2830
|
+
description=xBR-lv2 upsampling filter
|
|
2831
|
+
passes=1
|
|
2832
|
+
|
|
2833
|
+
[pass.0]
|
|
2834
|
+
integerScaling=1
|
|
2835
|
+
vertexShader=xbr.vs
|
|
2836
|
+
fragmentShader=xbr.fs
|
|
2837
|
+
|
|
2838
|
+
[pass.0.uniform.XBR_Y_WEIGHT]
|
|
2839
|
+
type=float
|
|
2840
|
+
default=48
|
|
2841
|
+
readableName=Y Weight
|
|
2842
|
+
min=0
|
|
2843
|
+
max=100
|
|
2844
|
+
|
|
2845
|
+
[pass.0.uniform.XBR_EQ_THRESHOLD]
|
|
2846
|
+
type=float
|
|
2847
|
+
readableName=Eq Threshold
|
|
2848
|
+
default=25.0
|
|
2849
|
+
min=0.0
|
|
2850
|
+
max=50.0
|
|
2851
|
+
|
|
2852
|
+
[pass.0.uniform.XBR_SCALE]
|
|
2853
|
+
type=float
|
|
2854
|
+
readableName=xBR Scale
|
|
2855
|
+
default=4.0
|
|
2856
|
+
min=1.0
|
|
2857
|
+
max=5.0
|
|
2858
|
+
|
|
2859
|
+
[pass.0.uniform.XBR_LV2_COEFFICIENT]
|
|
2860
|
+
type=float
|
|
2861
|
+
readableName=Lv2 Coefficient
|
|
2862
|
+
default=2.0
|
|
2863
|
+
min=1.0
|
|
2864
|
+
max=3.0
|
|
2865
|
+
/*
|
|
2866
|
+
Hyllian's xBR-lv2 Shader
|
|
2867
|
+
|
|
2868
|
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
|
|
2869
|
+
|
|
2870
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2871
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2872
|
+
in the Software without restriction, including without limitation the rights
|
|
2873
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2874
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2875
|
+
furnished to do so, subject to the following conditions:
|
|
2876
|
+
|
|
2877
|
+
The above copyright notice and this permission notice shall be included in
|
|
2878
|
+
all copies or substantial portions of the Software.
|
|
2879
|
+
|
|
2880
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2881
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2882
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2883
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2884
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2885
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2886
|
+
THE SOFTWARE.
|
|
2887
|
+
|
|
2888
|
+
|
|
2889
|
+
Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.
|
|
2890
|
+
*/
|
|
2891
|
+
|
|
2892
|
+
uniform float XBR_Y_WEIGHT;
|
|
2893
|
+
uniform float XBR_EQ_THRESHOLD;
|
|
2894
|
+
uniform float XBR_SCALE;
|
|
2895
|
+
uniform float XBR_LV2_COEFFICIENT;
|
|
2896
|
+
|
|
2897
|
+
uniform sampler2D tex;
|
|
2898
|
+
uniform vec2 texSize;
|
|
2899
|
+
|
|
2900
|
+
varying vec2 texCoord;
|
|
2901
|
+
varying vec4 TEX1;
|
|
2902
|
+
varying vec4 TEX2;
|
|
2903
|
+
varying vec4 TEX3;
|
|
2904
|
+
varying vec4 TEX4;
|
|
2905
|
+
varying vec4 TEX5;
|
|
2906
|
+
varying vec4 TEX6;
|
|
2907
|
+
varying vec4 TEX7;
|
|
2908
|
+
|
|
2909
|
+
const vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
2910
|
+
const vec4 Bo = vec4( 1.0, 1.0, -1.0, -1.0 );
|
|
2911
|
+
const vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );
|
|
2912
|
+
const vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
2913
|
+
const vec4 Bx = vec4( 0.5, 2.0, -0.5, -2.0 );
|
|
2914
|
+
const vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );
|
|
2915
|
+
const vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
2916
|
+
const vec4 By = vec4( 2.0, 0.5, -2.0, -0.5 );
|
|
2917
|
+
const vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
|
|
2918
|
+
const vec4 Ci = vec4( 0.25, 0.25, 0.25, 0.25 );
|
|
2919
|
+
|
|
2920
|
+
const vec3 Y = vec3(0.2126, 0.7152, 0.0722);
|
|
2921
|
+
|
|
2922
|
+
vec4 df4(vec4 A, vec4 B) {
|
|
2923
|
+
return abs(A - B);
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
float c_df(vec3 c1, vec3 c2) {
|
|
2927
|
+
vec3 d = abs(c1 - c2);
|
|
2928
|
+
return d.r + d.g + d.b;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
bvec4 eq4(vec4 A, vec4 B) {
|
|
2932
|
+
return lessThan(df4(A, B), vec4(XBR_EQ_THRESHOLD));
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
bvec4 and4(bvec4 A, bvec4 B) {
|
|
2936
|
+
return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w);
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
bvec4 nand4(bvec4 A, bvec4 B) {
|
|
2940
|
+
return bvec4(!(A.x && B.x), !(A.y && B.y), !(A.z && B.z), !(A.w && B.w));
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) {
|
|
2944
|
+
return (df4(a,b) + df4(a,c) + df4(d,e) + df4(d,f) + 4.0 * df4(g,h));
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
float lum(vec3 rgb) {
|
|
2948
|
+
return dot(rgb, Y) * XBR_Y_WEIGHT;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
void main() {
|
|
2952
|
+
// fractional position inside the source pixel (in source-pixel space)
|
|
2953
|
+
vec2 fp = fract(texCoord * texSize);
|
|
2954
|
+
|
|
2955
|
+
// Sample neighborhood
|
|
2956
|
+
vec3 A1 = texture2D(tex, TEX1.xw).rgb;
|
|
2957
|
+
vec3 B1 = texture2D(tex, TEX1.yw).rgb;
|
|
2958
|
+
vec3 C1 = texture2D(tex, TEX1.zw).rgb;
|
|
2959
|
+
|
|
2960
|
+
vec3 A = texture2D(tex, TEX2.xw).rgb;
|
|
2961
|
+
vec3 B = texture2D(tex, TEX2.yw).rgb;
|
|
2962
|
+
vec3 C = texture2D(tex, TEX2.zw).rgb;
|
|
2963
|
+
|
|
2964
|
+
vec3 D = texture2D(tex, TEX3.xw).rgb;
|
|
2965
|
+
vec3 E = texture2D(tex, TEX3.yw).rgb;
|
|
2966
|
+
vec3 F = texture2D(tex, TEX3.zw).rgb;
|
|
2967
|
+
|
|
2968
|
+
vec3 G = texture2D(tex, TEX4.xw).rgb;
|
|
2969
|
+
vec3 H = texture2D(tex, TEX4.yw).rgb;
|
|
2970
|
+
vec3 I = texture2D(tex, TEX4.zw).rgb;
|
|
2971
|
+
|
|
2972
|
+
vec3 G5 = texture2D(tex, TEX5.xw).rgb;
|
|
2973
|
+
vec3 H5 = texture2D(tex, TEX5.yw).rgb;
|
|
2974
|
+
vec3 I5 = texture2D(tex, TEX5.zw).rgb;
|
|
2975
|
+
|
|
2976
|
+
vec3 A0 = texture2D(tex, TEX6.xy).rgb;
|
|
2977
|
+
vec3 D0 = texture2D(tex, TEX6.xz).rgb;
|
|
2978
|
+
vec3 G0 = texture2D(tex, TEX6.xw).rgb;
|
|
2979
|
+
|
|
2980
|
+
vec3 C4 = texture2D(tex, TEX7.xy).rgb;
|
|
2981
|
+
vec3 F4 = texture2D(tex, TEX7.xz).rgb;
|
|
2982
|
+
vec3 I4 = texture2D(tex, TEX7.xw).rgb;
|
|
2983
|
+
|
|
2984
|
+
// Replace mat4x3/transpose with explicit luma packing (GLSL ES 1.00 safe)
|
|
2985
|
+
vec4 b = vec4(lum(B), lum(D), lum(H), lum(F));
|
|
2986
|
+
vec4 c = vec4(lum(C), lum(A), lum(G), lum(I));
|
|
2987
|
+
vec4 e = vec4(lum(E), lum(E), lum(E), lum(E));
|
|
2988
|
+
vec4 d = b.yzwx;
|
|
2989
|
+
vec4 f = b.wxyz;
|
|
2990
|
+
vec4 g = c.zwxy;
|
|
2991
|
+
vec4 h = b.zwxy;
|
|
2992
|
+
vec4 i = c.wxyz;
|
|
2993
|
+
|
|
2994
|
+
vec4 i4v = vec4(lum(I4), lum(C1), lum(A0), lum(G5));
|
|
2995
|
+
vec4 i5v = vec4(lum(I5), lum(C4), lum(A1), lum(G0));
|
|
2996
|
+
vec4 h5v = vec4(lum(H5), lum(F4), lum(B1), lum(D0));
|
|
2997
|
+
vec4 f4v = h5v.yzwx;
|
|
2998
|
+
|
|
2999
|
+
// Edge detection math
|
|
3000
|
+
vec4 fx = (Ao * fp.y + Bo * fp.x);
|
|
3001
|
+
vec4 fx_left = (Ax * fp.y + Bx * fp.x);
|
|
3002
|
+
vec4 fx_up = (Ay * fp.y + By * fp.x);
|
|
3003
|
+
|
|
3004
|
+
bvec4 interp_restriction_lv0 = and4(notEqual(e, f), notEqual(e, h));
|
|
3005
|
+
bvec4 interp_restriction_lv1 = interp_restriction_lv0;
|
|
3006
|
+
|
|
3007
|
+
bvec4 interp_restriction_lv2_left = and4(notEqual(e, g), notEqual(d, g));
|
|
3008
|
+
bvec4 interp_restriction_lv2_up = and4(notEqual(e, c), notEqual(b, c));
|
|
3009
|
+
|
|
3010
|
+
vec4 delta = vec4(1.0 / XBR_SCALE);
|
|
3011
|
+
vec4 deltaL = vec4(0.5 / XBR_SCALE, 1.0 / XBR_SCALE, 0.5 / XBR_SCALE, 1.0 / XBR_SCALE);
|
|
3012
|
+
vec4 deltaU = deltaL.yxwz;
|
|
3013
|
+
|
|
3014
|
+
vec4 fx45i = clamp((fx + delta - Co - Ci) / (2.0 * delta ), 0.0, 1.0);
|
|
3015
|
+
vec4 fx45 = clamp((fx + delta - Co ) / (2.0 * delta ), 0.0, 1.0);
|
|
3016
|
+
vec4 fx30 = clamp((fx_left + deltaL - Co ) / (2.0 * deltaL), 0.0, 1.0);
|
|
3017
|
+
vec4 fx60 = clamp((fx_up + deltaU - Co ) / (2.0 * deltaU), 0.0, 1.0);
|
|
3018
|
+
|
|
3019
|
+
vec4 wd1 = weighted_distance(e, c, g, i, h5v, f4v, h, f);
|
|
3020
|
+
vec4 wd2 = weighted_distance(h, d, i5v, f, i4v, b, e, i);
|
|
3021
|
+
|
|
3022
|
+
bvec4 edri = and4(lessThanEqual(wd1, wd2), interp_restriction_lv0);
|
|
3023
|
+
bvec4 edr = and4(lessThan(wd1, wd2), interp_restriction_lv1);
|
|
3024
|
+
|
|
3025
|
+
bvec4 edr_left = and4(
|
|
3026
|
+
lessThanEqual((XBR_LV2_COEFFICIENT * df4(f, g)), df4(h, c)),
|
|
3027
|
+
interp_restriction_lv2_left
|
|
3028
|
+
);
|
|
3029
|
+
bvec4 edr_up = and4(
|
|
3030
|
+
greaterThanEqual(df4(f, g), (XBR_LV2_COEFFICIENT * df4(h, c))),
|
|
3031
|
+
interp_restriction_lv2_up
|
|
3032
|
+
);
|
|
3033
|
+
|
|
3034
|
+
edr = and4(edr, nand4(edri.yzwx, edri.wxyz));
|
|
3035
|
+
edr_left = and4(and4(edr_left, edr), eq4(e, c));
|
|
3036
|
+
edr_up = and4(and4(edr_up, edr), eq4(e, g));
|
|
3037
|
+
|
|
3038
|
+
fx45 *= vec4(edr);
|
|
3039
|
+
fx30 *= vec4(edr_left);
|
|
3040
|
+
fx60 *= vec4(edr_up);
|
|
3041
|
+
fx45i *= vec4(edri);
|
|
3042
|
+
|
|
3043
|
+
vec4 px = vec4(lessThanEqual(df4(e, f), df4(e, h)));
|
|
3044
|
+
|
|
3045
|
+
vec4 maximos = max(max(fx30, fx60), max(fx45, fx45i));
|
|
3046
|
+
|
|
3047
|
+
vec3 res1 = E;
|
|
3048
|
+
res1 = mix(res1, mix(H, F, px.x), maximos.x);
|
|
3049
|
+
res1 = mix(res1, mix(B, D, px.z), maximos.z);
|
|
3050
|
+
|
|
3051
|
+
vec3 res2 = E;
|
|
3052
|
+
res2 = mix(res1, mix(F, B, px.y), maximos.y);
|
|
3053
|
+
res2 = mix(res1, mix(D, H, px.w), maximos.w);
|
|
3054
|
+
|
|
3055
|
+
vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));
|
|
3056
|
+
|
|
3057
|
+
gl_FragColor = vec4(res, 1.0);
|
|
3058
|
+
}/*
|
|
3059
|
+
Hyllian's xBR-lv3 Shader
|
|
3060
|
+
|
|
3061
|
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
|
|
3062
|
+
|
|
3063
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3064
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3065
|
+
in the Software without restriction, including without limitation the rights
|
|
3066
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3067
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
3068
|
+
furnished to do so, subject to the following conditions:
|
|
3069
|
+
|
|
3070
|
+
The above copyright notice and this permission notice shall be included in
|
|
3071
|
+
all copies or substantial portions of the Software.
|
|
3072
|
+
|
|
3073
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3074
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3075
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3076
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3077
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3078
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
3079
|
+
THE SOFTWARE.
|
|
3080
|
+
|
|
3081
|
+
Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.
|
|
3082
|
+
*/
|
|
3083
|
+
|
|
3084
|
+
attribute vec4 position;
|
|
3085
|
+
|
|
3086
|
+
uniform vec2 texSize;
|
|
3087
|
+
|
|
3088
|
+
varying vec2 texCoord;
|
|
3089
|
+
varying vec4 TEX1;
|
|
3090
|
+
varying vec4 TEX2;
|
|
3091
|
+
varying vec4 TEX3;
|
|
3092
|
+
varying vec4 TEX4;
|
|
3093
|
+
varying vec4 TEX5;
|
|
3094
|
+
varying vec4 TEX6;
|
|
3095
|
+
varying vec4 TEX7;
|
|
3096
|
+
|
|
3097
|
+
void main() {
|
|
3098
|
+
gl_Position = position;
|
|
3099
|
+
|
|
3100
|
+
vec2 ps = vec2(1.0) / texSize;
|
|
3101
|
+
float dx = ps.x;
|
|
3102
|
+
float dy = ps.y;
|
|
3103
|
+
|
|
3104
|
+
// A1 B1 C1
|
|
3105
|
+
// A0 A B C C4
|
|
3106
|
+
// D0 D E F F4
|
|
3107
|
+
// G0 G H I I4
|
|
3108
|
+
// G5 H5 I5
|
|
3109
|
+
|
|
3110
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
3111
|
+
|
|
3112
|
+
// IMPORTANT: use 0.0 (float literal) for strict GLSL ES 1.00 compilers
|
|
3113
|
+
TEX1 = texCoord.xxxy + vec4(-dx, 0.0, dx, -2.0 * dy); // A1 B1 C1
|
|
3114
|
+
TEX2 = texCoord.xxxy + vec4(-dx, 0.0, dx, -1.0 * dy); // A B C
|
|
3115
|
+
TEX3 = texCoord.xxxy + vec4(-dx, 0.0, dx, 0.0 ); // D E F
|
|
3116
|
+
TEX4 = texCoord.xxxy + vec4(-dx, 0.0, dx, 1.0 * dy); // G H I
|
|
3117
|
+
TEX5 = texCoord.xxxy + vec4(-dx, 0.0, dx, 2.0 * dy); // G5 H5 I5
|
|
3118
|
+
TEX6 = texCoord.xyyy + vec4(-2.0 * dx, -dy, 0.0, dy); // A0 D0 G0
|
|
3119
|
+
TEX7 = texCoord.xyyy + vec4( 2.0 * dx, -dy, 0.0, dy); // C4 F4 I4
|
|
3120
|
+
}[shader]
|
|
3121
|
+
name=xBR-lv3
|
|
3122
|
+
author=Hyllian
|
|
3123
|
+
description=xBR-lv3 upsampling filter
|
|
3124
|
+
passes=1
|
|
3125
|
+
|
|
3126
|
+
[pass.0]
|
|
3127
|
+
integerScaling=1
|
|
3128
|
+
vertexShader=xbr.vs
|
|
3129
|
+
fragmentShader=xbr.fs
|
|
3130
|
+
|
|
3131
|
+
[pass.0.uniform.XBR_Y_WEIGHT]
|
|
3132
|
+
type=float
|
|
3133
|
+
default=48
|
|
3134
|
+
readableName=Y Weight
|
|
3135
|
+
min=0
|
|
3136
|
+
max=100
|
|
3137
|
+
|
|
3138
|
+
[pass.0.uniform.XBR_EQ_THRESHOLD]
|
|
3139
|
+
type=float
|
|
3140
|
+
readableName=Eq Threshold
|
|
3141
|
+
default=10.0
|
|
3142
|
+
min=0.0
|
|
3143
|
+
max=50.0
|
|
3144
|
+
|
|
3145
|
+
[pass.0.uniform.XBR_EQ_THRESHOLD2]
|
|
3146
|
+
type=float
|
|
3147
|
+
readableName=Eq Threshold2
|
|
3148
|
+
default=2.0
|
|
3149
|
+
min=0.0
|
|
3150
|
+
max=4.0
|
|
3151
|
+
|
|
3152
|
+
[pass.0.uniform.XBR_LV2_COEFFICIENT]
|
|
3153
|
+
type=float
|
|
3154
|
+
readableName=Lv2 Coefficient
|
|
3155
|
+
default=2.0
|
|
3156
|
+
min=1.0
|
|
3157
|
+
max=3.0
|
|
3158
|
+
/*
|
|
3159
|
+
Hyllian's xBR-lv3 Shader
|
|
3160
|
+
|
|
3161
|
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
|
|
3162
|
+
|
|
3163
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3164
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3165
|
+
in the Software without restriction, including without limitation the rights
|
|
3166
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3167
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
3168
|
+
furnished to do so, subject to the following conditions:
|
|
3169
|
+
|
|
3170
|
+
The above copyright notice and this permission notice shall be included in
|
|
3171
|
+
all copies or substantial portions of the Software.
|
|
3172
|
+
|
|
3173
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3174
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3175
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3176
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3177
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3178
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
3179
|
+
THE SOFTWARE.
|
|
3180
|
+
|
|
3181
|
+
|
|
3182
|
+
Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.
|
|
3183
|
+
*/
|
|
3184
|
+
|
|
3185
|
+
uniform float XBR_Y_WEIGHT;
|
|
3186
|
+
uniform float XBR_EQ_THRESHOLD;
|
|
3187
|
+
uniform float XBR_EQ_THRESHOLD2;
|
|
3188
|
+
uniform float XBR_LV2_COEFFICIENT;
|
|
3189
|
+
|
|
3190
|
+
uniform sampler2D tex;
|
|
3191
|
+
uniform vec2 texSize;
|
|
3192
|
+
|
|
3193
|
+
varying vec2 texCoord;
|
|
3194
|
+
varying vec4 TEX1;
|
|
3195
|
+
varying vec4 TEX2;
|
|
3196
|
+
varying vec4 TEX3;
|
|
3197
|
+
varying vec4 TEX4;
|
|
3198
|
+
varying vec4 TEX5;
|
|
3199
|
+
varying vec4 TEX6;
|
|
3200
|
+
varying vec4 TEX7;
|
|
3201
|
+
|
|
3202
|
+
const mat3 yuv = mat3(
|
|
3203
|
+
0.299, 0.587, 0.114,
|
|
3204
|
+
-0.169, -0.331, 0.499,
|
|
3205
|
+
0.499, -0.418, -0.0813
|
|
3206
|
+
);
|
|
3207
|
+
|
|
3208
|
+
// keep same delta
|
|
3209
|
+
const vec4 delta = vec4(0.4, 0.4, 0.4, 0.4);
|
|
3210
|
+
|
|
3211
|
+
vec4 df4(vec4 A, vec4 B) {
|
|
3212
|
+
return abs(A - B);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
float c_df(vec3 c1, vec3 c2) {
|
|
3216
|
+
vec3 d = abs(c1 - c2);
|
|
3217
|
+
return d.r + d.g + d.b;
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
bvec4 eq4(vec4 A, vec4 B) {
|
|
3221
|
+
return lessThan(df4(A, B), vec4(XBR_EQ_THRESHOLD));
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
bvec4 eq24(vec4 A, vec4 B) {
|
|
3225
|
+
return lessThan(df4(A, B), vec4(XBR_EQ_THRESHOLD2));
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
bvec4 and4(bvec4 A, bvec4 B) {
|
|
3229
|
+
return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w);
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
bvec4 or4(bvec4 A, bvec4 B) {
|
|
3233
|
+
return bvec4(A.x || B.x, A.y || B.y, A.z || B.z, A.w || B.w);
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) {
|
|
3237
|
+
return (df4(a,b) + df4(a,c) + df4(d,e) + df4(d,f) + 4.0 * df4(g,h));
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
void main() {
|
|
3241
|
+
bvec4 edr, edr_left, edr_up, edr3_left, edr3_up, px;
|
|
3242
|
+
bvec4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up;
|
|
3243
|
+
bvec4 interp_restriction_lv3_left, interp_restriction_lv3_up;
|
|
3244
|
+
bvec4 nc, nc30, nc60, nc45, nc15, nc75;
|
|
3245
|
+
vec4 fx, fx_left, fx_up, fx3_left, fx3_up;
|
|
3246
|
+
vec3 res1, res2, pix1, pix2;
|
|
3247
|
+
float blend1, blend2;
|
|
3248
|
+
|
|
3249
|
+
// IMPORTANT: initialize to avoid undefined reads on some compilers
|
|
3250
|
+
pix1 = vec3(0.0);
|
|
3251
|
+
pix2 = vec3(0.0);
|
|
3252
|
+
blend1 = 0.0;
|
|
3253
|
+
blend2 = 0.0;
|
|
3254
|
+
|
|
3255
|
+
vec2 fp = fract(texCoord * texSize);
|
|
3256
|
+
|
|
3257
|
+
vec3 A1 = texture2D(tex, TEX1.xw).rgb;
|
|
3258
|
+
vec3 B1 = texture2D(tex, TEX1.yw).rgb;
|
|
3259
|
+
vec3 C1 = texture2D(tex, TEX1.zw).rgb;
|
|
3260
|
+
|
|
3261
|
+
vec3 A = texture2D(tex, TEX2.xw).rgb;
|
|
3262
|
+
vec3 B = texture2D(tex, TEX2.yw).rgb;
|
|
3263
|
+
vec3 C = texture2D(tex, TEX2.zw).rgb;
|
|
3264
|
+
|
|
3265
|
+
vec3 D = texture2D(tex, TEX3.xw).rgb;
|
|
3266
|
+
vec3 E = texture2D(tex, TEX3.yw).rgb;
|
|
3267
|
+
vec3 F = texture2D(tex, TEX3.zw).rgb;
|
|
3268
|
+
|
|
3269
|
+
vec3 G = texture2D(tex, TEX4.xw).rgb;
|
|
3270
|
+
vec3 H = texture2D(tex, TEX4.yw).rgb;
|
|
3271
|
+
vec3 I = texture2D(tex, TEX4.zw).rgb;
|
|
3272
|
+
|
|
3273
|
+
vec3 G5 = texture2D(tex, TEX5.xw).rgb;
|
|
3274
|
+
vec3 H5 = texture2D(tex, TEX5.yw).rgb;
|
|
3275
|
+
vec3 I5 = texture2D(tex, TEX5.zw).rgb;
|
|
3276
|
+
|
|
3277
|
+
vec3 A0 = texture2D(tex, TEX6.xy).rgb;
|
|
3278
|
+
vec3 D0 = texture2D(tex, TEX6.xz).rgb;
|
|
3279
|
+
vec3 G0 = texture2D(tex, TEX6.xw).rgb;
|
|
3280
|
+
|
|
3281
|
+
vec3 C4 = texture2D(tex, TEX7.xy).rgb;
|
|
3282
|
+
vec3 F4 = texture2D(tex, TEX7.xz).rgb;
|
|
3283
|
+
vec3 I4 = texture2D(tex, TEX7.xw).rgb;
|
|
3284
|
+
|
|
3285
|
+
// Replace mat4x3 + transpose with explicit dot products (GLSL ES 1.00 safe)
|
|
3286
|
+
// Original: transpose(mat4x3(...)) * (XBR_Y_WEIGHT * yuv[0])
|
|
3287
|
+
vec3 Yw = (XBR_Y_WEIGHT * yuv[0]);
|
|
3288
|
+
|
|
3289
|
+
vec4 b = vec4(dot(B, Yw), dot(D, Yw), dot(H, Yw), dot(F, Yw));
|
|
3290
|
+
vec4 c = vec4(dot(C, Yw), dot(A, Yw), dot(G, Yw), dot(I, Yw));
|
|
3291
|
+
vec4 e = vec4(dot(E, Yw), dot(E, Yw), dot(E, Yw), dot(E, Yw));
|
|
3292
|
+
vec4 d = b.yzwx;
|
|
3293
|
+
vec4 f = b.wxyz;
|
|
3294
|
+
vec4 g = c.zwxy;
|
|
3295
|
+
vec4 h = b.zwxy;
|
|
3296
|
+
vec4 i = c.wxyz;
|
|
3297
|
+
|
|
3298
|
+
vec4 i4v = vec4(dot(I4, Yw), dot(C1, Yw), dot(A0, Yw), dot(G5, Yw));
|
|
3299
|
+
vec4 i5v = vec4(dot(I5, Yw), dot(C4, Yw), dot(A1, Yw), dot(G0, Yw));
|
|
3300
|
+
vec4 h5v = vec4(dot(H5, Yw), dot(F4, Yw), dot(B1, Yw), dot(D0, Yw));
|
|
3301
|
+
vec4 f4v = h5v.yzwx;
|
|
3302
|
+
|
|
3303
|
+
vec4 c1 = i4v.yzwx;
|
|
3304
|
+
vec4 g0 = i5v.wxyz;
|
|
3305
|
+
vec4 b1 = h5v.zwxy;
|
|
3306
|
+
vec4 d0 = h5v.wxyz;
|
|
3307
|
+
|
|
3308
|
+
// same constants as original
|
|
3309
|
+
vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
3310
|
+
vec4 Bo = vec4( 1.0, 1.0, -1.0, -1.0 );
|
|
3311
|
+
vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );
|
|
3312
|
+
vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
3313
|
+
vec4 Bx = vec4( 0.5, 2.0, -0.5, -2.0 );
|
|
3314
|
+
vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );
|
|
3315
|
+
vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
|
|
3316
|
+
vec4 By = vec4( 2.0, 0.5, -2.0, -0.5 );
|
|
3317
|
+
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
|
|
3318
|
+
|
|
3319
|
+
vec4 Az = vec4( 6.0, -2.0, -6.0, 2.0 );
|
|
3320
|
+
vec4 Bz = vec4( 2.0, 6.0, -2.0, -6.0 );
|
|
3321
|
+
vec4 Cz = vec4( 5.0, 3.0, -3.0, -1.0 );
|
|
3322
|
+
vec4 Aw = vec4( 2.0, -6.0, -2.0, 6.0 );
|
|
3323
|
+
vec4 Bw = vec4( 6.0, 2.0, -6.0, -2.0 );
|
|
3324
|
+
vec4 Cw = vec4( 5.0, -1.0, -3.0, 3.0 );
|
|
3325
|
+
|
|
3326
|
+
fx = (Ao * fp.y + Bo * fp.x);
|
|
3327
|
+
fx_left = (Ax * fp.y + Bx * fp.x);
|
|
3328
|
+
fx_up = (Ay * fp.y + By * fp.x);
|
|
3329
|
+
fx3_left = (Az * fp.y + Bz * fp.x);
|
|
3330
|
+
fx3_up = (Aw * fp.y + Bw * fp.x);
|
|
3331
|
+
|
|
3332
|
+
// Keep CORNER_* behavior EXACTLY. Default path is CORNER_C branch (the else).
|
|
3333
|
+
#ifdef CORNER_A
|
|
3334
|
+
interp_restriction_lv1 = and4(notEqual(e, f), notEqual(e, h));
|
|
3335
|
+
#elif defined(CORNER_B)
|
|
3336
|
+
interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq4(f,b) && !eq4(h,d) || eq4(e,i) && !eq4(f,i4v) && !eq4(h,i5v) || eq4(e,g) || eq4(e,c) ) );
|
|
3337
|
+
#elif defined(CORNER_D)
|
|
3338
|
+
interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq4(f,b) && !eq4(h,d) || eq4(e,i) && !eq4(f,i4v) && !eq4(h,i5v) || eq4(e,g) || eq4(e,c) ) && (f!=f4v && f!=i || h!=h5v && h!=i || h!=g || f!=c || eq4(b,c1) && eq4(d,g0)));
|
|
3339
|
+
#else
|
|
3340
|
+
interp_restriction_lv1 = and4(
|
|
3341
|
+
and4(notEqual(e, f), notEqual(e, h)),
|
|
3342
|
+
or4(
|
|
3343
|
+
or4(
|
|
3344
|
+
and4(not(eq4(f,b)), not(eq4(f,c))),
|
|
3345
|
+
and4(not(eq4(h,d)), not(eq4(h,g)))
|
|
3346
|
+
),
|
|
3347
|
+
or4(
|
|
3348
|
+
and4(
|
|
3349
|
+
eq4(e,i),
|
|
3350
|
+
or4(
|
|
3351
|
+
and4(not(eq4(f,f4v)), not(eq4(f,i4v))),
|
|
3352
|
+
and4(not(eq4(h,h5v)), not(eq4(h,i5v)))
|
|
3353
|
+
)
|
|
3354
|
+
),
|
|
3355
|
+
or4(eq4(e,g), eq4(e,c))
|
|
3356
|
+
)
|
|
3357
|
+
)
|
|
3358
|
+
);
|
|
3359
|
+
#endif
|
|
3360
|
+
|
|
3361
|
+
interp_restriction_lv2_left = and4(notEqual(e, g), notEqual(d, g));
|
|
3362
|
+
interp_restriction_lv2_up = and4(notEqual(e, c), notEqual(b, c));
|
|
3363
|
+
interp_restriction_lv3_left = and4(eq24(g, g0), not(eq24(d0, g0)));
|
|
3364
|
+
interp_restriction_lv3_up = and4(eq24(c, c1), not(eq24(b1, c1)));
|
|
3365
|
+
|
|
3366
|
+
vec4 fx45 = smoothstep(Co - delta, Co + delta, fx);
|
|
3367
|
+
vec4 fx30 = smoothstep(Cx - delta, Cx + delta, fx_left);
|
|
3368
|
+
vec4 fx60 = smoothstep(Cy - delta, Cy + delta, fx_up);
|
|
3369
|
+
vec4 fx15 = smoothstep(Cz - delta, Cz + delta, fx3_left);
|
|
3370
|
+
vec4 fx75 = smoothstep(Cw - delta, Cw + delta, fx3_up);
|
|
3371
|
+
|
|
3372
|
+
edr = and4(
|
|
3373
|
+
lessThan(
|
|
3374
|
+
weighted_distance(e, c, g, i, h5v, f4v, h, f),
|
|
3375
|
+
weighted_distance(h, d, i5v, f, i4v, b, e, i)
|
|
3376
|
+
),
|
|
3377
|
+
interp_restriction_lv1
|
|
3378
|
+
);
|
|
3379
|
+
|
|
3380
|
+
edr_left = and4(lessThanEqual((XBR_LV2_COEFFICIENT * df4(f,g)), df4(h,c)), interp_restriction_lv2_left);
|
|
3381
|
+
edr_up = and4(greaterThanEqual(df4(f,g), (XBR_LV2_COEFFICIENT * df4(h,c))), interp_restriction_lv2_up);
|
|
3382
|
+
edr3_left = interp_restriction_lv3_left;
|
|
3383
|
+
edr3_up = interp_restriction_lv3_up;
|
|
3384
|
+
|
|
3385
|
+
nc45 = and4(edr, bvec4(fx45));
|
|
3386
|
+
nc30 = and4(edr, and4(edr_left, bvec4(fx30)));
|
|
3387
|
+
nc60 = and4(edr, and4(edr_up, bvec4(fx60)));
|
|
3388
|
+
nc15 = and4(and4(edr, edr_left), and4(edr3_left, bvec4(fx15)));
|
|
3389
|
+
nc75 = and4(and4(edr, edr_up), and4(edr3_up, bvec4(fx75)));
|
|
3390
|
+
|
|
3391
|
+
px = lessThanEqual(df4(e, f), df4(e, h));
|
|
3392
|
+
|
|
3393
|
+
nc = bvec4(
|
|
3394
|
+
(nc75.x || nc15.x || nc30.x || nc60.x || nc45.x),
|
|
3395
|
+
(nc75.y || nc15.y || nc30.y || nc60.y || nc45.y),
|
|
3396
|
+
(nc75.z || nc15.z || nc30.z || nc60.z || nc45.z),
|
|
3397
|
+
(nc75.w || nc15.w || nc30.w || nc60.w || nc45.w)
|
|
3398
|
+
);
|
|
3399
|
+
|
|
3400
|
+
vec4 final45 = vec4(nc45) * fx45;
|
|
3401
|
+
vec4 final30 = vec4(nc30) * fx30;
|
|
3402
|
+
vec4 final60 = vec4(nc60) * fx60;
|
|
3403
|
+
vec4 final15 = vec4(nc15) * fx15;
|
|
3404
|
+
vec4 final75 = vec4(nc75) * fx75;
|
|
3405
|
+
|
|
3406
|
+
vec4 maximo = max(max(max(final15, final75), max(final30, final60)), final45);
|
|
3407
|
+
|
|
3408
|
+
if (nc.x) { pix1 = px.x ? F : H; blend1 = maximo.x; }
|
|
3409
|
+
else if (nc.y) { pix1 = px.y ? B : F; blend1 = maximo.y; }
|
|
3410
|
+
else if (nc.z) { pix1 = px.z ? D : B; blend1 = maximo.z; }
|
|
3411
|
+
else if (nc.w) { pix1 = px.w ? H : D; blend1 = maximo.w; }
|
|
3412
|
+
|
|
3413
|
+
if (nc.w) { pix2 = px.w ? H : D; blend2 = maximo.w; }
|
|
3414
|
+
else if (nc.z) { pix2 = px.z ? D : B; blend2 = maximo.z; }
|
|
3415
|
+
else if (nc.y) { pix2 = px.y ? B : F; blend2 = maximo.y; }
|
|
3416
|
+
else if (nc.x) { pix2 = px.x ? F : H; blend2 = maximo.x; }
|
|
3417
|
+
|
|
3418
|
+
res1 = mix(E, pix1, blend1);
|
|
3419
|
+
res2 = mix(E, pix2, blend2);
|
|
3420
|
+
|
|
3421
|
+
vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));
|
|
3422
|
+
|
|
3423
|
+
gl_FragColor = vec4(res, 1.0);
|
|
3424
|
+
}/*
|
|
3425
|
+
Hyllian's xBR-lv3 Shader
|
|
3426
|
+
|
|
3427
|
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
|
|
3428
|
+
|
|
3429
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3430
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3431
|
+
in the Software without restriction, including without limitation the rights
|
|
3432
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3433
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
3434
|
+
furnished to do so, subject to the following conditions:
|
|
3435
|
+
|
|
3436
|
+
The above copyright notice and this permission notice shall be included in
|
|
3437
|
+
all copies or substantial portions of the Software.
|
|
3438
|
+
|
|
3439
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3440
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3441
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3442
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3443
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3444
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
3445
|
+
THE SOFTWARE.
|
|
3446
|
+
|
|
3447
|
+
Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.
|
|
3448
|
+
*/
|
|
3449
|
+
|
|
3450
|
+
attribute vec4 position;
|
|
3451
|
+
|
|
3452
|
+
uniform vec2 texSize;
|
|
3453
|
+
|
|
3454
|
+
varying vec2 texCoord;
|
|
3455
|
+
varying vec4 TEX1;
|
|
3456
|
+
varying vec4 TEX2;
|
|
3457
|
+
varying vec4 TEX3;
|
|
3458
|
+
varying vec4 TEX4;
|
|
3459
|
+
varying vec4 TEX5;
|
|
3460
|
+
varying vec4 TEX6;
|
|
3461
|
+
varying vec4 TEX7;
|
|
3462
|
+
|
|
3463
|
+
void main() {
|
|
3464
|
+
gl_Position = position;
|
|
3465
|
+
|
|
3466
|
+
vec2 ps = vec2(1.0) / texSize;
|
|
3467
|
+
float dx = ps.x;
|
|
3468
|
+
float dy = ps.y;
|
|
3469
|
+
|
|
3470
|
+
texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
|
|
3471
|
+
|
|
3472
|
+
// use 0.0 (float literals) for strict GLSL ES 1.00 compilers
|
|
3473
|
+
TEX1 = texCoord.xxxy + vec4(-dx, 0.0, dx, -2.0 * dy); // A1 B1 C1
|
|
3474
|
+
TEX2 = texCoord.xxxy + vec4(-dx, 0.0, dx, -1.0 * dy); // A B C
|
|
3475
|
+
TEX3 = texCoord.xxxy + vec4(-dx, 0.0, dx, 0.0 ); // D E F
|
|
3476
|
+
TEX4 = texCoord.xxxy + vec4(-dx, 0.0, dx, 1.0 * dy); // G H I
|
|
3477
|
+
TEX5 = texCoord.xxxy + vec4(-dx, 0.0, dx, 2.0 * dy); // G5 H5 I5
|
|
3478
|
+
TEX6 = texCoord.xyyy + vec4(-2.0 * dx, -dy, 0.0, dy); // A0 D0 G0
|
|
3479
|
+
TEX7 = texCoord.xyyy + vec4( 2.0 * dx, -dy, 0.0, dy); // C4 F4 I4
|
|
3480
|
+
}
|