Mr.doob 7 years ago
parent
commit
e5388e4570
100 changed files with 7761 additions and 5276 deletions
  1. 70 67
      build/three.js
  2. 400 392
      build/three.min.js
  3. 70 67
      build/three.module.js
  4. 7 0
      docs/api/audio/Audio.html
  5. 10 4
      docs/api/core/BufferGeometry.html
  6. 14 12
      docs/api/core/Object3D.html
  7. 2 2
      docs/api/geometries/ExtrudeBufferGeometry.html
  8. 2 2
      docs/api/geometries/ExtrudeGeometry.html
  9. 2 2
      docs/api/geometries/ParametricBufferGeometry.html
  10. 4 3
      docs/api/loaders/ImageBitmapLoader.html
  11. 1 2
      docs/api/loaders/ImageLoader.html
  12. 3 3
      docs/api/loaders/ObjectLoader.html
  13. 3 0
      docs/api/materials/PointsMaterial.html
  14. 11 5
      docs/api/math/Color.html
  15. 14 14
      docs/api/math/Matrix3.html
  16. 29 29
      docs/api/math/Matrix4.html
  17. 34 34
      docs/api/math/Vector2.html
  18. 52 52
      docs/api/math/Vector3.html
  19. 35 35
      docs/api/math/Vector4.html
  20. 1 1
      docs/api/objects/Line.html
  21. 1 1
      docs/api/objects/Mesh.html
  22. 1 1
      docs/api/objects/Points.html
  23. 4 1
      docs/api/objects/SkinnedMesh.html
  24. 1 1
      docs/api/objects/Sprite.html
  25. 1 0
      docs/api/textures/DataTexture.html
  26. 1 1
      docs/api/textures/Texture.html
  27. 102 0
      docs/examples/animations/CCDIKSolver.html
  28. 169 0
      docs/examples/animations/MMDAnimationHelper.html
  29. 112 0
      docs/examples/animations/MMDPhysics.html
  30. 1 1
      docs/examples/exporters/GLTFExporter.html
  31. 62 0
      docs/examples/exporters/PLYExporter.html
  32. 22 0
      docs/examples/loaders/GLTFLoader.html
  33. 118 0
      docs/examples/loaders/MMDLoader.html
  34. 2 2
      docs/examples/quickhull/QuickHull.html
  35. 1 0
      docs/examples/renderers/CSS2DRenderer.html
  36. 10 1
      docs/list.js
  37. 5 5
      docs/manual/introduction/Animation-system.html
  38. 3 3
      docs/manual/introduction/Creating-a-scene.html
  39. 1 1
      docs/manual/introduction/FAQ.html
  40. 132 0
      docs/manual/introduction/Loading-3D-models.html
  41. 7 0
      docs/manual/introduction/Useful-links.html
  42. 1 1
      docs/page.js
  43. 4 4
      docs/scenes/js/geometry.js
  44. 150 0
      examples/css2d_label.html
  45. 5 0
      examples/files.js
  46. 26 5
      examples/js/BufferGeometryUtils.js
  47. 14 10
      examples/js/Cloth.js
  48. 77 67
      examples/js/ConvexObjectBreaker.js
  49. 327 327
      examples/js/MarchingCubes.js
  50. 299 299
      examples/js/Octree.js
  51. 14 28
      examples/js/ParametricGeometries.js
  52. 41 4
      examples/js/ShaderGodRays.js
  53. 278 239
      examples/js/animation/CCDIKSolver.js
  54. 1038 0
      examples/js/animation/MMDAnimationHelper.js
  55. 964 774
      examples/js/animation/MMDPhysics.js
  56. 14 6
      examples/js/cameras/CinematicCamera.js
  57. 2 6
      examples/js/controls/OrbitControls.js
  58. 4 12
      examples/js/controls/TransformControls.js
  59. 32 33
      examples/js/crossfade/scenes.js
  60. 2 4
      examples/js/curves/NURBSSurface.js
  61. 11 14
      examples/js/curves/NURBSUtils.js
  62. 8 8
      examples/js/effects/OutlineEffect.js
  63. 35 9
      examples/js/exporters/GLTFExporter.js
  64. 417 112
      examples/js/exporters/PLYExporter.js
  65. 0 94
      examples/js/exporters/STLBinaryExporter.js
  66. 110 25
      examples/js/exporters/STLExporter.js
  67. 0 1
      examples/js/libs/draco/gltf/draco_decoder.js
  68. BIN
      examples/js/libs/draco/gltf/draco_decoder.wasm
  69. 3 0
      examples/js/libs/draco/gltf/draco_encoder.js
  70. 119 115
      examples/js/libs/draco/gltf/draco_wasm_wrapper.js
  71. 2 2
      examples/js/lines/LineMaterial.js
  72. 79 1
      examples/js/loaders/ColladaLoader.js
  73. 87 15
      examples/js/loaders/DRACOLoader.js
  74. 8 7
      examples/js/loaders/EXRLoader.js
  75. 1 7
      examples/js/loaders/EquiangularToCubeGenerator.js
  76. 430 158
      examples/js/loaders/GLTFLoader.js
  77. 22 9
      examples/js/loaders/LoaderSupport.js
  78. 1171 1995
      examples/js/loaders/MMDLoader.js
  79. 2 1
      examples/js/loaders/NodeMaterialLoader.js
  80. 43 10
      examples/js/loaders/OBJLoader2.js
  81. 95 8
      examples/js/loaders/SVGLoader.js
  82. 19 1
      examples/js/loaders/VRMLoader.js
  83. 1 1
      examples/js/loaders/sea3d/SEA3DLoader.js
  84. 2 2
      examples/js/nodes/InputNode.js
  85. 8 8
      examples/js/nodes/NodeMaterial.js
  86. 29 0
      examples/js/nodes/NodeUniform.js
  87. 4 4
      examples/js/nodes/accessors/CameraNode.js
  88. 4 19
      examples/js/nodes/inputs/FloatNode.js
  89. 3 18
      examples/js/nodes/inputs/IntNode.js
  90. 4 4
      examples/js/nodes/utils/BlurNode.js
  91. 3 3
      examples/js/nodes/utils/TimerNode.js
  92. 2 2
      examples/js/nodes/utils/VelocityNode.js
  93. 2 2
      examples/js/objects/Reflector.js
  94. 0 2
      examples/js/objects/ReflectorRTT.js
  95. 1 7
      examples/js/pmrem/PMREMCubeUVPacker.js
  96. 2 8
      examples/js/pmrem/PMREMGenerator.js
  97. 62 0
      examples/js/renderers/CSS2DRenderer.js
  98. 46 12
      examples/js/shaders/BokehShader2.js
  99. 88 5
      examples/js/vr/WebVR.js
  100. 26 24
      examples/misc_exporter_obj.html

File diff suppressed because it is too large
+ 70 - 67
build/three.js


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


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


+ 7 - 0
docs/api/audio/Audio.html

@@ -179,6 +179,13 @@
 		(whether playback should loop).
 		(whether playback should loop).
 		</p>
 		</p>
 
 
+		<h3>[method:null setMediaElementSource]( mediaElement )</h3>
+		<p>
+		Applies the given object of type [link:https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement HTMLMediaElement] as the source of this audio.<br />
+		Also sets [page:Audio.hasPlaybackControl hasPlaybackControl] to false.
+
+		</p>
+
 		<h3>[method:null setNodeSource]( audioNode )</h3>
 		<h3>[method:null setNodeSource]( audioNode )</h3>
 		<p>
 		<p>
 		Setup the [page:Audio.source source] to the audioBuffer, and sets [page:Audio.sourceType sourceType] to 'audioNode'.<br />
 		Setup the [page:Audio.source source] to the audioBuffer, and sets [page:Audio.sourceType sourceType] to 'audioNode'.<br />

+ 10 - 4
docs/api/core/BufferGeometry.html

@@ -185,6 +185,12 @@
 		Optional name for this bufferGeometry instance. Default is an empty string.
 		Optional name for this bufferGeometry instance. Default is an empty string.
 		</p>
 		</p>
 
 
+		<h3>[property:Object userData]</h3>
+		<p>
+		An object that can be used to store custom data about the BufferGeometry. It should not hold
+		references to functions as these will not be cloned.
+		</p>
+
 		<h3>[property:String uuid]</h3>
 		<h3>[property:String uuid]</h3>
 		<p>
 		<p>
 		[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this object instance.
 		[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this object instance.
@@ -195,7 +201,7 @@
 
 
 		<h3>[page:EventDispatcher EventDispatcher] methods are available on this class.</h3>
 		<h3>[page:EventDispatcher EventDispatcher] methods are available on this class.</h3>
 
 
-		<h3>[method:null addAttribute]( [param:String name], [param:BufferAttribute attribute] )</h3>
+		<h3>[method:BufferGeometry addAttribute]( [param:String name], [param:BufferAttribute attribute] )</h3>
 		<p>
 		<p>
 		Adds an attribute to this geometry. Use this rather than the attributes property,
 		Adds an attribute to this geometry. Use this rather than the attributes property,
 		because an internal hashmap of [page:.attributes] is maintained to speed up iterating over
 		because an internal hashmap of [page:.attributes] is maintained to speed up iterating over
@@ -242,19 +248,19 @@
 		<h3>[method:null dispose]()</h3>
 		<h3>[method:null dispose]()</h3>
 		<p>
 		<p>
 		Disposes the object from memory. <br />
 		Disposes the object from memory. <br />
-		You need to call this when you want the bufferGeometry removed while the application is running.
+		You need to call this when you want the BufferGeometry removed while the application is running.
 		</p>
 		</p>
 
 
 		<h3>[method:BufferGeometry fromDirectGeometry]( [param:Geometry] )</h3>
 		<h3>[method:BufferGeometry fromDirectGeometry]( [param:Geometry] )</h3>
 		<p>
 		<p>
-			Populates this BufferGeometry with data from a [page:DirectGeometry] object.<br /><br />
+			Populates this BufferGeometry with data from a [page:DirectGeometry] object containing faces. Not implemented for a line geometry.<br /><br />
 
 
 			Note: [page:DirectGeometry] is mainly used as an intermediary object for converting between [page:Geometry]
 			Note: [page:DirectGeometry] is mainly used as an intermediary object for converting between [page:Geometry]
 			and BufferGeometry.
 			and BufferGeometry.
 		</p>
 		</p>
 
 
 		<h3>[method:BufferGeometry fromGeometry]( [param:Geometry] )</h3>
 		<h3>[method:BufferGeometry fromGeometry]( [param:Geometry] )</h3>
-		<p>Populates this BufferGeometry with data from a [page:Geometry] object.</p>
+		<p>Populates this BufferGeometry with data from a [page:Geometry] object containing faces. Not implemented for a line geometry.</p>
 
 
 		<h3>[method:BufferAttribute getAttribute]( [param:String name] )</h3>
 		<h3>[method:BufferAttribute getAttribute]( [param:String name] )</h3>
 		<p>Returns the [page:BufferAttribute attribute] with the specified name.</p>
 		<p>Returns the [page:BufferAttribute attribute] with the specified name.</p>

+ 14 - 12
docs/api/core/Object3D.html

@@ -109,7 +109,8 @@
 		</p>
 		</p>
 
 
 		<h3>[property:Object3D parent]</h3>
 		<h3>[property:Object3D parent]</h3>
-		<p>Object's parent in the [link:https://en.wikipedia.org/wiki/Scene_graph scene graph].</p>
+		<p>Object's parent in the [link:https://en.wikipedia.org/wiki/Scene_graph scene graph]. An object can have at most
+		one parent.</p>
 
 
 		<h3>[property:Vector3 position]</h3>
 		<h3>[property:Vector3 position]</h3>
 		<p>A [page:Vector3] representing the object's local position. Default is (0, 0, 0).</p>
 		<p>A [page:Vector3] representing the object's local position. Default is (0, 0, 0).</p>
@@ -190,7 +191,8 @@
 
 
 		<h3>[method:null add]( [param:Object3D object], ... )</h3>
 		<h3>[method:null add]( [param:Object3D object], ... )</h3>
 		<p>
 		<p>
-		Adds *object* as child of this object. An arbitrary number of objects may be added.<br /><br />
+		Adds *object* as child of this object. An arbitrary number of objects may be added. Any current parent on an
+		object passed in here will be removed, since an object can have at most one parent.<br /><br />
 
 
 		See [page:Group] for info on manually grouping objects.
 		See [page:Group] for info on manually grouping objects.
 		</p>
 		</p>
@@ -208,7 +210,7 @@
 		Returns a clone of this object and optionally all descendants.
 		Returns a clone of this object and optionally all descendants.
 		</p>
 		</p>
 
 
-		<h3>[method:Object3D copy]( [param:Object3D object], [param:Boolean recursive] )</h3>
+		<h3>[method:this copy]( [param:Object3D object], [param:Boolean recursive] )</h3>
 		<p>
 		<p>
 		recursive -- if true, descendants of the object are also copied. Default is true.<br /><br />
 		recursive -- if true, descendants of the object are also copied. Default is true.<br /><br />
 
 
@@ -299,7 +301,7 @@
 		Removes *object* as child of this object. An arbitrary number of objects may be removed.
 		Removes *object* as child of this object. An arbitrary number of objects may be removed.
 		</p>
 		</p>
 
 
-		<h3>[method:Object3D rotateOnAxis]( [param:Vector3 axis], [param:Float angle] )</h3>
+		<h3>[method:this rotateOnAxis]( [param:Vector3 axis], [param:Float angle] )</h3>
 		<p>
 		<p>
 		axis -- A normalized vector in object space. <br />
 		axis -- A normalized vector in object space. <br />
 		angle -- The angle in radians.<br /><br />
 		angle -- The angle in radians.<br /><br />
@@ -307,7 +309,7 @@
 		Rotate an object along an axis in object space. The axis is assumed to be normalized.
 		Rotate an object along an axis in object space. The axis is assumed to be normalized.
 		</p>
 		</p>
 
 
-		<h3>[method:Object3D rotateOnWorldAxis]( [param:Vector3 axis], [param:Float angle] )</h3>
+		<h3>[method:this rotateOnWorldAxis]( [param:Vector3 axis], [param:Float angle] )</h3>
 		<p>
 		<p>
 		axis -- A normalized vector in world space. <br />
 		axis -- A normalized vector in world space. <br />
 		angle -- The angle in radians.<br /><br />
 		angle -- The angle in radians.<br /><br />
@@ -316,21 +318,21 @@
 		Method Assumes no rotated parent.
 		Method Assumes no rotated parent.
 		</p>
 		</p>
 
 
-		<h3>[method:null rotateX]( [param:Float rad] )</h3>
+		<h3>[method:this rotateX]( [param:Float rad] )</h3>
 		<p>
 		<p>
 		rad - the angle to rotate in radians.<br /><br />
 		rad - the angle to rotate in radians.<br /><br />
 
 
 		Rotates the object around x axis in local space.
 		Rotates the object around x axis in local space.
 		</p>
 		</p>
 
 
-		<h3>[method:null rotateY]( [param:Float rad] )</h3>
+		<h3>[method:this rotateY]( [param:Float rad] )</h3>
 		<p>
 		<p>
 		rad - the angle to rotate in radians.<br /><br />
 		rad - the angle to rotate in radians.<br /><br />
 
 
 		Rotates the object around y axis in local space.
 		Rotates the object around y axis in local space.
 		</p>
 		</p>
 
 
-		<h3>[method:null rotateZ]( [param:Float rad] )</h3>
+		<h3>[method:this rotateZ]( [param:Float rad] )</h3>
 		<p>
 		<p>
 		rad - the angle to rotate in radians.<br /><br />
 		rad - the angle to rotate in radians.<br /><br />
 
 
@@ -376,7 +378,7 @@
 			Convert the object to JSON format.
 			Convert the object to JSON format.
 		</p>
 		</p>
 
 
-		<h3>[method:Object3D translateOnAxis]( [param:Vector3 axis], [param:Float distance] )</h3>
+		<h3>[method:this translateOnAxis]( [param:Vector3 axis], [param:Float distance] )</h3>
 		<p>
 		<p>
 		axis -- A normalized vector in object space.<br />
 		axis -- A normalized vector in object space.<br />
 		distance -- The distance to translate.<br /><br />
 		distance -- The distance to translate.<br /><br />
@@ -384,13 +386,13 @@
 		Translate an object by distance along an axis in object space. The axis is assumed to be normalized.
 		Translate an object by distance along an axis in object space. The axis is assumed to be normalized.
 		</p>
 		</p>
 
 
-		<h3>[method:null translateX]( [param:Float distance] )</h3>
+		<h3>[method:this translateX]( [param:Float distance] )</h3>
 		<p>Translates object along x axis by *distance* units.</p>
 		<p>Translates object along x axis by *distance* units.</p>
 
 
-		<h3>[method:null translateY]( [param:Float distance] )</h3>
+		<h3>[method:this translateY]( [param:Float distance] )</h3>
 		<p>Translates object along y axis by *distance* units.</p>
 		<p>Translates object along y axis by *distance* units.</p>
 
 
-		<h3>[method:null translateZ]( [param:Float distance] )</h3>
+		<h3>[method:this translateZ]( [param:Float distance] )</h3>
 		<p>Translates object along z axis by *distance* units.</p>
 		<p>Translates object along z axis by *distance* units.</p>
 
 
 		<h3>[method:null traverse]( [param:Function callback] )</h3>
 		<h3>[method:null traverse]( [param:Function callback] )</h3>

+ 2 - 2
docs/api/geometries/ExtrudeBufferGeometry.html

@@ -47,7 +47,7 @@
 
 
 		var extrudeSettings = {
 		var extrudeSettings = {
 			steps: 2,
 			steps: 2,
-			amount: 16,
+			depth: 16,
 			bevelEnabled: true,
 			bevelEnabled: true,
 			bevelThickness: 1,
 			bevelThickness: 1,
 			bevelSize: 1,
 			bevelSize: 1,
@@ -72,7 +72,7 @@
 			<ul>
 			<ul>
 				<li>curveSegments — int. Number of points on the curves. Default is 12.</li>
 				<li>curveSegments — int. Number of points on the curves. Default is 12.</li>
 				<li>steps — int. Number of points used for subdividing segments along the depth of the extruded spline. Default is 1.</li>
 				<li>steps — int. Number of points used for subdividing segments along the depth of the extruded spline. Default is 1.</li>
-				<li>amount — int. Depth to extrude the shape. Default is 100.</li>
+				<li>depth — float. Depth to extrude the shape. Default is 100.</li>
 				<li>bevelEnabled — bool. Apply beveling to the shape. Default is true.</li>
 				<li>bevelEnabled — bool. Apply beveling to the shape. Default is true.</li>
 				<li>bevelThickness — float. How deep into the original shape the bevel goes. Default is 6.</li>
 				<li>bevelThickness — float. How deep into the original shape the bevel goes. Default is 6.</li>
 				<li>bevelSize — float. Distance from the shape outline that the bevel extends. Default is bevelThickness - 2.</li>
 				<li>bevelSize — float. Distance from the shape outline that the bevel extends. Default is bevelThickness - 2.</li>

+ 2 - 2
docs/api/geometries/ExtrudeGeometry.html

@@ -47,7 +47,7 @@
 
 
 		var extrudeSettings = {
 		var extrudeSettings = {
 			steps: 2,
 			steps: 2,
-			amount: 16,
+			depth: 16,
 			bevelEnabled: true,
 			bevelEnabled: true,
 			bevelThickness: 1,
 			bevelThickness: 1,
 			bevelSize: 1,
 			bevelSize: 1,
@@ -72,7 +72,7 @@
 			<ul>
 			<ul>
 				<li>curveSegments — int. Number of points on the curves. Default is 12.</li>
 				<li>curveSegments — int. Number of points on the curves. Default is 12.</li>
 				<li>steps — int. Number of points used for subdividing segments along the depth of the extruded spline. Default is 1.</li>
 				<li>steps — int. Number of points used for subdividing segments along the depth of the extruded spline. Default is 1.</li>
-				<li>amount — int. Depth to extrude the shape. Default is 100.</li>
+				<li>depth — float. Depth to extrude the shape. Default is 100.</li>
 				<li>bevelEnabled — bool. Apply beveling to the shape. Default is true.</li>
 				<li>bevelEnabled — bool. Apply beveling to the shape. Default is true.</li>
 				<li>bevelThickness — float. How deep into the original shape the bevel goes. Default is 6.</li>
 				<li>bevelThickness — float. How deep into the original shape the bevel goes. Default is 6.</li>
 				<li>bevelSize — float. Distance from the shape outline that the bevel extends. Default is bevelThickness - 2.</li>
 				<li>bevelSize — float. Distance from the shape outline that the bevel extends. Default is bevelThickness - 2.</li>

+ 2 - 2
docs/api/geometries/ParametricBufferGeometry.html

@@ -37,8 +37,8 @@
 		<code>
 		<code>
 		var geometry = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, 25, 25 );
 		var geometry = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, 25, 25 );
 		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
 		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
-		var cube = new THREE.Mesh( geometry, material );
-		scene.add( cube );
+		var klein = new THREE.Mesh( geometry, material );
+		scene.add( klein );
 		</code>
 		</code>
 
 
 
 

+ 4 - 3
docs/api/loaders/ImageBitmapLoader.html

@@ -11,8 +11,9 @@
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
 		<p class="desc">
 		<p class="desc">
-			A loader for loading an [page:Image] as an [link:https://developer.mozilla.org/de/docs/Web/API/ImageBitmap ImageBitmap]. An ImageBitmap provides an asynchronous and resource efficient pathway to prepare textures for rendering in WebGL.
-
+			A loader for loading an [page:Image] as an [link:https://developer.mozilla.org/de/docs/Web/API/ImageBitmap ImageBitmap].
+			An ImageBitmap provides an asynchronous and resource efficient pathway to prepare textures for rendering in WebGL.<br/>
+			Unlike [page:FileLoader], [name] does not avoid multiple concurrent requests to the same URL.
 		</p>
 		</p>
 
 
 		<h2>Example</h2>
 		<h2>Example</h2>
@@ -76,7 +77,7 @@
 		[page:String url] — the path or URL to the file. This can also be a
 		[page:String url] — the path or URL to the file. This can also be a
 			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
 			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
 		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Image image].<br />
 		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Image image].<br />
-		[page:Function onProgress] — Will be called while load progresses. The argument will be the progress event.<br />
+		[page:Function onProgress] — This callback function is currently not supported.<br />
 		[page:Function onError] — Will be called when load errors.<br />
 		[page:Function onError] — Will be called when load errors.<br />
 		</p>
 		</p>
 		<p>
 		<p>

+ 1 - 2
docs/api/loaders/ImageLoader.html

@@ -12,7 +12,6 @@
 
 
 		<p class="desc">
 		<p class="desc">
 			A loader for loading an [page:Image].
 			A loader for loading an [page:Image].
-
 			This uses the [page:FileLoader] internally for loading files, and is used internally by the
 			This uses the [page:FileLoader] internally for loading files, and is used internally by the
 			[page:CubeTextureLoader], [page:ObjectLoader] and [page:TextureLoader].
 			[page:CubeTextureLoader], [page:ObjectLoader] and [page:TextureLoader].
 		</p>
 		</p>
@@ -88,7 +87,7 @@
 		[page:String url] — the path or URL to the file. This can also be a
 		[page:String url] — the path or URL to the file. This can also be a
 			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
 			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
 		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Image image].<br />
 		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Image image].<br />
-		[page:Function onProgress] — Will be called while load progresses. The argument will be the progress event.<br />
+		[page:Function onProgress] — This callback function is currently not supported.<br />
 		[page:Function onError] — Will be called when load errors.<br />
 		[page:Function onError] — Will be called when load errors.<br />
 		</p>
 		</p>
 		<p>
 		<p>

+ 3 - 3
docs/api/loaders/ObjectLoader.html

@@ -110,7 +110,7 @@
 		<h3>[method:Object3D parse]( [param:Object json], [param:Function onLoad]  )</h3>
 		<h3>[method:Object3D parse]( [param:Object json], [param:Function onLoad]  )</h3>
 		<p>
 		<p>
 		[page:Object json] — required. The JSON source to parse.<br /><br />
 		[page:Object json] — required. The JSON source to parse.<br /><br />
-		[page:Function onLoad] — Will be called when parsed completes. The argument will be the parsed [page:Object3D object].<br />
+		[page:Function onLoad] — Will be called when parsed completes. The argument will be the parsed [page:Object3D object].<br /><br />
 
 
 		Parse a <em>JSON</em> structure and return a threejs object.
 		Parse a <em>JSON</em> structure and return a threejs object.
 		This is used internally by [page:.load], but can also be used directly to parse
 		This is used internally by [page:.load], but can also be used directly to parse
@@ -213,12 +213,12 @@
 		</ul>
 		</ul>
 		</p>
 		</p>
 
 
-		<h3>[method:null setCrossOrigin]( [param:String value] )</h3>
+		<h3>[method:ObjectLoader setCrossOrigin]( [param:String value] )</h3>
 		<p>
 		<p>
 		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
 		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
 		</p>
 		</p>
 
 
-		<h3>[method:null setTexturePath]( [param:String value] )</h3>
+		<h3>[method:ObjectLoader setTexturePath]( [param:String value] )</h3>
 		<p>
 		<p>
 		[page:String value] — The base path or URL from which textures will be loaded.<br /><br />
 		[page:String value] — The base path or URL from which textures will be loaded.<br /><br />
 
 

+ 3 - 0
docs/api/materials/PointsMaterial.html

@@ -84,6 +84,9 @@ scene.add( starField );
 
 
 		<p>Sets the color of the points using data from a [page:Texture].</p>
 		<p>Sets the color of the points using data from a [page:Texture].</p>
 
 
+		<h3>[property:Boolean morphTargets]</h3>
+		<p>Define whether the material uses morphTargets. Default is false.</p>
+
 		<h3>[property:Number size]</h3>
 		<h3>[property:Number size]</h3>
 		<p>Sets the size of the points. Default is 1.0.</p>
 		<p>Sets the size of the points. Default is 1.0.</p>
 
 

+ 11 - 5
docs/api/math/Color.html

@@ -121,11 +121,17 @@ var color = new THREE.Color( 1, 0, 0 );
 			Copies the [page:.r r], [page:.g g] and [page:.b b] parameters from [page:Color color] in to this color.
 			Copies the [page:.r r], [page:.g g] and [page:.b b] parameters from [page:Color color] in to this color.
 		</p>
 		</p>
 
 
-		<h3>[method:Color convertGammaToLinear]() </h3>
-		<p>Converts this color from gamma to linear space by squaring the values of [page:.r r], [page:.g g] and [page:.b b] ).</p>
-
-		<h3>[method:Color convertLinearToGamma]() </h3>
-		<p>Converts this color from linear to gamma space by taking the square root of [page:.r r], [page:.g g] and [page:.b b]).</p>
+		<h3>[method:Color convertGammaToLinear]( [param:Float gammaFactor] ) </h3>
+		<p>
+		[page:Float gammaFactor] - (optional). Default is *2.0*.<br /><br />
+		Converts this color from gamma to linear space by taking [page:.r r], [page:.g g] and [page:.b b] to the power of [page:Float gammaFactor].
+		</p>
+		
+		<h3>[method:Color convertLinearToGamma]( [param:Float gammaFactor] ) </h3>
+		<p>
+		[page:Float gammaFactor] - (optional). Default is *2.0*.<br /><br />
+		Converts this color from linear to gamma space by taking [page:.r r], [page:.g g] and [page:.b b] to the power of 1 / [page:Float gammaFactor].
+		</p>
 
 
 		<h3>[method:Color copyGammaToLinear]( [param:Color color], [param:Float gammaFactor] ) </h3>
 		<h3>[method:Color copyGammaToLinear]( [param:Color color], [param:Float gammaFactor] ) </h3>
 		<p>
 		<p>

+ 14 - 14
docs/api/math/Matrix3.html

@@ -83,7 +83,7 @@ m.elements = [ 11, 21, 31,
 		<h3>[method:Matrix3 clone]()</h3>
 		<h3>[method:Matrix3 clone]()</h3>
 		<p>Creates a new Matrix3 and with identical elements to this one.</p>
 		<p>Creates a new Matrix3 and with identical elements to this one.</p>
 
 
-		<h3>[method:Matrix3 copy]( [param:Matrix3 m] )</h3>
+		<h3>[method:this copy]( [param:Matrix3 m] )</h3>
 		<p>Copies the elements of matrix [page:Matrix3 m] into this matrix.</p>
 		<p>Copies the elements of matrix [page:Matrix3 m] into this matrix.</p>
 
 
 		<h3>[method:Float determinant]()</h3>
 		<h3>[method:Float determinant]()</h3>
@@ -95,7 +95,7 @@ m.elements = [ 11, 21, 31,
 		<h3>[method:Boolean equals]( [param:Matrix3 m] )</h3>
 		<h3>[method:Boolean equals]( [param:Matrix3 m] )</h3>
 		<p>Return true if this matrix and [page:Matrix3 m] are equal.</p>
 		<p>Return true if this matrix and [page:Matrix3 m] are equal.</p>
 
 
-		<h3>[method:Matrix3 fromArray]( [param:Array array], [param:Integer offset] )</h3>
+		<h3>[method:this fromArray]( [param:Array array], [param:Integer offset] )</h3>
 		<p>
 		<p>
 		[page:Array array] - the array to read the elements from.<br />
 		[page:Array array] - the array to read the elements from.<br />
 		[page:Integer offset] - (optional) index of first element in the array. Default is 0.<br /><br />
 		[page:Integer offset] - (optional) index of first element in the array. Default is 0.<br /><br />
@@ -104,7 +104,7 @@ m.elements = [ 11, 21, 31,
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 getInverse]( [param:Matrix3 m], [param:Boolean throwOnDegenerate] )</h3>
+		<h3>[method:this getInverse]( [param:Matrix3 m], [param:Boolean throwOnDegenerate] )</h3>
 		<p>
 		<p>
 		[page:Matrix3 m] - the matrix to take the inverse of.<br />
 		[page:Matrix3 m] - the matrix to take the inverse of.<br />
 		[page:Boolean throwOnDegenerate] - (optional) If true, throw an error if the matrix is degenerate (not invertible).<br /><br />
 		[page:Boolean throwOnDegenerate] - (optional) If true, throw an error if the matrix is degenerate (not invertible).<br /><br />
@@ -115,7 +115,7 @@ m.elements = [ 11, 21, 31,
 		If [page:Boolean throwOnDegenerate] is not set and the matrix is not invertible, set this to the 3x3 identity matrix.
 		If [page:Boolean throwOnDegenerate] is not set and the matrix is not invertible, set this to the 3x3 identity matrix.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 getNormalMatrix]( [param:Matrix4 m] )</h3>
+		<h3>[method:this getNormalMatrix]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		[page:Matrix4 m] - [page:Matrix4]<br /><br />
 		[page:Matrix4 m] - [page:Matrix4]<br /><br />
 
 
@@ -124,7 +124,7 @@ m.elements = [ 11, 21, 31,
 	  of the matrix [page:Matrix4 m].
 	  of the matrix [page:Matrix4 m].
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 identity]()</h3>
+		<h3>[method:this identity]()</h3>
 		<p>
 		<p>
 		Resets this matrix to the 3x3 identity matrix:
 		Resets this matrix to the 3x3 identity matrix:
 		<code>
 		<code>
@@ -135,17 +135,17 @@ m.elements = [ 11, 21, 31,
 
 
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 multiply]( [param:Matrix3 m] )</h3>
+		<h3>[method:this multiply]( [param:Matrix3 m] )</h3>
 		<p>Post-multiplies this matrix by [page:Matrix3 m].</p>
 		<p>Post-multiplies this matrix by [page:Matrix3 m].</p>
 
 
-		<h3>[method:Matrix3 multiplyMatrices]( [param:Matrix3 a], [param:Matrix3 b] )</h3>
+		<h3>[method:this multiplyMatrices]( [param:Matrix3 a], [param:Matrix3 b] )</h3>
 		<p>Sets this matrix to [page:Matrix3 a] x [page:Matrix3 b].</p>
 		<p>Sets this matrix to [page:Matrix3 a] x [page:Matrix3 b].</p>
 
 
-		<h3>[method:Matrix3 multiplyScalar]( [param:Float s] )</h3>
+		<h3>[method:this multiplyScalar]( [param:Float s] )</h3>
 		<p>Multiplies every component of the matrix by the scalar value *s*.</p>
 		<p>Multiplies every component of the matrix by the scalar value *s*.</p>
 
 
 		<h3>
 		<h3>
-			[method:Matrix3 set](
+			[method:this set](
 			[page:Float n11], [page:Float n12], [page:Float n13],
 			[page:Float n11], [page:Float n12], [page:Float n13],
 			[page:Float n21], [page:Float n22], [page:Float n23],
 			[page:Float n21], [page:Float n22], [page:Float n23],
 			[page:Float n31], [page:Float n32], [page:Float n33] )
 			[page:Float n31], [page:Float n32], [page:Float n33] )
@@ -163,14 +163,14 @@ m.elements = [ 11, 21, 31,
 		sequence of values.
 		sequence of values.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 premultiply]( [param:Matrix3 m] )</h3>
+		<h3>[method:this premultiply]( [param:Matrix3 m] )</h3>
 		<p>Pre-multiplies this matrix by [page:Matrix3 m].</p>
 		<p>Pre-multiplies this matrix by [page:Matrix3 m].</p>
 
 
-		<h3>[method:Matrix3 setFromMatrix4]( [param:Matrix4 m] )</h3>
+		<h3>[method:this setFromMatrix4]( [param:Matrix4 m] )</h3>
 		<p>Set this matrx to the upper 3x3 matrix of the Matrix4 [page:Matrix4 m].</p>
 		<p>Set this matrx to the upper 3x3 matrix of the Matrix4 [page:Matrix4 m].</p>
 
 
 		<h3>
 		<h3>
-			[method:Matrix3 setUvTransform](
+			[method:this setUvTransform](
 			[page:Float tx], [page:Float ty], [page:Float sx], [page:Float sy],
 			[page:Float tx], [page:Float ty], [page:Float sx], [page:Float sy],
 			[page:Float rotation], [page:Float cx], [page:Float cy] )
 			[page:Float rotation], [page:Float cx], [page:Float cy] )
 		</h3>
 		</h3>
@@ -195,10 +195,10 @@ m.elements = [ 11, 21, 31,
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix3 transpose]()</h3>
+		<h3>[method:this transpose]()</h3>
 		<p>[link:https://en.wikipedia.org/wiki/Transpose Transposes] this matrix in place.</p>
 		<p>[link:https://en.wikipedia.org/wiki/Transpose Transposes] this matrix in place.</p>
 
 
-		<h3>[method:Matrix3 transposeIntoArray]( [param:Array array] )</h3>
+		<h3>[method:this transposeIntoArray]( [param:Array array] )</h3>
 		<p>
 		<p>
 		[page:Array array] -  array to store the resulting vector in.<br /><br />
 		[page:Array array] -  array to store the resulting vector in.<br /><br />
 
 

+ 29 - 29
docs/api/math/Matrix4.html

@@ -119,7 +119,7 @@ m.elements = [ 11, 21, 31, 41,
 		<h3>[method:Matrix4 clone]()</h3>
 		<h3>[method:Matrix4 clone]()</h3>
 		<p>Creates a new Matrix4 with identical [page:.elements elements] to this one.</p>
 		<p>Creates a new Matrix4 with identical [page:.elements elements] to this one.</p>
 
 
-		<h3>[method:Matrix4 compose]( [param:Vector3 position], [param:Quaternion quaternion], [param:Vector3 scale] )</h3>
+		<h3>[method:this compose]( [param:Vector3 position], [param:Quaternion quaternion], [param:Vector3 scale] )</h3>
 		<p>
 		<p>
 		Sets this matrix to the transformation composed of [page:Vector3 position],
 		Sets this matrix to the transformation composed of [page:Vector3 position],
 		[page:Quaternion quaternion] and [page:Vector3 scale]. Internally this calls
 		[page:Quaternion quaternion] and [page:Vector3 scale]. Internally this calls
@@ -128,10 +128,10 @@ m.elements = [ 11, 21, 31, 41,
 		[page:.setPosition setPosition]( [page:Vector3 position] ).
 		[page:.setPosition setPosition]( [page:Vector3 position] ).
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 copy]( [param:Matrix4 m] )</h3>
+		<h3>[method:this copy]( [param:Matrix4 m] )</h3>
 		<p>Copies the [page:.elements elements] of matrix [page:Matrix4 m] into this matrix.</p>
 		<p>Copies the [page:.elements elements] of matrix [page:Matrix4 m] into this matrix.</p>
 
 
-		<h3>[method:Matrix4 copyPosition]( [param:Matrix4 m] )</h3>
+		<h3>[method:this copyPosition]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Copies the translation component of the supplied matrix [page:Matrix4 m] into this
 		Copies the translation component of the supplied matrix [page:Matrix4 m] into this
 		matrix's translation component.
 		matrix's translation component.
@@ -154,7 +154,7 @@ m.elements = [ 11, 21, 31, 41,
 		<h3>[method:Boolean equals]( [param:Matrix4 m] )</h3>
 		<h3>[method:Boolean equals]( [param:Matrix4 m] )</h3>
 		<p>Return true if this matrix and [page:Matrix4 m] are equal.</p>
 		<p>Return true if this matrix and [page:Matrix4 m] are equal.</p>
 
 
-		<h3>[method:Matrix4 extractBasis]( [param:Vector3 xAxis], [param:Vector3 yAxis], [param:Vector3 zAxis] )</h3>
+		<h3>[method:this extractBasis]( [param:Vector3 xAxis], [param:Vector3 yAxis], [param:Vector3 zAxis] )</h3>
 		<p>
 		<p>
 		Extracts the [link:https://en.wikipedia.org/wiki/Basis_(linear_algebra) basis] of this
 		Extracts the [link:https://en.wikipedia.org/wiki/Basis_(linear_algebra) basis] of this
 		matrix into the three axis vectors provided. If this matrix is:
 		matrix into the three axis vectors provided. If this matrix is:
@@ -172,13 +172,13 @@ zAxis = (c, g, k)
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 extractRotation]( [param:Matrix4 m] )</h3>
+		<h3>[method:this extractRotation]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Extracts the rotation component of the supplied matrix [page:Matrix4 m] into this matrix's
 		Extracts the rotation component of the supplied matrix [page:Matrix4 m] into this matrix's
 		rotation component.
 		rotation component.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 fromArray]( [param:Array array], [param:Integer offset] )</h3>
+		<h3>[method:this fromArray]( [param:Array array], [param:Integer offset] )</h3>
 		<p>
 		<p>
 		[page:Array array] - the array to read the elements from.<br />
 		[page:Array array] - the array to read the elements from.<br />
 		[page:Integer offset] - ( optional ) offset into the array. Default is 0.<br /><br />
 		[page:Integer offset] - ( optional ) offset into the array. Default is 0.<br /><br />
@@ -187,7 +187,7 @@ zAxis = (c, g, k)
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 getInverse]( [param:Matrix4 m], [param:Boolean throwOnDegenerate] )</h3>
+		<h3>[method:this getInverse]( [param:Matrix4 m], [param:Boolean throwOnDegenerate] )</h3>
 		<p>
 		<p>
 		[page:Matrix4 m] - the matrix to take the inverse of.<br />
 		[page:Matrix4 m] - the matrix to take the inverse of.<br />
 		[page:Boolean throwOnDegenerate] - (optional) If true, throw an error if the matrix is degenerate (not invertible).<br /><br />
 		[page:Boolean throwOnDegenerate] - (optional) If true, throw an error if the matrix is degenerate (not invertible).<br /><br />
@@ -202,16 +202,16 @@ zAxis = (c, g, k)
 		<h3>[method:Float getMaxScaleOnAxis]()</h3>
 		<h3>[method:Float getMaxScaleOnAxis]()</h3>
 		<p>Gets the maximum scale value of the 3 axes.</p>
 		<p>Gets the maximum scale value of the 3 axes.</p>
 
 
-		<h3>[method:Matrix4 identity]()</h3>
+		<h3>[method:this identity]()</h3>
 		<p>Resets this matrix to the [link:https://en.wikipedia.org/wiki/Identity_matrix identity matrix].</p>
 		<p>Resets this matrix to the [link:https://en.wikipedia.org/wiki/Identity_matrix identity matrix].</p>
 
 
-		<h3>[method:Matrix4 lookAt]( [param:Vector3 eye], [param:Vector3 center], [param:Vector3 up], )</h3>
+		<h3>[method:this lookAt]( [param:Vector3 eye], [param:Vector3 center], [param:Vector3 up], )</h3>
 		<p>
 		<p>
 			Constructs a rotation matrix, looking from [page:Vector3 eye] towards [page:Vector3 center]
 			Constructs a rotation matrix, looking from [page:Vector3 eye] towards [page:Vector3 center]
 			oriented by the [page:Vector3 up] vector.
 			oriented by the [page:Vector3 up] vector.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationAxis]( [param:Vector3 axis], [param:Float theta] )</h3>
+		<h3>[method:this makeRotationAxis]( [param:Vector3 axis], [param:Float theta] )</h3>
 		<p>
 		<p>
 		[page:Vector3 axis] — Rotation axis, should be normalized.<br />
 		[page:Vector3 axis] — Rotation axis, should be normalized.<br />
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 		[page:Float theta] — Rotation angle in radians.<br /><br />
@@ -222,7 +222,7 @@ zAxis = (c, g, k)
 		See the discussion [link:http://www.gamedev.net/reference/articles/article1199.asp here].
 		See the discussion [link:http://www.gamedev.net/reference/articles/article1199.asp here].
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeBasis]( [param:Vector3 xAxis], [param:Vector3 yAxis], [param:Vector3 zAxis] )</h3>
+		<h3>[method:this makeBasis]( [param:Vector3 xAxis], [param:Vector3 yAxis], [param:Vector3 zAxis] )</h3>
 		<p>
 		<p>
 		Set this to the [link:https://en.wikipedia.org/wiki/Basis_(linear_algebra) basis] matrix consisting
 		Set this to the [link:https://en.wikipedia.org/wiki/Basis_(linear_algebra) basis] matrix consisting
 		of the three provided basis vectors:
 		of the three provided basis vectors:
@@ -234,26 +234,26 @@ xAxis.z, yAxis.z, zAxis.z, 0,
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makePerspective]( [param:Float left], [param:Float right], [param:Float top], [param:Float bottom], [param:Float near], [param:Float far] )</h3>
+		<h3>[method:this makePerspective]( [param:Float left], [param:Float right], [param:Float top], [param:Float bottom], [param:Float near], [param:Float far] )</h3>
 		<p>
 		<p>
 			Creates a [link:https://en.wikipedia.org/wiki/3D_projection#Perspective_projection perspective projection] matrix.
 			Creates a [link:https://en.wikipedia.org/wiki/3D_projection#Perspective_projection perspective projection] matrix.
 			This is used internally by [page:PerspectiveCamera.updateProjectionMatrix]()
 			This is used internally by [page:PerspectiveCamera.updateProjectionMatrix]()
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeOrthographic]( [param:Float left], [param:Float right], [param:Float top], [param:Float bottom], [param:Float near], [param:Float far] )</h3>
+		<h3>[method:this makeOrthographic]( [param:Float left], [param:Float right], [param:Float top], [param:Float bottom], [param:Float near], [param:Float far] )</h3>
 		<p>
 		<p>
 		Creates an [link:https://en.wikipedia.org/wiki/Orthographic_projection orthographic projection] matrix.
 		Creates an [link:https://en.wikipedia.org/wiki/Orthographic_projection orthographic projection] matrix.
 		This is used internally by [page:OrthographicCamera.updateProjectionMatrix]().
 		This is used internally by [page:OrthographicCamera.updateProjectionMatrix]().
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationFromEuler]( [param:Euler euler] )</h3>
+		<h3>[method:this makeRotationFromEuler]( [param:Euler euler] )</h3>
 		<p>
 		<p>
 		Sets the rotation component (the upper left 3x3 matrix) of this matrix to the rotation specified by the given [page:Euler Euler Angle].
 		Sets the rotation component (the upper left 3x3 matrix) of this matrix to the rotation specified by the given [page:Euler Euler Angle].
 		The rest of the matrix is set to the identity. Depending on the [page:Euler.order order] of the [page:Euler euler], there are six possible outcomes.
 		The rest of the matrix is set to the identity. Depending on the [page:Euler.order order] of the [page:Euler euler], there are six possible outcomes.
 		See [link:https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix this page] for a complete list.
 		See [link:https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix this page] for a complete list.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationFromQuaternion]( [param:Quaternion q] )</h3>
+		<h3>[method:this makeRotationFromQuaternion]( [param:Quaternion q] )</h3>
 		<p>
 		<p>
 		Sets the rotation component of this matrix to the rotation specified by [page:Quaternion q], as outlined
 		Sets the rotation component of this matrix to the rotation specified by [page:Quaternion q], as outlined
 		[link:https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion here].
 		[link:https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion here].
@@ -266,7 +266,7 @@ xAxis.z, yAxis.z, zAxis.z, 0,
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationX]( [param:Float theta] )</h3>
+		<h3>[method:this makeRotationX]( [param:Float theta] )</h3>
 		<p>
 		<p>
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 
 
@@ -280,7 +280,7 @@ xAxis.z, yAxis.z, zAxis.z, 0,
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationY]( [param:Float theta] )</h3>
+		<h3>[method:this makeRotationY]( [param:Float theta] )</h3>
 		<p>
 		<p>
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 
 
@@ -294,7 +294,7 @@ cos(&theta;)  0 sin(&theta;) 0
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeRotationZ]( [param:Float theta] )</h3>
+		<h3>[method:this makeRotationZ]( [param:Float theta] )</h3>
 		<p>
 		<p>
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 		[page:Float theta] — Rotation angle in radians.<br /><br />
 
 
@@ -308,7 +308,7 @@ sin(&theta;) cos(&theta;)  0 0
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeScale]( [param:Float x], [param:Float y], [param:Float z] )</h3>
+		<h3>[method:this makeScale]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		<p>
 		<p>
 			[page:Float x] - the amount to scale in the X axis.<br />
 			[page:Float x] - the amount to scale in the X axis.<br />
 			[page:Float y] - the amount to scale in the Y axis.<br />
 			[page:Float y] - the amount to scale in the Y axis.<br />
@@ -323,7 +323,7 @@ x, 0, 0, 0,
 			</code>
 			</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeShear]( [param:Float x], [param:Float y], [param:Float z] )</h3>
+		<h3>[method:this makeShear]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		<p>
 		<p>
 		[page:Float x] - the amount to shear in the X axis.<br />
 		[page:Float x] - the amount to shear in the X axis.<br />
 		[page:Float y] - the amount to shear in the Y axis.<br />
 		[page:Float y] - the amount to shear in the Y axis.<br />
@@ -338,7 +338,7 @@ x, y, 1, 0,
 </code>
 </code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 makeTranslation]( [param:Float x], [param:Float y], [param:Float z] )</h3>
+		<h3>[method:this makeTranslation]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		<p>
 		<p>
 			[page:Float x] - the amount to translate in the X axis.<br />
 			[page:Float x] - the amount to translate in the X axis.<br />
 			[page:Float y] - the amount to translate in the Y axis.<br />
 			[page:Float y] - the amount to translate in the Y axis.<br />
@@ -353,22 +353,22 @@ x, y, 1, 0,
 		</code>
 		</code>
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 multiply]( [param:Matrix4 m] )</h3>
+		<h3>[method:this multiply]( [param:Matrix4 m] )</h3>
 		<p>Post-multiplies this matrix by [page:Matrix4 m].</p>
 		<p>Post-multiplies this matrix by [page:Matrix4 m].</p>
 
 
-		<h3>[method:Matrix4 multiplyMatrices]( [param:Matrix4 a], [param:Matrix4 b] )</h3>
+		<h3>[method:this multiplyMatrices]( [param:Matrix4 a], [param:Matrix4 b] )</h3>
 		<p>Sets this matrix to [page:Matrix4 a] x [page:Matrix4 b].</p>
 		<p>Sets this matrix to [page:Matrix4 a] x [page:Matrix4 b].</p>
 
 
-		<h3>[method:Matrix4 multiplyScalar]( [param:Float s] )</h3>
+		<h3>[method:this multiplyScalar]( [param:Float s] )</h3>
 		<p>Multiplies every component of the matrix by a scalar value [page:Float s].</p>
 		<p>Multiplies every component of the matrix by a scalar value [page:Float s].</p>
 
 
-		<h3>[method:Matrix4 premultiply]( [param:Matrix4 m] )</h3>
+		<h3>[method:this premultiply]( [param:Matrix4 m] )</h3>
 		<p>Pre-multiplies this matrix by [page:Matrix4 m].</p>
 		<p>Pre-multiplies this matrix by [page:Matrix4 m].</p>
 
 
-		<h3>[method:Matrix4 scale]( [param:Vector3 v] )</h3>
+		<h3>[method:this scale]( [param:Vector3 v] )</h3>
 		<p>Multiplies the columns of this matrix by vector [page:Vector3 v].</p>
 		<p>Multiplies the columns of this matrix by vector [page:Vector3 v].</p>
 
 
-		<h3>[method:Matrix4 set](
+		<h3>[method:this set](
 			[page:Float n11], [page:Float n12], [page:Float n13], [page:Float n14],
 			[page:Float n11], [page:Float n12], [page:Float n13], [page:Float n14],
 			[page:Float n21], [page:Float n22], [page:Float n23], [page:Float n24],
 			[page:Float n21], [page:Float n22], [page:Float n23], [page:Float n24],
 			[page:Float n31], [page:Float n32], [page:Float n33], [page:Float n34],
 			[page:Float n31], [page:Float n32], [page:Float n33], [page:Float n34],
@@ -378,7 +378,7 @@ x, y, 1, 0,
 			[page:Float n12], ... [page:Float n44].
 			[page:Float n12], ... [page:Float n44].
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 setPosition]( [param:Vector3 v] )</h3>
+		<h3>[method:this setPosition]( [param:Vector3 v] )</h3>
 		<p>
 		<p>
 			Sets the position component for this matrix from vector [page:Vector3 v], without affecting the
 			Sets the position component for this matrix from vector [page:Vector3 v], without affecting the
 			rest of the matrix - i.e. if the matrix is currently:
 			rest of the matrix - i.e. if the matrix is currently:
@@ -406,7 +406,7 @@ m, n, o, p
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		[link:https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order column-major] format.
 		</p>
 		</p>
 
 
-		<h3>[method:Matrix4 transpose]()</h3>
+		<h3>[method:this transpose]()</h3>
 		<p>[link:https://en.wikipedia.org/wiki/Transpose Transposes] this matrix.</p>
 		<p>[link:https://en.wikipedia.org/wiki/Transpose Transposes] this matrix.</p>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>

+ 34 - 34
docs/api/math/Vector2.html

@@ -82,16 +82,16 @@
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
-		<h3>[method:Vector2 add]( [param:Vector2 v] )</h3>
+		<h3>[method:this add]( [param:Vector2 v] )</h3>
 		<p>Adds [page:Vector2 v] to this vector.</p>
 		<p>Adds [page:Vector2 v] to this vector.</p>
 
 
-		<h3>[method:Vector2 addScalar]( [param:Float s] )</h3>
+		<h3>[method:this addScalar]( [param:Float s] )</h3>
 		<p>Adds the scalar value [page:Float s] to this vector's [page:.x x] and [page:.y y] values.</p>
 		<p>Adds the scalar value [page:Float s] to this vector's [page:.x x] and [page:.y y] values.</p>
 
 
-		<h3>[method:Vector2 addScaledVector]( [param:Vector2 v], [param:Float s] )</h3>
+		<h3>[method:this addScaledVector]( [param:Vector2 v], [param:Float s] )</h3>
 		<p>Adds the multiple of [page:Vector2 v] and [page:Float s] to this vector.</p>
 		<p>Adds the multiple of [page:Vector2 v] and [page:Float s] to this vector.</p>
 
 
-		<h3>[method:Vector2 addVectors]( [param:Vector2 a], [param:Vector2 b] )</h3>
+		<h3>[method:this addVectors]( [param:Vector2 a], [param:Vector2 b] )</h3>
 		<p>Sets this vector to [page:Vector2 a] + [page:Vector2 b].</p>
 		<p>Sets this vector to [page:Vector2 a] + [page:Vector2 b].</p>
 
 
 		<h3>[method:Float angle]()</h3>
 		<h3>[method:Float angle]()</h3>
@@ -99,17 +99,17 @@
 		Computes the angle in radians of this vector with respect to the positive x-axis.
 		Computes the angle in radians of this vector with respect to the positive x-axis.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 applyMatrix3]( [param:Matrix3 m] )</h3>
+		<h3>[method:this applyMatrix3]( [param:Matrix3 m] )</h3>
 		<p>
 		<p>
 		Multiplies this vector (with an implicit 1 as the 3rd component) by m.
 		Multiplies this vector (with an implicit 1 as the 3rd component) by m.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 ceil]()</h3>
+		<h3>[method:this ceil]()</h3>
 		<p>
 		<p>
 		The [page:.x x] and [page:.y y] components of the vector are rounded up to the nearest integer value.
 		The [page:.x x] and [page:.y y] components of the vector are rounded up to the nearest integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 clamp]( [param:Vector2 min], [param:Vector2 max] )</h3>
+		<h3>[method:this clamp]( [param:Vector2 min], [param:Vector2 max] )</h3>
 		<p>
 		<p>
 		[page:Vector2 min] - the minimum x and y values.<br />
 		[page:Vector2 min] - the minimum x and y values.<br />
 		[page:Vector2 max] - the maximum x and y values in the desired range<br /><br />
 		[page:Vector2 max] - the maximum x and y values in the desired range<br /><br />
@@ -118,7 +118,7 @@
 		If this vector's x or y value is less than the min vector's x or y value, it is replaced by the corresponding value.
 		If this vector's x or y value is less than the min vector's x or y value, it is replaced by the corresponding value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 clampLength]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampLength]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
@@ -127,7 +127,7 @@
 		If this vector's length is less than the min value, it is replaced by the min value.
 		If this vector's length is less than the min value, it is replaced by the min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 clampScalar]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampScalar]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
@@ -141,7 +141,7 @@
 		Returns a new Vector2 with the same [page:.x x] and [page:.y y] values as this one.
 		Returns a new Vector2 with the same [page:.x x] and [page:.y y] values as this one.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 copy]( [param:Vector2 v] )</h3>
+		<h3>[method:this copy]( [param:Vector2 v] )</h3>
 		<p>
 		<p>
 			Copies the values of the passed Vector2's [page:.x x] and [page:.y y]
 			Copies the values of the passed Vector2's [page:.x x] and [page:.y y]
 			properties to this Vector2.
 			properties to this Vector2.
@@ -162,10 +162,10 @@
 		as it is slightly more efficient to calculate.
 		as it is slightly more efficient to calculate.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 divide]( [param:Vector2 v] )</h3>
+		<h3>[method:this divide]( [param:Vector2 v] )</h3>
 		<p>Divides this vector by [page:Vector2 v].</p>
 		<p>Divides this vector by [page:Vector2 v].</p>
 
 
-		<h3>[method:Vector2 divideScalar]( [param:Float s] )</h3>
+		<h3>[method:this divideScalar]( [param:Float s] )</h3>
 		<p>
 		<p>
 		Divides this vector by scalar [page:Float s].<br />
 		Divides this vector by scalar [page:Float s].<br />
 		Sets vector to *( 0, 0 )* if [page:Float s] = 0.
 		Sets vector to *( 0, 0 )* if [page:Float s] = 0.
@@ -180,10 +180,10 @@
 		<h3>[method:Boolean equals]( [param:Vector2 v] )</h3>
 		<h3>[method:Boolean equals]( [param:Vector2 v] )</h3>
 		<p>Checks for strict equality of this vector and [page:Vector2 v].</p>
 		<p>Checks for strict equality of this vector and [page:Vector2 v].</p>
 
 
-		<h3>[method:Vector2 floor]()</h3>
+		<h3>[method:this floor]()</h3>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 
 
-		<h3>[method:Vector2 fromArray]( [param:Array array], [param:Integer offset] )</h3>
+		<h3>[method:this fromArray]( [param:Array array], [param:Integer offset] )</h3>
 		<p>
 		<p>
 		[page:Array array] - the source array.<br />
 		[page:Array array] - the source array.<br />
 		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
@@ -191,7 +191,7 @@
 		Sets this vector's [page:.x x] value to be array[ offset ] and [page:.y y] value to be array[ offset + 1 ].
 		Sets this vector's [page:.x x] value to be array[ offset ] and [page:.y y] value to be array[ offset + 1 ].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
+		<h3>[method:this fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
 		<p>
 		<p>
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:Integer index] - index in the attribute.<br /><br />
 		[page:Integer index] - index in the attribute.<br /><br />
@@ -223,7 +223,7 @@
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 lerp]( [param:Vector2 v], [param:Float alpha] )</h3>
+		<h3>[method:this lerp]( [param:Vector2 v], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
@@ -232,7 +232,7 @@
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector2 v].
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector2 v].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 lerpVectors]( [param:Vector2 v1], [param:Vector2 v2], [param:Float alpha] )</h3>
+		<h3>[method:this lerpVectors]( [param:Vector2 v1], [param:Vector2 v2], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector2 v1] - the starting [page:Vector2].<br />
 		[page:Vector2 v1] - the starting [page:Vector2].<br />
 		[page:Vector2 v2] - [page:Vector2] to interpolate towards.<br />
 		[page:Vector2 v2] - [page:Vector2] to interpolate towards.<br />
@@ -243,35 +243,35 @@
 		- alpha = 0 will be [page:Vector2 v1], and alpha = 1 will be [page:Vector2 v2].
 		- alpha = 0 will be [page:Vector2 v1], and alpha = 1 will be [page:Vector2 v2].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 negate]()</h3>
+		<h3>[method:this negate]()</h3>
 		<p>Inverts this vector - i.e. sets x = -x and y = -y.</p>
 		<p>Inverts this vector - i.e. sets x = -x and y = -y.</p>
 
 
-		<h3>[method:Vector2 normalize]()</h3>
+		<h3>[method:this normalize]()</h3>
 		<p>
 		<p>
 		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		as this one, but [page:.length length] 1.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 max]( [param:Vector2 v] )</h3>
+		<h3>[method:this max]( [param:Vector2 v] )</h3>
 		<p>
 		<p>
 		If this vector's x or y value is less than [page:Vector2 v]'s x or y value, replace
 		If this vector's x or y value is less than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding max value.
 		that value with the corresponding max value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 min]( [param:Vector2 v] )</h3>
+		<h3>[method:this min]( [param:Vector2 v] )</h3>
 		<p>
 		<p>
 		If this vector's x or y value is greater than [page:Vector2 v]'s x or y value, replace
 		If this vector's x or y value is greater than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding min value.
 		that value with the corresponding min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 multiply]( [param:Vector2 v] )</h3>
+		<h3>[method:this multiply]( [param:Vector2 v] )</h3>
 		<p>Multiplies this vector by [page:Vector2 v].</p>
 		<p>Multiplies this vector by [page:Vector2 v].</p>
 
 
 
 
-		<h3>[method:Vector2 multiplyScalar]( [param:Float s] )</h3>
+		<h3>[method:this multiplyScalar]( [param:Float s] )</h3>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 
 
-		<h3>[method:Vector2 rotateAround]( [param:Vector2 center], [param:float angle] )</h3>
+		<h3>[method:this rotateAround]( [param:Vector2 center], [param:float angle] )</h3>
 		<p>
 		<p>
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:float angle] - the angle to rotate, in radians.<br /><br />
 			[page:float angle] - the angle to rotate, in radians.<br /><br />
@@ -279,15 +279,15 @@
 			Rotates the vector around [page:Vector2 center] by [page:float angle] radians.
 			Rotates the vector around [page:Vector2 center] by [page:float angle] radians.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 round]()</h3>
+		<h3>[method:this round]()</h3>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 
 
-		<h3>[method:Vector2 roundToZero]()</h3>
+		<h3>[method:this roundToZero]()</h3>
 		<p>
 		<p>
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 set]( [param:Float x], [param:Float y] )</h3>
+		<h3>[method:this set]( [param:Float x], [param:Float y] )</h3>
 		<p>Sets the [page:.x x] and [page:.y y] components of this vector.</p>
 		<p>Sets the [page:.x x] and [page:.y y] components of this vector.</p>
 
 
 		<h3>[method:null setComponent]( [param:Integer index], [param:Float value] )</h3>
 		<h3>[method:null setComponent]( [param:Integer index], [param:Float value] )</h3>
@@ -299,30 +299,30 @@
 		If index equals 1 set [page:.y y] to [page:Float value]
 		If index equals 1 set [page:.y y] to [page:Float value]
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 setLength]( [param:Float l] )</h3>
+		<h3>[method:this setLength]( [param:Float l] )</h3>
 		<p>
 		<p>
 		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		[page:Float l].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 setScalar]( [param:Float scalar] )</h3>
+		<h3>[method:this setScalar]( [param:Float scalar] )</h3>
 		<p>
 		<p>
 		Sets the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
 		Sets the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector2 setX]( [param:Float x] )</h3>
+		<h3>[method:this setX]( [param:Float x] )</h3>
 		<p>Replaces this vector's [page:.x x] value with [page:Float x].</p>
 		<p>Replaces this vector's [page:.x x] value with [page:Float x].</p>
 
 
-		<h3>[method:Vector2 setY]( [param:Float y] )</h3>
+		<h3>[method:this setY]( [param:Float y] )</h3>
 		<p>Replaces this vector's [page:.y y] value with [page:Float y].</p>
 		<p>Replaces this vector's [page:.y y] value with [page:Float y].</p>
 
 
-		<h3>[method:Vector2 sub]( [param:Vector2 v] )</h3>
+		<h3>[method:this sub]( [param:Vector2 v] )</h3>
 		<p>Subtracts [page:Vector2 v] from this vector.</p>
 		<p>Subtracts [page:Vector2 v] from this vector.</p>
 
 
-		<h3>[method:Vector2 subScalar]( [param:Float s] )</h3>
+		<h3>[method:this subScalar]( [param:Float s] )</h3>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] components.</p>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] components.</p>
 
 
-		<h3>[method:Vector2 subVectors]( [param:Vector2 a], [param:Vector2 b] )</h3>
+		<h3>[method:this subVectors]( [param:Vector2 a], [param:Vector2 b] )</h3>
 		<p>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</p>
 		<p>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</p>
 
 
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>

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

@@ -79,19 +79,19 @@ var d = a.distanceTo( b );
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
-		<h3>[method:Vector3 add]( [param:Vector3 v] )</h3>
+		<h3>[method:this add]( [param:Vector3 v] )</h3>
 		<p>Adds [page:Vector3 v] to this vector.</p>
 		<p>Adds [page:Vector3 v] to this vector.</p>
 
 
-		<h3>[method:Vector3 addScalar]( [param:Float s] )</h3>
+		<h3>[method:this addScalar]( [param:Float s] )</h3>
 		<p>Adds the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</p>
 		<p>Adds the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</p>
 
 
-		<h3>[method:Vector3 addScaledVector]( [param:Vector3 v], [param:Float s] )</h3>
+		<h3>[method:this addScaledVector]( [param:Vector3 v], [param:Float s] )</h3>
 		<p>Adds the multiple of [page:Vector3 v] and [page:Float s] to this vector.</p>
 		<p>Adds the multiple of [page:Vector3 v] and [page:Float s] to this vector.</p>
 
 
-		<h3>[method:Vector3 addVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
+		<h3>[method:this addVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<p>Sets this vector to [page:Vector3 a] + [page:Vector3 b].</p>
 		<p>Sets this vector to [page:Vector3 a] + [page:Vector3 b].</p>
 
 
-		<h3>[method:Vector3 applyAxisAngle]( [param:Vector3 axis], [param:Float angle] )</h3>
+		<h3>[method:this applyAxisAngle]( [param:Vector3 axis], [param:Float angle] )</h3>
 		<p>
 		<p>
 		[page:Vector3 axis] - A normalized [page:Vector3].<br />
 		[page:Vector3 axis] - A normalized [page:Vector3].<br />
 		[page:Float angle] - An angle in radians.<br /><br />
 		[page:Float angle] - An angle in radians.<br /><br />
@@ -99,21 +99,21 @@ var d = a.distanceTo( b );
 		Applies a rotation specified by an axis and an angle to this vector.
 		Applies a rotation specified by an axis and an angle to this vector.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 applyEuler]( [param:Euler euler] )</h3>
+		<h3>[method:this applyEuler]( [param:Euler euler] )</h3>
 		<p>
 		<p>
 		Applies euler transform to this vector by converting the [page:Euler] object to a
 		Applies euler transform to this vector by converting the [page:Euler] object to a
 		[page:Quaternion] and applying.
 		[page:Quaternion] and applying.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 applyMatrix3]( [param:Matrix3 m] )</h3>
+		<h3>[method:this applyMatrix3]( [param:Matrix3 m] )</h3>
 		<p>Multiplies this vector by [page:Matrix3 m]</p>
 		<p>Multiplies this vector by [page:Matrix3 m]</p>
 
 
-		<h3>[method:Vector3 applyMatrix4]( [param:Matrix4 m] )</h3>
+		<h3>[method:this applyMatrix4]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Multiplies this vector (with an implicit 1 in the 4th dimension) and m, and divides by perspective.
 		Multiplies this vector (with an implicit 1 in the 4th dimension) and m, and divides by perspective.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 applyQuaternion]( [param:Quaternion quaternion] )</h3>
+		<h3>[method:this applyQuaternion]( [param:Quaternion quaternion] )</h3>
 		<p>
 		<p>
 		Applies a [page:Quaternion] transform to this vector.
 		Applies a [page:Quaternion] transform to this vector.
 		</p>
 		</p>
@@ -124,12 +124,12 @@ var d = a.distanceTo( b );
 		Returns the angle between this vector and vector [page:Vector3 v] in radians.
 		Returns the angle between this vector and vector [page:Vector3 v] in radians.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 ceil]()</h3>
+		<h3>[method:this ceil]()</h3>
 		<p>
 		<p>
 		The [page:.x x], [page:.y y] and [page:.z z] components of the vector are rounded up to the nearest integer value.
 		The [page:.x x], [page:.y y] and [page:.z z] components of the vector are rounded up to the nearest integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 clamp]( [param:Vector3 min], [param:Vector3 max] )</h3>
+		<h3>[method:this clamp]( [param:Vector3 min], [param:Vector3 max] )</h3>
 		<p>
 		<p>
 		[page:Vector3 min] - the minimum [page:.x x], [page:.y y] and [page:.z z] values.<br />
 		[page:Vector3 min] - the minimum [page:.x x], [page:.y y] and [page:.z z] values.<br />
 		[page:Vector3 max] - the maximum [page:.x x], [page:.y y] and [page:.z z] values in the desired range<br /><br />
 		[page:Vector3 max] - the maximum [page:.x x], [page:.y y] and [page:.z z] values in the desired range<br /><br />
@@ -138,7 +138,7 @@ var d = a.distanceTo( b );
 		If this vector's x, y or z value is less than the min vector's x, y or z value, it is replaced by the corresponding value.
 		If this vector's x, y or z value is less than the min vector's x, y or z value, it is replaced by the corresponding value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 clampLength]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampLength]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
@@ -147,7 +147,7 @@ var d = a.distanceTo( b );
 		If this vector's length is less than the min value, it is replaced by the min value.
 		If this vector's length is less than the min value, it is replaced by the min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 clampScalar]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampScalar]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
@@ -161,18 +161,18 @@ var d = a.distanceTo( b );
 		Returns a new vector3 with the same [page:.x x], [page:.y y] and [page:.z z] values as this one.
 		Returns a new vector3 with the same [page:.x x], [page:.y y] and [page:.z z] values as this one.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 copy]( [param:Vector3 v] )</h3>
+		<h3>[method:this copy]( [param:Vector3 v] )</h3>
 		<p>
 		<p>
 			Copies the values of the passed vector3's [page:.x x], [page:.y y] and [page:.z z]
 			Copies the values of the passed vector3's [page:.x x], [page:.y y] and [page:.z z]
 			properties to this vector3.
 			properties to this vector3.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 cross]( [param:Vector3 v] )</h3>
+		<h3>[method:this cross]( [param:Vector3 v] )</h3>
 		<p>
 		<p>
 		Sets this vector to [link:https://en.wikipedia.org/wiki/Cross_product cross product] of itself and [page:Vector3 v].
 		Sets this vector to [link:https://en.wikipedia.org/wiki/Cross_product cross product] of itself and [page:Vector3 v].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 crossVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
+		<h3>[method:this crossVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<p>
 		<p>
 		Sets this vector to [link:https://en.wikipedia.org/wiki/Cross_product cross product] of [page:Vector3 a] and [page:Vector3 b].
 		Sets this vector to [link:https://en.wikipedia.org/wiki/Cross_product cross product] of [page:Vector3 a] and [page:Vector3 b].
 		</p>
 		</p>
@@ -192,10 +192,10 @@ var d = a.distanceTo( b );
 		as it is slightly more efficient to calculate.
 		as it is slightly more efficient to calculate.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 divide]( [param:Vector3 v] )</h3>
+		<h3>[method:this divide]( [param:Vector3 v] )</h3>
 		<p>Divides this vector by [page:Vector3 v].</p>
 		<p>Divides this vector by [page:Vector3 v].</p>
 
 
-		<h3>[method:Vector3 divideScalar]( [param:Float s] )</h3>
+		<h3>[method:this divideScalar]( [param:Float s] )</h3>
 		<p>
 		<p>
 		Divides this vector by scalar [page:Float s].<br />
 		Divides this vector by scalar [page:Float s].<br />
 		Sets vector to *( 0, 0, 0 )* if *[page:Float s] = 0*.
 		Sets vector to *( 0, 0, 0 )* if *[page:Float s] = 0*.
@@ -210,10 +210,10 @@ var d = a.distanceTo( b );
 		<h3>[method:Boolean equals]( [param:Vector3 v] )</h3>
 		<h3>[method:Boolean equals]( [param:Vector3 v] )</h3>
 		<p>Checks for strict equality of this vector and [page:Vector3 v].</p>
 		<p>Checks for strict equality of this vector and [page:Vector3 v].</p>
 
 
-		<h3>[method:Vector3 floor]()</h3>
+		<h3>[method:this floor]()</h3>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 
 
-		<h3>[method:Vector3 fromArray]( [param:Array array], [param:Integer offset] )</h3>
+		<h3>[method:this fromArray]( [param:Array array], [param:Integer offset] )</h3>
 		<p>
 		<p>
 		[page:Array array] - the source array.<br />
 		[page:Array array] - the source array.<br />
 		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
 		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
@@ -222,7 +222,7 @@ var d = a.distanceTo( b );
 		and [page:.z z] value to be array[ offset + 2 ].
 		and [page:.z z] value to be array[ offset + 2 ].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
+		<h3>[method:this fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
 		<p>
 		<p>
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:Integer index] - index in the attribute.<br /><br />
 		[page:Integer index] - index in the attribute.<br /><br />
@@ -255,7 +255,7 @@ var d = a.distanceTo( b );
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 lerp]( [param:Vector3 v], [param:Float alpha] )</h3>
+		<h3>[method:this lerp]( [param:Vector3 v], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector3 v] - [page:Vector3] to interpolate towards.<br />
 		[page:Vector3 v] - [page:Vector3] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
@@ -264,7 +264,7 @@ var d = a.distanceTo( b );
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector3 v].
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector3 v].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 lerpVectors]( [param:Vector3 v1], [param:Vector3 v2], [param:Float alpha] )</h3>
+		<h3>[method:this lerpVectors]( [param:Vector3 v1], [param:Vector3 v2], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector3 v1] - the starting [page:Vector3].<br />
 		[page:Vector3 v1] - the starting [page:Vector3].<br />
 		[page:Vector3 v2] - [page:Vector3] to interpolate towards.<br />
 		[page:Vector3 v2] - [page:Vector3] to interpolate towards.<br />
@@ -275,44 +275,44 @@ var d = a.distanceTo( b );
 		- alpha = 0 will be [page:Vector3 v1], and alpha = 1 will be [page:Vector3 v2].
 		- alpha = 0 will be [page:Vector3 v1], and alpha = 1 will be [page:Vector3 v2].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 max]( [param:Vector3 v] )</h3>
+		<h3>[method:this max]( [param:Vector3 v] )</h3>
 		<p>
 		<p>
 		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
 		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding max value.
 		that value with the corresponding max value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 min]( [param:Vector3 v] )</h3>
+		<h3>[method:this min]( [param:Vector3 v] )</h3>
 		<p>
 		<p>
 		If this vector's x, y or z value is greater than [page:Vector3 v]'s x, y or z value, replace
 		If this vector's x, y or z value is greater than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding min value.
 		that value with the corresponding min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 multiply]( [param:Vector3 v] )</h3>
+		<h3>[method:this multiply]( [param:Vector3 v] )</h3>
 		<p>Multiplies this vector by [page:Vector3 v].</p>
 		<p>Multiplies this vector by [page:Vector3 v].</p>
 
 
-		<h3>[method:Vector3 multiplyScalar]( [param:Float s] )</h3>
+		<h3>[method:this multiplyScalar]( [param:Float s] )</h3>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 
 
-		<h3>[method:Vector3 multiplyVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
+		<h3>[method:this multiplyVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<p>Sets this vector equal to [page:Vector3 a] * [page:Vector3 b], component-wise.</p>
 		<p>Sets this vector equal to [page:Vector3 a] * [page:Vector3 b], component-wise.</p>
 
 
-		<h3>[method:Vector3 negate]()</h3>
+		<h3>[method:this negate]()</h3>
 		<p>Inverts this vector - i.e. sets x = -x, y = -y and z = -z.</p>
 		<p>Inverts this vector - i.e. sets x = -x, y = -y and z = -z.</p>
 
 
-		<h3>[method:Vector3 normalize]()</h3>
+		<h3>[method:this normalize]()</h3>
 		<p>
 		<p>
 		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		as this one, but [page:.length length] 1.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 project]( [param:Camera camera] )</h3>
+		<h3>[method:this project]( [param:Camera camera] )</h3>
 		<p>
 		<p>
 		[page:Camera camera] — camera to use in the projection.<br /><br />
 		[page:Camera camera] — camera to use in the projection.<br /><br />
 
 
 		[link:https://en.wikipedia.org/wiki/Vector_projection Projects] the vector with the camera.
 		[link:https://en.wikipedia.org/wiki/Vector_projection Projects] the vector with the camera.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 projectOnPlane]( [param:Vector3 planeNormal] )</h3>
+		<h3>[method:this projectOnPlane]( [param:Vector3 planeNormal] )</h3>
 		<p>
 		<p>
 		[page:Vector3 planeNormal] - A vector representing a plane normal.<br /><br />
 		[page:Vector3 planeNormal] - A vector representing a plane normal.<br /><br />
 
 
@@ -320,10 +320,10 @@ var d = a.distanceTo( b );
 		normal from this vector.
 		normal from this vector.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 projectOnVector]( [param:Vector3] )</h3>
+		<h3>[method:this projectOnVector]( [param:Vector3] )</h3>
 		<p>[link:https://en.wikipedia.org/wiki/Vector_projection Projects] this vector onto another vector.</p>
 		<p>[link:https://en.wikipedia.org/wiki/Vector_projection Projects] this vector onto another vector.</p>
 
 
-		<h3>[method:Vector3 reflect]( [param:Vector3 normal] )</h3>
+		<h3>[method:this reflect]( [param:Vector3 normal] )</h3>
 		<p>
 		<p>
 		[page:Vector3 normal] - the normal to the reflecting plane<br /><br />
 		[page:Vector3 normal] - the normal to the reflecting plane<br /><br />
 
 
@@ -331,15 +331,15 @@ var d = a.distanceTo( b );
 		have unit length.
 		have unit length.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 round]()</h3>
+		<h3>[method:this round]()</h3>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 
 
-		<h3>[method:Vector3 roundToZero]()</h3>
+		<h3>[method:this roundToZero]()</h3>
 		<p>
 		<p>
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 set]( [param:Float x], [param:Float y], [param:Float z] )</h3>
+		<h3>[method:this set]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		<p>Sets the [page:.x x], [page:.y y] and [page:.z z] components of this vector.</p>
 		<p>Sets the [page:.x x], [page:.y y] and [page:.z z] components of this vector.</p>
 
 
 		<h3>[method:null setComponent]( [param:Integer index], [param:Float value] )</h3>
 		<h3>[method:null setComponent]( [param:Integer index], [param:Float value] )</h3>
@@ -352,61 +352,61 @@ var d = a.distanceTo( b );
 		If index equals 2 set [page:.z z] to [page:Float value]
 		If index equals 2 set [page:.z z] to [page:Float value]
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setFromCylindrical]( [param:Cylindrical c] )</h3>
+		<h3>[method:this setFromCylindrical]( [param:Cylindrical c] )</h3>
 		<p>
 		<p>
 		Sets this vector from the cylindrical coordinates [page:Cylindrical c].
 		Sets this vector from the cylindrical coordinates [page:Cylindrical c].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setFromMatrixColumn]( [param:Matrix4 matrix], [param:Integer index] )</h3>
+		<h3>[method:this setFromMatrixColumn]( [param:Matrix4 matrix], [param:Integer index] )</h3>
 		<p>
 		<p>
 		Sets this vector's [page:.x x], [page:.y y] and [page:.z z] equal to the column of
 		Sets this vector's [page:.x x], [page:.y y] and [page:.z z] equal to the column of
 		the [page:Matrix4 matrix] specified by the [page:Integer index].
 		the [page:Matrix4 matrix] specified by the [page:Integer index].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setFromMatrixPosition]( [param:Matrix4 m] )</h3>
+		<h3>[method:this setFromMatrixPosition]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Sets this vector to the position elements of the
 		Sets this vector to the position elements of the
 		[link:https://en.wikipedia.org/wiki/Transformation_matrix transformation matrix] [page:Matrix4 m].
 		[link:https://en.wikipedia.org/wiki/Transformation_matrix transformation matrix] [page:Matrix4 m].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setFromMatrixScale]( [param:Matrix4 m] )</h3>
+		<h3>[method:this setFromMatrixScale]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Sets this vector to the scale elements of the
 		Sets this vector to the scale elements of the
 		[link:https://en.wikipedia.org/wiki/Transformation_matrix transformation matrix] [page:Matrix4 m].
 		[link:https://en.wikipedia.org/wiki/Transformation_matrix transformation matrix] [page:Matrix4 m].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setFromSpherical]( [param:Spherical s] )</h3>
+		<h3>[method:this setFromSpherical]( [param:Spherical s] )</h3>
 		<p>
 		<p>
 		Sets this vector from the spherical coordinates [page:Spherical s].
 		Sets this vector from the spherical coordinates [page:Spherical s].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setLength]( [param:Float l] )</h3>
+		<h3>[method:this setLength]( [param:Float l] )</h3>
 		<p>
 		<p>
 		Set this vector to the vector with the same direction as this one, but [page:.length length]
 		Set this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		[page:Float l].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setScalar]( [param:Float scalar] )</h3>
+		<h3>[method:this setScalar]( [param:Float scalar] )</h3>
 		<p>
 		<p>
 		Set the [page:.x x], [page:.y y] and [page:.z z] values of this vector both equal to [page:Float scalar].
 		Set the [page:.x x], [page:.y y] and [page:.z z] values of this vector both equal to [page:Float scalar].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 setX]( [param:Float x] )</h3>
+		<h3>[method:this setX]( [param:Float x] )</h3>
 		<p>Replace this vector's [page:.x x] value with [page:Float x].</p>
 		<p>Replace this vector's [page:.x x] value with [page:Float x].</p>
 
 
-		<h3>[method:Vector3 setY]( [param:Float y] )</h3>
+		<h3>[method:this setY]( [param:Float y] )</h3>
 		<p>Replace this vector's [page:.y y] value with [page:Float y].</p>
 		<p>Replace this vector's [page:.y y] value with [page:Float y].</p>
 
 
-		<h3>[method:Vector3 setZ]( [param:Float z] )</h3>
+		<h3>[method:this setZ]( [param:Float z] )</h3>
 		<p>Replace this vector's [page:.z z] value with [page:Float z].</p>
 		<p>Replace this vector's [page:.z z] value with [page:Float z].</p>
 
 
-		<h3>[method:Vector3 sub]( [param:Vector3 v] )</h3>
+		<h3>[method:this sub]( [param:Vector3 v] )</h3>
 		<p>Subtracts [page:Vector3 v] from this vector.</p>
 		<p>Subtracts [page:Vector3 v] from this vector.</p>
 
 
-		<h3>[method:Vector3 subScalar]( [param:Float s] )</h3>
+		<h3>[method:this subScalar]( [param:Float s] )</h3>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x], [page:.y y] and [page:.z z] compnents.</p>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x], [page:.y y] and [page:.z z] compnents.</p>
 
 
-		<h3>[method:Vector3 subVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
+		<h3>[method:this subVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<p>Sets this vector to [page:Vector3 a] - [page:Vector3 b].</p>
 		<p>Sets this vector to [page:Vector3 a] - [page:Vector3 b].</p>
 
 
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>
@@ -418,13 +418,13 @@ var d = a.distanceTo( b );
 		Returns an array [x, y, z], or copies x, y and z into the provided [page:Array array].
 		Returns an array [x, y, z], or copies x, y and z into the provided [page:Array array].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 transformDirection]( [param:Matrix4 m] )</h3>
+		<h3>[method:this transformDirection]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Transforms the direction of this vector by a matrix (the upper left 3 x 3 subset of a [page:Matrix4 m])
 		Transforms the direction of this vector by a matrix (the upper left 3 x 3 subset of a [page:Matrix4 m])
 		and then [page:.normalize normalizes] the result.
 		and then [page:.normalize normalizes] the result.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector3 unproject]( [param:Camera camera] )</h3>
+		<h3>[method:this unproject]( [param:Camera camera] )</h3>
 		<p>
 		<p>
 		[page:Camera camera] — camera to use in the projection.<br /><br />
 		[page:Camera camera] — camera to use in the projection.<br /><br />
 
 

+ 35 - 35
docs/api/math/Vector4.html

@@ -81,29 +81,29 @@ var d = a.dot( b );
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
-		<h3>[method:Vector4 add]( [param:Vector4 v] )</h3>
+		<h3>[method:this add]( [param:Vector4 v] )</h3>
 		<p>Adds [page:Vector4 v] to this vector.</p>
 		<p>Adds [page:Vector4 v] to this vector.</p>
 
 
-		<h3>[method:Vector4 addScalar]( [param:Float s] )</h3>
+		<h3>[method:this addScalar]( [param:Float s] )</h3>
 		<p>Adds the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</p>
 		<p>Adds the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</p>
 
 
-		<h3>[method:Vector4 addScaledVector]( [param:Vector4 v], [param:Float s] )</h3>
+		<h3>[method:this addScaledVector]( [param:Vector4 v], [param:Float s] )</h3>
 		<p>Adds the multiple of [page:Vector4 v] and [page:Float s] to this vector.</p>
 		<p>Adds the multiple of [page:Vector4 v] and [page:Float s] to this vector.</p>
 
 
-		<h3>[method:Vector4 addVectors]( [param:Vector4 a], [param:Vector4 b] )</h3>
+		<h3>[method:this addVectors]( [param:Vector4 a], [param:Vector4 b] )</h3>
 		<p>Sets this vector to [page:Vector4 a] + [page:Vector4 b].</p>
 		<p>Sets this vector to [page:Vector4 a] + [page:Vector4 b].</p>
 
 
-		<h3>[method:Vector4 applyMatrix4]( [param:Matrix4 m] )</h3>
+		<h3>[method:this applyMatrix4]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 		Multiplies this vector by 4 x 4 [page:Matrix4 m].
 		Multiplies this vector by 4 x 4 [page:Matrix4 m].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 ceil]()</h3>
+		<h3>[method:this ceil]()</h3>
 		<p>
 		<p>
 		The [page:.x x], [page:.y y], [page:.z z] and [page:.w w] components of the vector are rounded up to the nearest integer value.
 		The [page:.x x], [page:.y y], [page:.z z] and [page:.w w] components of the vector are rounded up to the nearest integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 clamp]( [param:Vector4 min], [param:Vector4 max] )</h3>
+		<h3>[method:this clamp]( [param:Vector4 min], [param:Vector4 max] )</h3>
 		<p>
 		<p>
 		[page:Vector4 min] - the minimum [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.<br />
 		[page:Vector4 min] - the minimum [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.<br />
 		[page:Vector4 max] - the maximum [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values in the desired range<br /><br />
 		[page:Vector4 max] - the maximum [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values in the desired range<br /><br />
@@ -112,7 +112,7 @@ var d = a.dot( b );
 		If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, it is replaced by the corresponding value.
 		If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, it is replaced by the corresponding value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 clampLength]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampLength]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float min] - the minimum value the length will be clamped to <br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
 		[page:Float max] - the maximum value the length will be clamped to<br /><br />
@@ -121,7 +121,7 @@ var d = a.dot( b );
 		If this vector's length is less than the min value, it is replaced by the min value.
 		If this vector's length is less than the min value, it is replaced by the min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 clampScalar]( [param:Float min], [param:Float max] )</h3>
+		<h3>[method:this clampScalar]( [param:Float min], [param:Float max] )</h3>
 		<p>
 		<p>
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float min] - the minimum value the components will be clamped to <br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
 		[page:Float max] - the maximum value the components will be clamped to<br /><br />
@@ -135,13 +135,13 @@ var d = a.dot( b );
 		Returns a new Vector4 with the same [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values as this one.
 		Returns a new Vector4 with the same [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values as this one.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 copy]( [param:Vector4 v] )</h3>
+		<h3>[method:this copy]( [param:Vector4 v] )</h3>
 		<p>
 		<p>
 			Copies the values of the passed Vector4's [page:.x x], [page:.y y], [page:.z z] and [page:.w w]
 			Copies the values of the passed Vector4's [page:.x x], [page:.y y], [page:.z z] and [page:.w w]
 			properties to this Vector4.
 			properties to this Vector4.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 divideScalar]( [param:Float s] )</h3>
+		<h3>[method:this divideScalar]( [param:Float s] )</h3>
 		<p>
 		<p>
 		Divides this vector by scalar [page:Float s].<br />
 		Divides this vector by scalar [page:Float s].<br />
 		Sets vector to *( 0, 0, 0, 0 )* if *[page:Float s] = 0*.
 		Sets vector to *( 0, 0, 0, 0 )* if *[page:Float s] = 0*.
@@ -156,10 +156,10 @@ var d = a.dot( b );
 		<h3>[method:Boolean equals]( [param:Vector4 v] )</h3>
 		<h3>[method:Boolean equals]( [param:Vector4 v] )</h3>
 		<p>Checks for strict equality of this vector and [page:Vector4 v].</p>
 		<p>Checks for strict equality of this vector and [page:Vector4 v].</p>
 
 
-		<h3>[method:Vector4 floor]()</h3>
+		<h3>[method:this floor]()</h3>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 		<p>The components of the vector are rounded down to the nearest integer value.</p>
 
 
-		<h3>[method:Vector4 fromArray]( [param:Array array], [param:Integer offset] )</h3>
+		<h3>[method:this fromArray]( [param:Array array], [param:Integer offset] )</h3>
 		<p>
 		<p>
 		[page:Array array] - the source array.<br />
 		[page:Array array] - the source array.<br />
 		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
@@ -168,7 +168,7 @@ var d = a.dot( b );
 		[page:.z z] value to be array[ offset + 2 ] and [page:.w w ] value to be array[ offset + 3 ].
 		[page:.z z] value to be array[ offset + 2 ] and [page:.w w ] value to be array[ offset + 3 ].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
+		<h3>[method:this fromBufferAttribute]( [param:BufferAttribute attribute], [param:Integer index] )</h3>
 		<p>
 		<p>
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:BufferAttribute attribute] - the source attribute.<br />
 		[page:Integer index] - index in the attribute.<br /><br />
 		[page:Integer index] - index in the attribute.<br /><br />
@@ -202,7 +202,7 @@ var d = a.dot( b );
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		vectors, you should compare the length squared instead as it is slightly more efficient to calculate.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 lerp]( [param:Vector4 v], [param:Float alpha] )</h3>
+		<h3>[method:this lerp]( [param:Vector4 v], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector4 v] - [page:Vector4] to interpolate towards.<br />
 		[page:Vector4 v] - [page:Vector4] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
@@ -211,7 +211,7 @@ var d = a.dot( b );
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector4 v].
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector4 v].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 lerpVectors]( [param:Vector4 v1], [param:Vector4 v2], [param:Float alpha] )</h3>
+		<h3>[method:this lerpVectors]( [param:Vector4 v1], [param:Vector4 v2], [param:Float alpha] )</h3>
 		<p>
 		<p>
 		[page:Vector4 v1] - the starting [page:Vector4].<br />
 		[page:Vector4 v1] - the starting [page:Vector4].<br />
 		[page:Vector4 v2] - [page:Vector4] to interpolate towards.<br />
 		[page:Vector4 v2] - [page:Vector4] to interpolate towards.<br />
@@ -222,42 +222,42 @@ var d = a.dot( b );
 		- alpha = 0 will be [page:Vector4 v1], and alpha = 1 will be [page:Vector4 v2].
 		- alpha = 0 will be [page:Vector4 v1], and alpha = 1 will be [page:Vector4 v2].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 negate]()</h3>
+		<h3>[method:this negate]()</h3>
 		<p>Inverts this vector - i.e. sets x = -x, y = -y, z = -z and w = -w.</p>
 		<p>Inverts this vector - i.e. sets x = -x, y = -y, z = -z and w = -w.</p>
 
 
-		<h3>[method:Vector4 normalize]()</h3>
+		<h3>[method:this normalize]()</h3>
 		<p>
 		<p>
 		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		as this one, but [page:.length length] 1.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 max]( [param:Vector4 v] )</h3>
+		<h3>[method:this max]( [param:Vector4 v] )</h3>
 		<p>
 		<p>
 		If this vector's x, y, z or w value is less than [page:Vector4 v]'s x, y, z or w value, replace
 		If this vector's x, y, z or w value is less than [page:Vector4 v]'s x, y, z or w value, replace
 		that value with the corresponding max value.
 		that value with the corresponding max value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 min]( [param:Vector4 v] )</h3>
+		<h3>[method:this min]( [param:Vector4 v] )</h3>
 		<p>
 		<p>
 		If this vector's x, y, z or w value is greater than [page:Vector4 v]'s x, y, z or w value, replace
 		If this vector's x, y, z or w value is greater than [page:Vector4 v]'s x, y, z or w value, replace
 		that value with the corresponding min value.
 		that value with the corresponding min value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 multiplyScalar]( [param:Float s] )</h3>
+		<h3>[method:this multiplyScalar]( [param:Float s] )</h3>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 		<p>Multiplies this vector by scalar [page:Float s].</p>
 
 
-		<h3>[method:Vector4 round]()</h3>
+		<h3>[method:this round]()</h3>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 		<p>The components of the vector are rounded to the nearest integer value.</p>
 
 
-		<h3>[method:Vector4 roundToZero]()</h3>
+		<h3>[method:this roundToZero]()</h3>
 		<p>
 		<p>
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 set]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>
+		<h3>[method:this set]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>
 		<p>Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] components of this vector.</p>
 		<p>Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] components of this vector.</p>
 
 
-		<h3>[method:Vector4 setAxisAngleFromQuaternion]( [param:Quaterion q] )</h3>
+		<h3>[method:this setAxisAngleFromQuaternion]( [param:Quaterion q] )</h3>
 		<p>
 		<p>
 			[page:Quaterion q] - a normalized [page:Quaterion]<br /><br />
 			[page:Quaterion q] - a normalized [page:Quaterion]<br /><br />
 
 
@@ -265,7 +265,7 @@ var d = a.dot( b );
 			quaternion's axis and [page:.w w] to the angle.
 			quaternion's axis and [page:.w w] to the angle.
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 setAxisAngleFromRotationMatrix]( [param:Matrix4 m] )</h3>
+		<h3>[method:this setAxisAngleFromRotationMatrix]( [param:Matrix4 m] )</h3>
 		<p>
 		<p>
 			 [page:Matrix4 m] - a [page:Matrix4] of which the upper left 3x3 matrix is a pure rotation matrix.<br /><br />
 			 [page:Matrix4 m] - a [page:Matrix4] of which the upper left 3x3 matrix is a pure rotation matrix.<br /><br />
 
 
@@ -284,36 +284,36 @@ var d = a.dot( b );
 		</p>
 		</p>
 
 
 
 
-		<h3>[method:Vector4 setLength]( [param:Float l] )</h3>
+		<h3>[method:this setLength]( [param:Float l] )</h3>
 		<p>
 		<p>
 		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		[page:Float l].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 setScalar]( [param:Float scalar] )</h3>
+		<h3>[method:this setScalar]( [param:Float scalar] )</h3>
 		<p>
 		<p>
 		Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
 		Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
 		</p>
 		</p>
 
 
-		<h3>[method:Vector4 setX]( [param:Float x] )</h3>
+		<h3>[method:this setX]( [param:Float x] )</h3>
 		<p>Replaces this vector's [page:.x x] value with [page:Float x].</p>
 		<p>Replaces this vector's [page:.x x] value with [page:Float x].</p>
 
 
-		<h3>[method:Vector4 setY]( [param:Float y] )</h3>
+		<h3>[method:this setY]( [param:Float y] )</h3>
 		<p>Replaces this vector's [page:.y y] value with [page:Float y].</p>
 		<p>Replaces this vector's [page:.y y] value with [page:Float y].</p>
 
 
-		<h3>[method:Vector4 setZ]( [param:Float z] )</h3>
+		<h3>[method:this setZ]( [param:Float z] )</h3>
 		<p>Replaces this vector's [page:.z z] value with [page:Float z].</p>
 		<p>Replaces this vector's [page:.z z] value with [page:Float z].</p>
 
 
-		<h3>[method:Vector4 setW]( [param:Float w] )</h3>
+		<h3>[method:this setW]( [param:Float w] )</h3>
 		<p>Replaces this vector's [page:.w w] value with [page:Float w].</p>
 		<p>Replaces this vector's [page:.w w] value with [page:Float w].</p>
 
 
-		<h3>[method:Vector4 sub]( [param:Vector4 v] )</h3>
+		<h3>[method:this sub]( [param:Vector4 v] )</h3>
 		<p>Subtracts [page:Vector4 v] from this vector.</p>
 		<p>Subtracts [page:Vector4 v] from this vector.</p>
 
 
-		<h3>[method:Vector4 subScalar]( [param:Float s] )</h3>
+		<h3>[method:this subScalar]( [param:Float s] )</h3>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] compnents.</p>
 		<p>Subtracts [page:Float s]  from this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] compnents.</p>
 
 
-		<h3>[method:Vector4 subVectors]( [param:Vector4 a], [param:Vector4 b] )</h3>
+		<h3>[method:this subVectors]( [param:Vector4 a], [param:Vector4 b] )</h3>
 		<p>Sets this vector to [page:Vector4 a] - [page:Vector4 b].</p>
 		<p>Sets this vector to [page:Vector4 a] - [page:Vector4 b].</p>
 
 
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [param:Array array], [param:Integer offset] )</h3>

+ 1 - 1
docs/api/objects/Line.html

@@ -79,7 +79,7 @@
 		Computes an array of distance values which are necessary for [page:LineDashedMaterial]. For each vertex in the geometry, the method calculates the cumulative length from the current point to the very beginning of the line.
 		Computes an array of distance values which are necessary for [page:LineDashedMaterial]. For each vertex in the geometry, the method calculates the cumulative length from the current point to the very beginning of the line.
 		</p>
 		</p>
 
 
-		<h3>[method:Array raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
+		<h3>[method:null raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
 		<p>
 		<p>
 		Get intersections between a casted [page:Ray] and this Line.
 		Get intersections between a casted [page:Ray] and this Line.
 		[page:Raycaster.intersectObject] will call this method.
 		[page:Raycaster.intersectObject] will call this method.

+ 1 - 1
docs/api/objects/Mesh.html

@@ -92,7 +92,7 @@
 		<h3>[method:Mesh clone]()</h3>
 		<h3>[method:Mesh clone]()</h3>
 		<p>Returns a clone of this [name] object and its descendants.</p>
 		<p>Returns a clone of this [name] object and its descendants.</p>
 
 
-		<h3>[method:Array raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
+		<h3>[method:null raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
 		<p>
 		<p>
 		Get intersections between a casted ray and this mesh.
 		Get intersections between a casted ray and this mesh.
 		[page:Raycaster.intersectObject] will call this method.
 		[page:Raycaster.intersectObject] will call this method.

+ 1 - 1
docs/api/objects/Points.html

@@ -58,7 +58,7 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 		<p>See the base [page:Object3D] class for common methods.</p>
 		<p>See the base [page:Object3D] class for common methods.</p>
 
 
-		<h3>[method:Array raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
+		<h3>[method:null raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
 		<p>
 		<p>
 		Get intersections between a casted ray and this Points.
 		Get intersections between a casted ray and this Points.
 		[page:Raycaster.intersectObject] will call this method.
 		[page:Raycaster.intersectObject] will call this method.

+ 4 - 1
docs/api/objects/SkinnedMesh.html

@@ -12,7 +12,10 @@
 
 
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
-		<p class="desc">A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.</p>
+		<p class="desc">
+			A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.
+			The material must support skinning and have skinning enabled - see [page:MeshStandardMaterial.skinning].
+		</p>
 
 
 		<iframe id="scene" src="scenes/bones-browser.html"></iframe>
 		<iframe id="scene" src="scenes/bones-browser.html"></iframe>
 
 

+ 1 - 1
docs/api/objects/Sprite.html

@@ -76,7 +76,7 @@ scene.add( sprite );
 		Copies the properties of the passed sprite to this one.
 		Copies the properties of the passed sprite to this one.
 		</p>
 		</p>
 
 
-		<h3>[method:Array raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
+		<h3>[method:null raycast]( [param:Raycaster raycaster], [param:Array intersects] )</h3>
 		<p>
 		<p>
 		Get intersections between a casted ray and this sprite.
 		Get intersections between a casted ray and this sprite.
 		[page:Raycaster.intersectObject] will call this method.
 		[page:Raycaster.intersectObject] will call this method.

+ 1 - 0
docs/api/textures/DataTexture.html

@@ -57,6 +57,7 @@
 		// used the buffer to create a [name]
 		// used the buffer to create a [name]
 
 
 		var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
 		var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
+		texture.needsUpdate = true
 		</code>
 		</code>
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>

+ 1 - 1
docs/api/textures/Texture.html

@@ -60,7 +60,7 @@
 		Array of user-specified mipmaps (optional).
 		Array of user-specified mipmaps (optional).
 		</p>
 		</p>
 
 
-		<h3>[property:object mapping]</h3>
+		<h3>[property:number mapping]</h3>
 		<p>
 		<p>
 		How the image is applied to the object. An object type of [page:Textures THREE.UVMapping] is the default,
 		How the image is applied to the object. An object type of [page:Textures THREE.UVMapping] is the default,
 		where the U,V coordinates are used to apply the map.<br />
 		where the U,V coordinates are used to apply the map.<br />

+ 102 - 0
docs/examples/animations/CCDIKSolver.html

@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p class="desc"> A solver for IK with <a href="https://sites.google.com/site/auraliusproject/ccd-algorithm"><em>CCD Algorithm</em></a>. <br /><br />
+		[name] solves Inverse Kinematics Problem with CCD Algorithm.
+		[name] is designed to work with [page:SkinnedMesh] loaded by [page:MMDLoader] but also can be used for generic [page:SkinnedMesh].
+		</p>
+
+		<h2>Example</h2>
+
+		<code>
+		var ikSolver;
+
+		// Load MMD resources and instantiate CCDIKSolver
+		new THREE.MMDLoader().load(
+			'models/mmd/miku.pmd',
+			function ( mesh ) {
+
+				ikSolver = new CCDIKSolver( mesh, mesh.geometry.iks );
+				scene.add( mesh );
+
+			}
+		);
+
+		function render() {
+
+			animate(); // update bones
+			if ( ikSolver !== undefined ) ikSolver.update();
+			renderer.render( scene, camera );
+
+		}
+		</code>
+
+		[example:webgl_loader_mmd]<br />
+		[example:webgl_loader_mmd_pose]<br />
+		[example:webgl_loader_mmd_audio]<br />
+
+		<br />
+		<hr>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:SkinnedMesh mesh], [param:Array iks] )</h3>
+		<p>
+		[page:SkinnedMesh mesh] — [page:SkinnedMesh] for which [name] solves IK problem.<br />
+		[page:Array iks] — An array of [page:Object] specifying IK parameter. target, effector, and link-index are index integers in .skeleton.bones.
+		The bones relation should be "links[ n ], links[ n - 1 ], ..., links[ 0 ], effector" in order from parent to child.<br />
+		<ul>
+			<li>[page:Integer target] — Target bone.</li>
+			<li>[page:Integer effector] — Effector bone.</li>
+			<li>[page:Array links] — An array of [page: Object] specifying link bones.
+			<ul>
+				<li>[page:Integer index] — Link bone.</li>
+				<li>[page:Vector3 limitation] — (optional) Rotation axis. Default is undefined.</li>
+				<li>[page:Vector3 rotationMin] — (optional) Rotation minimum limit. Default is undefined.</li>
+				<li>[page:Vector3 rotationMax] — (optional) Rotation maximum limit. Default is undefined.</li>
+				<li>[page:Boolean enabled] — (optional) Default is true.</li>
+			</ul>
+			</li>
+			<li>[page:Integer iteration] — (optional) Iteration number of calculation. Smaller is faster but less precise. Default is 1.</li>
+			<li>[page:Number minAngle] — (optional) Minimum rotation angle in a step. Default is undefined.</li>
+			<li>[page:Number maxAngle] — (optional) Maximum rotation angle in a step. Default is undefined.</li>
+		</ul>
+		</p>
+		<p>
+		Creates a new [name].
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Array iks]</h3>
+		<p>An array of IK parameter passed to the constructor.</p>
+
+		<h3>[property:SkinnedMesh mesh]</h3>
+		<p>[page:SkinnedMesh] passed to the constructor.</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:CCDIKHelper createHelper]()</h3>
+		<p>
+		Return [page:CCDIKHelper]. You can visualize IK bones by adding the helper to scene.
+		</p>
+
+		<h3>[method:CCDIKSolver update]()</h3>
+		<p>
+		Update bones quaternion by solving CCD algorithm.
+		</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/animation/CCDIKSolver.js examples/js/animation/CCDIKSolver.js]
+	</body>
+</html>

+ 169 - 0
docs/examples/animations/MMDAnimationHelper.html

@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p class="desc"> A animation helper for <a href="http://www.geocities.jp/higuchuu4/index_e.htm"><em>MMD</em></a> resources. <br /><br />
+		[name] handles animation of MMD assets loaded by [page:MMDLoader] with MMD special features as IK, Grant, and Physics.
+		It uses [page:CCDIKSolver] and [page:MMDPhysics] inside.
+		</p>
+
+		<h2>Example</h2>
+
+		<code>
+		// Instantiate a helper
+		var helper = new THREE.MMDAnimationHelper();
+
+		// Load MMD resources and add to helper
+		new THREE.MMDLoader().loadWithAnimation(
+			'models/mmd/miku.pmd',
+			'models/mmd/dance.vmd',
+			function ( mmd ) {
+
+				helper.add( mmd.mesh, {
+					animation: mmd.animation,
+					physics: true
+				} );
+
+				scene.add( mmd.mesh );
+
+				new THREE.AudioLoader().load(
+					'audios/mmd/song.mp3',
+					function ( buffer ) {
+
+						var listener = new THREE.AudioListener();
+						var audio = new THREE.Audio( listener )
+							.setBuffer( buffer );
+
+						listener.position.z = 1;
+
+						scene.add( audio );
+						scene.add( listener );
+
+					}
+
+				);
+
+			}
+		);
+
+		function render() {
+
+			helper.update( clock.getDelta() );
+			renderer.render( scene, camera );
+
+		}
+		</code>
+
+		[example:webgl_loader_mmd]<br />
+		[example:webgl_loader_mmd_pose]<br />
+		[example:webgl_loader_mmd_audio]<br />
+
+		<br />
+		<hr>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:Object params] )</h3>
+		<p>
+		[page:Object params] — (optional)<br />
+		<ul>
+			<li> [page:Boolean sync] - Whether animation durations of added objects are synched. Default is true.</li>
+			<li> [page:Number afterglow] - Default is 0.0.</li>
+			<li> [page:Boolean resetPhysicsOnLoop] - Default is true.</li>
+		</ul>
+		</p>
+		<p>
+		Creates a new [name].
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Audio audio]</h3>
+		<p>An [page:Audio] added to helper.</p>
+
+		<h3>[property:Camera camera]</h3>
+		<p>An [page:Camera] added to helper.</p>
+
+		<h3>[property:Array meshes]</h3>
+		<p>An array of [page:SkinnedMesh] added to helper.</p>
+
+		<h3>[property:WeakMap objects]</h3>
+		<p>A [page:WeakMap] which holds animation stuffs used in helper for objects added to helper. For example, you can access [page:AnimationMixer] for an added [page:SkinnedMesh] with "helper.objects.get( mesh ).mixer"</p>
+
+		<h3>[property:function onBeforePhysics]</h3>
+		<p>An optional callback that is executed immediately before the physicis calculation for an [page:SkinnedMesh]. This function is called with the [page:SkinnedMesh].</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:MMDAnimationHelper add]( [param:Object3D object], [param:Object params] )</h3>
+		<p>
+		[page:Object3D object] — [page:SkinnedMesh], [page:Camera], or [page:Audio]<br />
+		[page:Object params] — (optional)<br />
+		<ul>
+			<li>[page:AnimationClip animation] - an [page:AnimationClip] or an array of [page:AnimationClip] set to object. Only for [page:SkinnedMesh] and [page:Camera]. Default is undefined.</li>
+			<li>[page:Boolean physics] - Only for [page:SkinnedMesh]. A flag whether turn on physics. Default is true.</li>
+			<li>[page:Integer warmup] - Only for [page:SkinnedMesh] and physics is true. Physics parameter. Default is 60.</li>
+			<li>[page:Number unitStep] - Only for [page:SkinnedMesh] and physics is true. Physics parameter. Default is 1 / 65.</li>
+			<li>[page:Integer maxStepNum] - Only for [page:SkinnedMesh] and physics is true. Physics parameter. Default is 3.</li>
+			<li>[page:Vector3 gravity] - Only for [page:SkinnedMesh] and physics is true. Physics parameter. Default is ( 0, - 9.8 * 10, 0 ).</li>
+			<li>[page:Number delayTime] - Only for [page:Audio]. Default is 0.0.</li>
+		</ul>
+		</p>
+		<p>
+		Add an [page:SkinnedMesh], [page:Camera], or [page:Audio] to helper and setup animation. The anmation durations of added objects are synched.
+		If camera/audio has already been added, it'll be replaced with a new one.
+		</p>
+
+		<h3>[method:MMDAnimationHelper enable]( [param:string key], [param:Boolean enabled] )</h3>
+		<p>
+		[page:string key] — Allowed strings are 'animation', 'ik', 'grant', 'physics', and 'cameraAnimation'.<br />
+		[page:Boolean enabled] — true is enable, false is disable<br />
+		</p>
+		<p>
+		Enable/Disable an animation feature
+		</p>
+
+		<h3>[method:MMDAnimationHelper pose]( [param:SkinnedMesh mesh], [param:Object vpd], [param:Object params] )</h3>
+		<p>
+		[page:SkinnedMesh mesh] — [page:SkinnedMesh] which changes the posing. It doesn't need to be added to helper.<br />
+		[page:Object vpd] — VPD content obtained by [page:MMDLoader].loadVPD<br />
+		[page:Object params] — (optional)<br />
+		<ul>
+			<li>[page:Boolean resetPose] - Default is true.</li>
+			<li>[page:Boolean ik] - Default is true.</li>
+			<li>[page:Boolean grant] - Default is true.</li>
+		</ul>
+		</p>
+		<p>
+		Changes the posing of [page:SkinnedMesh] as VPD content specifies.
+		</p>
+
+		<h3>[method:MMDAnimationHelper remove]( [param:Object3D object] )</h3>
+		<p>
+		[page:Object3D object] — [page:SkinnedMesh], [page:Camera], or [page:Audio]<br />
+		</p>
+		<p>
+		Remove an [page:SkinnedMesh], [page:Camera], or [page:Audio] from helper.
+		</p>
+
+		<h3>[method:MMDAnimationHelper update]( [param:Nummber delta] )</h3>
+		<p>
+		[page:Number delta] — number in second<br />
+		</p>
+		<p>
+		Advance mixer time and update the animations of objects added to helper
+		</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/animation/MMDAnimationHelper.js examples/js/animation/MMDAnimationHelper.js]
+	</body>
+</html>

+ 112 - 0
docs/examples/animations/MMDPhysics.html

@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p class="desc"> A Physics handler for <a href="http://www.geocities.jp/higuchuu4/index_e.htm"><em>MMD</em></a> resources. <br /><br />
+		[name] calculates Physics for model loaded by [page:MMDLoader] with <a href="https://github.com/kripken/ammo.js/">ammo.js</a> (Bullet-based JavaScript Physics engine).
+		</p>
+
+		<h2>Example</h2>
+
+		<code>
+		var physics;
+
+		// Load MMD resources and instantiate MMDPhysics
+		new THREE.MMDLoader().load(
+			'models/mmd/miku.pmd',
+			function ( mesh ) {
+
+				physics = new THREE.MMDPhysics( mesh )
+				scene.add( mesh );
+
+			}
+		);
+
+		function render() {
+
+			var delta = clock.getDelta();
+			animate( delta );  // update bones
+			if ( physics !== undefined ) physics.update( delta );
+			renderer.render( scene, camera );
+
+		}
+		</code>
+
+		[example:webgl_loader_mmd]<br />
+		[example:webgl_loader_mmd_audio]<br />
+
+		<br />
+		<hr>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:SkinnedMesh mesh], [param:Array rigidBodyParams], [param:Array constraintParams], [param:Object params] )</h3>
+		<p>
+		[page:SkinnedMesh mesh] — [page:SkinnedMesh] for which [name] calculates Physics.<br />
+		[page:Array rigidBodyParams] — An array of [page:Object] specifying Rigid Body parameters.<br />
+		[page:Array constraintParams] — (optional) An array of [page:Object] specifying Constraint parameters.<br />
+		[page:Object params] — (optional)<br />
+		<ul>
+			<li>[page:Number unitStep] - Default is 1 / 65.</li>
+			<li>[page:Integer maxStepNum] - Default is 3.</li>
+			<li>[page:Vector3 gravity] - Default is ( 0, - 9.8 * 10, 0 )</li>
+		</ul>
+		</p>
+		<p>
+		Creates a new [name].
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Array mesh]</h3>
+		<p>[page:SkinnedMesh] passed to the constructor.</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:MMDPhysicsHelper createHelper]()</h3>
+		<p>
+		Return [page:MMDPhysicsHelper]. You can visualize Rigid bodies by adding the helper to scene.
+		</p>
+
+		<h3>[method:CCDIKSolver reset]()</h3>
+		<p>
+		Resets Rigid bodies transorm to current bone's.
+		</p>
+
+		<h3>[method:CCDIKSolver setGravity]( [param:Vector3 gravity] )</h3>
+		<p>
+		[page:Vector3 gravity] — Direction and volume of gravity.
+		</p>
+		<p>
+		Set gravity.
+		</p>
+
+		<h3>[method:CCDIKSolver update]( [param:Number delta] )</h3>
+		<p>
+		[page:Number delta] — Time in second.
+		</p>
+		<p>
+		Advance Physics calculation and updates bones.
+		</p>
+
+		<h3>[method:CCDIKSolver warmup]( [param:Integer cycles] )</h3>
+		<p>
+		[page:Number delta] — Time in second.
+		</p>
+		<p>
+		Warm up Rigid bodies. Calculates cycles steps.
+		</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/animation/MMDPhysics.js examples/js/animation/MMDPhysics.js]
+	</body>
+</html>

+ 1 - 1
docs/examples/exporters/GLTFExporter.html

@@ -25,7 +25,7 @@
 
 
 		<code>
 		<code>
 		// Instantiate a exporter
 		// Instantiate a exporter
-		var exporter = new THREE.GLTFExporter( defaultOptions );
+		var exporter = new THREE.GLTFExporter();
 
 
 		// Parse the input and generate the glTF output
 		// Parse the input and generate the glTF output
 		exporter.parse( scene, function ( gltf ) {
 		exporter.parse( scene, function ( gltf ) {

+ 62 - 0
docs/examples/exporters/PLYExporter.html

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p class="desc">
+		An exporter for *PLY*.
+		<br /><br />
+		<a href="https://www.khronos.org/gltf">PLY</a> (Polygon or Stanford Triangle Format) is a
+		file format for efficient delivery and loading of simple, static 3D content in a dense format.
+		Both binary and ascii formats are supported. PLY can store vertex positions, colors, normals and
+		uv coordinates. No textures or texture references are saved.
+		</p>
+
+		<h2>Example</h2>
+
+		<code>
+		// Instantiate an exporter
+		var exporter = new THREE.PLYExporter();
+
+		// Parse the input and generate the ply output
+		var data = exporter.parse( scene, options );
+		downloadFile(data);
+		</code>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]()</h3>
+		<p>
+		</p>
+		<p>
+		Creates a new [name].
+		</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:null parse]( [param:Object3D input], [param:Object options] )</h3>
+		<p>
+		[page:Object input] — Object3D<br />
+		[page:Options options] — Export options<br />
+		<ul>
+			<li>excludeAttributes - array. Which properties to explicitly exclude from the exported PLY file. Valid values are 'color', 'normal', 'uv', and 'index'. If triangle indices are excluded, then a point cloud is exported. Default is an empty array.</li>
+			<li>binary - bool. Export in binary format, returning an ArrayBuffer. Default is false.</li>
+		</ul>
+		</p>
+		<p>
+		Generates ply file data as string or ArrayBuffer (ascii or binary) output from the input object.
+		If the object is composed of multiple children and geometry, they are merged into a single mesh in the file.
+		</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/exporters/PLYExporter.js examples/js/exporters/PLYExporter.js]
+	</body>
+</html>

+ 22 - 0
docs/examples/loaders/GLTFLoader.html

@@ -84,6 +84,28 @@
 		<a href="https://github.com/stefanpenner/es6-promise">include a polyfill</a>
 		<a href="https://github.com/stefanpenner/es6-promise">include a polyfill</a>
 		providing a Promise replacement.</p>
 		providing a Promise replacement.</p>
 
 
+		<h2>Custom extensions</h2>
+
+		<p>
+			Metadata from unknown extensions is preserved as “.userData.gltfExtensions” on Object3D, Scene, and Material instances,
+			or attached to the response “gltf” object. Example:
+		</p>
+
+		<code>
+		loader.load('foo.gltf', function ( gltf ) {
+
+			var scene = gltf.scene;
+
+			var mesh = scene.children[ 3 ];
+
+			var fooExtension = mesh.userData.gltfExtensions.EXT_foo;
+
+			gltf.parser.getDependency( 'bufferView', fooExtension.bufferView )
+				.then( function ( fooBuffer ) { ... } );
+
+		} );
+		</code>
+
 		<br>
 		<br>
 		<hr>
 		<hr>
 
 

+ 118 - 0
docs/examples/loaders/MMDLoader.html

@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:Loader] &rarr;
+		<h1>[name]</h1>
+
+		<p class="desc"> A loader for <a href="http://www.geocities.jp/higuchuu4/index_e.htm"><em>MMD</em></a> resources. <br /><br />
+		[name] creates Three.js Objects from MMD resources as PMD, PMX, VMD, and VPD files.
+		See [page:MMDAnimationHelper] for MMD animation handling as IK, Grant, and Physics.<br /><br />
+
+		If you want raw content of MMD resources, use .loadPMD/PMX/VMD/VPD methods.
+
+		<h2>Example</h2>
+
+		<code>
+		// Instantiate a loader
+		var loader = new THREE.MMDLoader();
+
+		// Load a MMD model
+		loader.load(
+			// path to PMD/PMX file
+			'models/mmd/miku.pmd',
+			// called when the resource is loaded
+			function ( mesh ) {
+
+				scene.add( mesh );
+
+			},
+			// called when loading is in progresses
+			function ( xhr ) {
+
+				console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
+
+			},
+			// called when loading has errors
+			function ( error ) {
+
+				console.log( 'An error happened' );
+
+			}
+		);
+		</code>
+
+		[example:webgl_loader_mmd]<br />
+		[example:webgl_loader_mmd_pose]<br />
+		[example:webgl_loader_mmd_audio]<br />
+
+		<br />
+		<hr>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:LoadingManager manager] )</h3>
+		<p>
+		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+		</p>
+		<p>
+		Creates a new [name].
+		</p>
+
+		<h2>Properties</h2>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
+		<p>
+		[page:String url] — A string containing the path/URL of the <em>.pmd</em> or <em>.pmx</em> file.<br />
+		[page:Function onLoad] — A function to be called after the loading is successfully completed.<br />
+		[page:Function onProgress] — (optional) A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, that contains .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+		[page:Function onError] — (optional) A function to be called if an error occurs during loading. The function receives error as an argument.<br />
+		</p>
+		<p>
+		Begin loading PMD/PMX model file from url and fire the callback function with the parsed [page:SkinnedMesh] containing [page:BufferGeometry] and an array of [page:MeshToonMaterial].
+		</p>
+
+		<h3>[method:null loadAnimation]( [param:String url], [param:Object3D object], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
+		<p>
+		[page:String url] — A string or an array of string containing the path/URL of the <em>.vmd</em> file(s).If two or more files are specified, they'll be merged.<br />
+		[page:Object3D object] — [page:SkinnedMesh] or [page:Camera]. Clip and its tacks will be fitting to this object.<br />
+		[page:Function onLoad] — A function to be called after the loading is successfully completed.<br />
+		[page:Function onProgress] — (optional) A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, that contains .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+		[page:Function onError] — (optional) A function to be called if an error occurs during loading. The function receives error as an argument.<br />
+		</p>
+		<p>
+		Begin loading VMD motion file(s) from url(s) and fire the callback function with the parsed [page:AnimatioinClip].
+		</p>
+
+		<h3>[method:null loadWithAnimation]( [param:String modelUrl], [param:String vmdUrl], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
+		<p>
+		[page:String modelUrl] — A string containing the path/URL of the <em>.pmd</em> or <em>.pmx</em> file.<br />
+		[page:String vmdUrl] — A string or an array of string containing the path/URL of the <em>.vmd</em> file(s).<br />
+		[page:Function onLoad] — A function to be called after the loading is successfully completed.<br />
+		[page:Function onProgress] — (optional) A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, that contains .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+		[page:Function onError] — (optional) A function to be called if an error occurs during loading. The function receives error as an argument.<br />
+		</p>
+		<p>
+		Begin loading PMD/PMX model file and VMD motion file(s) from urls and fire the callback function with an [page:Object] containing parsed [page:SkinnedMesh] and [page:AnimationClip] fitting to the [page:SkinnedMesh].
+		</p>
+
+		<h3>[method:MMDLoader setCrossOrigin]( [param:String crossOrigin] )</h3>
+		<p>
+		[page:String crossOrigin] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
+		</p>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/MMDLoader.js examples/js/loaders/MMDLoader.js]
+	</body>
+</html>

+ 2 - 2
docs/examples/quickhull/QuickHull.html

@@ -72,13 +72,13 @@
 		<p>Makes this convex hull empty.</p>
 		<p>Makes this convex hull empty.</p>
 
 
 		<h3>[method:QuickHull addVertexToFace]( [param:VertexNode vertex], [param:Face face]	)</h3>
 		<h3>[method:QuickHull addVertexToFace]( [param:VertexNode vertex], [param:Face face]	)</h3>
-		[page:VertexNodeNode vertex] - The vetex to add.<br /><br />
+		[page:VertexNodeNode vertex] - The vertex to add.<br /><br />
 		[page:Face face] - The target face.<br /><br />
 		[page:Face face] - The target face.<br /><br />
 
 
 		<p>Adds a vertex to the 'assigned' list of vertices and assigns it to the given face.</p>
 		<p>Adds a vertex to the 'assigned' list of vertices and assigns it to the given face.</p>
 
 
 		<h3>[method:QuickHull removeVertexFromFace]( [param:VertexNode vertex], [param:Face face]	)</h3>
 		<h3>[method:QuickHull removeVertexFromFace]( [param:VertexNode vertex], [param:Face face]	)</h3>
-		[page:VertexNode vertex] - The vetex to remove.<br /><br />
+		[page:VertexNode vertex] - The vertex to remove.<br /><br />
 		[page:Face face] - The target face.<br /><br />
 		[page:Face face] - The target face.<br /><br />
 
 
 		<p>Removes a vertex from the 'assigned' list of vertices and from the given face. It also makes sure that the link from 'face' to the first vertex it sees in 'assigned' is linked correctly after the removal.</p>
 		<p>Removes a vertex from the 'assigned' list of vertices and from the given face. It also makes sure that the link from 'face' to the first vertex it sees in 'assigned' is linked correctly after the removal.</p>

+ 1 - 0
docs/examples/renderers/CSS2DRenderer.html

@@ -33,6 +33,7 @@
 		<h2>Examples</h2>
 		<h2>Examples</h2>
 
 
 		<p>
 		<p>
+			[example:css2d_label]<br>
 			[example:webgl_loader_pdb molecules]
 			[example:webgl_loader_pdb molecules]
 		</p>
 		</p>
 
 

+ 10 - 1
docs/list.js

@@ -10,6 +10,7 @@ var list = {
 			"How to run things locally": "manual/introduction/How-to-run-things-locally",
 			"How to run things locally": "manual/introduction/How-to-run-things-locally",
 			"Drawing Lines": "manual/introduction/Drawing-lines",
 			"Drawing Lines": "manual/introduction/Drawing-lines",
 			"Creating Text": "manual/introduction/Creating-text",
 			"Creating Text": "manual/introduction/Creating-text",
+			"Loading 3D Models": "manual/introduction/Loading-3D-models",
 			"Migration Guide": "manual/introduction/Migration-guide",
 			"Migration Guide": "manual/introduction/Migration-guide",
 			"Code Style Guide": "manual/introduction/Code-style-guide",
 			"Code Style Guide": "manual/introduction/Code-style-guide",
 			"FAQ": "manual/introduction/FAQ",
 			"FAQ": "manual/introduction/FAQ",
@@ -337,6 +338,12 @@ var list = {
 
 
 	"Examples": {
 	"Examples": {
 
 
+		"Animations": {
+			"CCDIKSolver": "examples/animations/CCDIKSolver",
+			"MMDAnimationHelper": "examples/animations/MMDAnimationHelper",
+			"MMDPhysics": "examples/animations/MMDPhysics"
+		},
+
 		"Controls": {
 		"Controls": {
 			"OrbitControls": "examples/controls/OrbitControls"
 			"OrbitControls": "examples/controls/OrbitControls"
 		},
 		},
@@ -350,6 +357,7 @@ var list = {
 		"Loaders": {
 		"Loaders": {
 			"BabylonLoader": "examples/loaders/BabylonLoader",
 			"BabylonLoader": "examples/loaders/BabylonLoader",
 			"GLTFLoader": "examples/loaders/GLTFLoader",
 			"GLTFLoader": "examples/loaders/GLTFLoader",
+			"MMDLoader": "examples/loaders/MMDLoader",
 			"MTLLoader": "examples/loaders/MTLLoader",
 			"MTLLoader": "examples/loaders/MTLLoader",
 			"OBJLoader": "examples/loaders/OBJLoader",
 			"OBJLoader": "examples/loaders/OBJLoader",
 			"OBJLoader2": "examples/loaders/OBJLoader2",
 			"OBJLoader2": "examples/loaders/OBJLoader2",
@@ -366,7 +374,8 @@ var list = {
 		},
 		},
 
 
 		"Exporters": {
 		"Exporters": {
-			"GLTFExporter": "examples/exporters/GLTFExporter"
+			"GLTFExporter": "examples/exporters/GLTFExporter",
+			"PLYExporter": "examples/exporters/PLYExporter"
 		},
 		},
 
 
 		"Plugins": {
 		"Plugins": {

+ 5 - 5
docs/manual/introduction/Animation-system.html

@@ -35,11 +35,11 @@
 		<p class="desc">
 		<p class="desc">
 
 
 			If you have successfully imported an animated 3D object (it doesn't matter if it has
 			If you have successfully imported an animated 3D object (it doesn't matter if it has
-			bones or morph targets or both) - for example exporting it from Blender with the
-			[link:https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/addons/io_three Blender exporter] and
-			loading it into a three.js scene using [page:JSONLoader] -, one of the geometry's
-			properties of the loaded mesh should be an array named "animations", containing the
-			[page:AnimationClip AnimationClips] for this model (see a list of possible loaders below).<br /><br />
+			bones or morph targets or both) — for example exporting, it from Blender with the
+			[link:https://github.com/KhronosGroup/glTF-Blender-Exporter glTF Blender exporter] and
+			loading it into a three.js scene using [page:GLTFLoader] — one of the response fields
+			should be an array named "animations", containing the [page:AnimationClip AnimationClips]
+			for this model (see a list of possible loaders below).<br /><br />
 
 
 			Each *AnimationClip* usually holds the data for a certain activity of the object. If the
 			Each *AnimationClip* usually holds the data for a certain activity of the object. If the
 			mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second
 			mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second

+ 3 - 3
docs/manual/introduction/Creating-a-scene.html

@@ -109,8 +109,8 @@
 		<p>Add the following right above the <strong>renderer.render</strong> call in your <strong>animate</strong> function:</p>
 		<p>Add the following right above the <strong>renderer.render</strong> call in your <strong>animate</strong> function:</p>
 
 
 		<code>
 		<code>
-		cube.rotation.x += 0.1;
-		cube.rotation.y += 0.1;
+		cube.rotation.x += 0.01;
+		cube.rotation.y += 0.01;
 		</code>
 		</code>
 
 
 		<p>This will be run every frame (normally 60 times per second), and give the cube a nice rotation animation. Basically, anything you want to move or change while the app is running has to go through the animate loop. You can of course call other functions from there, so that you don't end up with a <strong>animate</strong> function that's hundreds of p.
 		<p>This will be run every frame (normally 60 times per second), and give the cube a nice rotation animation. Basically, anything you want to move or change while the app is running has to go through the animate loop. You can of course call other functions from there, so that you don't end up with a <strong>animate</strong> function that's hundreds of p.
@@ -153,7 +153,7 @@
 						cube.rotation.x += 0.1;
 						cube.rotation.x += 0.1;
 						cube.rotation.y += 0.1;
 						cube.rotation.y += 0.1;
 
 
-						renderer.render(scene, camera);
+						renderer.render( scene, camera );
 					};
 					};
 
 
 					animate();
 					animate();

+ 1 - 1
docs/manual/introduction/FAQ.html

@@ -16,7 +16,7 @@
 				The recommended format for importing and exporting assets is glTF (GL Transmission Format). Because glTF is focused on runtime asset delivery, it is compact to transmit and fast to load.
 				The recommended format for importing and exporting assets is glTF (GL Transmission Format). Because glTF is focused on runtime asset delivery, it is compact to transmit and fast to load.
 			</p>
 			</p>
 			<p>
 			<p>
-				three.js provides loaders for many other popular formats like FBX, Collada or OBJ as well. Nevertheless, you should always try to establish a glTF based workflow in your projects first.
+				three.js provides loaders for many other popular formats like FBX, Collada or OBJ as well. Nevertheless, you should always try to establish a glTF based workflow in your projects first. For more information, see [link:#manual/introduction/Loading-3D-models loading 3D models].
 			</p>
 			</p>
 		</div>
 		</div>
 
 

+ 132 - 0
docs/manual/introduction/Loading-3D-models.html

@@ -0,0 +1,132 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8">
+  <base href="../../" />
+  <script src="list.js"></script>
+  <script src="page.js"></script>
+  <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+  <h1>[name]</h1>
+  <br />
+
+  <p>
+    3D models are available in hundreds of file formats, each with different
+    purposes, assorted features, and varying complexity. Although
+    <a href="https://github.com/mrdoob/three.js/tree/dev/examples/js/loaders">
+    three.js provides many loaders</a>, choosing the right format and
+    workflow will save time and frustration later on. Some formats are
+    difficult to work with, inefficient for realtime experiences, or simply not
+    fully supported at this time.
+  </p>
+
+  <p>
+    This guide provides a workflow recommended for most users, and suggestions
+    for what to try if things don't go as expected.
+  </p>
+
+  <h2>Before we start</h2>
+
+  <p>
+    If you're new to running a local server, begin with
+    [link:#manual/introduction/How-to-run-things-locally how to run things locally]
+    first. Many common errors viewing 3D models can be avoided by hosting files
+    correctly.
+  </p>
+
+  <h2>Recommended workflow</h2>
+
+  <p>
+    Where possible, we recommend using glTF (GL Transmission Format). Both
+    <small>.GLB</small> and <small>.GLTF</small> versions of the format are
+    well supported. Because glTF is focused on runtime asset delivery, it is
+    compact to transmit and fast to load. Features include meshes, materials,
+    textures, skins, skeletons, morph targets, animations, lights, and
+    cameras.
+  </p>
+
+  <p>
+    Public-domain glTF files are available on sites like
+    <a href="https://sketchfab.com/models?features=downloadable&sort_by=-likeCount&type=models">
+    Sketchfab</a>, or various tools include glTF export:
+  </p>
+
+  <ul>
+    <li><a href="https://github.com/KhronosGroup/glTF-Blender-Exporter">glTF-Blender-Exporter</a> by the Khronos Group</li>
+    <li><a href="https://github.com/KhronosGroup/COLLADA2GLTF">COLLADA2GLTF</a> by the Khronos Group</li>
+    <li><a href="https://github.com/facebookincubator/FBX2glTF">FBX2GLTF</a> by Facebook</li>
+    <li><a href="https://github.com/AnalyticalGraphicsInc/obj2gltf">OBJ2GLTF</a> by Analytical Graphics Inc</li>
+    <li><a href="https://www.allegorithmic.com/products/substance-painter">Substance Painter</a> by Allegorithmic</li>
+    <li><a href="https://www.foundry.com/products/modo">Modo</a> by Foundry</li>
+    <li><a href="https://www.marmoset.co/toolbag/">Toolbag</a> by Marmoset</li>
+    <li>&hellip;and <a href="https://github.com/khronosgroup/gltf#gltf-tools">many more</a></li>
+  </ul>
+
+  <p>
+    If your preferred tools do not support glTF, consider requesting glTF
+    export from the authors, or posting on
+    <a href="https://github.com/KhronosGroup/glTF/issues/1051">the glTF roadmap thread</a>.
+  </p>
+
+  <p>
+    When glTF is not an option, popular formats such as FBX, OBJ, or COLLADA
+    are also available and regularly maintained.
+  </p>
+
+  <h2>Troubleshooting</h2>
+
+  <p>
+    You've spent hours modeling an artisanal masterpiece, you load it into
+    the webpage, and — oh no! 😭 It's distorted, miscolored, or missing entirely.
+    Start with these troubleshooting steps:
+  </p>
+
+  <ol>
+    <li>
+      Check the JavaScript console for errors, and make sure you've used an
+      <em>onError</em> callback when calling <em>.load()</em> to log the result.
+    </li>
+    <li>
+      View the model in another application. For glTF, drag-and-drop viewers
+      are available for
+      <a href="https://gltf-viewer.donmccurdy.com/">three.js</a> and
+      <a href="http://sandbox.babylonjs.com/">babylon.js</a>. If the model
+      appears correctly in one or more applications,
+      <a href="https://github.com/mrdoob/three.js/issues/new">file a bug against three.js</a>.
+      If the model cannot be shown in any application, we strongly encourage
+      filing a bug with the application used to create the model.
+    </li>
+    <li>
+      Try scaling the model up or down by a factor of 1000. Many models are
+      scaled differently, and large models may not appear if the camera is
+      inside the model.
+    </li>
+    <li>
+      Look for failed texture requests in the network tab, like
+      <em>C:\\Path\To\Model\texture.jpg</em>. Use paths relative to your
+      model instead, such as <em>images/texture.jpg</em> — this may require
+      editing the model file in a text editor.
+    </li>
+  </ol>
+
+  <h2>Asking for help</h2>
+
+  <p>
+    If you've gone through the troubleshooting process above and your model
+    still isn't working, the right approach to asking for help will get you to
+    a solution faster. Whenever possible, include your model (or a simpler
+    model with the same problem) in any formats you have available. Include
+    enough information for someone else to reproduce the issue quickly —
+    ideally, a live demo.
+  </p>
+
+  <p>
+    TODO: Do we recommend model-related questions go to GitHub, Stack Overflow,
+    or the Discourse forum?
+  </p>
+</body>
+
+</html>

+ 7 - 0
docs/manual/introduction/Useful-links.html

@@ -126,6 +126,13 @@
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 		</li>
 		</li>
 	 </ul>
 	 </ul>
+		
+	<h2>WebGL References</h2>
+	 <ul>
+		 <li>
+			[link:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf] - Reference of all WebGL and GLSL keywords, terminology, syntex and definations.
+		 </li>
+	 </ul>
 
 
 	 <h2>Old Links</h2>
 	 <h2>Old Links</h2>
 	 <p>
 	 <p>

+ 1 - 1
docs/page.js

@@ -70,7 +70,7 @@ function onDocumentLoad( event ) {
 	text = text.replace( /\[example:([\w\_]+)\]/gi, "[example:$1 $1]" ); // [example:name] to [example:name title]
 	text = text.replace( /\[example:([\w\_]+)\]/gi, "[example:$1 $1]" ); // [example:name] to [example:name title]
 	text = text.replace( /\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, "<a href=\"../examples/#$1\"  target=\"_blank\">$2</a>" ); // [example:name title]
 	text = text.replace( /\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, "<a href=\"../examples/#$1\"  target=\"_blank\">$2</a>" ); // [example:name title]
 
 
-	text = text.replace( /<a class="param" onclick="window.parent.setUrlFragment\('\w+'\)">(null|Boolean|Object|Array|Number|String|Integer|Float|TypedArray|ArrayBuffer)<\/a>/gi, '<span class="param">$1</span>' ); // remove links to primitive types
+	text = text.replace( /<a class="param" onclick="window.parent.setUrlFragment\('\w+'\)">(null|this|Boolean|Object|Array|Number|String|Integer|Float|TypedArray|ArrayBuffer)<\/a>/gi, '<span class="param">$1</span>' ); // remove links to primitive types
 
 
 	document.body.innerHTML = text;
 	document.body.innerHTML = text;
 
 

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

@@ -1264,7 +1264,7 @@ var guis = {
 
 
 		var data = {
 		var data = {
 			steps: 2,
 			steps: 2,
-			amount: 16,
+			depth: 16,
 			bevelEnabled: true,
 			bevelEnabled: true,
 			bevelThickness: 1,
 			bevelThickness: 1,
 			bevelSize: 1,
 			bevelSize: 1,
@@ -1292,7 +1292,7 @@ var guis = {
 		var folder = gui.addFolder( 'THREE.ExtrudeGeometry' );
 		var folder = gui.addFolder( 'THREE.ExtrudeGeometry' );
 
 
 		folder.add( data, 'steps', 1, 10 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'steps', 1, 10 ).step( 1 ).onChange( generateGeometry );
-		folder.add( data, 'amount', 1, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'depth', 1, 20 ).onChange( generateGeometry );
 		folder.add( data, 'bevelThickness', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelThickness', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSize', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSize', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSegments', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSegments', 1, 5 ).step( 1 ).onChange( generateGeometry );
@@ -1305,7 +1305,7 @@ var guis = {
 
 
 		var data = {
 		var data = {
 			steps: 2,
 			steps: 2,
-			amount: 16,
+			depth: 16,
 			bevelEnabled: true,
 			bevelEnabled: true,
 			bevelThickness: 1,
 			bevelThickness: 1,
 			bevelSize: 1,
 			bevelSize: 1,
@@ -1333,7 +1333,7 @@ var guis = {
 		var folder = gui.addFolder( 'THREE.ExtrudeBufferGeometry' );
 		var folder = gui.addFolder( 'THREE.ExtrudeBufferGeometry' );
 
 
 		folder.add( data, 'steps', 1, 10 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'steps', 1, 10 ).step( 1 ).onChange( generateGeometry );
-		folder.add( data, 'amount', 1, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'depth', 1, 20 ).onChange( generateGeometry );
 		folder.add( data, 'bevelThickness', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelThickness', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSize', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSize', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSegments', 1, 5 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSegments', 1, 5 ).step( 1 ).onChange( generateGeometry );

+ 150 - 0
examples/css2d_label.html

@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<title>three.js css2d - label</title>
+		<style>
+			body {
+				background-color: #000;
+				margin: 0;
+				overflow: hidden;
+			}
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				color: #FFF;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+				z-index: 1;
+			}
+
+			.label{
+				color: #FFF;
+				font-family: sans-serif;
+				padding: 2px;
+				background: rgba( 0, 0, 0, .6 );
+			}
+
+			a {
+				color: #000000;
+			}
+
+		</style>
+	</head>
+	<body>
+		<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - three.js css2d - label</div>
+
+		<script src="../build/three.js"></script>
+
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script src="js/renderers/CSS2DRenderer.js"></script>
+
+		<script>
+
+			var camera, scene, renderer, labelRenderer;
+			var controls;
+			var clock = new THREE.Clock();
+			var textureLoader = new THREE.TextureLoader();
+
+			var earth, moon;
+
+			init();
+			animate();
+
+			function init() {
+
+				var EARTH_RADIUS = 1;
+				var MOON_RADIUS = 0.27;
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 10, 5, 20 );
+
+				controls = new THREE.OrbitControls( camera );
+
+				scene = new THREE.Scene();
+
+				scene2 = new THREE.Scene();
+
+				dirLight = new THREE.DirectionalLight( 0xffffff );
+				dirLight.position.set( 0, 0, 1 );
+				scene.add( dirLight );
+
+				var axesHelper = new THREE.AxesHelper( 5 );
+				scene.add( axesHelper );
+
+				//
+
+				var earthGeometry = new THREE.SphereBufferGeometry( EARTH_RADIUS, 16, 16 );
+				var earthMaterial = new THREE.MeshPhongMaterial( {
+					specular: 0x333333,
+					shininess: 5,
+					map: textureLoader.load( 'textures/planets/earth_atmos_2048.jpg' ),
+					specularMap: textureLoader.load( 'textures/planets/earth_specular_2048.jpg' ),
+					normalMap: textureLoader.load( 'textures/planets/earth_normal_2048.jpg' ),
+					normalScale: new THREE.Vector2( 0.85, 0.85 )
+				} );
+				earth = new THREE.Mesh( earthGeometry, earthMaterial );
+				scene.add( earth );
+
+				var moonGeometry = new THREE.SphereBufferGeometry( MOON_RADIUS, 16, 16 );
+				var moonMaterial = new THREE.MeshPhongMaterial( {
+					shininess: 5,
+					map: textureLoader.load( 'textures/planets/moon_1024.jpg' )
+				} );
+				moon = new THREE.Mesh( moonGeometry, moonMaterial );
+				scene.add( moon );
+
+				//
+
+				var earthDiv = document.createElement( 'div' );
+				earthDiv.className = 'label';
+				earthDiv.textContent = 'Earth';
+				earthDiv.style.marginTop = '-1em';
+				var earthLabel = new THREE.CSS2DObject( earthDiv );
+				earthLabel.position.set( 0, EARTH_RADIUS, 0 );
+				earth.add( earthLabel );
+
+				var moonDiv = document.createElement( 'div' );
+				moonDiv.className = 'label';
+				moonDiv.textContent = 'Moon';
+				moonDiv.style.marginTop = '-1em';
+				var moonLabel = new THREE.CSS2DObject( moonDiv );
+				moonLabel.position.set( 0, MOON_RADIUS, 0 );
+				moon.add( moonLabel );
+
+				//
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				labelRenderer = new THREE.CSS2DRenderer();
+				labelRenderer.setSize( window.innerWidth, window.innerHeight );
+				labelRenderer.domElement.style.position = 'absolute';
+				labelRenderer.domElement.style.top = 0;
+				document.body.appendChild( labelRenderer.domElement );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				var elapsed = clock.getElapsedTime();
+
+				moon.position.set( Math.sin( elapsed ) * 5, 0, Math.cos( elapsed ) * 5 );
+
+				renderer.render( scene, camera );
+				labelRenderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 5 - 0
examples/files.js

@@ -284,6 +284,7 @@ var files = {
 		"webgl_buffergeometry_instancing_billboards",
 		"webgl_buffergeometry_instancing_billboards",
 		"webgl_buffergeometry_instancing_dynamic",
 		"webgl_buffergeometry_instancing_dynamic",
 		"webgl_buffergeometry_instancing_interleaved_dynamic",
 		"webgl_buffergeometry_instancing_interleaved_dynamic",
+		"webgl_buffergeometry_instancing_lambert",
 		"webgl_buffergeometry_lines",
 		"webgl_buffergeometry_lines",
 		"webgl_buffergeometry_lines_indexed",
 		"webgl_buffergeometry_lines_indexed",
 		"webgl_buffergeometry_points",
 		"webgl_buffergeometry_points",
@@ -341,6 +342,7 @@ var files = {
 		"misc_controls_transform",
 		"misc_controls_transform",
 		"misc_exporter_gltf",
 		"misc_exporter_gltf",
 		"misc_exporter_obj",
 		"misc_exporter_obj",
+		"misc_exporter_stl",
 		"misc_fps",
 		"misc_fps",
 		"misc_lights_test",
 		"misc_lights_test",
 		"misc_lookat",
 		"misc_lookat",
@@ -358,6 +360,9 @@ var files = {
 		"css3d_sprites",
 		"css3d_sprites",
 		"css3d_youtube"
 		"css3d_youtube"
 	],
 	],
+	"css2d": [
+		"css2d_label"
+	],
 	"canvas": [
 	"canvas": [
 		"canvas_ascii_effect",
 		"canvas_ascii_effect",
 		"canvas_camera_orthographic",
 		"canvas_camera_orthographic",

+ 26 - 5
examples/js/BufferGeometryUtils.js

@@ -188,7 +188,7 @@ THREE.BufferGeometryUtils = {
 	 * @param  {Array<THREE.BufferGeometry>} geometries
 	 * @param  {Array<THREE.BufferGeometry>} geometries
 	 * @return {THREE.BufferGeometry}
 	 * @return {THREE.BufferGeometry}
 	 */
 	 */
-	mergeBufferGeometries: function ( geometries ) {
+	mergeBufferGeometries: function ( geometries, useGroups ) {
 
 
 		var isIndexed = geometries[ 0 ].index !== null;
 		var isIndexed = geometries[ 0 ].index !== null;
 
 
@@ -200,6 +200,8 @@ THREE.BufferGeometryUtils = {
 
 
 		var mergedGeometry = new THREE.BufferGeometry();
 		var mergedGeometry = new THREE.BufferGeometry();
 
 
+		var offset = 0;
+
 		for ( var i = 0; i < geometries.length; ++ i ) {
 		for ( var i = 0; i < geometries.length; ++ i ) {
 
 
 			var geometry = geometries[ i ];
 			var geometry = geometries[ i ];
@@ -234,11 +236,30 @@ THREE.BufferGeometryUtils = {
 
 
 			// gather .userData
 			// gather .userData
 
 
-			if ( geometry.userData !== undefined ) {
+			mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
+			mergedGeometry.userData.mergedUserData.push( geometry.userData );
+
+			if ( useGroups ) {
+
+				var count;
+
+				if ( isIndexed ) {
+
+					count = geometry.index.count;
+
+				} else if ( geometry.attributes.position !== undefined ) {
+
+					count = geometry.attributes.position.count;
+
+				} else {
+
+					return null;
+
+				}
+
+				mergedGeometry.addGroup( offset, count, i );
 
 
-				mergedGeometry.userData = mergedGeometry.userData || {};
-				mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
-				mergedGeometry.userData.mergedUserData.push( geometry.userData );
+				offset += count;
 
 
 			}
 			}
 
 

+ 14 - 10
examples/js/Cloth.js

@@ -46,15 +46,13 @@ var lastTime;
 
 
 function plane( width, height ) {
 function plane( width, height ) {
 
 
-	return function ( u, v, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	return function ( u, v, target ) {
 
 
 		var x = ( u - 0.5 ) * width;
 		var x = ( u - 0.5 ) * width;
 		var y = ( v + 0.5 ) * height;
 		var y = ( v + 0.5 ) * height;
 		var z = 0;
 		var z = 0;
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	};
 	};
 
 
@@ -62,20 +60,26 @@ function plane( width, height ) {
 
 
 function Particle( x, y, z, mass ) {
 function Particle( x, y, z, mass ) {
 
 
-	this.position = clothFunction( x, y ); // position
-	this.previous = clothFunction( x, y ); // previous
-	this.original = clothFunction( x, y );
+	this.position = new THREE.Vector3();
+	this.previous = new THREE.Vector3();
+	this.original = new THREE.Vector3();
 	this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
 	this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
 	this.mass = mass;
 	this.mass = mass;
 	this.invMass = 1 / mass;
 	this.invMass = 1 / mass;
 	this.tmp = new THREE.Vector3();
 	this.tmp = new THREE.Vector3();
 	this.tmp2 = new THREE.Vector3();
 	this.tmp2 = new THREE.Vector3();
 
 
+	// init
+
+	clothFunction( x, y, this.position ); // position
+	clothFunction( x, y, this.previous ); // previous
+	clothFunction( x, y, this.original );
+
 }
 }
 
 
 // Force -> Acceleration
 // Force -> Acceleration
 
 
-Particle.prototype.addForce = function( force ) {
+Particle.prototype.addForce = function ( force ) {
 
 
 	this.a.add(
 	this.a.add(
 		this.tmp2.copy( force ).multiplyScalar( this.invMass )
 		this.tmp2.copy( force ).multiplyScalar( this.invMass )
@@ -86,7 +90,7 @@ Particle.prototype.addForce = function( force ) {
 
 
 // Performs Verlet integration
 // Performs Verlet integration
 
 
-Particle.prototype.integrate = function( timesq ) {
+Particle.prototype.integrate = function ( timesq ) {
 
 
 	var newPos = this.tmp.subVectors( this.position, this.previous );
 	var newPos = this.tmp.subVectors( this.position, this.previous );
 	newPos.multiplyScalar( DRAG ).add( this.position );
 	newPos.multiplyScalar( DRAG ).add( this.position );
@@ -280,7 +284,7 @@ function simulate( time ) {
 
 
 	// Ball Constraints
 	// Ball Constraints
 
 
-	ballPosition.z = - Math.sin( Date.now() / 600 ) * 90 ; //+ 40;
+	ballPosition.z = - Math.sin( Date.now() / 600 ) * 90; //+ 40;
 	ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
 	ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
 
 
 	if ( sphere.visible ) {
 	if ( sphere.visible ) {

+ 77 - 67
examples/js/ConvexObjectBreaker.js

@@ -25,10 +25,10 @@
  *
  *
  * @param {double} minSizeForBreak Min size a debris can have to break.
  * @param {double} minSizeForBreak Min size a debris can have to break.
  * @param {double} smallDelta Max distance to consider that a point belongs to a plane.
  * @param {double} smallDelta Max distance to consider that a point belongs to a plane.
- * 
+ *
   */
   */
 
 
-THREE.ConvexObjectBreaker = function( minSizeForBreak, smallDelta ) {
+THREE.ConvexObjectBreaker = function ( minSizeForBreak, smallDelta ) {
 
 
 	this.minSizeForBreak = minSizeForBreak || 1.4;
 	this.minSizeForBreak = minSizeForBreak || 1.4;
 	this.smallDelta = smallDelta || 0.0001;
 	this.smallDelta = smallDelta || 0.0001;
@@ -45,9 +45,7 @@ THREE.ConvexObjectBreaker = function( minSizeForBreak, smallDelta ) {
 
 
 	this.segments = [];
 	this.segments = [];
 	var n = 30 * 30;
 	var n = 30 * 30;
-	for ( var i = 0; i < n; i++ ) {
-		this.segments[ i ] = false;
-	}
+	for ( var i = 0; i < n; i ++ ) this.segments[ i ] = false;
 
 
 };
 };
 
 
@@ -55,7 +53,7 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 	constructor: THREE.ConvexObjectBreaker,
 	constructor: THREE.ConvexObjectBreaker,
 
 
-	prepareBreakableObject: function( object, mass, velocity, angularVelocity, breakable ) {
+	prepareBreakableObject: function ( object, mass, velocity, angularVelocity, breakable ) {
 
 
 		// object is a THREE.Object3d (normally a Mesh), must have a Geometry, and it must be convex.
 		// object is a THREE.Object3d (normally a Mesh), must have a Geometry, and it must be convex.
 		// Its material property is propagated to its children (sub-pieces)
 		// Its material property is propagated to its children (sub-pieces)
@@ -63,9 +61,7 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 		// Create vertices mark
 		// Create vertices mark
 		var vertices = object.geometry.vertices;
 		var vertices = object.geometry.vertices;
-		for ( var i = 0, il = vertices.length; i < il; i++ ) {
-			vertices[ i ].mark = 0;
-		}
+		for ( var i = 0, il = vertices.length; i < il; i ++ ) vertices[ i ].mark = 0;
 
 
 		var userData = object.userData;
 		var userData = object.userData;
 		userData.mass = mass;
 		userData.mass = mass;
@@ -78,11 +74,10 @@ THREE.ConvexObjectBreaker.prototype = {
 	/*
 	/*
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
 	 * @param {int} maxRandomIterations Max random iterations for not-radial cuts
 	 * @param {int} maxRandomIterations Max random iterations for not-radial cuts
-	 * @param {double} minSizeForRadialSubdivision Min size a debris can have to break in radial subdivision.
 	 *
 	 *
 	 * Returns the array of pieces
 	 * Returns the array of pieces
 	 */
 	 */
-	subdivideByImpact: function( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations, minSizeForRadialSubdivision ) {
+	subdivideByImpact: function ( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations ) {
 
 
 		var debris = [];
 		var debris = [];
 
 
@@ -103,9 +98,9 @@ THREE.ConvexObjectBreaker.prototype = {
 				debris.push( subObject );
 				debris.push( subObject );
 
 
 				return;
 				return;
-				
+
 			}
 			}
-			
+
 			var angle = Math.PI;
 			var angle = Math.PI;
 
 
 			if ( numIterations === 0 ) {
 			if ( numIterations === 0 ) {
@@ -113,19 +108,17 @@ THREE.ConvexObjectBreaker.prototype = {
 				tempPlane2.normal.copy( tempPlane1.normal );
 				tempPlane2.normal.copy( tempPlane1.normal );
 				tempPlane2.constant = tempPlane1.constant;
 				tempPlane2.constant = tempPlane1.constant;
 
 
-			}
-			else {
+			} else {
 
 
 				if ( numIterations <= maxRadialIterations ) {
 				if ( numIterations <= maxRadialIterations ) {
-					
+
 					angle = ( endAngle - startAngle ) * ( 0.2 + 0.6 * Math.random() ) + startAngle;
 					angle = ( endAngle - startAngle ) * ( 0.2 + 0.6 * Math.random() ) + startAngle;
 
 
 					// Rotate tempPlane2 at impact point around normal axis and the angle
 					// Rotate tempPlane2 at impact point around normal axis and the angle
 					scope.tempVector3_2.copy( object.position ).sub( pointOfImpact ).applyAxisAngle( normal, angle ).add( pointOfImpact );
 					scope.tempVector3_2.copy( object.position ).sub( pointOfImpact ).applyAxisAngle( normal, angle ).add( pointOfImpact );
 					tempPlane2.setFromCoplanarPoints( pointOfImpact, scope.tempVector3, scope.tempVector3_2 );
 					tempPlane2.setFromCoplanarPoints( pointOfImpact, scope.tempVector3, scope.tempVector3_2 );
 
 
-				}
-				else {
+				} else {
 
 
 					angle = ( ( 0.5 * ( numIterations & 1 ) ) + 0.2 * ( 2 - Math.random() ) ) * Math.PI;
 					angle = ( ( 0.5 * ( numIterations & 1 ) ) + 0.2 * ( 2 - Math.random() ) ) * Math.PI;
 
 
@@ -164,7 +157,7 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 	},
 	},
 
 
-	cutByPlane: function( object, plane, output ) {
+	cutByPlane: function ( object, plane, output ) {
 
 
 		// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 		// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 		// object2 can be null if the plane doesn't cut the object.
 		// object2 can be null if the plane doesn't cut the object.
@@ -183,22 +176,18 @@ THREE.ConvexObjectBreaker.prototype = {
 		var delta = this.smallDelta;
 		var delta = this.smallDelta;
 
 
 		// Reset vertices mark
 		// Reset vertices mark
-		for ( var i = 0; i < numPoints; i++ ) {
-			points[ i ].mark = 0;
-		}
+		for ( var i = 0; i < numPoints; i ++ ) points[ i ].mark = 0;
 
 
 		// Reset segments mark
 		// Reset segments mark
 		var numPointPairs = numPoints * numPoints;
 		var numPointPairs = numPoints * numPoints;
-		for ( var i = 0; i < numPointPairs; i++ ) {
-			this.segments[ i ] = false;
-		}
+		for ( var i = 0; i < numPointPairs; i ++ ) this.segments[ i ] = false;
 
 
 		// Iterate through the faces to mark edges shared by coplanar faces
 		// Iterate through the faces to mark edges shared by coplanar faces
-		for ( var i = 0, il = faces.length - 1; i < il; i++ ) {
+		for ( var i = 0, il = faces.length - 1; i < il; i ++ ) {
 
 
 			var face1 = faces[ i ];
 			var face1 = faces[ i ];
 
 
-			for ( var j = i + 1, jl = faces.length; j < jl; j++ ) {
+			for ( var j = i + 1, jl = faces.length; j < jl; j ++ ) {
 
 
 				var face2 = faces[ j ];
 				var face2 = faces[ j ];
 
 
@@ -215,18 +204,24 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 
 
 					if ( a1 === a2 || a1 === b2 || a1 === c2 ) {
 					if ( a1 === a2 || a1 === b2 || a1 === c2 ) {
+
 						if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
 						if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
+
 							this.segments[ a1 * numPoints + b1 ] = true;
 							this.segments[ a1 * numPoints + b1 ] = true;
 							this.segments[ b1 * numPoints + a1 ] = true;
 							this.segments[ b1 * numPoints + a1 ] = true;
-						}
-						else {
+
+						}	else {
+
 							this.segments[ c1 * numPoints + a1 ] = true;
 							this.segments[ c1 * numPoints + a1 ] = true;
 							this.segments[ a1 * numPoints + c1 ] = true;
 							this.segments[ a1 * numPoints + c1 ] = true;
+
 						}
 						}
-					}
-					else if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
+
+					}	else if ( b1 === a2 || b1 === b2 || b1 === c2 ) {
+
 						this.segments[ c1 * numPoints + b1 ] = true;
 						this.segments[ c1 * numPoints + b1 ] = true;
 						this.segments[ b1 * numPoints + c1 ] = true;
 						this.segments[ b1 * numPoints + c1 ] = true;
+
 					}
 					}
 
 
 				}
 				}
@@ -245,17 +240,14 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 			var face = faces[ i ];
 			var face = faces[ i ];
 
 
-			for ( var segment = 0; segment < 3; segment++ ) {
+			for ( var segment = 0; segment < 3; segment ++ ) {
 
 
 				var i0 = segment === 0 ? face.a : ( segment === 1 ? face.b : face.c );
 				var i0 = segment === 0 ? face.a : ( segment === 1 ? face.b : face.c );
 				var i1 = segment === 0 ? face.b : ( segment === 1 ? face.c : face.a );
 				var i1 = segment === 0 ? face.b : ( segment === 1 ? face.c : face.a );
 
 
 				var segmentState = this.segments[ i0 * numPoints + i1 ];
 				var segmentState = this.segments[ i0 * numPoints + i1 ];
 
 
-				if ( segmentState ) {
-					// The segment already has been processed in another face
-					continue;
-				}
+				if ( segmentState ) continue; // The segment already has been processed in another face
 
 
 				// Mark segment as processed (also inverted segment)
 				// Mark segment as processed (also inverted segment)
 				this.segments[ i0 * numPoints + i1 ] = true;
 				this.segments[ i0 * numPoints + i1 ] = true;
@@ -270,19 +262,23 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					if ( d > delta ) {
 					if ( d > delta ) {
+
 						p0.mark = 2;
 						p0.mark = 2;
 						points2.push( p0 );
 						points2.push( p0 );
-					}
-					else if ( d < - delta ) {
+
+					} else if ( d < - delta ) {
+
 						p0.mark = 1;
 						p0.mark = 1;
 						points1.push( p0 );
 						points1.push( p0 );
-					}
-					else {
+
+					} else {
+
 						p0.mark = 3;
 						p0.mark = 3;
 						points1.push( p0 );
 						points1.push( p0 );
 						var p0_2 = p0.clone();
 						var p0_2 = p0.clone();
 						p0_2.mark = 3;
 						p0_2.mark = 3;
 						points2.push( p0_2 );
 						points2.push( p0_2 );
+
 					}
 					}
 
 
 				}
 				}
@@ -293,19 +289,23 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					if ( d > delta ) {
 					if ( d > delta ) {
+
 						p1.mark = 2;
 						p1.mark = 2;
 						points2.push( p1 );
 						points2.push( p1 );
-					}
-					else if ( d < - delta ) {
+
+					} else if ( d < - delta ) {
+
 						p1.mark = 1;
 						p1.mark = 1;
 						points1.push( p1 );
 						points1.push( p1 );
-					}
-					else {
+
+					}	else {
+
 						p1.mark = 3;
 						p1.mark = 3;
 						points1.push( p1 );
 						points1.push( p1 );
 						var p1_2 = p1.clone();
 						var p1_2 = p1.clone();
 						p1_2.mark = 3;
 						p1_2.mark = 3;
 						points2.push( p1_2 );
 						points2.push( p1_2 );
+
 					}
 					}
 
 
 				}
 				}
@@ -319,13 +319,18 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 					this.tempLine1.start.copy( p0 );
 					this.tempLine1.start.copy( p0 );
 					this.tempLine1.end.copy( p1 );
 					this.tempLine1.end.copy( p1 );
-					var intersection = localPlane.intersectLine( this.tempLine1 );
+
+					var intersection = new THREE.Vector3();
+					intersection = localPlane.intersectLine( this.tempLine1, intersection );
+
 					if ( intersection === undefined ) {
 					if ( intersection === undefined ) {
+
 						// Shouldn't happen
 						// Shouldn't happen
 						console.error( "Internal error: segment does not intersect plane." );
 						console.error( "Internal error: segment does not intersect plane." );
 						output.segmentedObject1 = null;
 						output.segmentedObject1 = null;
 						output.segmentedObject2 = null;
 						output.segmentedObject2 = null;
 						return 0;
 						return 0;
+
 					}
 					}
 
 
 					intersection.mark = 1;
 					intersection.mark = 1;
@@ -347,33 +352,40 @@ THREE.ConvexObjectBreaker.prototype = {
 		this.tempCM1.set( 0, 0, 0 );
 		this.tempCM1.set( 0, 0, 0 );
 		var radius1 = 0;
 		var radius1 = 0;
 		var numPoints1 = points1.length;
 		var numPoints1 = points1.length;
+
 		if ( numPoints1 > 0 ) {
 		if ( numPoints1 > 0 ) {
-			for ( var i = 0; i < numPoints1; i++ ) {
-				this.tempCM1.add( points1[ i ] );
-			}
+
+			for ( var i = 0; i < numPoints1; i ++ ) this.tempCM1.add( points1[ i ] );
+
 			this.tempCM1.divideScalar( numPoints1 );
 			this.tempCM1.divideScalar( numPoints1 );
-			for ( var i = 0; i < numPoints1; i++ ) {
+			for ( var i = 0; i < numPoints1; i ++ ) {
+
 				var p = points1[ i ];
 				var p = points1[ i ];
 				p.sub( this.tempCM1 );
 				p.sub( this.tempCM1 );
 				radius1 = Math.max( radius1, p.x, p.y, p.z );
 				radius1 = Math.max( radius1, p.x, p.y, p.z );
+
 			}
 			}
 			this.tempCM1.add( object.position );
 			this.tempCM1.add( object.position );
+
 		}
 		}
 
 
 		this.tempCM2.set( 0, 0, 0 );
 		this.tempCM2.set( 0, 0, 0 );
 		var radius2 = 0;
 		var radius2 = 0;
 		var numPoints2 = points2.length;
 		var numPoints2 = points2.length;
 		if ( numPoints2 > 0 ) {
 		if ( numPoints2 > 0 ) {
-			for ( var i = 0; i < numPoints2; i++ ) {
-				this.tempCM2.add( points2[ i ] );
-			}
+
+			for ( var i = 0; i < numPoints2; i ++ ) this.tempCM2.add( points2[ i ] );
+
 			this.tempCM2.divideScalar( numPoints2 );
 			this.tempCM2.divideScalar( numPoints2 );
-			for ( var i = 0; i < numPoints2; i++ ) {
+			for ( var i = 0; i < numPoints2; i ++ ) {
+
 				var p = points2[ i ];
 				var p = points2[ i ];
 				p.sub( this.tempCM2 );
 				p.sub( this.tempCM2 );
 				radius2 = Math.max( radius2, p.x, p.y, p.z );
 				radius2 = Math.max( radius2, p.x, p.y, p.z );
+
 			}
 			}
 			this.tempCM2.add( object.position );
 			this.tempCM2.add( object.position );
+
 		}
 		}
 
 
 		var object1 = null;
 		var object1 = null;
@@ -389,7 +401,7 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 			this.prepareBreakableObject( object1, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius1 > this.minSizeForBreak );
 			this.prepareBreakableObject( object1, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius1 > this.minSizeForBreak );
 
 
-			numObjects++;
+			numObjects ++;
 
 
 		}
 		}
 
 
@@ -401,11 +413,10 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 			this.prepareBreakableObject( object2, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius2 > this.minSizeForBreak );
 			this.prepareBreakableObject( object2, newMass, object.userData.velocity, object.userData.angularVelocity, 2 * radius2 > this.minSizeForBreak );
 
 
-			numObjects++;
+			numObjects ++;
 
 
 		}
 		}
 
 
-
 		output.object1 = object1;
 		output.object1 = object1;
 		output.object2 = object2;
 		output.object2 = object2;
 
 
@@ -415,7 +426,7 @@ THREE.ConvexObjectBreaker.prototype = {
 
 
 };
 };
 
 
-THREE.ConvexObjectBreaker.transformFreeVector = function( v, m ) {
+THREE.ConvexObjectBreaker.transformFreeVector = function ( v, m ) {
 
 
 	// input:
 	// input:
 	// vector interpreted as a free vector
 	// vector interpreted as a free vector
@@ -424,15 +435,15 @@ THREE.ConvexObjectBreaker.transformFreeVector = function( v, m ) {
 	var x = v.x, y = v.y, z = v.z;
 	var x = v.x, y = v.y, z = v.z;
 	var e = m.elements;
 	var e = m.elements;
 
 
-	v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
-	v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
+	v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
+	v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
 	v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
 	v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
 
 
 	return v;
 	return v;
 
 
 };
 };
 
 
-THREE.ConvexObjectBreaker.transformFreeVectorInverse = function( v, m ) {
+THREE.ConvexObjectBreaker.transformFreeVectorInverse = function ( v, m ) {
 
 
 	// input:
 	// input:
 	// vector interpreted as a free vector
 	// vector interpreted as a free vector
@@ -441,15 +452,15 @@ THREE.ConvexObjectBreaker.transformFreeVectorInverse = function( v, m ) {
 	var x = v.x, y = v.y, z = v.z;
 	var x = v.x, y = v.y, z = v.z;
 	var e = m.elements;
 	var e = m.elements;
 
 
-	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ]  * z;
-	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ]  * z;
+	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z;
+	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z;
 	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
 	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
 
 
 	return v;
 	return v;
 
 
 };
 };
 
 
-THREE.ConvexObjectBreaker.transformTiedVectorInverse = function( v, m ) {
+THREE.ConvexObjectBreaker.transformTiedVectorInverse = function ( v, m ) {
 
 
 	// input:
 	// input:
 	// vector interpreted as a tied (ordinary) vector
 	// vector interpreted as a tied (ordinary) vector
@@ -458,18 +469,17 @@ THREE.ConvexObjectBreaker.transformTiedVectorInverse = function( v, m ) {
 	var x = v.x, y = v.y, z = v.z;
 	var x = v.x, y = v.y, z = v.z;
 	var e = m.elements;
 	var e = m.elements;
 
 
-	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ]  * z - e[ 12 ];
-	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ]  * z - e[ 13 ];
+	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z - e[ 12 ];
+	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z - e[ 13 ];
 	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
 	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
 
 
 	return v;
 	return v;
 
 
 };
 };
 
 
-THREE.ConvexObjectBreaker.transformPlaneToLocalSpace = function() {
+THREE.ConvexObjectBreaker.transformPlaneToLocalSpace = function () {
 
 
 	var v1 = new THREE.Vector3();
 	var v1 = new THREE.Vector3();
-	var m1 = new THREE.Matrix3();
 
 
 	return function transformPlaneToLocalSpace( plane, m, resultPlane ) {
 	return function transformPlaneToLocalSpace( plane, m, resultPlane ) {
 
 

+ 327 - 327
examples/js/MarchingCubes.js

@@ -57,7 +57,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		this.hasUvs = false;
 		this.hasUvs = false;
 
 
 		this.positionArray = new Float32Array( this.maxCount * 3 );
 		this.positionArray = new Float32Array( this.maxCount * 3 );
-		this.normalArray   = new Float32Array( this.maxCount * 3 );
+		this.normalArray = new Float32Array( this.maxCount * 3 );
 
 
 		if ( this.enableUvs ) {
 		if ( this.enableUvs ) {
 
 
@@ -67,7 +67,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 		if ( this.enableColors ) {
 		if ( this.enableColors ) {
 
 
-			this.colorArray   = new Float32Array( this.maxCount * 3 );
+			this.colorArray = new Float32Array( this.maxCount * 3 );
 
 
 		}
 		}
 
 
@@ -86,7 +86,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 	function VIntX( q, offset, isol, x, y, z, valp1, valp2 ) {
 	function VIntX( q, offset, isol, x, y, z, valp1, valp2 ) {
 
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-		nc = scope.normal_cache;
+			nc = scope.normal_cache;
 
 
 		vlist[ offset + 0 ] = x + mu * scope.delta;
 		vlist[ offset + 0 ] = x + mu * scope.delta;
 		vlist[ offset + 1 ] = y;
 		vlist[ offset + 1 ] = y;
@@ -101,7 +101,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 	function VIntY( q, offset, isol, x, y, z, valp1, valp2 ) {
 	function VIntY( q, offset, isol, x, y, z, valp1, valp2 ) {
 
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-		nc = scope.normal_cache;
+			nc = scope.normal_cache;
 
 
 		vlist[ offset + 0 ] = x;
 		vlist[ offset + 0 ] = x;
 		vlist[ offset + 1 ] = y + mu * scope.delta;
 		vlist[ offset + 1 ] = y + mu * scope.delta;
@@ -118,7 +118,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 	function VIntZ( q, offset, isol, x, y, z, valp1, valp2 ) {
 	function VIntZ( q, offset, isol, x, y, z, valp1, valp2 ) {
 
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
-		nc = scope.normal_cache;
+			nc = scope.normal_cache;
 
 
 		vlist[ offset + 0 ] = x;
 		vlist[ offset + 0 ] = x;
 		vlist[ offset + 1 ] = y;
 		vlist[ offset + 1 ] = y;
@@ -138,7 +138,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 		if ( scope.normal_cache[ q3 ] === 0.0 ) {
 		if ( scope.normal_cache[ q3 ] === 0.0 ) {
 
 
-			scope.normal_cache[ q3 + 0 ] = scope.field[ q - 1 ] 	    - scope.field[ q + 1 ];
+			scope.normal_cache[ q3 + 0 ] = scope.field[ q - 1 ] - scope.field[ q + 1 ];
 			scope.normal_cache[ q3 + 1 ] = scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
 			scope.normal_cache[ q3 + 1 ] = scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
 			scope.normal_cache[ q3 + 2 ] = scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
 			scope.normal_cache[ q3 + 2 ] = scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
 
 
@@ -271,7 +271,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 			compNorm( q1 );
 			compNorm( q1 );
 			compNorm( q1z );
 			compNorm( q1z );
-			VIntZ( q1 * 3, 27, isol, fx2, fy,  fz, field1, field5 );
+			VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5 );
 
 
 		}
 		}
 
 
@@ -287,11 +287,11 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 			compNorm( qy );
 			compNorm( qy );
 			compNorm( qyz );
 			compNorm( qyz );
-			VIntZ( qy * 3, 33, isol, fx,  fy2, fz, field2, field6 );
+			VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6 );
 
 
 		}
 		}
 
 
-		cubeindex <<= 4;  // re-purpose cubeindex into an offset into triTable
+		cubeindex <<= 4; // re-purpose cubeindex into an offset into triTable
 
 
 		var o1, o2, o3, numtris = 0, i = 0;
 		var o1, o2, o3, numtris = 0, i = 0;
 
 
@@ -482,7 +482,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		var max_z = Math.floor( zs + radius ); if ( max_z > this.size - 1 ) max_z = this.size - 1;
 		var max_z = Math.floor( zs + radius ); if ( max_z > this.size - 1 ) max_z = this.size - 1;
 		var min_y = Math.floor( ys - radius ); if ( min_y < 1 ) min_y = 1;
 		var min_y = Math.floor( ys - radius ); if ( min_y < 1 ) min_y = 1;
 		var max_y = Math.floor( ys + radius ); if ( max_y > this.size - 1 ) max_y = this.size - 1;
 		var max_y = Math.floor( ys + radius ); if ( max_y > this.size - 1 ) max_y = this.size - 1;
-		var min_x = Math.floor( xs - radius ); if ( min_x < 1  ) min_x = 1;
+		var min_x = Math.floor( xs - radius ); if ( min_x < 1 ) min_x = 1;
 		var max_x = Math.floor( xs + radius ); if ( max_x > this.size - 1 ) max_x = this.size - 1;
 		var max_x = Math.floor( xs + radius ); if ( max_x > this.size - 1 ) max_x = this.size - 1;
 
 
 
 
@@ -517,7 +517,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 	};
 	};
 
 
-	this.addPlaneX = function( strength, subtract ) {
+	this.addPlaneX = function ( strength, subtract ) {
 
 
 		var x, y, z, xx, val, xdiv, cxy,
 		var x, y, z, xx, val, xdiv, cxy,
 
 
@@ -557,7 +557,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 	};
 	};
 
 
-	this.addPlaneY = function( strength, subtract ) {
+	this.addPlaneY = function ( strength, subtract ) {
 
 
 		var x, y, z, yy, val, ydiv, cy, cxy,
 		var x, y, z, yy, val, ydiv, cy, cxy,
 
 
@@ -596,7 +596,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 	};
 	};
 
 
-	this.addPlaneZ = function( strength, subtract ) {
+	this.addPlaneZ = function ( strength, subtract ) {
 
 
 		var x, y, z, zz, val, zdiv, cz, cyz,
 		var x, y, z, zz, val, zdiv, cz, cyz,
 
 
@@ -688,48 +688,48 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 
 	};
 	};
 
 
-	this.generateGeometry = function() {
+	this.generateGeometry = function () {
 
 
-		var start = 0, geo = new THREE.Geometry();
-		var normals = [];
+		console.warn( 'THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry' );
+		return this.generateBufferGeometry();
 
 
-		var geo_callback = function( object ) {
-
-			for ( var i = 0; i < object.count; i ++ ) {
-
-				var vertex = new THREE.Vector3().fromArray( object.positionArray, i * 3 );
-				var normal = new THREE.Vector3().fromArray( object.normalArray, i * 3 );
+	};
 
 
-				geo.vertices.push( vertex );
-				normals.push( normal );
+	function concatenate( a, b, length ) {
 
 
-			}
+		var result = new Float32Array( a.length + length );
+		result.set( a, 0 );
+		result.set( b.slice( 0, length ), a.length );
+		return result;
 
 
-			var nfaces = object.count / 3;
-
-			for ( i = 0; i < nfaces; i ++ ) {
+	}
 
 
-				var a = ( start + i ) * 3;
-				var b = a + 1;
-				var c = a + 2;
+	this.generateBufferGeometry = function () {
 
 
-				var na = normals[ a ];
-				var nb = normals[ b ];
-				var nc = normals[ c ];
+		var geo = new THREE.BufferGeometry();
+		var posArray = new Float32Array();
+		var normArray = new Float32Array();
+		var colorArray = new Float32Array();
+		var uvArray = new Float32Array();
+		var scope = this;
 
 
-				var face = new THREE.Face3( a, b, c, [ na, nb, nc ] );
-				geo.faces.push( face );
+		var geo_callback = function ( object ) {
 
 
-			}
+			if ( scope.hasPositions ) posArray = concatenate( posArray, object.positionArray, object.count * 3 );
+			if ( scope.hasNormals ) normArray = concatenate( normArray, object.normalArray, object.count * 3 );
+			if ( scope.hasColors ) colorArray = concatenate( colorArray, object.colorArray, object.count * 3 );
+			if ( scope.hasUvs ) uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
 
 
-			start += nfaces;
 			object.count = 0;
 			object.count = 0;
 
 
 		};
 		};
 
 
 		this.render( geo_callback );
 		this.render( geo_callback );
 
 
-		// console.log( "generated " + geo.faces.length + " triangles" );
+		if ( this.hasPositions ) geo.addAttribute( 'position', new THREE.BufferAttribute( posArray, 3 ) );
+		if ( this.hasNormals ) geo.addAttribute( 'normal', new THREE.BufferAttribute( normArray, 3 ) );
+		if ( this.hasColors ) geo.addAttribute( 'color', new THREE.BufferAttribute( colorArray, 3 ) );
+		if ( this.hasUvs ) geo.addAttribute( 'uv', new THREE.BufferAttribute( uvArray, 2 ) );
 
 
 		return geo;
 		return geo;
 
 
@@ -752,293 +752,293 @@ THREE.MarchingCubes.prototype.constructor = THREE.MarchingCubes;
 // who in turn got them from Cory Gene Bloyd.
 // who in turn got them from Cory Gene Bloyd.
 
 
 THREE.edgeTable = new Int32Array( [
 THREE.edgeTable = new Int32Array( [
-0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
-0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
-0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
-0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
-0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
-0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
-0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
-0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
-0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
-0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
-0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
-0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
-0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
-0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
-0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
-0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
-0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
-0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
-0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
-0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
-0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
-0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
-0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
-0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
-0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
-0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
-0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
-0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
-0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
-0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
-0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
-0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ] );
+	0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+	0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+	0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+	0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+	0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+	0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+	0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
+	0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+	0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
+	0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+	0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
+	0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+	0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
+	0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+	0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
+	0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+	0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+	0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+	0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+	0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+	0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+	0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+	0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+	0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
+	0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+	0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
+	0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+	0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
+	0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+	0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
+	0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+	0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ] );
 
 
 THREE.triTable = new Int32Array( [
 THREE.triTable = new Int32Array( [
-- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 8, 3, 9, 8, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 2, 10, 0, 2, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 8, 3, 2, 10, 8, 10, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 11, 2, 8, 11, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 9, 0, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 11, 2, 1, 9, 11, 9, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 10, 1, 11, 10, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 10, 1, 0, 8, 10, 8, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 9, 0, 3, 11, 9, 11, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 3, 0, 7, 3, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 1, 9, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 1, 9, 4, 7, 1, 7, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 4, 7, 3, 0, 4, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 2, 10, 9, 0, 2, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
-8, 4, 7, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 4, 7, 11, 2, 4, 2, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 0, 1, 8, 4, 7, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, - 1, - 1, - 1, - 1,
-3, 10, 1, 3, 11, 10, 7, 8, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, - 1, - 1, - 1, - 1,
-4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
-4, 7, 11, 4, 11, 9, 9, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 5, 4, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 5, 4, 1, 5, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 5, 4, 8, 3, 5, 3, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 0, 8, 1, 2, 10, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 2, 10, 5, 4, 2, 4, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, - 1, - 1, - 1, - 1,
-9, 5, 4, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 11, 2, 0, 8, 11, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 5, 4, 0, 1, 5, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, - 1, - 1, - 1, - 1,
-10, 3, 11, 10, 1, 3, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, - 1, - 1, - 1, - 1,
-5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
-5, 4, 8, 5, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 7, 8, 5, 7, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 3, 0, 9, 5, 3, 5, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 7, 8, 0, 1, 7, 1, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 7, 8, 9, 5, 7, 10, 1, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, - 1, - 1, - 1, - 1,
-8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, - 1, - 1, - 1, - 1,
-2, 10, 5, 2, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 9, 5, 7, 8, 9, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
-2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, - 1, - 1, - 1, - 1,
-11, 2, 1, 11, 1, 7, 7, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, - 1, - 1, - 1, - 1,
-5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, - 1,
-11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, - 1,
-11, 10, 5, 7, 11, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 0, 1, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 8, 3, 1, 9, 8, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 6, 5, 2, 6, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 6, 5, 1, 2, 6, 3, 0, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 6, 5, 9, 0, 6, 0, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, - 1, - 1, - 1, - 1,
-2, 3, 11, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 0, 8, 11, 2, 0, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 1, 9, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, - 1, - 1, - 1, - 1,
-6, 3, 11, 6, 5, 3, 5, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
-3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, - 1, - 1, - 1, - 1,
-6, 5, 9, 6, 9, 11, 11, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 10, 6, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 3, 0, 4, 7, 3, 6, 5, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 9, 0, 5, 10, 6, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
-6, 1, 2, 6, 5, 1, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, - 1, - 1, - 1, - 1,
-8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, - 1, - 1, - 1, - 1,
-7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, - 1,
-3, 11, 2, 7, 8, 4, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
-0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1,
-9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, - 1,
-8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
-5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, - 1,
-0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, - 1,
-6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, - 1, - 1, - 1, - 1,
-10, 4, 9, 6, 4, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 10, 6, 4, 9, 10, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 0, 1, 10, 6, 0, 6, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
-1, 4, 9, 1, 2, 4, 2, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, - 1, - 1, - 1, - 1,
-0, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 3, 2, 8, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 4, 9, 10, 6, 4, 11, 2, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, - 1, - 1, - 1, - 1,
-3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
-6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, - 1,
-9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, - 1, - 1, - 1, - 1,
-8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, - 1,
-3, 11, 6, 3, 6, 0, 0, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-6, 4, 8, 11, 6, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 10, 6, 7, 8, 10, 8, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, - 1, - 1, - 1, - 1,
-10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, - 1, - 1, - 1, - 1,
-10, 6, 7, 10, 7, 1, 1, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
-2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, - 1,
-7, 8, 0, 7, 0, 6, 6, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 3, 2, 6, 7, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
-2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, - 1,
-1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, - 1,
-11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, - 1, - 1, - 1, - 1,
-8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, - 1,
-0, 9, 1, 11, 6, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, - 1, - 1, - 1, - 1,
-7, 11, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 0, 8, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 1, 9, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 1, 9, 8, 3, 1, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 1, 2, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, 3, 0, 8, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 9, 0, 2, 10, 9, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, - 1, - 1, - 1, - 1,
-7, 2, 3, 6, 2, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-7, 0, 8, 7, 6, 0, 6, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 7, 6, 2, 3, 7, 0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, - 1, - 1, - 1, - 1,
-10, 7, 6, 10, 1, 7, 1, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, - 1, - 1, - 1, - 1,
-0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, - 1, - 1, - 1, - 1,
-7, 6, 10, 7, 10, 8, 8, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-6, 8, 4, 11, 8, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 6, 11, 3, 0, 6, 0, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 6, 11, 8, 4, 6, 9, 0, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, - 1, - 1, - 1, - 1,
-6, 8, 4, 6, 11, 8, 2, 10, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, - 1, - 1, - 1, - 1,
-4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, - 1, - 1, - 1, - 1,
-10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, - 1,
-8, 2, 3, 8, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, - 1, - 1, - 1, - 1,
-1, 9, 4, 1, 4, 2, 2, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, - 1, - 1, - 1, - 1,
-10, 1, 0, 10, 0, 6, 6, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, - 1,
-10, 9, 4, 6, 10, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 9, 5, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, 4, 9, 5, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 0, 1, 5, 4, 0, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, - 1, - 1, - 1, - 1,
-9, 5, 4, 10, 1, 2, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, - 1, - 1, - 1, - 1,
-7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, - 1, - 1, - 1, - 1,
-3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, - 1,
-7, 2, 3, 7, 6, 2, 5, 4, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, - 1, - 1, - 1, - 1,
-3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, - 1, - 1, - 1, - 1,
-6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, - 1,
-9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, - 1, - 1, - 1, - 1,
-1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, - 1,
-4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, - 1,
-7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, - 1, - 1, - 1, - 1,
-6, 9, 5, 6, 11, 9, 11, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, - 1, - 1, - 1, - 1,
-0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, - 1, - 1, - 1, - 1,
-6, 11, 3, 6, 3, 5, 5, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, - 1, - 1, - 1, - 1,
-0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, - 1,
-11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, - 1,
-6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, - 1, - 1, - 1, - 1,
-5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, - 1, - 1, - 1, - 1,
-9, 5, 6, 9, 6, 0, 0, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, - 1,
-1, 5, 6, 2, 1, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, - 1,
-10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, - 1, - 1, - 1, - 1,
-0, 3, 8, 5, 6, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 5, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 5, 10, 7, 5, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 5, 10, 11, 7, 5, 8, 3, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 11, 7, 5, 10, 11, 1, 9, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, - 1, - 1, - 1, - 1,
-11, 1, 2, 11, 7, 1, 7, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, - 1, - 1, - 1, - 1,
-9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, - 1, - 1, - 1, - 1,
-7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, - 1,
-2, 5, 10, 2, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, - 1, - 1, - 1, - 1,
-9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, - 1, - 1, - 1, - 1,
-9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, - 1,
-1, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 7, 0, 7, 1, 1, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 0, 3, 9, 3, 5, 5, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 8, 7, 5, 9, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 8, 4, 5, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, - 1, - 1, - 1, - 1,
-0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, - 1, - 1, - 1, - 1,
-10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, - 1,
-2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, - 1, - 1, - 1, - 1,
-0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, - 1,
-0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, - 1,
-9, 4, 5, 2, 11, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, - 1, - 1, - 1, - 1,
-5, 10, 2, 5, 2, 4, 4, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, - 1,
-5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, - 1, - 1, - 1, - 1,
-8, 4, 5, 8, 5, 3, 3, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 4, 5, 1, 0, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, - 1, - 1, - 1, - 1,
-9, 4, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 11, 7, 4, 9, 11, 9, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, - 1, - 1, - 1, - 1,
-1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, - 1, - 1, - 1, - 1,
-3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, - 1,
-4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, - 1, - 1, - 1, - 1,
-9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, - 1,
-11, 7, 4, 11, 4, 2, 2, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, - 1, - 1, - 1, - 1,
-2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, - 1, - 1, - 1, - 1,
-9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, - 1,
-3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, - 1,
-1, 10, 2, 8, 7, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 9, 1, 4, 1, 7, 7, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, - 1, - 1, - 1, - 1,
-4, 0, 3, 7, 4, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-4, 8, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 0, 9, 3, 9, 11, 11, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 1, 10, 0, 10, 8, 8, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 1, 10, 11, 3, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 2, 11, 1, 11, 9, 9, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, - 1, - 1, - 1, - 1,
-0, 2, 11, 8, 0, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-3, 2, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 3, 8, 2, 8, 10, 10, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-9, 10, 2, 0, 9, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, - 1, - 1, - 1, - 1,
-1, 10, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-1, 3, 8, 9, 1, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 9, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-0, 3, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
-- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 ] );
+	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 8, 3, 9, 8, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 2, 10, 0, 2, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 8, 3, 2, 10, 8, 10, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 11, 2, 8, 11, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 11, 2, 1, 9, 11, 9, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 10, 1, 11, 10, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 10, 1, 0, 8, 10, 8, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 9, 0, 3, 11, 9, 11, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 3, 0, 7, 3, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 1, 9, 4, 7, 1, 7, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 4, 7, 3, 0, 4, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 2, 10, 9, 0, 2, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+	8, 4, 7, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 4, 7, 11, 2, 4, 2, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 1, 8, 4, 7, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, - 1, - 1, - 1, - 1,
+	3, 10, 1, 3, 11, 10, 7, 8, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, - 1, - 1, - 1, - 1,
+	4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+	4, 7, 11, 4, 11, 9, 9, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 5, 4, 1, 5, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 5, 4, 8, 3, 5, 3, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 1, 2, 10, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 2, 10, 5, 4, 2, 4, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, - 1, - 1, - 1, - 1,
+	9, 5, 4, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 11, 2, 0, 8, 11, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 5, 4, 0, 1, 5, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, - 1, - 1, - 1, - 1,
+	10, 3, 11, 10, 1, 3, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, - 1, - 1, - 1, - 1,
+	5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+	5, 4, 8, 5, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 7, 8, 5, 7, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 3, 0, 9, 5, 3, 5, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 7, 8, 0, 1, 7, 1, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 7, 8, 9, 5, 7, 10, 1, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, - 1, - 1, - 1, - 1,
+	8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, - 1, - 1, - 1, - 1,
+	2, 10, 5, 2, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 9, 5, 7, 8, 9, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+	2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, - 1, - 1, - 1, - 1,
+	11, 2, 1, 11, 1, 7, 7, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, - 1, - 1, - 1, - 1,
+	5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, - 1,
+	11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, - 1,
+	11, 10, 5, 7, 11, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 1, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 8, 3, 1, 9, 8, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 5, 2, 6, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 5, 1, 2, 6, 3, 0, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 6, 5, 9, 0, 6, 0, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, - 1, - 1, - 1, - 1,
+	2, 3, 11, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 0, 8, 11, 2, 0, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, - 1, - 1, - 1, - 1,
+	6, 3, 11, 6, 5, 3, 5, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+	3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, - 1, - 1, - 1, - 1,
+	6, 5, 9, 6, 9, 11, 11, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 3, 0, 4, 7, 3, 6, 5, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 5, 10, 6, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+	6, 1, 2, 6, 5, 1, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, - 1, - 1, - 1, - 1,
+	8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, - 1, - 1, - 1, - 1,
+	7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, - 1,
+	3, 11, 2, 7, 8, 4, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+	0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1,
+	9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, - 1,
+	8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+	5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, - 1,
+	0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, - 1,
+	6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, - 1, - 1, - 1, - 1,
+	10, 4, 9, 6, 4, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 10, 6, 4, 9, 10, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 0, 1, 10, 6, 0, 6, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+	1, 4, 9, 1, 2, 4, 2, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, - 1, - 1, - 1, - 1,
+	0, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 3, 2, 8, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 4, 9, 10, 6, 4, 11, 2, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, - 1, - 1, - 1, - 1,
+	3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+	6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, - 1,
+	9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, - 1, - 1, - 1, - 1,
+	8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, - 1,
+	3, 11, 6, 3, 6, 0, 0, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 4, 8, 11, 6, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 10, 6, 7, 8, 10, 8, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, - 1, - 1, - 1, - 1,
+	10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, - 1, - 1, - 1, - 1,
+	10, 6, 7, 10, 7, 1, 1, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+	2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, - 1,
+	7, 8, 0, 7, 0, 6, 6, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 3, 2, 6, 7, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+	2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, - 1,
+	1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, - 1,
+	11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, - 1, - 1, - 1, - 1,
+	8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, - 1,
+	0, 9, 1, 11, 6, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, - 1, - 1, - 1, - 1,
+	7, 11, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 1, 9, 8, 3, 1, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 1, 2, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 3, 0, 8, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 9, 0, 2, 10, 9, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, - 1, - 1, - 1, - 1,
+	7, 2, 3, 6, 2, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 0, 8, 7, 6, 0, 6, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 7, 6, 2, 3, 7, 0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, - 1, - 1, - 1, - 1,
+	10, 7, 6, 10, 1, 7, 1, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, - 1, - 1, - 1, - 1,
+	0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, - 1, - 1, - 1, - 1,
+	7, 6, 10, 7, 10, 8, 8, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 8, 4, 11, 8, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 6, 11, 3, 0, 6, 0, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 6, 11, 8, 4, 6, 9, 0, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, - 1, - 1, - 1, - 1,
+	6, 8, 4, 6, 11, 8, 2, 10, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, - 1, - 1, - 1, - 1,
+	4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, - 1, - 1, - 1, - 1,
+	10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, - 1,
+	8, 2, 3, 8, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, - 1, - 1, - 1, - 1,
+	1, 9, 4, 1, 4, 2, 2, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, - 1, - 1, - 1, - 1,
+	10, 1, 0, 10, 0, 6, 6, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, - 1,
+	10, 9, 4, 6, 10, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 5, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 4, 9, 5, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 0, 1, 5, 4, 0, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, - 1, - 1, - 1, - 1,
+	9, 5, 4, 10, 1, 2, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, - 1, - 1, - 1, - 1,
+	7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, - 1, - 1, - 1, - 1,
+	3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, - 1,
+	7, 2, 3, 7, 6, 2, 5, 4, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, - 1, - 1, - 1, - 1,
+	3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, - 1, - 1, - 1, - 1,
+	6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, - 1,
+	9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, - 1, - 1, - 1, - 1,
+	1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, - 1,
+	4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, - 1,
+	7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, - 1, - 1, - 1, - 1,
+	6, 9, 5, 6, 11, 9, 11, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, - 1, - 1, - 1, - 1,
+	0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, - 1, - 1, - 1, - 1,
+	6, 11, 3, 6, 3, 5, 5, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, - 1, - 1, - 1, - 1,
+	0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, - 1,
+	11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, - 1,
+	6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, - 1, - 1, - 1, - 1,
+	5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, - 1, - 1, - 1, - 1,
+	9, 5, 6, 9, 6, 0, 0, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, - 1,
+	1, 5, 6, 2, 1, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, - 1,
+	10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, - 1, - 1, - 1, - 1,
+	0, 3, 8, 5, 6, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 5, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 5, 10, 7, 5, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 5, 10, 11, 7, 5, 8, 3, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 11, 7, 5, 10, 11, 1, 9, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, - 1, - 1, - 1, - 1,
+	11, 1, 2, 11, 7, 1, 7, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, - 1, - 1, - 1, - 1,
+	9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, - 1, - 1, - 1, - 1,
+	7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, - 1,
+	2, 5, 10, 2, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, - 1, - 1, - 1, - 1,
+	9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, - 1, - 1, - 1, - 1,
+	9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, - 1,
+	1, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 7, 0, 7, 1, 1, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 3, 9, 3, 5, 5, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 8, 7, 5, 9, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 8, 4, 5, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, - 1, - 1, - 1, - 1,
+	0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, - 1, - 1, - 1, - 1,
+	10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, - 1,
+	2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, - 1, - 1, - 1, - 1,
+	0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, - 1,
+	0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, - 1,
+	9, 4, 5, 2, 11, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, - 1, - 1, - 1, - 1,
+	5, 10, 2, 5, 2, 4, 4, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, - 1,
+	5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, - 1, - 1, - 1, - 1,
+	8, 4, 5, 8, 5, 3, 3, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 4, 5, 1, 0, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, - 1, - 1, - 1, - 1,
+	9, 4, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 11, 7, 4, 9, 11, 9, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, - 1, - 1, - 1, - 1,
+	1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, - 1, - 1, - 1, - 1,
+	3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, - 1,
+	4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, - 1, - 1, - 1, - 1,
+	9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, - 1,
+	11, 7, 4, 11, 4, 2, 2, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, - 1, - 1, - 1, - 1,
+	2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, - 1, - 1, - 1, - 1,
+	9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, - 1,
+	3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, - 1,
+	1, 10, 2, 8, 7, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 1, 4, 1, 7, 7, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, - 1, - 1, - 1, - 1,
+	4, 0, 3, 7, 4, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 8, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 9, 3, 9, 11, 11, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 10, 0, 10, 8, 8, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 1, 10, 11, 3, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 11, 1, 11, 9, 9, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, - 1, - 1, - 1, - 1,
+	0, 2, 11, 8, 0, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 2, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 8, 2, 8, 10, 10, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 10, 2, 0, 9, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, - 1, - 1, - 1, - 1,
+	1, 10, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 3, 8, 9, 1, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 9, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 3, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 ] );

File diff suppressed because it is too large
+ 299 - 299
examples/js/Octree.js


+ 14 - 28
examples/js/ParametricGeometries.js

@@ -7,9 +7,7 @@
 
 
 THREE.ParametricGeometries = {
 THREE.ParametricGeometries = {
 
 
-	klein: function ( v, u, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	klein: function ( v, u, target ) {
 
 
 		u *= Math.PI;
 		u *= Math.PI;
 		v *= 2 * Math.PI;
 		v *= 2 * Math.PI;
@@ -30,29 +28,25 @@ THREE.ParametricGeometries = {
 
 
 		y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
 		y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	},
 	},
 
 
 	plane: function ( width, height ) {
 	plane: function ( width, height ) {
 
 
-		return function ( u, v, optionalTarget ) {
-
-			var result = optionalTarget || new THREE.Vector3();
+		return function ( u, v, target ) {
 
 
 			var x = u * width;
 			var x = u * width;
 			var y = 0;
 			var y = 0;
 			var z = v * height;
 			var z = v * height;
 
 
-			return result.set( x, y, z );
+			target.set( x, y, z );
 
 
 		};
 		};
 
 
 	},
 	},
 
 
-	mobius: function ( u, t, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	mobius: function ( u, t, target ) {
 
 
 		// flat mobius strip
 		// flat mobius strip
 		// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
 		// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
@@ -67,13 +61,11 @@ THREE.ParametricGeometries = {
 		y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
 		y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
 		z = u * Math.sin( v / 2 );
 		z = u * Math.sin( v / 2 );
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	},
 	},
 
 
-	mobius3d: function ( u, t, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	mobius3d: function ( u, t, target ) {
 
 
 		// volumetric mobius strip
 		// volumetric mobius strip
 
 
@@ -91,7 +83,7 @@ THREE.ParametricGeometries = {
 		y = ( major + x ) * Math.sin( u );
 		y = ( major + x ) * Math.sin( u );
 		x = ( major + x ) * Math.cos( u );
 		x = ( major + x ) * Math.cos( u );
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	}
 	}
 
 
@@ -126,9 +118,7 @@ THREE.ParametricGeometries.TubeGeometry = function ( path, segments, radius, seg
 	this.normals = normals;
 	this.normals = normals;
 	this.binormals = binormals;
 	this.binormals = binormals;
 
 
-	var ParametricTube = function ( u, v, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	var ParametricTube = function ( u, v, target ) {
 
 
 		v *= 2 * Math.PI;
 		v *= 2 * Math.PI;
 
 
@@ -156,7 +146,7 @@ THREE.ParametricGeometries.TubeGeometry = function ( path, segments, radius, seg
 		pos.y += cx * normal.y + cy * binormal.y;
 		pos.y += cx * normal.y + cy * binormal.y;
 		pos.z += cx * normal.z + cy * binormal.z;
 		pos.z += cx * normal.z + cy * binormal.z;
 
 
-		return result.copy( pos );
+		target.copy( pos );
 
 
 	};
 	};
 
 
@@ -226,9 +216,7 @@ THREE.ParametricGeometries.TorusKnotGeometry.prototype.constructor = THREE.Param
   *********************************************/
   *********************************************/
 THREE.ParametricGeometries.SphereGeometry = function ( size, u, v ) {
 THREE.ParametricGeometries.SphereGeometry = function ( size, u, v ) {
 
 
-	function sphere( u, v, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	function sphere( u, v, target ) {
 
 
 		u *= Math.PI;
 		u *= Math.PI;
 		v *= 2 * Math.PI;
 		v *= 2 * Math.PI;
@@ -237,7 +225,7 @@ THREE.ParametricGeometries.SphereGeometry = function ( size, u, v ) {
 		var y = size * Math.sin( u ) * Math.sin( v );
 		var y = size * Math.sin( u ) * Math.sin( v );
 		var z = size * Math.cos( u );
 		var z = size * Math.cos( u );
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	}
 	}
 
 
@@ -257,15 +245,13 @@ THREE.ParametricGeometries.SphereGeometry.prototype.constructor = THREE.Parametr
 
 
 THREE.ParametricGeometries.PlaneGeometry = function ( width, depth, segmentsWidth, segmentsDepth ) {
 THREE.ParametricGeometries.PlaneGeometry = function ( width, depth, segmentsWidth, segmentsDepth ) {
 
 
-	function plane( u, v, optionalTarget ) {
-
-		var result = optionalTarget || new THREE.Vector3();
+	function plane( u, v, target ) {
 
 
 		var x = u * width;
 		var x = u * width;
 		var y = 0;
 		var y = 0;
 		var z = v * depth;
 		var z = v * depth;
 
 
-		return result.set( x, y, z );
+		target.set( x, y, z );
 
 
 	}
 	}
 
 

+ 41 - 4
examples/js/ShaderGodRays.js

@@ -20,15 +20,52 @@
 
 
 THREE.ShaderGodRays = {
 THREE.ShaderGodRays = {
 
 
+	'godrays_depthMask': {
+
+		uniforms: {
+
+			tInput: {
+				value: null
+			}
+
+		},
+
+		vertexShader: [
+
+			"varying vec2 vUv;",
+
+			"void main() {",
+
+			" vUv = uv;",
+			" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"varying vec2 vUv;",
+
+			"uniform sampler2D tInput;",
+
+			"void main() {",
+
+			"	gl_FragColor = vec4( 1.0 ) - texture2D( tInput, vUv );",
+
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+
 	/**
 	/**
 	 * The god-ray generation shader.
 	 * The god-ray generation shader.
 	 *
 	 *
 	 * First pass:
 	 * First pass:
 	 *
 	 *
-	 * The input is the depth map. I found that the output from the
-	 * THREE.MeshDepthMaterial material was directly suitable without
-	 * requiring any treatment whatsoever.
-	 *
 	 * The depth map is blurred along radial lines towards the "sun". The
 	 * The depth map is blurred along radial lines towards the "sun". The
 	 * output is written to a temporary render target (I used a 1/4 sized
 	 * output is written to a temporary render target (I used a 1/4 sized
 	 * target).
 	 * target).

+ 278 - 239
examples/js/animation/CCDIKSolver.js

@@ -2,416 +2,455 @@
  * @author takahiro / https://github.com/takahirox
  * @author takahiro / https://github.com/takahirox
  *
  *
  * CCD Algorithm
  * CCD Algorithm
- *  https://sites.google.com/site/auraliusproject/ccd-algorithm
- *
- * mesh.geometry needs to have iks array.
+ *  - https://sites.google.com/site/auraliusproject/ccd-algorithm
  *
  *
  * // ik parameter example
  * // ik parameter example
  * //
  * //
- * // target, effector, index in links are bone index in skeleton.
+ * // target, effector, index in links are bone index in skeleton.bones.
  * // the bones relation should be
  * // the bones relation should be
  * // <-- parent                                  child -->
  * // <-- parent                                  child -->
  * // links[ n ], links[ n - 1 ], ..., links[ 0 ], effector
  * // links[ n ], links[ n - 1 ], ..., links[ 0 ], effector
- * ik = {
+ * iks = [ {
  *	target: 1,
  *	target: 1,
  *	effector: 2,
  *	effector: 2,
  *	links: [ { index: 5, limitation: new THREE.Vector3( 1, 0, 0 ) }, { index: 4, enabled: false }, { index : 3 } ],
  *	links: [ { index: 5, limitation: new THREE.Vector3( 1, 0, 0 ) }, { index: 4, enabled: false }, { index : 3 } ],
  *	iteration: 10,
  *	iteration: 10,
  *	minAngle: 0.0,
  *	minAngle: 0.0,
  *	maxAngle: 1.0,
  *	maxAngle: 1.0,
- * };
+ * } ];
  */
  */
 
 
-THREE.CCDIKSolver = function ( mesh ) {
+THREE.CCDIKSolver = ( function () {
 
 
-	this.mesh = mesh;
+	/**
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {Array<Object>} iks
+	 */
+	function CCDIKSolver( mesh, iks ) {
 
 
-	this._valid();
+		this.mesh = mesh;
+		this.iks = iks || [];
 
 
-};
+		this._valid();
 
 
-THREE.CCDIKSolver.prototype = {
+	}
 
 
-	constructor: THREE.CCDIKSolver,
+	CCDIKSolver.prototype = {
 
 
-	_valid: function () {
+		constructor: CCDIKSolver,
 
 
-		var iks = this.mesh.geometry.iks;
-		var bones = this.mesh.skeleton.bones;
+		/**
+		 * Update IK bones.
+		 *
+		 * @return {THREE.CCDIKSolver}
+		 */
+		update: function () {
 
 
-		for ( var i = 0, il = iks.length; i < il; i ++ ) {
+			var q = new THREE.Quaternion();
+			var targetPos = new THREE.Vector3();
+			var targetVec = new THREE.Vector3();
+			var effectorPos = new THREE.Vector3();
+			var effectorVec = new THREE.Vector3();
+			var linkPos = new THREE.Vector3();
+			var invLinkQ = new THREE.Quaternion();
+			var linkScale = new THREE.Vector3();
+			var axis = new THREE.Vector3();
+			var vector = new THREE.Vector3();
 
 
-			var ik = iks[ i ];
+			return function update() {
 
 
-			var effector = bones[ ik.effector ];
+				var bones = this.mesh.skeleton.bones;
+				var iks = this.iks;
 
 
-			var links = ik.links;
+				// for reference overhead reduction in loop
+				var math = Math;
 
 
-			var link0, link1;
+				for ( var i = 0, il = iks.length; i < il; i++ ) {
 
 
-			link0 = effector;
+					var ik = iks[ i ];
+					var effector = bones[ ik.effector ];
+					var target = bones[ ik.target ];
 
 
-			for ( var j = 0, jl = links.length; j < jl; j ++ ) {
+					// don't use getWorldPosition() here for the performance
+					// because it calls updateMatrixWorld( true ) inside.
+					targetPos.setFromMatrixPosition( target.matrixWorld );
 
 
-				link1 = bones[ links[ j ].index ];
+					var links = ik.links;
+					var iteration = ik.iteration !== undefined ? ik.iteration : 1;
 
 
-				if ( link0.parent !== link1 ) {
+					for ( var j = 0; j < iteration; j++ ) {
 
 
-					console.warn( 'THREE.CCDIKSolver: bone ' + link0.name + ' is not the child of bone ' + link1.name );
+						var rotated = false;
 
 
-				}
+						for ( var k = 0, kl = links.length; k < kl; k++ ) {
 
 
-				link0 = link1;
+							var link = bones[ links[ k ].index ];
 
 
-			}
-
-		}
+							// skip this link and following links.
+							// this skip is used for MMD performance optimization.
+							if ( links[ k ].enabled === false ) break;
 
 
-	},
+							var limitation = links[ k ].limitation;
+							var rotationMin = links[ k ].rotationMin;
+							var rotationMax = links[ k ].rotationMax;
 
 
-	/*
-	 * save the bone matrices before solving IK.
-	 * they're used for generating VMD and VPD.
-	 */
-	_saveOriginalBonesInfo: function () {
+							// don't use getWorldPosition/Quaternion() here for the performance
+							// because they call updateMatrixWorld( true ) inside.
+							link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
+							invLinkQ.inverse();
+							effectorPos.setFromMatrixPosition( effector.matrixWorld );
 
 
-		var bones = this.mesh.skeleton.bones;
+							// work in link world
+							effectorVec.subVectors( effectorPos, linkPos );
+							effectorVec.applyQuaternion( invLinkQ );
+							effectorVec.normalize();
 
 
-		for ( var i = 0, il = bones.length; i < il; i ++ ) {
+							targetVec.subVectors( targetPos, linkPos );
+							targetVec.applyQuaternion( invLinkQ );
+							targetVec.normalize();
 
 
-			var bone = bones[ i ];
+							var angle = targetVec.dot( effectorVec );
 
 
-			if ( bone.userData.ik === undefined ) bone.userData.ik = {};
+							if ( angle > 1.0 ) {
 
 
-			bone.userData.ik.originalMatrix = bone.matrix.toArray();
+								angle = 1.0;
 
 
-		}
+							} else if ( angle < -1.0 ) {
 
 
-	},
+								angle = -1.0;
 
 
-	update: function ( saveOriginalBones ) {
+							}
 
 
-		var q = new THREE.Quaternion();
+							angle = math.acos( angle );
 
 
-		var targetPos = new THREE.Vector3();
-		var targetVec = new THREE.Vector3();
-		var effectorPos = new THREE.Vector3();
-		var effectorVec = new THREE.Vector3();
-		var linkPos = new THREE.Vector3();
-		var invLinkQ = new THREE.Quaternion();
-		var linkScale = new THREE.Vector3();
-		var axis = new THREE.Vector3();
+							// skip if changing angle is too small to prevent vibration of bone
+							// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
+							if ( angle < 1e-5 ) continue;
 
 
-		var bones = this.mesh.skeleton.bones;
-		var iks = this.mesh.geometry.iks;
+							if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
 
 
-		var boneParams = this.mesh.geometry.bones;
+								angle = ik.minAngle;
 
 
-		// for reference overhead reduction in loop
-		var math = Math;
+							}
 
 
-		this.mesh.updateMatrixWorld( true );
+							if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
 
 
-		if ( saveOriginalBones === true ) this._saveOriginalBonesInfo();
+								angle = ik.maxAngle;
 
 
-		for ( var i = 0, il = iks.length; i < il; i++ ) {
+							}
 
 
-			var ik = iks[ i ];
-			var effector = bones[ ik.effector ];
-			var target = bones[ ik.target ];
+							axis.crossVectors( effectorVec, targetVec );
+							axis.normalize();
 
 
-			// don't use getWorldPosition() here for the performance
-			// because it calls updateMatrixWorld( true ) inside.
-			targetPos.setFromMatrixPosition( target.matrixWorld );
+							q.setFromAxisAngle( axis, angle );
+							link.quaternion.multiply( q );
 
 
-			var links = ik.links;
-			var iteration = ik.iteration !== undefined ? ik.iteration : 1;
+							// TODO: re-consider the limitation specification
+							if ( limitation !== undefined ) {
 
 
-			for ( var j = 0; j < iteration; j++ ) {
+								var c = link.quaternion.w;
 
 
-				var rotated = false;
+								if ( c > 1.0 ) c = 1.0;
 
 
-				for ( var k = 0, kl = links.length; k < kl; k++ ) {
+								var c2 = math.sqrt( 1 - c * c );
+								link.quaternion.set( limitation.x * c2,
+								                     limitation.y * c2,
+								                     limitation.z * c2,
+								                     c );
 
 
-					var link = bones[ links[ k ].index ];
+							}
 
 
-					// skip this link and following links.
-					// this skip is used for MMD performance optimization.
-					if ( links[ k ].enabled === false ) break;
+							if ( rotationMin !== undefined ) {
 
 
-					var limitation = links[ k ].limitation;
+								link.rotation.setFromVector3(
+									link.rotation
+										.toVector3( vector )
+										.max( rotationMin ) );
 
 
-					// don't use getWorldPosition/Quaternion() here for the performance
-					// because they call updateMatrixWorld( true ) inside.
-					link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
-					invLinkQ.inverse();
-					effectorPos.setFromMatrixPosition( effector.matrixWorld );
+							}
 
 
-					// work in link world
-					effectorVec.subVectors( effectorPos, linkPos );
-					effectorVec.applyQuaternion( invLinkQ );
-					effectorVec.normalize();
+							if ( rotationMax !== undefined ) {
 
 
-					targetVec.subVectors( targetPos, linkPos );
-					targetVec.applyQuaternion( invLinkQ );
-					targetVec.normalize();
+								link.rotation.setFromVector3(
+									link.rotation
+										.toVector3( vector )
+										.min( rotationMax ) );
 
 
-					var angle = targetVec.dot( effectorVec );
+							}
 
 
-					if ( angle > 1.0 ) {
+							link.updateMatrixWorld( true );
 
 
-						angle = 1.0;
+							rotated = true;
 
 
-					} else if ( angle < -1.0 ) {
+						}
 
 
-						angle = -1.0;
+						if ( ! rotated ) break;
 
 
 					}
 					}
 
 
-					angle = math.acos( angle );
+				}
 
 
-					// skip if changing angle is too small to prevent vibration of bone
-					// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
-					if ( angle < 1e-5 ) continue;
+				return this;
 
 
-					if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
+			};
 
 
-						angle = ik.minAngle;
+		}(),
 
 
-					}
+		/**
+		 * Creates Helper
+		 *
+		 * @return {CCDIKHelper}
+		 */
+		createHelper: function () {
 
 
-					if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
+			return new CCDIKHelper( this.mesh, this.mesh.geometry.userData.MMD.iks );
 
 
-						angle = ik.maxAngle;
+		},
 
 
-					}
+		// private methods
 
 
-					axis.crossVectors( effectorVec, targetVec );
-					axis.normalize();
+		_valid: function () {
 
 
-					q.setFromAxisAngle( axis, angle );
-					link.quaternion.multiply( q );
+			var iks = this.iks;
+			var bones = this.mesh.skeleton.bones;
 
 
-					// TODO: re-consider the limitation specification
-					if ( limitation !== undefined ) {
+			for ( var i = 0, il = iks.length; i < il; i ++ ) {
 
 
-						var c = link.quaternion.w;
+				var ik = iks[ i ];
+				var effector = bones[ ik.effector ];
+				var links = ik.links;
+				var link0, link1;
 
 
-						if ( c > 1.0 ) {
+				link0 = effector;
 
 
-							c = 1.0;
+				for ( var j = 0, jl = links.length; j < jl; j ++ ) {
 
 
-						}
+					link1 = bones[ links[ j ].index ];
 
 
-						var c2 = math.sqrt( 1 - c * c );
-						link.quaternion.set( limitation.x * c2,
-						                     limitation.y * c2,
-						                     limitation.z * c2,
-						                     c );
+					if ( link0.parent !== link1 ) {
+
+						console.warn( 'THREE.CCDIKSolver: bone ' + link0.name + ' is not the child of bone ' + link1.name );
 
 
 					}
 					}
 
 
-					link.updateMatrixWorld( true );
-					rotated = true;
+					link0 = link1;
 
 
 				}
 				}
 
 
-				if ( ! rotated ) break;
-
 			}
 			}
 
 
 		}
 		}
 
 
-		// just in case
-		this.mesh.updateMatrixWorld( true );
+	};
 
 
-	}
+	/**
+	 * Visualize IK bones
+	 *
+	 * @param {SkinnedMesh} mesh
+	 * @param {Array<Object>} iks
+	 */
+	function CCDIKHelper( mesh, iks ) {
+
+		THREE.Object3D.call( this );
+
+		this.root = mesh;
+		this.iks = iks || [];
+
+		this.matrix.copy( mesh.matrixWorld );
+		this.matrixAutoUpdate = false;
 
 
-};
+		this.sphereGeometry = new THREE.SphereBufferGeometry( 0.25, 16, 8 );
 
 
+		this.targetSphereMaterial = new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0xff8888 ),
+			depthTest: false,
+			depthWrite: false,
+			transparent: true
+		} );
 
 
-THREE.CCDIKHelper = function ( mesh ) {
+		this.effectorSphereMaterial = new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0x88ff88 ),
+			depthTest: false,
+			depthWrite: false,
+			transparent: true
+		} );
 
 
-	if ( mesh.geometry.iks === undefined || mesh.skeleton === undefined ) {
+		this.linkSphereMaterial = new THREE.MeshBasicMaterial( {
+			color: new THREE.Color( 0x8888ff ),
+			depthTest: false,
+			depthWrite: false,
+			transparent: true
+		} );
 
 
-		throw 'THREE.CCDIKHelper requires iks in mesh.geometry and skeleton in mesh.';
+		this.lineMaterial = new THREE.LineBasicMaterial( {
+			color: new THREE.Color( 0xff0000 ),
+			depthTest: false,
+			depthWrite: false,
+			transparent: true
+		} );
+
+		this._init();
 
 
 	}
 	}
 
 
-	THREE.Object3D.call( this );
+	CCDIKHelper.prototype = Object.assign( Object.create( THREE.Object3D.prototype ), {
 
 
-	this.root = mesh;
+		constructor: CCDIKHelper,
 
 
-	this.matrix = mesh.matrixWorld;
-	this.matrixAutoUpdate = false;
+		/**
+		 * Updates IK bones visualization.
+		 */
+		updateMatrixWorld: function () {
 
 
-	this.sphereGeometry = new THREE.SphereBufferGeometry( 0.25, 16, 8 );
+			var matrix = new THREE.Matrix4();
+			var vector = new THREE.Vector3();
 
 
-	this.targetSphereMaterial = new THREE.MeshBasicMaterial( {
-		color: new THREE.Color( 0xff8888 ),
-		depthTest: false,
-		depthWrite: false,
-		transparent: true
-	} );
+			function getPosition( bone, matrixWorldInv ) {
 
 
-	this.effectorSphereMaterial = new THREE.MeshBasicMaterial( {
-		color: new THREE.Color( 0x88ff88 ),
-		depthTest: false,
-		depthWrite: false,
-		transparent: true
-	} );
+				return vector
+					.setFromMatrixPosition( bone.matrixWorld )
+					.applyMatrix4( matrixWorldInv );
 
 
-	this.linkSphereMaterial = new THREE.MeshBasicMaterial( {
-		color: new THREE.Color( 0x8888ff ),
-		depthTest: false,
-		depthWrite: false,
-		transparent: true
-	} );
+			}
 
 
-	this.lineMaterial = new THREE.LineBasicMaterial( {
-		color: new THREE.Color( 0xff0000 ),
-		depthTest: false,
-		depthWrite: false,
-		transparent: true
-	} );
+			function setPositionOfBoneToAttributeArray( array, index, bone, matrixWorldInv ) {
 
 
-	this._init();
-	this.update();
+				var v = getPosition( bone, matrixWorldInv );
 
 
-};
+				array[ index * 3 + 0 ] = v.x;
+				array[ index * 3 + 1 ] = v.y;
+				array[ index * 3 + 2 ] = v.z;
 
 
-THREE.CCDIKHelper.prototype = Object.create( THREE.Object3D.prototype );
-THREE.CCDIKHelper.prototype.constructor = THREE.CCDIKHelper;
+			}
 
 
-THREE.CCDIKHelper.prototype._init = function () {
+			return function updateMatrixWorld( force ) {
 
 
-	var self = this;
-	var mesh = this.root;
-	var iks = mesh.geometry.iks;
+				var mesh = this.root;
 
 
-	function createLineGeometry( ik ) {
+				if ( this.visible ) {
 
 
-		var geometry = new THREE.BufferGeometry();
-		var vertices = new Float32Array( ( 2 + ik.links.length ) * 3 );
-		geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
+					var offset = 0;
 
 
-		return geometry;
+					var iks = this.iks;
+					var bones = mesh.skeleton.bones;
 
 
-	}
+					matrix.getInverse( mesh.matrixWorld );
 
 
-	function createTargetMesh() {
+					for ( var i = 0, il = iks.length; i < il; i ++ ) {
 
 
-		return new THREE.Mesh( self.sphereGeometry, self.targetSphereMaterial );
+						var ik = iks[ i ];
 
 
-	}
+						var targetBone = bones[ ik.target ];
+						var effectorBone = bones[ ik.effector ];
 
 
-	function createEffectorMesh() {
+						var targetMesh = this.children[ offset ++ ];
+						var effectorMesh = this.children[ offset ++ ];
 
 
-		return new THREE.Mesh( self.sphereGeometry, self.effectorSphereMaterial );
+						targetMesh.position.copy( getPosition( targetBone, matrix ) );
+						effectorMesh.position.copy( getPosition( effectorBone, matrix ) );
 
 
-	}
+						for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
 
 
-	function createLinkMesh() {
+							var link = ik.links[ j ];
+							var linkBone = bones[ link.index ];
 
 
-		return new THREE.Mesh( self.sphereGeometry, self.linkSphereMaterial );
+							var linkMesh = this.children[ offset ++ ];
 
 
-	}
+							linkMesh.position.copy( getPosition( linkBone, matrix ) );
 
 
-	function createLine( ik ) {
+						}
 
 
-		return new THREE.Line( createLineGeometry( ik ), self.lineMaterial );
+						var line = this.children[ offset ++ ];
+						var array = line.geometry.attributes.position.array;
 
 
-	}
+						setPositionOfBoneToAttributeArray( array, 0, targetBone, matrix );
+						setPositionOfBoneToAttributeArray( array, 1, effectorBone, matrix );
 
 
-	for ( var i = 0, il = iks.length; i < il; i ++ ) {
+						for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
 
 
-		var ik = iks[ i ];
+							var link = ik.links[ j ];
+							var linkBone = bones[ link.index ];
+							setPositionOfBoneToAttributeArray( array, j + 2, linkBone, matrix );
 
 
-		this.add( createTargetMesh() );
-		this.add( createEffectorMesh() );
+						}
 
 
-		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+						line.geometry.attributes.position.needsUpdate = true;
 
 
-			this.add( createLinkMesh() );
+					}
 
 
-		}
+				}
 
 
-		this.add( createLine( ik ) );
+				this.matrix.copy( mesh.matrixWorld );
 
 
-	}
+				THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
 
 
-};
+			};
 
 
-THREE.CCDIKHelper.prototype.update = function () {
+		}(),
 
 
-	var offset = 0;
+		// private method
 
 
-	var mesh = this.root;
-	var iks = mesh.geometry.iks;
-	var bones = mesh.skeleton.bones;
+		_init: function () {
 
 
-	var matrixWorldInv = new THREE.Matrix4().getInverse( mesh.matrixWorld );
-	var vector = new THREE.Vector3();
+			var self = this;
+			var mesh = this.root;
+			var iks = this.iks;
 
 
-	function getPosition( bone ) {
+			function createLineGeometry( ik ) {
 
 
-		vector.setFromMatrixPosition( bone.matrixWorld );
-		vector.applyMatrix4( matrixWorldInv );
+				var geometry = new THREE.BufferGeometry();
+				var vertices = new Float32Array( ( 2 + ik.links.length ) * 3 );
+				geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
 
 
-		return vector;
+				return geometry;
 
 
-	}
+			}
 
 
-	function setPositionOfBoneToAttributeArray( array, index, bone ) {
+			function createTargetMesh() {
 
 
-		var v = getPosition( bone );
+				return new THREE.Mesh( self.sphereGeometry, self.targetSphereMaterial );
 
 
-		array[ index * 3 + 0 ] = v.x;
-		array[ index * 3 + 1 ] = v.y;
-		array[ index * 3 + 2 ] = v.z;
+			}
 
 
-	}
+			function createEffectorMesh() {
 
 
-	for ( var i = 0, il = iks.length; i < il; i ++ ) {
+				return new THREE.Mesh( self.sphereGeometry, self.effectorSphereMaterial );
 
 
-		var ik = iks[ i ];
+			}
 
 
-		var targetBone = bones[ ik.target ];
-		var effectorBone = bones[ ik.effector ];
+			function createLinkMesh() {
 
 
-		var targetMesh = this.children[ offset ++ ];
-		var effectorMesh = this.children[ offset ++ ];
+				return new THREE.Mesh( self.sphereGeometry, self.linkSphereMaterial );
 
 
-		targetMesh.position.copy( getPosition( targetBone ) );
-		effectorMesh.position.copy( getPosition( effectorBone ) );
+			}
 
 
-		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+			function createLine( ik ) {
 
 
-			var link = ik.links[ j ];
-			var linkBone = bones[ link.index ];
+				return new THREE.Line( createLineGeometry( ik ), self.lineMaterial );
 
 
-			var linkMesh = this.children[ offset ++ ];
+			}
 
 
-			linkMesh.position.copy( getPosition( linkBone ) );
+			for ( var i = 0, il = iks.length; i < il; i ++ ) {
 
 
-		}
+				var ik = iks[ i ];
 
 
-		var line = this.children[ offset ++ ];
-		var array = line.geometry.attributes.position.array;
+				this.add( createTargetMesh() );
+				this.add( createEffectorMesh() );
 
 
-		setPositionOfBoneToAttributeArray( array, 0, targetBone );
-		setPositionOfBoneToAttributeArray( array, 1, effectorBone );
+				for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
 
 
-		for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
+					this.add( createLinkMesh() );
 
 
-			var link = ik.links[ j ];
-			var linkBone = bones[ link.index ];
-			setPositionOfBoneToAttributeArray( array, j + 2, linkBone );
+				}
+
+				this.add( createLine( ik ) );
+
+			}
 
 
 		}
 		}
 
 
-		line.geometry.attributes.position.needsUpdate = true;
+	} );
 
 
-	}
+	return CCDIKSolver;
 
 
-};
+} )();

+ 1038 - 0
examples/js/animation/MMDAnimationHelper.js

@@ -0,0 +1,1038 @@
+/**
+ * @author takahiro / https://github.com/takahirox
+ *
+ * MMDAnimationHelper handles animation of MMD assets loaded by MMDLoader
+ * with MMD special features as IK, Grant, and Physics.
+ *
+ * Dependencies
+ *  - ammo.js https://github.com/kripken/ammo.js
+ *  - THREE.MMDPhysics
+ *  - THREE.CCDIKSolver
+ *
+ * TODO
+ *  - more precise grant skinning support.
+ */
+
+THREE.MMDAnimationHelper = ( function () {
+
+	/**
+	 * @param {Object} params - (optional)
+	 * @param {boolean} params.sync - Whether animation durations of added objects are synched. Default is true.
+	 * @param {Number} params.afterglow - Default is 0.0.
+	 * @param {boolean} params resetPhysicsOnLoop - Default is true.
+	 */
+	function MMDAnimationHelper( params ) {
+
+		params = params || {};
+
+		this.meshes = [];
+
+		this.camera = null;
+		this.cameraTarget = new THREE.Object3D();
+		this.cameraTarget.name = 'target';
+
+		this.audio = null;
+		this.audioManager = null;
+
+		this.objects = new WeakMap();
+
+		this.configuration = {
+			sync: params.sync !== undefined
+				? params.sync : true,
+			afterglow: params.afterglow !== undefined
+				? params.afterglow : 0.0,
+			resetPhysicsOnLoop: params.resetPhysicsOnLoop !== undefined
+				? params.resetPhysicsOnLoop : true
+		};
+
+		this.enabled = {
+			animation: true,
+			ik: true,
+			grant: true,
+			physics: true,
+			cameraAnimation: true
+		};
+
+		this.onBeforePhysics = function ( mesh ) {};
+
+		// experimental
+		this.sharedPhysics = false;
+		this.masterPhysics = null;
+
+	}
+
+	MMDAnimationHelper.prototype = {
+
+		constructor: MMDAnimationHelper,
+
+		/**
+		 * Adds an Three.js Object to helper and setups animation.
+		 * The anmation durations of added objects are synched
+		 * if this.configuration.sync is true.
+		 *
+		 * @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
+		 * @param {Object} params - (optional)
+		 * @param {THREE.AnimationClip|Array<THREE.AnimationClip>} params.animation - Only for THREE.SkinnedMesh and THREE.Camera. Default is undefined.
+		 * @param {boolean} params.physics - Only for THREE.SkinnedMesh. Default is true.
+		 * @param {Integer} params.warmup - Only for THREE.SkinnedMesh and physics is true. Default is 60.
+		 * @param {Number} params.unitStep - Only for THREE.SkinnedMesh and physics is true. Default is 1 / 65.
+		 * @param {Integer} params.maxStepNum - Only for THREE.SkinnedMesh and physics is true. Default is 3.
+		 * @param {THREE.Vector3} params.gravity - Only for THREE.SkinnedMesh and physics is true. Default ( 0, - 9.8 * 10, 0 ).
+		 * @param {Number} params.delayTime - Only for THREE.Audio. Default is 0.0.
+		 * @return {THREE.MMDAnimationHelper}
+		 */
+		add: function ( object, params ) {
+
+			params = params || {};
+
+			if ( object.isSkinnedMesh ) {
+
+				this._addMesh( object, params );
+
+			} else if ( object.isCamera ) {
+
+				this._setupCamera( object, params );
+
+			} else if ( object.type === 'Audio' ) {
+
+				this._setupAudio( object, params );
+
+			} else {
+
+				throw new Error( 'THREE.MMDAnimationHelper.add: '
+					+ 'accepts only '
+					+ 'THREE.SkinnedMesh or '
+					+ 'THREE.Camera or '
+					+ 'THREE.Audio instance.' );
+
+			}
+
+			if ( this.configuration.sync ) this._syncDuration();
+
+			return this;
+
+		},
+
+		/**
+		 * Removes an Three.js Object from helper.
+		 *
+		 * @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
+		 * @return {THREE.MMDAnimationHelper}
+		 */
+		remove: function ( object ) {
+
+			if ( object.isSkinnedMesh ) {
+
+				this._removeMesh( object );
+
+			} else if ( object.isCamera ) {
+
+				this._clearCamera( object );
+
+			} else if ( object.type === 'Audio' ) {
+
+				this._clearAudio( object );
+
+			} else {
+
+				throw new Error( 'THREE.MMDAnimationHelper.remove: '
+					+ 'accepts only '
+					+ 'THREE.SkinnedMesh or '
+					+ 'THREE.Camera or '
+					+ 'THREE.Audio instance.' );
+
+			}
+
+			if ( this.configuration.sync ) this._syncDuration();
+
+			return this;
+
+		},
+
+		/**
+		 * Updates the animation.
+		 *
+		 * @param {Number} delta
+		 * @return {THREE.MMDAnimationHelper}
+		 */
+		update: function ( delta ) {
+
+			if ( this.audioManager !== null ) this.audioManager.control( delta );
+
+			for ( var i = 0; i < this.meshes.length; i ++ ) {
+
+				this._animateMesh( this.meshes[ i ], delta );
+
+			}
+
+			if ( this.sharedPhysics ) this._updateSharedPhysics( delta );
+
+			if ( this.camera !== null ) this._animateCamera( this.camera, delta );
+
+			return this;
+
+		},
+
+		/**
+		 * Changes the pose of SkinnedMesh as VPD specifies.
+		 *
+		 * @param {THREE.SkinnedMesh} mesh
+		 * @param {Object} vpd - VPD content parsed MMDParser
+		 * @param {Object} params - (optional)
+		 * @param {boolean} params.resetPose - Default is true.
+		 * @param {boolean} params.ik - Default is true.
+		 * @param {boolean} params.grant - Default is true.
+		 * @return {THREE.MMDAnimationHelper}
+		 */
+		pose: function ( mesh, vpd, params ) {
+
+			params = params || {};
+
+			if ( params.resetPose !== false ) mesh.pose();
+
+			var bones = mesh.skeleton.bones;
+			var boneParams = vpd.bones;
+
+			var boneNameDictionary = {};
+
+			for ( var i = 0, il = bones.length; i < il; i ++ ) {
+
+				boneNameDictionary[ bones[ i ].name ] = i;
+
+			}
+
+			var vector = new THREE.Vector3();
+			var quaternion = new THREE.Quaternion();
+
+			for ( var i = 0, il = boneParams.length; i < il; i ++ ) {
+
+				var boneParam = boneParams[ i ];
+				var boneIndex = boneNameDictionary[ boneParam.name ];
+
+				if ( boneIndex === undefined ) continue;
+
+				var bone = bones[ boneIndex ];
+				bone.position.add( vector.fromArray( boneParam.translation ) );
+				bone.quaternion.multiply( quaternion.fromArray( boneParam.quaternion ) );
+
+			}
+
+			mesh.updateMatrixWorld( true );
+
+			if ( params.ik !== false ) {
+
+				this._createCCDIKSolver( mesh ).update( params.saveOriginalBonesBeforeIK );  // this param is experimental
+
+			}
+
+			if ( params.grant !== false ) {
+
+				this.createGrantSolver( mesh ).update();
+
+			}
+
+			return this;
+
+		},
+
+		/**
+		 * Enabes/Disables an animation feature.
+		 *
+		 * @param {string} key
+		 * @param {boolean} enebled
+		 * @return {THREE.MMDAnimationHelper}
+		 */
+		enable: function ( key, enabled ) {
+
+			if ( this.enabled[ key ] === undefined ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper.enable: '
+					+ 'unknown key ' + key );
+
+			}
+
+			this.enabled[ key ] = enabled;
+
+			if ( key === 'physics' ) {
+
+				for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+					this._optimizeIK( this.meshes[ i ], enabled );
+
+				}
+
+			}
+
+			return this;
+
+		},
+
+		/**
+		 * Creates an GrantSolver instance.
+		 *
+		 * @param {THREE.SkinnedMesh} mesh
+		 * @return {GrantSolver}
+		 */
+		createGrantSolver: function ( mesh ) {
+
+			return new GrantSolver( mesh, mesh.geometry.userData.MMD.grants );
+
+		},
+
+		// private methods
+
+		_addMesh: function ( mesh, params ) {
+
+			if ( this.meshes.indexOf( mesh ) >= 0 ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._addMesh: '
+					+ 'SkinnedMesh \'' + mesh.name + '\' has already been added.' );
+
+			}
+
+			this.meshes.push( mesh );
+			this.objects.set( mesh, { looped: false } );
+
+			this._setupMeshAnimation( mesh, params.animation );
+
+			if ( params.physics !== false ) {
+
+				this._setupMeshPhysics( mesh, params );
+
+			}
+
+			return this;
+
+		},
+
+		_setupCamera: function ( camera, params ) {
+
+			if ( this.camera === camera ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._setupCamera: '
+					+ 'Camera \'' + camera.name + '\' has already been set.' );
+
+			}
+
+			if ( this.camera ) this.clearCamera( this.camera );
+
+			this.camera = camera;
+
+			camera.add( this.cameraTarget );
+
+			this.objects.set( camera, {} );
+
+			if ( params.animation !== undefined ) {
+
+				this._setupCameraAnimation( camera, params.animation )
+
+			}
+
+			return this;
+
+		},
+
+		_setupAudio: function ( audio, params ) {
+
+			if ( this.audio === audio ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._setupAudio: '
+					+ 'Audio \'' + audio.name + '\' has already been set.' );
+
+			}
+
+			if ( this.audio ) this.clearAudio( this.audio );
+
+			this.audio = audio;
+			this.audioManager = new AudioManager( audio, params );
+
+			this.objects.set( this.audioManager, {
+				duration: this.audioManager.duration
+			} );
+
+			return this;
+
+		},
+
+		_removeMesh: function ( mesh ) {
+
+			var found = false;
+			var writeIndex = 0;
+
+			for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+				if ( this.meshes[ i ] === mesh ) {
+
+					this.objects.delete( mesh );
+					found = true;
+
+					continue;
+
+				}
+
+				this.meshes[ writeIndex ++ ] = this.meshes[ i ];
+
+			}
+
+			if ( ! found ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._removeMesh: '
+					+ 'SkinnedMesh \'' + mesh.name + '\' has not been added yet.' );
+
+			}
+
+			this.meshes.length = writeIndex;
+
+			return this;
+
+		},
+
+		_clearCamera: function ( camera ) {
+
+			if ( camera !== this.camera ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._clearCamera: '
+					+ 'Camera \'' + camera.name + '\' has not been set yet.' );
+
+			}
+
+			this.camera.remove( this.cameraTarget );
+
+			this.objects.delete( this.camera );
+			this.camera = null;
+
+			return this;
+
+		},
+
+		_clearAudio: function ( audio ) {
+
+			if ( audio !== this.audio ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper._clearAudio: '
+					+ 'Audio \'' + audio.name + '\' has not been set yet.' );
+
+			}
+
+			this.objects.delete( this.audioManager );
+
+			this.audio = null;
+			this.audioManager = null;
+
+			return this;
+
+		},
+
+		_setupMeshAnimation: function ( mesh, animation ) {
+
+			var objects = this.objects.get( mesh );
+
+			if ( animation !== undefined ) {
+
+				var animations = Array.isArray( animation )
+					? animation : [ animation ];
+
+				objects.mixer = new THREE.AnimationMixer( mesh );
+
+				for ( var i = 0, il = animations.length; i < il; i ++ ) {
+
+					objects.mixer.clipAction( animations[ i ] ).play();
+
+				}
+
+				// TODO: find a workaround not to access ._clip looking like a private property
+				objects.mixer.addEventListener( 'loop', function ( event ) {
+
+					var tracks = event.action._clip.tracks;
+
+					if ( tracks.length > 0 &&
+					     tracks[ 0 ].name.slice( 0, 6 ) !== '.bones' ) return;
+
+					objects.looped = true;
+
+				} );
+
+			}
+
+			objects.ikSolver = this._createCCDIKSolver( mesh );
+			objects.grantSolver = this.createGrantSolver( mesh );
+
+			return this;
+
+		},
+
+		_setupCameraAnimation: function ( camera, animation ) {
+
+			var animations = Array.isArray( animation )
+				? animation : [ animation ];
+
+			var objects = this.objects.get( camera );
+
+			objects.mixer = new THREE.AnimationMixer( camera );
+
+			for ( var i = 0, il = animations.length; i < il; i ++ ) {
+
+				objects.mixer.clipAction( animations[ i ] ).play();
+
+			}
+
+		},
+
+		_setupMeshPhysics: function ( mesh, params ) {
+
+			var objects = this.objects.get( mesh );
+
+			// shared physics is experimental
+
+			if ( params.world === undefined && this.sharedPhysics ) {
+
+				var masterPhysics = this._getMasterPhysics();
+
+				if ( masterPhysics !== null ) world = masterPhysics.world;
+
+			}
+
+			objects.physics = this._createMMDPhysics( mesh, params );
+
+			if ( objects.mixer && params.animationWarmup !== false ) {
+
+				this._animateMesh( mesh, 0 );
+				objects.physics.reset();
+
+			}
+
+			objects.physics.warmup( params.warmup !== undefined ? params.warmup : 60 );
+
+			this._optimizeIK( mesh, true );
+
+		},
+
+		_animateMesh: function ( mesh, delta ) {
+
+			var objects = this.objects.get( mesh );
+
+			var mixer = objects.mixer;
+			var ikSolver = objects.ikSolver;
+			var grantSolver = objects.grantSolver;
+			var physics = objects.physics;
+			var looped = objects.looped;
+
+			// alternate solution to save/restore bones but less performant?
+			//mesh.pose();
+			//this._updatePropertyMixersBuffer( mesh );
+
+			if ( mixer && this.enabled.animation ) {
+
+				this._restoreBones( mesh );
+
+				mixer.update( delta );
+
+				this._saveBones( mesh );
+
+				if ( ikSolver && this.enabled.ik ) {
+
+					mesh.updateMatrixWorld( true );
+					ikSolver.update();
+
+				}
+
+				if ( grantSolver && this.enabled.grant ) {
+
+					grantSolver.update();
+
+				}
+
+			}
+
+			if ( looped === true && this.enabled.physics ) {
+
+				if ( physics && this.configuration.resetPhysicsOnLoop ) physics.reset();
+
+				objects.looped = false;
+
+			}
+
+			if ( physics && this.enabled.physics && ! this.sharedPhysics ) {
+
+				this.onBeforePhysics( mesh );
+				physics.update( delta );
+
+			}
+
+		},
+
+		_animateCamera: function ( camera, delta ) {
+
+			var mixer = this.objects.get( camera ).mixer;
+
+			if ( mixer && this.enabled.cameraAnimation ) {
+
+				mixer.update( delta );
+
+				camera.updateProjectionMatrix();
+
+				camera.up.set( 0, 1, 0 );
+				camera.up.applyQuaternion( camera.quaternion );
+				camera.lookAt( this.cameraTarget.position );
+
+			}
+
+		},
+
+		_optimizeIK: function ( mesh, physicsEnabled ) {
+
+			var iks = mesh.geometry.userData.MMD.iks;
+			var bones = mesh.geometry.userData.MMD.bones;
+
+			for ( var i = 0, il = iks.length; i < il; i ++ ) {
+
+				var ik = iks[ i ];
+				var links = ik.links;
+
+				for ( var j = 0, jl = links.length; j < jl; j ++ ) {
+
+					var link = links[ j ];
+
+					if ( physicsEnabled === true ) {
+
+						// disable IK of the bone the corresponding rigidBody type of which is 1 or 2
+						// because its rotation will be overriden by physics
+						link.enabled = bones[ link.index ].rigidBodyType > 0 ? false : true;
+
+					} else {
+
+						link.enabled = true;
+
+					}
+
+				}
+
+			}
+
+		},
+
+		_createCCDIKSolver: function ( mesh ) {
+
+			if ( THREE.CCDIKSolver === undefined ) {
+
+				throw new Error( 'THREE.MMDAnimationHelper: Import THREE.CCDIKSolver.' );
+
+			}
+
+			return new THREE.CCDIKSolver( mesh, mesh.geometry.userData.MMD.iks );
+
+		},
+
+		_createMMDPhysics: function ( mesh, params ) {
+
+			if ( THREE.MMDPhysics === undefined ) {
+
+				throw new Error( 'THREE.MMDPhysics: Import THREE.MMDPhysics.' );
+
+			}
+
+			return new THREE.MMDPhysics(
+				mesh,
+				mesh.geometry.userData.MMD.rigidBodies,
+				mesh.geometry.userData.MMD.constraints,
+				params );
+
+		},
+
+		/*
+		 * Detects the longest duration and then sets it to them to sync.
+		 * TODO: Not to access private properties ( ._actions and ._clip )
+		 */
+		_syncDuration: function () {
+
+			var max = 0.0;
+
+			var objects = this.objects;
+			var meshes = this.meshes;
+			var camera = this.camera;
+			var audioManager = this.audioManager;
+
+			// get the longest duration
+
+			for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+
+				var mixer = this.objects.get( meshes[ i ] ).mixer;
+
+				if ( mixer === undefined ) continue;
+
+				for ( var j = 0; j < mixer._actions.length; j ++ ) {
+
+					var clip = mixer._actions[ j ]._clip;
+
+					if ( ! objects.has( clip ) ) {
+
+						objects.set( clip, {
+							duration: clip.duration
+						} )
+
+					}
+
+					max = Math.max( max, objects.get( clip ).duration );
+
+				}
+
+			}
+
+			if ( camera !== null ) {
+
+				var mixer = this.objects.get( camera ).mixer;
+
+				if ( mixer !== undefined ) {
+
+					for ( var i = 0, il = mixer._actions.length; i < il; i ++ ) {
+
+						var clip = mixer._actions[ i ]._clip;
+
+						if ( ! objects.has( clip ) ) {
+
+							objects.set( clip, {
+								duration: clip.duration
+							} )
+
+						}
+
+						max = Math.max( max, objects.get( clip ).duration );
+
+					}
+
+				}
+
+			}
+
+			if ( audioManager !== null ) {
+
+				max = Math.max( max, objects.get( audioManager ).duration );
+
+			}
+
+			max += this.configuration.afterglow;
+
+			// update the duration
+
+			for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+				var mixer = this.objects.get( this.meshes[ i ] ).mixer;
+
+				if ( mixer === undefined ) continue;
+
+				for ( var j = 0, jl = mixer._actions.length; j < jl; j ++ ) {
+
+					mixer._actions[ j ]._clip.duration = max;
+
+				}
+
+			}
+
+			if ( camera !== null ) {
+
+				var mixer = this.objects.get( camera ).mixer;
+
+				if ( mixer !== undefined ) {
+
+					for ( var i = 0, il = mixer._actions.length; i < il; i ++ ) {
+
+						mixer._actions[ i ]._clip.duration = max;
+
+					}
+
+				}
+
+			}
+
+			if ( audioManager !== null ) {
+
+				audioManager.duration = max;
+
+			}
+
+		},
+
+		// workaround
+
+		_updatePropertyMixersBuffer: function ( mesh ) {
+
+			var mixer = this.objects.get( mesh ).mixer;
+
+			var propertyMixers = mixer._bindings;
+			var accuIndex = mixer._accuIndex;
+
+			for ( var i = 0, il = propertyMixers.length; i < il; i ++ ) {
+
+				var propertyMixer = propertyMixers[ i ];
+				var buffer = propertyMixer.buffer;
+				var stride = propertyMixer.valueSize;
+				var offset = ( accuIndex + 1 ) * stride;
+
+				propertyMixer.binding.getValue( buffer, offset );
+
+			}
+
+		},
+
+		/*
+		 * Avoiding these two issues by restore/save bones before/after mixer animation.
+		 *
+		 * 1. PropertyMixer used by AnimationMixer holds cache value in .buffer.
+		 *    Calculating IK, Grant, and Physics after mixer animation can break
+		 *    the cache coherency.
+		 *
+		 * 2. Applying Grant two or more times without reset the posing breaks model.
+		 */
+		_saveBones: function ( mesh ) {
+
+			var objects = this.objects.get( mesh );
+
+			var bones = mesh.skeleton.bones;
+
+			var backupBones = objects.backupBones;
+
+			if ( backupBones === undefined ) {
+
+				backupBones = new Float32Array( bones.length * 7 );
+				objects.backupBones = backupBones;
+
+			}
+
+			for ( var i = 0, il = bones.length; i < il; i ++ ) {
+
+				var bone = bones[ i ];
+				bone.position.toArray( backupBones, i * 7 );
+				bone.quaternion.toArray( backupBones, i * 7 + 3 );
+
+			}
+
+		},
+
+		_restoreBones: function ( mesh ) {
+
+			var objects = this.objects.get( mesh );
+
+			var backupBones = objects.backupBones;
+
+			if ( backupBones === undefined ) return;
+
+			var bones = mesh.skeleton.bones;
+
+			for ( var i = 0, il = bones.length; i < il; i ++ ) {
+
+				var bone = bones[ i ];
+				bone.position.fromArray( backupBones, i * 7 );
+				bone.quaternion.fromArray( backupBones, i * 7 + 3 );
+
+			}
+
+		},
+
+		// experimental
+
+		_getMasterPhysics: function () {
+
+			if ( this.masterPhysics !== null ) return this.masterPhysics;
+
+			for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+				var physics = this.meshes[ i ].physics;
+
+				if ( physics !== undefined && physics !== null ) {
+
+					this.masterPhysics = physics;
+					return this.masterPhysics;
+
+				}
+
+			}
+
+			return null;
+
+		},
+
+		_updateSharedPhysics: function ( delta ) {
+
+			if ( this.meshes.length === 0 || ! this.enabled.physics || ! this.sharedPhysics ) return;
+
+			var physics = this._getMasterPhysics();
+
+			if ( physics === null ) return;
+
+			for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+				var p = this.meshes[ i ].physics;
+
+				if ( p !== null && p !== undefined ) {
+
+					p.updateRigidBodies();
+
+				}
+
+			}
+
+			physics.stepSimulation( delta );
+
+			for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+
+				var p = this.meshes[ i ].physics;
+
+				if ( p !== null && p !== undefined ) {
+
+					p.updateBones();
+
+				}
+
+			}
+
+		}
+
+	};
+
+	//
+
+	/**
+	 * @param {THREE.Audio} audio
+	 * @param {Object} params - (optional)
+	 * @param {Nuumber} params.delayTime
+	 */
+	function AudioManager( audio, params ) {
+
+		params = params || {};
+
+		this.audio = audio;
+
+		this.elapsedTime = 0.0;
+		this.currentTime = 0.0;
+		this.delayTime = params.delayTime !== undefined
+			? params.delayTime : 0.0;
+
+		this.audioDuration = this.audio.buffer.duration;
+		this.duration = this.audioDuration + this.delayTime;
+
+	}
+
+	AudioManager.prototype = {
+
+		constructor: AudioManager,
+
+		/**
+		 * @param {Number} delta
+		 * @return {AudioManager}
+		 */
+		control: function ( delta ) {
+
+			this.elapsed += delta;
+			this.currentTime += delta;
+
+			if ( this._shouldStopAudio() ) this.audio.stop();
+			if ( this._shouldStartAudio() ) this.audio.play();
+
+			return this;
+
+		},
+
+		// private methods
+
+		_shouldStartAudio: function () {
+
+			if ( this.audio.isPlaying ) return false;
+
+			while ( this.currentTime >= this.duration ) {
+
+				this.currentTime -= this.duration;
+
+			}
+
+			if ( this.currentTime < this.delayTime ) return false;
+
+			this.audio.startTime = this.currentTime - this.delayTime;
+
+			return true;
+
+		},
+
+		_shouldStopAudio: function () {
+
+			return this.audio.isPlaying &&
+				this.currentTime >= this.duration;
+
+		}
+
+	};
+
+	/**
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {Array<Object>} grants
+	 */
+	function GrantSolver( mesh, grants ) {
+
+		this.mesh = mesh;
+		this.grants = grants || [];
+
+	}
+
+	GrantSolver.prototype = {
+
+		constructor: GrantSolver,
+
+		/**
+		 * @return {GrantSolver}
+		 */
+		update: function () {
+
+			var quaternion = new THREE.Quaternion();
+
+			return function () {
+
+				var bones = this.mesh.skeleton.bones;
+				var grants = this.grants;
+
+				for ( var i = 0, il = grants.length; i < il; i ++ ) {
+
+					var grant = grants[ i ];
+					var bone = bones[ grant.index ];
+					var parentBone = bones[ grant.parentIndex ];
+
+					if ( grant.isLocal ) {
+
+						// TODO: implement
+						if ( grant.affectPosition ) {
+
+						}
+
+						// TODO: implement
+						if ( grant.affectRotation ) {
+
+						}
+
+					} else {
+
+						// TODO: implement
+						if ( grant.affectPosition ) {
+
+						}
+
+						if ( grant.affectRotation ) {
+
+							quaternion.set( 0, 0, 0, 1 );
+							quaternion.slerp( parentBone.quaternion, grant.ratio );
+							bone.quaternion.multiply( quaternion );
+
+						}
+
+					}
+
+				}
+
+				return this;
+
+			};
+
+		}()
+
+	};
+
+	return MMDAnimationHelper;
+
+} )();

+ 964 - 774
examples/js/animation/MMDPhysics.js

@@ -4,1214 +4,1404 @@
  * Dependencies
  * Dependencies
  *  - Ammo.js https://github.com/kripken/ammo.js
  *  - Ammo.js https://github.com/kripken/ammo.js
  *
  *
- * MMD specific Physics class.
- *
- * See THREE.MMDLoader for the passed parameter list of RigidBody/Constraint.
- *
- * Requirement:
- *  - don't change object's scale from (1,1,1) after setting physics to object
+ * MMDPhysics calculates physics with Ammo(Bullet based JavaScript Physics engine)
+ * for MMD model loaded by THREE.MMDLoader.
  *
  *
  * TODO
  * TODO
- *  - optimize for the performance
- *  - use Physijs http://chandlerprall.github.io/Physijs/
- *    and improve the performance by making use of Web worker.
- *  - if possible, make this class being non-MMD specific.
- *  - object scale change support
+ *  - Physics in Worker
  */
  */
 
 
-THREE.MMDPhysics = function ( mesh, params ) {
+THREE.MMDPhysics = ( function () {
 
 
-	if ( params === undefined ) params = {};
+	/**
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {Array<Object>} rigidBodyParams
+	 * @param {Array<Object>} (optional) constraintParams
+	 * @param {Object} params - (optional)
+	 * @param {Number} params.unitStep - Default is 1 / 65.
+	 * @param {Integer} params.maxStepNum - Default is 3.
+	 * @param {THREE.Vector3} params.gravity - Default is ( 0, - 9.8 * 10, 0 )
+	 */
+	function MMDPhysics( mesh, rigidBodyParams, constraintParams, params ) {
 
 
-	this.mesh = mesh;
-	this.helper = new THREE.MMDPhysics.ResourceHelper();
+		if ( typeof Ammo === 'undefined' ) {
 
 
-	/*
-	 * I don't know why but 1/60 unitStep easily breaks models
-	 * so I set it 1/65 so far.
-	 * Don't set too small unitStep because
-	 * the smaller unitStep can make the performance worse.
-	 */
-	this.unitStep = ( params.unitStep !== undefined ) ? params.unitStep : 1 / 65;
-	this.maxStepNum = ( params.maxStepNum !== undefined ) ? params.maxStepNum : 3;
+			throw new Error( 'THREE.MMDPhysics: Import ammo.js https://github.com/kripken/ammo.js' );
 
 
-	this.world = params.world !== undefined ? params.world : null;
-	this.bodies = [];
-	this.constraints = [];
+		}
 
 
-	this.init( mesh );
+		constraintParams = constraintParams || [];
+		params = params || {};
 
 
-};
+		this.manager = new ResourceManager();
 
 
-THREE.MMDPhysics.prototype = {
+		this.mesh = mesh;
 
 
-	constructor: THREE.MMDPhysics,
+		/*
+		 * I don't know why but 1/60 unitStep easily breaks models
+		 * so I set it 1/65 so far.
+		 * Don't set too small unitStep because
+		 * the smaller unitStep can make the performance worse.
+		 */
+		this.unitStep = ( params.unitStep !== undefined ) ? params.unitStep : 1 / 65;
+		this.maxStepNum = ( params.maxStepNum !== undefined ) ? params.maxStepNum : 3;
+		this.gravity = new THREE.Vector3( 0, - 9.8 * 10, 0 );
 
 
-	init: function ( mesh ) {
+		if ( params.gravity !== undefined ) this.gravity.copy( gravity );
 
 
-		var parent = mesh.parent;
+		this.world = params.world !== undefined ? params.world : null; // experimental
 
 
-		if ( parent !== null ) {
+		this.bodies = [];
+		this.constraints = [];
 
 
-			parent.remove( mesh );
+		this._init( mesh, rigidBodyParams, constraintParams );
 
 
-		}
+	}
 
 
-		var helper = this.helper;
-		var currentPosition = helper.allocThreeVector3();
-		var currentRotation = helper.allocThreeEuler();
-		var currentScale = helper.allocThreeVector3();
+	MMDPhysics.prototype = {
 
 
-		currentPosition.copy( mesh.position );
-		currentRotation.copy( mesh.rotation );
-		currentScale.copy( mesh.scale );
+		constructor: MMDPhysics,
 
 
-		mesh.position.set( 0, 0, 0 );
-		mesh.rotation.set( 0, 0, 0 );
-		mesh.scale.set( 1, 1, 1 );
+		/**
+		 * Advances Physics calculation and updates bones.
+		 *
+		 * @param {Number} delta - time in second
+		 * @return {THREE.MMDPhysics}
+		 */
+		update: function ( delta ) {
 
 
-		mesh.updateMatrixWorld( true );
+			var manager = this.manager;
+			var mesh = this.mesh;
 
 
-		if ( this.world === null ) this.initWorld();
-		this.initRigidBodies();
-		this.initConstraints();
+			// rigid bodies and constrains are for
+			// mesh's world scale (1, 1, 1).
+			// Convert to (1, 1, 1) if it isn't.
 
 
-		if ( parent !== null ) {
+			var isNonDefaultScale = false;
 
 
-			parent.add( mesh );
+			var position = manager.allocThreeVector3();
+			var quaternion = manager.allocThreeQuaternion();
+			var scale = manager.allocThreeVector3();
 
 
-		}
+			mesh.matrixWorld.decompose( position, quaternion, scale );
 
 
-		mesh.position.copy( currentPosition );
-		mesh.rotation.copy( currentRotation );
-		mesh.scale.copy( currentScale );
+			if ( scale.x !== 1 || scale.y !== 1 || scale.z !== 1 ) {
 
 
-		mesh.updateMatrixWorld( true );
+				isNonDefaultScale = true;
 
 
-		this.reset();
+			}
 
 
-		helper.freeThreeVector3( currentPosition );
-		helper.freeThreeEuler( currentRotation );
-		helper.freeThreeVector3( currentScale );
+			var parent;
 
 
-	},
+			if ( isNonDefaultScale ) {
 
 
-	initWorld: function () {
+				parent = mesh.parent;
 
 
-		var config = new Ammo.btDefaultCollisionConfiguration();
-		var dispatcher = new Ammo.btCollisionDispatcher( config );
-		var cache = new Ammo.btDbvtBroadphase();
-		var solver = new Ammo.btSequentialImpulseConstraintSolver();
-		var world = new Ammo.btDiscreteDynamicsWorld( dispatcher, cache, solver, config );
-		world.setGravity( new Ammo.btVector3( 0, -9.8 * 10, 0 ) );
-		this.world = world;
+				if ( parent !== null ) mesh.parent = null;
 
 
-	},
+				scale.copy( this.mesh.scale );
 
 
-	initRigidBodies: function () {
+				mesh.scale.set( 1, 1, 1 );
+				mesh.updateMatrixWorld( true );
 
 
-		var bodies = this.mesh.geometry.rigidBodies;
+			}
 
 
-		for ( var i = 0; i < bodies.length; i++ ) {
+			// calculate physics and update bones
 
 
-			var b = new THREE.MMDPhysics.RigidBody( this.mesh, this.world, bodies[ i ], this.helper );
-			this.bodies.push( b );
+			this._updateRigidBodies();
+			this._stepSimulation( delta );
+			this._updateBones();
 
 
-		}
+			// restore mesh if converted above
 
 
-	},
+			if ( isNonDefaultScale ) {
 
 
-	initConstraints: function () {
+				if ( parent !== null ) parent.parent = parent;
 
 
-		var constraints = this.mesh.geometry.constraints;
+				mesh.scale.copy( scale );
 
 
-		for ( var i = 0; i < constraints.length; i++ ) {
+			}
 
 
-			var params = constraints[ i ];
-			var bodyA = this.bodies[ params.rigidBodyIndex1 ];
-			var bodyB = this.bodies[ params.rigidBodyIndex2 ];
-			var c = new THREE.MMDPhysics.Constraint( this.mesh, this.world, bodyA, bodyB, params, this.helper );
-			this.constraints.push( c );
+			manager.freeThreeVector3( scale );
+			manager.freeThreeQuaternion( quaternion );
+			manager.freeThreeVector3( position );
 
 
-		}
+			return this;
 
 
+		},
 
 
-	},
+		/**
+		 * Resets rigid bodies transorm to current bone's.
+		 *
+		 * @return {THREE.MMDPhysics}
+		 */
+		reset: function () {
 
 
-	update: function ( delta ) {
+			for ( var i = 0, il = this.bodies.length; i < il; i++ ) {
 
 
-		this.updateRigidBodies();
-		this.stepSimulation( delta );
-		this.updateBones();
+				this.bodies[ i ].reset();
 
 
-	},
+			}
 
 
-	stepSimulation: function ( delta ) {
+			return this;
 
 
-		var unitStep = this.unitStep;
-		var stepTime = delta;
-		var maxStepNum = ( ( delta / unitStep ) | 0 ) + 1;
+		},
 
 
-		if ( stepTime < unitStep ) {
+		/**
+		 * Warm ups Rigid bodies. Calculates cycles steps.
+		 *
+		 * @param {Integer} cycles
+		 * @return {THREE.MMDPhysics}
+		 */
+		warmup: function ( cycles ) {
 
 
-			stepTime = unitStep;
-			maxStepNum = 1;
+			for ( var i = 0; i < cycles; i++ ) {
 
 
-		}
+				this.update( 1 / 60 );
 
 
-		if ( maxStepNum > this.maxStepNum ) {
+			}
 
 
-			maxStepNum = this.maxStepNum;
+			return this;
 
 
-		}
+		},
 
 
-		this.world.stepSimulation( stepTime, maxStepNum, unitStep );
+		/**
+		 * Sets gravity.
+		 *
+		 * @param {THREE.Vector3} gravity
+		 * @return {MMDPhysicsHelper}
+		 */
+		setGravity: function ( gravity ) {
 
 
-	},
+			this.world.setGravity( new Ammo.btVector3( gravity.x, gravity.y, gravity.z ) );
+			this.gravity.copy( gravity );
 
 
-	updateRigidBodies: function () {
+			return this;
 
 
-		for ( var i = 0; i < this.bodies.length; i++ ) {
+		},
 
 
-			this.bodies[ i ].updateFromBone();
+		/**
+		 * Creates MMDPhysicsHelper
+		 *
+		 * @return {MMDPhysicsHelper}
+		 */
+		createHelper: function () {
 
 
-		}
+			return new MMDPhysicsHelper( this.mesh, this );
 
 
-	},
+		},
 
 
-	updateBones: function () {
+		// private methods
 
 
-		for ( var i = 0; i < this.bodies.length; i++ ) {
+		_init: function ( mesh, rigidBodyParams, constraintParams ) {
 
 
-			this.bodies[ i ].updateBone();
+			var manager = this.manager;
 
 
-		}
+			// rigid body/constraint parameters are for
+			// mesh's default world transform as position(0, 0, 0),
+			// quaternion(0, 0, 0, 1) and scale(0, 0, 0)
 
 
-	},
+			var parent = mesh.parent;
 
 
-	reset: function () {
+			if ( parent !== null ) parent = null;
 
 
-		for ( var i = 0; i < this.bodies.length; i++ ) {
+			var currentPosition = manager.allocThreeVector3();
+			var currentQuaternion = manager.allocThreeQuaternion();
+			var currentScale = manager.allocThreeVector3();
 
 
-			this.bodies[ i ].reset();
+			currentPosition.copy( mesh.position );
+			currentQuaternion.copy( mesh.quaternion );
+			currentScale.copy( mesh.scale );
 
 
-		}
+			mesh.position.set( 0, 0, 0 );
+			mesh.quaternion.set( 0, 0, 0, 1 );
+			mesh.scale.set( 1, 1, 1 );
 
 
-	},
+			mesh.updateMatrixWorld( true );
 
 
-	warmup: function ( cycles ) {
+			if ( this.world === null ) {
 
 
-		for ( var i = 0; i < cycles; i++ ) {
+				this.world = this._createWorld();
+				this.setGravity( this.gravity );
 
 
-			this.update( 1 / 60 );
+			}
 
 
-		}
+			this._initRigidBodies( rigidBodyParams );
+			this._initConstraints( constraintParams );
 
 
-	}
+			if ( parent !== null ) mesh.parent = parent;
 
 
-};
+			mesh.position.copy( currentPosition );
+			mesh.quaternion.copy( currentQuaternion );
+			mesh.scale.copy( currentScale );
 
 
-/**
- * This helper class responsibilies are
- *
- * 1. manage Ammo.js and Three.js object resources and
- *    improve the performance and the memory consumption by
- *    reusing objects.
- *
- * 2. provide simple Ammo object operations.
- */
-THREE.MMDPhysics.ResourceHelper = function () {
+			mesh.updateMatrixWorld( true );
 
 
-	// for Three.js
-	this.threeVector3s = [];
-	this.threeMatrix4s = [];
-	this.threeQuaternions = [];
-	this.threeEulers = [];
+			this.reset();
 
 
-	// for Ammo.js
-	this.transforms = [];
-	this.quaternions = [];
-	this.vector3s = [];
+			manager.freeThreeVector3( currentPosition );
+			manager.freeThreeQuaternion( currentQuaternion );
+			manager.freeThreeVector3( currentScale );
 
 
-};
+		},
 
 
-THREE.MMDPhysics.ResourceHelper.prototype = {
+		_createWorld: function () {
 
 
-	allocThreeVector3: function () {
+			var config = new Ammo.btDefaultCollisionConfiguration();
+			var dispatcher = new Ammo.btCollisionDispatcher( config );
+			var cache = new Ammo.btDbvtBroadphase();
+			var solver = new Ammo.btSequentialImpulseConstraintSolver();
+			var world = new Ammo.btDiscreteDynamicsWorld( dispatcher, cache, solver, config );
+			return world;
 
 
-		return ( this.threeVector3s.length > 0 ) ? this.threeVector3s.pop() : new THREE.Vector3();
+		},
 
 
-	},
+		_initRigidBodies: function ( rigidBodies ) {
 
 
-	freeThreeVector3: function ( v ) {
+			for ( var i = 0, il = rigidBodies.length; i < il; i++ ) {
 
 
-		this.threeVector3s.push( v );
+				this.bodies.push( new RigidBody(
+					this.mesh, this.world, rigidBodies[ i ], this.manager ) );
 
 
-	},
+			}
 
 
-	allocThreeMatrix4: function () {
+		},
 
 
-		return ( this.threeMatrix4s.length > 0 ) ? this.threeMatrix4s.pop() : new THREE.Matrix4();
+		_initConstraints: function ( constraints ) {
 
 
-	},
+			for ( var i = 0, il = constraints.length; i < il; i++ ) {
 
 
-	freeThreeMatrix4: function ( m ) {
+				var params = constraints[ i ];
+				var bodyA = this.bodies[ params.rigidBodyIndex1 ];
+				var bodyB = this.bodies[ params.rigidBodyIndex2 ];
+				this.constraints.push( new Constraint(
+					this.mesh, this.world, bodyA, bodyB, params, this.manager ) );
 
 
-		this.threeMatrix4s.push( m );
+			}
 
 
-	},
 
 
-	allocThreeQuaternion: function () {
+		},
 
 
-		return ( this.threeQuaternions.length > 0 ) ? this.threeQuaternions.pop() : new THREE.Quaternion();
+		_stepSimulation: function ( delta ) {
 
 
-	},
+			var unitStep = this.unitStep;
+			var stepTime = delta;
+			var maxStepNum = ( ( delta / unitStep ) | 0 ) + 1;
 
 
-	freeThreeQuaternion: function ( q ) {
+			if ( stepTime < unitStep ) {
 
 
-		this.threeQuaternions.push( q );
+				stepTime = unitStep;
+				maxStepNum = 1;
 
 
-	},
+			}
 
 
-	allocThreeEuler: function () {
+			if ( maxStepNum > this.maxStepNum ) {
 
 
-		return ( this.threeEulers.length > 0 ) ? this.threeEulers.pop() : new THREE.Euler();
+				maxStepNum = this.maxStepNum;
 
 
-	},
+			}
 
 
-	freeThreeEuler: function ( e ) {
+			this.world.stepSimulation( stepTime, maxStepNum, unitStep );
 
 
-		this.threeEulers.push( e );
+		},
 
 
-	},
+		_updateRigidBodies: function () {
 
 
-	allocTransform: function () {
+			for ( var i = 0, il = this.bodies.length; i < il; i++ ) {
 
 
-		return ( this.transforms.length > 0 ) ? this.transforms.pop() : new Ammo.btTransform();
+				this.bodies[ i ].updateFromBone();
 
 
-	},
+			}
 
 
-	freeTransform: function ( t ) {
+		},
 
 
-		this.transforms.push( t );
+		_updateBones: function () {
 
 
-	},
+			for ( var i = 0, il = this.bodies.length; i < il; i++ ) {
 
 
-	allocQuaternion: function () {
+				this.bodies[ i ].updateBone();
 
 
-		return ( this.quaternions.length > 0 ) ? this.quaternions.pop() : new Ammo.btQuaternion();
+			}
 
 
-	},
+		}
 
 
-	freeQuaternion: function ( q ) {
+	};
 
 
-		this.quaternions.push( q );
+	/**
+	 * This manager's responsibilies are
+	 *
+	 * 1. manage Ammo.js and Three.js object resources and
+	 *    improve the performance and the memory consumption by
+	 *    reusing objects.
+	 *
+	 * 2. provide simple Ammo object operations.
+	 */
+	function ResourceManager() {
 
 
-	},
+		// for Three.js
+		this.threeVector3s = [];
+		this.threeMatrix4s = [];
+		this.threeQuaternions = [];
+		this.threeEulers = [];
 
 
-	allocVector3: function () {
+		// for Ammo.js
+		this.transforms = [];
+		this.quaternions = [];
+		this.vector3s = [];
 
 
-		return ( this.vector3s.length > 0 ) ? this.vector3s.pop() : new Ammo.btVector3();
+	}
 
 
-	},
+	ResourceManager.prototype = {
 
 
-	freeVector3: function ( v ) {
+		constructor: ResourceManager,
 
 
-		this.vector3s.push( v );
+		allocThreeVector3: function () {
 
 
-	},
+			return ( this.threeVector3s.length > 0 )
+				? this.threeVector3s.pop()
+				: new THREE.Vector3();
 
 
-	setIdentity: function ( t ) {
+		},
 
 
-		t.setIdentity();
+		freeThreeVector3: function ( v ) {
 
 
-	},
+			this.threeVector3s.push( v );
 
 
-	getBasis: function ( t ) {
+		},
 
 
-		var q = this.allocQuaternion();
-		t.getBasis().getRotation( q );
-		return q;
+		allocThreeMatrix4: function () {
 
 
-	},
+			return ( this.threeMatrix4s.length > 0 )
+				? this.threeMatrix4s.pop()
+				: new THREE.Matrix4();
 
 
-	getBasisAsMatrix3: function ( t ) {
+		},
 
 
-		var q = this.getBasis( t );
-		var m = this.quaternionToMatrix3( q );
-		this.freeQuaternion( q );
-		return m;
+		freeThreeMatrix4: function ( m ) {
 
 
-	},
+			this.threeMatrix4s.push( m );
 
 
-	getOrigin: function( t ) {
+		},
 
 
-		return t.getOrigin();
+		allocThreeQuaternion: function () {
 
 
-	},
+			return ( this.threeQuaternions.length > 0 )
+				? this.threeQuaternions.pop()
+				: new THREE.Quaternion();
 
 
-	setOrigin: function( t, v ) {
+		},
 
 
-		t.getOrigin().setValue( v.x(), v.y(), v.z() );
+		freeThreeQuaternion: function ( q ) {
 
 
-	},
+			this.threeQuaternions.push( q );
 
 
-	copyOrigin: function( t1, t2 ) {
+		},
 
 
-		var o = t2.getOrigin();
-		this.setOrigin( t1, o );
+		allocThreeEuler: function () {
 
 
-	},
+			return ( this.threeEulers.length > 0 )
+				? this.threeEulers.pop()
+				: new THREE.Euler();
 
 
-	setBasis: function( t, q ) {
+		},
 
 
-		t.setRotation( q );
+		freeThreeEuler: function ( e ) {
 
 
-	},
+			this.threeEulers.push( e );
 
 
-	setBasisFromMatrix3: function( t, m ) {
+		},
 
 
-		var q = this.matrix3ToQuaternion( m );
-		this.setBasis( t, q );
-		this.freeQuaternion( q );
+		allocTransform: function () {
 
 
-	},
+			return ( this.transforms.length > 0 )
+				? this.transforms.pop()
+				: new Ammo.btTransform();
 
 
-	setOriginFromArray3: function ( t, a ) {
+		},
 
 
-		t.getOrigin().setValue( a[ 0 ], a[ 1 ], a[ 2 ] );
+		freeTransform: function ( t ) {
 
 
-	},
+			this.transforms.push( t );
 
 
-	setOriginFromThreeVector3: function ( t, v ) {
+		},
 
 
-		t.getOrigin().setValue( v.x, v.y, v.z );
+		allocQuaternion: function () {
 
 
-	},
+			return ( this.quaternions.length > 0 )
+				? this.quaternions.pop()
+				: new Ammo.btQuaternion();
 
 
-	setBasisFromArray3: function ( t, a ) {
+		},
 
 
-		var thQ = this.allocThreeQuaternion();
-		var thE = this.allocThreeEuler();
-		thE.set( a[ 0 ], a[ 1 ], a[ 2 ] );
-		this.setBasisFromThreeQuaternion( t, thQ.setFromEuler( thE ) );
+		freeQuaternion: function ( q ) {
 
 
-		this.freeThreeEuler( thE );
-		this.freeThreeQuaternion( thQ );
+			this.quaternions.push( q );
 
 
-	},
+		},
 
 
-	setBasisFromThreeQuaternion: function ( t, a ) {
+		allocVector3: function () {
 
 
-		var q = this.allocQuaternion();
+			return ( this.vector3s.length > 0 )
+				? this.vector3s.pop()
+				: new Ammo.btVector3();
 
 
-		q.setX( a.x );
-		q.setY( a.y );
-		q.setZ( a.z );
-		q.setW( a.w );
-		this.setBasis( t, q );
+		},
 
 
-		this.freeQuaternion( q );
+		freeVector3: function ( v ) {
 
 
-	},
+			this.vector3s.push( v );
 
 
-	multiplyTransforms: function ( t1, t2 ) {
+		},
 
 
-		var t = this.allocTransform();
-		this.setIdentity( t );
+		setIdentity: function ( t ) {
 
 
-		var m1 = this.getBasisAsMatrix3( t1 );
-		var m2 = this.getBasisAsMatrix3( t2 );
+			t.setIdentity();
 
 
-		var o1 = this.getOrigin( t1 );
-		var o2 = this.getOrigin( t2 );
+		},
 
 
-		var v1 = this.multiplyMatrix3ByVector3( m1, o2 );
-		var v2 = this.addVector3( v1, o1 );
-		this.setOrigin( t, v2 );
+		getBasis: function ( t ) {
 
 
-		var m3 = this.multiplyMatrices3( m1, m2 );
-		this.setBasisFromMatrix3( t, m3 );
+			var q = this.allocQuaternion();
+			t.getBasis().getRotation( q );
+			return q;
 
 
-		this.freeVector3( v1 );
-		this.freeVector3( v2 );
+		},
 
 
-		return t;
+		getBasisAsMatrix3: function ( t ) {
 
 
-	},
+			var q = this.getBasis( t );
+			var m = this.quaternionToMatrix3( q );
+			this.freeQuaternion( q );
+			return m;
 
 
-	inverseTransform: function ( t ) {
+		},
 
 
-		var t2 = this.allocTransform();
+		getOrigin: function( t ) {
 
 
-		var m1 = this.getBasisAsMatrix3( t );
-		var o = this.getOrigin( t );
+			return t.getOrigin();
 
 
-		var m2 = this.transposeMatrix3( m1 );
-		var v1 = this.negativeVector3( o );
-		var v2 = this.multiplyMatrix3ByVector3( m2, v1 );
+		},
 
 
-		this.setOrigin( t2, v2 );
-		this.setBasisFromMatrix3( t2, m2 );
+		setOrigin: function( t, v ) {
 
 
-		this.freeVector3( v1 );
-		this.freeVector3( v2 );
+			t.getOrigin().setValue( v.x(), v.y(), v.z() );
 
 
-		return t2;
+		},
 
 
-	},
+		copyOrigin: function( t1, t2 ) {
 
 
-	multiplyMatrices3: function ( m1, m2 ) {
+			var o = t2.getOrigin();
+			this.setOrigin( t1, o );
 
 
-		var m3 = [];
+		},
 
 
-		var v10 = this.rowOfMatrix3( m1, 0 );
-		var v11 = this.rowOfMatrix3( m1, 1 );
-		var v12 = this.rowOfMatrix3( m1, 2 );
+		setBasis: function( t, q ) {
 
 
-		var v20 = this.columnOfMatrix3( m2, 0 );
-		var v21 = this.columnOfMatrix3( m2, 1 );
-		var v22 = this.columnOfMatrix3( m2, 2 );
+			t.setRotation( q );
 
 
-		m3[ 0 ] = this.dotVectors3( v10, v20 );
-		m3[ 1 ] = this.dotVectors3( v10, v21 );
-		m3[ 2 ] = this.dotVectors3( v10, v22 );
-		m3[ 3 ] = this.dotVectors3( v11, v20 );
-		m3[ 4 ] = this.dotVectors3( v11, v21 );
-		m3[ 5 ] = this.dotVectors3( v11, v22 );
-		m3[ 6 ] = this.dotVectors3( v12, v20 );
-		m3[ 7 ] = this.dotVectors3( v12, v21 );
-		m3[ 8 ] = this.dotVectors3( v12, v22 );
+		},
 
 
-		this.freeVector3( v10 );
-		this.freeVector3( v11 );
-		this.freeVector3( v12 );
-		this.freeVector3( v20 );
-		this.freeVector3( v21 );
-		this.freeVector3( v22 );
+		setBasisFromMatrix3: function( t, m ) {
 
 
-		return m3;
+			var q = this.matrix3ToQuaternion( m );
+			this.setBasis( t, q );
+			this.freeQuaternion( q );
 
 
-	},
+		},
 
 
-	addVector3: function( v1, v2 ) {
+		setOriginFromArray3: function ( t, a ) {
 
 
-		var v = this.allocVector3();
-		v.setValue( v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z() );
-		return v;
+			t.getOrigin().setValue( a[ 0 ], a[ 1 ], a[ 2 ] );
 
 
-	},
+		},
 
 
-	dotVectors3: function( v1, v2 ) {
+		setOriginFromThreeVector3: function ( t, v ) {
 
 
-		return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
+			t.getOrigin().setValue( v.x, v.y, v.z );
 
 
-	},
+		},
 
 
-	rowOfMatrix3: function( m, i ) {
+		setBasisFromArray3: function ( t, a ) {
 
 
-		var v = this.allocVector3();
-		v.setValue( m[ i * 3 + 0 ], m[ i * 3 + 1 ], m[ i * 3 + 2 ] );
-		return v;
+			var thQ = this.allocThreeQuaternion();
+			var thE = this.allocThreeEuler();
+			thE.set( a[ 0 ], a[ 1 ], a[ 2 ] );
+			this.setBasisFromThreeQuaternion( t, thQ.setFromEuler( thE ) );
 
 
-	},
+			this.freeThreeEuler( thE );
+			this.freeThreeQuaternion( thQ );
 
 
-	columnOfMatrix3: function( m, i ) {
+		},
 
 
-		var v = this.allocVector3();
-		v.setValue( m[ i + 0 ], m[ i + 3 ], m[ i + 6 ] );
-		return v;
+		setBasisFromThreeQuaternion: function ( t, a ) {
 
 
-	},
+			var q = this.allocQuaternion();
 
 
-	negativeVector3: function( v ) {
+			q.setX( a.x );
+			q.setY( a.y );
+			q.setZ( a.z );
+			q.setW( a.w );
+			this.setBasis( t, q );
 
 
-		var v2 = this.allocVector3();
-		v2.setValue( -v.x(), -v.y(), -v.z() );
-		return v2;
+			this.freeQuaternion( q );
 
 
-	},
+		},
 
 
-	multiplyMatrix3ByVector3: function ( m, v ) {
+		multiplyTransforms: function ( t1, t2 ) {
 
 
-		var v4 = this.allocVector3();
+			var t = this.allocTransform();
+			this.setIdentity( t );
 
 
-		var v0 = this.rowOfMatrix3( m, 0 );
-		var v1 = this.rowOfMatrix3( m, 1 );
-		var v2 = this.rowOfMatrix3( m, 2 );
-		var x = this.dotVectors3( v0, v );
-		var y = this.dotVectors3( v1, v );
-		var z = this.dotVectors3( v2, v );
+			var m1 = this.getBasisAsMatrix3( t1 );
+			var m2 = this.getBasisAsMatrix3( t2 );
 
 
-		v4.setValue( x, y, z );
+			var o1 = this.getOrigin( t1 );
+			var o2 = this.getOrigin( t2 );
 
 
-		this.freeVector3( v0 );
-		this.freeVector3( v1 );
-		this.freeVector3( v2 );
+			var v1 = this.multiplyMatrix3ByVector3( m1, o2 );
+			var v2 = this.addVector3( v1, o1 );
+			this.setOrigin( t, v2 );
 
 
-		return v4;
+			var m3 = this.multiplyMatrices3( m1, m2 );
+			this.setBasisFromMatrix3( t, m3 );
 
 
-	},
+			this.freeVector3( v1 );
+			this.freeVector3( v2 );
 
 
-	transposeMatrix3: function( m ) {
+			return t;
 
 
-		var m2 = [];
-		m2[ 0 ] = m[ 0 ];
-		m2[ 1 ] = m[ 3 ];
-		m2[ 2 ] = m[ 6 ];
-		m2[ 3 ] = m[ 1 ];
-		m2[ 4 ] = m[ 4 ];
-		m2[ 5 ] = m[ 7 ];
-		m2[ 6 ] = m[ 2 ];
-		m2[ 7 ] = m[ 5 ];
-		m2[ 8 ] = m[ 8 ];
-		return m2;
+		},
 
 
-	},
+		inverseTransform: function ( t ) {
 
 
-	quaternionToMatrix3: function ( q ) {
+			var t2 = this.allocTransform();
 
 
-		var m = [];
+			var m1 = this.getBasisAsMatrix3( t );
+			var o = this.getOrigin( t );
 
 
-		var x = q.x();
-		var y = q.y();
-		var z = q.z();
-		var w = q.w();
+			var m2 = this.transposeMatrix3( m1 );
+			var v1 = this.negativeVector3( o );
+			var v2 = this.multiplyMatrix3ByVector3( m2, v1 );
 
 
-		var xx = x * x;
-		var yy = y * y;
-		var zz = z * z;
+			this.setOrigin( t2, v2 );
+			this.setBasisFromMatrix3( t2, m2 );
 
 
-		var xy = x * y;
-		var yz = y * z;
-		var zx = z * x;
+			this.freeVector3( v1 );
+			this.freeVector3( v2 );
 
 
-		var xw = x * w;
-		var yw = y * w;
-		var zw = z * w;
+			return t2;
 
 
-		m[ 0 ] = 1 - 2 * ( yy + zz );
-		m[ 1 ] = 2 * ( xy - zw );
-		m[ 2 ] = 2 * ( zx + yw );
-		m[ 3 ] = 2 * ( xy + zw );
-		m[ 4 ] = 1 - 2 * ( zz + xx );
-		m[ 5 ] = 2 * ( yz - xw );
-		m[ 6 ] = 2 * ( zx - yw );
-		m[ 7 ] = 2 * ( yz + xw );
-		m[ 8 ] = 1 - 2 * ( xx + yy );
+		},
 
 
-		return m;
+		multiplyMatrices3: function ( m1, m2 ) {
 
 
-	},
+			var m3 = [];
 
 
-	matrix3ToQuaternion: function( m ) {
+			var v10 = this.rowOfMatrix3( m1, 0 );
+			var v11 = this.rowOfMatrix3( m1, 1 );
+			var v12 = this.rowOfMatrix3( m1, 2 );
 
 
-		var t = m[ 0 ] + m[ 4 ] + m[ 8 ];
-		var s, x, y, z, w;
+			var v20 = this.columnOfMatrix3( m2, 0 );
+			var v21 = this.columnOfMatrix3( m2, 1 );
+			var v22 = this.columnOfMatrix3( m2, 2 );
 
 
-		if( t > 0 ) {
+			m3[ 0 ] = this.dotVectors3( v10, v20 );
+			m3[ 1 ] = this.dotVectors3( v10, v21 );
+			m3[ 2 ] = this.dotVectors3( v10, v22 );
+			m3[ 3 ] = this.dotVectors3( v11, v20 );
+			m3[ 4 ] = this.dotVectors3( v11, v21 );
+			m3[ 5 ] = this.dotVectors3( v11, v22 );
+			m3[ 6 ] = this.dotVectors3( v12, v20 );
+			m3[ 7 ] = this.dotVectors3( v12, v21 );
+			m3[ 8 ] = this.dotVectors3( v12, v22 );
 
 
-			s = Math.sqrt( t + 1.0 ) * 2;
-			w = 0.25 * s;
-			x = ( m[ 7 ] - m[ 5 ] ) / s;
-			y = ( m[ 2 ] - m[ 6 ] ) / s; 
-			z = ( m[ 3 ] - m[ 1 ] ) / s; 
+			this.freeVector3( v10 );
+			this.freeVector3( v11 );
+			this.freeVector3( v12 );
+			this.freeVector3( v20 );
+			this.freeVector3( v21 );
+			this.freeVector3( v22 );
 
 
-		} else if( ( m[ 0 ] > m[ 4 ] ) && ( m[ 0 ] > m[ 8 ] ) ) {
+			return m3;
 
 
-			s = Math.sqrt( 1.0 + m[ 0 ] - m[ 4 ] - m[ 8 ] ) * 2;
-			w = ( m[ 7 ] - m[ 5 ] ) / s;
-			x = 0.25 * s;
-			y = ( m[ 1 ] + m[ 3 ] ) / s;
-			z = ( m[ 2 ] + m[ 6 ] ) / s;
+		},
 
 
-		} else if( m[ 4 ] > m[ 8 ] ) {
+		addVector3: function( v1, v2 ) {
 
 
-			s = Math.sqrt( 1.0 + m[ 4 ] - m[ 0 ] - m[ 8 ] ) * 2;
-			w = ( m[ 2 ] - m[ 6 ] ) / s;
-			x = ( m[ 1 ] + m[ 3 ] ) / s;
-			y = 0.25 * s;
-			z = ( m[ 5 ] + m[ 7 ] ) / s;
+			var v = this.allocVector3();
+			v.setValue( v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z() );
+			return v;
 
 
-		} else {
+		},
 
 
-			s = Math.sqrt( 1.0 + m[ 8 ] - m[ 0 ] - m[ 4 ] ) * 2;
-			w = ( m[ 3 ] - m[ 1 ] ) / s;
-			x = ( m[ 2 ] + m[ 6 ] ) / s;
-			y = ( m[ 5 ] + m[ 7 ] ) / s;
-			z = 0.25 * s;
+		dotVectors3: function( v1, v2 ) {
 
 
-		}
+			return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
 
 
-		var q = this.allocQuaternion();
-		q.setX( x );
-		q.setY( y );
-		q.setZ( z );
-		q.setW( w );
-		return q;
+		},
 
 
-	}
+		rowOfMatrix3: function( m, i ) {
 
 
-};
+			var v = this.allocVector3();
+			v.setValue( m[ i * 3 + 0 ], m[ i * 3 + 1 ], m[ i * 3 + 2 ] );
+			return v;
 
 
-THREE.MMDPhysics.RigidBody = function ( mesh, world, params, helper ) {
+		},
 
 
-	this.mesh  = mesh;
-	this.world = world;
-	this.params = params;
-	this.helper = helper;
+		columnOfMatrix3: function( m, i ) {
 
 
-	this.body = null;
-	this.bone = null;
-	this.boneOffsetForm = null;
-	this.boneOffsetFormInverse = null;
+			var v = this.allocVector3();
+			v.setValue( m[ i + 0 ], m[ i + 3 ], m[ i + 6 ] );
+			return v;
 
 
-	this.init();
+		},
 
 
-};
+		negativeVector3: function( v ) {
 
 
-THREE.MMDPhysics.RigidBody.prototype = {
+			var v2 = this.allocVector3();
+			v2.setValue( -v.x(), -v.y(), -v.z() );
+			return v2;
 
 
-	constructor: THREE.MMDPhysics.RigidBody,
+		},
 
 
-	init: function () {
+		multiplyMatrix3ByVector3: function ( m, v ) {
 
 
-		function generateShape( p ) {
+			var v4 = this.allocVector3();
 
 
-			switch( p.shapeType ) {
+			var v0 = this.rowOfMatrix3( m, 0 );
+			var v1 = this.rowOfMatrix3( m, 1 );
+			var v2 = this.rowOfMatrix3( m, 2 );
+			var x = this.dotVectors3( v0, v );
+			var y = this.dotVectors3( v1, v );
+			var z = this.dotVectors3( v2, v );
 
 
-				case 0:
-					return new Ammo.btSphereShape( p.width );
+			v4.setValue( x, y, z );
 
 
-				case 1:
-					return new Ammo.btBoxShape( new Ammo.btVector3( p.width, p.height, p.depth ) );
+			this.freeVector3( v0 );
+			this.freeVector3( v1 );
+			this.freeVector3( v2 );
 
 
-				case 2:
-					return new Ammo.btCapsuleShape( p.width, p.height );
+			return v4;
 
 
-				default:
-					throw 'unknown shape type ' + p.shapeType;
+		},
 
 
-			}
+		transposeMatrix3: function( m ) {
 
 
-		}
+			var m2 = [];
+			m2[ 0 ] = m[ 0 ];
+			m2[ 1 ] = m[ 3 ];
+			m2[ 2 ] = m[ 6 ];
+			m2[ 3 ] = m[ 1 ];
+			m2[ 4 ] = m[ 4 ];
+			m2[ 5 ] = m[ 7 ];
+			m2[ 6 ] = m[ 2 ];
+			m2[ 7 ] = m[ 5 ];
+			m2[ 8 ] = m[ 8 ];
+			return m2;
 
 
-		var helper = this.helper;
-		var params = this.params;
-		var bones = this.mesh.skeleton.bones;
-		var bone = ( params.boneIndex === -1 ) ? new THREE.Bone() : bones[ params.boneIndex ];
+		},
 
 
-		var shape = generateShape( params );
-		var weight = ( params.type === 0 ) ? 0 : params.weight;
-		var localInertia = helper.allocVector3();
-		localInertia.setValue( 0, 0, 0 );
+		quaternionToMatrix3: function ( q ) {
 
 
-		if( weight !== 0 ) {
+			var m = [];
 
 
-			shape.calculateLocalInertia( weight, localInertia );
+			var x = q.x();
+			var y = q.y();
+			var z = q.z();
+			var w = q.w();
 
 
-		}
+			var xx = x * x;
+			var yy = y * y;
+			var zz = z * z;
 
 
-		var boneOffsetForm = helper.allocTransform();
-		helper.setIdentity( boneOffsetForm );
-		helper.setOriginFromArray3( boneOffsetForm, params.position );
-		helper.setBasisFromArray3( boneOffsetForm, params.rotation );
+			var xy = x * y;
+			var yz = y * z;
+			var zx = z * x;
 
 
-		var vector = helper.allocThreeVector3();
-		var boneForm = helper.allocTransform();
-		helper.setIdentity( boneForm );
-		helper.setOriginFromThreeVector3( boneForm, bone.getWorldPosition( vector ) );
+			var xw = x * w;
+			var yw = y * w;
+			var zw = z * w;
 
 
-		var form = helper.multiplyTransforms( boneForm, boneOffsetForm );
-		var state = new Ammo.btDefaultMotionState( form );
+			m[ 0 ] = 1 - 2 * ( yy + zz );
+			m[ 1 ] = 2 * ( xy - zw );
+			m[ 2 ] = 2 * ( zx + yw );
+			m[ 3 ] = 2 * ( xy + zw );
+			m[ 4 ] = 1 - 2 * ( zz + xx );
+			m[ 5 ] = 2 * ( yz - xw );
+			m[ 6 ] = 2 * ( zx - yw );
+			m[ 7 ] = 2 * ( yz + xw );
+			m[ 8 ] = 1 - 2 * ( xx + yy );
 
 
-		var info = new Ammo.btRigidBodyConstructionInfo( weight, state, shape, localInertia );
-		info.set_m_friction( params.friction );
-		info.set_m_restitution( params.restitution );
+			return m;
 
 
-		var body = new Ammo.btRigidBody( info );
+		},
 
 
-		if ( params.type === 0 ) {
+		matrix3ToQuaternion: function( m ) {
 
 
-			body.setCollisionFlags( body.getCollisionFlags() | 2 );
+			var t = m[ 0 ] + m[ 4 ] + m[ 8 ];
+			var s, x, y, z, w;
 
 
-			/*
-			 * It'd be better to comment out this line though in general I should call this method
-			 * because I'm not sure why but physics will be more like MMD's
-			 * if I comment out.
-			 */
-			body.setActivationState( 4 );
+			if( t > 0 ) {
 
 
-		}
+				s = Math.sqrt( t + 1.0 ) * 2;
+				w = 0.25 * s;
+				x = ( m[ 7 ] - m[ 5 ] ) / s;
+				y = ( m[ 2 ] - m[ 6 ] ) / s; 
+				z = ( m[ 3 ] - m[ 1 ] ) / s; 
 
 
-		body.setDamping( params.positionDamping, params.rotationDamping );
-		body.setSleepingThresholds( 0, 0 );
+			} else if( ( m[ 0 ] > m[ 4 ] ) && ( m[ 0 ] > m[ 8 ] ) ) {
 
 
-		this.world.addRigidBody( body, 1 << params.groupIndex, params.groupTarget );
+				s = Math.sqrt( 1.0 + m[ 0 ] - m[ 4 ] - m[ 8 ] ) * 2;
+				w = ( m[ 7 ] - m[ 5 ] ) / s;
+				x = 0.25 * s;
+				y = ( m[ 1 ] + m[ 3 ] ) / s;
+				z = ( m[ 2 ] + m[ 6 ] ) / s;
 
 
-		this.body = body;
-		this.bone = bone;
-		this.boneOffsetForm = boneOffsetForm;
-		this.boneOffsetFormInverse = helper.inverseTransform( boneOffsetForm );
+			} else if( m[ 4 ] > m[ 8 ] ) {
 
 
-		helper.freeVector3( localInertia );
-		helper.freeTransform( form );
-		helper.freeTransform( boneForm );
-		helper.freeThreeVector3( vector );
+				s = Math.sqrt( 1.0 + m[ 4 ] - m[ 0 ] - m[ 8 ] ) * 2;
+				w = ( m[ 2 ] - m[ 6 ] ) / s;
+				x = ( m[ 1 ] + m[ 3 ] ) / s;
+				y = 0.25 * s;
+				z = ( m[ 5 ] + m[ 7 ] ) / s;
 
 
-	},
+			} else {
 
 
-	reset: function () {
+				s = Math.sqrt( 1.0 + m[ 8 ] - m[ 0 ] - m[ 4 ] ) * 2;
+				w = ( m[ 3 ] - m[ 1 ] ) / s;
+				x = ( m[ 2 ] + m[ 6 ] ) / s;
+				y = ( m[ 5 ] + m[ 7 ] ) / s;
+				z = 0.25 * s;
 
 
-		this.setTransformFromBone();
+			}
 
 
-	},
+			var q = this.allocQuaternion();
+			q.setX( x );
+			q.setY( y );
+			q.setZ( z );
+			q.setW( w );
+			return q;
 
 
-	updateFromBone: function () {
+		}
 
 
-		if ( this.params.boneIndex === -1 ) {
+	};
 
 
-			return;
+	/**
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {Ammo.btDiscreteDynamicsWorld} world
+	 * @param {Object} params
+	 * @param {ResourceManager} manager
+	 */
+	function RigidBody( mesh, world, params, manager ) {
 
 
-		}
+		this.mesh  = mesh;
+		this.world = world;
+		this.params = params;
+		this.manager = manager;
 
 
-		if ( this.params.type === 0 ) {
+		this.body = null;
+		this.bone = null;
+		this.boneOffsetForm = null;
+		this.boneOffsetFormInverse = null;
 
 
-			this.setTransformFromBone();
+		this._init();
 
 
-		}
+	}
 
 
-	},
+	RigidBody.prototype = {
 
 
-	updateBone: function () {
+		constructor: MMDPhysics.RigidBody,
 
 
-		if ( this.params.type === 0 || this.params.boneIndex === -1 ) {
+		/**
+		 * Resets rigid body transform to the current bone's.
+		 *
+		 * @return {RigidBody}
+		 */
+		reset: function () {
 
 
-			return;
+			this._setTransformFromBone();
+			return this;
 
 
-		}
+		},
 
 
-		this.updateBoneRotation();
+		/**
+		 * Updates rigid body's transform from the current bone.
+		 *
+		 * @return {RidigBody}
+		 */
+		updateFromBone: function () {
 
 
-		if ( this.params.type === 1 ) {
+			if ( this.params.boneIndex !== - 1 &&
+				this.params.type === 0 ) {
 
 
-			this.updateBonePosition();
+				this._setTransformFromBone();
 
 
-		}
+			}
 
 
-		this.bone.updateMatrixWorld( true );
+			return this;
 
 
-		if ( this.params.type === 2 ) {
+		},
 
 
-			this.setPositionFromBone();
+		/**
+		 * Updates bone from the current ridid body's transform.
+		 *
+		 * @return {RidigBody}
+		 */
+		updateBone: function () {
 
 
-		}
+			if ( this.params.type === 0 ||
+				this.params.boneIndex === - 1 ) {
 
 
-	},
+				return this;
 
 
-	getBoneTransform: function () {
+			}
 
 
-		var helper = this.helper;
-		var p = helper.allocThreeVector3();
-		var q = helper.allocThreeQuaternion();
+			this._updateBoneRotation();
 
 
-		this.bone.getWorldPosition( p );
-		this.bone.getWorldQuaternion( q );
+			if ( this.params.type === 1 ) {
 
 
-		var tr = helper.allocTransform();
-		helper.setOriginFromThreeVector3( tr, p );
-		helper.setBasisFromThreeQuaternion( tr, q );
+				this._updateBonePosition();
 
 
-		var form = helper.multiplyTransforms( tr, this.boneOffsetForm );
+			}
 
 
-		helper.freeTransform( tr );
-		helper.freeThreeQuaternion( q );
-		helper.freeThreeVector3( p );
+			this.bone.updateMatrixWorld( true );
 
 
-		return form;
+			if ( this.params.type === 2 ) {
 
 
-	},
+				this._setPositionFromBone();
 
 
-	getWorldTransformForBone: function () {
+			}
 
 
-		var helper = this.helper;
+			return this;
 
 
-		var tr = helper.allocTransform();
-		this.body.getMotionState().getWorldTransform( tr );
-		var tr2 = helper.multiplyTransforms( tr, this.boneOffsetFormInverse );
+		},
 
 
-		helper.freeTransform( tr );
+		// private methods
 
 
-		return tr2;
+		_init: function () {
 
 
-	},
+			function generateShape( p ) {
 
 
-	setTransformFromBone: function () {
+				switch( p.shapeType ) {
 
 
-		var helper = this.helper;
-		var form = this.getBoneTransform();
+					case 0:
+						return new Ammo.btSphereShape( p.width );
 
 
-		// TODO: check the most appropriate way to set
-		//this.body.setWorldTransform( form );
-		this.body.setCenterOfMassTransform( form );
-		this.body.getMotionState().setWorldTransform( form );
+					case 1:
+						return new Ammo.btBoxShape( new Ammo.btVector3( p.width, p.height, p.depth ) );
 
 
-		helper.freeTransform( form );
+					case 2:
+						return new Ammo.btCapsuleShape( p.width, p.height );
 
 
-	},
+					default:
+						throw 'unknown shape type ' + p.shapeType;
 
 
-	setPositionFromBone: function () {
+				}
 
 
-		var helper = this.helper;
-		var form = this.getBoneTransform();
+			}
 
 
-		var tr = helper.allocTransform();
-		this.body.getMotionState().getWorldTransform( tr );
-		helper.copyOrigin( tr, form );
+			var manager = this.manager;
+			var params = this.params;
+			var bones = this.mesh.skeleton.bones;
+			var bone = ( params.boneIndex === - 1 )
+				? new THREE.Bone()
+				: bones[ params.boneIndex ];
 
 
-		// TODO: check the most appropriate way to set
-		//this.body.setWorldTransform( tr );
-		this.body.setCenterOfMassTransform( tr );
-		this.body.getMotionState().setWorldTransform( tr );
+			var shape = generateShape( params );
+			var weight = ( params.type === 0 ) ? 0 : params.weight;
+			var localInertia = manager.allocVector3();
+			localInertia.setValue( 0, 0, 0 );
 
 
-		helper.freeTransform( tr );
-		helper.freeTransform( form );
+			if( weight !== 0 ) {
 
 
-	},
+				shape.calculateLocalInertia( weight, localInertia );
 
 
-	updateBoneRotation: function () {
+			}
 
 
-		this.bone.updateMatrixWorld( true );
+			var boneOffsetForm = manager.allocTransform();
+			manager.setIdentity( boneOffsetForm );
+			manager.setOriginFromArray3( boneOffsetForm, params.position );
+			manager.setBasisFromArray3( boneOffsetForm, params.rotation );
 
 
-		var helper = this.helper;
+			var vector = manager.allocThreeVector3();
+			var boneForm = manager.allocTransform();
+			manager.setIdentity( boneForm );
+			manager.setOriginFromThreeVector3( boneForm, bone.getWorldPosition( vector ) );
 
 
-		var tr = this.getWorldTransformForBone();
-		var q = helper.getBasis( tr );
+			var form = manager.multiplyTransforms( boneForm, boneOffsetForm );
+			var state = new Ammo.btDefaultMotionState( form );
 
 
-		var thQ = helper.allocThreeQuaternion();
-		var thQ2 = helper.allocThreeQuaternion();
-		var thQ3 = helper.allocThreeQuaternion();
+			var info = new Ammo.btRigidBodyConstructionInfo( weight, state, shape, localInertia );
+			info.set_m_friction( params.friction );
+			info.set_m_restitution( params.restitution );
 
 
-		thQ.set( q.x(), q.y(), q.z(), q.w() );
-		thQ2.setFromRotationMatrix( this.bone.matrixWorld );
-		thQ2.conjugate();
-		thQ2.multiply( thQ );
+			var body = new Ammo.btRigidBody( info );
 
 
-		//this.bone.quaternion.multiply( thQ2 );
+			if ( params.type === 0 ) {
 
 
-		thQ3.setFromRotationMatrix( this.bone.matrix );
-		this.bone.quaternion.copy( thQ2.multiply( thQ3 ) );
+				body.setCollisionFlags( body.getCollisionFlags() | 2 );
 
 
-		helper.freeThreeQuaternion( thQ );
-		helper.freeThreeQuaternion( thQ2 );
-		helper.freeThreeQuaternion( thQ3 );
+				/*
+				 * It'd be better to comment out this line though in general I should call this method
+				 * because I'm not sure why but physics will be more like MMD's
+				 * if I comment out.
+				 */
+				body.setActivationState( 4 );
 
 
-		helper.freeQuaternion( q );
-		helper.freeTransform( tr );
+			}
 
 
-	},
+			body.setDamping( params.positionDamping, params.rotationDamping );
+			body.setSleepingThresholds( 0, 0 );
 
 
-	updateBonePosition: function () {
+			this.world.addRigidBody( body, 1 << params.groupIndex, params.groupTarget );
 
 
-		var helper = this.helper;
+			this.body = body;
+			this.bone = bone;
+			this.boneOffsetForm = boneOffsetForm;
+			this.boneOffsetFormInverse = manager.inverseTransform( boneOffsetForm );
 
 
-		var tr = this.getWorldTransformForBone();
+			manager.freeVector3( localInertia );
+			manager.freeTransform( form );
+			manager.freeTransform( boneForm );
+			manager.freeThreeVector3( vector );
 
 
-		var thV = helper.allocThreeVector3();
+		},
 
 
-		var o = helper.getOrigin( tr );
-		thV.set( o.x(), o.y(), o.z() );
+		_getBoneTransform: function () {
 
 
-		var v = this.bone.worldToLocal( thV );
-		this.bone.position.add( v );
+			var manager = this.manager;
+			var p = manager.allocThreeVector3();
+			var q = manager.allocThreeQuaternion();
+			var s = manager.allocThreeVector3();
 
 
-		helper.freeThreeVector3( thV );
+			this.bone.matrixWorld.decompose( p, q, s );
 
 
-		helper.freeTransform( tr );
+			var tr = manager.allocTransform();
+			manager.setOriginFromThreeVector3( tr, p );
+			manager.setBasisFromThreeQuaternion( tr, q );
 
 
-	}
+			var form = manager.multiplyTransforms( tr, this.boneOffsetForm );
 
 
-};
+			manager.freeTransform( tr );
+			manager.freeThreeVector3( s );
+			manager.freeThreeQuaternion( q );
+			manager.freeThreeVector3( p );
 
 
-THREE.MMDPhysics.Constraint = function ( mesh, world, bodyA, bodyB, params, helper ) {
+			return form;
 
 
-	this.mesh  = mesh;
-	this.world = world;
-	this.bodyA = bodyA;
-	this.bodyB = bodyB;
-	this.params = params;
-	this.helper = helper;
+		},
 
 
-	this.constraint = null;
+		_getWorldTransformForBone: function () {
 
 
-	this.init();
+			var manager = this.manager;
 
 
-};
+			var tr = manager.allocTransform();
+			this.body.getMotionState().getWorldTransform( tr );
+			var tr2 = manager.multiplyTransforms( tr, this.boneOffsetFormInverse );
 
 
-THREE.MMDPhysics.Constraint.prototype = {
+			manager.freeTransform( tr );
 
 
-	constructor: THREE.MMDPhysics.Constraint,
+			return tr2;
 
 
-	init: function () {
+		},
 
 
-		var helper = this.helper;
-		var params = this.params;
-		var bodyA = this.bodyA;
-		var bodyB = this.bodyB;
+		_setTransformFromBone: function () {
 
 
-		var form = helper.allocTransform();
-		helper.setIdentity( form );
-		helper.setOriginFromArray3( form, params.position );
-		helper.setBasisFromArray3( form, params.rotation );
+			var manager = this.manager;
+			var form = this._getBoneTransform();
 
 
-		var formA = helper.allocTransform();
-		var formB = helper.allocTransform();
+			// TODO: check the most appropriate way to set
+			//this.body.setWorldTransform( form );
+			this.body.setCenterOfMassTransform( form );
+			this.body.getMotionState().setWorldTransform( form );
 
 
-		bodyA.body.getMotionState().getWorldTransform( formA );
-		bodyB.body.getMotionState().getWorldTransform( formB );
+			manager.freeTransform( form );
 
 
-		var formInverseA = helper.inverseTransform( formA );
-		var formInverseB = helper.inverseTransform( formB );
+		},
 
 
-		var formA2 = helper.multiplyTransforms( formInverseA, form );
-		var formB2 = helper.multiplyTransforms( formInverseB, form );
+		_setPositionFromBone: function () {
 
 
-		var constraint = new Ammo.btGeneric6DofSpringConstraint( bodyA.body, bodyB.body, formA2, formB2, true );
+			var manager = this.manager;
+			var form = this._getBoneTransform();
 
 
-		var lll = helper.allocVector3();
-		var lul = helper.allocVector3();
-		var all = helper.allocVector3();
-		var aul = helper.allocVector3();
+			var tr = manager.allocTransform();
+			this.body.getMotionState().getWorldTransform( tr );
+			manager.copyOrigin( tr, form );
 
 
-		lll.setValue( params.translationLimitation1[ 0 ],
-		              params.translationLimitation1[ 1 ],
-		              params.translationLimitation1[ 2 ] );
-		lul.setValue( params.translationLimitation2[ 0 ],
-		              params.translationLimitation2[ 1 ],
-		              params.translationLimitation2[ 2 ] );
-		all.setValue( params.rotationLimitation1[ 0 ],
-		              params.rotationLimitation1[ 1 ],
-		              params.rotationLimitation1[ 2 ] );
-		aul.setValue( params.rotationLimitation2[ 0 ],
-		              params.rotationLimitation2[ 1 ],
-		              params.rotationLimitation2[ 2 ] );
+			// TODO: check the most appropriate way to set
+			//this.body.setWorldTransform( tr );
+			this.body.setCenterOfMassTransform( tr );
+			this.body.getMotionState().setWorldTransform( tr );
 
 
-		constraint.setLinearLowerLimit( lll );
-		constraint.setLinearUpperLimit( lul );
-		constraint.setAngularLowerLimit( all );
-		constraint.setAngularUpperLimit( aul );
+			manager.freeTransform( tr );
+			manager.freeTransform( form );
 
 
-		for ( var i = 0; i < 3; i++ ) {
+		},
 
 
-			if( params.springPosition[ i ] !== 0 ) {
+		_updateBoneRotation: function () {
 
 
-				constraint.enableSpring( i, true );
-				constraint.setStiffness( i, params.springPosition[ i ] );
+			var manager = this.manager;
 
 
-			}
+			var tr = this._getWorldTransformForBone();
+			var q = manager.getBasis( tr );
 
 
-		}
+			var thQ = manager.allocThreeQuaternion();
+			var thQ2 = manager.allocThreeQuaternion();
+			var thQ3 = manager.allocThreeQuaternion();
 
 
-		for ( var i = 0; i < 3; i++ ) {
+			thQ.set( q.x(), q.y(), q.z(), q.w() );
+			thQ2.setFromRotationMatrix( this.bone.matrixWorld );
+			thQ2.conjugate();
+			thQ2.multiply( thQ );
 
 
-			if( params.springRotation[ i ] !== 0 ) {
+			//this.bone.quaternion.multiply( thQ2 );
 
 
-				constraint.enableSpring( i + 3, true );
-				constraint.setStiffness( i + 3, params.springRotation[ i ] );
+			thQ3.setFromRotationMatrix( this.bone.matrix );
+			this.bone.quaternion.copy( thQ2.multiply( thQ3 ) );
 
 
-			}
+			manager.freeThreeQuaternion( thQ );
+			manager.freeThreeQuaternion( thQ2 );
+			manager.freeThreeQuaternion( thQ3 );
 
 
-		}
+			manager.freeQuaternion( q );
+			manager.freeTransform( tr );
 
 
-		/*
-		 * Currently(10/31/2016) official ammo.js doesn't support
-		 * btGeneric6DofSpringConstraint.setParam method.
-		 * You need custom ammo.js (add the method into idl) if you wanna use.
-		 * By setting this parameter, physics will be more like MMD's
-		 */
-		if ( constraint.setParam !== undefined ) {
+		},
 
 
-			for ( var i = 0; i < 6; i ++ ) {
+		_updateBonePosition: function () {
 
 
-				// this parameter is from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
-				constraint.setParam( 2, 0.475, i );
+			var manager = this.manager;
 
 
-			}
+			var tr = this._getWorldTransformForBone();
+
+			var thV = manager.allocThreeVector3();
+
+			var o = manager.getOrigin( tr );
+			thV.set( o.x(), o.y(), o.z() );
+
+			var v = this.bone.worldToLocal( thV );
+			this.bone.position.add( v );
+
+			manager.freeThreeVector3( thV );
+
+			manager.freeTransform( tr );
 
 
 		}
 		}
 
 
-		this.world.addConstraint( constraint, true );
-		this.constraint = constraint;
-
-		helper.freeTransform( form );
-		helper.freeTransform( formA );
-		helper.freeTransform( formB );
-		helper.freeTransform( formInverseA );
-		helper.freeTransform( formInverseB );
-		helper.freeTransform( formA2 );
-		helper.freeTransform( formB2 );
-		helper.freeVector3( lll );
-		helper.freeVector3( lul );
-		helper.freeVector3( all );
-		helper.freeVector3( aul );
+	};
+
+	/**
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {Ammo.btDiscreteDynamicsWorld} world
+	 * @param {RigidBody} bodyA
+	 * @param {RigidBody} bodyB
+	 * @param {Object} params
+	 * @param {ResourceManager} manager
+	 */
+	function Constraint( mesh, world, bodyA, bodyB, params, manager ) {
+
+		this.mesh  = mesh;
+		this.world = world;
+		this.bodyA = bodyA;
+		this.bodyB = bodyB;
+		this.params = params;
+		this.manager = manager;
+
+		this.constraint = null;
+
+		this._init();
 
 
 	}
 	}
 
 
-};
+	Constraint.prototype = {
 
 
+		constructor: Constraint,
 
 
-THREE.MMDPhysicsHelper = function ( mesh ) {
+		// private method
 
 
-	if ( mesh.physics === undefined || mesh.geometry.rigidBodies === undefined ) {
+		_init: function () {
 
 
-		throw 'THREE.MMDPhysicsHelper requires physics in mesh and rigidBodies in mesh.geometry.';
+			var manager = this.manager;
+			var params = this.params;
+			var bodyA = this.bodyA;
+			var bodyB = this.bodyB;
 
 
-	}
+			var form = manager.allocTransform();
+			manager.setIdentity( form );
+			manager.setOriginFromArray3( form, params.position );
+			manager.setBasisFromArray3( form, params.rotation );
 
 
-	THREE.Object3D.call( this );
+			var formA = manager.allocTransform();
+			var formB = manager.allocTransform();
 
 
-	this.root = mesh;
+			bodyA.body.getMotionState().getWorldTransform( formA );
+			bodyB.body.getMotionState().getWorldTransform( formB );
 
 
-	this.matrix = mesh.matrixWorld;
-	this.matrixAutoUpdate = false;
+			var formInverseA = manager.inverseTransform( formA );
+			var formInverseB = manager.inverseTransform( formB );
 
 
-	this.materials = [];
+			var formA2 = manager.multiplyTransforms( formInverseA, form );
+			var formB2 = manager.multiplyTransforms( formInverseB, form );
 
 
-	this.materials.push(
-		new THREE.MeshBasicMaterial( {
-			color: new THREE.Color( 0xff8888 ),
-			wireframe: true,
-			depthTest: false,
-			depthWrite: false,
-			opacity: 0.25,
-			transparent: true
-		} )
-	);
+			var constraint = new Ammo.btGeneric6DofSpringConstraint( bodyA.body, bodyB.body, formA2, formB2, true );
 
 
-	this.materials.push(
-		new THREE.MeshBasicMaterial( {
-			color: new THREE.Color( 0x88ff88 ),
-			wireframe: true,
-			depthTest: false,
-			depthWrite: false,
-			opacity: 0.25,
-			transparent: true
-		} )
-	);
+			var lll = manager.allocVector3();
+			var lul = manager.allocVector3();
+			var all = manager.allocVector3();
+			var aul = manager.allocVector3();
 
 
-	this.materials.push(
-		new THREE.MeshBasicMaterial( {
-			color: new THREE.Color( 0x8888ff ),
-			wireframe: true,
-			depthTest: false,
-			depthWrite: false,
-			opacity: 0.25,
-			transparent: true
-		} )
-	);
+			lll.setValue( params.translationLimitation1[ 0 ],
+			              params.translationLimitation1[ 1 ],
+			              params.translationLimitation1[ 2 ] );
+			lul.setValue( params.translationLimitation2[ 0 ],
+			              params.translationLimitation2[ 1 ],
+			              params.translationLimitation2[ 2 ] );
+			all.setValue( params.rotationLimitation1[ 0 ],
+			              params.rotationLimitation1[ 1 ],
+			              params.rotationLimitation1[ 2 ] );
+			aul.setValue( params.rotationLimitation2[ 0 ],
+			              params.rotationLimitation2[ 1 ],
+			              params.rotationLimitation2[ 2 ] );
 
 
-	this._init();
-	this.update();
+			constraint.setLinearLowerLimit( lll );
+			constraint.setLinearUpperLimit( lul );
+			constraint.setAngularLowerLimit( all );
+			constraint.setAngularUpperLimit( aul );
 
 
-};
+			for ( var i = 0; i < 3; i++ ) {
 
 
-THREE.MMDPhysicsHelper.prototype = Object.create( THREE.Object3D.prototype );
-THREE.MMDPhysicsHelper.prototype.constructor = THREE.MMDPhysicsHelper;
+				if( params.springPosition[ i ] !== 0 ) {
 
 
-THREE.MMDPhysicsHelper.prototype._init = function () {
+					constraint.enableSpring( i, true );
+					constraint.setStiffness( i, params.springPosition[ i ] );
 
 
-	var mesh = this.root;
-	var rigidBodies = mesh.geometry.rigidBodies;
+				}
+
+			}
+
+			for ( var i = 0; i < 3; i++ ) {
+
+				if( params.springRotation[ i ] !== 0 ) {
+
+					constraint.enableSpring( i + 3, true );
+					constraint.setStiffness( i + 3, params.springRotation[ i ] );
+
+				}
+
+			}
 
 
-	function createGeometry( param ) {
+			/*
+			 * Currently(10/31/2016) official ammo.js doesn't support
+			 * btGeneric6DofSpringConstraint.setParam method.
+			 * You need custom ammo.js (add the method into idl) if you wanna use.
+			 * By setting this parameter, physics will be more like MMD's
+			 */
+			if ( constraint.setParam !== undefined ) {
 
 
-		switch ( param.shapeType ) {
+				for ( var i = 0; i < 6; i ++ ) {
 
 
-			case 0:
-				return new THREE.SphereBufferGeometry( param.width, 16, 8 );
+					// this parameter is from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
+					constraint.setParam( 2, 0.475, i );
 
 
-			case 1:
-				return new THREE.BoxBufferGeometry( param.width * 2, param.height * 2, param.depth * 2, 8, 8, 8 );
+				}
 
 
-			case 2:
-				return new createCapsuleGeometry( param.width, param.height, 16, 8 );
+			}
 
 
-			default:
-				return null;
+			this.world.addConstraint( constraint, true );
+			this.constraint = constraint;
+
+			manager.freeTransform( form );
+			manager.freeTransform( formA );
+			manager.freeTransform( formB );
+			manager.freeTransform( formInverseA );
+			manager.freeTransform( formInverseB );
+			manager.freeTransform( formA2 );
+			manager.freeTransform( formB2 );
+			manager.freeVector3( lll );
+			manager.freeVector3( lul );
+			manager.freeVector3( all );
+			manager.freeVector3( aul );
 
 
 		}
 		}
 
 
+	};
+
+	/**
+	 * Visualize Rigid bodies
+	 *
+	 * @param {THREE.SkinnedMesh} mesh
+	 * @param {THREE.Physics} physics
+	 */
+	function MMDPhysicsHelper( mesh, physics ) {
+
+		THREE.Object3D.call( this );
+
+		this.root = mesh;
+		this.physics = physics;
+
+		this.matrix.copy( mesh.matrixWorld );
+		this.matrixAutoUpdate = false;
+
+		this.materials = [];
+
+		this.materials.push(
+			new THREE.MeshBasicMaterial( {
+				color: new THREE.Color( 0xff8888 ),
+				wireframe: true,
+				depthTest: false,
+				depthWrite: false,
+				opacity: 0.25,
+				transparent: true
+			} )
+		);
+
+		this.materials.push(
+			new THREE.MeshBasicMaterial( {
+				color: new THREE.Color( 0x88ff88 ),
+				wireframe: true,
+				depthTest: false,
+				depthWrite: false,
+				opacity: 0.25,
+				transparent: true
+			} )
+		);
+
+		this.materials.push(
+			new THREE.MeshBasicMaterial( {
+				color: new THREE.Color( 0x8888ff ),
+				wireframe: true,
+				depthTest: false,
+				depthWrite: false,
+				opacity: 0.25,
+				transparent: true
+			} )
+		);
+
+		this._init();
+
 	}
 	}
 
 
-	// copy from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mytest37.js?ver=20160815
-	function createCapsuleGeometry( radius, cylinderHeight, segmentsRadius, segmentsHeight ) {
+	MMDPhysicsHelper.prototype = Object.assign( Object.create( THREE.Object3D.prototype ), {
 
 
-		var geometry = new THREE.CylinderBufferGeometry( radius, radius, cylinderHeight, segmentsRadius, segmentsHeight, true );
-		var upperSphere = new THREE.Mesh( new THREE.SphereBufferGeometry( radius, segmentsRadius, segmentsHeight, 0, Math.PI * 2, 0, Math.PI / 2 ) );
-		var lowerSphere = new THREE.Mesh( new THREE.SphereBufferGeometry( radius, segmentsRadius, segmentsHeight, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2 ) );
+		constructor: MMDPhysicsHelper,
 
 
-		upperSphere.position.set( 0, cylinderHeight / 2, 0 );
-		lowerSphere.position.set( 0, -cylinderHeight / 2, 0 );
+		/**
+		 * Updates Rigid Bodies visualization.
+		 */
+		updateMatrixWorld: function () {
 
 
-		upperSphere.updateMatrix();
-		lowerSphere.updateMatrix();
+			var position = new THREE.Vector3();
+			var quaternion = new THREE.Quaternion();
+			var scale = new THREE.Vector3();
+			var matrixWorldInv = new THREE.Matrix4();
 
 
-		geometry.merge( upperSphere.geometry, upperSphere.matrix );
-		geometry.merge( lowerSphere.geometry, lowerSphere.matrix );
+			return function updateMatrixWorld( force ) {
 
 
-		return geometry;
+				var mesh = this.root;
 
 
-	}
+				if ( this.visible ) {
 
 
-	for ( var i = 0, il = rigidBodies.length; i < il; i ++ ) {
+					var bodies = this.physics.bodies;
 
 
-		var param = rigidBodies[ i ];
-		this.add( new THREE.Mesh( createGeometry( param ), this.materials[ param.type ] ) );
+					matrixWorldInv
+						.copy( mesh.matrixWorld )
+						.decompose( position, quaternion, scale )
+						.compose( position, quaternion, scale.set( 1, 1, 1 ) )
+						.getInverse( matrixWorldInv );
 
 
-	}
+					for ( var i = 0, il = bodies.length; i < il; i ++ ) {
 
 
-};
+						var body = bodies[ i ].body;
+						var child = this.children[ i ];
 
 
-THREE.MMDPhysicsHelper.prototype.update = function () {
+						var tr = body.getCenterOfMassTransform();
+						var origin = tr.getOrigin();
+						var rotation = tr.getRotation();
 
 
-	var mesh = this.root;
-	var rigidBodies = mesh.geometry.rigidBodies;
-	var bodies = mesh.physics.bodies;
+						child.position
+							.set( origin.x(), origin.y(), origin.z() )
+							.applyMatrix4( matrixWorldInv );
 
 
-	var matrixWorldInv = new THREE.Matrix4().getInverse( mesh.matrixWorld );
-	var vector = new THREE.Vector3();
-	var quaternion = new THREE.Quaternion();
-	var quaternion2 = new THREE.Quaternion();
+						child.quaternion
+							.setFromRotationMatrix( matrixWorldInv )
+							.multiply(
+								quaternion.set(
+									rotation.x(), rotation.y(), rotation.z(), rotation.w() )
+							);
 
 
-	function getPosition( origin ) {
+					}
 
 
-		vector.set( origin.x(), origin.y(), origin.z() );
-		vector.applyMatrix4( matrixWorldInv );
+				}
 
 
-		return vector;
+				this.matrix
+					.copy( mesh.matrixWorld )
+					.decompose( position, quaternion, scale )
+					.compose( position, quaternion, scale.set( 1, 1, 1 ) );
 
 
-	}
+				THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
 
 
-	function getQuaternion( rotation ) {
+			};
 
 
-		quaternion.set( rotation.x(), rotation.y(), rotation.z(), rotation.w() );
-		quaternion2.setFromRotationMatrix( matrixWorldInv );
-		quaternion2.multiply( quaternion );
+		}(),
 
 
-		return quaternion2;
+		// private method
 
 
-	}
+		_init: function () {
 
 
-	for ( var i = 0, il = rigidBodies.length; i < il; i ++ ) {
+			var mesh = this.root;
+			var bodies = this.physics.bodies;
 
 
-		var body = bodies[ i ].body;
-		var mesh = this.children[ i ];
+			function createGeometry( param ) {
 
 
-		var tr = body.getCenterOfMassTransform();
+				switch ( param.shapeType ) {
 
 
-		mesh.position.copy( getPosition( tr.getOrigin() ) );
-		mesh.quaternion.copy( getQuaternion( tr.getRotation() ) );
+					case 0:
+						return new THREE.SphereBufferGeometry( param.width, 16, 8 );
 
 
-	}
+					case 1:
+						return new THREE.BoxBufferGeometry( param.width * 2, param.height * 2, param.depth * 2, 8, 8, 8 );
+
+					case 2:
+						return new createCapsuleGeometry( param.width, param.height, 16, 8 );
+
+					default:
+						return null;
+
+				}
+
+			}
+
+			// copy from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mytest37.js?ver=20160815
+			function createCapsuleGeometry( radius, cylinderHeight, segmentsRadius, segmentsHeight ) {
+
+				var geometry = new THREE.CylinderBufferGeometry( radius, radius, cylinderHeight, segmentsRadius, segmentsHeight, true );
+				var upperSphere = new THREE.Mesh( new THREE.SphereBufferGeometry( radius, segmentsRadius, segmentsHeight, 0, Math.PI * 2, 0, Math.PI / 2 ) );
+				var lowerSphere = new THREE.Mesh( new THREE.SphereBufferGeometry( radius, segmentsRadius, segmentsHeight, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2 ) );
+
+				upperSphere.position.set( 0, cylinderHeight / 2, 0 );
+				lowerSphere.position.set( 0, - cylinderHeight / 2, 0 );
+
+				upperSphere.updateMatrix();
+				lowerSphere.updateMatrix();
+
+				geometry.merge( upperSphere.geometry, upperSphere.matrix );
+				geometry.merge( lowerSphere.geometry, lowerSphere.matrix );
+
+				return geometry;
+
+			}
+
+			for ( var i = 0, il = bodies.length; i < il; i ++ ) {
+
+				var param = bodies[ i ].params;
+				this.add( new THREE.Mesh( createGeometry( param ), this.materials[ param.type ] ) );
+
+			}
+
+		}
+
+	} );
+
+	return MMDPhysics;
 
 
-};
+} )();

+ 14 - 6
examples/js/cameras/CinematicCamera.js

@@ -5,20 +5,28 @@
  * @author kaypiKun
  * @author kaypiKun
  */
  */
 
 
-THREE.CinematicCamera = function( fov, aspect, near, far ) {
+THREE.CinematicCamera = function ( fov, aspect, near, far ) {
 
 
 	THREE.PerspectiveCamera.call( this, fov, aspect, near, far );
 	THREE.PerspectiveCamera.call( this, fov, aspect, near, far );
 
 
-	this.type = "CinematicCamera";
+	this.type = 'CinematicCamera';
 
 
-	this.postprocessing = { enabled	: true };
+	this.postprocessing = { enabled: true };
 	this.shaderSettings = {
 	this.shaderSettings = {
 		rings: 3,
 		rings: 3,
 		samples: 4
 		samples: 4
 	};
 	};
 
 
-	this.material_depth = new THREE.MeshDepthMaterial();
-	this.material_depth.depthPacking = THREE.RGBADepthPacking;
+	var depthShader = THREE.BokehDepthShader;
+
+	this.materialDepth = new THREE.ShaderMaterial( {
+		uniforms: depthShader.uniforms,
+		vertexShader: depthShader.vertexShader,
+		fragmentShader: depthShader.fragmentShader
+	} );
+
+	this.materialDepth.uniforms[ 'mNear' ].value = near;
+	this.materialDepth.uniforms[ 'mFar' ].value = far;
 
 
 	// In case of cinematicCamera, having a default lens set is important
 	// In case of cinematicCamera, having a default lens set is important
 	this.setLens();
 	this.setLens();
@@ -178,7 +186,7 @@ THREE.CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) {
 
 
 		// Render depth into texture
 		// Render depth into texture
 
 
-		scene.overrideMaterial = this.material_depth;
+		scene.overrideMaterial = this.materialDepth;
 		renderer.render( scene, camera, this.postprocessing.rtTextureDepth, true );
 		renderer.render( scene, camera, this.postprocessing.rtTextureDepth, true );
 
 
 		// Render bokeh composite
 		// Render bokeh composite

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

@@ -461,10 +461,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
 		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
 
 
-		// rotating across whole screen goes 360 degrees around
-		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth );
+		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
 
 
-		// rotating up and down along whole screen attempts to go 360, but limited to 180
 		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
 		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
 
 
 		rotateStart.copy( rotateEnd );
 		rotateStart.copy( rotateEnd );
@@ -611,10 +609,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
 		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
 
 
-		// rotating across whole screen goes 360 degrees around
-		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth );
+		rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
 
 
-		// rotating up and down along whole screen attempts to go 360, but limited to 180
 		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
 		rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
 
 
 		rotateStart.copy( rotateEnd );
 		rotateStart.copy( rotateEnd );

+ 4 - 12
examples/js/controls/TransformControls.js

@@ -227,12 +227,8 @@
 
 
 		THREE.TransformGizmo.call( this );
 		THREE.TransformGizmo.call( this );
 
 
-		var arrowGeometry = new THREE.Geometry();
-		var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) );
-		mesh.position.y = 0.5;
-		mesh.updateMatrix();
-
-		arrowGeometry.merge( mesh.geometry, mesh.matrix );
+		var arrowGeometry = new THREE.ConeBufferGeometry( 0.05, 0.2, 12, 1, false );
+		arrowGeometry.translate( 0, 0.5, 0 );
 
 
 		var lineXGeometry = new THREE.BufferGeometry();
 		var lineXGeometry = new THREE.BufferGeometry();
 		lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
 		lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
@@ -505,12 +501,8 @@
 
 
 		THREE.TransformGizmo.call( this );
 		THREE.TransformGizmo.call( this );
 
 
-		var arrowGeometry = new THREE.Geometry();
-		var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) );
-		mesh.position.y = 0.5;
-		mesh.updateMatrix();
-
-		arrowGeometry.merge( mesh.geometry, mesh.matrix );
+		var arrowGeometry = new THREE.BoxBufferGeometry( 0.125, 0.125, 0.125 );
+		arrowGeometry.translate( 0, 0.5, 0 );
 
 
 		var lineXGeometry = new THREE.BufferGeometry();
 		var lineXGeometry = new THREE.BufferGeometry();
 		lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0,  1, 0, 0 ], 3 ) );
 		lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0,  1, 0, 0 ], 3 ) );

+ 32 - 33
examples/js/crossfade/scenes.js

@@ -1,76 +1,75 @@
 function generateGeometry( objectType, numObjects ) {
 function generateGeometry( objectType, numObjects ) {
 
 
-	var geometry = new THREE.Geometry();
+	function applyVertexColors( geometry, color ) {
 
 
-	function applyVertexColors( g, c ) {
+		var position = geometry.attributes.position;
+		var colors = [];
 
 
-		g.faces.forEach( function( f ) {
+		for ( var i = 0; i < position.count; i ++ ) {
 
 
-			var n = ( f instanceof THREE.Face3 ) ? 3 : 4;
+			colors.push( color.r, color.g, color.b );
 
 
-			for ( var j = 0; j < n; j ++ ) {
+		}
 
 
-				f.vertexColors[ j ] = c;
+		geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
 
 
-			}
+	}
 
 
-		} );
+	var geometries = [];
 
 
-	}
+	var matrix = new THREE.Matrix4();
+	var position = new THREE.Vector3();
+	var rotation = new THREE.Euler();
+	var quaternion = new THREE.Quaternion();
+	var scale = new THREE.Vector3();
+	var color = new THREE.Color();
 
 
 	for ( var i = 0; i < numObjects; i ++ ) {
 	for ( var i = 0; i < numObjects; i ++ ) {
 
 
-		var position = new THREE.Vector3();
-
 		position.x = Math.random() * 10000 - 5000;
 		position.x = Math.random() * 10000 - 5000;
 		position.y = Math.random() * 6000 - 3000;
 		position.y = Math.random() * 6000 - 3000;
 		position.z = Math.random() * 8000 - 4000;
 		position.z = Math.random() * 8000 - 4000;
 
 
-		var rotation = new THREE.Euler();
-
 		rotation.x = Math.random() * 2 * Math.PI;
 		rotation.x = Math.random() * 2 * Math.PI;
 		rotation.y = Math.random() * 2 * Math.PI;
 		rotation.y = Math.random() * 2 * Math.PI;
 		rotation.z = Math.random() * 2 * Math.PI;
 		rotation.z = Math.random() * 2 * Math.PI;
-
-		var scale = new THREE.Vector3();
-
-		var geom, color = new THREE.Color();
+		quaternion.setFromEuler( rotation, false );
 
 
 		scale.x = Math.random() * 200 + 100;
 		scale.x = Math.random() * 200 + 100;
 
 
-		if ( objectType == "cube" ) {
+		var geometry;
+
+		if ( objectType === 'cube' ) {
 
 
-			geom = new THREE.BoxGeometry( 1, 1, 1 );
+			geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
+			geometry = geometry.toNonIndexed(); // merging needs consistent buffer geometries
 			scale.y = Math.random() * 200 + 100;
 			scale.y = Math.random() * 200 + 100;
 			scale.z = Math.random() * 200 + 100;
 			scale.z = Math.random() * 200 + 100;
-			color.setRGB( 0, 0, Math.random() + 0.1 );
+			color.setRGB( 0, 0, 0.1 + 0.9 * Math.random() );
 
 
-		} else if ( objectType == "sphere" ) {
+		} else if ( objectType === 'sphere' ) {
 
 
-			geom = new THREE.IcosahedronGeometry( 1, 1 );
+			geometry = new THREE.IcosahedronBufferGeometry( 1, 1 );
 			scale.y = scale.z = scale.x;
 			scale.y = scale.z = scale.x;
-			color.setRGB( Math.random() + 0.1, 0, 0 );
+			color.setRGB( 0.1 + 0.9 * Math.random(), 0, 0 );
 
 
 		}
 		}
 
 
 		// give the geom's vertices a random color, to be displayed
 		// give the geom's vertices a random color, to be displayed
-		applyVertexColors( geom, color );
+		applyVertexColors( geometry, color );
 
 
-		var mesh = new THREE.Mesh( geom );
-		mesh.position.copy( position );
-		mesh.rotation.copy( rotation );
-		mesh.scale.copy( scale );
-		mesh.updateMatrix();
+		matrix.compose( position, quaternion, scale );
+		geometry.applyMatrix( matrix );
 
 
-		geometry.merge( mesh.geometry, mesh.matrix );
+		geometries.push( geometry );
 
 
 	}
 	}
 
 
-	return geometry;
+	return THREE.BufferGeometryUtils.mergeBufferGeometries( geometries );
 
 
 }
 }
 
 
-function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
+function Scene( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
 
 
 	this.clearColor = clearColor;
 	this.clearColor = clearColor;
 
 
@@ -94,7 +93,7 @@ function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
 	var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
 	var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
 	this.fbo = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
 	this.fbo = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
 
 
-	this.render = function( delta, rtt ) {
+	this.render = function ( delta, rtt ) {
 
 
 		this.mesh.rotation.x += delta * this.rotationSpeed.x;
 		this.mesh.rotation.x += delta * this.rotationSpeed.x;
 		this.mesh.rotation.y += delta * this.rotationSpeed.y;
 		this.mesh.rotation.y += delta * this.rotationSpeed.y;

+ 2 - 4
examples/js/curves/NURBSSurface.js

@@ -42,14 +42,12 @@ THREE.NURBSSurface.prototype = {
 
 
 	constructor: THREE.NURBSSurface,
 	constructor: THREE.NURBSSurface,
 
 
-	getPoint: function ( t1, t2 ) {
+	getPoint: function ( t1, t2, target ) {
 
 
 		var u = this.knots1[ 0 ] + t1 * ( this.knots1[ this.knots1.length - 1 ] - this.knots1[ 0 ] ); // linear mapping t1->u
 		var u = this.knots1[ 0 ] + t1 * ( this.knots1[ this.knots1.length - 1 ] - this.knots1[ 0 ] ); // linear mapping t1->u
 		var v = this.knots2[ 0 ] + t2 * ( this.knots2[ this.knots2.length - 1 ] - this.knots2[ 0 ] ); // linear mapping t2->u
 		var v = this.knots2[ 0 ] + t2 * ( this.knots2[ this.knots2.length - 1 ] - this.knots2[ 0 ] ); // linear mapping t2->u
 
 
-		return THREE.NURBSUtils.calcSurfacePoint( this.degree1, this.degree2, this.knots1, this.knots2, this.controlPoints, u, v );
+		THREE.NURBSUtils.calcSurfacePoint( this.degree1, this.degree2, this.knots1, this.knots2, this.controlPoints, u, v, target );
 
 
 	}
 	}
 };
 };
-
-

+ 11 - 14
examples/js/curves/NURBSUtils.js

@@ -19,7 +19,7 @@ THREE.NURBSUtils = {
 	p : degree
 	p : degree
 	u : parametric value
 	u : parametric value
 	U : knot vector
 	U : knot vector
-	
+
 	returns the span
 	returns the span
 	*/
 	*/
 	findSpan: function( p,  u,  U ) {
 	findSpan: function( p,  u,  U ) {
@@ -43,7 +43,7 @@ THREE.NURBSUtils = {
 		var mid = Math.floor( ( low + high ) / 2 );
 		var mid = Math.floor( ( low + high ) / 2 );
 
 
 		while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
 		while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
-		  
+
 			if ( u < U[ mid ] ) {
 			if ( u < U[ mid ] ) {
 
 
 				high = mid;
 				high = mid;
@@ -61,16 +61,16 @@ THREE.NURBSUtils = {
 		return mid;
 		return mid;
 
 
 	},
 	},
-    
-		
+
+
 	/*
 	/*
 	Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
 	Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
-   
+
 	span : span in which u lies
 	span : span in which u lies
 	u    : parametric point
 	u    : parametric point
 	p    : degree
 	p    : degree
 	U    : knot vector
 	U    : knot vector
-	
+
 	returns array[p+1] with basis functions values.
 	returns array[p+1] with basis functions values.
 	*/
 	*/
 	calcBasisFunctions: function( span, u, p, U ) {
 	calcBasisFunctions: function( span, u, p, U ) {
@@ -81,7 +81,7 @@ THREE.NURBSUtils = {
 		N[ 0 ] = 1.0;
 		N[ 0 ] = 1.0;
 
 
 		for ( var j = 1; j <= p; ++ j ) {
 		for ( var j = 1; j <= p; ++ j ) {
-	   
+
 			left[ j ] = u - U[ span + 1 - j ];
 			left[ j ] = u - U[ span + 1 - j ];
 			right[ j ] = U[ span + j ] - u;
 			right[ j ] = U[ span + j ] - u;
 
 
@@ -108,7 +108,7 @@ THREE.NURBSUtils = {
 
 
 	/*
 	/*
 	Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
 	Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
- 
+
 	p : degree of B-Spline
 	p : degree of B-Spline
 	U : knot vector
 	U : knot vector
 	P : control points (x, y, z, w)
 	P : control points (x, y, z, w)
@@ -422,7 +422,7 @@ THREE.NURBSUtils = {
 
 
 	/*
 	/*
 	Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
 	Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
- 
+
 	p1, p2 : degrees of B-Spline surface
 	p1, p2 : degrees of B-Spline surface
 	U1, U2 : knot vectors
 	U1, U2 : knot vectors
 	P      : control points (x, y, z, w)
 	P      : control points (x, y, z, w)
@@ -430,7 +430,7 @@ THREE.NURBSUtils = {
 
 
 	returns point for given (u, v)
 	returns point for given (u, v)
 	*/
 	*/
-	calcSurfacePoint: function( p, q, U, V, P, u, v ) {
+	calcSurfacePoint: function ( p, q, U, V, P, u, v, target ) {
 
 
 		var uspan = this.findSpan( p, u, U );
 		var uspan = this.findSpan( p, u, U );
 		var vspan = this.findSpan( q, v, V );
 		var vspan = this.findSpan( q, v, V );
@@ -462,11 +462,8 @@ THREE.NURBSUtils = {
 		}
 		}
 
 
 		Sw.divideScalar( Sw.w );
 		Sw.divideScalar( Sw.w );
-		return new THREE.Vector3( Sw.x, Sw.y, Sw.z );
+		target.set( Sw.x, Sw.y, Sw.z );
 
 
 	}
 	}
 
 
 };
 };
-
-
-

+ 8 - 8
examples/js/effects/OutlineEffect.js

@@ -6,15 +6,15 @@
  * // How to set default outline parameters
  * // How to set default outline parameters
  * new THREE.OutlineEffect( renderer, {
  * new THREE.OutlineEffect( renderer, {
  * 	defaultThickNess: 0.01,
  * 	defaultThickNess: 0.01,
- * 	defaultColor: new THREE.Color( 0x888888 ),
+ * 	defaultColor: [ 0, 0, 0 ],
  * 	defaultAlpha: 0.8,
  * 	defaultAlpha: 0.8,
  * 	defaultKeepAlive: true // keeps outline material in cache even if material is removed from scene
  * 	defaultKeepAlive: true // keeps outline material in cache even if material is removed from scene
  * } );
  * } );
  *
  *
  * // How to set outline parameters for each material
  * // How to set outline parameters for each material
- * material.outlineParameters = {
+ * material.userData.outlineParameters = {
  * 	thickNess: 0.01,
  * 	thickNess: 0.01,
- * 	color: new THREE.Color( 0x888888 ),
+ * 	color: [ 0, 0, 0 ]
  * 	alpha: 0.8,
  * 	alpha: 0.8,
  * 	visible: true,
  * 	visible: true,
  * 	keepAlive: true
  * 	keepAlive: true
@@ -31,7 +31,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 	this.enabled = true;
 	this.enabled = true;
 
 
 	var defaultThickness = parameters.defaultThickness !== undefined ? parameters.defaultThickness : 0.003;
 	var defaultThickness = parameters.defaultThickness !== undefined ? parameters.defaultThickness : 0.003;
-	var defaultColor = parameters.defaultColor !== undefined ? parameters.defaultColor : new THREE.Color( 0x000000 );
+	var defaultColor = new THREE.Color().fromArray( parameters.defaultColor !== undefined ? parameters.defaultColor : [ 0, 0, 0 ] );
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
 	var defaultKeepAlive = parameters.defaultKeepAlive !== undefined ? parameters.defaultKeepAlive : false;
 	var defaultKeepAlive = parameters.defaultKeepAlive !== undefined ? parameters.defaultKeepAlive : false;
 
 
@@ -140,7 +140,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		var shaderID = shaderIDs[ originalMaterial.type ];
 		var shaderID = shaderIDs[ originalMaterial.type ];
 		var originalUniforms, originalVertexShader;
 		var originalUniforms, originalVertexShader;
-		var outlineParameters = originalMaterial.outlineParameters;
+		var outlineParameters = originalMaterial.userData.outlineParameters;
 
 
 		if ( shaderID !== undefined ) {
 		if ( shaderID !== undefined ) {
 
 
@@ -300,14 +300,14 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	function updateUniforms( material, originalMaterial ) {
 	function updateUniforms( material, originalMaterial ) {
 
 
-		var outlineParameters = originalMaterial.outlineParameters;
+		var outlineParameters = originalMaterial.userData.outlineParameters;
 
 
 		material.uniforms.outlineAlpha.value = originalMaterial.opacity;
 		material.uniforms.outlineAlpha.value = originalMaterial.opacity;
 
 
 		if ( outlineParameters !== undefined ) {
 		if ( outlineParameters !== undefined ) {
 
 
 			if ( outlineParameters.thickness !== undefined ) material.uniforms.outlineThickness.value = outlineParameters.thickness;
 			if ( outlineParameters.thickness !== undefined ) material.uniforms.outlineThickness.value = outlineParameters.thickness;
-			if ( outlineParameters.color !== undefined ) material.uniforms.outlineColor.value.copy( outlineParameters.color );
+			if ( outlineParameters.color !== undefined ) material.uniforms.outlineColor.value.fromArray( outlineParameters.color );
 			if ( outlineParameters.alpha !== undefined ) material.uniforms.outlineAlpha.value = outlineParameters.alpha;
 			if ( outlineParameters.alpha !== undefined ) material.uniforms.outlineAlpha.value = outlineParameters.alpha;
 
 
 		}
 		}
@@ -318,7 +318,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		if ( material.name === 'invisible' ) return;
 		if ( material.name === 'invisible' ) return;
 
 
-		var outlineParameters = originalMaterial.outlineParameters;
+		var outlineParameters = originalMaterial.userData.outlineParameters;
 
 
 		material.skinning = originalMaterial.skinning;
 		material.skinning = originalMaterial.skinning;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphTargets = originalMaterial.morphTargets;

+ 35 - 9
examples/js/exporters/GLTFExporter.js

@@ -66,6 +66,7 @@ THREE.GLTFExporter.prototype = {
 	parse: function ( input, onDone, options ) {
 	parse: function ( input, onDone, options ) {
 
 
 		var DEFAULT_OPTIONS = {
 		var DEFAULT_OPTIONS = {
+			binary: false,
 			trs: false,
 			trs: false,
 			onlyVisible: true,
 			onlyVisible: true,
 			truncateDrawRange: true,
 			truncateDrawRange: true,
@@ -325,6 +326,29 @@ THREE.GLTFExporter.prototype = {
 
 
 		}
 		}
 
 
+		/**
+		 * Serializes a userData.
+		 *
+		 * @param {THREE.Object3D|THREE.Material} object
+		 * @returns {Object}
+		 */
+		function serializeUserData( object ) {
+
+			try {
+
+				return JSON.parse( JSON.stringify( object.userData ) );
+
+			} catch ( error ) {
+
+				console.warn( 'THREE.GLTFExporter: userData of \'' + object.name + '\' ' +
+					'won\'t be serialized because of JSON.stringify error - ' + error.message );
+
+				return {};
+
+			}
+
+		}
+
 		/**
 		/**
 		 * Process a buffer to append to the default one.
 		 * Process a buffer to append to the default one.
 		 * @param  {ArrayBuffer} buffer
 		 * @param  {ArrayBuffer} buffer
@@ -936,6 +960,12 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
+			if ( Object.keys( material.userData ).length > 0 ) {
+
+				gltfMaterial.extras = serializeUserData( material );
+
+			}
+
 			outputJSON.materials.push( gltfMaterial );
 			outputJSON.materials.push( gltfMaterial );
 
 
 			var index = outputJSON.materials.length - 1;
 			var index = outputJSON.materials.length - 1;
@@ -1152,6 +1182,8 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
+			var extras = ( Object.keys( geometry.userData ).length > 0 ) ? serializeUserData( geometry ) : undefined;
+
 			var forceIndices = options.forceIndices;
 			var forceIndices = options.forceIndices;
 			var isMultiMaterial = Array.isArray( mesh.material );
 			var isMultiMaterial = Array.isArray( mesh.material );
 
 
@@ -1193,6 +1225,8 @@ THREE.GLTFExporter.prototype = {
 					attributes: attributes,
 					attributes: attributes,
 				};
 				};
 
 
+				if ( extras ) primitive.extras = extras;
+
 				if ( targets.length > 0 ) primitive.targets = targets;
 				if ( targets.length > 0 ) primitive.targets = targets;
 
 
 				if ( geometry.index !== null ) {
 				if ( geometry.index !== null ) {
@@ -1512,15 +1546,7 @@ THREE.GLTFExporter.prototype = {
 
 
 			if ( object.userData && Object.keys( object.userData ).length > 0 ) {
 			if ( object.userData && Object.keys( object.userData ).length > 0 ) {
 
 
-				try {
-
-					gltfNode.extras = JSON.parse( JSON.stringify( object.userData ) );
-
-				} catch ( e ) {
-
-					throw new Error( 'THREE.GLTFExporter: userData can\'t be serialized' );
-
-				}
+				gltfNode.extras = serializeUserData( object );
 
 
 			}
 			}
 
 

+ 417 - 112
examples/js/exporters/PLYExporter.js

@@ -5,9 +5,8 @@
  * Usage:
  * Usage:
  *  var exporter = new THREE.PLYExporter();
  *  var exporter = new THREE.PLYExporter();
  *
  *
- *  // second argument is an array of attributes to
- *  // exclude from the format ('color', 'uv', 'normal')
- *  var data = exporter.parse(mesh, [ 'color' ]);
+ *  // second argument is a list of options
+ *  var data = exporter.parse( mesh, { binary: true, excludeAttributes: [ 'color' ] } );
  *
  *
  * Format Definition:
  * Format Definition:
  *  http://paulbourke.net/dataformats/ply/
  *  http://paulbourke.net/dataformats/ply/
@@ -19,40 +18,75 @@ THREE.PLYExporter.prototype = {
 
 
 	constructor: THREE.PLYExporter,
 	constructor: THREE.PLYExporter,
 
 
-	parse: function ( object, excludeProperties ) {
+	parse: function ( object, options ) {
 
 
-		if ( Array.isArray( excludeProperties ) !== true ) {
+		// Iterate over the valid meshes in the object
+		function traverseMeshes( cb ) {
 
 
-			excludeProperties = [];
+			object.traverse( function ( child ) {
+
+				if ( child.isMesh === true ) {
+
+					var mesh = child;
+					var geometry = mesh.geometry;
+
+					if ( geometry.isGeometry === true ) {
+
+						geometry = geomToBufferGeom.get( geometry );
+
+					}
+
+					if ( geometry.isBufferGeometry === true ) {
+
+						if ( geometry.getAttribute( 'position' ) !== undefined ) {
+
+							cb( mesh, geometry );
+
+						}
+
+					}
+
+				}
+
+			} );
 
 
 		}
 		}
 
 
-		var includeNormals = excludeProperties.indexOf( 'normal' ) === - 1;
-		var includeColors = excludeProperties.indexOf( 'color' ) === - 1;
-		var includeUVs = excludeProperties.indexOf( 'uv' ) === - 1;
+		// Default options
+		var defaultOptions = {
+			binary: false,
+			excludeAttributes: [] // normal, uv, color, index
+		};
+
+		options = Object.assign( defaultOptions, options );
 
 
-		// count the number of vertices
+		var excludeAttributes = options.excludeAttributes;
+		var geomToBufferGeom = new WeakMap();
+		var includeNormals = false;
+		var includeColors = false;
+		var includeUVs = false;
+		var includeIndices = true;
+
+		// count the vertices, check which properties are used,
+		// and cache the BufferGeometry
 		var vertexCount = 0;
 		var vertexCount = 0;
 		var faceCount = 0;
 		var faceCount = 0;
-		var vertexList = '';
-		var faceList = '';
-
-		var vertex = new THREE.Vector3();
-		var normalMatrixWorld = new THREE.Matrix3();
 		object.traverse( function ( child ) {
 		object.traverse( function ( child ) {
 
 
-			if ( child instanceof THREE.Mesh ) {
+			if ( child.isMesh === true ) {
 
 
 				var mesh = child;
 				var mesh = child;
 				var geometry = mesh.geometry;
 				var geometry = mesh.geometry;
 
 
-				if ( geometry instanceof THREE.Geometry ) {
+				if ( geometry.isGeometry === true ) {
 
 
-					geometry = new THREE.BufferGeometry().setFromObject( mesh );
+					var bufferGeometry = geomToBufferGeom.get( geometry ) || new THREE.BufferGeometry().setFromObject( mesh );
+					geomToBufferGeom.set( geometry, bufferGeometry );
+					geometry = bufferGeometry;
 
 
 				}
 				}
 
 
-				if ( geometry instanceof THREE.BufferGeometry ) {
+				if ( geometry.isBufferGeometry === true ) {
 
 
 					var vertices = geometry.getAttribute( 'position' );
 					var vertices = geometry.getAttribute( 'position' );
 					var normals = geometry.getAttribute( 'normal' );
 					var normals = geometry.getAttribute( 'normal' );
@@ -60,102 +94,279 @@ THREE.PLYExporter.prototype = {
 					var colors = geometry.getAttribute( 'color' );
 					var colors = geometry.getAttribute( 'color' );
 					var indices = geometry.getIndex();
 					var indices = geometry.getIndex();
 
 
-					normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
-
 					if ( vertices === undefined ) {
 					if ( vertices === undefined ) {
 
 
 						return;
 						return;
 
 
 					}
 					}
 
 
-					// form each line
-					for ( var i = 0, l = vertices.count; i < l; i ++ ) {
+					vertexCount += vertices.count;
+					faceCount += indices ? indices.count / 3 : vertices.count / 3;
+
+					if ( normals !== undefined ) includeNormals = true;
+
+					if ( uvs !== undefined ) includeUVs = true;
 
 
-						vertex.x = vertices.getX( i );
-						vertex.y = vertices.getY( i );
-						vertex.z = vertices.getZ( i );
+					if ( colors !== undefined ) includeColors = true;
 
 
-						vertex.applyMatrix4( mesh.matrixWorld );
+				}
 
 
+			}
 
 
-						// Position information
-						var line =
-							vertex.x + ' ' +
-							vertex.y + ' ' +
-							vertex.z;
+		} );
 
 
-						// Normal information
-						if ( includeNormals === true ) {
+		includeNormals = includeNormals && excludeAttributes.indexOf( 'normal' ) === - 1;
+		includeColors = includeColors && excludeAttributes.indexOf( 'color' ) === - 1;
+		includeUVs = includeUVs && excludeAttributes.indexOf( 'uv' ) === - 1;
+		includeIndices = includeIndices && excludeAttributes.indexOf( 'index' ) === - 1;
 
 
-							if ( normals !== undefined ) {
 
 
-								vertex.x = normals.getX( i );
-								vertex.y = normals.getY( i );
-								vertex.z = normals.getZ( i );
+		if ( includeIndices && faceCount !== Math.floor( faceCount ) ) {
 
 
-								vertex.applyMatrix3( normalMatrixWorld );
+			// point cloud meshes will not have an index array and may not have a
+			// number of vertices that is divisble by 3 (and therefore representable
+			// as triangles)
+			console.error(
 
 
-								line += ' ' +
-									vertex.x + ' ' +
-									vertex.y + ' ' +
-									vertex.z;
+				'PLYExporter: Failed to generate a valid PLY file with triangle indices because the ' +
+				'number of indices is not divisible by 3.'
 
 
-							} else {
+			);
 
 
-								line += ' 0 0 0';
+			return null;
 
 
-							}
+		}
 
 
-						}
+		// get how many bytes will be needed to save out the faces
+		// so we can use a minimal amount of memory / data
+		var indexByteCount = 1;
+
+		if ( vertexCount > 256 ) { // 2^8 bits
+
+			indexByteCount = 2;
+
+		}
+
+		if ( vertexCount > 65536 ) { // 2^16 bits
+
+			indexByteCount = 4;
+
+		}
+
+
+		var header =
+			'ply\n' +
+			`format ${ options.binary ? 'binary_big_endian' : 'ascii' } 1.0\n` +
+			`element vertex ${vertexCount}\n` +
+
+			// position
+			'property float x\n' +
+			'property float y\n' +
+			'property float z\n';
+
+		if ( includeNormals === true ) {
+
+			// normal
+			header +=
+				'property float nx\n' +
+				'property float ny\n' +
+				'property float nz\n';
+
+		}
+
+		if ( includeUVs === true ) {
+
+			// uvs
+			header +=
+				'property float s\n' +
+				'property float t\n';
+
+		}
+
+		if ( includeColors === true ) {
+
+			// colors
+			header +=
+				'property uchar red\n' +
+				'property uchar green\n' +
+				'property uchar blue\n';
+
+		}
+
+		if ( includeIndices === true ) {
+
+			// faces
+			header +=
+				`element face ${faceCount}\n` +
+				`property list uchar uint${ indexByteCount * 8 } vertex_index\n`;
+
+		}
 
 
-						// UV information
-						if ( includeUVs === true ) {
+		header += 'end_header\n';
 
 
-							if ( uvs !== undefined ) {
 
 
-								line += ' ' +
-									uvs.getX( i ) + ' ' +
-									uvs.getY( i );
+		// Generate attribute data
+		var vertex = new THREE.Vector3();
+		var normalMatrixWorld = new THREE.Matrix3();
+
+		if ( options.binary === true ) {
+
+			// Binary File Generation
+			var headerBin = new TextEncoder().encode( header );
+
+			// 3 position values at 4 bytes
+			// 3 normal values at 4 bytes
+			// 3 color channels with 1 byte
+			// 2 uv values at 4 bytes
+			var vertexListLength = vertexCount * ( 4 * 3 + ( includeNormals ? 4 * 3 : 0 ) + ( includeColors ? 3 : 0 ) + ( includeUVs ? 4 * 2 : 0 ) );
+
+			// 1 byte shape desciptor
+			// 3 vertex indices at ${indexByteCount} bytes
+			var faceListLength = includeIndices ? faceCount * ( indexByteCount * 3 + 1 ) : 0;
+			var output = new DataView( new ArrayBuffer( headerBin.length + vertexListLength + faceListLength ) );
+			new Uint8Array( output.buffer ).set( headerBin, 0 );
+
+
+			var vOffset = headerBin.length;
+			var fOffset = headerBin.length + vertexListLength;
+			var writtenVertices = 0;
+			traverseMeshes( function ( mesh, geometry ) {
+
+				var vertices = geometry.getAttribute( 'position' );
+				var normals = geometry.getAttribute( 'normal' );
+				var uvs = geometry.getAttribute( 'uv' );
+				var colors = geometry.getAttribute( 'color' );
+				var indices = geometry.getIndex();
+
+				normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
+
+				for ( var i = 0, l = vertices.count; i < l; i ++ ) {
+
+					vertex.x = vertices.getX( i );
+					vertex.y = vertices.getY( i );
+					vertex.z = vertices.getZ( i );
+
+					vertex.applyMatrix4( mesh.matrixWorld );
 
 
-							} else if ( includeUVs !== false ) {
 
 
-								line += ' 0 0';
+					// Position information
+					output.setFloat32( vOffset, vertex.x );
+					vOffset += 4;
 
 
-							}
+					output.setFloat32( vOffset, vertex.y );
+					vOffset += 4;
+
+					output.setFloat32( vOffset, vertex.z );
+					vOffset += 4;
+
+					// Normal information
+					if ( includeNormals === true ) {
+
+						if ( normals != null ) {
+
+							vertex.x = normals.getX( i );
+							vertex.y = normals.getY( i );
+							vertex.z = normals.getZ( i );
+
+							vertex.applyMatrix3( normalMatrixWorld );
+
+							output.setFloat32( vOffset, vertex.x );
+							vOffset += 4;
+
+							output.setFloat32( vOffset, vertex.y );
+							vOffset += 4;
+
+							output.setFloat32( vOffset, vertex.z );
+							vOffset += 4;
+
+						} else {
+
+							output.setFloat32( vOffset, 0 );
+							vOffset += 4;
+
+							output.setFloat32( vOffset, 0 );
+							vOffset += 4;
+
+							output.setFloat32( vOffset, 0 );
+							vOffset += 4;
 
 
 						}
 						}
 
 
-						// Color information
-						if ( includeColors === true ) {
+					}
 
 
-							if ( colors !== undefined ) {
+					// UV information
+					if ( includeUVs === true ) {
 
 
-								line += ' ' +
-									Math.floor( colors.getX( i ) ) + ' ' +
-									Math.floor( colors.getY( i ) ) + ' ' +
-									Math.floor( colors.getZ( i ) );
+						if ( uvs != null ) {
 
 
-							} else {
+							output.setFloat32( vOffset, uvs.getX( i ) );
+							vOffset += 4;
 
 
-								line += ' 255 255 255';
+							output.setFloat32( vOffset, uvs.getY( i ) );
+							vOffset += 4;
 
 
-							}
+						} else if ( includeUVs !== false ) {
+
+							output.setFloat32( vOffset, 0 );
+							vOffset += 4;
+
+							output.setFloat32( vOffset, 0 );
+							vOffset += 4;
 
 
 						}
 						}
 
 
-						vertexList += line + '\n';
+					}
+
+					// Color information
+					if ( includeColors === true ) {
+
+						if ( colors != null ) {
+
+							output.setUint8( vOffset, Math.floor( colors.getX( i ) * 255 ) );
+							vOffset += 1;
+
+							output.setUint8( vOffset, Math.floor( colors.getY( i ) * 255 ) );
+							vOffset += 1;
+
+							output.setUint8( vOffset, Math.floor( colors.getZ( i ) * 255 ) );
+							vOffset += 1;
+
+						} else {
+
+							output.setUint8( vOffset, 255 );
+							vOffset += 1;
+
+							output.setUint8( vOffset, 255 );
+							vOffset += 1;
+
+							output.setUint8( vOffset, 255 );
+							vOffset += 1;
+
+						}
 
 
 					}
 					}
 
 
+				}
+
+				if ( includeIndices === true ) {
 
 
 					// Create the face list
 					// Create the face list
+					var faceIndexFunc = `setUint${indexByteCount * 8}`;
 					if ( indices !== null ) {
 					if ( indices !== null ) {
 
 
-						for ( i = 0, l = indices.count; i < l; i += 3 ) {
+						for ( var i = 0, l = indices.count; i < l; i += 3 ) {
+
+							output.setUint8( fOffset, 3 );
+							fOffset += 1;
 
 
-							faceList += `3 ${ indices.getX( i + 0 ) + vertexCount }`;
-							faceList += ` ${ indices.getX( i + 1 ) + vertexCount }`;
-							faceList += ` ${ indices.getX( i + 2 ) + vertexCount }\n`;
+							output[ faceIndexFunc ]( fOffset, indices.getX( i + 0 ) + writtenVertices );
+							fOffset += indexByteCount;
+
+							output[ faceIndexFunc ]( fOffset, indices.getX( i + 1 ) + writtenVertices );
+							fOffset += indexByteCount;
+
+							output[ faceIndexFunc ]( fOffset, indices.getX( i + 2 ) + writtenVertices );
+							fOffset += indexByteCount;
 
 
 						}
 						}
 
 
@@ -163,70 +374,164 @@ THREE.PLYExporter.prototype = {
 
 
 						for ( var i = 0, l = vertices.count; i < l; i += 3 ) {
 						for ( var i = 0, l = vertices.count; i < l; i += 3 ) {
 
 
-							faceList += `3 ${ vertexCount + i } ${ vertexCount + i + 1 } ${ vertexCount + i + 2 }\n`;
+							output.setUint8( fOffset, 3 );
+							fOffset += 1;
+
+							output[ faceIndexFunc ]( fOffset, writtenVertices + i );
+							fOffset += indexByteCount;
+
+							output[ faceIndexFunc ]( fOffset, writtenVertices + i + 1 );
+							fOffset += indexByteCount;
+
+							output[ faceIndexFunc ]( fOffset, writtenVertices + i + 2 );
+							fOffset += indexByteCount;
 
 
 						}
 						}
 
 
 					}
 					}
 
 
-					vertexCount += vertices.count;
-					faceCount += indices ? indices.count / 3 : vertices.count / 3;
+				}
+
+
+				// Save the amount of verts we've already written so we can offset
+				// the face index on the next mesh
+				writtenVertices += vertices.count;
+
+			} );
+
+			return output;
+
+		} else {
+
+			// Ascii File Generation
+			// count the number of vertices
+			var writtenVertices = 0;
+			var vertexList = '';
+			var faceList = '';
+
+			traverseMeshes( function ( mesh, geometry ) {
+
+				var vertices = geometry.getAttribute( 'position' );
+				var normals = geometry.getAttribute( 'normal' );
+				var uvs = geometry.getAttribute( 'uv' );
+				var colors = geometry.getAttribute( 'color' );
+				var indices = geometry.getIndex();
+
+				normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
+
+				// form each line
+				for ( var i = 0, l = vertices.count; i < l; i ++ ) {
+
+					vertex.x = vertices.getX( i );
+					vertex.y = vertices.getY( i );
+					vertex.z = vertices.getZ( i );
+
+					vertex.applyMatrix4( mesh.matrixWorld );
+
+
+					// Position information
+					var line =
+						vertex.x + ' ' +
+						vertex.y + ' ' +
+						vertex.z;
+
+					// Normal information
+					if ( includeNormals === true ) {
+
+						if ( normals != null ) {
+
+							vertex.x = normals.getX( i );
+							vertex.y = normals.getY( i );
+							vertex.z = normals.getZ( i );
+
+							vertex.applyMatrix3( normalMatrixWorld );
+
+							line += ' ' +
+								vertex.x + ' ' +
+								vertex.y + ' ' +
+								vertex.z;
+
+						} else {
+
+							line += ' 0 0 0';
+
+						}
+
+					}
+
+					// UV information
+					if ( includeUVs === true ) {
+
+						if ( uvs != null ) {
+
+							line += ' ' +
+								uvs.getX( i ) + ' ' +
+								uvs.getY( i );
+
+						} else if ( includeUVs !== false ) {
+
+							line += ' 0 0';
+
+						}
+
+					}
+
+					// Color information
+					if ( includeColors === true ) {
+
+						if ( colors != null ) {
+
+							line += ' ' +
+								Math.floor( colors.getX( i ) * 255 ) + ' ' +
+								Math.floor( colors.getY( i ) * 255 ) + ' ' +
+								Math.floor( colors.getZ( i ) * 255 );
+
+						} else {
+
+							line += ' 255 255 255';
+
+						}
+
+					}
+
+					vertexList += line + '\n';
 
 
 				}
 				}
 
 
-			}
+				// Create the face list
+				if ( includeIndices === true ) {
 
 
-		} );
+					if ( indices !== null ) {
 
 
-		var output =
-			'ply\n' +
-			'format ascii 1.0\n' +
-			`element vertex ${vertexCount}\n` +
+						for ( var i = 0, l = indices.count; i < l; i += 3 ) {
 
 
-			// position
-			'property float x\n' +
-			'property float y\n' +
-			'property float z\n';
+							faceList += `3 ${ indices.getX( i + 0 ) + writtenVertices }`;
+							faceList += ` ${ indices.getX( i + 1 ) + writtenVertices }`;
+							faceList += ` ${ indices.getX( i + 2 ) + writtenVertices }\n`;
 
 
-		if ( includeNormals === true ) {
+						}
 
 
-			// normal
-			output +=
-				'property float nx\n' +
-				'property float ny\n' +
-				'property float nz\n';
+					} else {
 
 
-		}
+						for ( var i = 0, l = vertices.count; i < l; i += 3 ) {
 
 
-		if ( includeUVs === true ) {
+							faceList += `3 ${ writtenVertices + i } ${ writtenVertices + i + 1 } ${ writtenVertices + i + 2 }\n`;
 
 
-			// uvs
-			output +=
-				'property float s\n' +
-				'property float t\n';
+						}
 
 
-		}
+					}
 
 
-		if ( includeColors === true ) {
+					faceCount += indices ? indices.count / 3 : vertices.count / 3;
 
 
-			// colors
-			output +=
-				'property uchar red\n' +
-				'property uchar green\n' +
-				'property uchar blue\n';
+				}
 
 
-		}
+				writtenVertices += vertices.count;
 
 
-		// faces
-		output +=
-			`element face ${faceCount}\n` +
-			'property list uchar int vertex_index\n' +
-			'end_header\n' +
+			} );
 
 
-			`${vertexList}\n` +
-			`${faceList}\n`;
+			return `${ header }${vertexList}\n${ includeIndices ? `${faceList}\n` : '' }`;
 
 
-		return output;
+		}
 
 
 	}
 	}
 
 

+ 0 - 94
examples/js/exporters/STLBinaryExporter.js

@@ -1,94 +0,0 @@
-/**
- * @author kovacsv / http://kovacsv.hu/
- * @author mrdoob / http://mrdoob.com/
- * @author mudcube / http://mudcu.be/
- */
-
-THREE.STLBinaryExporter = function () {};
-
-THREE.STLBinaryExporter.prototype = {
-
-	constructor: THREE.STLBinaryExporter,
-
-	parse: ( function () {
-
-		var vector = new THREE.Vector3();
-		var normalMatrixWorld = new THREE.Matrix3();
-
-		return function parse( scene ) {
-
-			// We collect objects first, as we may need to convert from BufferGeometry to Geometry
-			var objects = [];
-			var triangles = 0;
-			scene.traverse( function ( object ) {
-
-				if ( ! ( object instanceof THREE.Mesh ) ) return;
-
-				var geometry = object.geometry;
-				if ( geometry instanceof THREE.BufferGeometry ) {
-
-					geometry = new THREE.Geometry().fromBufferGeometry( geometry );
-
-				}
-
-				if ( ! ( geometry instanceof THREE.Geometry ) ) return;
-				triangles += geometry.faces.length;
-
-				objects.push( {
-
-					geometry: geometry,
-					matrix: object.matrixWorld
-
-				} );
-
-			} );
-
-			var offset = 80; // skip header
-			var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4;
-			var arrayBuffer = new ArrayBuffer( bufferLength );
-			var output = new DataView( arrayBuffer );
-			output.setUint32( offset, triangles, true ); offset += 4;
-
-			// Traversing our collected objects
-			objects.forEach( function ( object ) {
-
-				var vertices = object.geometry.vertices;
-				var faces = object.geometry.faces;
-
-				normalMatrixWorld.getNormalMatrix( object.matrix );
-
-				for ( var i = 0, l = faces.length; i < l; i ++ ) {
-
-					var face = faces[ i ];
-
-					vector.copy( face.normal ).applyMatrix3( normalMatrixWorld ).normalize();
-
-					output.setFloat32( offset, vector.x, true ); offset += 4; // normal
-					output.setFloat32( offset, vector.y, true ); offset += 4;
-					output.setFloat32( offset, vector.z, true ); offset += 4;
-
-					var indices = [ face.a, face.b, face.c ];
-
-					for ( var j = 0; j < 3; j ++ ) {
-
-						vector.copy( vertices[ indices[ j ] ] ).applyMatrix4( object.matrix );
-
-						output.setFloat32( offset, vector.x, true ); offset += 4; // vertices
-						output.setFloat32( offset, vector.y, true ); offset += 4;
-						output.setFloat32( offset, vector.z, true ); offset += 4;
-
-					}
-
-					output.setUint16( offset, 0, true ); offset += 2; // attribute byte count
-
-				}
-
-			} );
-
-			return output;
-
-		};
-
-	}() )
-
-};

+ 110 - 25
examples/js/exporters/STLExporter.js

@@ -1,6 +1,15 @@
 /**
 /**
  * @author kovacsv / http://kovacsv.hu/
  * @author kovacsv / http://kovacsv.hu/
  * @author mrdoob / http://mrdoob.com/
  * @author mrdoob / http://mrdoob.com/
+ * @author mudcube / http://mudcu.be/
+ * @author Mugen87 / https://github.com/Mugen87
+ *
+ * Usage:
+ *  var exporter = new THREE.STLExporter();
+ *
+ *  // second argument is a list of options
+ *  var data = exporter.parse( mesh, { binary: true } );
+ *
  */
  */
 
 
 THREE.STLExporter = function () {};
 THREE.STLExporter = function () {};
@@ -14,65 +23,141 @@ THREE.STLExporter.prototype = {
 		var vector = new THREE.Vector3();
 		var vector = new THREE.Vector3();
 		var normalMatrixWorld = new THREE.Matrix3();
 		var normalMatrixWorld = new THREE.Matrix3();
 
 
-		return function parse( scene ) {
+		return function parse( scene, options ) {
 
 
-			var output = '';
+			if ( options === undefined ) options = {};
 
 
-			output += 'solid exported\n';
+			var binary = options.binary !== undefined ? options.binary : false;
+
+			//
+
+			var objects = [];
+			var triangles = 0;
 
 
 			scene.traverse( function ( object ) {
 			scene.traverse( function ( object ) {
 
 
-				if ( object instanceof THREE.Mesh ) {
+				if ( object.isMesh ) {
 
 
 					var geometry = object.geometry;
 					var geometry = object.geometry;
-					var matrixWorld = object.matrixWorld;
 
 
-					if ( geometry instanceof THREE.BufferGeometry ) {
+					if ( geometry.isBufferGeometry ) {
 
 
 						geometry = new THREE.Geometry().fromBufferGeometry( geometry );
 						geometry = new THREE.Geometry().fromBufferGeometry( geometry );
 
 
 					}
 					}
 
 
-					if ( geometry instanceof THREE.Geometry ) {
+					if ( geometry.isGeometry ) {
 
 
-						var vertices = geometry.vertices;
-						var faces = geometry.faces;
+						triangles += geometry.faces.length;
 
 
-						normalMatrixWorld.getNormalMatrix( matrixWorld );
+						objects.push( {
 
 
-						for ( var i = 0, l = faces.length; i < l; i ++ ) {
+							geometry: geometry,
+							matrixWorld: object.matrixWorld
 
 
-							var face = faces[ i ];
+						} );
 
 
-							vector.copy( face.normal ).applyMatrix3( normalMatrixWorld ).normalize();
+					}
 
 
-							output += '\tfacet normal ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
-							output += '\t\touter loop\n';
+				}
 
 
-							var indices = [ face.a, face.b, face.c ];
+			} );
 
 
-							for ( var j = 0; j < 3; j ++ ) {
+			if ( binary ) {
+
+				var offset = 80; // skip header
+				var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4;
+				var arrayBuffer = new ArrayBuffer( bufferLength );
+				var output = new DataView( arrayBuffer );
+				output.setUint32( offset, triangles, true ); offset += 4;
+
+				for ( var i = 0, il = objects.length; i < il; i ++ ) {
+
+					var object = objects[ i ];
+
+					var vertices = object.geometry.vertices;
+					var faces = object.geometry.faces;
+					var matrixWorld = object.matrixWorld;
 
 
-								vector.copy( vertices[ indices[ j ] ] ).applyMatrix4( matrixWorld );
+					normalMatrixWorld.getNormalMatrix( matrixWorld );
 
 
-								output += '\t\t\tvertex ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
+					for ( var j = 0, jl = faces.length; j < jl; j ++ ) {
 
 
-							}
+						var face = faces[ j ];
 
 
-							output += '\t\tendloop\n';
-							output += '\tendfacet\n';
+						vector.copy( face.normal ).applyMatrix3( normalMatrixWorld ).normalize();
+
+						output.setFloat32( offset, vector.x, true ); offset += 4; // normal
+						output.setFloat32( offset, vector.y, true ); offset += 4;
+						output.setFloat32( offset, vector.z, true ); offset += 4;
+
+						var indices = [ face.a, face.b, face.c ];
+
+						for ( var k = 0; k < 3; k ++ ) {
+
+							vector.copy( vertices[ indices[ k ] ] ).applyMatrix4( matrixWorld );
+
+							output.setFloat32( offset, vector.x, true ); offset += 4; // vertices
+							output.setFloat32( offset, vector.y, true ); offset += 4;
+							output.setFloat32( offset, vector.z, true ); offset += 4;
 
 
 						}
 						}
 
 
+						output.setUint16( offset, 0, true ); offset += 2; // attribute byte count
+
 					}
 					}
 
 
 				}
 				}
 
 
-			} );
+				return output;
+
+			} else {
+
+				var output = '';
+
+				output += 'solid exported\n';
+
+				for ( var i = 0, il = objects.length; i < il; i ++ ) {
+
+					var object = objects[ i ];
+
+					var vertices = object.geometry.vertices;
+					var faces = object.geometry.faces;
+					var matrixWorld = object.matrixWorld;
+
+					normalMatrixWorld.getNormalMatrix( matrixWorld );
+
+					for ( var j = 0, jl = faces.length; j < jl; j ++ ) {
+
+						var face = faces[ j ];
+
+						vector.copy( face.normal ).applyMatrix3( normalMatrixWorld ).normalize();
+
+						output += '\tfacet normal ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
+						output += '\t\touter loop\n';
+
+						var indices = [ face.a, face.b, face.c ];
+
+						for ( var k = 0; k < 3; k ++ ) {
+
+							vector.copy( vertices[ indices[ k ] ] ).applyMatrix4( matrixWorld );
+
+							output += '\t\t\tvertex ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
+
+						}
+
+						output += '\t\tendloop\n';
+						output += '\tendfacet\n';
+
+					}
+
+				}
+
+				output += 'endsolid exported\n';
 
 
-			output += 'endsolid exported\n';
+				return output;
 
 
-			return output;
+			}
 
 
 		};
 		};
 
 

File diff suppressed because it is too large
+ 0 - 1
examples/js/libs/draco/gltf/draco_decoder.js


BIN
examples/js/libs/draco/gltf/draco_decoder.wasm


File diff suppressed because it is too large
+ 3 - 0
examples/js/libs/draco/gltf/draco_encoder.js


+ 119 - 115
examples/js/libs/draco/gltf/draco_wasm_wrapper.js

@@ -1,115 +1,119 @@
-var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(c,f,n){c!=Array.prototype&&c!=Object.prototype&&(c[f]=n.value)};$jscomp.getGlobal=function(c){return"undefined"!=typeof window&&window===c?c:"undefined"!=typeof global&&null!=global?global:c};$jscomp.global=$jscomp.getGlobal(this);
-$jscomp.polyfill=function(c,f,n,D){if(f){n=$jscomp.global;c=c.split(".");for(D=0;D<c.length-1;D++){var g=c[D];g in n||(n[g]={});n=n[g]}c=c[c.length-1];D=n[c];f=f(D);f!=D&&null!=f&&$jscomp.defineProperty(n,c,{configurable:!0,writable:!0,value:f})}};$jscomp.polyfill("Math.imul",function(c){return c?c:function(f,c){f=Number(f);c=Number(c);var n=f&65535,g=c&65535;return n*g+((f>>>16&65535)*g+n*(c>>>16&65535)<<16>>>0)|0}},"es6","es3");
-$jscomp.polyfill("Math.clz32",function(c){return c?c:function(f){f=Number(f)>>>0;if(0===f)return 32;var c=0;0===(f&4294901760)&&(f<<=16,c+=16);0===(f&4278190080)&&(f<<=8,c+=8);0===(f&4026531840)&&(f<<=4,c+=4);0===(f&3221225472)&&(f<<=2,c+=2);0===(f&2147483648)&&c++;return c}},"es6","es3");$jscomp.polyfill("Math.trunc",function(c){return c?c:function(c){c=Number(c);if(isNaN(c)||Infinity===c||-Infinity===c||0===c)return c;var f=Math.floor(Math.abs(c));return 0>c?-f:f}},"es6","es3");
-$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0;$jscomp.Symbol=function(c){return $jscomp.SYMBOL_PREFIX+(c||"")+$jscomp.symbolCounter_++};
-$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var c=$jscomp.global.Symbol.iterator;c||(c=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[c]&&$jscomp.defineProperty(Array.prototype,c,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(c){var f=0;return $jscomp.iteratorPrototype(function(){return f<c.length?{done:!1,value:c[f++]}:{done:!0}})};
-$jscomp.iteratorPrototype=function(c){$jscomp.initSymbolIterator();c={next:c};c[$jscomp.global.Symbol.iterator]=function(){return this};return c};$jscomp.makeIterator=function(c){$jscomp.initSymbolIterator();var f=c[Symbol.iterator];return f?f.call(c):$jscomp.arrayIterator(c)};$jscomp.FORCE_POLYFILL_PROMISE=!1;
-$jscomp.polyfill("Promise",function(c){function f(){this.batch_=null}function n(c){return c instanceof g?c:new g(function(f,R){f(c)})}if(c&&!$jscomp.FORCE_POLYFILL_PROMISE)return c;f.prototype.asyncExecute=function(c){null==this.batch_&&(this.batch_=[],this.asyncExecuteBatch_());this.batch_.push(c);return this};f.prototype.asyncExecuteBatch_=function(){var c=this;this.asyncExecuteFunction(function(){c.executeBatch_()})};var D=$jscomp.global.setTimeout;f.prototype.asyncExecuteFunction=function(c){D(c,
-0)};f.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var c=this.batch_;this.batch_=[];for(var f=0;f<c.length;++f){var g=c[f];delete c[f];try{g()}catch(v){this.asyncThrow_(v)}}}this.batch_=null};f.prototype.asyncThrow_=function(c){this.asyncExecuteFunction(function(){throw c;})};var g=function(c){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var f=this.createResolveAndReject_();try{c(f.resolve,f.reject)}catch(u){f.reject(u)}};g.prototype.createResolveAndReject_=
-function(){function c(c){return function(R){g||(g=!0,c.call(f,R))}}var f=this,g=!1;return{resolve:c(this.resolveTo_),reject:c(this.reject_)}};g.prototype.resolveTo_=function(c){if(c===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(c instanceof g)this.settleSameAsPromise_(c);else{a:switch(typeof c){case "object":var f=null!=c;break a;case "function":f=!0;break a;default:f=!1}f?this.resolveToNonPromiseObj_(c):this.fulfill_(c)}};g.prototype.resolveToNonPromiseObj_=function(c){var f=
-void 0;try{f=c.then}catch(u){this.reject_(u);return}"function"==typeof f?this.settleSameAsThenable_(f,c):this.fulfill_(c)};g.prototype.reject_=function(c){this.settle_(2,c)};g.prototype.fulfill_=function(c){this.settle_(1,c)};g.prototype.settle_=function(c,f){if(0!=this.state_)throw Error("Cannot settle("+c+", "+f|"): Promise already settled in state"+this.state_);this.state_=c;this.result_=f;this.executeOnSettledCallbacks_()};g.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var c=
-this.onSettledCallbacks_,f=0;f<c.length;++f)c[f].call(),c[f]=null;this.onSettledCallbacks_=null}};var ha=new f;g.prototype.settleSameAsPromise_=function(c){var f=this.createResolveAndReject_();c.callWhenSettled_(f.resolve,f.reject)};g.prototype.settleSameAsThenable_=function(c,f){var g=this.createResolveAndReject_();try{c.call(f,g.resolve,g.reject)}catch(v){g.reject(v)}};g.prototype.then=function(c,f){function n(c,f){return"function"==typeof c?function(f){try{v(c(f))}catch(aa){R(aa)}}:f}var v,R,D=
-new g(function(c,f){v=c;R=f});this.callWhenSettled_(n(c,v),n(f,R));return D};g.prototype.catch=function(c){return this.then(void 0,c)};g.prototype.callWhenSettled_=function(c,f){function g(){switch(n.state_){case 1:c(n.result_);break;case 2:f(n.result_);break;default:throw Error("Unexpected state: "+n.state_);}}var n=this;null==this.onSettledCallbacks_?ha.asyncExecute(g):this.onSettledCallbacks_.push(function(){ha.asyncExecute(g)})};g.resolve=n;g.reject=function(c){return new g(function(f,g){g(c)})};
-g.race=function(c){return new g(function(f,g){for(var v=$jscomp.makeIterator(c),u=v.next();!u.done;u=v.next())n(u.value).callWhenSettled_(f,g)})};g.all=function(c){var f=$jscomp.makeIterator(c),u=f.next();return u.done?n([]):new g(function(c,g){function D(f){return function(g){v[f]=g;L--;0==L&&c(v)}}var v=[],L=0;do v.push(void 0),L++,n(u.value).callWhenSettled_(D(v.length-1),g),u=f.next();while(!u.done)})};return g},"es6","es3");
-var DracoDecoderModule=function(c){function f(a,b){a||S("Assertion failed: "+b)}function n(e,b){if(0===b||!e)return"";for(var d=0,l,c=0;;){l=O[e+c>>0];d|=l;if(0==l&&!b)break;c++;if(b&&c==b)break}b||(b=c);l="";if(128>d){for(;0<b;)d=String.fromCharCode.apply(String,O.subarray(e,e+Math.min(b,1024))),l=l?l+d:d,e+=1024,b-=1024;return l}return a.UTF8ToString(e)}function D(a){return a.replace(/__Z[\w\d_]+/g,function(a){return a===a?a:a+" ["+a+"]"})}function g(){a:{var e=Error();if(!e.stack){try{throw Error(0);
-}catch(b){e=b}if(!e.stack){e="(no stack trace available)";break a}}e=e.stack.toString()}a.extraStackTrace&&(e+="\n"+a.extraStackTrace());return D(e)}function ha(a,b){0<a%b&&(a+=b-a%b);return a}function R(){a.HEAP8=ba=new Int8Array(E);a.HEAP16=ua=new Int16Array(E);a.HEAP32=w=new Int32Array(E);a.HEAPU8=O=new Uint8Array(E);a.HEAPU16=Ja=new Uint16Array(E);a.HEAPU32=Ka=new Uint32Array(E);a.HEAPF32=La=new Float32Array(E);a.HEAPF64=Ma=new Float64Array(E)}function Ha(){var e=a.usingWasm?va:Na,b=2147483648-
-e;if(w[X>>2]>b)return!1;var d=x;for(x=Math.max(x,db);x<w[X>>2];)x=536870912>=x?ha(2*x,e):Math.min(ha((3*x+2147483648)/4,e),b);e=a.reallocBuffer(x);if(!e||e.byteLength!=x)return x=d,!1;a.buffer=E=e;R();return!0}function u(e){for(;0<e.length;){var b=e.shift();if("function"==typeof b)b();else{var d=b.func;"number"===typeof d?void 0===b.arg?a.dynCall_v(d):a.dynCall_vi(d,b.arg):d(void 0===b.arg?null:b.arg)}}}function v(e){ca++;a.monitorRunDependencies&&a.monitorRunDependencies(ca)}function Ia(e){ca--;
-a.monitorRunDependencies&&a.monitorRunDependencies(ca);0==ca&&(null!==wa&&(clearInterval(wa),wa=null),oa&&(e=oa,oa=null,e()))}function ia(){return!!ia.uncaught_exception}function ma(){var e=z.last;if(!e)return(m.setTempRet0(0),0)|0;var b=z.infos[e],d=b.type;if(!d)return(m.setTempRet0(0),e)|0;var l=Array.prototype.slice.call(arguments);a.___cxa_is_pointer_type(d);ma.buffer||(ma.buffer=Oa(4));w[ma.buffer>>2]=e;e=ma.buffer;for(var c=0;c<l.length;c++)if(l[c]&&a.___cxa_can_catch(l[c],d,e))return e=w[e>>
-2],b.adjusted=e,(m.setTempRet0(l[c]),e)|0;e=w[e>>2];return(m.setTempRet0(d),e)|0}function L(e,b){t.varargs=b;try{var d=t.get(),l=t.get(),c=t.get();e=0;L.buffer||(L.buffers=[null,[],[]],L.printChar=function(b,e){var d=L.buffers[b];f(d);if(0===e||10===e){b=1===b?a.print:a.printErr;a:{for(var l=e=0;d[l];)++l;if(16<l-e&&d.subarray&&Pa)e=Pa.decode(d.subarray(e,l));else for(l="";;){var c=d[e++];if(!c){e=l;break a}if(c&128){var g=d[e++]&63;if(192==(c&224))l+=String.fromCharCode((c&31)<<6|g);else{var h=d[e++]&
-63;if(224==(c&240))c=(c&15)<<12|g<<6|h;else{var F=d[e++]&63;if(240==(c&248))c=(c&7)<<18|g<<12|h<<6|F;else{var k=d[e++]&63;if(248==(c&252))c=(c&3)<<24|g<<18|h<<12|F<<6|k;else{var pa=d[e++]&63;c=(c&1)<<30|g<<24|h<<18|F<<12|k<<6|pa}}}65536>c?l+=String.fromCharCode(c):(c-=65536,l+=String.fromCharCode(55296|c>>10,56320|c&1023))}}else l+=String.fromCharCode(c)}}b(e);d.length=0}else d.push(e)});for(b=0;b<c;b++){for(var g=w[l+8*b>>2],h=w[l+(8*b+4)>>2],k=0;k<h;k++)L.printChar(d,O[g+k]);e+=h}return e}catch(xa){return"undefined"!==
-typeof FS&&xa instanceof FS.ErrnoError||S(xa),-xa.errno}}function na(e,b){na.seen||(na.seen={});e in na.seen||(a.dynCall_v(b),na.seen[e]=1)}function aa(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}function ya(e){function b(){if(!a.calledRun&&(a.calledRun=!0,!ja)){Qa||(Qa=!0,u(Ra));u(Sa);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Ta.unshift(a.postRun.shift());
-u(Ta)}}null===Ua&&(Ua=Date.now());if(!(0<ca)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Va.unshift(a.preRun.shift());u(Va);0<ca||a.calledRun||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}function S(e){if(a.onAbort)a.onAbort(e);void 0!==e?(a.print(e),a.printErr(e),e=JSON.stringify(e)):e="";ja=!0;var b="abort("+e+") at "+g()+"\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";
-Wa&&Wa.forEach(function(a){b=a(b,e)});throw b;}function r(){}function B(a){return(a||r).__cache__}function T(a,b){var e=B(b),c=e[a];if(c)return c;c=Object.create((b||r).prototype);c.ptr=a;return e[a]=c}function U(a){if("string"===typeof a){for(var b=0,e=0;e<a.length;++e){var c=a.charCodeAt(e);55296<=c&&57343>=c&&(c=65536+((c&1023)<<10)|a.charCodeAt(++e)&1023);127>=c?++b:b=2047>=c?b+2:65535>=c?b+3:2097151>=c?b+4:67108863>=c?b+5:b+6}b=Array(b+1);e=0;c=b.length;if(0<c){c=e+c-1;for(var f=0;f<a.length;++f){var g=
-a.charCodeAt(f);55296<=g&&57343>=g&&(g=65536+((g&1023)<<10)|a.charCodeAt(++f)&1023);if(127>=g){if(e>=c)break;b[e++]=g}else{if(2047>=g){if(e+1>=c)break;b[e++]=192|g>>6}else{if(65535>=g){if(e+2>=c)break;b[e++]=224|g>>12}else{if(2097151>=g){if(e+3>=c)break;b[e++]=240|g>>18}else{if(67108863>=g){if(e+4>=c)break;b[e++]=248|g>>24}else{if(e+5>=c)break;b[e++]=252|g>>30;b[e++]=128|g>>24&63}b[e++]=128|g>>18&63}b[e++]=128|g>>12&63}b[e++]=128|g>>6&63}b[e++]=128|g&63}}b[e]=0}a=k.alloc(b,ba);k.copy(b,ba,a)}return a}
-function A(){throw"cannot construct a Status, no constructor in IDL";}function G(){this.ptr=gb();B(G)[this.ptr]=this}function H(){this.ptr=hb();B(H)[this.ptr]=this}function p(){this.ptr=ib();B(p)[this.ptr]=this}function K(){this.ptr=jb();B(K)[this.ptr]=this}function y(){this.ptr=kb();B(y)[this.ptr]=this}function q(){this.ptr=lb();B(q)[this.ptr]=this}function I(){this.ptr=mb();B(I)[this.ptr]=this}function V(){this.ptr=nb();B(V)[this.ptr]=this}function M(){this.ptr=ob();B(M)[this.ptr]=this}function h(){this.ptr=
-pb();B(h)[this.ptr]=this}function C(){this.ptr=qb();B(C)[this.ptr]=this}function Y(){throw"cannot construct a VoidPtr, no constructor in IDL";}function J(){this.ptr=rb();B(J)[this.ptr]=this}function N(){this.ptr=sb();B(N)[this.ptr]=this}var a=c=c||{},Xa=!1,Ya=!1;a.onRuntimeInitialized=function(){Xa=!0;if(Ya&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ya=!0;if(Xa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(a){if("string"!==
-typeof a)return!1;a=a.split(".");return 2>a.length||3<a.length?!1:1==a[0]&&0<=a[1]&&2>=a[1]?!0:0!=a[0]||10<a[1]?!1:!0};a||(a=("undefined"!==typeof c?c:null)||{});var qa={},Z;for(Z in a)a.hasOwnProperty(Z)&&(qa[Z]=a[Z]);var ka=!1,fa=!1,la=!1,ra=!1;if(a.ENVIRONMENT)if("WEB"===a.ENVIRONMENT)ka=!0;else if("WORKER"===a.ENVIRONMENT)fa=!0;else if("NODE"===a.ENVIRONMENT)la=!0;else if("SHELL"===a.ENVIRONMENT)ra=!0;else throw Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");
-else ka="object"===typeof window,fa="function"===typeof importScripts,la="object"===typeof process&&"function"===typeof require&&!ka&&!fa,ra=!ka&&!la&&!fa;if(la){a.print||(a.print=console.log);a.printErr||(a.printErr=console.warn);var za,Aa;a.read=function(a,b){za||(za=require("fs"));Aa||(Aa=require("path"));a=Aa.normalize(a);a=za.readFileSync(a);return b?a:a.toString()};a.readBinary=function(e){e=a.read(e,!0);e.buffer||(e=new Uint8Array(e));f(e.buffer);return e};a.thisProgram||(a.thisProgram=1<process.argv.length?
-process.argv[1].replace(/\\/g,"/"):"unknown-program");a.arguments=process.argv.slice(2);process.on("uncaughtException",function(a){if(!(a instanceof aa))throw a;});a.inspect=function(){return"[Emscripten Module object]"}}else if(ra)a.print||(a.print=print),"undefined"!=typeof printErr&&(a.printErr=printErr),a.read="undefined"!=typeof read?function(a){return read(a)}:function(){throw"no read() available";},a.readBinary=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));
-a=read(a,"binary");f("object"===typeof a);return a},"undefined"!=typeof scriptArgs?a.arguments=scriptArgs:"undefined"!=typeof arguments&&(a.arguments=arguments),"function"===typeof quit&&(a.quit=function(a,b){quit(a)});else if(ka||fa)a.read=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},fa&&(a.readBinary=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),a.readAsync=function(a,
-b,d){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=function(){200==e.status||0==e.status&&e.response?b(e.response):d()};e.onerror=d;e.send(null)},"undefined"!=typeof arguments&&(a.arguments=arguments),"undefined"!==typeof console?(a.print||(a.print=function(a){console.log(a)}),a.printErr||(a.printErr=function(a){console.warn(a)})):a.print||(a.print=function(a){}),"undefined"===typeof a.setWindowTitle&&(a.setWindowTitle=function(a){document.title=a});else throw Error("Unknown runtime environment. Where are we?");
-a.print||(a.print=function(){});a.printErr||(a.printErr=a.print);a.arguments||(a.arguments=[]);a.thisProgram||(a.thisProgram="./this.program");a.quit||(a.quit=function(a,b){throw b;});a.print=a.print;a.printErr=a.printErr;a.preRun=[];a.postRun=[];for(Z in qa)qa.hasOwnProperty(Z)&&(a[Z]=qa[Z]);qa=void 0;var m={setTempRet0:function(a){return tempRet0=a},getTempRet0:function(){return tempRet0},stackSave:function(){return P},stackRestore:function(a){P=a},getNativeTypeSize:function(a){switch(a){case "i1":case "i8":return 1;
-case "i16":return 2;case "i32":return 4;case "i64":return 8;case "float":return 4;case "double":return 8;default:return"*"===a[a.length-1]?m.QUANTUM_SIZE:"i"===a[0]?(a=parseInt(a.substr(1)),f(0===a%8),a/8):0}},getNativeFieldSize:function(a){return Math.max(m.getNativeTypeSize(a),m.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(a,b){"double"===b||"i64"===b?a&7&&(f(4===(a&7)),a+=4):f(0===(a&3));return a},getAlignSize:function(a,b,d){return d||"i64"!=a&&"double"!=a?a?Math.min(b||(a?m.getNativeFieldSize(a):
-0),m.QUANTUM_SIZE):Math.min(b,8):8},dynCall:function(e,b,d){return d&&d.length?a["dynCall_"+e].apply(null,[b].concat(d)):a["dynCall_"+e].call(null,b)},functionPointers:[],addFunction:function(a){for(var b=0;b<m.functionPointers.length;b++)if(!m.functionPointers[b])return m.functionPointers[b]=a,2*(1+b);throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.";},removeFunction:function(a){m.functionPointers[(a-2)/2]=null},warnOnce:function(e){m.warnOnce.shown||
-(m.warnOnce.shown={});m.warnOnce.shown[e]||(m.warnOnce.shown[e]=1,a.printErr(e))},funcWrappers:{},getFuncWrapper:function(a,b){if(a){f(b);m.funcWrappers[b]||(m.funcWrappers[b]={});var d=m.funcWrappers[b];d[a]||(d[a]=1===b.length?function(){return m.dynCall(b,a)}:2===b.length?function(d){return m.dynCall(b,a,[d])}:function(){return m.dynCall(b,a,Array.prototype.slice.call(arguments))});return d[a]}},getCompilerSetting:function(a){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work";
-},stackAlloc:function(a){var b=P;P=P+a|0;P=P+15&-16;return b},staticAlloc:function(a){var b=W;W=W+a|0;W=W+15&-16;return b},dynamicAlloc:function(a){var b=w[X>>2];a=(b+a+15|0)&-16;w[X>>2]=a;return a>=x&&!Ha()?(w[X>>2]=b,0):b},alignMemory:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},makeBigInt:function(a,b,d){return d?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},GLOBAL_BASE:1024,QUANTUM_SIZE:4,__dummy__:0},ja=0,Pa="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;"undefined"!==
-typeof TextDecoder&&new TextDecoder("utf-16le");var va=65536,Na=16777216,db=16777216,ba,O,ua,Ja,w,Ka,La,Ma,W,Ba,P,sa,Ca,X;var Da=W=Ba=P=sa=Ca=X=0;a.reallocBuffer||(a.reallocBuffer=function(a){try{if(ArrayBuffer.transfer)var b=ArrayBuffer.transfer(E,a);else{var d=ba;b=new ArrayBuffer(a);(new Int8Array(b)).set(d)}}catch(l){return!1}return tb(b)?b:!1});try{var Ea=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);Ea(new ArrayBuffer(4))}catch(e){Ea=function(a){return a.byteLength}}var Fa=
-a.TOTAL_STACK||5242880,x=a.TOTAL_MEMORY||16777216;x<Fa&&a.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+x+"! (TOTAL_STACK="+Fa+")");if(a.buffer)var E=a.buffer;else"object"===typeof WebAssembly&&"function"===typeof WebAssembly.Memory?(a.wasmMemory=new WebAssembly.Memory({initial:x/va}),E=a.wasmMemory.buffer):E=new ArrayBuffer(x);R();w[0]=1668509029;ua[1]=25459;if(115!==O[2]||99!==O[3])throw"Runtime error: expected the system to be little-endian!";a.HEAP=void 0;a.buffer=E;a.HEAP8=
-ba;a.HEAP16=ua;a.HEAP32=w;a.HEAPU8=O;a.HEAPU16=Ja;a.HEAPU32=Ka;a.HEAPF32=La;a.HEAPF64=Ma;var Va=[],Ra=[],Sa=[],Za=[],Ta=[],Qa=!1;f(Math.imul&&Math.fround&&Math.clz32&&Math.trunc,"this is a legacy browser, build with LEGACY_VM_SUPPORT");var ca=0,wa=null,oa=null;a.preloadedImages={};a.preloadedAudios={};var Q=null;(function(){function e(){try{if(a.wasmBinary)return new Uint8Array(a.wasmBinary);if(a.readBinary)return a.readBinary(c);throw"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)";
-}catch(eb){S(eb)}}function b(){return a.wasmBinary||!ka&&!fa||"function"!==typeof fetch?new Promise(function(a,b){a(e())}):fetch(c,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+c+"'";return a.arrayBuffer()}).catch(function(){return e()})}function d(d,e,l){function f(b,d){h=b.exports;if(h.memory){b=h.memory;d=a.buffer;b.byteLength<d.byteLength&&a.printErr("the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here");
-d=new Int8Array(d);var e=new Int8Array(b);Q||d.set(e.subarray(a.STATIC_BASE,a.STATIC_BASE+a.STATIC_BUMP),a.STATIC_BASE);e.set(d);a.buffer=E=b;R()}a.asm=h;a.usingWasm=!0;Ia("wasm-instantiate")}function k(a){f(a.instance,a.module)}function F(d){b().then(function(a){return WebAssembly.instantiate(a,g)}).then(d).catch(function(b){a.printErr("failed to asynchronously prepare wasm: "+b);S(b)})}if("object"!==typeof WebAssembly)return a.printErr("no native wasm support detected"),!1;if(!(a.wasmMemory instanceof
-WebAssembly.Memory))return a.printErr("no native wasm Memory in use"),!1;e.memory=a.wasmMemory;g.global={NaN:NaN,Infinity:Infinity};g["global.Math"]=d.Math;g.env=e;v("wasm-instantiate");if(a.instantiateWasm)try{return a.instantiateWasm(g,f)}catch(fb){return a.printErr("Module.instantiateWasm callback failed with error: "+fb),!1}a.wasmBinary||"function"!==typeof WebAssembly.instantiateStreaming||0===c.indexOf("data:")||"function"!==typeof fetch?F(k):WebAssembly.instantiateStreaming(fetch(c,{credentials:"same-origin"}),
-g).then(k).catch(function(b){a.printErr("wasm streaming compile failed: "+b);a.printErr("falling back to ArrayBuffer instantiation");F(k)});return{}}var c="draco_decoder.wasm",f="draco_decoder.temp.asm.js";"function"===typeof a.locateFile&&(a.locateFile("draco_decoder.wast"),c=a.locateFile(c),f=a.locateFile(f));var g={global:null,env:null,asm2wasm:{"f64-rem":function(a,b){return a%b},"debugger":function(){debugger}},parent:a},h=null;a.asmPreload=a.asm;var k=a.reallocBuffer;a.reallocBuffer=function(b){if("asmjs"===
-m)var d=k(b);else a:{b=ha(b,a.usingWasm?va:Na);var e=a.buffer.byteLength;if(a.usingWasm)try{d=-1!==a.wasmMemory.grow((b-e)/65536)?a.buffer=a.wasmMemory.buffer:null;break a}catch(fd){d=null;break a}d=void 0}return d};var m="";a.asm=function(b,e,c){if(!e.table){var l=a.wasmTableSize;void 0===l&&(l=1024);var f=a.wasmMaxTableSize;e.table="object"===typeof WebAssembly&&"function"===typeof WebAssembly.Table?void 0!==f?new WebAssembly.Table({initial:l,maximum:f,element:"anyfunc"}):new WebAssembly.Table({initial:l,
-element:"anyfunc"}):Array(l);a.wasmTable=e.table}e.memoryBase||(e.memoryBase=a.STATIC_BASE);e.tableBase||(e.tableBase=0);(b=d(b,e,c))||S("no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods");return b}})();Da=m.GLOBAL_BASE;W=Da+17952;Ra.push();Q=null;a.STATIC_BASE=Da;a.STATIC_BUMP=17952;var ub=W;W+=16;var z={last:0,caught:[],infos:{},deAdjust:function(a){if(!a||z.infos[a])return a;
-for(var b in z.infos)if(z.infos[b].adjusted===a)return b;return a},addRef:function(a){a&&z.infos[a].refcount++},decRef:function(e){if(e){var b=z.infos[e];f(0<b.refcount);b.refcount--;0!==b.refcount||b.rethrown||(b.destructor&&a.dynCall_vi(b.destructor,e),delete z.infos[e],___cxa_free_exception(e))}},clearRef:function(a){a&&(z.infos[a].refcount=0)}},t={varargs:0,get:function(a){t.varargs+=4;return w[t.varargs-4>>2]},getStr:function(){return n(t.get())},get64:function(){var a=t.get(),b=t.get();0<=a?
-f(0===b):f(-1===b);return a},getZero:function(){f(0===t.get())}},ta={},Ga=1;Za.push(function(){var e=a._fflush;e&&e(0);if(e=L.printChar){var b=L.buffers;b[1].length&&e(1,10);b[2].length&&e(2,10)}});X=m.staticAlloc(4);Ba=P=m.alignMemory(W);sa=Ba+Fa;Ca=m.alignMemory(sa);w[X>>2]=Ca;a.wasmTableSize=468;a.wasmMaxTableSize=468;a.asmGlobalArg={Math:Math,Int8Array:Int8Array,Int16Array:Int16Array,Int32Array:Int32Array,Uint8Array:Uint8Array,Uint16Array:Uint16Array,Uint32Array:Uint32Array,Float32Array:Float32Array,
-Float64Array:Float64Array,NaN:NaN,Infinity:Infinity,byteLength:Ea};a.asmLibraryArg={abort:S,assert:f,enlargeMemory:Ha,getTotalMemory:function(){return x},abortOnCannotGrowMemory:function(){S("Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value "+x+", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 ")},
-invoke_ii:function(e,b){try{return a.dynCall_ii(e,b)}catch(d){if("number"!==typeof d&&"longjmp"!==d)throw d;a.setThrew(1,0)}},invoke_iii:function(e,b,d){try{return a.dynCall_iii(e,b,d)}catch(l){if("number"!==typeof l&&"longjmp"!==l)throw l;a.setThrew(1,0)}},invoke_iiii:function(e,b,d,c){try{return a.dynCall_iiii(e,b,d,c)}catch(F){if("number"!==typeof F&&"longjmp"!==F)throw F;a.setThrew(1,0)}},invoke_iiiiiii:function(e,b,d,c,f,g,h){try{return a.dynCall_iiiiiii(e,b,d,c,f,g,h)}catch(ea){if("number"!==
-typeof ea&&"longjmp"!==ea)throw ea;a.setThrew(1,0)}},invoke_v:function(e){try{a.dynCall_v(e)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_vi:function(e,b){try{a.dynCall_vi(e,b)}catch(d){if("number"!==typeof d&&"longjmp"!==d)throw d;a.setThrew(1,0)}},invoke_vii:function(e,b,d){try{a.dynCall_vii(e,b,d)}catch(l){if("number"!==typeof l&&"longjmp"!==l)throw l;a.setThrew(1,0)}},invoke_viii:function(e,b,d,c){try{a.dynCall_viii(e,b,d,c)}catch(F){if("number"!==typeof F&&
-"longjmp"!==F)throw F;a.setThrew(1,0)}},invoke_viiii:function(e,b,d,c,f){try{a.dynCall_viiii(e,b,d,c,f)}catch(pa){if("number"!==typeof pa&&"longjmp"!==pa)throw pa;a.setThrew(1,0)}},invoke_viiiii:function(e,b,d,c,f,g){try{a.dynCall_viiiii(e,b,d,c,f,g)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},invoke_viiiiii:function(e,b,d,c,f,g,h){try{a.dynCall_viiiiii(e,b,d,c,f,g,h)}catch(ea){if("number"!==typeof ea&&"longjmp"!==ea)throw ea;a.setThrew(1,0)}},__ZSt18uncaught_exceptionv:ia,
-___assert_fail:function(a,b,d,c){ja=!0;throw"Assertion failed: "+n(a)+", at: "+[b?n(b):"unknown filename",d,c?n(c):"unknown function"]+" at "+g();},___cxa_allocate_exception:function(a){return Oa(a)},___cxa_begin_catch:function(a){var b=z.infos[a];b&&!b.caught&&(b.caught=!0,ia.uncaught_exception--);b&&(b.rethrown=!1);z.caught.push(a);z.addRef(z.deAdjust(a));return a},___cxa_find_matching_catch:ma,___cxa_pure_virtual:function(){ja=!0;throw"Pure virtual function called!";},___cxa_throw:function(a,b,
-d){z.infos[a]={ptr:a,adjusted:a,type:b,destructor:d,refcount:0,caught:!1,rethrown:!1};z.last=a;"uncaught_exception"in ia?ia.uncaught_exception++:ia.uncaught_exception=1;throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";},___gxx_personality_v0:function(){},___resumeException:function(a){z.last||(z.last=a);throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
-},___setErrNo:function(c){a.___errno_location&&(w[a.___errno_location()>>2]=c);return c},___syscall140:function(a,b){t.varargs=b;try{var d=t.getStreamFromFD();t.get();var c=t.get(),e=t.get(),f=t.get();FS.llseek(d,c,f);w[e>>2]=d.position;d.getdents&&0===c&&0===f&&(d.getdents=null);return 0}catch(da){return"undefined"!==typeof FS&&da instanceof FS.ErrnoError||S(da),-da.errno}},___syscall146:L,___syscall6:function(a,b){t.varargs=b;try{var d=t.getStreamFromFD();FS.close(d);return 0}catch(l){return"undefined"!==
-typeof FS&&l instanceof FS.ErrnoError||S(l),-l.errno}},_abort:function(){a.abort()},_emscripten_memcpy_big:function(a,b,d){O.set(O.subarray(b,b+d),a);return a},_pthread_getspecific:function(a){return ta[a]||0},_pthread_key_create:function(a,b){if(0==a)return 22;w[a>>2]=Ga;ta[Ga]=0;Ga++;return 0},_pthread_once:na,_pthread_setspecific:function(a,b){if(!(a in ta))return 22;ta[a]=b;return 0},DYNAMICTOP_PTR:X,tempDoublePtr:ub,ABORT:ja,STACKTOP:P,STACK_MAX:sa};var $a=a.asm(a.asmGlobalArg,a.asmLibraryArg,
-E);a.asm=$a;a.___cxa_can_catch=function(){return a.asm.___cxa_can_catch.apply(null,arguments)};a.___cxa_is_pointer_type=function(){return a.asm.___cxa_is_pointer_type.apply(null,arguments)};var hb=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,arguments)},vb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,
-arguments)},wb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},xb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,arguments)},kb=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,
-arguments)},yb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},zb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,arguments)},Ab=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,
-arguments)},Bb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},Cb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,arguments)},jb=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return a.asm._emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,
-arguments)},Db=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm._emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Eb=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm._emscripten_bind_AttributeTransformData_transform_type_0.apply(null,arguments)},ob=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm._emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},Fb=a._emscripten_bind_DecoderBuffer_Init_2=
-function(){return a.asm._emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},Gb=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm._emscripten_bind_DecoderBuffer___destroy___0.apply(null,arguments)},Hb=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,arguments)},Ib=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,
-arguments)},pb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm._emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},Jb=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},Kb=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Lb=a._emscripten_bind_Decoder_GetAttributeFloat_3=
-function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Mb=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},Nb=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,arguments)},Ob=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeId_2.apply(null,
-arguments)},Pb=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Qb=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,arguments)},Rb=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,arguments)},Sb=a._emscripten_bind_Decoder_GetAttribute_2=
-function(){return a.asm._emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},Tb=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=function(){return a.asm._emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},Ub=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm._emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},Vb=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm._emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},
-Wb=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,arguments)},Xb=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm._emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Yb=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm._emscripten_bind_Decoder___destroy___0.apply(null,arguments)},mb=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,
-arguments)},Zb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},$b=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},ac=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},rb=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm._emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,
-arguments)},bc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},cc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},dc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoInt32Array_size_0.apply(null,arguments)},nb=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm._emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
-arguments)},ec=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm._emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},qb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm._emscripten_bind_Mesh_Mesh_0.apply(null,arguments)},fc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm._emscripten_bind_Mesh___destroy___0.apply(null,arguments)},gc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm._emscripten_bind_Mesh_num_attributes_0.apply(null,
-arguments)},hc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm._emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},ic=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm._emscripten_bind_Mesh_num_points_0.apply(null,arguments)},jc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},kc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,
-arguments)},lc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},mc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},nc=a._emscripten_bind_MetadataQuerier_HasDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasDoubleEntry_2.apply(null,arguments)},oc=a._emscripten_bind_MetadataQuerier_HasEntry_2=
-function(){return a.asm._emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},pc=a._emscripten_bind_MetadataQuerier_HasIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasIntEntry_2.apply(null,arguments)},qc=a._emscripten_bind_MetadataQuerier_HasStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasStringEntry_2.apply(null,arguments)},lb=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm._emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,
-arguments)},rc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm._emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,arguments)},sc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm._emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},sb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm._emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},tc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm._emscripten_bind_Metadata___destroy___0.apply(null,
-arguments)},uc=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm._emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return a.asm._emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},vc=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm._emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},wc=a._emscripten_bind_PointAttribute_attribute_type_0=
-function(){return a.asm._emscripten_bind_PointAttribute_attribute_type_0.apply(null,arguments)},xc=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},yc=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_stride_0.apply(null,arguments)},zc=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm._emscripten_bind_PointAttribute_data_type_0.apply(null,
-arguments)},Ac=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm._emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Bc=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm._emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Cc=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm._emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Dc=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm._emscripten_bind_PointAttribute_unique_id_0.apply(null,
-arguments)},gb=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm._emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},Ec=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm._emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Fc=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm._emscripten_bind_PointCloud_num_attributes_0.apply(null,arguments)},Gc=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm._emscripten_bind_PointCloud_num_points_0.apply(null,
-arguments)},Hc=a._emscripten_bind_Status___destroy___0=function(){return a.asm._emscripten_bind_Status___destroy___0.apply(null,arguments)},Ic=a._emscripten_bind_Status_code_0=function(){return a.asm._emscripten_bind_Status_code_0.apply(null,arguments)},Jc=a._emscripten_bind_Status_error_msg_0=function(){return a.asm._emscripten_bind_Status_error_msg_0.apply(null,arguments)},Kc=a._emscripten_bind_Status_ok_0=function(){return a.asm._emscripten_bind_Status_ok_0.apply(null,arguments)},Lc=a._emscripten_bind_VoidPtr___destroy___0=
-function(){return a.asm._emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},Oc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=
-function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,arguments)},Pc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},Qc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
-arguments)},Rc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},Sc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},Uc=
-a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)},Vc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},Wc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},Xc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
-function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},Yc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},Zc=a._emscripten_enum_draco_StatusCode_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_ERROR.apply(null,arguments)},$c=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm._emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,
-arguments)},ad=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},bd=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm._emscripten_enum_draco_StatusCode_OK.apply(null,arguments)},cd=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},dd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,
-arguments)};a._emscripten_get_global_libc=function(){return a.asm._emscripten_get_global_libc.apply(null,arguments)};var tb=a._emscripten_replace_memory=function(){return a.asm._emscripten_replace_memory.apply(null,arguments)};a._free=function(){return a.asm._free.apply(null,arguments)};a._llvm_bswap_i32=function(){return a.asm._llvm_bswap_i32.apply(null,arguments)};var Oa=a._malloc=function(){return a.asm._malloc.apply(null,arguments)};a._memcpy=function(){return a.asm._memcpy.apply(null,arguments)};
-a._memmove=function(){return a.asm._memmove.apply(null,arguments)};a._memset=function(){return a.asm._memset.apply(null,arguments)};a._sbrk=function(){return a.asm._sbrk.apply(null,arguments)};a.establishStackSpace=function(){return a.asm.establishStackSpace.apply(null,arguments)};a.getTempRet0=function(){return a.asm.getTempRet0.apply(null,arguments)};a.runPostSets=function(){return a.asm.runPostSets.apply(null,arguments)};a.setTempRet0=function(){return a.asm.setTempRet0.apply(null,arguments)};
-a.setThrew=function(){return a.asm.setThrew.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};
-a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,
-arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};m.stackAlloc=a.stackAlloc;m.stackSave=a.stackSave;m.stackRestore=a.stackRestore;m.establishStackSpace=a.establishStackSpace;m.setTempRet0=a.setTempRet0;m.getTempRet0=a.getTempRet0;a.asm=$a;if(Q)if("function"===typeof a.locateFile?Q=a.locateFile(Q):a.memoryInitializerPrefixURL&&(Q=a.memoryInitializerPrefixURL+Q),la||ra){var ed=a.readBinary(Q);O.set(ed,m.GLOBAL_BASE)}else{var bb=function(){a.readAsync(Q,ab,
-function(){throw"could not load memory initializer "+Q;})};v("memory initializer");var ab=function(c){c.byteLength&&(c=new Uint8Array(c));O.set(c,m.GLOBAL_BASE);a.memoryInitializerRequest&&delete a.memoryInitializerRequest.response;Ia("memory initializer")};if(a.memoryInitializerRequest){var cb=function(){var c=a.memoryInitializerRequest,b=c.response;200!==c.status&&0!==c.status?(console.warn("a problem seems to have happened with Module.memoryInitializerRequest, status: "+c.status+", retrying "+
-Q),bb()):ab(b)};a.memoryInitializerRequest.response?setTimeout(cb,0):a.memoryInitializerRequest.addEventListener("load",cb)}else bb()}a.then=function(c){if(a.calledRun)c(a);else{var b=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){b&&b();c(a)}}return a};aa.prototype=Error();aa.prototype.constructor=aa;var Ua=null;oa=function b(){a.calledRun||ya();a.calledRun||(oa=b)};a.run=ya;a.exit=function(b,d){if(!d||!a.noExitRuntime){if(!a.noExitRuntime&&(ja=!0,P=void 0,u(Za),a.onExit))a.onExit(b);la&&
-process.exit(b);a.quit(b,new aa(b))}};var Wa=[];a.abort=S;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();ya();r.prototype=Object.create(r.prototype);r.prototype.constructor=r;r.prototype.__class__=r;r.__cache__={};a.WrapperObject=r;a.getCache=B;a.wrapPointer=T;a.castObject=function(a,d){return T(a.ptr,d)};a.NULL=T(0);a.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";a.__destroy__();
-delete B(a.__class__)[a.ptr]};a.compare=function(a,d){return a.ptr===d.ptr};a.getPointer=function(a){return a.ptr};a.getClass=function(a){return a.__class__};var k={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(k.needed){for(var b=0;b<k.temps.length;b++)a._free(k.temps[b]);k.temps.length=0;a._free(k.buffer);k.buffer=0;k.size+=k.needed;k.needed=0}k.buffer||(k.size+=128,k.buffer=a._malloc(k.size),f(k.buffer));k.pos=0},alloc:function(b,d){f(k.buffer);b=b.length*d.BYTES_PER_ELEMENT;b=
-b+7&-8;k.pos+b>=k.size?(f(0<b),k.needed+=b,d=a._malloc(b),k.temps.push(d)):(d=k.buffer+k.pos,k.pos+=b);return d},copy:function(a,d,c){switch(d.BYTES_PER_ELEMENT){case 2:c>>=1;break;case 4:c>>=2;break;case 8:c>>=3}for(var b=0;b<a.length;b++)d[c+b]=a[b]}};A.prototype=Object.create(r.prototype);A.prototype.constructor=A;A.prototype.__class__=A;A.__cache__={};a.Status=A;A.prototype.code=A.prototype.code=function(){return Ic(this.ptr)};A.prototype.ok=A.prototype.ok=function(){return!!Kc(this.ptr)};A.prototype.error_msg=
-A.prototype.error_msg=function(){return n(Jc(this.ptr))};A.prototype.__destroy__=A.prototype.__destroy__=function(){Hc(this.ptr)};G.prototype=Object.create(r.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.PointCloud=G;G.prototype.num_attributes=G.prototype.num_attributes=function(){return Fc(this.ptr)};G.prototype.num_points=G.prototype.num_points=function(){return Gc(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){Ec(this.ptr)};H.prototype=Object.create(r.prototype);
-H.prototype.constructor=H;H.prototype.__class__=H;H.__cache__={};a.AttributeOctahedronTransform=H;H.prototype.InitFromAttribute=H.prototype.InitFromAttribute=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!vb(b,a)};H.prototype.quantization_bits=H.prototype.quantization_bits=function(){return xb(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){wb(this.ptr)};p.prototype=Object.create(r.prototype);p.prototype.constructor=p;p.prototype.__class__=p;p.__cache__=
-{};a.PointAttribute=p;p.prototype.size=p.prototype.size=function(){return Cc(this.ptr)};p.prototype.GetAttributeTransformData=p.prototype.GetAttributeTransformData=function(){return T(uc(this.ptr),K)};p.prototype.attribute_type=p.prototype.attribute_type=function(){return wc(this.ptr)};p.prototype.data_type=p.prototype.data_type=function(){return zc(this.ptr)};p.prototype.num_components=p.prototype.num_components=function(){return Bc(this.ptr)};p.prototype.normalized=p.prototype.normalized=function(){return!!Ac(this.ptr)};
-p.prototype.byte_stride=p.prototype.byte_stride=function(){return yc(this.ptr)};p.prototype.byte_offset=p.prototype.byte_offset=function(){return xc(this.ptr)};p.prototype.unique_id=p.prototype.unique_id=function(){return Dc(this.ptr)};p.prototype.__destroy__=p.prototype.__destroy__=function(){vc(this.ptr)};K.prototype=Object.create(r.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.AttributeTransformData=K;K.prototype.transform_type=K.prototype.transform_type=function(){return Eb(this.ptr)};
-K.prototype.__destroy__=K.prototype.__destroy__=function(){Db(this.ptr)};y.prototype=Object.create(r.prototype);y.prototype.constructor=y;y.prototype.__class__=y;y.__cache__={};a.AttributeQuantizationTransform=y;y.prototype.InitFromAttribute=y.prototype.InitFromAttribute=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!yb(b,a)};y.prototype.quantization_bits=y.prototype.quantization_bits=function(){return Bb(this.ptr)};y.prototype.min_value=y.prototype.min_value=function(a){var b=
-this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Ab(b,a)};y.prototype.range=y.prototype.range=function(){return Cb(this.ptr)};y.prototype.__destroy__=y.prototype.__destroy__=function(){zb(this.ptr)};q.prototype=Object.create(r.prototype);q.prototype.constructor=q;q.prototype.__class__=q;q.__cache__={};a.MetadataQuerier=q;q.prototype.HasEntry=q.prototype.HasEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return!!oc(b,a,d)};q.prototype.HasIntEntry=
-q.prototype.HasIntEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return!!pc(b,a,d)};q.prototype.GetIntEntry=q.prototype.GetIntEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return lc(b,a,d)};q.prototype.HasDoubleEntry=q.prototype.HasDoubleEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return!!nc(b,
-a,d)};q.prototype.GetDoubleEntry=q.prototype.GetDoubleEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return jc(b,a,d)};q.prototype.HasStringEntry=q.prototype.HasStringEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return!!qc(b,a,d)};q.prototype.GetStringEntry=q.prototype.GetStringEntry=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);
-d=d&&"object"===typeof d?d.ptr:U(d);return n(mc(b,a,d))};q.prototype.NumEntries=q.prototype.NumEntries=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return rc(b,a)};q.prototype.GetEntryName=q.prototype.GetEntryName=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return n(kc(b,a,d))};q.prototype.__destroy__=q.prototype.__destroy__=function(){sc(this.ptr)};I.prototype=Object.create(r.prototype);I.prototype.constructor=I;I.prototype.__class__=
-I;I.__cache__={};a.DracoFloat32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Zb(b,a)};I.prototype.size=I.prototype.size=function(){return ac(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){$b(this.ptr)};V.prototype=Object.create(r.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){ec(this.ptr)};M.prototype=
-Object.create(r.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DecoderBuffer=M;M.prototype.Init=M.prototype.Init=function(a,d){var b=this.ptr;k.prepare();if("object"==typeof a&&"object"===typeof a){var c=k.alloc(a,ba);k.copy(a,ba,c);a=c}d&&"object"===typeof d&&(d=d.ptr);Fb(b,a,d)};M.prototype.__destroy__=M.prototype.__destroy__=function(){Gb(this.ptr)};h.prototype=Object.create(r.prototype);h.prototype.constructor=h;h.prototype.__class__=h;h.__cache__={};a.Decoder=h;
-h.prototype.GetEncodedGeometryType=h.prototype.GetEncodedGeometryType=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Tb(b,a)};h.prototype.DecodeBufferToPointCloud=h.prototype.DecodeBufferToPointCloud=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return T(Ib(b,a,d),A)};h.prototype.DecodeBufferToMesh=h.prototype.DecodeBufferToMesh=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return T(Hb(b,
-a,d),A)};h.prototype.GetAttributeId=h.prototype.GetAttributeId=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return Ob(b,a,d)};h.prototype.GetAttributeIdByName=h.prototype.GetAttributeIdByName=function(a,d){var b=this.ptr;k.prepare();a&&"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);return Nb(b,a,d)};h.prototype.GetAttributeIdByMetadataEntry=h.prototype.GetAttributeIdByMetadataEntry=function(a,d,c){var b=this.ptr;k.prepare();a&&
-"object"===typeof a&&(a=a.ptr);d=d&&"object"===typeof d?d.ptr:U(d);c=c&&"object"===typeof c?c.ptr:U(c);return Mb(b,a,d,c)};h.prototype.GetAttribute=h.prototype.GetAttribute=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return T(Sb(b,a,d),p)};h.prototype.GetAttributeByUniqueId=h.prototype.GetAttributeByUniqueId=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return T(Jb(b,a,d),p)};h.prototype.GetMetadata=
-h.prototype.GetMetadata=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return T(Vb(b,a),N)};h.prototype.GetAttributeMetadata=h.prototype.GetAttributeMetadata=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return T(Rb(b,a,d),N)};h.prototype.GetFaceFromMesh=h.prototype.GetFaceFromMesh=function(a,d,c){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);c&&"object"===typeof c&&(c=c.ptr);return!!Ub(b,a,d,c)};
-h.prototype.GetTriangleStripsFromMesh=h.prototype.GetTriangleStripsFromMesh=function(a,d){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);return Wb(b,a,d)};h.prototype.GetAttributeFloat=h.prototype.GetAttributeFloat=function(a,d,c){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);d&&"object"===typeof d&&(d=d.ptr);c&&"object"===typeof c&&(c=c.ptr);return!!Lb(b,a,d,c)};h.prototype.GetAttributeFloatForAllPoints=h.prototype.GetAttributeFloatForAllPoints=function(a,c,
-f){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);c&&"object"===typeof c&&(c=c.ptr);f&&"object"===typeof f&&(f=f.ptr);return!!Kb(b,a,c,f)};h.prototype.GetAttributeIntForAllPoints=h.prototype.GetAttributeIntForAllPoints=function(a,c,f){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);c&&"object"===typeof c&&(c=c.ptr);f&&"object"===typeof f&&(f=f.ptr);return!!Qb(b,a,c,f)};h.prototype.GetAttributeInt32ForAllPoints=h.prototype.GetAttributeInt32ForAllPoints=function(a,c,f){var b=this.ptr;a&&"object"===
-typeof a&&(a=a.ptr);c&&"object"===typeof c&&(c=c.ptr);f&&"object"===typeof f&&(f=f.ptr);return!!Pb(b,a,c,f)};h.prototype.SkipAttributeTransform=h.prototype.SkipAttributeTransform=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);Xb(b,a)};h.prototype.__destroy__=h.prototype.__destroy__=function(){Yb(this.ptr)};C.prototype=Object.create(r.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Mesh=C;C.prototype.num_faces=C.prototype.num_faces=function(){return hc(this.ptr)};
-C.prototype.num_attributes=C.prototype.num_attributes=function(){return gc(this.ptr)};C.prototype.num_points=C.prototype.num_points=function(){return ic(this.ptr)};C.prototype.__destroy__=C.prototype.__destroy__=function(){fc(this.ptr)};Y.prototype=Object.create(r.prototype);Y.prototype.constructor=Y;Y.prototype.__class__=Y;Y.__cache__={};a.VoidPtr=Y;Y.prototype.__destroy__=Y.prototype.__destroy__=function(){Lc(this.ptr)};J.prototype=Object.create(r.prototype);J.prototype.constructor=J;J.prototype.__class__=
-J;J.__cache__={};a.DracoInt32Array=J;J.prototype.GetValue=J.prototype.GetValue=function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return bc(b,a)};J.prototype.size=J.prototype.size=function(){return dc(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){cc(this.ptr)};N.prototype=Object.create(r.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.Metadata=N;N.prototype.__destroy__=N.prototype.__destroy__=function(){tc(this.ptr)};(function(){function b(){a.OK=
-bd();a.ERROR=Zc();a.IO_ERROR=ad();a.INVALID_PARAMETER=$c();a.UNSUPPORTED_VERSION=dd();a.UNKNOWN_VERSION=cd();a.INVALID_GEOMETRY_TYPE=Qc();a.POINT_CLOUD=Rc();a.TRIANGULAR_MESH=Sc();a.ATTRIBUTE_INVALID_TRANSFORM=Mc();a.ATTRIBUTE_NO_TRANSFORM=Nc();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=Pc();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=Oc();a.INVALID=Vc();a.POSITION=Xc();a.NORMAL=Wc();a.COLOR=Tc();a.TEX_COORD=Yc();a.GENERIC=Uc()}a.calledRun?b():Sa.unshift(b)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();
-return c};"object"===typeof module&&module.exports&&(module.exports=DracoDecoderModule);
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(d,k,f){d!=Array.prototype&&d!=Object.prototype&&(d[k]=f.value)};$jscomp.getGlobal=function(d){return"undefined"!=typeof window&&window===d?d:"undefined"!=typeof global&&null!=global?global:d};$jscomp.global=$jscomp.getGlobal(this);
+$jscomp.polyfill=function(d,k,f,u){if(k){f=$jscomp.global;d=d.split(".");for(u=0;u<d.length-1;u++){var h=d[u];h in f||(f[h]={});f=f[h]}d=d[d.length-1];u=f[d];k=k(u);k!=u&&null!=k&&$jscomp.defineProperty(f,d,{configurable:!0,writable:!0,value:k})}};$jscomp.polyfill("Math.imul",function(d){return d?d:function(d,f){d=Number(d);f=Number(f);var k=d&65535,h=f&65535;return k*h+((d>>>16&65535)*h+k*(f>>>16&65535)<<16>>>0)|0}},"es6","es3");
+$jscomp.polyfill("Math.clz32",function(d){return d?d:function(d){d=Number(d)>>>0;if(0===d)return 32;var f=0;0===(d&4294901760)&&(d<<=16,f+=16);0===(d&4278190080)&&(d<<=8,f+=8);0===(d&4026531840)&&(d<<=4,f+=4);0===(d&3221225472)&&(d<<=2,f+=2);0===(d&2147483648)&&f++;return f}},"es6","es3");$jscomp.polyfill("Math.trunc",function(d){return d?d:function(d){d=Number(d);if(isNaN(d)||Infinity===d||-Infinity===d||0===d)return d;var f=Math.floor(Math.abs(d));return 0>d?-f:f}},"es6","es3");
+$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.Symbol=function(){var d=0;return function(k){return $jscomp.SYMBOL_PREFIX+(k||"")+d++}}();
+$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var d=$jscomp.global.Symbol.iterator;d||(d=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[d]&&$jscomp.defineProperty(Array.prototype,d,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(d){var k=0;return $jscomp.iteratorPrototype(function(){return k<d.length?{done:!1,value:d[k++]}:{done:!0}})};
+$jscomp.iteratorPrototype=function(d){$jscomp.initSymbolIterator();d={next:d};d[$jscomp.global.Symbol.iterator]=function(){return this};return d};$jscomp.makeIterator=function(d){$jscomp.initSymbolIterator();var k=d[Symbol.iterator];return k?k.call(d):$jscomp.arrayIterator(d)};$jscomp.FORCE_POLYFILL_PROMISE=!1;
+$jscomp.polyfill("Promise",function(d){function k(){this.batch_=null}function f(d){return d instanceof h?d:new h(function(r,f){r(d)})}if(d&&!$jscomp.FORCE_POLYFILL_PROMISE)return d;k.prototype.asyncExecute=function(d){null==this.batch_&&(this.batch_=[],this.asyncExecuteBatch_());this.batch_.push(d);return this};k.prototype.asyncExecuteBatch_=function(){var d=this;this.asyncExecuteFunction(function(){d.executeBatch_()})};var u=$jscomp.global.setTimeout;k.prototype.asyncExecuteFunction=function(d){u(d,
+0)};k.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var d=this.batch_;this.batch_=[];for(var B=0;B<d.length;++B){var f=d[B];delete d[B];try{f()}catch(v){this.asyncThrow_(v)}}}this.batch_=null};k.prototype.asyncThrow_=function(d){this.asyncExecuteFunction(function(){throw d;})};var h=function(d){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var r=this.createResolveAndReject_();try{d(r.resolve,r.reject)}catch(Y){r.reject(Y)}};h.prototype.createResolveAndReject_=
+function(){function d(d){return function(r){h||(h=!0,d.call(f,r))}}var f=this,h=!1;return{resolve:d(this.resolveTo_),reject:d(this.reject_)}};h.prototype.resolveTo_=function(d){if(d===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(d instanceof h)this.settleSameAsPromise_(d);else{a:switch(typeof d){case "object":var f=null!=d;break a;case "function":f=!0;break a;default:f=!1}f?this.resolveToNonPromiseObj_(d):this.fulfill_(d)}};h.prototype.resolveToNonPromiseObj_=function(d){var f=
+void 0;try{f=d.then}catch(Y){this.reject_(Y);return}"function"==typeof f?this.settleSameAsThenable_(f,d):this.fulfill_(d)};h.prototype.reject_=function(d){this.settle_(2,d)};h.prototype.fulfill_=function(d){this.settle_(1,d)};h.prototype.settle_=function(d,f){if(0!=this.state_)throw Error("Cannot settle("+d+", "+f|"): Promise already settled in state"+this.state_);this.state_=d;this.result_=f;this.executeOnSettledCallbacks_()};h.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var d=
+this.onSettledCallbacks_,f=0;f<d.length;++f)d[f].call(),d[f]=null;this.onSettledCallbacks_=null}};var ha=new k;h.prototype.settleSameAsPromise_=function(d){var f=this.createResolveAndReject_();d.callWhenSettled_(f.resolve,f.reject)};h.prototype.settleSameAsThenable_=function(d,f){var h=this.createResolveAndReject_();try{d.call(f,h.resolve,h.reject)}catch(v){h.reject(v)}};h.prototype.then=function(d,f){function k(d,f){return"function"==typeof d?function(f){try{v(d(f))}catch(O){r(O)}}:f}var v,r,B=new h(function(d,
+f){v=d;r=f});this.callWhenSettled_(k(d,v),k(f,r));return B};h.prototype.catch=function(d){return this.then(void 0,d)};h.prototype.callWhenSettled_=function(d,f){function h(){switch(k.state_){case 1:d(k.result_);break;case 2:f(k.result_);break;default:throw Error("Unexpected state: "+k.state_);}}var k=this;null==this.onSettledCallbacks_?ha.asyncExecute(h):this.onSettledCallbacks_.push(function(){ha.asyncExecute(h)})};h.resolve=f;h.reject=function(d){return new h(function(f,h){h(d)})};h.race=function(d){return new h(function(h,
+k){for(var v=$jscomp.makeIterator(d),r=v.next();!r.done;r=v.next())f(r.value).callWhenSettled_(h,k)})};h.all=function(d){var k=$jscomp.makeIterator(d),r=k.next();return r.done?f([]):new h(function(d,h){function v(f){return function(h){u[f]=h;B--;0==B&&d(u)}}var u=[],B=0;do u.push(void 0),B++,f(r.value).callWhenSettled_(v(u.length-1),h),r=k.next();while(!r.done)})};return h},"es6","es3");
+var DracoDecoderModule=function(d){function k(a,c){c||(c=16);return Math.ceil(a/c)*c}function f(a,c){a||O("Assertion failed: "+c)}function u(a,c){if(0===c||!a)return"";for(var b=0,e,d=0;;){e=W[a+d>>0];b|=e;if(0==e&&!c)break;d++;if(c&&d==c)break}c||(c=d);e="";if(128>b){for(;0<c;)b=String.fromCharCode.apply(String,W.subarray(a,a+Math.min(c,1024))),e=e?e+b:b,a+=1024,c-=1024;return e}return h(W,a)}function h(a,c){for(var b=c;a[b];)++b;if(16<b-c&&a.subarray&&Ia)return Ia.decode(a.subarray(c,b));for(b=
+"";;){var e=a[c++];if(!e)return b;if(e&128){var d=a[c++]&63;if(192==(e&224))b+=String.fromCharCode((e&31)<<6|d);else{var f=a[c++]&63;if(224==(e&240))e=(e&15)<<12|d<<6|f;else{var g=a[c++]&63;if(240==(e&248))e=(e&7)<<18|d<<12|f<<6|g;else{var h=a[c++]&63;if(248==(e&252))e=(e&3)<<24|d<<18|f<<12|g<<6|h;else{var k=a[c++]&63;e=(e&1)<<30|d<<24|f<<18|g<<12|h<<6|k}}}65536>e?b+=String.fromCharCode(e):(e-=65536,b+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else b+=String.fromCharCode(e)}}function ha(a,c){0<
+a%c&&(a+=c-a%c);return a}function r(){a.HEAP8=ia=new Int8Array(D);a.HEAP16=Ja=new Int16Array(D);a.HEAP32=E=new Int32Array(D);a.HEAPU8=W=new Uint8Array(D);a.HEAPU16=new Uint16Array(D);a.HEAPU32=new Uint32Array(D);a.HEAPF32=new Float32Array(D);a.HEAPF64=new Float64Array(D)}function B(e){for(;0<e.length;){var c=e.shift();if("function"==typeof c)c();else{var b=c.func;"number"===typeof b?void 0===c.arg?a.dynCall_v(b):a.dynCall_vi(b,c.arg):b(void 0===c.arg?null:c.arg)}}}function Y(a){return String.prototype.startsWith?
+a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}function v(){return!!v.uncaught_exception}function la(){var e=y.last;if(!e)return(sa(0),0)|0;var c=y.infos[e],b=c.type;if(!b)return(sa(0),e)|0;var p=Array.prototype.slice.call(arguments);a.___cxa_is_pointer_type(b);la.buffer||(la.buffer=Ka(4));E[la.buffer>>2]=e;e=la.buffer;for(var d=0;d<p.length;d++)if(p[d]&&a.___cxa_can_catch(p[d],b,e))return e=E[e>>2],c.adjusted=e,(sa(p[d]),e)|0;e=E[e>>2];
+return(sa(b),e)|0}function Z(e,c){w.varargs=c;try{var b=w.get(),p=w.get(),d=w.get();e=0;Z.buffers||(Z.buffers=[null,[],[]],Z.printChar=function(c,b){var e=Z.buffers[c];f(e);0===b||10===b?((1===c?a.print:a.printErr)(h(e,0)),e.length=0):e.push(b)});for(c=0;c<d;c++){for(var g=E[p+8*c>>2],k=E[p+(8*c+4)>>2],l=0;l<k;l++)Z.printChar(b,W[g+l]);e+=k}return e}catch(ya){return"undefined"!==typeof FS&&ya instanceof FS.ErrnoError||O(ya),-ya.errno}}function ma(e,c){ma.seen||(ma.seen={});e in ma.seen||(a.dynCall_v(c),
+ma.seen[e]=1)}function na(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}function wa(e){function c(){if(!a.calledRun&&(a.calledRun=!0,!oa)){La||(La=!0,B(Ma));B(Na);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Oa.unshift(a.postRun.shift());B(Oa)}}if(!(0<ea)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Pa.unshift(a.preRun.shift());
+B(Pa);0<ea||a.calledRun||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);c()},1)):c())}}function O(e){if(a.onAbort)a.onAbort(e);void 0!==e?(a.print(e),a.printErr(e),e=JSON.stringify(e)):e="";oa=!0;throw"abort("+e+"). Build with -s ASSERTIONS=1 for more info.";}function m(){}function t(a){return(a||m).__cache__}function T(a,c){var b=t(c),e=b[a];if(e)return e;e=Object.create((c||m).prototype);e.ptr=a;return b[a]=e}function U(a){if("string"===typeof a){for(var c=
+0,b=0;b<a.length;++b){var e=a.charCodeAt(b);55296<=e&&57343>=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++b)&1023);127>=e?++c:c=2047>=e?c+2:65535>=e?c+3:2097151>=e?c+4:67108863>=e?c+5:c+6}c=Array(c+1);b=0;e=c.length;if(0<e){e=b+e-1;for(var d=0;d<a.length;++d){var f=a.charCodeAt(d);55296<=f&&57343>=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++d)&1023);if(127>=f){if(b>=e)break;c[b++]=f}else{if(2047>=f){if(b+1>=e)break;c[b++]=192|f>>6}else{if(65535>=f){if(b+2>=e)break;c[b++]=224|f>>12}else{if(2097151>=f){if(b+
+3>=e)break;c[b++]=240|f>>18}else{if(67108863>=f){if(b+4>=e)break;c[b++]=248|f>>24}else{if(b+5>=e)break;c[b++]=252|f>>30;c[b++]=128|f>>24&63}c[b++]=128|f>>18&63}c[b++]=128|f>>12&63}c[b++]=128|f>>6&63}c[b++]=128|f&63}}c[b]=0}a=l.alloc(c,ia);l.copy(c,ia,a)}return a}function z(){throw"cannot construct a Status, no constructor in IDL";}function F(){this.ptr=Wa();t(F)[this.ptr]=this}function G(){this.ptr=Xa();t(G)[this.ptr]=this}function H(){this.ptr=Ya();t(H)[this.ptr]=this}function I(){this.ptr=Za();
+t(I)[this.ptr]=this}function J(){this.ptr=$a();t(J)[this.ptr]=this}function n(){this.ptr=ab();t(n)[this.ptr]=this}function P(){this.ptr=bb();t(P)[this.ptr]=this}function x(){this.ptr=cb();t(x)[this.ptr]=this}function K(){this.ptr=db();t(K)[this.ptr]=this}function q(){this.ptr=eb();t(q)[this.ptr]=this}function L(){this.ptr=fb();t(L)[this.ptr]=this}function M(){this.ptr=gb();t(M)[this.ptr]=this}function V(){this.ptr=hb();t(V)[this.ptr]=this}function Q(){this.ptr=ib();t(Q)[this.ptr]=this}function g(){this.ptr=
+jb();t(g)[this.ptr]=this}function C(){this.ptr=kb();t(C)[this.ptr]=this}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function N(){this.ptr=lb();t(N)[this.ptr]=this}function R(){this.ptr=mb();t(R)[this.ptr]=this}d=d||{};var a="undefined"!==typeof d?d:{},Qa=!1,Ra=!1;a.onRuntimeInitialized=function(){Qa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ra=!0;if(Qa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=
+function(a){if("string"!==typeof a)return!1;a=a.split(".");return 2>a.length||3<a.length?!1:1==a[0]&&0<=a[1]&&3>=a[1]?!0:0!=a[0]||10<a[1]?!1:!0};var pa={},aa;for(aa in a)a.hasOwnProperty(aa)&&(pa[aa]=a[aa]);a.arguments=[];a.thisProgram="./this.program";a.quit=function(a,c){throw c;};a.preRun=[];a.postRun=[];var ja=!1,fa=!1,qa=!1,za=!1;if(a.ENVIRONMENT)if("WEB"===a.ENVIRONMENT)ja=!0;else if("WORKER"===a.ENVIRONMENT)fa=!0;else if("NODE"===a.ENVIRONMENT)qa=!0;else if("SHELL"===a.ENVIRONMENT)za=!0;else throw Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.");
+else ja="object"===typeof window,fa="function"===typeof importScripts,qa="object"===typeof process&&"function"===typeof require&&!ja&&!fa,za=!ja&&!qa&&!fa;if(qa){var Aa,Ba;a.read=function(a,c){Aa||(Aa=require("fs"));Ba||(Ba=require("path"));a=Ba.normalize(a);a=Aa.readFileSync(a);return c?a:a.toString()};a.readBinary=function(e){e=a.read(e,!0);e.buffer||(e=new Uint8Array(e));f(e.buffer);return e};1<process.argv.length&&(a.thisProgram=process.argv[1].replace(/\\/g,"/"));a.arguments=process.argv.slice(2);
+process.on("uncaughtException",function(a){if(!(a instanceof na))throw a;});process.on("unhandledRejection",function(a,c){process.exit(1)});a.inspect=function(){return"[Emscripten Module object]"}}else if(za)"undefined"!=typeof read&&(a.read=function(a){return read(a)}),a.readBinary=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");f("object"===typeof a);return a},"undefined"!=typeof scriptArgs?a.arguments=scriptArgs:"undefined"!=typeof arguments&&
+(a.arguments=arguments),"function"===typeof quit&&(a.quit=function(a,c){quit(a)});else if(ja||fa)a.read=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.send(null);return c.responseText},fa&&(a.readBinary=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)}),a.readAsync=function(a,c,b){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=function(){200==e.status||0==e.status&&e.response?
+c(e.response):b()};e.onerror=b;e.send(null)},a.setWindowTitle=function(a){document.title=a};a.print="undefined"!==typeof console?console.log.bind(console):"undefined"!==typeof print?print:null;a.printErr="undefined"!==typeof printErr?printErr:"undefined"!==typeof console&&console.warn.bind(console)||a.print;a.print=a.print;a.printErr=a.printErr;for(aa in pa)pa.hasOwnProperty(aa)&&(a[aa]=pa[aa]);pa=void 0;var oa=0,Ia="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;"undefined"!==typeof TextDecoder&&
+new TextDecoder("utf-16le");var ia,W,Ja,E,ba,Ca,ta,ua,Da,ka;var Ea=ba=Ca=ta=ua=Da=ka=0;var Sa=!1;a.reallocBuffer||(a.reallocBuffer=function(a){try{if(ArrayBuffer.transfer)var c=ArrayBuffer.transfer(D,a);else{var b=ia;c=new ArrayBuffer(a);(new Int8Array(c)).set(b)}}catch(p){return!1}return nb(c)?c:!1});try{var Ta=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);Ta(new ArrayBuffer(4))}catch(e){Ta=function(a){return a.byteLength}}var Fa=a.TOTAL_STACK||
+5242880,A=a.TOTAL_MEMORY||16777216;A<Fa&&a.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+A+"! (TOTAL_STACK="+Fa+")");if(a.buffer)var D=a.buffer;else"object"===typeof WebAssembly&&"function"===typeof WebAssembly.Memory?(a.wasmMemory=new WebAssembly.Memory({initial:A/65536}),D=a.wasmMemory.buffer):D=new ArrayBuffer(A),a.buffer=D;r();E[0]=1668509029;Ja[1]=25459;if(115!==W[2]||99!==W[3])throw"Runtime error: expected the system to be little-endian!";var Pa=[],Ma=[],Na=[],ob=[],Oa=[],
+La=!1,ea=0,Ga=null,ra=null;a.preloadedImages={};a.preloadedAudios={};(function(){function e(){try{if(a.wasmBinary)return new Uint8Array(a.wasmBinary);if(a.readBinary)return a.readBinary(f);throw"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)";}catch(Va){O(Va)}}function c(){return a.wasmBinary||!ja&&!fa||"function"!==typeof fetch?new Promise(function(a,c){a(e())}):fetch(f,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+
+f+"'";return a.arrayBuffer()}).catch(function(){return e()})}function b(b,e,d){function p(c,b){k=c.exports;k.memory&&(c=k.memory,b=a.buffer,c.byteLength<b.byteLength&&a.printErr("the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here"),b=new Int8Array(b),(new Int8Array(c)).set(b),a.buffer=D=c,r());a.asm=k;a.usingWasm=!0;ea--;a.monitorRunDependencies&&a.monitorRunDependencies(ea);0==ea&&(null!==Ga&&(clearInterval(Ga),Ga=null),ra&&(c=ra,ra=null,c()))}
+function g(a){p(a.instance,a.module)}function S(b){c().then(function(a){return WebAssembly.instantiate(a,h)}).then(b).catch(function(c){a.printErr("failed to asynchronously prepare wasm: "+c);O(c)})}if("object"!==typeof WebAssembly)return a.printErr("no native wasm support detected"),!1;if(!(a.wasmMemory instanceof WebAssembly.Memory))return a.printErr("no native wasm Memory in use"),!1;e.memory=a.wasmMemory;h.global={NaN:NaN,Infinity:Infinity};h["global.Math"]=Math;h.env=e;ea++;a.monitorRunDependencies&&
+a.monitorRunDependencies(ea);if(a.instantiateWasm)try{return a.instantiateWasm(h,p)}catch(pb){return a.printErr("Module.instantiateWasm callback failed with error: "+pb),!1}a.wasmBinary||"function"!==typeof WebAssembly.instantiateStreaming||Y(f)||"function"!==typeof fetch?S(g):WebAssembly.instantiateStreaming(fetch(f,{credentials:"same-origin"}),h).then(g).catch(function(c){a.printErr("wasm streaming compile failed: "+c);a.printErr("falling back to ArrayBuffer instantiation");S(g)});return{}}var d=
+"draco_decoder.wast",f="draco_decoder.wasm",g="draco_decoder.temp.asm.js";"function"===typeof a.locateFile&&(Y(d)||(d=a.locateFile(d)),Y(f)||(f=a.locateFile(f)),Y(g)||(g=a.locateFile(g)));var h={global:null,env:null,asm2wasm:{"f64-rem":function(a,c){return a%c},"debugger":function(){debugger}},parent:a},k=null;a.asmPreload=a.asm;var l=a.reallocBuffer;a.reallocBuffer=function(c){if("asmjs"===m)var b=l(c);else a:{c=ha(c,a.usingWasm?65536:16777216);var e=a.buffer.byteLength;if(a.usingWasm)try{b=-1!==
+a.wasmMemory.grow((c-e)/65536)?a.buffer=a.wasmMemory.buffer:null;break a}catch(ud){b=null;break a}b=void 0}return b};var m="";a.asm=function(c,e,d){if(!e.table){var p=a.wasmTableSize;void 0===p&&(p=1024);var f=a.wasmMaxTableSize;e.table="object"===typeof WebAssembly&&"function"===typeof WebAssembly.Table?void 0!==f?new WebAssembly.Table({initial:p,maximum:f,element:"anyfunc"}):new WebAssembly.Table({initial:p,element:"anyfunc"}):Array(p);a.wasmTable=e.table}e.memoryBase||(e.memoryBase=a.STATIC_BASE);
+e.tableBase||(e.tableBase=0);(c=b(c,e,d))||O("no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods");return c}})();Ea=1024;ba=Ea+14480;Ma.push();a.STATIC_BASE=Ea;a.STATIC_BUMP=14480;var qb=ba;ba+=16;var y={last:0,caught:[],infos:{},deAdjust:function(a){if(!a||y.infos[a])return a;for(var c in y.infos)if(y.infos[c].adjusted===a)return c;return a},addRef:function(a){a&&y.infos[a].refcount++},
+decRef:function(e){if(e){var c=y.infos[e];f(0<c.refcount);c.refcount--;0!==c.refcount||c.rethrown||(c.destructor&&a.dynCall_vi(c.destructor,e),delete y.infos[e],___cxa_free_exception(e))}},clearRef:function(a){a&&(y.infos[a].refcount=0)}},w={varargs:0,get:function(a){w.varargs+=4;return E[w.varargs-4>>2]},getStr:function(){return u(w.get())},get64:function(){var a=w.get(),c=w.get();0<=a?f(0===c):f(-1===c);return a},getZero:function(){f(0===w.get())}},va={},Ha=1;ka=function(a){f(!Sa);var c=ba;ba=ba+
+a+15&-16;return c}(4);Ca=ta=k(ba);ua=Ca+Fa;Da=k(ua);E[ka>>2]=Da;Sa=!0;a.wasmTableSize=468;a.wasmMaxTableSize=468;a.asmGlobalArg={};a.asmLibraryArg={abort:O,assert:f,enlargeMemory:function(){var e=a.usingWasm?65536:16777216,c=2147483648-e;if(E[ka>>2]>c)return!1;var b=A;for(A=Math.max(A,16777216);A<E[ka>>2];)A=536870912>=A?ha(2*A,e):Math.min(ha((3*A+2147483648)/4,e),c);e=a.reallocBuffer(A);if(!e||e.byteLength!=A)return A=b,!1;a.buffer=D=e;r();return!0},getTotalMemory:function(){return A},abortOnCannotGrowMemory:function(){O("Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value "+
+A+", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 ")},invoke_ii:function(e,c){try{return a.dynCall_ii(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_iii:function(e,c,b){try{return a.dynCall_iii(e,c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_iiii:function(e,c,b,d){try{return a.dynCall_iiii(e,
+c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_iiiiiii:function(e,c,b,d,f,g,h){try{return a.dynCall_iiiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},invoke_v:function(e){try{a.dynCall_v(e)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;a.setThrew(1,0)}},invoke_vi:function(e,c){try{a.dynCall_vi(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_vii:function(e,c,b){try{a.dynCall_vii(e,
+c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_viii:function(e,c,b,d){try{a.dynCall_viii(e,c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_viiii:function(e,c,b,d,f){try{a.dynCall_viiii(e,c,b,d,f)}catch(xa){if("number"!==typeof xa&&"longjmp"!==xa)throw xa;a.setThrew(1,0)}},invoke_viiiii:function(e,c,b,d,f,g){try{a.dynCall_viiiii(e,c,b,d,f,g)}catch(ca){if("number"!==typeof ca&&"longjmp"!==ca)throw ca;a.setThrew(1,0)}},invoke_viiiiii:function(e,
+c,b,d,f,g,h){try{a.dynCall_viiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},__ZSt18uncaught_exceptionv:v,___cxa_allocate_exception:function(a){return Ka(a)},___cxa_begin_catch:function(a){var c=y.infos[a];c&&!c.caught&&(c.caught=!0,v.uncaught_exception--);c&&(c.rethrown=!1);y.caught.push(a);y.addRef(y.deAdjust(a));return a},___cxa_find_matching_catch:la,___cxa_pure_virtual:function(){oa=!0;throw"Pure virtual function called!";},___cxa_throw:function(a,
+c,b){y.infos[a]={ptr:a,adjusted:a,type:c,destructor:b,refcount:0,caught:!1,rethrown:!1};y.last=a;"uncaught_exception"in v?v.uncaught_exception++:v.uncaught_exception=1;throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";},___gxx_personality_v0:function(){},___resumeException:function(a){y.last||(y.last=a);throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+},___setErrNo:function(d){a.___errno_location&&(E[a.___errno_location()>>2]=d);return d},___syscall140:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();w.get();var d=w.get(),e=w.get(),f=w.get();FS.llseek(b,d,f);E[e>>2]=b.position;b.getdents&&0===d&&0===f&&(b.getdents=null);return 0}catch(ca){return"undefined"!==typeof FS&&ca instanceof FS.ErrnoError||O(ca),-ca.errno}},___syscall146:Z,___syscall6:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();FS.close(b);return 0}catch(p){return"undefined"!==
+typeof FS&&p instanceof FS.ErrnoError||O(p),-p.errno}},_abort:function(){a.abort()},_emscripten_memcpy_big:function(a,c,b){W.set(W.subarray(c,c+b),a);return a},_llvm_trap:function(){O("trap!")},_pthread_getspecific:function(a){return va[a]||0},_pthread_key_create:function(a,c){if(0==a)return 22;E[a>>2]=Ha;va[Ha]=0;Ha++;return 0},_pthread_once:ma,_pthread_setspecific:function(a,c){if(!(a in va))return 22;va[a]=c;return 0},flush_NO_FILESYSTEM:function(){var d=a._fflush;d&&d(0);if(d=Z.printChar){var c=
+Z.buffers;c[1].length&&d(1,10);c[2].length&&d(2,10)}},DYNAMICTOP_PTR:ka,tempDoublePtr:qb,ABORT:oa,STACKTOP:ta,STACK_MAX:ua};var Ua=a.asm(a.asmGlobalArg,a.asmLibraryArg,D);a.asm=Ua;a.___cxa_can_catch=function(){return a.asm.___cxa_can_catch.apply(null,arguments)};a.___cxa_is_pointer_type=function(){return a.asm.___cxa_is_pointer_type.apply(null,arguments)};var $a=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,
+arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,
+arguments)},cb=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,arguments)},ub=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},vb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,
+arguments)},wb=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,arguments)},xb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},yb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,
+arguments)},bb=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return a.asm._emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,arguments)},zb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm._emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Ab=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm._emscripten_bind_AttributeTransformData_transform_type_0.apply(null,
+arguments)},ib=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm._emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},Bb=a._emscripten_bind_DecoderBuffer_Init_2=function(){return a.asm._emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},Cb=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm._emscripten_bind_DecoderBuffer___destroy___0.apply(null,arguments)},Db=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,
+arguments)},Eb=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,arguments)},jb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm._emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},Fb=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},Gb=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=
+function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Hb=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Ib=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},Jb=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,
+arguments)},Kb=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeId_2.apply(null,arguments)},Lb=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3.apply(null,arguments)},Mb=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Nb=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=
+function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3.apply(null,arguments)},Ob=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,arguments)},Pb=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,arguments)},Qb=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3.apply(null,
+arguments)},Rb=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3.apply(null,arguments)},Sb=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3.apply(null,arguments)},Tb=a._emscripten_bind_Decoder_GetAttribute_2=function(){return a.asm._emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},Ub=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=
+function(){return a.asm._emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},Vb=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm._emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},Wb=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm._emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},Xb=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,
+arguments)},Yb=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm._emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Zb=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm._emscripten_bind_Decoder___destroy___0.apply(null,arguments)},gb=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,arguments)},$b=a._emscripten_bind_DracoFloat32Array_GetValue_1=
+function(){return a.asm._emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},ac=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},bc=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},fb=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return a.asm._emscripten_bind_DracoInt16Array_DracoInt16Array_0.apply(null,
+arguments)},cc=a._emscripten_bind_DracoInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt16Array_GetValue_1.apply(null,arguments)},dc=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt16Array___destroy___0.apply(null,arguments)},ec=a._emscripten_bind_DracoInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoInt16Array_size_0.apply(null,arguments)},lb=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm._emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,
+arguments)},fc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},gc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},hc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoInt32Array_size_0.apply(null,arguments)},db=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return a.asm._emscripten_bind_DracoInt8Array_DracoInt8Array_0.apply(null,
+arguments)},ic=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt8Array_GetValue_1.apply(null,arguments)},jc=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt8Array___destroy___0.apply(null,arguments)},kc=a._emscripten_bind_DracoInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoInt8Array_size_0.apply(null,arguments)},Wa=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0.apply(null,
+arguments)},lc=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt16Array_GetValue_1.apply(null,arguments)},mc=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt16Array___destroy___0.apply(null,arguments)},nc=a._emscripten_bind_DracoUInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_size_0.apply(null,arguments)},Za=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0.apply(null,
+arguments)},oc=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt32Array_GetValue_1.apply(null,arguments)},pc=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt32Array___destroy___0.apply(null,arguments)},qc=a._emscripten_bind_DracoUInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_size_0.apply(null,arguments)},Ya=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0.apply(null,
+arguments)},rc=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt8Array_GetValue_1.apply(null,arguments)},sc=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt8Array___destroy___0.apply(null,arguments)},tc=a._emscripten_bind_DracoUInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_size_0.apply(null,arguments)},hb=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm._emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
+arguments)},uc=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm._emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},kb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm._emscripten_bind_Mesh_Mesh_0.apply(null,arguments)},vc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm._emscripten_bind_Mesh___destroy___0.apply(null,arguments)},wc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm._emscripten_bind_Mesh_num_attributes_0.apply(null,
+arguments)},xc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm._emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},yc=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm._emscripten_bind_Mesh_num_points_0.apply(null,arguments)},zc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},Ac=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,
+arguments)},Bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},Cc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},Dc=a._emscripten_bind_MetadataQuerier_HasDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasDoubleEntry_2.apply(null,arguments)},Ec=a._emscripten_bind_MetadataQuerier_HasEntry_2=
+function(){return a.asm._emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},Fc=a._emscripten_bind_MetadataQuerier_HasIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasIntEntry_2.apply(null,arguments)},Gc=a._emscripten_bind_MetadataQuerier_HasStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasStringEntry_2.apply(null,arguments)},eb=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm._emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,
+arguments)},Hc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm._emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,arguments)},Ic=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm._emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},mb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm._emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},Jc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm._emscripten_bind_Metadata___destroy___0.apply(null,
+arguments)},Kc=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm._emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},ab=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return a.asm._emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},Lc=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm._emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},Mc=a._emscripten_bind_PointAttribute_attribute_type_0=
+function(){return a.asm._emscripten_bind_PointAttribute_attribute_type_0.apply(null,arguments)},Nc=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},Oc=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_stride_0.apply(null,arguments)},Pc=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm._emscripten_bind_PointAttribute_data_type_0.apply(null,
+arguments)},Qc=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm._emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Rc=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm._emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Sc=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm._emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Tc=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm._emscripten_bind_PointAttribute_unique_id_0.apply(null,
+arguments)},Xa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm._emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},Uc=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm._emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Vc=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm._emscripten_bind_PointCloud_num_attributes_0.apply(null,arguments)},Wc=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm._emscripten_bind_PointCloud_num_points_0.apply(null,
+arguments)},Xc=a._emscripten_bind_Status___destroy___0=function(){return a.asm._emscripten_bind_Status___destroy___0.apply(null,arguments)},Yc=a._emscripten_bind_Status_code_0=function(){return a.asm._emscripten_bind_Status_code_0.apply(null,arguments)},Zc=a._emscripten_bind_Status_error_msg_0=function(){return a.asm._emscripten_bind_Status_error_msg_0.apply(null,arguments)},$c=a._emscripten_bind_Status_ok_0=function(){return a.asm._emscripten_bind_Status_ok_0.apply(null,arguments)},ad=a._emscripten_bind_VoidPtr___destroy___0=
+function(){return a.asm._emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},bd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,arguments)},cd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},dd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=
+function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,arguments)},ed=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},fd=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
+arguments)},gd=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},hd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},id=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},jd=
+a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)},kd=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},ld=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},md=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
+function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},nd=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_ERROR.apply(null,arguments)},pd=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm._emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,
+arguments)},qd=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},rd=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm._emscripten_enum_draco_StatusCode_OK.apply(null,arguments)},sd=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},td=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,
+arguments)},nb=a._emscripten_replace_memory=function(){return a.asm._emscripten_replace_memory.apply(null,arguments)};a._free=function(){return a.asm._free.apply(null,arguments)};a._llvm_bswap_i32=function(){return a.asm._llvm_bswap_i32.apply(null,arguments)};var Ka=a._malloc=function(){return a.asm._malloc.apply(null,arguments)};a._memcpy=function(){return a.asm._memcpy.apply(null,arguments)};a._memmove=function(){return a.asm._memmove.apply(null,arguments)};a._memset=function(){return a.asm._memset.apply(null,
+arguments)};a._sbrk=function(){return a.asm._sbrk.apply(null,arguments)};a.establishStackSpace=function(){return a.asm.establishStackSpace.apply(null,arguments)};a.getTempRet0=function(){return a.asm.getTempRet0.apply(null,arguments)};a.runPostSets=function(){return a.asm.runPostSets.apply(null,arguments)};var sa=a.setTempRet0=function(){return a.asm.setTempRet0.apply(null,arguments)};a.setThrew=function(){return a.asm.setThrew.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,
+arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,
+arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};a.asm=Ua;a.then=function(d){if(a.calledRun)d(a);
+else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();d(a)}}return a};na.prototype=Error();na.prototype.constructor=na;ra=function c(){a.calledRun||wa();a.calledRun||(ra=c)};a.run=wa;a.exit=function(c,b){if(!b||!a.noExitRuntime||0!==c){if(!a.noExitRuntime&&(oa=!0,ta=void 0,B(ob),a.onExit))a.onExit(c);qa&&process.exit(c);a.quit(c,new na(c))}};a.abort=O;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();a.noExitRuntime=!0;
+wa();m.prototype=Object.create(m.prototype);m.prototype.constructor=m;m.prototype.__class__=m;m.__cache__={};a.WrapperObject=m;a.getCache=t;a.wrapPointer=T;a.castObject=function(a,b){return T(a.ptr,b)};a.NULL=T(0);a.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";a.__destroy__();delete t(a.__class__)[a.ptr]};a.compare=function(a,b){return a.ptr===b.ptr};a.getPointer=function(a){return a.ptr};a.getClass=function(a){return a.__class__};var l=
+{buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(l.needed){for(var c=0;c<l.temps.length;c++)a._free(l.temps[c]);l.temps.length=0;a._free(l.buffer);l.buffer=0;l.size+=l.needed;l.needed=0}l.buffer||(l.size+=128,l.buffer=a._malloc(l.size),f(l.buffer));l.pos=0},alloc:function(c,b){f(l.buffer);c=c.length*b.BYTES_PER_ELEMENT;c=c+7&-8;l.pos+c>=l.size?(f(0<c),l.needed+=c,b=a._malloc(c),l.temps.push(b)):(b=l.buffer+l.pos,l.pos+=c);return b},copy:function(a,b,d){switch(b.BYTES_PER_ELEMENT){case 2:d>>=
+1;break;case 4:d>>=2;break;case 8:d>>=3}for(var c=0;c<a.length;c++)b[d+c]=a[c]}};z.prototype=Object.create(m.prototype);z.prototype.constructor=z;z.prototype.__class__=z;z.__cache__={};a.Status=z;z.prototype.code=z.prototype.code=function(){return Yc(this.ptr)};z.prototype.ok=z.prototype.ok=function(){return!!$c(this.ptr)};z.prototype.error_msg=z.prototype.error_msg=function(){return u(Zc(this.ptr))};z.prototype.__destroy__=z.prototype.__destroy__=function(){Xc(this.ptr)};F.prototype=Object.create(m.prototype);
+F.prototype.constructor=F;F.prototype.__class__=F;F.__cache__={};a.DracoUInt16Array=F;F.prototype.GetValue=F.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return lc(c,a)};F.prototype.size=F.prototype.size=function(){return nc(this.ptr)};F.prototype.__destroy__=F.prototype.__destroy__=function(){mc(this.ptr)};G.prototype=Object.create(m.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.PointCloud=G;G.prototype.num_attributes=G.prototype.num_attributes=
+function(){return Vc(this.ptr)};G.prototype.num_points=G.prototype.num_points=function(){return Wc(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){Uc(this.ptr)};H.prototype=Object.create(m.prototype);H.prototype.constructor=H;H.prototype.__class__=H;H.__cache__={};a.DracoUInt8Array=H;H.prototype.GetValue=H.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return rc(c,a)};H.prototype.size=H.prototype.size=function(){return tc(this.ptr)};H.prototype.__destroy__=
+H.prototype.__destroy__=function(){sc(this.ptr)};I.prototype=Object.create(m.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoUInt32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return oc(c,a)};I.prototype.size=I.prototype.size=function(){return qc(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){pc(this.ptr)};J.prototype=Object.create(m.prototype);J.prototype.constructor=J;J.prototype.__class__=
+J;J.__cache__={};a.AttributeOctahedronTransform=J;J.prototype.InitFromAttribute=J.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!rb(c,a)};J.prototype.quantization_bits=J.prototype.quantization_bits=function(){return tb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){sb(this.ptr)};n.prototype=Object.create(m.prototype);n.prototype.constructor=n;n.prototype.__class__=n;n.__cache__={};a.PointAttribute=n;n.prototype.size=n.prototype.size=
+function(){return Sc(this.ptr)};n.prototype.GetAttributeTransformData=n.prototype.GetAttributeTransformData=function(){return T(Kc(this.ptr),P)};n.prototype.attribute_type=n.prototype.attribute_type=function(){return Mc(this.ptr)};n.prototype.data_type=n.prototype.data_type=function(){return Pc(this.ptr)};n.prototype.num_components=n.prototype.num_components=function(){return Rc(this.ptr)};n.prototype.normalized=n.prototype.normalized=function(){return!!Qc(this.ptr)};n.prototype.byte_stride=n.prototype.byte_stride=
+function(){return Oc(this.ptr)};n.prototype.byte_offset=n.prototype.byte_offset=function(){return Nc(this.ptr)};n.prototype.unique_id=n.prototype.unique_id=function(){return Tc(this.ptr)};n.prototype.__destroy__=n.prototype.__destroy__=function(){Lc(this.ptr)};P.prototype=Object.create(m.prototype);P.prototype.constructor=P;P.prototype.__class__=P;P.__cache__={};a.AttributeTransformData=P;P.prototype.transform_type=P.prototype.transform_type=function(){return Ab(this.ptr)};P.prototype.__destroy__=
+P.prototype.__destroy__=function(){zb(this.ptr)};x.prototype=Object.create(m.prototype);x.prototype.constructor=x;x.prototype.__class__=x;x.__cache__={};a.AttributeQuantizationTransform=x;x.prototype.InitFromAttribute=x.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!ub(c,a)};x.prototype.quantization_bits=x.prototype.quantization_bits=function(){return xb(this.ptr)};x.prototype.min_value=x.prototype.min_value=function(a){var c=this.ptr;a&&"object"===
+typeof a&&(a=a.ptr);return wb(c,a)};x.prototype.range=x.prototype.range=function(){return yb(this.ptr)};x.prototype.__destroy__=x.prototype.__destroy__=function(){vb(this.ptr)};K.prototype=Object.create(m.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DracoInt8Array=K;K.prototype.GetValue=K.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return ic(c,a)};K.prototype.size=K.prototype.size=function(){return kc(this.ptr)};K.prototype.__destroy__=
+K.prototype.__destroy__=function(){jc(this.ptr)};q.prototype=Object.create(m.prototype);q.prototype.constructor=q;q.prototype.__class__=q;q.__cache__={};a.MetadataQuerier=q;q.prototype.HasEntry=q.prototype.HasEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Ec(c,a,b)};q.prototype.HasIntEntry=q.prototype.HasIntEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);
+return!!Fc(c,a,b)};q.prototype.GetIntEntry=q.prototype.GetIntEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return Bc(c,a,b)};q.prototype.HasDoubleEntry=q.prototype.HasDoubleEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Dc(c,a,b)};q.prototype.GetDoubleEntry=q.prototype.GetDoubleEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=
+a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return zc(c,a,b)};q.prototype.HasStringEntry=q.prototype.HasStringEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Gc(c,a,b)};q.prototype.GetStringEntry=q.prototype.GetStringEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return u(Cc(c,a,b))};q.prototype.NumEntries=q.prototype.NumEntries=function(a){var c=this.ptr;
+a&&"object"===typeof a&&(a=a.ptr);return Hc(c,a)};q.prototype.GetEntryName=q.prototype.GetEntryName=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return u(Ac(c,a,b))};q.prototype.__destroy__=q.prototype.__destroy__=function(){Ic(this.ptr)};L.prototype=Object.create(m.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.DracoInt16Array=L;L.prototype.GetValue=L.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&
+(a=a.ptr);return cc(c,a)};L.prototype.size=L.prototype.size=function(){return ec(this.ptr)};L.prototype.__destroy__=L.prototype.__destroy__=function(){dc(this.ptr)};M.prototype=Object.create(m.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DracoFloat32Array=M;M.prototype.GetValue=M.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return $b(c,a)};M.prototype.size=M.prototype.size=function(){return bc(this.ptr)};M.prototype.__destroy__=M.prototype.__destroy__=
+function(){ac(this.ptr)};V.prototype=Object.create(m.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){uc(this.ptr)};Q.prototype=Object.create(m.prototype);Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.DecoderBuffer=Q;Q.prototype.Init=Q.prototype.Init=function(a,b){var c=this.ptr;l.prepare();if("object"==typeof a&&"object"===typeof a){var d=l.alloc(a,ia);l.copy(a,ia,d);a=
+d}b&&"object"===typeof b&&(b=b.ptr);Bb(c,a,b)};Q.prototype.__destroy__=Q.prototype.__destroy__=function(){Cb(this.ptr)};g.prototype=Object.create(m.prototype);g.prototype.constructor=g;g.prototype.__class__=g;g.__cache__={};a.Decoder=g;g.prototype.GetEncodedGeometryType=g.prototype.GetEncodedGeometryType=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Ub(c,a)};g.prototype.DecodeBufferToPointCloud=g.prototype.DecodeBufferToPointCloud=function(a,b){var c=this.ptr;a&&"object"===typeof a&&
+(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Eb(c,a,b),z)};g.prototype.DecodeBufferToMesh=g.prototype.DecodeBufferToMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Db(c,a,b),z)};g.prototype.GetAttributeId=g.prototype.GetAttributeId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return Kb(c,a,b)};g.prototype.GetAttributeIdByName=g.prototype.GetAttributeIdByName=function(a,b){var c=
+this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return Jb(c,a,b)};g.prototype.GetAttributeIdByMetadataEntry=g.prototype.GetAttributeIdByMetadataEntry=function(a,b,d){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);d=d&&"object"===typeof d?d.ptr:U(d);return Ib(c,a,b,d)};g.prototype.GetAttribute=g.prototype.GetAttribute=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=
+b.ptr);return T(Tb(c,a,b),n)};g.prototype.GetAttributeByUniqueId=g.prototype.GetAttributeByUniqueId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Fb(c,a,b),n)};g.prototype.GetMetadata=g.prototype.GetMetadata=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return T(Wb(c,a),R)};g.prototype.GetAttributeMetadata=g.prototype.GetAttributeMetadata=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&
+(b=b.ptr);return T(Pb(c,a,b),R)};g.prototype.GetFaceFromMesh=g.prototype.GetFaceFromMesh=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Vb(c,a,b,d)};g.prototype.GetTriangleStripsFromMesh=g.prototype.GetTriangleStripsFromMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return Xb(c,a,b)};g.prototype.GetAttributeFloat=g.prototype.GetAttributeFloat=function(a,
+b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Hb(c,a,b,d)};g.prototype.GetAttributeFloatForAllPoints=g.prototype.GetAttributeFloatForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Gb(c,a,b,d)};g.prototype.GetAttributeIntForAllPoints=g.prototype.GetAttributeIntForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===
+typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ob(c,a,b,d)};g.prototype.GetAttributeInt8ForAllPoints=g.prototype.GetAttributeInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Nb(c,a,b,d)};g.prototype.GetAttributeUInt8ForAllPoints=g.prototype.GetAttributeUInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===
+typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Sb(c,a,b,d)};g.prototype.GetAttributeInt16ForAllPoints=g.prototype.GetAttributeInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Lb(c,a,b,d)};g.prototype.GetAttributeUInt16ForAllPoints=g.prototype.GetAttributeUInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&
+"object"===typeof d&&(d=d.ptr);return!!Qb(c,a,b,d)};g.prototype.GetAttributeInt32ForAllPoints=g.prototype.GetAttributeInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Mb(c,a,b,d)};g.prototype.GetAttributeUInt32ForAllPoints=g.prototype.GetAttributeUInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=
+d.ptr);return!!Rb(c,a,b,d)};g.prototype.SkipAttributeTransform=g.prototype.SkipAttributeTransform=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);Yb(c,a)};g.prototype.__destroy__=g.prototype.__destroy__=function(){Zb(this.ptr)};C.prototype=Object.create(m.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Mesh=C;C.prototype.num_faces=C.prototype.num_faces=function(){return xc(this.ptr)};C.prototype.num_attributes=C.prototype.num_attributes=function(){return wc(this.ptr)};
+C.prototype.num_points=C.prototype.num_points=function(){return yc(this.ptr)};C.prototype.__destroy__=C.prototype.__destroy__=function(){vc(this.ptr)};X.prototype=Object.create(m.prototype);X.prototype.constructor=X;X.prototype.__class__=X;X.__cache__={};a.VoidPtr=X;X.prototype.__destroy__=X.prototype.__destroy__=function(){ad(this.ptr)};N.prototype=Object.create(m.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.DracoInt32Array=N;N.prototype.GetValue=N.prototype.GetValue=
+function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return fc(b,a)};N.prototype.size=N.prototype.size=function(){return hc(this.ptr)};N.prototype.__destroy__=N.prototype.__destroy__=function(){gc(this.ptr)};R.prototype=Object.create(m.prototype);R.prototype.constructor=R;R.prototype.__class__=R;R.__cache__={};a.Metadata=R;R.prototype.__destroy__=R.prototype.__destroy__=function(){Jc(this.ptr)};(function(){function c(){a.OK=rd();a.ERROR=od();a.IO_ERROR=qd();a.INVALID_PARAMETER=pd();a.UNSUPPORTED_VERSION=
+td();a.UNKNOWN_VERSION=sd();a.INVALID_GEOMETRY_TYPE=fd();a.POINT_CLOUD=gd();a.TRIANGULAR_MESH=hd();a.ATTRIBUTE_INVALID_TRANSFORM=bd();a.ATTRIBUTE_NO_TRANSFORM=cd();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=ed();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=dd();a.INVALID=kd();a.POSITION=md();a.NORMAL=ld();a.COLOR=id();a.TEX_COORD=nd();a.GENERIC=jd()}a.calledRun?c():Na.unshift(c)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();return d};
+"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);

+ 2 - 2
examples/js/lines/LineMaterial.js

@@ -168,9 +168,9 @@ THREE.ShaderLib[ 'line' ] = {
 
 
 			gl_Position = clip;
 			gl_Position = clip;
 
 
-			#include <logdepthbuf_vertex>
+			vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation
 
 
-			#include <worldpos_vertex>
+			#include <logdepthbuf_vertex>
 			#include <clipping_planes_vertex>
 			#include <clipping_planes_vertex>
 			#include <fog_vertex>
 			#include <fog_vertex>
 
 

+ 79 - 1
examples/js/loaders/ColladaLoader.js

@@ -2686,6 +2686,82 @@ THREE.ColladaLoader.prototype = {
 
 
 		}
 		}
 
 
+		// physics
+
+		function parsePhysicsModel( xml ) {
+
+			var data = {
+				name: xml.getAttribute( 'name' ) || '',
+				rigidBodies: {}
+			};
+
+			for ( var i = 0; i < xml.childNodes.length; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'rigid_body':
+						data.rigidBodies[ child.getAttribute( 'name' ) ] = {};
+						parsePhysicsRigidBody( child, data.rigidBodies[ child.getAttribute( 'name' ) ] );
+						break;
+
+				}
+
+			}
+
+			library.physicsModels[ xml.getAttribute( 'id' ) ] = data;
+
+		}
+
+		function parsePhysicsRigidBody( xml, data ) {
+
+			for ( var i = 0; i < xml.childNodes.length; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'technique_common':
+						parsePhysicsTechniqueCommon( child, data );
+						break;
+
+				}
+
+			}
+
+		}
+
+		function parsePhysicsTechniqueCommon( xml, data ) {
+
+			for ( var i = 0; i < xml.childNodes.length; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'inertia':
+						data.inertia = parseFloats( child.textContent );
+						break;
+
+					case 'mass':
+						data.mass = parseFloats( child.textContent )[0];
+						break;
+
+				}
+
+			}
+
+		}
+
+		// scene
+
 		function parseKinematicsScene( xml ) {
 		function parseKinematicsScene( xml ) {
 
 
 			var data = {
 			var data = {
@@ -3282,7 +3358,7 @@ THREE.ColladaLoader.prototype = {
 						// and weights defined for it. But we still have to add the bone to the sorted bone list in order to
 						// and weights defined for it. But we still have to add the bone to the sorted bone list in order to
 						// ensure a correct animation of the model.
 						// ensure a correct animation of the model.
 
 
-						 boneInverse = new THREE.Matrix4();
+						boneInverse = new THREE.Matrix4();
 
 
 					}
 					}
 
 
@@ -3684,6 +3760,7 @@ THREE.ColladaLoader.prototype = {
 			nodes: {},
 			nodes: {},
 			visualScenes: {},
 			visualScenes: {},
 			kinematicsModels: {},
 			kinematicsModels: {},
+			physicsModels: {},
 			kinematicsScenes: {}
 			kinematicsScenes: {}
 		};
 		};
 
 
@@ -3699,6 +3776,7 @@ THREE.ColladaLoader.prototype = {
 		parseLibrary( collada, 'library_nodes', 'node', parseNode );
 		parseLibrary( collada, 'library_nodes', 'node', parseNode );
 		parseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene );
 		parseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene );
 		parseLibrary( collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel );
 		parseLibrary( collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel );
+		parseLibrary( collada, 'library_physics_models', 'physics_model', parsePhysicsModel );
 		parseLibrary( collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene );
 		parseLibrary( collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene );
 
 
 		buildLibrary( library.animations, buildAnimation );
 		buildLibrary( library.animations, buildAnimation );

+ 87 - 15
examples/js/loaders/DRACOLoader.js

@@ -52,14 +52,17 @@ THREE.DRACOLoader.prototype = {
 
 
     setPath: function(value) {
     setPath: function(value) {
         this.path = value;
         this.path = value;
+        return this;
     },
     },
 
 
     setCrossOrigin: function(value) {
     setCrossOrigin: function(value) {
         this.crossOrigin = value;
         this.crossOrigin = value;
+        return this;
     },
     },
 
 
     setVerbosity: function(level) {
     setVerbosity: function(level) {
         this.verbosity = level;
         this.verbosity = level;
+        return this;
     },
     },
 
 
     /**
     /**
@@ -70,6 +73,7 @@ THREE.DRACOLoader.prototype = {
      */
      */
     setDrawMode: function(drawMode) {
     setDrawMode: function(drawMode) {
         this.drawMode = drawMode;
         this.drawMode = drawMode;
+        return this;
     },
     },
 
 
     /**
     /**
@@ -84,6 +88,7 @@ THREE.DRACOLoader.prototype = {
           skipDequantization = skip;
           skipDequantization = skip;
         this.getAttributeOptions(attributeName).skipDequantization =
         this.getAttributeOptions(attributeName).skipDequantization =
             skipDequantization;
             skipDequantization;
+        return this;
     },
     },
 
 
     /**
     /**
@@ -100,17 +105,18 @@ THREE.DRACOLoader.prototype = {
      * The format is:
      * The format is:
      *     attributeUniqueIdMap[attributeName] = attributeId
      *     attributeUniqueIdMap[attributeName] = attributeId
      */
      */
-    decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap) {
+    decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap,
+                              attributeTypeMap) {
       var scope = this;
       var scope = this;
       THREE.DRACOLoader.getDecoderModule()
       THREE.DRACOLoader.getDecoderModule()
           .then( function ( module ) {
           .then( function ( module ) {
             scope.decodeDracoFileInternal( rawBuffer, module.decoder, callback,
             scope.decodeDracoFileInternal( rawBuffer, module.decoder, callback,
-              attributeUniqueIdMap || {});
+              attributeUniqueIdMap || {}, attributeTypeMap || {});
           });
           });
     },
     },
 
 
     decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback,
     decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback,
-                                      attributeUniqueIdMap) {
+                                      attributeUniqueIdMap, attributeTypeMap) {
       /*
       /*
        * Here is how to use Draco Javascript decoder and get the geometry.
        * Here is how to use Draco Javascript decoder and get the geometry.
        */
        */
@@ -136,38 +142,103 @@ THREE.DRACOLoader.prototype = {
         throw new Error(errorMsg);
         throw new Error(errorMsg);
       }
       }
       callback(this.convertDracoGeometryTo3JS(dracoDecoder, decoder,
       callback(this.convertDracoGeometryTo3JS(dracoDecoder, decoder,
-          geometryType, buffer, attributeUniqueIdMap));
+          geometryType, buffer, attributeUniqueIdMap, attributeTypeMap));
     },
     },
 
 
     addAttributeToGeometry: function(dracoDecoder, decoder, dracoGeometry,
     addAttributeToGeometry: function(dracoDecoder, decoder, dracoGeometry,
-                                     attributeName, attribute, geometry,
-                                     geometryBuffer) {
+                                     attributeName, attributeType, attribute, 
+                                     geometry, geometryBuffer) {
       if (attribute.ptr === 0) {
       if (attribute.ptr === 0) {
         var errorMsg = 'THREE.DRACOLoader: No attribute ' + attributeName;
         var errorMsg = 'THREE.DRACOLoader: No attribute ' + attributeName;
         console.error(errorMsg);
         console.error(errorMsg);
         throw new Error(errorMsg);
         throw new Error(errorMsg);
       }
       }
+
       var numComponents = attribute.num_components();
       var numComponents = attribute.num_components();
-      var attributeData = new dracoDecoder.DracoFloat32Array();
-      decoder.GetAttributeFloatForAllPoints(
-          dracoGeometry, attribute, attributeData);
       var numPoints = dracoGeometry.num_points();
       var numPoints = dracoGeometry.num_points();
       var numValues = numPoints * numComponents;
       var numValues = numPoints * numComponents;
-      // Allocate space for attribute.
-      geometryBuffer[attributeName] = new Float32Array(numValues);
+      var attributeData;
+      var TypedBufferAttribute;
+
+      switch ( attributeType ) {
+
+        case Float32Array:
+          attributeData = new dracoDecoder.DracoFloat32Array();
+          decoder.GetAttributeFloatForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Float32Array( numValues );
+          TypedBufferAttribute = THREE.Float32BufferAttribute;
+          break;
+
+        case Int8Array:
+          attributeData = new dracoDecoder.DracoInt8Array();
+          decoder.GetAttributeInt8ForAllPoints(
+            dracoGeometry, attribute, attributeData );
+          geometryBuffer[ attributeName ] = new Int8Array( numValues );
+          TypedBufferAttribute = THREE.Int8BufferAttribute;
+          break;
+
+        case Int16Array:
+          attributeData = new dracoDecoder.DracoInt16Array();
+          decoder.GetAttributeInt16ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Int16Array( numValues );
+          TypedBufferAttribute = THREE.Int16BufferAttribute;
+          break;
+
+        case Int32Array:
+          attributeData = new dracoDecoder.DracoInt32Array();
+          decoder.GetAttributeInt32ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Int32Array( numValues );
+          TypedBufferAttribute = THREE.Int32BufferAttribute;
+          break;
+
+        case Uint8Array:
+          attributeData = new dracoDecoder.DracoUInt8Array();
+          decoder.GetAttributeUInt8ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint8Array( numValues );
+          TypedBufferAttribute = THREE.Uint8BufferAttribute;
+          break;
+
+        case Uint16Array:
+          attributeData = new dracoDecoder.DracoUInt16Array();
+          decoder.GetAttributeUInt16ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint16Array( numValues );
+          TypedBufferAttribute = THREE.Uint16BufferAttribute;
+          break;
+
+        case Uint32Array:
+          attributeData = new dracoDecoder.DracoUInt32Array();
+          decoder.GetAttributeUInt32ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint32Array( numValues );
+          TypedBufferAttribute = THREE.Uint32BufferAttribute;
+          break;
+
+        default:
+          var errorMsg = 'THREE.DRACOLoader: Unexpected attribute type.';
+          console.error( errorMsg );
+          throw new Error( errorMsg );
+
+      }
+      
       // Copy data from decoder.
       // Copy data from decoder.
       for (var i = 0; i < numValues; i++) {
       for (var i = 0; i < numValues; i++) {
         geometryBuffer[attributeName][i] = attributeData.GetValue(i);
         geometryBuffer[attributeName][i] = attributeData.GetValue(i);
       }
       }
       // Add attribute to THREEJS geometry for rendering.
       // Add attribute to THREEJS geometry for rendering.
       geometry.addAttribute(attributeName,
       geometry.addAttribute(attributeName,
-          new THREE.Float32BufferAttribute(geometryBuffer[attributeName],
+          new TypedBufferAttribute(geometryBuffer[attributeName],
             numComponents));
             numComponents));
       dracoDecoder.destroy(attributeData);
       dracoDecoder.destroy(attributeData);
     },
     },
 
 
     convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType,
     convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType,
-                                        buffer, attributeUniqueIdMap) {
+                                        buffer, attributeUniqueIdMap,
+                                        attributeTypeMap) {
         if (this.getAttributeOptions('position').skipDequantization === true) {
         if (this.getAttributeOptions('position').skipDequantization === true) {
           decoder.SkipAttributeTransform(dracoDecoder.POSITION);
           decoder.SkipAttributeTransform(dracoDecoder.POSITION);
         }
         }
@@ -244,18 +315,19 @@ THREE.DRACOLoader.prototype = {
               }
               }
               var attribute = decoder.GetAttribute(dracoGeometry, attId);
               var attribute = decoder.GetAttribute(dracoGeometry, attId);
               this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
               this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
-                  attributeName, attribute, geometry, geometryBuffer);
+                  attributeName, Float32Array, attribute, geometry, geometryBuffer);
             }
             }
           }
           }
         }
         }
 
 
         // Add attributes of user specified unique id. E.g. GLTF models.
         // Add attributes of user specified unique id. E.g. GLTF models.
         for (var attributeName in attributeUniqueIdMap) {
         for (var attributeName in attributeUniqueIdMap) {
+          var attributeType = attributeTypeMap[attributeName] || Float32Array;
           var attributeId = attributeUniqueIdMap[attributeName];
           var attributeId = attributeUniqueIdMap[attributeName];
           var attribute = decoder.GetAttributeByUniqueId(dracoGeometry,
           var attribute = decoder.GetAttributeByUniqueId(dracoGeometry,
                                                          attributeId);
                                                          attributeId);
           this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
           this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
-              attributeName, attribute, geometry, geometryBuffer);
+              attributeName, attributeType, attribute, geometry, geometryBuffer);
         }
         }
 
 
         // For mesh, we need to generate the faces.
         // For mesh, we need to generate the faces.

+ 8 - 7
examples/js/loaders/EXRLoader.js

@@ -355,16 +355,17 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 			lc -= 8;
 			lc -= 8;
 
 
 			var cs = ( c >> lc );
 			var cs = ( c >> lc );
+			var cs = new Uint8Array([cs])[0];
 
 
-			if ( out + cs > oe ) {
+			if ( outBufferOffset.value + cs > outBufferEndOffset ) {
 
 
-				throw 'Issue with getCode';
+				return false;
 
 
 			}
 			}
 
 
-			var s = out[ - 1 ];
+			var s = outBuffer[ outBufferOffset.value - 1 ];
 
 
-			while ( cs -- > 0 ) {
+			while ( cs-- > 0 ) {
 
 
 				outBuffer[ outBufferOffset.value ++ ] = s;
 				outBuffer[ outBufferOffset.value ++ ] = s;
 
 
@@ -376,7 +377,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 		} else {
 		} else {
 
 
-			throw 'Issue with getCode';
+			return false;
 
 
 		}
 		}
 
 
@@ -917,7 +918,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		var whiteX = parseFloat32( dataView, offset );
 		var whiteX = parseFloat32( dataView, offset );
 		var whiteY = parseFloat32( dataView, offset );
 		var whiteY = parseFloat32( dataView, offset );
 
 
-		return { redX: redX, redY: redY, greenX, greenY, blueX, blueY, whiteX, whiteY };
+		return { redX: redX, redY: redY, greenX: greenX, greenY: greenY, blueX: blueX, blueY: blueY, whiteX: whiteX, whiteY: whiteY };
 
 
 	}
 	}
 
 
@@ -1171,7 +1172,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		width: width,
 		width: width,
 		height: height,
 		height: height,
 		data: byteArray,
 		data: byteArray,
-		format: THREE.RGBFormat,
+		format: EXRHeader.channels.length == 4 ? THREE.RGBAFormat : THREE.RGBFormat,
 		type: THREE.FloatType
 		type: THREE.FloatType
 	};
 	};
 
 

+ 1 - 7
examples/js/loaders/EquiangularToCubeGenerator.js

@@ -95,13 +95,7 @@ THREE.EquiangularToCubeGenerator.prototype = {
 					gl_FragColor = vec4( color, 1.0 );\n\
 					gl_FragColor = vec4( color, 1.0 );\n\
 				}",
 				}",
 
 
-			blending: THREE.CustomBlending,
-			premultipliedAlpha: false,
-			blendSrc: THREE.OneFactor,
-			blendDst: THREE.ZeroFactor,
-			blendSrcAlpha: THREE.OneFactor,
-			blendDstAlpha: THREE.ZeroFactor,
-			blendEquation: THREE.AddEquation
+			blending: THREE.NoBlending
 
 
 		} );
 		} );
 
 

+ 430 - 158
examples/js/loaders/GLTFLoader.js

@@ -123,33 +123,42 @@ THREE.GLTFLoader = ( function () {
 
 
 			if ( json.extensionsUsed ) {
 			if ( json.extensionsUsed ) {
 
 
-				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_LIGHTS ) >= 0 ) {
+				for ( var i = 0; i < json.extensionsUsed.length; ++ i ) {
 
 
-					extensions[ EXTENSIONS.KHR_LIGHTS ] = new GLTFLightsExtension( json );
+					var extensionName = json.extensionsUsed[ i ];
+					var extensionsRequired = json.extensionsRequired || [];
 
 
-				}
-
-				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_UNLIT ) >= 0 ) {
+					switch ( extensionName ) {
 
 
-					extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] = new GLTFMaterialsUnlitExtension( json );
+						case EXTENSIONS.KHR_LIGHTS:
+							extensions[ extensionName ] = new GLTFLightsExtension( json );
+							break;
 
 
-				}
+						case EXTENSIONS.KHR_MATERIALS_UNLIT:
+							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json );
+							break;
 
 
-				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ) >= 0 ) {
+						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
+							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
+							break;
 
 
-					extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
+						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
+							extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
+							break;
 
 
-				}
+						case EXTENSIONS.MSFT_TEXTURE_DDS:
+							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
+							break;
 
 
-				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ) >= 0 ) {
+						default:
 
 
-					extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] = new GLTFDracoMeshCompressionExtension( this.dracoLoader );
+							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
 
 
-				}
+								console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
 
 
-				if ( json.extensionsUsed.indexOf( EXTENSIONS.MSFT_TEXTURE_DDS ) >= 0 ) {
+							}
 
 
-					extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
+					}
 
 
 				}
 				}
 
 
@@ -163,16 +172,20 @@ THREE.GLTFLoader = ( function () {
 
 
 			} );
 			} );
 
 
-			parser.parse( function ( scene, scenes, cameras, animations, asset ) {
+			parser.parse( function ( scene, scenes, cameras, animations, json ) {
 
 
 				var glTF = {
 				var glTF = {
 					scene: scene,
 					scene: scene,
 					scenes: scenes,
 					scenes: scenes,
 					cameras: cameras,
 					cameras: cameras,
 					animations: animations,
 					animations: animations,
-					asset: asset
+					asset: json.asset,
+					parser: parser,
+					userData: {}
 				};
 				};
 
 
+				addUnknownExtensionsToUserData( extensions, glTF, json );
+
 				onLoad( glTF );
 				onLoad( glTF );
 
 
 			}, onError );
 			}, onError );
@@ -442,7 +455,7 @@ THREE.GLTFLoader = ( function () {
 	 *
 	 *
 	 * Specification: https://github.com/KhronosGroup/glTF/pull/874
 	 * Specification: https://github.com/KhronosGroup/glTF/pull/874
 	 */
 	 */
-	function GLTFDracoMeshCompressionExtension ( dracoLoader ) {
+	function GLTFDracoMeshCompressionExtension ( json, dracoLoader ) {
 
 
 		if ( ! dracoLoader ) {
 		if ( ! dracoLoader ) {
 
 
@@ -451,16 +464,20 @@ THREE.GLTFLoader = ( function () {
 		}
 		}
 
 
 		this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
 		this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
+		this.json = json;
 		this.dracoLoader = dracoLoader;
 		this.dracoLoader = dracoLoader;
 
 
 	}
 	}
 
 
 	GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) {
 	GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) {
 
 
+		var json = this.json;
 		var dracoLoader = this.dracoLoader;
 		var dracoLoader = this.dracoLoader;
 		var bufferViewIndex = primitive.extensions[ this.name ].bufferView;
 		var bufferViewIndex = primitive.extensions[ this.name ].bufferView;
 		var gltfAttributeMap = primitive.extensions[ this.name ].attributes;
 		var gltfAttributeMap = primitive.extensions[ this.name ].attributes;
 		var threeAttributeMap = {};
 		var threeAttributeMap = {};
+		var attributeNormalizedMap = {};
+		var attributeTypeMap = {};
 
 
 		for ( var attributeName in gltfAttributeMap ) {
 		for ( var attributeName in gltfAttributeMap ) {
 
 
@@ -470,11 +487,38 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
+		for ( attributeName in primitive.attributes ) {
+
+			if ( ATTRIBUTES[ attributeName ] !== undefined && gltfAttributeMap[ attributeName ] !== undefined ) {
+
+				var accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
+				var componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
+
+				attributeTypeMap[ ATTRIBUTES[ attributeName ] ]  = componentType;
+				attributeNormalizedMap[ ATTRIBUTES[ attributeName ] ] = accessorDef.normalized === true;
+
+			}
+
+		}
+
 		return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
 		return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
 
 
 			return new Promise( function ( resolve ) {
 			return new Promise( function ( resolve ) {
 
 
-				dracoLoader.decodeDracoFile( bufferView, resolve, threeAttributeMap );
+				dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
+
+					for ( var attributeName in geometry.attributes ) {
+
+						var attribute = geometry.attributes[ attributeName ];
+						var normalized = attributeNormalizedMap[ attributeName ];
+
+						if ( normalized !== undefined ) attribute.normalized = normalized;
+
+					}
+
+					resolve( geometry );
+
+				}, threeAttributeMap, attributeTypeMap );
 
 
 			} );
 			} );
 
 
@@ -572,7 +616,6 @@ THREE.GLTFLoader = ( function () {
 				].join( '\n' );
 				].join( '\n' );
 
 
 				var fragmentShader = shader.fragmentShader
 				var fragmentShader = shader.fragmentShader
-					.replace( '#include <specularmap_fragment>', '' )
 					.replace( 'uniform float roughness;', 'uniform vec3 specular;' )
 					.replace( 'uniform float roughness;', 'uniform vec3 specular;' )
 					.replace( 'uniform float metalness;', 'uniform float glossiness;' )
 					.replace( 'uniform float metalness;', 'uniform float glossiness;' )
 					.replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
 					.replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
@@ -1151,18 +1194,31 @@ THREE.GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
+	function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
+
+		// Add unknown glTF extensions to an object's userData.
+
+		for ( var name in objectDef.extensions ) {
+
+			if ( knownExtensions[ name ] === undefined ) {
+
+				object.userData.gltfExtensions = object.userData.gltfExtensions || {};
+				object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
+
+			}
+
+		}
+
+	}
+
 	/**
 	/**
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
 	 *
 	 *
-	 * @param {THREE.Mesh} mesh
-	 * @param {GLTF.Mesh} meshDef
-	 * @param {GLTF.Primitive} primitiveDef
+	 * @param {THREE.Geometry} geometry
+	 * @param {Array<GLTF.Target>} targets
 	 * @param {Array<THREE.BufferAttribute>} accessors
 	 * @param {Array<THREE.BufferAttribute>} accessors
 	 */
 	 */
-	function addMorphTargets( mesh, meshDef, primitiveDef, accessors ) {
-
-		var geometry = mesh.geometry;
-		var targets = primitiveDef.targets;
+	function addMorphTargets( geometry, targets, accessors ) {
 
 
 		var hasMorphPosition = false;
 		var hasMorphPosition = false;
 		var hasMorphNormal = false;
 		var hasMorphNormal = false;
@@ -1270,6 +1326,14 @@ THREE.GLTFLoader = ( function () {
 		if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 		if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 		if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
 		if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
 
 
+	}
+
+	/**
+	 * @param {THREE.Mesh} mesh
+	 * @param {GLTF.Mesh} meshDef
+	 */
+	function updateMorphTargets( mesh, meshDef ) {
+
 		mesh.updateMorphTargets();
 		mesh.updateMorphTargets();
 
 
 		if ( meshDef.weights !== undefined ) {
 		if ( meshDef.weights !== undefined ) {
@@ -1315,26 +1379,31 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		var attribA = a.attributes || {};
-		var attribB = b.attributes || {};
-		var keysA = Object.keys( attribA );
-		var keysB = Object.keys( attribB );
+		return isObjectEqual( a.attributes, b.attributes );
+
+	}
 
 
-		if ( keysA.length !== keysB.length ) {
+	function isObjectEqual( a, b ) {
 
 
-			return false;
+		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
+
+		for ( var key in a ) {
+
+			if ( a[ key ] !== b[ key ] ) return false;
 
 
 		}
 		}
 
 
-		for ( var i = 0, il = keysA.length; i < il; i ++ ) {
+		return true;
+
+	}
 
 
-			var key = keysA[ i ];
+	function isArrayEqual( a, b ) {
 
 
-			if ( attribA[ key ] !== attribB[ key ] ) {
+		if ( a.length !== b.length ) return false;
 
 
-				return false;
+		for ( var i = 0, il = a.length; i < il; i ++ ) {
 
 
-			}
+			if ( a[ i ] !== b[ i ] ) return false;
 
 
 		}
 		}
 
 
@@ -1348,11 +1417,35 @@ THREE.GLTFLoader = ( function () {
 
 
 			var cached = cache[ i ];
 			var cached = cache[ i ];
 
 
-			if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) {
+			if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) return cached.promise;
 
 
-				return cached.promise;
+		}
 
 
-			}
+		return null;
+
+	}
+
+	function getCachedCombinedGeometry( cache, geometries ) {
+
+		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+
+			var cached = cache[ i ];
+
+			if ( isArrayEqual( geometries, cached.baseGeometries ) ) return cached.geometry;
+
+		}
+
+		return null;
+
+	}
+
+	function getCachedMultiPassGeometry( cache, geometry, primitives ) {
+
+		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+
+			var cached = cache[ i ];
+
+			if ( geometry === cached.baseGeometry && isArrayEqual( primitives, cached.primitives ) ) return cached.geometry;
 
 
 		}
 		}
 
 
@@ -1385,6 +1478,47 @@ THREE.GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
+	/**
+	 * Checks if we can build a single Mesh with MultiMaterial from multiple primitives.
+	 * Returns true if all primitives use the same attributes/morphAttributes/mode
+	 * and also have index. Otherwise returns false.
+	 *
+	 * @param {Array<GLTF.Primitive>} primitives
+	 * @return {Boolean}
+	 */
+	function isMultiPassGeometry( primitives ) {
+
+		if ( primitives.length < 2 ) return false;
+
+		var primitive0 = primitives[ 0 ];
+		var targets0 = primitive0.targets || [];
+
+		if ( primitive0.indices === undefined ) return false;
+
+		for ( var i = 1, il = primitives.length; i < il; i ++ ) {
+
+			var primitive = primitives[ i ];
+
+			if ( primitive0.mode !== primitive.mode ) return false;
+			if ( primitive.indices === undefined ) return false;
+			if ( ! isObjectEqual( primitive0.attributes, primitive.attributes ) ) return false;
+
+			var targets = primitive.targets || [];
+
+			if ( targets0.length !== targets.length ) return false;
+
+			for ( var j = 0, jl = targets0.length; j < jl; j ++ ) {
+
+				if ( ! isObjectEqual( targets0[ j ], targets[ j ] ) ) return false;
+
+			}
+
+		}
+
+		return true;
+
+	}
+
 	/* GLTF PARSER */
 	/* GLTF PARSER */
 
 
 	function GLTFParser( json, extensions, options ) {
 	function GLTFParser( json, extensions, options ) {
@@ -1398,6 +1532,8 @@ THREE.GLTFLoader = ( function () {
 
 
 		// BufferGeometry caching
 		// BufferGeometry caching
 		this.primitiveCache = [];
 		this.primitiveCache = [];
+		this.multiplePrimitivesCache = [];
+		this.multiPassGeometryCache = []
 
 
 		this.textureLoader = new THREE.TextureLoader( this.options.manager );
 		this.textureLoader = new THREE.TextureLoader( this.options.manager );
 		this.textureLoader.setCrossOrigin( this.options.crossOrigin );
 		this.textureLoader.setCrossOrigin( this.options.crossOrigin );
@@ -1429,10 +1565,9 @@ THREE.GLTFLoader = ( function () {
 			var scenes = dependencies.scenes || [];
 			var scenes = dependencies.scenes || [];
 			var scene = scenes[ json.scene || 0 ];
 			var scene = scenes[ json.scene || 0 ];
 			var animations = dependencies.animations || [];
 			var animations = dependencies.animations || [];
-			var asset = json.asset;
 			var cameras = dependencies.cameras || [];
 			var cameras = dependencies.cameras || [];
 
 
-			onLoad( scene, scenes, cameras, animations, asset );
+			onLoad( scene, scenes, cameras, animations, json );
 
 
 		} ).catch( onError );
 		} ).catch( onError );
 
 
@@ -2105,12 +2240,15 @@ THREE.GLTFLoader = ( function () {
 
 
 			}
 			}
 
 
-			// emissiveTexture and baseColorTexture use sRGB encoding.
+			// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
 			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
 			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
 			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
 			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
+			if ( material.specularMap ) material.specularMap.encoding = THREE.sRGBEncoding;
 
 
 			if ( materialDef.extras ) material.userData = materialDef.extras;
 			if ( materialDef.extras ) material.userData = materialDef.extras;
 
 
+			if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
+
 			return material;
 			return material;
 
 
 		} );
 		} );
@@ -2122,7 +2260,7 @@ THREE.GLTFLoader = ( function () {
 	 * @param  {GLTF.Primitive} primitiveDef
 	 * @param  {GLTF.Primitive} primitiveDef
 	 * @param  {Array<THREE.BufferAttribute>} accessors
 	 * @param  {Array<THREE.BufferAttribute>} accessors
 	 */
 	 */
-	function addPrimitiveAttributes ( geometry, primitiveDef, accessors ) {
+	function addPrimitiveAttributes( geometry, primitiveDef, accessors ) {
 
 
 		var attributes = primitiveDef.attributes;
 		var attributes = primitiveDef.attributes;
 
 
@@ -2139,16 +2277,33 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		if ( primitiveDef.indices !== undefined && !geometry.index ) {
+		if ( primitiveDef.indices !== undefined && ! geometry.index ) {
 
 
 			geometry.setIndex( accessors[ primitiveDef.indices ] );
 			geometry.setIndex( accessors[ primitiveDef.indices ] );
 
 
 		}
 		}
 
 
+		if ( primitiveDef.targets !== undefined ) {
+
+			addMorphTargets( geometry, primitiveDef.targets, accessors );
+
+		}
+
+		if ( primitiveDef.extras !== undefined ) {
+
+			geometry.userData = primitiveDef.extras;
+
+		}
+
 	}
 	}
 
 
 	/**
 	/**
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
+	 *
+	 * Creates BufferGeometries from primitives.
+	 * If we can build a single BufferGeometry with .groups from multiple primitives, returns one BufferGeometry.
+	 * Otherwise, returns BufferGeometries without .groups as many as primitives.
+	 *
 	 * @param {Array<Object>} primitives
 	 * @param {Array<Object>} primitives
 	 * @return {Promise<Array<THREE.BufferGeometry>>}
 	 * @return {Promise<Array<THREE.BufferGeometry>>}
 	 */
 	 */
@@ -2158,6 +2313,22 @@ THREE.GLTFLoader = ( function () {
 		var extensions = this.extensions;
 		var extensions = this.extensions;
 		var cache = this.primitiveCache;
 		var cache = this.primitiveCache;
 
 
+		var isMultiPass = isMultiPassGeometry( primitives );
+		var originalPrimitives;
+
+		if ( isMultiPass ) {
+
+			originalPrimitives = primitives; // save original primitives and use later
+
+			// We build a single BufferGeometry with .groups from multiple primitives
+			// because all primitives share the same attributes/morph/mode and have indices.
+
+			primitives = [ primitives[ 0 ] ];
+
+			// Sets .groups and combined indices to a geometry later in this method.
+
+		}
+
 		return this.getDependencies( 'accessor' ).then( function ( accessors ) {
 		return this.getDependencies( 'accessor' ).then( function ( accessors ) {
 
 
 			var pending = [];
 			var pending = [];
@@ -2201,12 +2372,7 @@ THREE.GLTFLoader = ( function () {
 					var geometryPromise = Promise.resolve( geometry );
 					var geometryPromise = Promise.resolve( geometry );
 
 
 					// Cache this geometry
 					// Cache this geometry
-					cache.push( {
-
-						primitive: primitive,
-						promise: geometryPromise
-
-					} );
+					cache.push( { primitive: primitive, promise: geometryPromise } );
 
 
 					pending.push( geometryPromise );
 					pending.push( geometryPromise );
 
 
@@ -2214,7 +2380,83 @@ THREE.GLTFLoader = ( function () {
 
 
 			}
 			}
 
 
-			return Promise.all( pending );
+			return Promise.all( pending ).then( function ( geometries ) {
+
+				if ( isMultiPass ) {
+
+					var baseGeometry = geometries[ 0 ];
+
+					// See if we've already created this combined geometry
+					var cache = parser.multiPassGeometryCache;
+					var cached = getCachedMultiPassGeometry( cache, baseGeometry, originalPrimitives );
+
+					if ( cached !== null ) return [ cached.geometry ];
+
+					// Cloning geometry because of index override.
+					// Attributes can be reused so cloning by myself here.
+					var geometry = new THREE.BufferGeometry();
+
+					geometry.name = baseGeometry.name;
+					geometry.userData = baseGeometry.userData;
+
+					for ( var key in baseGeometry.attributes ) geometry.addAttribute( key, baseGeometry.attributes[ key ] );
+					for ( var key in baseGeometry.morphAttributes ) geometry.morphAttributes[ key ] = baseGeometry.morphAttributes[ key ];
+
+					var indices = [];
+					var offset = 0;
+
+					for ( var i = 0, il = originalPrimitives.length; i < il; i ++ ) {
+
+						var accessor = accessors[ originalPrimitives[ i ].indices ];
+
+						for ( var j = 0, jl = accessor.count; j < jl; j ++ ) indices.push( accessor.array[ j ] );
+
+						geometry.addGroup( offset, accessor.count, i );
+
+						offset += accessor.count;
+
+					}
+
+					geometry.setIndex( indices );
+
+					cache.push( { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives } );
+
+					return [ geometry ];
+
+				} else if ( geometries.length > 1 && THREE.BufferGeometryUtils !== undefined ) {
+
+					// Tries to merge geometries with BufferGeometryUtils if possible
+
+					for ( var i = 1, il = primitives.length; i < il; i ++ ) {
+
+						// can't merge if draw mode is different
+						if ( primitives[ 0 ].mode !== primitives[ i ].mode ) return geometries;
+
+					}
+
+					// See if we've already created this combined geometry
+					var cache = parser.multiplePrimitivesCache;
+					var cached = getCachedCombinedGeometry( cache, geometries );
+
+					if ( cached ) {
+
+						if ( cached.geometry !== null ) return [ cached.geometry ];
+
+					} else {
+
+						var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries( geometries, true );
+
+						cache.push( { geometry: geometry, baseGeometries: geometries } );
+
+						if ( geometry !== null ) return [ geometry ];
+
+					}
+
+				}
+
+				return geometries;
+
+			} );
 
 
 		} );
 		} );
 
 
@@ -2240,188 +2482,214 @@ THREE.GLTFLoader = ( function () {
 
 
 		] ).then( function ( dependencies ) {
 		] ).then( function ( dependencies ) {
 
 
-			var group = new THREE.Group();
-
 			var primitives = meshDef.primitives;
 			var primitives = meshDef.primitives;
+			var originalMaterials = [];
+
+			for ( var i = 0, il = primitives.length; i < il; i ++ ) {
+
+				originalMaterials[ i ] = primitives[ i ].material === undefined
+					? createDefaultMaterial()
+					: dependencies.materials[ primitives[ i ].material ];
+
+			}
 
 
 			return scope.loadGeometries( primitives ).then( function ( geometries ) {
 			return scope.loadGeometries( primitives ).then( function ( geometries ) {
 
 
-				for ( var i = 0, il = primitives.length; i < il; i ++ ) {
+				var isMultiMaterial = geometries.length === 1 && geometries[ 0 ].groups.length > 0;
 
 
-					var primitive = primitives[ i ];
-					var geometry = geometries[ i ];
+				var meshes = [];
 
 
-					var material = primitive.material === undefined
-						? createDefaultMaterial()
-						: dependencies.materials[ primitive.material ];
+				for ( var i = 0, il = geometries.length; i < il; i ++ ) {
 
 
-					if ( material.aoMap
-							&& geometry.attributes.uv2 === undefined
-							&& geometry.attributes.uv !== undefined ) {
+					var geometry = geometries[ i ];
+					var primitive = primitives[ i ];
 
 
-						console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
-						geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
+					// 1. create Mesh
 
 
-					}
+					var mesh;
 
 
-					// If the material will be modified later on, clone it now.
-					var useVertexColors = geometry.attributes.color !== undefined;
-					var useFlatShading = geometry.attributes.normal === undefined;
-					var useSkinning = meshDef.isSkinnedMesh === true;
-					var useMorphTargets = primitive.targets !== undefined;
+					var material = isMultiMaterial ? originalMaterials : originalMaterials[ i ]
 
 
-					if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
+					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
+						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
+						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
+						primitive.mode === undefined ) {
 
 
-						if ( material.isGLTFSpecularGlossinessMaterial ) {
+						// .isSkinnedMesh isn't in glTF spec. See .markDefs()
+						mesh = meshDef.isSkinnedMesh === true
+							? new THREE.SkinnedMesh( geometry, material )
+							: new THREE.Mesh( geometry, material );
 
 
-							var specGlossExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
-							material = specGlossExtension.cloneMaterial( material );
+						if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
 
 
-						} else {
+							mesh.drawMode = THREE.TriangleStripDrawMode;
+
+						} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
 
 
-							material = material.clone();
+							mesh.drawMode = THREE.TriangleFanDrawMode;
 
 
 						}
 						}
 
 
-					}
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
 
 
-					if ( useVertexColors ) {
+						mesh = new THREE.LineSegments( geometry, material );
 
 
-						material.vertexColors = THREE.VertexColors;
-						material.needsUpdate = true;
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
 
 
-					}
+						mesh = new THREE.Line( geometry, material );
 
 
-					if ( useFlatShading ) {
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
 
 
-						material.flatShading = true;
+						mesh = new THREE.LineLoop( geometry, material );
+
+					} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
+
+						mesh = new THREE.Points( geometry, material );
+
+					} else {
+
+						throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
 
 
 					}
 					}
 
 
-					var mesh;
+					if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
 
 
-					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
-						primitive.mode === undefined ) {
+						updateMorphTargets( mesh, meshDef );
 
 
-						if ( useSkinning ) {
+					}
 
 
-							mesh = new THREE.SkinnedMesh( geometry, material );
-							material.skinning = true;
+					mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
 
 
-						} else {
+					if ( geometries.length > 1 ) mesh.name += '_' + i;
 
 
-							mesh = new THREE.Mesh( geometry, material );
+					if ( meshDef.extras !== undefined ) mesh.userData = meshDef.extras;
 
 
-						}
+					meshes.push( mesh );
 
 
-						if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
+					// 2. update Material depending on Mesh and BufferGeometry
 
 
-							mesh.drawMode = THREE.TriangleStripDrawMode;
+					var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
 
 
-						} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
+					var useVertexColors = geometry.attributes.color !== undefined;
+					var useFlatShading = geometry.attributes.normal === undefined;
+					var useSkinning = mesh.isSkinnedMesh === true;
+					var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0;
+					var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
 
 
-							mesh.drawMode = THREE.TriangleFanDrawMode;
+					for ( var j = 0, jl = materials.length; j < jl; j ++ ) {
 
 
-						}
+						var material = materials[ j ];
 
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ||
-						primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ||
-						primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
+						if ( mesh.isPoints ) {
 
 
-						var cacheKey = 'LineBasicMaterial:' + material.uuid;
+							var cacheKey = 'PointsMaterial:' + material.uuid;
 
 
-						var lineMaterial = scope.cache.get( cacheKey );
+							var pointsMaterial = scope.cache.get( cacheKey );
 
 
-						if ( ! lineMaterial ) {
+							if ( ! pointsMaterial ) {
 
 
-							lineMaterial = new THREE.LineBasicMaterial();
-							THREE.Material.prototype.copy.call( lineMaterial, material );
-							lineMaterial.color.copy( material.color );
-							lineMaterial.lights = false;  // LineBasicMaterial doesn't support lights yet
+								pointsMaterial = new THREE.PointsMaterial();
+								THREE.Material.prototype.copy.call( pointsMaterial, material );
+								pointsMaterial.color.copy( material.color );
+								pointsMaterial.map = material.map;
+								pointsMaterial.lights = false;  // PointsMaterial doesn't support lights yet
 
 
-							scope.cache.add( cacheKey, lineMaterial );
+								scope.cache.add( cacheKey, pointsMaterial );
 
 
-						}
+							}
 
 
-						material = lineMaterial;
+							material = pointsMaterial;
 
 
-						if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
+						} else if ( mesh.isLine ) {
 
 
-							mesh = new THREE.LineSegments( geometry, material );
+							var cacheKey = 'LineBasicMaterial:' + material.uuid;
 
 
-						} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
+							var lineMaterial = scope.cache.get( cacheKey );
 
 
-							mesh = new THREE.Line( geometry, material );
+							if ( ! lineMaterial ) {
 
 
-						} else {
+								lineMaterial = new THREE.LineBasicMaterial();
+								THREE.Material.prototype.copy.call( lineMaterial, material );
+								lineMaterial.color.copy( material.color );
+								lineMaterial.lights = false;  // LineBasicMaterial doesn't support lights yet
 
 
-							mesh = new THREE.LineLoop( geometry, material );
+								scope.cache.add( cacheKey, lineMaterial );
 
 
-						}
+							}
 
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
+							material = lineMaterial;
 
 
-						var cacheKey = 'PointsMaterial:' + material.uuid;
+						}
 
 
-						var pointsMaterial = scope.cache.get( cacheKey );
+						// Clone the material if it will be modified
+						if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
 
 
-						if ( ! pointsMaterial ) {
+							var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
 
 
-							pointsMaterial = new THREE.PointsMaterial();
-							THREE.Material.prototype.copy.call( pointsMaterial, material );
-							pointsMaterial.color.copy( material.color );
-							pointsMaterial.map = material.map;
-							pointsMaterial.lights = false;  // PointsMaterial doesn't support lights yet
+							if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
+							if ( useSkinning ) cacheKey += 'skinning:';
+							if ( useVertexColors ) cacheKey += 'vertex-colors:';
+							if ( useFlatShading ) cacheKey += 'flat-shading:';
+							if ( useMorphTargets ) cacheKey += 'morph-targets:';
+							if ( useMorphNormals ) cacheKey += 'morph-normals:';
 
 
-							scope.cache.add( cacheKey, pointsMaterial );
+							var cachedMaterial = scope.cache.get( cacheKey );
 
 
-						}
+							if ( ! cachedMaterial ) {
 
 
-						material = pointsMaterial;
+								cachedMaterial = material.isGLTFSpecularGlossinessMaterial
+										? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material )
+										: material.clone();
 
 
-						mesh = new THREE.Points( geometry, material );
+								if ( useSkinning ) cachedMaterial.skinning = true;
+								if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
+								if ( useFlatShading ) cachedMaterial.flatShading = true;
+								if ( useMorphTargets ) cachedMaterial.morphTargets = true;
+								if ( useMorphNormals ) cachedMaterial.morphNormals = true;
 
 
-					} else {
+								scope.cache.add( cacheKey, cachedMaterial );
 
 
-						throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
+							}
 
 
-					}
+							material = cachedMaterial;
 
 
-					mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
+						}
 
 
-					if ( useMorphTargets ) {
+						materials[ j ] = material;
 
 
-						addMorphTargets( mesh, meshDef, primitive, dependencies.accessors );
+						// workarounds for mesh and geometry
 
 
-						material.morphTargets = true;
+						if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
 
 
-						if ( mesh.geometry.morphAttributes.normal !== undefined ) material.morphNormals = true;
+							console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
+							geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
 
 
-					}
+						}
 
 
-					if ( meshDef.extras !== undefined ) mesh.userData = meshDef.extras;
-					if ( primitive.extras !== undefined ) mesh.geometry.userData = primitive.extras;
+						if ( material.isGLTFSpecularGlossinessMaterial ) {
 
 
-					// for Specular-Glossiness.
-					if ( material.isGLTFSpecularGlossinessMaterial === true ) {
+							// for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
+							mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
 
 
-						mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
+						}
 
 
 					}
 					}
 
 
-					if ( primitives.length > 1 ) {
+					mesh.material = isMultiMaterial ? materials : materials[ 0 ];
 
 
-						mesh.name += '_' + i;
+				}
 
 
-						group.add( mesh );
+				if ( meshes.length === 1 ) {
 
 
-					} else {
+					return meshes[ 0 ];
 
 
-						return mesh;
+				}
 
 
-					}
+				var group = new THREE.Group();
+
+				for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+
+					group.add( meshes[ i ] );
 
 
 				}
 				}
 
 
@@ -2568,14 +2836,13 @@ THREE.GLTFLoader = ( function () {
 
 
 						if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
 						if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
 
 
-							// node should be THREE.Group here but
+							// node can be THREE.Group here but
 							// PATH_PROPERTIES.weights(morphTargetInfluences) should be
 							// PATH_PROPERTIES.weights(morphTargetInfluences) should be
-							// the property of a mesh object under node.
-							// So finding targets here.
+							// the property of a mesh object under group.
 
 
 							node.traverse( function ( object ) {
 							node.traverse( function ( object ) {
 
 
-								if ( object.isMesh === true && object.material.morphTargets === true ) {
+								if ( object.isMesh === true && object.morphTargetInfluences ) {
 
 
 									targetNames.push( object.name ? object.name : object.uuid );
 									targetNames.push( object.name ? object.name : object.uuid );
 
 
@@ -2665,6 +2932,7 @@ THREE.GLTFLoader = ( function () {
 
 
 			var node;
 			var node;
 
 
+			// .isBone isn't in glTF spec. See .markDefs
 			if ( nodeDef.isBone === true ) {
 			if ( nodeDef.isBone === true ) {
 
 
 				node = new THREE.Bone();
 				node = new THREE.Bone();
@@ -2731,6 +2999,8 @@ THREE.GLTFLoader = ( function () {
 
 
 			if ( nodeDef.extras ) node.userData = nodeDef.extras;
 			if ( nodeDef.extras ) node.userData = nodeDef.extras;
 
 
+			if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
+
 			if ( nodeDef.matrix !== undefined ) {
 			if ( nodeDef.matrix !== undefined ) {
 
 
 				var matrix = new THREE.Matrix4();
 				var matrix = new THREE.Matrix4();
@@ -2863,6 +3133,8 @@ THREE.GLTFLoader = ( function () {
 
 
 				if ( sceneDef.extras ) scene.userData = sceneDef.extras;
 				if ( sceneDef.extras ) scene.userData = sceneDef.extras;
 
 
+				if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
+
 				var nodeIds = sceneDef.nodes || [];
 				var nodeIds = sceneDef.nodes || [];
 
 
 				for ( var i = 0, il = nodeIds.length; i < il; i ++ ) {
 				for ( var i = 0, il = nodeIds.length; i < il; i ++ ) {

+ 22 - 9
examples/js/loaders/LoaderSupport.js

@@ -166,11 +166,12 @@ THREE.LoaderSupport.ResourceDescriptor = (function () {
 		} else {
 		} else {
 
 
 			this.path = Validator.verifyInput( urlParts.slice( 0, urlParts.length - 1).join( '/' ) + '/', null );
 			this.path = Validator.verifyInput( urlParts.slice( 0, urlParts.length - 1).join( '/' ) + '/', null );
-			this.name = Validator.verifyInput( urlParts[ urlParts.length - 1 ], null );
+			this.name = urlParts[ urlParts.length - 1 ];
 			this.url = url;
 			this.url = url;
 
 
 		}
 		}
-		this.extension = Validator.verifyInput( extension, "default" );
+		this.name = Validator.verifyInput( this.name, 'Unnamed_Resource' );
+		this.extension = Validator.verifyInput( extension, 'default' );
 		this.extension = this.extension.trim();
 		this.extension = this.extension.trim();
 		this.content = null;
 		this.content = null;
 	}
 	}
@@ -348,7 +349,7 @@ THREE.LoaderSupport.PrepData = (function () {
  */
  */
 THREE.LoaderSupport.MeshBuilder = (function () {
 THREE.LoaderSupport.MeshBuilder = (function () {
 
 
-	var LOADER_MESH_BUILDER_VERSION = '1.2.0';
+	var LOADER_MESH_BUILDER_VERSION = '1.2.1';
 
 
 	var Validator = THREE.LoaderSupport.Validator;
 	var Validator = THREE.LoaderSupport.Validator;
 
 
@@ -540,16 +541,20 @@ THREE.LoaderSupport.MeshBuilder = (function () {
 			);
 			);
 			if ( Validator.isValid( callbackOnMeshAlterResult ) ) {
 			if ( Validator.isValid( callbackOnMeshAlterResult ) ) {
 
 
-				if ( ! callbackOnMeshAlterResult.isDisregardMesh() && callbackOnMeshAlterResult.providesAlteredMeshes() ) {
+				if ( callbackOnMeshAlterResult.isDisregardMesh() ) {
+
+					useOrgMesh = false;
+
+				} else if ( callbackOnMeshAlterResult.providesAlteredMeshes() ) {
 
 
 					for ( var i in callbackOnMeshAlterResult.meshes ) {
 					for ( var i in callbackOnMeshAlterResult.meshes ) {
 
 
 						meshes.push( callbackOnMeshAlterResult.meshes[ i ] );
 						meshes.push( callbackOnMeshAlterResult.meshes[ i ] );
 
 
 					}
 					}
+					useOrgMesh = false;
 
 
 				}
 				}
-				useOrgMesh = false;
 
 
 			}
 			}
 
 
@@ -1219,7 +1224,7 @@ THREE.LoaderSupport.WorkerSupport = (function () {
  */
  */
 THREE.LoaderSupport.WorkerDirector = (function () {
 THREE.LoaderSupport.WorkerDirector = (function () {
 
 
-	var LOADER_WORKER_DIRECTOR_VERSION = '2.2.0';
+	var LOADER_WORKER_DIRECTOR_VERSION = '2.2.1';
 
 
 	var Validator = THREE.LoaderSupport.Validator;
 	var Validator = THREE.LoaderSupport.Validator;
 
 
@@ -1418,9 +1423,16 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 			if ( Validator.isValid( prepDataCallbacks.onProgress ) ) prepDataCallbacks.onProgress( event );
 			if ( Validator.isValid( prepDataCallbacks.onProgress ) ) prepDataCallbacks.onProgress( event );
 		};
 		};
 
 
-		var wrapperOnMeshAlter = function ( event ) {
-			if ( Validator.isValid( globalCallbacks.onMeshAlter ) ) globalCallbacks.onMeshAlter( event );
-			if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) prepDataCallbacks.onMeshAlter( event );
+		var wrapperOnMeshAlter = function ( event, override ) {
+			if ( Validator.isValid( globalCallbacks.onMeshAlter ) ) override = globalCallbacks.onMeshAlter( event, override );
+			if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) override = globalCallbacks.onMeshAlter( event, override );
+			return override;
+		};
+
+		var wrapperOnLoadMaterials = function ( materials ) {
+			if ( Validator.isValid( globalCallbacks.onLoadMaterials ) ) materials = globalCallbacks.onLoadMaterials( materials );
+			if ( Validator.isValid( prepDataCallbacks.onLoadMaterials ) ) materials = prepDataCallbacks.onLoadMaterials( materials );
+			return materials;
 		};
 		};
 
 
 		supportDesc.loader = this._buildLoader( supportDesc.instanceNo );
 		supportDesc.loader = this._buildLoader( supportDesc.instanceNo );
@@ -1429,6 +1441,7 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 		updatedCallbacks.setCallbackOnLoad( wrapperOnLoad );
 		updatedCallbacks.setCallbackOnLoad( wrapperOnLoad );
 		updatedCallbacks.setCallbackOnProgress( wrapperOnProgress );
 		updatedCallbacks.setCallbackOnProgress( wrapperOnProgress );
 		updatedCallbacks.setCallbackOnMeshAlter( wrapperOnMeshAlter );
 		updatedCallbacks.setCallbackOnMeshAlter( wrapperOnMeshAlter );
+		updatedCallbacks.setCallbackOnLoadMaterials( wrapperOnLoadMaterials );
 		prepData.callbacks = updatedCallbacks;
 		prepData.callbacks = updatedCallbacks;
 
 
 		supportDesc.loader.run( prepData, supportDesc.workerSupport );
 		supportDesc.loader.run( prepData, supportDesc.workerSupport );

+ 1171 - 1995
examples/js/loaders/MMDLoader.js

@@ -3,31 +3,23 @@
  *
  *
  * Dependencies
  * Dependencies
  *  - mmd-parser https://github.com/takahirox/mmd-parser
  *  - mmd-parser https://github.com/takahirox/mmd-parser
- *  - ammo.js https://github.com/kripken/ammo.js
  *  - THREE.TGALoader
  *  - THREE.TGALoader
- *  - THREE.MMDPhysics
- *  - THREE.CCDIKSolver
  *  - THREE.OutlineEffect
  *  - THREE.OutlineEffect
  *
  *
+ * MMDLoader creates Three.js Objects from MMD resources as
+ * PMD, PMX, VMD, and VPD files.
  *
  *
- * This loader loads and parses PMD/PMX and VMD binary files
- * then creates mesh for Three.js.
- *
- * PMD/PMX is a model data format and VMD is a motion data format
- * used in MMD(Miku Miku Dance).
- *
- * MMD is a 3D CG animation tool which is popular in Japan.
- *
+ * PMD/PMX is a model data format, VMD is a motion data format
+ * VPD is a posing data format used in MMD(Miku Miku Dance).
  *
  *
  * MMD official site
  * MMD official site
- *  http://www.geocities.jp/higuchuu4/index_e.htm
+ *  - http://www.geocities.jp/higuchuu4/index_e.htm
  *
  *
- * PMD, VMD format
- *  http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
+ * PMD, VMD format (in Japanese)
+ *  - http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
  *
  *
  * PMX format
  * PMX format
- *  http://gulshan-i-raz.geo.jp/labs/2012/10/17/pmx-format1/
- *
+ *  - https://gist.github.com/felixjones/f8a06bd48f9da9a4539f
  *
  *
  * TODO
  * TODO
  *  - light motion in vmd support.
  *  - light motion in vmd support.
@@ -37,2691 +29,1875 @@
  *  - shadow support.
  *  - shadow support.
  */
  */
 
 
-THREE.MMDLoader = function ( manager ) {
-
-	THREE.Loader.call( this );
-	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-	this.parser = new MMDParser.Parser();
-	this.textureCrossOrigin = null;
-
-};
-
-THREE.MMDLoader.prototype = Object.create( THREE.Loader.prototype );
-THREE.MMDLoader.prototype.constructor = THREE.MMDLoader;
-
-/*
- * base64 encoded defalut toon textures toon00.bmp - toon10.bmp
- * Users don't need to prepare default texture files.
- *
- * This idea is from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
- */
-THREE.MMDLoader.prototype.defaultToonTextures = [
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/bWiiMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh8aBHZBl14e8wAAAABJRU5ErkJggg==',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOUlEQVRYR+3WMREAMAwDsYY/yoDI7MLwIiP40+RJklfcCCBAgAABAgTqArfb/QMCCBAgQIAAgbbAB3z/e0F3js2cAAAAAElFTkSuQmCC',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/B5ilMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh81dWyx0gFwKAAAAABJRU5ErkJggg==',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOklEQVRYR+3WoREAMAwDsWb/UQtCy9wxTOQJ/oQ8SXKKGwEECBAgQIBAXeDt7f4BAQQIECBAgEBb4AOz8Hzx7WLY4wAAAABJRU5ErkJggg==',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABPUlEQVRYR+1XwW7CMAy1+f9fZOMysSEOEweEOPRNdm3HbdOyIhAcklPrOs/PLy9RygBALxzcCDQFmgJNgaZAU6Ap0BR4PwX8gsRMVLssMRH5HcpzJEaWL7EVg9F1IHRlyqQohgVr4FGUlUcMJSjcUlDw0zvjeun70cLWmneoyf7NgBTQSniBTQQSuJAZsOnnaczjIMb5hCiuHKxokCrJfVnrctyZL0PkJAJe1HMil4nxeyi3Ypfn1kX51jpPvo/JeCNC4PhVdHdJw2XjBR8brF8PEIhNVn12AgP7uHsTBguBn53MUZCqv7Lp07Pn5k1Ro+uWmUNn7D+M57rtk7aG0Vo73xyF/fbFf0bPJjDXngnGocDTdFhygZjwUQrMNrDcmZlQT50VJ/g/UwNyHpu778+yW+/ksOz/BFo54P4AsUXMfRq7XWsAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACMElEQVRYR+2Xv4pTQRTGf2dubhLdICiii2KnYKHVolhauKWPoGAnNr6BD6CvIVaihYuI2i1ia0BY0MZGRHQXjZj/mSPnnskfNWiWZUlzJ5k7M2cm833nO5Mziej2DWWJRUoCpQKlAntSQCqgw39/iUWAGmh37jrRnVsKlgpiqmkoGVABA7E57fvY+pJDdgKqF6HzFCSADkDq+F6AHABtQ+UMVE5D7zXod7fFNhTEckTbj5XQgHzNN+5tQvc5NG7C6BNkp6D3EmpXHDR+dQAjFLchW3VS9rlw3JBh+B7ys5Cf9z0GW1C/7P32AyBAOAz1q4jGliIH3YPuBnSfQX4OGreTIgEYQb/pBDtPnEQ4CivXYPAWBk13oHrB54yA9QuSn2H4AcKRpEILDt0BUzj+RLR1V5EqjD66NPRBVpLcQwjHoHYJOhsQv6U4mnzmrIXJCFr4LDwm/xBUoboG9XX4cc9VKdYoSA2yk5NQLJaKDUjTBoveG3Z2TElTxwjNK4M3LEZgUdDdruvcXzKBpStgp2NPiWi3ks9ZXxIoFVi+AvHLdc9TqtjL3/aYjpPlrzOcEnK62Szhimdd7xX232zFDTgtxezOu3WNMRLjiKgjtOhHVMd1loynVHvOgjuIIJMaELEqhJAV/RCSLbWTcfPFakFgFlALTRRvx+ok6Hlp/Q+v3fmx90bMyUzaEAhmM3KvHlXTL5DxnbGf/1M8RNNACLL5MNtPxP/mypJAqcDSFfgFhpYqWUzhTEAAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
-	'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII='
-];
-
-/*
- * Set 'anonymous' for the the texture image file in other domain
- * even if server responds with "Access-Control-Allow-Origin: *"
- * because some image operation fails in MMDLoader.
- */
-THREE.MMDLoader.prototype.setTextureCrossOrigin = function ( value ) {
-
-	this.textureCrossOrigin = value;
-
-};
-
-THREE.MMDLoader.prototype.load = function ( modelUrl, vmdUrls, callback, onProgress, onError ) {
-
-	var scope = this;
-
-	this.loadModel( modelUrl, function ( mesh ) {
-
-		scope.loadVmds( vmdUrls, function ( vmd ) {
-
-			scope.pourVmdIntoModel( mesh, vmd );
-			callback( mesh );
-
-		}, onProgress, onError );
-
-	}, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.loadModel = function ( url, callback, onProgress, onError ) {
-
-	var scope = this;
-
-	var texturePath = THREE.LoaderUtils.extractUrlBase( url );
-	var modelExtension = this.extractExtension( url );
-
-	this.loadFileAsBuffer( url, function ( buffer ) {
-
-		callback( scope.createModel( buffer, modelExtension, texturePath, onProgress, onError ) );
-
-	}, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.createModel = function ( buffer, modelExtension, texturePath, onProgress, onError ) {
-
-	return this.createMesh( this.parseModel( buffer, modelExtension ), texturePath, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.loadVmd = function ( url, callback, onProgress, onError ) {
-
-	var scope = this;
-
-	this.loadFileAsBuffer( url, function ( buffer ) {
-
-		callback( scope.parseVmd( buffer ) );
-
-	}, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.loadVmds = function ( urls, callback, onProgress, onError ) {
-
-	var scope = this;
-
-	var vmds = [];
-	urls = urls.slice();
-
-	function run() {
-
-		var url = urls.shift();
-
-		scope.loadVmd( url, function ( vmd ) {
-
-			vmds.push( vmd );
-
-			if ( urls.length > 0 ) {
-
-				run();
-
-			} else {
-
-				callback( scope.mergeVmds( vmds ) );
-
-			}
-
-		}, onProgress, onError );
-
-	}
-
-	run();
-
-};
-
-THREE.MMDLoader.prototype.loadAudio = function ( url, callback, onProgress, onError ) {
-
-	var listener = new THREE.AudioListener();
-	var audio = new THREE.Audio( listener );
-	var loader = new THREE.AudioLoader( this.manager );
-
-	loader.load( url, function ( buffer ) {
-
-		audio.setBuffer( buffer );
-		callback( audio, listener );
-
-	}, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.loadVpd = function ( url, callback, onProgress, onError, params ) {
-
-	var scope = this;
+THREE.MMDLoader = ( function () {
 
 
-	var func = ( ( params && params.charcode === 'unicode' ) ? this.loadFileAsText : this.loadFileAsShiftJISText ).bind( this );
-
-	func( url, function ( text ) {
-
-		callback( scope.parseVpd( text ) );
-
-	}, onProgress, onError );
-
-};
-
-THREE.MMDLoader.prototype.parseModel = function ( buffer, modelExtension ) {
-
-	// Should I judge from model data header?
-	switch ( modelExtension.toLowerCase() ) {
+	/**
+	 * @param {THREE.LoadingManager} manager
+	 */
+	function MMDLoader( manager ) {
 
 
-		case 'pmd':
-			return this.parsePmd( buffer );
+		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
 
 
-		case 'pmx':
-			return this.parsePmx( buffer );
+		this.loader = new THREE.FileLoader( this.manager );
 
 
-		default:
-			throw 'extension ' + modelExtension + ' is not supported.';
+		this.parser = null; // lazy generation
+		this.meshBuilder = new MeshBuilder( this.manager );
+		this.animationBuilder = new AnimationBuilder();
 
 
 	}
 	}
 
 
-};
-
-THREE.MMDLoader.prototype.parsePmd = function ( buffer ) {
+	MMDLoader.prototype = {
 
 
-	return this.parser.parsePmd( buffer, true );
+		constructor: MMDLoader,
 
 
-};
+		crossOrigin: undefined,
 
 
-THREE.MMDLoader.prototype.parsePmx = function ( buffer ) {
+		/**
+		 * @param {string} value
+		 * @return {THREE.MMDLoader}
+		 */
+		setCrossOrigin: function ( crossOrigin ) {
 
 
-	return this.parser.parsePmx( buffer, true );
+			this.crossOrigin = crossOrigin;
+			return this;
 
 
-};
+		},
 
 
-THREE.MMDLoader.prototype.parseVmd = function ( buffer ) {
+		// Load MMD assets as Three.js Object
 
 
-	return this.parser.parseVmd( buffer, true );
+		/**
+		 * Loads Model file (.pmd or .pmx) as a THREE.SkinnedMesh.
+		 *
+		 * @param {string} url - url to Model(.pmd or .pmx) file
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		load: function ( url, onLoad, onProgress, onError ) {
 
 
-};
+			var parser = this._getParser();
+			var builder = this.meshBuilder.setCrossOrigin( this.crossOrigin );
 
 
-THREE.MMDLoader.prototype.parseVpd = function ( text ) {
+			var texturePath = THREE.LoaderUtils.extractUrlBase( url );
+			var modelExtension = this._extractExtension( url ).toLowerCase();
 
 
-	return this.parser.parseVpd( text, true );
+			// Should I detect by seeing header?
+			if ( modelExtension !== 'pmd' && modelExtension !== 'pmx' ) {
 
 
-};
+				if ( onError ) onError( new Error( 'THREE.MMDLoader: Unknown model file extension .' + modelExtension + '.' ) );
 
 
-THREE.MMDLoader.prototype.mergeVmds = function ( vmds ) {
+				return;
 
 
-	return this.parser.mergeVmds( vmds );
-
-};
+			}
 
 
-THREE.MMDLoader.prototype.pourVmdIntoModel = function ( mesh, vmd, name ) {
+			this[ modelExtension === 'pmd' ? 'loadPMD' : 'loadPMX' ]( url, function ( data ) {
 
 
-	this.createAnimation( mesh, vmd, name );
+				onLoad(	builder.build( data, texturePath, onProgress, onError )	);
 
 
-};
+			}, onProgress, onError );
 
 
-THREE.MMDLoader.prototype.pourVmdIntoCamera = function ( camera, vmd, name ) {
+		},
 
 
-	var helper = new THREE.MMDLoader.DataCreationHelper();
+		/**
+		 * Loads Motion file(s) (.vmd) as a THREE.AnimationClip.
+		 * If two or more files are specified, they'll be merged.
+		 *
+		 * @param {string|Array<string>} url - url(s) to animation(.vmd) file(s)
+		 * @param {THREE.SkinnedMesh|THREE.Camera} object - tracks will be fitting to this object
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadAnimation: function ( url, object, onLoad, onProgress, onError ) {
 
 
-	var initAnimation = function () {
+			var builder = this.animationBuilder;
 
 
-		var orderedMotions = helper.createOrderedMotionArray( vmd.cameras );
+			this.loadVMD( url, function ( vmd ) {
 
 
-		var times = [];
-		var centers = [];
-		var quaternions = [];
-		var positions = [];
-		var fovs = [];
+				onLoad( object.isCamera
+					? builder.buildCameraAnimation( vmd )
+					: builder.build( vmd, object ) );
 
 
-		var cInterpolations = [];
-		var qInterpolations = [];
-		var pInterpolations = [];
-		var fInterpolations = [];
+			}, onProgress, onError );
 
 
-		var quaternion = new THREE.Quaternion();
-		var euler = new THREE.Euler();
-		var position = new THREE.Vector3();
-		var center = new THREE.Vector3();
+		},
 
 
-		var pushVector3 = function ( array, vec ) {
+		/**
+		 * Loads mode file and motion file(s) as an object containing
+		 * a THREE.SkinnedMesh and a THREE.AnimationClip.
+		 * Tracks of THREE.AnimationClip are fitting to the model.
+		 *
+		 * @param {string} modelUrl - url to Model(.pmd or .pmx) file
+		 * @param {string|Array{string}} vmdUrl - url(s) to animation(.vmd) file
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadWithAnimation: function ( modelUrl, vmdUrl, onLoad, onProgress, onError ) {
 
 
-			array.push( vec.x );
-			array.push( vec.y );
-			array.push( vec.z );
+			var scope = this;
 
 
-		};
+			this.load( modelUrl, function ( mesh ) {
 
 
-		var pushQuaternion = function ( array, q ) {
+				scope.loadAnimation( vmdUrl, mesh, function ( animation ) {
 
 
-			array.push( q.x );
-			array.push( q.y );
-			array.push( q.z );
-			array.push( q.w );
+					onLoad( {
+						mesh: mesh,
+						animation: animation
+					} );
 
 
-		};
+				}, onProgress, onError );
 
 
-		var pushInterpolation = function ( array, interpolation, index ) {
+			}, onProgress, onError );
 
 
-			array.push( interpolation[ index * 4 + 0 ] / 127 ); // x1
-			array.push( interpolation[ index * 4 + 1 ] / 127 ); // x2
-			array.push( interpolation[ index * 4 + 2 ] / 127 ); // y1
-			array.push( interpolation[ index * 4 + 3 ] / 127 ); // y2
+		},
 
 
-		};
+		// Load MMD assets as Object data parsed by MMDParser
 
 
-		var createTrack = function ( node, type, times, values, interpolations ) {
+		/**
+		 * Loads .pmd file as an Object.
+		 *
+		 * @param {string} url - url to .pmd file
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadPMD: function ( url, onLoad, onProgress, onError ) {
 
 
-			/*
-			 * optimizes here not to let KeyframeTrackPrototype optimize
-			 * because KeyframeTrackPrototype optimizes times and values but
-			 * doesn't optimize interpolations.
-			 */
-			if ( times.length > 2 ) {
+			var parser = this._getParser();
 
 
-				times = times.slice();
-				values = values.slice();
-				interpolations = interpolations.slice();
+			this.loader
+				.setMimeType( undefined )
+				.setResponseType( 'arraybuffer' )
+				.load( url, function ( buffer ) {
 
 
-				var stride = values.length / times.length;
-				var interpolateStride = ( stride === 3 ) ? 12 : 4; // 3: Vector3, others: Quaternion or Number
+					onLoad( parser.parsePmd( buffer, true ) );
 
 
-				var index = 1;
+				}, onProgress, onError );
 
 
-				for ( var aheadIndex = 2, endIndex = times.length; aheadIndex < endIndex; aheadIndex ++ ) {
+		},
 
 
-					for ( var i = 0; i < stride; i ++ ) {
+		/**
+		 * Loads .pmx file as an Object.
+		 *
+		 * @param {string} url - url to .pmx file
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadPMX: function ( url, onLoad, onProgress, onError ) {
 
 
-						if ( values[ index * stride + i ] !== values[ ( index - 1 ) * stride + i ] ||
-							values[ index * stride + i ] !== values[ aheadIndex * stride + i ] ) {
+			var parser = this._getParser();
 
 
-							index ++;
-							break;
+			this.loader
+				.setMimeType( undefined )
+				.setResponseType( 'arraybuffer' )
+				.load( url, function ( buffer ) {
 
 
-						}
+					onLoad( parser.parsePmx( buffer, true ) );
 
 
-					}
+				}, onProgress, onError );
 
 
-					if ( aheadIndex > index ) {
+		},
 
 
-						times[ index ] = times[ aheadIndex ];
+		/**
+		 * Loads .vmd file as an Object. If two or more files are specified
+		 * they'll be merged.
+		 *
+		 * @param {string|Array<string>} url - url(s) to .vmd file(s)
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadVMD: function ( url, onLoad, onProgress, onError ) {
 
 
-						for ( var i = 0; i < stride; i ++ ) {
+			var urls = Array.isArray( url ) ? url : [ url ];
 
 
-							values[ index * stride + i ] = values[ aheadIndex * stride + i ];
+			var vmds = [];
+			var vmdNum = urls.length;
 
 
-						}
+			var scope = this;
+			var parser = this._getParser();
 
 
-						for ( var i = 0; i < interpolateStride; i ++ ) {
+			this.loader
+				.setMimeType( undefined )
+				.setResponseType( 'arraybuffer' );
 
 
-							interpolations[ index * interpolateStride + i ] = interpolations[ aheadIndex * interpolateStride + i ];
+			for ( var i = 0, il = urls.length; i < il; i ++ ) {
 
 
-						}
+				this.loader.load( urls[ i ], function ( buffer ) {
 
 
-					}
+					vmds.push( parser.parseVmd( buffer, true ) );
 
 
-				}
+					if ( vmds.length === vmdNum ) onLoad( parser.mergeVmds( vmds ) );
 
 
-				times.length = index + 1;
-				values.length = ( index + 1 ) * stride;
-				interpolations.length = ( index + 1 ) * interpolateStride;
+				}, onProgress, onError );
 
 
 			}
 			}
 
 
-			return new THREE.MMDLoader[ type ]( node, times, values, interpolations );
-
-		};
-
-		for ( var i = 0; i < orderedMotions.length; i ++ ) {
+		},
 
 
-			var m = orderedMotions[ i ];
+		/**
+		 * Loads .vpd file as an Object.
+		 *
+		 * @param {string} url - url to .vpd file
+		 * @param {boolean} isUnicode
+		 * @param {function} onLoad
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 */
+		loadVPD: function ( url, isUnicode, onLoad, onProgress, onError, params ) {
 
 
-			var time = m.frameNum / 30;
-			var pos = m.position;
-			var rot = m.rotation;
-			var distance = m.distance;
-			var fov = m.fov;
-			var interpolation = m.interpolation;
+			params = params || {};
 
 
-			position.set( 0, 0, - distance );
-			center.set( pos[ 0 ], pos[ 1 ], pos[ 2 ] );
+			var parser = this._getParser();
 
 
-			euler.set( - rot[ 0 ], - rot[ 1 ], - rot[ 2 ] );
-			quaternion.setFromEuler( euler );
+			this.loader
+				.setMimeType( isUnicode ? undefined : 'text/plain; charset=shift_jis' )
+				.setResponseType( 'text' )
+				.load( url, function ( text ) {
 
 
-			position.add( center );
-			position.applyQuaternion( quaternion );
+					onLoad( parser.parseVpd( text, true ) );
 
 
-			/*
-			 * Note: This is a workaround not to make Animation system calculate lerp
-			 *       if the diff from the last frame is 1 frame (in 30fps).
-			 */
-			if ( times.length > 0 && time < times[ times.length - 1 ] + ( 1 / 30 ) * 1.5 ) {
+				}, onProgress, onError );
 
 
-				times[ times.length - 1 ] = time - 1e-13;
+		},
 
 
-			}
+		// private methods
 
 
-			times.push( time );
+		_extractExtension: function ( url ) {
 
 
-			pushVector3( centers, center );
-			pushQuaternion( quaternions, quaternion );
-			pushVector3( positions, position );
+			var index = url.lastIndexOf( '.' );
+			return index < 0 ? '' : url.slice( index + 1 );
 
 
-			fovs.push( fov );
+		},
 
 
-			for ( var j = 0; j < 3; j ++ ) {
+		_getParser: function () {
 
 
-				pushInterpolation( cInterpolations, interpolation, j );
+			if ( this.parser === null ) {
 
 
-			}
+				if ( typeof MMDParser === 'undefined' ) {
 
 
-			pushInterpolation( qInterpolations, interpolation, 3 );
+					throw new Error( 'THREE.MMDLoader: Import MMDParser https://github.com/takahirox/mmd-parser' );
 
 
-			// use same one parameter for x, y, z axis.
-			for ( var j = 0; j < 3; j ++ ) {
+				}
 
 
-				pushInterpolation( pInterpolations, interpolation, 4 );
+				this.parser = new MMDParser.Parser();
 
 
 			}
 			}
 
 
-			pushInterpolation( fInterpolations, interpolation, 5 );
+			return this.parser;
 
 
 		}
 		}
 
 
-		if ( times.length === 0 ) return;
-
-		var tracks = [];
-
-		tracks.push( createTrack( '.center', 'VectorKeyframeTrackEx', times, centers, cInterpolations ) );
-		tracks.push( createTrack( '.quaternion', 'QuaternionKeyframeTrackEx', times, quaternions, qInterpolations ) );
-		tracks.push( createTrack( '.position', 'VectorKeyframeTrackEx', times, positions, pInterpolations ) );
-		tracks.push( createTrack( '.fov', 'NumberKeyframeTrackEx', times, fovs, fInterpolations ) );
-
-		var clip = new THREE.AnimationClip( name === undefined ? THREE.Math.generateUUID() : name, - 1, tracks );
-
-		if ( camera.center === undefined ) camera.center = new THREE.Vector3( 0, 0, 0 );
-		if ( camera.animations === undefined ) camera.animations = [];
-		camera.animations.push( clip );
-
 	};
 	};
 
 
-	initAnimation();
-
-};
-
-THREE.MMDLoader.prototype.extractExtension = function ( url ) {
+	// Utilities
 
 
-	var index = url.lastIndexOf( '.' );
-
-	if ( index < 0 ) {
+	/*
+	 * base64 encoded defalut toon textures toon00.bmp - toon10.bmp.
+	 * We don't need to request external toon image files.
+	 * This idea is from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
+	 */
+	var DEFAULT_TOON_TEXTURES = [
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/bWiiMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh8aBHZBl14e8wAAAABJRU5ErkJggg==',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOUlEQVRYR+3WMREAMAwDsYY/yoDI7MLwIiP40+RJklfcCCBAgAABAgTqArfb/QMCCBAgQIAAgbbAB3z/e0F3js2cAAAAAElFTkSuQmCC',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/B5ilMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh81dWyx0gFwKAAAAABJRU5ErkJggg==',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOklEQVRYR+3WoREAMAwDsWb/UQtCy9wxTOQJ/oQ8SXKKGwEECBAgQIBAXeDt7f4BAQQIECBAgEBb4AOz8Hzx7WLY4wAAAABJRU5ErkJggg==',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABPUlEQVRYR+1XwW7CMAy1+f9fZOMysSEOEweEOPRNdm3HbdOyIhAcklPrOs/PLy9RygBALxzcCDQFmgJNgaZAU6Ap0BR4PwX8gsRMVLssMRH5HcpzJEaWL7EVg9F1IHRlyqQohgVr4FGUlUcMJSjcUlDw0zvjeun70cLWmneoyf7NgBTQSniBTQQSuJAZsOnnaczjIMb5hCiuHKxokCrJfVnrctyZL0PkJAJe1HMil4nxeyi3Ypfn1kX51jpPvo/JeCNC4PhVdHdJw2XjBR8brF8PEIhNVn12AgP7uHsTBguBn53MUZCqv7Lp07Pn5k1Ro+uWmUNn7D+M57rtk7aG0Vo73xyF/fbFf0bPJjDXngnGocDTdFhygZjwUQrMNrDcmZlQT50VJ/g/UwNyHpu778+yW+/ksOz/BFo54P4AsUXMfRq7XWsAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACMElEQVRYR+2Xv4pTQRTGf2dubhLdICiii2KnYKHVolhauKWPoGAnNr6BD6CvIVaihYuI2i1ia0BY0MZGRHQXjZj/mSPnnskfNWiWZUlzJ5k7M2cm833nO5Mziej2DWWJRUoCpQKlAntSQCqgw39/iUWAGmh37jrRnVsKlgpiqmkoGVABA7E57fvY+pJDdgKqF6HzFCSADkDq+F6AHABtQ+UMVE5D7zXod7fFNhTEckTbj5XQgHzNN+5tQvc5NG7C6BNkp6D3EmpXHDR+dQAjFLchW3VS9rlw3JBh+B7ys5Cf9z0GW1C/7P32AyBAOAz1q4jGliIH3YPuBnSfQX4OGreTIgEYQb/pBDtPnEQ4CivXYPAWBk13oHrB54yA9QuSn2H4AcKRpEILDt0BUzj+RLR1V5EqjD66NPRBVpLcQwjHoHYJOhsQv6U4mnzmrIXJCFr4LDwm/xBUoboG9XX4cc9VKdYoSA2yk5NQLJaKDUjTBoveG3Z2TElTxwjNK4M3LEZgUdDdruvcXzKBpStgp2NPiWi3ks9ZXxIoFVi+AvHLdc9TqtjL3/aYjpPlrzOcEnK62Szhimdd7xX232zFDTgtxezOu3WNMRLjiKgjtOhHVMd1loynVHvOgjuIIJMaELEqhJAV/RCSLbWTcfPFakFgFlALTRRvx+ok6Hlp/Q+v3fmx90bMyUzaEAhmM3KvHlXTL5DxnbGf/1M8RNNACLL5MNtPxP/mypJAqcDSFfgFhpYqWUzhTEAAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=',
+		'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII='
+	];
+
+	// Builders. They build Three.js object from Object data parsed by MMDParser.
+
+	/**
+	 * @param {THREE.LoadingManager} manager
+	 */
+	function MeshBuilder( manager ) {
 
 
-		return null;
+		this.geometryBuilder = new GeometryBuilder();
+		this.materialBuilder = new MaterialBuilder( manager );
 
 
 	}
 	}
 
 
-	return url.slice( index + 1 );
+	MeshBuilder.prototype = {
 
 
-};
+		constructor: MeshBuilder,
 
 
-THREE.MMDLoader.prototype.loadFile = function ( url, onLoad, onProgress, onError, responseType, mimeType ) {
+		crossOrigin: undefined,
 
 
-	var loader = new THREE.FileLoader( this.manager );
+		/**
+		 * @param {string} crossOrigin
+		 * @return {MeshBuilder}
+		 */
+		setCrossOrigin: function ( crossOrigin ) {
 
 
-	if ( mimeType !== undefined ) loader.setMimeType( mimeType );
+			this.crossOrigin = crossOrigin;
+			return this;
 
 
-	loader.setResponseType( responseType );
+		},
 
 
-	var request = loader.load( url, function ( result ) {
+		/**
+		 * @param {Object} data - parsed PMD/PMX data
+		 * @param {string} texturePath
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 * @return {THREE.SkinnedMesh}
+		 */
+		build: function ( data, texturePath, onProgress, onError ) {
 
 
-		onLoad( result );
+			var geometry = this.geometryBuilder.build( data );
+			var material = this.materialBuilder
+					.setCrossOrigin( this.crossOrigin )
+					.setTexturePath( texturePath )
+					.build( data, geometry, onProgress, onError );
 
 
-	}, onProgress, onError );
+			var mesh = new THREE.SkinnedMesh( geometry, material );
 
 
-	return request;
+			// console.log( mesh ); // for console debug
 
 
-};
-
-THREE.MMDLoader.prototype.loadFileAsBuffer = function ( url, onLoad, onProgress, onError ) {
-
-	this.loadFile( url, onLoad, onProgress, onError, 'arraybuffer' );
-
-};
-
-THREE.MMDLoader.prototype.loadFileAsText = function ( url, onLoad, onProgress, onError ) {
-
-	this.loadFile( url, onLoad, onProgress, onError, 'text' );
-
-};
-
-THREE.MMDLoader.prototype.loadFileAsShiftJISText = function ( url, onLoad, onProgress, onError ) {
-
-	this.loadFile( url, onLoad, onProgress, onError, 'text', 'text/plain; charset=shift_jis' );
-
-};
-
-THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress, onError ) {
-
-	var scope = this;
-	var geometry = new THREE.BufferGeometry();
-	var materials = [];
-
-	var buffer = {};
-
-	buffer.vertices = [];
-	buffer.uvs = [];
-	buffer.normals = [];
-	buffer.skinIndices = [];
-	buffer.skinWeights = [];
-	buffer.indices = [];
-
-	var initVartices = function () {
-
-		for ( var i = 0; i < model.metadata.vertexCount; i ++ ) {
-
-			var v = model.vertices[ i ];
-
-			for ( var j = 0, jl = v.position.length; j < jl; j ++ ) {
-
-				buffer.vertices.push( v.position[ j ] );
-
-			}
-
-			for ( var j = 0, jl = v.normal.length; j < jl; j ++ ) {
-
-				buffer.normals.push( v.normal[ j ] );
-
-			}
-
-			for ( var j = 0, jl = v.uv.length; j < jl; j ++ ) {
-
-				buffer.uvs.push( v.uv[ j ] );
-
-			}
-
-			for ( var j = 0; j < 4; j ++ ) {
-
-				buffer.skinIndices.push( v.skinIndices.length - 1 >= j ? v.skinIndices[ j ] : 0.0 );
-
-			}
-
-			for ( var j = 0; j < 4; j ++ ) {
-
-				buffer.skinWeights.push( v.skinWeights.length - 1 >= j ? v.skinWeights[ j ] : 0.0 );
-
-			}
-
-		}
-
-	};
-
-	var initFaces = function () {
-
-		for ( var i = 0; i < model.metadata.faceCount; i ++ ) {
-
-			var f = model.faces[ i ];
-
-			for ( var j = 0, jl = f.indices.length; j < jl; j ++ ) {
-
-				buffer.indices.push( f.indices[ j ] );
-
-			}
+			return mesh;
 
 
 		}
 		}
 
 
 	};
 	};
 
 
-	var initBones = function () {
-
-		var bones = [];
+	//
 
 
-		var rigidBodies = model.rigidBodies;
-		var dictionary = {};
+	function GeometryBuilder() {
 
 
-		for ( var i = 0, il = rigidBodies.length; i < il; i ++ ) {
-
-			var body = rigidBodies[ i ];
-			var value = dictionary[ body.boneIndex ];
-
-			// keeps greater number if already value is set without any special reasons
-			value = value === undefined ? body.type : Math.max( body.type, value );
-
-			dictionary[ body.boneIndex ] = value;
-
-		}
-
-		for ( var i = 0; i < model.metadata.boneCount; i ++ ) {
-
-			var bone = {};
-			var b = model.bones[ i ];
-
-			bone.parent = b.parentIndex;
-			bone.name = b.name;
-			bone.pos = [ b.position[ 0 ], b.position[ 1 ], b.position[ 2 ] ];
-			bone.rotq = [ 0, 0, 0, 1 ];
-			bone.scl = [ 1, 1, 1 ];
-
-			if ( bone.parent !== - 1 ) {
-
-				bone.pos[ 0 ] -= model.bones[ bone.parent ].position[ 0 ];
-				bone.pos[ 1 ] -= model.bones[ bone.parent ].position[ 1 ];
-				bone.pos[ 2 ] -= model.bones[ bone.parent ].position[ 2 ];
-
-			}
-
-			bone.rigidBodyType = dictionary[ i ] !== undefined ? dictionary[ i ] : - 1;
+	}
 
 
-			bones.push( bone );
+	GeometryBuilder.prototype = {
 
 
-		}
+		constructor: GeometryBuilder,
 
 
-		geometry.bones = bones;
+		/**
+		 * @param {Object} data - parsed PMD/PMX data
+		 * @return {THREE.BufferGeometry}
+		 */
+		build: function ( data ) {
 
 
-	};
+			// for geometry
+			var positions = [];
+			var uvs = [];
+			var normals = [];
 
 
-	var initIKs = function () {
+			var indices = [];
 
 
-		var iks = [];
+			var groups = [];
 
 
-		// TODO: remove duplicated codes between PMD and PMX
-		if ( model.metadata.format === 'pmd' ) {
+			var bones = [];
+			var skinIndices = [];
+			var skinWeights = [];
 
 
-			for ( var i = 0; i < model.metadata.ikCount; i ++ ) {
+			var morphTargets = [];
+			var morphPositions = [];
 
 
-				var ik = model.iks[ i ];
-				var param = {};
+			var iks = [];
+			var grants = [];
 
 
-				param.target = ik.target;
-				param.effector = ik.effector;
-				param.iteration = ik.iteration;
-				param.maxAngle = ik.maxAngle * 4;
-				param.links = [];
+			var rigidBodies = [];
+			var constraints = [];
 
 
-				for ( var j = 0; j < ik.links.length; j ++ ) {
+			// for work
+			var offset = 0;
+			var boneTypeTable = {};
 
 
-					var link = {};
-					link.index = ik.links[ j ].index;
+			// positions, normals, uvs, skinIndices, skinWeights
 
 
-					if ( model.bones[ link.index ].name.indexOf( 'ひざ' ) >= 0 ) {
+			for ( var i = 0; i < data.metadata.vertexCount; i ++ ) {
 
 
-						link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
+				var v = data.vertices[ i ];
 
 
-					}
+				for ( var j = 0, jl = v.position.length; j < jl; j ++ ) {
 
 
-					param.links.push( link );
+					positions.push( v.position[ j ] );
 
 
 				}
 				}
 
 
-				iks.push( param );
-
-			}
-
-		} else {
-
-			for ( var i = 0; i < model.metadata.boneCount; i ++ ) {
-
-				var b = model.bones[ i ];
-				var ik = b.ik;
-
-				if ( ik === undefined ) {
+				for ( var j = 0, jl = v.normal.length; j < jl; j ++ ) {
 
 
-					continue;
+					normals.push( v.normal[ j ] );
 
 
 				}
 				}
 
 
-				var param = {};
+				for ( var j = 0, jl = v.uv.length; j < jl; j ++ ) {
 
 
-				param.target = i;
-				param.effector = ik.effector;
-				param.iteration = ik.iteration;
-				param.maxAngle = ik.maxAngle;
-				param.links = [];
+					uvs.push( v.uv[ j ] );
 
 
-				for ( var j = 0; j < ik.links.length; j ++ ) {
+				}
 
 
-					var link = {};
-					link.index = ik.links[ j ].index;
-					link.enabled = true;
+				for ( var j = 0; j < 4; j ++ ) {
 
 
-					if ( ik.links[ j ].angleLimitation === 1 ) {
+					skinIndices.push( v.skinIndices.length - 1 >= j ? v.skinIndices[ j ] : 0.0 );
 
 
-						link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
-						// TODO: use limitation angles
-						// link.lowerLimitationAngle;
-						// link.upperLimitationAngle;
+				}
 
 
-					}
+				for ( var j = 0; j < 4; j ++ ) {
 
 
-					param.links.push( link );
+					skinWeights.push( v.skinWeights.length - 1 >= j ? v.skinWeights[ j ] : 0.0 );
 
 
 				}
 				}
 
 
-				iks.push( param );
-
 			}
 			}
 
 
-		}
-
-		geometry.iks = iks;
-
-	};
-
-	var initGrants = function () {
-
-		if ( model.metadata.format === 'pmd' ) {
-
-			return;
-
-		}
+			// indices
 
 
-		var grants = [];
+			for ( var i = 0; i < data.metadata.faceCount; i ++ ) {
 
 
-		for ( var i = 0; i < model.metadata.boneCount; i ++ ) {
+				var face = data.faces[ i ];
 
 
-			var b = model.bones[ i ];
-			var grant = b.grant;
+				for ( var j = 0, jl = face.indices.length; j < jl; j ++ ) {
 
 
-			if ( grant === undefined ) {
+					indices.push( face.indices[ j ] );
 
 
-				continue;
+				}
 
 
 			}
 			}
 
 
-			var param = {};
-
-			param.index = i;
-			param.parentIndex = grant.parentIndex;
-			param.ratio = grant.ratio;
-			param.isLocal = grant.isLocal;
-			param.affectRotation = grant.affectRotation;
-			param.affectPosition = grant.affectPosition;
-			param.transformationClass = b.transformationClass;
-
-			grants.push( param );
-
-		}
-
-		grants.sort( function ( a, b ) {
-
-			return a.transformationClass - b.transformationClass;
-
-		} );
-
-		geometry.grants = grants;
-
-	};
-
-	var initMorphs = function () {
-
-		function updateVertex( attribute, index, v, ratio ) {
-
-			attribute.array[ index * 3 + 0 ] += v.position[ 0 ] * ratio;
-			attribute.array[ index * 3 + 1 ] += v.position[ 1 ] * ratio;
-			attribute.array[ index * 3 + 2 ] += v.position[ 2 ] * ratio;
-
-		}
+			// groups
 
 
-		function updateVertices( attribute, m, ratio ) {
+			for ( var i = 0; i < data.metadata.materialCount; i ++ ) {
 
 
-			for ( var i = 0; i < m.elementCount; i ++ ) {
+				var material = data.materials[ i ];
 
 
-				var v = m.elements[ i ];
+				groups.push( {
+					offset: offset * 3,
+					count: material.faceCount * 3
+				} );
 
 
-				var index;
+				offset += material.faceCount;
 
 
-				if ( model.metadata.format === 'pmd' ) {
+			}
 
 
-					index = model.morphs[ 0 ].elements[ v.index ].index;
+			// bones
 
 
-				} else {
+			for ( var i = 0; i < data.metadata.rigidBodyCount; i ++ ) {
 
 
-					index = v.index;
+				var body = data.rigidBodies[ i ];
+				var value = boneTypeTable[ body.boneIndex ];
 
 
-				}
+				// keeps greater number if already value is set without any special reasons
+				value = value === undefined ? body.type : Math.max( body.type, value );
 
 
-				updateVertex( attribute, index, v, ratio );
+				boneTypeTable[ body.boneIndex ] = value;
 
 
 			}
 			}
 
 
-		}
+			for ( var i = 0; i < data.metadata.boneCount; i ++ ) {
 
 
-		var morphTargets = [];
-		var attributes = [];
+				var boneData = data.bones[ i ];
 
 
-		for ( var i = 0; i < model.metadata.morphCount; i ++ ) {
+				var bone = {
+					parent: boneData.parentIndex,
+					name: boneData.name,
+					pos: boneData.position.slice( 0, 3 ),
+					rotq: [ 0, 0, 0, 1 ],
+					scl: [ 1, 1, 1 ],
+					rigidBodyType: boneTypeTable[ i ] !== undefined ? boneTypeTable[ i ] : - 1
+				};
 
 
-			var m = model.morphs[ i ];
-			var params = { name: m.name };
+				if ( bone.parent !== - 1 ) {
 
 
-			var attribute = new THREE.Float32BufferAttribute( model.metadata.vertexCount * 3, 3 );
-			attribute.name = m.name;
+					bone.pos[ 0 ] -= data.bones[ bone.parent ].position[ 0 ];
+					bone.pos[ 1 ] -= data.bones[ bone.parent ].position[ 1 ];
+					bone.pos[ 2 ] -= data.bones[ bone.parent ].position[ 2 ];
 
 
-			for ( var j = 0; j < model.metadata.vertexCount * 3; j ++ ) {
+				}
 
 
-				attribute.array[ j ] = buffer.vertices[ j ];
+				bones.push( bone );
 
 
 			}
 			}
 
 
-			if ( model.metadata.format === 'pmd' ) {
-
-				if ( i !== 0 ) {
-
-					updateVertices( attribute, m, 1.0 );
-
-				}
+			// iks
 
 
-			} else {
+			// TODO: remove duplicated codes between PMD and PMX
+			if ( data.metadata.format === 'pmd' ) {
 
 
-				if ( m.type === 0 ) { // group
+				for ( var i = 0; i < data.metadata.ikCount; i ++ ) {
 
 
-					for ( var j = 0; j < m.elementCount; j ++ ) {
+					var ik = data.iks[ i ];
 
 
-						var m2 = model.morphs[ m.elements[ j ].index ];
-						var ratio = m.elements[ j ].ratio;
+					var param = {
+						target: ik.target,
+						effector: ik.effector,
+						iteration: ik.iteration,
+						maxAngle: ik.maxAngle * 4,
+						links: []
+					};
 
 
-						if ( m2.type === 1 ) {
+					for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
 
 
-							updateVertices( attribute, m2, ratio );
+						var link = {};
+						link.index = ik.links[ j ].index;
+						link.enabled = true;
 
 
-						} else {
+						if ( data.bones[ link.index ].name.indexOf( 'ひざ' ) >= 0 ) {
 
 
-							// TODO: implement
+							link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
 
 
 						}
 						}
 
 
-					}
-
-				} else if ( m.type === 1 ) { // vertex
-
-					updateVertices( attribute, m, 1.0 );
-
-				} else if ( m.type === 2 ) { // bone
-
-					// TODO: implement
-
-				} else if ( m.type === 3 ) { // uv
-
-					// TODO: implement
+						param.links.push( link );
 
 
-				} else if ( m.type === 4 ) { // additional uv1
+					}
 
 
-					// TODO: implement
+					iks.push( param );
 
 
-				} else if ( m.type === 5 ) { // additional uv2
+				}
 
 
-					// TODO: implement
+			} else {
 
 
-				} else if ( m.type === 6 ) { // additional uv3
+				for ( var i = 0; i < data.metadata.boneCount; i ++ ) {
 
 
-					// TODO: implement
+					var ik = data.bones[ i ].ik;
 
 
-				} else if ( m.type === 7 ) { // additional uv4
+					if ( ik === undefined ) continue;
 
 
-					// TODO: implement
+					var param = {
+						target: i,
+						effector: ik.effector,
+						iteration: ik.iteration,
+						maxAngle: ik.maxAngle,
+						links: []
+					};
 
 
-				} else if ( m.type === 8 ) { // material
+					for ( var j = 0, jl = ik.links.length; j < jl; j ++ ) {
 
 
-					// TODO: implement
+						var link = {};
+						link.index = ik.links[ j ].index;
+						link.enabled = true;
 
 
-				}
+						if ( ik.links[ j ].angleLimitation === 1 ) {
 
 
-			}
+							// Revert if rotationMin/Max doesn't work well
+							// link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
 
 
-			morphTargets.push( params );
-			attributes.push( attribute );
+							var rotationMin = ik.links[ j ].lowerLimitationAngle;
+							var rotationMax = ik.links[ j ].upperLimitationAngle;
 
 
-		}
+							// Convert Left to Right coordinate by myself because
+							// MMDParser doesn't convert. It's a MMDParser's bug
 
 
-		geometry.morphTargets = morphTargets;
-		geometry.morphAttributes.position = attributes;
+							var tmp1 = - rotationMax[ 0 ];
+							var tmp2 = - rotationMax[ 1 ];
+							rotationMax[ 0 ] = - rotationMin[ 0 ];
+							rotationMax[ 1 ] = - rotationMin[ 1 ];
+							rotationMin[ 0 ] = tmp1;
+							rotationMin[ 1 ] = tmp2;
 
 
-	};
+							link.rotationMin = new THREE.Vector3().fromArray( rotationMin );
+							link.rotationMax = new THREE.Vector3().fromArray( rotationMax );
 
 
-	var initMaterials = function () {
+						}
 
 
-		var textures = {};
-		var textureLoader = new THREE.TextureLoader( scope.manager );
-		var tgaLoader = new THREE.TGALoader( scope.manager );
-		var canvas = document.createElement( 'canvas' );
-		var context = canvas.getContext( '2d' );
-		var offset = 0;
-		var materialParams = [];
-
-		if ( scope.textureCrossOrigin !== null ) textureLoader.setCrossOrigin( scope.textureCrossOrigin );
-
-		function loadTexture( filePath, params ) {
-
-			if ( params === undefined ) {
-
-				params = {};
-
-			}
-
-			var fullPath;
-
-			if ( params.defaultTexturePath === true ) {
-
-				try {
-
-					fullPath = scope.defaultToonTextures[ parseInt( filePath.match( 'toon([0-9]{2})\.bmp$' )[ 1 ] ) ];
-
-				} catch ( e ) {
-
-					console.warn( 'THREE.MMDLoader: ' + filePath + ' seems like not right default texture path. Using toon00.bmp instead.' );
-					fullPath = scope.defaultToonTextures[ 0 ];
-
-				}
-
-			} else {
-
-				fullPath = texturePath + filePath;
-
-			}
-
-			if ( textures[ fullPath ] !== undefined ) return fullPath;
-
-			var loader = THREE.Loader.Handlers.get( fullPath );
-
-			if ( loader === null ) {
-
-				loader = ( filePath.indexOf( '.tga' ) >= 0 ) ? tgaLoader : textureLoader;
-
-			}
-
-			var texture = loader.load( fullPath, function ( t ) {
-
-				// MMD toon texture is Axis-Y oriented
-				// but Three.js gradient map is Axis-X oriented.
-				// So here replaces the toon texture image with the rotated one.
-				if ( params.isToonTexture === true ) {
-
-					var image = t.image;
-					var width = image.width;
-					var height = image.height;
-
-					canvas.width = width;
-					canvas.height = height;
-
-					context.clearRect( 0, 0, width, height );
-					context.translate( width / 2.0, height / 2.0 );
-					context.rotate( 0.5 * Math.PI ); // 90.0 * Math.PI / 180.0
-					context.translate( - width / 2.0, - height / 2.0 );
-					context.drawImage( image, 0, 0 );
-
-					t.image = context.getImageData( 0, 0, width, height );
-
-				}
-
-				t.flipY = false;
-				t.wrapS = THREE.RepeatWrapping;
-				t.wrapT = THREE.RepeatWrapping;
-
-				for ( var i = 0; i < texture.readyCallbacks.length; i ++ ) {
-
-					texture.readyCallbacks[ i ]( texture );
-
-				}
-
-				delete texture.readyCallbacks;
-
-			}, onProgress, onError );
-
-			if ( params.sphericalReflectionMapping === true ) {
-
-				texture.mapping = THREE.SphericalReflectionMapping;
-
-			}
-
-			texture.readyCallbacks = [];
-
-			textures[ fullPath ] = texture;
-
-			return fullPath;
-
-		}
-
-		function getTexture( name, textures ) {
-
-			if ( textures[ name ] === undefined ) {
-
-				console.warn( 'THREE.MMDLoader: Undefined texture', name );
-
-			}
-
-			return textures[ name ];
-
-		}
-
-		for ( var i = 0; i < model.metadata.materialCount; i ++ ) {
-
-			var m = model.materials[ i ];
-			var params = {};
-
-			params.faceOffset = offset;
-			params.faceNum = m.faceCount;
-
-			offset += m.faceCount;
-
-			params.name = m.name;
-
-			/*
-			 * Color
-			 *
-			 * MMD         MeshToonMaterial
-			 * diffuse  -  color
-			 * specular -  specular
-			 * ambient  -  emissive * a
-			 *               (a = 1.0 without map texture or 0.2 with map texture)
-			 *
-			 * MeshToonMaterial doesn't have ambient. Set it to emissive instead.
-			 * It'll be too bright if material has map texture so using coef 0.2.
-			 */
-			params.color = new THREE.Color( m.diffuse[ 0 ], m.diffuse[ 1 ], m.diffuse[ 2 ] );
-			params.opacity = m.diffuse[ 3 ];
-			params.specular = new THREE.Color( m.specular[ 0 ], m.specular[ 1 ], m.specular[ 2 ] );
-			params.shininess = m.shininess;
-
-			if ( params.opacity === 1.0 ) {
-
-				params.side = THREE.FrontSide;
-				params.transparent = false;
-
-			} else {
-
-				params.side = THREE.DoubleSide;
-				params.transparent = true;
-
-			}
-
-			if ( model.metadata.format === 'pmd' ) {
-
-				if ( m.fileName ) {
-
-					var fileName = m.fileName;
-					var fileNames = [];
-
-					var index = fileName.lastIndexOf( '*' );
-
-					if ( index >= 0 ) {
-
-						fileNames.push( fileName.slice( 0, index ) );
-						fileNames.push( fileName.slice( index + 1 ) );
-
-					} else {
-
-						fileNames.push( fileName );
+						param.links.push( link );
 
 
 					}
 					}
 
 
-					for ( var j = 0; j < fileNames.length; j ++ ) {
-
-						var n = fileNames[ j ];
-
-						if ( n.indexOf( '.sph' ) >= 0 || n.indexOf( '.spa' ) >= 0 ) {
-
-							params.envMap = loadTexture( n, { sphericalReflectionMapping: true } );
-
-							if ( n.indexOf( '.sph' ) >= 0 ) {
-
-								params.envMapType = THREE.MultiplyOperation;
-
-							} else {
-
-								params.envMapType = THREE.AddOperation;
-
-							}
-
-						} else {
-
-							params.map = loadTexture( n );
-
-						}
-
-					}
-
-				}
-
-			} else {
-
-				if ( m.textureIndex !== - 1 ) {
-
-					var n = model.textures[ m.textureIndex ];
-					params.map = loadTexture( n );
-
-				}
-
-				// TODO: support m.envFlag === 3
-				if ( m.envTextureIndex !== - 1 && ( m.envFlag === 1 || m.envFlag == 2 ) ) {
-
-					var n = model.textures[ m.envTextureIndex ];
-					params.envMap = loadTexture( n, { sphericalReflectionMapping: true } );
-
-					if ( m.envFlag === 1 ) {
-
-						params.envMapType = THREE.MultiplyOperation;
-
-					} else {
-
-						params.envMapType = THREE.AddOperation;
-
-					}
-
-				}
-
-			}
-
-			var coef = ( params.map === undefined ) ? 1.0 : 0.2;
-			params.emissive = new THREE.Color( m.ambient[ 0 ] * coef, m.ambient[ 1 ] * coef, m.ambient[ 2 ] * coef );
-
-			materialParams.push( params );
-
-		}
-
-		for ( var i = 0; i < materialParams.length; i ++ ) {
-
-			var p = materialParams[ i ];
-			var p2 = model.materials[ i ];
-			var m = new THREE.MeshToonMaterial();
-
-			geometry.addGroup( p.faceOffset * 3, p.faceNum * 3, i );
-
-			if ( p.name !== undefined ) m.name = p.name;
-
-			m.skinning = geometry.bones.length > 0 ? true : false;
-			m.morphTargets = geometry.morphTargets.length > 0 ? true : false;
-			m.lights = true;
-			m.side = ( model.metadata.format === 'pmx' && ( p2.flag & 0x1 ) === 1 ) ? THREE.DoubleSide : p.side;
-			m.transparent = p.transparent;
-			m.fog = true;
-
-			m.blending = THREE.CustomBlending;
-			m.blendSrc = THREE.SrcAlphaFactor;
-			m.blendDst = THREE.OneMinusSrcAlphaFactor;
-			m.blendSrcAlpha = THREE.SrcAlphaFactor;
-			m.blendDstAlpha = THREE.DstAlphaFactor;
-
-			if ( p.map !== undefined ) {
-
-				m.faceOffset = p.faceOffset;
-				m.faceNum = p.faceNum;
-
-				// Check if this part of the texture image the material uses requires transparency
-				function checkTextureTransparency( m ) {
-
-					m.map.readyCallbacks.push( function ( t ) {
-
-						// Is there any efficient ways?
-						function createImageData( image ) {
-
-							var c = document.createElement( 'canvas' );
-							c.width = image.width;
-							c.height = image.height;
-
-							var ctx = c.getContext( '2d' );
-							ctx.drawImage( image, 0, 0 );
-
-							return ctx.getImageData( 0, 0, c.width, c.height );
-
-						}
-
-						function detectTextureTransparency( image, uvs, indices ) {
-
-							var width = image.width;
-							var height = image.height;
-							var data = image.data;
-							var threshold = 253;
-
-							if ( data.length / ( width * height ) !== 4 ) {
-
-								return false;
-
-							}
-
-							for ( var i = 0; i < indices.length; i += 3 ) {
-
-								var centerUV = { x: 0.0, y: 0.0 };
-
-								for ( var j = 0; j < 3; j ++ ) {
-
-									var index = indices[ i * 3 + j ];
-									var uv = { x: uvs[ index * 2 + 0 ], y: uvs[ index * 2 + 1 ] };
-
-									if ( getAlphaByUv( image, uv ) < threshold ) {
-
-										return true;
-
-									}
-
-									centerUV.x += uv.x;
-									centerUV.y += uv.y;
-
-								}
-
-								centerUV.x /= 3;
-								centerUV.y /= 3;
-
-								if ( getAlphaByUv( image, centerUV ) < threshold ) {
-
-									return true;
-
-								}
-
-							}
-
-							return false;
-
-						}
-
-						/*
-						 * This method expects
-						 *   t.flipY = false
-						 *   t.wrapS = THREE.RepeatWrapping
-						 *   t.wrapT = THREE.RepeatWrapping
-						 * TODO: more precise
-						 */
-						function getAlphaByUv( image, uv ) {
-
-							var width = image.width;
-							var height = image.height;
-
-							var x = Math.round( uv.x * width ) % width;
-							var y = Math.round( uv.y * height ) % height;
-
-							if ( x < 0 ) {
-
-								x += width;
-
-							}
-
-							if ( y < 0 ) {
-
-								y += height;
-
-							}
-
-							var index = y * width + x;
-
-							return image.data[ index * 4 + 3 ];
-
-						}
-
-						var imageData = t.image.data !== undefined ? t.image : createImageData( t.image );
-						var indices = geometry.index.array.slice( m.faceOffset * 3, m.faceOffset * 3 + m.faceNum * 3 );
-
-						if ( detectTextureTransparency( imageData, geometry.attributes.uv.array, indices ) ) m.transparent = true;
-
-						delete m.faceOffset;
-						delete m.faceNum;
-
-					} );
-
-				}
-
-				m.map = getTexture( p.map, textures );
-				checkTextureTransparency( m );
-
-			}
-
-			if ( p.envMap !== undefined ) {
-
-				m.envMap = getTexture( p.envMap, textures );
-				m.combine = p.envMapType;
-
-			}
-
-			m.opacity = p.opacity;
-			m.color = p.color;
-
-			if ( p.emissive !== undefined ) {
-
-				m.emissive = p.emissive;
-
-			}
-
-			m.specular = p.specular;
-			m.shininess = Math.max( p.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
-
-			if ( model.metadata.format === 'pmd' ) {
-
-				function isDefaultToonTexture( n ) {
-
-					if ( n.length !== 10 ) {
-
-						return false;
-
-					}
-
-					return n.match( /toon(10|0[0-9]).bmp/ ) === null ? false : true;
-
-				}
-
-				// parameters for OutlineEffect
-				m.outlineParameters = {
-					thickness: p2.edgeFlag === 1 ? 0.003 : 0.0,
-					color: new THREE.Color( 0.0, 0.0, 0.0 ),
-					alpha: 1.0
-				};
-
-				if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
-
-				var toonFileName = ( p2.toonIndex === - 1 ) ? 'toon00.bmp' : model.toonTextures[ p2.toonIndex ].fileName;
-				var uuid = loadTexture( toonFileName, { isToonTexture: true, defaultTexturePath: isDefaultToonTexture( toonFileName ) } );
-				m.gradientMap = getTexture( uuid, textures );
-
-			} else {
-
-				// parameters for OutlineEffect
-				m.outlineParameters = {
-					thickness: p2.edgeSize / 300,
-					color: new THREE.Color( p2.edgeColor[ 0 ], p2.edgeColor[ 1 ], p2.edgeColor[ 2 ] ),
-					alpha: p2.edgeColor[ 3 ]
-				};
-
-				if ( ( p2.flag & 0x10 ) === 0 || m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
-
-				var toonFileName, isDefaultToon;
-
-				if ( p2.toonIndex === - 1 || p2.toonFlag !== 0 ) {
-
-					var num = p2.toonIndex + 1;
-					toonFileName = 'toon' + ( num < 10 ? '0' + num : num ) + '.bmp';
-					isDefaultToon = true;
-
-				} else {
-
-					toonFileName = model.textures[ p2.toonIndex ];
-					isDefaultToon = false;
-
-				}
-
-				var uuid = loadTexture( toonFileName, { isToonTexture: true, defaultTexturePath: isDefaultToon } );
-				m.gradientMap = getTexture( uuid, textures );
-
-			}
-
-			materials.push( m );
-
-		}
-
-		if ( model.metadata.format === 'pmx' ) {
-
-			function checkAlphaMorph( morph, elements ) {
-
-				if ( morph.type !== 8 ) {
-
-					return;
-
-				}
-
-				for ( var i = 0; i < elements.length; i ++ ) {
-
-					var e = elements[ i ];
-
-					if ( e.index === - 1 ) {
-
-						continue;
-
-					}
-
-					var m = materials[ e.index ];
-
-					if ( m.opacity !== e.diffuse[ 3 ] ) {
-
-						m.transparent = true;
-
-					}
-
-				}
-
-			}
-
-			for ( var i = 0; i < model.morphs.length; i ++ ) {
-
-				var morph = model.morphs[ i ];
-				var elements = morph.elements;
-
-				if ( morph.type === 0 ) {
-
-					for ( var j = 0; j < elements.length; j ++ ) {
-
-						var morph2 = model.morphs[ elements[ j ].index ];
-						var elements2 = morph2.elements;
-
-						checkAlphaMorph( morph2, elements2 );
-
-					}
-
-				} else {
-
-					checkAlphaMorph( morph, elements );
-
-				}
-
-			}
-
-		}
-
-	};
-
-	var initPhysics = function () {
-
-		var rigidBodies = [];
-		var constraints = [];
-
-		for ( var i = 0; i < model.metadata.rigidBodyCount; i ++ ) {
-
-			var b = model.rigidBodies[ i ];
-			var keys = Object.keys( b );
-
-			var p = {};
-
-			for ( var j = 0; j < keys.length; j ++ ) {
-
-				var key = keys[ j ];
-				p[ key ] = b[ key ];
-
-			}
-
-			/*
-			 * RigidBody position parameter in PMX seems global position
-			 * while the one in PMD seems offset from corresponding bone.
-			 * So unify being offset.
-			 */
-			if ( model.metadata.format === 'pmx' ) {
-
-				if ( p.boneIndex !== - 1 ) {
-
-					var bone = model.bones[ p.boneIndex ];
-					p.position[ 0 ] -= bone.position[ 0 ];
-					p.position[ 1 ] -= bone.position[ 1 ];
-					p.position[ 2 ] -= bone.position[ 2 ];
-
-				}
-
-			}
-
-			rigidBodies.push( p );
-
-		}
-
-		for ( var i = 0; i < model.metadata.constraintCount; i ++ ) {
-
-			var c = model.constraints[ i ];
-			var keys = Object.keys( c );
-
-			var p = {};
-
-			for ( var j = 0; j < keys.length; j ++ ) {
-
-				var key = keys[ j ];
-				p[ key ] = c[ key ];
-
-			}
-
-			var bodyA = rigidBodies[ p.rigidBodyIndex1 ];
-			var bodyB = rigidBodies[ p.rigidBodyIndex2 ];
-
-			/*
-			 * Refer to http://www20.atpages.jp/katwat/wp/?p=4135
-			 */
-			if ( bodyA.type !== 0 && bodyB.type === 2 ) {
-
-				if ( bodyA.boneIndex !== - 1 && bodyB.boneIndex !== - 1 &&
-				     model.bones[ bodyB.boneIndex ].parentIndex === bodyA.boneIndex ) {
-
-					bodyB.type = 1;
-
-				}
-
-			}
-
-			constraints.push( p );
-
-		}
-
-		geometry.rigidBodies = rigidBodies;
-		geometry.constraints = constraints;
-
-	};
-
-	var initGeometry = function () {
-
-		geometry.setIndex( buffer.indices );
-		geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( buffer.vertices, 3 ) );
-		geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( buffer.normals, 3 ) );
-		geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( buffer.uvs, 2 ) );
-		geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( buffer.skinIndices, 4 ) );
-		geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffer.skinWeights, 4 ) );
-
-		geometry.computeBoundingSphere();
-		geometry.mmdFormat = model.metadata.format;
-
-	};
-
-	initVartices();
-	initFaces();
-	initBones();
-	initIKs();
-	initGrants();
-	initMorphs();
-	initMaterials();
-	initPhysics();
-	initGeometry();
-
-	var mesh = new THREE.SkinnedMesh( geometry, materials );
-
-	// console.log( mesh ); // for console debug
-
-	return mesh;
-
-};
-
-THREE.MMDLoader.prototype.createAnimation = function ( mesh, vmd, name ) {
-
-	var helper = new THREE.MMDLoader.DataCreationHelper();
-
-	var initMotionAnimations = function () {
-
-		if ( vmd.metadata.motionCount === 0 ) {
-
-			return;
-
-		}
-
-		var bones = mesh.geometry.bones;
-		var orderedMotions = helper.createOrderedMotionArrays( bones, vmd.motions, 'boneName' );
-
-		var tracks = [];
-
-		var pushInterpolation = function ( array, interpolation, index ) {
-
-			array.push( interpolation[ index + 0 ] / 127 ); // x1
-			array.push( interpolation[ index + 8 ] / 127 ); // x2
-			array.push( interpolation[ index + 4 ] / 127 ); // y1
-			array.push( interpolation[ index + 12 ] / 127 ); // y2
-
-		};
-
-		for ( var i = 0; i < orderedMotions.length; i ++ ) {
-
-			var times = [];
-			var positions = [];
-			var rotations = [];
-			var pInterpolations = [];
-			var rInterpolations = [];
-
-			var bone = bones[ i ];
-			var array = orderedMotions[ i ];
-
-			for ( var j = 0; j < array.length; j ++ ) {
-
-				var time = array[ j ].frameNum / 30;
-				var pos = array[ j ].position;
-				var rot = array[ j ].rotation;
-				var interpolation = array[ j ].interpolation;
-
-				times.push( time );
-
-				for ( var k = 0; k < 3; k ++ ) {
-
-					positions.push( bone.pos[ k ] + pos[ k ] );
-
-				}
-
-				for ( var k = 0; k < 4; k ++ ) {
-
-					rotations.push( rot[ k ] );
+					iks.push( param );
 
 
 				}
 				}
 
 
-				for ( var k = 0; k < 3; k ++ ) {
-
-					pushInterpolation( pInterpolations, interpolation, k );
+			}
 
 
-				}
+			// grants
 
 
-				pushInterpolation( rInterpolations, interpolation, 3 );
+			if ( data.metadata.format === 'pmx' ) {
 
 
-			}
+				for ( var i = 0; i < data.metadata.boneCount; i ++ ) {
 
 
-			if ( times.length === 0 ) continue;
+					var boneData = data.bones[ i ];
+					var grant = boneData.grant;
 
 
-			var boneName = '.bones[' + bone.name + ']';
+					if ( grant === undefined ) continue;
 
 
-			tracks.push( new THREE.MMDLoader.VectorKeyframeTrackEx( boneName + '.position', times, positions, pInterpolations ) );
-			tracks.push( new THREE.MMDLoader.QuaternionKeyframeTrackEx( boneName + '.quaternion', times, rotations, rInterpolations ) );
+					var param = {
+						index: i,
+						parentIndex: grant.parentIndex,
+						ratio: grant.ratio,
+						isLocal: grant.isLocal,
+						affectRotation: grant.affectRotation,
+						affectPosition: grant.affectPosition,
+						transformationClass: boneData.transformationClass
+					};
 
 
-		}
+					grants.push( param );
 
 
-		var clip = new THREE.AnimationClip( name === undefined ? THREE.Math.generateUUID() : name, - 1, tracks );
+				}
 
 
-		if ( mesh.geometry.animations === undefined ) mesh.geometry.animations = [];
-		mesh.geometry.animations.push( clip );
+				grants.sort( function ( a, b ) {
 
 
-	};
+					return a.transformationClass - b.transformationClass;
 
 
-	var initMorphAnimations = function () {
+				} );
 
 
-		if ( vmd.metadata.morphCount === 0 ) {
+			}
 
 
-			return;
+			// morph
 
 
-		}
+			function updateAttributes( attribute, morph, ratio ) {
 
 
-		var orderedMorphs = helper.createOrderedMotionArrays( mesh.geometry.morphTargets, vmd.morphs, 'morphName' );
+				for ( var i = 0; i < morph.elementCount; i ++ ) {
 
 
-		var tracks = [];
+					var element = morph.elements[ i ];
 
 
-		for ( var i = 0; i < orderedMorphs.length; i ++ ) {
+					var index;
 
 
-			var times = [];
-			var values = [];
-			var array = orderedMorphs[ i ];
+					if ( data.metadata.format === 'pmd' ) {
 
 
-			for ( var j = 0; j < array.length; j ++ ) {
+						index = data.morphs[ 0 ].elements[ element.index ].index;
 
 
-				times.push( array[ j ].frameNum / 30 );
-				values.push( array[ j ].weight );
+					} else {
 
 
-			}
+						index = element.index;
 
 
-			if ( times.length === 0 ) continue;
+					}
 
 
-			tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + i + ']', times, values ) );
+					attribute.array[ index * 3 + 0 ] += element.position[ 0 ] * ratio;
+					attribute.array[ index * 3 + 1 ] += element.position[ 1 ] * ratio;
+					attribute.array[ index * 3 + 2 ] += element.position[ 2 ] * ratio;
 
 
-		}
+				}
 
 
-		var clip = new THREE.AnimationClip( name === undefined ? THREE.Math.generateUUID() : name + 'Morph', - 1, tracks );
+			}
 
 
-		if ( mesh.geometry.animations === undefined ) mesh.geometry.animations = [];
-		mesh.geometry.animations.push( clip );
+			for ( var i = 0; i < data.metadata.morphCount; i ++ ) {
 
 
-	};
+				var morph = data.morphs[ i ];
+				var params = { name: morph.name };
 
 
-	initMotionAnimations();
-	initMorphAnimations();
+				var attribute = new THREE.Float32BufferAttribute( data.metadata.vertexCount * 3, 3 );
+				attribute.name = morph.name;
 
 
-};
+				for ( var j = 0; j < data.metadata.vertexCount * 3; j ++ ) {
 
 
-THREE.MMDLoader.DataCreationHelper = function () {
+					attribute.array[ j ] = positions[ j ];
 
 
-};
+				}
 
 
-THREE.MMDLoader.DataCreationHelper.prototype = {
+				if ( data.metadata.format === 'pmd' ) {
 
 
-	constructor: THREE.MMDLoader.DataCreationHelper,
+					if ( i !== 0 ) {
 
 
-	/*
-	 * Note: Sometimes to use Japanese Unicode characters runs into problems in Three.js.
-	 *       In such a case, use this method to convert it to Unicode hex charcode strings,
-	 *       like 'あいう' -> '0x30420x30440x3046'
-	 */
+						updateAttributes( attribute, morph, 1.0 );
 
 
-	toCharcodeStrings: function ( s ) {
+					}
 
 
-		var str = '';
+				} else {
 
 
-		for ( var i = 0; i < s.length; i ++ ) {
+					if ( morph.type === 0 ) { // group
 
 
-			str += '0x' + ( '0000' + s[ i ].charCodeAt().toString( 16 ) ).substr( - 4 );
+						for ( var j = 0; j < morph.elementCount; j ++ ) {
 
 
-		}
+							var morph2 = data.morphs[ morph.elements[ j ].index ];
+							var ratio = morph.elements[ j ].ratio;
 
 
-		return str;
+							if ( morph2.type === 1 ) {
 
 
-	},
+								updateAttributes( attribute, morph2, ratio );
 
 
-	createDictionary: function ( array ) {
+							} else {
 
 
-		var dict = {};
+								// TODO: implement
 
 
-		for ( var i = 0; i < array.length; i ++ ) {
+							}
 
 
-			dict[ array[ i ].name ] = i;
+						}
 
 
-		}
+					} else if ( morph.type === 1 ) { // vertex
 
 
-		return dict;
+						updateAttributes( attribute, morph, 1.0 );
 
 
-	},
+					} else if ( morph.type === 2 ) { // bone
 
 
-	initializeMotionArrays: function ( array ) {
+						// TODO: implement
 
 
-		var result = [];
+					} else if ( morph.type === 3 ) { // uv
 
 
-		for ( var i = 0; i < array.length; i ++ ) {
+						// TODO: implement
 
 
-			result[ i ] = [];
+					} else if ( morph.type === 4 ) { // additional uv1
 
 
-		}
+						// TODO: implement
 
 
-		return result;
+					} else if ( morph.type === 5 ) { // additional uv2
 
 
-	},
+						// TODO: implement
 
 
-	sortMotionArray: function ( array ) {
+					} else if ( morph.type === 6 ) { // additional uv3
 
 
-		array.sort( function ( a, b ) {
+						// TODO: implement
 
 
-			return a.frameNum - b.frameNum;
+					} else if ( morph.type === 7 ) { // additional uv4
 
 
-		} );
+						// TODO: implement
 
 
-	},
+					} else if ( morph.type === 8 ) { // material
 
 
-	sortMotionArrays: function ( arrays ) {
+						// TODO: implement
 
 
-		for ( var i = 0; i < arrays.length; i ++ ) {
+					}
 
 
-			this.sortMotionArray( arrays[ i ] );
+				}
 
 
-		}
+				morphTargets.push( params );
+				morphPositions.push( attribute );
 
 
-	},
+			}
 
 
-	createMotionArray: function ( array ) {
+			// rigid bodies from rigidBodies field.
 
 
-		var result = [];
+			for ( var i = 0; i < data.metadata.rigidBodyCount; i ++ ) {
 
 
-		for ( var i = 0; i < array.length; i ++ ) {
+				var rigidBody = data.rigidBodies[ i ];
+				var params = {};
 
 
-			result.push( array[ i ] );
+				for ( var key in rigidBody ) {
 
 
-		}
+					params[ key ] = rigidBody[ key ];
 
 
-		return result;
+				}
 
 
-	},
+				/*
+				 * RigidBody position parameter in PMX seems global position
+				 * while the one in PMD seems offset from corresponding bone.
+				 * So unify being offset.
+				 */
+				if ( data.metadata.format === 'pmx' ) {
 
 
-	createMotionArrays: function ( array, result, dict, key ) {
+					if ( params.boneIndex !== - 1 ) {
 
 
-		for ( var i = 0; i < array.length; i ++ ) {
+						var bone = data.bones[ params.boneIndex ];
+						params.position[ 0 ] -= bone.position[ 0 ];
+						params.position[ 1 ] -= bone.position[ 1 ];
+						params.position[ 2 ] -= bone.position[ 2 ];
 
 
-			var a = array[ i ];
-			var num = dict[ a[ key ] ];
+					}
 
 
-			if ( num === undefined ) {
+				}
 
 
-				continue;
+				rigidBodies.push( params );
 
 
 			}
 			}
 
 
-			result[ num ].push( a );
+			// constraints from constraints field.
 
 
-		}
+			for ( var i = 0; i < data.metadata.constraintCount; i ++ ) {
 
 
-	},
+				var constraint = data.constraints[ i ];
+				var params = {};
 
 
-	createOrderedMotionArray: function ( array ) {
+				for ( var key in constraint ) {
 
 
-		var result = this.createMotionArray( array );
-		this.sortMotionArray( result );
-		return result;
+					params[ key ] = constraint[ key ];
 
 
-	},
+				}
 
 
-	createOrderedMotionArrays: function ( targetArray, motionArray, key ) {
+				var bodyA = rigidBodies[ params.rigidBodyIndex1 ];
+				var bodyB = rigidBodies[ params.rigidBodyIndex2 ];
 
 
-		var dict = this.createDictionary( targetArray );
-		var result = this.initializeMotionArrays( targetArray );
-		this.createMotionArrays( motionArray, result, dict, key );
-		this.sortMotionArrays( result );
+				// Refer to http://www20.atpages.jp/katwat/wp/?p=4135
+				if ( bodyA.type !== 0 && bodyB.type === 2 ) {
 
 
-		return result;
+					if ( bodyA.boneIndex !== - 1 && bodyB.boneIndex !== - 1 &&
+					     data.bones[ bodyB.boneIndex ].parentIndex === bodyA.boneIndex ) {
 
 
-	}
+						bodyB.type = 1;
 
 
-};
+					}
 
 
-/*
- * extends existing KeyframeTrack for bone and camera animation.
- *   - use Float64Array for times
- *   - use Cubic Bezier curves interpolation
- */
-THREE.MMDLoader.VectorKeyframeTrackEx = function ( name, times, values, interpolationParameterArray ) {
+				}
 
 
-	this.interpolationParameters = new Float32Array( interpolationParameterArray );
+				constraints.push( params );
 
 
-	THREE.VectorKeyframeTrack.call( this, name, times, values );
+			}
 
 
-};
+			// build BufferGeometry.
 
 
-THREE.MMDLoader.VectorKeyframeTrackEx.prototype = Object.create( THREE.VectorKeyframeTrack.prototype );
-THREE.MMDLoader.VectorKeyframeTrackEx.prototype.constructor = THREE.MMDLoader.VectorKeyframeTrackEx;
-THREE.MMDLoader.VectorKeyframeTrackEx.prototype.TimeBufferType = Float64Array;
+			var geometry = new THREE.BufferGeometry();
 
 
-THREE.MMDLoader.VectorKeyframeTrackEx.prototype.InterpolantFactoryMethodCubicBezier = function ( result ) {
+			geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
+			geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
+			geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
+			geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( skinIndices, 4 ) );
+			geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeights, 4 ) );
+			geometry.setIndex( indices );
 
 
-	return new THREE.MMDLoader.CubicBezierInterpolation( this.times, this.values, this.getValueSize(), result, this.interpolationParameters );
+			for ( var i = 0, il = groups.length; i < il; i ++ ) {
 
 
-};
+				geometry.addGroup( groups[ i ].offset, groups[ i ].count, i );
 
 
-THREE.MMDLoader.VectorKeyframeTrackEx.prototype.setInterpolation = function ( interpolation ) {
+			}
 
 
-	this.createInterpolant = this.InterpolantFactoryMethodCubicBezier;
+			geometry.bones = bones;
 
 
-};
+			geometry.morphTargets = morphTargets;
+			geometry.morphAttributes.position = morphPositions;
 
 
-THREE.MMDLoader.QuaternionKeyframeTrackEx = function ( name, times, values, interpolationParameterArray ) {
+			geometry.userData.MMD = {
+				bones: bones,
+				iks: iks,
+				grants: grants,
+				rigidBodies: rigidBodies,
+				constraints: constraints,
+				format: data.metadata.format
+			};
 
 
-	this.interpolationParameters = new Float32Array( interpolationParameterArray );
+			geometry.computeBoundingSphere();
 
 
-	THREE.QuaternionKeyframeTrack.call( this, name, times, values );
+			return geometry;
 
 
-};
+		}
 
 
-THREE.MMDLoader.QuaternionKeyframeTrackEx.prototype = Object.create( THREE.QuaternionKeyframeTrack.prototype );
-THREE.MMDLoader.QuaternionKeyframeTrackEx.prototype.constructor = THREE.MMDLoader.QuaternionKeyframeTrackEx;
-THREE.MMDLoader.QuaternionKeyframeTrackEx.prototype.TimeBufferType = Float64Array;
+	};
 
 
-THREE.MMDLoader.QuaternionKeyframeTrackEx.prototype.InterpolantFactoryMethodCubicBezier = function ( result ) {
+	//
 
 
-	return new THREE.MMDLoader.CubicBezierInterpolation( this.times, this.values, this.getValueSize(), result, this.interpolationParameters );
+	/**
+	 * @param {THREE.LoadingManager} manager
+	 */
+	function MaterialBuilder( manager ) {
 
 
-};
+		this.manager = manager;
 
 
-THREE.MMDLoader.QuaternionKeyframeTrackEx.prototype.setInterpolation = function ( interpolation ) {
+		this.textureLoader = new THREE.TextureLoader( this.manager );
+		this.tgaLoader = null; // lazy generation
 
 
-	this.createInterpolant = this.InterpolantFactoryMethodCubicBezier;
+	}
 
 
-};
+	MaterialBuilder.prototype = {
 
 
-THREE.MMDLoader.NumberKeyframeTrackEx = function ( name, times, values, interpolationParameterArray ) {
+		constructor: MaterialBuilder,
 
 
-	this.interpolationParameters = new Float32Array( interpolationParameterArray );
+		crossOrigin: undefined,
 
 
-	THREE.NumberKeyframeTrack.call( this, name, times, values );
+		texturePath: undefined,
 
 
-};
+		/**
+		 * @param {string} crossOrigin
+		 * @return {MaterialBuilder}
+		 */
+		setCrossOrigin: function ( crossOrigin ) {
 
 
-THREE.MMDLoader.NumberKeyframeTrackEx.prototype = Object.create( THREE.NumberKeyframeTrack.prototype );
-THREE.MMDLoader.NumberKeyframeTrackEx.prototype.constructor = THREE.MMDLoader.NumberKeyframeTrackEx;
-THREE.MMDLoader.NumberKeyframeTrackEx.prototype.TimeBufferType = Float64Array;
+			this.crossOrigin = crossOrigin;
+			return this;
 
 
-THREE.MMDLoader.NumberKeyframeTrackEx.prototype.InterpolantFactoryMethodCubicBezier = function ( result ) {
+		},
 
 
-	return new THREE.MMDLoader.CubicBezierInterpolation( this.times, this.values, this.getValueSize(), result, this.interpolationParameters );
+		/**
+		 * @param {string} texturePath
+		 * @return {MaterialBuilder}
+		 */
+		setTexturePath: function ( texturePath ) {
 
 
-};
+			this.texturePath = texturePath;
+			return this;
 
 
-THREE.MMDLoader.NumberKeyframeTrackEx.prototype.setInterpolation = function ( interpolation ) {
+		},
 
 
-	this.createInterpolant = this.InterpolantFactoryMethodCubicBezier;
+		/**
+		 * @param {Object} data - parsed PMD/PMX data
+		 * @param {THREE.BufferGeometry} geometry - some properties are dependend on geometry
+		 * @param {function} onProgress
+		 * @param {function} onError
+		 * @return {Array<THREE.MeshToonMaterial>}
+		 */
+		build: function ( data, geometry, onProgress, onError ) {
 
 
-};
+			var materials = [];
 
 
-THREE.MMDLoader.CubicBezierInterpolation = function ( parameterPositions, sampleValues, sampleSize, resultBuffer, params ) {
+			var textures = {};
 
 
-	THREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
+			this.textureLoader.setCrossOrigin( this.crossOrigin );
 
 
-	this.params = params;
+			// materials
 
 
-};
+			for ( var i = 0; i < data.metadata.materialCount; i ++ ) {
 
 
-THREE.MMDLoader.CubicBezierInterpolation.prototype = Object.create( THREE.LinearInterpolant.prototype );
-THREE.MMDLoader.CubicBezierInterpolation.prototype.constructor = THREE.MMDLoader.CubicBezierInterpolation;
+				var material = data.materials[ i ];
 
 
-THREE.MMDLoader.CubicBezierInterpolation.prototype.interpolate_ = function ( i1, t0, t, t1 ) {
+				var params = { userData: {} };
 
 
-	var result = this.resultBuffer;
-	var values = this.sampleValues;
-	var stride = this.valueSize;
+				if ( material.name !== undefined ) params.name = material.name;
 
 
-	var offset1 = i1 * stride;
-	var offset0 = offset1 - stride;
+				/*
+				 * Color
+				 *
+				 * MMD         MeshToonMaterial
+				 * diffuse  -  color
+				 * specular -  specular
+				 * ambient  -  emissive * a
+				 *               (a = 1.0 without map texture or 0.2 with map texture)
+				 *
+				 * MeshToonMaterial doesn't have ambient. Set it to emissive instead.
+				 * It'll be too bright if material has map texture so using coef 0.2.
+				 */
+				params.color = new THREE.Color().fromArray( material.diffuse );
+				params.opacity = material.diffuse[ 3 ];
+				params.specular = new THREE.Color().fromArray( material.specular );
+				params.emissive = new THREE.Color().fromArray( material.ambient );
+				params.shininess = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
+				params.transparent = params.opacity !== 1.0;
 
 
-	var weight1 = ( t - t0 ) / ( t1 - t0 );
+				// 
 
 
-	if ( stride === 4 ) { // Quaternion
+				params.skinning = geometry.bones.length > 0 ? true : false;
+				params.morphTargets = geometry.morphTargets.length > 0 ? true : false;
+				params.lights = true;
+				params.fog = true;
 
 
-		var x1 = this.params[ i1 * 4 + 0 ];
-		var x2 = this.params[ i1 * 4 + 1 ];
-		var y1 = this.params[ i1 * 4 + 2 ];
-		var y2 = this.params[ i1 * 4 + 3 ];
+				// blend
 
 
-		var ratio = this._calculate( x1, x2, y1, y2, weight1 );
+				params.blending = THREE.CustomBlending;
+				params.blendSrc = THREE.SrcAlphaFactor;
+				params.blendDst = THREE.OneMinusSrcAlphaFactor;
+				params.blendSrcAlpha = THREE.SrcAlphaFactor;
+				params.blendDstAlpha = THREE.DstAlphaFactor;
 
 
-		THREE.Quaternion.slerpFlat( result, 0, values, offset0, values, offset1, ratio );
+				// side
 
 
-	} else if ( stride === 3 ) { // Vector3
+				if ( data.metadata.format === 'pmx' && ( material.flag & 0x1 ) === 1 ) {
 
 
-		for ( var i = 0; i !== stride; ++ i ) {
+					params.side = THREE.DoubleSide;
 
 
-			var x1 = this.params[ i1 * 12 + i * 4 + 0 ];
-			var x2 = this.params[ i1 * 12 + i * 4 + 1 ];
-			var y1 = this.params[ i1 * 12 + i * 4 + 2 ];
-			var y2 = this.params[ i1 * 12 + i * 4 + 3 ];
+				} else {
 
 
-			var ratio = this._calculate( x1, x2, y1, y2, weight1 );
+					params.side = params.opacity === 1.0 ? THREE.FrontSide : THREE.DoubleSide;
 
 
-			result[ i ] = values[ offset0 + i ] * ( 1 - ratio ) + values[ offset1 + i ] * ratio;
+				}
 
 
-		}
+				if ( data.metadata.format === 'pmd' ) {
 
 
-	} else { // Number
+					// map, envMap
 
 
-		var x1 = this.params[ i1 * 4 + 0 ];
-		var x2 = this.params[ i1 * 4 + 1 ];
-		var y1 = this.params[ i1 * 4 + 2 ];
-		var y2 = this.params[ i1 * 4 + 3 ];
+					if ( material.fileName ) {
 
 
-		var ratio = this._calculate( x1, x2, y1, y2, weight1 );
+						var fileName = material.fileName;
+						var fileNames = fileName.split( '*' );
 
 
-		result[ 0 ] = values[ offset0 ] * ( 1 - ratio ) + values[ offset1 ] * ratio;
+						// fileNames[ 0 ]: mapFileName
+						// fileNames[ 1 ]: envMapFileName( optional )
 
 
-	}
+						params.map = this._loadTexture( fileNames[ 0 ], textures );
 
 
-	return result;
+						if ( fileNames.length > 1 ) {
 
 
-};
+							var extension = fileNames[ 1 ].slice( - 4 ).toLowerCase();
 
 
-THREE.MMDLoader.CubicBezierInterpolation.prototype._calculate = function ( x1, x2, y1, y2, x ) {
+							params.envMap = this._loadTexture(
+								fileNames[ 1 ],
+								textures,
+								{ sphericalReflectionMapping: true }
+							);
 
 
-	/*
-	 * Cubic Bezier curves
-	 *   https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
-	 *
-	 * B(t) = ( 1 - t ) ^ 3 * P0
-	 *      + 3 * ( 1 - t ) ^ 2 * t * P1
-	 *      + 3 * ( 1 - t ) * t^2 * P2
-	 *      + t ^ 3 * P3
-	 *      ( 0 <= t <= 1 )
-	 *
-	 * MMD uses Cubic Bezier curves for bone and camera animation interpolation.
-	 *   http://d.hatena.ne.jp/edvakf/20111016/1318716097
-	 *
-	 *    x = ( 1 - t ) ^ 3 * x0
-	 *      + 3 * ( 1 - t ) ^ 2 * t * x1
-	 *      + 3 * ( 1 - t ) * t^2 * x2
-	 *      + t ^ 3 * x3
-	 *    y = ( 1 - t ) ^ 3 * y0
-	 *      + 3 * ( 1 - t ) ^ 2 * t * y1
-	 *      + 3 * ( 1 - t ) * t^2 * y2
-	 *      + t ^ 3 * y3
-	 *      ( x0 = 0, y0 = 0 )
-	 *      ( x3 = 1, y3 = 1 )
-	 *      ( 0 <= t, x1, x2, y1, y2 <= 1 )
-	 *
-	 * Here solves this equation with Bisection method,
-	 *   https://en.wikipedia.org/wiki/Bisection_method
-	 * gets t, and then calculate y.
-	 *
-	 * f(t) = 3 * ( 1 - t ) ^ 2 * t * x1
-	 *      + 3 * ( 1 - t ) * t^2 * x2
-	 *      + t ^ 3 - x = 0
-	 *
-	 * (Another option: Newton's method
-	 *    https://en.wikipedia.org/wiki/Newton%27s_method)
-	 */
+							params.combine = extension === '.sph'
+								? THREE.MultiplyOperation
+								: THREE.AddOperation;
 
 
-	var c = 0.5;
-	var t = c;
-	var s = 1.0 - t;
-	var loop = 15;
-	var eps = 1e-5;
-	var math = Math;
+						}
 
 
-	var sst3, stt3, ttt;
+					}
 
 
-	for ( var i = 0; i < loop; i ++ ) {
+					// gradientMap
 
 
-		sst3 = 3.0 * s * s * t;
-		stt3 = 3.0 * s * t * t;
-		ttt = t * t * t;
+					var toonFileName = ( material.toonIndex === - 1 )
+						? 'toon00.bmp'
+						: data.toonTextures[ material.toonIndex ].fileName;
 
 
-		var ft = ( sst3 * x1 ) + ( stt3 * x2 ) + ( ttt ) - x;
+					params.gradientMap = this._loadTexture(
+						toonFileName,
+						textures,
+						{
+							isToonTexture: true,
+							isDefaultToonTexture: this._isDefaultToonTexture( toonFileName )
+						}
+					);
 
 
-		if ( math.abs( ft ) < eps ) break;
+					// parameters for OutlineEffect
 
 
-		c /= 2.0;
+					params.userData.outlineParameters = {
+						thickness: material.edgeFlag === 1 ? 0.003 : 0.0,
+						color: [ 0, 0, 0 ],
+						alpha: 1.0,
+						visible: material.edgeFlag === 1
+					};
 
 
-		t += ( ft < 0 ) ? c : - c;
-		s = 1.0 - t;
+				} else {
 
 
-	}
+					// map
 
 
-	return ( sst3 * y1 ) + ( stt3 * y2 ) + ttt;
+					if ( material.textureIndex !== - 1 ) {
 
 
-};
+						params.map = this._loadTexture( data.textures[ material.textureIndex ], textures );
 
 
-THREE.MMDAudioManager = function ( audio, listener, p ) {
+					}
 
 
-	var params = ( p === null || p === undefined ) ? {} : p;
+					// envMap TODO: support m.envFlag === 3
 
 
-	this.audio = audio;
-	this.listener = listener;
+					if ( material.envTextureIndex !== - 1 && ( material.envFlag === 1 || material.envFlag == 2 ) ) {
 
 
-	this.elapsedTime = 0.0;
-	this.currentTime = 0.0;
-	this.delayTime = params.delayTime !== undefined ? params.delayTime : 0.0;
+						params.envMap = this._loadTexture(
+							data.textures[ material.envTextureIndex ],
+							textures, { sphericalReflectionMapping: true }
+						);
 
 
-	this.audioDuration = this.audio.buffer.duration;
-	this.duration = this.audioDuration + this.delayTime;
+						params.combine = material.envFlag === 1
+							? THREE.MultiplyOperation
+							: THREE.AddOperation;
 
 
-};
+					}
 
 
-THREE.MMDAudioManager.prototype = {
+					// gradientMap
 
 
-	constructor: THREE.MMDAudioManager,
+					var toonFileName, isDefaultToon;
 
 
-	control: function ( delta ) {
+					if ( material.toonIndex === - 1 || material.toonFlag !== 0 ) {
 
 
-		this.elapsed += delta;
-		this.currentTime += delta;
+						toonFileName = 'toon' + ( '0' + ( material.toonIndex + 1 ) ).slice( - 2 ) + '.bmp';
+						isDefaultToon = true;
 
 
-		if ( this.checkIfStopAudio() ) {
+					} else {
 
 
-			this.audio.stop();
+						toonFileName = data.textures[ material.toonIndex ];
+						isDefaultToon = false;
 
 
-		}
+					}
 
 
-		if ( this.checkIfStartAudio() ) {
+					params.gradientMap = this._loadTexture(
+						toonFileName,
+						textures,
+						{
+							isToonTexture: true,
+							isDefaultToonTexture: isDefaultToon
+						}
+					);
 
 
-			this.audio.play();
+					// parameters for OutlineEffect
+					params.userData.outlineParameters = {
+						thickness: material.edgeSize / 300,  // TODO: better calculation?
+						color: material.edgeColor.slice( 0, 3 ),
+						alpha: material.edgeColor[ 3 ],
+						visible: ( material.flag & 0x10 ) !== 0 && material.edgeSize > 0.0
+					};
 
 
-		}
+				}
 
 
-	},
+				if ( params.map !== undefined ) {
 
 
-	checkIfStartAudio: function () {
+					if ( ! params.transparent ) {
 
 
-		if ( this.audio.isPlaying ) {
+						this._checkImageTransparency( params.map, geometry, i );
 
 
-			return false;
+					}
 
 
-		}
+					params.emissive.multiplyScalar( 0.2 );
 
 
-		while ( this.currentTime >= this.duration ) {
+				}
 
 
-			this.currentTime -= this.duration;
+				materials.push( new THREE.MeshToonMaterial( params ) );
 
 
-		}
+			}
 
 
-		if ( this.currentTime < this.delayTime ) {
+			if ( data.metadata.format === 'pmx' ) {
 
 
-			return false;
+				// set transparent true if alpha morph is defined.
 
 
-		}
+				function checkAlphaMorph( elements, materials ) {
 
 
-		this.audio.startTime = this.currentTime - this.delayTime;
+					for ( var i = 0, il = elements.length; i < il; i ++ ) {
 
 
-		return true;
+						var element = elements[ i ];
 
 
-	},
+						if ( element.index === - 1 ) continue;
 
 
-	checkIfStopAudio: function () {
+						var material = materials[ element.index ];
 
 
-		if ( ! this.audio.isPlaying ) {
+						if ( material.opacity !== element.diffuse[ 3 ] ) {
 
 
-			return false;
+							material.transparent = true;
 
 
-		}
+						}
 
 
-		if ( this.currentTime >= this.duration ) {
+					}
 
 
-			return true;
+				}
 
 
-		}
+				for ( var i = 0, il = data.morphs.length; i < il; i ++ ) {
 
 
-		return false;
+					var morph = data.morphs[ i ];
+					var elements = morph.elements;
 
 
-	}
+					if ( morph.type === 0 ) {
 
 
-};
+						for ( var j = 0, jl = elements.length; j < jl; j ++ ) {
 
 
-THREE.MMDGrantSolver = function ( mesh ) {
+							var morph2 = data.morphs[ elements[ j ].index ];
 
 
-	this.mesh = mesh;
+							if ( morph2.type !== 8 ) continue;
 
 
-};
+							checkAlphaMorph( morph2.elements, materials );
 
 
-THREE.MMDGrantSolver.prototype = {
+						}
 
 
-	constructor: THREE.MMDGrantSolver,
+					} else if ( morph.type === 8 ) {
 
 
-	update: function () {
+						checkAlphaMorph( elements, materials );
 
 
-		var q = new THREE.Quaternion();
+					}
 
 
-		return function () {
+				}
 
 
-			for ( var i = 0; i < this.mesh.geometry.grants.length; i ++ ) {
+			}
 
 
-				var g = this.mesh.geometry.grants[ i ];
-				var b = this.mesh.skeleton.bones[ g.index ];
-				var pb = this.mesh.skeleton.bones[ g.parentIndex ];
+			return materials;
 
 
-				if ( g.isLocal ) {
+		},
 
 
-					// TODO: implement
-					if ( g.affectPosition ) {
+		// private methods
 
 
-					}
+		_getTGALoader: function () {
 
 
-					// TODO: implement
-					if ( g.affectRotation ) {
+			if ( this.tgaLoader === null ) {
 
 
-					}
+				if ( THREE.TGALoader === undefined ) {
 
 
-				} else {
+					throw new Error( 'THREE.MMDLoader: Import THREE.TGALoader' );
 
 
-					// TODO: implement
-					if ( g.affectPosition ) {
+				}
 
 
-					}
+				this.tgaLoader = new THREE.TGALoader( this.manager );
 
 
-					if ( g.affectRotation ) {
+			}
 
 
-						q.set( 0, 0, 0, 1 );
-						q.slerp( pb.quaternion, g.ratio );
-						b.quaternion.multiply( q );
+			return this.tgaLoader;
 
 
-					}
+		},
 
 
-				}
+		_isDefaultToonTexture: function ( name ) {
 
 
-			}
+			if ( name.length !== 10 ) return false;
 
 
-		};
+			return /toon(10|0[0-9])\.bmp/.test( name );
 
 
-	}()
+		},
 
 
-};
+		_loadTexture: function ( filePath, textures, params, onProgress, onError ) {
 
 
-THREE.MMDHelper = function () {
+			params = params || {};
 
 
-	this.meshes = [];
+			var scope = this;
 
 
-	this.doAnimation = true;
-	this.doIk = true;
-	this.doGrant = true;
-	this.doPhysics = true;
-	this.doCameraAnimation = true;
+			var fullPath;
 
 
-	this.sharedPhysics = false;
-	this.masterPhysics = null;
+			if ( params.isDefaultToonTexture === true ) {
 
 
-	this.audioManager = null;
-	this.camera = null;
+				var index;
 
 
-};
+				try {
 
 
-THREE.MMDHelper.prototype = {
+					index = parseInt( filePath.match( 'toon([0-9]{2})\.bmp$' )[ 1 ] );
 
 
-	constructor: THREE.MMDHelper,
+				} catch ( e ) {
 
 
-	add: function ( mesh ) {
+					console.warn( 'THREE.MMDLoader: ' + filePath + ' seems like a '
+						+ 'not right default texture path. Using toon00.bmp instead.' );
 
 
-		if ( ! ( mesh instanceof THREE.SkinnedMesh ) ) {
+					index = 0;
 
 
-			throw new Error( 'THREE.MMDHelper.add() accepts only THREE.SkinnedMesh instance.' );
+				}
 
 
-		}
+				fullPath = DEFAULT_TOON_TEXTURES[ index ];
 
 
-		if ( mesh.mixer === undefined ) mesh.mixer = null;
-		if ( mesh.ikSolver === undefined ) mesh.ikSolver = null;
-		if ( mesh.grantSolver === undefined ) mesh.grantSolver = null;
-		if ( mesh.physics === undefined ) mesh.physics = null;
-		if ( mesh.looped === undefined ) mesh.looped = false;
+			} else {
 
 
-		this.meshes.push( mesh );
+				fullPath = this.texturePath + filePath;
 
 
-		// workaround until I make IK and Physics Animation plugin
-		this.initBackupBones( mesh );
+			}
 
 
-	},
+			if ( textures[ fullPath ] !== undefined ) return textures[ fullPath ];
 
 
-	setAudio: function ( audio, listener, params ) {
+			var loader = THREE.Loader.Handlers.get( fullPath );
 
 
-		this.audioManager = new THREE.MMDAudioManager( audio, listener, params );
+			if ( loader === null ) {
 
 
-	},
+				loader = ( filePath.slice( - 4 ).toLowerCase() === '.tga' )
+					? this._getTGALoader()
+					: this.textureLoader;
 
 
-	setCamera: function ( camera ) {
+			}
 
 
-		camera.mixer = null;
-		this.camera = camera;
+			var texture = loader.load( fullPath, function ( t ) {
 
 
-	},
+				// MMD toon texture is Axis-Y oriented
+				// but Three.js gradient map is Axis-X oriented.
+				// So here replaces the toon texture image with the rotated one.
+				if ( params.isToonTexture === true ) {
 
 
-	setPhysicses: function ( params ) {
+					t.image = scope._getRotatedImage( t.image );
 
 
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+				}
 
 
-			this.setPhysics( this.meshes[ i ], params );
+				t.flipY = false;
+				t.wrapS = THREE.RepeatWrapping;
+				t.wrapT = THREE.RepeatWrapping;
 
 
-		}
+				for ( var i = 0; i < texture.readyCallbacks.length; i ++ ) {
 
 
-	},
+					texture.readyCallbacks[ i ]( texture );
 
 
-	setPhysics: function ( mesh, params ) {
+				}
 
 
-		params = ( params === undefined ) ? {} : Object.assign( {}, params );
+				delete texture.readyCallbacks;
 
 
-		if ( params.world === undefined && this.sharedPhysics ) {
+			}, onProgress, onError );
 
 
-			var masterPhysics = this.getMasterPhysics();
+			if ( params.sphericalReflectionMapping === true ) {
 
 
-			if ( masterPhysics !== null ) params.world = masterPhysics.world;
+				texture.mapping = THREE.SphericalReflectionMapping;
 
 
-		}
+			}
 
 
-		var warmup = params.warmup !== undefined ? params.warmup : 60;
+			texture.readyCallbacks = [];
 
 
-		var physics = new THREE.MMDPhysics( mesh, params );
+			textures[ fullPath ] = texture;
 
 
-		if ( mesh.mixer !== null && mesh.mixer !== undefined && params.preventAnimationWarmup !== true ) {
+			return texture;
 
 
-			this.animateOneMesh( 0, mesh );
-			physics.reset();
+		},
 
 
-		}
+		_getRotatedImage: function ( image ) {
 
 
-		physics.warmup( warmup );
+			var canvas = document.createElement( 'canvas' );
+			var context = canvas.getContext( '2d' );
 
 
-		this.updateIKParametersDependingOnPhysicsEnabled( mesh, true );
+			var width = image.width;
+			var height = image.height;
 
 
-		mesh.physics = physics;
+			canvas.width = width;
+			canvas.height = height;
 
 
-	},
+			context.clearRect( 0, 0, width, height );
+			context.translate( width / 2.0, height / 2.0 );
+			context.rotate( 0.5 * Math.PI ); // 90.0 * Math.PI / 180.0
+			context.translate( - width / 2.0, - height / 2.0 );
+			context.drawImage( image, 0, 0 );
 
 
-	getMasterPhysics: function () {
+			return context.getImageData( 0, 0, width, height );
 
 
-		if ( this.masterPhysics !== null ) return this.masterPhysics;
+		},
 
 
-		for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+		// Check if the partial image area used by the texture is transparent.
+		_checkImageTransparency: function ( map, geometry, groupIndex ) {
 
 
-			var physics = this.meshes[ i ].physics;
+			map.readyCallbacks.push( function ( texture ) {
 
 
-			if ( physics !== undefined && physics !== null ) {
+				// Is there any efficient ways?
+				function createImageData( image ) {
 
 
-				this.masterPhysics = physics;
-				return this.masterPhysics;
+					var canvas = document.createElement( 'canvas' );
+					canvas.width = image.width;
+					canvas.height = image.height;
 
 
-			}
+					var context = canvas.getContext( '2d' );
+					context.drawImage( image, 0, 0 );
 
 
-		}
+					return context.getImageData( 0, 0, canvas.width, canvas.height );
 
 
-		return null;
+				}
 
 
-	},
+				function detectImageTransparency( image, uvs, indices ) {
 
 
-	enablePhysics: function ( enabled ) {
+					var width = image.width;
+					var height = image.height;
+					var data = image.data;
+					var threshold = 253;
 
 
-		if ( enabled === true ) {
+					if ( data.length / ( width * height ) !== 4 ) return false;
 
 
-			this.doPhysics = true;
+					for ( var i = 0; i < indices.length; i += 3 ) {
 
 
-		} else {
+						var centerUV = { x: 0.0, y: 0.0 };
 
 
-			this.doPhysics = false;
+						for ( var j = 0; j < 3; j ++ ) {
 
 
-		}
+							var index = indices[ i * 3 + j ];
+							var uv = { x: uvs[ index * 2 + 0 ], y: uvs[ index * 2 + 1 ] };
 
 
-		for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+							if ( getAlphaByUv( image, uv ) < threshold ) return true;
 
 
-			this.updateIKParametersDependingOnPhysicsEnabled( this.meshes[ i ], enabled );
+							centerUV.x += uv.x;
+							centerUV.y += uv.y;
 
 
-		}
+						}
 
 
-	},
+						centerUV.x /= 3;
+						centerUV.y /= 3;
 
 
-	updateIKParametersDependingOnPhysicsEnabled: function ( mesh, physicsEnabled ) {
+						if ( getAlphaByUv( image, centerUV ) < threshold ) return true;
 
 
-		var iks = mesh.geometry.iks;
-		var bones = mesh.geometry.bones;
+					}
 
 
-		for ( var j = 0, jl = iks.length; j < jl; j ++ ) {
+					return false;
 
 
-			var ik = iks[ j ];
-			var links = ik.links;
+				}
 
 
-			for ( var k = 0, kl = links.length; k < kl; k ++ ) {
+				/*
+				 * This method expects
+				 *   texture.flipY = false
+				 *   texture.wrapS = THREE.RepeatWrapping
+				 *   texture.wrapT = THREE.RepeatWrapping
+				 * TODO: more precise
+				 */
+				function getAlphaByUv( image, uv ) {
 
 
-				var link = links[ k ];
+					var width = image.width;
+					var height = image.height;
 
 
-				if ( physicsEnabled === true ) {
+					var x = Math.round( uv.x * width ) % width;
+					var y = Math.round( uv.y * height ) % height;
 
 
-					// disable IK of the bone the corresponding rigidBody type of which is 1 or 2
-					// because its rotation will be overriden by physics
-					link.enabled = bones[ link.index ].rigidBodyType > 0 ? false : true;
+					if ( x < 0 ) x += width;
+					if ( y < 0 ) y += height;
 
 
-				} else {
+					var index = y * width + x;
 
 
-					link.enabled = true;
+					return image.data[ index * 4 + 3 ];
 
 
 				}
 				}
 
 
-			}
+				var imageData = texture.image.data !== undefined
+					? texture.image
+					: createImageData( texture.image );
 
 
-		}
+				var group = geometry.groups[ groupIndex ];
 
 
-	},
+				if ( detectImageTransparency(
+					imageData,
+					geometry.attributes.uv.array,
+					geometry.index.array.slice( group.start, group.start + group.count ) ) ) {
 
 
-	setAnimations: function () {
+					map.transparent = true;
 
 
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+				}
 
 
-			this.setAnimation( this.meshes[ i ] );
+			} );
 
 
 		}
 		}
 
 
-	},
+	};
+
+	//
 
 
-	setAnimation: function ( mesh ) {
+	function AnimationBuilder() {
 
 
-		if ( mesh.geometry.animations !== undefined ) {
+	}
 
 
-			mesh.mixer = new THREE.AnimationMixer( mesh );
+	AnimationBuilder.prototype = {
 
 
-			// TODO: find a workaround not to access (seems like) private properties
-			//       the name of them begins with "_".
-			mesh.mixer.addEventListener( 'loop', function ( e ) {
+		constructor: AnimationBuilder,
 
 
-				if ( e.action._clip.tracks.length > 0 &&
-				     e.action._clip.tracks[ 0 ].name.indexOf( '.bones' ) !== 0 ) return;
+		/**
+		 * @param {Object} vmd - parsed VMD data
+		 * @param {THREE.SkinnedMesh} mesh - tracks will be fitting to mesh
+		 * @return {THREE.AnimationClip}
+		 */
+		build: function ( vmd, mesh ) {
 
 
-				var mesh = e.target._root;
-				mesh.looped = true;
+			// combine skeletal and morph animations
 
 
-			} );
+			var tracks = this.buildSkeletalAnimation( vmd, mesh ).tracks;
+			var tracks2 = this.buildMorphAnimation( vmd, mesh ).tracks;
 
 
-			var foundAnimation = false;
-			var foundMorphAnimation = false;
+			for ( var i = 0, il = tracks2.length; i < il; i ++ ) {
 
 
-			for ( var i = 0; i < mesh.geometry.animations.length; i ++ ) {
+				tracks.push( tracks2[ i ] );
 
 
-				var clip = mesh.geometry.animations[ i ];
+			}
 
 
-				var action = mesh.mixer.clipAction( clip );
+			return new THREE.AnimationClip( '', - 1, tracks );
 
 
-				if ( clip.tracks.length > 0 && clip.tracks[ 0 ].name.indexOf( '.morphTargetInfluences' ) === 0 ) {
+		},
 
 
-					if ( ! foundMorphAnimation ) {
+		/**
+		 * @param {Object} vmd - parsed VMD data
+		 * @param {THREE.SkinnedMesh} mesh - tracks will be fitting to mesh
+		 * @return {THREE.AnimationClip}
+		 */
+		buildSkeletalAnimation: function ( vmd, mesh ) {
 
 
-						action.play();
-						foundMorphAnimation = true;
+			function pushInterpolation( array, interpolation, index ) {
 
 
-					}
+				array.push( interpolation[ index + 0 ] / 127 ); // x1
+				array.push( interpolation[ index + 8 ] / 127 ); // x2
+				array.push( interpolation[ index + 4 ] / 127 ); // y1
+				array.push( interpolation[ index + 12 ] / 127 ); // y2
 
 
-				} else {
+			};
 
 
-					if ( ! foundAnimation ) {
+			var tracks = [];
 
 
-						action.play();
-						foundAnimation = true;
+			var motions = {};
+			var bones = mesh.skeleton.bones;
+			var boneNameDictionary = {};
 
 
-					}
+			for ( var i = 0, il = bones.length; i < il; i ++ ) {
 
 
-				}
+				boneNameDictionary[ bones[ i ].name ] = true;
 
 
 			}
 			}
 
 
-			if ( foundAnimation ) {
+			for ( var i = 0; i < vmd.metadata.motionCount; i ++ ) {
 
 
-				mesh.ikSolver = new THREE.CCDIKSolver( mesh );
+				var motion = vmd.motions[ i ];
+				var boneName = motion.boneName;
 
 
-				if ( mesh.geometry.grants !== undefined ) {
+				if ( boneNameDictionary[ boneName ] === undefined ) continue;
 
 
-					mesh.grantSolver = new THREE.MMDGrantSolver( mesh );
-
-				}
+				motions[ boneName ] = motions[ boneName ] || [];
+				motions[ boneName ].push( motion );
 
 
 			}
 			}
 
 
-		}
-
-	},
+			for ( var key in motions ) {
 
 
-	setCameraAnimation: function ( camera ) {
+				var array = motions[ key ];
 
 
-		if ( camera.animations !== undefined ) {
+				array.sort( function ( a, b ) {
 
 
-			camera.mixer = new THREE.AnimationMixer( camera );
-			camera.mixer.clipAction( camera.animations[ 0 ] ).play();
+					return a.frameNum - b.frameNum;
 
 
-		}
-
-	},
-
-	/*
-	 * detect the longest duration among model, camera, and audio animations and then
-	 * set it to them to sync.
-	 * TODO: touching private properties ( ._actions and ._clip ) so consider better way
-	 *       to access them for safe and modularity.
-	 */
-	unifyAnimationDuration: function ( params ) {
+				} );
 
 
-		params = params === undefined ? {} : params;
+				var times = [];
+				var positions = [];
+				var rotations = [];
+				var pInterpolations = [];
+				var rInterpolations = [];
 
 
-		var max = 0.0;
+				var basePosition = mesh.skeleton.getBoneByName( key ).position.toArray();
 
 
-		var camera = this.camera;
-		var audioManager = this.audioManager;
+				for ( var i = 0, il = array.length; i < il; i ++ ) {
 
 
-		// check the longest duration
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+					var time = array[ i ].frameNum / 30;
+					var position = array[ i ].position;
+					var rotation = array[ i ].rotation;
+					var interpolation = array[ i ].interpolation;
 
 
-			var mesh = this.meshes[ i ];
-			var mixer = mesh.mixer;
+					times.push( time );
 
 
-			if ( mixer === null ) {
+					for ( var j = 0; j < 3; j ++ ) positions.push( basePosition[ j ] + position[ j ] );
+					for ( var j = 0; j < 4; j ++ ) rotations.push( rotation[ j ] );
+					for ( var j = 0; j < 3; j ++ ) pushInterpolation( pInterpolations, interpolation, j );
 
 
-				continue;
+					pushInterpolation( rInterpolations, interpolation, 3 );
 
 
-			}
+				}
 
 
-			for ( var j = 0; j < mixer._actions.length; j ++ ) {
+				var targetName = '.bones[' + key + ']';
 
 
-				var action = mixer._actions[ j ];
-				max = Math.max( max, action._clip.duration );
+				tracks.push( this._createTrack( targetName + '.position', THREE.VectorKeyframeTrack, times, positions, pInterpolations ) );
+				tracks.push( this._createTrack( targetName + '.quaternion', THREE.QuaternionKeyframeTrack, times, rotations, rInterpolations ) );
 
 
 			}
 			}
 
 
-		}
+			return new THREE.AnimationClip( '', - 1, tracks );
 
 
-		if ( camera !== null && camera.mixer !== null ) {
+		},
 
 
-			var mixer = camera.mixer;
+		/**
+		 * @param {Object} vmd - parsed VMD data
+		 * @param {THREE.SkinnedMesh} mesh - tracks will be fitting to mesh
+		 * @return {THREE.AnimationClip}
+		 */
+		buildMorphAnimation: function ( vmd, mesh ) {
 
 
-			for ( var i = 0; i < mixer._actions.length; i ++ ) {
+			var tracks = [];
 
 
-				var action = mixer._actions[ i ];
-				max = Math.max( max, action._clip.duration );
+			var morphs = {};
+			var morphTargetDictionary = mesh.morphTargetDictionary;
 
 
-			}
+			for ( var i = 0; i < vmd.metadata.morphCount; i ++ ) {
 
 
-		}
+				var morph = vmd.morphs[ i ];
+				var morphName = morph.morphName;
 
 
-		if ( audioManager !== null ) {
+				if ( morphTargetDictionary[ morphName ] === undefined ) continue;
 
 
-			max = Math.max( max, audioManager.duration );
+				morphs[ morphName ] = morphs[ morphName ] || [];
+				morphs[ morphName ].push( morph );
 
 
-		}
+			}
 
 
-		if ( params.afterglow !== undefined ) {
+			for ( var key in morphs ) {
 
 
-			max += params.afterglow;
+				var array = morphs[ key ];
 
 
-		}
+				array.sort( function ( a, b ) {
 
 
-		// set the duration
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+					return a.frameNum - b.frameNum;
 
 
-			var mesh = this.meshes[ i ];
-			var mixer = mesh.mixer;
+				} );
 
 
-			if ( mixer === null ) {
+				var times = [];
+				var values = [];
 
 
-				continue;
+				for ( var i = 0, il = array.length; i < il; i ++ ) {
 
 
-			}
+					times.push( array[ i ].frameNum / 30 );
+					values.push( array[ i ].weight );
 
 
-			for ( var j = 0; j < mixer._actions.length; j ++ ) {
+				}
 
 
-				var action = mixer._actions[ j ];
-				action._clip.duration = max;
+				tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + morphTargetDictionary[ key ] + ']', times, values ) );
 
 
 			}
 			}
 
 
-		}
+			return new THREE.AnimationClip( '', - 1, tracks );
 
 
-		if ( camera !== null && camera.mixer !== null ) {
+		},
 
 
-			var mixer = camera.mixer;
+		/**
+		 * @param {Object} vmd - parsed VMD data
+		 * @return {THREE.AnimationClip}
+		 */
+		buildCameraAnimation: function ( vmd ) {
 
 
-			for ( var i = 0; i < mixer._actions.length; i ++ ) {
+			function pushVector3( array, vec ) {
 
 
-				var action = mixer._actions[ i ];
-				action._clip.duration = max;
+				array.push( vec.x );
+				array.push( vec.y );
+				array.push( vec.z );
 
 
 			}
 			}
 
 
-		}
-
-		if ( audioManager !== null ) {
+			function pushQuaternion( array, q ) {
 
 
-			audioManager.duration = max;
+				array.push( q.x );
+				array.push( q.y );
+				array.push( q.z );
+				array.push( q.w );
 
 
-		}
+			}
 
 
-	},
+			function pushInterpolation( array, interpolation, index ) {
 
 
-	controlAudio: function ( delta ) {
+				array.push( interpolation[ index * 4 + 0 ] / 127 ); // x1
+				array.push( interpolation[ index * 4 + 1 ] / 127 ); // x2
+				array.push( interpolation[ index * 4 + 2 ] / 127 ); // y1
+				array.push( interpolation[ index * 4 + 3 ] / 127 ); // y2
 
 
-		if ( this.audioManager === null ) {
+			};
 
 
-			return;
+			var tracks = [];
 
 
-		}
+			var cameras = vmd.cameras === undefined ? [] : vmd.cameras.slice();
 
 
-		this.audioManager.control( delta );
+			cameras.sort( function ( a, b ) {
 
 
-	},
+				return a.frameNum - b.frameNum;
 
 
-	animate: function ( delta ) {
+			} );
 
 
-		this.controlAudio( delta );
+			var times = [];
+			var centers = [];
+			var quaternions = [];
+			var positions = [];
+			var fovs = [];
 
 
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+			var cInterpolations = [];
+			var qInterpolations = [];
+			var pInterpolations = [];
+			var fInterpolations = [];
 
 
-			this.animateOneMesh( delta, this.meshes[ i ] );
+			var quaternion = new THREE.Quaternion();
+			var euler = new THREE.Euler();
+			var position = new THREE.Vector3();
+			var center = new THREE.Vector3();
 
 
-		}
+			for ( var i = 0, il = cameras.length; i < il; i ++ ) {
 
 
-		if ( this.sharedPhysics ) this.updateSharedPhysics( delta );
+				var motion = cameras[ i ];
 
 
-		this.animateCamera( delta );
+				var time = motion.frameNum / 30;
+				var pos = motion.position;
+				var rot = motion.rotation;
+				var distance = motion.distance;
+				var fov = motion.fov;
+				var interpolation = motion.interpolation;
 
 
-	},
+				times.push( time );
 
 
-	animateOneMesh: function ( delta, mesh ) {
+				position.set( 0, 0, - distance );
+				center.set( pos[ 0 ], pos[ 1 ], pos[ 2 ] );
 
 
-		var mixer = mesh.mixer;
-		var ikSolver = mesh.ikSolver;
-		var grantSolver = mesh.grantSolver;
-		var physics = mesh.physics;
+				euler.set( - rot[ 0 ], - rot[ 1 ], - rot[ 2 ] );
+				quaternion.setFromEuler( euler );
 
 
-		if ( mixer !== null && this.doAnimation === true ) {
+				position.add( center );
+				position.applyQuaternion( quaternion );
 
 
-			// restore/backupBones are workaround
-			// until I make IK, Grant, and Physics Animation plugin
-			this.restoreBones( mesh );
+				pushVector3( centers, center );
+				pushQuaternion( quaternions, quaternion );
+				pushVector3( positions, position );
 
 
-			mixer.update( delta );
+				fovs.push( fov );
 
 
-			this.backupBones( mesh );
+				for ( var j = 0; j < 3; j ++ ) {
 
 
-		}
+					pushInterpolation( cInterpolations, interpolation, j );
 
 
-		if ( ikSolver !== null && this.doIk === true ) {
+				}
 
 
-			ikSolver.update();
+				pushInterpolation( qInterpolations, interpolation, 3 );
 
 
-		}
+				// use the same parameter for x, y, z axis.
+				for ( var j = 0; j < 3; j ++ ) {
 
 
-		if ( grantSolver !== null && this.doGrant === true ) {
+					pushInterpolation( pInterpolations, interpolation, 4 );
 
 
-			grantSolver.update();
+				}
 
 
-		}
+				pushInterpolation( fInterpolations, interpolation, 5 );
 
 
-		if ( mesh.looped === true ) {
+			}
 
 
-			if ( physics !== null ) physics.reset();
+			var tracks = [];
 
 
-			mesh.looped = false;
+			// I expect an object whose name 'target' exists under THREE.Camera
+			tracks.push( this._createTrack( 'target.position', THREE.VectorKeyframeTrack, times, centers, cInterpolations ) );
 
 
-		}
+			tracks.push( this._createTrack( '.quaternion', THREE.QuaternionKeyframeTrack, times, quaternions, qInterpolations ) );
+			tracks.push( this._createTrack( '.position', THREE.VectorKeyframeTrack, times, positions, pInterpolations ) );
+			tracks.push( this._createTrack( '.fov', THREE.NumberKeyframeTrack, times, fovs, fInterpolations ) );
 
 
-		if ( physics !== null && this.doPhysics && ! this.sharedPhysics ) {
+			return new THREE.AnimationClip( '', - 1, tracks );
 
 
-			physics.update( delta );
+		},
 
 
-		}
+		// private method
 
 
-	},
+		_createTrack: function ( node, typedKeyframeTrack, times, values, interpolations ) {
 
 
-	updateSharedPhysics: function ( delta ) {
+			/*
+			 * optimizes here not to let KeyframeTrackPrototype optimize
+			 * because KeyframeTrackPrototype optimizes times and values but
+			 * doesn't optimize interpolations.
+			 */
+			if ( times.length > 2 ) {
 
 
-		if ( this.meshes.length === 0 || ! this.doPhysics || ! this.sharedPhysics ) return;
+				times = times.slice();
+				values = values.slice();
+				interpolations = interpolations.slice();
 
 
-		var physics = this.getMasterPhysics();
+				var stride = values.length / times.length;
+				var interpolateStride = interpolations.length / times.length;
 
 
-		if ( physics === null ) return;
+				var index = 1;
 
 
-		for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+				for ( var aheadIndex = 2, endIndex = times.length; aheadIndex < endIndex; aheadIndex ++ ) {
 
 
-			var p = this.meshes[ i ].physics;
+					for ( var i = 0; i < stride; i ++ ) {
 
 
-			if ( p !== null && p !== undefined ) {
+						if ( values[ index * stride + i ] !== values[ ( index - 1 ) * stride + i ] ||
+							values[ index * stride + i ] !== values[ aheadIndex * stride + i ] ) {
 
 
-				p.updateRigidBodies();
+							index ++;
+							break;
 
 
-			}
+						}
 
 
-		}
+					}
 
 
-		physics.stepSimulation( delta );
+					if ( aheadIndex > index ) {
 
 
-		for ( var i = 0, il = this.meshes.length; i < il; i ++ ) {
+						times[ index ] = times[ aheadIndex ];
 
 
-			var p = this.meshes[ i ].physics;
+						for ( var i = 0; i < stride; i ++ ) {
 
 
-			if ( p !== null && p !== undefined ) {
+							values[ index * stride + i ] = values[ aheadIndex * stride + i ];
 
 
-				p.updateBones();
+						}
 
 
-			}
+						for ( var i = 0; i < interpolateStride; i ++ ) {
 
 
-		}
+							interpolations[ index * interpolateStride + i ] = interpolations[ aheadIndex * interpolateStride + i ];
 
 
-	},
+						}
 
 
-	animateCamera: function ( delta ) {
+					}
 
 
-		if ( this.camera === null ) {
+				}
 
 
-			return;
+				times.length = index + 1;
+				values.length = ( index + 1 ) * stride;
+				interpolations.length = ( index + 1 ) * interpolateStride;
 
 
-		}
+			}
 
 
-		var mixer = this.camera.mixer;
+			var track = new typedKeyframeTrack( node, times, values );
 
 
-		if ( mixer !== null && this.camera.center !== undefined && this.doCameraAnimation === true ) {
+			track.createInterpolant = function InterpolantFactoryMethodCubicBezier( result ) {
 
 
-			mixer.update( delta );
+				return new CubicBezierInterpolation( this.times, this.values, this.getValueSize(), result, new Float32Array( interpolations ) );
 
 
-			// TODO: Let PerspectiveCamera automatically update?
-			this.camera.updateProjectionMatrix();
+			};
 
 
-			this.camera.up.set( 0, 1, 0 );
-			this.camera.up.applyQuaternion( this.camera.quaternion );
-			this.camera.lookAt( this.camera.center );
+			return track;
 
 
 		}
 		}
 
 
-	},
-
-	poseAsVpd: function ( mesh, vpd, params ) {
-
-		if ( params === undefined ) params = {};
-
-		if ( params.preventResetPose !== true ) mesh.pose();
+	};
 
 
-		var bones = mesh.skeleton.bones;
-		var bones2 = vpd.bones;
+	// interpolation
 
 
-		var table = {};
+	function CubicBezierInterpolation( parameterPositions, sampleValues, sampleSize, resultBuffer, params ) {
 
 
-		for ( var i = 0; i < bones.length; i ++ ) {
+		THREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 
 
-			table[ bones[ i ].name ] = i;
+		this.interpolationParams = params;
 
 
-		}
+	}
 
 
-		var thV = new THREE.Vector3();
-		var thQ = new THREE.Quaternion();
+	CubicBezierInterpolation.prototype = Object.assign( Object.create( THREE.Interpolant.prototype ), {
 
 
-		for ( var i = 0; i < bones2.length; i ++ ) {
+		constructor: CubicBezierInterpolation,
 
 
-			var b = bones2[ i ];
-			var index = table[ b.name ];
+		interpolate_: function ( i1, t0, t, t1 ) {
 
 
-			if ( index === undefined ) continue;
+			var result = this.resultBuffer;
+			var values = this.sampleValues;
+			var stride = this.valueSize;
+			var params = this.interpolationParams;
 
 
-			var b2 = bones[ index ];
-			var t = b.translation;
-			var q = b.quaternion;
+			var offset1 = i1 * stride;
+			var offset0 = offset1 - stride;
 
 
-			thV.set( t[ 0 ], t[ 1 ], t[ 2 ] );
-			thQ.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );
+			// No interpolation if next key frame is in one frame in 30fps.
+			// This is from MMD animation spec.
+			// '1.5' is for precision loss. times are Float32 in Three.js Animation system.
+			var weight1 = ( ( t1 - t0 ) < 1 / 30 * 1.5 ) ? 0.0 : ( t - t0 ) / ( t1 - t0 );
 
 
-			b2.position.add( thV );
-			b2.quaternion.multiply( thQ );
+			if ( stride === 4 ) { // Quaternion
 
 
-		}
+				var x1 = params[ i1 * 4 + 0 ];
+				var x2 = params[ i1 * 4 + 1 ];
+				var y1 = params[ i1 * 4 + 2 ];
+				var y2 = params[ i1 * 4 + 3 ];
 
 
-		mesh.updateMatrixWorld( true );
+				var ratio = this._calculate( x1, x2, y1, y2, weight1 );
 
 
-		if ( params.preventIk !== true ) {
+				THREE.Quaternion.slerpFlat( result, 0, values, offset0, values, offset1, ratio );
 
 
-			var solver = new THREE.CCDIKSolver( mesh );
-			solver.update( params.saveOriginalBonesBeforeIK );
+			} else if ( stride === 3 ) { // Vector3
 
 
-		}
+				for ( var i = 0; i !== stride; ++ i ) {
 
 
-		if ( params.preventGrant !== true && mesh.geometry.grants !== undefined ) {
+					var x1 = params[ i1 * 12 + i * 4 + 0 ];
+					var x2 = params[ i1 * 12 + i * 4 + 1 ];
+					var y1 = params[ i1 * 12 + i * 4 + 2 ];
+					var y2 = params[ i1 * 12 + i * 4 + 3 ];
 
 
-			var solver = new THREE.MMDGrantSolver( mesh );
-			solver.update();
+					var ratio = this._calculate( x1, x2, y1, y2, weight1 );
 
 
-		}
+					result[ i ] = values[ offset0 + i ] * ( 1 - ratio ) + values[ offset1 + i ] * ratio;
 
 
-	},
+				}
 
 
-	/*
-	 * Note: These following three functions are workaround for r74dev.
-	 *       THREE.PropertyMixer.apply() seems to save values into buffer cache
-	 *       when mixer.update() is called.
-	 *       ikSolver.update() and physics.update() change bone position/quaternion
-	 *       without mixer.update() then buffer cache will be inconsistent.
-	 *       So trying to avoid buffer cache inconsistency by doing
-	 *       backup bones position/quaternion right after mixer.update() call
-	 *       and then restore them after rendering.
-	 */
-	initBackupBones: function ( mesh ) {
+			} else { // Number
 
 
-		mesh.skeleton.backupBones = [];
+				var x1 = params[ i1 * 4 + 0 ];
+				var x2 = params[ i1 * 4 + 1 ];
+				var y1 = params[ i1 * 4 + 2 ];
+				var y2 = params[ i1 * 4 + 3 ];
 
 
-		for ( var i = 0; i < mesh.skeleton.bones.length; i ++ ) {
+				var ratio = this._calculate( x1, x2, y1, y2, weight1 );
 
 
-			mesh.skeleton.backupBones.push( mesh.skeleton.bones[ i ].clone() );
+				result[ 0 ] = values[ offset0 ] * ( 1 - ratio ) + values[ offset1 ] * ratio;
 
 
-		}
+			}
 
 
-	},
+			return result;
 
 
-	backupBones: function ( mesh ) {
+		},
 
 
-		mesh.skeleton.backupBoneIsSaved = true;
+		_calculate: function ( x1, x2, y1, y2, x ) {
 
 
-		for ( var i = 0; i < mesh.skeleton.bones.length; i ++ ) {
+			/*
+			 * Cubic Bezier curves
+			 *   https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
+			 *
+			 * B(t) = ( 1 - t ) ^ 3 * P0
+			 *      + 3 * ( 1 - t ) ^ 2 * t * P1
+			 *      + 3 * ( 1 - t ) * t^2 * P2
+			 *      + t ^ 3 * P3
+			 *      ( 0 <= t <= 1 )
+			 *
+			 * MMD uses Cubic Bezier curves for bone and camera animation interpolation.
+			 *   http://d.hatena.ne.jp/edvakf/20111016/1318716097
+			 *
+			 *    x = ( 1 - t ) ^ 3 * x0
+			 *      + 3 * ( 1 - t ) ^ 2 * t * x1
+			 *      + 3 * ( 1 - t ) * t^2 * x2
+			 *      + t ^ 3 * x3
+			 *    y = ( 1 - t ) ^ 3 * y0
+			 *      + 3 * ( 1 - t ) ^ 2 * t * y1
+			 *      + 3 * ( 1 - t ) * t^2 * y2
+			 *      + t ^ 3 * y3
+			 *      ( x0 = 0, y0 = 0 )
+			 *      ( x3 = 1, y3 = 1 )
+			 *      ( 0 <= t, x1, x2, y1, y2 <= 1 )
+			 *
+			 * Here solves this equation with Bisection method,
+			 *   https://en.wikipedia.org/wiki/Bisection_method
+			 * gets t, and then calculate y.
+			 *
+			 * f(t) = 3 * ( 1 - t ) ^ 2 * t * x1
+			 *      + 3 * ( 1 - t ) * t^2 * x2
+			 *      + t ^ 3 - x = 0
+			 *
+			 * (Another option: Newton's method
+			 *    https://en.wikipedia.org/wiki/Newton%27s_method)
+			 */
 
 
-			var b = mesh.skeleton.backupBones[ i ];
-			var b2 = mesh.skeleton.bones[ i ];
-			b.position.copy( b2.position );
-			b.quaternion.copy( b2.quaternion );
+			var c = 0.5;
+			var t = c;
+			var s = 1.0 - t;
+			var loop = 15;
+			var eps = 1e-5;
+			var math = Math;
 
 
-		}
+			var sst3, stt3, ttt;
 
 
-	},
+			for ( var i = 0; i < loop; i ++ ) {
 
 
-	restoreBones: function ( mesh ) {
+				sst3 = 3.0 * s * s * t;
+				stt3 = 3.0 * s * t * t;
+				ttt = t * t * t;
 
 
-		if ( mesh.skeleton.backupBoneIsSaved !== true ) {
+				var ft = ( sst3 * x1 ) + ( stt3 * x2 ) + ( ttt ) - x;
 
 
-			return;
+				if ( math.abs( ft ) < eps ) break;
 
 
-		}
+				c /= 2.0;
 
 
-		mesh.skeleton.backupBoneIsSaved = false;
+				t += ( ft < 0 ) ? c : - c;
+				s = 1.0 - t;
 
 
-		for ( var i = 0; i < mesh.skeleton.bones.length; i ++ ) {
+			}
 
 
-			var b = mesh.skeleton.bones[ i ];
-			var b2 = mesh.skeleton.backupBones[ i ];
-			b.position.copy( b2.position );
-			b.quaternion.copy( b2.quaternion );
+			return ( sst3 * y1 ) + ( stt3 * y2 ) + ttt;
 
 
 		}
 		}
 
 
-	}
+	} );
+
+	return MMDLoader;
 
 
-};
+} )();

+ 2 - 1
examples/js/loaders/NodeMaterialLoader.js

@@ -184,9 +184,10 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
 
 
 			switch ( node.type ) {
 			switch ( node.type ) {
 
 
+				case "IntNode":
 				case "FloatNode":
 				case "FloatNode":
 
 
-					object.number = node.number;
+					object.value = node.value;
 
 
 					break;
 					break;
 
 

+ 43 - 10
examples/js/loaders/OBJLoader2.js

@@ -17,7 +17,7 @@ if ( THREE.LoaderSupport === undefined ) console.error( '"THREE.LoaderSupport" i
  */
  */
 THREE.OBJLoader2 = (function () {
 THREE.OBJLoader2 = (function () {
 
 
-	var OBJLOADER2_VERSION = '2.4.0';
+	var OBJLOADER2_VERSION = '2.4.1';
 	var Validator = THREE.LoaderSupport.Validator;
 	var Validator = THREE.LoaderSupport.Validator;
 
 
 	function OBJLoader2( manager ) {
 	function OBJLoader2( manager ) {
@@ -35,6 +35,7 @@ THREE.OBJLoader2 = (function () {
 		this.useIndices = false;
 		this.useIndices = false;
 		this.disregardNormals = false;
 		this.disregardNormals = false;
 		this.materialPerSmoothingGroup = false;
 		this.materialPerSmoothingGroup = false;
+		this.useOAsMesh = false;
 		this.loaderRootNode = new THREE.Group();
 		this.loaderRootNode = new THREE.Group();
 
 
 		this.meshBuilder = new THREE.LoaderSupport.MeshBuilder();
 		this.meshBuilder = new THREE.LoaderSupport.MeshBuilder();
@@ -126,6 +127,16 @@ THREE.OBJLoader2 = (function () {
 		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
 		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
 	};
 	};
 
 
+	/**
+	 * Usually 'o' is meta-information and does not result in creation of new meshes, but mesh creation on occurrence of "o" can be enforced.
+	 * @memberOf THREE.OBJLoader2
+	 *
+	 * @param {boolean} useOAsMesh=false
+	 */
+	OBJLoader2.prototype.setUseOAsMesh = function ( useOAsMesh ) {
+		this.useOAsMesh = useOAsMesh === true;
+	};
+
 	OBJLoader2.prototype._setCallbacks = function ( callbacks ) {
 	OBJLoader2.prototype._setCallbacks = function ( callbacks ) {
 		if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
 		if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
 		if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
 		if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
@@ -297,6 +308,7 @@ THREE.OBJLoader2 = (function () {
 			this.setUseIndices( prepData.useIndices );
 			this.setUseIndices( prepData.useIndices );
 			this.setDisregardNormals( prepData.disregardNormals );
 			this.setDisregardNormals( prepData.disregardNormals );
 			this.setMaterialPerSmoothingGroup( prepData.materialPerSmoothingGroup );
 			this.setMaterialPerSmoothingGroup( prepData.materialPerSmoothingGroup );
+			this.setUseOAsMesh( prepData.useOAsMesh );
 
 
 			this._setCallbacks( prepData.getCallbacks() );
 			this._setCallbacks( prepData.getCallbacks() );
 
 
@@ -323,6 +335,7 @@ THREE.OBJLoader2 = (function () {
 		var parser = new Parser();
 		var parser = new Parser();
 		parser.setLogging( this.logging.enabled, this.logging.debug );
 		parser.setLogging( this.logging.enabled, this.logging.debug );
 		parser.setMaterialPerSmoothingGroup( this.materialPerSmoothingGroup );
 		parser.setMaterialPerSmoothingGroup( this.materialPerSmoothingGroup );
+		parser.setUseOAsMesh( this.useOAsMesh );
 		parser.setUseIndices( this.useIndices );
 		parser.setUseIndices( this.useIndices );
 		parser.setDisregardNormals( this.disregardNormals );
 		parser.setDisregardNormals( this.disregardNormals );
 		// sync code works directly on the material references
 		// sync code works directly on the material references
@@ -434,6 +447,7 @@ THREE.OBJLoader2 = (function () {
 				params: {
 				params: {
 					useAsync: true,
 					useAsync: true,
 					materialPerSmoothingGroup: this.materialPerSmoothingGroup,
 					materialPerSmoothingGroup: this.materialPerSmoothingGroup,
+					useOAsMesh: this.useOAsMesh,
 					useIndices: this.useIndices,
 					useIndices: this.useIndices,
 					disregardNormals: this.disregardNormals
 					disregardNormals: this.disregardNormals
 				},
 				},
@@ -469,6 +483,7 @@ THREE.OBJLoader2 = (function () {
 			this.materials = {};
 			this.materials = {};
 			this.useAsync = false;
 			this.useAsync = false;
 			this.materialPerSmoothingGroup = false;
 			this.materialPerSmoothingGroup = false;
+			this.useOAsMesh = false;
 			this.useIndices = false;
 			this.useIndices = false;
 			this.disregardNormals = false;
 			this.disregardNormals = false;
 
 
@@ -541,6 +556,10 @@ THREE.OBJLoader2 = (function () {
 			this.materialPerSmoothingGroup = materialPerSmoothingGroup;
 			this.materialPerSmoothingGroup = materialPerSmoothingGroup;
 		};
 		};
 
 
+		Parser.prototype.setUseOAsMesh = function ( useOAsMesh ) {
+			this.useOAsMesh = useOAsMesh;
+		};
+
 		Parser.prototype.setUseIndices = function ( useIndices ) {
 		Parser.prototype.setUseIndices = function ( useIndices ) {
 			this.useIndices = useIndices;
 			this.useIndices = useIndices;
 		};
 		};
@@ -579,6 +598,7 @@ THREE.OBJLoader2 = (function () {
 					+ matNames
 					+ matNames
 					+ '\n\tuseAsync: ' + this.useAsync
 					+ '\n\tuseAsync: ' + this.useAsync
 					+ '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup
 					+ '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup
+					+ '\n\tuseOAsMesh: ' + this.useOAsMesh
 					+ '\n\tuseIndices: ' + this.useIndices
 					+ '\n\tuseIndices: ' + this.useIndices
 					+ '\n\tdisregardNormals: ' + this.disregardNormals
 					+ '\n\tdisregardNormals: ' + this.disregardNormals
 					+ '\n\tcallbackMeshBuilderName: ' + this.callbackMeshBuilder.name
 					+ '\n\tcallbackMeshBuilderName: ' + this.callbackMeshBuilder.name
@@ -826,7 +846,8 @@ THREE.OBJLoader2 = (function () {
 					break;
 					break;
 
 
 				case 'o':
 				case 'o':
-					// 'o' is pure meta-information and does not result in creation of new meshes
+					// 'o' is meta-information and usually does not result in creation of new meshes, but can be enforced with "useOAsMesh"
+					if ( this.useOAsMesh ) this.processCompletedMesh();
 					this.rawMesh.objectName = reconstructString( this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte );
 					this.rawMesh.objectName = reconstructString( this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte );
 					break;
 					break;
 
 
@@ -926,7 +947,7 @@ THREE.OBJLoader2 = (function () {
 				vertices.push( scope.vertices[ indexPointerV++ ] );
 				vertices.push( scope.vertices[ indexPointerV++ ] );
 				vertices.push( scope.vertices[ indexPointerV ] );
 				vertices.push( scope.vertices[ indexPointerV ] );
 
 
-				var indexPointerC = scope.colors.length > 0 ? indexPointerV : null;
+				var indexPointerC = scope.colors.length > 0 ? indexPointerV + 1 : null;
 				if ( indexPointerC !== null ) {
 				if ( indexPointerC !== null ) {
 
 
 					var colors = scope.rawMesh.subGroupInUse.colors;
 					var colors = scope.rawMesh.subGroupInUse.colors;
@@ -1356,19 +1377,31 @@ THREE.OBJLoader2 = (function () {
 			mtlLoader.setPath( resource.path );
 			mtlLoader.setPath( resource.path );
 			if ( Validator.isValid( materialOptions ) ) mtlLoader.setMaterialOptions( materialOptions );
 			if ( Validator.isValid( materialOptions ) ) mtlLoader.setMaterialOptions( materialOptions );
 
 
+			var parseTextWithMtlLoader = function ( content ) {
+				var contentAsText = content;
+				if ( typeof( content ) !== 'string' && ! ( content instanceof String ) ) {
+
+					if ( content.length > 0 || content.byteLength > 0 ) {
+
+						contentAsText = THREE.LoaderUtils.decodeText( content );
+
+					} else {
+
+						throw 'Unable to parse mtl as it it seems to be neither a String, an Array or an ArrayBuffer!';
+					}
+
+				}
+				processMaterials( mtlLoader.parse( contentAsText ) );
+			};
+
 			if ( Validator.isValid( resource.content ) ) {
 			if ( Validator.isValid( resource.content ) ) {
 
 
-				processMaterials( Validator.isValid( resource.content ) ? mtlLoader.parse( resource.content ) : null );
+				parseTextWithMtlLoader( resource.content );
 
 
 			} else if ( Validator.isValid( resource.url ) ) {
 			} else if ( Validator.isValid( resource.url ) ) {
 
 
 				var fileLoader = new THREE.FileLoader( this.manager );
 				var fileLoader = new THREE.FileLoader( this.manager );
-				fileLoader.load( resource.url, function ( text ) {
-
-					resource.content = text;
-					processMaterials( mtlLoader.parse( text ) );
-
-				}, this._onProgress, this._onError );
+				fileLoader.load( resource.url, parseTextWithMtlLoader, this._onProgress, this._onError );
 
 
 			}
 			}
 		}
 		}

+ 95 - 8
examples/js/loaders/SVGLoader.js

@@ -221,14 +221,16 @@ THREE.SVGLoader.prototype = {
 						break;
 						break;
 
 
 					case 'A':
 					case 'A':
-						console.warn( command );
 						var numbers = parseFloats( data );
 						var numbers = parseFloats( data );
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
-							// TODO
+							var start = point.clone();
 							point.x = numbers[ j + 5 ];
 							point.x = numbers[ j + 5 ];
 							point.y = numbers[ j + 6 ];
 							point.y = numbers[ j + 6 ];
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
+							parseArcCommand(
+								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
+							);
 						}
 						}
 						break;
 						break;
 
 
@@ -287,6 +289,8 @@ THREE.SVGLoader.prototype = {
 								point.x + numbers[ j + 4 ],
 								point.x + numbers[ j + 4 ],
 								point.y + numbers[ j + 5 ]
 								point.y + numbers[ j + 5 ]
 							);
 							);
+							control.x = point.x + numbers[ j + 2 ];
+							control.y = point.y + numbers[ j + 3 ];
 							point.x += numbers[ j + 4 ];
 							point.x += numbers[ j + 4 ];
 							point.y += numbers[ j + 5 ];
 							point.y += numbers[ j + 5 ];
 						}
 						}
@@ -295,8 +299,6 @@ THREE.SVGLoader.prototype = {
 					case 's':
 					case 's':
 						var numbers = parseFloats( data );
 						var numbers = parseFloats( data );
 						path.bezierCurveTo(
 						path.bezierCurveTo(
-							// TODO: Not sure if point needs
-							// to be added to reflection...
 							getReflection( point.x, control.x ),
 							getReflection( point.x, control.x ),
 							getReflection( point.y, control.y ),
 							getReflection( point.y, control.y ),
 							point.x + numbers[ 0 ],
 							point.x + numbers[ 0 ],
@@ -341,14 +343,16 @@ THREE.SVGLoader.prototype = {
 						break;
 						break;
 
 
 					case 'a':
 					case 'a':
-						console.warn( command );
 						var numbers = parseFloats( data );
 						var numbers = parseFloats( data );
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
-							// TODO
+							var start = point.clone();
 							point.x += numbers[ j + 5 ];
 							point.x += numbers[ j + 5 ];
 							point.y += numbers[ j + 6 ];
 							point.y += numbers[ j + 6 ];
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
+							parseArcCommand(
+								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
+							);
 						}
 						}
 						break;
 						break;
 
 
@@ -372,6 +376,78 @@ THREE.SVGLoader.prototype = {
 
 
 		}
 		}
 
 
+		/**
+		 * https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
+		 * https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ Appendix: Endpoint to center arc conversion
+		 * From
+		 * rx ry x-axis-rotation large-arc-flag sweep-flag x y
+		 * To
+		 * aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation
+		 */
+
+		function parseArcCommand( path, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, start, end ) {
+
+			x_axis_rotation = x_axis_rotation * Math.PI / 180;
+
+			// Ensure radii are positive
+			rx = Math.abs( rx );
+			ry = Math.abs( ry );
+
+			// Compute (x1′, y1′)
+			var dx2 = ( start.x - end.x ) / 2.0;
+			var dy2 = ( start.y - end.y ) / 2.0;
+			var x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
+			var y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;
+
+			// Compute (cx′, cy′)
+			var rxs = rx * rx;
+			var rys = ry * ry;
+			var x1ps = x1p * x1p;
+			var y1ps = y1p * y1p;
+
+			// Ensure radii are large enough
+			var cr = x1ps / rxs + y1ps / rys;
+
+			if ( cr > 1 ) {
+
+				// scale up rx,ry equally so cr == 1
+				var s = Math.sqrt( cr );
+				rx = s * rx;
+				ry = s * ry;
+				rxs = rx * rx;
+				rys = ry * ry;
+
+			}
+
+			var dq = ( rxs * y1ps + rys * x1ps );
+			var pq = ( rxs * rys - dq ) / dq;
+			var q = Math.sqrt( Math.max( 0, pq ) );
+			if ( large_arc_flag === sweep_flag ) q = - q;
+			var cxp = q * rx * y1p / ry;
+			var cyp = - q * ry * x1p / rx;
+
+			// Step 3: Compute (cx, cy) from (cx′, cy′)
+			var cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
+			var cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;
+
+			// Step 4: Compute θ1 and Δθ
+			var theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
+			var delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry ) % ( Math.PI * 2 );
+
+			path.currentPath.absellipse( cx, cy, rx, ry, theta, theta + delta, sweep_flag === 0, x_axis_rotation );
+
+		}
+
+		function svgAngle( ux, uy, vx, vy ) {
+
+			var dot = ux * vx + uy * vy;
+			var len = Math.sqrt( ux * ux + uy * uy ) *  Math.sqrt( vx * vx + vy * vy );
+			var ang = Math.acos( Math.max( -1, Math.min( 1, dot / len ) ) ); // floating point precision, slightly over values appear
+			if ( ( ux * vy - uy * vx ) < 0 ) ang = - ang;
+			return ang;
+
+		}
+
 		/*
 		/*
 		* According to https://www.w3.org/TR/SVG/shapes.html#RectElementRXAttribute
 		* According to https://www.w3.org/TR/SVG/shapes.html#RectElementRXAttribute
 		* rounded corner should be rendered to elliptical arc, but bezier curve does the job well enough
 		* rounded corner should be rendered to elliptical arc, but bezier curve does the job well enough
@@ -544,7 +620,7 @@ THREE.SVGLoader.prototype = {
 
 
 		function getReflection( a, b ) {
 		function getReflection( a, b ) {
 
 
-			return 2 * a - ( b - a );
+			return a - ( b - a );
 
 
 		}
 		}
 
 
@@ -554,7 +630,18 @@ THREE.SVGLoader.prototype = {
 
 
 			for ( var i = 0; i < array.length; i ++ ) {
 			for ( var i = 0; i < array.length; i ++ ) {
 
 
-				array[ i ] = parseFloat( array[ i ] );
+				var number = array[ i ];
+
+				// Handle values like 48.6037.7
+				// TODO Find a regex for this
+
+				if ( number.indexOf( '.' ) !== number.lastIndexOf( '.' ) ) {
+
+					array.splice( i + 1, 0, '0.' + number.split( '.' )[ 2 ] );
+
+				}
+
+				array[ i ] = parseFloat( number );
 
 
 			}
 			}
 
 

+ 19 - 1
examples/js/loaders/VRMLoader.js

@@ -30,7 +30,13 @@ THREE.VRMLoader = ( function () {
 
 
 		load: function ( url, onLoad, onProgress, onError ) {
 		load: function ( url, onLoad, onProgress, onError ) {
 
 
-			this.gltfLoader.load( url, onLoad, onProgress, onError );
+			var scope = this;
+
+			this.gltfLoader.load( url, function ( gltf ) {
+
+				scope.parse( gltf, onLoad );
+
+			}, onProgress, onError );
 
 
 		},
 		},
 
 
@@ -53,6 +59,18 @@ THREE.VRMLoader = ( function () {
 			this.glTFLoader.setDRACOLoader( dracoLoader );
 			this.glTFLoader.setDRACOLoader( dracoLoader );
 			return this;
 			return this;
 
 
+		},
+
+		parse: function ( gltf, onLoad ) {
+
+			var gltfParser = gltf.parser;
+			var gltfExtensions = gltf.userData.gltfExtensions || {};
+			var vrmExtension = gltfExtensions.VRM || {};
+
+			// handle VRM Extension here
+
+			onLoad( gltf );
+
 		}
 		}
 
 
 	};
 	};

+ 1 - 1
examples/js/loaders/sea3d/SEA3DLoader.js

@@ -1211,7 +1211,7 @@ THREE.SEA3D.Dummy = function ( width, height, depth ) {
 	this.height = height != undefined ? height : 100;
 	this.height = height != undefined ? height : 100;
 	this.depth = depth != undefined ? depth : 100;
 	this.depth = depth != undefined ? depth : 100;
 
 
-	var geo = new THREE.BoxGeometry( this.width, this.height, this.depth, 1, 1, 1 );
+	var geo = new THREE.BoxBufferGeometry( this.width, this.height, this.depth, 1, 1, 1 );
 
 
 	geo.computeBoundingBox();
 	geo.computeBoundingBox();
 	geo.computeBoundingSphere();
 	geo.computeBoundingSphere();

+ 2 - 2
examples/js/nodes/InputNode.js

@@ -42,7 +42,7 @@ THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns,
 
 
 			if ( ! data.vertex ) {
 			if ( ! data.vertex ) {
 
 
-				data.vertex = material.createVertexUniform( type, this.value, ns, needsUpdate );
+				data.vertex = material.createVertexUniform( type, this, ns, needsUpdate );
 
 
 			}
 			}
 
 
@@ -52,7 +52,7 @@ THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns,
 
 
 			if ( ! data.fragment ) {
 			if ( ! data.fragment ) {
 
 
-				data.fragment = material.createFragmentUniform( type, this.value, ns, needsUpdate );
+				data.fragment = material.createFragmentUniform( type, this, ns, needsUpdate );
 
 
 			}
 			}
 
 

+ 8 - 8
examples/js/nodes/NodeMaterial.js

@@ -282,16 +282,16 @@ THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
 
 
 };
 };
 
 
-THREE.NodeMaterial.prototype.createUniform = function ( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createUniform = function ( type, node, ns, needsUpdate ) {
 
 
 	var index = this.uniformList.length;
 	var index = this.uniformList.length;
 
 
-	var uniform = {
+	var uniform = new THREE.NodeUniform( {
 		type: type,
 		type: type,
-		value: value,
 		name: ns ? ns : 'nVu' + index,
 		name: ns ? ns : 'nVu' + index,
+		node: node,
 		needsUpdate: needsUpdate
 		needsUpdate: needsUpdate
-	};
+	} );
 
 
 	this.uniformList.push( uniform );
 	this.uniformList.push( uniform );
 
 
@@ -487,9 +487,9 @@ THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
 
 
 };
 };
 
 
-THREE.NodeMaterial.prototype.createVertexUniform = function ( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createVertexUniform = function ( type, node, ns, needsUpdate ) {
 
 
-	var uniform = this.createUniform( type, value, ns, needsUpdate );
+	var uniform = this.createUniform( type, node, ns, needsUpdate );
 
 
 	this.vertexUniform.push( uniform );
 	this.vertexUniform.push( uniform );
 	this.vertexUniform[ uniform.name ] = uniform;
 	this.vertexUniform[ uniform.name ] = uniform;
@@ -500,9 +500,9 @@ THREE.NodeMaterial.prototype.createVertexUniform = function ( type, value, ns, n
 
 
 };
 };
 
 
-THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, value, ns, needsUpdate ) {
+THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, node, ns, needsUpdate ) {
 
 
-	var uniform = this.createUniform( type, value, ns, needsUpdate );
+	var uniform = this.createUniform( type, node, ns, needsUpdate );
 
 
 	this.fragmentUniform.push( uniform );
 	this.fragmentUniform.push( uniform );
 	this.fragmentUniform[ uniform.name ] = uniform;
 	this.fragmentUniform[ uniform.name ] = uniform;

+ 29 - 0
examples/js/nodes/NodeUniform.js

@@ -0,0 +1,29 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.NodeUniform = function ( params ) {
+
+	params = params || {};
+
+	this.name = params.name;
+	this.type = params.type;
+	this.node = params.node;
+	this.needsUpdate = params.needsUpdate;
+
+};
+
+Object.defineProperties( THREE.NodeUniform.prototype, {
+	value: {
+		get: function () {
+
+			return this.node.value;
+
+		},
+		set: function ( val ) {
+
+			this.node.value = val;
+
+		}
+	}
+} );

+ 4 - 4
examples/js/nodes/accessors/CameraNode.js

@@ -150,8 +150,8 @@ THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
 
 
 			var camera = this.camera;
 			var camera = this.camera;
 
 
-			this.near.number = camera.near;
-			this.far.number = camera.far;
+			this.near.value = camera.near;
+			this.far.value = camera.far;
 
 
 			break;
 			break;
 
 
@@ -175,8 +175,8 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
 
 
 			case THREE.CameraNode.DEPTH:
 			case THREE.CameraNode.DEPTH:
 
 
-				data.near = this.near.number;
-				data.far = this.far.number;
+				data.near = this.near.value;
+				data.far = this.far.value;
 
 
 				break;
 				break;
 
 

+ 4 - 19
examples/js/nodes/inputs/FloatNode.js

@@ -6,7 +6,7 @@ THREE.FloatNode = function ( value ) {
 
 
 	THREE.InputNode.call( this, 'fv1' );
 	THREE.InputNode.call( this, 'fv1' );
 
 
-	this.value = [ value || 0 ];
+	this.value = value || 0;
 
 
 };
 };
 
 
@@ -14,26 +14,11 @@ THREE.FloatNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.FloatNode.prototype.constructor = THREE.FloatNode;
 THREE.FloatNode.prototype.constructor = THREE.FloatNode;
 THREE.FloatNode.prototype.nodeType = "Float";
 THREE.FloatNode.prototype.nodeType = "Float";
 
 
-Object.defineProperties( THREE.FloatNode.prototype, {
-	number: {
-		get: function () {
-
-			return this.value[ 0 ];
-
-		},
-		set: function ( val ) {
-
-			this.value[ 0 ] = val;
-
-		}
-	}
-} );
-
 THREE.FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 THREE.FloatNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 
-	var value = this.number;
+	var val = this.value;
 
 
-	return builder.format( Math.floor( value ) !== value ? value : value + ".0", type, output );
+	return builder.format( Math.floor( val ) !== val ? val : val + ".0", type, output );
 
 
 };
 };
 
 
@@ -45,7 +30,7 @@ THREE.FloatNode.prototype.toJSON = function ( meta ) {
 
 
 		data = this.createJSONNode( meta );
 		data = this.createJSONNode( meta );
 
 
-		data.number = this.number;
+		data.value = this.value;
 
 
 		if ( this.readonly === true ) data.readonly = true;
 		if ( this.readonly === true ) data.readonly = true;
 
 

+ 3 - 18
examples/js/nodes/inputs/IntNode.js

@@ -6,7 +6,7 @@ THREE.IntNode = function ( value ) {
 
 
 	THREE.InputNode.call( this, 'iv1' );
 	THREE.InputNode.call( this, 'iv1' );
 
 
-	this.value = [ Math.floor( value || 0 ) ];
+	this.value = Math.floor( value || 0 );
 
 
 };
 };
 
 
@@ -14,24 +14,9 @@ THREE.IntNode.prototype = Object.create( THREE.InputNode.prototype );
 THREE.IntNode.prototype.constructor = THREE.IntNode;
 THREE.IntNode.prototype.constructor = THREE.IntNode;
 THREE.IntNode.prototype.nodeType = "Int";
 THREE.IntNode.prototype.nodeType = "Int";
 
 
-Object.defineProperties( THREE.IntNode.prototype, {
-	number: {
-		get: function () {
-
-			return this.value[ 0 ];
-
-		},
-		set: function ( val ) {
-
-			this.value[ 0 ] = Math.floor( val );
-
-		}
-	}
-} );
-
 THREE.IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 THREE.IntNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
 
 
-	return builder.format( this.number, type, output );
+	return builder.format( this.value, type, output );
 
 
 };
 };
 
 
@@ -43,7 +28,7 @@ THREE.IntNode.prototype.toJSON = function ( meta ) {
 
 
 		data = this.createJSONNode( meta );
 		data = this.createJSONNode( meta );
 
 
-		data.number = this.number;
+		data.value = this.value;
 
 
 		if ( this.readonly === true ) data.readonly = true;
 		if ( this.readonly === true ) data.readonly = true;
 
 

+ 4 - 4
examples/js/nodes/utils/BlurNode.js

@@ -59,15 +59,15 @@ THREE.BlurNode.prototype.updateFrame = function ( frame ) {
 
 
 	if ( this.size ) {
 	if ( this.size ) {
 
 
-		this.horizontal.number = this.radius.x / this.size.x;
-		this.vertical.number = this.radius.y / this.size.y;
+		this.horizontal.value = this.radius.x / this.size.x;
+		this.vertical.value = this.radius.y / this.size.y;
 
 
 	} else if ( this.value.value && this.value.value.image ) {
 	} else if ( this.value.value && this.value.value.image ) {
 
 
 		var image = this.value.value.image;
 		var image = this.value.value.image;
 
 
-		this.horizontal.number = this.radius.x / image.width;
-		this.vertical.number = this.radius.y / image.height;
+		this.horizontal.value = this.radius.x / image.width;
+		this.vertical.value = this.radius.y / image.height;
 
 
 	}
 	}
 
 

+ 3 - 3
examples/js/nodes/utils/TimerNode.js

@@ -42,19 +42,19 @@ THREE.TimerNode.prototype.updateFrame = function ( frame ) {
 
 
 		case THREE.TimerNode.LOCAL:
 		case THREE.TimerNode.LOCAL:
 
 
-			this.number += frame.delta * scale;
+			this.value += frame.delta * scale;
 
 
 			break;
 			break;
 
 
 		case THREE.TimerNode.DELTA:
 		case THREE.TimerNode.DELTA:
 
 
-			this.number = frame.delta * scale;
+			this.value = frame.delta * scale;
 
 
 			break;
 			break;
 
 
 		default:
 		default:
 
 
-			this.number = frame.time * scale;
+			this.value = frame.time * scale;
 
 
 	}
 	}
 
 

+ 2 - 2
examples/js/nodes/utils/VelocityNode.js

@@ -74,7 +74,7 @@ THREE.VelocityNode.prototype.setTarget = function ( target ) {
 
 
 	if ( target ) {
 	if ( target ) {
 
 
-		this.position = target.getWorldPosition();
+		this.position = target.getWorldPosition( this.position || new THREE.Vector3() );
 		this.oldPosition = this.position.clone();
 		this.oldPosition = this.position.clone();
 
 
 	}
 	}
@@ -85,7 +85,7 @@ THREE.VelocityNode.prototype.updateFrameVelocity = function ( frame ) {
 
 
 	if ( this.target ) {
 	if ( this.target ) {
 
 
-		this.position = this.target.getWorldPosition();
+		this.position = this.target.getWorldPosition( this.position || new THREE.Vector3() );
 		this.velocity.subVectors( this.position, this.oldPosition );
 		this.velocity.subVectors( this.position, this.oldPosition );
 		this.oldPosition.copy( this.position );
 		this.oldPosition.copy( this.position );
 
 

+ 2 - 2
examples/js/objects/Reflector.js

@@ -55,8 +55,7 @@ THREE.Reflector = function ( geometry, options ) {
 	var material = new THREE.ShaderMaterial( {
 	var material = new THREE.ShaderMaterial( {
 		uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
 		uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
 		fragmentShader: shader.fragmentShader,
 		fragmentShader: shader.fragmentShader,
-		vertexShader: shader.vertexShader,
-
+		vertexShader: shader.vertexShader
 	} );
 	} );
 
 
 	material.uniforms.tDiffuse.value = renderTarget.texture;
 	material.uniforms.tDiffuse.value = renderTarget.texture;
@@ -64,6 +63,7 @@ THREE.Reflector = function ( geometry, options ) {
 	material.uniforms.textureMatrix.value = textureMatrix;
 	material.uniforms.textureMatrix.value = textureMatrix;
 
 
 	this.material = material;
 	this.material = material;
+	this.renderOrder = - Infinity; // render first
 
 
 	this.onBeforeRender = function ( renderer, scene, camera ) {
 	this.onBeforeRender = function ( renderer, scene, camera ) {
 
 

+ 0 - 2
examples/js/objects/ReflectorRTT.js

@@ -4,8 +4,6 @@ THREE.ReflectorRTT = function ( geometry, options ) {
 
 
 	this.geometry.setDrawRange( 0, 0 ); // avoid rendering geometry
 	this.geometry.setDrawRange( 0, 0 ); // avoid rendering geometry
 
 
-	this.renderOrder = -Infinity; // render RTT first
-
 };
 };
 
 
 THREE.ReflectorRTT.prototype = Object.create( THREE.Reflector.prototype );
 THREE.ReflectorRTT.prototype = Object.create( THREE.Reflector.prototype );

+ 1 - 7
examples/js/pmrem/PMREMCubeUVPacker.js

@@ -178,13 +178,7 @@ THREE.PMREMCubeUVPacker.prototype = {
 					gl_FragColor = linearToOutputTexel( color );\
 					gl_FragColor = linearToOutputTexel( color );\
 				}",
 				}",
 
 
-			blending: THREE.CustomBlending,
-			premultipliedAlpha: false,
-			blendSrc: THREE.OneFactor,
-			blendDst: THREE.ZeroFactor,
-			blendSrcAlpha: THREE.OneFactor,
-			blendDstAlpha: THREE.ZeroFactor,
-			blendEquation: THREE.AddEquation
+			blending: THREE.NoBlending
 
 
 		} );
 		} );
 
 

+ 2 - 8
examples/js/pmrem/PMREMGenerator.js

@@ -53,7 +53,7 @@ THREE.PMREMGenerator = function ( sourceTexture, samplesPerLevel, resolution ) {
 
 
 	this.shader = this.getShader();
 	this.shader = this.getShader();
 	this.shader.defines[ 'SAMPLES_PER_LEVEL' ] = this.samplesPerLevel;
 	this.shader.defines[ 'SAMPLES_PER_LEVEL' ] = this.samplesPerLevel;
-	this.planeMesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2, 0 ), this.shader );
+	this.planeMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2, 0 ), this.shader );
 	this.planeMesh.material.side = THREE.DoubleSide;
 	this.planeMesh.material.side = THREE.DoubleSide;
 	this.scene = new THREE.Scene();
 	this.scene = new THREE.Scene();
 	this.scene.add( this.planeMesh );
 	this.scene.add( this.planeMesh );
@@ -259,13 +259,7 @@ THREE.PMREMGenerator.prototype = {
 					gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\
 					gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\
 				}",
 				}",
 
 
-			blending: THREE.CustomBlending,
-			premultipliedAlpha: false,
-			blendSrc: THREE.OneFactor,
-			blendDst: THREE.ZeroFactor,
-			blendSrcAlpha: THREE.OneFactor,
-			blendDstAlpha: THREE.ZeroFactor,
-			blendEquation: THREE.AddEquation
+			blending: THREE.NoBlending
 
 
 		} );
 		} );
 
 

+ 62 - 0
examples/js/renderers/CSS2DRenderer.js

@@ -37,6 +37,10 @@ THREE.CSS2DRenderer = function () {
 	var viewMatrix = new THREE.Matrix4();
 	var viewMatrix = new THREE.Matrix4();
 	var viewProjectionMatrix = new THREE.Matrix4();
 	var viewProjectionMatrix = new THREE.Matrix4();
 
 
+	var cache = {
+		objects: new WeakMap()
+	};
+
 	var domElement = document.createElement( 'div' );
 	var domElement = document.createElement( 'div' );
 	domElement.style.overflow = 'hidden';
 	domElement.style.overflow = 'hidden';
 
 
@@ -79,6 +83,12 @@ THREE.CSS2DRenderer = function () {
 			element.style.oTransform = style;
 			element.style.oTransform = style;
 			element.style.transform = style;
 			element.style.transform = style;
 
 
+			var objectData = {
+				distanceToCameraSquared: getDistanceToSquared( camera, object )
+			};
+
+			cache.objects.set( object, objectData );
+
 			if ( element.parentNode !== domElement ) {
 			if ( element.parentNode !== domElement ) {
 
 
 				domElement.appendChild( element );
 				domElement.appendChild( element );
@@ -95,6 +105,57 @@ THREE.CSS2DRenderer = function () {
 
 
 	};
 	};
 
 
+	var getDistanceToSquared = function () {
+
+		var a = new THREE.Vector3();
+		var b = new THREE.Vector3();
+
+		return function ( object1, object2 ) {
+
+			a.setFromMatrixPosition( object1.matrixWorld );
+			b.setFromMatrixPosition( object2.matrixWorld );
+
+			return a.distanceToSquared( b );
+
+		};
+
+	}();
+
+	var filterAndFlatten = function ( scene ) {
+
+		var result = [];
+
+		scene.traverse( function ( object ) {
+
+			if ( object instanceof THREE.CSS2DObject ) result.push( object );
+
+		} );
+
+		return result;
+
+	};
+
+	var zOrder = function ( scene ) {
+
+		var sorted = filterAndFlatten( scene ).sort( function ( a, b ) {
+
+			var distanceA = cache.objects.get( a ).distanceToCameraSquared;
+			var distanceB = cache.objects.get( b ).distanceToCameraSquared;
+
+			return distanceA - distanceB;
+
+		} );
+
+		var zMax = sorted.length;
+
+		for ( var i = 0, l = sorted.length; i < l; i ++ ) {
+
+			sorted[ i ].element.style.zIndex = zMax - i;
+
+		}
+
+	};
+
 	this.render = function ( scene, camera ) {
 	this.render = function ( scene, camera ) {
 
 
 		scene.updateMatrixWorld();
 		scene.updateMatrixWorld();
@@ -105,6 +166,7 @@ THREE.CSS2DRenderer = function () {
 		viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, viewMatrix );
 		viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, viewMatrix );
 
 
 		renderObject( scene, camera );
 		renderObject( scene, camera );
+		zOrder( scene );
 
 
 	};
 	};
 
 

+ 46 - 12
examples/js/shaders/BokehShader2.js

@@ -142,14 +142,6 @@ THREE.BokehShader = {
 
 
 		"//------------------------------------------",
 		"//------------------------------------------",
 
 
-		"float getDepth( const in vec2 screenPosition ) {",
-		"	#if DEPTH_PACKING == 1",
-		"	return unpackRGBAToDepth( texture2D( tDepth, screenPosition ) );",
-		"	#else",
-		"	return texture2D( tDepth, screenPosition ).x;",
-		"	#endif",
-		"}",
-
 		"float penta(vec2 coords) {",
 		"float penta(vec2 coords) {",
 			"//pentagonal shape",
 			"//pentagonal shape",
 			"float scale = float(rings) - 1.3;",
 			"float scale = float(rings) - 1.3;",
@@ -211,7 +203,7 @@ THREE.BokehShader = {
 
 
 
 
 			"for( int i=0; i<9; i++ ) {",
 			"for( int i=0; i<9; i++ ) {",
-				"float tmp = getDepth( coords + offset[ i ] );",
+				"float tmp = texture2D(tDepth, coords + offset[i]).r;",
 				"d += tmp * kernel[i];",
 				"d += tmp * kernel[i];",
 			"}",
 			"}",
 
 
@@ -273,10 +265,10 @@ THREE.BokehShader = {
 		"void main() {",
 		"void main() {",
 			"//scene depth calculation",
 			"//scene depth calculation",
 
 
-			"float depth = linearize( getDepth( vUv.xy ) );",
+			"float depth = linearize(texture2D(tDepth,vUv.xy).x);",
 
 
 			"// Blur depth?",
 			"// Blur depth?",
-			"if (depthblur) {",
+			"if ( depthblur ) {",
 				"depth = linearize(bdepth(vUv.xy));",
 				"depth = linearize(bdepth(vUv.xy));",
 			"}",
 			"}",
 
 
@@ -286,7 +278,7 @@ THREE.BokehShader = {
 
 
 			"if (shaderFocus) {",
 			"if (shaderFocus) {",
 
 
-				"fDepth = linearize( getDepth( focusCoords ) );",
+				"fDepth = linearize(texture2D(tDepth,focusCoords).x);",
 
 
 			"}",
 			"}",
 
 
@@ -363,3 +355,45 @@ THREE.BokehShader = {
 	].join( "\n" )
 	].join( "\n" )
 
 
 };
 };
+
+THREE.BokehDepthShader = {
+
+	uniforms: {
+
+		"mNear": { value: 1.0 },
+		"mFar": { value: 1000.0 },
+
+	},
+
+	vertexShader: [
+
+		"varying float vViewZDepth;",
+
+		"void main() {",
+
+		"	#include <begin_vertex>",
+		"	#include <project_vertex>",
+
+		"	vViewZDepth = - mvPosition.z;",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"uniform float mNear;",
+		"uniform float mFar;",
+
+		"varying float vViewZDepth;",
+
+		"void main() {",
+
+		"	float color = 1.0 - smoothstep( mNear, mFar, vViewZDepth );",
+		"	gl_FragColor = vec4( vec3( color ), 1.0 );",
+
+		"} "
+
+	].join( "\n" )
+
+};

+ 88 - 5
examples/js/vr/WebVR.js

@@ -7,9 +7,9 @@
 
 
 var WEBVR = {
 var WEBVR = {
 
 
-	createButton: function ( renderer ) {
+	createButton: function ( renderer, options ) {
 
 
-		function showEnterVR( display ) {
+		function showEnterVR( device ) {
 
 
 			button.style.display = '';
 			button.style.display = '';
 
 
@@ -24,11 +24,71 @@ var WEBVR = {
 
 
 			button.onclick = function () {
 			button.onclick = function () {
 
 
-				display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] );
+				device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
 
 
 			};
 			};
 
 
-			renderer.vr.setDevice( display );
+			renderer.vr.setDevice( device );
+
+		}
+
+		function showEnterXR( device ) {
+
+			var currentSession = null;
+
+			function onSessionStarted( session ) {
+
+				if ( options === undefined ) options = {};
+				if ( options.frameOfReferenceType === undefined ) options.frameOfReferenceType = 'stage';
+
+				session.addEventListener( 'end', onSessionEnded );
+
+				renderer.vr.setSession( session, options );
+				button.textContent = 'EXIT XR';
+
+				currentSession = session;
+
+			}
+
+			function onSessionEnded( event ) {
+
+				currentSession.removeEventListener( 'end', onSessionEnded );
+
+				renderer.vr.setSession( null );
+				button.textContent = 'ENTER XR';
+
+				currentSession = null;
+
+			}
+
+			//
+
+			button.style.display = '';
+
+			button.style.cursor = 'pointer';
+			button.style.left = 'calc(50% - 50px)';
+			button.style.width = '100px';
+
+			button.textContent = 'ENTER XR';
+
+			button.onmouseenter = function () { button.style.opacity = '1.0'; };
+			button.onmouseleave = function () { button.style.opacity = '0.5'; };
+
+			button.onclick = function () {
+
+				if ( currentSession === null ) {
+
+					device.requestSession( { exclusive: true } ).then( onSessionStarted );
+
+				} else {
+
+					currentSession.end();
+
+				}
+
+			};
+
+			renderer.vr.setDevice( device );
 
 
 		}
 		}
 
 
@@ -68,7 +128,30 @@ var WEBVR = {
 
 
 		}
 		}
 
 
-		if ( 'getVRDisplays' in navigator ) {
+		var isWebXR = false;
+
+		if ( 'xr' in navigator ) {
+
+			isWebXR = true;
+
+			var button = document.createElement( 'button' );
+			button.style.display = 'none';
+
+			stylizeElement( button );
+
+			navigator.xr.requestDevice().then( function ( device ) {
+
+				device.supportsSession( { exclusive: true } ).then( function () {
+
+					showEnterXR( device );
+
+				} ).catch( showVRNotFound );
+
+			} ).catch( showVRNotFound );
+
+			return button;
+
+		} else if ( 'getVRDisplays' in navigator ) {
 
 
 			var button = document.createElement( 'button' );
 			var button = document.createElement( 'button' );
 			button.style.display = 'none';
 			button.style.display = 'none';

+ 26 - 24
examples/misc_exporter_obj.html

@@ -81,15 +81,15 @@
 
 
 			function addGeometry( type ) {
 			function addGeometry( type ) {
 
 
-				for( var i = 0; i < scene.children.length; i++ ) {
+				for( var i = 0; i < scene.children.length; i ++ ) {
 
 
-					var current = scene.children[ i ];
+					var child = scene.children[ i ];
 
 
-					if( current instanceof THREE.Mesh ) {
+					if( child.isMesh ) {
 
 
-						current.geometry.dispose();
-						scene.remove( current );
-						i--;
+						child.geometry.dispose();
+						scene.remove( child );
+						i --;
 
 
 					}
 					}
 
 
@@ -98,14 +98,7 @@
 				if ( type === 1 ) {
 				if ( type === 1 ) {
 
 
 					var material = new THREE.MeshLambertMaterial( { color : 0x00cc00 } );
 					var material = new THREE.MeshLambertMaterial( { color : 0x00cc00 } );
-
-					var geometry = new THREE.Geometry();
-					geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
-					geometry.vertices.push( new THREE.Vector3(  50, -50, 0 ) );
-					geometry.vertices.push( new THREE.Vector3(  50,  50, 0 ) );
-					var face = new THREE.Face3( 0, 1, 2 );
-					geometry.faces.push( face );
-					geometry.computeFaceNormals();
+					var geometry = generateTriangleGeometry();
 
 
 					scene.add( new THREE.Mesh( geometry, material ) );
 					scene.add( new THREE.Mesh( geometry, material ) );
 
 
@@ -125,14 +118,7 @@
 				} else if ( type === 4 || type === 5 ) {
 				} else if ( type === 4 || type === 5 ) {
 
 
 					var material = new THREE.MeshLambertMaterial( { color : 0x00cc00 } );
 					var material = new THREE.MeshLambertMaterial( { color : 0x00cc00 } );
-
-					var geometry = new THREE.Geometry();
-					geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
-					geometry.vertices.push( new THREE.Vector3(  50, -50, 0 ) );
-					geometry.vertices.push( new THREE.Vector3(  50,  50, 0 ) );
-					var face = new THREE.Face3( 0, 1, 2 );
-					geometry.faces.push( face );
-					geometry.computeFaceNormals();
+					var geometry = generateTriangleGeometry()
 
 
 					var mesh = new THREE.Mesh( geometry, material );
 					var mesh = new THREE.Mesh( geometry, material );
 					mesh.position.x = -200;
 					mesh.position.x = -200;
@@ -244,8 +230,8 @@
 
 
 				requestAnimationFrame( animate );
 				requestAnimationFrame( animate );
 
 
-				camera.position.x += ( mouseX - camera.position.x ) * .05;
-				camera.position.y += ( -mouseY - camera.position.y ) * .05;
+				camera.position.x += ( mouseX - camera.position.x ) * 0.05;
+				camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
 				camera.lookAt( scene.position );
 				camera.lookAt( scene.position );
 
 
 				light.position.set( camera.position.x, camera.position.y, camera.position.z ).normalize();
 				light.position.set( camera.position.x, camera.position.y, camera.position.z ).normalize();
@@ -253,6 +239,22 @@
 
 
 			}
 			}
 
 
+			function generateTriangleGeometry() {
+
+				var geometry = new THREE.BufferGeometry();
+				var vertices = [];
+
+				vertices.push( - 50, - 50, 0 );
+				vertices.push( 50, - 50, 0 );
+				vertices.push( 50, 50, 0 );
+
+				geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+				geometry.computeVertexNormals();
+
+				return geometry;
+
+			}
+
 			init();
 			init();
 			animate();
 			animate();
 
 

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