In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Particles3Dを使った・・キャプチャ上手く撮れたver

Partcles3Dライブラリを使ってみた。
* 
* 被写界深度によってパーティクルの色を変えれるっぽい
* さらに3Dオブジェクトみたいにマウスで回せる
*
Get Adobe Flash player
by selflash 03 Oct 2009
/**
 * Copyright selflash ( http://wonderfl.net/user/selflash )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iK0l
 */

/**
 * Partcles3Dライブラリを使ってみた。
 * 
 * 被写界深度によってパーティクルの色を変えれるっぽい
 * さらに3Dオブジェクトみたいにマウスで回せる
 * 
 */

/**
 * @author Dan Gries
 * www.dangries.com
 * djg@dangries.com
 * Prepared for www.flashandmath.com.
 * 
 * Last modified July 22, 2008.
 * 
 * Feel free to use and modify the classes in the package 
 * com.dangries.* to create your own Flash applications under the
 * following two conditions:
 * 
 * 1) If possible, please include a line acknowledging this work and the author
 * with your application in a way that is visible in your compiled file
 * or on your html page. 
 * 
 * 2) If you choose to modify the classes in the package 
 * com.dangries.*, put them into a package different from
 * the original. In this case too, please acknowledge this work
 * in a way visible to the user.
 */

