topical media & game development

talk show tell print

mobile-query-three-plugins-flamethrower-examples-vendor-fireworks.js-fireworks-bundle.js / js



  
  
  var Fireworks        = {};
////////////////////////////////////////////////////////////////////////////

// //
////////////////////////////////////////////////////////////////////////////

Fireworks.EffectsStackBuilder = function(emitter){ this._emitter = emitter; };
Getter for the emitter

  
  Fireworks.EffectsStackBuilder.prototype.emitter        = function(){
          return this._emitter;        
  };
  
  Fireworks.EffectsStackBuilder.prototype.back        = function(){
          return this._emitter;
  }
  
  Fireworks.EffectsStackBuilder.prototype.createEffect        = function(name, opts){
          var creator        = Fireworks.createEffect(name, opts).pushTo(this._emitter).back(this);
          creator.effect().emitter(this._emitter);
          return creator;
  }
  
  
////////////////////////////////////////////////////////////////////////////

// //
////////////////////////////////////////////////////////////////////////////

Basic Fireworks.Effect builder

  
  Fireworks.createEffect        = function(name, opts){
          // handle polymophism
          if( typeof(name) === 'object' ){
                  opts        = name;
                  name        = undefined;
          }
          
          var effect        = new Fireworks.Effect();
          effect.opts        = opts;
          effect.name        = name;
          effect.back        = null;
          var methods        = {
                  onCreate: function(val){
                          effect.onCreate        = val;
                          return methods;
                  },
                  onBirth: function(val){
                          effect.onBirth        = val;
                          return methods;
                  },
                  onUpdate: function(val){
                          effect.onUpdate        = val;
                          return methods;
                  },
                  onDeath: function(val){
                          effect.onDeath        = val;
                          return methods;
                  },
                  onPreUpdate: function(val){
                          effect.onPreUpdate        = val;
                          return methods;
                  },
                  onPreRender: function(val){
                          effect.onPreRender        = val;
                          return methods;
                  },
                  onRender: function(val){
                          effect.onRender        = val;
                          return methods;
                  },
                  onPostRender: function(val){
                          effect.onPostRender        = val;
                          return methods;
                  },
                  onIntensityChange: function(val){
                          effect.onIntensityChange= val;
                          return methods;
                  },
                  pushTo        : function(emitter){
                          emitter.effects().push(effect);
                          return methods;        
                  },
                  back        : function(value){
                          if( value === undefined )        return effect.back;        
                          effect.back        = value;
                          return methods;        
                  },
                  effect        : function(){
                          return effect;
                  }
          }
          return methods;
  }
  
  
An effect to apply on particles

  
  Fireworks.Effect        = function(){
          this._emitter        = null;
  }
  
  Fireworks.Effect.prototype.destroy        = function(){
  }
  
  
Getter/Setter for the emitter

  
  Fireworks.Effect.prototype.emitter        = function(value){
          if( value === undefined )        return this._emitter;        
          this._emitter        = value;
          return this;        
  };
  
  
Callback called on particle creation

  
  //Fireworks.Effect.prototype.onCreate        = function(){
  //}
  //
  
Callback called when a particle is spawning TODO to rename onSpawn

  
  //Fireworks.Effect.prototype.onBirth        = function(){
  //}
  //
  //Fireworks.Effect.prototype.onDeath        = function(){
  //}
  //
  //Fireworks.Effect.prototype.onUpdate        = function(){
  //}
  
  Fireworks.createEmitter        = function(opts){
          return new Fireworks.Emitter(opts);
  }
  
  
The emitter of particles

  
  Fireworks.Emitter        = function(opts){
          this._nParticles        = opts.nParticles !== undefined ? opts.nParticles : 100;
          this._particles                = [];
          this._effects                = [];
          this._started                = false;
          this._onUpdated                = null;
          this._intensity                = 0;
          this._maxDeltaTime        = 1/3;
  
          this._effectsStackBuilder        = new Fireworks.EffectsStackBuilder(this)
  }
  
  Fireworks.Emitter.prototype.destroy        = function()
  {
          this._effects.forEach(function(effect){
                  effect.destroy();
          });
          this._particles.forEach(function(particle){
                  particle.destroy();
          });
  }
  
  
////////////////////////////////////////////////////////////////////////////

// Getters //
////////////////////////////////////////////////////////////////////////////

Fireworks.Emitter.prototype.effects = function(){ return this._effects; } Fireworks.Emitter.prototype.effect = function(name){ for(var i = 0; i < this._effects.length; i++){ var effect = this._effects[i]; if( effect.name === name ) return effect; } return null; } Fireworks.Emitter.prototype.particles = function(){ return this._particles; } Fireworks.Emitter.prototype.liveParticles = function(){ return this._liveParticles; } Fireworks.Emitter.prototype.deadParticles = function(){ return this._deadParticles; } Fireworks.Emitter.prototype.nParticles = function(){ return this._nParticles; } Fireworks.Emitter.prototype.effectsStackBuilder = function(){ return this._effectsStackBuilder; }
Getter/setter for intensity

  
  Fireworks.Emitter.prototype.intensity        = function(value){
          // if it is a getter, return value
          if( value === undefined )        return this._intensity;
          // if the value didnt change, return for chained api
          if( value === this._intensity )        return this;
          // sanity check
          console.assert( value >= 0, 'Fireworks.Emitter.intensity: invalid value.', value);
          console.assert( value <= 1, 'Fireworks.Emitter.intensity: invalid value.', value);
          // backup the old value
          var oldValue        = this._intensity;
          // update the value
          this._intensity        = value;
          // notify all effects
          this._effects.forEach(function(effect){
                  if( !effect.onIntensityChange )        return;
                  effect.onIntensityChange(this._intensity, oldValue);                        
          }.bind(this));
          return this;        // for chained API
  }
  
  
