Browse Source

Merge branch 'dev' into FixSkinningShadow

Conflicts:
	src/renderers/webgl/WebGLShadowMap.js
takahiro 8 years ago
parent
commit
0a24f91309
48 changed files with 2147 additions and 2267 deletions
  1. 485 528
      build/three.js
  2. 331 333
      build/three.min.js
  3. 485 528
      build/three.module.js
  4. 6 6
      docs/api/math/Line3.html
  5. 4 4
      docs/api/math/Math.html
  6. 6 6
      docs/api/math/Quaternion.html
  7. 20 21
      docs/api/math/Vector2.html
  8. 5 5
      docs/api/math/Vector3.html
  9. 18 19
      docs/api/math/Vector4.html
  10. 2 2
      docs/scenes/js/geometry.js
  11. 8 0
      examples/js/controls/OrbitControls.js
  12. 9 20
      examples/js/loaders/GLTF2Loader.js
  13. 14 13
      examples/js/loaders/GLTFLoader.js
  14. 72 81
      examples/js/renderers/CanvasRenderer.js
  15. 75 35
      examples/js/renderers/Projector.js
  16. 12 0
      examples/models/json/suzanne.json
  17. 0 2
      examples/webgl_effects_peppersghost.html
  18. 1 3
      examples/webgl_loader_gltf.html
  19. 2 2
      examples/webgl_performance.html
  20. 2 2
      examples/webgl_performance_static.html
  21. 1 1
      package.json
  22. 0 16
      src/cameras/Camera.js
  23. 4 0
      src/core/BufferAttribute.js
  24. 5 5
      src/core/Layers.js
  25. 18 3
      src/core/Object3D.js
  26. 11 0
      src/lights/RectAreaLight.js
  27. 7 0
      src/loaders/ObjectLoader.js
  28. 1 0
      src/materials/SpriteMaterial.js
  29. 12 8
      src/math/Quaternion.js
  30. 24 33
      src/math/Vector2.js
  31. 4 22
      src/math/Vector3.js
  32. 4 15
      src/math/Vector4.js
  33. 1 0
      src/objects/Points.js
  34. 139 127
      src/renderers/WebGLRenderer.js
  35. 153 0
      src/renderers/webgl/WebGLAttributes.js
  36. 99 54
      src/renderers/webgl/WebGLGeometries.js
  37. 16 225
      src/renderers/webgl/WebGLObjects.js
  38. 19 17
      src/renderers/webgl/WebGLProperties.js
  39. 20 20
      src/renderers/webgl/WebGLShadowMap.js
  40. 16 53
      src/renderers/webgl/WebGLState.js
  41. 9 10
      src/renderers/webgl/WebGLTextures.js
  42. 2 2
      src/renderers/webgl/plugins/LensFlarePlugin.js
  43. 2 2
      src/renderers/webgl/plugins/SpritePlugin.js
  44. 10 30
      test/unit/src/core/Object3D.js
  45. 4 5
      test/unit/src/math/Triangle.js
  46. 1 1
      test/unit/src/math/Vector2.js
  47. 1 1
      test/unit/src/math/Vector3.js
  48. 7 7
      test/unit/src/math/Vector4.js

File diff suppressed because it is too large
+ 485 - 528
build/three.js


File diff suppressed because it is too large
+ 331 - 333
build/three.min.js


File diff suppressed because it is too large
+ 485 - 528
build/three.module.js


+ 6 - 6
docs/api/math/Line3.html

@@ -40,7 +40,7 @@
 		<h2>Methods</h2>
 
 		<h3>[method:Line3 applyMatrix4]( [page:Matrix4 matrix] )</h3>
-		<div>Apply a matrix transform to the line segment.</div>
+		<div>Applies a matrix transform to the line segment.</div>
 
 		<h3>[method:Vector3 at]( [page:Float t], [page:Vector3 optionalTarget] )</h3>
 		<div>
@@ -48,12 +48,12 @@
 		[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 		otherwise a new [page:Vector3] will be created.<br /><br />
 
-		Return a vector at a certain position along the line. When [page:Float t] = 0, it returns the start vector,
+		Returns a vector at a certain position along the line. When [page:Float t] = 0, it returns the start vector,
 		and when [page:Float t] = 1 it returns the end vector.<br />
 		</div>
 
 		<h3>[method:Line3 clone]()</h3>
-		<div>Return a new [page:Line3] with the same [page:.start start] and [page:.end end] vectors as this one.</div>
+		<div>Returns a new [page:Line3] with the same [page:.start start] and [page:.end end] vectors as this one.</div>
 
 		<h3>[method:Vector3 closestPointToPoint]( [page:Vector3 point], [page:Boolean clampToLine], [page:Vector3 optionalTarget] )</h3>
 		<div>
@@ -72,7 +72,7 @@
 		[page:Boolean clampToLine] - Whether to clamp the result to the range [0, 1].<br /><br />
 
 		Returns a point parameter based on the closest point as projected on the line segement.
-		If clamp to line is true, then the returned value will be between 0 and 1.
+		If [page:Boolean clampToLine] is true, then the returned value will be between 0 and 1.
 		</div>
 
 		<h3>[method:Line3 copy]( [page:Line3 line] )</h3>
@@ -109,13 +109,13 @@
 			[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 			otherwise a new [page:Vector3] will be created.<br /><br />
 
-		Return the center of the line segment.
+		Returns the center of the line segment.
 		</div>
 
 		<h3>[method:Line3 set]( [page:Vector3 start], [page:Vector3 end] )</h3>
 		<div>
 		[page:Vector3 start] - set the [page:.start start point] of the line.<br />
-		end - [page:Vector3] - set the [page:.end end point] of the line.<br /><br />
+		[page:Vector3 end] - set the [page:.end end point] of the line.<br /><br />
 
 		Sets the start and end values by copying the provided vectors.
 		</div>

+ 4 - 4
docs/api/math/Math.html

@@ -30,7 +30,7 @@
 		<div>
 		[page:Integer n], [page:Integer m] - Integers<br /><br />
 
-		Compute the Euclidean modulo of m % [page:Integer n], that is:
+		Computes the Euclidean modulo of [page:Integer m] % [page:Integer n], that is:
 		<code>( ( n % m ) + m ) % m</code>
 		</div>
 
@@ -71,10 +71,10 @@
 		</div>
 
 		<h3>[method:Integer nearestPowerOfTwo]( [page:Number n] )</h3>
-		<div>	Return the nearest power of 2 to a given number [page:Number n].</div>
+		<div>	Returns the nearest power of 2 to a given number [page:Number n].</div>
 
 		<h3>[method:Integer nextPowerOfTwo]( [page:Number n] )</h3>
-		<div>Return the nearest power of 2 that is bigger than [page:Number n].</div>
+		<div>Returns the nearest power of 2 that is bigger than [page:Number n].</div>
 
 		<h3>[method:Float radToDeg]( [page:Float radians] )</h3>
 		<div>Converts radians to degrees.</div>
@@ -83,7 +83,7 @@
 		<div>Random float in the interval [page:Float low] to [page:Float high].</div>
 
 		<h3>[method:Float randFloatSpread]( [page:Float range] )</h3>
-		<div>Random float in the intercal *- [page:Float range] / 2* to *[page:Float range] / 2*.</div>
+		<div>Random float in the interval *- [page:Float range] / 2* to *[page:Float range] / 2*.</div>
 
 		<h3>[method:Integer randInt]( [page:Integer low], [page:Integer high] )</h3>
 		<div>Random integer in the interval [page:Float low] to [page:Float high].</div>

+ 6 - 6
docs/api/math/Quaternion.html

@@ -89,7 +89,7 @@
 
 		<h3>[method:Float dot]( [page:Quaternion v] )</h3>
 		<div>
-			Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of
+			Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of
 			quaternions [page:Quaternion v] and this one.
 		</div>
 
@@ -137,11 +137,11 @@
 		</div>
 
 		<h3>[method:Quaternion onChange]( [page:Function onChangeCallback] )</h3>
-		<div>Set the [page:.onChangeCallback onChangeCallback]() method.</div>
+		<div>Sets the [page:.onChangeCallback onChangeCallback]() method.</div>
 
 		<h3>[method:Quaternion onChangeCallback]( )</h3>
 		<div>
-			This function is called whenever and of the following occur:
+			This function is called whenever any of the following occurs:
 			<ul>
 				<li>
 					The [page:.x x], [page:.y y], [page:.z z] or
@@ -188,7 +188,7 @@
 		<div>
 		Sets this quaternion from rotation specified by [page:Vector3 axis] and [page:Float angle].<br />
 		Adapted from the method [link:http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm here].<br />
-		*Axis* is asumed to be normalized, *angle* is in radians.
+		*Axis* is assumed to be normalized, *angle* is in radians.
 		</div>
 
 		<h3>[method:Quaternion setFromEuler]( [page:Euler euler] )</h3>
@@ -210,8 +210,8 @@
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - An optional array to store the quaternion. If not specified a new array will be created.<br/>
-		[page:Integer offset] - optional) if specified, the result will be copied
+		[page:Array array] - An optional array to store the quaternion. If not specified, a new array will be created.<br/>
+		[page:Integer offset] - (optional) if specified, the result will be copied
 		into this [page:Array].<br /><br />
 
 		Returns the numerical elements of this quaternion in an array of format [x, y, z, w].

+ 20 - 21
docs/api/math/Vector2.html

@@ -54,7 +54,7 @@
 		[page:Float x] - the x value of the vector. Default is *0*.<br />
 		[page:Float y] -  the y value of the vector. Default is *0*.<br /><br />
 
-		Created a new [name].
+		Creates a new [name].
 		</div>
 
 
@@ -64,7 +64,7 @@
 		<div>
 			Used to check whether this or derived classes are Vector2s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float height]</h3>
@@ -84,7 +84,7 @@
 		<div>Adds [page:Vector2 v] to this vector.</div>
 
 		<h3>[method:Vector2 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x] and [page:.y y] values.</div>
+		<div>Adds the scalar value [page:Float s] to this vector's [page:.x x] and [page:.y y] values.</div>
 
 		<h3>[method:Vector2 addScaledVector]( [page:Vector2 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector2 v] and [page:Float s] to this vector.</div>
@@ -131,13 +131,13 @@
 
 		<h3>[method:Vector2 clone]()</h3>
 		<div>
-		Returns a new vector2 with the same [page:.x x] and [page:.y y] values as this one.
+		Returns a new Vector2 with the same [page:.x x] and [page:.y y] values as this one.
 		</div>
 
 		<h3>[method:Vector2 copy]( [page:Vector2 v] )</h3>
 		<div>
-			Copies the values of the passed vector2's [page:.x x] and [page:.y y]
-			properties to this vector2.
+			Copies the values of the passed Vector2's [page:.x x] and [page:.y y]
+			properties to this Vector2.
 		</div>
 
 		<h3>[method:Float distanceTo]( [page:Vector2 v] )</h3>
@@ -166,7 +166,7 @@
 
 		<h3>[method:Float dot]( [page:Vector2 v] )</h3>
 		<div>
-		Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
+		Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
 	  vector and [page:Vector2 v].
 		</div>
 
@@ -179,9 +179,9 @@
 		<h3>[method:Vector2 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		[page:Array array] - the source array.<br />
-		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
+		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 
-		Sets this vector's [page:.x x] value to be array[0] and [page:.y y] value to be array[1].
+		Sets this vector's [page:.x x] value to be array[ offset ] and [page:.y y] value to be array[ offset + 1 ].
 		</div>
 
 		<h3>[method:Vector2 fromBufferAttribute]( [page:BufferAttribute attribute], [page:Integer index] )</h3>
@@ -221,7 +221,7 @@
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 
-		Linearly interpolate between this vector and [page:Vector2 v], where alpha is the
+		Linearly interpolates between this vector and [page:Vector2 v], where alpha is the
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector2 v].
 		</div>
 
@@ -241,19 +241,19 @@
 
 		<h3>[method:Vector2 normalize]()</h3>
 		<div>
-		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
+		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		</div>
 
 		<h3>[method:Vector2 max]( [page:Vector2 v] )</h3>
 		<div>
-		If this vector's x or y value is less than [page:Vector2 v's] x or y value, replace
+		If this vector's x or y value is less than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding max value.
 		</div>
 
 		<h3>[method:Vector2 min]( [page:Vector2 v] )</h3>
 		<div>
-		If this vector's x or y value is greater than [page:Vector2 v's] x or y value, replace
+		If this vector's x or y value is greater than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding min value.
 		</div>
 
@@ -269,7 +269,7 @@
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:float angle] - the angle to rotate, in radians.<br /><br />
 
-			Rotate the vector arounf [page:Vector2 center] by [page:float angle] radians.
+			Rotates the vector around [page:Vector2 center] by [page:float angle] radians.
 		</div>
 
 		<h3>[method:Vector2 round]()</h3>
@@ -294,34 +294,33 @@
 
 		<h3>[method:Vector2 setLength]( [page:Float l] )</h3>
 		<div>
-		Set this vector to the vector with the same direction as this one, but [page:.length length]
+		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		</div>
 
 		<h3>[method:Vector2 setScalar]( [page:Float scalar] )</h3>
 		<div>
-		Set the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
+		Sets the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
 		</div>
 
 		<h3>[method:Vector2 setX]( [page:Float x] )</h3>
-		<div>Replace this vector's [page:.x x] value with [page:Float x].</div>
+		<div>Replaces this vector's [page:.x x] value with [page:Float x].</div>
 
 		<h3>[method:Vector2 setY]( [page:Float y] )</h3>
-		<div>Replace this vector's [page:.y y] value with [page:Float y].</div>
+		<div>Replaces this vector's [page:.y y] value with [page:Float y].</div>
 
 		<h3>[method:Vector2 sub]( [page:Vector2 v] )</h3>
 		<div>Subtracts [page:Vector2 v] from this vector.</div>
 
 		<h3>[method:Vector2 subScalar]( [page:Float s] )</h3>