package {
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.filters.BlurFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.events.MouseEvent;
	import flash.utils.Timer;
	
	// 本来ならいかのパッケージをimportする必要があるがwonderflでは対応して
	// いないのでこのソースの一番したにパッケージの中身をぶちまけてます。
	//import com.dangries.bitmapUtilities.*;
	//import com.dangries.objects.Particle3D;
	//import com.dangries.geom3D.*;
	//import com.dangries.display.*;
	
	import net.hires.debug.Stats;
	
	[SWF(width = "500", height = "500", backgroundColor = "#000000", frameRate = "60")]
	//========================================================================
	// ParticlesOrbitsクラス
	//========================================================================
	public class ParticlesOrbits extends Sprite {
		private var noiseMaker:NoiseParticleMaker;
		private var particles:Array/*noiseMaker.particleArray*/;		
		private var canvas:RotatingParticleBoard;
		private var canvasRect:Rectangle;
		private var p:Particle3D;
		private var i:int;//for文で使いまわす
		private var colorTransform:ColorTransform = new ColorTransform(.95, .95, .95, 0.8, 1, 1, 1, -2.5);	

		private const NUM_DESTINATIONS:Number = 2;		
		private const NUM_PARTICLES:Number = 8000;
		private const NUM_DISTANCE:Number = 100;
		
		//========================================================================
		// コンストラクタ
		//========================================================================
		public function ParticlesOrbits() {
		    Wonderfl.capture_delay( 30 );
			canvas = new RotatingParticleBoard(stage.stageWidth, stage.stageHeight, true, 0x00000000, 200);
			canvas.setDepthDarken(0, -50, 2);
			canvas.holder.x = stage.stageWidth / 2 - canvas.width / 2;
			canvas.holder.y = stage.stageHeight / 2 - canvas.height / 2;
			canvas.currentQ = new Quaternion(Math.cos(Math.PI / 12), Math.sin(Math.PI / 12) / Math.sqrt(2), 0, -Math.sin(Math.PI / 12) / Math.sqrt(2));
			canvas.autoQuaternion = new Quaternion(1, 0, 0, 0);
			canvas.arcballRad = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height) / 2;
			canvas.moveLightWithRecess = true;
			canvas.recess = NUM_DISTANCE;
			
			canvasRect = new Rectangle(0, 0, canvas.width, canvas.height);
			
			lightDistanceUpdate();
		
			noiseMaker = new NoiseParticleMaker(NUM_PARTICLES);
			noiseMaker.addEventListener(NoiseParticleMaker.PARTICLES_CREATED, onCreatedHandler);
			noiseMaker.createParticles();	
			
			
			addChild(new Stats());
		}		
		//========================================================================
		// パーティクルの準備が出来た?後に実行される処理
		//========================================================================
		private function onCreatedHandler(e:Event):void {
			particles = noiseMaker.particleArray;
			
			noiseMaker.buildDestinationArrays(NUM_DESTINATIONS);
			
			// 3パターン適当に
			var flg:Number = Math.random();
			if (flg >= 0 && flg < .3 ){
				setPositionsRandomCube();
			}else if (flg >= .3 && flg < .6) {
				setPositionsRandomSphere();
			}else if (flg >= .6 && flg < 10) {
				setPositionsRandomCylinder();
			};
			
			for (i = 0; i < particles.length; i++) {
				p = particles[i];
				p.x = p.dest[0].x;
				p.y = p.dest[0].y;
				p.z = p.dest[0].z;
				p.setColor(0xFFFFFF/*0xFF7EAAD6*/);
				
				var vx:Number = p.y * 0.02;
				var vy:Number = -p.x * 0.02;
				var vz:Number = 0;
				p.vel = new Point3D(vx, vy, vz);
			}
	
			stage.addChild(canvas.holder);
			
			var timer:Timer = new Timer(0);
			timer.addEventListener(TimerEvent.TIMER, loop);
			timer.start();
			
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);		
		}		
		//========================================================================
		// 被写界深度によって色を更新してるっぽい
		//========================================================================
		private function lightDistanceUpdate():void {
			var d:Number = Math.pow(0.01 * 33, 0.2);
			var d2:Number = 0.5 * Math.pow(Math.cos(d * Math.PI), 3) + 1;
			canvas.setDepthDarken(10, 64 - d2 * 200, 1);
		}	
		//========================================================================
		// loop
		//========================================================================
		private function loop(e:TimerEvent):void {
			var q:Number = (Math.random() - .5) * 2;
            var w:Number = (Math.random() - .5) * 2;
            var t:Number = (Math.random() - .5) * 2;
            colorTransform = new ColorTransform(q, w, t, 0.7, 0, 0, 0, -2.5);
			e.currentTarget.delay = Math.random() * 2000 + 500;	
		}
		//========================================================================
		// onEnterFrameHandler
		//========================================================================
		private function onEnterFrameHandler(e:Event):void {
			var scaledAccelFactor:Number = (1.33 + 1.33 * 2);			
			
			for (i = 0; i < particles.length; i++) {
				p = particles[i];
				var dSquared:Number = p.x * p.x + p.y * p.y + p.z * p.z;
				
				var ax:Number = -p.x / (0.000001 + dSquared);
				var ay:Number = -p.y / (0.000001 + dSquared);
				var az:Number = -p.z / (0.000001 + dSquared);
				
				p.vel.x = (p.vel.x + scaledAccelFactor * ax);
				p.vel.y = (p.vel.y + scaledAccelFactor * ay);
				p.vel.z = (p.vel.z + scaledAccelFactor * az);
				
				p.x += p.vel.x;
				p.y += p.vel.y;
				p.z += p.vel.z;
			}
			
			canvas.bitmapData.lock();
			canvas.bitmapData.colorTransform(canvasRect, colorTransform);			
			canvas.drawParticles(particles);
			canvas.bitmapData.unlock();
		}	
				
		//========================================================================
		// Cube
		//========================================================================
		private function setPositionsRandomCube():void {
			for (i = 0; i < particles.length; i++) {
				p = particles[i];
				var s1:Number = 1 * Math.floor(Math.random() * 2) - 1;
				var s2:Number = 1 * Math.random() - 1;
				var s3:Number = 1 * Math.random() - 1;
				var sArray:Array/*Number*/ = [s1, s2, s3];
				var shift:int = Math.floor(Math.random() * 3);				
				p.dest[0].x = 75 * sArray[shift];
				p.dest[0].y = 1000 * sArray[(shift + 1) % 3];
				p.dest[0].z = 15 * sArray[(shift + 2) % 3];
			}
		}		
		//========================================================================
		// Sphere
		//========================================================================
		private function setPositionsRandomSphere():void {
			for (i = 0; i < particles.length; i++) {
				p = particles[i];
				var theta:Number = Math.random() * Math.PI * 2;
				var phi:Number = Math.acos(2 * Math.random() - 1);
				p.dest[0].x = 100 * Math.sin(phi) * Math.sin(theta);
				p.dest[0].y = 500 * Math.sin(phi) * Math.sin(theta);
				p.dest[0].z = 70 * Math.sin(phi);
			}
		}		
		//========================================================================
		// Cylinder
		//========================================================================
		private function setPositionsRandomCylinder():void {
			for (i = 0; i < particles.length; i++) {
				p = particles[i];
				var theta:Number = Math.random() * 2 * Math.PI;
				p.dest[0].x = 400 * Math.sin(theta);
				p.dest[0].y = 70 * Math.cos(theta);
				p.dest[0].z = 70 * (2 * Math.random() - 1);
			}
		}
	}
}





