Browse Source

Merge remote-tracking branch 'mrdoob/dev' into sheen

Daniel Sturk 6 years ago
parent
commit
b2ab31d903
100 changed files with 1725 additions and 4688 deletions
  1. 192 345
      build/three.js
  2. 187 567
      build/three.min.js
  3. 192 345
      build/three.module.js
  4. 3 0
      docs/api/en/audio/Audio.html
  5. 8 0
      docs/api/en/core/Raycaster.html
  6. 1 1
      docs/api/en/math/Matrix4.html
  7. 1 1
      docs/api/en/scenes/FogExp2.html
  8. 2 2
      docs/manual/en/introduction/Creating-a-scene.html
  9. 6 1
      docs/manual/en/introduction/How-to-use-WebGL2.html
  10. 1 1
      docs/manual/zh/introduction/Creating-a-scene.html
  11. 0 3
      editor/index.html
  12. 0 29
      editor/js/Loader.js
  13. 0 3
      editor/sw.js
  14. 11 11
      examples/files.js
  15. 1 1
      examples/js/controls/DragControls.js
  16. 2 162
      examples/js/controls/OrbitControls.js
  17. 1 1
      examples/js/controls/OrthographicTrackballControls.js
  18. 1 1
      examples/js/curves/CurveExtras.js
  19. 1 1
      examples/js/effects/AsciiEffect.js
  20. 1 1
      examples/js/exporters/ColladaExporter.js
  21. 42 3
      examples/js/exporters/GLTFExporter.js
  22. 1 1
      examples/js/geometries/ParametricGeometries.js
  23. 0 658
      examples/js/libs/ctm.js
  24. 0 517
      examples/js/libs/lzma.js
  25. 1 1
      examples/js/loaders/AMFLoader.js
  26. 1 1
      examples/js/loaders/DDSLoader.js
  27. 95 35
      examples/js/loaders/STLLoader.js
  28. 1 1
      examples/js/loaders/TDSLoader.js
  29. 1 1
      examples/js/loaders/TGALoader.js
  30. 0 279
      examples/js/loaders/ctm/CTMLoader.js
  31. 0 19
      examples/js/loaders/ctm/CTMWorker.js
  32. 1 1
      examples/js/modifiers/SimplifyModifier.js
  33. 1 1
      examples/js/modifiers/SubdivisionModifier.js
  34. 3 2
      examples/js/shaders/TranslucentShader.js
  35. 1 1
      examples/js/utils/UVsDebug.js
  36. 1 1
      examples/jsm/controls/DragControls.js
  37. 2 162
      examples/jsm/controls/OrbitControls.js
  38. 1 1
      examples/jsm/controls/OrthographicTrackballControls.js
  39. 2 2
      examples/jsm/controls/TransformControls.d.ts
  40. 1 1
      examples/jsm/curves/CurveExtras.js
  41. 1 1
      examples/jsm/effects/AsciiEffect.js
  42. 1 1
      examples/jsm/exporters/ColladaExporter.js
  43. 42 3
      examples/jsm/exporters/GLTFExporter.js
  44. 1 1
      examples/jsm/geometries/ParametricGeometries.js
  45. 1 1
      examples/jsm/loaders/AMFLoader.js
  46. 1 1
      examples/jsm/loaders/DDSLoader.js
  47. 1 0
      examples/jsm/loaders/GLTFLoader.js
  48. 95 35
      examples/jsm/loaders/STLLoader.js
  49. 1 1
      examples/jsm/loaders/TDSLoader.js
  50. 1 1
      examples/jsm/loaders/TGALoader.js
  51. 0 20
      examples/jsm/loaders/ctm/CTMLoader.d.ts
  52. 0 288
      examples/jsm/loaders/ctm/CTMLoader.js
  53. 1 1
      examples/jsm/modifiers/SimplifyModifier.js
  54. 1 1
      examples/jsm/modifiers/SubdivisionModifier.js
  55. 2 1
      examples/jsm/nodes/accessors/NormalNode.js
  56. 6 1
      examples/jsm/nodes/accessors/ReflectNode.js
  57. 9 2
      examples/jsm/nodes/core/FunctionNode.js
  58. 1 0
      examples/jsm/nodes/materials/StandardNodeMaterial.js
  59. 13 3
      examples/jsm/nodes/materials/nodes/StandardNode.js
  60. 5 3
      examples/jsm/nodes/misc/TextureCubeNode.js
  61. 3 2
      examples/jsm/shaders/TranslucentShader.js
  62. 1 1
      examples/jsm/utils/UVsDebug.js
  63. 1 1
      examples/misc_controls_transform.html
  64. BIN
      examples/models/ctm/LeePerry.ctm
  65. BIN
      examples/models/ctm/WaltHead.ctm
  66. BIN
      examples/models/ctm/ben.ctm
  67. BIN
      examples/models/ctm/camaro/camaro.ctm
  68. 0 113
      examples/models/ctm/camaro/camaro.js
  69. BIN
      examples/models/ctm/camaro/car-ao.png
  70. BIN
      examples/models/ctm/camaro/plane-ao-256.png
  71. BIN
      examples/models/ctm/hand.ctm
  72. BIN
      examples/textures/nvidia_tentacle/tentacle_object_space.png
  73. BIN
      examples/textures/nvidia_tentacle/tentacle_tangent_space.png
  74. 1 0
      examples/textures/pbr/Scratched_gold/Scratched_gold.txt
  75. BIN
      examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_AO.png
  76. BIN
      examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Base_Color.png
  77. BIN
      examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Height.png
  78. BIN
      examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png
  79. BIN
      examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Roughness.png
  80. 7 3
      examples/webgl_furnace_test.html
  81. 0 242
      examples/webgl_loader_ctm_materials.html
  82. 0 3
      examples/webgl_loader_stl.html
  83. 13 8
      examples/webgl_materials_clearcoat_normalmap.html
  84. 145 69
      examples/webgl_materials_nodes.html
  85. 3 1
      examples/webgl_shadowmap_performance.html
  86. 242 164
      package-lock.json
  87. 5 5
      package.json
  88. 3 10
      src/Three.Legacy.js
  89. 66 75
      src/animation/PropertyBinding.js
  90. 1 0
      src/audio/Audio.d.ts
  91. 2 1
      src/audio/Audio.js
  92. 4 11
      src/audio/AudioListener.js
  93. 4 11
      src/audio/PositionalAudio.js
  94. 2 8
      src/cameras/StereoCamera.js
  95. 114 167
      src/core/BufferGeometry.js
  96. 41 78
      src/core/Geometry.js
  97. 108 181
      src/core/Object3D.js
  98. 6 0
      src/core/Raycaster.d.ts
  99. 3 2
      src/core/Raycaster.js
  100. 1 3
      src/helpers/ArrowHelper.js

File diff suppressed because it is too large
+ 192 - 345
build/three.js


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


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


+ 3 - 0
docs/api/en/audio/Audio.html

@@ -91,6 +91,9 @@
 		<h3>[property:Number offset]</h3>
 		<p>An offset to the time within the audio buffer that playback should begin. Same as the *offset* paramter of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/start AudioBufferSourceNode.start](). Default is *0*.</p>
 
+		<h3>[property:Number duration]</h3>
+		<p>Overrides the duration of the audio. Same as the *duration* paramter of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/start AudioBufferSourceNode.start](). Default is *undefined* to play the whole buffer.</p>
+
 		<h3>[property:String source]</h3>
 		<p>An [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode AudioBufferSourceNode] created
 		using [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createBufferSource AudioContext.createBufferSource]().</p>

+ 8 - 0
docs/api/en/core/Raycaster.html

@@ -103,6 +103,14 @@
 		This value shouldn't be negative and should be smaller than the far property.
 		</p>
 
+		<h3>[property:Camera camera]</h3>
+		<p>
+		The camera to use when raycasting against view-dependent objects such as billboarded objects like [page:Sprites]. This field
+		can be set manually or is set when calling "setFromCamera".
+
+		Defaults to null.
+		</p>
+
 		<h3>[property:Object params]</h3>
 		<p>
 		An object with the following properties:

+ 1 - 1
docs/api/en/math/Matrix4.html

@@ -56,7 +56,7 @@
 
 			This means that calling
 		<code>
