1// Compatibility #ifdefs needed for parameters 2#ifdef GL_ES 3#define COMPAT_PRECISION mediump 4#else 5#define COMPAT_PRECISION 6#endif 7 8// Parameter lines go here: 9#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01 10#ifdef PARAMETER_UNIFORM 11// All parameter floats need to have COMPAT_PRECISION in front of them 12uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE; 13#else 14#define RETRO_PIXEL_SIZE 0.84 15#endif 16 17#if defined(VERTEX) 18 19#if __VERSION__ >= 130 20#define COMPAT_VARYING out 21#define COMPAT_ATTRIBUTE in 22#define COMPAT_TEXTURE texture 23#else 24#define COMPAT_VARYING varying 25#define COMPAT_ATTRIBUTE attribute 26#define COMPAT_TEXTURE texture2D 27#endif 28 29#ifdef GL_ES 30#define COMPAT_PRECISION mediump 31#else 32#define COMPAT_PRECISION 33#endif 34 35COMPAT_ATTRIBUTE vec4 VertexCoord; 36COMPAT_ATTRIBUTE vec4 COLOR; 37COMPAT_ATTRIBUTE vec4 TexCoord; 38COMPAT_VARYING vec4 COL0; 39COMPAT_VARYING vec4 TEX0; 40// out variables go here as COMPAT_VARYING whatever 41 42vec4 _oPosition1; 43uniform mat4 MVPMatrix; 44uniform COMPAT_PRECISION int FrameDirection; 45uniform COMPAT_PRECISION int FrameCount; 46uniform COMPAT_PRECISION vec2 OutputSize; 47uniform COMPAT_PRECISION vec2 TextureSize; 48uniform COMPAT_PRECISION vec2 InputSize; 49 50// compatibility #defines 51#define vTexCoord TEX0.xy 52#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 53#define OutSize vec4(OutputSize, 1.0 / OutputSize) 54 55void main() 56{ 57 gl_Position = MVPMatrix * VertexCoord; 58 TEX0.xy = VertexCoord.xy; 59// Paste vertex contents here: 60} 61 62#elif defined(FRAGMENT) 63 64#if __VERSION__ >= 130 65#define COMPAT_VARYING in 66#define COMPAT_TEXTURE texture 67out vec4 FragColor; 68#else 69#define COMPAT_VARYING varying 70#define FragColor gl_FragColor 71#define COMPAT_TEXTURE texture2D 72#endif 73 74#ifdef GL_ES 75#ifdef GL_FRAGMENT_PRECISION_HIGH 76precision highp float; 77#else 78precision mediump float; 79#endif 80#define COMPAT_PRECISION mediump 81#else 82#define COMPAT_PRECISION 83#endif 84 85uniform COMPAT_PRECISION int FrameDirection; 86uniform COMPAT_PRECISION int FrameCount; 87uniform COMPAT_PRECISION vec2 OutputSize; 88uniform COMPAT_PRECISION vec2 TextureSize; 89uniform COMPAT_PRECISION vec2 InputSize; 90uniform sampler2D Texture; 91COMPAT_VARYING vec4 TEX0; 92// in variables go here as COMPAT_VARYING whatever 93 94// compatibility #defines 95#define Source Texture 96#define vTexCoord TEX0.xy 97 98#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 99#define OutSize vec4(OutputSize, 1.0 / OutputSize) 100 101// delete all 'params.' or 'registers.' or whatever in the fragment 102float iGlobalTime = float(FrameCount)*0.025; 103vec2 iResolution = OutputSize.xy; 104 105// PSX Rendering - TDM - 2016-08-06 106// https://www.shadertoy.com/view/Mt3Gz2 107 108// Lack of perspective-correct texturing, z-buffer, float data type and bilinear filtering lead to this kind of buggy rendering. 109 110/* 111"PSX rendering" by Alexander Alekseev aka TDM - 2016 112License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. 113*/ 114 115#define PSX_MODE 116 117#ifdef PSX_MODE 118 #define INT_VERTICES 119 vec2 RESOLUTION = vec2(320.0, 240.0); 120#else 121 #define BILINEAR 122 vec2 RESOLUTION = iResolution.xy; 123#endif 124 125// math 126float _cross(vec2 a, vec2 b) { 127 return a.x * b.y - a.y * b.x; 128} 129vec3 barycentric(vec2 a, vec2 b, vec2 c, vec2 p) { 130 vec2 ab = b - a, ac = c - a, ap = p - a; 131 vec2 vw = vec2(_cross(ap,ac),_cross(ab,ap)) / _cross(ab,ac); 132 return vec3(1.0-vw.x-vw.y, vw); 133} 134float quantization(float a, float b) { 135 return floor(a * b) / b; 136} 137vec2 quantization(vec2 a, float b) { 138 return floor(a * b) / b; 139} 140vec2 quantization(vec2 a, vec2 b) { 141 return floor(a * b) / b; 142} 143vec3 quantization(vec3 a, float b) { 144 return floor(a * b) / b; 145} 146float hash( vec2 p ) { 147 float h = dot(p,vec2(127.1,311.7)); 148 return fract(sin(h)*43758.5453123); 149} 150 151float noise1(vec2 p) { 152 #ifndef BILINEAR 153 return hash(floor(p)); 154 #else 155 vec2 i = floor(p); 156 vec2 f = fract(p); 157 vec2 tx = mix(vec2(hash(i),hash(i+vec2(0.,1.))) , 158 vec2(hash(i+vec2(1.,0.)),hash(i+vec2(1.))),f.x); 159 return mix(tx.x,tx.y,f.y); 160 #endif 161} 162mat4 getRotMatrix(vec3 a) { 163 vec3 s = sin(a); 164 vec3 c = cos(a); 165 mat4 ret; 166 ret[0] = vec4(c.y*c.z,c.y*s.z,-s.y,0.0); 167 ret[1] = vec4(s.x*s.y*c.z-c.x*s.z,s.x*s.y*s.z+c.x*c.z,s.x*c.y,0.0); 168 ret[2] = vec4(c.x*s.y*c.z+s.x*s.z, c.x*s.y*s.z-s.x*c.z, c.x*c.y,0.0); 169 ret[3] = vec4(0.0,0.0,0.0,1.0); 170 return ret; 171} 172mat4 getPosMatrix(vec3 p) { 173 mat4 ret; 174 ret[0] = vec4(1.0,0.0,0.0,p.x); 175 ret[1] = vec4(0.0,1.0,0.0,p.y); 176 ret[2] = vec4(0.0,0.0,1.0,p.z); 177 ret[3] = vec4(0.0,0.0,0.0,1.0); 178 return ret; 179} 180 181// textures 182vec4 textureGround(vec2 uv) { 183 const vec2 RES = vec2(8.0, 8.0); 184 vec2 NEW = uv * RES; 185 float n = noise1(NEW); 186 n = n * 0.2 + 0.5; 187 return vec4(n*0.9,n*0.6,n*0.4,1.0); 188} 189 190vec4 textureWall(vec2 uv) { 191 const vec2 RES = vec2(32.0, 16.0); 192 vec2 NEW = uv * RES; 193 vec2 iuv = floor(NEW); 194 float n = noise1(NEW); 195 n = n * 0.5 + 0.25; 196 float nc = n * (smoothstep(1.0,0.4, iuv.x / RES.x) * 0.5 + 0.5); 197 return vec4(nc * 0.4, nc * 1.0, nc * 0.5, n + uv.x - abs(uv.y-0.5) ); 198} 199 200vec4 textureBox(vec2 uv) { 201 const vec2 RES = vec2(8.0, 8.0); 202 vec2 NEW = uv * RES; 203 vec2 iuv = (floor(NEW) + 0.5) / RES; 204 float n = noise1(NEW); 205 n = max(abs(iuv.x - 0.5), abs(iuv.y - 0.5)) * 2.0; 206 n = n * n; 207 n = 0.5 + n * 0.4 + noise1(NEW) * 0.1; 208 return vec4(n, n*0.8, n*0.5, 1.0); 209} 210 211vec4 textureSky(vec2 uv) { 212 const vec2 RES = vec2(8.0, 32.0); 213 vec2 NEW = uv * RES; 214 float n = noise1(NEW); 215 n = n * 0.05 + 0.8; 216 return vec4(0.5,n*1.0,n*1.1,1.0); 217} 218 219// rasterization 220void triangle(vec2 p, 221 vec2 v0, vec2 v1, vec2 v2, 222 vec2 uv0, vec2 uv1, vec2 uv2, 223 in int tex, inout vec3 color) { 224 225 if(_cross(v2-v0,v1-v0) <= 1e-4) return; 226 227 vec3 bary = abs(barycentric(v0,v1,v2, p)); 228 if(bary.x + bary.y + bary.z <= 1.0001) { 229 vec2 uv = uv0 * bary.x + uv1 * bary.y + uv2 * bary.z; 230 vec4 frag; 231 if(tex == 0) { 232 frag = textureGround(uv); 233 } else if(tex == 1) { 234 frag = textureWall(uv); 235 } else { 236 frag = textureBox(uv); 237 } 238 if(frag.w > 0.5) color = frag.xyz; 239 } 240} 241void quad(vec2 p, 242 vec2 v0, vec2 v1, vec2 v2, vec2 v3, 243 vec2 uv0, vec2 uv1, vec2 uv2, vec2 uv3, 244 in int tex, inout vec3 color) { 245 triangle(p, v0,v1,v2, uv0,uv1,uv2, tex,color); 246 triangle(p, v2,v3,v0, uv2,uv3,uv0, tex,color); 247} 248 249// geometry transformation engine 250void gte(inout vec3 v, mat4 mat) { 251 252 // perspective 253 v = (vec4(v,1.0) * mat).xyz; 254 v.xy /= max(v.z, 1.0); 255 256 v *= 2.0; 257 258 // quantization to simulate int 259 #ifdef INT_VERTICES 260 const vec2 QUANT = vec2(320.0, 240.0) * 0.25; 261 v.xy = quantization(v.xy, QUANT); 262 #endif 263} 264 265// renderer 266void gpu(vec2 p, 267 vec2 v0, vec2 v1, vec2 v2, vec2 v3, 268 vec2 uv0, vec2 uv1, vec2 uv2, vec2 uv3, 269 in int tex, inout vec3 color) { 270 271 quad(p, 272 v0,v1,v2,v3, 273 uv0,uv1,uv2,uv3, 274 tex,color); 275} 276 277void mainImage( out vec4 fragColor, in vec2 fragCoord ) { 278 vec2 uv = fragCoord.xy / iResolution.xy; 279 uv = uv * 2.0 - 1.0; 280 uv.x *= iResolution.x / iResolution.y; 281 282 uv = quantization(uv, RESOLUTION * 0.5); 283 284 const float WIDTH = 1.3; 285 const float HEIGHT = 6.0; 286 const float DEPTH = 4.0; 287 const float LOD = 4.0; 288 289 float time = iGlobalTime * 2.; 290 291 vec3 posv = vec3(-WIDTH*3.0,-2.0, -time+5.0); 292 vec3 rotv = vec3(sin(time)*0.05 + 0.1, 293 sin(time*0.9)*0.05, 294 sin(time*0.7)*0.05); 295 296 // int-like position 297 #ifdef INT_VERTICES 298 posv = quantization(posv, 64.0); 299 rotv = quantization(rotv, 256.0); 300 #endif 301 302 mat4 cam = getPosMatrix(posv); 303 mat4 rot = getRotMatrix(rotv); 304 cam = cam * rot; 305 306 vec3 c = textureSky(uv + vec2(rotv.y,-rotv.x) * 3.0).xyz; 307 308 // ground 309 float z_offset = -floor((posv.z + DEPTH * 1.5) / DEPTH) * DEPTH * 0.5; 310 float poly_depth = DEPTH; 311 312 for(int dip = 0; dip < 32; dip++) { 313 314 // kinda LOD 315 z_offset += step(mod(float(dip),4.0), 0.5) * poly_depth * 0.5; 316 #ifdef PSX_MODE 317 if(dip > 11) poly_depth = DEPTH * LOD; 318 #endif 319 320 vec3 vert[4]; 321 vert[0] = vec3(-WIDTH,0.0, poly_depth); 322 vert[1] = vec3(-WIDTH,0.0, 0.0); 323 vert[2] = vec3( WIDTH,0.0, 0.0); 324 vert[3] = vec3( WIDTH,0.0, poly_depth); 325 326 vec3 posv = vec3(mod(float(dip),4.0) * WIDTH, 327 0.0, 328 z_offset); 329 330 mat4 pos = getPosMatrix(posv * 2.0); 331 mat4 mat = pos * cam; 332 333 for(int i = 0; i < 4; i++) gte(vert[i], mat); 334 335 gpu(uv, 336 vert[3].xy,vert[2].xy,vert[1].xy,vert[0].xy, 337 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 338 0, c); 339 } 340 341 // walls 342 z_offset = -floor((posv.z + DEPTH ) / DEPTH) * DEPTH * 0.5; 343 poly_depth = DEPTH; 344 345 for(int dip = 0; dip < 8; dip++) { 346 347 // kinda LOD 348 z_offset += poly_depth * 0.5; 349 #ifdef PSX_MODE 350 if(dip > 2) poly_depth = DEPTH * LOD; 351 #endif 352 353 vec3 vert[4]; 354 vert[0] = vec3(0.0,HEIGHT, poly_depth); 355 vert[1] = vec3(0.0,HEIGHT, 0.0); 356 vert[2] = vec3(0.0,0.0, 0.0); 357 vert[3] = vec3(0.0,0.0, poly_depth); 358 359 vec3 posv = vec3(WIDTH * 3.5, 360 0.0, 361 z_offset); 362 //posv.z -= z_offset; 363 364 mat4 posm = getPosMatrix(posv * 2.0); 365 mat4 mat = posm * cam; 366 367 for(int i = 0; i < 4; i++) gte(vert[i], mat); 368 369 gpu(uv, 370 vert[0].xy,vert[1].xy,vert[2].xy,vert[3].xy, 371 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 372 1, c); 373 374 375 vert[0] = vec3(0.0,HEIGHT, poly_depth); 376 vert[1] = vec3(0.0,HEIGHT, 0.0); 377 vert[2] = vec3( 0.0,0.0, 0.0); 378 vert[3] = vec3( 0.0,0.0, poly_depth); 379 380 posv = vec3(-WIDTH * 0.5, 381 0.0, 382 z_offset); 383 384 posm = getPosMatrix(posv * 2.0); 385 mat = posm * cam; 386 387 for(int i = 0; i < 4; i++) gte(vert[i], mat); 388 389 gpu(uv, 390 vert[3].xy,vert[2].xy,vert[1].xy,vert[0].xy, 391 vec2(1.0,0.0), vec2(1.0), vec2(0.0,1.0),vec2(0.0), 392 1, c); 393 } 394 395 // box 396 vec3 vert[8]; 397 vert[0] = vec3(-1.0,-1.0, 1.0); 398 vert[1] = vec3(-1.0, 1.0, 1.0); 399 vert[2] = vec3( 1.0, 1.0, 1.0); 400 vert[3] = vec3( 1.0,-1.0, 1.0); 401 vert[4] = vec3(-1.0,-1.0,-1.0); 402 vert[5] = vec3(-1.0, 1.0,-1.0); 403 vert[6] = vec3( 1.0, 1.0,-1.0); 404 vert[7] = vec3( 1.0,-1.0,-1.0); 405 406 vec3 box_posv = vec3(-posv.x, 407 2.0, 408 -posv.z + 15.0); 409 410 rotv = vec3(time * 0.5, time * 0.6, time * 0.7); 411 mat4 posm = getRotMatrix(rotv) * getPosMatrix(box_posv); 412 mat4 mat = posm * cam; 413 414 for(int i = 0; i < 8; i++) { 415 vert[i].y *= 0.65; 416 gte(vert[i], mat); 417 } 418 419 gpu(uv, 420 vert[3].xy,vert[2].xy,vert[1].xy,vert[0].xy, 421 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 422 2, c); 423 gpu(uv, 424 vert[4].xy,vert[5].xy,vert[6].xy,vert[7].xy, 425 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 426 2, c); 427 428 gpu(uv, 429 vert[7].xy,vert[6].xy,vert[2].xy,vert[3].xy, 430 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 431 2, c); 432 gpu(uv, 433 vert[0].xy,vert[1].xy,vert[5].xy,vert[4].xy, 434 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 435 2, c); 436 437 gpu(uv, 438 vert[2].xy,vert[6].xy,vert[5].xy,vert[1].xy, 439 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 440 2, c); 441 gpu(uv, 442 vert[0].xy,vert[4].xy,vert[7].xy,vert[3].xy, 443 vec2(0.0),vec2(0.0,1.0),vec2(1.0),vec2(1.0,0.0), 444 2, c); 445 446 // fragment 447 fragColor = vec4(c,1.0); 448} 449 450 void main(void) 451{ 452 //just some shit to wrap shadertoy's stuff 453 vec2 FragCoord = vTexCoord.xy*OutputSize.xy; 454 mainImage(FragColor,FragCoord); 455} 456#endif 457