//================================================================================
// これより下はライブラリの中身をそのままぶちまけてます
//
// @author Dan Gries
// www.dangries.com
// djg@dangries.com
// Prepared for www.flashandmath.com.
//
//================================================================================
    import flash.display.*;
	import flash.events.*;
	import flash.events.MouseEvent;
	import flash.text.*;
	
	class RotatingParticleBoard extends Bitmap {
		
		public var zBuffer:Array;
		
		public var fLen:Number;
		public var projOriginX:Number;
		public var projOriginY:Number;
		
		public var recess:Number;
		
		//darkening related variables
		private var useDepthDarken:Boolean;
		private var A:Number;
		private var expRate:Number;
		private var maxBrighten:Number;
		
		private var bgColor:Number;
		
		//Vars used in functions
		private var f:Number;
		private var m:Number;
		private var dColor:uint;
		private var intX:int;
		private var intY:int;
		private var p:Particle3D;
		private var X2:Number;
		private var Y2:Number;
		private var Z2:Number;
		private var wX:Number;
		private var wY:Number;
		private var wZ:Number;
		private var xX:Number;
		private var xY:Number;
		private var xZ:Number;
		private var yY:Number;
		private var yZ:Number;
		private var zZ:Number;
		
		public var frame:Shape;
		public var holder:Sprite;
		
		private var v1:Point3D;
		private var v2:Point3D;
		private var lastV:Point3D;
		private var rSquare:Number;
		private var invR:Number;
		
		private var mouseDragging:Boolean;
		private var lastQ:Quaternion;
		private var changeQ:Quaternion;
		private var requestQ:Quaternion;
		private var inside:Boolean;
		private var numRadii:Number;
		
		private var stepChangeQ:Quaternion;
		private var dV:Point3D;
		
		public var averagingSize:int;
		private var averagingArray:Array;
		private var qSum:Quaternion;
		
		public var arcballRad:Number;
		public var currentQ:Quaternion;
		public var autoQuaternion:Quaternion;
		
		public var moveLightWithRecess:Boolean;
		
		public var easingRatio:Number;
		
		private var s:Number;
		
		//Text box can be used to print parameters, etc., for testing purposes.
		//public var txtMonitor:TextField;
		
		public function RotatingParticleBoard(w:Number, h:Number, transp:Boolean = true, fillColor:Number = 0x00000000, _fLen:Number = 200) {			
			var thisData:BitmapData = new BitmapData(w, h, transp, fillColor);
			this.bitmapData = thisData;
			this.zBuffer = [];
			this.useDepthDarken = false; //changed to true in setDepthDarken
			this.projOriginX = w/2;
			this.projOriginY = h/2;
			this.fLen = _fLen;
			this.bgColor = fillColor;
			this.recess = 0;
			
			this.holder = new Sprite();
			this.holder.addChild(this);
			this.x = 0;
			this.y = 0;
			
			this.arcballRad = 0.5*Math.sqrt(Math.pow(w,2)+Math.pow(h,2));
			this.lastQ = new Quaternion();
			this.currentQ = new Quaternion(1,0,0,0);
			this.autoQuaternion = new Quaternion(1,0,0,0);
			this.requestQ = new Quaternion();
			this.changeQ = new Quaternion(1,0,0,0);
			
			this.stepChangeQ = new Quaternion();
			
			this.v1 = new Point3D();
			this.v2 = new Point3D();
			this.dV = new Point3D();
				
			this.mouseDragging = false;
			
			this.easingRatio = 0.4;
			
			this.averagingSize = 8;
			this.averagingArray = [];
			
			this.holder.addEventListener(Event.ADDED_TO_STAGE, addListeners);
			
			this.moveLightWithRecess = false;
			
			/*
			//FOR TESTING
			txtMonitor = new TextField();
			txtMonitor.autoSize = TextFieldAutoSize.LEFT;
			txtMonitor.x = 0;
			txtMonitor.y = h+25;
			txtMonitor.defaultTextFormat = new TextFormat("Arial",10,0xFFFFFF);
			txtMonitor.text = "testing";
			this.holder.addChild(txtMonitor);
			*/
			
		}
		
		private function addListeners(evt:Event):void {
			this.holder.removeEventListener(Event.ADDED_TO_STAGE, addListeners);
			this.holder.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
		}
		
		public function makeFrame(thick:Number, c:uint, inputAlpha:Number):void {
			this.frame = new Shape();
			this.frame.graphics.lineStyle(thick, c, inputAlpha);
			this.frame.graphics.drawRect(0,0,this.width,this.height);
			this.frame.x = 0;
			this.frame.y = 0;
			this.holder.addChild(frame);
		}
		
		public function setDepthDarken(unityDepth:Number, halfDepth:Number, _maxBrighten:Number):void {
			this.useDepthDarken = true;
			this.A = Math.pow(2, unityDepth/(halfDepth-unityDepth));
			this.expRate = Math.LN2/(unityDepth-halfDepth);
			this.maxBrighten = _maxBrighten;
		}
		
		public function clearBoard(particles:Array):void {
			for (var i:Number = 0; i<=particles.length-1; i++) {
				p = particles[i];
				if (p.onScreen) {
					intX = int(p.projX);
					intY = int(p.projY);
					zBuffer[intX+this.height*intY] = Number.NEGATIVE_INFINITY;
					
					//could also insert the code below to erase pixels,
					//but my method has been to use a blur filter and
					//a colorTransform applied to whole bitmap, which
					//creates "ghost" which fades out after a few frames.
					
					//this.bitmapData.setPixel32(intX, intY, bgColor);
				}
			}
		}//end of clearBoard

		public function drawParticles(particles:Array):void {
			
			clearBoard(particles);
			
			///////////
			//viewpoint change by mouse
			if (mouseDragging) {
				v2.x = (holder.mouseX-projOriginX)/arcballRad;
				v2.y = (holder.mouseY-projOriginY)/arcballRad;
				rSquare = v2.x*v2.x + v2.y*v2.y;
				//for mouse position outside Arcball perimeter:
				if (rSquare > 1) {
					invR = 1/Math.sqrt(rSquare);
					v2.x = v2.x*invR;
					v2.y = v2.y*invR;
					v2.z = 0;
				}
				//for mouse position inside Arcball perimeter:
				else {
					v2.z = Math.sqrt(1 - rSquare);
					inside = true;
				}
		
				//interpret mouse movement as request for rotation change
				requestQ.w = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
				requestQ.x = v1.y*v2.z - v2.y*v1.z;
				requestQ.y = -v1.x*v2.z + v2.x*v1.z;
				requestQ.z = v1.x*v2.y - v2.x*v1.y;
				
				//smooth movement is accomplished by rotating only 40% towards the 
				//requested rotation in each frame.  After about ten frames,
				//the rotation will be within 1% of the requested rotation.
				changeQ.w += easingRatio*(requestQ.w - changeQ.w);
				changeQ.x += easingRatio*(requestQ.x - changeQ.x);
				changeQ.y += easingRatio*(requestQ.y - changeQ.y);
				changeQ.z += easingRatio*(requestQ.z - changeQ.z);
				//ensure that the change quaternion is a unit quaternion:
				s = 1/Math.sqrt(changeQ.w*changeQ.w +changeQ.x*changeQ.x+changeQ.y*changeQ.y+changeQ.z*changeQ.z);
				changeQ.w *= s;
				changeQ.x *= s;
				changeQ.y *= s;
				changeQ.z *= s;				
				
				//tracking each rotation to determine auto rotation after mouse up:
				
				//determine last movement
				stepChangeQ.w = lastV.x*v2.x + lastV.y*v2.y + lastV.z*v2.z;
				stepChangeQ.x = lastV.y*v2.z - v2.y*lastV.z;
				stepChangeQ.y = -lastV.x*v2.z + v2.x*lastV.z;
				stepChangeQ.z = lastV.x*v2.y - v2.x*lastV.y;
				//stepChangeQ = stepChangeQ.normalize();
				
				lastV = v2.clone();
				
				averagingArray.push(stepChangeQ);
				
				if (averagingArray.length > averagingSize) {
					averagingArray.splice(0,1);
				}
				
				//TESTING:
				//txtMonitor.text = stepChangeQ.toString(4);
				//txtMonitor.appendText("  "+qSum.toString(4));
			}
			
			else {
				lastQ = currentQ.clone();
				changeQ.w = autoQuaternion.w;
				changeQ.x = autoQuaternion.x;
				changeQ.y = autoQuaternion.y;
				changeQ.z = autoQuaternion.z;
			}
			
			//find current resultant rotation by quaternion multiplication
			//of lastQ and changeQ	
			currentQ.w = changeQ.w*lastQ.w - changeQ.x*lastQ.x - changeQ.y*lastQ.y - changeQ.z*lastQ.z;
			currentQ.x = changeQ.w*lastQ.x + lastQ.w*changeQ.x + changeQ.y*lastQ.z - lastQ.y*changeQ.z;
			currentQ.y = changeQ.w*lastQ.y + lastQ.w*changeQ.y - changeQ.x*lastQ.z + lastQ.x*changeQ.z;
			currentQ.z = changeQ.w*lastQ.z + lastQ.w*changeQ.z + changeQ.x*lastQ.y - lastQ.x*changeQ.y;
			
			
			///////////
			for (var i:Number = 0; i<=particles.length-1; i++) {
				p = particles[i];
				
				//viewpoint-relative coordinates found by quaternion rotation.
				//Quaternion has been converted to rotation matrix, using
				//common subexpressions for efficiency.
				//(Efficient algorithm found on Wikipedia!)
				
				X2 = 2*currentQ.x;
				Y2 = 2*currentQ.y;
				Z2 = 2*currentQ.z;
				wX = currentQ.w*X2;
				wY = currentQ.w*Y2;
				wZ = currentQ.w*Z2;
				xX = currentQ.x*X2;
				xY = currentQ.x*Y2;
				xZ = currentQ.x*Z2;
				yY = currentQ.y*Y2;
				yZ = currentQ.y*Z2;
				zZ = currentQ.z*Z2;
				
				p.u = (1-(yY+zZ))*p.x + (xY-wZ)*p.y + (xZ+wY)*p.z;
				p.v = (xY+wZ)*p.x + (1-(xX+zZ))*p.y + (yZ-wX)*p.z;
				p.w = (xZ-wY)*p.x + (yZ+wX)*p.y + (1-(xX+yY))*p.z - recess;
				
				//Projection coordinates
				m = fLen/(fLen - p.w);
				p.projX = p.u*m + projOriginX;
				p.projY = p.v*m + projOriginY;
				
				//test if particle is in viewable region
				if ((p.projX > this.width)||(p.projX<0)||(p.projY<0)||(p.projY>this.height)||(p.w>fLen-1)) {
					p.onScreen = false;
				}
				else {
					p.onScreen = true;
				}
				
				//drawing
				intX = int(p.projX);
				intY = int(p.projY);
				if (p.onScreen) {
					if (!(p.w < zBuffer[intX+this.height*intY])) {
						if (this.useDepthDarken) {
							//position-based darkening - exponential
							if (moveLightWithRecess) {
								f = A*Math.exp(expRate*(p.w+recess));
							}
							else {
								f = A*Math.exp(expRate*(p.w));
							}
							if (f>maxBrighten) {
								f = maxBrighten;
							}
							dColor = (0xFF000000) |(Math.min(255,f*p.red) << 16) | (Math.min(255,f*p.green) << 8) | (Math.min(255,f*p.blue));
							this.bitmapData.setPixel32(intX, intY, dColor);
						}
						else {
							this.bitmapData.setPixel32(intX, intY, p.color);
						}
												
						this.zBuffer[intX+this.height*intY] = p.w;
					}
				}
			}
		}//end of drawParticles
		
		private function onDown(evt:MouseEvent):void {
			this.holder.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);
			this.holder.root.addEventListener(MouseEvent.MOUSE_UP, onUp);
			mouseDragging = true;
			changeQ = new Quaternion(1,0,0,0);
			qSum = new Quaternion(0,0,0,0);
			averagingArray = [qSum];
			lastQ = currentQ.clone();
			v1.x = (holder.mouseX-projOriginX)/arcballRad;
			v1.y = (holder.mouseY-projOriginY)/arcballRad;
			rSquare = v1.x*v1.x + v1.y*v1.y;
			if (rSquare > 1) {
				invR = 1/Math.sqrt(rSquare);
				v1.x = v1.x*invR;
				v1.y = v1.y*invR;
				v1.z = 0;
				inside = false;
			}
			else {
				v1.z = Math.sqrt(1 - rSquare);
				inside = true;
			}
			lastV = v1.clone();
		}
		
		private function onUp(evt:MouseEvent):void {
			this.holder.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
			this.holder.root.removeEventListener(MouseEvent.MOUSE_UP, onUp);
			mouseDragging = false;
			if (averagingArray.length>0) {
				qSum = new Quaternion(0,0,0,0);
				for (var t:Number = 0; t<= averagingArray.length-1; t++) {
					qSum = qSum.add(averagingArray[t]);
				}
				if (qSum.magnitudeSquare() != 0) {
					autoQuaternion = qSum.normalize();
				}
				//else {
					//autoQuaternion = new Quaternion(1,0,0,0);
				//}
			}
			//TESTING:
			//txtMonitor.text =averagingArray.length.toString();
		}
		
	}//end of class definition


	import flash.display.*;
	class Particle3D {
		
		public var x:Number;
		public var y:Number;
		public var z:Number;		
		
		private var outputPoint:Point3D;
		
		//links, for creating linked lists
		public var next:Particle3D;
		public var prev:Particle3D;
		
		public var onScreen:Boolean;
		
		//velocity and acceleration vectors
		public var vel:Point3D = new Point3D();
		public var accel:Point3D = new Point3D();
		
		public var lastX:Number;
		public var lastY:Number;
		public var lastZ:Number;
		
		//projected coordinates
		public var projX:Number;
		public var projY:Number;
		
		//coords WRT viewpoint axes
		public var u:Number;
		public var v:Number;
		public var w:Number;
		
		//location in source picture
		public var picX:Number;
		public var picY:Number;
		
		//destination array
		public var dest:Array;
		
		//attributes
		public var color:uint;
		public var red:Number;
		public var green:Number;
		public var blue:Number;
		public var lum:Number;
		public var alpha:Number;
		
		public var initColor:uint;
		public var initRed:Number;
		public var initGreen:Number;
		public var initBlue:Number;
		public var initLum:Number;
		
		public var destColor:uint;
		public var destRed:Number;
		public var destGreen:Number;
		public var destBlue:Number;
		public var destLum:Number;
				
		public var colorChanging:Boolean;
		
		function Particle3D(thisColor:Number = 0xFFFFFFFF):void {
			this.dest = [];
			this.color = thisColor;
			this.red = getRed(thisColor);
			this.green = getGreen(thisColor);
			this.blue = getBlue(thisColor);
			this.alpha = getAlpha(thisColor);
			this.lum = 0.2126*this.red + 0.7152*this.green + 0.0722*this.blue;
			this.colorChanging = false;
			this.onScreen = true;
		}
		
		public function setColor(thisColor:Number):void {
			this.color = thisColor;
			this.red = getRed(thisColor);
			this.green = getGreen(thisColor);
			this.blue = getBlue(thisColor);
			this.alpha = getAlpha(thisColor);
			this.lum = 0.2126*this.red + 0.7152*this.green + 0.0722*this.blue;
		}
		
		public function getAlpha(c:Number):Number {
			return Number((c >> 24) & 0xFF);
		}
		public function getRed(c:Number):Number {
			return Number((c >> 16) & 0xFF);
		}
		public function getGreen(c:Number):Number {
			return Number((c >> 8) & 0xFF);
		}
		public function getBlue(c:Number):Number {
			return Number(c & 0xFF);
		}
	}


	import flash.display.*;
	import flash.events.*;
	class NoiseParticleMaker extends EventDispatcher {
		
		public static const PARTICLES_CREATED:String="particlesCreated";
		
		private var _particleArray:Array;
		public var numParticles:Number;
		
		public function NoiseParticleMaker(num:Number):void {
			this._particleArray = [];
			this.numParticles = num;
		}

		public function createParticles():void {
			var c:uint;
			var r:Number;
			var g:Number;
			var b:Number;
			for (var i:Number=0; i<=numParticles-1; i++) {
				r = Math.random()*255;
				g = Math.random()*255;
				b = Math.random()*255;
				c = uint(0xFF000000 | int(r) << 16 | int(g) << 8 | int(b));
				var p:Particle3D = new Particle3D(c);
				//add to array			
				this.particleArray.push(p);
			}
			dispatchEvent(new Event(NoiseParticleMaker.PARTICLES_CREATED));
		}
				
		public function setGlobalAlpha(globalAlpha:Number):void {
			var c:uint;
			var p:Particle3D;
			trace(_particleArray.length);
			for (var t:int=0; t<= _particleArray.length - 1; t++) {
				p = _particleArray[t];
				p.setColor((uint(255*globalAlpha) << 24) | (p.color & 0x00FFFFFF));
			}
		}
		
		public function buildDestinationArrays(numDestinations:Number):void {
			var p:Particle3D;
			for (var t:int=0; t<= _particleArray.length - 1; t++) {
				p = _particleArray[t];
				for (var n:Number = 0; n <= numDestinations-1; n++) {
					var thisPoint3D:Point3D = new Point3D();
					p.dest.push(thisPoint3D);
				}
			}
		}
		
		public function get particleArray():Array {
			return _particleArray;
		}
		
	}

	class Quaternion {
		public var w:Number;
		public var x:Number;
		public var y:Number;
		public var z:Number;
		
		private var qOutput:Quaternion;
		
		public function Quaternion(_w:Number=0,_x:Number=0, _y:Number=0, _z:Number=0) {
			this.w = _w;
			this.x = _x;
			this.y = _y;
			this.z = _z;
		}
		
		public function clone():Quaternion {
			return new Quaternion(this.w, this.x, this.y, this.z);
		}
		
		public function add(q:Quaternion):Quaternion {
			qOutput = new Quaternion()
			qOutput.w = this.w + q.w;
			qOutput.x = this.x + q.x;
			qOutput.y = this.y + q.y;
			qOutput.z = this.z + q.z;
			return qOutput;
		}
		
		public function subtract(q:Quaternion):Quaternion {
			qOutput = new Quaternion()
			qOutput.w = this.w - q.w;
			qOutput.x = this.x - q.x;
			qOutput.y = this.y - q.y;
			qOutput.z = this.z - q.z;
			return qOutput;
		}
		
		public function normalize():Quaternion {
			qOutput = new Quaternion()
			var mag:Number = Math.sqrt(this.w*this.w + this.x*this.x + this.y*this.y + this.z*this.z);
			qOutput.w = this.w/mag;
			qOutput.x = this.x/mag;
			qOutput.y = this.y/mag;
			qOutput.z = this.z/mag;
			return qOutput;
		}
		
		public function magnitudeSquare():Number {
			return this.w*this.w + this.x*this.x + this.y*this.y +this.z*this.z;
		}
		
		public function toString(radix:int):String {
			return "(" + this.w.toFixed(radix) + ", " + this.x.toFixed(radix) + ", " + this.y.toFixed(radix) + ", " + this.z.toFixed(radix) + ")";
		}

	}

	class Point3D {
		
		public var x:Number;
		public var y:Number;
		public var z:Number;		
		
		private var outputPoint:Point3D;
		
		public function Point3D(x1:Number=0,y1:Number=0,z1:Number=0):void {
			this.x = x1;
			this.y = y1;
			this.z = z1;
		}
		
		public function clone():Point3D {
			outputPoint = new Point3D();
			outputPoint.x = this.x;
			outputPoint.y = this.y;
			outputPoint.z = this.z;
			return outputPoint;
		}
	}