Getter/setter for intensity

  
  Fireworks.Emitter.prototype.maxDeltaTime        = function(value){
          if( value === undefined )        return this._maxDeltaTime;
          this._maxDeltaTime        = value;
          return this;
  }
  
  
////////////////////////////////////////////////////////////////////////////

// backward compatibility //
////////////////////////////////////////////////////////////////////////////

Fireworks.Emitter.prototype.setParticleData = function(particle, namespace, value){ particle.set(namespace, value); } Fireworks.Emitter.prototype.getParticleData = function(particle, namespace){ return particle.get(namespace); }
////////////////////////////////////////////////////////////////////////////

// Start function //
////////////////////////////////////////////////////////////////////////////

Fireworks.Emitter.prototype.start = function() { console.assert( this._effects.length > 0, "At least one effect MUST be set") console.assert( this._started === false ); this._particles = new Array(this._nParticles); for(var i = 0; i < this._nParticles; i++){ this._particles[i] = new Fireworks.Particle(); } this._liveParticles = []; this._deadParticles = this._particles.slice(0); this._started = true; // onCreate on all particles this._effects.forEach(function(effect){ if( !effect.onCreate ) return; this._particles.forEach(function(particle, particleIdx){ effect.onCreate(particle, particleIdx); }) }.bind(this)); // set the intensity to 1 this.intensity(1) return this; // for chained API } Fireworks.Emitter.prototype.update = function(deltaTime){ // bound the deltaTime to this._maxDeltaTime deltaTime = Math.min(this._maxDeltaTime, deltaTime) // honor effect.onPreUpdate this._effects.forEach(function(effect){ if( !effect.onPreUpdate ) return; effect.onPreUpdate(deltaTime); }.bind(this)); // update each particles this._effects.forEach(function(effect){ if( !effect.onUpdate ) return; this._liveParticles.forEach(function(particle){ effect.onUpdate(particle, deltaTime); }) }.bind(this)); return this; // for chained API } Fireworks.Emitter.prototype.render = function(){ this._effects.forEach(function(effect){ if( !effect.onPreRender ) return; effect.onPreRender(); }.bind(this)); this._effects.forEach(function(effect){ if( !effect.onRender ) return; this._liveParticles.forEach(function(particle){ effect.onRender(particle); }) }.bind(this)); this._effects.forEach(function(effect){ if( !effect.onPostRender ) return; effect.onPostRender(); }.bind(this)); return this; // for chained API }
////////////////////////////////////////////////////////////////////////////

// //
////////////////////////////////////////////////////////////////////////////

kill this particle

  
  Fireworks.Emitter.prototype.killParticle        = function(particle)
  {
          var idx        = this._liveParticles.indexOf(particle);
          console.assert( idx !== -1 )
          this._liveParticles.splice(idx, 1)
          this._deadParticles.push(particle);
          // do the death on all effects
          this.effects().forEach(function(effect){
                  effect.onDeath && effect.onDeath(particle);                        
          }.bind(this));
  }
  
  
Spawn a particle

  
  Fireworks.Emitter.prototype.spawnParticle        = function(){
          console.assert(this._deadParticles.length >= 1, 'no more particle available' );
          // change the particles 
          var particle        = this.deadParticles().pop();
          this.liveParticles().push(particle);
          // do the birth on all effects
          this.effects().forEach(function(effect){
                  effect.onBirth && effect.onBirth(particle);                        
          }.bind(this));
  }
  Fireworks.createLinearGradient        = function(opts){
          var LinearGradient        = new Fireworks.LinearGradient(opts);
          return LinearGradient;
  }
  
  
The emitter of particles

  
  Fireworks.LinearGradient        = function(opts){
          this._keyPoints        = [];
  }
  
  Fireworks.LinearGradient.prototype.push        = function(x, y){
          this._keyPoints.push({
                  x        : x,
                  y        : y
          });
          return this;
  }
  
  
Compute a value for this LinearGradient

  
  Fireworks.LinearGradient.prototype.get        = function(x){
          for( var i = 0; i < this._keyPoints.length; i++ ){
                  var keyPoint        = this._keyPoints[i];
                  if( x <= keyPoint.x )        break;
          }
  
          if( i === 0 )        return this._keyPoints[0].y;
  
          console.assert(i < this._keyPoints.length )
  
          var prev        = this._keyPoints[i-1];
          var next        = this._keyPoints[i];
          
          var ratio        = (x - prev.x) / (next.x - prev.x)
          var y                = prev.y + ratio * (next.y - prev.y)
          
          return y;
  };
  
The emitter of particles

  
  Fireworks.Particle        = function(){
  }
  
  Fireworks.Particle.prototype.set        = function(key, value){
          console.assert( this[key] === undefined, "key already defined: "+key );
          this[key]        = value;
          return this[key];
  }
  
  Fireworks.Particle.prototype.get        = function(key){
          console.assert( this[key] !== undefined, "key undefined: "+key );
          return this[key];
  }
  
  Fireworks.Particle.prototype.has        = function(key){
          return this[key] !== undefined        ? true : false;
  }
  Fireworks.Shape        = function(){
  }
  
  
**
// *
parameter: {Fireworks.Vector} point the point coordinate to test
// *
returns: {Boolean} true if point is inside the shape, false otherwise
//*/ //Fireworks.Shape.prototype.contains = function(point){ //} //
**
// * generate a random point contained in this shape // *
returns: {Fireworks.Vector} the just generated random point
//*/ //Firefly.Shape.prototype.randomPoint = function(vector){ //} Fireworks.createVector = function(x, y, z){ return new Fireworks.Vector(x,y,z); };
jme- copy of THREE.Vector3 github.com/mrdoob/three.js/blob/master/src/core/Vector3.js
author: mr.doob / mrdoob.com/
author: kile / kile.stravaganza.org/
author: philogb / blog.thejit.org/
author: mikael emtinger / gomo.se/
author: egraether / egraether.com/

  
  
  Fireworks.Vector = function ( x, y, z ) {
  
          this.x = x || 0;
          this.y = y || 0;
          this.z = z || 0;
  
  };
  
  Fireworks.Vector.prototype = {
  
          constructor: Fireworks.Vector,
  
          set: function ( x, y, z ) {
  
                  this.x = x;
                  this.y = y;
                  this.z = z;
  
                  return this;
  
          },
  
          setX: function ( x ) {
  
                  this.x = x;
  
                  return this;
  
          },
  
          setY: function ( y ) {
  
                  this.y = y;
  
                  return this;
  
          },
  
          setZ: function ( z ) {
  
                  this.z = z;
  
                  return this;
  
          },
          
          random        : function( ) {
                  this.x        = Math.random() - 0.5;
                  this.y        = Math.random() - 0.5;
                  this.z        = Math.random() - 0.5;
                  return this;
          }, // jme - added
          
          toString        : function(){
                  return JSON.stringify(this);
          }, // jme - added
  
          copy: function ( v ) {
  
                  this.x = v.x;
                  this.y = v.y;
                  this.z = v.z;
  
                  return this;
  
          },
  
          add: function ( a, b ) {
  
                  this.x = a.x + b.x;
                  this.y = a.y + b.y;
                  this.z = a.z + b.z;
  
                  return this;
  
          },
  
          addSelf: function ( v ) {
  
                  this.x += v.x;
                  this.y += v.y;
                  this.z += v.z;
  
                  return this;
  
          },
  
          addScalar: function ( s ) {
  
                  this.x += s;
                  this.y += s;
                  this.z += s;
  
                  return this;
  
          },
  
          sub: function ( a, b ) {
  
                  this.x = a.x - b.x;
                  this.y = a.y - b.y;
                  this.z = a.z - b.z;
  
                  return this;
  
          },
  
          subSelf: function ( v ) {
  
                  this.x -= v.x;
                  this.y -= v.y;
                  this.z -= v.z;
  
                  return this;
  
          },
  
          multiply: function ( a, b ) {
  
                  this.x = a.x * b.x;
                  this.y = a.y * b.y;
                  this.z = a.z * b.z;
  
                  return this;
  
          },
  
          multiplySelf: function ( v ) {
  
                  this.x *= v.x;
                  this.y *= v.y;
                  this.z *= v.z;
  
                  return this;
  
          },
  
          multiplyScalar: function ( s ) {
  
                  this.x *= s;
                  this.y *= s;
                  this.z *= s;
  
                  return this;
  
          },
  
          divideSelf: function ( v ) {
  
                  this.x /= v.x;
                  this.y /= v.y;
                  this.z /= v.z;
  
                  return this;
  
          },
  
          divideScalar: function ( s ) {
  
                  if ( s ) {
  
                          this.x /= s;
                          this.y /= s;
                          this.z /= s;
  
                  } else {
  
                          this.x = 0;
                          this.y = 0;
                          this.z = 0;
  
                  }
  
                  return this;
  
          },
  
          negate: function() {
  
                  return this.multiplyScalar( - 1 );
  
          },
  
          dot: function ( v ) {
  
                  return this.x * v.x + this.y * v.y + this.z * v.z;
  
          },
  
          lengthSq: function () {
  
                  return this.x * this.x + this.y * this.y + this.z * this.z;
  
          },
  
          length: function () {
  
                  return Math.sqrt( this.lengthSq() );
  
          },
  
          normalize: function () {
  
                  return this.divideScalar( this.length() );
  
          },
  
          setLength: function ( l ) {
  
                  return this.normalize().multiplyScalar( l );
  
          },
          
          cross: function ( a, b ) {
  
                  this.x = a.y * b.z - a.z * b.y;
                  this.y = a.z * b.x - a.x * b.z;
                  this.z = a.x * b.y - a.y * b.x;
  
                  return this;
  
          },
  
          crossSelf: function ( v ) {
  
                  var x = this.x, y = this.y, z = this.z;
  
                  this.x = y * v.z - z * v.y;
                  this.y = z * v.x - x * v.z;
                  this.z = x * v.y - y * v.x;
  
                  return this;
  
          },
  
          distanceTo: function ( v ) {
  
                  return Math.sqrt( this.distanceToSquared( v ) );
  
          },
  
          distanceToSquared: function ( v ) {
  
                  return new Fireworks.Vector().sub( this, v ).lengthSq();
  
          },
  
          equals: function ( v ) {
  
                  return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
  
          },
  
          isZero: function () {
  
                  return ( this.lengthSq() < 0.0001 /* almostZero */ );
  
          },
  
          clone: function () {
  
                  return new Fireworks.Vector( this.x, this.y, this.z );
  
          }
  
  };
  
Shortcut to create Fireworks.EffectRandomDriftVelocity

  
  Fireworks.EffectsStackBuilder.prototype.acceleration        = function(opts)
  {
          opts                = opts                || {};
          var effectId        = opts.effectId        || 'acceleration';
          console.assert( opts.shape instanceof Fireworks.Shape );
          // create the effect itself
          Fireworks.createEffect(effectId, {
                  shape        : opts.shape
          }).onCreate(function(particle){
                  particle.set('acceleration', {
                          vector        : new Fireworks.Vector()
                  });
          }).onBirth(function(particle){
                  var acceleration= particle.get('acceleration').vector;
                  this.opts.shape.randomPoint(acceleration)
          }).onUpdate(function(particle, deltaTime){
                  var velocity        = particle.get('velocity').vector;
                  var acceleration= particle.get('acceleration').vector;
                  velocity.x        += acceleration.x * deltaTime;
                  velocity.y        += acceleration.y * deltaTime;
                  velocity.z        += acceleration.z * deltaTime;
          }).pushTo(this._emitter);
  
          return this;        // for chained API
  };
  
Handle the friction - aka a value between 0 and 1 which multiply the velocity
parameter: {Number} value the friction number between 0 and 1

  
  Fireworks.EffectsStackBuilder.prototype.friction        = function(value)
  {
          // handle parameter polymorphism
          value        = value !== undefined ? value        : 1;
          // sanity check
          console.assert( value >= 0 && value <= 1.0 );
          // create the effect itself
          Fireworks.createEffect('friction')
          .onCreate(function(particle, particleIdx){
                  particle.set('friction', {
                          value        : value
                  });
          })
          .onBirth(function(particle){
                  var data        = particle.get('friction');
                  data.value        = value
          })
          .onUpdate(function(particle){
                  var friction        = particle.get('friction').value;
                  var velocity        = particle.get('velocity').vector;
                  velocity.multiplyScalar(friction);
          })
          .pushTo(this._emitter);
          // return this for chained API
          return this;
  };
  
Shortcut to create Fireworks.EffectRandomDriftVelocity

  
  Fireworks.EffectsStackBuilder.prototype.lifeTime        = function(minAge, maxAge)
  {        
          // sanity check
          console.assert( minAge !== undefined )
          // if maxAge isnt 
          if( maxAge === undefined )        maxAge        = minAge;
          console.assert( maxAge !== undefined )
          // create the effect itself
          var emitter        = this._emitter;
          Fireworks.createEffect('lifeTime', {
                  minAge        : minAge,
                  maxAge        : maxAge
          }).onCreate(function(particle){
                  var data        = particle.set('lifeTime', {
                          curAge        : 0,
                          minAge        : 0,
                          maxAge        : 0,
                          normalizedAge        : function(){
                                  return (data.curAge - data.minAge) / (data.maxAge - data.minAge);
                          }
                  });
          }).onBirth(function(particle){
                  var lifeTime        = particle.get('lifeTime');
                  lifeTime.curAge        = 0;
                  lifeTime.maxAge        = this.opts.minAge + Math.random()*(this.opts.maxAge-this.opts.minAge);
          }).onUpdate(function(particle, deltaTime){
                  var lifeTime        = particle.get('lifeTime');
                  lifeTime.curAge        += deltaTime;
                  if( lifeTime.curAge > lifeTime.maxAge )        emitter.killParticle(particle);
          }).pushTo(this._emitter);
          // return this for chained API
          return this;
  };
  
Shortcut to create Fireworks.EffectRandomDriftVelocity

  
  Fireworks.EffectsStackBuilder.prototype.position        = function(shape)
  {
          console.assert( shape instanceof Fireworks.Shape );
          Fireworks.createEffect('position', {
                  shape        : shape
          }).onCreate(function(particle){
                  particle.set('position', {
                          vector        : new Fireworks.Vector()
                  });
          }).onBirth(function(particle){
                  var position        = particle.get('position').vector;
                  this.opts.shape.randomPoint(position)
          }).pushTo(this._emitter);
          return this;        // for chained API
  };
  
Shortcut to create Fireworks.EffectRandomDriftVelocity

  
  Fireworks.EffectsStackBuilder.prototype.radialVelocity        = function(minSpeed, maxSpeed)
  {
          Fireworks.createEffect('radialVelocity', {
                  minSpeed        : minSpeed,
                  maxSpeed        : maxSpeed        
          }).onCreate(function(particle){
                  particle.set('velocity', {
                          vector        : new Fireworks.Vector()
                  });
          }).onBirth(function(particle, deltaTime){
                  var position        = particle.get('position').vector;
                  var velocity        = particle.get('velocity').vector;
                  var length        = this.opts.minSpeed + (this.opts.maxSpeed - this.opts.minSpeed)*Math.random();
                  velocity.copy(position).setLength(length);
          }).onUpdate(function(particle, deltaTime){
                  var position        = particle.get('position').vector;
                  var velocity        = particle.get('velocity').vector;
                  position.x        += velocity.x * deltaTime;
                  position.y        += velocity.y * deltaTime;
                  position.z        += velocity.z * deltaTime;
          }).pushTo(this._emitter);
  
          return this;        // for chained API
  };
  
Shortcut to create Fireworks.EffectRandomDriftVelocity

  
  Fireworks.EffectsStackBuilder.prototype.randomVelocityDrift        = function(drift)
  {
          // create the effect itself
          Fireworks.createEffect('randomVelocityDrift', {
                  drift        : drift
          }).onUpdate(function(particle, deltaTime){
                  var velocity        = particle.get('velocity').vector;
                  velocity.x        += (Math.random()*2 - 1) * this.opts.drift.x * deltaTime;
                  velocity.y        += (Math.random()*2 - 1) * this.opts.drift.y * deltaTime;
                  velocity.z        += (Math.random()*2 - 1) * this.opts.drift.z * deltaTime;
          }).pushTo(this._emitter);
          // return for chained API
          return this;        // for chained API
  };
  
Create a velocity effect
parameter: {Fireworks.Shape} shape set the direction of the velocity by a randompoint in this shape
parameter: {Number?} speed set the speed itself. if undefined, keep randompoint length for speed

  
  Fireworks.EffectsStackBuilder.prototype.velocity        = function(shape, speed)
  {
          Fireworks.createEffect('velocity', {
                  shape        : shape, 
                  speed        : speed !== undefined ? speed : -1
          }).onCreate(function(particle){
                  particle.set('velocity', {
                          vector        : new Fireworks.Vector()
                  });
          }).onBirth(function(particle){
                  var velocity        = particle.get('velocity').vector;
                  this.opts.shape.randomPoint(velocity)
                  if( this.opts.speed !== -1 )        velocity.setLength(this.opts.speed);
          }).onUpdate(function(particle, deltaTime){
                  var position        = particle.get('position').vector;
                  var velocity        = particle.get('velocity').vector;
                  position.x        += velocity.x * deltaTime;
                  position.y        += velocity.y * deltaTime;
                  position.z        += velocity.z * deltaTime;
          }).pushTo(this._emitter);
  
          return this;        // for chained API
  };
  
Shortcut to create Fireworks.Shape.Box

  
  Fireworks.createShapeBox        = function(centerX, centerY, centerZ, sizeX, sizeY, sizeZ){
          var center        = new Fireworks.Vector(centerX, centerY, centerZ);
          var size        = new Fireworks.Vector(sizeX, sizeY, sizeZ);
          return new Fireworks.Shape.Box(center, size);
  };
  
  
Handle a Firework.Shape forming a sphere
parameter: {Fireworks.Vector} center the center of the sphape
parameter: {Fireworks.Vector} shape the size of the shape

  
  Fireworks.Shape.Box        = function(center, size)
  {
          this.center        = center;
          this.size        = size;
          this._vector        = new Fireworks.Vector();
  }
  
  // inherit from Fireworks.Effect
  Fireworks.Shape.Box.prototype = new Fireworks.Shape();
  Fireworks.Shape.Box.prototype.constructor = Fireworks.Shape.Box;
  
  Fireworks.Shape.Box.prototype.contains        = function(point){
          // compute delta between the point and the center
          var delta        = this._vector.sub(point, this.center);
          // test the delta is too far
          if( Math.abs(delta.x) > this.size.x/2 )        return false;
          if( Math.abs(delta.y) > this.size.y/2 )        return false;
          if( Math.abs(delta.z) > this.size.z/2 )        return false;
          // if all tests, passed true
          return true;
  }
  
  Fireworks.Shape.Box.prototype.randomPoint        = function(vector){
          var point        = vector        || this._vector;
          // get a random point
          point.x        = Math.random() * this.size.x - this.size.x/2;
          point.y        = Math.random() * this.size.y - this.size.y/2;
          point.z        = Math.random() * this.size.z - this.size.z/2;
          // add this.center
          point.addSelf(this.center);
          // return the point
          return point;
  }
  
Shortcut to create Fireworks.Shape.Point

  
  Fireworks.createShapePoint        = function(positionX, positionY, positionZ){
          var position        = new Fireworks.Vector(positionX, positionY, positionZ);
          return new Fireworks.Shape.Point(position);
  };
  
  
Handle a Firework.Shape forming a point
parameter: {Fireworks.Vector} position the position of the point

  
  Fireworks.Shape.Point        = function(position)
  {
          this.position        = position;
          this._vector        = new Fireworks.Vector();
  }
  
  // inherit from Fireworks.Effect
  Fireworks.Shape.Point.prototype = new Fireworks.Shape();
  Fireworks.Shape.Point.prototype.constructor = Fireworks.Shape.Point;
  
  Fireworks.Shape.Point.prototype.contains        = function(point){
          if( point.x !== this.position.x )        return false;
          if( point.y !== this.position.y )        return false;
          if( point.z !== this.position.z )        return false;
          // if all tests, passed true
          return true;
  }
  
  Fireworks.Shape.Point.prototype.randomPoint        = function(vector){
          var point        = vector        || this._vector;
          // get a random point
          point.copy(this.position);
          // return the point
          return point;
  }
  
Shortcut to create Fireworks.Shape.Box

  
  Fireworks.createShapeSphere        = function(centerX, centerY, centerZ, radius, boundingbox){
          var center        = new Fireworks.Vector(centerX, centerY, centerZ);
          return new Fireworks.ShapeSphere(center, radius);
  };
  
  
Handle a Firework.Shape forming a sphere
parameter: {Fireworks.Vector} center the center of the sphere
parameter: {Number} radius the radius of the sphere

  
  Fireworks.ShapeSphere        = function(center, radius)
  {
          this.center        = center;
          this.radius        = radius;
          this._vector        = new Fireworks.Vector();
  }
  
  // inherit from Fireworks.Effect
  Fireworks.ShapeSphere.prototype = new Fireworks.Shape();
  Fireworks.ShapeSphere.prototype.constructor = Fireworks.ShapeSphere;
  
  Fireworks.ShapeSphere.prototype.contains        = function(point){
          // compute distance between the point and the center
          var distance        = this._vector.sub(point, this.center).length();
          // return true if this distance is <= than sphere radius
          return distance <= this.radius;
  }
  
  Fireworks.ShapeSphere.prototype.randomPoint        = function(vector){
          var point        = vector        || this._vector;
          // get a random point
          point.x        = Math.random()-0.5;
          point.y        = Math.random()-0.5;
          point.z        = Math.random()-0.5;
          // compute the length between the point 
          var length        = Math.random()*this.radius;
          // set the point at the proper distance;
          point.setLength( length );
          // add the center
          point.addSelf(this.center);
          // return the point
          return point;
  }
  
Spawner deliverying paricles in one shot
parameter: {Number?} the number of particle to emit

  
  Fireworks.EffectsStackBuilder.prototype.spawnerOneShot        = function(nParticles)
  {
          // handle parameter polymorphism
          nParticles        = nParticles        || this.emitter().nParticles();
          // define local variables
          var emitter        = this.emitter();
          var nSent        = 0;
          var spawning        = true;
  
          // create the effect itself
          Fireworks.createEffect('spawner', {
                  start        : function(){ spawning = true;        },
                  stop        : function(){ spawning = false;        }
          }).onPreUpdate(function(deltaTime){
                  // if spawning is false, do nothing
                  if( spawning === false )        return;
                  // if already completed, do nothing
                  if( nParticles === nSent )        return;
                  // spawn each particle
                  var amount        = nParticles - nSent;
                  amount                = Math.min(amount, emitter.deadParticles().length);
                  for(var i = 0; i < amount; i++){
                          emitter.spawnParticle();
                  }
                  // update the amount of sent particles
                  nSent        += amount;
          }).pushTo(this._emitter);
          // return this for chained API
          return this;
  };
  
Spawner deliverying paricles at a steady rate
parameter: {Number?} rate the rate at which it gonna emit

  
  Fireworks.EffectsStackBuilder.prototype.spawnerSteadyRate        = function(rate)
  {
          // handle parameter polymorphism
          rate        = rate !== undefined ? rate        : 1;
          // define local variables
          var emitter        = this.emitter();
          var nToCreate        = 1;
          var spawning        = true;
          
          // create the effect itself
          Fireworks.createEffect('spawner', {
                  rate        : rate,
                  start        : function(){ spawning = true;        },
                  stop        : function(){ spawning = false;        }
          }).onPreUpdate(function(deltaTime){
                  var rate        = this.opts.rate;
                  // if spawning is false, do nothing
                  if( spawning === false )        return;
                  // update nToCreate
                  nToCreate        += rate * deltaTime;
                  // nParticles is the interger part of nToCreate as you spawn them one by one
                  var nParticles        = Math.floor(nToCreate);
                  // dont spawn more particles than available
                  // TODO here estimate how much more is needed to never lack of it
                  nParticles        = Math.min(nParticles, emitter.deadParticles().length);
                  // update nToCreate
                  nToCreate        -= nParticles;
                  // spawn each particle
                  for(var i = 0; i < nParticles; i++){
                          emitter.spawnParticle();
                  }
          }).pushTo(this._emitter);
          // return this for chained API
          return this;
  };
  
render to canvas

  
  Fireworks.EffectsStackBuilder.prototype.renderToCanvas        = function(opts)
  {
          opts        = opts                || {};
          var ctx        = opts.ctx        || buildDefaultContext();
          // create the effect itself
          var effect        = Fireworks.createEffect('renderToCanvas', {
                  ctx        : ctx
          }).pushTo(this._emitter);
  
          if( opts.type === 'arc' )                ctorTypeArc(effect);
          else if( opts.type === 'drawImage' )        ctorTypeDrawImage(effect);
          else{
                  console.assert(false, 'renderToCanvas opts.type is invalid: ');
          }
  
          return this;        // for chained API
          
  
          function buildDefaultContext(){
                  // build canvas element
                  var canvas        = document.createElement('canvas');
                  canvas.width        = window.innerWidth;
                  canvas.height        = window.innerHeight;
                  document.body.appendChild(canvas);
                  // canvas.style
                  canvas.style.position        = "absolute";
                  canvas.style.left        = 0;
                  canvas.style.top        = 0;
                  // setup ctx
                  var ctx                = canvas.getContext('2d');
                  // return ctx
                  return ctx;
          }
  
          function ctorTypeArc(){
                  return effect.onCreate(function(particle, particleIdx){
                          particle.set('renderToCanvas', {
                                  size        : 3
                          });
                  }).onRender(function(particle){
                          var position        = particle.get('position').vector;
                          var size        = particle.get('renderToCanvas').size;
  
                          ctx.beginPath();
                          ctx.arc(position.x + canvas.width /2, 
                                  position.y + canvas.height/2, size, 0, Math.PI*2, true); 
                          ctx.fill();                                        
                  });
          };
          function ctorTypeDrawImage(){
                  // handle parameter polymorphism
                  if( typeof(opts.image) === 'string' ){
                          var images        = [new Image];
                          images[0].src        = opts.image;
                  }else if( opts.image instanceof Image ){
                          var images        = [opts.image];
                  }else if( opts.image instanceof Array ){
                          var images        = opts.image;
                  }else        console.assert(false, 'invalid .renderToCanvas() options')
  
                  return effect.onCreate(function(particle, particleIdx){
                          particle.set('renderToCanvas', {
                                  scale                : 1,        // should that be there ? or in its own effect ?
                                  opacity                : 1,        // should that be there ? or in its own effect ?
                                  rotation        : 0*Math.PI
                          });
                  }).onRender(function(particle){
                          var position        = particle.get('position').vector;
                          var data        = particle.get('renderToCanvas');
                          var canonAge        = particle.get('lifeTime').normalizedAge();
                          var imageIdx        = Math.floor(canonAge * images.length);
                          var image        = images[imageIdx];
                          // save the context
                          ctx.save();
                          // translate in canvas's center, and the particle position
                          ctx.translate(position.x + canvas.width/2, position.y + canvas.height/2);
                          // set the scale of this particles
                          ctx.scale(data.scale, data.scale);
                          // set the rotation
                          ctx.rotate(data.rotation);
                          // set ctx.globalAlpha
                          ctx.globalAlpha        = data.opacity; 
                          // draw the image itself
                          if( image instanceof Image ){
                                  ctx.drawImage(image, -image.width/2, -image.height/2);                        
                          }else if( typeof(image) === 'object' ){
                                  ctx.drawImage(image.image
                                           ,  image.offsetX,  image.offsetY , image.width, image.height
                                          , -image.width/2, -image.height/2, image.width, image.height);
                          }else        console.assert(false);
                          // restore the context
                          ctx.restore();
                  });
          };
  };
  
render to three.js THREE.Object3D If i play with object3D.visible true/false instead of Object3D.add/remove i got a lot of artefacts

  
  Fireworks.EffectsStackBuilder.prototype.renderToThreejsObject3D        = function(opts)
  {
          var effectId        = opts.effectId        || 'renderToThreeParticleSystem';
          var container        = opts.container;
  
          // create the effect itself
          Fireworks.createEffect(effectId)
          .onCreate(function(particle, particleIdx){
                  particle.set('threejsObject3D', {
                          object3d        : opts.create()
                  });
                  console.assert(particle.get('threejsObject3D').object3d instanceof THREE.Object3D);
                  
                  var object3d        = particle.get('threejsObject3D').object3d;
  
  //                object3d.visible= false;
          }).onBirth(function(particle){
                  var object3d        = particle.get('threejsObject3D').object3d;
  //                object3d.visible= true;
  container.add(object3d);
          }).onDeath(function(particle){
                  var object3d        = particle.get('threejsObject3D').object3d;
  //                object3d.visible= false;
  container.remove(object3d);
          }).onRender(function(particle){
                  var object3d        = particle.get('threejsObject3D').object3d;
                  var position        = particle.get('position').vector;
                  object3d.position.set(position.x, position.y, position.z);
          }).pushTo(this._emitter);
          return this;        // for chained API
  };
  
render to three.js to THREE.ParticleSystem

  
  Fireworks.EffectsStackBuilder.prototype.renderToThreejsParticleSystem        = function(opts)
  {
          opts                        = opts                        || {};
          var effectId                = opts.effectId                || 'renderToThreejsParticleSystem';
          var particleSystem        = opts.particleSystem        || defaultParticleSystem;
          // if opts.particleSystem is a function, call it to create the particleSystem
          if( typeof(particleSystem) === 'function' )        particleSystem        = particleSystem(this._emitter);
          // sanity check
          console.assert(particleSystem instanceof THREE.ParticleSystem, "particleSystem MUST be THREE.ParticleSystem");
          // some aliases
          var geometry        = particleSystem.geometry;
          console.assert(geometry.vertices.length >= this._emitter.nParticles())
          // create the effect itself
          Fireworks.createEffect(effectId, {
                  particleSystem        : particleSystem
          }).onCreate(function(particle, particleIdx){
                  particle.set('threejsParticle', {
                          particleIdx        : particleIdx
                  });
                  var vertex        = geometry.vertices[particleIdx];
                  vertex.set(Infinity, Infinity, Infinity);
          }).onDeath(function(particle){
                  var particleIdx        = particle.get('threejsParticle').particleIdx;
                  var vertex        = geometry.vertices[particleIdx];
                  vertex.set(Infinity, Infinity, Infinity);
          }).onRender(function(particle){
                  var particleIdx        = particle.get('threejsParticle').particleIdx;
                  var vertex        = geometry.vertices[particleIdx];
                  var position        = particle.get('position').vector;
                  vertex.set(position.x, position.y, position.z);
          }).pushTo(this._emitter);
          return this;        // for chained API
  
  

/////////////////////////////////////////////////////////////////

// Internal Functions //

/////////////////////////////////////////////////////////////////

function defaultParticleSystem(emitter){ var geometry = new THREE.Geometry(); for( var i = 0; i < emitter.nParticles(); i++ ){ geometry.vertices.push( new THREE.Vector3() ); } var material = new THREE.ParticleBasicMaterial({ size : 5, sizeAttenuation : true, color : 0xE01B6A, map : generateTexture(), blending : THREE.AdditiveBlending, depthWrite : false, transparent : true }); var particleSystem = new THREE.ParticleSystem(geometry, material); particleSystem.dynamic = true; particleSystem.sortParticles = true; return particleSystem; } function generateTexture(size){ size = size || 128; var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( '2d' ); canvas.width = canvas.height = size; var gradient = context.createRadialGradient( canvas.width/2, canvas.height /2, 0, canvas.width /2, canvas.height /2, canvas.width /2 ); gradient.addColorStop( 0 , 'rgba(255,255,255,1)' ); gradient.addColorStop( 0.5, 'rgba(255,255,255,1)' ); gradient.addColorStop( 0.7, 'rgba(128,128,128,1)' ); gradient.addColorStop( 1 , 'rgba(0,0,0,1)' ); context.beginPath(); context.arc(size/2, size/2, size/2, 0, Math.PI*2, false); context.closePath(); context.fillStyle = gradient; //context.fillStyle = 'rgba(128,128,128,1)'; context.fill(); var texture = new THREE.Texture( canvas ); texture.needsUpdate = true; return texture; } }; Fireworks.Emitter.prototype.bindTriggerDomEvents = function(domElement){ var tmp = new Fireworks.BindTriggerDomEvents(this, domElement); return this; // for chained API } Fireworks.BindTriggerDomEvents = function(emitter, domElement){ this._domElement= domElement || document.body; // bind mouse event this._onMouseDown = function(){ emitter.effect('spawner').opts.start(); }; this._onMouseUp = function(){ emitter.effect('spawner').opts.stop(); }; this._domElement.addEventListener('mousedown' , this._onMouseDown ); this._domElement.addEventListener('mouseup' , this._onMouseUp ); // change emitter intensity on mousewheel this._onMouseWheel = function(event){ var intensity = emitter.intensity(); intensity += event.wheelDelta < 0 ? -0.05 : 0.05; intensity = Math.max(intensity, 0); intensity = Math.min(intensity, 1); emitter.intensity(intensity); }; this._domElement.addEventListener('mousewheel' , this._onMouseWheel ); } Fireworks.BindTriggerDomEvents.prototype.destroy = function(){ this._domElement.removeEventListener('mousedown' , this._onMouseDown ); this._domElement.removeEventListener('mouseup' , this._onMouseUp ); this._domElement.removeEventListener('mousewheel' , this._onMouseWheel ); }; Fireworks.DatGui4Emitter = function(emitter){ var gui = new dat.GUI(); var effects = emitter.effects(); effects.forEach(function(effect, idx){ var effectName = effect.name || "effect-"+idx; var opts = effect.opts || {}; var keys = Object.keys(opts).filter(function(key){ if( opts[key] instanceof Fireworks.Vector ) return true; if( typeof(opts[key]) === 'object' ) return false; return true; }); if( keys.length ){ var folder = gui.addFolder('Effect: '+effectName); keys.forEach(function(key){ if( opts[key] instanceof Fireworks.Vector ){ folder.add(opts[key], 'x').name(key+"X"); folder.add(opts[key], 'y').name(key+"Y"); folder.add(opts[key], 'z').name(key+"Z"); }else{ folder.add(opts, key); } }); } }); // return the built gui return gui; };Fireworks.ProceduralTextures = {}; Fireworks.ProceduralTextures.buildTexture = function(size) { size = size || 150; var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( '2d' ); canvas.width = canvas.height = size; var gradient = context.createRadialGradient( canvas.width/2, canvas.height /2, 0, canvas.width /2, canvas.height /2, canvas.width /2 ); gradient.addColorStop( 0 , 'rgba(255,255,255,1)' ); gradient.addColorStop( 0.5, 'rgba(255,255,255,1)' ); gradient.addColorStop( 0.7, 'rgba(128,128,128,1)' ); gradient.addColorStop( 1 , 'rgba(0,0,0,1)' ); context.beginPath(); context.arc(size/2, size/2, size/2, 0, Math.PI*2, false); context.closePath(); context.fillStyle = gradient; //context.fillStyle = 'rgba(128,128,128,1)'; context.fill(); var texture = new THREE.Texture( canvas ); texture.needsUpdate = true; return texture; }


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.