var USE_SYNTH = 0; // Vector stuff function vecOp(code) { return eval('(function(o,a,b){for(var i=o.length;--i>=0;)' + code + ';return o})') } function vomNew(s) { return new Float32Array(s) } var vecDot = function(a,b) { var s = 0; for ( var i in a ) { s += a[i]*b[i]; } return s; }; var vecLen = function(a) { return Math.sqrt( vecDot(a,a) ) }; var vecNorm = function(o,a) { var l = vecLen(a); return l ? vecScale(o,a,1/l) : vecCopy(o,a); }; var vecCross = function(o,a,b) { return vecSet(o, a[1]*b[2]-a[2]*b[1] , a[2]*b[0]-a[0]*b[2] , a[0]*b[1]-a[1]*b[0] ); }; var vecs2Mat3 = function(o,a,b,c){ for ( var i = 0 ; i < 3 ; i ++ ) { o[i*3+0] = a[i]; o[i*3+1] = b[i]; o[i*3+2] = c[i]; } }; var vecSet = vecOp('o[i]=arguments[i+1]') , vecCopy = vecOp('o[i]=a[i]') , vecAdd = vecOp('o[i]=a[i]+b[i]') , vecSub = vecOp('o[i]=a[i]-b[i]') , vecScale = vecOp('o[i]=a[i]*b'); // Shaders var shaderHeader = 'precision highp float;varying !2 zx;'; function shaderFloat( v ) { return '' + v + ( v == Math.floor(v) ? '.' : '' ); } function shaderVec( v ) { return v.map(shaderFloat).join(','); } // Raymarchers var materials = [ { albedo: [.05,.05,.05] , metallic: .7 , smoothness: .02 , r0: .01 } , { albedo: [ .2,.2,.2 ] , noise: [ .1,.1,.1] , noiseScale: 5 , metallic: .7 , smoothness: .9 , r0: .01 } , { albedo: [ 1,1,1 ] , metallic: .5 , smoothness: .4 , r0: .02 } , { albedo: [ 3,0,0 ] , noise: [.6,0,0], noiseScale: 6 , metallic: .3 , smoothness: .1 , r0: .6 } , { albedo: [ 0,2,0 ] , noise: [0,.2,0], noiseScale: 15 , metallic: .9 , smoothness: .5 , r0: .4 } , { albedo: [ 3,1.5,0 ] , noise: [.3,.6,0], noiseScale: .3 , metallic: .95 , smoothness: .6 , r0: .9 } , { albedo: [ .1,.1,.1 ] , noise: [3,3,3] , noiseScale: 3, metallic: 0 , smoothness: .04 , r0: .002 } , { albedo: [ 0,1.5,2 ] , metallic: .9 , smoothness: .3 , r0: .4 } ]; var raymarchers = { tunnel: { maxDistance: 100 , epsilon: .025 , epsilonMultiplier: 1 , step: .7 , depth: 64 , normalDelta: .0005 , noiseScale: .5 , reflectionDistance: .3 , fog: .4 , fogDensity: .015 , aoSteps: 4 , aoDelta: 2 , aoWeight: .75 , materials: [0,1,2,3] , map: [ "y=x+.1*(sin(x.zxy*.17+u4[0]*.5)+sin(x.yzx*.7+u4[0]*1.5))*8.5*(1.+cos(sin(x.z*.1)+x.z*.3)),", "z=14.-length(y.xy),", "w=x.x==.0?1.570795*(x.y>.0?1.:-1.):atan(x.y,x.x),", "q=8.35-u4[8]*1.35,", "y=!3(9.*(mod(w+x.z*.02,.628)-.314),length(x.xy)-9.,mod(x.z,12.56)-6.28),", "u=min(length(y.xy)-.25+.1*cos(x.z*8.+u4[0]*.1),length(y.yz)-.5),", "y=!3(q*(mod(w+x.z*.02,1.256636)-.628318),y.y+9.-q,mod(x.z,62.8318)-31.4159)," , "o=step(u,z)+1.,", "z=min(u,z),", "u=length(y)-1.3;", "if(u 0 ) { ctx.misc[4] += desync; } ctx.misc[4] *= Math.random( ) * .25 + .75; }; }; var balls1CamFunc = function(lax,laz,desync) { var dsf = desyncFunc(desync); return function(ctx) { var z = demoTime*3; vecSet(ctx.camPos,0,4,z); vecSet(ctx.lookAt,lax,0,z+laz); vecSet(ctx.up,0,0,1); ctx.misc[8]= ctx.misc[2] = 0; dsf(ctx,this.time); }; }; var balls2CamCommon = function(ctx) { var z = demoTime*5; vecSet(ctx.camPos,Math.cos(demoTime)*12,8,Math.sin(demoTime)*12+z); vecSet(ctx.lookAt,1,0,z); vecSet(ctx.up,0,1,0); ctx.toNearPlane = 2.5; z = demoTime - direction[43].startTime; ctx.misc[8]=z; }; var balls2LightFunc = function(scale) { return function(ctx,lctx) { var z = demoTime*30; vecSet(lctx.pos,scale*Math.cos(demoTime*2)*5,3,scale*Math.sin(demoTime*2)*5+z); vecSet(lctx.colour,1,1,1); lctx.distance = 4; return true; }; }; var fract1CamCommon = function(ctx) { var z = demoTime; vecSet(ctx.camPos,4,2.5+.025*z,6.7); vecSet(ctx.lookAt,0,2.5-.05*z,6.7); vecSet(ctx.up,0,0,1); ctx.misc[8] = ctx.misc[9] = 0; ctx.toNearPlane = 3; }; var fract1CamFunc = function(desync) { var dsf = desyncFunc(desync); return function(ctx){ fract1CamCommon(ctx); dsf(ctx,this.time); }; }; var fract2CamCommon = function(ctx,bs) { vecSet(ctx.camPos,5*Math.sin(demoTime*.2),9*Math.cos(demoTime*.41),7.8); vecCopy(ctx.lookAt,ctx.camPos); ctx.lookAt[0] = Math.cos(demoTime*.2); ctx.lookAt[1] = Math.sin(demoTime*.33); ctx.lookAt[2] -= 2; vecSet(ctx.up,0,0,1); ctx.toNearPlane = 3; ctx.misc[8] = bs; ctx.misc[9] = 1; }; var drawText = function(str,x) { twoDCtx.shadowBlur = c2height/5; twoDCtx.fillText( str , x , c2height / 2 ); twoDCtx.shadowBlur = 0; twoDCtx.strokeText( str , x , c2height / 2 ); }; var titleText = function(str,shake,alpha,r,g,b) { drawText( str , canvasWidth/15 ); context.misc[5] = 1 - c2rHeight + Math.random() * shake - shake * .5; context.misc[6] = alpha; vecSet( context.textColour , r , g , b ); }; var greetings = "Greetings to ... Mog, Sycop, Tim & Wullon ... Adinpsz ... Alcatraz ... ASD ... Bits'n'Bites ... Brain Control ... Cocoon ... Conspiracy ... Ctrl+Alt+Test ... Fairlight ... Farbrausch ... Kewlers ... LNX ... Loonies ... Mercury ... Popsy Team ... Razor 1911 ... RGBA ... 7th Cube ... Still ... TPOLM ... TRBL ... Umlaut Design ... X-Men ... Youth Uprising ... Everyone here at DemoJS 2014!"; var greetingsText = function() { var t = ( demoTime - direction[34].startTime ) * canvasWidth * .5; drawText( greetings , canvasWidth - t ); context.misc[5] = 1 - c2rHeight + Math.random() * .02 - .01; context.misc[6] = 1; vecSet( context.textColour , 1 , 1 , 1 ); }; var squaresCam = function(ctx) { var t = demoTime - direction[25].startTime; var z = t*10 - 80; vecSet(ctx.camPos,z,0,0); vecSet(ctx.lookAt,z+Math.cos(t*.5) * 80,Math.sin(t*.25)*40,100); vecSet(ctx.up,0,1,0); }; var squaresCam2 = function(ctx,s) { var t = demoTime - direction[s].startTime; var z = t*20 - 80; vecSet(ctx.camPos,0,0,z); vecSet(ctx.lookAt,Math.cos(t*.5) * 80,Math.sin(t*.25)*40,z+100); vecSet(ctx.up,Math.sin(t),Math.cos(t),0); ctx.misc[4] = Math.random() * .025 - .0125; }; var tunnelLight = function(ctx,lctx) { vecAdd(lctx.pos,vecNorm(lctx.pos,vecScale(lctx.pos,ctx.lookAt,-1)),ctx.camPos); lctx.pos[1] -= .5; vecSet(lctx.colour,3,3,3); lctx.distance = 30; return true; }; var tunnelCam = function(ctx,mul) { var z = demoTime*30*ctx.tunMul; vecSet(ctx.camPos,1.1*Math.cos(z*.1),Math.sin(z*.02),z); z += 5; vecSet(ctx.lookAt,-Math.sin(z*.05),-.7*Math.cos(z*.033),z); vecSet(ctx.up,0,1,0); ctx.toNearPlane = 2; }; var tunnelLightBall = function(ctx,lctx) { vecSet(lctx.pos , 4*Math.sin(demoTime*.5)*Math.cos(demoTime*.7) , 3*Math.cos(demoTime*1.5), demoTime*30*ctx.tunMul+14+16*Math.sin(demoTime*3.3)*Math.cos(demoTime*.77) ); vecSet(lctx.colour,1,1,1); lctx.distance = 15; return true; }; var direction = [ { // Music rows rows: 36 , // Raymarcher id rm: 'tunnel' , setGlobals: function( ctx ) { var z = tun1CamCommon(ctx,this); z *= z*z; ctx.misc[2] = 1 - z; ctx.toNearPlane = 5; } , lights: [ lightFunc(3,20) ] , updateText: null } , { rows: 18 , rm: 'tunnel' , setGlobals: function( ctx ) { var z = tun1CamCommon(ctx,this); ctx.toNearPlane = 5 - 2.25 * z; ctx.misc[2] = 0; } , lights: [ lightFunc(3,20) ] , updateText: null } , { rows: 36 , rm: 'tunnel' , setGlobals: function( ctx ) { var z = tun1CamCommon(ctx,this); ctx.toNearPlane = 2.75 - 2.25 * z; ctx.misc[2] = z; } , lights: [ lightFunc(3,20) ] , updateText: null } , { rows: 18 , rm: 'balls' , setGlobals: function( ctx ) { var z = demoTime*3; vecSet(ctx.camPos,0,4,z); vecSet(ctx.lookAt,4,0,z); vecSet(ctx.up,0,0,1); z = ctx.stepTime / this.time; z *= z*z; ctx.misc[2] = 1 - z; ctx.toNearPlane = 2.5; } , lights: [ lightFunc(.75,8) ] , updateText: null } , { rows: 22 , rm: 'balls' , setGlobals: balls1CamFunc(4,0,0) , lights: [ lightFunc(1,8) ] , updateText: null } , { rows: 22 , rm: 'balls' , setGlobals: balls1CamFunc(2,-2,0) , lights: [ lightFunc(1,8) ] , updateText: null } , { rows: 3 , rm: 'balls' , setGlobals: balls1CamFunc( 6 , 0 , -.5 ) , lights: [ lightFunc(.5,4) ] , updateText: null } , { rows: 9 , rm: 'balls' , setGlobals: balls1CamFunc( 6 , 0 , .5 ) , lights: [ lightFunc(.5,4) ] , updateText: null } , { rows: 3 , rm: 'balls' , setGlobals: balls1CamFunc( 2 , 2 , -.2 ) , lights: [ lightFunc(1,8) ] , updateText: null } , { rows: 9 , rm: 'balls' , setGlobals: balls1CamFunc( 2 , 2 , .2 ) , lights: [ lightFunc(1,8) ] , updateText: null } , { rows: 3 , rm: 'balls' , setGlobals: balls1CamFunc( 2 , 5 , -.7 ) , lights: [ lightFunc(1,2) ] , updateText: null } , { rows: 7 , rm: 'balls' , setGlobals: balls1CamFunc( 2 , 2 , .7 ) , lights: [ lightFunc(1,2) ] , updateText: null } , { rows: 9 , rm: 'balls' , setGlobals: function(ctx) { var z = demoTime*3; ctx.misc[2] = ctx.stepTime / this.time; vecSet(ctx.camPos,0,4+ctx.misc[2]*2,z); vecSet(ctx.lookAt,2,0,z+2); vecSet(ctx.up,0,0,1); ctx.misc[3] = 1; } , lights: [ lightFunc(1,2) ] , updateText: null } , { rows: 21 , rm: 'fractals' , setGlobals: function( ctx ) { fract1CamCommon(ctx); ctx.misc[3] = 1; var z = ctx.stepTime / this.time; ctx.misc[2] = 1 - z*z*z; } , lights : [ fractLight = function(ctx,lctx) { vecCopy(lctx.pos,ctx.camPos); lctx.pos[2]+=2; vecSet(lctx.colour,1,1,1); lctx.distance = 3; return true; } ], updateText: null } , { rows: 14 , rm: 'fractals' , setGlobals: fract1CamFunc(0) , lights : [ fractLight ], updateText: null } , { rows: 3 , rm: 'fractals' , setGlobals: fract1CamFunc(-.4) , lights : [ fractLight ], updateText: null } , { rows: 9 , rm: 'fractals' , setGlobals: fract1CamFunc(.4) , lights : [ fractLight ], updateText: null } , { rows: 3 , rm: 'fractals' , setGlobals: fract1CamFunc(-.2) , lights : [ fractLight ], updateText: null } , { rows: 9 , rm: 'fractals' , setGlobals: fract1CamFunc(.2) , lights : [ fractLight ], updateText: null } , { rows: 12 , rm: 'fractals' , setGlobals: function(ctx) { fract1CamCommon(ctx); ctx.misc[4] = -( 6 * ctx.stepTime / this.time ) % 1; ctx.misc[4] *= Math.random( ) * .25 + .75; } , lights : [ fractLight ], updateText: null } , { rows: 22 , rm: 'fractals' , setGlobals: function(ctx) { fract1CamCommon(ctx); ctx.misc[3] = .4; ctx.misc[2] = ctx.stepTime / this.time; ctx.toNearPlane = 3 - 2.5*Math.max(1,2*ctx.misc[2]); ctx.misc[4] = ( 30 * ctx.misc[2] ) % 1; ctx.misc[4] *= Math.random( ) * .15 + .85; } , lights : [ fractLight ], updateText: null } , { rows: 3 , rm: 'fractals' , setGlobals: neutral = function(ctx) { fract1CamCommon(ctx); ctx.misc[3] = .4; ctx.misc[2] = 1; ctx.misc[4] = 0; } , lights : [ fractLight ], updateText: null } , { rows: 12 , rm: 'fractals' , setGlobals: neutral , lights : [ fractLight ], updateText: function() { titleText( "TheT(ourist)" , .08 , 1 , 1 , 1 , 1 ); } } , { rows: 12 , rm: 'fractals' , setGlobals: neutral , lights : [ fractLight ], updateText: function() { titleText( "TheT(ourist)" , .08 , 1 - context.stepTime / this.time , 1 , 1 , 1 ); } } , { rows: 12 , rm: 'fractals' , setGlobals: neutral , lights : [ fractLight ], updateText: function() { titleText( "presents" , .08 , 1 - context.stepTime / this.time , 1 , 1 , 1 ); } } , { rows: 20 , rm: 'squares' , setGlobals: function(ctx) { squaresCam(ctx); ctx.toNearPlane = 2.5; ctx.misc[2] = 1 - ctx.stepTime / this.time; } , lights : [ lightFunc(1,30) ], updateText: function() { titleText( "Sine City" , .04 , context.stepTime / this.time , 1 , 1 , 1 ); } } , { rows: 52 , rm: 'squares' , setGlobals: function(ctx) { squaresCam(ctx); ctx.misc[2] = 0; } , lights : [ lightFunc(1,30) ], updateText: function() { titleText( "Sine City" , .04 , 1 , 1 , 1 , 1 ); } } , { rows: 12 , rm: 'squares' , setGlobals: function(ctx){ squaresCam(ctx); var z = context.stepTime / this.time; ctx.misc[3] = 1; ctx.misc[2] = Math.max(0,1-z*2); } , lights : [ lightFunc(1,30) ], updateText: function() { var z = context.stepTime / this.time; titleText( "Sine City" , .04 , 1 , 1 - z , 1 - z * .5 , 1 - z ); } } , { rows: 12 , rm: 'squares' , setGlobals: function(ctx) { squaresCam(ctx); var z = context.stepTime / this.time; ctx.misc[4] = ( 1 - z ) * .7 + Math.random() * .025 - .0125; ctx.misc[1] = 1 - .5 * z; } , lights : [ lightFunc(1,30) ], updateText: function() { titleText( "Sine City" , .04 , 1 , 0 , .5 , 0 ); } } , { rows: 9 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,29); var z = context.stepTime / this.time; ctx.misc[2] = Math.max(0,1-z*1.5); ctx.misc[4] += ( z - 1 ) * .3; ctx.misc[1] = .5 - .5 * z; } , lights : [ lightFunc(1,30) ], updateText: function() { titleText( "Sine City" , .04 , 1 - context.stepTime / this.time , 0 , .5 , 0 ); } } , { rows: 69 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,29); ctx.misc[1] = 0; } , lights : [ lightFunc(1,30) ], updateText: null } , { rows: 11 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,29); ctx.misc[3] = .2; ctx.misc[2] = context.stepTime / this.time; } , lights : [ lightFunc(1,30) ], updateText: null } , { rows: 11 , rm: 'tunnel' , setGlobals: function(ctx) { ctx.tunMul = 1; tunnelCam(ctx); ctx.misc[2] = 1 - context.stepTime / this.time; } , lights : [ tunnelLight ], updateText: null } , { rows: 17 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[2] = 0; ctx.misc[4] = (1.2 - 1.2 * context.stepTime / this.time) * (.98 + .04*Math.random()); } , lights : [ tunnelLight ], updateText: null } , { rows: 18 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[4] = 0; ctx.misc[8] = context.stepTime / this.time; } , lights : [ tunnelLight ], updateText: greetingsText } , { rows: 36 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[2] = 1 - Math.min(4*context.stepTime / this.time,1); ctx.misc[8] = 1; } , lights : tunLights = [ tunnelLight , tunnelLightBall ], updateText: greetingsText } , { rows: 33 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[2] = context.stepTime / this.time; ctx.misc[3] = .7; ctx.misc[4] = -((4*ctx.misc[2])%1)*(.95+Math.random()*.1); } , lights : tunLights , updateText: greetingsText } , { rows: 9 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,0); ctx.misc[2] = context.stepTime / this.time; ctx.misc[3] = 1; } , lights : [ fractLight ], updateText: greetingsText } , { rows: 20 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,context.stepTime / this.time); ctx.misc[2] = 0; } , lights : [ fractLight ], updateText: greetingsText } , { rows: 31 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,1); ctx.misc[2] = Math.min(0,1-5*context.stepTime / this.time); } , lights : [ fractLight ], updateText: greetingsText } , { rows: 5 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,1); ctx.misc[2] = 1-context.stepTime / this.time; } , lights : [ fractLight ], updateText: greetingsText } , { rows: 18 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,1); ctx.misc[2] = Math.min(0,1-5*context.stepTime / this.time); ctx.misc[4] = Math.max(0,1.6*context.stepTime / this.time - .8 )*(.95+Math.random()*.1); } , lights : [ fractLight ], updateText: greetingsText } , { rows: 12 , rm: 'fractals' , setGlobals: function(ctx) { fract2CamCommon(ctx,1); ctx.misc[3] = .1; ctx.misc[2] = context.stepTime / this.time; ctx.misc[4] = .8*(1-ctx.misc[2])*(.9+Math.random()*.2); } , lights : [ fractLight ], updateText: greetingsText } , { rows: 22 , rm: 'balls' , setGlobals: function(ctx) { balls2CamCommon(ctx); ctx.misc[2] = 1-context.stepTime / this.time; ctx.misc[4] = 0; } , lights : ballsLights = [ lightFunc(.6,30) , balls2LightFunc(1),balls2LightFunc(-1) ], updateText: greetingsText } , { rows: 59 , rm: 'balls' , setGlobals: function(ctx) { balls2CamCommon(ctx); ctx.misc[3] = .8; ctx.misc[2] = Math.max(0,1-(12*context.stepTime / this.time)%4); } , lights : ballsLights, updateText: greetingsText } , { rows: 8 , rm: 'balls' , setGlobals: function(ctx) { balls2CamCommon(ctx); ctx.misc[3] = .1; ctx.misc[2] = context.stepTime / this.time; ctx.misc[4] = .1-Math.random()*.2; } , lights : ballsLights, updateText: null } , { rows: 7 , rm: 'tunnel' , setGlobals: function(ctx) { ctx.tunMul = 2; tunnelCam(ctx); ctx.misc[2] = 1-context.stepTime / this.time; ctx.misc[4] = .1-Math.random()*.2; } , lights : tunLights , updateText: null } , { rows: 22 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[4] = .1-Math.random()*.2; } , lights : tunLights , updateText: null } , { rows: 10 , rm: 'tunnel' , setGlobals: function(ctx) { tunnelCam(ctx); ctx.misc[4] = context.stepTime*4+.1-Math.random()*.2; ctx.misc[3] = 1; ctx.misc[2] = context.stepTime / this.time; } , lights : tunLights , updateText: null } , { rows: 10 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,49); ctx.misc[4] = (demoTime-direction[48].startTime)*4+.1-Math.random()*.2; ctx.misc[2] = 1-context.stepTime / this.time; } , lights : [ lightFunc(1,30) ] , updateText: null } , { rows: 40 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,49); ctx.misc[4] = -(demoTime-direction[48].startTime)*6; } , lights : [ lightFunc(1,30) ] , updateText: null } , { rows: 40 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,49); ctx.misc[4] = (demoTime-direction[48].startTime)*8; ctx.misc[3] = 0; ctx.misc[2] = context.stepTime / this.time; } , lights : [ lightFunc(1,30) ] , updateText: null } , { rows: 68 , rm: 'squares' , setGlobals: function(ctx) { squaresCam2(ctx,49); ctx.misc[2] = 1 } , lights : [ lightFunc(1,30) ] , updateText: null } ]; var t = 0; var BPM = 120; for ( var i in direction ) { direction[ i ].startTime = t; t += ( direction[i].time = direction[ i ].rows * 60 / ( BPM * 4 ) ); direction[ i ].endTime = t; } rows = t * BPM * 4 / 60; t = 0; function createRaymarcherCode( def , nLights ) { var w = 'uniform '; var code = shaderHeader + [ w+'mat3 u0;' , w+'sampler2D u1;' , w+'!3 u2,u3;' , w+'float u4[10];' ].join('\n'); var u = 5; for ( var i in def.lights ) { code += w+'!3 u' + u++ + ', u' + u++ + ';'+w+'float u' + u++ + ';'; } code += [ "const !2 c=!2(1.,-1.)*"+def.normalDelta+";" , "float p,z,w,u,o,zy,q,x,a,zz;" , "!2 e,h;" , "!3 l=!3(zx,1.),m,r,s=u2,yx=!3(1.),n=!3(.0),b,v,xxx,xy,d,xx,xz,y;" , "!4 f;" , "float g(float x)" , "{" , "return fract(sin(x)*43758.5453);" , "}" , "float yy(!3 x)" , "{" , "m=floor(x),y=fract(x)," , "y*=y*(3.-2.*y)," , "z=m.x+m.y*57.+m.z*113.;" , "return mix(mix(mix(g(z),g(z+1.),y.x)," , "mix(g(z+57.),g(z+58.),y.x),y.y)," , "mix(mix(g(z+113.),g(z+114.),y.x)," , "mix(g(z+170.),g(z+171.),y.x),y.y),y.z);" , "}" , "float yyx(!2 x,float a)" , "{" , "e=pow(abs(x),!2(a));" , "return pow(e.x+e.y,1./a);" , "}" , "mat2 t(float x)" , "{" , "e=!2(cos(x),sin(x));" , "return mat2(-e.x,e.y,e.y,e.x);" , "}" , "float yz(!3 x)" , "{" , "return length(mod(x.xy,!2(15.))-!2(7.5))-.5+.05*sin(x.z*9.42477);" , "}" , "!2 k(!3 x,float a) {" ].join("\n"); code += def.map + '}'; code += [ "void main()" , "{" , "l.y+=mod(u4[4],1.)*2.2;" , "if(l.y>1.){" , "if(l.y < 1.2)discard;" , "l.y-=2.2;" , "}" , "l.x*=1.6," , "r=normalize(l*u0);" , "for(int j=0;j<2;j++){" , "v=r,xxx=s,xy=!3(.0)," , "x=.0,a=" + def.epsilon + ';' , "for(int i=0;i<" + def.depth + ";i++){" , "h=k(s+r*x,x);" , "if(h.x< a||i>" + def.depth + "/(j+1)||x>" + def.maxDistance + ".)break;" , "x+=h.x*" + def.step + ",a*=" + shaderFloat( def.epsilonMultiplier ) + ";" , "}" , "h.x=x;", "if(x<"+ def.maxDistance+ ".){" , "d=s+r*x," , "f=!4(" , "k(d+c.xyy,x).x," , "k(d+c.yyx,x).x," , "k(d+c.yxy,x).x," , "k(d+c.xxx,x).x" , ")," , "xx=normalize(f.x*c.xyy+f.y*c.yyx+f.z*c.yxy+f.w*c.xxx)," , "a=.0," , "p=" + def.aoWeight + ";" , "for(int i=1;i<="+def.aoSteps+";i++)" , "x=(float(i)/"+def.aoSteps+".)*"+ shaderFloat( def.aoDelta ) + "," , "m=d+xx*x," , "a+=p*(x-k(m,distance(m,s)).x)," , "p*=.5;" , "q=max(.1,1.-clamp(pow(a,1.),.0,1.));" , ].join('\n'); for ( var i in def.materials ) { if ( i > 0 ) { code += 'else '; } var m = materials[ def.materials[i] ]; code += 'if(h.y==' + i + '.)' + 'xz='; if ( m.noiseScale ) { code += 'mix(!3(' + shaderVec( m.albedo ) + '),!3(' + shaderVec( m.noise ) + '),yy(d*' + shaderFloat( def.noiseScale * m.noiseScale ) + '))'; } else { code += '!3(' + shaderVec( m.albedo ) + ')'; } code += ',w=' + shaderFloat( m.metallic ) + ',u=' + m.smoothness + ',o=' + m.r0 + ';'; } code += [ "v=reflect(r,xx)," , "z="+def.fogDensity+"*h.x," , "z=clamp(exp(-z*z*z*1.442695),.0,1.)," , "x=clamp((1.+dot(normalize(v+r),r)),.0,1.),a=x*x," , "zz=o+(1.-o)*x*a*a*(u*.9+.1)," , "y=mix(!3(1.),xz/dot(!3(.299,.587,.114),xz),w)," , "m=!3(.0)," , "zy=exp2(4.+6.*u)," , ].join('\n'); u = 5; for ( var l in def.lights ) { var b = def.lights[l]; code += [ "p=length(b=u" + u + "-d)," , "b/=p," , "p=max(1.,p-u" + (u+2) + ")*" + b.attenuation + "," , "p=1./max(1.,p*p)," , "m+=mix((1.-w)*xz*q,y*pow(max(dot(reflect(r,xx),b),.0),zy)*(zy+2.)/8.,zz)*p*max(dot(b,xx),.0)*u" + (u+1) + "," ].join('\n'); u+=3; } code += [ "xy=yx*z*normalize(y)*o*(u*.9+.1)*zz," , "m=mix(!3(" + shaderFloat(def.fog) + "),m,z)," , "xxx+=normalize(v)*" + def.reflectionDistance + ";" , "}else" , "m=!3(" + shaderFloat(def.fog) + ');' ].join('\n'); u=5; for ( var l in def.lights ) { var b = def.lights[l]; var h = b.vRadius; if ( h ) { code += [ "b=s-u" + u + "," , "p=dot(r,r),a=2.*dot(b,r)," , "x=a*a-4.*p*(dot(b,b)-" + (h*h) + ")," , "e=x<.0?!2(-1.):(x=sqrt(x),-.5*!2(a+x,a-x)/p)," , "e=!2(min(e.x,e.y),max(e.x,e.y));" , "if(e.x>.0&&e.yml?nl:ml; for ( var i=1;i<=nl;i++) { var sd = createRaymarcherCode(rm,i); shaders[sn] = [glCtx.FRAGMENT_SHADER,sd[0]]; programs[n + '_' + i] = [ sd[1] , 0 , sn++ ]; } } var context = { camPos: vomNew(3), lookAt: vomNew(3), up: vomNew(3), toNearPlane: 0 , misc: vomNew(10) , textColour: vomNew(3) , lights: [] }; for ( var i = 0;ivw){ C1.width=canvasWidth=vw; C1.height=canvasHeight=ch; }else{ C1.width=canvasWidth=cw; C1.height=canvasHeight=vh; } C2.style.width=C2.width=canvasWidth; c2height=C2.style.height=C2.height=Math.max(canvasHeight/8,100); c2rHeight=c2height/canvasHeight; twoDCtx.shadowColor = "#ccc"; twoDCtx.font = "normal small-caps bold " + Math.floor(c2height/2) + "px monospace"; twoDCtx.fillStyle = "#111"; twoDCtx.strokeStyle = "#ddd"; C1.style.left=Math.floor((vw-canvasWidth)*.5); C1.style.top=Math.floor((vh-canvasHeight)*.5); glCtx.viewport(0,0,canvasWidth,canvasHeight); } // FIXME: re-enable! document.body.style.cursor = 'none'; document.body.style.background = 'black'; document.body.innerHTML = '