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