-		<div>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] compnents.</div>
+		<div>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] components.</div>
 
 		<h3>[method:Vector2 subVectors]( [page:Vector2 a], [page:Vector2 b] )</h3>
 		<div>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</div>
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - (optional) array to store the vector to. If this is not provided
-		a new array will be created.<br />
+		[page:Array array] - (optional) array to store the vector to. If this is not provided, a new array will be created.<br />
 		[page:Integer offset] - (optional) optional offset into the array.<br /><br />
 
 		Returns an array [x, y], or copies x and y into the provided [page:Array array].

+ 5 - 5
docs/api/math/Vector3.html

@@ -65,7 +65,7 @@ var d = a.distanceTo( b );
 		<div>
 			Used to check whether this or derived classes are Vector3s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float x]</h3>
@@ -81,7 +81,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector3 v] to this vector.</div>
 
 		<h3>[method:Vector3 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</div>
+		<div>Adds the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</div>
 
 		<h3>[method:Vector3 addScaledVector]( [page:Vector3 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector3 v] and [page:Float s] to this vector.</div>
@@ -104,7 +104,7 @@ var d = a.distanceTo( b );
 		</div>
 
 		<h3>[method:Vector3 applyMatrix3]( [page:Matrix3 m] )</h3>
-		<div>Multiply this vector by [page:Matrix3 m]</div>
+		<div>Multiplies this vector by [page:Matrix3 m]</div>
 
 		<h3>[method:Vector3 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
@@ -284,13 +284,13 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector3 max]( [page:Vector3 v] )</h3>
 		<div>
-		If this vector's x, y or z value is less than [page:Vector3 v's] x, y or z value, replace
+		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding max value.
 		</div>
 
 		<h3>[method:Vector3 min]( [page:Vector3 v] )</h3>
 		<div>
-		If this vector's x, y or z value is greater than [page:Vector3 v's] x, y or z value, replace
+		If this vector's x, y or z value is greater than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding min value.
 		</div>
 

+ 18 - 19
docs/api/math/Vector4.html

@@ -22,7 +22,7 @@
 			<li>
 				A direction and length in 4D space. In three.js the length will always be the
 				[link:https://en.wikipedia.org/wiki/Euclidean_distance Euclidean distance]
-				(straight-line distance) from (0, 0, 0, 0, 0) to (x, y, z, w) and the direction is also
+				(straight-line distance) from (0, 0, 0, 0) to (x, y, z, w) and the direction is also
 				measured from (0, 0, 0, 0) towards (x, y, z, w).
 			</li>
 			<li>
@@ -42,7 +42,7 @@ var a = new THREE.Vector4( 0, 1, 0, 0 );
 //no arguments; will be initialised to (0, 0, 0, 1)
 var b = new THREE.Vector4( );
 
-var d = a.distanceTo( b );
+var d = a.dot( b );
 		</code>
 
 
@@ -65,7 +65,7 @@ var d = a.distanceTo( b );
 		<div>
 			Used to check whether this or derived classes are Vector4s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float x]</h3>
@@ -83,7 +83,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector4 v] to this vector.</div>
 
 		<h3>[method:Vector4 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</div>
+		<div>Adds the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</div>
 
 		<h3>[method:Vector4 addScaledVector]( [page:Vector4 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector4 v] and [page:Float s] to this vector.</div>
@@ -93,7 +93,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
-		Multiply this vector by 4 x 4 [page:Matrix4 m].
+		Multiplies this vector by 4 x 4 [page:Matrix4 m].
 		</div>
 
 		<h3>[method:Vector4 ceil]()</h3>
@@ -138,7 +138,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Float dot]( [page:Vector4 v] )</h3>
 		<div>
-		Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
+		Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
 		vector and [page:Vector4 v].
 		</div>
 
@@ -151,7 +151,7 @@ var d = a.distanceTo( b );
 		<h3>[method:Vector4 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		[page:Array array] - the source array.<br />
-		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
+		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 
 		Sets this vector's [page:.x x] value to be array[ offset + 0 ], [page:.y y] value to be array[ offset + 1 ]
 		[page:.z z] value to be array[ offset + 2 ] and [page:.w w ] value to be array[ offset + 3 ].
@@ -196,7 +196,7 @@ var d = a.distanceTo( b );
 		[page:Vector4 v] - [page:Vector4] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 
-		Linearly interpolate between this vector and [page:Vector4 v], where alpha is the
+		Linearly interpolates between this vector and [page:Vector4 v], where alpha is the
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector4 v].
 		</div>
 
@@ -216,7 +216,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 normalize]()</h3>
 		<div>
-		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
+		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		</div>
 
@@ -250,7 +250,7 @@ var d = a.distanceTo( b );
 		<div>
 			[page:Quaterion q] - a normalized [page:Quaterion]<br /><br />
 
-			Set the [page:.x x], [page:.y y] and [page:.z z] components of this vector to the
+			Sets the [page:.x x], [page:.y y] and [page:.z z] components of this vector to the
 			quaternion's axis and [page:.w w] to the angle.
 		</div>
 
@@ -258,7 +258,7 @@ var d = a.distanceTo( b );
 		<div>
 			 [page:Matrix4 m] - a [page:Matrix4] of which the upper left 3x3 matrix is a pure rotation matrix.<br /><br />
 
-			Set the [page:.x x], [page:.y y] and [page:.z z] to the axis of rotation and [page:.w w] to the angle.
+			Sets the [page:.x x], [page:.y y] and [page:.z z] to the axis of rotation and [page:.w w] to the angle.
 		</div>
 
 		<h3>[method:null setComponent]( [page:Integer index], [page:Float value] )</h3>
@@ -275,26 +275,26 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 setLength]( [page:Float l] )</h3>
 		<div>
-		Set this vector to the vector with the same direction as this one, but [page:.length length]
+		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		</div>
 
 		<h3>[method:Vector4 setScalar]( [page:Float scalar] )</h3>
 		<div>
-		Set the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
+		Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
 		</div>
 
 		<h3>[method:Vector4 setX]( [page:Float x] )</h3>
-		<div>Replace this vector's [page:.x x] value with [page:Float x].</div>
+		<div>Replaces this vector's [page:.x x] value with [page:Float x].</div>
 
 		<h3>[method:Vector4 setY]( [page:Float y] )</h3>
-		<div>Replace this vector's [page:.y y] value with [page:Float y].</div>
+		<div>Replaces this vector's [page:.y y] value with [page:Float y].</div>
 
 		<h3>[method:Vector4 setZ]( [page:Float z] )</h3>
-		<div>Replace this vector's [page:.z z] value with [page:Float z].</div>
+		<div>Replaces this vector's [page:.z z] value with [page:Float z].</div>
 
 		<h3>[method:Vector4 setW]( [page:Float w] )</h3>
-		<div>Replace this vector's [page:.w w] value with [page:Float w].</div>
+		<div>Replaces this vector's [page:.w w] value with [page:Float w].</div>
 
 		<h3>[method:Vector4 sub]( [page:Vector4 v] )</h3>
 		<div>Subtracts [page:Vector4 v] from this vector.</div>
@@ -307,8 +307,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - (optional) array to store the vector to. If this is not provided
-		a new array will be created.<br />
+		[page:Array array] - (optional) array to store the vector to. If this is not provided, a new array will be created.<br />
 		[page:Integer offset] - (optional) optional offset into the array.<br /><br />
 
 		Returns an array [x, y, z, w], or copies x, y, z and w into the provided [page:Array array].

+ 2 - 2
docs/scenes/js/geometry.js

