1#version 130
2
3// OmniScale
4// by Lior Halphon
5// ported to RetroArch glsl by hunterk
6
7/*
8MIT License
9
10Copyright (c) 2015-2016 Lior Halphon
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29*/
30
31#if defined(VERTEX)
32
33#if __VERSION__ >= 130
34#define COMPAT_VARYING out
35#define COMPAT_ATTRIBUTE in
36#define COMPAT_TEXTURE texture
37#else
38#define COMPAT_VARYING varying
39#define COMPAT_ATTRIBUTE attribute
40#define COMPAT_TEXTURE texture2D
41#endif
42
43#ifdef GL_ES
44#define COMPAT_PRECISION mediump
45#else
46#define COMPAT_PRECISION
47#endif
48
49COMPAT_ATTRIBUTE vec4 VertexCoord;
50COMPAT_ATTRIBUTE vec4 COLOR;
51COMPAT_ATTRIBUTE vec4 TexCoord;
52COMPAT_VARYING vec4 COL0;
53COMPAT_VARYING vec4 TEX0;
54
55uniform mat4 MVPMatrix;
56uniform COMPAT_PRECISION int FrameDirection;
57uniform COMPAT_PRECISION int FrameCount;
58uniform COMPAT_PRECISION vec2 OutputSize;
59uniform COMPAT_PRECISION vec2 TextureSize;
60uniform COMPAT_PRECISION vec2 InputSize;
61
62// vertex compatibility #defines
63#define vTexCoord TEX0.xy
64#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
65#define outsize vec4(OutputSize, 1.0 / OutputSize)
66
67void main()
68{
69    gl_Position = MVPMatrix * VertexCoord;
70    COL0 = COLOR;
71    TEX0.xy = TexCoord.xy;
72}
73
74#elif defined(FRAGMENT)
75
76#if __VERSION__ >= 130
77#define COMPAT_VARYING in
78#define COMPAT_TEXTURE texture
79out mediump vec4 FragColor;
80#else
81#define COMPAT_VARYING varying
82#define FragColor gl_FragColor
83#define COMPAT_TEXTURE texture2D
84#endif
85
86#ifdef GL_ES
87#ifdef GL_FRAGMENT_PRECISION_HIGH
88precision highp float;
89#else
90precision mediump float;
91precision mediump int;
92#endif
93#define COMPAT_PRECISION mediump
94#else
95#define COMPAT_PRECISION
96#endif
97
98uniform COMPAT_PRECISION int FrameDirection;
99uniform COMPAT_PRECISION int FrameCount;
100uniform COMPAT_PRECISION vec2 OutputSize;
101uniform COMPAT_PRECISION vec2 TextureSize;
102uniform COMPAT_PRECISION vec2 InputSize;
103uniform sampler2D Texture;
104COMPAT_VARYING vec4 TEX0;
105
106// fragment compatibility #defines
107#define Source Texture
108#define vTexCoord TEX0.xy
109
110#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
111#define outsize vec4(OutputSize, 1.0 / OutputSize)
112
113/* We use the same colorspace as the HQ algorithms. */
114vec3 rgb_to_hq_colospace(vec4 rgb)
115{
116    return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
117                 0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
118                -0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b);
119}
120
121
122bool is_different(vec4 a, vec4 b)
123{
124    vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b));
125    return diff.x > 0.125 || diff.y > 0.027 || diff.z > 0.031;
126}
127
128#define P(m, r) ((pattern & (m)) == (r))
129
130#define uResolution outsize.xy
131#define textureDimensions SourceSize.xy
132
133vec4 scale(sampler2D image, vec2 coord)
134{
135    // o = offset, the width of a pixel
136    vec2 o = 1.0 / textureDimensions;
137    vec2 texCoord = coord;
138
139    /* We always calculate the top left quarter.  If we need a different quarter, we flip our co-ordinates */
140
141    // p = the position within a pixel [0...1]
142    vec2 p = fract(texCoord * textureDimensions);
143
144    if (p.x > 0.5) {
145        o.x = -o.x;
146        p.x = 1.0 - p.x;
147    }
148    if (p.y > 0.5) {
149        o.y = -o.y;
150        p.y = 1.0 - p.y;
151    }
152
153
154
155    vec4 w0 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x, -o.y));
156    vec4 w1 = COMPAT_TEXTURE(image, texCoord + vec2(    0, -o.y));
157    vec4 w2 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x, -o.y));
158    vec4 w3 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x,    0));
159    vec4 w4 = COMPAT_TEXTURE(image, texCoord + vec2(    0,    0));
160    vec4 w5 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x,    0));
161    vec4 w6 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x,  o.y));
162    vec4 w7 = COMPAT_TEXTURE(image, texCoord + vec2(    0,  o.y));
163    vec4 w8 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x,  o.y));
164
165    int pattern = 0;
166    if (is_different(w0, w4)) pattern |= 1 << 0;
167    if (is_different(w1, w4)) pattern |= 1 << 1;
168    if (is_different(w2, w4)) pattern |= 1 << 2;
169    if (is_different(w3, w4)) pattern |= 1 << 3;
170    if (is_different(w5, w4)) pattern |= 1 << 4;
171    if (is_different(w6, w4)) pattern |= 1 << 5;
172    if (is_different(w7, w4)) pattern |= 1 << 6;
173    if (is_different(w8, w4)) pattern |= 1 << 7;
174
175    if ((P(0xbf,0x37) || P(0xdb,0x13)) && is_different(w1, w5))
176        return mix(w4, w3, 0.5 - p.x);
177    if ((P(0xdb,0x49) || P(0xef,0x6d)) && is_different(w7, w3))
178        return mix(w4, w1, 0.5 - p.y);
179    if ((P(0x0b,0x0b) || P(0xfe,0x4a) || P(0xfe,0x1a)) && is_different(w3, w1))
180        return w4;
181    if ((P(0x6f,0x2a) || P(0x5b,0x0a) || P(0xbf,0x3a) || P(0xdf,0x5a) ||
182         P(0x9f,0x8a) || P(0xcf,0x8a) || P(0xef,0x4e) || P(0x3f,0x0e) ||
183         P(0xfb,0x5a) || P(0xbb,0x8a) || P(0x7f,0x5a) || P(0xaf,0x8a) ||
184         P(0xeb,0x8a)) && is_different(w3, w1))
185        return mix(w4, mix(w4, w0, 0.5 - p.x), 0.5 - p.y);
186    if (P(0x0b,0x08))
187        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);
188    if (P(0x0b,0x02))
189        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);
190    if (P(0x2f,0x2f)) {
191        float dist = length(p - vec2(0.5));
192        float pixel_size = length(1.0 / (uResolution / textureDimensions));
193        if (dist < 0.5 - pixel_size / 2.) {
194            return w4;
195        }
196        vec4 r;
197        if (is_different(w0, w1) || is_different(w0, w3)) {
198            r = mix(w1, w3, p.y - p.x + 0.5);
199        }
200        else {
201            r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
202        }
203
204        if (dist > 0.5 + pixel_size / 2.) {
205            return r;
206        }
207        return mix(w4, r, (dist - 0.5 + pixel_size / 2.) / pixel_size);
208    }
209    if (P(0xbf,0x37) || P(0xdb,0x13)) {
210        float dist = p.x - 2.0 * p.y;
211        float pixel_size = length(1.0 / (uResolution / textureDimensions)) * sqrt(5.);
212        if (dist > pixel_size / 2.) {
213            return w1;
214        }
215        vec4 r = mix(w3, w4, p.x + 0.5);
216        if (dist < -pixel_size / 2.) {
217            return r;
218        }
219        return mix(r, w1, (dist + pixel_size / 2.) / pixel_size);
220    }
221    if (P(0xdb,0x49) || P(0xef,0x6d)) {
222        float dist = p.y - 2.0 * p.x;
223        float pixel_size = length(1.0 / (uResolution / textureDimensions)) * sqrt(5.);
224        if (p.y - 2.0 * p.x > pixel_size / 2.) {
225            return w3;
226        }
227        vec4 r = mix(w1, w4, p.x + 0.5);
228        if (dist < -pixel_size / 2.) {
229            return r;
230        }
231        return mix(r, w3, (dist + pixel_size / 2.) / pixel_size);
232    }
233    if (P(0xbf,0x8f) || P(0x7e,0x0e)) {
234        float dist = p.x + 2.0 * p.y;
235        float pixel_size = length(1.0 / (uResolution / textureDimensions)) * sqrt(5.);
236
237        if (dist > 1.0 + pixel_size / 2.) {
238            return w4;
239        }
240
241        vec4 r;
242        if (is_different(w0, w1) || is_different(w0, w3)) {
243            r = mix(w1, w3, p.y - p.x + 0.5);
244        }
245        else {
246            r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
247        }
248
249        if (dist < 1.0 - pixel_size / 2.) {
250            return r;
251        }
252
253        return mix(r, w4, (dist + pixel_size / 2. - 1.0) / pixel_size);
254
255    }
256
257    if (P(0x7e,0x2a) || P(0xef,0xab)) {
258        float dist = p.y + 2.0 * p.x;
259        float pixel_size = length(1.0 / (uResolution / textureDimensions)) * sqrt(5.);
260
261        if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2.) {
262            return w4;
263        }
264
265        vec4 r;
266
267        if (is_different(w0, w1) || is_different(w0, w3)) {
268            r = mix(w1, w3, p.y - p.x + 0.5);
269        }
270        else {
271            r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
272        }
273
274        if (dist < 1.0 - pixel_size / 2.) {
275            return r;
276        }
277
278        return mix(r, w4, (dist + pixel_size / 2. - 1.0) / pixel_size);
279    }
280
281    if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
282        return mix(w4, w3, 0.5 - p.x);
283
284    if (P(0x4b,0x09) || P(0x8b,0x89) || P(0x1f,0x19) || P(0x3b,0x19))
285        return mix(w4, w1, 0.5 - p.y);
286
287    if (P(0xfb,0x6a) || P(0x6f,0x6e) || P(0x3f,0x3e) || P(0xfb,0xfa) ||
288        P(0xdf,0xde) || P(0xdf,0x1e))
289        return mix(w4, w0, (1.0 - p.x - p.y) / 2.0);
290
291    if (P(0x4f,0x4b) || P(0x9f,0x1b) || P(0x2f,0x0b) ||
292        P(0xbe,0x0a) || P(0xee,0x0a) || P(0x7e,0x0a) || P(0xeb,0x4b) ||
293        P(0x3b,0x1b)) {
294        float dist = p.x + p.y;
295        float pixel_size = length(1.0 / (uResolution / textureDimensions));
296
297        if (dist > 0.5 + pixel_size / 2.) {
298            return w4;
299        }
300
301        vec4 r;
302        if (is_different(w0, w1) || is_different(w0, w3)) {
303            r = mix(w1, w3, p.y - p.x + 0.5);
304        }
305        else {
306            r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
307        }
308
309        if (dist < 0.5 - pixel_size / 2.) {
310            return r;
311        }
312
313        return mix(r, w4, (dist + pixel_size / 2. - 0.5) / pixel_size);
314    }
315
316    if (P(0x0b,0x01))
317        return mix(mix(w4, w3, 0.5 - p.x), mix(w1, (w1 + w3) / 2.0, 0.5 - p.x), 0.5 - p.y);
318
319    if (P(0x0b,0x00))
320        return mix(mix(w4, w3, 0.5 - p.x), mix(w1, w0, 0.5 - p.x), 0.5 - p.y);
321
322    float dist = p.x + p.y;
323    float pixel_size = length(1.0 / (uResolution / textureDimensions));
324
325    if (dist > 0.5 + pixel_size / 2.)
326        return w4;
327
328    /* We need more samples to "solve" this diagonal */
329    vec4 x0 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x * 2.0, -o.y * 2.0));
330    vec4 x1 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x      , -o.y * 2.0));
331    vec4 x2 = COMPAT_TEXTURE(image, texCoord + vec2(  0.0      , -o.y * 2.0));
332    vec4 x3 = COMPAT_TEXTURE(image, texCoord + vec2(  o.x      , -o.y * 2.0));
333    vec4 x4 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x * 2.0, -o.y      ));
334    vec4 x5 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x * 2.0,  0.0      ));
335    vec4 x6 = COMPAT_TEXTURE(image, texCoord + vec2( -o.x * 2.0,  o.y      ));
336
337    if (is_different(x0, w4)) pattern |= 1 << 8;
338    if (is_different(x1, w4)) pattern |= 1 << 9;
339    if (is_different(x2, w4)) pattern |= 1 << 10;
340    if (is_different(x3, w4)) pattern |= 1 << 11;
341    if (is_different(x4, w4)) pattern |= 1 << 12;
342    if (is_different(x5, w4)) pattern |= 1 << 13;
343    if (is_different(x6, w4)) pattern |= 1 << 14;
344
345    int diagonal_bias = -7;
346    while (pattern != 0) {
347        diagonal_bias += pattern & 1;
348        pattern >>= 1;
349    }
350
351    if (diagonal_bias <=  0) {
352        vec4 r = mix(w1, w3, p.y - p.x + 0.5);
353        if (dist < 0.5 - pixel_size / 2.) {
354            return r;
355        }
356        return mix(r, w4, (dist + pixel_size / 2. - 0.5) / pixel_size);
357    }
358
359    return w4;
360}
361
362void main()
363{
364	FragColor = scale(Source, vTexCoord);
365}
366#endif
367