1#version 120
2// Compatibility #ifdefs needed for parameters
3#ifdef GL_ES
4#define COMPAT_PRECISION mediump
5#else
6#define COMPAT_PRECISION
7#endif
8
9// Parameter lines go here:
10#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
11#ifdef PARAMETER_UNIFORM
12// All parameter floats need to have COMPAT_PRECISION in front of them
13uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
14#else
15#define RETRO_PIXEL_SIZE 0.84
16#endif
17
18#if defined(VERTEX)
19
20#if __VERSION__ >= 130
21#define COMPAT_VARYING out
22#define COMPAT_ATTRIBUTE in
23#define COMPAT_TEXTURE texture
24#else
25#define COMPAT_VARYING varying
26#define COMPAT_ATTRIBUTE attribute
27#define COMPAT_TEXTURE texture2D
28#endif
29
30#ifdef GL_ES
31#define COMPAT_PRECISION mediump
32#else
33#define COMPAT_PRECISION
34#endif
35
36COMPAT_ATTRIBUTE vec4 VertexCoord;
37COMPAT_ATTRIBUTE vec4 COLOR;
38COMPAT_ATTRIBUTE vec4 TexCoord;
39COMPAT_VARYING vec4 COL0;
40COMPAT_VARYING vec4 TEX0;
41// out variables go here as COMPAT_VARYING whatever
42
43vec4 _oPosition1;
44uniform mat4 MVPMatrix;
45uniform COMPAT_PRECISION int FrameDirection;
46uniform COMPAT_PRECISION int FrameCount;
47uniform COMPAT_PRECISION vec2 OutputSize;
48uniform COMPAT_PRECISION vec2 TextureSize;
49uniform COMPAT_PRECISION vec2 InputSize;
50
51// compatibility #defines
52#define vTexCoord TEX0.xy
53#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
54#define OutSize vec4(OutputSize, 1.0 / OutputSize)
55
56void main()
57{
58    gl_Position = MVPMatrix * VertexCoord;
59    TEX0.xy = VertexCoord.xy;
60// Paste vertex contents here:
61}
62
63#elif defined(FRAGMENT)
64
65#if __VERSION__ >= 130
66#define COMPAT_VARYING in
67#define COMPAT_TEXTURE texture
68out vec4 FragColor;
69#else
70#define COMPAT_VARYING varying
71#define FragColor gl_FragColor
72#define COMPAT_TEXTURE texture2D
73#endif
74
75#ifdef GL_ES
76#ifdef GL_FRAGMENT_PRECISION_HIGH
77precision highp float;
78#else
79precision mediump float;
80#endif
81#define COMPAT_PRECISION mediump
82#else
83#define COMPAT_PRECISION
84#endif
85
86uniform COMPAT_PRECISION int FrameDirection;
87uniform COMPAT_PRECISION int FrameCount;
88uniform COMPAT_PRECISION vec2 OutputSize;
89uniform COMPAT_PRECISION vec2 TextureSize;
90uniform COMPAT_PRECISION vec2 InputSize;
91uniform sampler2D Texture;
92COMPAT_VARYING vec4 TEX0;
93// in variables go here as COMPAT_VARYING whatever
94
95// compatibility #defines
96#define Source Texture
97#define vTexCoord TEX0.xy
98
99#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
100#define OutSize vec4(OutputSize, 1.0 / OutputSize)
101
102// delete all 'params.' or 'registers.' or whatever in the fragment
103float iGlobalTime = float(FrameCount)*0.025;
104vec2 iResolution = OutputSize.xy;
105
106//////////////////////////////////////////////////////////////////////////////////////
107///////////////////// CREATED BY KIM BERKEBY, SEP 2017 ///////////////////////////////
108//////////////////////////////////////////////////////////////////////////////////////
109////// BIG THANKS TO Inigo Quilez FOR PROVIDING THE SHAPE DISTANCE FUNCTIONS /////////
110//////////////////////////////////////////////////////////////////////////////////////
111
112struct RayHit
113{
114  bool hit;
115  vec3 hitPos;
116  vec3 normal;
117  float dist;
118  float depth;
119  float steps;
120  int hitID;
121};
122
123
124RayHit marchResult;
125
126
127float sdBox( vec3 p, vec3 b )
128{
129  vec3 d = abs(p) - b;
130  return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
131}
132
133float sdTriPrism( vec3 p, vec2 h )
134{
135  vec3 q = abs(p);
136  return max(q.z-h.y, max(q.x*0.866025+p.y*0.5, -p.y)-h.x*0.5);
137}
138
139float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
140{
141  vec3 pa = p - a, ba = b - a;
142  float h = clamp( dot(pa, ba)/dot(ba, ba), 0.0, 1.0 );
143  return length( pa - ba*h ) - r;
144}
145
146#define rotate(a) mat2(cos(a), -sin(a), sin(a), cos(a))
147
148float Cable( vec3 p, vec3 a, vec3 b, float r )
149{
150  vec3 pa = p - a;
151  b.xz = mix(b.xz, b.xz*rotate(1.1), smoothstep(1.0, 6.0, pa.z));
152  b.xz = mix(b.xz, b.xz*rotate(-1.20), smoothstep(1.0, 14.0, pa.z));
153  b.y = mix(b.y, -1.55, smoothstep(.0, 1.0, pa.z));
154
155  vec3 ba = b - a;
156  float h = clamp( dot(pa, ba)/dot(ba, ba), 0.0, 1.0 );
157
158  return length( pa - ba*h ) - r;
159}
160
161
162float sdCappedCylinder( vec3 p, vec2 h )
163{
164  vec2 d = abs(vec2(length(p.xz), p.y)) - h;
165  return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
166}
167
168float sdEllipsoid( in vec3 p, in vec3 r )
169{
170  return (length( p/r ) - 1.0) * min(min(r.x, r.y), r.z);
171}
172
173
174vec3 opRotXY( vec3 pos, vec3 rayPos, float rad )
175{
176  vec3 sPos = rayPos-pos;
177  sPos.xy *= rotate(rad);
178  return sPos+rayPos;
179}
180vec3 opRotXZ( vec3 pos, vec3 rayPos, float rad )
181{
182  vec3 sPos = rayPos-pos;
183  sPos.xz *= rotate(rad);
184  return sPos+rayPos;
185}
186vec3 opRotYZ( vec3 pos, vec3 rayPos, float rad )
187{
188  vec3 sPos = rayPos-pos;
189  sPos.yz *= rotate(rad);
190  return sPos+rayPos;
191}
192
193
194
195float ControllerBase(in vec3 p, vec3 oPos, float oScale)
196{
197
198  float d = sdCappedCylinder(p-oPos-vec3(1.40, -0.04, 0.0), vec2(1.0, 0.12)*oScale);
199  d = min(d, sdCappedCylinder(p-oPos-vec3(-1.40, -0.04, 0.0), vec2(1.0, 0.12)*oScale));
200  d = min(d, sdCappedCylinder(p-oPos-vec3(-.35, 0.0, -.40), vec2(0.5, 0.08)*oScale));
201  d = min(d, sdCappedCylinder(p-oPos-vec3(.35, 0.0, -.40), vec2(0.5, 0.08)*oScale));
202
203
204  d=min(d, sdBox(p-oPos-vec3(.0, 0.0, 0.2), vec3(1.0, .08, 0.7)*oScale));
205  d = min(d, sdBox(p-oPos-vec3(.0, 0.0, 0.2), vec3(0.50, .07, 0.79)*oScale));
206  d=max(d, -sdBox(p-oPos-vec3(.0, 0.0, 1.1), vec3(0.20, 1.08, 0.15)*oScale));
207
208  return d;
209}
210
211float ShoulderButtons(in vec3 p, float controllBase, vec3 oPos, float oScale)
212{
213  float d = sdCappedCylinder(p-oPos-vec3(1.45, -0.1, 0.10), vec2(1.0, 0.12)*oScale);
214  d = min(d, sdCappedCylinder(p-oPos-vec3(-1.45, -0.1, 0.10), vec2(1.0, 0.12)*oScale));
215  d =  min(d, sdBox(p-oPos-vec3(.0, -0.1, 0.2), vec3(1.60, .08, 0.8)*oScale));
216
217  d=  max(d, -sdBox(p-oPos-vec3(.0, 0.0, 0.42), vec3(1.2, 1.08, 2.9)*oScale));
218  d=  max(d, -sdBox(p-oPos-vec3(2.50, 0.0, 0.42), vec3(0.4, 1.08, 2.9)*oScale));
219  d=  max(d, -sdBox(p-oPos-vec3(-2.50, 0.0, 0.42), vec3(0.4, 1.08, 2.9)*oScale));
220
221  d=  max(d, -sdBox(p-oPos-vec3(0, 0.0, -0.42), vec3(3.0, 0.68, 1.)*oScale));
222
223  return d;
224}
225
226
227float d,d1,d2,d3,d4,d5,d6,d7,d8,d9;
228
229float Map( in vec3 p)
230{
231    d,d1,d2,d3,d4,d5,d6,d7,d8,d9 = 100000.0;
232
233  d8 = ControllerBase(p, vec3(0, -0.51, 1.0), 1.05);
234  d = ControllerBase(p, vec3(0, -0.3, 1.0), 1.0);
235
236  // button ring
237  d=  max(d, -sdCappedCylinder(p-vec3(-1.45, -0.22, 1.0), vec2(0.8, 0.02)));
238  d8=  min(d8, sdCappedCylinder(p-vec3(-1.45, -0.25, 1.0), vec2(0.765, 0.03)));
239  d8=  min(d8, sdEllipsoid(p-vec3(-1.45, -0.25, 1.0), vec3(0.7, 0.1, 0.7)));
240
241  // button holes
242  d8=  max(d8, -sdEllipsoid(p-vec3(-1.45, -0.18, 1.40), vec3(0.32, 0.06, 0.32)));
243  d8=  max(d8, -sdEllipsoid(p-vec3(-1.45, -0.18, .60), vec3(0.32, 0.06, 0.32)));
244  d8=  max(d8, -sdEllipsoid(p-vec3(-1.90, -0.18, 1.0), vec3(0.32, 0.06, 0.32)));
245  d8=  max(d8, -sdEllipsoid(p-vec3(-1.00, -0.18, 1.0), vec3(0.32, 0.06, 0.32)));
246
247  // buttons
248  d2= sdCappedCylinder(p-vec3(-1.45, -0.3, 1.40), vec2(0.18, 0.12));
249  d9= sdCappedCylinder(p-vec3(-1.45, -0.3, 0.60), vec2(0.18, 0.12));
250  d2= min(d2, sdCappedCylinder(p-vec3(-1.90, -0.3, 1.0), vec2(0.18, 0.12)));
251  d9= min(d9, sdCappedCylinder(p-vec3(-1.0, -0.3, 1.0), vec2(0.18, 0.12)));
252
253  // button details
254  d2=  max(d2, -sdEllipsoid(p-vec3(-1.45, -0.16, 1.40), vec3(0.25, 0.04, 0.25)));
255  d9=  max(d9, -sdEllipsoid(p-vec3(-1.45, -0.16, .60), vec3(0.25, 0.04, 0.25)));
256  d2=  max(d2, -sdEllipsoid(p-vec3(-1.90, -0.16, 1.0), vec3(0.25, 0.04, 0.25)));
257  d9=  max(d9, -sdEllipsoid(p-vec3(-1.0, -0.16, 1.0), vec3(0.25, 0.04, 0.25)));
258
259  // cross cutout
260  d=  max(d, -sdEllipsoid(p-vec3(1.55, -0.22, 1.0), vec3(0.7, 0.1, 0.7)));
261  d=  max(d, -sdEllipsoid(p-vec3(1.55, -0.22, 1.0), vec3(1.0, 0.03, 1.0)));
262  d3 = sdEllipsoid(p-vec3(1.55, -0.265, 1.0), vec3(.46, 0.06, .46));
263
264  // cross
265  d3 = min(d3, sdBox(p-vec3(1.55, -0.22, 1.0), vec3(0.4, 0.06, 0.13)));
266  d3 = min(d3, sdBox(p-vec3(1.55, -0.22, 1.0), vec3(0.13, 0.06, 0.4)));
267
268  // cross details
269  d3=  max(d3, -sdEllipsoid(p-vec3(1.55, -0.2, 1.0), vec3(0.16, 0.04, 0.16)));
270
271  // calculate button arrows and perform boolean
272  vec3 pPos = p-vec3(1.55, -0.13, 1.25);
273  pPos.xz *=rotate(radians(120.0));
274  pPos.zy *=rotate(radians(90.0));
275  d3 = max(d3, -sdTriPrism(pPos, vec2(.15, 0.05)));
276
277  pPos = p-vec3(1.55, -0.13, 0.75);
278  pPos.xz *=rotate(radians(300.0));
279  pPos.zy *=rotate(radians(90.0));
280  d3 = max(d3, -sdTriPrism(pPos, vec2(.15, 0.05)));
281
282  pPos = p-vec3(1.8, -0.13, 1.0);
283  pPos.xz *=rotate(radians(210.0));
284  pPos.zy *=rotate(radians(90.0));
285  d3 = max(d3, -sdTriPrism(pPos, vec2(.15, 0.05)));
286
287  pPos = p-vec3(1.3, -0.13, 1.0);
288  pPos.xz *=rotate(radians(30.0));
289  pPos.zy *=rotate(radians(90.0));
290  d3 = max(d3, -sdTriPrism(pPos, vec2(.15, 0.05)));
291
292  // cable input
293  d=max(d, -sdCapsule(p-vec3(.0, -0.4, 2.1), vec3(0.0, 0.0, -0.5), vec3(0.0, 0.0, 3.0), 0.13));
294  d=min(d, sdCapsule(p-vec3(.0, -0.39, 2.07), vec3(0.0, 0.0, -0.1), vec3(0.0, 0.0, -0.1), 0.11));
295
296  // cable
297  d4 = sdCapsule(p-vec3(.0, -0.39, 2.07), vec3(0.0, 0.0, 0), vec3(0.0, 0.0, 0), 0.11);
298  d4=min(d4, Cable(p-vec3(.0, -0.4, 2.1), vec3(0., 0., -1.0), vec3(0., 0., 70.0), 0.072));
299
300  // analog buttons
301  d= max(d, -sdEllipsoid(p-vec3(0.35, -0.15, .50), vec3(0.4, 0.2, 0.4)));
302  d= max(d, -sdEllipsoid(p-vec3(-0.35, -0.15, .50), vec3(0.4, 0.2, 0.4)));
303
304  d5=  sdEllipsoid(p-vec3(0.35, -0.35, .50), vec3(0.3, 0.18, 0.3));
305  d5= min(d5, sdCappedCylinder(p-vec3(0.35, -0.35, .50), vec2(0.15, 0.3)));
306  d5=  min(d5, sdEllipsoid(p-vec3(0.35, -0.05, .50), vec3(0.22, 0.03, 0.22)));
307
308  d5=  min(d5, sdEllipsoid(p-vec3(-0.35, -0.35, .50), vec3(0.3, 0.18, 0.3)));
309  d5= min(d5, sdCappedCylinder(p-vec3(-0.35, -0.35, .50), vec2(0.15, 0.3)));
310  d5=  min(d5, sdEllipsoid(p-vec3(-0.35, -0.05, .50), vec3(0.22, 0.03, 0.22)));
311
312  // start select cutouts
313  d=max(d, -sdCapsule(p-vec3(-.1, -.06, 1.4), vec3(0., 0., -0.15), vec3(-0.22, 0., 0.05), 0.2));
314  d=max(d, -sdCapsule(p-vec3(.45, -.06, 1.4), vec3(0., 0., -0.15), vec3(-0.22, 0., 0.05), 0.2));
315
316  // start select buttons
317  d7=sdCapsule(p-vec3(-.1, -.25, 1.4), vec3(0., 0., -0.15), vec3(-0.22, 0., 0.05), 0.095);
318  d7=min(d7, sdCapsule(p-vec3(.45, -.25, 1.4), vec3(0., 0., -0.15), vec3(-0.22, 0., 0.05), 0.095));
319
320  d6 = ShoulderButtons(p, d, vec3(0, -0.3, 1.0), 1.0);
321
322
323  return  min(d,min(d2,min(d3,min(d4,min(d5,min(d6,min(d7,min(d8,min(d9,p.y+0.75)))))))));
324}
325
326
327vec3 calcNormal( in vec3 pos )
328{
329    const vec3 eps = vec3(0.02, 0.0, 0.0);
330  return normalize( vec3(Map(pos+eps.xyy) - Map(pos-eps.xyy), 0.5*2.0*eps.x, Map(pos+eps.yyx) - Map(pos-eps.yyx) ) );
331}
332
333float SoftShadow( in vec3 origin, in vec3 direction )
334{
335  float res = 2.0;
336  float t = 0.0;
337  float hardness = 6.50;
338  for ( int i=0; i<10; i++ )
339  {
340    float h = Map(origin+direction*t);
341    res = min( res, hardness*h/t );
342    t += clamp( h, 0.02, 0.075 );
343    if ( h<0.002 ) break;
344  }
345  return clamp( res, 0.0, 1.0 );
346}
347
348
349RayHit March(in vec3 origin, in vec3 direction, float maxDist, float precis, int maxSteps)
350{
351  RayHit result;
352
353  float t = 0.0, dist = 0.0, distStep = 1.0;
354  vec3 rayPos =vec3(0);
355
356  for ( int i=0; i<maxSteps; i++ )
357  {
358    rayPos =origin+direction*t;
359    dist = Map( rayPos);
360
361    if (abs(dist)<precis || t>maxDist )
362    {
363        result.hitID =10;
364
365        if(d == dist){  result.hitID =1;}
366        else if(d2 == dist){  result.hitID =2;}
367        else if(d3 == dist){  result.hitID =3;}
368        else if(d4 == dist){  result.hitID =4;}
369        else if(d5 == dist){  result.hitID =5;}
370        else if(d6 == dist){  result.hitID =6;}
371        else if(d7 == dist){  result.hitID =7;}
372        else if(d8 == dist){  result.hitID =8;}
373        else if(d9 == dist){  result.hitID =9;}
374
375      result.depth = t;
376      result.dist = dist;
377      result.hitPos = origin+((direction*t)*0.99);
378      result.steps = float(i);
379      break;
380    }
381    t += dist*distStep;
382  }
383
384
385  return result;
386}
387
388// Thanks to Inigo Quilez
389mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
390{
391  vec3 cw = normalize(ta-ro);
392  vec3 cp = vec3(sin(cr), cos(cr), 0.0);
393  vec3 cu = normalize( cross(cw, cp) );
394  vec3 cv = normalize( cross(cu, cw) );
395  return mat3( cu, cv, cw );
396}
397
398vec3 GetSceneLight(float specLevel, vec3 normal, vec3 pos, vec3 rayDir)
399{
400  vec3 light1 = normalize(vec3(-1.0, 2.8, 1.0));
401
402  vec3 reflectDir = reflect( rayDir, normal );
403  specLevel *= pow(clamp( dot( reflectDir, light1 ), 0.0, 1.0 ), 16.0);
404
405  float amb = clamp( 0.5+0.5*normal.y, 0.0, 1.0 );
406  float diffuse = clamp( dot( normal, light1 ), 0.0, 1.0 );
407  float skyLight = smoothstep( -0.1, 0.1, reflectDir.y );
408  float fill = pow( clamp(1.0+dot(normal, rayDir), 0.0, 1.0), 1.0 )*1.0;
409  float backLight = clamp( dot( normal, normalize(vec3(-light1.x, 0.0, -light1.z))), 0.0, 1.0 )*5.0;
410
411  diffuse *= SoftShadow( pos, light1);
412  skyLight *= SoftShadow( pos, reflectDir);
413
414  vec3 lightTot = 1.30*diffuse*vec3(1.00, 0.80, 0.55);
415  lightTot += specLevel*vec3(1.00, 0.90, 0.70)*diffuse;
416  lightTot += 0.40*amb*vec3(0.40, 0.60, 1.00);
417  lightTot += 0.50*skyLight*vec3(0.40, 0.60, 1.00);
418  lightTot += 0.50*backLight*vec3(0.25, 0.25, 0.25);
419
420  return lightTot+(0.25*fill*vec3(1.00, 1.00, 1.00));
421}
422
423
424void mainImage( out vec4 fragColor, in vec2 fragCoord )
425{
426#ifdef MOUSE
427  vec2 mo = iMouse.xy/iResolution.xy;
428#else
429  vec2 mo = 0.0/iResolution.xy;
430#endif
431  vec2 uv = fragCoord.xy / iResolution.xy;
432  vec2 screenSpace = (-iResolution.xy + 2.0*(fragCoord))/iResolution.y;
433
434  float camrot = 0.5*iGlobalTime;
435#ifdef MOUSE
436  if (iMouse.w>0.1) camrot=0.0;
437#endif
438
439  vec3 rayOrigin = vec3( -0.5+3.5*cos(camrot + 6.0*mo.x), 1.0 + 2.0, 0.5 + 4.0*sin(camrot + 6.0*mo.x) );
440  mat3 ca = setCamera( rayOrigin, vec3( 0.0, -0.9, 0.5 ), 0.0 );
441  vec3 rayDir = ca * normalize( vec3(screenSpace.xy, 2.0) );
442  vec4 color =vec4(0);
443
444   marchResult = March(rayOrigin, rayDir, 110.0, 0.001, 128);
445   marchResult.normal = calcNormal(marchResult.hitPos);
446
447      // pad top, buttons, cross, cable, sticks, shoulder buttons
448  const vec4[10] partColor = vec4[] (vec4(.65, 0.14, 0.14, 0.6), // pad top
449  vec4(0.5, 0.14, .14, 0.6), //buttons
450  vec4(.3, 0.3, 0.3, 0.5), //cross
451  vec4(0.2, 0.2, 0.2, 0.35), //cable
452  vec4(.3, 0.3, 0.3, 0.4), //sticks
453  vec4(0.5, 0.5, .5, 0.6), // shoulder buttons
454  vec4(.3, 0.3, 0.3, 0.5), // start/select
455  vec4(.3, 0.3, 0.3, 0.4), // pad bottom
456  vec4(0.5, 0.5, .5, 0.6), //buttons left
457  vec4(.35, .35, .34, 0.3)); // ground
458   vec4 col =partColor[marchResult.hitID-1];
459   vec3 light = GetSceneLight(col.a, marchResult.normal, marchResult.hitPos, rayDir);
460
461    // reflections in floor
462    if (marchResult.hitID==10)
463    {
464      vec3 refDir = normalize(reflect(rayDir, marchResult.normal));
465      RayHit reflectResult = March(marchResult.hitPos + (refDir*0.001), refDir, 30.0, 0.03, 64);
466
467      if (reflectResult.hit==true)
468      {
469        col = mix(col, col+(col* partColor[reflectResult.hitID-1]), .65);
470      }
471    }
472
473    float rim = clamp(1.0+dot(marchResult.normal, rayDir), 0.0, 1.0);
474#ifdef TEXTURE
475    vec4 ref = vec4(texture( iChannel0, marchResult.normal+rayDir).rgb, 1.0);
476    ref += rim*pow(0.5, 2.0);
477    ref /= pow(2.0, col.a);
478#endif
479
480    // apply lightning
481    color = col*vec4(light, 1.0);
482#ifdef TEXTURE
483    color.rgb= mix((color.rgb+(color.rgb*ref.rgb))*col.a, (color.rgb+vec3(1.4))*col.a, pow(marchResult.normal.r, 2.0));
484#else
485    color.rgb= mix((color.rgb+(color.rgb))*col.a, (color.rgb+vec3(1.4))*col.a, pow(marchResult.normal.r, 2.0));
486#endif
487
488
489  fragColor = vec4(pow(color.rgb, vec3(1.0/0.9)), 1.0 ) * (0.5 + 0.5*pow( 16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.2 ));
490  //  fragColor = vec4(marchResult.normal,1.0);
491}
492
493 void main(void)
494{
495  //just some shit to wrap shadertoy's stuff
496  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
497  mainImage(FragColor,FragCoord);
498}
499#endif
500