-var m = new Matrix4();
+var m = new THREE.Matrix4();
 
 m.set( 11, 12, 13, 14,
        21, 22, 23, 24,

+ 1 - 1
docs/api/en/scenes/FogExp2.html

@@ -10,7 +10,7 @@
 	<body>
 		<h1>[name]</h1>
 
-		<p class="desc">This class contains the parameters that define exponential fog, i.e., that grows exponentially denser with the distance.</p>
+		<p class="desc">This class contains the parameters that define exponential squared fog, which gives a clear view near the camera and a faster than exponentially densening fog farther from the camera.</p>
 
 
 		<h2>Constructor</h2>

+ 2 - 2
docs/manual/en/introduction/Creating-a-scene.html

@@ -20,7 +20,7 @@
 		&lt;!DOCTYPE html&gt;
 		&lt;html&gt;
 			&lt;head&gt;
-				&lt;meta charset=utf-8&gt;
+				&lt;meta charset="utf-8"&gt;
 				&lt;title&gt;My first three.js app&lt;/title&gt;
 				&lt;style&gt;
 					body { margin: 0; }
@@ -118,7 +118,7 @@
 		<h2>The result</h2>
 		<p>Congratulations! You have now completed your first three.js application. It's simple, you have to start somewhere.</p>
 
-		<p>The full code is available below. Play around with it to get a better understanding of how it works.</p>
+		<p>The full code is available below and as an editable [link:https://jsfiddle.net/mkba0ecu/ live example]. Play around with it to get a better understanding of how it works.</p>
 
 		<code>
 		&lt;html&gt;

+ 6 - 1
docs/manual/en/introduction/How-to-use-WebGL2.html

@@ -48,9 +48,14 @@ if ( WEBGL.isWebGL2Available() === false ) {
 		automatically convert the built-in material's shader code to GLSL ES 3.00.
 	</p>
 
+	<p>
+		Since you are manually creating the WebGL 2 rendering context, you also have to pass in all necessary context attributes.
+		Note: It's not possible to modify these attributes after the context has been created, so passing them to the WebGLRenderer won't have any effect.
+	</p>
+
 	<code>
 var canvas = document.createElement( 'canvas' );
-var context = canvas.getContext( 'webgl2' );
+var context = canvas.getContext( 'webgl2', { alpha: false } );
 var renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context } );
 	</code>
 

+ 1 - 1
docs/manual/zh/introduction/Creating-a-scene.html

@@ -20,7 +20,7 @@
 		&lt;!DOCTYPE html&gt;
 		&lt;html&gt;
 			&lt;head&gt;
-				&lt;meta charset=utf-8&gt;
+				&lt;meta charset="utf-8"&gt;
 				&lt;title&gt;My first three.js app&lt;/title&gt;
 				&lt;style&gt;
 					body { margin: 0; }

+ 0 - 3
editor/index.html

@@ -22,8 +22,6 @@
 		<script src="../examples/js/libs/chevrotain.min.js"></script> <!-- VRML -->
 		<script src="../examples/js/libs/jszip.min.js"></script>
 		<script src="../examples/js/libs/inflate.min.js"></script> <!-- FBX -->
-		<script src="../examples/js/libs/lzma.js"></script> <!-- CTM -->
-		<script src="../examples/js/libs/ctm.js"></script> <!-- CTM -->
 
 		<script src="../examples/js/loaders/AMFLoader.js"></script>
 		<script src="../examples/js/loaders/AWDLoader.js"></script>
@@ -45,7 +43,6 @@
 		<script src="../examples/js/loaders/TDSLoader.js"></script>
 		<script src="../examples/js/loaders/VRMLLoader.js"></script>
 		<script src="../examples/js/loaders/VTKLoader.js"></script>
-		<script src="../examples/js/loaders/ctm/CTMLoader.js"></script>
 
 		<script src="../examples/js/exporters/ColladaExporter.js"></script>
 		<script src="../examples/js/exporters/GLTFExporter.js"></script>

+ 0 - 29
editor/js/Loader.js

@@ -140,35 +140,6 @@ var Loader = function ( editor ) {
 
 				break;
 
-			case 'ctm':
-
-				reader.addEventListener( 'load', function ( event ) {
-
-					var data = new Uint8Array( event.target.result );
-
-					var stream = new CTM.Stream( data );
-					stream.offset = 0;
-
-					var loader = new THREE.CTMLoader();
-					loader.createModel( new CTM.File( stream ), function ( geometry ) {
-
-						geometry.sourceType = "ctm";
-						geometry.sourceFile = file.name;
-
-						var material = new THREE.MeshStandardMaterial();
-
-						var mesh = new THREE.Mesh( geometry, material );
-						mesh.name = filename;
-
-						editor.execute( new AddObjectCommand( editor, mesh ) );
-
-					} );
-
-				}, false );
-				reader.readAsArrayBuffer( file );
-
-				break;
-
 			case 'dae':
 
 				reader.addEventListener( 'load', function ( event ) {

+ 0 - 3
editor/sw.js

@@ -13,8 +13,6 @@ const staticAssets = [
 	'../examples/js/libs/chevrotain.min.js',
 	'../examples/js/libs/jszip.min.js',
 	'../examples/js/libs/inflate.min.js',
-	'../examples/js/libs/lzma.js',
-	'../examples/js/libs/ctm.js',
 
 	'../examples/js/loaders/AMFLoader.js',
 	'../examples/js/loaders/AWDLoader.js',
@@ -36,7 +34,6 @@ const staticAssets = [
 	'../examples/js/loaders/TDSLoader.js',
 	'../examples/js/loaders/VRMLLoader.js',
 	'../examples/js/loaders/VTKLoader.js',
-	'../examples/js/loaders/ctm/CTMLoader.js',
 
 	'../examples/js/exporters/ColladaExporter.js',
 	'../examples/js/exporters/GLTFExporter.js',

+ 11 - 11
examples/files.js

@@ -85,8 +85,6 @@ var files = {
 		"webgl_loader_collada",
 		"webgl_loader_collada_kinematics",
 		"webgl_loader_collada_skinning",
-		"webgl_loader_ctm",
-		"webgl_loader_ctm_materials",
 		"webgl_loader_draco",
 		"webgl_loader_fbx",
 		"webgl_loader_fbx_nurbs",
@@ -103,7 +101,6 @@ var files = {
 		"webgl_loader_mmd",
 		"webgl_loader_mmd_pose",
 		"webgl_loader_mmd_audio",
-		"webgl_loader_nodes",
 		"webgl_loader_nrrd",
 		"webgl_loader_obj",
 		"webgl_loader_obj_mtl",
@@ -160,13 +157,10 @@ var files = {
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps_exr",
 		"webgl_materials_envmaps_hdr",
-		"webgl_materials_envmaps_hdr_nodes",
 		"webgl_materials_envmaps_parallax",
-		"webgl_materials_envmaps_pmrem_nodes",
 		"webgl_materials_grass",
 		"webgl_materials_lightmap",
 		"webgl_materials_matcap",
-		"webgl_materials_nodes",
 		"webgl_materials_normalmap",
 		"webgl_materials_normalmap_object_space",
 		"webgl_materials_parallaxmap",
@@ -194,7 +188,6 @@ var files = {
 		"webgl_materials_sheen",
 		"webgl_math_orientation_transform",
 		"webgl_mirror",
-		"webgl_mirror_nodes",
 		"webgl_modifier_simplifier",
 		"webgl_modifier_subdivision",
 		"webgl_modifier_tessellation",
@@ -215,7 +208,6 @@ var files = {
 		"webgl_panorama_equirectangular",
 		"webgl_performance",
 		"webgl_performance_doublesided",
-		"webgl_performance_nodes",
 		"webgl_performance_static",
 		"webgl_points_billboards",
 		"webgl_points_dynamic",
@@ -243,7 +235,6 @@ var files = {
 		"webgl_shadowmesh",
 		"webgl_skinning_simple",
 		"webgl_sprites",
-		"webgl_sprites_nodes",
 		"webgl_terrain_dynamic",
 		"webgl_test_memory",
 		"webgl_test_memory2",
@@ -253,6 +244,17 @@ var files = {
 		"webgl_water",
 		"webgl_water_flowmap"
 	],
+	"webgl / nodes": [
+		"webgl_loader_nodes",
+		"webgl_materials_envmaps_hdr_nodes",
+		"webgl_materials_envmaps_pmrem_nodes",
+		"webgl_materials_nodes",
+		"webgl_mirror_nodes",
+		"webgl_performance_nodes",
+		"webgl_postprocessing_nodes",
+		"webgl_postprocessing_nodes_pass",
+		"webgl_sprites_nodes",
+	],
 	"webgl / postprocessing": [
 		"webgl_postprocessing",
 		"webgl_postprocessing_advanced",
@@ -268,8 +270,6 @@ var files = {
 		"webgl_postprocessing_masking",
 		"webgl_postprocessing_ssaa",
 		"webgl_postprocessing_ssaa_unbiased",
-		"webgl_postprocessing_nodes",
-		"webgl_postprocessing_nodes_pass",
 		"webgl_postprocessing_outline",
 		"webgl_postprocessing_pixel",
 		"webgl_postprocessing_procedural",

+ 1 - 1
examples/js/controls/DragControls.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / https://github.com/zz85
  * @author mrdoob / http://mrdoob.com
  * Running this will allow you to drag three.js objects around the screen.

+ 2 - 162
examples/js/controls/OrbitControls.js

@@ -460,32 +460,24 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleMouseDownRotate( event ) {
 
-		//console.log( 'handleMouseDownRotate' );
-
 		rotateStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseDownDolly( event ) {
 
-		//console.log( 'handleMouseDownDolly' );
-
 		dollyStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseDownPan( event ) {
 
-		//console.log( 'handleMouseDownPan' );
-
 		panStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseMoveRotate( event ) {
 
-		//console.log( 'handleMouseMoveRotate' );
-
 		rotateEnd.set( event.clientX, event.clientY );
 
 		rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
@@ -504,8 +496,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleMouseMoveDolly( event ) {
 
-		//console.log( 'handleMouseMoveDolly' );
-
 		dollyEnd.set( event.clientX, event.clientY );
 
 		dollyDelta.subVectors( dollyEnd, dollyStart );
@@ -528,8 +518,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleMouseMovePan( event ) {
 
-		//console.log( 'handleMouseMovePan' );
-
 		panEnd.set( event.clientX, event.clientY );
 
 		panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
@@ -544,14 +532,12 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleMouseUp( /*event*/ ) {
 
-		// console.log( 'handleMouseUp' );
+		// no-op
 
 	}
 
 	function handleMouseWheel( event ) {
 
-		// console.log( 'handleMouseWheel' );
-
 		if ( event.deltaY < 0 ) {
 
 			dollyOut( getZoomScale() );
@@ -568,8 +554,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleKeyDown( event ) {
 
-		// console.log( 'handleKeyDown' );
-
 		var needsUpdate = false;
 
 		switch ( event.keyCode ) {
@@ -610,8 +594,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartRotate( event ) {
 
-		//console.log( 'handleTouchStartRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -629,8 +611,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartPan( event ) {
 
-		//console.log( 'handleTouchStartPan' );
-
 		if ( event.touches.length == 1 ) {
 
 			panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -648,8 +628,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDolly( event ) {
 
-		//console.log( 'handleTouchStartDolly' );
-
 		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
 
@@ -661,8 +639,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDollyPan( event ) {
 
-		//console.log( 'handleTouchStartDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchStartDolly( event );
 
 		if ( scope.enablePan ) handleTouchStartPan( event );
@@ -671,8 +647,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDollyRotate( event ) {
 
-		//console.log( 'handleTouchStartDollyRotate' );
-
 		if ( scope.enableZoom ) handleTouchStartDolly( event );
 
 		if ( scope.enableRotate ) handleTouchStartRotate( event );
@@ -681,8 +655,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveRotate( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -710,8 +682,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMovePan( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -735,8 +705,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDolly( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
 
@@ -754,8 +722,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDollyPan( event ) {
 
-		//console.log( 'handleTouchMoveDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchMoveDolly( event );
 
 		if ( scope.enablePan ) handleTouchMovePan( event );
@@ -764,8 +730,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDollyRotate( event ) {
 
-		//console.log( 'handleTouchMoveDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchMoveDolly( event );
 
 		if ( scope.enableRotate ) handleTouchMoveRotate( event );
@@ -774,7 +738,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleTouchEnd( /*event*/ ) {
 
-		//console.log( 'handleTouchEnd' );
+		// no-op
 
 	}
 
@@ -1181,130 +1145,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
 THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
 
-Object.defineProperties( THREE.OrbitControls.prototype, {
-
-	center: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
-			return this.target;
-
-		}
-
-	},
-
-	// backward compatibility
-
-	noZoom: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
-			return ! this.enableZoom;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
-			this.enableZoom = ! value;
-
-		}
-
-	},
-
-	noRotate: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
-			return ! this.enableRotate;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
-			this.enableRotate = ! value;
-
-		}
-
-	},
-
-	noPan: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
-			return ! this.enablePan;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
-			this.enablePan = ! value;
-
-		}
-
-	},
-
-	noKeys: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
-			return ! this.enableKeys;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
-			this.enableKeys = ! value;
-
-		}
-
-	},
-
-	staticMoving: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
-			return ! this.enableDamping;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
-			this.enableDamping = ! value;
-
-		}
-
-	},
-
-	dynamicDampingFactor: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
-			return this.dampingFactor;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
-			this.dampingFactor = value;
-
-		}
-
-	}
-
-} );
 
 // This set of controls performs orbiting, dollying (zooming), and panning.
 // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).

+ 1 - 1
examples/js/controls/OrthographicTrackballControls.js

@@ -265,7 +265,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 			mouseChange.copy( _panEnd ).sub( _panStart );
 
-			if ( mouseChange.lengthSq() ) {
+			if ( mouseChange.lengthSq() > EPS ) {
 
 				// Scale movement to keep clicked/dragged position under cursor
 				var scale_x = ( _this.object.right - _this.object.left ) / _this.object.zoom;

+ 1 - 1
examples/js/curves/CurveExtras.js

@@ -1,4 +1,4 @@
-/*
+/**
  * A bunch of parametric curves
  * @author zz85
  *

+ 1 - 1
examples/js/effects/AsciiEffect.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / https://github.com/zz85
  *
  * Ascii generation is based on http://www.nihilogic.dk/labs/jsascii/

+ 1 - 1
examples/js/exporters/ColladaExporter.js

@@ -485,7 +485,7 @@ THREE.ColladaExporter.prototype = {
 
 					(
 						m.side === THREE.DoubleSide ?
-							`<extra><technique><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>` :
+							`<extra><technique profile="THREEJS"><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>` :
 							''
 					) +
 

+ 42 - 3
examples/js/exporters/GLTFExporter.js

@@ -895,7 +895,7 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
-			if ( material.isShaderMaterial ) {
+			if ( material.isShaderMaterial && !material.isGLTFSpecularGlossinessMaterial ) {
 
 				console.warn( 'GLTFExporter: THREE.ShaderMaterial not supported.' );
 				return null;
@@ -915,6 +915,12 @@ THREE.GLTFExporter.prototype = {
 
 				extensionsUsed[ 'KHR_materials_unlit' ] = true;
 
+			} else if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+				gltfMaterial.extensions = { KHR_materials_pbrSpecularGlossiness: {} };
+
+				extensionsUsed[ 'KHR_materials_pbrSpecularGlossiness' ] = true;
+
 			} else if ( ! material.isMeshStandardMaterial ) {
 
 				console.warn( 'GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.' );
@@ -947,6 +953,23 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
+			// pbrSpecularGlossiness diffuse, specular and glossiness factor
+			if ( material.isGLTFSpecularGlossinessMaterial ) {
+				
+				if ( gltfMaterial.pbrMetallicRoughness.baseColorFactor ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseFactor = gltfMaterial.pbrMetallicRoughness.baseColorFactor;
+				  
+				}
+
+				var specularFactor = [ 1, 1, 1 ];
+				material.specular.toArray( specularFactor, 0 );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularFactor = specularFactor;
+
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.glossinessFactor = material.glossiness;
+			
+			}
+
 			// pbrMetallicRoughness.metallicRoughnessTexture
 			if ( material.metalnessMap || material.roughnessMap ) {
 
@@ -964,12 +987,28 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
-			// pbrMetallicRoughness.baseColorTexture
+			// pbrMetallicRoughness.baseColorTexture or pbrSpecularGlossiness diffuseTexture
 			if ( material.map ) {
 
 				var baseColorMapDef = { index: processTexture( material.map ) };
 				applyTextureTransform( baseColorMapDef, material.map );
+
+				if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseTexture = baseColorMapDef;
+
+				}
+
 				gltfMaterial.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
+				
+			}
+
+			// pbrSpecularGlossiness specular map
+			if ( material.isGLTFSpecularGlossinessMaterial && material.specularMap ) {
+
+				var specularMapDef = { index: processTexture( material.specularMap ) };
+				applyTextureTransform( specularMapDef, material.specularMap );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularGlossinessTexture = specularMapDef;
 
 			}
 
@@ -1004,7 +1043,7 @@ THREE.GLTFExporter.prototype = {
 
 				var normalMapDef = { index: processTexture( material.normalMap ) };
 
-				if ( material.normalScale.x !== - 1 ) {
+				if ( material.normalScale && material.normalScale.x !== - 1 ) {
 
 					if ( material.normalScale.x !== material.normalScale.y ) {
 

+ 1 - 1
examples/js/geometries/ParametricGeometries.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85
  *
  * Experimenting of primitive geometry creation using Surface Parametric equations

+ 0 - 658
examples/js/libs/ctm.js

@@ -1,658 +0,0 @@
-/*
-Copyright (c) 2011 Juan Mellado
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-/*
-References:
-- "OpenCTM: The Open Compressed Triangle Mesh file format" by Marcus Geelnard
-  http://openctm.sourceforge.net/
-*/
-
-var CTM = CTM || {};
-
-// browserify support
-if ( typeof module === 'object' ) {
-
-	module.exports = CTM;
-
-}
-
-CTM.CompressionMethod = {
-  RAW: 0x00574152,
-  MG1: 0x0031474d,
-  MG2: 0x0032474d
-};
-
-CTM.Flags = {
-  NORMALS: 0x00000001
-};
-
-CTM.File = function(stream) {
-	this.load(stream);
-};
-
-CTM.File.prototype.load = function(stream) {
-	this.header = new CTM.FileHeader(stream);
-
-	this.body = new CTM.FileBody(this.header);
-
-	this.getReader().read(stream, this.body);
-};
-
-CTM.File.prototype.getReader = function() {
-	var reader;
-
-	switch (this.header.compressionMethod){
-		case CTM.CompressionMethod.RAW:
-			reader = new CTM.ReaderRAW();
-			break;
-		case CTM.CompressionMethod.MG1:
-			reader = new CTM.ReaderMG1();
-			break;
-		case CTM.CompressionMethod.MG2:
-			reader = new CTM.ReaderMG2();
-			break;
-	}
-
-	return reader;
-};
-
-CTM.FileHeader = function(stream) {
-	stream.readInt32(); //magic "OCTM"
-	this.fileFormat = stream.readInt32();
-	this.compressionMethod = stream.readInt32();
-	this.vertexCount = stream.readInt32();
-	this.triangleCount = stream.readInt32();
-	this.uvMapCount = stream.readInt32();
-	this.attrMapCount = stream.readInt32();
-	this.flags = stream.readInt32();
-	this.comment = stream.readString();
-};
-
-CTM.FileHeader.prototype.hasNormals = function() {
-	return this.flags & CTM.Flags.NORMALS;
-};
-
-CTM.FileBody = function(header) {
-	var i = header.triangleCount * 3,
-      v = header.vertexCount * 3,
-      n = header.hasNormals() ? header.vertexCount * 3 : 0,
-      u = header.vertexCount * 2,
-      a = header.vertexCount * 4,
-      j = 0;
-
-	var data = new ArrayBuffer(
-    (i + v + n + (u * header.uvMapCount) + (a * header.attrMapCount) ) * 4);
-
-	this.indices = new Uint32Array(data, 0, i);
-
-	this.vertices = new Float32Array(data, i * 4, v);
-
-	if ( header.hasNormals() ) {
-		this.normals = new Float32Array(data, (i + v) * 4, n);
-	}
-
-	if (header.uvMapCount) {
-		this.uvMaps = [];
-		for (j = 0; j < header.uvMapCount; ++ j) {
-			this.uvMaps[j] = { uv: new Float32Array(data,
-        (i + v + n + (j * u) ) * 4, u) };
-		}
-	}
-
-	if (header.attrMapCount) {
-		this.attrMaps = [];
-		for (j = 0; j < header.attrMapCount; ++ j) {
-			this.attrMaps[j] = { attr: new Float32Array(data,
-        (i + v + n + (u * header.uvMapCount) + (j * a) ) * 4, a) };
-		}
-	}
-};
-
-CTM.FileMG2Header = function(stream) {
-	stream.readInt32(); //magic "MG2H"
-	this.vertexPrecision = stream.readFloat32();
-	this.normalPrecision = stream.readFloat32();
-	this.lowerBoundx = stream.readFloat32();
-	this.lowerBoundy = stream.readFloat32();
-	this.lowerBoundz = stream.readFloat32();
-	this.higherBoundx = stream.readFloat32();
-	this.higherBoundy = stream.readFloat32();
-	this.higherBoundz = stream.readFloat32();
-	this.divx = stream.readInt32();
-	this.divy = stream.readInt32();
-	this.divz = stream.readInt32();
-
-	this.sizex = (this.higherBoundx - this.lowerBoundx) / this.divx;
-	this.sizey = (this.higherBoundy - this.lowerBoundy) / this.divy;
-	this.sizez = (this.higherBoundz - this.lowerBoundz) / this.divz;
-};
-
-CTM.ReaderRAW = function() {
-};
-
-CTM.ReaderRAW.prototype.read = function(stream, body) {
-	this.readIndices(stream, body.indices);
-	this.readVertices(stream, body.vertices);
-
-	if (body.normals) {
-		this.readNormals(stream, body.normals);
-	}
-	if (body.uvMaps) {
-		this.readUVMaps(stream, body.uvMaps);
-	}
-	if (body.attrMaps) {
-		this.readAttrMaps(stream, body.attrMaps);
-	}
-};
-
-CTM.ReaderRAW.prototype.readIndices = function(stream, indices) {
-	stream.readInt32(); //magic "INDX"
-	stream.readArrayInt32(indices);
-};
-
-CTM.ReaderRAW.prototype.readVertices = function(stream, vertices) {
-	stream.readInt32(); //magic "VERT"
-	stream.readArrayFloat32(vertices);
-};
-
-CTM.ReaderRAW.prototype.readNormals = function(stream, normals) {
-	stream.readInt32(); //magic "NORM"
-	stream.readArrayFloat32(normals);
-};
-
-CTM.ReaderRAW.prototype.readUVMaps = function(stream, uvMaps) {
-	var i = 0;
-	for (; i < uvMaps.length; ++ i) {
-		stream.readInt32(); //magic "TEXC"
-
-		uvMaps[i].name = stream.readString();
-		uvMaps[i].filename = stream.readString();
-		stream.readArrayFloat32(uvMaps[i].uv);
-	}
-};
-
-CTM.ReaderRAW.prototype.readAttrMaps = function(stream, attrMaps) {
-	var i = 0;
-	for (; i < attrMaps.length; ++ i) {
-		stream.readInt32(); //magic "ATTR"
-
-		attrMaps[i].name = stream.readString();
-		stream.readArrayFloat32(attrMaps[i].attr);
-	}
-};
-
-CTM.ReaderMG1 = function() {
-};
-
-CTM.ReaderMG1.prototype.read = function(stream, body) {
-	this.readIndices(stream, body.indices);
-	this.readVertices(stream, body.vertices);
-
-	if (body.normals) {
-		this.readNormals(stream, body.normals);
-	}
-	if (body.uvMaps) {
-		this.readUVMaps(stream, body.uvMaps);
-	}
-	if (body.attrMaps) {
-		this.readAttrMaps(stream, body.attrMaps);
-	}
-};
-
-CTM.ReaderMG1.prototype.readIndices = function(stream, indices) {
-	stream.readInt32(); //magic "INDX"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(indices, 3);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-	CTM.restoreIndices(indices, indices.length);
-};
-
-CTM.ReaderMG1.prototype.readVertices = function(stream, vertices) {
-	stream.readInt32(); //magic "VERT"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(vertices, 1);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-};
-
-CTM.ReaderMG1.prototype.readNormals = function(stream, normals) {
-	stream.readInt32(); //magic "NORM"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(normals, 3);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-};
-
-CTM.ReaderMG1.prototype.readUVMaps = function(stream, uvMaps) {
-	var i = 0;
-	for (; i < uvMaps.length; ++ i) {
-		stream.readInt32(); //magic "TEXC"
-
-		uvMaps[i].name = stream.readString();
-		uvMaps[i].filename = stream.readString();
-
-		stream.readInt32(); //packed size
-
-		var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
-		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-	}
-};
-
-CTM.ReaderMG1.prototype.readAttrMaps = function(stream, attrMaps) {
-	var i = 0;
-	for (; i < attrMaps.length; ++ i) {
-		stream.readInt32(); //magic "ATTR"
-
-		attrMaps[i].name = stream.readString();
-
-		stream.readInt32(); //packed size
-
-		var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
-		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-	}
-};
-
-CTM.ReaderMG2 = function() {
-};
-
-CTM.ReaderMG2.prototype.read = function(stream, body) {
-	this.MG2Header = new CTM.FileMG2Header(stream);
-
-	this.readVertices(stream, body.vertices);
-	this.readIndices(stream, body.indices);
-
-	if (body.normals) {
-		this.readNormals(stream, body);
-	}
-	if (body.uvMaps) {
-		this.readUVMaps(stream, body.uvMaps);
-	}
-	if (body.attrMaps) {
-		this.readAttrMaps(stream, body.attrMaps);
-	}
-};
-
-CTM.ReaderMG2.prototype.readVertices = function(stream, vertices) {
-	stream.readInt32(); //magic "VERT"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(vertices, 3);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-	var gridIndices = this.readGridIndices(stream, vertices);
-
-	CTM.restoreVertices(vertices, this.MG2Header, gridIndices, this.MG2Header.vertexPrecision);
-};
-
-CTM.ReaderMG2.prototype.readGridIndices = function(stream, vertices) {
-	stream.readInt32(); //magic "GIDX"
-	stream.readInt32(); //packed size
-
-	var gridIndices = new Uint32Array(vertices.length / 3);
-
-	var interleaved = new CTM.InterleavedStream(gridIndices, 1);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-	CTM.restoreGridIndices(gridIndices, gridIndices.length);
-
-	return gridIndices;
-};
-
-CTM.ReaderMG2.prototype.readIndices = function(stream, indices) {
-	stream.readInt32(); //magic "INDX"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(indices, 3);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-	CTM.restoreIndices(indices, indices.length);
-};
-
-CTM.ReaderMG2.prototype.readNormals = function(stream, body) {
-	stream.readInt32(); //magic "NORM"
-	stream.readInt32(); //packed size
-
-	var interleaved = new CTM.InterleavedStream(body.normals, 3);
-	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-	var smooth = CTM.calcSmoothNormals(body.indices, body.vertices);
-
-	CTM.restoreNormals(body.normals, smooth, this.MG2Header.normalPrecision);
-};
-
-CTM.ReaderMG2.prototype.readUVMaps = function(stream, uvMaps) {
-	var i = 0;
-	for (; i < uvMaps.length; ++ i) {
-		stream.readInt32(); //magic "TEXC"
-
-		uvMaps[i].name = stream.readString();
-		uvMaps[i].filename = stream.readString();
-
-		var precision = stream.readFloat32();
-
-		stream.readInt32(); //packed size
-
-		var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
-		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-		CTM.restoreMap(uvMaps[i].uv, 2, precision);
-	}
-};
-
-CTM.ReaderMG2.prototype.readAttrMaps = function(stream, attrMaps) {
-	var i = 0;
-	for (; i < attrMaps.length; ++ i) {
-		stream.readInt32(); //magic "ATTR"
-
-		attrMaps[i].name = stream.readString();
-
-		var precision = stream.readFloat32();
-
-		stream.readInt32(); //packed size
-
-		var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
-		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
-
-		CTM.restoreMap(attrMaps[i].attr, 4, precision);
-	}
-};
-
-CTM.restoreIndices = function(indices, len) {
-	var i = 3;
-	if (len > 0) {
-		indices[2] += indices[0];
-		indices[1] += indices[0];
-	}
-	for (; i < len; i += 3) {
-		indices[i] += indices[i - 3];
-
-		if (indices[i] === indices[i - 3]) {
-			indices[i + 1] += indices[i - 2];
-		}else {
-			indices[i + 1] += indices[i];
-		}
-
-		indices[i + 2] += indices[i];
-	}
-};
-
-CTM.restoreGridIndices = function(gridIndices, len) {
-	var i = 1;
-	for (; i < len; ++ i) {
-		gridIndices[i] += gridIndices[i - 1];
-	}
-};
-
-CTM.restoreVertices = function(vertices, grid, gridIndices, precision) {
-	var gridIdx, delta, x, y, z,
-      intVertices = new Uint32Array(vertices.buffer, vertices.byteOffset, vertices.length),
-      ydiv = grid.divx, zdiv = ydiv * grid.divy,
-      prevGridIdx = 0x7fffffff, prevDelta = 0,
-      i = 0, j = 0, len = gridIndices.length;
-
-	for (; i < len; j += 3) {
-		x = gridIdx = gridIndices[i ++];
-
-		z = ~~(x / zdiv);
-		x -= ~~(z * zdiv);
-		y = ~~(x / ydiv);
-		x -= ~~(y * ydiv);
-
-		delta = intVertices[j];
-		if (gridIdx === prevGridIdx) {
-			delta += prevDelta;
-		}
-
-		vertices[j]     = grid.lowerBoundx +
-      x * grid.sizex + precision * delta;
-		vertices[j + 1] = grid.lowerBoundy +
-      y * grid.sizey + precision * intVertices[j + 1];
-		vertices[j + 2] = grid.lowerBoundz +
-      z * grid.sizez + precision * intVertices[j + 2];
-
-		prevGridIdx = gridIdx;
-		prevDelta = delta;
-	}
-};
-
-CTM.restoreNormals = function(normals, smooth, precision) {
-	var ro, phi, theta, sinPhi,
-      nx, ny, nz, by, bz, len,
-      intNormals = new Uint32Array(normals.buffer, normals.byteOffset, normals.length),
-      i = 0, k = normals.length,
-      PI_DIV_2 = 3.141592653589793238462643 * 0.5;
-
-	for (; i < k; i += 3) {
-		ro = intNormals[i] * precision;
-		phi = intNormals[i + 1];
-
-		if (phi === 0) {
-			normals[i]     = smooth[i]     * ro;
-			normals[i + 1] = smooth[i + 1] * ro;
-			normals[i + 2] = smooth[i + 2] * ro;
-		}else {
-
-			if (phi <= 4) {
-				theta = (intNormals[i + 2] - 2) * PI_DIV_2;
-			}else {
-				theta = ( (intNormals[i + 2] * 4 / phi) - 2) * PI_DIV_2;
-			}
-
-			phi *= precision * PI_DIV_2;
-			sinPhi = ro * Math.sin(phi);
-
-			nx = sinPhi * Math.cos(theta);
-			ny = sinPhi * Math.sin(theta);
-			nz = ro * Math.cos(phi);
-
-			bz = smooth[i + 1];
-			by = smooth[i] - smooth[i + 2];
-
-			len = Math.sqrt(2 * bz * bz + by * by);
-			if (len > 1e-20) {
-				by /= len;
-				bz /= len;
-			}
-
-			normals[i] = smooth[i] * nz + (smooth[i + 1] * bz - smooth[i + 2] * by) * ny - bz * nx;
-			normals[i + 1] = smooth[i + 1] * nz - (smooth[i + 2] + smooth[i]) * bz  * ny + by * nx;
-			normals[i + 2] = smooth[i + 2] * nz + (smooth[i] * by + smooth[i + 1] * bz) * ny + bz * nx;
-		}
-	}
-};
-
-CTM.restoreMap = function(map, count, precision) {
-	var delta, value,
-      intMap = new Uint32Array(map.buffer, map.byteOffset, map.length),
-      i = 0, j, len = map.length;
-
-	for (; i < count; ++ i) {
-		delta = 0;
-
-		for (j = i; j < len; j += count) {
-			value = intMap[j];
-
-			delta += value & 1 ? -( (value + 1) >> 1) : value >> 1;
-
-			map[j] = delta * precision;
-		}
-	}
-};
-
-CTM.calcSmoothNormals = function(indices, vertices) {
-	var smooth = new Float32Array(vertices.length),
-      indx, indy, indz, nx, ny, nz,
-      v1x, v1y, v1z, v2x, v2y, v2z, len,
-      i, k;
-
-	for (i = 0, k = indices.length; i < k;) {
-		indx = indices[i ++] * 3;
-		indy = indices[i ++] * 3;
-		indz = indices[i ++] * 3;
-
-		v1x = vertices[indy]     - vertices[indx];
-		v2x = vertices[indz]     - vertices[indx];
-		v1y = vertices[indy + 1] - vertices[indx + 1];
-		v2y = vertices[indz + 1] - vertices[indx + 1];
-		v1z = vertices[indy + 2] - vertices[indx + 2];
-		v2z = vertices[indz + 2] - vertices[indx + 2];
-
-		nx = v1y * v2z - v1z * v2y;
-		ny = v1z * v2x - v1x * v2z;
-		nz = v1x * v2y - v1y * v2x;
-
-		len = Math.sqrt(nx * nx + ny * ny + nz * nz);
-		if (len > 1e-10) {
-			nx /= len;
-			ny /= len;
-			nz /= len;
-		}
-
-		smooth[indx]     += nx;
-		smooth[indx + 1] += ny;
-		smooth[indx + 2] += nz;
-		smooth[indy]     += nx;
-		smooth[indy + 1] += ny;
-		smooth[indy + 2] += nz;
-		smooth[indz]     += nx;
-		smooth[indz + 1] += ny;
-		smooth[indz + 2] += nz;
-	}
-
-	for (i = 0, k = smooth.length; i < k; i += 3) {
-		len = Math.sqrt(smooth[i] * smooth[i] +
-      smooth[i + 1] * smooth[i + 1] +
-      smooth[i + 2] * smooth[i + 2]);
-
-		if (len > 1e-10) {
-			smooth[i]     /= len;
-			smooth[i + 1] /= len;
-			smooth[i + 2] /= len;
-		}
-	}
-
-	return smooth;
-};
-
-CTM.isLittleEndian = (function() {
-	var buffer = new ArrayBuffer(2),
-      bytes = new Uint8Array(buffer),
-      ints = new Uint16Array(buffer);
-
-	bytes[0] = 1;
-
-	return ints[0] === 1;
-}());
-
-CTM.InterleavedStream = function(data, count) {
-	this.data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
-	this.offset = CTM.isLittleEndian ? 3 : 0;
-	this.count = count * 4;
-	this.len = this.data.length;
-};
-
-CTM.InterleavedStream.prototype.writeByte = function(value) {
-	this.data[this.offset] = value;
-
-	this.offset += this.count;
-	if (this.offset >= this.len) {
-
-		this.offset -= this.len - 4;
-		if (this.offset >= this.count) {
-
-			this.offset -= this.count + (CTM.isLittleEndian ? 1 : -1);
-		}
-	}
-};
-
-CTM.Stream = function(data) {
-	this.data = data;
-	this.offset = 0;
-};
-
-CTM.Stream.prototype.TWO_POW_MINUS23 = Math.pow(2, -23);
-
-CTM.Stream.prototype.TWO_POW_MINUS126 = Math.pow(2, -126);
-
-CTM.Stream.prototype.readByte = function() {
-	return this.data[this.offset ++] & 0xff;
-};
-
-CTM.Stream.prototype.readInt32 = function() {
-	var i = this.readByte();
-	i |= this.readByte() << 8;
-	i |= this.readByte() << 16;
-	return i | (this.readByte() << 24);
-};
-
-CTM.Stream.prototype.readFloat32 = function() {
-	var m = this.readByte();
-	m += this.readByte() << 8;
-
-	var b1 = this.readByte();
-	var b2 = this.readByte();
-
-	m += (b1 & 0x7f) << 16;
-	var e = ( (b2 & 0x7f) << 1) | ( (b1 & 0x80) >>> 7);
-	var s = b2 & 0x80 ? -1 : 1;
-
-	if (e === 255) {
-		return m !== 0 ? NaN : s * Infinity;
-	}
-	if (e > 0) {
-		return s * (1 + (m * this.TWO_POW_MINUS23) ) * Math.pow(2, e - 127);
-	}
-	if (m !== 0) {
-		return s * m * this.TWO_POW_MINUS126;
-	}
-	return s * 0;
-};
-
-CTM.Stream.prototype.readString = function() {
-	var len = this.readInt32();
-
-	this.offset += len;
-
-	return String.fromCharCode.apply(null, this.data.subarray(this.offset - len, this.offset));
-};
-
-CTM.Stream.prototype.readArrayInt32 = function(array) {
-	var i = 0, len = array.length;
-
-	while (i < len) {
-		array[i ++] = this.readInt32();
-	}
-
-	return array;
-};
-
-CTM.Stream.prototype.readArrayFloat32 = function(array) {
-	var i = 0, len = array.length;
-
-	while (i < len) {
-		array[i ++] = this.readFloat32();
-	}
-
-	return array;
-};

+ 0 - 517
examples/js/libs/lzma.js

@@ -1,517 +0,0 @@
-
-var LZMA = LZMA || {};
-
-// browserify support
-if ( typeof module === 'object' ) {
-
-	module.exports = LZMA;
-
-}
-
-LZMA.OutWindow = function() {
-	this._windowSize = 0;
-};
-
-LZMA.OutWindow.prototype.create = function(windowSize) {
-	if ( (!this._buffer) || (this._windowSize !== windowSize) ) {
-		this._buffer = [];
-	}
-	this._windowSize = windowSize;
-	this._pos = 0;
-	this._streamPos = 0;
-};
-
-LZMA.OutWindow.prototype.flush = function() {
-	var size = this._pos - this._streamPos;
-	if (size !== 0) {
-		while (size --) {
-			this._stream.writeByte(this._buffer[this._streamPos ++]);
-		}
-		if (this._pos >= this._windowSize) {
-			this._pos = 0;
-		}
-		this._streamPos = this._pos;
-	}
-};
-
-LZMA.OutWindow.prototype.releaseStream = function() {
-	this.flush();
-	this._stream = null;
-};
-
-LZMA.OutWindow.prototype.setStream = function(stream) {
-	this.releaseStream();
-	this._stream = stream;
-};
-
-LZMA.OutWindow.prototype.init = function(solid) {
-	if (!solid) {
-		this._streamPos = 0;
-		this._pos = 0;
-	}
-};
-
-LZMA.OutWindow.prototype.copyBlock = function(distance, len) {
-	var pos = this._pos - distance - 1;
-	if (pos < 0) {
-		pos += this._windowSize;
-	}
-	while (len --) {
-		if (pos >= this._windowSize) {
-			pos = 0;
-		}
-		this._buffer[this._pos ++] = this._buffer[pos ++];
-		if (this._pos >= this._windowSize) {
-			this.flush();
-		}
-	}
-};
-
-LZMA.OutWindow.prototype.putByte = function(b) {
-	this._buffer[this._pos ++] = b;
-	if (this._pos >= this._windowSize) {
-		this.flush();
-	}
-};
-
-LZMA.OutWindow.prototype.getByte = function(distance) {
-	var pos = this._pos - distance - 1;
-	if (pos < 0) {
-		pos += this._windowSize;
-	}
-	return this._buffer[pos];
-};
-
-LZMA.RangeDecoder = function() {
-};
-
-LZMA.RangeDecoder.prototype.setStream = function(stream) {
-	this._stream = stream;
-};
-
-LZMA.RangeDecoder.prototype.releaseStream = function() {
-	this._stream = null;
-};
-
-LZMA.RangeDecoder.prototype.init = function() {
-	var i = 5;
-
-	this._code = 0;
-	this._range = -1;
-
-	while (i --) {
-		this._code = (this._code << 8) | this._stream.readByte();
-	}
-};
-
-LZMA.RangeDecoder.prototype.decodeDirectBits = function(numTotalBits) {
-	var result = 0, i = numTotalBits, t;
-
-	while (i --) {
-		this._range >>>= 1;
-		t = (this._code - this._range) >>> 31;
-		this._code -= this._range & (t - 1);
-		result = (result << 1) | (1 - t);
-
-		if ( (this._range & 0xff000000) === 0) {
-			this._code = (this._code << 8) | this._stream.readByte();
-			this._range <<= 8;
-		}
-	}
-
-	return result;
-};
-
-LZMA.RangeDecoder.prototype.decodeBit = function(probs, index) {
-	var prob = probs[index],
-      newBound = (this._range >>> 11) * prob;
-
-	if ( (this._code ^ 0x80000000) < (newBound ^ 0x80000000) ) {
-		this._range = newBound;
-		probs[index] += (2048 - prob) >>> 5;
-		if ( (this._range & 0xff000000) === 0) {
-			this._code = (this._code << 8) | this._stream.readByte();
-			this._range <<= 8;
-		}
-		return 0;
-	}
-
-	this._range -= newBound;
-	this._code -= newBound;
-	probs[index] -= prob >>> 5;
-	if ( (this._range & 0xff000000) === 0) {
-		this._code = (this._code << 8) | this._stream.readByte();
-		this._range <<= 8;
-	}
-	return 1;
-};
-
-LZMA.initBitModels = function(probs, len) {
-	while (len --) {
-		probs[len] = 1024;
-	}
-};
-
-LZMA.BitTreeDecoder = function(numBitLevels) {
-	this._models = [];
-	this._numBitLevels = numBitLevels;
-};
-
-LZMA.BitTreeDecoder.prototype.init = function() {
-	LZMA.initBitModels(this._models, 1 << this._numBitLevels);
-};
-
-LZMA.BitTreeDecoder.prototype.decode = function(rangeDecoder) {
-	var m = 1, i = this._numBitLevels;
-
-	while (i --) {
-		m = (m << 1) | rangeDecoder.decodeBit(this._models, m);
-	}
-	return m - (1 << this._numBitLevels);
-};
-
-LZMA.BitTreeDecoder.prototype.reverseDecode = function(rangeDecoder) {
-	var m = 1, symbol = 0, i = 0, bit;
-
-	for (; i < this._numBitLevels; ++ i) {
-		bit = rangeDecoder.decodeBit(this._models, m);
-		m = (m << 1) | bit;
-		symbol |= bit << i;
-	}
-	return symbol;
-};
-
-LZMA.reverseDecode2 = function(models, startIndex, rangeDecoder, numBitLevels) {
-	var m = 1, symbol = 0, i = 0, bit;
-
-	for (; i < numBitLevels; ++ i) {
-		bit = rangeDecoder.decodeBit(models, startIndex + m);
-		m = (m << 1) | bit;
-		symbol |= bit << i;
-	}
-	return symbol;
-};
-
-LZMA.LenDecoder = function() {
-	this._choice = [];
-	this._lowCoder = [];
-	this._midCoder = [];
-	this._highCoder = new LZMA.BitTreeDecoder(8);
-	this._numPosStates = 0;
-};
-
-LZMA.LenDecoder.prototype.create = function(numPosStates) {
-	for (; this._numPosStates < numPosStates; ++ this._numPosStates) {
-		this._lowCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
-		this._midCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
-	}
-};
-
-LZMA.LenDecoder.prototype.init = function() {
-	var i = this._numPosStates;
-	LZMA.initBitModels(this._choice, 2);
-	while (i --) {
-		this._lowCoder[i].init();
-		this._midCoder[i].init();
-	}
-	this._highCoder.init();
-};
-
-LZMA.LenDecoder.prototype.decode = function(rangeDecoder, posState) {
-	if (rangeDecoder.decodeBit(this._choice, 0) === 0) {
-		return this._lowCoder[posState].decode(rangeDecoder);
-	}
-	if (rangeDecoder.decodeBit(this._choice, 1) === 0) {
-		return 8 + this._midCoder[posState].decode(rangeDecoder);
-	}
-	return 16 + this._highCoder.decode(rangeDecoder);
-};
-
-LZMA.Decoder2 = function() {
-	this._decoders = [];
-};
-
-LZMA.Decoder2.prototype.init = function() {
-	LZMA.initBitModels(this._decoders, 0x300);
-};
-
-LZMA.Decoder2.prototype.decodeNormal = function(rangeDecoder) {
-	var symbol = 1;
-
-	do {
-		symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
-	}while (symbol < 0x100);
-
-	return symbol & 0xff;
-};
-
-LZMA.Decoder2.prototype.decodeWithMatchByte = function(rangeDecoder, matchByte) {
-	var symbol = 1, matchBit, bit;
-
-	do {
-		matchBit = (matchByte >> 7) & 1;
-		matchByte <<= 1;
-		bit = rangeDecoder.decodeBit(this._decoders, ( (1 + matchBit) << 8) + symbol);
-		symbol = (symbol << 1) | bit;
-		if (matchBit !== bit) {
-			while (symbol < 0x100) {
-				symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
-			}
-			break;
-		}
-	}while (symbol < 0x100);
-
-	return symbol & 0xff;
-};
-
-LZMA.LiteralDecoder = function() {
-};
-
-LZMA.LiteralDecoder.prototype.create = function(numPosBits, numPrevBits) {
-	var i;
-
-	if (this._coders
-    && (this._numPrevBits === numPrevBits)
-    && (this._numPosBits === numPosBits) ) {
-		return;
-	}
-	this._numPosBits = numPosBits;
-	this._posMask = (1 << numPosBits) - 1;
-	this._numPrevBits = numPrevBits;
-
-	this._coders = [];
-
-	i = 1 << (this._numPrevBits + this._numPosBits);
-	while (i --) {
-		this._coders[i] = new LZMA.Decoder2();
-	}
-};
-
-LZMA.LiteralDecoder.prototype.init = function() {
-	var i = 1 << (this._numPrevBits + this._numPosBits);
-	while (i --) {
-		this._coders[i].init();
-	}
-};
-
-LZMA.LiteralDecoder.prototype.getDecoder = function(pos, prevByte) {
-	return this._coders[( (pos & this._posMask) << this._numPrevBits)
-    + ( (prevByte & 0xff) >>> (8 - this._numPrevBits) )];
-};
-
-LZMA.Decoder = function() {
-	this._outWindow = new LZMA.OutWindow();
-	this._rangeDecoder = new LZMA.RangeDecoder();
-	this._isMatchDecoders = [];
-	this._isRepDecoders = [];
-	this._isRepG0Decoders = [];
-	this._isRepG1Decoders = [];
-	this._isRepG2Decoders = [];
-	this._isRep0LongDecoders = [];
-	this._posSlotDecoder = [];
-	this._posDecoders = [];
-	this._posAlignDecoder = new LZMA.BitTreeDecoder(4);
-	this._lenDecoder = new LZMA.LenDecoder();
-	this._repLenDecoder = new LZMA.LenDecoder();
-	this._literalDecoder = new LZMA.LiteralDecoder();
-	this._dictionarySize = -1;
-	this._dictionarySizeCheck = -1;
-
-	this._posSlotDecoder[0] = new LZMA.BitTreeDecoder(6);
-	this._posSlotDecoder[1] = new LZMA.BitTreeDecoder(6);
-	this._posSlotDecoder[2] = new LZMA.BitTreeDecoder(6);
-	this._posSlotDecoder[3] = new LZMA.BitTreeDecoder(6);
-};
-
-LZMA.Decoder.prototype.setDictionarySize = function(dictionarySize) {
-	if (dictionarySize < 0) {
-		return false;
-	}
-	if (this._dictionarySize !== dictionarySize) {
-		this._dictionarySize = dictionarySize;
-		this._dictionarySizeCheck = Math.max(this._dictionarySize, 1);
-		this._outWindow.create( Math.max(this._dictionarySizeCheck, 4096) );
-	}
-	return true;
-};
-
-LZMA.Decoder.prototype.setLcLpPb = function(lc, lp, pb) {
-	var numPosStates = 1 << pb;
-
-	if (lc > 8 || lp > 4 || pb > 4) {
-		return false;
-	}
-
-	this._literalDecoder.create(lp, lc);
-
-	this._lenDecoder.create(numPosStates);
-	this._repLenDecoder.create(numPosStates);
-	this._posStateMask = numPosStates - 1;
-
-	return true;
-};
-
-LZMA.Decoder.prototype.init = function() {
-	var i = 4;
-
-	this._outWindow.init(false);
-
-	LZMA.initBitModels(this._isMatchDecoders, 192);
-	LZMA.initBitModels(this._isRep0LongDecoders, 192);
-	LZMA.initBitModels(this._isRepDecoders, 12);
-	LZMA.initBitModels(this._isRepG0Decoders, 12);
-	LZMA.initBitModels(this._isRepG1Decoders, 12);
-	LZMA.initBitModels(this._isRepG2Decoders, 12);
-	LZMA.initBitModels(this._posDecoders, 114);
-
-	this._literalDecoder.init();
-
-	while (i --) {
-		this._posSlotDecoder[i].init();
-	}
-
-	this._lenDecoder.init();
-	this._repLenDecoder.init();
-	this._posAlignDecoder.init();
-	this._rangeDecoder.init();
-};
-
-LZMA.Decoder.prototype.decode = function(inStream, outStream, outSize) {
-	var state = 0, rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0, nowPos64 = 0, prevByte = 0,
-      posState, decoder2, len, distance, posSlot, numDirectBits;
-
-	this._rangeDecoder.setStream(inStream);
-	this._outWindow.setStream(outStream);
-
-	this.init();
-
-	while (outSize < 0 || nowPos64 < outSize) {
-		posState = nowPos64 & this._posStateMask;
-
-		if (this._rangeDecoder.decodeBit(this._isMatchDecoders, (state << 4) + posState) === 0) {
-			decoder2 = this._literalDecoder.getDecoder(nowPos64 ++, prevByte);
-
-			if (state >= 7) {
-				prevByte = decoder2.decodeWithMatchByte(this._rangeDecoder, this._outWindow.getByte(rep0) );
-			}else {
-				prevByte = decoder2.decodeNormal(this._rangeDecoder);
-			}
-			this._outWindow.putByte(prevByte);
-
-			state = state < 4 ? 0 : state - (state < 10 ? 3 : 6);
-
-		}else {
-
-			if (this._rangeDecoder.decodeBit(this._isRepDecoders, state) === 1) {
-				len = 0;
-				if (this._rangeDecoder.decodeBit(this._isRepG0Decoders, state) === 0) {
-					if (this._rangeDecoder.decodeBit(this._isRep0LongDecoders, (state << 4) + posState) === 0) {
-						state = state < 7 ? 9 : 11;
-						len = 1;
-					}
-				}else {
-					if (this._rangeDecoder.decodeBit(this._isRepG1Decoders, state) === 0) {
-						distance = rep1;
-					}else {
-						if (this._rangeDecoder.decodeBit(this._isRepG2Decoders, state) === 0) {
-							distance = rep2;
-						}else {
-							distance = rep3;
-							rep3 = rep2;
-						}
-						rep2 = rep1;
-					}
-					rep1 = rep0;
-					rep0 = distance;
-				}
-				if (len === 0) {
-					len = 2 + this._repLenDecoder.decode(this._rangeDecoder, posState);
-					state = state < 7 ? 8 : 11;
-				}
-			}else {
-				rep3 = rep2;
-				rep2 = rep1;
-				rep1 = rep0;
-
-				len = 2 + this._lenDecoder.decode(this._rangeDecoder, posState);
-				state = state < 7 ? 7 : 10;
-
-				posSlot = this._posSlotDecoder[len <= 5 ? len - 2 : 3].decode(this._rangeDecoder);
-				if (posSlot >= 4) {
-
-					numDirectBits = (posSlot >> 1) - 1;
-					rep0 = (2 | (posSlot & 1) ) << numDirectBits;
-
-					if (posSlot < 14) {
-						rep0 += LZMA.reverseDecode2(this._posDecoders,
-                rep0 - posSlot - 1, this._rangeDecoder, numDirectBits);
-					}else {
-						rep0 += this._rangeDecoder.decodeDirectBits(numDirectBits - 4) << 4;
-						rep0 += this._posAlignDecoder.reverseDecode(this._rangeDecoder);
-						if (rep0 < 0) {
-							if (rep0 === -1) {
-								break;
-							}
-							return false;
-						}
-					}
-				}else {
-					rep0 = posSlot;
-				}
-			}
-
-			if (rep0 >= nowPos64 || rep0 >= this._dictionarySizeCheck) {
-				return false;
-			}
-
-			this._outWindow.copyBlock(rep0, len);
-			nowPos64 += len;
-			prevByte = this._outWindow.getByte(0);
-		}
-	}
-
-	this._outWindow.flush();
-	this._outWindow.releaseStream();
-	this._rangeDecoder.releaseStream();
-
-	return true;
-};
-
-LZMA.Decoder.prototype.setDecoderProperties = function(properties) {
-	var value, lc, lp, pb, dictionarySize;
-
-	if (properties.size < 5) {
-		return false;
-	}
-
-	value = properties.readByte();
-	lc = value % 9;
-	value = ~~(value / 9);
-	lp = value % 5;
-	pb = ~~(value / 5);
-
-	if ( !this.setLcLpPb(lc, lp, pb) ) {
-		return false;
-	}
-
-	dictionarySize = properties.readByte();
-	dictionarySize |= properties.readByte() << 8;
-	dictionarySize |= properties.readByte() << 16;
-	dictionarySize += properties.readByte() * 16777216;
-
-	return this.setDictionarySize(dictionarySize);
-};
-
-LZMA.decompress = function(properties, inStream, outStream, outSize) {
-	var decoder = new LZMA.Decoder();
-
-	if ( !decoder.setDecoderProperties(properties) ) {
-		throw "Incorrect stream properties";
-	}
-
-	if ( !decoder.decode(inStream, outStream, outSize) ) {
-		throw "Error in data stream";
-	}
-
-	return true;
-};

+ 1 - 1
examples/js/loaders/AMFLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author tamarintech / https://tamarintech.com
  *
  * Description: Early release of an AMF Loader following the pattern of the

+ 1 - 1
examples/js/loaders/DDSLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author mrdoob / http://mrdoob.com/
  */
 

+ 95 - 35
examples/js/loaders/STLLoader.js

@@ -3,6 +3,7 @@
  * @author mrdoob / http://mrdoob.com/
  * @author gero3 / https://github.com/gero3
  * @author Mugen87 / https://github.com/Mugen87
+ * @author neverhood311 / https://github.com/neverhood311
  *
  * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
  *
@@ -27,6 +28,31 @@
  *    material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors });
  *  } else { .... }
  *  var mesh = new THREE.Mesh( geometry, material );
+ *
+ * For ASCII STLs containing multiple solids, each solid is assigned to a different group.
+ * Groups can be used to assign a different color by defining an array of materials with the same length of
+ * geometry.groups and passing it to the Mesh constructor:
+ *
+ * var mesh = new THREE.Mesh( geometry, material );
+ *
+ * For example:
+ *
+ *  var materials = [];
+ *  var nGeometryGroups = geometry.groups.length;
+ *
+ *  var colorMap = ...; // Some logic to index colors.
+ *
+ *  for (var i = 0; i < nGeometryGroups; i++) {
+ *
+ *		var material = new THREE.MeshPhongMaterial({
+ *			color: colorMap[i],
+ *			wireframe: false
+ *		});
+ *
+ *  }
+ *
+ *  materials.push(material);
+ *  var mesh = new THREE.Mesh(geometry, materials);
  */
 
 
@@ -106,7 +132,7 @@ THREE.STLLoader.prototype = {
 
 				// If "solid" text is matched to the current offset, declare it to be an ASCII STL.
 
-				if ( matchDataViewAt ( solid, reader, off ) ) return false;
+				if ( matchDataViewAt( solid, reader, off ) ) return false;
 
 			}
 
@@ -148,7 +174,7 @@ THREE.STLLoader.prototype = {
 					( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
 
 					hasColors = true;
-					colors = [];
+					colors = new Float32Array( faces * 3 * 3 );
 
 					defaultR = reader.getUint8( index + 6 ) / 255;
 					defaultG = reader.getUint8( index + 7 ) / 255;
@@ -164,8 +190,8 @@ THREE.STLLoader.prototype = {
 
 			var geometry = new THREE.BufferGeometry();
 
-			var vertices = [];
-			var normals = [];
+			var vertices = new Float32Array( faces * 3 * 3 );
+			var normals = new Float32Array( faces * 3 * 3 );
 
 			for ( var face = 0; face < faces; face ++ ) {
 
@@ -199,16 +225,21 @@ THREE.STLLoader.prototype = {
 				for ( var i = 1; i <= 3; i ++ ) {
 
 					var vertexstart = start + i * 12;
+					var componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 );
 
-					vertices.push( reader.getFloat32( vertexstart, true ) );
-					vertices.push( reader.getFloat32( vertexstart + 4, true ) );
-					vertices.push( reader.getFloat32( vertexstart + 8, true ) );
+					vertices[ componentIdx ] = reader.getFloat32( vertexstart, true );
+					vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true );
+					vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true );
 
-					normals.push( normalX, normalY, normalZ );
+					normals[ componentIdx ] = normalX;
+					normals[ componentIdx + 1 ] = normalY;
+					normals[ componentIdx + 2 ] = normalZ;
 
 					if ( hasColors ) {
 
-						colors.push( r, g, b );
+						colors[ componentIdx ] = r;
+						colors[ componentIdx + 1 ] = g;
+						colors[ componentIdx + 2 ] = b;
 
 					}
 
@@ -216,12 +247,12 @@ THREE.STLLoader.prototype = {
 
 			}
 
-			geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
-			geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
+			geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
+			geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
 
 			if ( hasColors ) {
 
-				geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+				geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
 				geometry.hasColors = true;
 				geometry.alpha = alpha;
 
@@ -234,6 +265,7 @@ THREE.STLLoader.prototype = {
 		function parseASCII( data ) {
 
 			var geometry = new THREE.BufferGeometry();
+			var patternSolid = /solid([\s\S]*?)endsolid/g;
 			var patternFace = /facet([\s\S]*?)endfacet/g;
 			var faceCounter = 0;
 
@@ -248,53 +280,80 @@ THREE.STLLoader.prototype = {
 
 			var result;
 
-			while ( ( result = patternFace.exec( data ) ) !== null ) {
+			var groupVertexes = [];
+			var groupCount = 0;
+			var startVertex = 0;
+			var endVertex = 0;
 
-				var vertexCountPerFace = 0;
-				var normalCountPerFace = 0;
+			while ( ( result = patternSolid.exec( data ) ) !== null ) {
 
-				var text = result[ 0 ];
+				startVertex = endVertex;
 
-				while ( ( result = patternNormal.exec( text ) ) !== null ) {
+				var solid = result[ 0 ];
 
-					normal.x = parseFloat( result[ 1 ] );
-					normal.y = parseFloat( result[ 2 ] );
-					normal.z = parseFloat( result[ 3 ] );
-					normalCountPerFace ++;
+				while ( ( result = patternFace.exec( solid ) ) !== null ) {
 
-				}
+					var vertexCountPerFace = 0;
+					var normalCountPerFace = 0;
 
-				while ( ( result = patternVertex.exec( text ) ) !== null ) {
+					var text = result[ 0 ];
 
-					vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
-					normals.push( normal.x, normal.y, normal.z );
-					vertexCountPerFace ++;
+					while ( ( result = patternNormal.exec( text ) ) !== null ) {
 
-				}
+						normal.x = parseFloat( result[ 1 ] );
+						normal.y = parseFloat( result[ 2 ] );
+						normal.z = parseFloat( result[ 3 ] );
+						normalCountPerFace ++;
 
-				// every face have to own ONE valid normal
+					}
 
-				if ( normalCountPerFace !== 1 ) {
+					while ( ( result = patternVertex.exec( text ) ) !== null ) {
 
-					console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
+						vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
+						normals.push( normal.x, normal.y, normal.z );
+						vertexCountPerFace ++;
+						endVertex ++;
 
-				}
+					}
 
-				// each face have to own THREE valid vertices
+					// every face have to own ONE valid normal
 
-				if ( vertexCountPerFace !== 3 ) {
+					if ( normalCountPerFace !== 1 ) {
 
-					console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
+						console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
+
+					}
+
+					// each face have to own THREE valid vertices
+
+					if ( vertexCountPerFace !== 3 ) {
+
+						console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
+
+					}
+
+					faceCounter ++;
 
 				}
 
-				faceCounter ++;
+				groupVertexes.push( { startVertex: startVertex, endVertex: endVertex } );
+				groupCount ++;
 
 			}
 
 			geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
 			geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
 
+			if ( groupCount > 0 ) {
+
+				for ( var i = 0; i < groupVertexes.length; i ++ ) {
+
+					geometry.addGroup( groupVertexes[ i ].startVertex, groupVertexes[ i ].endVertex, i );
+
+				}
+
+			}
+
 			return geometry;
 
 		}
@@ -321,6 +380,7 @@ THREE.STLLoader.prototype = {
 					array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
 
 				}
+
 				return array_buffer.buffer || array_buffer;
 
 			} else {

+ 1 - 1
examples/js/loaders/TDSLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * Autodesk 3DS three.js file loader, based on lib3ds.
  *
  * Loads geometry with uv and materials basic properties with texture support.

+ 1 - 1
examples/js/loaders/TGALoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author Daosheng Mu / https://github.com/DaoshengMu/
  * @author mrdoob / http://mrdoob.com/
  * @author takahirox / https://github.com/takahirox/

+ 0 - 279
examples/js/loaders/ctm/CTMLoader.js

@@ -1,279 +0,0 @@
-/**
- * Loader for CTM encoded models generated by OpenCTM tools:
- *	http://openctm.sourceforge.net/
- *
- * Uses js-openctm library by Juan Mellado
- *	http://code.google.com/p/js-openctm/
- *
- * @author alteredq / http://alteredqualia.com/
- *
- * OpenCTM LICENSE:
- *
- * Copyright (c) 2009-2010 Marcus Geelnard
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- *     1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- *
- *    2. Altered source versions must be plainly marked as such, and must not
- *    be misrepresented as being the original software.
- *
- *    3. This notice may not be removed or altered from any source
- *    distribution.
- *
- */
-
-/* global CTM */
-
-THREE.CTMLoader = function () {
-
-	this.workerPath = null;
-
-};
-
-THREE.CTMLoader.prototype.constructor = THREE.CTMLoader;
-
-THREE.CTMLoader.prototype.setWorkerPath = function ( workerPath ) {
-
-	this.workerPath = workerPath;
-
-};
-
-// Load multiple CTM parts defined in JSON
-
-THREE.CTMLoader.prototype.loadParts = function ( url, callback, parameters ) {
-
-	parameters = parameters || {};
-
-	var scope = this;
-
-	var xhr = new XMLHttpRequest();
-
-	var basePath = parameters.basePath ? parameters.basePath : THREE.LoaderUtils.extractUrlBase( url );
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === 4 ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				var jsonObject = JSON.parse( xhr.responseText );
-
-				var materials = [], geometries = [], counter = 0;
-
-				function callbackFinal( geometry ) {
-
-					counter += 1;
-
-					geometries.push( geometry );
-
-					if ( counter === jsonObject.offsets.length ) {
-
-						callback( geometries, materials );
-
-					}
-
-				}
-
-
-				// init materials
-
-				for ( var i = 0; i < jsonObject.materials.length; i ++ ) {
-
-					materials[ i ] = THREE.Loader.prototype.createMaterial( jsonObject.materials[ i ], basePath );
-
-				}
-
-				// load joined CTM file
-
-				var partUrl = basePath + jsonObject.data;
-				var parametersPart = { useWorker: parameters.useWorker, worker: parameters.worker, offsets: jsonObject.offsets };
-				scope.load( partUrl, callbackFinal, parametersPart );
-
-			}
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.setRequestHeader( "Content-Type", "text/plain" );
-	xhr.send( null );
-
-};
-
-// Load CTMLoader compressed models
-//	- parameters
-//		- url (required)
-//		- callback (required)
-
-THREE.CTMLoader.prototype.load = function ( url, callback, parameters ) {
-
-	parameters = parameters || {};
-
-	var scope = this;
-
-	var offsets = parameters.offsets !== undefined ? parameters.offsets : [ 0 ];
-
-	var xhr = new XMLHttpRequest(),
-		callbackProgress = null;
-
-	var length = 0;
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === 4 ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				var binaryData = new Uint8Array( xhr.response );
-
-				var s = Date.now();
-
-				if ( parameters.useWorker ) {
-
-					var worker = parameters.worker || new Worker( scope.workerPath );
-
-					worker.onmessage = function ( event ) {
-
-						var files = event.data;
-
-						for ( var i = 0; i < files.length; i ++ ) {
-
-							var ctmFile = files[ i ];
-
-							var e1 = Date.now();
-							// console.log( "CTM data parse time [worker]: " + (e1-s) + " ms" );
-
-							scope._createGeometry( ctmFile, callback );
-
-							var e = Date.now();
-							console.log( "model load time [worker]: " + ( e - e1 ) + " ms, total: " + ( e - s ) );
-
-						}
-
-
-					};
-
-					worker.postMessage( { "data": binaryData, "offsets": offsets }, [ binaryData.buffer ] );
-
-				} else {
-
-					for ( var i = 0; i < offsets.length; i ++ ) {
-
-						var stream = new CTM.Stream( binaryData );
-						stream.offset = offsets[ i ];
-
-						var ctmFile = new CTM.File( stream );
-
-						scope._createGeometry( ctmFile, callback );
-
-					}
-
-					//var e = Date.now();
-					//console.log( "CTM data parse time [inline]: " + (e-s) + " ms" );
-
-				}
-
-			} else {
-
-				console.error( "Couldn't load [" + url + "] [" + xhr.status + "]" );
-
-			}
-
-		} else if ( xhr.readyState === 3 ) {
-
-			if ( callbackProgress ) {
-
-				if ( length === 0 ) {
-
-					length = xhr.getResponseHeader( "Content-Length" );
-
-				}
-
-				callbackProgress( { total: length, loaded: xhr.responseText.length } );
-
-			}
-
-		} else if ( xhr.readyState === 2 ) {
-
-			length = xhr.getResponseHeader( "Content-Length" );
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.responseType = "arraybuffer";
-
-	xhr.send( null );
-
-};
-
-
-THREE.CTMLoader.prototype._createGeometry = function ( file, callback ) {
-
-	var geometry = new THREE.BufferGeometry();
-
-	var indices = file.body.indices;
-	var positions = file.body.vertices;
-	var normals = file.body.normals;
-
-	var uvs, colors;
-
-	var uvMaps = file.body.uvMaps;
-
-	if ( uvMaps !== undefined && uvMaps.length > 0 ) {
-
-		uvs = uvMaps[ 0 ].uv;
-
-	}
-
-	var attrMaps = file.body.attrMaps;
-
-	if ( attrMaps !== undefined && attrMaps.length > 0 && attrMaps[ 0 ].name === 'Color' ) {
-
-		colors = attrMaps[ 0 ].attr;
-
-	}
-
-	geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
-	geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
-
-	if ( normals !== undefined ) {
-
-		geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
-
-	}
-
-	if ( uvs !== undefined ) {
-
-		geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
-
-	}
-
-	if ( colors !== undefined ) {
-
-		geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 4 ) );
-
-	}
-
-	// compute vertex normals if not present in the CTM model
-	if ( geometry.attributes.normal === undefined ) {
-
-		geometry.computeVertexNormals();
-
-	}
-
-	callback( geometry );
-
-};

+ 0 - 19
examples/js/loaders/ctm/CTMWorker.js

@@ -1,19 +0,0 @@
-importScripts( "../../libs/lzma.js", "../../libs/ctm.js" );
-
-self.onmessage = function ( event ) {
-
-	var files = [];
-
-	for ( var i = 0; i < event.data.offsets.length; i ++ ) {
-
-		var stream = new CTM.Stream( event.data.data );
-		stream.offset = event.data.offsets[ i ];
-
-		files[ i ] = new CTM.File( stream, [ event.data.data.buffer ] );
-
-	}
-
-	self.postMessage( files );
-	self.close();
-
-};

+ 1 - 1
examples/js/modifiers/SimplifyModifier.js

@@ -1,4 +1,4 @@
-/*
+/**
  *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  *
  *	Simplification Geometry Modifier

+ 1 - 1
examples/js/modifiers/SubdivisionModifier.js

@@ -1,4 +1,4 @@
-/*
+/**
  *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  *	@author centerionware / http://www.centerionware.com
  *

+ 3 - 2
examples/js/shaders/TranslucentShader.js

@@ -61,6 +61,7 @@ THREE.TranslucentShader = {
 	].join( "\n" ),
 
 	fragmentShader: [
+		"#define USE_UV",
 		"#define USE_MAP",
 		"#define PHONG",
 		"#define TRANSLUCENT",
@@ -137,7 +138,7 @@ THREE.TranslucentShader = {
 
 		"			RE_Direct( directLight, geometry, material, reflectedLight );",
 
-		"			#if defined( TRANSLUCENT ) && defined( USE_MAP )",
+		"			#if defined( TRANSLUCENT ) && defined( USE_UV )",
 		"			RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight);",
 		"			#endif",
 		"		}",
@@ -159,7 +160,7 @@ THREE.TranslucentShader = {
 
 		"			RE_Direct( directLight, geometry, material, reflectedLight );",
 
-		"			#if defined( TRANSLUCENT ) && defined( USE_MAP )",
+		"			#if defined( TRANSLUCENT ) && defined( USE_UV )",
 		"			RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight);",
 		"			#endif",
 		"		}",

+ 1 - 1
examples/js/utils/UVsDebug.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / http://github.com/zz85
  * @author WestLangley / http://github.com/WestLangley
  * @author Mugen87 / https://github.com/Mugen87

+ 1 - 1
examples/jsm/controls/DragControls.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / https://github.com/zz85
  * @author mrdoob / http://mrdoob.com
  * Running this will allow you to drag three.js objects around the screen.

+ 2 - 162
examples/jsm/controls/OrbitControls.js

@@ -470,32 +470,24 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleMouseDownRotate( event ) {
 
-		//console.log( 'handleMouseDownRotate' );
-
 		rotateStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseDownDolly( event ) {
 
-		//console.log( 'handleMouseDownDolly' );
-
 		dollyStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseDownPan( event ) {
 
-		//console.log( 'handleMouseDownPan' );
-
 		panStart.set( event.clientX, event.clientY );
 
 	}
 
 	function handleMouseMoveRotate( event ) {
 
-		//console.log( 'handleMouseMoveRotate' );
-
 		rotateEnd.set( event.clientX, event.clientY );
 
 		rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
@@ -514,8 +506,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleMouseMoveDolly( event ) {
 
-		//console.log( 'handleMouseMoveDolly' );
-
 		dollyEnd.set( event.clientX, event.clientY );
 
 		dollyDelta.subVectors( dollyEnd, dollyStart );
@@ -538,8 +528,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleMouseMovePan( event ) {
 
-		//console.log( 'handleMouseMovePan' );
-
 		panEnd.set( event.clientX, event.clientY );
 
 		panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
@@ -554,14 +542,12 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleMouseUp( /*event*/ ) {
 
-		// console.log( 'handleMouseUp' );
+		// no-op
 
 	}
 
 	function handleMouseWheel( event ) {
 
-		// console.log( 'handleMouseWheel' );
-
 		if ( event.deltaY < 0 ) {
 
 			dollyOut( getZoomScale() );
@@ -578,8 +564,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleKeyDown( event ) {
 
-		// console.log( 'handleKeyDown' );
-
 		var needsUpdate = false;
 
 		switch ( event.keyCode ) {
@@ -620,8 +604,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartRotate( event ) {
 
-		//console.log( 'handleTouchStartRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -639,8 +621,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartPan( event ) {
 
-		//console.log( 'handleTouchStartPan' );
-
 		if ( event.touches.length == 1 ) {
 
 			panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -658,8 +638,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDolly( event ) {
 
-		//console.log( 'handleTouchStartDolly' );
-
 		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
 
@@ -671,8 +649,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDollyPan( event ) {
 
-		//console.log( 'handleTouchStartDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchStartDolly( event );
 
 		if ( scope.enablePan ) handleTouchStartPan( event );
@@ -681,8 +657,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchStartDollyRotate( event ) {
 
-		//console.log( 'handleTouchStartDollyRotate' );
-
 		if ( scope.enableZoom ) handleTouchStartDolly( event );
 
 		if ( scope.enableRotate ) handleTouchStartRotate( event );
@@ -691,8 +665,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveRotate( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -720,8 +692,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMovePan( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		if ( event.touches.length == 1 ) {
 
 			panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
@@ -745,8 +715,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDolly( event ) {
 
-		//console.log( 'handleTouchMoveRotate' );
-
 		var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 		var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
 
@@ -764,8 +732,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDollyPan( event ) {
 
-		//console.log( 'handleTouchMoveDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchMoveDolly( event );
 
 		if ( scope.enablePan ) handleTouchMovePan( event );
@@ -774,8 +740,6 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchMoveDollyRotate( event ) {
 
-		//console.log( 'handleTouchMoveDollyPan' );
-
 		if ( scope.enableZoom ) handleTouchMoveDolly( event );
 
 		if ( scope.enableRotate ) handleTouchMoveRotate( event );
@@ -784,7 +748,7 @@ var OrbitControls = function ( object, domElement ) {
 
 	function handleTouchEnd( /*event*/ ) {
 
-		//console.log( 'handleTouchEnd' );
+		// no-op
 
 	}
 
@@ -1191,130 +1155,6 @@ var OrbitControls = function ( object, domElement ) {
 OrbitControls.prototype = Object.create( EventDispatcher.prototype );
 OrbitControls.prototype.constructor = OrbitControls;
 
-Object.defineProperties( OrbitControls.prototype, {
-
-	center: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
-			return this.target;
-
-		}
-
-	},
-
-	// backward compatibility
-
-	noZoom: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
-			return ! this.enableZoom;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
-			this.enableZoom = ! value;
-
-		}
-
-	},
-
-	noRotate: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
-			return ! this.enableRotate;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
-			this.enableRotate = ! value;
-
-		}
-
-	},
-
-	noPan: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
-			return ! this.enablePan;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
-			this.enablePan = ! value;
-
-		}
-
-	},
-
-	noKeys: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
-			return ! this.enableKeys;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
-			this.enableKeys = ! value;
-
-		}
-
-	},
-
-	staticMoving: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
-			return ! this.enableDamping;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
-			this.enableDamping = ! value;
-
-		}
-
-	},
-
-	dynamicDampingFactor: {
-
-		get: function () {
-
-			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
-			return this.dampingFactor;
-
-		},
-
-		set: function ( value ) {
-
-			console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
-			this.dampingFactor = value;
-
-		}
-
-	}
-
-} );
 
 // This set of controls performs orbiting, dollying (zooming), and panning.
 // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).

+ 1 - 1
examples/jsm/controls/OrthographicTrackballControls.js

@@ -272,7 +272,7 @@ var OrthographicTrackballControls = function ( object, domElement ) {
 
 			mouseChange.copy( _panEnd ).sub( _panStart );
 
-			if ( mouseChange.lengthSq() ) {
+			if ( mouseChange.lengthSq() > EPS ) {
 
 				// Scale movement to keep clicked/dragged position under cursor
 				var scale_x = ( _this.object.right - _this.object.left ) / _this.object.zoom;

+ 2 - 2
examples/jsm/controls/TransformControls.d.ts

@@ -42,8 +42,8 @@ export class TransformControls extends Object3D {
   pointerUp(pointer: Object): void;
   getMode(): string;
   setMode(mode: string): void;
-  setTranslationSnap(translationSnap: Vector3): void;
-  setRotationSnap(rotationSnap: Euler): void;
+  setTranslationSnap(translationSnap: Number | null): void;
+  setRotationSnap(rotationSnap: Number | null): void;
   setSize(size: number): void;
   setSpace(space: string): void;
   dispose(): void;

+ 1 - 1
examples/jsm/curves/CurveExtras.js

@@ -1,4 +1,4 @@
-/*
+/**
  * A bunch of parametric curves
  * @author zz85
  *

+ 1 - 1
examples/jsm/effects/AsciiEffect.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / https://github.com/zz85
  *
  * Ascii generation is based on http://www.nihilogic.dk/labs/jsascii/

+ 1 - 1
examples/jsm/exporters/ColladaExporter.js

@@ -496,7 +496,7 @@ ColladaExporter.prototype = {
 
 					(
 						m.side === DoubleSide ?
-							`<extra><technique><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>` :
+							`<extra><technique profile="THREEJS"><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>` :
 							''
 					) +
 

+ 42 - 3
examples/jsm/exporters/GLTFExporter.js

@@ -919,7 +919,7 @@ GLTFExporter.prototype = {
 
 			}
 
-			if ( material.isShaderMaterial ) {
+			if ( material.isShaderMaterial && !material.isGLTFSpecularGlossinessMaterial ) {
 
 				console.warn( 'GLTFExporter: THREE.ShaderMaterial not supported.' );
 				return null;
@@ -939,6 +939,12 @@ GLTFExporter.prototype = {
 
 				extensionsUsed[ 'KHR_materials_unlit' ] = true;
 
+			} else if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+				gltfMaterial.extensions = { KHR_materials_pbrSpecularGlossiness: {} };
+
+				extensionsUsed[ 'KHR_materials_pbrSpecularGlossiness' ] = true;
+
 			} else if ( ! material.isMeshStandardMaterial ) {
 
 				console.warn( 'GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.' );
@@ -971,6 +977,23 @@ GLTFExporter.prototype = {
 
 			}
 
+			// pbrSpecularGlossiness diffuse, specular and glossiness factor
+			if ( material.isGLTFSpecularGlossinessMaterial ) {
+				
+				if ( gltfMaterial.pbrMetallicRoughness.baseColorFactor ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseFactor = gltfMaterial.pbrMetallicRoughness.baseColorFactor;
+				  
+				}
+
+				var specularFactor = [ 1, 1, 1 ];
+				material.specular.toArray( specularFactor, 0 );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularFactor = specularFactor;
+
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.glossinessFactor = material.glossiness;
+			
+			}
+
 			// pbrMetallicRoughness.metallicRoughnessTexture
 			if ( material.metalnessMap || material.roughnessMap ) {
 
@@ -988,12 +1011,28 @@ GLTFExporter.prototype = {
 
 			}
 
-			// pbrMetallicRoughness.baseColorTexture
+			// pbrMetallicRoughness.baseColorTexture or pbrSpecularGlossiness diffuseTexture
 			if ( material.map ) {
 
 				var baseColorMapDef = { index: processTexture( material.map ) };
 				applyTextureTransform( baseColorMapDef, material.map );
+
+				if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseTexture = baseColorMapDef;
+
+				}
+
 				gltfMaterial.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
+				
+			}
+
+			// pbrSpecularGlossiness specular map
+			if ( material.isGLTFSpecularGlossinessMaterial && material.specularMap ) {
+
+				var specularMapDef = { index: processTexture( material.specularMap ) };
+				applyTextureTransform( specularMapDef, material.specularMap );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularGlossinessTexture = specularMapDef;
 
 			}
 
@@ -1028,7 +1067,7 @@ GLTFExporter.prototype = {
 
 				var normalMapDef = { index: processTexture( material.normalMap ) };
 
-				if ( material.normalScale.x !== - 1 ) {
+				if ( material.normalScale && material.normalScale.x !== - 1 ) {
 
 					if ( material.normalScale.x !== material.normalScale.y ) {
 

+ 1 - 1
examples/jsm/geometries/ParametricGeometries.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85
  *
  * Experimenting of primitive geometry creation using Surface Parametric equations

+ 1 - 1
examples/jsm/loaders/AMFLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author tamarintech / https://tamarintech.com
  *
  * Description: Early release of an AMF Loader following the pattern of the

+ 1 - 1
examples/jsm/loaders/DDSLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author mrdoob / http://mrdoob.com/
  */
 

+ 1 - 0
examples/jsm/loaders/GLTFLoader.js

@@ -2205,6 +2205,7 @@ var GLTFLoader = ( function () {
 				pointsMaterial.color.copy( material.color );
 				pointsMaterial.map = material.map;
 				pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
+				pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
 
 				this.cache.add( cacheKey, pointsMaterial );
 

+ 95 - 35
examples/jsm/loaders/STLLoader.js

@@ -3,6 +3,7 @@
  * @author mrdoob / http://mrdoob.com/
  * @author gero3 / https://github.com/gero3
  * @author Mugen87 / https://github.com/Mugen87
+ * @author neverhood311 / https://github.com/neverhood311
  *
  * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
  *
@@ -27,6 +28,31 @@
  *    material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors });
  *  } else { .... }
  *  var mesh = new THREE.Mesh( geometry, material );
+ *
+ * For ASCII STLs containing multiple solids, each solid is assigned to a different group.
+ * Groups can be used to assign a different color by defining an array of materials with the same length of
+ * geometry.groups and passing it to the Mesh constructor:
+ *
+ * var mesh = new THREE.Mesh( geometry, material );
+ *
+ * For example:
+ *
+ *  var materials = [];
+ *  var nGeometryGroups = geometry.groups.length;
+ *
+ *  var colorMap = ...; // Some logic to index colors.
+ *
+ *  for (var i = 0; i < nGeometryGroups; i++) {
+ *
+ *		var material = new THREE.MeshPhongMaterial({
+ *			color: colorMap[i],
+ *			wireframe: false
+ *		});
+ *
+ *  }
+ *
+ *  materials.push(material);
+ *  var mesh = new THREE.Mesh(geometry, materials);
  */
 
 import {
@@ -116,7 +142,7 @@ STLLoader.prototype = {
 
 				// If "solid" text is matched to the current offset, declare it to be an ASCII STL.
 
-				if ( matchDataViewAt ( solid, reader, off ) ) return false;
+				if ( matchDataViewAt( solid, reader, off ) ) return false;
 
 			}
 
@@ -158,7 +184,7 @@ STLLoader.prototype = {
 					( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) {
 
 					hasColors = true;
-					colors = [];
+					colors = new Float32Array( faces * 3 * 3 );
 
 					defaultR = reader.getUint8( index + 6 ) / 255;
 					defaultG = reader.getUint8( index + 7 ) / 255;
@@ -174,8 +200,8 @@ STLLoader.prototype = {
 
 			var geometry = new BufferGeometry();
 
-			var vertices = [];
-			var normals = [];
+			var vertices = new Float32Array( faces * 3 * 3 );
+			var normals = new Float32Array( faces * 3 * 3 );
 
 			for ( var face = 0; face < faces; face ++ ) {
 
@@ -209,16 +235,21 @@ STLLoader.prototype = {
 				for ( var i = 1; i <= 3; i ++ ) {
 
 					var vertexstart = start + i * 12;
+					var componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 );
 
-					vertices.push( reader.getFloat32( vertexstart, true ) );
-					vertices.push( reader.getFloat32( vertexstart + 4, true ) );
-					vertices.push( reader.getFloat32( vertexstart + 8, true ) );
+					vertices[ componentIdx ] = reader.getFloat32( vertexstart, true );
+					vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true );
+					vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true );
 
-					normals.push( normalX, normalY, normalZ );
+					normals[ componentIdx ] = normalX;
+					normals[ componentIdx + 1 ] = normalY;
+					normals[ componentIdx + 2 ] = normalZ;
 
 					if ( hasColors ) {
 
-						colors.push( r, g, b );
+						colors[ componentIdx ] = r;
+						colors[ componentIdx + 1 ] = g;
+						colors[ componentIdx + 2 ] = b;
 
 					}
 
@@ -226,12 +257,12 @@ STLLoader.prototype = {
 
 			}
 
-			geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
-			geometry.addAttribute( 'normal', new BufferAttribute( new Float32Array( normals ), 3 ) );
+			geometry.addAttribute( 'position', new BufferAttribute( vertices, 3 ) );
+			geometry.addAttribute( 'normal', new BufferAttribute( normals, 3 ) );
 
 			if ( hasColors ) {
 
-				geometry.addAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 3 ) );
+				geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );
 				geometry.hasColors = true;
 				geometry.alpha = alpha;
 
@@ -244,6 +275,7 @@ STLLoader.prototype = {
 		function parseASCII( data ) {
 
 			var geometry = new BufferGeometry();
+			var patternSolid = /solid([\s\S]*?)endsolid/g;
 			var patternFace = /facet([\s\S]*?)endfacet/g;
 			var faceCounter = 0;
 
@@ -258,53 +290,80 @@ STLLoader.prototype = {
 
 			var result;
 
-			while ( ( result = patternFace.exec( data ) ) !== null ) {
+			var groupVertexes = [];
+			var groupCount = 0;
+			var startVertex = 0;
+			var endVertex = 0;
 
-				var vertexCountPerFace = 0;
-				var normalCountPerFace = 0;
+			while ( ( result = patternSolid.exec( data ) ) !== null ) {
 
-				var text = result[ 0 ];
+				startVertex = endVertex;
 
-				while ( ( result = patternNormal.exec( text ) ) !== null ) {
+				var solid = result[ 0 ];
 
-					normal.x = parseFloat( result[ 1 ] );
-					normal.y = parseFloat( result[ 2 ] );
-					normal.z = parseFloat( result[ 3 ] );
-					normalCountPerFace ++;
+				while ( ( result = patternFace.exec( solid ) ) !== null ) {
 
-				}
+					var vertexCountPerFace = 0;
+					var normalCountPerFace = 0;
 
-				while ( ( result = patternVertex.exec( text ) ) !== null ) {
+					var text = result[ 0 ];
 
-					vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
-					normals.push( normal.x, normal.y, normal.z );
-					vertexCountPerFace ++;
+					while ( ( result = patternNormal.exec( text ) ) !== null ) {
 
-				}
+						normal.x = parseFloat( result[ 1 ] );
+						normal.y = parseFloat( result[ 2 ] );
+						normal.z = parseFloat( result[ 3 ] );
+						normalCountPerFace ++;
 
-				// every face have to own ONE valid normal
+					}
 
-				if ( normalCountPerFace !== 1 ) {
+					while ( ( result = patternVertex.exec( text ) ) !== null ) {
 
-					console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
+						vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );
+						normals.push( normal.x, normal.y, normal.z );
+						vertexCountPerFace ++;
+						endVertex ++;
 
-				}
+					}
 
-				// each face have to own THREE valid vertices
+					// every face have to own ONE valid normal
 
-				if ( vertexCountPerFace !== 3 ) {
+					if ( normalCountPerFace !== 1 ) {
 
-					console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
+						console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter );
+
+					}
+
+					// each face have to own THREE valid vertices
+
+					if ( vertexCountPerFace !== 3 ) {
+
+						console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter );
+
+					}
+
+					faceCounter ++;
 
 				}
 
-				faceCounter ++;
+				groupVertexes.push( { startVertex: startVertex, endVertex: endVertex } );
+				groupCount ++;
 
 			}
 
 			geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 			geometry.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 
+			if ( groupCount > 0 ) {
+
+				for ( var i = 0; i < groupVertexes.length; i ++ ) {
+
+					geometry.addGroup( groupVertexes[ i ].startVertex, groupVertexes[ i ].endVertex, i );
+
+				}
+
+			}
+
 			return geometry;
 
 		}
@@ -331,6 +390,7 @@ STLLoader.prototype = {
 					array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian
 
 				}
+
 				return array_buffer.buffer || array_buffer;
 
 			} else {

+ 1 - 1
examples/jsm/loaders/TDSLoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * Autodesk 3DS three.js file loader, based on lib3ds.
  *
  * Loads geometry with uv and materials basic properties with texture support.

+ 1 - 1
examples/jsm/loaders/TGALoader.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author Daosheng Mu / https://github.com/DaoshengMu/
  * @author mrdoob / http://mrdoob.com/
  * @author takahirox / https://github.com/takahirox/

+ 0 - 20
examples/jsm/loaders/ctm/CTMLoader.d.ts

@@ -1,20 +0,0 @@
-import {
-  BufferGeometry,
-  Material
-} from '../../../../src/Three';
-
-export interface CTMLoaderParameters {
-  basePath?: string;
-  offsets?: number[];
-  useWorker?: boolean;
-  worker?: object;
-}
-
-export class CTMLoader {
-  constructor();
-  workerPath: string;
-
-  load(url: string, onLoad: (geometry: BufferGeometry) => void, parameters: CTMLoaderParameters): void;
-  loadParts(url: string, onLoad: (geometries: BufferGeometry[], materials: Material[]) => void, parameters: CTMLoaderParameters): void;
-  setWorkerPath(value: string): this;
-}

+ 0 - 288
examples/jsm/loaders/ctm/CTMLoader.js

@@ -1,288 +0,0 @@
-/**
- * Loader for CTM encoded models generated by OpenCTM tools:
- *	http://openctm.sourceforge.net/
- *
- * Uses js-openctm library by Juan Mellado
- *	http://code.google.com/p/js-openctm/
- *
- * @author alteredq / http://alteredqualia.com/
- *
- * OpenCTM LICENSE:
- *
- * Copyright (c) 2009-2010 Marcus Geelnard
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- *     1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- *
- *    2. Altered source versions must be plainly marked as such, and must not
- *    be misrepresented as being the original software.
- *
- *    3. This notice may not be removed or altered from any source
- *    distribution.
- *
- */
-
-import {
-	BufferAttribute,
-	BufferGeometry,
-	Loader,
-	LoaderUtils
-} from "../../../../build/three.module.js";
-
-/* global CTM */
-
-var CTMLoader = function () {
-
-	this.workerPath = null;
-
-};
-
-CTMLoader.prototype.constructor = CTMLoader;
-
-CTMLoader.prototype.setWorkerPath = function ( workerPath ) {
-
-	this.workerPath = workerPath;
-
-};
-
-// Load multiple CTM parts defined in JSON
-
-CTMLoader.prototype.loadParts = function ( url, callback, parameters ) {
-
-	parameters = parameters || {};
-
-	var scope = this;
-
-	var xhr = new XMLHttpRequest();
-
-	var basePath = parameters.basePath ? parameters.basePath : LoaderUtils.extractUrlBase( url );
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === 4 ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				var jsonObject = JSON.parse( xhr.responseText );
-
-				var materials = [], geometries = [], counter = 0;
-
-				function callbackFinal( geometry ) {
-
-					counter += 1;
-
-					geometries.push( geometry );
-
-					if ( counter === jsonObject.offsets.length ) {
-
-						callback( geometries, materials );
-
-					}
-
-				}
-
-
-				// init materials
-
-				for ( var i = 0; i < jsonObject.materials.length; i ++ ) {
-
-					materials[ i ] = Loader.prototype.createMaterial( jsonObject.materials[ i ], basePath );
-
-				}
-
-				// load joined CTM file
-
-				var partUrl = basePath + jsonObject.data;
-				var parametersPart = { useWorker: parameters.useWorker, worker: parameters.worker, offsets: jsonObject.offsets };
-				scope.load( partUrl, callbackFinal, parametersPart );
-
-			}
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.setRequestHeader( "Content-Type", "text/plain" );
-	xhr.send( null );
-
-};
-
-// Load CTMLoader compressed models
-//	- parameters
-//		- url (required)
-//		- callback (required)
-
-CTMLoader.prototype.load = function ( url, callback, parameters ) {
-
-	parameters = parameters || {};
-
-	var scope = this;
-
-	var offsets = parameters.offsets !== undefined ? parameters.offsets : [ 0 ];
-
-	var xhr = new XMLHttpRequest(),
-		callbackProgress = null;
-
-	var length = 0;
-
-	xhr.onreadystatechange = function () {
-
-		if ( xhr.readyState === 4 ) {
-
-			if ( xhr.status === 200 || xhr.status === 0 ) {
-
-				var binaryData = new Uint8Array( xhr.response );
-
-				var s = Date.now();
-
-				if ( parameters.useWorker ) {
-
-					var worker = parameters.worker || new Worker( scope.workerPath );
-
-					worker.onmessage = function ( event ) {
-
-						var files = event.data;
-
-						for ( var i = 0; i < files.length; i ++ ) {
-
-							var ctmFile = files[ i ];
-
-							var e1 = Date.now();
-							// console.log( "CTM data parse time [worker]: " + (e1-s) + " ms" );
-
-							scope._createGeometry( ctmFile, callback );
-
-							var e = Date.now();
-							console.log( "model load time [worker]: " + ( e - e1 ) + " ms, total: " + ( e - s ) );
-
-						}
-
-
-					};
-
-					worker.postMessage( { "data": binaryData, "offsets": offsets }, [ binaryData.buffer ] );
-
-				} else {
-
-					for ( var i = 0; i < offsets.length; i ++ ) {
-
-						var stream = new CTM.Stream( binaryData );
-						stream.offset = offsets[ i ];
-
-						var ctmFile = new CTM.File( stream );
-
-						scope._createGeometry( ctmFile, callback );
-
-					}
-
-					//var e = Date.now();
-					//console.log( "CTM data parse time [inline]: " + (e-s) + " ms" );
-
-				}
-
-			} else {
-
-				console.error( "Couldn't load [" + url + "] [" + xhr.status + "]" );
-
-			}
-
-		} else if ( xhr.readyState === 3 ) {
-
-			if ( callbackProgress ) {
-
-				if ( length === 0 ) {
-
-					length = xhr.getResponseHeader( "Content-Length" );
-
-				}
-
-				callbackProgress( { total: length, loaded: xhr.responseText.length } );
-
-			}
-
-		} else if ( xhr.readyState === 2 ) {
-
-			length = xhr.getResponseHeader( "Content-Length" );
-
-		}
-
-	};
-
-	xhr.open( "GET", url, true );
-	xhr.responseType = "arraybuffer";
-
-	xhr.send( null );
-
-};
-
-
-CTMLoader.prototype._createGeometry = function ( file, callback ) {
-
-	var geometry = new BufferGeometry();
-
-	var indices = file.body.indices;
-	var positions = file.body.vertices;
-	var normals = file.body.normals;
-
-	var uvs, colors;
-
-	var uvMaps = file.body.uvMaps;
-
-	if ( uvMaps !== undefined && uvMaps.length > 0 ) {
-
-		uvs = uvMaps[ 0 ].uv;
-
-	}
-
-	var attrMaps = file.body.attrMaps;
-
-	if ( attrMaps !== undefined && attrMaps.length > 0 && attrMaps[ 0 ].name === 'Color' ) {
-
-		colors = attrMaps[ 0 ].attr;
-
-	}
-
-	geometry.setIndex( new BufferAttribute( indices, 1 ) );
-	geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );
-
-	if ( normals !== undefined ) {
-
-		geometry.addAttribute( 'normal', new BufferAttribute( normals, 3 ) );
-
-	}
-
-	if ( uvs !== undefined ) {
-
-		geometry.addAttribute( 'uv', new BufferAttribute( uvs, 2 ) );
-
-	}
-
-	if ( colors !== undefined ) {
-
-		geometry.addAttribute( 'color', new BufferAttribute( colors, 4 ) );
-
-	}
-
-	// compute vertex normals if not present in the CTM model
-	if ( geometry.attributes.normal === undefined ) {
-
-		geometry.computeVertexNormals();
-
-	}
-
-	callback( geometry );
-
-};
-
-export { CTMLoader };

+ 1 - 1
examples/jsm/modifiers/SimplifyModifier.js

@@ -1,4 +1,4 @@
-/*
+/**
  *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  *
  *	Simplification Geometry Modifier

+ 1 - 1
examples/jsm/modifiers/SubdivisionModifier.js

@@ -1,4 +1,4 @@
-/*
+/**
  *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  *	@author centerionware / http://www.centerionware.com
  *

+ 2 - 1
examples/jsm/nodes/accessors/NormalNode.js

@@ -36,7 +36,8 @@ NormalNode.prototype.generate = function ( builder, output ) {
 
 		case NormalNode.LOCAL:
 
-			result = 'normal';
+			if ( builder.isShader( 'vertex' ) ) result = 'objectNormal';
+			else result = 'geometryNormal';
 
 			break;
 

+ 6 - 1
examples/jsm/nodes/accessors/ReflectNode.js

@@ -3,6 +3,8 @@
  */
 
 import { TempNode } from '../core/TempNode.js';
+import { PositionNode } from './PositionNode.js';
+import { NormalNode } from './NormalNode.js';
 
 function ReflectNode( scope ) {
 
@@ -44,7 +46,10 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 			case ReflectNode.VECTOR:
 
-				builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
+				var viewNormal = new NormalNode().build( builder, 'v3' );
+				var viewPosition = new PositionNode( PositionNode.VIEW ).build( builder, 'v3' );
+
+				builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( ' + viewPosition + ' ), ' + viewNormal + ' ), viewMatrix );' );
 
 				result = 'reflectVec';
 

+ 9 - 2
examples/jsm/nodes/core/FunctionNode.js

@@ -12,6 +12,7 @@ var declarationRegexp = /^([a-z_0-9]+)\s([a-z_0-9]+)\s*\((.*?)\)/i,
 function FunctionNode( src, includes, extensions, keywords, type ) {
 
 	this.isMethod = type === undefined;
+	this.isInterface = false;
 
 	TempNode.call( this, type );
 
@@ -139,7 +140,11 @@ FunctionNode.prototype.generate = function ( builder, output ) {
 
 	} else if ( this.isMethod ) {
 
-		builder.include( this, false, src );
+		if ( ! this.isInterface ) {
+
+			builder.include( this, false, src );
+
+		}
 
 		return this.name;
 
@@ -181,7 +186,7 @@ FunctionNode.prototype.parse = function ( src, includes, extensions, keywords )
 					var qualifier = inputs[ i ++ ];
 					var type, name;
 
-					if ( qualifier == 'in' || qualifier == 'out' || qualifier == 'inout' ) {
+					if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) {
 
 						type = inputs[ i ++ ];
 
@@ -204,6 +209,8 @@ FunctionNode.prototype.parse = function ( src, includes, extensions, keywords )
 
 			}
 
+			this.isInterface = this.src.indexOf('{') === -1;
+
 		} else {
 
 			this.type = '';

+ 1 - 0
examples/jsm/nodes/materials/StandardNodeMaterial.js

@@ -27,6 +27,7 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
 	'reflectivity',
 	'clearCoat',
 	'clearCoatRoughness',
+	'clearCoatNormal',
 	'normal',
 	'emissive',
 	'ambient',

+ 13 - 3
examples/jsm/nodes/materials/nodes/StandardNode.js

@@ -32,9 +32,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 	var code;
 
-	builder.define( this.clearCoat || this.clearCoatRoughness ? 'PHYSICAL' : 'STANDARD' );
-
-	if ( this.energyPreservation ) builder.define( 'ENERGY_PRESERVATION' );
+	builder.define( this.clearCoat || this.clearCoatRoughness || this.clearCoatNormal ? 'PHYSICAL' : 'STANDARD' );
 
 	builder.requires.lights = true;
 
@@ -147,6 +145,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 		if ( this.clearCoat ) this.clearCoat.analyze( builder );
 		if ( this.clearCoatRoughness ) this.clearCoatRoughness.analyze( builder );
+		if ( this.clearCoatNormal ) this.clearCoatNormal.analyze( builder );
 
 		if ( this.reflectivity ) this.reflectivity.analyze( builder );
 
@@ -188,6 +187,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 		var clearCoat = this.clearCoat ? this.clearCoat.flow( builder, 'f' ) : undefined;
 		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.flow( builder, 'f' ) : undefined;
+		var clearCoatNormal = this.clearCoatNormal ? this.clearCoatNormal.flow( builder, 'v3' ) : undefined;
 
 		var reflectivity = this.reflectivity ? this.reflectivity.flow( builder, 'f' ) : undefined;
 
@@ -244,6 +244,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 			// add before: prevent undeclared normal
 			"	#include <normal_fragment_begin>",
+			"	#include <clearcoat_normal_fragment_begin>",
 
 			// add before: prevent undeclared material
 			"	PhysicalMaterial material;",
@@ -295,6 +296,15 @@ StandardNode.prototype.build = function ( builder ) {
 
 		}
 
+		if ( clearCoatNormal ) {
+
+			output.push(
+				clearCoatNormal.code,
+				'clearCoatNormal = ' + clearCoatNormal.result + ';'
+			);
+
+		}
+
 		// optimization for now
 
 		output.push(

+ 5 - 3
examples/jsm/nodes/misc/TextureCubeNode.js

@@ -11,17 +11,19 @@ import { NormalNode } from '../accessors/NormalNode.js';
 import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 import { BlinnExponentToRoughnessNode } from '../bsdfs/BlinnExponentToRoughnessNode.js';
 
-function TextureCubeNode( value, textureSize ) {
+function TextureCubeNode( value, textureSize, uv, bias ) {
 
 	TempNode.call( this, 'v4' );
 
 	this.value = value;
 	this.textureSize = textureSize || new FloatNode( 1024 );
+	this.uv = uv || new ReflectNode( ReflectNode.VECTOR );
+	this.bias = bias || new BlinnExponentToRoughnessNode();
 
 	this.radianceCache = { uv: new TextureCubeUVNode(
-		new ReflectNode( ReflectNode.VECTOR ),
+		this.uv,
 		this.textureSize,
-		new BlinnExponentToRoughnessNode()
+		this.bias
 	) };
 
 	this.irradianceCache = { uv: new TextureCubeUVNode(

+ 3 - 2
examples/jsm/shaders/TranslucentShader.js

@@ -68,6 +68,7 @@ var TranslucentShader = {
 	].join( "\n" ),
 
 	fragmentShader: [
+		"#define USE_UV",
 		"#define USE_MAP",
 		"#define PHONG",
 		"#define TRANSLUCENT",
@@ -144,7 +145,7 @@ var TranslucentShader = {
 
 		"			RE_Direct( directLight, geometry, material, reflectedLight );",
 
-		"			#if defined( TRANSLUCENT ) && defined( USE_MAP )",
+		"			#if defined( TRANSLUCENT ) && defined( USE_UV )",
 		"			RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight);",
 		"			#endif",
 		"		}",
@@ -166,7 +167,7 @@ var TranslucentShader = {
 
 		"			RE_Direct( directLight, geometry, material, reflectedLight );",
 
-		"			#if defined( TRANSLUCENT ) && defined( USE_MAP )",
+		"			#if defined( TRANSLUCENT ) && defined( USE_UV )",
 		"			RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight);",
 		"			#endif",
 		"		}",

+ 1 - 1
examples/jsm/utils/UVsDebug.js

@@ -1,4 +1,4 @@
-/*
+/**
  * @author zz85 / http://github.com/zz85
  * @author WestLangley / http://github.com/WestLangley
  * @author Mugen87 / https://github.com/Mugen87

+ 1 - 1
examples/misc_controls_transform.html

@@ -83,7 +83,7 @@
 
 						case 17: // Ctrl
 							control.setTranslationSnap( 100 );
-							control.setRotationSnap( Math.degToRad( 15 ) );
+							control.setRotationSnap( THREE.Math.degToRad( 15 ) );
 							break;
 
 						case 87: // W

BIN
examples/models/ctm/LeePerry.ctm


BIN
examples/models/ctm/WaltHead.ctm


BIN
examples/models/ctm/ben.ctm


BIN
examples/models/ctm/camaro/camaro.ctm


+ 0 - 113
examples/models/ctm/camaro/camaro.js

@@ -1,113 +0,0 @@
-{
-"data" : "camaro.ctm",
-
-"offsets": [ 0, 39262, 79223, 83542, 94677, 95890, 144902, 470461 ],
-
-"materials" :
-	[
-	{
-	"DbgColor" : 15658734,
-	"DbgIndex" : 0,
-	"DbgName" : "Body_car-ao",
-	"colorDiffuse" : [0.1816, 0.3264, 0.3704],
-	"colorSpecular" : [2.0, 2.0, 2.0],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 778.431373,
-	"opacity" : 1.0
-	},
-
-	{
-	"DbgColor" : 15597568,
-	"DbgIndex" : 1,
-	"DbgName" : "tire_car-ao",
-	"colorDiffuse" : [0.2168, 0.2168, 0.2104],
-	"colorSpecular" : [0.1, 0.1, 0.1],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 15.686275,
-	"opacity" : 1.0
-	},
-
-	{
-	"DbgColor" : 60928,
-	"DbgIndex" : 2,
-	"DbgName" : "black2_car-ao",
-	"colorDiffuse" : [0.0, 0.0, 0.0],
-	"colorSpecular" : [0.0, 0.0, 0.0],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 0.0,
-	"opacity" : 1.0
-	},
-
-	{
-	"DbgColor" : 238,
-	"DbgIndex" : 3,
-	"DbgName" : "tireling_car-ao",
-	"colorDiffuse" : [0.4, 0.4, 0.4],
-	"colorSpecular" : [0.2, 0.2, 0.2],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 15.686275,
-	"opacity" : 1.0
-	},
-
-	{
-	"DbgColor" : 15658496,
-	"DbgIndex" : 4,
-	"DbgName" : "glass_car-ao",
-	"colorDiffuse" : [0.16, 0.248, 0.2448],
-	"colorSpecular" : [2.0, 2.0, 2.0],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 778.431373,
-	"opacity" : 0.34
-	},
-
-	{
-	"DbgColor" : 61166,
-	"DbgIndex" : 5,
-	"DbgName" : "black_car-ao",
-	"colorDiffuse" : [0.0816, 0.0816, 0.0816],
-	"colorSpecular" : [0.2, 0.2, 0.2],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 3.921569,
-	"opacity" : 1.0
-	},
-
-	{
-	"DbgColor" : 15597806,
-	"DbgIndex" : 6,
-	"DbgName" : "mirror_car-ao",
-	"colorDiffuse" : [0.24, 0.24, 0.24],
-	"colorSpecular" : [2.0, 2.0, 2.0],
-	"illumination" : 2,
-	"mapDiffuse" : "car-ao.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 778.431373,
-	"opacity" : 1.0
-	},
-
-
-	{
-	"DbgColor" : 3744854,
-	"DbgIndex" : 8,
-	"DbgName" : "Material.001_plane-ao-256",
-	"colorDiffuse" : [0.798635, 0.776149, 0.8],
-	"colorSpecular" : [0.5, 0.5, 0.5],
-	"illumination" : 2,
-	"mapDiffuse" : "plane-ao-256.png",
-	"opticalDensity" : 1.0,
-	"specularCoef" : 96.078431,
-	"opacity" : 1.0
-	}
-	]
-}

BIN
examples/models/ctm/camaro/car-ao.png


BIN
examples/models/ctm/camaro/plane-ao-256.png


BIN
examples/models/ctm/hand.ctm


BIN
examples/textures/nvidia_tentacle/tentacle_object_space.png


BIN
examples/textures/nvidia_tentacle/tentacle_tangent_space.png


+ 1 - 0
examples/textures/pbr/Scratched_gold/Scratched_gold.txt

@@ -0,0 +1 @@
+https://www.cgbookcase.com/textures/scratched-gold-01

BIN
examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_AO.png


BIN
examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Base_Color.png


BIN
examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Height.png


BIN
examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png


BIN
examples/textures/pbr/Scratched_gold/Scratched_gold_01_1K_Roughness.png


+ 7 - 3
examples/webgl_furnace_test.html

@@ -60,18 +60,22 @@
 
 			function createObjects() {
 
-				var geo = new THREE.SphereBufferGeometry( 0.4, 32, 32 );
+				var geometry = new THREE.SphereBufferGeometry( 0.4, 32, 32 );
+
 				var count = 10;
+
 				for ( var x = 0; x <= count; x ++ ) {
 
-					var mesh = new THREE.Mesh( geo, new THREE.MeshPhysicalMaterial( {
+					var material = new THREE.MeshPhysicalMaterial( {
 						roughness: x / count,
 						metalness: 1,
 						color: 0xffffff,
 						envMap: radianceMap,
 						envMapIntensity: 1,
 						reflectivity: 1,
-					} ) );
+					} );
+
+					var mesh = new THREE.Mesh( geometry, material );
 					mesh.position.x = x - ( Math.floor( count / 2 ) );
 					scene.add( mesh );
 

+ 0 - 242
examples/webgl_loader_ctm_materials.html

@@ -1,242 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - CTM loader materials</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-	<body>
-		<div id="info">
-			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl -
-			using <a href="https://github.com/jcmellado/js-openctm"  target="_blank" rel="noopener">js-openctm</a><br/>
-			camaro by <a href="http://www.turbosquid.com/3d-models/blender-camaro/411348" target="_blank" rel="noopener">dskfnwn</a> -
-			skybox by <a href="http://ict.debevec.org/~debevec/" target="_blank" rel="noopener">Paul Debevec</a>
-		</div>
-
-		<script type="module">
-
-			import * as THREE from '../build/three.module.js';
-
-			import Stats from './jsm/libs/stats.module.js';
-
-			import { CTMLoader } from './jsm/loaders/ctm/CTMLoader.js';
-			import { OrbitControls } from './jsm/controls/OrbitControls.js';
-
-			var SCREEN_WIDTH = window.innerWidth;
-			var SCREEN_HEIGHT = window.innerHeight;
-
-			var container, stats;
-
-			var camera, scene, controls;
-			var renderer;
-
-			var textureCube;
-
-			init();
-			animate();
-
-			function init() {
-
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				// CAMERA
-
-				camera = new THREE.PerspectiveCamera( 30, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
-				camera.position.set( 185, 40, 170 );
-
-				// SCENE
-
-				var r = "textures/cube/pisa/";
-				var urls = [
-					r + "px.png", r + "nx.png",
-					r + "py.png", r + "ny.png",
-					r + "pz.png", r + "nz.png"
-				];
-
-				textureCube = new THREE.CubeTextureLoader().load( urls );
-
-				scene = new THREE.Scene();
-				scene.background = textureCube;
-
-				// LIGHTS
-
-				var light = new THREE.PointLight( 0xffffff, 1 );
-				light.position.set( 2, 5, 1 );
-				light.position.multiplyScalar( 30 );
-				scene.add( light );
-
-				var light = new THREE.PointLight( 0xffffff, 0.75 );
-				light.position.set( - 12, 4.6, 2.4 );
-				light.position.multiplyScalar( 30 );
-				scene.add( light );
-
-				scene.add( new THREE.AmbientLight( 0x050505 ) );
-
-				// RENDERER
-
-				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
-				renderer.domElement.style.position = "relative";
-				container.appendChild( renderer.domElement );
-
-				controls = new OrbitControls( camera, renderer.domElement );
-				controls.maxPolarAngle = Math.PI / 2;
-				controls.minDistance = 150;
-				controls.maxDistance = 500;
-
-				// STATS
-
-				stats = new Stats();
-				container.appendChild( stats.dom );
-
-				// EVENTS
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-				// LOADER
-
-				var start = Date.now();
-
-				// new way via CTMLoader and separate parts
-
-				var position = new THREE.Vector3( - 105, - 78, - 30 );
-				var scale = new THREE.Vector3( 30, 30, 30 );
-
-				var loader = new CTMLoader();
-				loader.setWorkerPath( "js/loaders/ctm/CTMWorker.js" );
-
-				loader.loadParts( "models/ctm/camaro/camaro.js", function ( geometries, materials ) {
-
-					hackMaterials( materials );
-
-					for ( var i = 0; i < geometries.length; i ++ ) {
-
-						var mesh = new THREE.Mesh( geometries[ i ], materials[ i ] );
-						mesh.position.copy( position );
-						mesh.scale.copy( scale );
-						scene.add( mesh );
-
-					}
-
-					var end = Date.now();
-
-					console.log( "load time:", end - start, "ms" );
-
-				}, { useWorker: true } );
-
-			}
-
-			//
-
-			function hackMaterials( materials ) {
-
-				for ( var i = 0; i < materials.length; i ++ ) {
-
-					var m = materials[ i ];
-
-					if ( m.name.indexOf( "Body" ) !== - 1 ) {
-
-						var mm = new THREE.MeshStandardMaterial();
-
-						mm.color.setHex( 0x000000 );
-						mm.lightMap = m.map;
-						mm.envMap = textureCube;
-						mm.metalness = 0.5;
-						mm.roughness = 0.3;
-
-						materials[ i ] = mm;
-
-					} else if ( m.name.indexOf( "tire_car" ) !== - 1 ) {
-
-						var mm = new THREE.MeshStandardMaterial();
-
-						mm.color.setHex( 0x000000 );
-						mm.lightMap = m.map;
-						mm.metalness = 0.1;
-						mm.roughness = 0.9;
-
-						materials[ i ] = mm;
-
-					} else if ( m.name.indexOf( "mirror" ) !== - 1 ) {
-
-						var mm = new THREE.MeshStandardMaterial();
-
-						mm.color.setHex( 0x808080 );
-						mm.lightMap = m.map;
-						mm.envMap = textureCube;
-						mm.metalness = 0.9;
-						mm.roughness = 0.5;
-
-						materials[ i ] = mm;
-
-					} else if ( m.name.indexOf( "glass" ) !== - 1 ) {
-
-						var mm = new THREE.MeshStandardMaterial();
-
-						mm.color.copy( m.color );
-						mm.envMap = textureCube;
-						mm.metalness = 1;
-						mm.roughtness = 0.1;
-						mm.opacity = m.opacity;
-						mm.transparent = true;
-
-						materials[ i ] = mm;
-
-					} else if ( m.name.indexOf( "Material.001" ) !== - 1 ) {
-
-						var mm = new THREE.MeshPhongMaterial( { map: m.map } );
-
-						mm.specularMap = m.map;
-						mm.shininess = 30;
-						mm.color.setHex( 0x404040 );
-
-						materials[ i ] = mm;
-
-					}
-
-					materials[ i ].side = THREE.DoubleSide;
-
-				}
-
-			}
-
-			//
-
-			function onWindowResize() {
-
-				SCREEN_WIDTH = window.innerWidth;
-				SCREEN_HEIGHT = window.innerHeight;
-
-				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
-
-				camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
-				camera.updateProjectionMatrix();
-
-			}
-
-			//
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				render();
-				stats.update();
-
-			}
-
-			function render() {
-
-				renderer.render( scene, camera );
-
-			}
-
-		</script>
-
-	</body>
-</html>

+ 0 - 3
examples/webgl_loader_stl.html

@@ -181,9 +181,6 @@
 				directionalLight.shadow.camera.near = 1;
 				directionalLight.shadow.camera.far = 4;
 
-				directionalLight.shadow.mapSize.width = 1024;
-				directionalLight.shadow.mapSize.height = 1024;
-
 				directionalLight.shadow.bias = - 0.002;
 
 			}

+ 13 - 8
examples/webgl_materials_clearcoat_normalmap.html

@@ -85,9 +85,9 @@
 						normalMap.wrapS = THREE.RepeatWrapping;
 						normalMap.wrapT = THREE.RepeatWrapping;
 
-						var clearCoatNormaMap = textureLoader.load( "textures/waternormals.jpg" );
-						clearCoatNormaMap.wrapS = THREE.RepeatWrapping;
-						clearCoatNormaMap.wrapT = THREE.RepeatWrapping;
+						var normalMap2 = textureLoader.load( "textures/water/Water_1_M_Normal.jpg" );
+
+						var clearCoatNormaMap = textureLoader.load( "textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png" );
 
 						//
 
@@ -119,9 +119,11 @@
 
 						var material = new THREE.MeshPhysicalMaterial( {
 							clearCoat: 1.0,
+							metalness: 0.0,
+							color: 0xff0000,
 							envMap: hdrCubeRenderTarget.texture,
-							map: diffuse,
-							clearCoatNormalMap: clearCoatNormaMap
+							clearCoatNormalMap: clearCoatNormaMap,
+							clearCoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
 						} );
 						var mesh = new THREE.Mesh( geometry, material );
 						mesh.position.x = - 100;
@@ -132,10 +134,13 @@
 
 						var material = new THREE.MeshPhysicalMaterial( {
 							clearCoat: 1.0,
+							metalness: 1.0,
+							color: 0xff0000,
 							envMap: hdrCubeRenderTarget.texture,
-							map: diffuse,
-							normalMap: normalMap,
-							clearCoatNormalMap: clearCoatNormaMap
+							normalMap: normalMap2,
+							normalScale: new THREE.Vector2( 0.15, 0.15 ),
+							clearCoatNormalMap: clearCoatNormaMap,
+							clearCoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
 						} );
 						var mesh = new THREE.Mesh( geometry, material );
 						mesh.position.x = 100;

+ 145 - 69
examples/webgl_materials_nodes.html

@@ -71,63 +71,56 @@
 
 			}
 
-			var cubemap = function () {
+			var premTexture, pmremCube, pmremGenerator, pmremCubeUVPacker, premSize = 1024;
 
-				var path = "textures/cube/Park2/";
-				var format = '.jpg';
-				var urls = [
-					path + 'posx' + format, path + 'negx' + format,
-					path + 'posy' + format, path + 'negy' + format,
-					path + 'posz' + format, path + 'negz' + format
-				];
+			function updatePREM( textureCube ) {
 
-				var textureCube = new THREE.CubeTextureLoader().load( urls );
-				textureCube.format = THREE.RGBFormat;
+				pmremCube = pmremCube || textureCube;
 
-				library[ textureCube.uuid ] = textureCube;
+				if ( ! pmremCube || ! renderer ) return;
 
-				return textureCube;
+				var minFilter = pmremCube.minFilter;
+				var magFilter = pmremCube.magFilter;
+				var generateMipmaps = pmremCube.generateMipmaps;
 
-			}();
+				pmremGenerator = new PMREMGenerator( pmremCube, undefined, premSize / 4 );
+				pmremGenerator.update( renderer );
 
-			function generatePREM( cubeMap, textureSize ) {
+				pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
+				pmremCubeUVPacker.update( renderer );
 
-				textureSize = textureSize || 1024;
+				pmremCube.minFilter = minFilter;
+				pmremCube.magFilter = magFilter;
+				pmremCube.generateMipmaps = pmremCube.generateMipmaps;
+				pmremCube.needsUpdate = true;
 
-				var pmremGenerator = new PMREMGenerator( cubeMap, undefined, textureSize / 4 );
-				pmremGenerator.update( renderer );
+				premTexture = pmremCubeUVPacker.CubeUVRenderTarget.texture
 
-				var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
-				pmremCubeUVPacker.update( renderer );
+				library[ premTexture.uuid ] = premTexture;
 
 				pmremGenerator.dispose();
 				pmremCubeUVPacker.dispose();
 
-				return pmremCubeUVPacker.CubeUVRenderTarget.texture;
-
 			}
 
-			var premTexture;
-
-			function getPREM( callback, textureSize ) {
-
-				if ( premTexture ) return callback( premTexture );
-
-				var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
-				var hdrCubeMap = new HDRCubeTextureLoader()
-					.setPath( './textures/cube/pisaHDR/' )
-					.setDataType( THREE.UnsignedByteType )
-					.load( hdrUrls, function () {
+			var cubemap = function () {
 
-						premTexture = generatePREM( hdrCubeMap, textureSize );
+				var path = "textures/cube/Park2/";
+				var format = '.jpg';
+				var urls = [
+					path + 'posx' + format, path + 'negx' + format,
+					path + 'posy' + format, path + 'negy' + format,
+					path + 'posz' + format, path + 'negz' + format
+				];
 
-						library[ premTexture.uuid ] = premTexture;
+				var textureCube = new THREE.CubeTextureLoader().load( urls, updatePREM );
+				textureCube.format = THREE.RGBFormat;
 
-						callback( premTexture );
+				library[ textureCube.uuid ] = textureCube;
 
-					} );
+				return textureCube;
 
-			}
+			}();
 
 			window.addEventListener( 'load', init );
 
@@ -176,6 +169,8 @@
 				library[ camera.uuid ] = camera;
 				library[ mesh.uuid ] = mesh;
 
+				updatePREM();
+
 				window.addEventListener( 'resize', onWindowResize, false );
 
 				updateMaterial();
@@ -226,6 +221,7 @@
 					'adv / expression': 'expression',
 					'adv / sss': 'sss',
 					'adv / translucent': 'translucent',
+					'adv / bias': 'bias',
 					'node / position': 'node-position',
 					'node / normal': 'node-normal',
 					'node / reflect': 'node-reflect',
@@ -504,14 +500,8 @@
 						mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
 						mtl.normal.scale = normalMask;
 
-						getPREM(function(texture) {
-
-							var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( texture ) );
-
-							mtl.environment = new Nodes.OperatorNode( envNode, intensity, Nodes.OperatorNode.MUL );
-							mtl.needsUpdate = true;
-
-						});
+						var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( premTexture ) );
+						mtl.environment = new Nodes.OperatorNode( envNode, intensity, Nodes.OperatorNode.MUL );
 
 						// GUI
 
@@ -587,18 +577,13 @@
 						mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
 						mtl.normal.scale = normalScale;
 
-						getPREM(function(texture) {
-
-							var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( texture ) );
-
-							var subSlotNode = new Nodes.SubSlotNode();
-							subSlotNode.slots['radiance'] = new Nodes.OperatorNode( radiance, envNode, Nodes.OperatorNode.MUL );
-							subSlotNode.slots['irradiance'] = new Nodes.OperatorNode( irradiance, envNode, Nodes.OperatorNode.MUL );
+						var envNode = new Nodes.TextureCubeNode( new Nodes.TextureNode( premTexture ) );
 
-							mtl.environment = subSlotNode;
-							mtl.needsUpdate = true;
+						var subSlotNode = new Nodes.SubSlotNode();
+						subSlotNode.slots['radiance'] = new Nodes.OperatorNode( radiance, envNode, Nodes.OperatorNode.MUL );
+						subSlotNode.slots['irradiance'] = new Nodes.OperatorNode( irradiance, envNode, Nodes.OperatorNode.MUL );
 
-						});
+						mtl.environment = subSlotNode
 
 						// GUI
 
@@ -757,6 +742,7 @@
 						//mtl.reflectivity = // reflectivity (float)
 						//mtl.clearCoat = // clearCoat (float)
 						//mtl.clearCoatRoughness = // clearCoatRoughness (float)
+						//mtl.clearCoatNormal = // clearCoatNormal (vec3)
 						//mtl.normal = // normal (vec3)
 						//mtl.emissive = // emissive color (vec3)
 						//mtl.ambient = // ambient color (vec3)
@@ -769,6 +755,7 @@
 						var mask = new Nodes.SwitchNode( new Nodes.TextureNode( getTexture( "decalDiffuse" ) ), 'w' );
 
 						var normalScale = new Nodes.FloatNode( .3 );
+						var clearCoatNormalScale = new Nodes.FloatNode( .1 );
 
 						var roughnessA = new Nodes.FloatNode( .5 );
 						var metalnessA = new Nodes.FloatNode( .5 );
@@ -800,12 +787,20 @@
 							Nodes.OperatorNode.MUL
 						);
 
+						var clearCoatNormalMask = new Nodes.OperatorNode(
+							mask,
+							clearCoatNormalScale,
+							Nodes.OperatorNode.MUL
+						);
+
 						mtl.color = new Nodes.ColorNode( 0xEEEEEE );
 						mtl.roughness = roughness;
 						mtl.metalness = metalness;
 						mtl.reflectivity = reflectivity;
 						mtl.clearCoat = clearCoat;
 						mtl.clearCoatRoughness = clearCoatRoughness;
+						mtl.clearCoatNormal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
+						mtl.clearCoatNormal.scale = clearCoatNormalMask;
 						mtl.environment = new Nodes.CubeTextureNode( cubemap );
 						mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
 						mtl.normal.scale = normalMask;
@@ -836,6 +831,12 @@
 
 						}, false, 0, 1 );
 
+						addGui( 'clearCoatNormalScale', clearCoatNormalScale.value, function ( val ) {
+
+							clearCoatNormalScale.value = val;
+
+						}, false, 0, 1 );
+
 						addGui( 'roughnessA', roughnessA.value, function ( val ) {
 
 							roughnessA.value = val;
@@ -2483,6 +2484,67 @@
 
 						break;
 
+					case 'bias':
+
+						// MATERIAL
+
+						var bias = new Nodes.FloatNode( .5 );
+						var maxMIPLevel = new Nodes.MaxMIPLevelNode( new Nodes.TextureCubeNode( cubemap ) );
+						var mipsBias = new Nodes.OperatorNode( bias, maxMIPLevel, Nodes.OperatorNode.MUL );
+
+						mtl = new Nodes.PhongNodeMaterial();
+						mtl.color.value.setHex( 0xFFFFFF );
+
+						function biasMode( val ) {
+
+							switch( val ) {
+
+								case 'prem':
+
+									mtl.color = new Nodes.TextureCubeNode( new Nodes.TextureNode( premTexture ), undefined, undefined, bias );
+
+									break;
+
+								case 'lod':
+
+									var textureCubeFunction = new Nodes.FunctionNode( 'vec4 textureCubeLodEXT( samplerCube texture, vec3 uv, float bias );', undefined, { shaderTextureLOD: true } 								);
+
+									mtl.color = new Nodes.FunctionCallNode( textureCubeFunction, [ new Nodes.CubeTextureNode( cubemap ), new Nodes.ReflectNode(), mipsBias ] );
+
+									break;
+
+								case 'basic':
+
+									var textureCubeFunction = new Nodes.FunctionNode( 'vec4 textureCube( samplerCube texture, vec3 uv, float bias );' );
+
+									mtl.color = new Nodes.FunctionCallNode( textureCubeFunction, [ new Nodes.CubeTextureNode( cubemap ), new Nodes.ReflectNode(), mipsBias ] );
+
+									break;
+
+							}
+
+							mtl.needsUpdate = true;
+
+						}
+
+						biasMode( 'prem' );
+
+						// GUI
+
+						addGui( 'scope', {
+							PREM: 'prem',
+							LOD: 'lod',
+							BASIC: 'basic'
+						}, biasMode );
+
+						addGui( 'bias', bias.value, function ( val ) {
+
+							bias.value = val;
+
+						}, false, 0, 1 );
+
+						break;
+
 					case 'node-position':
 
 						// MATERIAL
@@ -2534,28 +2596,42 @@
 
 					case 'node-reflect':
 
-						// MATERIAL
+							// MATERIAL
 
-						var node = new Nodes.ReflectNode();
+							var node = new Nodes.ReflectNode();
 
-						mtl = new Nodes.PhongNodeMaterial();
-						mtl.environment = new Nodes.CubeTextureNode( cubemap, node );
+							var nodeMaterial = new Nodes.StandardNodeMaterial();
+							nodeMaterial.environment = new Nodes.CubeTextureNode( cubemap, node );
+							nodeMaterial.roughness.value = .5;
+							nodeMaterial.metalness.value = 1;
 
-						// GUI
+							var standardMaterial = new THREE.MeshStandardMaterial( {
+								color: nodeMaterial.color.value,
+								side: defaultSide,
+								envMap: cubemap,
+								roughness: nodeMaterial.roughness.value,
+								metalness: 1
+							} );
 
-						addGui( 'scope', {
-							vector: Nodes.ReflectNode.VECTOR,
-							cube: Nodes.ReflectNode.CUBE,
-							sphere: Nodes.ReflectNode.SPHERE
-						}, function ( val ) {
+							mtl = nodeMaterial;
 
-							node.scope = val;
+							// GUI
 
-							mtl.needsUpdate = true;
+							addGui( 'node', true, function ( val ) {
 
-						} );
+								mtl = val ? nodeMaterial : standardMaterial;
+								mesh.material = mtl;
 
-						break;
+							} );
+
+							addGui( 'roughness', nodeMaterial.roughness.value, function ( val ) {
+
+								nodeMaterial.roughness.value = val;
+								standardMaterial.roughness = val;
+
+							}, false, 0, 1 );
+
+							break;
 
 
 					case 'varying':

+ 3 - 1
examples/webgl_shadowmap_performance.html

@@ -100,6 +100,8 @@
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				container.appendChild( renderer.domElement );
 
+				renderer.gammaOutput = true;
+				renderer.gammaFactor = 2.2;
 				renderer.autoClear = false;
 
 				//
@@ -137,7 +139,7 @@
 				// GROUND
 
 				var geometry = new THREE.PlaneBufferGeometry( 100, 100 );
-				var planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffdd99 } );
+				var planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffb851 } );
 
 				var ground = new THREE.Mesh( geometry, planeMaterial );
 

+ 242 - 164
package-lock.json

@@ -1,22 +1,22 @@
 {
   "name": "three",
-  "version": "0.105.1",
+  "version": "0.107.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
     "@babel/code-frame": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
-      "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+      "version": "7.5.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+      "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
       "dev": true,
       "requires": {
         "@babel/highlight": "^7.0.0"
       }
     },
     "@babel/highlight": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
-      "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+      "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
       "dev": true,
       "requires": {
         "chalk": "^2.0.0",
@@ -36,55 +36,81 @@
       "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
       "dev": true
     },
+    "@types/json-schema": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz",
+      "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==",
+      "dev": true
+    },
     "@types/node": {
-      "version": "12.0.10",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz",
-      "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==",
+      "version": "12.7.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
+      "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==",
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz",
-      "integrity": "sha512-mXv9ccCou89C8/4avKHuPB2WkSZyY/XcTQUXd5LFZAcLw1I3mWYVjUu6eS9Ja0QkP/ClolbcW9tb3Ov/pMdcqw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.0.0.tgz",
+      "integrity": "sha512-Mo45nxTTELODdl7CgpZKJISvLb+Fu64OOO2ZFc2x8sYSnUpFrBUW3H+H/ZGYmEkfnL6VkdtOSxgdt+Av79j0sA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "1.11.0",
-        "eslint-utils": "^1.3.1",
+        "@typescript-eslint/experimental-utils": "2.0.0",
+        "eslint-utils": "^1.4.0",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^2.0.1",
-        "tsutils": "^3.7.0"
+        "tsutils": "^3.14.0"
+      },
+      "dependencies": {
+        "eslint-utils": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz",
+          "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==",
+          "dev": true,
+          "requires": {
+            "eslint-visitor-keys": "^1.0.0"
+          }
+        }
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.11.0.tgz",
-      "integrity": "sha512-7LbfaqF6B8oa8cp/315zxKk8FFzosRzzhF8Kn/ZRsRsnpm7Qcu25cR/9RnAQo5utZ2KIWVgaALr+ZmcbG47ruw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.0.0.tgz",
+      "integrity": "sha512-XGJG6GNBXIEx/mN4eTRypN/EUmsd0VhVGQ1AG+WTgdvjHl0G8vHhVBHrd/5oI6RRYBRnedNymSYWW1HAdivtmg==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/typescript-estree": "1.11.0",
+        "@types/json-schema": "^7.0.3",
+        "@typescript-eslint/typescript-estree": "2.0.0",
         "eslint-scope": "^4.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.11.0.tgz",
-      "integrity": "sha512-5xBExyXaxVyczrZvbRKEXvaTUFFq7gIM9BynXukXZE0zF3IQP/FxF4mPmmh3gJ9egafZFqByCpPTFm3dk4SY7Q==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.0.0.tgz",
+      "integrity": "sha512-ibyMBMr0383ZKserIsp67+WnNVoM402HKkxqXGlxEZsXtnGGurbnY90pBO3e0nBUM7chEEOcxUhgw9aPq7fEBA==",
       "dev": true,
       "requires": {
         "@types/eslint-visitor-keys": "^1.0.0",
-        "@typescript-eslint/experimental-utils": "1.11.0",
-        "@typescript-eslint/typescript-estree": "1.11.0",
+        "@typescript-eslint/experimental-utils": "2.0.0",
+        "@typescript-eslint/typescript-estree": "2.0.0",
         "eslint-visitor-keys": "^1.0.0"
       }
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.11.0.tgz",
-      "integrity": "sha512-fquUHF5tAx1sM2OeRCC7wVxFd1iMELWMGCzOSmJ3pLzArj9+kRixdlC4d5MncuzXpjEqc6045p3KwM0o/3FuUA==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.0.0.tgz",
+      "integrity": "sha512-NXbmzA3vWrSgavymlzMWNecgNOuiMMp62MO3kI7awZRLRcsA1QrYWo6q08m++uuAGVbXH/prZi2y1AWuhSu63w==",
       "dev": true,
       "requires": {
         "lodash.unescape": "4.0.1",
-        "semver": "5.5.0"
+        "semver": "^6.2.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
       }
     },
     "acorn": {
@@ -100,9 +126,9 @@
       "dev": true
     },
     "ajv": {
-      "version": "6.10.0",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
-      "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
+      "version": "6.10.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+      "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
       "dev": true,
       "requires": {
         "fast-deep-equal": "^2.0.1",
@@ -112,10 +138,13 @@
       }
     },
     "ansi-escapes": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
-      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
-      "dev": true
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz",
+      "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.5.2"
+      }
     },
     "ansi-regex": {
       "version": "3.0.0",
@@ -210,12 +239,12 @@
       "dev": true
     },
     "cli-cursor": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
-      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
       "dev": true,
       "requires": {
-        "restore-cursor": "^2.0.0"
+        "restore-cursor": "^3.1.0"
       }
     },
     "cli-width": {
@@ -463,9 +492,9 @@
       }
     },
     "emoji-regex": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
     "end-of-stream": {
@@ -499,9 +528,9 @@
       "dev": true
     },
     "eslint": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz",
-      "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz",
+      "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -510,7 +539,7 @@
         "cross-spawn": "^6.0.5",
         "debug": "^4.0.1",
         "doctrine": "^3.0.0",
-        "eslint-scope": "^4.0.3",
+        "eslint-scope": "^5.0.0",
         "eslint-utils": "^1.3.1",
         "eslint-visitor-keys": "^1.0.0",
         "espree": "^6.0.0",
@@ -518,35 +547,61 @@
         "esutils": "^2.0.2",
         "file-entry-cache": "^5.0.1",
         "functional-red-black-tree": "^1.0.1",
-        "glob-parent": "^3.1.0",
+        "glob-parent": "^5.0.0",
         "globals": "^11.7.0",
         "ignore": "^4.0.6",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
-        "inquirer": "^6.2.2",
+        "inquirer": "^6.4.1",
         "is-glob": "^4.0.0",
         "js-yaml": "^3.13.1",
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "levn": "^0.3.0",
-        "lodash": "^4.17.11",
+        "lodash": "^4.17.14",
         "minimatch": "^3.0.4",
         "mkdirp": "^0.5.1",
         "natural-compare": "^1.4.0",
         "optionator": "^0.8.2",
         "progress": "^2.0.0",
         "regexpp": "^2.0.1",
-        "semver": "^5.5.1",
-        "strip-ansi": "^4.0.0",
-        "strip-json-comments": "^2.0.1",
+        "semver": "^6.1.2",
+        "strip-ansi": "^5.2.0",
+        "strip-json-comments": "^3.0.1",
         "table": "^5.2.3",
-        "text-table": "^0.2.0"
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
       },
       "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "eslint-scope": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
+          "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+          "dev": true,
+          "requires": {
+            "esrecurse": "^4.1.0",
+            "estraverse": "^4.1.1"
+          }
+        },
         "semver": {
-          "version": "5.7.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
-          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
           "dev": true
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
         }
       }
     },
@@ -629,9 +684,9 @@
       "dev": true
     },
     "esutils": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
     "eventemitter3": {
@@ -656,9 +711,9 @@
       }
     },
     "external-editor": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
-      "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
       "dev": true,
       "requires": {
         "chardet": "^0.7.0",
@@ -694,9 +749,9 @@
       "dev": true
     },
     "figures": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
-      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz",
+      "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==",
       "dev": true,
       "requires": {
         "escape-string-regexp": "^1.0.5"
@@ -799,24 +854,12 @@
       }
     },
     "glob-parent": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
+      "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
       "dev": true,
       "requires": {
-        "is-glob": "^3.1.0",
-        "path-dirname": "^1.0.0"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.0"
-          }
-        }
+        "is-glob": "^4.0.1"
       }
     },
     "globals": {
@@ -826,17 +869,17 @@
       "dev": true
     },
     "google-closure-compiler": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20190618.0.0.tgz",
-      "integrity": "sha512-f5zJQSWnlawuQlGo9TxcuprBGxIS5ksikj/pjDxdlRTXWt3dOKqEFA3CN8QshNYDl6oEjtO/ehiNx64fqEgkUA==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20190729.0.0.tgz",
+      "integrity": "sha512-z+egAPJmOkEgop6ZUjrE+bIOKqbKdx57J+SAGVgq9DAQnr3yVxQ+h9b8PSLcpgzMw/Y0rMCHpM3HkCTE2Y1ePQ==",
       "dev": true,
       "requires": {
         "chalk": "2.x",
-        "google-closure-compiler-java": "^20190618.0.0",
-        "google-closure-compiler-js": "^20190618.0.0",
-        "google-closure-compiler-linux": "^20190618.0.0",
-        "google-closure-compiler-osx": "^20190618.0.0",
-        "google-closure-compiler-windows": "^20190618.0.0",
+        "google-closure-compiler-java": "^20190729.0.0",
+        "google-closure-compiler-js": "^20190729.0.0",
+        "google-closure-compiler-linux": "^20190729.0.0",
+        "google-closure-compiler-osx": "^20190729.0.0",
+        "google-closure-compiler-windows": "^20190729.0.0",
         "minimist": "1.x",
         "vinyl": "2.x",
         "vinyl-sourcemaps-apply": "^0.2.0"
@@ -851,35 +894,35 @@
       }
     },
     "google-closure-compiler-java": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20190618.0.0.tgz",
-      "integrity": "sha512-y6gAyJHMH5k2SM0qj/lyErEjmFGMvcT3glcx5Lsrl99CGwImJY0gDi+Cy9S0pczZvLG+wUW33AEfEW9MtdRZ6A==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20190729.0.0.tgz",
+      "integrity": "sha512-SGStZiyasN31tlmKUMMzCNRXTZqeij5N7iEeHSIGOsUdlKw5Zj8VPbaqbCcHvfgpQaUbn29zCTgTYiYFJRkbwA==",
       "dev": true
     },
     "google-closure-compiler-js": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler-js/-/google-closure-compiler-js-20190618.0.0.tgz",
-      "integrity": "sha512-Xc/84uN00GLUzRwWx25Lg11VuSTz/1odWy0d+pM3F/26fXqi16ZhhkVoe6VVFklSSMVDyGTPAH0ZkyfZhinKhA==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler-js/-/google-closure-compiler-js-20190729.0.0.tgz",
+      "integrity": "sha512-ZDJRK3eiNfKLsO1+uVxHnvB8RTQMLHlJNKouMBcPzPNOAurEFRboHf5nx/0llO+MXVWZDIPhxpbuuD3WnQsprA==",
       "dev": true
     },
     "google-closure-compiler-linux": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20190618.0.0.tgz",
-      "integrity": "sha512-idWJ/sFmOSYfCmDbCVMcaBX2NCUCxukjt2UzT5PJmpoVLmJuwwoVbpQZVfvgRvEH4bLzvvcvJRfn5nIiODjjaQ==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20190729.0.0.tgz",
+      "integrity": "sha512-W4TRrQ1+FrCFu3yn4M0JTWTJCFsqLlBjkliB/xLFuWb5E7XQ8Xe/sPtkmeNzCo+ftd6B/KD7acaH2oMU0brMag==",
       "dev": true,
       "optional": true
     },
     "google-closure-compiler-osx": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20190618.0.0.tgz",
-      "integrity": "sha512-OzXMW+hKq76NJt9MIRQhV7pHTzHISCXtg+LZUPcqNT+V/tcvOlrSaflokmvyJPzEVk889QArYp8JgZ7mqHuY5g==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20190729.0.0.tgz",
+      "integrity": "sha512-g3mLUVFD85nRwVyl8X6ywZ14YFP6fo+kXdIvrBGxxUkUU8VbeIgr6GlgtAUS0eZ0WVs2hr5w6kjk7+5kyeBSJg==",
       "dev": true,
       "optional": true
     },
     "google-closure-compiler-windows": {
-      "version": "20190618.0.0",
-      "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20190618.0.0.tgz",
-      "integrity": "sha512-2qzY/fQneEg+zFvRGoNeJkAY6VU5OcmBT37l+xTBGQvy/AauCLWltSGcOYNEi7Qd3OEBVIcAJ+CzNOV9s3jfwA==",
+      "version": "20190729.0.0",
+      "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20190729.0.0.tgz",
+      "integrity": "sha512-tzFfu2ixOoAWJUcCsagNFE4o0xHV+LI4cD3AmI36ll2e0NW1aUjDPhiG5TSfAnMIvZwgkikG5tqnPnk8ljauAA==",
       "dev": true,
       "optional": true
     },
@@ -958,9 +1001,9 @@
       "dev": true
     },
     "import-fresh": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
-      "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
+      "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==",
       "dev": true,
       "requires": {
         "parent-module": "^1.0.0",
@@ -990,22 +1033,22 @@
       "dev": true
     },
     "inquirer": {
-      "version": "6.4.1",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.4.1.tgz",
-      "integrity": "sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==",
+      "version": "6.5.1",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz",
+      "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==",
       "dev": true,
       "requires": {
-        "ansi-escapes": "^3.2.0",
+        "ansi-escapes": "^4.2.1",
         "chalk": "^2.4.2",
-        "cli-cursor": "^2.1.0",
+        "cli-cursor": "^3.1.0",
         "cli-width": "^2.0.0",
         "external-editor": "^3.0.3",
-        "figures": "^2.0.0",
-        "lodash": "^4.17.11",
-        "mute-stream": "0.0.7",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.15",
+        "mute-stream": "0.0.8",
         "run-async": "^2.2.0",
         "rxjs": "^6.4.0",
-        "string-width": "^2.1.0",
+        "string-width": "^4.1.0",
         "strip-ansi": "^5.1.0",
         "through": "^2.3.6"
       },
@@ -1016,6 +1059,29 @@
           "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
           "dev": true
         },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz",
+          "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^5.2.0"
+          }
+        },
         "strip-ansi": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -1214,7 +1280,7 @@
     },
     "mkdirp": {
       "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
       "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
       "dev": true,
       "requires": {
@@ -1228,9 +1294,9 @@
       "dev": true
     },
     "mute-stream": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
     "natural-compare": {
@@ -1288,20 +1354,12 @@
       }
     },
     "onetime": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
-      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+      "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
       "dev": true,
       "requires": {
-        "mimic-fn": "^1.0.0"
-      },
-      "dependencies": {
-        "mimic-fn": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-          "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
-          "dev": true
-        }
+        "mimic-fn": "^2.1.0"
       }
     },
     "opener": {
@@ -1355,7 +1413,7 @@
     },
     "os-tmpdir": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
       "dev": true
     },
@@ -1420,12 +1478,6 @@
         "json-parse-better-errors": "^1.0.1"
       }
     },
-    "path-dirname": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
-      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
-      "dev": true
-    },
     "path-exists": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -1434,7 +1486,7 @@
     },
     "path-is-absolute": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },
@@ -1622,12 +1674,12 @@
       "dev": true
     },
     "restore-cursor": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
-      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
       "dev": true,
       "requires": {
-        "onetime": "^2.0.0",
+        "onetime": "^5.1.0",
         "signal-exit": "^3.0.2"
       }
     },
@@ -1641,14 +1693,22 @@
       }
     },
     "rollup": {
-      "version": "1.16.2",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.16.2.tgz",
-      "integrity": "sha512-UAZxaQvH0klYZdF+90xv9nGb+m4p8jdoaow1VL5/RzDK/gN/4CjvaMmJNcOIv1/+gtzswKhAg/467mzF0sLpAg==",
+      "version": "1.19.4",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.19.4.tgz",
+      "integrity": "sha512-G24w409GNj7i/Yam2cQla6qV2k6Nug8bD2DZg9v63QX/cH/dEdbNJg8H4lUm5M1bRpPKRUC465Rm9H51JTKOfQ==",
       "dev": true,
       "requires": {
         "@types/estree": "0.0.39",
-        "@types/node": "^12.0.8",
-        "acorn": "^6.1.1"
+        "@types/node": "^12.6.9",
+        "acorn": "^6.2.1"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
+          "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
+          "dev": true
+        }
       }
     },
     "run-async": {
@@ -1756,7 +1816,7 @@
     "spdx-expression-parse": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=",
       "dev": true,
       "requires": {
         "spdx-exceptions": "^2.1.0",
@@ -1810,9 +1870,9 @@
       "dev": true
     },
     "strip-json-comments": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
+      "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
       "dev": true
     },
     "supports-color": {
@@ -1833,13 +1893,13 @@
       }
     },
     "table": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz",
-      "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==",
+      "version": "5.4.6",
+      "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+      "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
       "dev": true,
       "requires": {
-        "ajv": "^6.9.1",
-        "lodash": "^4.17.11",
+        "ajv": "^6.10.2",
+        "lodash": "^4.17.14",
         "slice-ansi": "^2.1.0",
         "string-width": "^3.0.0"
       },
@@ -1850,6 +1910,12 @@
           "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
           "dev": true
         },
+        "emoji-regex": {
+          "version": "7.0.3",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+          "dev": true
+        },
         "string-width": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
@@ -1880,7 +1946,7 @@
     },
     "through": {
       "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
       "dev": true
     },
@@ -1906,9 +1972,9 @@
       "dev": true
     },
     "tsutils": {
-      "version": "3.14.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz",
-      "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==",
+      "version": "3.17.1",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
+      "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
       "dev": true,
       "requires": {
         "tslib": "^1.8.1"
@@ -1923,6 +1989,12 @@
         "prelude-ls": "~1.1.2"
       }
     },
+    "type-fest": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz",
+      "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==",
+      "dev": true
+    },
     "typescript": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
@@ -1959,6 +2031,12 @@
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
       "dev": true
     },
+    "v8-compile-cache": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
+      "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
+      "dev": true
+    },
     "validate-npm-package-license": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -2015,7 +2093,7 @@
     },
     "wrap-ansi": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
       "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
       "dev": true,
       "requires": {

+ 5 - 5
package.json

@@ -67,17 +67,17 @@
   },
   "homepage": "https://threejs.org/",
   "devDependencies": {
-    "@typescript-eslint/eslint-plugin": "^1.11.0",
-    "@typescript-eslint/parser": "^1.11.0",
+    "@typescript-eslint/eslint-plugin": "^2.0.0",
+    "@typescript-eslint/parser": "^2.0.0",
     "concurrently": "^4.1.1",
-    "eslint": "^6.0.1",
+    "eslint": "^6.1.0",
     "eslint-config-mdcs": "^4.2.3",
     "eslint-plugin-html": "^6.0.0",
     "failonlyreporter": "^1.0.0",
-    "google-closure-compiler": "20190618.0.0",
+    "google-closure-compiler": "20190729.0.0",
     "http-server": "^0.11.1",
     "qunit": "^2.9.2",
-    "rollup": "^1.16.2",
+    "rollup": "^1.19.4",
     "typescript": "^3.5.2"
   },
   "jspm": {

+ 3 - 10
src/Three.Legacy.js

@@ -594,17 +594,10 @@ Object.assign( Matrix4.prototype, {
 	},
 	getPosition: function () {
 
-		var v1;
+		console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
+		return new Vector3().setFromMatrixColumn( this, 3 );
 
-		return function getPosition() {
-
-			if ( v1 === undefined ) v1 = new Vector3();
-			console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
-			return v1.setFromMatrixColumn( this, 3 );
-
-		};
-
-	}(),
+	},
 	setRotationFromQuaternion: function ( q ) {
 
 		console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );

+ 66 - 75
src/animation/PropertyBinding.js

@@ -9,7 +9,40 @@
  */
 
 // Characters [].:/ are reserved for track binding syntax.
-var RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
+var _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
+var _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
+
+// Attempts to allow node names from any language. ES5's `\w` regexp matches
+// only latin characters, and the unicode \p{L} is not yet supported. So
+// instead, we exclude reserved characters and match everything else.
+var _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
+var _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
+
+// Parent directories, delimited by '/' or ':'. Currently unused, but must
+// be matched to parse the rest of the track name.
+var _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
+
+// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
+var _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
+
+// Object on target node, and accessor. May not contain reserved
+// characters. Accessor may contain any character except closing bracket.
+var _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
+
+// Property and accessor. May not contain reserved characters. Accessor may
+// contain any non-bracket characters.
+var _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
+
+var _trackRe = new RegExp( ''
+	+ '^'
+	+ _directoryRe
+	+ _nodeRe
+	+ _objectRe
+	+ _propertyRe
+	+ '$'
+);
+
+var _supportedObjectNames = [ 'material', 'materials', 'bones' ];
 
 function Composite( targetGroup, path, optionalParsedPath ) {
 
@@ -109,101 +142,59 @@ Object.assign( PropertyBinding, {
 	 * @param {string} name Node name to be sanitized.
 	 * @return {string}
 	 */
-	sanitizeNodeName: ( function () {
-
-		var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' );
-
-		return function sanitizeNodeName( name ) {
-
-			return name.replace( /\s/g, '_' ).replace( reservedRe, '' );
-
-		};
-
-	}() ),
-
-	parseTrackName: function () {
-
-		// Attempts to allow node names from any language. ES5's `\w` regexp matches
-		// only latin characters, and the unicode \p{L} is not yet supported. So
-		// instead, we exclude reserved characters and match everything else.
-		var wordChar = '[^' + RESERVED_CHARS_RE + ']';
-		var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
-
-		// Parent directories, delimited by '/' or ':'. Currently unused, but must
-		// be matched to parse the rest of the track name.
-		var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar );
+	sanitizeNodeName: function ( name ) {
 
-		// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
-		var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot );
+		return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
 
-		// Object on target node, and accessor. May not contain reserved
-		// characters. Accessor may contain any character except closing bracket.
-		var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar );
-
-		// Property and accessor. May not contain reserved characters. Accessor may
-		// contain any non-bracket characters.
-		var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar );
-
-		var trackRe = new RegExp( ''
-			+ '^'
-			+ directoryRe
-			+ nodeRe
-			+ objectRe
-			+ propertyRe
-			+ '$'
-		);
-
-		var supportedObjectNames = [ 'material', 'materials', 'bones' ];
-
-		return function parseTrackName( trackName ) {
+	},
 
-			var matches = trackRe.exec( trackName );
+	parseTrackName: function ( trackName ) {
 
-			if ( ! matches ) {
+		var matches = _trackRe.exec( trackName );
 
-				throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
+		if ( ! matches ) {
 
-			}
+			throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
 
-			var results = {
-				// directoryName: matches[ 1 ], // (tschw) currently unused
-				nodeName: matches[ 2 ],
-				objectName: matches[ 3 ],
-				objectIndex: matches[ 4 ],
-				propertyName: matches[ 5 ], // required
-				propertyIndex: matches[ 6 ]
-			};
+		}
 
-			var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
+		var results = {
+			// directoryName: matches[ 1 ], // (tschw) currently unused
+			nodeName: matches[ 2 ],
+			objectName: matches[ 3 ],
+			objectIndex: matches[ 4 ],
+			propertyName: matches[ 5 ], // required
+			propertyIndex: matches[ 6 ]
+		};
 
-			if ( lastDot !== undefined && lastDot !== - 1 ) {
+		var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
 
-				var objectName = results.nodeName.substring( lastDot + 1 );
+		if ( lastDot !== undefined && lastDot !== - 1 ) {
 
-				// Object names must be checked against a whitelist. Otherwise, there
-				// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
-				// 'bar' could be the objectName, or part of a nodeName (which can
-				// include '.' characters).
-				if ( supportedObjectNames.indexOf( objectName ) !== - 1 ) {
+			var objectName = results.nodeName.substring( lastDot + 1 );
 
-					results.nodeName = results.nodeName.substring( 0, lastDot );
-					results.objectName = objectName;
+			// Object names must be checked against a whitelist. Otherwise, there
+			// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
+			// 'bar' could be the objectName, or part of a nodeName (which can
+			// include '.' characters).
+			if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
 
-				}
+				results.nodeName = results.nodeName.substring( 0, lastDot );
+				results.objectName = objectName;
 
 			}
 
-			if ( results.propertyName === null || results.propertyName.length === 0 ) {
+		}
 
-				throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
+		if ( results.propertyName === null || results.propertyName.length === 0 ) {
 
-			}
+			throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
 
-			return results;
+		}
 
-		};
+		return results;
 
-	}(),
+	},
 
 	findNode: function ( root, nodeName ) {
 

+ 1 - 0
src/audio/Audio.d.ts

@@ -17,6 +17,7 @@ export class Audio extends Object3D {
 	loop: boolean;
 	startTime: number;
 	offset: number;
+	duration: number | undefined;
 	playbackRate: number;
 	isPlaying: boolean;
 	hasPlaybackControl: boolean;

+ 2 - 1
src/audio/Audio.js

@@ -24,6 +24,7 @@ function Audio( listener ) {
 	this.loop = false;
 	this.startTime = 0;
 	this.offset = 0;
+	this.duration = undefined;
 	this.playbackRate = 1;
 	this.isPlaying = false;
 	this.hasPlaybackControl = true;
@@ -98,7 +99,7 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 		source.loop = this.loop;
 		source.onended = this.onEnded.bind( this );
 		this.startTime = this.context.currentTime;
-		source.start( this.startTime, this.offset );
+		source.start( this.startTime, this.offset, this.duration );
 
 		this.isPlaying = true;
 

+ 4 - 11
src/audio/AudioListener.js

@@ -8,8 +8,10 @@ import { Clock } from '../core/Clock.js';
 import { Object3D } from '../core/Object3D.js';
 import { AudioContext } from './AudioContext.js';
 
-var _position, _quaternion, _scale;
-var _orientation;
+var _position = new Vector3();
+var _quaternion = new Quaternion();
+var _scale = new Vector3();
+var _orientation = new Vector3();
 
 function AudioListener() {
 
@@ -102,15 +104,6 @@ AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		Object3D.prototype.updateMatrixWorld.call( this, force );
 
-		if ( _position === undefined ) {
-
-			_position = new Vector3();
-			_quaternion = new Quaternion();
-			_scale = new Vector3();
-			_orientation = new Vector3();
-
-		}
-
 		var listener = this.context.listener;
 		var up = this.up;
 

+ 4 - 11
src/audio/PositionalAudio.js

@@ -7,8 +7,10 @@ import { Quaternion } from '../math/Quaternion.js';
 import { Audio } from './Audio.js';
 import { Object3D } from '../core/Object3D.js';
 
-var _position, _quaternion, _scale;
-var _orientation;
+var _position = new Vector3();
+var _quaternion = new Quaternion();
+var _scale = new Vector3();
+var _orientation = new Vector3();
 
 function PositionalAudio( listener ) {
 
@@ -100,15 +102,6 @@ PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
 
 		Object3D.prototype.updateMatrixWorld.call( this, force );
 
-		if ( _position === undefined ) {
-
-			_position = new Vector3();
-			_quaternion = new Quaternion();
-			_scale = new Vector3();
-			_orientation = new Vector3();
-
-		}
-
 		if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
 
 		this.matrixWorld.decompose( _position, _quaternion, _scale );

+ 2 - 8
src/cameras/StereoCamera.js

@@ -2,7 +2,8 @@ import { Matrix4 } from '../math/Matrix4.js';
 import { _Math } from '../math/Math.js';
 import { PerspectiveCamera } from './PerspectiveCamera.js';
 
-var _eyeRight, _eyeLeft;
+var _eyeRight = new Matrix4();
+var _eyeLeft = new Matrix4();
 
 /**
  * @author mrdoob / http://mrdoob.com/
@@ -40,13 +41,6 @@ Object.assign( StereoCamera.prototype, {
 
 	update: function ( camera ) {
 
-		if ( _eyeRight === undefined ) {
-
-			_eyeRight = new Matrix4();
-			_eyeLeft = new Matrix4();
-
-		}
-
 		var cache = this._cache;
 
 		var needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||

+ 114 - 167
src/core/BufferGeometry.js

@@ -15,11 +15,18 @@ import { arrayMax } from '../utils.js';
  * @author mrdoob / http://mrdoob.com/
  */
 
-var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
+var _bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
+
+var _m1 = new Matrix4();
+var _obj = new Object3D();
+var _offset = new Vector3();
+var _box = new Box3();
+var _boxMorphTargets = new Box3();
+var _vector = new Vector3();
 
 function BufferGeometry() {
 
-	Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } );
+	Object.defineProperty( this, 'id', { value: _bufferGeometryId += 2 } );
 
 	this.uuid = _Math.generateUUID();
 
@@ -182,129 +189,89 @@ BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototy
 
 	},
 
-	rotateX: function () {
+	rotateX: function ( angle ) {
 
 		// rotate geometry around world x-axis
 
-		var m1 = new Matrix4();
-
-		return function rotateX( angle ) {
-
-			m1.makeRotationX( angle );
+		_m1.makeRotationX( angle );
 
-			this.applyMatrix( m1 );
+		this.applyMatrix( _m1 );
 
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	rotateY: function () {
+	rotateY: function ( angle ) {
 
 		// rotate geometry around world y-axis
 
-		var m1 = new Matrix4();
-
-		return function rotateY( angle ) {
-
-			m1.makeRotationY( angle );
-
-			this.applyMatrix( m1 );
+		_m1.makeRotationY( angle );
 
-			return this;
+		this.applyMatrix( _m1 );
 
-		};
+		return this;
 
-	}(),
+	},
 
-	rotateZ: function () {
+	rotateZ: function ( angle ) {
 
 		// rotate geometry around world z-axis
 
-		var m1 = new Matrix4();
-
-		return function rotateZ( angle ) {
-
-			m1.makeRotationZ( angle );
+		_m1.makeRotationZ( angle );
 
-			this.applyMatrix( m1 );
+		this.applyMatrix( _m1 );
 
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	translate: function () {
+	translate: function ( x, y, z ) {
 
 		// translate geometry
 
-		var m1 = new Matrix4();
+		_m1.makeTranslation( x, y, z );
 
-		return function translate( x, y, z ) {
+		this.applyMatrix( _m1 );
 
-			m1.makeTranslation( x, y, z );
-
-			this.applyMatrix( m1 );
-
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	scale: function () {
+	scale: function ( x, y, z ) {
 
 		// scale geometry
 
-		var m1 = new Matrix4();
-
-		return function scale( x, y, z ) {
-
-			m1.makeScale( x, y, z );
-
-			this.applyMatrix( m1 );
-
-			return this;
-
-		};
+		_m1.makeScale( x, y, z );
 
-	}(),
+		this.applyMatrix( _m1 );
 
-	lookAt: function () {
+		return this;
 
-		var obj = new Object3D();
+	},
 
-		return function lookAt( vector ) {
+	lookAt: function ( vector ) {
 
-			obj.lookAt( vector );
+		_obj.lookAt( vector );
 
-			obj.updateMatrix();
+		_obj.updateMatrix();
 
-			this.applyMatrix( obj.matrix );
+		this.applyMatrix( _obj.matrix );
 
-		};
+		return this;
 
-	}(),
+	},
 
 	center: function () {
 
-		var offset = new Vector3();
-
-		return function center() {
-
-			this.computeBoundingBox();
-
-			this.boundingBox.getCenter( offset ).negate();
+		this.computeBoundingBox();
 
-			this.translate( offset.x, offset.y, offset.z );
+		this.boundingBox.getCenter( _offset ).negate();
 
-			return this;
+		this.translate( _offset.x, _offset.y, _offset.z );
 
-		};
+		return this;
 
-	}(),
+	},
 
 	setFromObject: function ( object ) {
 
@@ -601,144 +568,130 @@ BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototy
 
 	computeBoundingBox: function () {
 
-		var box = new Box3();
-
-		return function computeBoundingBox() {
+		if ( this.boundingBox === null ) {
 
-			if ( this.boundingBox === null ) {
+			this.boundingBox = new Box3();
 
-				this.boundingBox = new Box3();
-
-			}
-
-			var position = this.attributes.position;
-			var morphAttributesPosition = this.morphAttributes.position;
+		}
 
-			if ( position !== undefined ) {
+		var position = this.attributes.position;
+		var morphAttributesPosition = this.morphAttributes.position;
 
-				this.boundingBox.setFromBufferAttribute( position );
+		if ( position !== undefined ) {
 
-				// process morph attributes if present
+			this.boundingBox.setFromBufferAttribute( position );
 
-				if ( morphAttributesPosition ) {
+			// process morph attributes if present
 
-					for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
+			if ( morphAttributesPosition ) {
 
-						var morphAttribute = morphAttributesPosition[ i ];
-						box.setFromBufferAttribute( morphAttribute );
+				for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
 
-						this.boundingBox.expandByPoint( box.min );
-						this.boundingBox.expandByPoint( box.max );
+					var morphAttribute = morphAttributesPosition[ i ];
+					_box.setFromBufferAttribute( morphAttribute );
 
-					}
+					this.boundingBox.expandByPoint( _box.min );
+					this.boundingBox.expandByPoint( _box.max );
 
 				}
 
-			} else {
-
-				this.boundingBox.makeEmpty();
-
 			}
 
-			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
-
-				console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
+		} else {
 
-			}
+			this.boundingBox.makeEmpty();
 
-		};
+		}
 
-	}(),
+		if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
 
-	computeBoundingSphere: function () {
+			console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
 
-		var box = new Box3();
-		var boxMorphTargets = new Box3();
-		var vector = new Vector3();
+		}
 
-		return function computeBoundingSphere() {
+	},
 
-			if ( this.boundingSphere === null ) {
+	computeBoundingSphere: function () {
 
-				this.boundingSphere = new Sphere();
+		if ( this.boundingSphere === null ) {
 
-			}
+			this.boundingSphere = new Sphere();
 
-			var position = this.attributes.position;
-			var morphAttributesPosition = this.morphAttributes.position;
+		}
 
-			if ( position ) {
+		var position = this.attributes.position;
+		var morphAttributesPosition = this.morphAttributes.position;
 
-				// first, find the center of the bounding sphere
+		if ( position ) {
 
-				var center = this.boundingSphere.center;
+			// first, find the center of the bounding sphere
 
-				box.setFromBufferAttribute( position );
+			var center = this.boundingSphere.center;
 
-				// process morph attributes if present
+			_box.setFromBufferAttribute( position );
 
-				if ( morphAttributesPosition ) {
+			// process morph attributes if present
 
-					for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
+			if ( morphAttributesPosition ) {
 
-						var morphAttribute = morphAttributesPosition[ i ];
-						boxMorphTargets.setFromBufferAttribute( morphAttribute );
+				for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
 
-						box.expandByPoint( boxMorphTargets.min );
-						box.expandByPoint( boxMorphTargets.max );
+					var morphAttribute = morphAttributesPosition[ i ];
+					_boxMorphTargets.setFromBufferAttribute( morphAttribute );
 
-					}
+					_box.expandByPoint( _boxMorphTargets.min );
+					_box.expandByPoint( _boxMorphTargets.max );
 
 				}
 
-				box.getCenter( center );
+			}
 
-				// second, try to find a boundingSphere with a radius smaller than the
-				// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
+			_box.getCenter( center );
 
-				var maxRadiusSq = 0;
+			// second, try to find a boundingSphere with a radius smaller than the
+			// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
 
-				for ( var i = 0, il = position.count; i < il; i ++ ) {
+			var maxRadiusSq = 0;
 
-					vector.fromBufferAttribute( position, i );
+			for ( var i = 0, il = position.count; i < il; i ++ ) {
 
-					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
+				_vector.fromBufferAttribute( position, i );
 
-				}
+				maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
 
-				// process morph attributes if present
+			}
 
-				if ( morphAttributesPosition ) {
+			// process morph attributes if present
 
-					for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
+			if ( morphAttributesPosition ) {
 
-						var morphAttribute = morphAttributesPosition[ i ];
+				for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
 
-						for ( var j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
+					var morphAttribute = morphAttributesPosition[ i ];
 
-							vector.fromBufferAttribute( morphAttribute, j );
+					for ( var j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
 
-							maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
+						_vector.fromBufferAttribute( morphAttribute, j );
 
-						}
+						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
 
 					}
 
 				}
 
-				this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
+			}
 
-				if ( isNaN( this.boundingSphere.radius ) ) {
+			this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
 
-					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
+			if ( isNaN( this.boundingSphere.radius ) ) {
 
-				}
+				console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
 
 			}
 
-		};
+		}
 
-	}(),
+	},
 
 	computeFaceNormals: function () {
 
@@ -900,27 +853,21 @@ BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototy
 
 	normalizeNormals: function () {
 
-		var vector = new Vector3();
-
-		return function normalizeNormals() {
-
-			var normals = this.attributes.normal;
+		var normals = this.attributes.normal;
 
-			for ( var i = 0, il = normals.count; i < il; i ++ ) {
+		for ( var i = 0, il = normals.count; i < il; i ++ ) {
 
-				vector.x = normals.getX( i );
-				vector.y = normals.getY( i );
-				vector.z = normals.getZ( i );
+			_vector.x = normals.getX( i );
+			_vector.y = normals.getY( i );
+			_vector.z = normals.getZ( i );
 
-				vector.normalize();
+			_vector.normalize();
 
-				normals.setXYZ( i, vector.x, vector.y, vector.z );
+			normals.setXYZ( i, _vector.x, _vector.y, _vector.z );
 
-			}
-
-		};
+		}
 
-	}(),
+	},
 
 	toNonIndexed: function () {
 

+ 41 - 78
src/core/Geometry.js

@@ -19,11 +19,14 @@ import { _Math } from '../math/Math.js';
  * @author bhouston / http://clara.io
  */
 
-var geometryId = 0; // Geometry uses even numbers as Id
+var _geometryId = 0; // Geometry uses even numbers as Id
+var _m1 = new Matrix4();
+var _obj = new Object3D();
+var _offset = new Vector3();
 
 function Geometry() {
 
-	Object.defineProperty( this, 'id', { value: geometryId += 2 } );
+	Object.defineProperty( this, 'id', { value: _geometryId += 2 } );
 
 	this.uuid = _Math.generateUUID();
 
@@ -107,111 +110,77 @@ Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	},
 
-	rotateX: function () {
+	rotateX: function ( angle ) {
 
 		// rotate geometry around world x-axis
 
-		var m1 = new Matrix4();
+		_m1.makeRotationX( angle );
 
-		return function rotateX( angle ) {
+		this.applyMatrix( _m1 );
 
-			m1.makeRotationX( angle );
-
-			this.applyMatrix( m1 );
-
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	rotateY: function () {
+	rotateY: function ( angle ) {
 
 		// rotate geometry around world y-axis
 
-		var m1 = new Matrix4();
+		_m1.makeRotationY( angle );
 
-		return function rotateY( angle ) {
+		this.applyMatrix( _m1 );
 
-			m1.makeRotationY( angle );
-
-			this.applyMatrix( m1 );
-
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	rotateZ: function () {
+	rotateZ: function ( angle ) {
 
 		// rotate geometry around world z-axis
 
-		var m1 = new Matrix4();
-
-		return function rotateZ( angle ) {
-
-			m1.makeRotationZ( angle );
+		_m1.makeRotationZ( angle );
 
-			this.applyMatrix( m1 );
+		this.applyMatrix( _m1 );
 
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	translate: function () {
+	translate: function ( x, y, z ) {
 
 		// translate geometry
 
-		var m1 = new Matrix4();
-
-		return function translate( x, y, z ) {
-
-			m1.makeTranslation( x, y, z );
-
-			this.applyMatrix( m1 );
+		_m1.makeTranslation( x, y, z );
 
-			return this;
+		this.applyMatrix( _m1 );
 
-		};
+		return this;
 
-	}(),
+	},
 
-	scale: function () {
+	scale: function ( x, y, z ) {
 
 		// scale geometry
 
-		var m1 = new Matrix4();
-
-		return function scale( x, y, z ) {
-
-			m1.makeScale( x, y, z );
-
-			this.applyMatrix( m1 );
+		_m1.makeScale( x, y, z );
 
-			return this;
+		this.applyMatrix( _m1 );
 
-		};
-
-	}(),
-
-	lookAt: function () {
+		return this;
 
-		var obj = new Object3D();
+	},
 
-		return function lookAt( vector ) {
+	lookAt: function ( vector ) {
 
-			obj.lookAt( vector );
+		_obj.lookAt( vector );
 
-			obj.updateMatrix();
+		_obj.updateMatrix();
 
-			this.applyMatrix( obj.matrix );
+		this.applyMatrix( _obj.matrix );
 
-		};
+		return this;
 
-	}(),
+	},
 
 	fromBufferGeometry: function ( geometry ) {
 
@@ -348,21 +317,15 @@ Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	center: function () {
 
-		var offset = new Vector3();
-
-		return function center() {
-
-			this.computeBoundingBox();
-
-			this.boundingBox.getCenter( offset ).negate();
+		this.computeBoundingBox();
 
-			this.translate( offset.x, offset.y, offset.z );
+		this.boundingBox.getCenter( _offset ).negate();
 
-			return this;
+		this.translate( _offset.x, _offset.y, _offset.z );
 
-		};
+		return this;
 
-	}(),
+	},
 
 	normalize: function () {
 

+ 108 - 181
src/core/Object3D.js

@@ -8,6 +8,24 @@ import { Matrix3 } from '../math/Matrix3.js';
 import { _Math } from '../math/Math.js';
 import { TrianglesDrawMode } from '../constants.js';
 
+var _object3DId = 0;
+
+var _v1 = new Vector3();
+var _q1 = new Quaternion();
+var _m1 = new Matrix4();
+var _target = new Vector3();
+
+var _position = new Vector3();
+var _scale = new Vector3();
+var _quaternion = new Quaternion();
+
+var _xAxis = new Vector3( 1, 0, 0 );
+var _yAxis = new Vector3( 0, 1, 0 );
+var _zAxis = new Vector3( 0, 0, 1 );
+
+var _addedEvent = { type: 'added' };
+var _removedEvent = { type: 'removed' };
+
 /**
  * @author mrdoob / http://mrdoob.com/
  * @author mikael emtinger / http://gomo.se/
@@ -16,11 +34,9 @@ import { TrianglesDrawMode } from '../constants.js';
  * @author elephantatwork / www.elephantatwork.ch
  */
 
-var object3DId = 0;
-
 function Object3D() {
 
-	Object.defineProperty( this, 'id', { value: object3DId ++ } );
+	Object.defineProperty( this, 'id', { value: _object3DId ++ } );
 
 	this.uuid = _Math.generateUUID();
 
@@ -160,135 +176,81 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	},
 
-	rotateOnAxis: function () {
+	rotateOnAxis: function ( axis, angle ) {
 
 		// rotate object on axis in object space
 		// axis is assumed to be normalized
 
-		var q1 = new Quaternion();
+		_q1.setFromAxisAngle( axis, angle );
 
-		return function rotateOnAxis( axis, angle ) {
+		this.quaternion.multiply( _q1 );
 
-			q1.setFromAxisAngle( axis, angle );
-
-			this.quaternion.multiply( q1 );
-
-			return this;
-
-		};
+		return this;
 
-	}(),
+	},
 
-	rotateOnWorldAxis: function () {
+	rotateOnWorldAxis: function ( axis, angle ) {
 
 		// rotate object on axis in world space
 		// axis is assumed to be normalized
 		// method assumes no rotated parent
 
-		var q1 = new Quaternion();
-
-		return function rotateOnWorldAxis( axis, angle ) {
-
-			q1.setFromAxisAngle( axis, angle );
-
-			this.quaternion.premultiply( q1 );
-
-			return this;
-
-		};
-
-	}(),
-
-	rotateX: function () {
-
-		var v1 = new Vector3( 1, 0, 0 );
-
-		return function rotateX( angle ) {
-
-			return this.rotateOnAxis( v1, angle );
-
-		};
+		_q1.setFromAxisAngle( axis, angle );
 
-	}(),
+		this.quaternion.premultiply( _q1 );
 
-	rotateY: function () {
-
-		var v1 = new Vector3( 0, 1, 0 );
+		return this;
 
-		return function rotateY( angle ) {
+	},
 
-			return this.rotateOnAxis( v1, angle );
+	rotateX: function ( angle ) {
 
-		};
+		return this.rotateOnAxis( _xAxis, angle );
 
-	}(),
+	},
 
-	rotateZ: function () {
+	rotateY: function ( angle ) {
 
-		var v1 = new Vector3( 0, 0, 1 );
+		return this.rotateOnAxis( _yAxis, angle );
 
-		return function rotateZ( angle ) {
+	},
 
-			return this.rotateOnAxis( v1, angle );
+	rotateZ: function ( angle ) {
 
-		};
+		return this.rotateOnAxis( _zAxis, angle );
 
-	}(),
+	},
 
-	translateOnAxis: function () {
+	translateOnAxis: function ( axis, distance ) {
 
 		// translate object by distance along axis in object space
 		// axis is assumed to be normalized
 
-		var v1 = new Vector3();
-
-		return function translateOnAxis( axis, distance ) {
-
-			v1.copy( axis ).applyQuaternion( this.quaternion );
-
-			this.position.add( v1.multiplyScalar( distance ) );
-
-			return this;
-
-		};
+		_v1.copy( axis ).applyQuaternion( this.quaternion );
 
-	}(),
+		this.position.add( _v1.multiplyScalar( distance ) );
 
-	translateX: function () {
-
-		var v1 = new Vector3( 1, 0, 0 );
-
-		return function translateX( distance ) {
-
-			return this.translateOnAxis( v1, distance );
-
-		};
-
-	}(),
-
-	translateY: function () {
-
-		var v1 = new Vector3( 0, 1, 0 );
+		return this;
 
-		return function translateY( distance ) {
+	},
 
-			return this.translateOnAxis( v1, distance );
+	translateX: function ( distance ) {
 
-		};
+		return this.translateOnAxis( _xAxis, distance );
 
-	}(),
+	},
 
-	translateZ: function () {
+	translateY: function ( distance ) {
 
-		var v1 = new Vector3( 0, 0, 1 );
+		return this.translateOnAxis( _yAxis, distance );
 
-		return function translateZ( distance ) {
+	},
 
-			return this.translateOnAxis( v1, distance );
+	translateZ: function ( distance ) {
 
-		};
+		return this.translateOnAxis( _zAxis, distance );
 
-	}(),
+	},
 
 	localToWorld: function ( vector ) {
 
@@ -296,68 +258,53 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	},
 
-	worldToLocal: function () {
-
-		var m1 = new Matrix4();
-
-		return function worldToLocal( vector ) {
+	worldToLocal: function ( vector ) {
 
-			return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
+		return vector.applyMatrix4( _m1.getInverse( this.matrixWorld ) );
 
-		};
-
-	}(),
+	},
 
-	lookAt: function () {
+	lookAt: function ( x, y, z ) {
 
 		// This method does not support objects having non-uniformly-scaled parent(s)
 
-		var q1 = new Quaternion();
-		var m1 = new Matrix4();
-		var target = new Vector3();
-		var position = new Vector3();
-
-		return function lookAt( x, y, z ) {
+		if ( x.isVector3 ) {
 
-			if ( x.isVector3 ) {
+			_target.copy( x );
 
-				target.copy( x );
-
-			} else {
-
-				target.set( x, y, z );
+		} else {
 
-			}
+			_target.set( x, y, z );
 
-			var parent = this.parent;
+		}
 
-			this.updateWorldMatrix( true, false );
+		var parent = this.parent;
 
-			position.setFromMatrixPosition( this.matrixWorld );
+		this.updateWorldMatrix( true, false );
 
-			if ( this.isCamera || this.isLight ) {
+		_position.setFromMatrixPosition( this.matrixWorld );
 
-				m1.lookAt( position, target, this.up );
+		if ( this.isCamera || this.isLight ) {
 
-			} else {
+			_m1.lookAt( _position, _target, this.up );
 
-				m1.lookAt( target, position, this.up );
+		} else {
 
-			}
+			_m1.lookAt( _target, _position, this.up );
 
-			this.quaternion.setFromRotationMatrix( m1 );
+		}
 
-			if ( parent ) {
+		this.quaternion.setFromRotationMatrix( _m1 );
 
-				m1.extractRotation( parent.matrixWorld );
-				q1.setFromRotationMatrix( m1 );
-				this.quaternion.premultiply( q1.inverse() );
+		if ( parent ) {
 
-			}
+			_m1.extractRotation( parent.matrixWorld );
+			_q1.setFromRotationMatrix( _m1 );
+			this.quaternion.premultiply( _q1.inverse() );
 
-		};
+		}
 
-	}(),
+	},
 
 	add: function ( object ) {
 
@@ -391,7 +338,7 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 			object.parent = this;
 			this.children.push( object );
 
-			object.dispatchEvent( { type: 'added' } );
+			object.dispatchEvent( _addedEvent );
 
 		} else {
 
@@ -424,7 +371,7 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 			object.parent = null;
 			this.children.splice( index, 1 );
 
-			object.dispatchEvent( { type: 'removed' } );
+			object.dispatchEvent( _removedEvent );
 
 		}
 
@@ -432,37 +379,31 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	},
 
-	attach: function () {
+	attach: function ( object ) {
 
 		// adds object as a child of this, while maintaining the object's world transform
 
-		var m = new Matrix4();
-
-		return function attach( object ) {
-
-			this.updateWorldMatrix( true, false );
-
-			m.getInverse( this.matrixWorld );
+		this.updateWorldMatrix( true, false );
 
-			if ( object.parent !== null ) {
+		_m1.getInverse( this.matrixWorld );
 
-				object.parent.updateWorldMatrix( true, false );
+		if ( object.parent !== null ) {
 
-				m.multiply( object.parent.matrixWorld );
+			object.parent.updateWorldMatrix( true, false );
 
-			}
+			_m1.multiply( object.parent.matrixWorld );
 
-			object.applyMatrix( m );
+		}
 
-			object.updateWorldMatrix( false, false );
+		object.applyMatrix( _m1 );
 
-			this.add( object );
+		object.updateWorldMatrix( false, false );
 
-			return this;
+		this.add( object );
 
-		};
+		return this;
 
-	}(),
+	},
 
 	getObjectById: function ( id ) {
 
@@ -512,53 +453,39 @@ Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 	},
 
-	getWorldQuaternion: function () {
-
-		var position = new Vector3();
-		var scale = new Vector3();
-
-		return function getWorldQuaternion( target ) {
-
-			if ( target === undefined ) {
-
-				console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
-				target = new Quaternion();
-
-			}
+	getWorldQuaternion: function ( target ) {
 
-			this.updateMatrixWorld( true );
-
-			this.matrixWorld.decompose( position, target, scale );
+		if ( target === undefined ) {
 
-			return target;
+			console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
+			target = new Quaternion();
 
-		};
+		}
 
-	}(),
+		this.updateMatrixWorld( true );
 
-	getWorldScale: function () {
+		this.matrixWorld.decompose( _position, target, _scale );
 
-		var position = new Vector3();
-		var quaternion = new Quaternion();
+		return target;
 
-		return function getWorldScale( target ) {
+	},
 
-			if ( target === undefined ) {
+	getWorldScale: function ( target ) {
 
-				console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
-				target = new Vector3();
+		if ( target === undefined ) {
 
-			}
+			console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
+			target = new Vector3();
 
-			this.updateMatrixWorld( true );
+		}
 
-			this.matrixWorld.decompose( position, quaternion, target );
+		this.updateMatrixWorld( true );
 
-			return target;
+		this.matrixWorld.decompose( _position, _quaternion, target );
 
-		};
+		return target;
 
-	}(),
+	},
 
 	getWorldDirection: function ( target ) {
 

+ 6 - 0
src/core/Raycaster.d.ts

@@ -55,6 +55,12 @@ export class Raycaster {
 	 */
 	far: number;
 
+	/**
+	 * The camera to use when raycasting against view-dependent objects such as billboarded objects like Sprites. This field
+	 * can be set manually or is set when calling "setFromCamera".
+	 */
+	camera: Camera;
+
 	params: RaycasterParameters;
 
 	/**

+ 3 - 2
src/core/Raycaster.js

@@ -13,6 +13,7 @@ function Raycaster( origin, direction, near, far ) {
 
 	this.near = near || 0;
 	this.far = far || Infinity;
+	this.camera = null;
 
 	this.params = {
 		Mesh: {},
@@ -79,13 +80,13 @@ Object.assign( Raycaster.prototype, {
 
 			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
-			this._camera = camera;
+			this.camera = camera;
 
 		} else if ( ( camera && camera.isOrthographicCamera ) ) {
 
 			this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
 			this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
-			this._camera = camera;
+			this.camera = camera;
 
 		} else {
 

+ 1 - 3
src/helpers/ArrowHelper.js

@@ -24,7 +24,7 @@ import { Mesh } from '../objects/Mesh.js';
 import { Line } from '../objects/Line.js';
 import { Vector3 } from '../math/Vector3.js';
 
-var _axis;
+var _axis = new Vector3();
 var _lineGeometry, _coneGeometry;
 
 function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {
@@ -70,8 +70,6 @@ ArrowHelper.prototype.constructor = ArrowHelper;
 
 ArrowHelper.prototype.setDirection = function ( dir ) {
 
-	if ( _axis === undefined ) _axis = new Vector3();
-
 	// dir is assumed to be normalized
 
 	if ( dir.y > 0.99999 ) {

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