MainShader = function(){
  var s = 
  {
    uniforms: {
      "resolution" : {type: "v2", value : new THREE.Vector2()},
      "time":   { type: "f", value: 0.0 },
      "beat" : {type: "f", value: 1.},
      "breakThings" : {type: "i", value: 0},
      "mainScene":   { type: "t", value: null },
      "phase":    { type: "f", value: -2.0},
      "lightPosition": {type: "v3", value : new THREE.Vector3()},
      "blend" : {type: "i", value: 0},
      "effect" : {type: "i", value: 0},
    },

    vertexShader: [

      "varying vec2 vUv;",
      "varying vec3 vNormal;",

      "void main() {",
        "vNormal = normal;",
        "vUv = uv;",
        "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

      "}"

    ].join("\n"),

    fragmentShader: [
      "#ifdef GL_ES",
      "precision highp float;",
      "#endif",
      
      "uniform vec2 resolution;",
      "uniform float time;",
      "uniform float beat;",
      "uniform int breakThings;",
      "uniform sampler2D mainScene;",
      "uniform float phase;",
      "uniform vec3 lightPosition;",
      "uniform int blend;",
      "uniform int effect;",
      
      "varying vec3 vNormal;",
      "varying vec2 vUv;",
      
      "float random( vec3 scale, float seed ){",
        "return fract( sin( dot( gl_FragCoord.xyz + seed, scale ) ) * 43758.5453 + seed );",
      "}",
      
      //-------------------------------------------
      //EFFECTS THAT CAN BE BLENDED INTO MAIN SCENE
      //-------------------------------------------
      "float u(float x){",
        "return (x > 0.0)?1.0:0.0;",
      "}",
      
      "float c(float y){",
        "return (y > 1.0)?1.0:y;",
      "}",
      
      "vec4 spherical(){",//effect 1
        "float timeS = time*2.0+50.0;",
          
        "vec2 p = (-1.0+2.0*vUv);",
        "float a = timeS*0.0001+10.0*atan(p.x, p.y);",
        "float r = length(p)*0.8;",
        
        "float w = cos(3.1415927-r*a)*random(vec3(1.0,1.0, 1.0), timeS*2.0)+timeS*2.5;",
        "float h = cos(3.1415927*a+r+2.0*w);",
        
        "float col = u(r)*sqrt(4.0-r);",
        "col *= cos(a-w+(r*4.0));",
        "col *= sin(r*30.0)*cos(a-w+r)+timeS*0.001;",
        
        "float red = c(1.0-abs(col*0.6*h));",
        "float green = c(1.0-abs(col*w*0.01));",
        "float blue = c(1.0-abs(col*h));",
        "float alpha = 1.0;",
        
        "vec4 color = vec4(0.5*red, 0.5*green, 0.5*blue, alpha);",
        "return color;",
      "}",
      //-------------------------------------------
      
      //-------------------------------------------
      //ray marcher
      //-------------------------------------------

      "const float EPSILON = 0.0005;",
      "const float MAX_DIST = 100.;",

      "const vec4 DIFFUSE_COLOR = vec4(0.5, 0.5, 0.6, 1.0);",
      "const vec4 SPECULAR_COLOR = vec4(0.3, 0.3, 0.6, 1.0);",
      "const vec4 AMBIENT_COLOR = vec4(0.2, 0.3, 0.3, 1.0);",
      "const vec4 FOG_COLOR = vec4(0.3, 0.4, 0.6, 1.0);",
      "const float SHINE = 1.2;",

      //2d-position in tunnel
      "vec2 position(float z){",
        
        "vec2 pos = sin(z*vec2(-2.7,0.05));",
        "pos *= vec2(0.3,0.2)+cos(z*vec2(-3.8,2.5))*vec2(0.09,-0.17);",
        "if(breakThings == 1){",
          "pos += vec2(0.3,0.39)+cos(z*vec2(-10.,0.01*random(vec3(1.0, 2.0, beat)*sin(time+100.), time)))*vec2(0.0865,1.0);",
        "}",
        "else{",
          "pos += vec2(0.3,0.39)+cos(z*vec2(-10.,0.01*sin((time+2.0)*0.3)))*vec2(0.0865,1.0);",
        "}",
        
        "return pos;",
      "}",

      "float tunnel(float x, float y, float z, float r){",
        "vec2 pos = position(z);",
        "vec2 e = vec2(1.1913, 15.4634);",
        "float radius=max(7.0,r+sin(z*e.x)*e.y)/10000.0;",
        "return radius/dot(vec2(x,y)-pos,vec2(x,y)-pos);",
      "}",

      "float dist(float x, float y, float z){",
        "float d3 = tunnel(x, y, z, 40.0);",
        "return d3;",
      "}",

      //origin = origin point of the ray
      //direction = unit vector of the direction of the ray
      //dt = distance that the ray has travelled
      "vec3 ray(vec3 origin, vec3 direction, float dt){",
        "return origin+(direction*dt);",
      "}",

      "vec3 normals(vec3 p){",
        "float nx = dist(p.x+EPSILON, p.y, p.z);", 
          "nx -= dist(p.x-EPSILON, p.y, p.z);",
        
        "float ny = dist(p.x, p.y+EPSILON, p.z);",
          "ny -= dist(p.x, p.y-EPSILON, p.z);",
        
        "float nz = dist(p.x, p.y, p.z+EPSILON);",
          "nz -= dist(p.x, p.y, p.z-EPSILON);",
        
        "return normalize(vec3(nx, ny, nz));",
      "}",

      "float facing(float nl){",
        "if(nl > 0.00){",
          "return 1.;",
        "}",
        "return 0.;",
      "}",

      "vec4 lightning(vec3 p, vec3 l){",

        "vec3 n = normals(p);",
        "vec3 light_dir=l-p;",
        "float nl = dot(n,normalize(light_dir));",
        "float d=max(0.0, nl);",
        
        "vec4 diff = vec4(d*1.2)*DIFFUSE_COLOR;",
        "vec4 spec = facing(nl)*vec4(d*1.2)*SPECULAR_COLOR*pow(d*0.5, SHINE);",
        "vec4 ambient = vec4(d*0.5)*AMBIENT_COLOR;",
        
        "return ambient+diff+spec;",
      "}",
      //EFFECT 2
      "vec4 rayTunnel(){",
        "float timeR=(time*10.0);",
        "vec2 uv=(-1.0+2.0*vUv);",
        
        //calculating the ray direction
        "float aspect=resolution.x/resolution.y;",
        "vec3 dir=normalize(vec3(uv*vec2(aspect,1.0),1.0));",

        "float d = 0.;",
        "float t = 0.;",
        "float fade = 0.0;",
        
        "vec3 orig = vec3(0.0, 0.0, timeR);",
        "vec3 light = vec3(0.0, 0.0, orig.z);",
        "vec3 pos = vec3(0.0, 0.0, 0.0);",
        "vec3 posT = pos;",
        "for(float t=0.0; t < MAX_DIST; ++t){",
          "pos = ray(orig, dir, t);",
          "d = dist(pos.x, pos.y, pos.z);",
          "if(d < EPSILON){",
            "fade=1.0-t/MAX_DIST;",
            "break;",
          "}",
          "posT=pos;",
          "pos+=dir/MAX_DIST;",
        "}",
        //track back
        "for(float i=0.0; i < 8.0; i++)",
        "{",
          "vec3 pos2=(posT+pos)/2.0;",
          "if(dist(pos2.x, pos2.y, pos2.z) < EPSILON){",
            "pos=pos2;",
          "}",
          "else{",
            "posT=pos2;",
          "}",
        "}",
        "vec4 l = lightning(pos, light);",
        "vec4 col = l*min(1.0,fade*10.);",
        "float	fog = exp( -0.05 * length( pos - orig ) );",
        "col = mix(FOG_COLOR, col, fog);",
        "return col;",
      "}",
      //-------------------------------------------
      
      //-------------------------------------------
      //DIFFERENT BLENDING OPTIONS
      //-------------------------------------------
      "vec4 corner(vec4 from, vec4 to){",//blend 3
        "float mixi = dot(vUv.x, vUv.y)+phase;",
        "vec4 color = mix(to, from, smoothstep(0.5, -0.25, mixi));",
        "return color;",
      "}",
      
      "vec4 fromCenter(vec4 from, vec4 to){",//blend 2
        "vec2 p = -1.0+2.0*vUv;",
        "float c = length(p)*2.0;",
        "c -= 1.1 + phase;",
        "vec4 color = mix(from, to, smoothstep(0.25, -0.25, c));",
        "return color;",
      "}",
      
      "vec4 layer(vec4 from, vec4 to){",//blend 1
        "vec4 color = mix(from, to, smoothstep(-1.0, 1.0, beat));",
        "return color;",
      "}",
      
      //MAIN
      "void main(void){",
        "vec4 scene = texture2D(mainScene, vUv);",
        "vec4 e = scene;",
        "vec4 c = scene;",
        
        
        "if(effect == 1){",
          "e = spherical();",
        "}",
        "else if(effect == 2){",
          "e = rayTunnel();",
        "}",
        "else if(effect == 3){",
          "e = mix(spherical(), rayTunnel(), smoothstep(-1.0, 1.0, sin(time*4.)*0.1));",
        "}",
        
        "if(blend == 1){",
          "c = layer(scene, e);",
        "}",
        "else if(blend == 2){",
          "c = fromCenter(scene, e);",
        "}",
        "else if(blend == 3){",
          "c = corner(scene, e);",
        "}",
        
        "gl_FragColor = c;",
      "}"
      
    ].join("\n")

  };
  return s;
};
