/** * @author mr.doob / http://mrdoob.com/ */ var THREE = THREE || { REVISION: '49dev' }; if ( ! self.Int32Array ) { self.Int32Array = Array; self.Float32Array = Array; } // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller // fixes from Paul Irish and Tino Zijdel (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }()); /** * @author mr.doob / http://mrdoob.com/ */ THREE.Color = function ( hex ) { if ( hex !== undefined ) this.setHex( hex ); return this; }; THREE.Color.prototype = { constructor: THREE.Color, r: 1, g: 1, b: 1, copy: function ( color ) { this.r = color.r; this.g = color.g; this.b = color.b; return this; }, copyGammaToLinear: function ( color ) { this.r = color.r * color.r; this.g = color.g * color.g; this.b = color.b * color.b; return this; }, copyLinearToGamma: function ( color ) { this.r = Math.sqrt( color.r ); this.g = Math.sqrt( color.g ); this.b = Math.sqrt( color.b ); return this; }, convertGammaToLinear: function () { var r = this.r, g = this.g, b = this.b; this.r = r * r; this.g = g * g; this.b = b * b; return this; }, convertLinearToGamma: function () { this.r = Math.sqrt( this.r ); this.g = Math.sqrt( this.g ); this.b = Math.sqrt( this.b ); return this; }, setRGB: function ( r, g, b ) { this.r = r; this.g = g; this.b = b; return this; }, setHSV: function ( h, s, v ) { // based on MochiKit implementation by Bob Ippolito // h,s,v ranges are < 0.0 - 1.0 > var i, f, p, q, t; if ( v === 0 ) { this.r = this.g = this.b = 0; } else { i = Math.floor( h * 6 ); f = ( h * 6 ) - i; p = v * ( 1 - s ); q = v * ( 1 - ( s * f ) ); t = v * ( 1 - ( s * ( 1 - f ) ) ); switch ( i ) { case 1: this.r = q; this.g = v; this.b = p; break; case 2: this.r = p; this.g = v; this.b = t; break; case 3: this.r = p; this.g = q; this.b = v; break; case 4: this.r = t; this.g = p; this.b = v; break; case 5: this.r = v; this.g = p; this.b = q; break; case 6: // fall through case 0: this.r = v; this.g = t; this.b = p; break; } } return this; }, setHex: function ( hex ) { hex = Math.floor( hex ); this.r = ( hex >> 16 & 255 ) / 255; this.g = ( hex >> 8 & 255 ) / 255; this.b = ( hex & 255 ) / 255; return this; }, lerpSelf: function ( color, alpha ) { this.r += ( color.r - this.r ) * alpha; this.g += ( color.g - this.g ) * alpha; this.b += ( color.b - this.b ) * alpha; return this; }, getHex: function () { return Math.floor( this.r * 255 ) << 16 ^ Math.floor( this.g * 255 ) << 8 ^ Math.floor( this.b * 255 ); }, getContextStyle: function () { return 'rgb(' + Math.floor( this.r * 255 ) + ',' + Math.floor( this.g * 255 ) + ',' + Math.floor( this.b * 255 ) + ')'; }, clone: function () { return new THREE.Color().setRGB( this.r, this.g, this.b ); } }; /** * @author mr.doob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ * @author egraether / http://egraether.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.Vector2 = function ( x, y ) { this.x = x || 0; this.y = y || 0; }; THREE.Vector2.prototype = { constructor: THREE.Vector2, 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; }, add: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; return this; }, addSelf: function ( v ) { this.x += v.x; this.y += v.y; return this; }, sub: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; return this; }, subSelf: function ( v ) { this.x -= v.x; this.y -= v.y; return this; }, multiplyScalar: function ( s ) { this.x *= s; this.y *= s; return this; }, divideScalar: function ( s ) { if ( s ) { this.x /= s; this.y /= s; } else { this.set( 0, 0 ); } return this; }, negate: function() { return this.multiplyScalar( - 1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y; }, lengthSq: function () { return this.x * this.x + this.y * this.y; }, length: function () { return Math.sqrt( this.lengthSq() ); }, normalize: function () { return this.divideScalar( this.length() ); }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { var dx = this.x - v.x, dy = this.y - v.y; return dx * dx + dy * dy; }, setLength: function ( l ) { return this.normalize().multiplyScalar( l ); }, lerpSelf: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; return this; }, equals: function( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) ); }, isZero: function () { return ( this.lengthSq() < 0.0001 /* almostZero */ ); }, clone: function () { return new THREE.Vector2( this.x, this.y ); } }; /** * @author mr.doob / http://mrdoob.com/ * @author kile / http://kile.stravaganza.org/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ */ THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, set: function ( x, y, z ) { this.x = x; this.y = y; this.z = z; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setZ: function ( z ) { this.z = z; return this; }, copy: function ( v ) { this.x = v.x; this.y = v.y; this.z = v.z; return this; }, add: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; return this; }, addSelf: function ( v ) { this.x += v.x; this.y += v.y; this.z += v.z; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; this.z += s; return this; }, sub: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; return this; }, subSelf: function ( v ) { this.x -= v.x; this.y -= v.y; this.z -= v.z; return this; }, multiply: function ( a, b ) { this.x = a.x * b.x; this.y = a.y * b.y; this.z = a.z * b.z; return this; }, multiplySelf: function ( v ) { this.x *= v.x; this.y *= v.y; this.z *= v.z; return this; }, multiplyScalar: function ( s ) { this.x *= s; this.y *= s; this.z *= s; return this; }, divideSelf: function ( v ) { this.x /= v.x; this.y /= v.y; this.z /= v.z; return this; }, divideScalar: function ( s ) { if ( s ) { this.x /= s; this.y /= s; this.z /= s; } else { this.x = 0; this.y = 0; this.z = 0; } return this; }, negate: function() { return this.multiplyScalar( - 1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z; }, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z; }, length: function () { return Math.sqrt( this.lengthSq() ); }, lengthManhattan: function () { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( l ) { return this.normalize().multiplyScalar( l ); }, lerpSelf: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; 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 x = this.x, y = this.y, z = this.z; this.x = y * v.z - z * v.y; this.y = z * v.x - x * v.z; this.z = x * v.y - y * v.x; return this; }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { return new THREE.Vector3().sub( this, v ).lengthSq(); }, getPositionFromMatrix: function ( m ) { this.x = m.elements[12]; this.y = m.elements[13]; this.z = m.elements[14]; return this; }, getRotationFromMatrix: function ( m, scale ) { var sx = scale ? scale.x : 1; var sy = scale ? scale.y : 1; var sz = scale ? scale.z : 1; var m11 = m.elements[0] / sx, m12 = m.elements[4] / sy, m13 = m.elements[8] / sz; var m21 = m.elements[1] / sx, m22 = m.elements[5] / sy, m23 = m.elements[9] / sz; var m33 = m.elements[10] / sz; this.y = Math.asin( m13 ); var cosY = Math.cos( this.y ); if ( Math.abs( cosY ) > 0.00001 ) { this.x = Math.atan2( - m23 / cosY, m33 / cosY ); this.z = Math.atan2( - m12 / cosY, m11 / cosY ); } else { this.x = 0; this.z = Math.atan2( m21, m22 ); } return this; }, /* // from http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m // order XYZ getEulerXYZFromQuaternion: function ( q ) { this.x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z ) ); this.y = Math.asin( 2 * ( q.x * q.z + q.y * q.w ) ); this.z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z ) ); }, // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm // order YZX (assuming heading == y, attitude == z, bank == x) getEulerYZXFromQuaternion: function ( q ) { var sqw = q.w * q.w; var sqx = q.x * q.x; var sqy = q.y * q.y; var sqz = q.z * q.z; var unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor var test = q.x * q.y + q.z * q.w; if ( test > 0.499 * unit ) { // singularity at north pole this.y = 2 * Math.atan2( q.x, q.w ); this.z = Math.PI / 2; this.x = 0; return; } if ( test < -0.499 * unit ) { // singularity at south pole this.y = -2 * Math.atan2( q.x, q.w ); this.z = -Math.PI / 2; this.x = 0; return; } this.y = Math.atan2( 2 * q.y * q.w - 2 * q.x * q.z, sqx - sqy - sqz + sqw ); this.z = Math.asin( 2 * test / unit ); this.x = Math.atan2( 2 * q.x * q.w - 2 * q.y * q.z, -sqx + sqy - sqz + sqw ); }, */ getScaleFromMatrix: function ( m ) { var sx = this.set( m.elements[0], m.elements[1], m.elements[2] ).length(); var sy = this.set( m.elements[4], m.elements[5], m.elements[6] ).length(); var sz = this.set( m.elements[8], m.elements[9], m.elements[10] ).length(); this.x = sx; this.y = sy; this.z = sz; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); }, isZero: function () { return ( this.lengthSq() < 0.0001 /* almostZero */ ); }, clone: function () { return new THREE.Vector3( this.x, this.y, this.z ); } }; /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ */ THREE.Vector4 = function ( x, y, z, w ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; this.w = ( w !== undefined ) ? w : 1; }; THREE.Vector4.prototype = { constructor: THREE.Vector4, 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 !== undefined ) ? v.w : 1; return this; }, add: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; this.w = a.w + b.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 ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; this.w = a.w - b.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 ) { if ( s ) { this.x /= s; this.y /= s; this.z /= s; this.w /= s; } else { this.x = 0; this.y = 0; this.z = 0; this.w = 1; } return this; }, negate: function() { return this.multiplyScalar( -1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; }, lengthSq: function () { return this.dot( this ); }, length: function () { return Math.sqrt( this.lengthSq() ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( l ) { return this.normalize().multiplyScalar( l ); }, lerpSelf: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; this.w += ( v.w - this.w ) * alpha; return this; }, clone: function () { return new THREE.Vector4( this.x, this.y, this.z, this.w ); } }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Frustum = function ( ) { this.planes = [ new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4() ]; }; THREE.Frustum.prototype.setFromMatrix = function ( m ) { var i, plane, planes = this.planes; var me = m.elements; var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; planes[ 0 ].set( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ); planes[ 1 ].set( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ); planes[ 2 ].set( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ); planes[ 3 ].set( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ); planes[ 4 ].set( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ); planes[ 5 ].set( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ); for ( i = 0; i < 6; i ++ ) { plane = planes[ i ]; plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) ); } }; THREE.Frustum.prototype.contains = function ( object ) { var distance, planes = this.planes, matrix = object.matrixWorld, me = matrix.elements, scale = THREE.Frustum.__v1.set( matrix.getColumnX().length(), matrix.getColumnY().length(), matrix.getColumnZ().length() ), radius = - object.geometry.boundingSphere.radius * Math.max( scale.x, Math.max( scale.y, scale.z ) ); for ( var i = 0; i < 6; i ++ ) { distance = planes[ i ].x * me[12] + planes[ i ].y * me[13] + planes[ i ].z * me[14] + planes[ i ].w; if ( distance <= radius ) return false; } return true; }; THREE.Frustum.__v1 = new THREE.Vector3(); /** * @author mr.doob / http://mrdoob.com/ */ THREE.Ray = function ( origin, direction ) { this.origin = origin || new THREE.Vector3(); this.direction = direction || new THREE.Vector3(); var precision = 0.0001; this.setPrecision = function ( value ) { precision = value; }; var a = new THREE.Vector3(); var b = new THREE.Vector3(); var c = new THREE.Vector3(); var d = new THREE.Vector3(); var originCopy = new THREE.Vector3(); var directionCopy = new THREE.Vector3(); var vector = new THREE.Vector3(); var normal = new THREE.Vector3(); var intersectPoint = new THREE.Vector3() this.intersectObject = function ( object ) { var intersect, intersects = []; if ( object instanceof THREE.Particle ) { var distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() ); if ( distance > object.scale.x ) { return []; } intersect = { distance: distance, point: object.position, face: null, object: object }; intersects.push( intersect ); } else if ( object instanceof THREE.Mesh ) { // Checking boundingSphere var distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() ); var scale = THREE.Frustum.__v1.set( object.matrixWorld.getColumnX().length(), object.matrixWorld.getColumnY().length(), object.matrixWorld.getColumnZ().length() ); if ( distance > object.geometry.boundingSphere.radius * Math.max( scale.x, Math.max( scale.y, scale.z ) ) ) { return intersects; } // Checking faces var f, fl, face, dot, scalar, geometry = object.geometry, vertices = geometry.vertices, objMatrix; object.matrixRotationWorld.extractRotation( object.matrixWorld ); for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) { face = geometry.faces[ f ]; originCopy.copy( this.origin ); directionCopy.copy( this.direction ); objMatrix = object.matrixWorld; // determine if ray intersects the plane of the face // note: this works regardless of the direction of the face normal vector = objMatrix.multiplyVector3( vector.copy( face.centroid ) ).subSelf( originCopy ); normal = object.matrixRotationWorld.multiplyVector3( normal.copy( face.normal ) ); dot = directionCopy.dot( normal ); // bail if ray and plane are parallel if ( Math.abs( dot ) < precision ) continue; // calc distance to plane scalar = normal.dot( vector ) / dot; // if negative distance, then plane is behind ray if ( scalar < 0 ) continue; if ( object.doubleSided || ( object.flipSided ? dot > 0 : dot < 0 ) ) { intersectPoint.add( originCopy, directionCopy.multiplyScalar( scalar ) ); if ( face instanceof THREE.Face3 ) { a = objMatrix.multiplyVector3( a.copy( vertices[ face.a ].position ) ); b = objMatrix.multiplyVector3( b.copy( vertices[ face.b ].position ) ); c = objMatrix.multiplyVector3( c.copy( vertices[ face.c ].position ) ); if ( pointInFace3( intersectPoint, a, b, c ) ) { intersect = { distance: originCopy.distanceTo( intersectPoint ), point: intersectPoint.clone(), face: face, object: object }; intersects.push( intersect ); } } else if ( face instanceof THREE.Face4 ) { a = objMatrix.multiplyVector3( a.copy( vertices[ face.a ].position ) ); b = objMatrix.multiplyVector3( b.copy( vertices[ face.b ].position ) ); c = objMatrix.multiplyVector3( c.copy( vertices[ face.c ].position ) ); d = objMatrix.multiplyVector3( d.copy( vertices[ face.d ].position ) ); if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) { intersect = { distance: originCopy.distanceTo( intersectPoint ), point: intersectPoint.clone(), face: face, object: object }; intersects.push( intersect ); } } } } } return intersects; } this.intersectObjects = function ( objects ) { var intersects = []; for ( var i = 0, l = objects.length; i < l; i ++ ) { Array.prototype.push.apply( intersects, this.intersectObject( objects[ i ] ) ); } intersects.sort( function ( a, b ) { return a.distance - b.distance; } ); return intersects; }; var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3(); var dot, intersect, distance; function distanceFromIntersection( origin, direction, position ) { v0.sub( position, origin ); dot = v0.dot( direction ); intersect = v1.add( origin, v2.copy( direction ).multiplyScalar( dot ) ); distance = position.distanceTo( intersect ); return distance; } // http://www.blackpawn.com/texts/pointinpoly/default.html var dot00, dot01, dot02, dot11, dot12, invDenom, u, v; function pointInFace3( p, a, b, c ) { v0.sub( c, a ); v1.sub( b, a ); v2.sub( p, 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.intersects = function ( r ) { // http://gamemath.com/2011/09/detecting-whether-two-boxes-overlap/ if ( _right < r.getLeft() ) return false; if ( _left > r.getRight() ) return false; if ( _bottom < r.getTop() ) return false; if ( _top > r.getBottom() ) return false; return true; }; this.empty = function () { _isEmpty = true; _left = 0; _top = 0; _right = 0; _bottom = 0; resize(); }; this.isEmpty = function () { return _isEmpty; }; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Math = { // Clamp value to range clamp: function ( x, a, b ) { return ( x < a ) ? a : ( ( x > b ) ? b : x ); }, // Clamp value to range to range mapLinear: function ( x, a1, a2, b1, b2 ) { return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); }, // Random float from <0, 1> with 16 bits of randomness // (standard Math.random() creates repetitive patterns when applied over larger space) random16: function () { return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; }, // Random integer from interval randInt: function ( low, high ) { return low + Math.floor( Math.random() * ( high - low + 1 ) ); }, // Random float from interval randFloat: function ( low, high ) { return low + Math.random() * ( high - low ); }, // Random float from <-range/2, range/2> interval randFloatSpread: function ( range ) { return range * ( 0.5 - Math.random() ); }, sign: function ( x ) { return ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 ); } }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Matrix3 = function () { this.m = []; }; THREE.Matrix3.prototype = { constructor: THREE.Matrix3, getInverse: function ( matrix ) { // input: THREE.Matrix4 // ( based on http://code.google.com/p/webgl-mjs/ ) var a11 = matrix.elements[10] * matrix.elements[5] - matrix.elements[6] * matrix.elements[9]; var a21 = - matrix.elements[10] * matrix.elements[1] + matrix.elements[2] * matrix.elements[9]; var a31 = matrix.elements[6] * matrix.elements[1] - matrix.elements[2] * matrix.elements[5]; var a12 = - matrix.elements[10] * matrix.elements[4] + matrix.elements[6] * matrix.elements[8]; var a22 = matrix.elements[10] * matrix.elements[0] - matrix.elements[2] * matrix.elements[8]; var a32 = - matrix.elements[6] * matrix.elements[0] + matrix.elements[2] * matrix.elements[4]; var a13 = matrix.elements[9] * matrix.elements[4] - matrix.elements[5] * matrix.elements[8]; var a23 = - matrix.elements[9] * matrix.elements[0] + matrix.elements[1] * matrix.elements[8]; var a33 = matrix.elements[5] * matrix.elements[0] - matrix.elements[1] * matrix.elements[4]; var det = matrix.elements[0] * a11 + matrix.elements[1] * a12 + matrix.elements[2] * a13; // no inverse if ( det === 0 ) { console.warn( "Matrix3.getInverse(): determinant == 0" ); } var idet = 1.0 / det; var m = this.m; m[ 0 ] = idet * a11; m[ 1 ] = idet * a21; m[ 2 ] = idet * a31; m[ 3 ] = idet * a12; m[ 4 ] = idet * a22; m[ 5 ] = idet * a32; m[ 6 ] = idet * a13; m[ 7 ] = idet * a23; m[ 8 ] = idet * a33; return this; }, /* transpose: function () { var tmp, m = this.m; tmp = m[1]; m[1] = m[3]; m[3] = tmp; tmp = m[2]; m[2] = m[6]; m[6] = tmp; tmp = m[5]; m[5] = m[7]; m[7] = tmp; return this; }, */ transposeIntoArray: function ( r ) { var m = this.m; r[ 0 ] = m[ 0 ]; r[ 1 ] = m[ 3 ]; r[ 2 ] = m[ 6 ]; r[ 3 ] = m[ 1 ]; r[ 4 ] = m[ 4 ]; r[ 5 ] = m[ 7 ]; r[ 6 ] = m[ 2 ]; r[ 7 ] = m[ 5 ]; r[ 8 ] = m[ 8 ]; 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 * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author timknip / http://www.floorplanner.com/ */ THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { this.elements = new Float32Array(16); this.set( ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, n14 || 0, n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, n24 || 0, n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1, n34 || 0, n41 || 0, n42 || 0, n43 || 0, ( n44 !== undefined ) ? n44 : 1 ); }; THREE.Matrix4.prototype = { constructor: THREE.Matrix4, set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { var te = this.elements; te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; return this; }, identity: function () { this.set( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, copy: function ( m ) { var me = m.elements; this.set( me[0], me[4], me[8], me[12], me[1], me[5], me[9], me[13], me[2], me[6], me[10], me[14], me[3], me[7], me[11], me[15] ); return this; }, lookAt: function ( eye, target, up ) { var te = this.elements; var x = THREE.Matrix4.__v1; var y = THREE.Matrix4.__v2; var z = THREE.Matrix4.__v3; z.sub( eye, target ).normalize(); if ( z.length() === 0 ) { z.z = 1; } x.cross( up, z ).normalize(); if ( x.length() === 0 ) { z.x += 0.0001; x.cross( up, z ).normalize(); } y.cross( z, x ); te[0] = x.x; te[4] = y.x; te[8] = z.x; te[1] = x.y; te[5] = y.y; te[9] = z.y; te[2] = x.z; te[6] = y.z; te[10] = z.z; return this; }, multiply: function ( a, b ) { var ae = a.elements, be = b.elements, te = this.elements; var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return this; }, multiplySelf: function ( m ) { return this.multiply( this, m ); }, multiplyToArray: function ( a, b, r ) { var te = this.elements; this.multiply( a, b ); r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; return this; }, multiplyScalar: function ( s ) { var te = this.elements; te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; return this; }, multiplyVector3: function ( v ) { var te = this.elements; var vx = v.x, vy = v.y, vz = v.z; var d = 1 / ( te[3] * vx + te[7] * vy + te[11] * vz + te[15] ); v.x = ( te[0] * vx + te[4] * vy + te[8] * vz + te[12] ) * d; v.y = ( te[1] * vx + te[5] * vy + te[9] * vz + te[13] ) * d; v.z = ( te[2] * vx + te[6] * vy + te[10] * vz + te[14] ) * d; return v; }, multiplyVector4: function ( v ) { var te = this.elements; var vx = v.x, vy = v.y, vz = v.z, vw = v.w; v.x = te[0] * vx + te[4] * vy + te[8] * vz + te[12] * vw; v.y = te[1] * vx + te[5] * vy + te[9] * vz + te[13] * vw; v.z = te[2] * vx + te[6] * vy + te[10] * vz + te[14] * vw; v.w = te[3] * vx + te[7] * vy + te[11] * vz + te[15] * vw; return v; }, rotateAxis: function ( v ) { var te = this.elements; var vx = v.x, vy = v.y, vz = v.z; v.x = vx * te[0] + vy * te[4] + vz * te[8]; v.y = vx * te[1] + vy * te[5] + vz * te[9]; v.z = vx * te[2] + vy * te[6] + vz * te[10]; v.normalize(); return v; }, crossVector: function ( a ) { var te = this.elements; var v = new THREE.Vector4(); v.x = te[0] * a.x + te[4] * a.y + te[8] * a.z + te[12] * a.w; v.y = te[1] * a.x + te[5] * a.y + te[9] * a.z + te[13] * a.w; v.z = te[2] * a.x + te[6] * a.y + te[10] * a.z + te[14] * a.w; v.w = ( a.w ) ? te[3] * a.x + te[7] * a.y + te[11] * a.z + te[15] * a.w : 1; return v; }, determinant: function () { var te = this.elements; var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; //TODO: make this more efficient //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) return ( n14 * n23 * n32 * n41- n13 * n24 * n32 * n41- n14 * n22 * n33 * n41+ n12 * n24 * n33 * n41+ n13 * n22 * n34 * n41- n12 * n23 * n34 * n41- n14 * n23 * n31 * n42+ n13 * n24 * n31 * n42+ n14 * n21 * n33 * n42- n11 * n24 * n33 * n42- n13 * n21 * n34 * n42+ n11 * n23 * n34 * n42+ n14 * n22 * n31 * n43- n12 * n24 * n31 * n43- n14 * n21 * n32 * n43+ n11 * n24 * n32 * n43+ n12 * n21 * n34 * n43- n11 * n22 * n34 * n43- n13 * n22 * n31 * n44+ n12 * n23 * n31 * n44+ n13 * n21 * n32 * n44- n11 * n23 * n32 * n44- n12 * n21 * n33 * n44+ n11 * n22 * n33 * n44 ); }, transpose: function () { var te = this.elements; var tmp; tmp = te[1]; te[1] = te[4]; te[4] = tmp; tmp = te[2]; te[2] = te[8]; te[8] = tmp; tmp = te[6]; te[6] = te[9]; te[9] = tmp; tmp = te[3]; te[3] = te[12]; te[12] = tmp; tmp = te[7]; te[7] = te[13]; te[13] = tmp; tmp = te[11]; te[11] = te[14]; te[14] = tmp; return this; }, flattenToArray: function ( flat ) { var te = this.elements; flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; return flat; }, flattenToArrayOffset: function( flat, offset ) { var te = this.elements; flat[ offset ] = te[0]; flat[ offset + 1 ] = te[1]; flat[ offset + 2 ] = te[2]; flat[ offset + 3 ] = te[3]; flat[ offset + 4 ] = te[4]; flat[ offset + 5 ] = te[5]; flat[ offset + 6 ] = te[6]; flat[ offset + 7 ] = te[7]; flat[ offset + 8 ] = te[8]; flat[ offset + 9 ] = te[9]; flat[ offset + 10 ] = te[10]; flat[ offset + 11 ] = te[11]; flat[ offset + 12 ] = te[12]; flat[ offset + 13 ] = te[13]; flat[ offset + 14 ] = te[14]; flat[ offset + 15 ] = te[15]; return flat; }, getPosition: function () { var te = this.elements; return THREE.Matrix4.__v1.set( te[12], te[13], te[14] ); }, setPosition: function ( v ) { var te = this.elements; te[12] = v.x; te[13] = v.y; te[14] = v.z; return this; }, getColumnX: function () { var te = this.elements; return THREE.Matrix4.__v1.set( te[0], te[1], te[2] ); }, getColumnY: function () { var te = this.elements; return THREE.Matrix4.__v1.set( te[4], te[5], te[6] ); }, getColumnZ: function() { var te = this.elements; return THREE.Matrix4.__v1.set( te[8], te[9], te[10] ); }, getInverse: function ( m ) { // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm var te = this.elements; var me = m.elements; var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; this.multiplyScalar( 1 / m.determinant() ); return this; }, setRotationFromEuler: function( v, order ) { var te = this.elements; var x = v.x, y = v.y, z = v.z; var a = Math.cos( x ), b = Math.sin( x ); var c = Math.cos( y ), d = Math.sin( y ); var e = Math.cos( z ), f = Math.sin( z ); switch ( order ) { case 'YXZ': var ce = c * e, cf = c * f, de = d * e, df = d * f; te[0] = ce + df * b; te[4] = de * b - cf; te[8] = a * d; te[1] = a * f; te[5] = a * e; te[9] = - b; te[2] = cf * b - de; te[6] = df + ce * b; te[10] = a * c; break; case 'ZXY': var ce = c * e, cf = c * f, de = d * e, df = d * f; te[0] = ce - df * b; te[4] = - a * f; te[8] = de + cf * b; te[1] = cf + de * b; te[5] = a * e; te[9] = df - ce * b; te[2] = - a * d; te[6] = b; te[10] = a * c; break; case 'ZYX': var ae = a * e, af = a * f, be = b * e, bf = b * f; te[0] = c * e; te[4] = be * d - af; te[8] = ae * d + bf; te[1] = c * f; te[5] = bf * d + ae; te[9] = af * d - be; te[2] = - d; te[6] = b * c; te[10] = a * c; break; case 'YZX': var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[0] = c * e; te[4] = bd - ac * f; te[8] = bc * f + ad; te[1] = f; te[5] = a * e; te[9] = - b * e; te[2] = - d * e; te[6] = ad * f + bc; te[10] = ac - bd * f; break; case 'XZY': var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[0] = c * e; te[4] = - f; te[8] = d * e; te[1] = ac * f + bd; te[5] = a * e; te[9] = ad * f - bc; te[2] = bc * f - ad; te[6] = b * e; te[10] = bd * f + ac; break; default: // 'XYZ' var ae = a * e, af = a * f, be = b * e, bf = b * f; te[0] = c * e; te[4] = - c * f; te[8] = d; te[1] = af + be * d; te[5] = ae - bf * d; te[9] = - b * c; te[2] = bf - ae * d; te[6] = be + af * d; te[10] = a * c; break; } return this; }, setRotationFromQuaternion: function( q ) { var te = this.elements; var x = q.x, y = q.y, z = q.z, w = q.w; var x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2; var yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2; te[0] = 1 - ( yy + zz ); te[4] = xy - wz; te[8] = xz + wy; te[1] = xy + wz; te[5] = 1 - ( xx + zz ); te[9] = yz - wx; te[2] = xz - wy; te[6] = yz + wx; te[10] = 1 - ( xx + yy ); return this; }, compose: function ( translation, rotation, scale ) { var te = this.elements; var mRotation = THREE.Matrix4.__m1; var mScale = THREE.Matrix4.__m2; mRotation.identity(); mRotation.setRotationFromQuaternion( rotation ); mScale.makeScale( scale.x, scale.y, scale.z ); this.multiply( mRotation, mScale ); te[12] = translation.x; te[13] = translation.y; te[14] = translation.z; return this; }, decompose: function ( translation, rotation, scale ) { // grab the axis vectors var te = this.elements; var x = THREE.Matrix4.__v1; var y = THREE.Matrix4.__v2; var z = THREE.Matrix4.__v3; x.set( te[0], te[1], te[2] ); y.set( te[4], te[5], te[6] ); z.set( te[8], te[9], te[10] ); translation = ( translation instanceof THREE.Vector3 ) ? translation : new THREE.Vector3(); rotation = ( rotation instanceof THREE.Quaternion ) ? rotation : new THREE.Quaternion(); scale = ( scale instanceof THREE.Vector3 ) ? scale : new THREE.Vector3(); scale.x = x.length(); scale.y = y.length(); scale.z = z.length(); translation.x = te[12]; translation.y = te[13]; translation.z = te[14]; // scale the rotation part var matrix = THREE.Matrix4.__m1; matrix.copy( this ); matrix.elements[0] /= scale.x; matrix.elements[1] /= scale.x; matrix.elements[2] /= scale.x; matrix.elements[4] /= scale.y; matrix.elements[5] /= scale.y; matrix.elements[6] /= scale.y; matrix.elements[8] /= scale.z; matrix.elements[9] /= scale.z; matrix.elements[10] /= scale.z; rotation.setFromRotationMatrix( matrix ); return [ translation, rotation, scale ]; }, extractPosition: function ( m ) { var te = this.elements; var me = m.elements; te[12] = me[12]; te[13] = me[13]; te[14] = me[14]; return this; }, extractRotation: function ( m ) { var te = this.elements; var me = m.elements; var vector = THREE.Matrix4.__v1; var scaleX = 1 / vector.set( me[0], me[1], me[2] ).length(); var scaleY = 1 / vector.set( me[4], me[5], me[6] ).length(); var scaleZ = 1 / vector.set( me[8], me[9], me[10] ).length(); te[0] = me[0] * scaleX; te[1] = me[1] * scaleX; te[2] = me[2] * scaleX; te[4] = me[4] * scaleY; te[5] = me[5] * scaleY; te[6] = me[6] * scaleY; te[8] = me[8] * scaleZ; te[9] = me[9] * scaleZ; te[10] = me[10] * scaleZ; return this; }, // translate: function ( v ) { var te = this.elements; var x = v.x, y = v.y, z = v.z; te[12] = te[0] * x + te[4] * y + te[8] * z + te[12]; te[13] = te[1] * x + te[5] * y + te[9] * z + te[13]; te[14] = te[2] * x + te[6] * y + te[10] * z + te[14]; te[15] = te[3] * x + te[7] * y + te[11] * z + te[15]; return this; }, rotateX: function ( angle ) { var te = this.elements; var m12 = te[4]; var m22 = te[5]; var m32 = te[6]; var m42 = te[7]; var m13 = te[8]; var m23 = te[9]; var m33 = te[10]; var m43 = te[11]; var c = Math.cos( angle ); var s = Math.sin( angle ); te[4] = c * m12 + s * m13; te[5] = c * m22 + s * m23; te[6] = c * m32 + s * m33; te[7] = c * m42 + s * m43; te[8] = c * m13 - s * m12; te[9] = c * m23 - s * m22; te[10] = c * m33 - s * m32; te[11] = c * m43 - s * m42; return this; }, rotateY: function ( angle ) { var te = this.elements; var m11 = te[0]; var m21 = te[1]; var m31 = te[2]; var m41 = te[3]; var m13 = te[8]; var m23 = te[9]; var m33 = te[10]; var m43 = te[11]; var c = Math.cos( angle ); var s = Math.sin( angle ); te[0] = c * m11 - s * m13; te[1] = c * m21 - s * m23; te[2] = c * m31 - s * m33; te[3] = c * m41 - s * m43; te[8] = c * m13 + s * m11; te[9] = c * m23 + s * m21; te[10] = c * m33 + s * m31; te[11] = c * m43 + s * m41; return this; }, rotateZ: function ( angle ) { var te = this.elements; var m11 = te[0]; var m21 = te[1]; var m31 = te[2]; var m41 = te[3]; var m12 = te[4]; var m22 = te[5]; var m32 = te[6]; var m42 = te[7]; var c = Math.cos( angle ); var s = Math.sin( angle ); te[0] = c * m11 + s * m12; te[1] = c * m21 + s * m22; te[2] = c * m31 + s * m32; te[3] = c * m41 + s * m42; te[4] = c * m12 - s * m11; te[5] = c * m22 - s * m21; te[6] = c * m32 - s * m31; te[7] = c * m42 - s * m41; return this; }, rotateByAxis: function ( axis, angle ) { var te = this.elements; // optimize by checking axis if ( axis.x === 1 && axis.y === 0 && axis.z === 0 ) { return this.rotateX( angle ); } else if ( axis.x === 0 && axis.y === 1 && axis.z === 0 ) { return this.rotateY( angle ); } else if ( axis.x === 0 && axis.y === 0 && axis.z === 1 ) { return this.rotateZ( angle ); } var x = axis.x, y = axis.y, z = axis.z; var n = Math.sqrt(x * x + y * y + z * z); x /= n; y /= n; z /= n; var xx = x * x, yy = y * y, zz = z * z; var c = Math.cos( angle ); var s = Math.sin( angle ); var oneMinusCosine = 1 - c; var xy = x * y * oneMinusCosine; var xz = x * z * oneMinusCosine; var yz = y * z * oneMinusCosine; var xs = x * s; var ys = y * s; var zs = z * s; var r11 = xx + (1 - xx) * c; var r21 = xy + zs; var r31 = xz - ys; var r12 = xy - zs; var r22 = yy + (1 - yy) * c; var r32 = yz + xs; var r13 = xz + ys; var r23 = yz - xs; var r33 = zz + (1 - zz) * c; var m11 = te[0], m21 = te[1], m31 = te[2], m41 = te[3]; var m12 = te[4], m22 = te[5], m32 = te[6], m42 = te[7]; var m13 = te[8], m23 = te[9], m33 = te[10], m43 = te[11]; var m14 = te[12], m24 = te[13], m34 = te[14], m44 = te[15]; te[0] = r11 * m11 + r21 * m12 + r31 * m13; te[1] = r11 * m21 + r21 * m22 + r31 * m23; te[2] = r11 * m31 + r21 * m32 + r31 * m33; te[3] = r11 * m41 + r21 * m42 + r31 * m43; te[4] = r12 * m11 + r22 * m12 + r32 * m13; te[5] = r12 * m21 + r22 * m22 + r32 * m23; te[6] = r12 * m31 + r22 * m32 + r32 * m33; te[7] = r12 * m41 + r22 * m42 + r32 * m43; te[8] = r13 * m11 + r23 * m12 + r33 * m13; te[9] = r13 * m21 + r23 * m22 + r33 * m23; te[10] = r13 * m31 + r23 * m32 + r33 * m33; te[11] = r13 * m41 + r23 * m42 + r33 * m43; return this; }, scale: function ( v ) { var te = this.elements; var x = v.x, y = v.y, z = v.z; te[0] *= x; te[4] *= y; te[8] *= z; te[1] *= x; te[5] *= y; te[9] *= z; te[2] *= x; te[6] *= y; te[10] *= z; te[3] *= x; te[7] *= y; te[11] *= z; return this; }, // makeTranslation: function ( x, y, z ) { this.set( 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 ); return this; }, makeRotationX: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationY: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationZ: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, makeRotationAxis: function ( axis, angle ) { // Based on http://www.gamedev.net/reference/articles/article1199.asp var c = Math.cos( angle ); var s = Math.sin( angle ); var t = 1 - c; var x = axis.x, y = axis.y, z = axis.z; var tx = t * x, ty = t * y; this.set( tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1 ); return this; }, makeScale: function ( x, y, z ) { this.set( x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 ); return this; }, makeFrustum: function ( left, right, bottom, top, near, far ) { var te = this.elements; var x = 2 * near / ( right - left ); var y = 2 * near / ( top - bottom ); var a = ( right + left ) / ( right - left ); var b = ( top + bottom ) / ( top - bottom ); var c = - ( far + near ) / ( far - near ); var d = - 2 * far * near / ( far - near ); te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; return this; }, makePerspective: function ( fov, aspect, near, far ) { var ymax = near * Math.tan( fov * Math.PI / 360 ); var ymin = - ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); }, makeOrthographic: function ( left, right, top, bottom, near, far ) { var te = this.elements; var w = right - left; var h = top - bottom; var p = far - near; var x = ( right + left ) / w; var y = ( top + bottom ) / h; var z = ( far + near ) / p; te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; te[2] = 0; te[6] = 0; te[10] = -2 / p; te[14] = -z; te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; return this; }, clone: function () { var te = this.elements; return new THREE.Matrix4( te[0], te[4], te[8], te[12], te[1], te[5], te[9], te[13], te[2], te[6], te[10], te[14], te[3], te[7], te[11], te[15] ); } }; THREE.Matrix4.__v1 = new THREE.Vector3(); THREE.Matrix4.__v2 = new THREE.Vector3(); THREE.Matrix4.__v3 = new THREE.Vector3(); THREE.Matrix4.__m1 = new THREE.Matrix4(); THREE.Matrix4.__m2 = new THREE.Matrix4(); /** * @author mr.doob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Object3D = function () { this.id = THREE.Object3DCount ++; this.name = ''; this.parent = undefined; this.children = []; this.up = new THREE.Vector3( 0, 1, 0 ); this.position = new THREE.Vector3(); this.rotation = new THREE.Vector3(); this.eulerOrder = 'XYZ'; this.scale = new THREE.Vector3( 1, 1, 1 ); this.doubleSided = false; this.flipSided = false; this.renderDepth = null; this.rotationAutoUpdate = true; this.matrix = new THREE.Matrix4(); this.matrixWorld = new THREE.Matrix4(); this.matrixRotationWorld = new THREE.Matrix4(); this.matrixAutoUpdate = true; this.matrixWorldNeedsUpdate = true; this.quaternion = new THREE.Quaternion(); this.useQuaternion = false; this.boundRadius = 0.0; this.boundRadiusScale = 1.0; this.visible = true; this.castShadow = false; this.receiveShadow = false; this.frustumCulled = true; this._vector = new THREE.Vector3(); }; THREE.Object3D.prototype = { constructor: THREE.Object3D, applyMatrix: function ( matrix ) { this.matrix.multiply( matrix, this.matrix ); this.scale.getScaleFromMatrix( this.matrix ); this.rotation.getRotationFromMatrix( this.matrix, this.scale ); this.position.getPositionFromMatrix( this.matrix ); }, translate: function ( distance, axis ) { this.matrix.rotateAxis( axis ); this.position.addSelf( axis.multiplyScalar( distance ) ); }, translateX: function ( distance ) { this.translate( distance, this._vector.set( 1, 0, 0 ) ); }, translateY: function ( distance ) { this.translate( distance, this._vector.set( 0, 1, 0 ) ); }, translateZ: function ( distance ) { this.translate( distance, this._vector.set( 0, 0, 1 ) ); }, lookAt: function ( vector ) { // TODO: Add hierarchy support. this.matrix.lookAt( vector, this.position, this.up ); if ( this.rotationAutoUpdate ) { this.rotation.getRotationFromMatrix( this.matrix ); } }, add: function ( object ) { if ( object === this ) { console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); return; } if ( this.children.indexOf( object ) === - 1 ) { if ( object.parent !== undefined ) { object.parent.remove( object ); } object.parent = this; this.children.push( object ); // add to scene var scene = this; while ( scene.parent !== undefined ) { scene = scene.parent; } if ( scene !== undefined && scene instanceof THREE.Scene ) { scene.__addObject( object ); } } }, remove: function ( object ) { var index = this.children.indexOf( object ); if ( index !== - 1 ) { object.parent = undefined; this.children.splice( index, 1 ); // remove from scene var scene = this; while ( scene.parent !== undefined ) { scene = scene.parent; } if ( scene !== undefined && scene instanceof THREE.Scene ) { scene.__removeObject( object ); } } }, getChildByName: function ( name, recursive ) { var c, cl, child; for ( c = 0, cl = this.children.length; c < cl; c ++ ) { child = this.children[ c ]; if ( child.name === name ) { return child; } if ( recursive ) { child = child.getChildByName( name, recursive ); if ( child !== undefined ) { return child; } } } return undefined; }, updateMatrix: function () { this.matrix.setPosition( this.position ); if ( this.useQuaternion ) { this.matrix.setRotationFromQuaternion( this.quaternion ); } else { this.matrix.setRotationFromEuler( this.rotation, this.eulerOrder ); } if ( this.scale.x !== 1 || this.scale.y !== 1 || this.scale.z !== 1 ) { this.matrix.scale( this.scale ); this.boundRadiusScale = Math.max( this.scale.x, Math.max( this.scale.y, this.scale.z ) ); } this.matrixWorldNeedsUpdate = true; }, updateMatrixWorld: function ( force ) { this.matrixAutoUpdate && this.updateMatrix(); // update matrixWorld if ( this.matrixWorldNeedsUpdate || force ) { if ( this.parent ) { this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix ); } else { this.matrixWorld.copy( this.matrix ); } this.matrixWorldNeedsUpdate = false; force = true; } // update children for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].updateMatrixWorld( force ); } } }; THREE.Object3DCount = 0; /** * @author mr.doob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ * @author julianwa / https://github.com/julianwa */ THREE.Projector = function() { var _object, _objectCount, _objectPool = [], _vertex, _vertexCount, _vertexPool = [], _face, _face3Count, _face3Pool = [], _face4Count, _face4Pool = [], _line, _lineCount, _linePool = [], _particle, _particleCount, _particlePool = [], _renderData = { objects: [], sprites: [], lights: [], elements: [] }, _vector3 = new THREE.Vector3(), _vector4 = new THREE.Vector4(), _projScreenMatrix = new THREE.Matrix4(), _projScreenobjectMatrixWorld = new THREE.Matrix4(), _frustum = new THREE.Frustum(), _clippedVertex1PositionScreen = new THREE.Vector4(), _clippedVertex2PositionScreen = new THREE.Vector4(), _face3VertexNormals; this.projectVector = function ( vector, camera ) { camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse ); _projScreenMatrix.multiplyVector3( vector ); return vector; }; this.unprojectVector = function ( vector, camera ) { camera.projectionMatrixInverse.getInverse( camera.projectionMatrix ); _projScreenMatrix.multiply( camera.matrixWorld, camera.projectionMatrixInverse ); _projScreenMatrix.multiplyVector3( vector ); return vector; }; this.pickingRay = function ( vector, camera ) { var end, ray, t; // set two vectors with opposing z values vector.z = -1.0; end = new THREE.Vector3( vector.x, vector.y, 1.0 ); this.unprojectVector( vector, camera ); this.unprojectVector( end, camera ); // find direction from vector to end end.subSelf( vector ).normalize(); return new THREE.Ray( vector, end ); }; this.projectGraph = function ( root, sort ) { _objectCount = 0; _renderData.objects.length = 0; _renderData.sprites.length = 0; _renderData.lights.length = 0; var projectObject = function ( object ) { if ( object.visible === false ) return; if ( ( object instanceof THREE.Mesh || object instanceof THREE.Line ) && ( object.frustumCulled === false || _frustum.contains( object ) ) ) { _vector3.copy( object.matrixWorld.getPosition() ); _projScreenMatrix.multiplyVector3( _vector3 ); _object = getNextObjectInPool(); _object.object = object; _object.z = _vector3.z; _renderData.objects.push( _object ); } else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) { _vector3.copy( object.matrixWorld.getPosition() ); _projScreenMatrix.multiplyVector3( _vector3 ); _object = getNextObjectInPool(); _object.object = object; _object.z = _vector3.z; _renderData.sprites.push( _object ); } else if ( object instanceof THREE.Light ) { _renderData.lights.push( object ); } for ( var c = 0, cl = object.children.length; c < cl; c ++ ) { projectObject( object.children[ c ] ); } }; projectObject( root ); sort && _renderData.objects.sort( painterSort ); return _renderData; }; this.projectScene = function ( scene, camera, sort ) { var near = camera.near, far = camera.far, visible = false, o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object, objectMatrixWorld, objectMatrixWorldRotation, geometry, geometryMaterials, vertices, vertex, vertexPositionScreen, faces, face, faceVertexNormals, normal, faceVertexUvs, uvs, v1, v2, v3, v4; _face3Count = 0; _face4Count = 0; _lineCount = 0; _particleCount = 0; _renderData.elements.length = 0; if ( camera.parent === undefined ) { console.warn( 'DEPRECATED: Camera hasn\'t been added to a Scene. Adding it...' ); scene.add( camera ); } scene.updateMatrixWorld(); camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); _renderData = this.projectGraph( scene, false ); for ( o = 0, ol = _renderData.objects.length; o < ol; o++ ) { object = _renderData.objects[ o ].object; objectMatrixWorld = object.matrixWorld; _vertexCount = 0; if ( object instanceof THREE.Mesh ) { geometry = object.geometry; geometryMaterials = object.geometry.materials; vertices = geometry.vertices; faces = geometry.faces; faceVertexUvs = geometry.faceVertexUvs; objectMatrixWorldRotation = object.matrixRotationWorld.extractRotation( objectMatrixWorld ); for ( v = 0, vl = vertices.length; v < vl; v ++ ) { _vertex = getNextVertexInPool(); _vertex.positionWorld.copy( vertices[ v ].position ); objectMatrixWorld.multiplyVector3( _vertex.positionWorld ); _vertex.positionScreen.copy( _vertex.positionWorld ); _projScreenMatrix.multiplyVector4( _vertex.positionScreen ); _vertex.positionScreen.x /= _vertex.positionScreen.w; _vertex.positionScreen.y /= _vertex.positionScreen.w; _vertex.visible = _vertex.positionScreen.z > near && _vertex.positionScreen.z < far; } for ( f = 0, fl = faces.length; f < fl; f ++ ) { face = faces[ f ]; if ( face instanceof THREE.Face3 ) { v1 = _vertexPool[ face.a ]; v2 = _vertexPool[ face.b ]; v3 = _vertexPool[ face.c ]; if ( v1.visible && v2.visible && v3.visible ) { visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; if ( object.doubleSided || visible != object.flipSided ) { _face = getNextFace3InPool(); _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); } else { continue; } } else { continue; } } else if ( face instanceof THREE.Face4 ) { v1 = _vertexPool[ face.a ]; v2 = _vertexPool[ face.b ]; v3 = _vertexPool[ face.c ]; v4 = _vertexPool[ face.d ]; if ( v1.visible && v2.visible && v3.visible && v4.visible ) { visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - ( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 || ( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) - ( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0; if ( object.doubleSided || visible != object.flipSided ) { _face = getNextFace4InPool(); _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); _face.v4.copy( v4 ); } else { continue; } } else { continue; } } _face.normalWorld.copy( face.normal ); if ( !visible && ( object.flipSided || object.doubleSided ) ) _face.normalWorld.negate(); objectMatrixWorldRotation.multiplyVector3( _face.normalWorld ); _face.centroidWorld.copy( face.centroid ); objectMatrixWorld.multiplyVector3( _face.centroidWorld ); _face.centroidScreen.copy( _face.centroidWorld ); _projScreenMatrix.multiplyVector3( _face.centroidScreen ); faceVertexNormals = face.vertexNormals; for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) { normal = _face.vertexNormalsWorld[ n ]; normal.copy( faceVertexNormals[ n ] ); if ( !visible && ( object.flipSided || object.doubleSided ) ) normal.negate(); objectMatrixWorldRotation.multiplyVector3( normal ); } for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) { uvs = faceVertexUvs[ c ][ f ]; if ( !uvs ) continue; for ( u = 0, ul = uvs.length; u < ul; u ++ ) { _face.uvs[ c ][ u ] = uvs[ u ]; } } _face.material = object.material; _face.faceMaterial = face.materialIndex !== null ? geometryMaterials[ face.materialIndex ] : null; _face.z = _face.centroidScreen.z; _renderData.elements.push( _face ); } } else if ( object instanceof THREE.Line ) { _projScreenobjectMatrixWorld.multiply( _projScreenMatrix, objectMatrixWorld ); vertices = object.geometry.vertices; v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ 0 ].position ); _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen ); // Handle LineStrip and LinePieces var step = object.type === THREE.LinePieces ? 2 : 1; for ( v = 1, vl = vertices.length; v < vl; v ++ ) { v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ v ].position ); _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen ); if ( ( v + 1 ) % step > 0 ) continue; v2 = _vertexPool[ _vertexCount - 2 ]; _clippedVertex1PositionScreen.copy( v1.positionScreen ); _clippedVertex2PositionScreen.copy( v2.positionScreen ); if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) ) { // Perform the perspective divide _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); _line = getNextLineInPool(); _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); _line.material = object.material; _renderData.elements.push( _line ); } } } } for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) { object = _renderData.sprites[ o ].object; objectMatrixWorld = object.matrixWorld; if ( object instanceof THREE.Particle ) { _vector4.set( objectMatrixWorld.elements[12], objectMatrixWorld.elements[13], objectMatrixWorld.elements[14], 1 ); _projScreenMatrix.multiplyVector4( _vector4 ); _vector4.z /= _vector4.w; if ( _vector4.z > 0 && _vector4.z < 1 ) { _particle = getNextParticleInPool(); _particle.x = _vector4.x / _vector4.w; _particle.y = _vector4.y / _vector4.w; _particle.z = _vector4.z; _particle.rotation = object.rotation.z; _particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); _particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); _particle.material = object.material; _renderData.elements.push( _particle ); } } } sort && _renderData.elements.sort( painterSort ); return _renderData; }; // Pools function getNextObjectInPool() { var object = _objectPool[ _objectCount ] = _objectPool[ _objectCount ] || new THREE.RenderableObject(); _objectCount ++; return object; } function getNextVertexInPool() { var vertex = _vertexPool[ _vertexCount ] = _vertexPool[ _vertexCount ] || new THREE.RenderableVertex(); _vertexCount ++; return vertex; } function getNextFace3InPool() { var face = _face3Pool[ _face3Count ] = _face3Pool[ _face3Count ] || new THREE.RenderableFace3(); _face3Count ++; return face; } function getNextFace4InPool() { var face = _face4Pool[ _face4Count ] = _face4Pool[ _face4Count ] || new THREE.RenderableFace4(); _face4Count ++; return face; } function getNextLineInPool() { var line = _linePool[ _lineCount ] = _linePool[ _lineCount ] || new THREE.RenderableLine(); _lineCount ++; return line; } function getNextParticleInPool() { var particle = _particlePool[ _particleCount ] = _particlePool[ _particleCount ] || new THREE.RenderableParticle(); _particleCount ++; return particle; } // function painterSort( a, b ) { return b.z - a.z; } function clipLine( s1, s2 ) { var alpha1 = 0, alpha2 = 1, // Calculate the boundary coordinate of each vertex for the near and far clip planes, // Z = -1 and Z = +1, respectively. bc1near = s1.z + s1.w, bc2near = s2.z + s2.w, bc1far = - s1.z + s1.w, bc2far = - s2.z + s2.w; if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { // Both vertices lie entirely within all clip planes. return true; } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { // Both vertices lie entirely outside one of the clip planes. return false; } else { // The line segment spans at least one clip plane. if ( bc1near < 0 ) { // v1 lies outside the near plane, v2 inside alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); } else if ( bc2near < 0 ) { // v2 lies outside the near plane, v1 inside alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); } if ( bc1far < 0 ) { // v1 lies outside the far plane, v2 inside alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); } else if ( bc2far < 0 ) { // v2 lies outside the far plane, v2 inside alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); } if ( alpha2 < alpha1 ) { // The line segment spans two boundaries, but is outside both of them. // (This can't happen when we're only clipping against just near/far but good // to leave the check here for future usage if other clip planes are added.) return false; } else { // Update the s1 and s2 vertices to match the clipped line segment. s1.lerpSelf( s2, alpha1 ); s2.lerpSelf( s1, 1 - alpha2 ); return true; } } } }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Quaternion = function( x, y, z, w ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; this.w = ( w !== undefined ) ? w : 1; }; THREE.Quaternion.prototype = { constructor: THREE.Quaternion, set: function ( x, y, z, w ) { this.x = x; this.y = y; this.z = z; this.w = w; return this; }, copy: function ( q ) { this.x = q.x; this.y = q.y; this.z = q.z; this.w = q.w; return this; }, setFromEuler: function ( vector ) { var c = Math.PI / 360, // 0.5 * Math.PI / 360, // 0.5 is an optimization x = vector.x * c, y = vector.y * c, z = vector.z * c, c1 = Math.cos( y ), s1 = Math.sin( y ), c2 = Math.cos( -z ), s2 = Math.sin( -z ), c3 = Math.cos( x ), s3 = Math.sin( x ), c1c2 = c1 * c2, s1s2 = s1 * s2; this.w = c1c2 * c3 - s1s2 * s3; this.x = c1c2 * s3 + s1s2 * c3; this.y = s1 * c2 * c3 + c1 * s2 * s3; this.z = c1 * s2 * c3 - s1 * c2 * s3; return this; }, setFromAxisAngle: function ( axis, angle ) { // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm // axis have to be normalized var halfAngle = angle / 2, s = Math.sin( halfAngle ); this.x = axis.x * s; this.y = axis.y * s; this.z = axis.z * s; this.w = Math.cos( halfAngle ); return this; }, setFromRotationMatrix: function ( m ) { // Adapted from: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm function copySign( a, b ) { return b < 0 ? -Math.abs( a ) : Math.abs( a ); } var absQ = Math.pow( m.determinant(), 1.0 / 3.0 ); this.w = Math.sqrt( Math.max( 0, absQ + m.elements[0] + m.elements[5] + m.elements[10] ) ) / 2; this.x = Math.sqrt( Math.max( 0, absQ + m.elements[0] - m.elements[5] - m.elements[10] ) ) / 2; this.y = Math.sqrt( Math.max( 0, absQ - m.elements[0] + m.elements[5] - m.elements[10] ) ) / 2; this.z = Math.sqrt( Math.max( 0, absQ - m.elements[0] - m.elements[5] + m.elements[10] ) ) / 2; this.x = copySign( this.x, ( m.elements[6] - m.elements[9] ) ); this.y = copySign( this.y, ( m.elements[8] - m.elements[2] ) ); this.z = copySign( this.z, ( m.elements[1] - m.elements[4] ) ); this.normalize(); return this; }, calculateW : function () { this.w = - Math.sqrt( Math.abs( 1.0 - this.x * this.x - this.y * this.y - this.z * this.z ) ); return this; }, inverse: function () { this.x *= -1; this.y *= -1; this.z *= -1; return this; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); }, normalize: function () { var l = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); if ( l === 0 ) { this.x = 0; this.y = 0; this.z = 0; this.w = 0; } else { l = 1 / l; this.x = this.x * l; this.y = this.y * l; this.z = this.z * l; this.w = this.w * l; } return this; }, multiply: function ( a, b ) { // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm this.x = a.x * b.w + a.y * b.z - a.z * b.y + a.w * b.x; this.y = -a.x * b.z + a.y * b.w + a.z * b.x + a.w * b.y; this.z = a.x * b.y - a.y * b.x + a.z * b.w + a.w * b.z; this.w = -a.x * b.x - a.y * b.y - a.z * b.z + a.w * b.w; return this; }, multiplySelf: function ( b ) { var qax = this.x, qay = this.y, qaz = this.z, qaw = this.w, qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w; this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; return this; }, multiplyVector3: function ( vector, dest ) { if ( !dest ) { dest = vector; } var x = vector.x, y = vector.y, z = vector.z, qx = this.x, qy = this.y, qz = this.z, qw = this.w; // calculate quat * vector var ix = qw * x + qy * z - qz * y, iy = qw * y + qz * x - qx * z, iz = qw * z + qx * y - qy * x, iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; return dest; }, clone: function () { return new THREE.Quaternion( this.x, this.y, this.z, this.w ); } } THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z; if (cosHalfTheta < 0) { qm.w = -qb.w; qm.x = -qb.x; qm.y = -qb.y; qm.z = -qb.z; cosHalfTheta = -cosHalfTheta; } else { qm.copy(qb); } if ( Math.abs( cosHalfTheta ) >= 1.0 ) { qm.w = qa.w; qm.x = qa.x; qm.y = qa.y; qm.z = qa.z; return qm; } var halfTheta = Math.acos( cosHalfTheta ), sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); if ( Math.abs( sinHalfTheta ) < 0.001 ) { qm.w = 0.5 * ( qa.w + qb.w ); qm.x = 0.5 * ( qa.x + qb.x ); qm.y = 0.5 * ( qa.y + qb.y ); qm.z = 0.5 * ( qa.z + qb.z ); return qm; } var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; qm.w = ( qa.w * ratioA + qm.w * ratioB ); qm.x = ( qa.x * ratioA + qm.x * ratioB ); qm.y = ( qa.y * ratioA + qm.y * ratioB ); qm.z = ( qa.z * ratioA + qm.z * ratioB ); return qm; } /** * @author mr.doob / http://mrdoob.com/ */ THREE.Vertex = function ( position ) { this.position = position || new THREE.Vector3(); }; THREE.Vertex.prototype = { constructor: THREE.Vertex, clone: function () { return new THREE.Vertex( this.position.clone() ); } }; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { this.a = a; this.b = b; this.c = c; this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); this.vertexNormals = normal instanceof Array ? normal : [ ]; this.color = color instanceof THREE.Color ? color : new THREE.Color(); this.vertexColors = color instanceof Array ? color : []; this.vertexTangents = []; this.materialIndex = materialIndex; this.centroid = new THREE.Vector3(); }; THREE.Face3.prototype = { constructor: THREE.Face3, clone: function () { var face = new THREE.Face3( this.a, this.b, this.c ); face.normal.copy( this.normal ); face.color.copy( this.color ); face.centroid.copy( this.centroid ); face.materialIndex = this.materialIndex; var i, il; for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); return face; } }; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { this.a = a; this.b = b; this.c = c; this.d = d; this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); this.vertexNormals = normal instanceof Array ? normal : [ ]; this.color = color instanceof THREE.Color ? color : new THREE.Color(); this.vertexColors = color instanceof Array ? color : []; this.vertexTangents = []; this.materialIndex = materialIndex; this.centroid = new THREE.Vector3(); }; THREE.Face4.prototype = { constructor: THREE.Face4, clone: function () { var face = new THREE.Face4( this.a, this.b, this.c, this.d ); face.normal.copy( this.normal ); face.color.copy( this.color ); face.centroid.copy( this.centroid ); face.materialIndex = this.materialIndex; var i, il; for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); return face; } }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.UV = function ( u, v ) { this.u = u || 0; this.v = v || 0; }; THREE.UV.prototype = { constructor: THREE.UV, set: function ( u, v ) { this.u = u; this.v = v; return this; }, copy: function ( uv ) { this.u = uv.u; this.v = uv.v; return this; }, lerpSelf: function ( uv, alpha ) { this.u += ( uv.u - this.u ) * alpha; this.v += ( uv.v - this.v ) * alpha; return this; }, clone: function () { return new THREE.UV( this.u, this.v ); } }; /** * @author mr.doob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ */ THREE.Camera = function () { THREE.Object3D.call( this ); this.matrixWorldInverse = new THREE.Matrix4(); this.projectionMatrix = new THREE.Matrix4(); this.projectionMatrixInverse = new THREE.Matrix4(); }; THREE.Camera.prototype = new THREE.Object3D(); THREE.Camera.prototype.constructor = THREE.Camera; THREE.Camera.prototype.lookAt = function ( vector ) { // TODO: Add hierarchy support. this.matrix.lookAt( this.position, vector, this.up ); if ( this.rotationAutoUpdate ) { this.rotation.getRotationFromMatrix( this.matrix ); } }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { THREE.Camera.call( this ); this.left = left; this.right = right; this.top = top; this.bottom = bottom; this.near = ( near !== undefined ) ? near : 0.1; this.far = ( far !== undefined ) ? far : 2000; this.updateProjectionMatrix(); }; THREE.OrthographicCamera.prototype = new THREE.Camera(); THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); }; /** * @author mr.doob / http://mrdoob.com/ * @author greggman / http://games.greggman.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { THREE.Camera.call( this ); this.fov = fov !== undefined ? fov : 50; this.aspect = aspect !== undefined ? aspect : 1; this.near = near !== undefined ? near : 0.1; this.far = far !== undefined ? far : 2000; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype = new THREE.Camera(); THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; /** * Uses Focal Length (in mm) to estimate and set FOV * 35mm (fullframe) camera is used if frame size is not specified; * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html */ THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { frameHeight = frameHeight !== undefined ? frameHeight : 24; this.fov = 2 * Math.atan( frameHeight / ( focalLength * 2 ) ) * ( 180 / Math.PI ); this.updateProjectionMatrix(); } /** * Sets an offset in a larger frustum. This is useful for multi-window or * multi-monitor/multi-machine setups. * * For example, if you have 3x2 monitors and each monitor is 1920x1080 and * the monitors are in grid like this * * +---+---+---+ * | A | B | C | * +---+---+---+ * | D | E | F | * +---+---+---+ * * then for each monitor you would call it like this * * var w = 1920; * var h = 1080; * var fullWidth = w * 3; * var fullHeight = h * 2; * * --A-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); * --B-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); * --C-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); * --D-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); * --E-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); * --F-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); * * Note there is no reason monitors have to be the same size or in a grid. */ THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { this.fullWidth = fullWidth; this.fullHeight = fullHeight; this.x = x; this.y = y; this.width = width; this.height = height; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { if ( this.fullWidth ) { var aspect = this.fullWidth / this.fullHeight; var top = Math.tan( this.fov * Math.PI / 360 ) * this.near; var bottom = -top; var left = aspect * bottom; var right = aspect * top; var width = Math.abs( right - left ); var height = Math.abs( top - bottom ); this.projectionMatrix.makeFrustum( left + this.x * width / this.fullWidth, left + ( this.x + this.width ) * width / this.fullWidth, top - ( this.y + this.height ) * height / this.fullHeight, top - this.y * height / this.fullHeight, this.near, this.far ); } else { this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); } }; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Light = function ( hex ) { THREE.Object3D.call( this ); this.color = new THREE.Color( hex ); }; THREE.Light.prototype = new THREE.Object3D(); THREE.Light.prototype.constructor = THREE.Light; THREE.Light.prototype.supr = THREE.Object3D.prototype; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Material = function ( parameters ) { parameters = parameters || {}; this.id = THREE.MaterialCount ++; this.name = ''; this.opacity = parameters.opacity !== undefined ? parameters.opacity : 1; this.transparent = parameters.transparent !== undefined ? parameters.transparent : false; this.blending = parameters.blending !== undefined ? parameters.blending : THREE.NormalBlending; this.blendSrc = parameters.blendSrc !== undefined ? parameters.blendSrc : THREE.SrcAlphaFactor; this.blendDst = parameters.blendDst !== undefined ? parameters.blendDst : THREE.OneMinusSrcAlphaFactor; this.blendEquation = parameters.blendEquation !== undefined ? parameters.blendEquation : THREE.AddEquation; this.depthTest = parameters.depthTest !== undefined ? parameters.depthTest : true; this.depthWrite = parameters.depthWrite !== undefined ? parameters.depthWrite : true; this.polygonOffset = parameters.polygonOffset !== undefined ? parameters.polygonOffset : false; this.polygonOffsetFactor = parameters.polygonOffsetFactor !== undefined ? parameters.polygonOffsetFactor : 0; this.polygonOffsetUnits = parameters.polygonOffsetUnits !== undefined ? parameters.polygonOffsetUnits : 0; this.alphaTest = parameters.alphaTest !== undefined ? parameters.alphaTest : 0; this.overdraw = parameters.overdraw !== undefined ? parameters.overdraw : false; // Boolean for fixing antialiasing gaps in CanvasRenderer this.needsUpdate = true; } THREE.MaterialCount = 0; // shading THREE.NoShading = 0; THREE.FlatShading = 1; THREE.SmoothShading = 2; // colors THREE.NoColors = 0; THREE.FaceColors = 1; THREE.VertexColors = 2; // blending modes THREE.NoBlending = 0; THREE.NormalBlending = 1; THREE.AdditiveBlending = 2; THREE.SubtractiveBlending = 3; THREE.MultiplyBlending = 4; THREE.AdditiveAlphaBlending = 5; THREE.CustomBlending = 6; // custom blending equations // (numbers start from 100 not to clash with other // mappings to OpenGL constants defined in Texture.js) THREE.AddEquation = 100; THREE.SubtractEquation = 101; THREE.ReverseSubtractEquation = 102; // custom blending destination factors THREE.ZeroFactor = 200; THREE.OneFactor = 201; THREE.SrcColorFactor = 202; THREE.OneMinusSrcColorFactor = 203; THREE.SrcAlphaFactor = 204; THREE.OneMinusSrcAlphaFactor = 205; THREE.DstAlphaFactor = 206; THREE.OneMinusDstAlphaFactor = 207; // custom blending source factors //THREE.ZeroFactor = 200; //THREE.OneFactor = 201; //THREE.SrcAlphaFactor = 204; //THREE.OneMinusSrcAlphaFactor = 205; //THREE.DstAlphaFactor = 206; //THREE.OneMinusDstAlphaFactor = 207; THREE.DstColorFactor = 208; THREE.OneMinusDstColorFactor = 209; THREE.SrcAlphaSaturateFactor = 210; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * * linewidth: , * linecap: "round", * linejoin: "round", * * vertexColors: * * fog: * } */ THREE.LineBasicMaterial = function ( parameters ) { THREE.Material.call( this, parameters ); parameters = parameters || {}; this.color = parameters.color !== undefined ? new THREE.Color( parameters.color ) : new THREE.Color( 0xffffff ); this.linewidth = parameters.linewidth !== undefined ? parameters.linewidth : 1; this.linecap = parameters.linecap !== undefined ? parameters.linecap : 'round'; this.linejoin = parameters.linejoin !== undefined ? parameters.linejoin : 'round'; this.vertexColors = parameters.vertexColors ? parameters.vertexColors : false; this.fog = parameters.fog !== undefined ? parameters.fog : true; }; THREE.LineBasicMaterial.prototype = new THREE.Material(); THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * lightMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * * fog: * } */ THREE.MeshBasicMaterial = function ( parameters ) { THREE.Material.call( this, parameters ); parameters = parameters || {}; // color property represents emissive for MeshBasicMaterial this.color = parameters.color !== undefined ? new THREE.Color( parameters.color ) : new THREE.Color( 0xffffff ); this.map = parameters.map !== undefined ? parameters.map : null; this.lightMap = parameters.lightMap !== undefined ? parameters.lightMap : null; this.envMap = parameters.envMap !== undefined ? parameters.envMap : null; this.combine = parameters.combine !== undefined ? parameters.combine : THREE.MultiplyOperation; this.reflectivity = parameters.reflectivity !== undefined ? parameters.reflectivity : 1; this.refractionRatio = parameters.refractionRatio !== undefined ? parameters.refractionRatio : 0.98; this.fog = parameters.fog !== undefined ? parameters.fog : true; this.shading = parameters.shading !== undefined ? parameters.shading : THREE.SmoothShading; this.wireframe = parameters.wireframe !== undefined ? parameters.wireframe : false; this.wireframeLinewidth = parameters.wireframeLinewidth !== undefined ? parameters.wireframeLinewidth : 1; this.wireframeLinecap = parameters.wireframeLinecap !== undefined ? parameters.wireframeLinecap : 'round'; this.wireframeLinejoin = parameters.wireframeLinejoin !== undefined ? parameters.wireframeLinejoin : 'round'; this.vertexColors = parameters.vertexColors !== undefined ? parameters.vertexColors : THREE.NoColors; this.skinning = parameters.skinning !== undefined ? parameters.skinning : false; this.morphTargets = parameters.morphTargets !== undefined ? parameters.morphTargets : false; }; THREE.MeshBasicMaterial.prototype = new THREE.Material(); THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * size: , * * blending: THREE.NormalBlending, * depthTest: , * * vertexColors: , * * fog: * } */ THREE.ParticleBasicMaterial = function ( parameters ) { THREE.Material.call( this, parameters ); parameters = parameters || {}; this.color = parameters.color !== undefined ? new THREE.Color( parameters.color ) : new THREE.Color( 0xffffff ); this.map = parameters.map !== undefined ? parameters.map : null; this.size = parameters.size !== undefined ? parameters.size : 1; this.sizeAttenuation = parameters.sizeAttenuation !== undefined ? parameters.sizeAttenuation : true; this.vertexColors = parameters.vertexColors !== undefined ? parameters.vertexColors : false; this.fog = parameters.fog !== undefined ? parameters.fog : true; }; THREE.ParticleBasicMaterial.prototype = new THREE.Material(); THREE.ParticleBasicMaterial.prototype.constructor = THREE.ParticleBasicMaterial; /** * @author mr.doob / http://mrdoob.com/ */ THREE.ParticleDOMMaterial = function ( domElement ) { THREE.Material.call( this ); this.domElement = domElement; }; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ */ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type ) { this.id = THREE.TextureCount ++; this.image = image; this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; this.format = format !== undefined ? format : THREE.RGBAFormat; this.type = type !== undefined ? type : THREE.UnsignedByteType; this.offset = new THREE.Vector2( 0, 0 ); this.repeat = new THREE.Vector2( 1, 1 ); this.generateMipmaps = true; this.premultiplyAlpha = false; this.needsUpdate = false; this.onUpdate = null; }; THREE.Texture.prototype = { constructor: THREE.Texture, clone: function () { var clonedTexture = new THREE.Texture( this.image, this.mapping, this.wrapS, this.wrapT, this.magFilter, this.minFilter, this.format, this.type ); clonedTexture.offset.copy( this.offset ); clonedTexture.repeat.copy( this.repeat ); return clonedTexture; } }; THREE.TextureCount = 0; THREE.MultiplyOperation = 0; THREE.MixOperation = 1; // Mapping modes THREE.UVMapping = function () {}; THREE.CubeReflectionMapping = function () {}; THREE.CubeRefractionMapping = function () {}; THREE.SphericalReflectionMapping = function () {}; THREE.SphericalRefractionMapping = function () {}; // Wrapping modes THREE.RepeatWrapping = 0; THREE.ClampToEdgeWrapping = 1; THREE.MirroredRepeatWrapping = 2; // Filters THREE.NearestFilter = 3; THREE.NearestMipMapNearestFilter = 4; THREE.NearestMipMapLinearFilter = 5; THREE.LinearFilter = 6; THREE.LinearMipMapNearestFilter = 7; THREE.LinearMipMapLinearFilter = 8; // Types THREE.ByteType = 9; THREE.UnsignedByteType = 10; THREE.ShortType = 11; THREE.UnsignedShortType = 12; THREE.IntType = 13; THREE.UnsignedIntType = 14; THREE.FloatType = 15; // Formats THREE.AlphaFormat = 16; THREE.RGBFormat = 17; THREE.RGBAFormat = 18; THREE.LuminanceFormat = 19; THREE.LuminanceAlphaFormat = 20; /** * @author alteredq / http://alteredqualia.com/ */ THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter ) { THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type ); this.image = { data: data, width: width, height: height }; }; THREE.DataTexture.prototype = new THREE.Texture(); THREE.DataTexture.prototype.constructor = THREE.DataTexture; THREE.DataTexture.prototype.clone = function () { var clonedTexture = new THREE.DataTexture( this.image.data, this.image.width, this.image.height, this.format, this.type, this.mapping, this.wrapS, this.wrapT, this.magFilter, this.minFilter ); clonedTexture.offset.copy( this.offset ); clonedTexture.repeat.copy( this.repeat ); return clonedTexture; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.Particle = function ( material ) { THREE.Object3D.call( this ); this.material = material; }; THREE.Particle.prototype = new THREE.Object3D(); THREE.Particle.prototype.constructor = THREE.Particle; /** * @author mr.doob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ */ THREE.Mesh = function ( geometry, material ) { THREE.Object3D.call( this ); this.geometry = geometry; this.material = ( material !== undefined ) ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: true } ); if ( this.geometry ) { // calc bound radius if( ! this.geometry.boundingSphere ) { this.geometry.computeBoundingSphere(); } this.boundRadius = geometry.boundingSphere.radius; // setup morph targets if( this.geometry.morphTargets.length ) { this.morphTargetBase = -1; this.morphTargetForcedOrder = []; this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for( var m = 0; m < this.geometry.morphTargets.length; m ++ ) { this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; } } } } THREE.Mesh.prototype = new THREE.Object3D(); THREE.Mesh.prototype.constructor = THREE.Mesh; THREE.Mesh.prototype.supr = THREE.Object3D.prototype; /* * Get Morph Target Index by Name */ THREE.Mesh.prototype.getMorphTargetIndexByName = function( name ) { if ( this.morphTargetDictionary[ name ] !== undefined ) { return this.morphTargetDictionary[ name ]; } console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); return 0; } /** * @author mr.doob / http://mrdoob.com/ */ THREE.Line = function ( geometry, material, type ) { THREE.Object3D.call( this ); this.geometry = geometry; this.material = ( material !== undefined ) ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); this.type = ( type !== undefined ) ? type : THREE.LineStrip; if ( this.geometry ) { if ( ! this.geometry.boundingSphere ) { this.geometry.computeBoundingSphere(); } } }; THREE.LineStrip = 0; THREE.LinePieces = 1; THREE.Line.prototype = new THREE.Object3D(); THREE.Line.prototype.constructor = THREE.Line; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Bone = function( belongsToSkin ) { THREE.Object3D.call( this ); this.skin = belongsToSkin; this.skinMatrix = new THREE.Matrix4(); }; THREE.Bone.prototype = new THREE.Object3D(); THREE.Bone.prototype.constructor = THREE.Bone; THREE.Bone.prototype.supr = THREE.Object3D.prototype; THREE.Bone.prototype.update = function( parentSkinMatrix, forceUpdate ) { // update local if ( this.matrixAutoUpdate ) { forceUpdate |= this.updateMatrix(); } // update skin matrix if ( forceUpdate || this.matrixWorldNeedsUpdate ) { if( parentSkinMatrix ) { this.skinMatrix.multiply( parentSkinMatrix, this.matrix ); } else { this.skinMatrix.copy( this.matrix ); } this.matrixWorldNeedsUpdate = false; forceUpdate = true; } // update children var child, i, l = this.children.length; for ( i = 0; i < l; i ++ ) { this.children[ i ].update( this.skinMatrix, forceUpdate ); } }; /** * @author mikael emtinger / http://gomo.se/ */ THREE.Sprite = function ( parameters ) { THREE.Object3D.call( this ); this.color = ( parameters.color !== undefined ) ? new THREE.Color( parameters.color ) : new THREE.Color( 0xffffff ); this.map = ( parameters.map !== undefined ) ? parameters.map : new THREE.Texture(); this.blending = ( parameters.blending !== undefined ) ? parameters.blending : THREE.NormalBlending; this.blendSrc = parameters.blendSrc !== undefined ? parameters.blendSrc : THREE.SrcAlphaFactor; this.blendDst = parameters.blendDst !== undefined ? parameters.blendDst : THREE.OneMinusSrcAlphaFactor; this.blendEquation = parameters.blendEquation !== undefined ? parameters.blendEquation : THREE.AddEquation; this.useScreenCoordinates = ( parameters.useScreenCoordinates !== undefined ) ? parameters.useScreenCoordinates : true; this.mergeWith3D = ( parameters.mergeWith3D !== undefined ) ? parameters.mergeWith3D : !this.useScreenCoordinates; this.affectedByDistance = ( parameters.affectedByDistance !== undefined ) ? parameters.affectedByDistance : !this.useScreenCoordinates; this.scaleByViewport = ( parameters.scaleByViewport !== undefined ) ? parameters.scaleByViewport : !this.affectedByDistance; this.alignment = ( parameters.alignment instanceof THREE.Vector2 ) ? parameters.alignment : THREE.SpriteAlignment.center; this.rotation3d = this.rotation; this.rotation = 0; this.opacity = 1; this.uvOffset = new THREE.Vector2( 0, 0 ); this.uvScale = new THREE.Vector2( 1, 1 ); }; THREE.Sprite.prototype = new THREE.Object3D(); THREE.Sprite.prototype.constructor = THREE.Sprite; /* * Custom update matrix */ THREE.Sprite.prototype.updateMatrix = function () { this.matrix.setPosition( this.position ); this.rotation3d.set( 0, 0, this.rotation ); this.matrix.setRotationFromEuler( this.rotation3d ); if ( this.scale.x !== 1 || this.scale.y !== 1 ) { this.matrix.scale( this.scale ); this.boundRadiusScale = Math.max( this.scale.x, this.scale.y ); } this.matrixWorldNeedsUpdate = true; }; /* * Alignment */ THREE.SpriteAlignment = {}; THREE.SpriteAlignment.topLeft = new THREE.Vector2( 1, -1 ); THREE.SpriteAlignment.topCenter = new THREE.Vector2( 0, -1 ); THREE.SpriteAlignment.topRight = new THREE.Vector2( -1, -1 ); THREE.SpriteAlignment.centerLeft = new THREE.Vector2( 1, 0 ); THREE.SpriteAlignment.center = new THREE.Vector2( 0, 0 ); THREE.SpriteAlignment.centerRight = new THREE.Vector2( -1, 0 ); THREE.SpriteAlignment.bottomLeft = new THREE.Vector2( 1, 1 ); THREE.SpriteAlignment.bottomCenter = new THREE.Vector2( 0, 1 ); THREE.SpriteAlignment.bottomRight = new THREE.Vector2( -1, 1 ); /** * @author mr.doob / http://mrdoob.com/ */ THREE.Scene = function () { THREE.Object3D.call( this ); this.fog = null; this.overrideMaterial = null; this.matrixAutoUpdate = false; this.__objects = []; this.__lights = []; this.__objectsAdded = []; this.__objectsRemoved = []; }; THREE.Scene.prototype = new THREE.Object3D(); THREE.Scene.prototype.constructor = THREE.Scene; THREE.Scene.prototype.__addObject = function ( object ) { if ( object instanceof THREE.Light ) { if ( this.__lights.indexOf( object ) === - 1 ) { this.__lights.push( object ); } } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { if ( this.__objects.indexOf( object ) === - 1 ) { this.__objects.push( object ); this.__objectsAdded.push( object ); // check if previously removed var i = this.__objectsRemoved.indexOf( object ); if ( i !== -1 ) { this.__objectsRemoved.splice( i, 1 ); } } } for ( var c = 0; c < object.children.length; c ++ ) { this.__addObject( object.children[ c ] ); } }; THREE.Scene.prototype.__removeObject = function ( object ) { if ( object instanceof THREE.Light ) { var i = this.__lights.indexOf( object ); if ( i !== -1 ) { this.__lights.splice( i, 1 ); } } else if ( !( object instanceof THREE.Camera ) ) { var i = this.__objects.indexOf( object ); if( i !== -1 ) { this.__objects.splice( i, 1 ); this.__objectsRemoved.push( object ); // check if previously added var ai = this.__objectsAdded.indexOf( object ); if ( ai !== -1 ) { this.__objectsAdded.splice( ai, 1 ); } } } for ( var c = 0; c < object.children.length; c ++ ) { this.__removeObject( object.children[ c ] ); } }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.DOMRenderer = function () { var _renderData, _elements, _width, _height, _widthHalf, _heightHalf, _transformProp, _projector = new THREE.Projector(); var getSupportedProp = function ( proparray ) { var root = document.documentElement for ( var i = 0; i < proparray.length; i ++ ) { if ( typeof root.style[ proparray[ i ] ] === "string" ) { return proparray[i]; } } return null; }; _transformProp = getSupportedProp( [ 'transform', 'MozTransform', 'WebkitTransform', 'msTransform', 'OTransform' ] ); this.domElement = document.createElement( 'div' ); this.setSize = function ( width, height ) { _width = width; _height = height; _widthHalf = _width / 2; _heightHalf = _height / 2; }; this.render = function ( scene, camera ) { var e, el, m, ml, element, material, dom, v1x, v1y; _renderData = _projector.projectScene( scene, camera ); _elements = _renderData.elements; for ( e = 0, el = _elements.length; e < el; e ++ ) { element = _elements[ e ]; if ( element instanceof THREE.RenderableParticle && element.material instanceof THREE.ParticleDOMMaterial ) { dom = element.material.domElement; v1x = element.x * _widthHalf + _widthHalf - ( dom.offsetWidth >> 1 ); v1y = element.y * _heightHalf + _heightHalf - ( dom.offsetHeight >> 1 ); dom.style.left = v1x + 'px'; dom.style.top = v1y + 'px'; dom.style.zIndex = Math.abs( Math.floor( ( 1 - element.z ) * camera.far / camera.near ) ) if ( _transformProp ) { var scaleX = element.scale.x * _widthHalf; var scaleY = element.scale.y * _heightHalf; var scaleVal = "scale(" + scaleX + "," + scaleY + ")"; dom.style[ _transformProp ] = scaleVal; } } } }; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableParticle = function () { this.x = null; this.y = null; this.z = null; this.rotation = null; this.scale = new THREE.Vector2(); this.material = null; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableVertex = function () { this.positionWorld = new THREE.Vector3(); this.positionScreen = new THREE.Vector4(); this.visible = true; }; THREE.RenderableVertex.prototype.copy = function ( vertex ) { this.positionWorld.copy( vertex.positionWorld ); this.positionScreen.copy( vertex.positionScreen ); } /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableFace3 = function () { this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.v3 = new THREE.RenderableVertex(); this.centroidWorld = new THREE.Vector3(); this.centroidScreen = new THREE.Vector3(); this.normalWorld = new THREE.Vector3(); this.vertexNormalsWorld = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; this.material = null; this.faceMaterial = null; this.uvs = [[]]; this.z = null; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableFace4 = function () { this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.v3 = new THREE.RenderableVertex(); this.v4 = new THREE.RenderableVertex(); this.centroidWorld = new THREE.Vector3(); this.centroidScreen = new THREE.Vector3(); this.normalWorld = new THREE.Vector3(); this.vertexNormalsWorld = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; this.material = null; this.faceMaterial = null; this.uvs = [[]]; this.z = null; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableObject = function () { this.object = null; this.z = null; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableParticle = function () { this.x = null; this.y = null; this.z = null; this.rotation = null; this.scale = new THREE.Vector2(); this.material = null; }; /** * @author mr.doob / http://mrdoob.com/ */ THREE.RenderableLine = function () { this.z = null; this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.material = null; };