Browse Source

Very basic example for RTT feature.

Szymon Nowak 14 years ago
parent
commit
868cab1e98
3 changed files with 5195 additions and 201 deletions
  1. 0 201
      build/ThreeExtras.js
  2. 5046 0
      build/ThreeWebGL.js
  3. 149 0
      examples/render_to_texture.html

File diff suppressed because it is too large
+ 0 - 201
build/ThreeExtras.js


+ 5046 - 0
build/ThreeWebGL.js

@@ -0,0 +1,5046 @@
+// ThreeWebGL.js r32 - http://github.com/mrdoob/three.js
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+var THREE = THREE || {};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Color = function ( hex ) {
+
+	this.autoUpdate = true;
+	this.setHex( hex );
+
+};
+
+THREE.Color.prototype = {
+
+	setRGB: function ( r, g, b ) {
+
+		this.r = r;
+		this.g = g;
+		this.b = b;
+
+		if ( this.autoUpdate ) {
+
+			this.updateHex();
+			this.updateStyleString();
+
+		}
+
+	},
+
+	setHex: function ( hex ) {
+
+		this.hex = ( ~~ hex ) & 0xffffff;
+
+		if ( this.autoUpdate ) {
+
+			this.updateRGBA();
+			this.updateStyleString();
+
+		}
+
+	},
+
+	updateHex: function () {
+
+		this.hex = ~~( this.r * 255 ) << 16 ^ ~~( this.g * 255 ) << 8 ^ ~~( this.b * 255 );
+
+	},
+
+	updateRGBA: function () {
+
+		this.r = ( this.hex >> 16 & 255 ) / 255;
+		this.g = ( this.hex >> 8 & 255 ) / 255;
+		this.b = ( this.hex & 255 ) / 255;
+
+	},
+
+	updateStyleString: function () {
+
+		this.__styleString = 'rgb(' + ~~( this.r * 255 ) + ',' + ~~( this.g * 255 ) + ',' + ~~( this.b * 255 ) + ')';
+
+	},
+
+	clone: function () {
+
+		return new THREE.Color( this.hex );
+
+	},
+
+
+	toString: function () {
+
+		return 'THREE.Color ( r: ' + this.r + ', g: ' + this.g + ', b: ' + this.b + ', hex: ' + this.hex + ' )';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author philogb / http://blog.thejit.org/
+ */
+
+THREE.Vector2 = function ( x, y ) {
+
+	this.x = x || 0;
+	this.y = y || 0;
+
+};
+
+THREE.Vector2.prototype = {
+
+	set: function ( x, y ) {
+
+		this.x = x;
+		this.y = y;
+
+		return this;
+
+	},
+
+	copy: function ( v ) {
+
+		this.x = v.x;
+		this.y = v.y;
+
+		return this;
+
+	},
+
+	addSelf: function ( v ) {
+
+		this.x += v.x;
+		this.y += v.y;
+
+		return this;
+
+	},
+
+	add: function ( v1, v2 ) {
+
+		this.x = v1.x + v2.x;
+		this.y = v1.y + v2.y;
+
+		return this;
+
+	},
+
+	subSelf: function ( v ) {
+
+		this.x -= v.x;
+		this.y -= v.y;
+
+		return this;
+
+	},
+
+	sub: function ( v1, v2 ) {
+
+		this.x = v1.x - v2.x;
+		this.y = v1.y - v2.y;
+
+		return this;
+
+	},
+
+	multiplyScalar: function ( s ) {
+
+		this.x *= s;
+		this.y *= s;
+
+		return this;
+
+	},
+
+	unit: function () {
+
+		this.multiplyScalar( 1 / this.length() );
+
+		return this;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this.x * this.x + this.y * this.y );
+
+	},
+
+	lengthSq: function () {
+
+		return this.x * this.x + this.y * this.y;
+
+	},
+
+	negate: function() {
+
+		this.x = - this.x;
+		this.y = - this.y;
+
+		return this;
+
+	},
+
+	clone: function () {
+
+		return new THREE.Vector2( this.x, this.y );
+
+	},
+
+	toString: function () {
+
+		return 'THREE.Vector2 (' + this.x + ', ' + this.y + ')';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author kile / http://kile.stravaganza.org/
+ * @author philogb / http://blog.thejit.org/
+ */
+
+THREE.Vector3 = function ( x, y, z ) {
+
+	this.x = x || 0;
+	this.y = y || 0;
+	this.z = z || 0;
+
+};
+
+THREE.Vector3.prototype = {
+
+	set: function ( x, y, z ) {
+
+		this.x = x;
+		this.y = y;
+		this.z = z;
+
+		return this;
+
+	},
+
+	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;
+
+	},
+
+	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 tx = this.x, ty = this.y, tz = this.z;
+
+		this.x = ty * v.z - tz * v.y;
+		this.y = tz * v.x - tx * v.z;
+		this.z = tx * v.y - ty * v.x;
+
+		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 ) {
+
+		this.x /= s;
+		this.y /= s;
+		this.z /= s;
+
+		return this;
+
+	},
+
+	dot: function ( v ) {
+
+		return this.x * v.x + this.y * v.y + this.z * v.z;
+
+	},
+
+	distanceTo: function ( v ) {
+
+		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
+		return Math.sqrt( dx * dx + dy * dy + dz * dz );
+
+	},
+
+	distanceToSquared: function ( v ) {
+
+		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
+		return dx * dx + dy * dy + dz * dz;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
+
+	},
+
+	lengthSq: function () {
+
+		return this.x * this.x + this.y * this.y + this.z * this.z;
+
+	},
+
+	negate: function () {
+
+		this.x = - this.x;
+		this.y = - this.y;
+		this.z = - this.z;
+
+		return this;
+
+	},
+
+	normalize: function () {
+
+		var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
+
+		length > 0 ? this.multiplyScalar( 1 / length ) : this.set( 0, 0, 0 );
+
+		return this;
+
+	},
+
+	setLength: function( len ) {
+
+		return this.normalize().multiplyScalar( len );
+
+	},
+
+	isZero: function () {
+
+		var almostZero = 0.0001;
+		return ( Math.abs( this.x ) < almostZero ) && ( Math.abs( this.y ) < almostZero ) && ( Math.abs( this.z ) < almostZero );
+
+	},
+
+	clone: function () {
+
+		return new THREE.Vector3( this.x, this.y, this.z );
+
+	},
+
+	toString: function () {
+
+		return 'THREE.Vector3 ( ' + this.x + ', ' + this.y + ', ' + this.z + ' )';
+
+	}
+
+};
+/**
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author philogb / http://blog.thejit.org/
+ */
+
+THREE.Vector4 = function ( x, y, z, w ) {
+
+	this.x = x || 0;
+	this.y = y || 0;
+	this.z = z || 0;
+	this.w = w || 1;
+
+};
+
+THREE.Vector4.prototype = {
+
+	set: function ( x, y, z, w ) {
+
+		this.x = x;
+		this.y = y;
+		this.z = z;
+		this.w = w;
+
+		return this;
+
+	},
+
+	copy: function ( v ) {
+
+		this.x = v.x;
+		this.y = v.y;
+		this.z = v.z;
+		this.w = v.w || 1.0;
+
+		return this;
+
+	},
+
+	add: function ( v1, v2 ) {
+
+		this.x = v1.x + v2.x;
+		this.y = v1.y + v2.y;
+		this.z = v1.z + v2.z;
+		this.w = v1.w + v2.w;
+
+		return this;
+
+	},
+
+	addSelf: function ( v ) {
+
+		this.x += v.x;
+		this.y += v.y;
+		this.z += v.z;
+		this.w += v.w;
+
+		return this;
+
+	},
+
+	sub: function ( v1, v2 ) {
+
+		this.x = v1.x - v2.x;
+		this.y = v1.y - v2.y;
+		this.z = v1.z - v2.z;
+		this.w = v1.w - v2.w;
+
+		return this;
+
+	},
+
+	subSelf: function ( v ) {
+
+		this.x -= v.x;
+		this.y -= v.y;
+		this.z -= v.z;
+		this.w -= v.w;
+
+		return this;
+
+	},
+
+	multiplyScalar: function ( s ) {
+
+		this.x *= s;
+		this.y *= s;
+		this.z *= s;
+		this.w *= s;
+
+		return this;
+
+	},
+
+	divideScalar: function ( s ) {
+
+		this.x /= s;
+		this.y /= s;
+		this.z /= s;
+		this.w /= s;
+
+		return this;
+
+	},
+
+	lerpSelf: function ( v, alpha ) {
+
+		this.x = this.x + (v.x - this.x) * alpha;
+		this.y = this.y + (v.y - this.y) * alpha;
+		this.z = this.z + (v.z - this.z) * alpha;
+		this.w = this.w + (v.w - this.w) * alpha;
+	},
+
+	clone: function () {
+
+		return new THREE.Vector4( this.x, this.y, this.z, this.w );
+
+	},
+
+	toString: function () {
+
+		return 'THREE.Vector4 (' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Ray = function ( origin, direction ) {
+
+	this.origin = origin || new THREE.Vector3();
+	this.direction = direction || new THREE.Vector3();
+
+}
+
+THREE.Ray.prototype = {
+
+	intersectScene: function ( scene ) {
+
+		var i, l, object,
+		objects = scene.objects,
+		intersects = [];
+
+		for ( i = 0, l = objects.length; i < l; i++ ) {
+
+			object = objects[i];
+
+			if ( object instanceof THREE.Mesh ) {
+
+				intersects = intersects.concat( this.intersectObject( object ) );
+
+			}
+
+		}
+
+		intersects.sort( function ( a, b ) { return a.distance - b.distance; } );
+
+		return intersects;
+
+	},
+
+	intersectObject: function ( object ) {
+
+		var f, fl, face, a, b, c, d, normal,
+		dot, scalar,
+		origin, direction,
+		geometry = object.geometry,
+		vertices = geometry.vertices,
+		intersect, intersects = [],
+		intersectPoint;
+
+		for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
+
+			face = geometry.faces[ f ];
+
+			origin = this.origin.clone();
+			direction = this.direction.clone();
+
+			a = object.matrix.multiplyVector3( vertices[ face.a ].position.clone() );
+			b = object.matrix.multiplyVector3( vertices[ face.b ].position.clone() );
+			c = object.matrix.multiplyVector3( vertices[ face.c ].position.clone() );
+			d = face instanceof THREE.Face4 ? object.matrix.multiplyVector3( vertices[ face.d ].position.clone() ) : null;
+
+			normal = object.rotationMatrix.multiplyVector3( face.normal.clone() );
+			dot = direction.dot( normal );
+
+			if ( dot < 0 ) { // Math.abs( dot ) > 0.0001
+
+				scalar = normal.dot( new THREE.Vector3().sub( a, origin ) ) / dot;
+				intersectPoint = origin.addSelf( direction.multiplyScalar( scalar ) );
+
+				if ( face instanceof THREE.Face3 ) {
+
+					if ( pointInFace3( intersectPoint, a, b, c ) ) {
+
+						intersect = {
+
+							distance: this.origin.distanceTo( intersectPoint ),
+							point: intersectPoint,
+							face: face,
+							object: object
+
+						};
+
+						intersects.push( intersect );
+
+					}
+
+				} else if ( face instanceof THREE.Face4 ) {
+
+					if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) {
+
+						intersect = {
+
+							distance: this.origin.distanceTo( intersectPoint ),
+							point: intersectPoint,
+							face: face,
+							object: object
+
+						};
+
+						intersects.push( intersect );
+
+					}
+
+				}
+
+			}
+
+		}
+
+		return intersects;
+
+		// http://www.blackpawn.com/texts/pointinpoly/default.html
+
+		function pointInFace3( p, a, b, c ) {
+
+			var v0 = c.clone().subSelf( a ), v1 = b.clone().subSelf( a ), v2 = p.clone().subSelf( a ),
+			dot00 = v0.dot( v0 ), dot01 = v0.dot( v1 ), dot02 = v0.dot( v2 ), dot11 = v1.dot( v1 ), dot12 = v1.dot( v2 ),
+
+			invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 ),
+			u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom,
+			v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+
+			return ( u > 0 ) && ( v > 0 ) && ( u + v < 1 );
+
+		}
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Rectangle = function () {
+
+	var _left, _top, _right, _bottom,
+	_width, _height, _isEmpty = true;
+
+	function resize() {
+
+		_width = _right - _left;
+		_height = _bottom - _top;
+
+	}
+
+	this.getX = function () {
+
+		return _left;
+
+	};
+
+	this.getY = function () {
+
+		return _top;
+
+	};
+
+	this.getWidth = function () {
+
+		return _width;
+
+	};
+
+	this.getHeight = function () {
+
+		return _height;
+
+	};
+
+	this.getLeft = function() {
+
+		return _left;
+
+	};
+
+	this.getTop = function() {
+
+		return _top;
+
+	};
+
+	this.getRight = function() {
+
+		return _right;
+
+	};
+
+	this.getBottom = function() {
+
+		return _bottom;
+
+	};
+
+	this.set = function ( left, top, right, bottom ) {
+
+		_isEmpty = false;
+
+		_left = left; _top = top;
+		_right = right; _bottom = bottom;
+
+		resize();
+
+	};
+
+	this.addPoint = function ( x, y ) {
+
+		if ( _isEmpty ) {
+
+			_isEmpty = false;
+			_left = x; _top = y;
+			_right = x; _bottom = y;
+
+			resize();
+
+		} else {
+
+			_left = _left < x ? _left : x; // Math.min( _left, x );
+			_top = _top < y ? _top : y; // Math.min( _top, y );
+			_right = _right > x ? _right : x; // Math.max( _right, x );
+			_bottom = _bottom > y ? _bottom : y; // Math.max( _bottom, y );
+
+			resize();
+		}
+
+	};
+
+	this.add3Points = function ( x1, y1, x2, y2, x3, y3 ) {
+
+		if (_isEmpty) {
+
+			_isEmpty = false;
+			_left = x1 < x2 ? ( x1 < x3 ? x1 : x3 ) : ( x2 < x3 ? x2 : x3 );
+			_top = y1 < y2 ? ( y1 < y3 ? y1 : y3 ) : ( y2 < y3 ? y2 : y3 );
+			_right = x1 > x2 ? ( x1 > x3 ? x1 : x3 ) : ( x2 > x3 ? x2 : x3 );
+			_bottom = y1 > y2 ? ( y1 > y3 ? y1 : y3 ) : ( y2 > y3 ? y2 : y3 );
+
+			resize();
+
+		} else {
+
+			_left = x1 < x2 ? ( x1 < x3 ? ( x1 < _left ? x1 : _left ) : ( x3 < _left ? x3 : _left ) ) : ( x2 < x3 ? ( x2 < _left ? x2 : _left ) : ( x3 < _left ? x3 : _left ) );
+			_top = y1 < y2 ? ( y1 < y3 ? ( y1 < _top ? y1 : _top ) : ( y3 < _top ? y3 : _top ) ) : ( y2 < y3 ? ( y2 < _top ? y2 : _top ) : ( y3 < _top ? y3 : _top ) );
+			_right = x1 > x2 ? ( x1 > x3 ? ( x1 > _right ? x1 : _right ) : ( x3 > _right ? x3 : _right ) ) : ( x2 > x3 ? ( x2 > _right ? x2 : _right ) : ( x3 > _right ? x3 : _right ) );
+			_bottom = y1 > y2 ? ( y1 > y3 ? ( y1 > _bottom ? y1 : _bottom ) : ( y3 > _bottom ? y3 : _bottom ) ) : ( y2 > y3 ? ( y2 > _bottom ? y2 : _bottom ) : ( y3 > _bottom ? y3 : _bottom ) );
+
+			resize();
+
+		};
+
+	};
+
+	this.addRectangle = function ( r ) {
+
+		if ( _isEmpty ) {
+
+			_isEmpty = false;
+			_left = r.getLeft(); _top = r.getTop();
+			_right = r.getRight(); _bottom = r.getBottom();
+
+			resize();
+
+		} else {
+
+			_left = _left < r.getLeft() ? _left : r.getLeft(); // Math.min(_left, r.getLeft() );
+			_top = _top < r.getTop() ? _top : r.getTop(); // Math.min(_top, r.getTop() );
+			_right = _right > r.getRight() ? _right : r.getRight(); // Math.max(_right, r.getRight() );
+			_bottom = _bottom > r.getBottom() ? _bottom : r.getBottom(); // Math.max(_bottom, r.getBottom() );
+
+			resize();
+
+		}
+
+	};
+
+	this.inflate = function ( v ) {
+
+		_left -= v; _top -= v;
+		_right += v; _bottom += v;
+
+		resize();
+
+	};
+
+	this.minSelf = function ( r ) {
+
+		_left = _left > r.getLeft() ? _left : r.getLeft(); // Math.max( _left, r.getLeft() );
+		_top = _top > r.getTop() ? _top : r.getTop(); // Math.max( _top, r.getTop() );
+		_right = _right < r.getRight() ? _right : r.getRight(); // Math.min( _right, r.getRight() );
+		_bottom = _bottom < r.getBottom() ? _bottom : r.getBottom(); // Math.min( _bottom, r.getBottom() );
+
+		resize();
+
+	};
+
+	/*
+	this.contains = function ( x, y ) {
+
+		return x > _left && x < _right && y > _top && y < _bottom;
+
+	};
+	*/
+
+	this.instersects = function ( r ) {
+
+		// return this.contains( r.getLeft(), r.getTop() ) || this.contains( r.getRight(), r.getTop() ) || this.contains( r.getLeft(), r.getBottom() ) || this.contains( r.getRight(), r.getBottom() );
+
+		return Math.min( _right, r.getRight() ) - Math.max( _left, r.getLeft() ) >= 0 &&
+		        Math.min( _bottom, r.getBottom() ) - Math.max( _top, r.getTop() ) >= 0;
+
+	};
+
+	this.empty = function () {
+
+		_isEmpty = true;
+
+		_left = 0; _top = 0;
+		_right = 0; _bottom = 0;
+
+		resize();
+
+	};
+
+	this.isEmpty = function () {
+
+		return _isEmpty;
+
+	};
+
+	this.toString = function () {
+
+		return "THREE.Rectangle ( left: " + _left + ", right: " + _right + ", top: " + _top + ", bottom: " + _bottom + ", width: " + _width + ", height: " + _height + " )";
+
+	};
+
+};
+THREE.Matrix3 = function () {
+
+	this.m = [];
+
+};
+
+THREE.Matrix3.prototype = {
+
+	transpose: function () {
+
+		var tmp;
+
+		tmp = this.m[1]; this.m[1] = this.m[3]; this.m[3] = tmp;
+		tmp = this.m[2]; this.m[2] = this.m[6]; this.m[6] = tmp;
+		tmp = this.m[5]; this.m[5] = this.m[7]; this.m[7] = tmp;
+
+		return this;
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author philogb / http://blog.thejit.org/
+ * @author jordi_ros / http://plattsoft.com
+ * @author D1plo1d / http://github.com/D1plo1d
+ */
+
+THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
+
+	this.n11 = n11 || 1; this.n12 = n12 || 0; this.n13 = n13 || 0; this.n14 = n14 || 0;
+	this.n21 = n21 || 0; this.n22 = n22 || 1; this.n23 = n23 || 0; this.n24 = n24 || 0;
+	this.n31 = n31 || 0; this.n32 = n32 || 0; this.n33 = n33 || 1; this.n34 = n34 || 0;
+	this.n41 = n41 || 0; this.n42 = n42 || 0; this.n43 = n43 || 0; this.n44 = n44 || 1;
+
+};
+
+THREE.Matrix4.prototype = {
+
+	identity: function () {
+
+		this.n11 = 1; this.n12 = 0; this.n13 = 0; this.n14 = 0;
+		this.n21 = 0; this.n22 = 1; this.n23 = 0; this.n24 = 0;
+		this.n31 = 0; this.n32 = 0; this.n33 = 1; this.n34 = 0;
+		this.n41 = 0; this.n42 = 0; this.n43 = 0; this.n44 = 1;
+
+		return this;
+
+	},
+
+	set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
+
+		this.n11 = n11; this.n12 = n12; this.n13 = n13; this.n14 = n14;
+		this.n21 = n21; this.n22 = n22; this.n23 = n23; this.n24 = n24;
+		this.n31 = n31; this.n32 = n32; this.n33 = n33; this.n34 = n34;
+		this.n41 = n41; this.n42 = n42; this.n43 = n43; this.n44 = n44;
+
+		return this;
+
+	},
+
+	copy: function ( m ) {
+
+		this.n11 = m.n11; this.n12 = m.n12; this.n13 = m.n13; this.n14 = m.n14;
+		this.n21 = m.n21; this.n22 = m.n22; this.n23 = m.n23; this.n24 = m.n24;
+		this.n31 = m.n31; this.n32 = m.n32; this.n33 = m.n33; this.n34 = m.n34;
+		this.n41 = m.n41; this.n42 = m.n42; this.n43 = m.n43; this.n44 = m.n44;
+
+		return this;
+
+	},
+
+	lookAt: function ( eye, center, up ) {
+
+		var x = new THREE.Vector3(), y = new THREE.Vector3(), z = new THREE.Vector3();
+
+		z.sub( eye, center ).normalize();
+		x.cross( up, z ).normalize();
+		y.cross( z, x ).normalize();
+
+		this.n11 = x.x; this.n12 = x.y; this.n13 = x.z; this.n14 = - x.dot( eye );
+		this.n21 = y.x; this.n22 = y.y; this.n23 = y.z; this.n24 = - y.dot( eye );
+		this.n31 = z.x; this.n32 = z.y; this.n33 = z.z; this.n34 = - z.dot( eye );
+		this.n41 = 0; this.n42 = 0; this.n43 = 0; this.n44 = 1;
+
+		return this;
+
+	},
+
+	multiplyVector3: function ( v ) {
+
+		var vx = v.x, vy = v.y, vz = v.z,
+		d = 1 / ( this.n41 * vx + this.n42 * vy + this.n43 * vz + this.n44 );
+
+		v.x = ( this.n11 * vx + this.n12 * vy + this.n13 * vz + this.n14 ) * d;
+		v.y = ( this.n21 * vx + this.n22 * vy + this.n23 * vz + this.n24 ) * d;
+		v.z = ( this.n31 * vx + this.n32 * vy + this.n33 * vz + this.n34 ) * d;
+
+		return v;
+
+	},
+
+	multiplyVector4: function ( v ) {
+
+		var vx = v.x, vy = v.y, vz = v.z, vw = v.w;
+
+		v.x = this.n11 * vx + this.n12 * vy + this.n13 * vz + this.n14 * vw;
+		v.y = this.n21 * vx + this.n22 * vy + this.n23 * vz + this.n24 * vw;
+		v.z = this.n31 * vx + this.n32 * vy + this.n33 * vz + this.n34 * vw;
+		v.w = this.n41 * vx + this.n42 * vy + this.n43 * vz + this.n44 * vw;
+
+		return v;
+
+	},
+
+	crossVector: function ( a ) {
+
+		var v = new THREE.Vector4();
+
+		v.x = this.n11 * a.x + this.n12 * a.y + this.n13 * a.z + this.n14 * a.w;
+		v.y = this.n21 * a.x + this.n22 * a.y + this.n23 * a.z + this.n24 * a.w;
+		v.z = this.n31 * a.x + this.n32 * a.y + this.n33 * a.z + this.n34 * a.w;
+
+		v.w = ( a.w ) ? this.n41 * a.x + this.n42 * a.y + this.n43 * a.z + this.n44 * a.w : 1;
+
+		return v;
+
+	},
+
+	multiply: function ( a, b ) {
+
+		var a11 = a.n11, a12 = a.n12, a13 = a.n13, a14 = a.n14,
+		a21 = a.n21, a22 = a.n22, a23 = a.n23, a24 = a.n24,
+		a31 = a.n31, a32 = a.n32, a33 = a.n33, a34 = a.n34,
+		a41 = a.n41, a42 = a.n42, a43 = a.n43, a44 = a.n44,
+
+		b11 = b.n11, b12 = b.n12, b13 = b.n13, b14 = b.n14,
+		b21 = b.n21, b22 = b.n22, b23 = b.n23, b24 = b.n24,
+		b31 = b.n31, b32 = b.n32, b33 = b.n33, b34 = b.n34,
+		b41 = b.n41, b42 = b.n42, b43 = b.n43, b44 = b.n44;
+
+		this.n11 = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
+		this.n12 = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
+		this.n13 = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
+		this.n14 = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
+
+		this.n21 = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
+		this.n22 = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
+		this.n23 = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
+		this.n24 = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
+
+		this.n31 = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
+		this.n32 = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
+		this.n33 = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
+		this.n34 = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
+
+		this.n41 = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
+		this.n42 = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
+		this.n43 = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
+		this.n44 = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
+
+		return this;
+
+	},
+
+	multiplySelf: function ( m ) {
+
+		var n11 = this.n11, n12 = this.n12, n13 = this.n13, n14 = this.n14,
+		n21 = this.n21, n22 = this.n22, n23 = this.n23, n24 = this.n24,
+		n31 = this.n31, n32 = this.n32, n33 = this.n33, n34 = this.n34,
+		n41 = this.n41, n42 = this.n42, n43 = this.n43, n44 = this.n44,
+		mn11 = m.n11, mn21 = m.n21, mn31 = m.n31, mn41 = m.n41,
+		mn12 = m.n12, mn22 = m.n22, mn32 = m.n32, mn42 = m.n42,
+		mn13 = m.n13, mn23 = m.n23, mn33 = m.n33, mn43 = m.n43,
+		mn14 = m.n14, mn24 = m.n24, mn34 = m.n34, mn44 = m.n44;
+
+		this.n11 = n11 * mn11 + n12 * mn21 + n13 * mn31 + n14 * mn41;
+		this.n12 = n11 * mn12 + n12 * mn22 + n13 * mn32 + n14 * mn42;
+		this.n13 = n11 * mn13 + n12 * mn23 + n13 * mn33 + n14 * mn43;
+		this.n14 = n11 * mn14 + n12 * mn24 + n13 * mn34 + n14 * mn44;
+
+		this.n21 = n21 * mn11 + n22 * mn21 + n23 * mn31 + n24 * mn41;
+		this.n22 = n21 * mn12 + n22 * mn22 + n23 * mn32 + n24 * mn42;
+		this.n23 = n21 * mn13 + n22 * mn23 + n23 * mn33 + n24 * mn43;
+		this.n24 = n21 * mn14 + n22 * mn24 + n23 * mn34 + n24 * mn44;
+
+		this.n31 = n31 * mn11 + n32 * mn21 + n33 * mn31 + n34 * mn41;
+		this.n32 = n31 * mn12 + n32 * mn22 + n33 * mn32 + n34 * mn42;
+		this.n33 = n31 * mn13 + n32 * mn23 + n33 * mn33 + n34 * mn43;
+		this.n34 = n31 * mn14 + n32 * mn24 + n33 * mn34 + n34 * mn44;
+
+		this.n41 = n41 * mn11 + n42 * mn21 + n43 * mn31 + n44 * mn41;
+		this.n42 = n41 * mn12 + n42 * mn22 + n43 * mn32 + n44 * mn42;
+		this.n43 = n41 * mn13 + n42 * mn23 + n43 * mn33 + n44 * mn43;
+		this.n44 = n41 * mn14 + n42 * mn24 + n43 * mn34 + n44 * mn44;
+
+		return this;
+
+	},
+
+	multiplyScalar: function ( s ) {
+
+		this.n11 *= s; this.n12 *= s; this.n13 *= s; this.n14 *= s;
+		this.n21 *= s; this.n22 *= s; this.n23 *= s; this.n24 *= s;
+		this.n31 *= s; this.n32 *= s; this.n33 *= s; this.n34 *= s;
+		this.n41 *= s; this.n42 *= s; this.n43 *= s; this.n44 *= s;
+
+		return this;
+
+	},
+
+	determinant: function () {
+
+		//TODO: make this more efficient
+		//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
+		return (
+			this.n14 * this.n23 * this.n32 * this.n41-
+			this.n13 * this.n24 * this.n32 * this.n41-
+			this.n14 * this.n22 * this.n33 * this.n41+
+			this.n12 * this.n24 * this.n33 * this.n41+
+
+			this.n13 * this.n22 * this.n34 * this.n41-
+			this.n12 * this.n23 * this.n34 * this.n41-
+			this.n14 * this.n23 * this.n31 * this.n42+
+			this.n13 * this.n24 * this.n31 * this.n42+
+
+			this.n14 * this.n21 * this.n33 * this.n42-
+			this.n11 * this.n24 * this.n33 * this.n42-
+			this.n13 * this.n21 * this.n34 * this.n42+
+			this.n11 * this.n23 * this.n34 * this.n42+
+
+			this.n14 * this.n22 * this.n31 * this.n43-
+			this.n12 * this.n24 * this.n31 * this.n43-
+			this.n14 * this.n21 * this.n32 * this.n43+
+			this.n11 * this.n24 * this.n32 * this.n43+
+
+			this.n12 * this.n21 * this.n34 * this.n43-
+			this.n11 * this.n22 * this.n34 * this.n43-
+			this.n13 * this.n22 * this.n31 * this.n44+
+			this.n12 * this.n23 * this.n31 * this.n44+
+
+			this.n13 * this.n21 * this.n32 * this.n44-
+			this.n11 * this.n23 * this.n32 * this.n44-
+			this.n12 * this.n21 * this.n33 * this.n44+
+			this.n11 * this.n22 * this.n33 * this.n44 );
+
+	},
+
+	transpose: function () {
+
+		function swap( obj, p1, p2 ) {
+
+			var aux = obj[ p1 ];
+			obj[ p1 ] = obj[ p2 ];
+			obj[ p2 ] = aux;
+
+		}
+
+		swap( this, 'n21', 'n12' );
+		swap( this, 'n31', 'n13' );
+		swap( this, 'n32', 'n23' );
+		swap( this, 'n41', 'n14' );
+		swap( this, 'n42', 'n24' );
+		swap( this, 'n43', 'n34' );
+
+		return this;
+
+	},
+
+	clone: function () {
+
+		var m = new THREE.Matrix4();
+
+		m.n11 = this.n11; m.n12 = this.n12; m.n13 = this.n13; m.n14 = this.n14;
+		m.n21 = this.n21; m.n22 = this.n22; m.n23 = this.n23; m.n24 = this.n24;
+		m.n31 = this.n31; m.n32 = this.n32; m.n33 = this.n33; m.n34 = this.n34;
+		m.n41 = this.n41; m.n42 = this.n42; m.n43 = this.n43; m.n44 = this.n44;
+
+		return m;
+
+	},
+
+	flatten: function() {
+
+		return [ this.n11, this.n21, this.n31, this.n41,
+			  this.n12, this.n22, this.n32, this.n42,
+			  this.n13, this.n23, this.n33, this.n43,
+			  this.n14, this.n24, this.n34, this.n44 ];
+
+	},
+
+	toString: function() {
+
+		return  "| " + this.n11 + " " + this.n12 + " " + this.n13 + " " + this.n14 + " |\n" +
+			"| " + this.n21 + " " + this.n22 + " " + this.n23 + " " + this.n24 + " |\n" +
+			"| " + this.n31 + " " + this.n32 + " " + this.n33 + " " + this.n34 + " |\n" +
+			"| " + this.n41 + " " + this.n42 + " " + this.n43 + " " + this.n44 + " |";
+
+	}
+
+};
+
+THREE.Matrix4.translationMatrix = function ( x, y, z ) {
+
+	var m = new THREE.Matrix4();
+
+	m.n14 = x;
+	m.n24 = y;
+	m.n34 = z;
+
+	return m;
+
+};
+
+THREE.Matrix4.scaleMatrix = function ( x, y, z ) {
+
+	var m = new THREE.Matrix4();
+
+	m.n11 = x;
+	m.n22 = y;
+	m.n33 = z;
+
+	return m;
+
+};
+
+THREE.Matrix4.rotationXMatrix = function ( theta ) {
+
+	var rot = new THREE.Matrix4();
+
+	rot.n22 = rot.n33 = Math.cos( theta );
+	rot.n32 = Math.sin( theta );
+	rot.n23 = - rot.n32;
+
+	return rot;
+
+};
+
+THREE.Matrix4.rotationYMatrix = function ( theta ) {
+
+	var rot = new THREE.Matrix4();
+
+	rot.n11 = rot.n33 = Math.cos( theta );
+	rot.n13 = Math.sin( theta );
+	rot.n31 = - rot.n13;
+
+	return rot;
+
+};
+
+THREE.Matrix4.rotationZMatrix = function ( theta ) {
+
+	var rot = new THREE.Matrix4();
+
+	rot.n11 = rot.n22 = Math.cos( theta );
+	rot.n21 = Math.sin( theta );
+	rot.n12 = - rot.n21;
+
+	return rot;
+
+};
+
+THREE.Matrix4.rotationAxisAngleMatrix = function ( axis, angle ) {
+
+	//Based on http://www.gamedev.net/reference/articles/article1199.asp
+
+	var rot = new THREE.Matrix4(),
+	c = Math.cos( angle ),
+	s = Math.sin( angle ),
+	t = 1 - c,
+	x = axis.x, y = axis.y, z = axis.z;
+
+	rot.n11 = t * x * x + c;
+	rot.n12 = t * x * y - s * z;
+	rot.n13 = t * x * z + s * y;
+	rot.n21 = t * x * y + s * z;
+	rot.n22 = t * y * y + c;
+	rot.n23 = t * y * z - s * x;
+	rot.n31 = t * x * z - s * y;
+	rot.n32 = t * y * z + s * x;
+	rot.n33 = t * z * z + c;
+
+	return rot;
+
+};
+
+THREE.Matrix4.makeInvert = function ( m1 ) {
+
+	//TODO: make this more efficient
+	//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
+	var m2 = new THREE.Matrix4();
+
+	m2.n11 = m1.n23*m1.n34*m1.n42 - m1.n24*m1.n33*m1.n42 + m1.n24*m1.n32*m1.n43 - m1.n22*m1.n34*m1.n43 - m1.n23*m1.n32*m1.n44 + m1.n22*m1.n33*m1.n44;
+	m2.n12 = m1.n14*m1.n33*m1.n42 - m1.n13*m1.n34*m1.n42 - m1.n14*m1.n32*m1.n43 + m1.n12*m1.n34*m1.n43 + m1.n13*m1.n32*m1.n44 - m1.n12*m1.n33*m1.n44;
+	m2.n13 = m1.n13*m1.n24*m1.n42 - m1.n14*m1.n23*m1.n42 + m1.n14*m1.n22*m1.n43 - m1.n12*m1.n24*m1.n43 - m1.n13*m1.n22*m1.n44 + m1.n12*m1.n23*m1.n44;
+	m2.n14 = m1.n14*m1.n23*m1.n32 - m1.n13*m1.n24*m1.n32 - m1.n14*m1.n22*m1.n33 + m1.n12*m1.n24*m1.n33 + m1.n13*m1.n22*m1.n34 - m1.n12*m1.n23*m1.n34;
+	m2.n21 = m1.n24*m1.n33*m1.n41 - m1.n23*m1.n34*m1.n41 - m1.n24*m1.n31*m1.n43 + m1.n21*m1.n34*m1.n43 + m1.n23*m1.n31*m1.n44 - m1.n21*m1.n33*m1.n44;
+	m2.n22 = m1.n13*m1.n34*m1.n41 - m1.n14*m1.n33*m1.n41 + m1.n14*m1.n31*m1.n43 - m1.n11*m1.n34*m1.n43 - m1.n13*m1.n31*m1.n44 + m1.n11*m1.n33*m1.n44;
+	m2.n23 = m1.n14*m1.n23*m1.n41 - m1.n13*m1.n24*m1.n41 - m1.n14*m1.n21*m1.n43 + m1.n11*m1.n24*m1.n43 + m1.n13*m1.n21*m1.n44 - m1.n11*m1.n23*m1.n44;
+	m2.n24 = m1.n13*m1.n24*m1.n31 - m1.n14*m1.n23*m1.n31 + m1.n14*m1.n21*m1.n33 - m1.n11*m1.n24*m1.n33 - m1.n13*m1.n21*m1.n34 + m1.n11*m1.n23*m1.n34;
+	m2.n31 = m1.n22*m1.n34*m1.n41 - m1.n24*m1.n32*m1.n41 + m1.n24*m1.n31*m1.n42 - m1.n21*m1.n34*m1.n42 - m1.n22*m1.n31*m1.n44 + m1.n21*m1.n32*m1.n44;
+	m2.n32 = m1.n14*m1.n32*m1.n41 - m1.n12*m1.n34*m1.n41 - m1.n14*m1.n31*m1.n42 + m1.n11*m1.n34*m1.n42 + m1.n12*m1.n31*m1.n44 - m1.n11*m1.n32*m1.n44;
+	m2.n33 = m1.n13*m1.n24*m1.n41 - m1.n14*m1.n22*m1.n41 + m1.n14*m1.n21*m1.n42 - m1.n11*m1.n24*m1.n42 - m1.n12*m1.n21*m1.n44 + m1.n11*m1.n22*m1.n44;
+	m2.n34 = m1.n14*m1.n22*m1.n31 - m1.n12*m1.n24*m1.n31 - m1.n14*m1.n21*m1.n32 + m1.n11*m1.n24*m1.n32 + m1.n12*m1.n21*m1.n34 - m1.n11*m1.n22*m1.n34;
+	m2.n41 = m1.n23*m1.n32*m1.n41 - m1.n22*m1.n33*m1.n41 - m1.n23*m1.n31*m1.n42 + m1.n21*m1.n33*m1.n42 + m1.n22*m1.n31*m1.n43 - m1.n21*m1.n32*m1.n43;
+	m2.n42 = m1.n12*m1.n33*m1.n41 - m1.n13*m1.n32*m1.n41 + m1.n13*m1.n31*m1.n42 - m1.n11*m1.n33*m1.n42 - m1.n12*m1.n31*m1.n43 + m1.n11*m1.n32*m1.n43;
+	m2.n43 = m1.n13*m1.n22*m1.n41 - m1.n12*m1.n23*m1.n41 - m1.n13*m1.n21*m1.n42 + m1.n11*m1.n23*m1.n42 + m1.n12*m1.n21*m1.n43 - m1.n11*m1.n22*m1.n43;
+	m2.n44 = m1.n12*m1.n23*m1.n31 - m1.n13*m1.n22*m1.n31 + m1.n13*m1.n21*m1.n32 - m1.n11*m1.n23*m1.n32 - m1.n12*m1.n21*m1.n33 + m1.n11*m1.n22*m1.n33;
+	m2.multiplyScalar( 1 / m1.determinant() );
+
+	return m2;
+
+};
+
+THREE.Matrix4.makeInvert3x3 = function ( m1 ) {
+
+	// input:  THREE.Matrix4, output: THREE.Matrix3
+	// ( based on http://code.google.com/p/webgl-mjs/ )
+
+	var m = m1.flatten(),
+	m2 = new THREE.Matrix3(),
+
+	a11 = m[ 10 ] * m[ 5 ] - m[ 6 ] * m[ 9 ],
+	a21 = - m[ 10 ] * m[ 1 ] + m[ 2 ] * m[ 9 ],
+	a31 = m[ 6 ] * m[ 1 ] - m[ 2 ] * m[ 5 ],
+	a12 = - m[ 10 ] * m[ 4 ] + m[ 6 ] * m[ 8 ],
+	a22 = m[ 10 ] * m[ 0 ] - m[ 2 ] * m[ 8 ],
+	a32 = - m[ 6 ] * m[ 0 ] + m[ 2 ] * m[ 4 ],
+	a13 = m[ 9 ] * m[ 4 ] - m[ 5 ] * m[ 8 ],
+	a23 = - m[ 9 ] * m[ 0 ] + m[ 1 ] * m[ 8 ],
+	a33 = m[ 5 ] * m[ 0 ] - m[ 1 ] * m[ 4 ],
+	det = m[ 0 ] * ( a11 ) + m[ 1 ] * ( a12 ) + m[ 2 ] * ( a13 ),
+	idet;
+
+	// no inverse
+	if (det == 0) throw "matrix not invertible";
+
+	idet = 1.0 / det;
+
+	m2.m[ 0 ] = idet * a11; m2.m[ 1 ] = idet * a21; m2.m[ 2 ] = idet * a31;
+	m2.m[ 3 ] = idet * a12; m2.m[ 4 ] = idet * a22; m2.m[ 5 ] = idet * a32;
+	m2.m[ 6 ] = idet * a13; m2.m[ 7 ] = idet * a23; m2.m[ 8 ] = idet * a33;
+
+	return m2;
+
+}
+
+THREE.Matrix4.makeFrustum = function( left, right, bottom, top, near, far ) {
+
+	var m, x, y, a, b, c, d;
+
+	m = new THREE.Matrix4();
+	x = 2 * near / ( right - left );
+	y = 2 * near / ( top - bottom );
+	a = ( right + left ) / ( right - left );
+	b = ( top + bottom ) / ( top - bottom );
+	c = - ( far + near ) / ( far - near );
+	d = - 2 * far * near / ( far - near );
+
+	m.n11 = x;  m.n12 = 0;  m.n13 = a;   m.n14 = 0;
+	m.n21 = 0;  m.n22 = y;  m.n23 = b;   m.n24 = 0;
+	m.n31 = 0;  m.n32 = 0;  m.n33 = c;   m.n34 = d;
+	m.n41 = 0;  m.n42 = 0;  m.n43 = - 1; m.n44 = 0;
+
+	return m;
+
+};
+
+THREE.Matrix4.makePerspective = function( fov, aspect, near, far ) {
+
+	var ymax, ymin, xmin, xmax;
+
+	ymax = near * Math.tan( fov * Math.PI / 360 );
+	ymin = - ymax;
+	xmin = ymin * aspect;
+	xmax = ymax * aspect;
+
+	return THREE.Matrix4.makeFrustum( xmin, xmax, ymin, ymax, near, far );
+
+};
+
+THREE.Matrix4.makeOrtho = function( left, right, top, bottom, near, far ) {
+
+	var m, x, y, z, w, h, p;
+
+	m = new THREE.Matrix4();
+	w = right - left;
+	h = top - bottom;
+	p = far - near;
+	x = ( right + left ) / w;
+	y = ( top + bottom ) / h;
+	z = ( far + near ) / p;
+
+	m.n11 = 2 / w; m.n12 = 0;     m.n13 = 0;      m.n14 = -x;
+	m.n21 = 0;     m.n22 = 2 / h; m.n23 = 0;      m.n24 = -y;
+	m.n31 = 0;     m.n32 = 0;     m.n33 = -2 / p; m.n34 = -z;
+	m.n41 = 0;     m.n42 = 0;     m.n43 = 0;      m.n44 = 1;
+
+	return m;
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Vertex = function ( position, normal ) {
+
+	this.position = position || new THREE.Vector3();
+	this.positionWorld = new THREE.Vector3();
+	this.positionScreen = new THREE.Vector4();
+
+	this.normal = normal || new THREE.Vector3();
+	this.normalWorld = new THREE.Vector3();
+	this.normalScreen = new THREE.Vector3();
+
+	this.tangent = new THREE.Vector4();
+
+	this.__visible = true;
+
+};
+
+THREE.Vertex.prototype = {
+
+	toString: function () {
+
+		return 'THREE.Vertex ( position: ' + this.position + ', normal: ' + this.normal + ' )';
+	}
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Face3 = function ( a, b, c, normal, materials ) {
+
+	this.a = a;
+	this.b = b;
+	this.c = c;
+
+	this.centroid = new THREE.Vector3();
+	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
+	this.vertexNormals = normal instanceof Array ? normal : [];
+
+	this.materials = materials instanceof Array ? materials : [ materials ];
+
+};
+
+THREE.Face3.prototype = {
+
+	toString: function () {
+
+		return 'THREE.Face3 ( ' + this.a + ', ' + this.b + ', ' + this.c + ' )';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Face4 = function ( a, b, c, d, normal, materials ) {
+
+	this.a = a;
+	this.b = b;
+	this.c = c;
+	this.d = d;
+
+	this.centroid = new THREE.Vector3();
+	this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
+	this.vertexNormals = normal instanceof Array ? normal : [];
+
+	this.materials = materials instanceof Array ? materials : [ materials ];
+
+};
+
+
+THREE.Face4.prototype = {
+
+	toString: function () {
+
+		return 'THREE.Face4 ( ' + this.a + ', ' + this.b + ', ' + this.c + ' ' + this.d + ' )';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.UV = function ( u, v ) {
+
+	this.u = u || 0;
+	this.v = v || 0;
+
+};
+
+THREE.UV.prototype = {
+
+	copy: function ( uv ) {
+
+		this.u = uv.u;
+		this.v = uv.v;
+
+	},
+
+	toString: function () {
+
+		return 'THREE.UV (' + this.u + ', ' + this.v + ')';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author kile / http://kile.stravaganza.org/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.Geometry = function () {
+
+	this.vertices = [];
+	this.faces = [];
+	this.uvs = [];
+
+	this.boundingBox = null;
+	this.boundingSphere = null;
+
+	this.geometryChunks = {};
+
+	this.hasTangents = false;
+
+};
+
+THREE.Geometry.prototype = {
+
+	computeCentroids: function () {
+
+		var f, fl, face;
+
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+			face = this.faces[ f ];
+			face.centroid.set( 0, 0, 0 );
+
+			if ( face instanceof THREE.Face3 ) {
+
+				face.centroid.addSelf( this.vertices[ face.a ].position );
+				face.centroid.addSelf( this.vertices[ face.b ].position );
+				face.centroid.addSelf( this.vertices[ face.c ].position );
+				face.centroid.divideScalar( 3 );
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				face.centroid.addSelf( this.vertices[ face.a ].position );
+				face.centroid.addSelf( this.vertices[ face.b ].position );
+				face.centroid.addSelf( this.vertices[ face.c ].position );
+				face.centroid.addSelf( this.vertices[ face.d ].position );
+				face.centroid.divideScalar( 4 );
+
+			}
+
+		}
+
+	},
+
+	computeFaceNormals: function ( useVertexNormals ) {
+
+		var n, nl, v, vl, vertex, f, fl, face, vA, vB, vC,
+		cb = new THREE.Vector3(), ab = new THREE.Vector3();
+
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			vertex = this.vertices[ v ];
+			vertex.normal.set( 0, 0, 0 );
+
+		}
+
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+			face = this.faces[ f ];
+
+			if ( useVertexNormals && face.vertexNormals.length  ) {
+
+				cb.set( 0, 0, 0 );
+
+				for ( n = 0, nl = face.normal.length; n < nl; n++ ) {
+
+					cb.addSelf( face.vertexNormals[n] );
+
+				}
+
+				cb.divideScalar( 3 );
+
+				if ( ! cb.isZero() ) {
+
+					cb.normalize();
+
+				}
+
+				face.normal.copy( cb );
+
+			} else {
+
+				vA = this.vertices[ face.a ];
+				vB = this.vertices[ face.b ];
+				vC = this.vertices[ face.c ];
+
+				cb.sub( vC.position, vB.position );
+				ab.sub( vA.position, vB.position );
+				cb.crossSelf( ab );
+
+				if ( !cb.isZero() ) {
+
+					cb.normalize();
+
+				}
+
+				face.normal.copy( cb );
+
+			}
+
+		}
+
+	},
+
+	computeVertexNormals: function () {
+
+		var v, vl, vertices = [],
+		f, fl, face;
+
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			vertices[ v ] = new THREE.Vector3();
+
+		}
+
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+			face = this.faces[ f ];
+
+			if ( face instanceof THREE.Face3 ) {
+
+				vertices[ face.a ].addSelf( face.normal );
+				vertices[ face.b ].addSelf( face.normal );
+				vertices[ face.c ].addSelf( face.normal );
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				vertices[ face.a ].addSelf( face.normal );
+				vertices[ face.b ].addSelf( face.normal );
+				vertices[ face.c ].addSelf( face.normal );
+				vertices[ face.d ].addSelf( face.normal );
+
+			}
+
+		}
+
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			vertices[ v ].normalize();
+
+		}
+
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+			face = this.faces[ f ];
+
+			if ( face instanceof THREE.Face3 ) {
+
+				face.vertexNormals[ 0 ] = vertices[ face.a ].clone();
+				face.vertexNormals[ 1 ] = vertices[ face.b ].clone();
+				face.vertexNormals[ 2 ] = vertices[ face.c ].clone();
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				face.vertexNormals[ 0 ] = vertices[ face.a ].clone();
+				face.vertexNormals[ 1 ] = vertices[ face.b ].clone();
+				face.vertexNormals[ 2 ] = vertices[ face.c ].clone();
+				face.vertexNormals[ 3 ] = vertices[ face.d ].clone();
+
+			}
+
+		}
+
+	},
+
+	computeTangents: function() {
+
+		// based on http://www.terathon.com/code/tangent.html
+		// tangents go to vertices
+
+		var f, fl, v, vl, face, uv, vA, vB, vC, uvA, uvB, uvC,
+			x1, x2, y1, y2, z1, z2,
+			s1, s2, t1, t2, r, t, test,
+			tan1 = [], tan2 = [],
+			sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
+			tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
+			n = new THREE.Vector3(), w;
+
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			tan1[ v ] = new THREE.Vector3();
+			tan2[ v ] = new THREE.Vector3();
+
+		}
+
+		function handleTriangle( context, a, b, c, ua, ub, uc ) {
+
+			vA = context.vertices[ a ].position;
+			vB = context.vertices[ b ].position;
+			vC = context.vertices[ c ].position;
+
+			uvA = uv[ ua ];
+			uvB = uv[ ub ];
+			uvC = uv[ uc ];
+
+			x1 = vB.x - vA.x;
+			x2 = vC.x - vA.x;
+			y1 = vB.y - vA.y;
+			y2 = vC.y - vA.y;
+			z1 = vB.z - vA.z;
+			z2 = vC.z - vA.z;
+
+			s1 = uvB.u - uvA.u;
+			s2 = uvC.u - uvA.u;
+			t1 = uvB.v - uvA.v;
+			t2 = uvC.v - uvA.v;
+
+			r = 1.0 / ( s1 * t2 - s2 * t1 );
+			sdir.set( ( t2 * x1 - t1 * x2 ) * r,
+					  ( t2 * y1 - t1 * y2 ) * r,
+					  ( t2 * z1 - t1 * z2 ) * r );
+			tdir.set( ( s1 * x2 - s2 * x1 ) * r,
+					  ( s1 * y2 - s2 * y1 ) * r,
+					  ( s1 * z2 - s2 * z1 ) * r );
+
+			tan1[ a ].addSelf( sdir );
+			tan1[ b ].addSelf( sdir );
+			tan1[ c ].addSelf( sdir );
+
+			tan2[ a ].addSelf( tdir );
+			tan2[ b ].addSelf( tdir );
+			tan2[ c ].addSelf( tdir );
+
+		}
+
+		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+
+			face = this.faces[ f ];
+			uv = this.uvs[ f ];
+
+			if ( face instanceof THREE.Face3 ) {
+
+				handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
+
+				this.vertices[ face.a ].normal.copy( face.vertexNormals[ 0 ] );
+				this.vertices[ face.b ].normal.copy( face.vertexNormals[ 1 ] );
+				this.vertices[ face.c ].normal.copy( face.vertexNormals[ 2 ] );
+
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
+				handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 );
+
+				this.vertices[ face.a ].normal.copy( face.vertexNormals[ 0 ] );
+				this.vertices[ face.b ].normal.copy( face.vertexNormals[ 1 ] );
+				this.vertices[ face.c ].normal.copy( face.vertexNormals[ 2 ] );
+				this.vertices[ face.d ].normal.copy( face.vertexNormals[ 3 ] );
+
+			}
+
+		}
+
+		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			n.copy( this.vertices[ v ].normal );
+			t = tan1[ v ];
+
+			// Gram-Schmidt orthogonalize
+
+			tmp.copy( t );
+			tmp.subSelf( n.multiplyScalar( n.dot( t ) ) ).normalize();
+
+			// Calculate handedness
+
+			tmp2.cross( this.vertices[ v ].normal, t );
+			test = tmp2.dot( tan2[ v ] );
+			w = (test < 0.0) ? -1.0 : 1.0;
+
+			this.vertices[ v ].tangent.set( tmp.x, tmp.y, tmp.z, w );
+
+		}
+
+		this.hasTangents = true;
+
+	},
+
+	computeBoundingBox: function () {
+
+		var vertex;
+
+		if ( this.vertices.length > 0 ) {
+
+			this.boundingBox = { 'x': [ this.vertices[ 0 ].position.x, this.vertices[ 0 ].position.x ],
+			'y': [ this.vertices[ 0 ].position.y, this.vertices[ 0 ].position.y ],
+			'z': [ this.vertices[ 0 ].position.z, this.vertices[ 0 ].position.z ] };
+
+			for ( var v = 1, vl = this.vertices.length; v < vl; v ++ ) {
+
+				vertex = this.vertices[ v ];
+
+				if ( vertex.position.x < this.boundingBox.x[ 0 ] ) {
+
+					this.boundingBox.x[ 0 ] = vertex.position.x;
+
+				} else if ( vertex.position.x > this.boundingBox.x[ 1 ] ) {
+
+					this.boundingBox.x[ 1 ] = vertex.position.x;
+
+				}
+
+				if ( vertex.position.y < this.boundingBox.y[ 0 ] ) {
+
+					this.boundingBox.y[ 0 ] = vertex.position.y;
+
+				} else if ( vertex.position.y > this.boundingBox.y[ 1 ] ) {
+
+					this.boundingBox.y[ 1 ] = vertex.position.y;
+
+				}
+
+				if ( vertex.position.z < this.boundingBox.z[ 0 ] ) {
+
+					this.boundingBox.z[ 0 ] = vertex.position.z;
+
+				} else if ( vertex.position.z > this.boundingBox.z[ 1 ] ) {
+
+					this.boundingBox.z[ 1 ] = vertex.position.z;
+
+				}
+
+			}
+
+		}
+
+	},
+
+	computeBoundingSphere: function () {
+
+		var radius = this.boundingSphere === null ? 0 : this.boundingSphere.radius;
+
+		for ( var v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+
+			radius = Math.max( radius, this.vertices[ v ].position.length() );
+
+		}
+
+		this.boundingSphere = { radius: radius };
+
+	},
+
+	sortFacesByMaterial: function () {
+
+		// TODO
+		// Should optimize by grouping faces with ColorFill / ColorStroke materials
+		// which could then use vertex color attributes instead of each being
+		// in its separate VBO
+
+		var i, l, f, fl, face, material, materials, vertices, mhash, ghash, hash_map = {};
+
+		function materialHash( material ) {
+
+			var hash_array = [];
+
+			for ( i = 0, l = material.length; i < l; i++ ) {
+
+				if ( material[ i ] == undefined ) {
+
+					hash_array.push( "undefined" );
+
+				} else {
+
+					hash_array.push( material[ i ].toString() );
+
+				}
+
+			}
+
+			return hash_array.join( '_' );
+
+		}
+
+		for ( f = 0, fl = this.faces.length; f < fl; f++ ) {
+
+			face = this.faces[ f ];
+			materials = face.materials;
+
+			mhash = materialHash( materials );
+
+			if ( hash_map[ mhash ] == undefined ) {
+
+				hash_map[ mhash ] = { 'hash': mhash, 'counter': 0 };
+
+			}
+
+			ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
+
+			if ( this.geometryChunks[ ghash ] == undefined ) {
+
+				this.geometryChunks[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0 };
+
+			}
+
+			vertices = face instanceof THREE.Face3 ? 3 : 4;
+
+			if ( this.geometryChunks[ ghash ].vertices + vertices > 65535 ) {
+
+				hash_map[ mhash ].counter += 1;
+				ghash = hash_map[ mhash ].hash + '_' + hash_map[ mhash ].counter;
+
+				if ( this.geometryChunks[ ghash ] == undefined ) {
+
+					this.geometryChunks[ ghash ] = { 'faces': [], 'materials': materials, 'vertices': 0 };
+
+				}
+
+			}
+
+			this.geometryChunks[ ghash ].faces.push( f );
+			this.geometryChunks[ ghash ].vertices += vertices;
+
+		}
+
+	},
+
+	toString: function () {
+
+		return 'THREE.Geometry ( vertices: ' + this.vertices + ', faces: ' + this.faces + ', uvs: ' + this.uvs + ' )';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Camera = function ( fov, aspect, near, far ) {
+
+	this.fov = fov;
+	this.aspect = aspect;
+	this.near = near;
+	this.far = far;
+
+	this.position = new THREE.Vector3();
+	this.target = { position: new THREE.Vector3() };
+
+	this.autoUpdateMatrix = true;
+
+	this.projectionMatrix = null;
+	this.matrix = new THREE.Matrix4();
+
+	this.up = new THREE.Vector3( 0, 1, 0 );
+
+	this.translateX = function ( amount ) {
+
+		var vector = this.target.position.clone().subSelf( this.position ).normalize().multiplyScalar( amount );
+		vector.cross( vector.clone(), this.up );
+
+		this.position.addSelf( vector );
+		this.target.position.addSelf( vector );
+
+	};
+
+	/* TODO
+	this.translateY = function ( amount ) {
+
+	};
+	*/
+
+	this.translateZ = function ( amount ) {
+
+		var vector = this.target.position.clone().subSelf( this.position ).normalize().multiplyScalar( amount );
+
+		this.position.subSelf( vector );
+		this.target.position.subSelf( vector );
+
+	};
+
+	this.updateMatrix = function () {
+
+		this.matrix.lookAt( this.position, this.target.position, this.up );
+
+	};
+
+	this.updateProjectionMatrix = function () {
+
+		this.projectionMatrix = THREE.Matrix4.makePerspective( this.fov, this.aspect, this.near, this.far );
+
+	};
+
+	this.updateProjectionMatrix();
+
+};
+
+THREE.Camera.prototype = {
+
+	toString: function () {
+
+		return 'THREE.Camera ( ' + this.position + ', ' + this.target.position + ' )';
+
+	}
+
+};
+THREE.Light = function ( hex ) {
+
+	this.color = new THREE.Color( hex );
+
+};
+THREE.AmbientLight = function ( hex ) {
+
+	THREE.Light.call( this, hex );
+
+};
+
+THREE.AmbientLight.prototype = new THREE.Light();
+THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; 
+THREE.DirectionalLight = function ( hex, intensity ) {
+
+	THREE.Light.call( this, hex );
+
+	this.position = new THREE.Vector3( 0, 1, 0 );
+	this.intensity = intensity || 1;
+
+};
+
+THREE.DirectionalLight.prototype = new THREE.Light();
+THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; 
+THREE.PointLight = function ( hex, intensity ) {
+
+	THREE.Light.call( this, hex );
+
+	this.position = new THREE.Vector3();
+	this.intensity = intensity || 1;
+
+};
+
+THREE.DirectionalLight.prototype = new THREE.Light();
+THREE.DirectionalLight.prototype.constructor = THREE.PointLight; 
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Object3D = function () {
+
+	this.id = THREE.Object3DCounter.value ++;
+
+	this.position = new THREE.Vector3();
+	this.rotation = new THREE.Vector3();
+	this.scale = new THREE.Vector3( 1, 1, 1 );
+
+	this.matrix = new THREE.Matrix4();
+	this.translationMatrix = new THREE.Matrix4();
+	this.rotationMatrix = new THREE.Matrix4();
+	this.scaleMatrix = new THREE.Matrix4();
+
+	this.screen = new THREE.Vector3();
+
+	this.autoUpdateMatrix = true;
+	this.visible = true;
+
+};
+
+THREE.Object3D.prototype = {
+
+	updateMatrix: function () {
+
+		this.matrixPosition = THREE.Matrix4.translationMatrix( this.position.x, this.position.y, this.position.z );
+
+		this.rotationMatrix = THREE.Matrix4.rotationXMatrix( this.rotation.x );
+		this.rotationMatrix.multiplySelf( THREE.Matrix4.rotationYMatrix( this.rotation.y ) );
+		this.rotationMatrix.multiplySelf( THREE.Matrix4.rotationZMatrix( this.rotation.z ) );
+
+		this.scaleMatrix = THREE.Matrix4.scaleMatrix( this.scale.x, this.scale.y, this.scale.z );
+
+		this.matrix.copy( this.matrixPosition );
+		this.matrix.multiplySelf( this.rotationMatrix );
+		this.matrix.multiplySelf( this.scaleMatrix );
+
+	}
+
+};
+
+THREE.Object3DCounter = { value: 0 };
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Particle = function ( materials ) {
+
+	THREE.Object3D.call( this );
+
+	this.materials = materials instanceof Array ? materials : [ materials ];
+
+	this.autoUpdateMatrix = false;
+
+};
+
+THREE.Particle.prototype = new THREE.Object3D();
+THREE.Particle.prototype.constructor = THREE.Particle;
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.ParticleSystem = function ( geometry, materials ) {
+
+	THREE.Object3D.call( this );
+
+	this.geometry = geometry;
+	this.materials = materials instanceof Array ? materials : [ materials ];
+
+	this.autoUpdateMatrix = false;
+
+};
+
+THREE.ParticleSystem.prototype = new THREE.Object3D();
+THREE.ParticleSystem.prototype.constructor = THREE.ParticleSystem;
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Line = function ( geometry, materials, type ) {
+
+	THREE.Object3D.call( this );
+
+	this.geometry = geometry;
+	this.materials = materials instanceof Array ? materials : [ materials ];
+	
+	this.type = type !== undefined ? type : THREE.LineContinuous;
+
+};
+
+THREE.LineStrip = 0;
+THREE.LinePieces = 1;
+
+THREE.Line.prototype = new THREE.Object3D();
+THREE.Line.prototype.constructor = THREE.Line;
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.Mesh = function ( geometry, materials ) {
+
+	THREE.Object3D.call( this );
+
+	this.geometry = geometry;
+	this.materials = materials instanceof Array ? materials : [ materials ];
+
+	this.flipSided = false;
+	this.doubleSided = false;
+
+	this.overdraw = false; // TODO: Move to material?
+
+	this.geometry.boundingSphere || this.geometry.computeBoundingSphere();
+
+};
+
+THREE.Mesh.prototype = new THREE.Object3D();
+THREE.Mesh.prototype.constructor = THREE.Mesh;
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.FlatShading = 0;
+THREE.SmoothShading = 1;
+
+THREE.NormalBlending = 0;
+THREE.AdditiveBlending = 1;
+THREE.SubtractiveBlending = 2;
+/**
+ * @author mr.doob / http://mrdoob.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  opacity: <float>,
+ *  blending: THREE.NormalBlending,
+ *  linewidth: <float>
+ * }
+ */
+
+THREE.LineBasicMaterial = function ( parameters ) {
+
+	this.color = new THREE.Color( 0xffffff );
+	this.opacity = 1;
+	this.blending = THREE.NormalBlending;
+	this.linewidth = 1;
+	this.linecap = 'round';
+	this.linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color.setHex( parameters.color );
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+		if ( parameters.linewidth !== undefined ) this.linewidth = parameters.linewidth;
+		if ( parameters.linecap !== undefined ) this.linecap = parameters.linecap;
+		if ( parameters.linejoin !== undefined ) this.linejoin = parameters.linejoin;
+	}
+
+};
+
+THREE.LineBasicMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.LineBasicMaterial (<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'opacity: ' + this.opacity + '<br/>' +
+			'blending: ' + this.blending + '<br/>' +
+			'linewidth: ' + this.linewidth +'<br/>' +
+			'linecap: ' + this.linecap +'<br/>' +
+			'linejoin: ' + this.linejoin +'<br/>' +
+			')';
+
+	}
+
+}
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  map: new THREE.Texture( <Image> ),
+ 
+ *  env_map: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ *  combine: THREE.Multiply,
+ *  reflectivity: <float>,
+ *  refraction_ratio: <float>,
+ 
+ *  opacity: <float>,
+ *  shading: THREE.SmoothShading,
+ *  blending: THREE.NormalBlending,
+ *  wireframe: <boolean>,
+ *  wireframe_linewidth: <float>
+ * }
+ */
+
+THREE.MeshBasicMaterial = function ( parameters ) {
+
+	this.id = THREE.MeshBasicMaterialCounter.value ++;
+
+	this.color = new THREE.Color( 0xffffff );
+	this.map = null;
+
+	this.env_map = null;
+	this.combine = THREE.MultiplyOperation;
+	this.reflectivity = 1;
+	this.refraction_ratio = 0.98;
+
+	this.fog = true;
+
+	this.opacity = 1;
+	this.shading = THREE.SmoothShading;
+	this.blending = THREE.NormalBlending;
+
+	this.wireframe = false;
+	this.wireframe_linewidth = 1;
+	this.wireframe_linecap = 'round';
+	this.wireframe_linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color.setHex( parameters.color );
+		if ( parameters.map !== undefined ) this.map = parameters.map;
+
+		if ( parameters.env_map !== undefined ) this.env_map = parameters.env_map;
+		if ( parameters.combine !== undefined ) this.combine = parameters.combine;
+		if ( parameters.reflectivity !== undefined ) this.reflectivity  = parameters.reflectivity;
+		if ( parameters.refraction_ratio !== undefined ) this.refraction_ratio  = parameters.refraction_ratio;
+
+		if ( parameters.fog !== undefined ) this.fog  = parameters.fog;
+
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.shading !== undefined ) this.shading = parameters.shading;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+		if ( parameters.wireframe !== undefined ) this.wireframe = parameters.wireframe;
+		if ( parameters.wireframe_linewidth !== undefined ) this.wireframe_linewidth = parameters.wireframe_linewidth;
+		if ( parameters.wireframe_linecap !== undefined ) this.wireframe_linecap = parameters.wireframe_linecap;
+		if ( parameters.wireframe_linejoin !== undefined ) this.wireframe_linejoin = parameters.wireframe_linejoin;
+
+	}
+
+};
+
+THREE.MeshBasicMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshBasicMaterial (<br/>' +
+			'id: ' + this.id + '<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'map: ' + this.map + '<br/>' +
+
+			'env_map: ' + this.env_map + '<br/>' +
+			'combine: ' + this.combine + '<br/>' +
+			'reflectivity: ' + this.reflectivity + '<br/>' +
+			'refraction_ratio: ' + this.refraction_ratio + '<br/>' +
+
+			'opacity: ' + this.opacity + '<br/>' +
+			'blending: ' + this.blending + '<br/>' +
+
+			'wireframe: ' + this.wireframe + '<br/>' +
+			'wireframe_linewidth: ' + this.wireframe_linewidth +'<br/>' +
+			'wireframe_linecap: ' + this.wireframe_linecap +'<br/>' +
+			'wireframe_linejoin: ' + this.wireframe_linejoin +'<br/>' +
+			')';
+
+	}
+
+};
+
+THREE.MeshBasicMaterialCounter = { value: 0 };
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  map: new THREE.Texture( <Image> ),
+ 
+ *  env_map: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ *  combine: THREE.Multiply,
+ *  reflectivity: <float>,
+ *  refraction_ratio: <float>,
+ 
+ *  opacity: <float>,
+ *  shading: THREE.SmoothShading,
+ *  blending: THREE.NormalBlending,
+ *  wireframe: <boolean>,
+ *  wireframe_linewidth: <float>
+ * }
+ */
+
+THREE.MeshLambertMaterial = function ( parameters ) {
+
+	this.id = THREE.MeshLambertMaterialCounter.value ++;
+
+	this.color = new THREE.Color( 0xffffff );
+	this.map = null;
+
+	this.env_map = null;
+	this.combine = THREE.MultiplyOperation;
+	this.reflectivity = 1;
+	this.refraction_ratio = 0.98;
+
+	this.fog = true;
+
+	this.opacity = 1;
+	this.shading = THREE.SmoothShading;
+	this.blending = THREE.NormalBlending;
+
+	this.wireframe = false;
+	this.wireframe_linewidth = 1;
+	this.wireframe_linecap = 'round';
+	this.wireframe_linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color.setHex( parameters.color );
+		if ( parameters.map !== undefined ) this.map = parameters.map;
+
+		if ( parameters.env_map !== undefined ) this.env_map = parameters.env_map;
+		if ( parameters.combine !== undefined ) this.combine = parameters.combine;
+		if ( parameters.reflectivity !== undefined ) this.reflectivity  = parameters.reflectivity;
+		if ( parameters.refraction_ratio !== undefined ) this.refraction_ratio  = parameters.refraction_ratio;
+
+		if ( parameters.fog !== undefined ) this.fog  = parameters.fog;
+
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.shading !== undefined ) this.shading = parameters.shading;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+		if ( parameters.wireframe !== undefined ) this.wireframe = parameters.wireframe;
+		if ( parameters.wireframe_linewidth !== undefined ) this.wireframe_linewidth = parameters.wireframe_linewidth;
+		if ( parameters.wireframe_linecap !== undefined ) this.wireframe_linecap = parameters.wireframe_linecap;
+		if ( parameters.wireframe_linejoin !== undefined ) this.wireframe_linejoin = parameters.wireframe_linejoin;
+
+	}
+
+};
+
+THREE.MeshLambertMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshLambertMaterial (<br/>' +
+			'id: ' + this.id + '<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'map: ' + this.map + '<br/>' +
+
+			'env_map: ' + this.env_map + '<br/>' +
+			'combine: ' + this.combine + '<br/>' +
+			'reflectivity: ' + this.reflectivity + '<br/>' +
+			'refraction_ratio: ' + this.refraction_ratio + '<br/>' +
+
+			'opacity: ' + this.opacity + '<br/>' +
+			'shading: ' + this.shading + '<br/>' +
+			'blending: ' + this.blending + '<br/>' +
+
+			'wireframe: ' + this.wireframe + '<br/>' +
+			'wireframe_linewidth: ' + this.wireframe_linewidth +'<br/>' +
+			'wireframe_linecap: ' + this.wireframe_linecap +'<br/>' +
+			'wireframe_linejoin: ' + this.wireframe_linejoin +'<br/>' +
+			' )';
+
+	}
+
+};
+
+THREE.MeshLambertMaterialCounter = { value: 0 };
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  ambient: <hex>,
+ *  specular: <hex>,
+ *  shininess: <float>,
+
+ *  map: new THREE.Texture( <Image> ),
+ *  specular_map: new THREE.Texture( <Image> ),
+
+ *  env_map: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ *  combine: THREE.Multiply,
+ *  reflectivity: <float>,
+ *  refraction_ratio: <float>,
+
+ *  opacity: <float>,
+ *  shading: THREE.SmoothShading,
+ *  blending: THREE.NormalBlending,
+ *  wireframe: <boolean>,
+ *  wireframe_linewidth: <float>
+ * }
+ */
+
+THREE.MeshPhongMaterial = function ( parameters ) {
+
+	this.id = THREE.MeshPhongMaterialCounter.value ++;
+
+	this.color = new THREE.Color( 0xffffff );
+	this.ambient = new THREE.Color( 0x050505 );
+	this.specular = new THREE.Color( 0x111111 );
+	this.shininess = 30;
+
+	this.map = null;
+	this.specular_map = null;
+
+	this.env_map = null;
+	this.combine = THREE.MultiplyOperation;
+	this.reflectivity = 1;
+	this.refraction_ratio = 0.98;
+
+	this.fog = true;
+
+	this.opacity = 1;
+	this.shading = THREE.SmoothShading;
+	this.blending = THREE.NormalBlending;
+
+	this.wireframe = false;
+	this.wireframe_linewidth = 1;
+	this.wireframe_linecap = 'round';
+	this.wireframe_linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color = new THREE.Color( parameters.color );
+		if ( parameters.ambient !== undefined ) this.ambient = new THREE.Color( parameters.ambient );
+		if ( parameters.specular !== undefined ) this.specular = new THREE.Color( parameters.specular );
+		if ( parameters.shininess !== undefined ) this.shininess = parameters.shininess;
+
+		if ( parameters.map !== undefined ) this.map = parameters.map;
+		if ( parameters.specular_map !== undefined ) this.specular_map = parameters.specular_map;
+
+		if ( parameters.env_map !== undefined ) this.env_map = parameters.env_map;
+		if ( parameters.combine !== undefined ) this.combine = parameters.combine;
+		if ( parameters.reflectivity !== undefined ) this.reflectivity  = parameters.reflectivity;
+		if ( parameters.refraction_ratio !== undefined ) this.refraction_ratio  = parameters.refraction_ratio;
+
+		if ( parameters.fog !== undefined ) this.fog  = parameters.fog;
+
+		if ( parameters.opacity !== undefined ) this.opacity = parameters.opacity;
+		if ( parameters.shading !== undefined ) this.shading = parameters.shading;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+		if ( parameters.wireframe !== undefined ) this.wireframe = parameters.wireframe;
+		if ( parameters.wireframe_linewidth !== undefined ) this.wireframe_linewidth = parameters.wireframe_linewidth;
+		if ( parameters.wireframe_linecap !== undefined ) this.wireframe_linecap = parameters.wireframe_linecap;
+		if ( parameters.wireframe_linejoin !== undefined ) this.wireframe_linejoin = parameters.wireframe_linejoin;
+
+	}
+
+};
+
+THREE.MeshPhongMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshPhongMaterial (<br/>' +
+			'id: ' + this.id + '<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'ambient: ' + this.ambient + '<br/>' +
+			'specular: ' + this.specular + '<br/>' +
+			'shininess: ' + this.shininess + '<br/>' +
+
+			'map: ' + this.map + '<br/>' +
+			'specular_map: ' + this.specular_map + '<br/>' +
+
+			'env_map: ' + this.env_map + '<br/>' +
+			'combine: ' + this.combine + '<br/>' +
+			'reflectivity: ' + this.reflectivity + '<br/>' +
+			'refraction_ratio: ' + this.refraction_ratio + '<br/>' +
+
+			'opacity: ' + this.opacity + '<br/>' +
+			'shading: ' + this.shading + '<br/>' +
+
+			'wireframe: ' + this.wireframe + '<br/>' +
+			'wireframe_linewidth: ' + this.wireframe_linewidth + '<br/>' +
+			'wireframe_linecap: ' + this.wireframe_linecap +'<br/>' +
+			'wireframe_linejoin: ' + this.wireframe_linejoin +'<br/>' +
+			')';
+
+	}
+
+};
+
+THREE.MeshPhongMaterialCounter = { value: 0 };
+/**
+ * @author mr.doob / http://mrdoob.com/
+ *
+ * parameters = {
+ *  opacity: <float>,
+ *  blending: THREE.NormalBlending
+ * } 
+ */
+
+THREE.MeshDepthMaterial = function ( parameters ) {
+
+	this.opacity = 1;
+	this.shading = THREE.SmoothShading;
+	this.blending = THREE.NormalBlending;
+
+	this.wireframe = false;
+	this.wireframe_linewidth = 1;
+	this.wireframe_linecap = 'round';
+	this.wireframe_linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+	}
+
+};
+
+THREE.MeshDepthMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshDepthMaterial';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ *
+ * parameters = {
+ *  opacity: <float>,
+ *  shading: THREE.FlatShading,
+ *  blending: THREE.NormalBlending
+ * }
+ */
+
+THREE.MeshNormalMaterial = function ( parameters ) {
+
+	this.opacity = 1;
+	this.shading = THREE.FlatShading;
+	this.blending = THREE.NormalBlending;
+
+	if ( parameters ) {
+
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.shading !== undefined ) this.shading  = parameters.shading;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+	}
+
+};
+
+THREE.MeshNormalMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshNormalMaterial';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.MeshFaceMaterial = function () {
+
+};
+
+THREE.MeshFaceMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshFaceMaterial';
+
+	}
+
+};
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ *  fragment_shader: <string>,
+ *  vertex_shader: <string>,
+ *  uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
+ *  shading: THREE.SmoothShading,
+ *  blending: THREE.NormalBlending,
+ *  wireframe: <boolean>,
+ *  wireframe_linewidth: <float>
+ * }
+ */
+
+THREE.MeshShaderMaterial = function ( parameters ) {
+
+	this.id = THREE.MeshShaderMaterialCounter.value ++;
+
+	this.fragment_shader = "void main() {}";
+	this.vertex_shader = "void main() {}";
+	this.uniforms = {};
+
+	this.opacity = 1;
+	this.shading = THREE.SmoothShading;
+	this.blending = THREE.NormalBlending;
+
+	this.wireframe = false;
+	this.wireframe_linewidth = 1;
+	this.wireframe_linecap = 'round';
+	this.wireframe_linejoin = 'round';
+
+	if ( parameters ) {
+
+		if ( parameters.fragment_shader !== undefined ) this.fragment_shader = parameters.fragment_shader;
+		if ( parameters.vertex_shader !== undefined ) this.vertex_shader = parameters.vertex_shader;
+
+		if ( parameters.uniforms !== undefined ) this.uniforms = parameters.uniforms;
+
+		if ( parameters.shading !== undefined ) this.shading = parameters.shading;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+		if ( parameters.wireframe !== undefined ) this.wireframe = parameters.wireframe;
+		if ( parameters.wireframe_linewidth !== undefined ) this.wireframe_linewidth = parameters.wireframe_linewidth;
+		if ( parameters.wireframe_linecap !== undefined ) this.wireframe_linecap = parameters.wireframe_linecap;
+		if ( parameters.wireframe_linejoin !== undefined ) this.wireframe_linejoin = parameters.wireframe_linejoin;
+
+	}
+
+};
+
+THREE.MeshShaderMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.MeshShaderMaterial (<br/>' +
+			'id: ' + this.id + '<br/>' +
+
+			'blending: ' + this.blending + '<br/>' +
+			'wireframe: ' + this.wireframe + '<br/>' +
+			'wireframe_linewidth: ' + this.wireframe_linewidth +'<br/>' +
+			'wireframe_linecap: ' + this.wireframe_linecap +'<br/>' +
+			'wireframe_linejoin: ' + this.wireframe_linejoin +'<br/>' +
+			')';
+
+	}
+
+};
+
+THREE.MeshShaderMaterialCounter = { value: 0 };
+/**
+ * @author mr.doob / http://mrdoob.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  map: new THREE.Texture( <Image> ),
+ *  opacity: <float>,
+ *  blending: THREE.NormalBlending
+ * }
+ */
+
+THREE.ParticleBasicMaterial = function ( parameters ) {
+
+	this.color = new THREE.Color( 0xffffff );
+	this.map = null;
+	this.opacity = 1;
+	this.blending = THREE.NormalBlending;
+
+	this.offset = new THREE.Vector2(); // TODO: expose to parameters
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color.setHex( parameters.color );
+		if ( parameters.map !== undefined ) this.map = parameters.map;
+		if ( parameters.opacity !== undefined ) this.opacity  = parameters.opacity;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+	}
+
+};
+
+THREE.ParticleBasicMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.ParticleBasicMaterial (<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'map: ' + this.map + '<br/>' +
+			'opacity: ' + this.opacity + '<br/>' +
+			'blending: ' + this.blending + '<br/>' +
+			')';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ *
+ * parameters = {
+ *  color: <hex>,
+ *  opacity: <float>,
+ *  blending: THREE.NormalBlending
+ * }
+ */
+
+THREE.ParticleCircleMaterial = function ( parameters ) {
+
+	this.color = new THREE.Color( 0xffffff );
+	this.opacity = 1;
+	this.blending = THREE.NormalBlending;
+
+	if ( parameters ) {
+
+		if ( parameters.color !== undefined ) this.color.setHex( parameters.color );
+		if ( parameters.opacity !== undefined ) this.opacity = parameters.opacity;
+		if ( parameters.blending !== undefined ) this.blending = parameters.blending;
+
+	}
+
+};
+
+THREE.ParticleCircleMaterial.prototype = {
+
+	toString: function () {
+
+		return 'THREE.ParticleCircleMaterial (<br/>' +
+			'color: ' + this.color + '<br/>' +
+			'opacity: ' + this.opacity + '<br/>' +
+			'blending: ' + this.blending + '<br/>' +
+			')';
+
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.Texture = function ( image, mapping, wrap_s, wrap_t, mag_filter, min_filter ) {
+
+	this.image = image;
+
+	this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();
+
+	this.wrap_s = wrap_s !== undefined ? wrap_s : THREE.ClampToEdgeWrapping;
+	this.wrap_t = wrap_t !== undefined ? wrap_t : THREE.ClampToEdgeWrapping;
+
+	this.mag_filter = mag_filter !== undefined ? mag_filter : THREE.LinearFilter;
+	this.min_filter = min_filter !== undefined ? min_filter : THREE.LinearMipMapLinearFilter;
+
+};
+
+THREE.Texture.prototype = {
+
+	clone: function () {
+
+		return new THREE.Texture( this.image, this.mapping, this.wrap_s, this.wrap_t, this.mag_filter, this.min_filter );
+
+	},
+
+	toString: function () {
+
+		return 'THREE.Texture (<br/>' +
+			'image: ' + this.image + '<br/>' +
+			'wrap_s: ' + this.wrap_s + '<br/>' +
+			'wrap_t: ' + this.wrap_t + '<br/>' +
+			'mag_filter: ' + this.mag_filter + '<br/>' +
+			'min_filter: ' + this.min_filter + '<br/>' +
+			')';
+
+	}
+
+};
+
+THREE.MultiplyOperation = 0;
+THREE.MixOperation = 1;
+
+THREE.RepeatWrapping = 0;
+THREE.ClampToEdgeWrapping = 1;
+THREE.MirroredRepeatWrapping = 2;
+
+THREE.NearestFilter = 3;
+THREE.NearestMipMapNearestFilter = 4;
+THREE.NearestMipMapLinearFilter = 5;
+THREE.LinearFilter = 6;
+THREE.LinearMipMapNearestFilter = 7;
+THREE.LinearMipMapLinearFilter = 8;
+
+THREE.RGBFormat = 9;
+
+THREE.UnsignedByteType = 10;
+THREE.RenderTexture = function ( width, height, options ) {
+
+	this.width = width;
+	this.height = height;
+
+	options = options || {};
+
+	this.wrap_s = options.wrap_s !== undefined ? options.wrap_s : THREE.ClampToEdgeWrapping;
+	this.wrap_t = options.wrap_t !== undefined ? options.wrap_t : THREE.ClampToEdgeWrapping;
+
+	this.mag_filter = options.mag_filter !== undefined ? options.mag_filter : THREE.LinearFilter;
+	this.min_filter = options.min_filter !== undefined ? options.min_filter : THREE.LinearFilter;
+
+	this.format = options.format !== undefined ? options.format : THREE.RGBFormat;
+	this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;
+
+};
+var Uniforms = {
+
+	clone: function( uniforms_src ) {
+
+		var u, p, parameter, parameter_src, uniforms_dst = {};
+
+		for ( u in uniforms_src ) {
+
+			uniforms_dst[ u ] = {};
+
+			for ( p in uniforms_src[ u ] ) {
+
+				parameter_src = uniforms_src[ u ][ p ];
+
+				if ( parameter_src instanceof THREE.Color ||
+					 parameter_src instanceof THREE.Vector3 ||
+					 parameter_src instanceof THREE.Texture ) {
+
+					uniforms_dst[ u ][ p ] = parameter_src.clone();
+
+				} else {
+
+					uniforms_dst[ u ][ p ] = parameter_src;
+
+				}
+
+			}
+
+		}
+
+		return uniforms_dst;
+
+	},
+	
+	merge: function( uniforms ) {
+		
+		var u, p, tmp, merged = {};
+		
+		for( u = 0; u < uniforms.length; u++ ) {
+			
+			tmp = this.clone( uniforms[ u ] );
+			
+			for ( p in tmp ) {
+				
+				merged[ p ] = tmp[ p ];
+			
+			}
+			
+		}
+		
+		return merged;
+		
+	}
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.CubeReflectionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.CubeRefractionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.LatitudeReflectionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.LatitudeRefractionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.SphericalReflectionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.SphericalRefractionMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.UVMapping = function () {
+
+
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Scene = function () {
+
+	this.objects = [];
+	this.lights = [];
+	this.fog = null;
+
+	this.addObject = function ( object ) {
+
+		var i = this.objects.indexOf( object );
+
+		if ( i === -1 ) {
+
+			this.objects.push( object );
+
+		}
+
+	};
+
+	this.removeObject = function ( object ) {
+
+		var i = this.objects.indexOf( object );
+
+		if ( i !== -1 ) {
+
+			this.objects.splice( i, 1 );
+
+		}
+
+	};
+
+	this.addLight = function ( light ) {
+
+		var i = this.lights.indexOf( light );
+
+		if ( i === -1 ) {
+
+			this.lights.push( light );
+
+		}
+
+	};
+
+	this.removeLight = function ( light ) {
+
+		var i = this.lights.indexOf( light );
+
+		if ( i !== -1 ) {
+
+			this.lights.splice( i, 1 );
+
+		}
+
+	};
+
+	this.toString = function () {
+
+		return 'THREE.Scene ( ' + this.objects + ' )';
+
+	};
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.Fog = function ( hex, near, far ) {
+
+	this.color = new THREE.Color( hex );
+	this.near = near || 1;
+	this.far = far || 1000;
+
+};
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.FogExp2 = function ( hex, density ) {
+
+	this.color = new THREE.Color( hex );
+	this.density = density || 0.00025;
+
+};
+/**
+ * @author supereggbert / http://www.paulbrunt.co.uk/
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.WebGLRenderer = function ( parameters ) {
+
+	// Currently you can use just up to 4 directional / point lights total.
+	// Chrome barfs on shader linking when there are more than 4 lights :(
+
+	// The problem comes from shader using too many varying vectors.
+
+	// This is not GPU limitation as the same shader works ok in Firefox
+	// and Chrome with "--use-gl=desktop" flag.
+
+	// Difference comes from Chrome on Windows using by default ANGLE,
+	// thus going DirectX9 route (while FF uses OpenGL).
+
+	// See http://code.google.com/p/chromium/issues/detail?id=63491
+
+	var _canvas = document.createElement( 'canvas' ), _gl,
+	_oldProgram = null,
+	_modelViewMatrix = new THREE.Matrix4(), _normalMatrix,
+
+	_viewMatrixArray = new Float32Array(16),
+	_modelViewMatrixArray = new Float32Array(16),
+	_projectionMatrixArray = new Float32Array(16),
+	_normalMatrixArray = new Float32Array(9),
+	_objectMatrixArray = new Float32Array(16),
+
+	// parameters defaults
+	
+	antialias = true,
+	clearColor = new THREE.Color( 0x000000 ),
+	clearAlpha = 0;
+
+	if ( parameters ) {
+		
+		if ( parameters.antialias !== undefined ) antialias = parameters.antialias;
+		if ( parameters.clearColor !== undefined ) clearColor.setHex( parameters.clearColor );
+		if ( parameters.clearAlpha !== undefined ) clearAlpha = parameters.clearAlpha;
+		
+	}
+		
+	this.domElement = _canvas;
+	this.autoClear = true;
+
+	initGL( antialias, clearColor, clearAlpha );
+
+	//alert( dumpObject( getGLParams() ) );
+
+	this.setSize = function ( width, height ) {
+
+		_canvas.width = width;
+		_canvas.height = height;
+		_gl.viewport( 0, 0, _canvas.width, _canvas.height );
+
+	};
+
+	this.setClearColor = function( hex, alpha ) {
+
+		var color = new THREE.Color( hex );
+		_gl.clearColor( color.r, color.g, color.b, alpha );
+
+	};
+
+	this.clear = function () {
+
+		_gl.clear( _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT );
+
+	};
+
+	this.setupLights = function ( program, lights ) {
+
+		var l, ll, light, r = 0, g = 0, b = 0,
+			dcolors = [], dpositions = [],
+			pcolors = [], ppositions = [];
+
+
+		for ( l = 0, ll = lights.length; l < ll; l++ ) {
+
+			light = lights[ l ];
+
+			if ( light instanceof THREE.AmbientLight ) {
+
+				r += light.color.r;
+				g += light.color.g;
+				b += light.color.b;
+				
+			} else if ( light instanceof THREE.DirectionalLight ) {
+
+				dcolors.push( light.color.r * light.intensity,
+							  light.color.g * light.intensity,
+							  light.color.b * light.intensity );
+
+				dpositions.push( light.position.x,
+								 light.position.y,
+								 light.position.z );
+
+			} else if( light instanceof THREE.PointLight ) {
+
+				pcolors.push( light.color.r * light.intensity,
+							  light.color.g * light.intensity,
+							  light.color.b * light.intensity );
+
+				ppositions.push( light.position.x,
+								 light.position.y,
+								 light.position.z );
+				
+			}
+
+		}
+		
+		return { ambient: [ r, g, b ], directional: { colors: dcolors, positions: dpositions }, point: { colors: pcolors, positions: ppositions } };
+
+	};
+
+	this.createParticleBuffers = function( object ) {
+	};
+	
+	this.createLineBuffers = function( object ) {
+		
+		var v, vl, vertex, 
+			vertexArray = [], lineArray = [], 
+			vertices = object.geometry.vertices;
+		
+		for ( v = 0, vl = vertices.length; v < vl; v++ ) {
+			
+			vertex = vertices[ v ].position;
+			vertexArray.push( vertex.x, vertex.y, vertex.z );
+			
+			lineArray.push( v );
+			
+		}
+			
+		if ( !vertexArray.length ) {
+
+			return;
+
+		}
+
+		object.__webGLVertexBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webGLVertexBuffer );
+		_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexArray ), _gl.STATIC_DRAW );
+		
+		object.__webGLLineBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, object.__webGLLineBuffer );
+		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( lineArray ), _gl.STATIC_DRAW );
+		
+		object.__webGLLineCount = lineArray.length;
+		
+	};
+	
+	this.createBuffers = function ( object, g ) {
+
+		var f, fl, fi, face, vertexNormals, faceNormal, normal, uv, v1, v2, v3, v4, t1, t2, t3, t4, m, ml, i,
+
+		faceArray = [],
+		lineArray = [],
+
+		vertexArray = [],
+		normalArray = [],
+		tangentArray = [],
+		uvArray = [],
+
+		vertexIndex = 0,
+
+		geometryChunk = object.geometry.geometryChunks[ g ],
+
+		needsSmoothNormals = bufferNeedsSmoothNormals ( geometryChunk, object );
+
+		for ( f = 0, fl = geometryChunk.faces.length; f < fl; f++ ) {
+
+			fi = geometryChunk.faces[ f ];
+
+			face = object.geometry.faces[ fi ];
+			vertexNormals = face.vertexNormals;
+			faceNormal = face.normal;
+			uv = object.geometry.uvs[ fi ];
+
+			if ( face instanceof THREE.Face3 ) {
+
+				v1 = object.geometry.vertices[ face.a ].position;
+				v2 = object.geometry.vertices[ face.b ].position;
+				v3 = object.geometry.vertices[ face.c ].position;
+
+				vertexArray.push( v1.x, v1.y, v1.z,
+								  v2.x, v2.y, v2.z,
+								  v3.x, v3.y, v3.z );
+
+				if ( object.geometry.hasTangents ) {
+
+					t1 = object.geometry.vertices[ face.a ].tangent;
+					t2 = object.geometry.vertices[ face.b ].tangent;
+					t3 = object.geometry.vertices[ face.c ].tangent;
+
+					tangentArray.push( t1.x, t1.y, t1.z, t1.w,
+									   t2.x, t2.y, t2.z, t2.w,
+									   t3.x, t3.y, t3.z, t3.w );
+
+				}
+
+				if ( vertexNormals.length == 3 && needsSmoothNormals ) {
+
+
+					for ( i = 0; i < 3; i ++ ) {
+
+						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
+
+					}
+
+				} else {
+
+					for ( i = 0; i < 3; i ++ ) {
+
+						normalArray.push( faceNormal.x, faceNormal.y, faceNormal.z );
+
+					}
+
+				}
+
+				if ( uv ) {
+
+					for ( i = 0; i < 3; i ++ ) {
+
+						uvArray.push( uv[ i ].u, uv[ i ].v );
+
+					}
+
+				}
+
+				faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2 );
+
+				// TODO: don't add lines that already exist (faces sharing edge)
+
+				lineArray.push( vertexIndex, vertexIndex + 1,
+								vertexIndex, vertexIndex + 2,
+								vertexIndex + 1, vertexIndex + 2 );
+
+				vertexIndex += 3;
+
+			} else if ( face instanceof THREE.Face4 ) {
+
+				v1 = object.geometry.vertices[ face.a ].position;
+				v2 = object.geometry.vertices[ face.b ].position;
+				v3 = object.geometry.vertices[ face.c ].position;
+				v4 = object.geometry.vertices[ face.d ].position;
+
+				vertexArray.push( v1.x, v1.y, v1.z,
+								  v2.x, v2.y, v2.z,
+								  v3.x, v3.y, v3.z,
+								  v4.x, v4.y, v4.z );
+
+				if ( object.geometry.hasTangents ) {
+
+					t1 = object.geometry.vertices[ face.a ].tangent;
+					t2 = object.geometry.vertices[ face.b ].tangent;
+					t3 = object.geometry.vertices[ face.c ].tangent;
+					t4 = object.geometry.vertices[ face.d ].tangent;
+
+					tangentArray.push( t1.x, t1.y, t1.z, t1.w,
+									   t2.x, t2.y, t2.z, t2.w,
+									   t3.x, t3.y, t3.z, t3.w,
+									   t4.x, t4.y, t4.z, t4.w );
+
+				}
+
+				if ( vertexNormals.length == 4 && needsSmoothNormals ) {
+
+					for ( i = 0; i < 4; i ++ ) {
+
+						normalArray.push( vertexNormals[ i ].x, vertexNormals[ i ].y, vertexNormals[ i ].z );
+
+					}
+
+				} else {
+
+					for ( i = 0; i < 4; i ++ ) {
+
+						normalArray.push( faceNormal.x, faceNormal.y, faceNormal.z );
+
+					}
+
+				}
+
+				if ( uv ) {
+
+					for ( i = 0; i < 4; i ++ ) {
+
+						uvArray.push( uv[ i ].u, uv[ i ].v );
+
+					}
+
+				}
+
+				faceArray.push( vertexIndex, vertexIndex + 1, vertexIndex + 2,
+								vertexIndex, vertexIndex + 2, vertexIndex + 3 );
+
+				// TODO: don't add lines that already exist (faces sharing edge)
+
+				lineArray.push( vertexIndex, vertexIndex + 1,
+								vertexIndex, vertexIndex + 2,
+								vertexIndex, vertexIndex + 3,
+								vertexIndex + 1, vertexIndex + 2,
+								vertexIndex + 2, vertexIndex + 3 );
+
+				vertexIndex += 4;
+
+			}
+
+		}
+
+		if ( !vertexArray.length ) {
+
+			return;
+
+		}
+
+		geometryChunk.__webGLVertexBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLVertexBuffer );
+		_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( vertexArray ), _gl.STATIC_DRAW );
+
+		geometryChunk.__webGLNormalBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
+		_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( normalArray ), _gl.STATIC_DRAW );
+
+		if ( object.geometry.hasTangents ) {
+
+			geometryChunk.__webGLTangentBuffer = _gl.createBuffer();
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLTangentBuffer );
+			_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( tangentArray ), _gl.STATIC_DRAW );
+
+		}
+
+		if ( uvArray.length > 0 ) {
+
+			geometryChunk.__webGLUVBuffer = _gl.createBuffer();
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLUVBuffer );
+			_gl.bufferData( _gl.ARRAY_BUFFER, new Float32Array( uvArray ), _gl.STATIC_DRAW );
+
+		}
+
+		geometryChunk.__webGLFaceBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLFaceBuffer );
+		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( faceArray ), _gl.STATIC_DRAW );
+
+		geometryChunk.__webGLLineBuffer = _gl.createBuffer();
+		_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLLineBuffer );
+		_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( lineArray ), _gl.STATIC_DRAW );
+
+		geometryChunk.__webGLFaceCount = faceArray.length;
+		geometryChunk.__webGLLineCount = lineArray.length;
+
+	};
+
+	function setMaterialShaders( material, shaders ) {
+
+		material.fragment_shader = shaders.fragment_shader;
+		material.vertex_shader = shaders.vertex_shader;
+		material.uniforms = Uniforms.clone( shaders.uniforms );
+
+	};
+
+	function refreshUniformsCommon( material, fog ) {
+		
+		// premultiply alpha
+		material.uniforms.color.value.setRGB( material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity );
+		
+		// pure color
+		//material.uniforms.color.value.setHex( material.color.hex );
+		
+		material.uniforms.opacity.value = material.opacity;
+		material.uniforms.map.texture = material.map;
+
+		material.uniforms.env_map.texture = material.env_map;
+		material.uniforms.reflectivity.value = material.reflectivity;
+		material.uniforms.refraction_ratio.value = material.refraction_ratio;
+		material.uniforms.combine.value = material.combine;
+		material.uniforms.useRefract.value = material.env_map && material.env_map.mapping instanceof THREE.CubeRefractionMapping;
+
+		if ( fog ) {
+
+			material.uniforms.fogColor.value.setHex( fog.color.hex );
+
+			if ( fog instanceof THREE.Fog ) {
+
+				material.uniforms.fogNear.value = fog.near;
+				material.uniforms.fogFar.value = fog.far;
+
+			} else if ( fog instanceof THREE.FogExp2 ) {
+
+				material.uniforms.fogDensity.value = fog.density;
+
+			}
+
+		}
+
+	};
+
+	function refreshUniformsLine( material, fog ) {
+		
+		material.uniforms.color.value.setRGB( material.color.r * material.opacity, material.color.g * material.opacity, material.color.b * material.opacity );		
+		material.uniforms.opacity.value = material.opacity;
+
+		if ( fog ) {
+
+			material.uniforms.fogColor.value.setHex( fog.color.hex );
+
+			if ( fog instanceof THREE.Fog ) {
+
+				material.uniforms.fogNear.value = fog.near;
+				material.uniforms.fogFar.value = fog.far;
+
+			} else if ( fog instanceof THREE.FogExp2 ) {
+
+				material.uniforms.fogDensity.value = fog.density;
+
+			}
+
+		}
+
+	};
+	
+	function refreshUniformsPhong( material ) {
+		
+		//material.uniforms.ambient.value.setHex( material.ambient.hex );
+		//material.uniforms.specular.value.setHex( material.specular.hex );
+		material.uniforms.ambient.value.setRGB( material.ambient.r, material.ambient.g, material.ambient.b );
+		material.uniforms.specular.value.setRGB( material.specular.r, material.specular.g, material.specular.b );
+		material.uniforms.shininess.value = material.shininess;
+		
+	};
+	
+	
+	function refreshLights( material, lights ) {
+		
+		material.uniforms.enableLighting.value = lights.directional.positions.length + lights.point.positions.length;
+		material.uniforms.ambientLightColor.value = lights.ambient;
+		material.uniforms.directionalLightColor.value = lights.directional.colors;
+		material.uniforms.directionalLightDirection.value = lights.directional.positions;
+		material.uniforms.pointLightColor.value = lights.point.colors;
+		material.uniforms.pointLightPosition.value = lights.point.positions;
+		
+	};
+	
+	this.renderBuffer = function ( camera, lights, fog, material, geometryChunk ) {
+
+		var program, u, identifiers, attributes, parameters, vector_lights, maxLightCount, linewidth, primitives;
+
+		if ( !material.program ) {
+
+			if ( material instanceof THREE.MeshDepthMaterial ) {
+
+				setMaterialShaders( material, THREE.ShaderLib[ 'depth' ] );
+
+				material.uniforms.mNear.value = camera.near;
+				material.uniforms.mFar.value = camera.far;
+
+			} else if ( material instanceof THREE.MeshNormalMaterial ) {
+
+				setMaterialShaders( material, THREE.ShaderLib[ 'normal' ] );
+
+			} else if ( material instanceof THREE.MeshBasicMaterial ) {
+
+				setMaterialShaders( material, THREE.ShaderLib[ 'basic' ] );
+
+				refreshUniformsCommon( material, fog );
+				
+			} else if ( material instanceof THREE.MeshLambertMaterial ) {
+				
+				setMaterialShaders( material, THREE.ShaderLib[ 'lambert' ] );
+				
+				refreshUniformsCommon( material, fog );
+				
+			} else if ( material instanceof THREE.MeshPhongMaterial ) {
+				
+				setMaterialShaders( material, THREE.ShaderLib[ 'phong' ] );
+				
+				refreshUniformsCommon( material, fog );
+				
+			} else if ( material instanceof THREE.LineBasicMaterial ) {
+				
+				setMaterialShaders( material, THREE.ShaderLib[ 'basic' ] );
+
+				refreshUniformsLine( material, fog );
+				
+			}
+
+			// heuristics to create shader parameters according to lights in the scene
+			// (not to blow over maxLights budget)
+
+			maxLightCount = allocateLights( lights, 4 );
+
+			parameters = { fog: fog, map: material.map, env_map: material.env_map, maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point };
+			material.program = buildProgram( material.fragment_shader, material.vertex_shader, parameters );
+
+			identifiers = [ 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'objectMatrix', 'cameraPosition' ];
+			for( u in material.uniforms ) {
+
+				identifiers.push(u);
+
+			}
+
+			cacheUniformLocations( material.program, identifiers );
+			cacheAttributeLocations( material.program, [ "position", "normal", "uv", "tangent" ] );
+
+		}
+
+		program = material.program;
+
+		if( program != _oldProgram ) {
+
+			_gl.useProgram( program );
+			_oldProgram = program;
+
+		}
+
+		this.loadCamera( program, camera );
+		this.loadMatrices( program );
+
+		if ( material instanceof THREE.MeshPhongMaterial || 
+			 material instanceof THREE.MeshLambertMaterial ) {
+
+			vector_lights = this.setupLights( program, lights );
+			refreshLights( material, vector_lights );
+
+		}
+
+		if ( material instanceof THREE.MeshBasicMaterial ||
+			 material instanceof THREE.MeshLambertMaterial ||
+			 material instanceof THREE.MeshPhongMaterial ) {
+			
+			refreshUniformsCommon( material, fog );
+
+		}
+		
+		if ( material instanceof THREE.LineBasicMaterial ) {
+			
+			refreshUniformsLine( material, fog );
+		}
+		
+		if ( material instanceof THREE.MeshPhongMaterial ) {
+			
+			refreshUniformsPhong( material );
+
+		}
+
+		setUniforms( program, material.uniforms );
+
+		attributes = program.attributes;
+
+		// vertices
+
+		_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLVertexBuffer );
+		_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+		_gl.enableVertexAttribArray( attributes.position );
+
+		// normals
+
+		if ( attributes.normal >= 0 ) {
+
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLNormalBuffer );
+			_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.enableVertexAttribArray( attributes.normal );
+
+		}
+
+		// tangents
+
+		if ( attributes.tangent >= 0 ) {
+
+			_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLTangentBuffer );
+			_gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 );
+			_gl.enableVertexAttribArray( attributes.tangent );
+
+		}
+
+		// uvs
+
+		if ( attributes.uv >= 0 ) {
+
+			if ( geometryChunk.__webGLUVBuffer ) {
+
+				_gl.bindBuffer( _gl.ARRAY_BUFFER, geometryChunk.__webGLUVBuffer );
+				_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
+
+				_gl.enableVertexAttribArray( attributes.uv );
+
+			} else {
+
+				_gl.disableVertexAttribArray( attributes.uv );
+
+			}
+
+		}
+
+		// render lines
+
+		if ( material.wireframe || material instanceof THREE.LineBasicMaterial ) {
+
+			linewidth = material.wireframe_linewidth !== undefined ? material.wireframe_linewidth : 
+					    material.linewidth !== undefined ? material.linewidth : 1;
+			
+			primitives = material instanceof THREE.LineBasicMaterial && geometryChunk.type == THREE.LineStrip ? _gl.LINE_STRIP : _gl.LINES;
+			
+			_gl.lineWidth( linewidth );
+			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLLineBuffer );
+			_gl.drawElements( primitives, geometryChunk.__webGLLineCount, _gl.UNSIGNED_SHORT, 0 );
+
+		// render triangles
+
+		} else {
+
+			_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryChunk.__webGLFaceBuffer );
+			_gl.drawElements( _gl.TRIANGLES, geometryChunk.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 );
+
+		}
+
+	};
+
+	this.renderPass = function ( camera, lights, fog, object, geometryChunk, blending, transparent ) {
+
+		var i, l, m, ml, material, meshMaterial;
+
+		for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
+
+			meshMaterial = object.materials[ m ];
+
+			if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
+
+				for ( i = 0, l = geometryChunk.materials.length; i < l; i++ ) {
+
+					material = geometryChunk.materials[ i ];
+
+					if ( material && material.blending == blending && ( material.opacity < 1.0 == transparent ) ) {
+
+						this.setBlending( material.blending );
+						this.renderBuffer( camera, lights, fog, material, geometryChunk );
+
+					}
+
+				}
+
+			} else {
+
+				material = meshMaterial;
+				if ( material && material.blending == blending && ( material.opacity < 1.0 == transparent ) ) {
+
+					this.setBlending( material.blending );
+					this.renderBuffer( camera, lights, fog, material, geometryChunk );
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.render = function( scene, camera, renderTarget ) {
+
+		var o, ol, webGLObject, object, buffer,
+			lights = scene.lights,
+			fog = scene.fog;
+
+		this.initWebGLObjects( scene );
+
+		setRenderTarget( renderTarget );
+
+		if ( this.autoClear ) {
+
+			this.clear();
+
+		}
+
+		camera.autoUpdateMatrix && camera.updateMatrix();
+
+		_viewMatrixArray.set( camera.matrix.flatten() );
+		_projectionMatrixArray.set( camera.projectionMatrix.flatten() );
+		
+		// opaque pass
+
+		for ( o = 0, ol = scene.__webGLObjects.length; o < ol; o++ ) {
+
+			webGLObject = scene.__webGLObjects[ o ];
+
+			object = webGLObject.object;
+			buffer = webGLObject.buffer;
+
+			if ( object.visible ) {
+
+				this.setupMatrices( object, camera );
+				this.renderPass( camera, lights, fog, object, buffer, THREE.NormalBlending, false );
+
+			}
+
+		}
+
+		// transparent pass
+
+		for ( o = 0, ol = scene.__webGLObjects.length; o < ol; o++ ) {
+
+			webGLObject = scene.__webGLObjects[ o ];
+
+			object = webGLObject.object;
+			buffer = webGLObject.buffer;
+
+			if ( object.visible ) {
+
+				this.setupMatrices( object, camera );
+
+				// opaque blended materials
+
+				this.renderPass( camera, lights, fog, object, buffer, THREE.AdditiveBlending, false );
+				this.renderPass( camera, lights, fog, object, buffer, THREE.SubtractiveBlending, false );
+
+				// transparent blended materials
+
+				this.renderPass( camera, lights, fog, object, buffer, THREE.AdditiveBlending, true );
+				this.renderPass( camera, lights, fog, object, buffer, THREE.SubtractiveBlending, true );
+
+				// transparent normal materials
+
+				this.renderPass( camera, lights, fog, object, buffer, THREE.NormalBlending, true );
+
+			}
+
+		}
+
+	};
+
+	this.initWebGLObjects = function( scene ) {
+
+		function add_buffer( objmap, id, buffer, object ) {
+			
+			if ( objmap[ id ] == undefined ) {
+
+				scene.__webGLObjects.push( { buffer: buffer, object: object } );
+				objmap[ id ] = 1;
+
+			}
+			
+		};
+		
+		var o, ol, object, g, geometryChunk, objmap;
+
+		if ( !scene.__webGLObjects ) {
+
+			scene.__webGLObjects = [];
+			scene.__webGLObjectsMap = {};
+
+		}
+		
+		for ( o = 0, ol = scene.objects.length; o < ol; o++ ) {
+
+			object = scene.objects[ o ];
+
+			if ( scene.__webGLObjectsMap[ object.id ] == undefined ) {
+
+				scene.__webGLObjectsMap[ object.id ] = {};
+
+			}
+
+			objmap = scene.__webGLObjectsMap[ object.id ];
+			
+			if ( object instanceof THREE.Mesh ) {
+				
+				// create separate VBOs per geometry chunk
+
+				for ( g in object.geometry.geometryChunks ) {
+
+					geometryChunk = object.geometry.geometryChunks[ g ];
+
+					// initialise VBO on the first access
+
+					if( ! geometryChunk.__webGLVertexBuffer ) {
+
+						this.createBuffers( object, g );
+
+					}
+
+					// create separate wrapper per each use of VBO
+
+					add_buffer( objmap, g, geometryChunk, object );
+
+				}
+
+			} else if ( object instanceof THREE.Line ) {
+				
+				
+				if( ! object.__webGLVertexBuffer ) {
+				
+					this.createLineBuffers( object );
+					
+				}
+				
+				add_buffer( objmap, 0, object, object );
+				
+
+			} else if ( object instanceof THREE.ParticleSystem ) {
+
+				if( ! object.__webGLVertexBuffer ) {
+				
+					this.createParticleBuffers( object );
+					
+				}
+				
+				add_buffer( objmap, 0, object, object );
+				
+				
+			}/*else if ( object instanceof THREE.Particle ) {
+
+			}*/
+
+		}
+
+	};
+
+	this.removeObject = function ( scene, object ) {
+
+		var o, ol, zobject;
+
+		for ( o = scene.__webGLObjects.length - 1; o >= 0; o-- ) {
+
+			zobject = scene.__webGLObjects[ o ].object;
+
+			if ( object == zobject ) {
+
+				scene.__webGLObjects.splice( o, 1 );
+
+			}
+
+		}
+
+	};
+
+	this.setupMatrices = function ( object, camera ) {
+
+		object.autoUpdateMatrix && object.updateMatrix();
+
+		_modelViewMatrix.multiply( camera.matrix, object.matrix );
+		_modelViewMatrixArray.set( _modelViewMatrix.flatten() );
+
+		_normalMatrix = THREE.Matrix4.makeInvert3x3( _modelViewMatrix ).transpose();
+		_normalMatrixArray.set( _normalMatrix.m );
+
+		_objectMatrixArray.set( object.matrix.flatten() );
+
+	};
+
+	this.loadMatrices = function ( program ) {
+
+		_gl.uniformMatrix4fv( program.uniforms.viewMatrix, false, _viewMatrixArray );
+		_gl.uniformMatrix4fv( program.uniforms.modelViewMatrix, false, _modelViewMatrixArray );
+		_gl.uniformMatrix4fv( program.uniforms.projectionMatrix, false, _projectionMatrixArray );
+		_gl.uniformMatrix3fv( program.uniforms.normalMatrix, false, _normalMatrixArray );
+		_gl.uniformMatrix4fv( program.uniforms.objectMatrix, false, _objectMatrixArray );
+
+	};
+
+	this.loadCamera = function( program, camera ) {
+
+		_gl.uniform3f( program.uniforms.cameraPosition, camera.position.x, camera.position.y, camera.position.z );
+
+	};
+
+	this.setBlending = function( blending ) {
+
+		switch ( blending ) {
+
+			case THREE.AdditiveBlending:
+
+				_gl.blendEquation( _gl.FUNC_ADD );
+				_gl.blendFunc( _gl.ONE, _gl.ONE );
+
+				break;
+
+			case THREE.SubtractiveBlending:
+
+				//_gl.blendEquation( _gl.FUNC_SUBTRACT );
+				_gl.blendFunc( _gl.DST_COLOR, _gl.ZERO );
+
+				break;
+
+			default:
+
+				_gl.blendEquation( _gl.FUNC_ADD );
+				_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
+
+				break;
+		}
+
+	};
+
+	this.setFaceCulling = function ( cullFace, frontFace ) {
+
+		if ( cullFace ) {
+
+			if ( !frontFace || frontFace == "ccw" ) {
+
+				_gl.frontFace( _gl.CCW );
+
+			} else {
+
+				_gl.frontFace( _gl.CW );
+
+			}
+
+			if( cullFace == "back" ) {
+
+				_gl.cullFace( _gl.BACK );
+
+			} else if( cullFace == "front" ) {
+
+				_gl.cullFace( _gl.FRONT );
+
+			} else {
+
+				_gl.cullFace( _gl.FRONT_AND_BACK );
+
+			}
+
+			_gl.enable( _gl.CULL_FACE );
+
+		} else {
+
+			_gl.disable( _gl.CULL_FACE );
+
+		}
+
+	};
+
+	this.supportsVertexTextures = function() {
+
+		return maxVertexTextures() > 0;
+
+	};
+
+	function maxVertexTextures() {
+
+		return _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
+
+	};
+
+	function initGL( antialias, clearColor, clearAlpha ) {
+
+		try {
+
+			_gl = _canvas.getContext( 'experimental-webgl', { antialias: antialias } );
+
+		} catch(e) { }
+
+		if (!_gl) {
+
+			alert("WebGL not supported");
+			throw "cannot create webgl context";
+
+		}
+
+		_gl.clearColor( 0, 0, 0, 1 );
+		_gl.clearDepth( 1 );
+
+		_gl.enable( _gl.DEPTH_TEST );
+		_gl.depthFunc( _gl.LEQUAL );
+
+		_gl.frontFace( _gl.CCW );
+		_gl.cullFace( _gl.BACK );
+		_gl.enable( _gl.CULL_FACE );
+
+		_gl.enable( _gl.BLEND );
+		_gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
+		_gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
+
+	};
+	
+	function buildProgram( fragment_shader, vertex_shader, parameters ) {
+
+		var program = _gl.createProgram(),
+
+		prefix_fragment = [
+			"#ifdef GL_ES",
+			"precision highp float;",
+			"#endif",
+		
+			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
+			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
+
+			parameters.fog ? "#define USE_FOG" : "",
+			parameters.fog instanceof THREE.FogExp2 ? "#define FOG_EXP2" : "",
+
+			parameters.map ? "#define USE_MAP" : "",
+			parameters.env_map ? "#define USE_ENVMAP" : "",
+
+			"uniform mat4 viewMatrix;",
+			"uniform vec3 cameraPosition;",
+			""
+		].join("\n"),
+
+		prefix_vertex = [
+			maxVertexTextures() > 0 ? "#define VERTEX_TEXTURES" : "",
+
+			"#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
+			"#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
+
+			parameters.map ? "#define USE_MAP" : "",
+			parameters.env_map ? "#define USE_ENVMAP" : "",
+
+			"uniform mat4 objectMatrix;",
+			"uniform mat4 modelViewMatrix;",
+			"uniform mat4 projectionMatrix;",
+			"uniform mat4 viewMatrix;",
+			"uniform mat3 normalMatrix;",
+			"uniform vec3 cameraPosition;",
+			"attribute vec3 position;",
+			"attribute vec3 normal;",
+			"attribute vec2 uv;",
+			""
+		].join("\n");
+
+		_gl.attachShader( program, getShader( "fragment", prefix_fragment + fragment_shader ) );
+		_gl.attachShader( program, getShader( "vertex", prefix_vertex + vertex_shader ) );
+
+		_gl.linkProgram( program );
+
+		if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
+
+			alert( "Could not initialise shaders\n"+
+					"VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
+			
+			//console.log( prefix_fragment + fragment_shader );
+			//console.log( prefix_vertex + vertex_shader );
+
+		}
+
+		program.uniforms = {};
+		program.attributes = {};
+
+		return program;
+
+	};
+
+	function setUniforms( program, uniforms ) {
+
+		var u, value, type, location, texture;
+
+		for( u in uniforms ) {
+
+			location = program.uniforms[u];
+			if ( !location ) continue;
+			
+			type = uniforms[u].type;
+			value = uniforms[u].value;
+			
+			if( type == "i" ) {
+
+				_gl.uniform1i( location, value );
+
+			} else if( type == "f" ) {
+
+				_gl.uniform1f( location, value );
+
+			} else if( type == "fv" ) {
+
+				_gl.uniform3fv( location, value );
+
+			} else if( type == "v2" ) {
+
+				_gl.uniform2f( location, value.x, value.y );
+
+			} else if( type == "v3" ) {
+
+				_gl.uniform3f( location, value.x, value.y, value.z );
+
+			} else if( type == "c" ) {
+
+				_gl.uniform3f( location, value.r, value.g, value.b );
+
+			} else if( type == "t" ) {
+
+				_gl.uniform1i( location, value );
+
+				texture = uniforms[u].texture;
+
+				if ( !texture ) continue;
+
+				if ( texture.image instanceof Array && texture.image.length == 6 ) {
+
+					setCubeTexture( texture, value );
+
+				} else {
+
+					setTexture( texture, value );
+
+				}
+
+			}
+
+		}
+
+	};
+
+	function setCubeTexture( texture, slot ) {
+
+		if ( texture.image.length == 6 ) {
+
+			if ( !texture.image.__webGLTextureCube &&
+				 !texture.image.__cubeMapInitialized && texture.image.loadCount == 6 ) {
+
+				texture.image.__webGLTextureCube = _gl.createTexture();
+
+				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube );
+
+				_gl.texParameteri( _gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
+				_gl.texParameteri( _gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
+
+				_gl.texParameteri( _gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MAG_FILTER, _gl.LINEAR );
+				_gl.texParameteri( _gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_LINEAR );
+
+				for ( var i = 0; i < 6; ++i ) {
+
+					_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image[ i ] );
+
+				}
+
+				_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
+
+				_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
+
+				texture.image.__cubeMapInitialized = true;
+
+			}
+
+			_gl.activeTexture( _gl.TEXTURE0 + slot );
+			_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webGLTextureCube );
+
+		}
+
+	};
+
+	function setTexture( texture, slot ) {
+
+		if ( !texture.__webGLTexture && texture.image.loaded ) {
+
+			texture.__webGLTexture = _gl.createTexture();
+			_gl.bindTexture( _gl.TEXTURE_2D, texture.__webGLTexture );
+			_gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image );
+
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrap_s ) );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrap_t ) );
+
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.mag_filter ) );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.min_filter ) );
+			_gl.generateMipmap( _gl.TEXTURE_2D );
+			_gl.bindTexture( _gl.TEXTURE_2D, null );
+
+		}
+
+		_gl.activeTexture( _gl.TEXTURE0 + slot );
+		_gl.bindTexture( _gl.TEXTURE_2D, texture.__webGLTexture );
+
+	};
+
+	function setRenderTarget( renderTexture ) {
+
+		var framebuffer;
+
+		if ( renderTexture && !renderTexture.__webGLFramebuffer ) {
+			renderTexture.__webGLFramebuffer = _gl.createFramebuffer();
+			renderTexture.__webGLRenderbuffer = _gl.createRenderbuffer();
+			renderTexture.__webGLTexture = _gl.createTexture();
+
+			// Setup renderbuffer
+			_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer );
+			_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTexture.width, renderTexture.height );
+
+			// Setup texture
+			_gl.bindTexture( _gl.TEXTURE_2D, renderTexture.__webGLTexture );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, paramThreeToGL( renderTexture.wrap_s ) );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, paramThreeToGL( renderTexture.wrap_t ) );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( renderTexture.mag_filter ) );
+			_gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( renderTexture.min_filter ) );
+			_gl.generateMipmap(_gl.TEXTURE_2D);
+			_gl.texImage2D( _gl.TEXTURE_2D, 0, paramThreeToGL( renderTexture.format ), renderTexture.width, renderTexture.height, 0, paramThreeToGL( renderTexture.format ), paramThreeToGL( renderTexture.type ), null);
+
+			// Setup framebuffer
+			_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTexture.__webGLFramebuffer );
+			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, renderTexture.__webGLTexture, 0 );
+			_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTexture.__webGLRenderbuffer);
+
+			// Release everything
+			_gl.bindTexture( _gl.TEXTURE_2D, null );
+			_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
+			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null);
+		}
+
+		framebuffer = renderTexture ? renderTexture.__webGLFramebuffer : null;
+		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+
+	}
+
+	function cacheUniformLocations( program, identifiers ) {
+
+		var i, l, id;
+
+		for( i = 0, l = identifiers.length; i < l; i++ ) {
+
+			id = identifiers[ i ];
+			program.uniforms[ id ] = _gl.getUniformLocation( program, id );
+
+		}
+
+	};
+
+	function cacheAttributeLocations( program, identifiers ) {
+
+		var i, l, id;
+
+		for( i = 0, l = identifiers.length; i < l; i++ ) {
+
+			id = identifiers[ i ];
+			program.attributes[ id ] = _gl.getAttribLocation( program, id );
+
+		}
+
+	};
+
+	function getShader( type, string ) {
+
+		var shader;
+
+		if ( type == "fragment" ) {
+
+			shader = _gl.createShader( _gl.FRAGMENT_SHADER );
+
+		} else if ( type == "vertex" ) {
+
+			shader = _gl.createShader( _gl.VERTEX_SHADER );
+
+		}
+
+		_gl.shaderSource( shader, string );
+		_gl.compileShader( shader );
+
+		if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
+
+			alert( _gl.getShaderInfoLog( shader ) );
+			return null;
+
+		}
+
+		return shader;
+
+	};
+
+	function paramThreeToGL( p ) {
+
+		switch ( p ) {
+
+			case THREE.RepeatWrapping: return _gl.REPEAT; break;
+			case THREE.ClampToEdgeWrapping: return _gl.CLAMP_TO_EDGE; break;
+			case THREE.MirroredRepeatWrapping: return _gl.MIRRORED_REPEAT; break;
+
+			case THREE.NearestFilter: return _gl.NEAREST; break;
+			case THREE.NearestMipMapNearestFilter: return _gl.NEAREST_MIPMAP_NEAREST; break;
+			case THREE.NearestMipMapLinearFilter: return _gl.NEAREST_MIPMAP_LINEAR; break;
+
+			case THREE.LinearFilter: return _gl.LINEAR; break;
+			case THREE.LinearMipMapNearestFilter: return _gl.LINEAR_MIPMAP_NEAREST; break;
+			case THREE.LinearMipMapLinearFilter: return _gl.LINEAR_MIPMAP_LINEAR; break;
+
+			case THREE.RGBFormat: return _gl.RGB; break;
+
+			case THREE.UnsignedByteType: return _gl.UNSIGNED_BYTE; break;
+
+		}
+
+		return 0;
+
+	};
+
+	function materialNeedsSmoothNormals( material ) {
+
+		return material && material.shading != undefined && material.shading == THREE.SmoothShading;
+
+	};
+
+	function bufferNeedsSmoothNormals( geometryChunk, object ) {
+
+		var m, ml, i, l, meshMaterial, needsSmoothNormals = false;
+
+		for ( m = 0, ml = object.materials.length; m < ml; m++ ) {
+
+			meshMaterial = object.materials[ m ];
+
+			if ( meshMaterial instanceof THREE.MeshFaceMaterial ) {
+
+				for ( i = 0, l = geometryChunk.materials.length; i < l; i++ ) {
+
+					if ( materialNeedsSmoothNormals( geometryChunk.materials[ i ] ) ) {
+
+						needsSmoothNormals = true;
+						break;
+
+					}
+
+				}
+
+			} else {
+
+				if ( materialNeedsSmoothNormals( meshMaterial ) ) {
+
+					needsSmoothNormals = true;
+					break;
+
+				}
+
+			}
+
+			if ( needsSmoothNormals ) break;
+
+		}
+
+		return needsSmoothNormals;
+
+	};
+
+	function allocateLights( lights, maxLights ) {
+
+		var l, ll, light, dirLights, pointLights, maxDirLights, maxPointLights;
+		dirLights = pointLights = maxDirLights = maxPointLights = 0;
+
+		for ( l = 0, ll = lights.length; l < ll; l++ ) {
+
+			light = lights[ l ];
+
+			if ( light instanceof THREE.DirectionalLight ) dirLights++;
+			if ( light instanceof THREE.PointLight ) pointLights++;
+
+		}
+
+		if ( ( pointLights + dirLights ) <= maxLights ) {
+
+			maxDirLights = dirLights;
+			maxPointLights = pointLights;
+
+		} else {
+
+			maxDirLights = Math.ceil( maxLights * dirLights / ( pointLights + dirLights ) );
+			maxPointLights = maxLights - maxDirLights;
+
+		}
+
+		return { 'directional' : maxDirLights, 'point' : maxPointLights };
+
+	};
+
+	/* DEBUG
+	function getGLParams() {
+
+		var params  = {
+
+			'MAX_VARYING_VECTORS': _gl.getParameter( _gl.MAX_VARYING_VECTORS ),
+			'MAX_VERTEX_ATTRIBS': _gl.getParameter( _gl.MAX_VERTEX_ATTRIBS ),
+
+			'MAX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ),
+			'MAX_VERTEX_TEXTURE_IMAGE_UNITS': _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ),
+			'MAX_COMBINED_TEXTURE_IMAGE_UNITS' : _gl.getParameter( _gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ),
+
+			'MAX_VERTEX_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ),
+			'MAX_FRAGMENT_UNIFORM_VECTORS': _gl.getParameter( _gl.MAX_FRAGMENT_UNIFORM_VECTORS )
+		}
+
+		return params;
+	};
+
+	function dumpObject( obj ) {
+
+		var p, str = "";
+		for ( p in obj ) {
+
+			str += p + ": " + obj[p] + "\n";
+
+		}
+
+		return str;
+	}
+	*/
+
+};
+
+THREE.Snippets = {
+	
+	fog_pars_fragment: [
+
+	"#ifdef USE_FOG",
+
+		"uniform vec3 fogColor;",
+
+		"#ifdef FOG_EXP2",
+			"uniform float fogDensity;",
+		"#else",
+			"uniform float fogNear;",
+			"uniform float fogFar;",
+		"#endif",
+
+	"#endif"
+
+	].join("\n"),
+
+	fog_fragment: [
+
+	"#ifdef USE_FOG",
+
+		"float depth = gl_FragCoord.z / gl_FragCoord.w;",
+
+		"#ifdef FOG_EXP2",
+			"const float LOG2 = 1.442695;",
+			"float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
+			"fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
+		"#else",
+			"float fogFactor = smoothstep( fogNear, fogFar, depth );",
+		"#endif",
+
+		"gl_FragColor = mix( gl_FragColor, vec4( fogColor, 1.0 ), fogFactor );",
+
+	"#endif"
+	
+	].join("\n"),
+	
+	envmap_pars_fragment: [
+	
+	"#ifdef USE_ENVMAP",
+	
+		"varying vec3 vReflect;",
+		"uniform float reflectivity;",
+		"uniform samplerCube env_map;",
+		"uniform int combine;",
+	
+	"#endif"
+	
+	].join("\n"),
+	
+	envmap_fragment: [
+	
+	"#ifdef USE_ENVMAP",
+
+		"cubeColor = textureCube( env_map, vec3( -vReflect.x, vReflect.yz ) );",
+		
+		"if ( combine == 1 ) {",
+
+			"gl_FragColor = mix( gl_FragColor, cubeColor, reflectivity );",
+
+		"} else {",
+
+			"gl_FragColor = gl_FragColor * cubeColor;",
+
+		"}",	
+
+	"#endif"
+	
+	].join("\n"),
+	
+	envmap_pars_vertex: [
+	
+	"#ifdef USE_ENVMAP",
+	
+		"varying vec3 vReflect;",
+		"uniform float refraction_ratio;",
+		"uniform bool useRefract;",
+		
+	"#endif"
+	
+	].join("\n"),
+
+	envmap_vertex : [
+	
+	"#ifdef USE_ENVMAP",
+	
+		"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+		"vec3 nWorld = mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal;",
+	
+		"if ( useRefract ) {",
+
+			"vReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refraction_ratio );",
+
+		"} else {",
+
+			"vReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );",
+
+		"}",
+
+	"#endif"
+	
+	].join("\n"),
+	
+	map_pars_fragment: [
+	
+	"#ifdef USE_MAP",
+		
+		"varying vec2 vUv;",
+		"uniform sampler2D map;",
+		  
+	"#endif"
+	
+	].join("\n"),
+	
+	map_pars_vertex: [
+	
+	"#ifdef USE_MAP",
+	
+		"varying vec2 vUv;",
+
+	"#endif"
+	
+	].join("\n"),
+	
+	map_fragment: [
+
+	"#ifdef USE_MAP",
+
+		"mapColor = texture2D( map, vUv );",
+
+	"#endif"
+	
+	].join("\n"),
+	
+	map_vertex: [
+	
+	"#ifdef USE_MAP",
+	
+		"vUv = uv;",
+		
+	"#endif"
+	
+	].join("\n"),
+	
+	lights_pars_vertex: [
+	
+	"uniform bool enableLighting;",
+	"uniform vec3 ambientLightColor;",
+	
+	"#if MAX_DIR_LIGHTS > 0",
+	
+		"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
+		"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
+		
+	"#endif",
+
+	"#if MAX_POINT_LIGHTS > 0",
+	
+		"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
+		"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
+		
+		"#ifdef PHONG",
+			"varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];",
+		"#endif",
+		
+	"#endif"
+	
+	].join("\n"),
+	
+	lights_vertex: [
+	
+	"if ( !enableLighting ) {",
+
+		"vLightWeighting = vec3( 1.0 );",
+
+	"} else {",
+
+		"vLightWeighting = ambientLightColor;",
+
+		"#if MAX_DIR_LIGHTS > 0",
+		
+		"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
+		
+			"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
+			"float directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );",
+			"vLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;",
+			
+		"}",
+		
+		"#endif",
+
+		"#if MAX_POINT_LIGHTS > 0",
+		
+		"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
+		
+			"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
+			"vec3 pointLightVector = normalize( lPosition.xyz - mvPosition.xyz );",
+			"float pointLightWeighting = max( dot( transformedNormal, pointLightVector ), 0.0 );",
+			"vLightWeighting += pointLightColor[ i ] * pointLightWeighting;",
+			
+			"#ifdef PHONG",
+				"vPointLightVector[ i ] = pointLightVector;",
+			"#endif",
+			
+		"}",
+		
+		"#endif",
+		
+	"}"
+	
+	].join("\n"),
+	
+	lights_pars_fragment: [
+	
+	"#if MAX_DIR_LIGHTS > 0",
+		"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
+	"#endif",
+	
+	"#if MAX_POINT_LIGHTS > 0",
+		"varying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];",
+	"#endif",
+	
+	"varying vec3 vViewPosition;",
+	"varying vec3 vNormal;"
+	
+	].join("\n"),
+	
+	lights_fragment: [
+	
+	"vec3 normal = normalize( vNormal );",
+	"vec3 viewPosition = normalize( vViewPosition );",
+	
+	"vec4 mSpecular = vec4( specular, opacity );",
+
+	"#if MAX_POINT_LIGHTS > 0",
+		
+		"vec4 pointDiffuse  = vec4( 0.0 );",
+		"vec4 pointSpecular = vec4( 0.0 );",
+
+		"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
+
+			"vec3 pointVector = normalize( vPointLightVector[ i ] );",
+			"vec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );",
+
+			"float pointDotNormalHalf = dot( normal, pointHalfVector );",
+			"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
+
+			"float pointSpecularWeight = 0.0;",
+			"if ( pointDotNormalHalf >= 0.0 )",
+				"pointSpecularWeight = pow( pointDotNormalHalf, shininess );",
+
+			"pointDiffuse  += mColor * pointDiffuseWeight;",
+			"pointSpecular += mSpecular * pointSpecularWeight;",
+
+			"}",
+
+	"#endif",
+	
+	"#if MAX_DIR_LIGHTS > 0",
+	
+		"vec4 dirDiffuse  = vec4( 0.0 );",
+		"vec4 dirSpecular = vec4( 0.0 );" ,
+
+		"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
+
+			"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
+
+			"vec3 dirVector = normalize( lDirection.xyz );",
+			"vec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );",
+
+			"float dirDotNormalHalf = dot( normal, dirHalfVector );",
+
+			"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
+
+			"float dirSpecularWeight = 0.0;",
+			"if ( dirDotNormalHalf >= 0.0 )",
+				"dirSpecularWeight = pow( dirDotNormalHalf, shininess );",
+
+			"dirDiffuse  += mColor * dirDiffuseWeight;",
+			"dirSpecular += mSpecular * dirSpecularWeight;",
+
+		"}",
+	
+	"#endif",
+
+	"vec4 totalLight = vec4( ambient, opacity );",
+
+	"#if MAX_DIR_LIGHTS > 0",
+		"totalLight += dirDiffuse + dirSpecular;",
+	"#endif",
+	
+	"#if MAX_POINT_LIGHTS > 0",
+		"totalLight += pointDiffuse + pointSpecular;",
+	"#endif"
+
+	].join("\n")
+
+};
+
+THREE.UniformsLib = {
+	
+	common: {
+		
+	"color"   : { type: "c", value: new THREE.Color( 0xeeeeee ) },
+	"opacity" : { type: "f", value: 1 },
+	"map"     : { type: "t", value: 0, texture: null },
+	
+	"env_map" 		  : { type: "t", value: 1, texture: null },
+	"useRefract"	  : { type: "i", value: 0 },
+	"reflectivity"    : { type: "f", value: 1 },
+	"refraction_ratio": { type: "f", value: 0.98 },
+	"combine"		  : { type: "i", value: 0 },
+	
+	"fogDensity": { type: "f", value: 0.00025 },
+	"fogNear"	: { type: "f", value: 1 },
+	"fogFar"	: { type: "f", value: 2000 },
+	"fogColor"	: { type: "c", value: new THREE.Color( 0xffffff ) }
+	
+	},
+	
+	lights: {
+		
+	"enableLighting" 			: { type: "i", value: 1 },
+	"ambientLightColor" 		: { type: "fv", value: [] },
+	"directionalLightDirection" : { type: "fv", value: [] },
+	"directionalLightColor" 	: { type: "fv", value: [] },
+	"pointLightPosition"		: { type: "fv", value: [] },
+	"pointLightColor"			: { type: "fv", value: [] }
+	
+	}
+	
+};
+
+THREE.ShaderLib = {
+
+	'depth': {
+
+		uniforms: { "mNear": { type: "f", value: 1.0 },
+					"mFar" : { type: "f", value: 2000.0 } },
+
+		fragment_shader: [
+
+			"uniform float mNear;",
+			"uniform float mFar;",
+
+			"void main() {",
+
+				"float depth = gl_FragCoord.z / gl_FragCoord.w;",
+				"float color = 1.0 - smoothstep( mNear, mFar, depth );",
+				"gl_FragColor = vec4( vec3( color ), 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertex_shader: [
+
+			"void main() {",
+
+				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	'normal': {
+
+		uniforms: { },
+
+		fragment_shader: [
+
+			"varying vec3 vNormal;",
+
+			"void main() {",
+
+				"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		vertex_shader: [
+
+			"varying vec3 vNormal;",
+
+			"void main() {",
+
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				"vNormal = normalize( normalMatrix * normal );",
+
+				"gl_Position = projectionMatrix * mvPosition;",
+
+			"}"
+
+		].join("\n")
+
+	},
+
+	'basic': {
+		
+		uniforms: THREE.UniformsLib[ "common" ],
+		
+		fragment_shader: [
+
+			"uniform vec3 color;",
+			"uniform float opacity;",
+			
+			THREE.Snippets[ "map_pars_fragment" ],
+			THREE.Snippets[ "envmap_pars_fragment" ],
+			THREE.Snippets[ "fog_pars_fragment" ],
+				
+			"void main() {",
+
+				"vec4 mColor = vec4( color, opacity );",
+				"vec4 mapColor = vec4( 1.0 );",
+				"vec4 cubeColor = vec4( 1.0 );",
+
+				THREE.Snippets[ "map_fragment" ],
+				
+				"gl_FragColor = mColor * mapColor;",
+				
+				THREE.Snippets[ "envmap_fragment" ],
+				THREE.Snippets[ "fog_fragment" ],
+				
+			"}"
+
+		].join("\n"),
+		
+		vertex_shader: [
+			
+			THREE.Snippets[ "map_pars_vertex" ],
+			THREE.Snippets[ "envmap_pars_vertex" ],
+			
+			"void main() {",
+		
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				
+				THREE.Snippets[ "map_vertex" ],
+				THREE.Snippets[ "envmap_vertex" ],
+				
+				"gl_Position = projectionMatrix * mvPosition;",
+
+			"}"
+
+		].join("\n")
+		
+	},
+
+	'lambert': {
+		
+		uniforms: Uniforms.merge( [ THREE.UniformsLib[ "common" ], 
+									THREE.UniformsLib[ "lights" ] ] ),
+		
+		fragment_shader: [
+			
+			"uniform vec3 color;",
+			"uniform float opacity;",
+			
+			"varying vec3 vLightWeighting;",
+				
+			THREE.Snippets[ "map_pars_fragment" ],
+			THREE.Snippets[ "envmap_pars_fragment" ],
+			THREE.Snippets[ "fog_pars_fragment" ],
+				
+			"void main() {",
+					
+				"vec4 mColor = vec4( color, opacity );",
+				"vec4 mapColor = vec4( 1.0 );",
+				"vec4 cubeColor = vec4( 1.0 );",
+
+				THREE.Snippets[ "map_fragment" ],
+
+				"gl_FragColor =  mColor * mapColor * vec4( vLightWeighting, 1.0 );",
+				
+				THREE.Snippets[ "envmap_fragment" ],
+				THREE.Snippets[ "fog_fragment" ],
+
+			"}"
+
+		].join("\n"),
+
+		vertex_shader: [
+		
+			"varying vec3 vLightWeighting;",
+			
+			THREE.Snippets[ "map_pars_vertex" ],
+			THREE.Snippets[ "envmap_pars_vertex" ],
+			THREE.Snippets[ "lights_pars_vertex" ],
+			
+			"void main() {",
+		
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				
+				THREE.Snippets[ "map_vertex" ],
+				THREE.Snippets[ "envmap_vertex" ],
+				
+				"vec3 transformedNormal = normalize( normalMatrix * normal );",
+				
+				THREE.Snippets[ "lights_vertex" ],
+				
+				"gl_Position = projectionMatrix * mvPosition;",
+
+			"}"
+
+		].join("\n")
+		
+	},
+	
+	'phong': {
+		
+		uniforms: Uniforms.merge( [ THREE.UniformsLib[ "common" ], 
+									THREE.UniformsLib[ "lights" ],
+									
+								    { "ambient"  : { type: "c", value: new THREE.Color( 0x050505 ) },
+									  "specular" : { type: "c", value: new THREE.Color( 0x111111 ) },
+									  "shininess": { type: "f", value: 30 }
+									}
+									
+								] ),
+		
+		fragment_shader: [
+			
+			"uniform vec3 color;",
+			"uniform float opacity;",
+			
+			"uniform vec3 ambient;",
+			"uniform vec3 specular;",
+			"uniform float shininess;",
+				
+			"varying vec3 vLightWeighting;",
+				
+			THREE.Snippets[ "map_pars_fragment" ],
+			THREE.Snippets[ "envmap_pars_fragment" ],
+			THREE.Snippets[ "fog_pars_fragment" ],
+			THREE.Snippets[ "lights_pars_fragment" ],
+				
+			"void main() {",
+					
+				"vec4 mColor = vec4( color, opacity );",
+				"vec4 mapColor = vec4( 1.0 );",
+				"vec4 cubeColor = vec4( 1.0 );",
+
+				THREE.Snippets[ "map_fragment" ],
+				THREE.Snippets[ "lights_fragment" ],
+
+				"gl_FragColor =  mapColor * totalLight * vec4( vLightWeighting, 1.0 );",
+				
+				THREE.Snippets[ "envmap_fragment" ],
+				THREE.Snippets[ "fog_fragment" ],
+
+			"}"
+
+		].join("\n"),
+
+		vertex_shader: [
+		
+			"#define PHONG",
+			
+			"varying vec3 vLightWeighting;",
+			"varying vec3 vViewPosition;",
+			"varying vec3 vNormal;",
+			
+			THREE.Snippets[ "map_pars_vertex" ],
+			THREE.Snippets[ "envmap_pars_vertex" ],
+			THREE.Snippets[ "lights_pars_vertex" ],
+			
+			"void main() {",
+		
+				"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+				
+				THREE.Snippets[ "map_vertex" ],
+				THREE.Snippets[ "envmap_vertex" ],
+				
+				"#ifndef USE_ENVMAP",
+					"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+				"#endif",
+				
+				"vViewPosition = cameraPosition - mPosition.xyz;",
+				
+				"vec3 transformedNormal = normalize( normalMatrix * normal );",
+				"vNormal = transformedNormal;",
+
+				THREE.Snippets[ "lights_vertex" ],
+				
+				"gl_Position = projectionMatrix * mvPosition;",
+
+			"}"
+
+		].join("\n")
+		
+	}	
+
+};

+ 149 - 0
examples/render_to_texture.html

@@ -0,0 +1,149 @@
+<!DOCTYPE HTML>
+<html lang="en">
+    <head>
+        <title>three.js - shader</title>
+        <meta charset="utf-8">
+        <style type="text/css">
+            body {
+                color: #ffffff;
+                font-family:Monospace;
+                font-size:13px;
+                text-align:center;
+                font-weight: bold;
+
+                background-color: #000000;
+                margin: 0px;
+                overflow: hidden;
+            }
+
+            #info {
+                position: absolute;
+                top: 0px; width: 100%;
+                padding: 5px;
+            }
+
+            a {
+
+                color: #ffffff;
+            }
+
+        </style>
+    </head>
+    <body>
+
+        <div id="container"></div>
+        <div id="info"><a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a></div>
+
+        <script type="text/javascript" src="js/Stats.js"></script>
+
+        <script type="text/javascript" src="../build/ThreeWebGL.js"></script>
+        <script type="text/javascript" src="../build/ThreeExtras.js"></script>
+
+        <script id="vertex_shader" type="x-shader/x-vertex">
+            varying vec2 vUv;
+
+            void main()
+            {
+               vUv = uv;
+               gl_Position = vec4( position, 1.0 );
+           }
+        </script>
+
+        <script id="fragment_shader_pass_1" type="x-shader/x-fragment">
+            void main(void)
+            {
+                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+            }
+        </script>
+
+        <script id="fragment_shader_pass_2" type="x-shader/x-fragment">
+            uniform sampler2D texture;
+
+            varying vec2 vUv;
+
+            void main(void)
+            {
+                vec4 color = texture2D(texture, vUv);
+                gl_FragColor = color;
+            }
+        </script>
+
+        <script type="text/javascript">
+
+            var container, stats;
+
+            var camera, scene, renderer;
+
+            var uniforms, rtTexture, material_1, material_2, mesh;
+
+            init();
+            setInterval( loop, 1000 / 60 );
+
+            function init() {
+
+                container = document.getElementById( 'container' );
+
+                renderer = new THREE.WebGLRenderer();
+                container.appendChild( renderer.domElement );
+
+                camera = new THREE.Camera();
+                camera.position.z = 1;
+
+                scene = new THREE.Scene();
+
+                rtTexture = new THREE.RenderTexture( 512, 512 );
+
+                material_1 = new THREE.MeshShaderMaterial( {
+
+                    uniforms: {},
+                    vertex_shader: document.getElementById( 'vertex_shader' ).textContent,
+                    fragment_shader: document.getElementById( 'fragment_shader_pass_1' ).textContent
+
+                } );
+
+                material_2 = new THREE.MeshShaderMaterial( {
+
+                    uniforms: { texture: { type: "t", value: 0, texture: rtTexture } },
+                    vertex_shader: document.getElementById( 'vertex_shader' ).textContent,
+                    fragment_shader: document.getElementById( 'fragment_shader_pass_2' ).textContent
+
+                } );
+
+                mesh = new THREE.Mesh( new Plane( 2, 2 ) );
+                scene.addObject( mesh );
+
+                onWindowResize();
+
+                window.addEventListener( 'resize', onWindowResize, false );
+
+                stats = new Stats();
+                stats.domElement.style.position = 'absolute';
+                stats.domElement.style.top = '0px';
+                container.appendChild( stats.domElement );
+
+            }
+
+            function onWindowResize( event ) {
+
+              renderer.setSize( window.innerWidth, window.innerHeight );
+
+            }
+
+            function loop() {
+
+                // Render to rtTexture
+                mesh.materials = [material_1];
+                renderer.render( scene, camera, rtTexture );
+
+                // Render to screen
+                mesh.materials = [material_2];
+                renderer.render( scene, camera );
+
+                stats.update();
+
+            }
+
+        </script>
+
+    </body>
+</html>

Some files were not shown because too many files changed in this diff