@@ -744,7 +744,7 @@ var guis = {
 
 		var folder = gui.addFolder( 'THREE.RingBufferGeometry' );
 
-		folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry );
+		folder.add( data, 'innerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
@@ -778,7 +778,7 @@ var guis = {
 
 		var folder = gui.addFolder( 'THREE.RingGeometry' );
 
-		folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry );
+		folder.add( data, 'innerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );

+ 8 - 0
examples/js/controls/OrbitControls.js

@@ -96,6 +96,14 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	};
 
+	this.saveState = function () {
+
+		scope.target0.copy( scope.target );
+		scope.position0.copy( scope.object.position );
+		scope.zoom0 = scope.object.zoom;
+
+	};
+
 	this.reset = function () {
 
 		scope.target.copy( scope.target0 );

+ 9 - 20
examples/js/loaders/GLTF2Loader.js

@@ -136,15 +136,6 @@ THREE.GLTF2Loader = ( function () {
 
 			update: function ( scene, camera ) {
 
-				// update scene graph
-
-				scene.updateMatrixWorld();
-
-				// update camera matrices and frustum
-
-				camera.updateMatrixWorld();
-				camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
 				for ( var name in objects ) {
 
 					var object = objects[ name ];
@@ -163,10 +154,6 @@ THREE.GLTF2Loader = ( function () {
 
 	}
 
-	/* GLTFSHADERS */
-
-	GLTF2Loader.Shaders = new GLTFRegistry();
-
 	/* GLTFSHADER */
 
 	function GLTFShader( targetNode, allNodes ) {
@@ -1063,7 +1050,7 @@ THREE.GLTF2Loader = ( function () {
 
 			return _each( json.textures, function ( texture ) {
 
-				if ( texture.source ) {
+				if ( texture.source !== undefined ) {
 
 					return new Promise( function ( resolve ) {
 
@@ -1103,7 +1090,7 @@ THREE.GLTF2Loader = ( function () {
 
 							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType;
 
-							if ( texture.sampler ) {
+							if ( texture.sampler !== undefined ) {
 
 								var sampler = json.samplers[ texture.sampler ];
 
@@ -1632,7 +1619,7 @@ THREE.GLTF2Loader = ( function () {
 
 						}
 
-						if ( primitive.indices ) {
+						if ( primitive.indices !== undefined ) {
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
@@ -1682,7 +1669,7 @@ THREE.GLTF2Loader = ( function () {
 
 						var meshNode;
 
-						if ( primitive.indices ) {
+						if ( primitive.indices !== undefined ) {
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
@@ -1999,7 +1986,7 @@ THREE.GLTF2Loader = ( function () {
 
 								var skinEntry;
 
-								if ( node.skin ) {
+								if ( node.skin !== undefined ) {
 
 									skinEntry = dependencies.skins[ node.skin ];
 
@@ -2177,8 +2164,10 @@ THREE.GLTF2Loader = ( function () {
 					// Register raw material meshes with GLTF2Loader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
-						var xshader = new GLTFShader( child, dependencies.nodes );
-						GLTF2Loader.Shaders.add( child.uuid, xshader );
+						child.gltfShader = new GLTFShader( child, dependencies.nodes );
+						child.onBeforeRender = function(renderer, scene, camera){
+							this.gltfShader.update(scene, camera);
+						};
 
 					}
 

+ 14 - 13
examples/js/loaders/GLTFLoader.js

@@ -135,15 +135,6 @@ THREE.GLTFLoader = ( function () {
 
 			update: function ( scene, camera ) {
 
-				// update scene graph
-
-				scene.updateMatrixWorld();
-
-				// update camera matrices and frustum
-
-				camera.updateMatrixWorld();
-				camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
 				for ( var name in objects ) {
 
 					var object = objects[ name ];
@@ -164,7 +155,15 @@ THREE.GLTFLoader = ( function () {
 
 	/* GLTFSHADERS */
 
-	GLTFLoader.Shaders = new GLTFRegistry();
+	GLTFLoader.Shaders = {
+
+		update: function () {
+
+			console.warn( 'THREE.GLTFLoader.Shaders has been deprecated, and now updates automatically.' );
+
+		}
+
+	};
 
 	/* GLTFSHADER */
 
@@ -1109,7 +1108,7 @@ THREE.GLTFLoader = ( function () {
 							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
 
 								console.warn( 'THREE.GLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' +
-								              'internalFormat will be forced to be the same value as format.' );
+															'internalFormat will be forced to be the same value as format.' );
 
 							}
 
@@ -2175,8 +2174,10 @@ THREE.GLTFLoader = ( function () {
 					// Register raw material meshes with GLTFLoader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
-						var xshader = new GLTFShader( child, dependencies.nodes );
-						GLTFLoader.Shaders.add( child.uuid, xshader );
+						child.gltfShader = new GLTFShader( child, dependencies.nodes );
+						child.onBeforeRender = function(renderer, scene, camera){
+							this.gltfShader.update(scene, camera);
+						};
 
 					}
 

+ 72 - 81
examples/js/renderers/CanvasRenderer.js

@@ -9,7 +9,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) {
 	this.type = 'SpriteCanvasMaterial';
 
 	this.color = new THREE.Color( 0xffffff );
-	this.program = function ( context, color ) {};
+	this.program = function () {};
 
 	this.setValues( parameters );
 
@@ -17,6 +17,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) {
 
 THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
 THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
+THREE.SpriteCanvasMaterial.prototype.isSpriteCanvasMaterial = true;
 
 THREE.SpriteCanvasMaterial.prototype.clone = function () {
 
@@ -39,78 +40,69 @@ THREE.CanvasRenderer = function ( parameters ) {
 	parameters = parameters || {};
 
 	var _this = this,
-	_renderData, _elements, _lights,
-	_projector = new THREE.Projector(),
+		_renderData, _elements, _lights,
+		_projector = new THREE.Projector(),
 
-	_canvas = parameters.canvas !== undefined
-			 ? parameters.canvas
-			 : document.createElement( 'canvas' ),
+		_canvas = parameters.canvas !== undefined
+				 ? parameters.canvas
+				 : document.createElement( 'canvas' ),
 
-	_canvasWidth = _canvas.width,
-	_canvasHeight = _canvas.height,
-	_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
-	_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
+		_canvasWidth = _canvas.width,
+		_canvasHeight = _canvas.height,
+		_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
+		_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
 
-	_viewportX = 0,
-	_viewportY = 0,
-	_viewportWidth = _canvasWidth,
-	_viewportHeight = _canvasHeight,
+		_viewportX = 0,
+		_viewportY = 0,
+		_viewportWidth = _canvasWidth,
+		_viewportHeight = _canvasHeight,
 
-	_pixelRatio = 1,
+		_pixelRatio = 1,
 
-	_context = _canvas.getContext( '2d', {
-		alpha: parameters.alpha === true
-	} ),
+		_context = _canvas.getContext( '2d', {
+			alpha: parameters.alpha === true
+		} ),
 
-	_clearColor = new THREE.Color( 0x000000 ),
-	_clearAlpha = parameters.alpha === true ? 0 : 1,
+		_clearColor = new THREE.Color( 0x000000 ),
+		_clearAlpha = parameters.alpha === true ? 0 : 1,
 
-	_contextGlobalAlpha = 1,
-	_contextGlobalCompositeOperation = 0,
-	_contextStrokeStyle = null,
-	_contextFillStyle = null,
-	_contextLineWidth = null,
-	_contextLineCap = null,
-	_contextLineJoin = null,
-	_contextLineDash = [],
+		_contextGlobalAlpha = 1,
+		_contextGlobalCompositeOperation = 0,
+		_contextStrokeStyle = null,
+		_contextFillStyle = null,
+		_contextLineWidth = null,
+		_contextLineCap = null,
+		_contextLineJoin = null,
+		_contextLineDash = [],
 
-	_camera,
+		_v1, _v2, _v3,
 
-	_v1, _v2, _v3, _v4,
-	_v5 = new THREE.RenderableVertex(),
-	_v6 = new THREE.RenderableVertex(),
+		_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
 
-	_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
-	_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
+		_color = new THREE.Color(),
 
-	_color = new THREE.Color(),
-	_color1 = new THREE.Color(),
-	_color2 = new THREE.Color(),
-	_color3 = new THREE.Color(),
-	_color4 = new THREE.Color(),
+		_diffuseColor = new THREE.Color(),
+		_emissiveColor = new THREE.Color(),
 
-	_diffuseColor = new THREE.Color(),
-	_emissiveColor = new THREE.Color(),
+		_lightColor = new THREE.Color(),
 
-	_lightColor = new THREE.Color(),
+		_patterns = {},
 
-	_patterns = {},
+		_uvs,
+		_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
 
-	_image, _uvs,
-	_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
+		_clipBox = new THREE.Box2(),
+		_clearBox = new THREE.Box2(),
+		_elemBox = new THREE.Box2(),
 
-	_clipBox = new THREE.Box2(),
-	_clearBox = new THREE.Box2(),
-	_elemBox = new THREE.Box2(),
+		_ambientLight = new THREE.Color(),
+		_directionalLights = new THREE.Color(),
+		_pointLights = new THREE.Color(),
 
-	_ambientLight = new THREE.Color(),
-	_directionalLights = new THREE.Color(),
-	_pointLights = new THREE.Color(),
-
-	_vector3 = new THREE.Vector3(), // Needed for PointLight
-	_centroid = new THREE.Vector3(),
-	_normal = new THREE.Vector3(),
-	_normalViewMatrix = new THREE.Matrix3();
+		_vector3 = new THREE.Vector3(), // Needed for PointLight
+		_centroid = new THREE.Vector3(),
+		_normal = new THREE.Vector3(),
+		_normalViewMatrix = new THREE.Matrix3();
 
 	/* TODO
 	_canvas.mozImageSmoothingEnabled = false;
@@ -266,10 +258,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_clearBox.intersect( _clipBox );
 			_clearBox.expandByScalar( 2 );
 
-			_clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
-			_clearBox.min.y =  - _clearBox.min.y + _canvasHeightHalf;		// higher y value !
-			_clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
-			_clearBox.max.y =  - _clearBox.max.y + _canvasHeightHalf;		// lower y value !
+			_clearBox.min.x =   _clearBox.min.x + _canvasWidthHalf;
+			_clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf;		// higher y value !
+			_clearBox.max.x =   _clearBox.max.x + _canvasWidthHalf;
+			_clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf;		// lower y value !
 
 			if ( _clearAlpha < 1 ) {
 
@@ -312,7 +304,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	this.render = function ( scene, camera ) {
 
-		if ( camera instanceof THREE.Camera === false ) {
+		if ( camera.isCamera === undefined ) {
 
 			console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
 			return;
@@ -341,7 +333,6 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
 		_elements = _renderData.elements;
 		_lights = _renderData.lights;
-		_camera = camera;
 
 		_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
 
@@ -454,17 +445,17 @@ THREE.CanvasRenderer = function ( parameters ) {
 			var light = _lights[ l ];
 			var lightColor = light.color;
 
-			if ( light instanceof THREE.AmbientLight ) {
+			if ( light.isAmbientLight ) {
 
 				_ambientLight.add( lightColor );
 
-			} else if ( light instanceof THREE.DirectionalLight ) {
+			} else if ( light.isDirectionalLight ) {
 
 				// for sprites
 
 				_directionalLights.add( lightColor );
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 				// for sprites
 
@@ -484,7 +475,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			_lightColor.copy( light.color );
 
-			if ( light instanceof THREE.DirectionalLight ) {
+			if ( light.isDirectionalLight ) {
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
 
@@ -496,7 +487,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 				color.add( _lightColor.multiplyScalar( amount ) );
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
 
@@ -530,7 +521,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_elemBox.min.set( v1.x - dist, v1.y - dist );
 		_elemBox.max.set( v1.x + dist, v1.y + dist );
 
-		if ( material instanceof THREE.SpriteMaterial ) {
+		if ( material.isSpriteMaterial ) {
 
 			var texture = material.map;
 
@@ -586,7 +577,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			}
 
-		} else if ( material instanceof THREE.SpriteCanvasMaterial ) {
+		} else if ( material.isSpriteCanvasMaterial ) {
 
 			setStrokeStyle( material.color.getStyle() );
 			setFillStyle( material.color.getStyle() );
@@ -623,7 +614,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
 		_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
 
-		if ( material instanceof THREE.LineBasicMaterial ) {
+		if ( material.isLineBasicMaterial ) {
 
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
@@ -670,7 +661,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_context.stroke();
 			_elemBox.expandByScalar( material.linewidth * 2 );
 
-		} else if ( material instanceof THREE.LineDashedMaterial ) {
+		} else if ( material.isLineDashedMaterial ) {
 
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
@@ -702,7 +693,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 		drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
 
-		if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
+		if ( ( material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) && material.map === null ) {
 
 			_diffuseColor.copy( material.color );
 			_emissiveColor.copy( material.emissive );
@@ -725,9 +716,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 				 ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
 				 : fillPath( _color );
 
-		} else if ( material instanceof THREE.MeshBasicMaterial ||
-				    material instanceof THREE.MeshLambertMaterial ||
-				    material instanceof THREE.MeshPhongMaterial ) {
+		} else if ( material.isMeshBasicMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) {
 
 			if ( material.map !== null ) {
 
@@ -776,7 +765,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			}
 
-		} else if ( material instanceof THREE.MeshNormalMaterial ) {
+		} else if ( material.isMeshNormalMaterial ) {
 
 			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
 
@@ -944,10 +933,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
 
 		var a, b, c, d, e, f, det, idet,
-		offsetX = texture.offset.x / texture.repeat.x,
-		offsetY = texture.offset.y / texture.repeat.y,
-		width = texture.image.width * texture.repeat.x,
-		height = texture.image.height * texture.repeat.y;
+			offsetX = texture.offset.x / texture.repeat.x,
+			offsetY = texture.offset.y / texture.repeat.y,
+			width = texture.image.width * texture.repeat.x,
+			height = texture.image.height * texture.repeat.y;
 
 		u0 = ( u0 + offsetX ) * width;
 		v0 = ( v0 + offsetY ) * height;
@@ -985,6 +974,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	}
 
+	/*
 	function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
 
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
@@ -1022,13 +1012,14 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.restore();
 
 	}
+	*/
 
 	// Hide anti-alias gaps
 
 	function expand( v1, v2, pixels ) {
 
 		var x = v2.x - v1.x, y = v2.y - v1.y,
-		det = x * x + y * y, idet;
+			det = x * x + y * y, idet;
 
 		if ( det === 0 ) return;
 

+ 75 - 35
examples/js/renderers/Projector.js

@@ -99,33 +99,32 @@ THREE.RenderableSprite = function () {
 THREE.Projector = function () {
 
 	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
-	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
-	_face, _faceCount, _facePool = [], _facePoolLength = 0,
-	_line, _lineCount, _linePool = [], _linePoolLength = 0,
-	_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
+		_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
+		_face, _faceCount, _facePool = [], _facePoolLength = 0,
+		_line, _lineCount, _linePool = [], _linePoolLength = 0,
+		_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
 
-	_renderData = { objects: [], lights: [], elements: [] },
+		_renderData = { objects: [], lights: [], elements: [] },
 
-	_vector3 = new THREE.Vector3(),
-	_vector4 = new THREE.Vector4(),
+		_vector3 = new THREE.Vector3(),
+		_vector4 = new THREE.Vector4(),
 
-	_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
-	_boundingBox = new THREE.Box3(),
-	_points3 = new Array( 3 ),
-	_points4 = new Array( 4 ),
+		_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
+		_boundingBox = new THREE.Box3(),
+		_points3 = new Array( 3 ),
 
-	_viewMatrix = new THREE.Matrix4(),
-	_viewProjectionMatrix = new THREE.Matrix4(),
+		_viewMatrix = new THREE.Matrix4(),
+		_viewProjectionMatrix = new THREE.Matrix4(),
 
-	_modelMatrix,
-	_modelViewProjectionMatrix = new THREE.Matrix4(),
+		_modelMatrix,
+		_modelViewProjectionMatrix = new THREE.Matrix4(),
 
-	_normalMatrix = new THREE.Matrix3(),
+		_normalMatrix = new THREE.Matrix3(),
 
-	_frustum = new THREE.Frustum(),
+		_frustum = new THREE.Frustum(),
 
-	_clippedVertex1PositionScreen = new THREE.Vector4(),
-	_clippedVertex2PositionScreen = new THREE.Vector4();
+		_clippedVertex1PositionScreen = new THREE.Vector4(),
+		_clippedVertex2PositionScreen = new THREE.Vector4();
 
 	//
 
@@ -143,7 +142,7 @@ THREE.Projector = function () {
 
 	};
 
-	this.pickingRay = function ( vector, camera ) {
+	this.pickingRay = function () {
 
 		console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
 
@@ -154,6 +153,7 @@ THREE.Projector = function () {
 	var RenderList = function () {
 
 		var normals = [];
+		var colors = [];
 		var uvs = [];
 
 		var object = null;
@@ -169,6 +169,7 @@ THREE.Projector = function () {
 			normalMatrix.getNormalMatrix( object.matrixWorld );
 
 			normals.length = 0;
+			colors.length = 0;
 			uvs.length = 0;
 
 		}
@@ -209,6 +210,12 @@ THREE.Projector = function () {
 
 		}
 
+		function pushColor( r, g, b ) {
+
+			colors.push( r, g, b );
+
+		}
+
 		function pushUv( x, y ) {
 
 			uvs.push( x, y );
@@ -241,17 +248,36 @@ THREE.Projector = function () {
 			var v1 = _vertexPool[ a ];
 			var v2 = _vertexPool[ b ];
 
-			_line = getNextLineInPool();
+			// Clip
+
+			v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );
+			v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );
+
+			if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {
+
+				// Perform the perspective divide
+				v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );
+				v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );
 
-			_line.id = object.id;
-			_line.v1.copy( v1 );
-			_line.v2.copy( v2 );
-			_line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
-			_line.renderOrder = object.renderOrder;
+				_line = getNextLineInPool();
+				_line.id = object.id;
+				_line.v1.copy( v1 );
+				_line.v2.copy( v2 );
+				_line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );
+				_line.renderOrder = object.renderOrder;
 
-			_line.material = object.material;
+				_line.material = object.material;
 
-			_renderData.elements.push( _line );
+				if ( object.material.vertexColors === THREE.VertexColors ) {
+
+					_line.vertexColors[ 0 ].fromArray( colors, a * 3 );
+					_line.vertexColors[ 1 ].fromArray( colors, b * 3 );
+
+				}
+
+				_renderData.elements.push( _line );
+
+			}
 
 		}
 
@@ -307,10 +333,11 @@ THREE.Projector = function () {
 			checkBackfaceCulling: checkBackfaceCulling,
 			pushVertex: pushVertex,
 			pushNormal: pushNormal,
+			pushColor: pushColor,
 			pushUv: pushUv,
 			pushLine: pushLine,
 			pushTriangle: pushTriangle
-		}
+		};
 
 	};
 
@@ -609,6 +636,8 @@ THREE.Projector = function () {
 
 			} else if ( object instanceof THREE.Line ) {
 
+				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
+
 				if ( geometry instanceof THREE.BufferGeometry ) {
 
 					var attributes = geometry.attributes;
@@ -623,6 +652,18 @@ THREE.Projector = function () {
 
 						}
 
+						if ( attributes.color !== undefined ) {
+
+							var colors = attributes.color.array;
+
+							for ( var i = 0, l = colors.length; i < l; i += 3 ) {
+
+								renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
+
+							}
+
+						}
+
 						if ( geometry.index !== null ) {
 
 							var indices = geometry.index.array;
@@ -649,8 +690,6 @@ THREE.Projector = function () {
 
 				} else if ( geometry instanceof THREE.Geometry ) {
 
-					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
-
 					var vertices = object.geometry.vertices;
 
 					if ( vertices.length === 0 ) continue;
@@ -861,10 +900,11 @@ THREE.Projector = function () {
 
 		// 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;
+
+			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 ) {
 

File diff suppressed because it is too large
+ 12 - 0
examples/models/json/suzanne.json


+ 0 - 2
examples/webgl_effects_peppersghost.html

@@ -125,8 +125,6 @@
 
 		function render() {
 
-				camera.lookAt( scene.position );
-
 				group.rotation.y += 0.01;
 
 				effect.render( scene, camera );

+ 1 - 3
examples/webgl_loader_gltf.html

@@ -202,8 +202,7 @@
 					scene.add(ground);
 				}
 
-				THREE.GLTF2Loader.Shaders.removeAll(); // remove all previous shaders
-				loader = new THREE.GLTF2Loader;
+				loader = new THREE.GLTF2Loader();
 
 				for (var i = 0; i < extensionSelect.children.length; i++) {
 					var child = extensionSelect.children[i];
@@ -338,7 +337,6 @@
 			function animate() {
 				requestAnimationFrame( animate );
 				if (mixer) mixer.update(clock.getDelta());
-				THREE.GLTF2Loader.Shaders.update(scene, camera);
 				if (cameraIndex == 0)
 					orbitControls.update();
 				render();

+ 2 - 2
examples/webgl_performance.html

@@ -52,8 +52,8 @@
 
 				var material = new THREE.MeshNormalMaterial();
 
-				var loader = new THREE.JSONLoader();
-				loader.load( 'obj/Suzanne.js', function ( geometry ) {
+				var loader = new THREE.BufferGeometryLoader();
+				loader.load( 'models/json/suzanne.json', function ( geometry ) {
 
 					geometry.computeVertexNormals();
 

+ 2 - 2
examples/webgl_performance_static.html

@@ -50,8 +50,8 @@
 
 				var material = new THREE.MeshNormalMaterial();
 
-				var loader = new THREE.JSONLoader();
-				loader.load( 'obj/Suzanne.js', function ( geometry ) {
+				var loader = new THREE.BufferGeometryLoader();
+				loader.load( 'models/json/suzanne.json', function ( geometry ) {
 
 					geometry.computeVertexNormals();
 

+ 1 - 1
package.json

@@ -33,7 +33,7 @@
     "build-closure": "rollup -c && java -jar utils/build/compiler/closure-compiler-v20160713.jar --warning_level=VERBOSE --jscomp_off=globalThis --jscomp_off=checkTypes --externs utils/build/externs.js --language_in=ECMASCRIPT5_STRICT --js build/three.js --js_output_file build/three.min.js",
     "dev": "rollup -c -w",
     "lint": "eslint src",
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "test": "rollup -c test/rollup.unit.config.js -w"
   },
   "keywords": [
     "three",

+ 0 - 16
src/cameras/Camera.js

@@ -41,22 +41,6 @@ Camera.prototype.getWorldDirection = function () {
 
 }();
 
-Camera.prototype.lookAt = function () {
-
-	// This routine does not support cameras with rotated and/or translated parent(s)
-
-	var m1 = new Matrix4();
-
-	return function lookAt( vector ) {
-
-		m1.lookAt( this.position, vector, this.up );
-
-		this.quaternion.setFromRotationMatrix( m1 );
-
-	};
-
-}();
-
 Camera.prototype.clone = function () {
 
 	return new this.constructor().copy( this );

+ 4 - 0
src/core/BufferAttribute.js

@@ -8,6 +8,8 @@ import { _Math } from '../math/Math';
  * @author mrdoob / http://mrdoob.com/
  */
 
+var bufferAttributeId = 0;
+
 function BufferAttribute( array, itemSize, normalized ) {
 
 	if ( Array.isArray( array ) ) {
@@ -16,6 +18,8 @@ function BufferAttribute( array, itemSize, normalized ) {
 
 	}
 
+	Object.defineProperty( this, 'id', { value: bufferAttributeId ++ } );
+
 	this.uuid = _Math.generateUUID();
 
 	this.array = array;

+ 5 - 5
src/core/Layers.js

@@ -4,7 +4,7 @@
 
 function Layers() {
 
-	this.mask = 1;
+	this.mask = 1 | 0;
 
 }
 
@@ -12,25 +12,25 @@ Object.assign( Layers.prototype, {
 
 	set: function ( channel ) {
 
-		this.mask = 1 << channel;
+		this.mask = 1 << channel | 0;
 
 	},
 
 	enable: function ( channel ) {
 
-		this.mask |= 1 << channel;
+		this.mask |= 1 << channel | 0;
 
 	},
 
 	toggle: function ( channel ) {
 
-		this.mask ^= 1 << channel;
+		this.mask ^= 1 << channel | 0;
 
 	},
 
 	disable: function ( channel ) {
 
-		this.mask &= ~ ( 1 << channel );
+		this.mask &= ~ ( 1 << channel | 0 );
 
 	},
 

+ 18 - 3
src/core/Object3D.js

@@ -279,7 +279,22 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 		return function lookAt( vector ) {
 
-			m1.lookAt( vector, this.position, this.up );
+			if ( this.position.distanceToSquared( vector ) === 0 ) {
+
+				console.warn( 'THREE.Object3D.lookAt(): target vector is the same as object position.' );
+				return;
+
+			}
+
+			if ( this.isCamera ) {
+
+				m1.lookAt( this.position, vector, this.up );
+
+			} else {
+
+				m1.lookAt( vector, this.position, this.up );
+
+			}
 
 			this.quaternion.setFromRotationMatrix( m1 );
 
@@ -526,9 +541,9 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 	updateMatrixWorld: function ( force ) {
 
-		if ( this.matrixAutoUpdate === true ) this.updateMatrix();
+		if ( this.matrixAutoUpdate ) this.updateMatrix();
 
-		if ( this.matrixWorldNeedsUpdate === true || force === true ) {
+		if ( this.matrixWorldNeedsUpdate || force ) {
 
 			if ( this.parent === null ) {
 

+ 11 - 0
src/lights/RectAreaLight.js

@@ -43,6 +43,17 @@ RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
 
 		return this;
 
+	},
+
+	toJSON: function ( meta ) {
+
+		var data = Light.prototype.toJSON.call( this, meta );
+
+		data.object.width = this.width;
+		data.object.height = this.height;
+
+		return data;
+
 	}
 
 } );

+ 7 - 0
src/loaders/ObjectLoader.js

@@ -38,6 +38,7 @@ import { SpotLight } from '../lights/SpotLight';
 import { PointLight } from '../lights/PointLight';
 import { DirectionalLight } from '../lights/DirectionalLight';
 import { AmbientLight } from '../lights/AmbientLight';
+import { RectAreaLight } from '../lights/RectAreaLight';
 import { OrthographicCamera } from '../cameras/OrthographicCamera';
 import { PerspectiveCamera } from '../cameras/PerspectiveCamera';
 import { Scene } from '../scenes/Scene';
@@ -626,6 +627,12 @@ Object.assign( ObjectLoader.prototype, {
 
 					break;
 
+				case 'RectAreaLight':
+
+					object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
+
+					break;
+
 				case 'SpotLight':
 
 					object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );

+ 1 - 0
src/materials/SpriteMaterial.js

@@ -34,6 +34,7 @@ function SpriteMaterial( parameters ) {
 
 SpriteMaterial.prototype = Object.create( Material.prototype );
 SpriteMaterial.prototype.constructor = SpriteMaterial;
+SpriteMaterial.prototype.isSpriteMaterial = true;
 
 SpriteMaterial.prototype.copy = function ( source ) {
 

+ 12 - 8
src/math/Quaternion.js

@@ -197,24 +197,28 @@ Object.assign( Quaternion.prototype, {
 
 	setFromEuler: function ( euler, update ) {
 
-		if ( (euler && euler.isEuler) === false ) {
+		if ( ( euler && euler.isEuler ) === false ) {
 
 			throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
 
 		}
 
+		var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
+
 		// http://www.mathworks.com/matlabcentral/fileexchange/
 		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
 		//	content/SpinCalc.m
 
-		var c1 = Math.cos( euler._x / 2 );
-		var c2 = Math.cos( euler._y / 2 );
-		var c3 = Math.cos( euler._z / 2 );
-		var s1 = Math.sin( euler._x / 2 );
-		var s2 = Math.sin( euler._y / 2 );
-		var s3 = Math.sin( euler._z / 2 );
+		var cos = Math.cos;
+		var sin = Math.sin;
+
+		var c1 = cos( x / 2 );
+		var c2 = cos( y / 2 );
+		var c3 = cos( z / 2 );
 
-		var order = euler.order;
+		var s1 = sin( x / 2 );
+		var s2 = sin( y / 2 );
+		var s3 = sin( z / 2 );
 
 		if ( order === 'XYZ' ) {
 

+ 24 - 33
src/math/Vector2.js

@@ -15,35 +15,35 @@ function Vector2( x, y ) {
 Object.defineProperties( Vector2.prototype, {
 
 	"width" : {
-		
-		get: function () { 
-			
-			return this.x; 
-		
+
+		get: function () {
+
+			return this.x;
+
 		},
-		
-		set: function ( value ) { 
-			
-			this.x = value; 
-		
+
+		set: function ( value ) {
+
+			this.x = value;
+
 		}
-		
+
 	},
 
 	"height" : {
-		
-		get: function () { 
-			
-			return this.y; 
-		
+
+		get: function () {
+
+			return this.y;
+
 		},
-		
-		set: function ( value ) { 
-			
-			this.y = value; 
-		
+
+		set: function ( value ) {
+
+			this.y = value;
+
 		}
-		
+
 	}
 
 } );
@@ -215,17 +215,8 @@ Object.assign( Vector2.prototype, {
 
 	multiplyScalar: function ( scalar ) {
 
-		if ( isFinite( scalar ) ) {
-
-			this.x *= scalar;
-			this.y *= scalar;
-
-		} else {
-
-			this.x = 0;
-			this.y = 0;
-
-		}
+		this.x *= scalar;
+		this.y *= scalar;
 
 		return this;
 

+ 4 - 22
src/math/Vector3.js

@@ -214,19 +214,9 @@ Object.assign( Vector3.prototype, {
 
 	multiplyScalar: function ( scalar ) {
 
-		if ( isFinite( scalar ) ) {
-
-			this.x *= scalar;
-			this.y *= scalar;
-			this.z *= scalar;
-
-		} else {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-
-		}
+		this.x *= scalar;
+		this.y *= scalar;
+		this.z *= scalar;
 
 		return this;
 
@@ -648,7 +638,7 @@ Object.assign( Vector3.prototype, {
 
 	},
 
-	setFromCylindrical: function( c ) {
+	setFromCylindrical: function ( c ) {
 
 		this.x = c.radius * Math.sin( c.theta );
 		this.y = c.y;
@@ -680,14 +670,6 @@ Object.assign( Vector3.prototype, {
 
 	setFromMatrixColumn: function ( m, index ) {
 
-		if ( typeof m === 'number' ) {
-
-			console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' );
-			var temp = m;
-			m = index;
-			index = temp;
-
-		}
 
 		return this.fromArray( m.elements, index * 4 );
 

+ 4 - 15
src/math/Vector4.js

@@ -213,21 +213,10 @@ Object.assign( Vector4.prototype, {
 
 	multiplyScalar: function ( scalar ) {
 
-		if ( isFinite( scalar ) ) {
-
-			this.x *= scalar;
-			this.y *= scalar;
-			this.z *= scalar;
-			this.w *= scalar;
-
-		} else {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-			this.w = 0;
-
-		}
+		this.x *= scalar;
+		this.y *= scalar;
+		this.z *= scalar;
+		this.w *= scalar;
 
 		return this;
 

+ 1 - 0
src/objects/Points.js

@@ -46,6 +46,7 @@ Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 			sphere.copy( geometry.boundingSphere );
 			sphere.applyMatrix4( matrixWorld );
+			sphere.radius += threshold;
 
 			if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
 

+ 139 - 127
src/renderers/WebGLRenderer.js

@@ -1,4 +1,4 @@
-import { REVISION, MaxEquation, MinEquation, RGB_ETC1_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, SrcAlphaSaturateFactor, OneMinusDstColorFactor, DstColorFactor, OneMinusDstAlphaFactor, DstAlphaFactor, OneMinusSrcAlphaFactor, SrcAlphaFactor, OneMinusSrcColorFactor, SrcColorFactor, OneFactor, ZeroFactor, ReverseSubtractEquation, SubtractEquation, AddEquation, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, FrontFaceDirectionCW, NoBlending, BackSide, DoubleSide, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, NoColors, FlatShading, LinearToneMapping } from '../constants';
+import { REVISION, MaxEquation, MinEquation, RGB_ETC1_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, SrcAlphaSaturateFactor, OneMinusDstColorFactor, DstColorFactor, OneMinusDstAlphaFactor, DstAlphaFactor, OneMinusSrcAlphaFactor, SrcAlphaFactor, OneMinusSrcColorFactor, SrcColorFactor, OneFactor, ZeroFactor, ReverseSubtractEquation, SubtractEquation, AddEquation, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, FrontFaceDirectionCW, NoBlending, BackSide, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, NoColors, FlatShading, LinearToneMapping } from '../constants';
 import { Matrix4 } from '../math/Matrix4';
 import { WebGLUniforms } from './webgl/WebGLUniforms';
 import { UniformsUtils } from './shaders/UniformsUtils';
@@ -13,11 +13,13 @@ import { PlaneBufferGeometry } from '../geometries/PlaneGeometry';
 import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
 import { PerspectiveCamera } from '../cameras/PerspectiveCamera';
 import { OrthographicCamera } from '../cameras/OrthographicCamera';
+import { WebGLAttributes } from './webgl/WebGLAttributes';
 import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer';
 import { WebGLBufferRenderer } from './webgl/WebGLBufferRenderer';
+import { WebGLGeometries } from './webgl/WebGLGeometries';
 import { WebGLLights } from './webgl/WebGLLights';
-import { WebGLPrograms } from './webgl/WebGLPrograms';
 import { WebGLObjects } from './webgl/WebGLObjects';
+import { WebGLPrograms } from './webgl/WebGLPrograms';
 import { WebGLTextures } from './webgl/WebGLTextures';
 import { WebGLProperties } from './webgl/WebGLProperties';
 import { WebGLState } from './webgl/WebGLState';
@@ -25,7 +27,7 @@ import { WebGLCapabilities } from './webgl/WebGLCapabilities';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { WebGLExtensions } from './webgl/WebGLExtensions';
 import { Vector3 } from '../math/Vector3';
-import { Sphere } from '../math/Sphere';
+// import { Sphere } from '../math/Sphere';
 import { WebGLClipping } from './webgl/WebGLClipping';
 import { Frustum } from '../math/Frustum';
 import { Vector4 } from '../math/Vector4';
@@ -156,8 +158,6 @@ function WebGLRenderer( parameters ) {
 		_clippingEnabled = false,
 		_localClippingEnabled = false,
 
-		_sphere = new Sphere(),
-
 		// camera matrices cache
 
 		_projScreenMatrix = new Matrix4(),
@@ -172,18 +172,18 @@ function WebGLRenderer( parameters ) {
 
 			hash: '',
 
-		ambient: [ 0, 0, 0 ],
-		directional: [],
-		directionalShadowMap: [],
-		directionalShadowMatrix: [],
-		spot: [],
-		spotShadowMap: [],
-		spotShadowMatrix: [],
-		rectArea: [],
-		point: [],
-		pointShadowMap: [],
-		pointShadowMatrix: [],
-		hemi: [],
+			ambient: [ 0, 0, 0 ],
+			directional: [],
+			directionalShadowMap: [],
+			directionalShadowMatrix: [],
+			spot: [],
+			spotShadowMap: [],
+			spotShadowMatrix: [],
+			rectArea: [],
+			point: [],
+			pointShadowMap: [],
+			pointShadowMatrix: [],
+			hemi: [],
 
 			shadows: []
 
@@ -191,8 +191,14 @@ function WebGLRenderer( parameters ) {
 
 		// info
 
+		_infoMemory = {
+			geometries: 0,
+			textures: 0
+		},
+
 		_infoRender = {
 
+			frame: 0,
 			calls: 0,
 			vertices: 0,
 			faces: 0,
@@ -203,12 +209,7 @@ function WebGLRenderer( parameters ) {
 	this.info = {
 
 		render: _infoRender,
-		memory: {
-
-			geometries: 0,
-			textures: 0
-
-		},
+		memory: _infoMemory,
 		programs: null
 
 	};
@@ -220,7 +221,7 @@ function WebGLRenderer( parameters ) {
 
 	try {
 
-		var attributes = {
+		var contextAttributes = {
 			alpha: _alpha,
 			depth: _depth,
 			stencil: _stencil,
@@ -229,7 +230,7 @@ function WebGLRenderer( parameters ) {
 			preserveDrawingBuffer: _preserveDrawingBuffer
 		};
 
-		_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
+		_gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );
 
 		if ( _gl === null ) {
 
@@ -284,9 +285,12 @@ function WebGLRenderer( parameters ) {
 	var capabilities = new WebGLCapabilities( _gl, extensions, parameters );
 
 	var state = new WebGLState( _gl, extensions, paramThreeToGL );
+
 	var properties = new WebGLProperties();
-	var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info );
-	var objects = new WebGLObjects( _gl, properties, this.info );
+	var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, _infoMemory );
+	var attributes = new WebGLAttributes( _gl );
+	var geometries = new WebGLGeometries( _gl, attributes, _infoMemory );
+	var objects = new WebGLObjects( _gl, geometries, _infoRender );
 	var programCache = new WebGLPrograms( this, capabilities );
 	var lightCache = new WebGLLights();
 
@@ -518,12 +522,12 @@ function WebGLRenderer( parameters ) {
 
 	this.resetGLState = resetGLState;
 
-	this.dispose = function() {
+	this.dispose = function () {
 
 		transparentObjects = [];
-		transparentObjectsLastIndex = -1;
+		transparentObjectsLastIndex = - 1;
 		opaqueObjects = [];
-		opaqueObjectsLastIndex = -1;
+		opaqueObjectsLastIndex = - 1;
 
 		_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
 
@@ -539,6 +543,7 @@ function WebGLRenderer( parameters ) {
 		setDefaultGLState();
 
 		properties.clear();
+		objects.clear();
 
 	}
 
@@ -558,7 +563,7 @@ function WebGLRenderer( parameters ) {
 
 		releaseMaterialProgramReference( material );
 
-		properties.delete( material );
+		properties.remove( material );
 
 	}
 
@@ -579,6 +584,16 @@ function WebGLRenderer( parameters ) {
 
 	// Buffer rendering
 
+	function renderObjectImmediate( object, program, material ) {
+
+		object.render( function ( object ) {
+
+			_this.renderBufferImmediate( object, program, material );
+
+		} );
+
+	}
+
 	this.renderBufferImmediate = function ( object, program, material ) {
 
 		state.initAttributes();
@@ -590,15 +605,15 @@ function WebGLRenderer( parameters ) {
 		if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
 		if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
 
-		var attributes = program.getAttributes();
+		var programAttributes = program.getAttributes();
 
 		if ( object.hasPositions ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 
-			state.enableAttribute( attributes.position );
-			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+			state.enableAttribute( programAttributes.position );
+			_gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );
 
 		}
 
@@ -637,9 +652,9 @@ function WebGLRenderer( parameters ) {
 
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 
-			state.enableAttribute( attributes.normal );
+			state.enableAttribute( programAttributes.normal );
 
-			_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 
 		}
 
@@ -648,7 +663,7 @@ function WebGLRenderer( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 
-			state.enableAttribute( attributes.uv );
+			state.enableAttribute( programAttributes.uv );
 
 			_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
 
@@ -659,9 +674,9 @@ function WebGLRenderer( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 
-			state.enableAttribute( attributes.color );
+			state.enableAttribute( programAttributes.color );
 
-			_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );
 
 		}
 
@@ -673,14 +688,16 @@ function WebGLRenderer( parameters ) {
 
 	};
 
+	var program, geometryProgram, updateBuffers;
+
 	this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
 
-		setMaterial( material );
+		state.setMaterial( material );
 
-		var program = setProgram( camera, fog, material, object );
+		program = setProgram( camera, fog, material, object );
+		geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe;
 
-		var updateBuffers = false;
-		var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe;
+		updateBuffers = false;
 
 		if ( geometryProgram !== _currentGeometryProgram ) {
 
@@ -695,6 +712,8 @@ function WebGLRenderer( parameters ) {
 
 		if ( morphTargetInfluences !== undefined ) {
 
+			// TODO Remove allocations
+
 			var activeInfluences = [];
 
 			for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) {
@@ -741,8 +760,7 @@ function WebGLRenderer( parameters ) {
 
 			}
 
-			program.getUniforms().setValue(
-				_gl, 'morphTargetInfluences', morphInfluences );
+			program.getUniforms().setValue( _gl, 'morphTargetInfluences', morphInfluences );
 
 			updateBuffers = true;
 
@@ -756,22 +774,18 @@ function WebGLRenderer( parameters ) {
 
 		if ( material.wireframe === true ) {
 
-			index = objects.getWireframeAttribute( geometry );
+			index = geometries.getWireframeAttribute( geometry );
 			rangeFactor = 2;
 
 		}
 
-		var renderer;
+		var renderer = bufferRenderer;
 
 		if ( index !== null ) {
 
 			renderer = indexedBufferRenderer;
 			renderer.setIndex( index );
 
-		} else {
-
-			renderer = bufferRenderer;
-
 		}
 
 		if ( updateBuffers ) {
@@ -780,7 +794,7 @@ function WebGLRenderer( parameters ) {
 
 			if ( index !== null ) {
 
-				_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) );
+				_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );
 
 			}
 
@@ -927,9 +941,9 @@ function WebGLRenderer( parameters ) {
 					var normalized = geometryAttribute.normalized;
 					var size = geometryAttribute.itemSize;
 
-					var attributeProperties = objects.getAttributeProperties( geometryAttribute );
+					var attributeProperties = attributes.get( geometryAttribute );
 
-					var buffer = attributeProperties.__webglBuffer;
+					var buffer = attributeProperties.buffer;
 					var type = attributeProperties.type;
 					var bytesPerElement = attributeProperties.bytesPerElement;
 
@@ -1111,7 +1125,7 @@ function WebGLRenderer( parameters ) {
 		_localClippingEnabled = this.localClippingEnabled;
 		_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
 
-		projectObject( scene, camera );
+		projectObject( scene, camera, _this.sortObjects );
 
 		opaqueObjects.length = opaqueObjectsLastIndex + 1;
 		transparentObjects.length = transparentObjectsLastIndex + 1;
@@ -1137,6 +1151,7 @@ function WebGLRenderer( parameters ) {
 
 		//
 
+		_infoRender.frame ++;
 		_infoRender.calls = 0;
 		_infoRender.vertices = 0;
 		_infoRender.faces = 0;
@@ -1263,9 +1278,9 @@ function WebGLRenderer( parameters ) {
 
 		// Ensure depth buffer writing is enabled so it can be cleared on next render
 
-		state.setDepthTest( true );
-		state.setDepthWrite( true );
-		state.setColorWrite( true );
+		state.buffers.depth.setTest( true );
+		state.buffers.depth.setMask( true );
+		state.buffers.color.setMask( true );
 
 		// _gl.finish();
 
@@ -1293,7 +1308,7 @@ function WebGLRenderer( parameters ) {
 
 		var renderItem = array[ index ];
 
-		if ( renderItem !== undefined ) {
+		if ( renderItem ) {
 
 			renderItem.id = object.id;
 			renderItem.object = object;
@@ -1320,8 +1335,11 @@ function WebGLRenderer( parameters ) {
 
 	}
 
+	/*
 	// TODO Duplicated code (Frustum)
 
+	var _sphere = new Sphere();
+
 	function isObjectViewable( object ) {
 
 		var geometry = object.geometry;
@@ -1370,12 +1388,13 @@ function WebGLRenderer( parameters ) {
 		return true;
 
 	}
+	*/
 
-	function projectObject( object, camera ) {
+	function projectObject( object, camera, sortObjects ) {
 
-		if ( object.visible === false ) return;
+		if ( ! object.visible ) return;
 
-		var visible = ( object.layers.mask & camera.layers.mask ) !== 0;
+		var visible = object.layers.test( camera.layers );
 
 		if ( visible ) {
 
@@ -1385,7 +1404,7 @@ function WebGLRenderer( parameters ) {
 
 			} else if ( object.isSprite ) {
 
-				if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) {
+				if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
 
 					sprites.push( object );
 
@@ -1397,10 +1416,10 @@ function WebGLRenderer( parameters ) {
 
 			} else if ( object.isImmediateRenderObject ) {
 
-				if ( _this.sortObjects === true ) {
+				if ( sortObjects ) {
 
-					_vector3.setFromMatrixPosition( object.matrixWorld );
-					_vector3.applyMatrix4( _projScreenMatrix );
+					_vector3.setFromMatrixPosition( object.matrixWorld )
+						.applyMatrix4( _projScreenMatrix );
 
 				}
 
@@ -1414,12 +1433,12 @@ function WebGLRenderer( parameters ) {
 
 				}
 
-				if ( object.frustumCulled === false || isObjectViewable( object ) === true ) {
+				if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
 
-					if ( _this.sortObjects === true ) {
+					if ( sortObjects ) {
 
-						_vector3.setFromMatrixPosition( object.matrixWorld );
-						_vector3.applyMatrix4( _projScreenMatrix );
+						_vector3.setFromMatrixPosition( object.matrixWorld )
+							.applyMatrix4( _projScreenMatrix );
 
 					}
 
@@ -1435,7 +1454,7 @@ function WebGLRenderer( parameters ) {
 							var group = groups[ i ];
 							var groupMaterial = material[ group.materialIndex ];
 
-							if ( groupMaterial && groupMaterial.visible === true ) {
+							if ( groupMaterial && groupMaterial.visible ) {
 
 								pushRenderItem( object, geometry, groupMaterial, _vector3.z, group );
 
@@ -1443,7 +1462,7 @@ function WebGLRenderer( parameters ) {
 
 						}
 
-					} else if ( material.visible === true ) {
+					} else if ( material.visible ) {
 
 						pushRenderItem( object, geometry, material, _vector3.z, null );
 
@@ -1459,7 +1478,7 @@ function WebGLRenderer( parameters ) {
 
 		for ( var i = 0, l = children.length; i < l; i ++ ) {
 
-			projectObject( children[ i ], camera );
+			projectObject( children[ i ], camera, sortObjects );
 
 		}
 
@@ -1483,17 +1502,13 @@ function WebGLRenderer( parameters ) {
 
 			if ( object.isImmediateRenderObject ) {
 
-				setMaterial( material );
+				state.setMaterial( material );
 
 				var program = setProgram( camera, scene.fog, material, object );
 
 				_currentGeometryProgram = '';
 
-				object.render( function ( object ) {
-
-					_this.renderBufferImmediate( object, program, material );
-
-				} );
+				renderObjectImmediate( object, program, material );
 
 			} else {
 
@@ -1575,7 +1590,7 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		var attributes = program.getAttributes();
+		var programAttributes = program.getAttributes();
 
 		if ( material.morphTargets ) {
 
@@ -1583,7 +1598,7 @@ function WebGLRenderer( parameters ) {
 
 			for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
 
-				if ( attributes[ 'morphTarget' + i ] >= 0 ) {
+				if ( programAttributes[ 'morphTarget' + i ] >= 0 ) {
 
 					material.numSupportedMorphTargets ++;
 
@@ -1599,7 +1614,7 @@ function WebGLRenderer( parameters ) {
 
 			for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
 
-				if ( attributes[ 'morphNormal' + i ] >= 0 ) {
+				if ( programAttributes[ 'morphNormal' + i ] >= 0 ) {
 
 					material.numSupportedMorphNormals ++;
 
@@ -1656,26 +1671,6 @@ function WebGLRenderer( parameters ) {
 
 	}
 
-	function setMaterial( material ) {
-
-		material.side === DoubleSide
-			? state.disable( _gl.CULL_FACE )
-			: state.enable( _gl.CULL_FACE );
-
-		state.setFlipSided( material.side === BackSide );
-
-		material.transparent === true
-			? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
-			: state.setBlending( NoBlending );
-
-		state.setDepthFunc( material.depthFunc );
-		state.setDepthTest( material.depthTest );
-		state.setDepthWrite( material.depthWrite );
-		state.setColorWrite( material.colorWrite );
-		state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
-
-	}
-
 	function setProgram( camera, fog, material, object ) {
 
 		_usedTextureUnits = 0;
@@ -2289,7 +2284,8 @@ function WebGLRenderer( parameters ) {
 
 			if ( light.castShadow ) {
 
-				_lights.shadows[ lightShadowsLength ++ ] = light;
+				_lights.shadows[ lightShadowsLength ] = light;
+				lightShadowsLength ++;
 
 			}
 
@@ -2301,7 +2297,7 @@ function WebGLRenderer( parameters ) {
 
 	function setupLights( lights, camera ) {
 
-		var l, ll, light,
+		var l, ll, light, shadow,
 			r = 0, g = 0, b = 0,
 			color,
 			intensity,
@@ -2310,11 +2306,11 @@ function WebGLRenderer( parameters ) {
 
 			viewMatrix = camera.matrixWorldInverse,
 
-		directionalLength = 0,
-		pointLength = 0,
-		spotLength = 0,
-		rectAreaLength = 0,
-		hemiLength = 0;
+			directionalLength = 0,
+			pointLength = 0,
+			spotLength = 0,
+			rectAreaLength = 0,
+			hemiLength = 0;
 
 		for ( l = 0, ll = lights.length; l < ll; l ++ ) {
 
@@ -2346,15 +2342,19 @@ function WebGLRenderer( parameters ) {
 
 				if ( light.castShadow ) {
 
-					uniforms.shadowBias = light.shadow.bias;
-					uniforms.shadowRadius = light.shadow.radius;
-					uniforms.shadowMapSize = light.shadow.mapSize;
+					shadow = light.shadow;
+
+					uniforms.shadowBias = shadow.bias;
+					uniforms.shadowRadius = shadow.radius;
+					uniforms.shadowMapSize = shadow.mapSize;
 
 				}
 
 				_lights.directionalShadowMap[ directionalLength ] = shadowMap;
 				_lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
-				_lights.directional[ directionalLength ++ ] = uniforms;
+				_lights.directional[ directionalLength ] = uniforms;
+
+				directionalLength ++;
 
 			} else if ( light.isSpotLight ) {
 
@@ -2379,15 +2379,19 @@ function WebGLRenderer( parameters ) {
 
 				if ( light.castShadow ) {
 
-					uniforms.shadowBias = light.shadow.bias;
-					uniforms.shadowRadius = light.shadow.radius;
-					uniforms.shadowMapSize = light.shadow.mapSize;
+					shadow = light.shadow;
+
+					uniforms.shadowBias = shadow.bias;
+					uniforms.shadowRadius = shadow.radius;
+					uniforms.shadowMapSize = shadow.mapSize;
 
 				}
 
 				_lights.spotShadowMap[ spotLength ] = shadowMap;
 				_lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
-				_lights.spot[ spotLength ++ ] = uniforms;
+				_lights.spot[ spotLength ] = uniforms;
+
+				spotLength ++;
 
 			} else if ( light.isRectAreaLight ) {
 
@@ -2419,7 +2423,9 @@ function WebGLRenderer( parameters ) {
 				// TODO (abelnation): RectAreaLight distance?
 				// uniforms.distance = distance;
 
-				_lights.rectArea[ rectAreaLength ++ ] = uniforms;
+				_lights.rectArea[ rectAreaLength ] = uniforms;
+
+				rectAreaLength ++;
 
 			} else if ( light.isPointLight ) {
 
@@ -2436,9 +2442,11 @@ function WebGLRenderer( parameters ) {
 
 				if ( light.castShadow ) {
 
-					uniforms.shadowBias = light.shadow.bias;
-					uniforms.shadowRadius = light.shadow.radius;
-					uniforms.shadowMapSize = light.shadow.mapSize;
+					shadow = light.shadow;
+
+					uniforms.shadowBias = shadow.bias;
+					uniforms.shadowRadius = shadow.radius;
+					uniforms.shadowMapSize = shadow.mapSize;
 
 				}
 
@@ -2455,7 +2463,9 @@ function WebGLRenderer( parameters ) {
 				_vector3.setFromMatrixPosition( light.matrixWorld ).negate();
 				_lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 );
 
-				_lights.point[ pointLength ++ ] = uniforms;
+				_lights.point[ pointLength ] = uniforms;
+
+				pointLength ++;
 
 			} else if ( light.isHemisphereLight ) {
 
@@ -2468,7 +2478,9 @@ function WebGLRenderer( parameters ) {
 				uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
 				uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
 
-				_lights.hemi[ hemiLength ++ ] = uniforms;
+				_lights.hemi[ hemiLength ] = uniforms;
+
+				hemiLength ++;
 
 			}
 
@@ -2519,7 +2531,7 @@ function WebGLRenderer( parameters ) {
 	this.allocTextureUnit = allocTextureUnit;
 
 	// this.setTexture2D = setTexture2D;
-	this.setTexture2D = ( function() {
+	this.setTexture2D = ( function () {
 
 		var warned = false;
 
@@ -2545,7 +2557,7 @@ function WebGLRenderer( parameters ) {
 
 	}() );
 
-	this.setTexture = ( function() {
+	this.setTexture = ( function () {
 
 		var warned = false;
 
@@ -2564,7 +2576,7 @@ function WebGLRenderer( parameters ) {
 
 	}() );
 
-	this.setTextureCube = ( function() {
+	this.setTextureCube = ( function () {
 
 		var warned = false;
 
@@ -2606,7 +2618,7 @@ function WebGLRenderer( parameters ) {
 
 	}() );
 
-	this.getCurrentRenderTarget = function() {
+	this.getCurrentRenderTarget = function () {
 
 		return _currentRenderTarget;
 

+ 153 - 0
src/renderers/webgl/WebGLAttributes.js

@@ -0,0 +1,153 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+function WebGLAttributes( gl ) {
+
+	var buffers = {};
+
+	function createBuffer( attribute, bufferType ) {
+
+		var array = attribute.array;
+		var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
+
+		var buffer = gl.createBuffer();
+
+		gl.bindBuffer( bufferType, buffer );
+		gl.bufferData( bufferType, array, usage );
+
+		attribute.onUploadCallback();
+
+		var type = gl.FLOAT;
+
+		if ( array instanceof Float32Array ) {
+
+			type = gl.FLOAT;
+
+		} else if ( array instanceof Float64Array ) {
+
+			console.warn( "Unsupported data buffer format: Float64Array" );
+
+		} else if ( array instanceof Uint16Array ) {
+
+			type = gl.UNSIGNED_SHORT;
+
+		} else if ( array instanceof Int16Array ) {
+
+			type = gl.SHORT;
+
+		} else if ( array instanceof Uint32Array ) {
+
+			type = gl.UNSIGNED_INT;
+
+		} else if ( array instanceof Int32Array ) {
+
+			type = gl.INT;
+
+		} else if ( array instanceof Int8Array ) {
+
+			type = gl.BYTE;
+
+		} else if ( array instanceof Uint8Array ) {
+
+			type = gl.UNSIGNED_BYTE;
+
+		}
+
+		return {
+			buffer: buffer,
+			type: type,
+			bytesPerElement: array.BYTES_PER_ELEMENT,
+			version: attribute.version
+		};
+
+	}
+
+	function updateBuffer( buffer, attribute, bufferType ) {
+
+		var array = attribute.array;
+		var updateRange = attribute.updateRange;
+
+		gl.bindBuffer( bufferType, buffer );
+
+		if ( attribute.dynamic === false ) {
+
+			gl.bufferData( bufferType, array, gl.STATIC_DRAW );
+
+		} else if ( updateRange.count === - 1 ) {
+
+			// Not using update ranges
+
+			gl.bufferSubData( bufferType, 0, array );
+
+		} else if ( updateRange.count === 0 ) {
+
+			console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
+
+		} else {
+
+			gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
+				array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
+
+			updateRange.count = 0; // reset range
+
+		}
+
+	}
+
+	//
+
+	function get( attribute ) {
+
+		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
+
+		return buffers[ attribute.id ];
+
+	}
+
+	function remove( attribute ) {
+
+		var data = buffers[ attribute.id ];
+
+		if ( data ) {
+
+			gl.deleteBuffer( data.buffer );
+
+			delete buffers[ attribute.id ];
+
+		}
+
+	}
+
+	function update( attribute, bufferType ) {
+
+		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
+
+		var data = buffers[ attribute.id ];
+
+		if ( data === undefined ) {
+
+			buffers[ attribute.id ] = createBuffer( attribute, bufferType );
+
+		} else if ( data.version < attribute.version ) {
+
+			updateBuffer( data.buffer, attribute, bufferType );
+
+			data.version = attribute.version;
+
+		}
+
+	}
+
+	return {
+
+		get: get,
+		remove: remove,
+		update: update
+
+	};
+
+}
+
+
+export { WebGLAttributes };

+ 99 - 54
src/renderers/webgl/WebGLGeometries.js

@@ -2,11 +2,14 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
+import { Uint16BufferAttribute, Uint32BufferAttribute } from '../../core/BufferAttribute';
 import { BufferGeometry } from '../../core/BufferGeometry';
+import { arrayMax } from '../../utils';
 
-function WebGLGeometries( gl, properties, info ) {
+function WebGLGeometries( gl, attributes, infoMemory ) {
 
 	var geometries = {};
+	var wireframeAttributes = {};
 
 	function onGeometryDispose( event ) {
 
@@ -15,132 +18,174 @@ function WebGLGeometries( gl, properties, info ) {
 
 		if ( buffergeometry.index !== null ) {
 
-			deleteAttribute( buffergeometry.index );
+			attributes.remove( buffergeometry.index );
 
 		}
 
-		deleteAttributes( buffergeometry.attributes );
+		for ( var name in buffergeometry.attributes ) {
+
+			attributes.remove( buffergeometry.attributes[ name ] );
+
+		}
 
 		geometry.removeEventListener( 'dispose', onGeometryDispose );
 
 		delete geometries[ geometry.id ];
 
-		// TODO
+		// TODO Remove duplicate code
 
-		var property = properties.get( geometry );
+		var attribute = wireframeAttributes[ geometry.id ];
 
-		if ( property.wireframe ) {
+		if ( attribute ) {
 
-			deleteAttribute( property.wireframe );
+			attributes.remove( attribute );
+			delete wireframeAttributes[ geometry.id ];
 
 		}
 
-		properties.delete( geometry );
+		attribute = wireframeAttributes[ buffergeometry.id ];
 
-		var bufferproperty = properties.get( buffergeometry );
+		if ( attribute ) {
 
-		if ( bufferproperty.wireframe ) {
-
-			deleteAttribute( bufferproperty.wireframe );
+			attributes.remove( attribute );
+			delete wireframeAttributes[ buffergeometry.id ];
 
 		}
 
-		properties.delete( buffergeometry );
-
 		//
 
-		info.memory.geometries --;
+		infoMemory.geometries --;
 
 	}
 
-	function getAttributeBuffer( attribute ) {
+	function get( object, geometry ) {
 
-		if ( attribute.isInterleavedBufferAttribute ) {
+		var buffergeometry = geometries[ geometry.id ];
 
-			return properties.get( attribute.data ).__webglBuffer;
+		if ( buffergeometry ) return buffergeometry;
 
-		}
+		geometry.addEventListener( 'dispose', onGeometryDispose );
 
-		return properties.get( attribute ).__webglBuffer;
+		if ( geometry.isBufferGeometry ) {
 
-	}
+			buffergeometry = geometry;
 
-	function deleteAttribute( attribute ) {
+		} else if ( geometry.isGeometry ) {
 
-		var buffer = getAttributeBuffer( attribute );
+			if ( geometry._bufferGeometry === undefined ) {
 
-		if ( buffer !== undefined ) {
+				geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
+
+			}
 
-			gl.deleteBuffer( buffer );
-			removeAttributeBuffer( attribute );
+			buffergeometry = geometry._bufferGeometry;
 
 		}
 
+		geometries[ geometry.id ] = buffergeometry;
+
+		infoMemory.geometries ++;
+
+		return buffergeometry;
+
 	}
 
-	function deleteAttributes( attributes ) {
+	function update( geometry ) {
 
-		for ( var name in attributes ) {
+		var index = geometry.index;
+		var geometryAttributes = geometry.attributes;
 
-			deleteAttribute( attributes[ name ] );
+		if ( index !== null ) {
+
+			attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
 
 		}
 
-	}
+		for ( var name in geometryAttributes ) {
 
-	function removeAttributeBuffer( attribute ) {
+			attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
 
-		if ( attribute.isInterleavedBufferAttribute ) {
+		}
 
-			properties.delete( attribute.data );
+		// morph targets
 
-		} else {
+		var morphAttributes = geometry.morphAttributes;
+
+		for ( var name in morphAttributes ) {
+
+			var array = morphAttributes[ name ];
 
-			properties.delete( attribute );
+			for ( var i = 0, l = array.length; i < l; i ++ ) {
+
+				attributes.update( array[ i ], gl.ARRAY_BUFFER );
+
+			}
 
 		}
 
 	}
 
-	return {
+	function getWireframeAttribute( geometry ) {
 
-		get: function ( object ) {
+		var attribute = wireframeAttributes[ geometry.id ];
 
-			var geometry = object.geometry;
+		if ( attribute ) return attribute;
 
-			if ( geometries[ geometry.id ] !== undefined ) {
+		var indices = [];
 
-				return geometries[ geometry.id ];
+		var geometryIndex = geometry.index;
+		var geometryAttributes = geometry.attributes;
 
-			}
+		// console.time( 'wireframe' );
 
-			geometry.addEventListener( 'dispose', onGeometryDispose );
+		if ( geometryIndex !== null ) {
 
-			var buffergeometry;
+			var array = geometryIndex.array;
 
-			if ( geometry.isBufferGeometry ) {
+			for ( var i = 0, l = array.length; i < l; i += 3 ) {
 
-				buffergeometry = geometry;
+				var a = array[ i + 0 ];
+				var b = array[ i + 1 ];
+				var c = array[ i + 2 ];
 
-			} else if ( geometry.isGeometry ) {
+				indices.push( a, b, b, c, c, a );
 
-				if ( geometry._bufferGeometry === undefined ) {
+			}
+
+		} else {
 
-					geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
+			var array = geometryAttributes.position.array;
 
-				}
+			for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
 
-				buffergeometry = geometry._bufferGeometry;
+				var a = i + 0;
+				var b = i + 1;
+				var c = i + 2;
+
+				indices.push( a, b, b, c, c, a );
 
 			}
 
-			geometries[ geometry.id ] = buffergeometry;
+		}
 
-			info.memory.geometries ++;
+		// console.timeEnd( 'wireframe' );
 
-			return buffergeometry;
+		attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
 
-		}
+		attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );
+
+		wireframeAttributes[ geometry.id ] = attribute;
+
+		return attribute;
+
+	}
+
+	return {
+
+		get: get,
+		update: update,
+
+		getWireframeAttribute: getWireframeAttribute
 
 	};
 

+ 16 - 225
src/renderers/webgl/WebGLObjects.js

@@ -2,256 +2,47 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-import { Uint16BufferAttribute, Uint32BufferAttribute } from '../../core/BufferAttribute';
-import { arrayMax } from '../../utils';
-import { WebGLGeometries } from './WebGLGeometries';
+function WebGLObjects( gl, geometries, infoRender ) {
 
-function WebGLObjects( gl, properties, info ) {
-
-	var geometries = new WebGLGeometries( gl, properties, info );
-
-	//
+	var updateList = {};
 
 	function update( object ) {
 
-		// TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter.
-
-		var geometry = geometries.get( object );
-
-		if ( object.geometry.isGeometry ) {
-
-			geometry.updateFromObject( object );
-
-		}
-
-		var index = geometry.index;
-		var attributes = geometry.attributes;
+		var frame = infoRender.frame;
 
-		if ( index !== null ) {
-
-			updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER );
-
-		}
-
-		for ( var name in attributes ) {
-
-			updateAttribute( attributes[ name ], gl.ARRAY_BUFFER );
-
-		}
+		var geometry = object.geometry;
+		var buffergeometry = geometries.get( object, geometry );
 
-		// morph targets
+		// Update once per frame
 
-		var morphAttributes = geometry.morphAttributes;
+		if ( updateList[ buffergeometry.id ] !== frame ) {
 
-		for ( var name in morphAttributes ) {
+			if ( geometry.isGeometry ) {
 
-			var array = morphAttributes[ name ];
-
-			for ( var i = 0, l = array.length; i < l; i ++ ) {
-
-				updateAttribute( array[ i ], gl.ARRAY_BUFFER );
+				buffergeometry.updateFromObject( object );
 
 			}
 
-		}
-
-		return geometry;
-
-	}
-
-	function updateAttribute( attribute, bufferType ) {
-
-		var data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute;
-
-		var attributeProperties = properties.get( data );
-
-		if ( attributeProperties.__webglBuffer === undefined ) {
-
-			createBuffer( attributeProperties, data, bufferType );
-
-		} else if ( attributeProperties.version !== data.version ) {
-
-			updateBuffer( attributeProperties, data, bufferType );
-
-		}
-
-	}
-
-	function createBuffer( attributeProperties, data, bufferType ) {
-
-		attributeProperties.__webglBuffer = gl.createBuffer();
-		gl.bindBuffer( bufferType, attributeProperties.__webglBuffer );
-
-		var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
-
-		gl.bufferData( bufferType, data.array, usage );
-
-		var type = gl.FLOAT;
-		var array = data.array;
-
-		if ( array instanceof Float32Array ) {
-
-			type = gl.FLOAT;
-
-		} else if ( array instanceof Float64Array ) {
-
-			console.warn( "Unsupported data buffer format: Float64Array" );
-
-		} else if ( array instanceof Uint16Array ) {
-
-			type = gl.UNSIGNED_SHORT;
-
-		} else if ( array instanceof Int16Array ) {
+			geometries.update( buffergeometry );
 
-			type = gl.SHORT;
-
-		} else if ( array instanceof Uint32Array ) {
-
-			type = gl.UNSIGNED_INT;
-
-		} else if ( array instanceof Int32Array ) {
-
-			type = gl.INT;
-
-		} else if ( array instanceof Int8Array ) {
-
-			type = gl.BYTE;
-
-		} else if ( array instanceof Uint8Array ) {
-
-			type = gl.UNSIGNED_BYTE;
+			updateList[ buffergeometry.id ] = frame;
 
 		}
 
-		attributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT;
-		attributeProperties.type = type;
-		attributeProperties.version = data.version;
-
-		data.onUploadCallback();
+		return buffergeometry;
 
 	}
 
-	function updateBuffer( attributeProperties, data, bufferType ) {
-
-		gl.bindBuffer( bufferType, attributeProperties.__webglBuffer );
-
-		if ( data.dynamic === false ) {
-
-			gl.bufferData( bufferType, data.array, gl.STATIC_DRAW );
-
-		} else if ( data.updateRange.count === - 1 ) {
-
-			// Not using update ranges
+	function clear() {
 
-			gl.bufferSubData( bufferType, 0, data.array );
-
-		} else if ( data.updateRange.count === 0 ) {
-
-			console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
-
-		} else {
-
-			gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT,
-							  data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) );
-
-			data.updateRange.count = 0; // reset range
-
-		}
-
-		attributeProperties.version = data.version;
-
-	}
-
-	function getAttributeBuffer( attribute ) {
-
-		if ( attribute.isInterleavedBufferAttribute ) {
-
-			return properties.get( attribute.data ).__webglBuffer;
-
-		}
-
-		return properties.get( attribute ).__webglBuffer;
-
-	}
-
-	function getAttributeProperties( attribute ) {
-
-		if ( attribute.isInterleavedBufferAttribute ) {
-
-			return properties.get( attribute.data );
-
-		}
-
-		return properties.get( attribute );
-
-	}
-
-	function getWireframeAttribute( geometry ) {
-
-		var property = properties.get( geometry );
-
-		if ( property.wireframe !== undefined ) {
-
-			return property.wireframe;
-
-		}
-
-		var indices = [];
-
-		var index = geometry.index;
-		var attributes = geometry.attributes;
-
-		// console.time( 'wireframe' );
-
-		if ( index !== null ) {
-
-			var array = index.array;
-
-			for ( var i = 0, l = array.length; i < l; i += 3 ) {
-
-				var a = array[ i + 0 ];
-				var b = array[ i + 1 ];
-				var c = array[ i + 2 ];
-
-				indices.push( a, b, b, c, c, a );
-
-			}
-
-		} else {
-
-			var array = attributes.position.array;
-
-			for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
-
-				var a = i + 0;
-				var b = i + 1;
-				var c = i + 2;
-
-				indices.push( a, b, b, c, c, a );
-
-			}
-
-		}
-
-		// console.timeEnd( 'wireframe' );
-
-		var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
-
-		updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER );
-
-		property.wireframe = attribute;
-
-		return attribute;
+		updateList = {};
 
 	}
 
 	return {
 
-		getAttributeBuffer: getAttributeBuffer,
-		getAttributeProperties: getAttributeProperties,
-		getWireframeAttribute: getWireframeAttribute,
-
-		update: update
+		update: update,
+		clear: clear
 
 	};
 

+ 19 - 17
src/renderers/webgl/WebGLProperties.js

@@ -6,36 +6,38 @@ function WebGLProperties() {
 
 	var properties = {};
 
-	return {
+	function get( object ) {
 
-		get: function ( object ) {
+		var uuid = object.uuid;
+		var map = properties[ uuid ];
 
-			var uuid = object.uuid;
-			var map = properties[ uuid ];
+		if ( map === undefined ) {
 
-			if ( map === undefined ) {
+			map = {};
+			properties[ uuid ] = map;
 
-				map = {};
-				properties[ uuid ] = map;
+		}
 
-			}
+		return map;
 
-			return map;
+	}
 
-		},
+	function remove( object ) {
 
-		delete: function ( object ) {
+		delete properties[ object.uuid ];
 
-			delete properties[ object.uuid ];
+	}
 
-		},
+	function clear() {
 
-		clear: function () {
+		properties = {};
 
-			properties = {};
-
-		}
+	}
 
+	return {
+		get: get,
+		remove: remove,
+		clear: clear
 	};
 
 }

+ 20 - 20
src/renderers/webgl/WebGLShadowMap.js

@@ -18,27 +18,27 @@ import { Frustum } from '../../math/Frustum';
 function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 	var _gl = _renderer.context,
-	_state = _renderer.state,
-	_frustum = new Frustum(),
-	_projScreenMatrix = new Matrix4(),
+		_state = _renderer.state,
+		_frustum = new Frustum(),
+		_projScreenMatrix = new Matrix4(),
 
-	_lightShadows = _lights.shadows,
+		_lightShadows = _lights.shadows,
 
-	_shadowMapSize = new Vector2(),
-	_maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ),
+		_shadowMapSize = new Vector2(),
+		_maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ),
 
-	_lookTarget = new Vector3(),
-	_lightPositionWorld = new Vector3(),
+		_lookTarget = new Vector3(),
+		_lightPositionWorld = new Vector3(),
 
-	_MorphingFlag = 1,
-	_SkinningFlag = 2,
+		_MorphingFlag = 1,
+		_SkinningFlag = 2,
 
-	_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
+		_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
 
-	_depthMaterials = new Array( _NumberOfMaterialVariants ),
-	_distanceMaterials = new Array( _NumberOfMaterialVariants ),
+		_depthMaterials = new Array( _NumberOfMaterialVariants ),
+		_distanceMaterials = new Array( _NumberOfMaterialVariants ),
 
-	_materialCache = {};
+		_materialCache = {};
 
 	var cubeDirections = [
 		new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
@@ -111,9 +111,9 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 		if ( _lightShadows.length === 0 ) return;
 
 		// Set GL state for depth map.
-		_state.buffers.color.setClear( 1, 1, 1, 1 );
 		_state.disable( _gl.BLEND );
-		_state.setDepthTest( true );
+		_state.buffers.color.setClear( 1, 1, 1, 1 );
+		_state.buffers.depth.setTest( true );
 		_state.setScissorTest( false );
 
 		// render depth map
@@ -393,11 +393,11 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 		if ( object.visible === false ) return;
 
-		var visible = ( object.layers.mask & camera.layers.mask ) !== 0;
+		var visible = object.layers.test( camera.layers );
 
 		if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
 
-			if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
+			if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
 
 				object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
 
@@ -413,7 +413,7 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 						var group = groups[ k ];
 						var groupMaterial = material[ group.materialIndex ];
 
-						if ( groupMaterial && groupMaterial.visible === true ) {
+						if ( groupMaterial && groupMaterial.visible ) {
 
 							var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
 							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
@@ -422,7 +422,7 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 					}
 
-				} else if ( material.visible === true ) {
+				} else if ( material.visible ) {
 
 					var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
 					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );

+ 16 - 53
src/renderers/webgl/WebGLState.js

@@ -2,7 +2,7 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending } from '../../constants';
+import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending, DoubleSide, BackSide } from '../../constants';
 import { Vector4 } from '../../math/Vector4';
 
 function WebGLState( gl, extensions, paramThreeToGL ) {
@@ -383,7 +383,7 @@ function WebGLState( gl, extensions, paramThreeToGL ) {
 		stencilBuffer.setClear( 0 );
 
 		enable( gl.DEPTH_TEST );
-		setDepthFunc( LessEqualDepth );
+		depthBuffer.setFunc( LessEqualDepth );
 
 		setFlipSided( false );
 		setCullFace( CullFaceBack );
@@ -625,53 +625,24 @@ function WebGLState( gl, extensions, paramThreeToGL ) {
 
 	}
 
-	// TODO Deprecate
+	function setMaterial( material ) {
 
-	function setColorWrite( colorWrite ) {
+		material.side === DoubleSide
+			? disable( gl.CULL_FACE )
+			: enable( gl.CULL_FACE );
 
-		colorBuffer.setMask( colorWrite );
+		setFlipSided( material.side === BackSide );
 
-	}
-
-	function setDepthTest( depthTest ) {
-
-		depthBuffer.setTest( depthTest );
-
-	}
-
-	function setDepthWrite( depthWrite ) {
-
-		depthBuffer.setMask( depthWrite );
-
-	}
-
-	function setDepthFunc( depthFunc ) {
-
-		depthBuffer.setFunc( depthFunc );
-
-	}
+		material.transparent === true
+			? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
+			: setBlending( NoBlending );
 
-	function setStencilTest( stencilTest ) {
+		depthBuffer.setFunc( material.depthFunc );
+		depthBuffer.setTest( material.depthTest );
+		depthBuffer.setMask( material.depthWrite );
+		colorBuffer.setMask( material.colorWrite );
 
-		stencilBuffer.setTest( stencilTest );
-
-	}
-
-	function setStencilWrite( stencilWrite ) {
-
-		stencilBuffer.setMask( stencilWrite );
-
-	}
-
-	function setStencilFunc( stencilFunc, stencilRef, stencilMask ) {
-
-		stencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask );
-
-	}
-
-	function setStencilOp( stencilFail, stencilZFail, stencilZPass ) {
-
-		stencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass );
+		setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
 
 	}
 
@@ -934,15 +905,7 @@ function WebGLState( gl, extensions, paramThreeToGL ) {
 		getCompressedTextureFormats: getCompressedTextureFormats,
 
 		setBlending: setBlending,
-
-		setColorWrite: setColorWrite,
-		setDepthTest: setDepthTest,
-		setDepthWrite: setDepthWrite,
-		setDepthFunc: setDepthFunc,
-		setStencilTest: setStencilTest,
-		setStencilWrite: setStencilWrite,
-		setStencilFunc: setStencilFunc,
-		setStencilOp: setStencilOp,
+		setMaterial: setMaterial,
 
 		setFlipSided: setFlipSided,
 		setCullFace: setCullFace,

+ 9 - 10
src/renderers/webgl/WebGLTextures.js

@@ -5,9 +5,8 @@
 import { LinearFilter, NearestFilter, RGBFormat, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, ClampToEdgeWrapping, NearestMipMapLinearFilter, NearestMipMapNearestFilter } from '../../constants';
 import { _Math } from '../../math/Math';
 
-function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) {
+function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, infoMemory ) {
 
-	var _infoMemory = info.memory;
 	var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );
 
 	//
@@ -96,7 +95,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 		deallocateTexture( texture );
 
-		_infoMemory.textures --;
+		infoMemory.textures --;
 
 
 	}
@@ -109,7 +108,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 		deallocateRenderTarget( renderTarget );
 
-		_infoMemory.textures --;
+		infoMemory.textures --;
 
 	}
 
@@ -136,7 +135,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 		}
 
 		// remove all webgl properties
-		properties.delete( texture );
+		properties.remove( texture );
 
 	}
 
@@ -175,8 +174,8 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 		}
 
-		properties.delete( renderTarget.texture );
-		properties.delete( renderTarget );
+		properties.remove( renderTarget.texture );
+		properties.remove( renderTarget );
 
 	}
 
@@ -228,7 +227,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 					textureProperties.__image__webglTextureCube = _gl.createTexture();
 
-					_infoMemory.textures ++;
+					infoMemory.textures ++;
 
 				}
 
@@ -399,7 +398,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 			textureProperties.__webglTexture = _gl.createTexture();
 
-			_infoMemory.textures ++;
+			infoMemory.textures ++;
 
 		}
 
@@ -700,7 +699,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, paramT
 
 		textureProperties.__webglTexture = _gl.createTexture();
 
-		_infoMemory.textures ++;
+		infoMemory.textures ++;
 
 		var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
 		var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );

+ 2 - 2
src/renderers/webgl/plugins/LensFlarePlugin.js

@@ -228,7 +228,7 @@ function LensFlarePlugin( renderer, flares ) {
 		gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
 
 		state.disable( gl.CULL_FACE );
-		state.setDepthWrite( false );
+		state.buffers.depth.setMask( false );
 
 		for ( var i = 0, l = flares.length; i < l; i ++ ) {
 
@@ -353,7 +353,7 @@ function LensFlarePlugin( renderer, flares ) {
 
 		state.enable( gl.CULL_FACE );
 		state.enable( gl.DEPTH_TEST );
-		state.setDepthWrite( true );
+		state.buffers.depth.setMask( true );
 
 		renderer.resetGLState();
 

+ 2 - 2
src/renderers/webgl/plugins/SpritePlugin.js

@@ -224,8 +224,8 @@ function SpritePlugin( renderer, sprites ) {
 			gl.uniform2fv( uniforms.scale, scale );
 
 			state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
-			state.setDepthTest( material.depthTest );
-			state.setDepthWrite( material.depthWrite );
+			state.buffers.depth.setTest( material.depthTest );
+			state.buffers.depth.setMask( material.depthWrite );
 
 			if ( material.map ) {
 

+ 10 - 30
test/unit/src/core/Object3D.js

@@ -12,8 +12,7 @@ QUnit.test( "rotateX" , function( assert ) {
 	var angleInRad = 1.562;
 	obj.rotateX(angleInRad);
 
-	// should calculate the correct rotation on x
-	checkIfFloatsAreEqual(obj.rotation.x, angleInRad, assert);
+	assert.numEqual( obj.rotation.x, angleInRad, "x is equal" );
 });
 
 QUnit.test( "rotateY" , function( assert ) {
@@ -22,8 +21,7 @@ QUnit.test( "rotateY" , function( assert ) {
 	var angleInRad = -0.346;
 	obj.rotateY(angleInRad);
 
-	// should calculate the correct rotation on y
-	checkIfFloatsAreEqual(obj.rotation.y, angleInRad, assert);
+	assert.numEqual( obj.rotation.y, angleInRad, "y is equal" );
 });
 
 QUnit.test( "rotateZ" , function( assert ) {
@@ -32,71 +30,53 @@ QUnit.test( "rotateZ" , function( assert ) {
 	var angleInRad = 1;
 	obj.rotateZ(angleInRad);
 
-	// should calculate the correct rotation on y
-	checkIfFloatsAreEqual(obj.rotation.z, angleInRad, assert);
+	assert.numEqual( obj.rotation.z, angleInRad, "z is equal" );
 });
 
 QUnit.test( "translateOnAxis" , function( assert ) {
 	var obj = new THREE.Object3D();
 
-	// get a reference object for comparing
-	var reference = {x: 1, y: 1.23, z: -4.56};
 	obj.translateOnAxis(new THREE.Vector3(1, 0, 0), 1);
 	obj.translateOnAxis(new THREE.Vector3(0, 1, 0), 1.23);
 	obj.translateOnAxis(new THREE.Vector3(0, 0, 1), -4.56);
 
-	checkIfPropsAreEqual(reference, obj.position, assert);
+	assert.propEqual( obj.position, { x: 1, y: 1.23, z: -4.56 } );
 });
 
 QUnit.test( "translateX" , function( assert ) {
 	var obj = new THREE.Object3D();
 	obj.translateX(1.234);
 
-	assert.ok( obj.position.x === 1.234 , "x is equal" );
+	assert.numEqual( obj.position.x, 1.234, "x is equal" );
 });
 
 QUnit.test( "translateY" , function( assert ) {
 	var obj = new THREE.Object3D();
 	obj.translateY(1.234);
 
-	assert.ok( obj.position.y === 1.234 , "y is equal" );
+	assert.numEqual( obj.position.y, 1.234, "y is equal" );
 });
 
 QUnit.test( "translateZ" , function( assert ) {
 	var obj = new THREE.Object3D();
 	obj.translateZ(1.234);
 
-	assert.ok( obj.position.z === 1.234 , "z is equal" );
+	assert.numEqual( obj.position.z, 1.234, "z is equal" );
 });
 
 QUnit.test( "lookAt" , function( assert ) {
 	var obj = new THREE.Object3D();
 	obj.lookAt(new THREE.Vector3(0, -1, 1));
 
-	assert.ok( obj.rotation.x * RadToDeg === 45 , "x is equal" );
+	assert.numEqual( obj.rotation.x * RadToDeg, 45, "x is equal" );
 });
 
 QUnit.test( "getWorldRotation" , function( assert ) {
 	var obj = new THREE.Object3D();
 
 	obj.lookAt(new THREE.Vector3(0, -1, 1));
-	assert.ok( obj.getWorldRotation().x * RadToDeg === 45 , "x is equal" );
+	assert.numEqual( obj.getWorldRotation().x * RadToDeg, 45, "x is equal" );
 
 	obj.lookAt(new THREE.Vector3(1, 0, 0));
-	assert.ok( obj.getWorldRotation().y * RadToDeg === 90 , "y is equal" );
+	assert.numEqual( obj.getWorldRotation().y * RadToDeg, 90, "y is equal" );
 });
-
-function checkIfPropsAreEqual(reference, obj, assert) {
-	assert.ok( obj.x === reference.x , "x is equal" );
-	assert.ok( obj.y === reference.y , "y is equal!" );
-	assert.ok( obj.z === reference.z , "z is equal!" );
-}
-
-// since float equal checking is a mess in js, one solution is to cut off
-// decimal places
-function checkIfFloatsAreEqual(f1, f2, assert) {
-	var f1Rounded = ((f1 * 1000) | 0) / 1000;
-	var f2Rounded = ((f2 * 1000) | 0) / 1000;
-
-	assert.ok( f1Rounded === f2Rounded, "passed" );
-}

+ 4 - 5
test/unit/src/math/Triangle.js

@@ -96,11 +96,10 @@ QUnit.test( "normal" , function( assert ) {
 QUnit.test( "plane" , function( assert ) {
 	var a = new THREE.Triangle();
 
-	// artificial normal is created in this case.
-	assert.ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
-	assert.ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
-	assert.ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
-	assert.ok( a.plane().normal.equals( a.normal() ), "Passed!" );
+	assert.ok( isNaN( a.plane().distanceToPoint( a.a ) ), "Passed!" );
+	assert.ok( isNaN( a.plane().distanceToPoint( a.b ) ), "Passed!" );
+	assert.ok( isNaN( a.plane().distanceToPoint( a.c ) ), "Passed!" );
+	assert.propEqual( a.plane().normal, {x: NaN, y: NaN, z: NaN}, "Passed!" );
 
 	a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	assert.ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );

+ 1 - 1
test/unit/src/math/Vector2.js

@@ -225,7 +225,7 @@ QUnit.test( "setLength" , function( assert ) {
 	a = new THREE.Vector2( 0, 0 );
 	assert.ok( a.length() == 0, "Passed!" );
 	a.setLength( y );
-	assert.ok( a.length() == 0, "Passed!" );
+	assert.ok( isNaN( a.length() ), "Passed!" );
 });
 
 QUnit.test( "lerp/clone", function( assert ) {

+ 1 - 1
test/unit/src/math/Vector3.js

@@ -235,7 +235,7 @@ QUnit.test( "setLength" , function( assert ) {
 	a = new THREE.Vector3( 0, 0, 0 );
 	assert.ok( a.length() == 0, "Passed!" );
 	a.setLength( y );
-	assert.ok( a.length() == 0, "Passed!" );
+	assert.ok( isNaN( a.length() ), "Passed!" );
 
 });
 

+ 7 - 7
test/unit/src/math/Vector4.js

@@ -132,9 +132,9 @@ QUnit.test( "multiply/divide", function( assert ) {
 
 	b.multiplyScalar( -2 );
 	assert.ok( b.x == 2*x, "Passed!" );
-	assert.ok( b.y == 2*y, "Passed!" );	
-	assert.ok( b.z == 2*z, "Passed!" );	
-	assert.ok( b.w == 2*w, "Passed!" );	
+	assert.ok( b.y == 2*y, "Passed!" );
+	assert.ok( b.z == 2*z, "Passed!" );
+	assert.ok( b.w == 2*w, "Passed!" );
 
 	a.divideScalar( -2 );
 	assert.ok( a.x == x, "Passed!" );
@@ -202,7 +202,7 @@ QUnit.test( "length/lengthSq", function( assert ) {
 	var c = new THREE.Vector4( 0, 0, z, 0 );
 	var d = new THREE.Vector4( 0, 0, 0, w );
 	var e = new THREE.Vector4( 0, 0, 0, 0 );
-	
+
 	assert.ok( a.length() == x, "Passed!" );
 	assert.ok( a.lengthSq() == x*x, "Passed!" );
 	assert.ok( b.length() == y, "Passed!" );
@@ -224,7 +224,7 @@ QUnit.test( "normalize" , function( assert ) {
 	var b = new THREE.Vector4( 0, -y, 0, 0 );
 	var c = new THREE.Vector4( 0, 0, z, 0 );
 	var d = new THREE.Vector4( 0, 0, 0, -w );
-	
+
 	a.normalize();
 	assert.ok( a.length() == 1, "Passed!" );
 	assert.ok( a.x == 1, "Passed!" );
@@ -249,7 +249,7 @@ QUnit.test( "distanceTo/distanceToSquared", function() {
 	var c = new THREE.Vector4( 0, 0, z, 0 );
 	var d = new THREE.Vector4( 0, 0, 0, -w );
 	var e = new THREE.Vector4();
-	
+
 	ok( a.distanceTo( e ) == x, "Passed!" );
 	ok( a.distanceToSquared( e ) == x*x, "Passed!" );
 
@@ -275,7 +275,7 @@ QUnit.test( "setLength" , function( assert ) {
 	a = new THREE.Vector4( 0, 0, 0, 0 );
 	assert.ok( a.length() == 0, "Passed!" );
 	a.setLength( y );
-	assert.ok( a.length() == 0, "Passed!" );
+	assert.ok( isNaN( a.length() ), "Passed!" );
 });
 
 QUnit.test( "lerp/clone", function( assert ) {

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