function cubeBlob()
{

    this.angularSpeed = 0.2; 
    this.lastTime = 0;
    this.cube;
    this.blob;
    this.blob_hide;
    this.map;
    this.modifier;
    this.bumpmap;
    this.renderer;
    this.scene;
    this.camera;
    this.angleChange;    
    this.light;

    this.composer;
    this.vblur;
    this.hblur;

    this.nBarHalf;
    this.histo;
    this.histoIdx;

    this.obj;
    this.obj_material;
    this.backMaterial;

    this.spike = 0.2;

    this.p1;
    this.accum = 0;

    var blur = 0.1;

    var back_obj;
    var carmine1;
    var carmine2;
    var carmine3;
    var credits1;
    var credits2;

    this.bx = [], this.by = [], this.bz = [];

    this.init = function(renderer, camera)
    {      
    
      this.renderer = renderer;
            
      this.camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10000 );
      this.camera.position.z = 40;
      this.scene = new THREE.Scene();

      var light = new THREE.DirectionalLight( 0xffffff );
      light.position.set( 0, 0, 100 ).normalize();
      this.scene.add(light);

      this.map = THREE.ImageUtils.loadTexture('assets/glass.jpg');
      this.bumpmap = THREE.ImageUtils.loadTexture('assets/glass_norms.jpg');

      this.backMaterial = new THREE.MeshPhongMaterial({ 
        map: this.map, 
        bumpMap: this.bumpmap        
      });
      
      var path = "assets/cube/";
      var format = '.jpg';
      var urls = [
          path + 'posx_1' + format, path + 'negx_1' + format,
          path + 'posy_1' + format, path + 'negy_1' + format,
          path + 'posz_1' + format, path + 'negz_1' + format
        ];

      var reflectionCube = THREE.ImageUtils.loadTextureCube(urls);
      reflectionCube.format = THREE.RGBFormat;

      var blob_text = THREE.ImageUtils.loadTexture('assets/glass.jpg');      
      blob_text.wrapS = THREE.RepeatWrapping;
      blob_text.wrapT = THREE.RepeatWrapping;
      blob_text.repeat.x = 4;
      blob_text.repeat.y = 4;

      var blob_text_norms = THREE.ImageUtils.loadTexture('assets/glass_norms.jpg');
      blob_text_norms.wrapS = THREE.RepeatWrapping;
      blob_text_norms.wrapT = THREE.RepeatWrapping;
      blob_text_norms.repeat.x = 4;
      blob_text_norms.repeat.y = 4;
      
      var cubeMaterial = new THREE.MeshPhongMaterial({ 
        color: 0xFF0000, 
        ambient: 0xFF0000, 
        specular: 0xFFFFFF, 
        map: blob_text, 
        bumpMap: blob_text_norms, 
        envMap: reflectionCube, 
        combine: THREE.MixOperation, 
        reflectivity: 0.1
      });

      this.obj_material = this.cubeMaterial;

      this.blob = new THREE.Mesh(new THREE.SphereGeometry(1, 100, 100), cubeMaterial);
      
      this.blob.scale.set(15, 15, 15);

      for (i = 0; i<this.blob.geometry.vertices.length; i ++)
      {
          this.bx[i] = this.blob.geometry.vertices[i].x;
          this.by[i] = this.blob.geometry.vertices[i].y;
          this.bz[i] = this.blob.geometry.vertices[i].z;
      }
      
      this.scene.add(this.blob);
      
      this.blob.doubleSided = true;     

      this.blob.castShadow = true;
      this.blob.receiveShadow = true;       

      /*
      this.light = new THREE.SpotLight(0xffffff, 1.25);
      this.light.position.set(-75, 175, 100);
      this.light.target.position.set( 0, 0, 0);
      this.light.castShadow = true;
    
      this.scene.add(this.light);
      */
      var spotLight = new THREE.SpotLight( 0xffffff );
      spotLight.position.set( -10, -10, 50 );

      spotLight.castShadow = true;

      spotLight.shadowDarkness = 0.5;      
      spotLight.shadowMapWidth  = 512;
      spotLight.shadowMapHeight = 512;

      spotLight.shadowCameraRight  =  5;
      spotLight.shadowCameraLeft   = -5;
      spotLight.shadowCameraTop    =  5;
      spotLight.shadowCameraBottom = -5;
      
      this.scene.add(spotLight);

      var loader = new THREE.OBJLoader();
      var scene = this.scene;      
      var obj_map = this.blob_text;
      var obj_bumpmap = this.blob_text_norms;
      loader.load('assets/blobox.obj', function(object) 
      {
        object.traverse(function(child) 
        {

          if (child instanceof THREE.Mesh) 
          {
            child.material.specular = 0xFFFFFF;
            child.material.map = THREE.ImageUtils.loadTexture('assets/concrete.png');
            child.material.bumpmap = THREE.ImageUtils.loadTexture('assets/concrete_norms.jpg');

            //child.castShadow = true;
            child.receiveShadow = true;
          }

        });
            
        scene.add(object);

        back_obj = object;
        back_obj.doubleSided = true;                    

      });    

      // Create Bokeh Overlay ----------------------------------------------------------------------------------------
      var map4 = THREE.ImageUtils.loadTexture( 'images/bokeh2.png' );
			map4.wrapS = map4.wrapT = THREE.RepeatWrapping;
      map4.repeat.set( 1, 1 );

			var material4 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0x000000,
        map: map4,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material4.opacity = 0.8;
      
      var overlay4 = new THREE.Mesh( new THREE.PlaneGeometry( 300, 200, 1, 1 ), material4 );
      overlay4.position.set( 0, 0, -30 );
      
      this.scene.add( overlay4 );
      
      // Create carmine1 Overlay ----------------------------------------------------------------------------------------
      var map1 = THREE.ImageUtils.loadTexture( 'images/qarmine1.png' );
			map1.wrapS = map1.wrapT = THREE.RepeatWrapping;
      map1.repeat.set( 1, 1 );

			var material1 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0xff0000,
        map: map1,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material1.opacity = 0.0;
      
      carmine1 = new THREE.Mesh( new THREE.PlaneGeometry( 250, 250, 1, 1 ), material1 );
      carmine1.position.set( 0, 0, -40 );
      
      this.scene.add( carmine1 );
      
      // Create carmine2 Overlay ----------------------------------------------------------------------------------------
      var map2 = THREE.ImageUtils.loadTexture( 'images/qarmine2.png' );
			map2.wrapS = map1.wrapT = THREE.RepeatWrapping;
      map2.repeat.set( 1, 1 );

			var material2 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0x000000,
        map: map2,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material2.opacity = 0.0;
      
      carmine2 = new THREE.Mesh( new THREE.PlaneGeometry( 250, 250, 1, 1 ), material2 );
      carmine2.position.set( 0, 0, -40 );
      
      this.scene.add( carmine2 );
      
      // Create carmine3 Overlay ----------------------------------------------------------------------------------------
      var map3 = THREE.ImageUtils.loadTexture( 'images/qarmine3.png' );
			map3.wrapS = map1.wrapT = THREE.RepeatWrapping;
      map3.repeat.set( 1, 1 );

			var material3 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0x000000,
        map: map3,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material3.opacity = 0.0;
      
      carmine3 = new THREE.Mesh( new THREE.PlaneGeometry( 250, 250, 1, 1 ), material3 );
      carmine3.position.set( 0, 0, -40 );
      
      this.scene.add( carmine3 );
      
      // Create credits1 Overlay ----------------------------------------------------------------------------------------
      var map4 = THREE.ImageUtils.loadTexture( 'images/credits1.png' );
			map4.wrapS = map1.wrapT = THREE.RepeatWrapping;
      map4.repeat.set( 1, 1 );

			var material4 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0x000000,
        map: map4,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material4.opacity = 0.0;
      
      credits1 = new THREE.Mesh( new THREE.PlaneGeometry( 100, 100, 1, 1 ), material4 );
      credits1.position.set( 0, 0, -40 );
      
      this.scene.add( credits1 );
      
      // Create credits2 Overlay ----------------------------------------------------------------------------------------
      var map5 = THREE.ImageUtils.loadTexture( 'images/credits2.png' );
			map5.wrapS = map1.wrapT = THREE.RepeatWrapping;
      map5.repeat.set( 1, 1 );

			var material5 = new THREE.MeshLambertMaterial( {
        color: 0xffffff,       
        specular: 0x000000,
        ambient: 0xffffff,
        emissive: 0x000000,
        map: map5,
        side: THREE.FrontSide,  
        transparent: true,
        depthTest: false
      } );
      material5.opacity = 0.0;
      
      credits2 = new THREE.Mesh( new THREE.PlaneGeometry( 100, 100, 1, 1 ), material5 );
      credits2.position.set( 0, 0, -40 );
      
      this.scene.add( credits2 );
      

      this.composer = new THREE.EffectComposer(this.renderer);
      this.composer.addPass(new THREE.RenderPass(this.scene, this.camera));     

      this.hblur = new THREE.ShaderPass(THREE.HorizontalTiltShiftShader);
      // this.hblur = new THREE.ShaderPass(THREE.DotScreenShader);
      this.composer.addPass(this.hblur);
        
      this.vblur = new THREE.ShaderPass(THREE.VerticalTiltShiftShader);
      this.vblur.renderToScreen = true;
      this.composer.addPass(this.vblur);

    };

    this.setupRenderer = function()
    {     
      this.renderer.setClearColor( 0x000000, 0 );
      this.camera.position.z = 40;          
      this.renderer.autoClear = true;

      this.renderer.shadowMapEnabled = true;      
      this.renderer.shadowMapSoft = true;            
    }
    
    this.preRenderer = function(){
        this.composer.render();    
    }
    
    
    this.render = function(demoFrame)
    {
        this.angleChange = this.angularSpeed * demoFrame * 2 * Math.PI / 1000;
        this.accum += demoFrame;
        //var demoFrame = 1.0;
        var tspeed = demoFrame;
                
        back_obj.rotation.y += demoFrame*0.2;
        back_obj.rotation.x += demoFrame*0.3;
        back_obj.rotation.z += demoFrame*0.4;        
        
        carmine1.material.opacity += demoFrame*0.07;
        carmine2.material.opacity += demoFrame*0.1;
        carmine3.material.opacity += demoFrame*0.2;
        
        // Remove Logo from scene
        if(this.accum > 8){
          this.scene.remove(carmine1);
        
        }
        if(this.accum > 10){
          this.scene.remove(carmine2);
        
        }
        if(this.accum > 9){
          this.scene.remove(carmine3);
        
        }

        // Add credits1         
        if(this.accum > 12){
          credits1.material.opacity += demoFrame*0.3;
        }        
        // Remove credits         
        if(this.accum > 15){
          credits1.material.opacity -= demoFrame*0.5;
        }

        // Add credits2         
        if(this.accum > 19){
          credits2.material.opacity += demoFrame*0.3;
        }        
        // Remove credits         
        if(this.accum > 22){
          credits2.material.opacity -= demoFrame*0.5;
        }                
        
        
        
        
        
        
        this.nBarHalf = Math.ceil(41/2);
        this.histo = sound.makeHistogram(this.nBarHalf);
        this.histoIdx = this.barIdx < this.nBarHalf ? this.nBarHalf-1-this.barIdx : this.barIdx - this.nBarHalf;       
        
        if (this.histo[0] > 195)  
        { 
          this.spike = 0.5;                             
        } 

        if (this.spike > 0.2) this.spike -= demoFrame*2.0;

        if (this.histo[10] > 120)  
        { 
          blur = 20;                             
        } 

        if (blur > 1) blur -= demoFrame * 100.0;
        // blur = 1;

        //this.spike = 0.2;

        for (i = 0, il = this.blob.geometry.vertices.length; i < il; i ++)
        {
            this.blob.geometry.vertices[i].x = this.bx[i] + 1.0 * Math.sin(tspeed * 1.15 + this.by[i] * this.bz[i]*5)*this.spike;
            this.blob.geometry.vertices[i].y = this.by[i] + 1.2 * Math.cos(tspeed * 1.80 + this.bx[i] * this.by[i]*5)*this.spike;
            this.blob.geometry.vertices[i].z = this.bz[i] - 1.4 * Math.cos(tspeed * 1.58 + this.by[i] * this.bx[i]*5)*this.spike;
        }        
        
        this.blob.geometry.dynamic = true;
        this.blob.geometry.verticesNeedUpdate = true;

        this.blob.rotation.y -= demoFrame;
        this.blob.rotation.x -= demoFrame/2;
        this.blob.rotation.z -= demoFrame/3;    

        // this.hblur.uniforms["h"].value = blur / window.innerHeight;    
        this.vblur.uniforms["v"].value = blur / window.innerWidth;    
                        
        // this.renderer.render(this.scene, this.camera);
        this.composer.render();
    }
}