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