Explorar o código

Merge branch 'dev' of [email protected]:mrdoob/three.js into tmp

Ben Houston %!s(int64=9) %!d(string=hai) anos
pai
achega
a600e3700f
Modificáronse 100 ficheiros con 4958 adicións e 2618 borrados
  1. 253 383
      build/three.js
  2. 341 297
      build/three.min.js
  3. 0 1
      docs/api/cameras/OrthographicCamera.html
  4. 1 2
      docs/api/constants/Materials.html
  5. 1 8
      docs/api/core/Geometry.html
  6. 2 2
      docs/api/core/Object3D.html
  7. 3 3
      docs/api/core/Raycaster.html
  8. 2 2
      docs/api/examples/SpriteCanvasMaterial.html
  9. 2 2
      docs/api/extras/geometries/TextGeometry.html
  10. 1 7
      docs/api/lights/DirectionalLight.html
  11. 0 6
      docs/api/lights/SpotLight.html
  12. 1 1
      docs/api/loaders/ColladaLoader.html
  13. 77 89
      docs/api/loaders/JSONLoader.html
  14. 1 1
      docs/api/loaders/MTLLoader.html
  15. 8 14
      docs/api/materials/MeshLambertMaterial.html
  16. 16 16
      docs/api/materials/MeshPhongMaterial.html
  17. 2 2
      docs/api/materials/PointsMaterial.html
  18. 21 46
      docs/api/materials/ShaderMaterial.html
  19. 9 9
      docs/api/math/Box2.html
  20. 14 14
      docs/api/math/Box3.html
  21. 7 16
      docs/api/math/Math.html
  22. 1 1
      docs/api/math/Matrix4.html
  23. 4 4
      docs/api/math/Plane.html
  24. 9 9
      docs/api/math/Ray.html
  25. 6 6
      docs/api/objects/Points.html
  26. 161 161
      docs/api/renderers/CanvasRenderer.html
  27. 1 1
      docs/index.html
  28. 5 6
      docs/list.js
  29. 32 30
      docs/scenes/geometry-browser.html
  30. 99 100
      docs/scenes/js/geometry.js
  31. 1 3
      docs/scenes/js/material.js
  32. 1 0
      editor/css/dark.css
  33. 1 0
      editor/css/light.css
  34. 12 0
      editor/css/main.css
  35. 12 19
      editor/index.html
  36. 1 0
      editor/js/Config.js
  37. 3 9
      editor/js/Editor.js
  38. 41 8
      editor/js/Loader.js
  39. 2 0
      editor/js/Menubar.Add.js
  40. 21 21
      editor/js/Menubar.File.js
  41. 10 6
      editor/js/Menubar.Status.js
  42. 4 0
      editor/js/Sidebar.Animation.js
  43. 23 3
      editor/js/Sidebar.Geometry.CircleGeometry.js
  44. 48 1
      editor/js/Sidebar.Material.js
  45. 67 2
      editor/js/Sidebar.Object3D.js
  46. 43 16
      editor/js/Sidebar.Project.js
  47. 2 2
      editor/js/Storage.js
  48. 7 8
      editor/js/Toolbar.js
  49. 5 1
      editor/js/Viewport.js
  50. 21 21
      editor/js/libs/app.js
  51. 3 163
      editor/js/libs/tern-threejs/threejs.js
  52. 103 74
      editor/js/libs/ui.js
  53. 1 1
      examples/canvas_geometry_panorama_fisheye.html
  54. 8 4
      examples/canvas_geometry_text.html
  55. 2 2
      examples/canvas_interactive_cubes.html
  56. 2 2
      examples/canvas_interactive_cubes_tween.html
  57. 2 2
      examples/canvas_interactive_voxelpainter.html
  58. 0 1
      examples/canvas_materials.html
  59. 0 238
      examples/canvas_materials_depth.html
  60. 10 4
      examples/canvas_morphtargets_horse.html
  61. 4 6
      examples/css3d_youtube.html
  62. 21 15
      examples/index.html
  63. 0 170
      examples/js/AudioObject.js
  64. 9 9
      examples/js/BlendCharacter.js
  65. 1 1
      examples/js/GPUParticleSystem.js
  66. 5 5
      examples/js/MD2Character.js
  67. 2 2
      examples/js/MD2CharacterComplex.js
  68. 1 3
      examples/js/MarchingCubes.js
  69. 2 2
      examples/js/MorphAnimMesh.js
  70. 54 60
      examples/js/ShaderSkin.js
  71. 1 1
      examples/js/UCSCharacter.js
  72. 2 2
      examples/js/controls/EditorControls.js
  73. 2 2
      examples/js/controls/OrbitControls.js
  74. 3 3
      examples/js/controls/OrthographicTrackballControls.js
  75. 2 2
      examples/js/controls/TrackballControls.js
  76. 54 13
      examples/js/controls/TransformControls.js
  77. 1 1
      examples/js/geometries/TeapotBufferGeometry.js
  78. 0 0
      examples/js/geometries/TextGeometry.js
  79. 674 0
      examples/js/libs/earcut.js
  80. 0 0
      examples/js/libs/jszip.min.js
  81. 502 0
      examples/js/loaders/AMFLoader.js
  82. 1 1
      examples/js/loaders/AWDLoader.js
  83. 1 1
      examples/js/loaders/BabylonLoader.js
  84. 22 0
      examples/js/loaders/BinaryLoader.js
  85. 3 5
      examples/js/loaders/ColladaLoader.js
  86. 865 0
      examples/js/loaders/ColladaLoader2.js
  87. 54 0
      examples/js/loaders/KMZLoader.js
  88. 1 1
      examples/js/loaders/MD2Loader.js
  89. 2 8
      examples/js/loaders/MTLLoader.js
  90. 1 1
      examples/js/loaders/SVGLoader.js
  91. 1 1
      examples/js/loaders/UTF8Loader.js
  92. 146 32
      examples/js/loaders/VRMLLoader.js
  93. 1 1
      examples/js/loaders/VTKLoader.js
  94. 20 1
      examples/js/loaders/ctm/CTMLoader.js
  95. 716 258
      examples/js/loaders/sea3d/SEA3D.js
  96. 244 152
      examples/js/loaders/sea3d/SEA3DLoader.js
  97. 2 2
      examples/js/math/Lut.js
  98. 0 5
      examples/js/postprocessing/GlitchPass.js
  99. 1 1
      examples/js/renderers/CSS3DRenderer.js
  100. 1 1
      examples/js/renderers/CSS3DStereoRenderer.js

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 253 - 383
build/three.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 341 - 297
build/three.min.js


+ 0 - 1
docs/api/cameras/OrthographicCamera.html

@@ -22,7 +22,6 @@
 		<div>[example:webgl_camera camera ]</div>
 		<div>[example:webgl_interactive_cubes_ortho interactive / cubes / ortho ]</div>
 		<div>[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]</div>
-		<div>[example:webgl_materials_normaldisplacementmap materials / normaldisplacementmap ]</div>
 		<div>[example:webgl_postprocessing_advanced postprocessing / advanced ]</div>
 		<div>[example:webgl_postprocessing_dof2 postprocessing / dof2 ]</div>
 		<div>[example:webgl_postprocessing_godrays postprocessing / godrays ]</div>

+ 1 - 2
docs/api/constants/Materials.html

@@ -19,7 +19,6 @@
 
 		<h2>Shading</h2>
 		<div>
-		THREE.NoShading<br />
 		THREE.FlatShading<br />
 		THREE.SmoothShading
 		</div>
@@ -40,7 +39,7 @@
 		THREE.MultiplyBlending<br />
 		THREE.CustomBlending
 		</div>
-	
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]

+ 1 - 8
docs/api/core/Geometry.html

@@ -62,7 +62,7 @@
 		<h3>[property:Array colors]</h3>
 		<div>
 		Array of vertex [page:Color colors], matching number and order of vertices.<br />
-		Used in [page:PointCloud] and [page:Line].<br />
+		Used in [page:Points] and [page:Line].<br />
 		[page:Mesh Meshes] use per-face-use-of-vertex colors embedded directly in faces.<br />
 		To signal an update in this array, [page:Geometry Geometry.colorsNeedUpdate] needs to be set to true.
 		</div>
@@ -88,13 +88,6 @@
 		Morph vertices match number and order of primary vertices.
 		</div>
 
-		<h3>[property:Array morphColors]</h3>
-		<div>
-		Array of morph colors. Morph colors have similar structure as morph targets, each color set is a Javascript object:
-		<code>morphColor = { name: "colorName", colors: [ new THREE.Color(), ... ] }</code>
-		Morph colors can match either the number and order of faces (face colors) or the number of vertices (vertex colors).
-		</div>
-
 		<h3>[property:Array morphNormals]</h3>
 		<div>
 		Array of morph normals. Morph normals have similar structure as morph targets, each normal set is a Javascript object:

+ 2 - 2
docs/api/core/Object3D.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -300,7 +300,7 @@
 
 		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
 		<div>
-		Abstract method to get intersections between a casted ray and this object. Subclasses such as [page:Mesh], [page:Line], and [page:PointCloud] implement this method in order to participate in raycasting.
+		Abstract method to get intersections between a casted ray and this object. Subclasses such as [page:Mesh], [page:Line], and [page:Points] implement this method in order to participate in raycasting.
 		</div>
 
 		<h2>Source</h2>

+ 3 - 3
docs/api/core/Raycaster.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -56,7 +56,7 @@
 			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera], 
 			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry], 
 			[example:webgl_interactive_lines Raycasting to a Line], 
-			[example:webgl_interactive_raycasting_pointcloud Raycasting to a PointCloud], 
+			[example:webgl_interactive_raycasting_pointcloud Raycasting to a Points], 
 			[example:webgl_geometry_terrain_raycast Terrain raycasting], 
 			[example:webgl_octree_raycasting Raycasting using an octree],
 			[example:webgl_interactive_voxelpainter Raycasting to paint voxels]</div>
@@ -149,7 +149,7 @@
         When intersecting a [page:Mesh] with a [page:BufferGeometry], the *faceIndex* will be *undefined*, and *indices* will be set; when intersecting a [page:Mesh] with a [page:Geometry], *indices* will be *undefined*. 
         </p>
 		<p>
-		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:PointCloud pointclouds].
+		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:Points pointclouds].
 		</p>
 		<p>
 		*Note* that for meshes, faces must be pointed towards the origin of the [page:.ray ray] in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the [page:Mesh.material material]'s [page:Material.side side] property to *THREE.DoubleSide*.  

+ 2 - 2
docs/api/materials/SpriteCanvasMaterial.html → docs/api/examples/SpriteCanvasMaterial.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -52,6 +52,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/renderers/CanvasRenderer.js examples/js/renderers/CanvasRenderer.js]
 	</body>
 </html>

+ 2 - 2
docs/api/extras/geometries/TextGeometry.html

@@ -93,13 +93,13 @@
 				<td>/examples/fonts/gentilis_bold.typeface.js</td>
 			</tr>
 			<tr>
-				<td>driod sans</td>
+				<td>droid sans</td>
 				<td>normal</td>
 				<td>normal</td>
 				<td>/examples/fonts/droid/droid_sans_regular.typeface.js</td>
 			</tr>
 			<tr>
-				<td>driod sans</td>
+				<td>droid sans</td>
 				<td>bold</td>
 				<td>normal</td>
 				<td>/examples/fonts/droid/droid_sans_bold.typeface.js</td>

+ 1 - 7
docs/api/lights/DirectionalLight.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -123,12 +123,6 @@ scene.add( directionalLight );</code>
 			Default — *0*.
 		</div>
 
-		<h3>[property:Float shadowDarkness]</h3>
-		<div>
-			Darkness of shadow casted by this light (from *0* to *1*).<br />
-			Default — *0.5*.
-		</div>
-
 		<h3>[property:Integer shadowMapWidth]</h3>
 		<div>
 			Shadow map texture width in pixels.<br />

+ 0 - 6
docs/api/lights/SpotLight.html

@@ -146,12 +146,6 @@
 			Default — *0*.
 		</div>
 
-		<h3>[property:Float shadowDarkness]</h3>
-		<div>
-			Darkness of shadow casted by this light (from *0* to *1*).<br />
-			Default — *0.5*.
-		</div>
-
 		<h3>[property:Integer shadowMapWidth]</h3>
 		<div>
 			Shadow map texture width in pixels.<br />

+ 1 - 1
docs/api/loaders/ColladaLoader.html

@@ -67,7 +67,7 @@
 		</div>
 		<div>
 		Set the .[page:Integer shading] property on the resource's materials.<br />
-		Options are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading].
+		Options are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading].
 		</div>
 
 		<h3>[method:null applySkin]( [page:Geometry geometry], [page:Object instanceCtrl], [page:Integer frame] )</h3>

+ 77 - 89
docs/api/loaders/JSONLoader.html

@@ -1,90 +1,78 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
+<!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>
-
-		<div class="desc">A loader for loading objects in JSON format.</div>
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]()</h3>
-		<div>
-		Creates a new [name].
-		</div>
-
-
-		<h2>Properties</h2>
-
-		<h3>[property:boolean withCredentials]</h3>
-		<div>
-		If true, the ajax request will use cookies.
-		</div>
-
-
-		<h2>Methods</h2>
-
-		<h3>[method:null load]( [page:String url], [page:Function callback], [page:String texturePath] )</h3>
-		<div>
-		[page:String url] — required<br />
-		[page:Function callback] — required. Will be called when load completes. The arguments will be the loaded [page:Object3D] and the loaded [page:Array materials].<br />
-		[page:String texturePath] — optional. If not specified, textures will be assumed to be in the same folder as the Javascript model file.
-		</div>
-
-		<h3>[method:null loadAjaxJSON]([page:JSONLoader context], [page:String url], [page:Function callback], [page:String texturePath], [page:Function callbackProgress])</h3>
-		<div>
-		[page:JSONLoader context] — The [page:JSONLoader] instance<br />
-		[page:String url] — required<br />
-		[page:Function callback] — required. This function will be called with the loaded model as an instance of [page:Geometry geometry] when the load is completed.<br />
-		[page:String texturePath] — Base path for textures.<br />
-		[page:Function callbackProgress] — Will be called while load progresses. The argument will be an [page:Object] containing two attributes: .[page:Integer total] and .[page:Integer loaded] bytes.
-		</div>
-		<div>
-		Begin loading from url and call <em>callback</em> with the parsed response content.
-		</div>
-
-		<h3>[method:Object3D parse]( [page:Object json], [page:String texturePath] )</h3>
-		<div>
-		[page:String json] — JSON object to parse.<br />
-		[page:String texturePath] — Base path for textures.
-		</div>
-		<div>
-		Parse a <em>JSON</em> structure and return an [page:Object] containing the parsed .[page:Geometry] and .[page:Array materials].
-		</div>
-
-
-		<h2>Example</h2>
-
-		<code>
-		// instantiate a loader
-		var loader = new THREE.JSONLoader();
-
-		// load a resource
-		loader.load(
-			// resource URL
-			'models/animated/monster/monster.js',
-			// Function when resource is loaded
-			function ( geometry, materials ) {
-				var material = new THREE.MeshFaceMaterial( materials );
-				var object = new THREE.Mesh( geometry, material );
-				scene.add( object );
-			}
-		);
-		</code>
-
-		[example:webgl_loader_json_blender]
-
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-	</body>
-</html>
+		<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>
+
+		<div class="desc">A loader for loading objects in JSON format.</div>
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]()</h3>
+		<div>
+		Creates a new [name].
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>[property:boolean withCredentials]</h3>
+		<div>
+		If true, the ajax request will use cookies.
+		</div>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null load]( [page:String url], [page:Function callback], [page:String texturePath] )</h3>
+		<div>
+		[page:String url] — required<br />
+		[page:Function callback] — required. Will be called when load completes. The arguments will be the loaded [page:Object3D] and the loaded [page:Array materials].<br />
+		[page:String texturePath] — optional. If not specified, textures will be assumed to be in the same folder as the Javascript model file.
+		</div>
+
+		<h3>[method:Object3D parse]( [page:Object json], [page:String texturePath] )</h3>
+		<div>
+		[page:String json] — JSON object to parse.<br />
+		[page:String texturePath] — Base path for textures.
+		</div>
+		<div>
+		Parse a <em>JSON</em> structure and return an [page:Object] containing the parsed .[page:Geometry] and .[page:Array materials].
+		</div>
+
+
+		<h2>Example</h2>
+
+		<code>
+		// instantiate a loader
+		var loader = new THREE.JSONLoader();
+
+		// load a resource
+		loader.load(
+			// resource URL
+			'models/animated/monster/monster.js',
+			// Function when resource is loaded
+			function ( geometry, materials ) {
+				var material = new THREE.MeshFaceMaterial( materials );
+				var object = new THREE.Mesh( geometry, material );
+				scene.add( object );
+			}
+		);
+		</code>
+
+		[example:webgl_loader_json_blender]
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 1 - 1
docs/api/loaders/MTLLoader.html

@@ -1,4 +1,4 @@
-<!D]OCTYPE html>
+<!DOCTYPE html>
 <html lang="en">
 	<head>
 		<meta charset="utf-8" />

+ 8 - 14
docs/api/materials/MeshLambertMaterial.html

@@ -13,7 +13,7 @@
 		<h1>[name]</h1>
 
 		<div class="desc">A material for non-shiny (Lambertian) surfaces, evaluated per vertex.</div>
-		
+
 		<iframe src='scenes/material-browser.html#MeshLambertMaterial'></iframe>
 
 		<h2>Constructor</h2>
@@ -30,7 +30,6 @@
 		alphaMap — Set alpha map. Default is null.<br />
 		envMap — Set env map. Default is null.<br />
 		fog — Define whether the material color is affected by global fog settings. Default is false.<br />
-		shading — How the triangles of a curved surface are rendered. Default is [page:Materials THREE.SmoothShading].<br/>
 		wireframe — Render geometry as wireframe. Default is false (i.e. render as smooth shaded).<br/>
 		wireframeLinewidth — Controls wireframe thickness. Default is 1.<br/>
 		wireframeLinecap — Define appearance of line ends. Default is 'round'.<br />
@@ -68,12 +67,12 @@
 		<div>Set env map. Default is null.</div>
 
 		<h3>[property:Integer combine]</h3>
-		<div>How to combine the result of the surface's color with the environment map, if any.</div> 
-		 
+		<div>How to combine the result of the surface's color with the environment map, if any.</div>
+
 		<div>Options are [page:Textures THREE.Multiply] (default), [page:Textures THREE.MixOperation], [page:Textures THREE.AddOperation]. If mix is chosen, the reflectivity is used to blend between the two colors.</div>
-		 
+
 		<h3>[property:Float reflectivity]</h3>
-		<div>How much the environment map affects the surface; also see "combine".</div> 
+		<div>How much the environment map affects the surface; also see "combine".</div>
 
 		<h3>[property:Float refractionRatio]</h3>
 		<div>The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.</div>
@@ -82,14 +81,9 @@
 		<div>Define whether the material color is affected by global fog settings. Default is *true*.</div>
 		<div>This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.</div>
 
-		<h3>[property:Integer shading]</h3>
-		<div>How the triangles of a curved surface are rendered: as a smooth surface, as flat separate facets, or no shading at all.</div>
-
-		<div>Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading].</div>
-		
 		<h3>[property:Boolean wireframe]</h3>
 		<div>Whether the triangles' edges are displayed instead of surfaces. Default is *false*.</div>
-		
+
 		<h3>[property:Float wireframeLinewidth]</h3>
 		<div>Line thickness for wireframe mode. Default is *1.0*.</div>
 		<div>Due to limitations in the <a href="https://code.google.com/p/angleproject/" target="_blank">ANGLE layer</a>, on Windows platforms linewidth will always be 1 regardless of the set value.</div>
@@ -108,9 +102,9 @@
 
 		<h3>[property:Boolean skinning]</h3>
 		<div>Define whether the material uses skinning. Default is *false*.</div>
-	
+
 		<h3>[property:Boolean morphTargets]</h3>
-		<div>Define whether the material uses morphTargets. Default is *false*.</div>	
+		<div>Define whether the material uses morphTargets. Default is *false*.</div>
 
 		<h3>[property:boolean morphNormals]</h3>
 		<div>

+ 16 - 16
docs/api/materials/MeshPhongMaterial.html

@@ -45,7 +45,7 @@
 		<div>
 		Example:<br>
 		materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) );
-	
+
 		</div>
 
 
@@ -68,14 +68,14 @@
 		</div>
 
 		<h3>[property:Float shininess]</h3>
-		<div>How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*. It should not be set to 0.</div>
+		<div>How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*.</div>
 
 		<h3>[property:boolean metal]</h3>
 		<div>
 			If set to true the shader multiplies the specular highlight by the underlying color of the object, making
 			it appear to be more metal-like and darker. If set to false the specular highlight is added ontop of the
 			underlying colors.
-		</div> 
+		</div>
 
 		<h3>[property:Texture map]</h3>
 		<div>Set color texture map. Default is null. The texture map color is modulated by the diffuse color.</div>
@@ -95,7 +95,7 @@
 			Bump doesn't actually affect the geometry of the object, only the lighting. If a normal map is defined this will
 			be ignored.
 		</div>
-		
+
 		<h3>[property:Float bumpScale]</h3>
 		<div>
 			How much the bump map affects the material. Typical ranges are 0-1. Default is 1.
@@ -106,11 +106,11 @@
 			The texture to create a normal map. The RGB values affect the surface normal for each pixel fragment and change
 			the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.
 		</div>
-		
+
 		<h3>[property:Vector2 normalScale]</h3>
 		<div>
 			How much the normal map affects the material. Typical ranges are 0-1. Default is (1,1).
-		</div> 
+		</div>
 
 		<h3>[property:Texture specularMap]</h3>
 		<div>The specular map value affects both how much the specular surface highlight contributes and how much of the environment map affects the surface. Default is null.</div>
@@ -121,14 +121,14 @@
 
 		<h3>[property:TextureCube envMap]</h3>
 		<div>Set env map. Default is null.</div>
-		
+
 		<h3>[property:Integer combine]</h3>
-		<div>How to combine the result of the surface's color with the environment map, if any.</div> 
-		 
+		<div>How to combine the result of the surface's color with the environment map, if any.</div>
+
 		<div>Options are [page:Textures THREE.MultiplyOperation] (default), [page:Textures THREE.MixOperation], [page:Textures THREE.AddOperation]. If mix is chosen, the reflectivity is used to blend between the two colors.</div>
-		 
+
 		<h3>[property:Float reflectivity]</h3>
-		<div>How much the environment map affects the surface; also see "combine".</div> 
+		<div>How much the environment map affects the surface; also see "combine".</div>
 
 		<h3>[property:Float refractionRatio]</h3>
 		<div>The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.</div>
@@ -140,11 +140,11 @@
 		<h3>[property:Integer shading]</h3>
 		<div>How the triangles of a curved surface are rendered: as a smooth surface, as flat separate facets, or no shading at all.</div>
 
-		<div>Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading].</div>
-		
+		<div>Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading].</div>
+
 		<h3>[property:Boolean wireframe]</h3>
 		<div>Whether the triangles' edges are displayed instead of surfaces. Default is *false*.</div>
-		
+
 		<h3>[property:Float wireframeLinewidth]</h3>
 		<div>Line thickness for wireframe mode. Default is *1.0*.</div>
 		<div>Due to limitations in the <a href="https://code.google.com/p/angleproject/" target="_blank">ANGLE layer</a>, on Windows platforms linewidth will always be 1 regardless of the set value.</div>
@@ -163,9 +163,9 @@
 
 		<h3>[property:Boolean skinning]</h3>
 		<div>Define whether the material uses skinning. Default is *false*.</div>
-	
+
 		<h3>[property:Boolean morphTargets]</h3>
-		<div>Define whether the material uses morphTargets. Default is *false*.</div>	
+		<div>Define whether the material uses morphTargets. Default is *false*.</div>
 
 		<h3>[property:boolean morphNormals]</h3>
 		<div>

+ 2 - 2
docs/api/materials/PointCloudMaterial.html → docs/api/materials/PointsMaterial.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -12,7 +12,7 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">The default material used by [page:PointCloud particle] systems.</div>
+		<div class="desc">The default material used by [page:Points particle] systems.</div>
 
 
 		<h2>Constructor</h2>

+ 21 - 46
docs/api/materials/ShaderMaterial.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -16,9 +16,13 @@
 		<ul>
 			<li>implement an effect not included with any of the built-in [page:Material materials]</li>
 			<li>combine many objects into a single [page:Geometry] or [page:BufferGeometry] in order to improve performance</li>
-			<li>associate custom data with individual vertices ("custom attributes")</li>
 		</ul>
-		Note that a ShaderMaterial will only be rendered properly by [page:WebGLRenderer], since the GLSL code in the vertexShader and fragmentShader properties must be compiled and run on the GPU using WebGL.
+		There are the following notes to bear in mind when using a *ShaderMaterial*:
+
+		<ul>
+			<li>A *ShaderMaterial* will only be rendered properly by [page:WebGLRenderer], since the GLSL code in the *vertexShader* and *fragmentShader* properties must be compiled and run on the GPU using WebGL.</li>
+			<li>As of THREE r72, directly assigning attributes in a *ShaderMaterial* is no longer supported. A [page:BufferGeometry] instance (instead of a [page:Geometry] instance) must be used instead, using [page:BufferAttribute] instances to define custom attributes.</li>
+		</ul>
 		</div>
 
 		<h3>Example</h3>
@@ -67,66 +71,51 @@
 		</p>
 
 		<h3>Custom attributes and uniforms</h3>
-		Custom attributes and uniforms must be declared both in your GLSL shader code (within *vertexShader* and/or *fragmentShader*), <emph>and</emph> in the *attributes* and *uniforms* properties of your ShaderMaterial. The declaration in the material is necessary to ensure [page:WebGLRenderer] passes your attribute/uniform data in a buffer to the GPU when the shader is run. Note that *varying*s only need to be declared within the shader code (not within the material).
+		<p>Both custom attributes and uniforms must be declared in your GLSL shader code (within *vertexShader* and/or *fragmentShader*). Custom uniforms must be defined in <emph>both</emph> the *uniforms* property of your *ShaderMaterial*, whereas any custom attributes must be defined via [page:BufferAttribute] instances. Note that *varying*s only need to be declared within the shader code (not within the material).
 		</p>
-		<p>
-		To declare a custom attribute, use the *attributes* property of the material:
-		<code>
-		attributes: {
-			vertexOpacity: { type: 'f', value: [] }
-		}
-		</code>
-		Each attribute must have a *type* property and a *value* property.
+
+		<p>To declare a custom attribute, please reference the [page:BufferGeometry] page for an overview, and the [page:BufferAttribute] page for a detailed look at the *BufferAttribute* API.</p>
+		<p>When creating your attributes, each typed array that you create to hold your attribute's data must be a multiple of your data type's size. For example, if your attribute is a [page:Vector3 THREE.Vector3] type, and you have 3000 vertices in your [page:BufferGeometry], your typed array value must be created with a length of 3000 * 3, or 9000 (one value per-component). A table of each data type's size is shown below for reference:</p>
+
 		<table>
-			<caption><a id="attribute-types">Attribute types</a></caption>
+			<caption><a id="attribute-sizes">Attribute sizes</a></caption>
 			<thead>
 				<tr>
-					<th>Attribute *type* string</th>
 					<th>GLSL type</th>
 					<th>JavaScript type</th>
+					<th>Size</th>
 				</tr>
 			</thead>
 			<tbody>
 				<tr>
-					<td><code>'f'</code></td>
 					<td>float</td>
 					<td>[page:Number]</td>
+					<td>1</td>
 				</tr>
 				<tr>
-					<td><code>'v2'</code></td>
 					<td>vec2</td>
 					<td>[page:Vector2 THREE.Vector2]</td>
+					<td>2</td>
 				</tr>
 				<tr>
-					<td><code>'v3'</code></td>
 					<td>vec3</td>
 					<td>[page:Vector3 THREE.Vector3]</td>
+					<td>3</td>
 				</tr>
 				<tr>
-					<td><code>'c'</code></td>
 					<td>vec3</td>
 					<td>[page:Color THREE.Color]</td>
+					<td>3</td>
 				</tr>
 				<tr>
-					<td><code>'v4'</code></td>
 					<td>vec4</td>
 					<td>[page:Vector4 THREE.Vector4]</td>
+					<td>4</td>
 				</tr>
 			</tbody>
 		</table>
-		The way attribute data is stored depends on whether you're using [page:BufferGeometry] or [page:Geometry]:
-		<ul>
-			<li>When using [page:Geometry], attribute data is stored directly on the <emph>material</emph>, using the attribute's *value* array; each element of *value* should correspond to one vertex. To update an attribute, set the *needsUpdate* flag to true on the material attribute:
-			<code>
-			material.attributes.vertexOpacity.needsUpdate = true;
-			</code>
-			</li>
-			<li>When using [page:BufferGeometry], attribute data is stored within a [page:BufferAttribute] on the geometry itself, and the *value* within the material is ignored. To update an attribute, set the *needsUpdate* flag to true on the [page:BufferAttribute] of the geometry:
-			<code>
-			geometry.attributes.vertexOpacity.needsUpdate = true;
-			</code>
-			See [page:BufferGeometry] for details.</li>
-		</ul>
+
+		Note that attribute buffers are <emph>not</emph> refreshed automatically when their values change. To update custom attributes, set the *needsUpdate* flag to true on the [page:BufferAttribute] of the geometry (see [page:BufferGeometry] for further details).
 		</p>
 
 		<p>
@@ -232,20 +221,6 @@
 		where *type* is a <a href="#uniform-types">uniform type string</a>, and *value* is the value of the uniform. Names must match the name of the uniform, as defined in the GLSL code. Note that uniforms are refreshed on every frame, so updating the value of the uniform will immediately update the value available to the GLSL code.
 		</div>
 
-		<h3>[property:Object attributes]</h3>
-		<div>
-		<p>
-		Object specifying the custom attributes to be passed to the shader code; keys are attribute names, values are definitions of the form
-		<code>
-		{ type: 'f', value: [1.0, 0.5, 2.0, ...] }
-		</code>
-		where *type* is an <a href="#attribute-types">attribute type string</a>, and *value* is an array containing an attribute value for each vertex in the geometry (or *undefined* if using [page:BufferGeometry]). Names must match the name of the attribute, as defined in the GLSL code.
-		</p>
-		<p>
-		Note that attribute buffers are <emph>not</emph> refreshed automatically when their values change; if using [page:Geometry], set <code>needsUpdate = true</code> on the attribute definition. If using [page:BufferGeometry], set <code>needsUpdate = true</code> on the [page:BufferAttribute].
-		</p>
-		</div>
-
 		<h3>[property:Object defines]</h3>
 		<div>
 		Defines custom constants using *#define* directives within the GLSL code for both the vertex shader and the fragment shader; each key/value pair yields another directive:

+ 9 - 9
docs/api/math/Box2.html

@@ -22,7 +22,7 @@
 		max -- Upper (x, y) boundary of the box.
 		</div>
 		<div>
-		Creates a box bounded by min and max. 
+		Creates a box bounded by min and max.
 		</div>
 
 
@@ -33,12 +33,12 @@
 		<h3>[property:Vector2 min]</h3>
 		<div>
 		Lower (x, y) boundary of this box.
-		</div> 
+		</div>
 
 		<h3>[property:Vector2 max]</h3>
 		<div>
 		Upper (x, y) boundary of this box.
-		</div> 
+		</div>
 
 		<h2>Methods</h2>
 
@@ -70,7 +70,7 @@
 		Clamps *point* within the bounds of this box.
 		</div>
 
-		<h3>[method:Boolean isIntersectionBox]([page:Box2 box])</h3>
+		<h3>[method:Boolean intersectsBox]([page:Box2 box])</h3>
 		<div>
 		box -- Box to check for intersection against.
 		</div>
@@ -99,7 +99,7 @@
 		box -- Box that will be unioned with this box.
 		</div>
 		<div>
-		Unions this box with *box* setting the upper bound of this box to the greater of the 
+		Unions this box with *box* setting the upper bound of this box to the greater of the
 		two boxes' upper bounds and the lower bound of this box to the lesser of the two boxes'
 		lower bounds.
 		</div>
@@ -108,7 +108,7 @@
 		<div>
 		point -- [page:Vector2]<br/>
 		optionalTarget -- [page:Vector2]<br/>
-		
+
 		</div>
 		<div>
 		Returns a point as a proportion of this box's width and height.
@@ -139,7 +139,7 @@
 		</div>
 		<div>
 		Returns true if this box includes the entirety of *box*. If this and *box* overlap exactly,</br>
-		this function also returns true. 
+		this function also returns true.
 		</div>
 
 		<h3>[method:Box2 translate]([page:Vector2 offset]) [page:Box2 this]</h3>
@@ -177,7 +177,7 @@
 		</div>
 		<div>
 		Expands this box equilaterally by *vector*. The width of this box will be
-		expanded by the x component of *vector* in both directions. The height of 
+		expanded by the x component of *vector* in both directions. The height of
 		this box will be expanded by the y component of *vector* in both directions.
 		</div>
 
@@ -222,7 +222,7 @@
 		<h3>[method:Box2 setFromCenterAndSize]([page:Vector2 center], [page:Vector2 size]) [page:Box2 this]</h3>
 		<div>
 		center -- Desired center position of the box. <br />
-		size -- Desired x and y dimensions of the box. 
+		size -- Desired x and y dimensions of the box.
 		</div>
 		<div>
 		Centers this box on *center* and sets this box's width and height to the values specified

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

@@ -22,7 +22,7 @@
 		max -- Upper (x, y, z) boundary of the box.
 		</div>
 		<div>
-		Creates a box bounded by min and max. 
+		Creates a box bounded by min and max.
 		</div>
 
 		<h2>Properties</h2>
@@ -37,7 +37,7 @@
 		<h3>[property:Vector3 max]</h3>
 		<div>
 		Upper (x, y, z) boundary of this box.
-		</div> 
+		</div>
 
 		<h2>Methods</h2>
 
@@ -51,7 +51,7 @@
 		<div>
 		Sets the lower and upper (x, y, z) boundaries of this box.
 		</div>
-		
+
 		<h3>[method:Box3 applyMatrix4]([page:Matrix4 matrix]) [page:Box3 this]</h3>
 		<div>
 		matrix -- The [page:Matrix4] to apply
@@ -69,7 +69,7 @@
 		Clamps *point* within the bounds of this box.
 		</div>
 
-		<h3>[method:Boolean isIntersectionBox]([page:Box3 box])</h3>
+		<h3>[method:Boolean intersectsBox]([page:Box3 box])</h3>
 		<div>
 		box -- Box to check for intersection against.
 		</div>
@@ -84,7 +84,7 @@
 		<div>
 		Sets the upper and lower bounds of this box to include all of the points in *points*.
 		</div>
-		
+
 		<h3>[method:Box3 setFromObject]([page:Object3D object]) [page:Box3 this]</h3>
 		<div>
 		object -- [page:Object3D] to compute the bounding box for.
@@ -93,8 +93,8 @@
 		Computes the world-axis-aligned bounding box of an object (including its children),
 		accounting for both the object's, and childrens', world transforms
 		</div>
-		
-		
+
+
 
 		<h3>[method:Vector3 size]([page:Vector3 optionalTarget])</h3>
 		<div>
@@ -109,7 +109,7 @@
 		box -- Box that will be unioned with this box.
 		</div>
 		<div>
-		Unions this box with *box* setting the upper bound of this box to the greater of the 
+		Unions this box with *box* setting the upper bound of this box to the greater of the
 		two boxes' upper bounds and the lower bound of this box to the lesser of the two boxes'
 		lower bounds.
 		</div>
@@ -139,7 +139,7 @@
 		</div>
 		<div>
 		Returns true if this box includes the entirety of *box*. If this and *box* overlap exactly,</br>
-		this function also returns true. 
+		this function also returns true.
 		</div>
 
 		<h3>[method:Boolean containsPoint]([page:Vector3 point])</h3>
@@ -149,7 +149,7 @@
 		<div>
 		Returns true if the specified point lies within the boundaries of this box.
 		</div>
-		
+
 		<h3>[method:Box3 translate]([page:Vector3 offset]) [page:Box3 this]</h3>
 		<div>
 		offset -- Direction and distance of offset.
@@ -186,7 +186,7 @@
 		<div>
 		Expands the boundaries of this box to include *point*.
 		</div>
-		
+
 		<h3>[method:Box3 expandByScalar]([page:float scalar]) [page:Box3 this]</h3>
 		<div>
 		scalar -- Distance to expand.
@@ -195,14 +195,14 @@
 		Expands each dimension of the box by *scalar*. If negative, the dimensions of the box <br/>
 		will be contracted.
 		</div>
-		
+
 		<h3>[method:Box3 expandByVector]([page:Vector3 vector]) [page:Box3 this]</h3>
 		<div>
 		vector -- Amount to expand this box in each dimension.
 		</div>
 		<div>
 		Expands this box equilaterally by *vector*. The width of this box will be
-		expanded by the x component of *vector* in both directions. The height of 
+		expanded by the x component of *vector* in both directions. The height of
 		this box will be expanded by the y component of *vector* in both directions.
 		The depth of this box will be expanded by the z component of *vector* in
 		both directions.
@@ -249,7 +249,7 @@
 		<h3>[method:Box3 setFromCenterAndSize]([page:Vector3 center], [page:Vector3 size]) [page:Box3 this]</h3>
 		<div>
 		center -- Desired center position of the box. <br />
-		size -- Desired x and y dimensions of the box. 
+		size -- Desired x and y dimensions of the box.
 		</div>
 		<div>
 		Centers this box on *center* and sets this box's width and height to the values specified

+ 7 - 16
docs/api/math/Math.html

@@ -16,23 +16,14 @@
 
 		<h2>Methods</h2>
 
-		<h3>[method:Float clamp]( [page:Float x], [page:Float a], [page:Float b] )</h3>
+		<h3>[method:Float clamp]( [page:Float value], [page:Float min], [page:Float max] )</h3>
 		<div>
-		x — Value to be clamped.<br />
-		a — Minimum value<br />
-		b — Maximum value.
+		value — Value to be clamped.<br />
+		min — Minimum value<br />
+		max — Maximum value.
 		</div>
 		<div>
-		Clamps the *x* to be between *a* and *b*.
-		</div>
-
-		<h3>[method:Float clampBottom]( [page:Float x], [page:Float a] )</h3>
-		<div>
-		x — Value to be clamped.<br />
-		a — Minimum value
-		</div>
-		<div>
-		Clamps the *x* to be larger than *a*.
+		Clamps the *value* to be between *min* and *max*.
 		</div>
 
 		<h3>[method:Float mapLinear]( [page:Float x], [page:Float a1], [page:Float a2], [page:Float b1], [page:Float b2] )</h3>
@@ -97,7 +88,7 @@
 		</div>
 		<div>
 		Returns a value between 0-1 that represents the percentage that x has moved between min and max, but smoothed or slowed down the closer X is to the min and max.<br/><br/>
-		
+
 		[link:http://en.wikipedia.org/wiki/Smoothstep Wikipedia]
 		</div>
 
@@ -110,7 +101,7 @@
 		<div>
 		Returns a value between 0-1. It works the same as smoothstep, but more smooth.
 		</div>
-		
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

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

@@ -223,7 +223,7 @@
 		Creates a perspective projection matrix.
 		</div>
 
-		<h3>[method:Matrix4 makeOrthographic]( [page:Float left], [page:Float right], [page:Float bottom], [page:Float top], [page:Float near], [page:Float far] ) [page:Matrix4 this]</h3>
+		<h3>[method:Matrix4 makeOrthographic]( [page:Float left], [page:Float right], [page:Float top], [page:Float bottom], [page:Float near], [page:Float far] ) [page:Matrix4 this]</h3>
 		<div>
 		Creates an orthographic projection matrix.
 		</div>

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

@@ -28,7 +28,7 @@
 		<h3>[property:Vector3 normal]</h3>
 
 		<h3>[property:Float constant]</h3>
-		
+
 		<h2>Methods</h2>
 
 
@@ -62,9 +62,9 @@
 		</div>
 		<div>
 		Apply a Matrix4 to the plane. The second parameter is optional.
-		
+
 		<code>
-		var optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ) 
+		var optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix )
 		</code>
 		</div>
 
@@ -77,7 +77,7 @@
 		Returns a vector in the same direction as the Plane's normal, but the magnitude is passed point's original distance to the plane.
 		</div>
 
-		<h3>[method:Boolean isIntersectionLine]([page:Line3 line])</h3>
+		<h3>[method:Boolean intersectsLine]([page:Line3 line])</h3>
 		<div>
 		line -- [page:Line3]
 		</div>

+ 9 - 9
docs/api/math/Ray.html

@@ -30,12 +30,12 @@
 		<h3>[property:Vector3 origin]</h3>
 		<div>
 		The origin of the [page:Ray].
-		</div> 
+		</div>
 
 		<h3>[property:Vector3 direction]</h3>
 		<div>
 		The direction of the [page:Ray]. This must be normalized (with [page:Vector3].normalize) for the methods to operate properly.
-		</div> 
+		</div>
 
 		<h2>Methods</h2>
 
@@ -77,7 +77,7 @@
 		<div>
 		Copy the properties of the provided [page:Ray], then return this [page:Ray].
 		</div>
-		
+
 		<h3>.distanceSqToSegment([page:Vector3 v0], [page:Vector3 v1], [page:Vector3 optionalPointOnRay] = null, [page:Vector3 optionalPointOnSegment] = null) [page:Float]</h3>
 		<div>
 		v0 -- [page:Vector3] The start of the line segment.
@@ -129,7 +129,7 @@
 		<div>
 		Intersect this [page:Ray] with a [page:Box3], returning the intersection point or *null* if there is no intersection.
 		</div>
-		
+
 		<h3>.intersectPlane([page:Plane plane], [page:Vector3 optionalTarget] = null) [page:Vector3]?</h3>
 		<div>
 		plane -- [page:Plane] The [page:Plane] to intersect with.<br />
@@ -139,7 +139,7 @@
 		Intersect this [page:Ray] with a [page:Plane], returning the intersection point or *null* if there is no intersection.
 		</div>
 		function ( a, b, c, backfaceCulling, optionalTarget )
-		
+
 		<h3>.intersectTriangle([page:Vector3 a], [page:Vector3 b], [page:Vector3 c], [page:Boolean backfaceCulling], [page:Vector3 optionalTarget] = null) [page:Vector3]?</h3>
 		<div>
 		a, b, c -- [page:Vector3] The [page:Vector3] points on the triangle.<br />
@@ -149,8 +149,8 @@
 		<div>
 		Intersect this [page:Ray] with a triangle, returning the intersection point or *null* if there is no intersection.
 		</div>
-		
-		<h3>[method:Boolean isIntersectionBox]([page:Box3 box])</h3>
+
+		<h3>[method:Boolean intersectsBox]([page:Box3 box])</h3>
 		<div>
 		box -- [page:Box3] The [page:Box3] to intersect with.
 		</div>
@@ -158,7 +158,7 @@
 		Return whether or not this [page:Ray] intersects with the [page:Box3].
 		</div>
 
-		<h3>[method:Boolean isIntersectionPlane]([page:Plane plane])</h3>
+		<h3>[method:Boolean intersectsPlane]([page:Plane plane])</h3>
 		<div>
 		plane -- [page:Plane] The [page:Plane] to intersect with.
 		</div>
@@ -166,7 +166,7 @@
 		Return whether or not this [page:Ray] intersects with the [page:Plane].
 		</div>
 
-		<h3>[method:Boolean isIntersectionSphere]([page:Sphere sphere])</h3>
+		<h3>[method:Boolean intersectsSphere]([page:Sphere sphere])</h3>
 		<div>
 		sphere -- [page:Sphere] The [page:Sphere] to intersect with.
 		</div>

+ 6 - 6
docs/api/objects/PointCloud.html → docs/api/objects/Points.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -33,27 +33,27 @@
 
 		<h3>[property:Material material]</h3>
 
-		<div>An instance of [page:Material], defining the object's appearance. Default is a [page:PointCloudMaterial] with randomised colour.</div>
+		<div>An instance of [page:Material], defining the object's appearance. Default is a [page:PointsMaterial] with randomised colour.</div>
 
 
 		<h2>Methods</h2>
 
-		<h3>[method:PointCloud clone]()</h3>
+		<h3>[method:Points clone]()</h3>
 		<div>
 		This creates a clone of the particle system.
 		</div>
 
 		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
 		<div>
-		Get intersections between a casted ray and this PointCloud. [page:Raycaster.intersectObject] will call this method.
+		Get intersections between a casted ray and this Points. [page:Raycaster.intersectObject] will call this method.
 		</div>
 
 		<h3>[method:Object3D clone]([page:Object3D object])</h3>
 		<div>
-		object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned PointCloud Object.
+		object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Points Object.
 		</div>
 		<div>
-		Clone a PointCloud Object.
+		Clone a Points Object.
 		</div>
 
 		<h2>Source</h2>

+ 161 - 161
docs/api/renderers/CanvasRenderer.html

@@ -1,162 +1,162 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
+<!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>
-
-		<div class="desc">
-			The Canvas renderer displays your beautifully crafted scenes <em>not</em> using WebGL, but draws it using the (slower) <a href="http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas/">Canvas 2D Context</a> API.<br /><br />
-			This renderer can be a nice fallback from [page:WebGLRenderer] for simple scenes:
-
-			<code>
-			function webglAvailable() {
-				try {
-					var canvas = document.createElement( 'canvas' );
-					return !!( window.WebGLRenderingContext && (
-						canvas.getContext( 'webgl' ) ||
-						canvas.getContext( 'experimental-webgl' ) )
-					);
-				} catch ( e ) {
-					return false;
-				}
-			}
-
-			if ( webglAvailable() ) {
-				renderer = new THREE.WebGLRenderer();
-			} else {
-				renderer = new THREE.CanvasRenderer();
-			}
-			</code>
-
-			Note: both WebGLRenderer and CanvasRenderer are embedded in the web page using an HTML5 &lt;canvas&gt; tag.
-			The "Canvas" in CanvasRenderer means it uses Canvas 2D instead of WebGL.<br /><br />
-
-			Don't confuse either CanvasRenderer with the SoftwareRenderer example, which simulates a screen buffer in a Javascript array.
-		</div>
-
-		<h2>Constructor</h2>
-
-
-		<h3>[name]([page:object parameters])</h3>
-        <div>parameters is an optional object with properties defining the renderer's behaviour. The constructor also accepts no parameters at all. In all cases, it will assume sane defaults when parameters are missing.</div>
-
-		<div>
-		canvas — A [page:Canvas] where the renderer draws its output.
-		</div>
-
-
-		<h2>Properties</h2>
-
-    <h3>[property:Object info]</h3>
-
-		<div>
-			An object with a series of statistical information about the graphics board memory and the rendering process. Useful for debugging or just for the sake of curiosity. The object contains the following fields:</div>
-			<ul>
-				<li>render:
-					<ul>
-						<li>vertices</li>
-						<li>faces</li>
-					</ul>
-				</li>
-			</ul>
-		</div>
-
-    <h3>[property:DOMElement domElement]</h3>
-
-		<div>
-			A [page:Canvas] where the renderer draws its output.<br />
-			This is automatically created by the renderer in the constructor (if not provided already); you just need to add it to your page.
-		</div>
-
-		<h3>[property:Boolean autoClear]</h3>
-		<div>
-      Defines whether the renderer should automatically clear its output before rendering.
-    </div>
-
-		<h3>[property:Boolean sortObjects]</h3>
-		<div>
-      Defines whether the renderer should sort objects. Default is true.<br />
-      Note: Sorting is used to attempt to properly render objects that have some degree of transparency.  By definition, sorting objects may not work in all cases.  Depending on the needs of application, it may be neccessary to turn off sorting and use other methods to deal with transparency rendering e.g. manually determining the object rendering order.
-    </div>
-
-		<h3>[property:boolean sortElements]</h3>
-		<div>
-			Defines whether the renderer should sort the face of each object. Default is true.
-		</div>
-
-
-		<h2>Methods</h2>
-
-		<h3>[method:null render]([page:Scene scene], [page:Camera camera])</h3>
-		<div>
-			scene -- The scene to render. <br />
-			camera -- the camera to view the scene.
-		</div>
-		<div>
-        Render a scene using a camera.
-		</div>
-
-		<h3>[method:null clear]()</h3>
-		<div>
-			Tells the renderer to clear its color drawing buffer with the clearcolor.
-		</div>
-
-		<h3>[method:null setClearColor]([page:Color color], [page:number alpha])</h3>
-		<div>
-			color -- The color to clear the canvas with. <br />
-			alpha -- The alpha channel to clear the canvas with.
-		</div>
-		<div>
-			This set the clearColor and the clearAlpha.
-		</div>
-
-
-		<h3>[method:null setSize]([page:Number width], [page:Number height])</h3>
-		<div>
-			width -- The width of the drawing canvas. <br />
-			height -- The height of the drawing canvas.
-		</div>
-		<div>
-			This set the size of the drawing canvas and if updateStyle is set, then the css of the canvas is updated too.
-		</div>
-
-		<h3>[method:null setClearColorHex]([page:number hex], [page:number alpha])</h3>
-		<div>
-			hex -- The the hexadecimal value of the color to clear the canvas with. <br />
-	    alpha -- The alpha channel to clear the canvas with.
-		</div>
-		<div>
-			This set the clearColor and the clearAlpha.
-		</div>
-
-		<h3>[method:number getClearColorHex]()</h3>
-		<div>
-			Returns the [page:number hex] color.
-		</div>
-
-		<h3>[method:number getClearAlpha]()</h3>
-		<div>
-			Returns the alpha value.
-		</div>
-
-		<h2>Empty Methods to Maintain Compatibility with [page:WebglRenderer]</h2>
-		<div>
-			[method:null clearColor]()<br/>
-			[method:null clearDepth]()<br/>
-			[method:null clearStencil]()<br/>
-			[method:null setFaceCulling]()<br/>
-			[method:null supportsVertexTextures]()<br/>
-			[method:number getMaxAnisotropy]() - returns 1 <br/>
-		</div>
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-	</body>
-</html>
+		<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>
+
+		<div class="desc">
+			The Canvas renderer displays your beautifully crafted scenes <em>not</em> using WebGL, but draws it using the (slower) <a href="http://drafts.htmlwg.org/2dcontext/html5_canvas_CR/Overview.html">Canvas 2D Context</a> API.<br /><br />
+			This renderer can be a nice fallback from [page:WebGLRenderer] for simple scenes:
+
+			<code>
+			function webglAvailable() {
+				try {
+					var canvas = document.createElement( 'canvas' );
+					return !!( window.WebGLRenderingContext && (
+						canvas.getContext( 'webgl' ) ||
+						canvas.getContext( 'experimental-webgl' ) )
+					);
+				} catch ( e ) {
+					return false;
+				}
+			}
+
+			if ( webglAvailable() ) {
+				renderer = new THREE.WebGLRenderer();
+			} else {
+				renderer = new THREE.CanvasRenderer();
+			}
+			</code>
+
+			Note: both WebGLRenderer and CanvasRenderer are embedded in the web page using an HTML5 &lt;canvas&gt; tag.
+			The "Canvas" in CanvasRenderer means it uses Canvas 2D instead of WebGL.<br /><br />
+
+			Don't confuse either CanvasRenderer with the SoftwareRenderer example, which simulates a screen buffer in a Javascript array.
+		</div>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:object parameters])</h3>
+        <div>parameters is an optional object with properties defining the renderer's behaviour. The constructor also accepts no parameters at all. In all cases, it will assume sane defaults when parameters are missing.</div>
+
+		<div>
+		canvas — A [page:Canvas] where the renderer draws its output.
+		</div>
+
+
+		<h2>Properties</h2>
+
+    <h3>[property:Object info]</h3>
+
+		<div>
+			An object with a series of statistical information about the graphics board memory and the rendering process. Useful for debugging or just for the sake of curiosity. The object contains the following fields:</div>
+			<ul>
+				<li>render:
+					<ul>
+						<li>vertices</li>
+						<li>faces</li>
+					</ul>
+				</li>
+			</ul>
+		</div>
+
+    <h3>[property:DOMElement domElement]</h3>
+
+		<div>
+			A [page:Canvas] where the renderer draws its output.<br />
+			This is automatically created by the renderer in the constructor (if not provided already); you just need to add it to your page.
+		</div>
+
+		<h3>[property:Boolean autoClear]</h3>
+		<div>
+      Defines whether the renderer should automatically clear its output before rendering.
+    </div>
+
+		<h3>[property:Boolean sortObjects]</h3>
+		<div>
+      Defines whether the renderer should sort objects. Default is true.<br />
+      Note: Sorting is used to attempt to properly render objects that have some degree of transparency.  By definition, sorting objects may not work in all cases.  Depending on the needs of application, it may be neccessary to turn off sorting and use other methods to deal with transparency rendering e.g. manually determining the object rendering order.
+    </div>
+
+		<h3>[property:boolean sortElements]</h3>
+		<div>
+			Defines whether the renderer should sort the face of each object. Default is true.
+		</div>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null render]([page:Scene scene], [page:Camera camera])</h3>
+		<div>
+			scene -- The scene to render. <br />
+			camera -- the camera to view the scene.
+		</div>
+		<div>
+        Render a scene using a camera.
+		</div>
+
+		<h3>[method:null clear]()</h3>
+		<div>
+			Tells the renderer to clear its color drawing buffer with the clearcolor.
+		</div>
+
+		<h3>[method:null setClearColor]([page:Color color], [page:number alpha])</h3>
+		<div>
+			color -- The color to clear the canvas with. <br />
+			alpha -- The alpha channel to clear the canvas with.
+		</div>
+		<div>
+			This set the clearColor and the clearAlpha.
+		</div>
+
+
+		<h3>[method:null setSize]([page:Number width], [page:Number height])</h3>
+		<div>
+			width -- The width of the drawing canvas. <br />
+			height -- The height of the drawing canvas.
+		</div>
+		<div>
+			This set the size of the drawing canvas and if updateStyle is set, then the css of the canvas is updated too.
+		</div>
+
+		<h3>[method:null setClearColorHex]([page:number hex], [page:number alpha])</h3>
+		<div>
+			hex -- The the hexadecimal value of the color to clear the canvas with. <br />
+	    alpha -- The alpha channel to clear the canvas with.
+		</div>
+		<div>
+			This set the clearColor and the clearAlpha.
+		</div>
+
+		<h3>[method:number getClearColorHex]()</h3>
+		<div>
+			Returns the [page:number hex] color.
+		</div>
+
+		<h3>[method:number getClearAlpha]()</h3>
+		<div>
+			Returns the alpha value.
+		</div>
+
+		<h2>Empty Methods to Maintain Compatibility with [page:WebglRenderer]</h2>
+		<div>
+			[method:null clearColor]()<br/>
+			[method:null clearDepth]()<br/>
+			[method:null clearStencil]()<br/>
+			[method:null setFaceCulling]()<br/>
+			[method:null supportsVertexTextures]()<br/>
+			[method:number getMaxAnisotropy]() - returns 1 <br/>
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 1 - 1
docs/index.html

@@ -417,6 +417,6 @@
 			].join('\n'));
 
 		</script>
-		<script src="../build/three.min.js"></script>
+		<script src="../build/three.min.js"></script> <!-- console sandbox -->
 	</body>
 </html>

+ 5 - 6
docs/list.js

@@ -4,7 +4,6 @@ var list = {
 		"Introduction": [
 			[ "Creating a scene", "manual/introduction/Creating-a-scene" ],
 			[ "Matrix transformations", "manual/introduction/Matrix-transformations" ]
-
 		]
 	},
 
@@ -32,7 +31,7 @@ var list = {
 			[ "Face3", "api/core/Face3" ],
 			[ "Geometry", "api/core/Geometry" ],
 			[ "Object3D", "api/core/Object3D" ],
-			[ "Raycaster", "api/core/Raycaster" ],
+			[ "Raycaster", "api/core/Raycaster" ]
 		],
 
 		"Lights": [
@@ -77,10 +76,9 @@ var list = {
 			[ "MeshLambertMaterial", "api/materials/MeshLambertMaterial" ],
 			[ "MeshNormalMaterial", "api/materials/MeshNormalMaterial" ],
 			[ "MeshPhongMaterial", "api/materials/MeshPhongMaterial" ],
-			[ "PointCloudMaterial", "api/materials/PointCloudMaterial" ],
+			[ "PointsMaterial", "api/materials/PointsMaterial" ],
 			[ "RawShaderMaterial", "api/materials/RawShaderMaterial" ],
 			[ "ShaderMaterial", "api/materials/ShaderMaterial" ],
-			[ "SpriteCanvasMaterial", "api/materials/SpriteCanvasMaterial" ],
 			[ "SpriteMaterial", "api/materials/SpriteMaterial" ]
 		],
 
@@ -113,7 +111,7 @@ var list = {
 			[ "LOD", "api/objects/LOD" ],
 			[ "Mesh", "api/objects/Mesh" ],
 			[ "MorphAnimMesh", "api/objects/MorphAnimMesh" ],
-			[ "PointCloud", "api/objects/PointCloud" ],
+			[ "Points", "api/objects/Points" ],
 			[ "SkinnedMesh", "api/objects/SkinnedMesh" ],
 			[ "Skeleton", "api/objects/Skeleton" ],
 			[ "Sprite", "api/objects/Sprite" ]
@@ -240,7 +238,8 @@ var list = {
 
 		"Examples" : [
 			[ "CombinedCamera", "api/examples/cameras/CombinedCamera" ],
-			[ "LookupTable", "api/examples/Lut" ]
+			[ "LookupTable", "api/examples/Lut" ],
+			[ "SpriteCanvasMaterial", "api/examples/SpriteCanvasMaterial" ]
 
 		]
 

+ 32 - 30
docs/scenes/geometry-browser.html

@@ -10,7 +10,7 @@
 				font-weight: normal;
 				font-style: normal;
 			}
-			
+
 			body {
 				margin:0;
 				font-family: 'inconsolata';
@@ -18,9 +18,9 @@
 				line-height: 18px;
 				overflow: hidden;
 			}
-			
+
 			canvas { width: 100%; height: 100% }
-			
+
 			#newWindow {
 				display: block;
 				position: absolute;
@@ -31,12 +31,14 @@
 		</style>
 	</head>
 	<body>
-		
+
 		<a id='newWindow' href='./geometry-browser.html' target='_blank'>Open in New Window</a>
-		
+
 		<script src="../../build/three.min.js"></script>
 		<script src='../../examples/js/libs/dat.gui.min.js'></script>
 		<script src="../../examples/js/controls/OrbitControls.js"></script>
+		<script src="../../examples/js/geometries/TextGeometry.js"></script>
+		<script src="../../examples/js/utils/FontUtils.js"></script>
 		<script src="../../examples/fonts/gentilis_bold.typeface.js"></script>
 		<script src="../../examples/fonts/gentilis_regular.typeface.js"></script>
 		<script src="../../examples/fonts/optimer_bold.typeface.js"></script>
@@ -45,22 +47,22 @@
 		<script src="../../examples/fonts/helvetiker_regular.typeface.js"></script>
 		<script src="../../examples/fonts/droid/droid_serif_regular.typeface.js"></script>
 		<script src="../../examples/fonts/droid/droid_serif_bold.typeface.js"></script>
-		
+
 		<script src='js/geometry.js'></script>
-		
+
 		<script>
-			
+
 			document.getElementById('newWindow').href += window.location.hash;
-			
+
 			var gui = new dat.GUI();
 			var scene = new THREE.Scene();
 			var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 50 );
 			camera.position.z = 30;
-			
+
 			var renderer = new THREE.WebGLRenderer({antialias: true});
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			document.body.appendChild( renderer.domElement );
-			
+
 			var orbit = new THREE.OrbitControls( camera, renderer.domElement );
 			orbit.enableZoom = false;
 
@@ -71,7 +73,7 @@
 			lights[0] = new THREE.PointLight( 0xffffff, 1, 0 );
 			lights[1] = new THREE.PointLight( 0xffffff, 1, 0 );
 			lights[2] = new THREE.PointLight( 0xffffff, 1, 0 );
-			
+
 			lights[0].position.set( 0, 200, 0 );
 			lights[1].position.set( 100, 200, 100 );
 			lights[2].position.set( -100, -200, -100 );
@@ -81,40 +83,40 @@
 			scene.add( lights[2] );
 
 			var mesh = new THREE.Object3D()
-			
+
 			mesh.add( new THREE.LineSegments(
-				
+
 				new THREE.Geometry(),
-				
+
 				new THREE.LineBasicMaterial({
 					color: 0xffffff,
 					transparent: true,
 					opacity: 0.5
 				})
-				
+
 			));
-			
+
 			mesh.add( new THREE.Mesh(
-				
+
 				new THREE.Geometry(),
-				
+
 				new THREE.MeshPhongMaterial({
 					color: 0x156289,
 					emissive: 0x072534,
 					side: THREE.DoubleSide,
 					shading: THREE.FlatShading
 				})
-				
+
 			));
-			
+
 			var options = chooseFromHash( mesh );
-			
+
 			scene.add( mesh );
-			
+
 			var prevFog = false;
-			
+
 			var render = function () {
-				
+
 				requestAnimationFrame( render );
 
 				var time = Date.now() * 0.001;
@@ -125,20 +127,20 @@
 				}
 
 				renderer.render( scene, camera );
-				
+
 			};
-			
+
 			window.addEventListener( 'resize', function () {
-				
+
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				
+
 			}, false );
 
 			render();
-			
+
 		</script>
 	</body>
 </html>

+ 99 - 100
docs/scenes/js/geometry.js

@@ -24,7 +24,6 @@ var constants = {
 
 	shading : {
 
-		"THREE.NoShading" : THREE.NoShading,
 		"THREE.FlatShading" : THREE.FlatShading,
 		"THREE.SmoothShading" : THREE.SmoothShading
 
@@ -81,13 +80,13 @@ var constants = {
 }
 
 function updateGroupGeometry( mesh, geometry ) {
-	
+
 	mesh.children[0].geometry.dispose();
 	mesh.children[1].geometry.dispose();
-	
+
 	mesh.children[0].geometry = new THREE.WireframeGeometry( geometry );
 	mesh.children[1].geometry = geometry;
-	
+
 	//these do not update nicely together if shared
 }
 
@@ -103,26 +102,26 @@ var guis = {
 			heightSegments : 1,
 			depthSegments : 1
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.BoxGeometry(
 					data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments
 				)
 			);
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.BoxGeometry');
-		
+
 		folder.add( data, 'width', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'height', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'depth', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'widthSegments', 1, 10 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'heightSegments', 1, 10 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'depthSegments', 1, 10 ).step(1).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
 
@@ -138,10 +137,10 @@ var guis = {
 			thetaStart : 0,
 			thetaLength : twoPi,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.CylinderGeometry(
 					data.radiusTop,
 					data.radiusBottom,
@@ -153,11 +152,11 @@ var guis = {
 					data.thetaLength
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.CylinderGeometry');
-		
+
 		folder.add( data, 'radiusTop', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'radiusBottom', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'height', 1, 50 ).onChange( generateGeometry );
@@ -166,8 +165,8 @@ var guis = {
 		folder.add( data, 'openEnded' ).onChange( generateGeometry );
 		folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
 		folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
-		
-		
+
+
 		generateGeometry();
 	},
 
@@ -179,103 +178,103 @@ var guis = {
 			thetaStart : 0,
 			thetaLength : twoPi,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.CircleGeometry(
 					data.radius, data.segments, data.thetaStart, data.thetaLength
 				)
 			);
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.CircleGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
 		folder.add( data, 'segments', 0, 128 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
 		folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
-	
+
 	DodecahedronGeometry : function() {
 
 		var data = {
 			radius : 10,
 			detail : 0,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.DodecahedronGeometry(
 					data.radius, data.detail
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.DodecahedronGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry )
 		folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry )
-		
+
 		generateGeometry()
-		
+
 	},
-	
+
 	IcosahedronGeometry : function() {
 
 		var data = {
 			radius : 10,
 			detail : 0,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.IcosahedronGeometry(
 					data.radius, data.detail
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.IcosahedronGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry )
 		folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry )
-		
+
 		generateGeometry()
-		
+
 	},
-	
+
 	OctahedronGeometry : function() {
 
 		var data = {
 			radius : 10,
 			detail : 0,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.OctahedronGeometry(
 					data.radius, data.detail
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.OctahedronGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry )
 		folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry )
-		
+
 		generateGeometry()
-		
+
 	},
 
 	PlaneGeometry : function( mesh ) {
@@ -286,24 +285,24 @@ var guis = {
 			widthSegments : 1,
 			heightSegments : 1
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.PlaneGeometry(
 					data.width, data.height, data.widthSegments, data.heightSegments
 				)
 			);
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.PlaneGeometry');
-		
+
 		folder.add( data, 'width', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'height', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'widthSegments', 1, 30 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'heightSegments', 1, 30 ).step(1).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
 
@@ -317,29 +316,29 @@ var guis = {
 			thetaStart : 0,
 			thetaLength : twoPi,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.RingGeometry(
 					data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength
 				)
 			);
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.RingGeometry');
-		
+
 		folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry );
 		folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 1, 30 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
 		folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
-	
+
 	SphereGeometry : function( mesh ) {
 
 		var data = {
@@ -351,19 +350,19 @@ var guis = {
 			thetaStart : 0,
 			thetaLength : Math.PI,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.SphereGeometry(
 					data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength
 				)
 			);
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.SphereGeometry');
-		
+
 		folder.add( data, 'radius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'widthSegments', 3, 32 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'heightSegments', 2, 32 ).step(1).onChange( generateGeometry );
@@ -371,36 +370,36 @@ var guis = {
 		folder.add( data, 'phiLength', 0, twoPi ).onChange( generateGeometry );
 		folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
 		folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
-	
+
 	TetrahedronGeometry : function() {
 
 		var data = {
 			radius : 10,
 			detail : 0,
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.TetrahedronGeometry(
 					data.radius, data.detail
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.TetrahedronGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry )
 		folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry )
-		
+
 		generateGeometry()
-		
+
 	},
-	
+
 	TextGeometry : function( mesh ) {
 
 		var data = {
@@ -415,33 +414,33 @@ var guis = {
 			bevelThickness : 1,
 			bevelSize : 0.5
 		};
-		
+
 		var fonts = [
 			"helvetiker",
 			"optimer",
 			"gentilis",
 			"droid serif"
 		]
-		
+
 		var weights = [
 			"normal", "bold"
 		]
-		
+
 		function generateGeometry() {
-			
+
 			var geometry = new THREE.TextGeometry( data.text, data )
-			
+
 			geometry.center()
-			
+
 			updateGroupGeometry( mesh, geometry );
-			
+
 		}
-		
+
 		//Hide the wireframe
 		mesh.children[0].visible = false;
 
 		var folder = gui.addFolder('THREE.TextGeometry');
-		
+
 		folder.add( data, 'text' ).onChange( generateGeometry );
 		folder.add( data, 'size', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'height', 1, 20 ).onChange( generateGeometry );
@@ -452,10 +451,10 @@ var guis = {
 		folder.add( data, 'bevelEnabled' ).onChange( generateGeometry );
 		folder.add( data, 'bevelThickness', 0.1, 3 ).onChange( generateGeometry );
 		folder.add( data, 'bevelSize', 0.1, 3 ).onChange( generateGeometry );
-		
+
 		generateGeometry();
 	},
-	
+
 	TorusGeometry : function( mesh ) {
 
 		var data = {
@@ -465,29 +464,29 @@ var guis = {
 			tubularSegments : 100,
 			arc : twoPi
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.TorusGeometry(
 					data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.TorusGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
 		folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
 		folder.add( data, 'radialSegments', 2, 30 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'tubularSegments', 3, 200 ).step(1).onChange( generateGeometry );
 		folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry );
-		
+
 		generateGeometry();
 
 	},
-	
+
 	TorusKnotGeometry : function( mesh ) {
 
 		var data = {
@@ -499,20 +498,20 @@ var guis = {
 			q : 3,
 			heightScale : 1
 		};
-		
+
 		function generateGeometry() {
-			
-			updateGroupGeometry( mesh, 
+
+			updateGroupGeometry( mesh,
 				new THREE.TorusKnotGeometry(
 					data.radius, data.tube, data.radialSegments, data.tubularSegments,
 					data.p, data.q, data.heightScale
 				)
 			)
-			
+
 		}
 
 		var folder = gui.addFolder('THREE.TorusGeometry');
-		
+
 		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry )
 		folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry )
 		folder.add( data, 'radialSegments', 3, 300 ).step(1).onChange( generateGeometry )
@@ -520,11 +519,11 @@ var guis = {
 		folder.add( data, 'p', 1, 20 ).step(1).onChange( generateGeometry )
 		folder.add( data, 'q', 1, 20 ).step(1).onChange( generateGeometry )
 		folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry )
-		
+
 		generateGeometry()
 
 	}
-	
+
 }
 
 function chooseFromHash ( mesh ) {

+ 1 - 3
docs/scenes/js/material.js

@@ -22,7 +22,6 @@ var constants = {
 
 	shading : {
 
-		"THREE.NoShading" : THREE.NoShading,
 		"THREE.FlatShading" : THREE.FlatShading,
 		"THREE.SmoothShading" : THREE.SmoothShading
 
@@ -404,7 +403,6 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
 	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
 
-	folder.add( material, 'shading', constants.shading ).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
 	folder.add( material, 'vertexColors', constants.colors ).onChange( needsUpdate( material, geometry ) );
@@ -441,7 +439,7 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
 	folder.addColor( data, 'specular' ).onChange( handleColorChange( material.specular ) );
 
-	folder.add( material, 'shininess', 1, 100);
+	folder.add( material, 'shininess', 0, 100);
 	folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );

+ 1 - 0
editor/css/dark.css

@@ -86,6 +86,7 @@ input.Number {
 	#menubar .menu.right {
 		float: right;
 		cursor: auto;
+		padding-right: 0px;
 		text-align: right;
 	}
 

+ 1 - 0
editor/css/light.css

@@ -79,6 +79,7 @@ input.Number {
 	#menubar .menu.right {
 		float: right;
 		cursor: auto;
+		padding-right: 0px;
 		text-align: right;
 	}
 

+ 12 - 0
editor/css/main.css

@@ -116,6 +116,18 @@ textarea, input { outline: none; } /* osx */
 	color: #8888ee;
 }
 
+.Line {
+	color: #88ee88;
+}
+
+.LineSegments {
+	color: #88ee88;
+}
+
+.Points {
+	color: #ee8888;
+}
+
 /* */
 
 .PointLight {

+ 12 - 19
editor/index.html

@@ -14,9 +14,13 @@
 
 		<script src="../examples/js/controls/EditorControls.js"></script>
 		<script src="../examples/js/controls/TransformControls.js"></script>
+
+		<script src="../examples/js/libs/jszip.min.js"></script>
+		<script src="../examples/js/loaders/AMFLoader.js"></script>
 		<script src="../examples/js/loaders/AWDLoader.js"></script>
 		<script src="../examples/js/loaders/BabylonLoader.js"></script>
 		<script src="../examples/js/loaders/ColladaLoader.js"></script>
+		<script src="../examples/js/loaders/KMZLoader.js"></script>
 		<script src="../examples/js/loaders/MD2Loader.js"></script>
 		<script src="../examples/js/loaders/OBJLoader.js"></script>
 		<script src="../examples/js/loaders/PLYLoader.js"></script>
@@ -67,7 +71,6 @@
 		<script src="js/libs/ternjs/doc_comment.js"></script>
 		<script src="js/libs/tern-threejs/threejs.js"></script>
 
-		<script src="js/libs/jszip.min.js"></script>
 		<script src="js/libs/sortable.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>
 		<script src="js/libs/ui.js"></script>
@@ -151,10 +154,8 @@
 			var sidebar = new Sidebar( editor );
 			document.body.appendChild( sidebar.dom );
 
-			/*
-			var dialog = new UI.Dialog();
-			document.body.appendChild( dialog.dom );
-			*/
+			var modal = new UI.Modal();
+			document.body.appendChild( modal.dom );
 
 			//
 
@@ -184,7 +185,7 @@
 
 				var timeout;
 
-				var saveState = function ( scene ) {
+				function saveState( scene ) {
 
 					if ( editor.config.getKey( 'autosave' ) === false ) {
 
@@ -212,7 +213,6 @@
 
 				var signals = editor.signals;
 
-				signals.editorCleared.add( saveState );
 				signals.geometryChanged.add( saveState );
 				signals.objectAdded.add( saveState );
 				signals.objectChanged.add( saveState );
@@ -221,18 +221,11 @@
 				signals.sceneGraphChanged.add( saveState );
 				signals.scriptChanged.add( saveState );
 
-				/*
-				var showDialog = function ( content ) {
-
-					dialog.clear();
+				signals.showModal.add( function ( content ) {
 
-					dialog.add( content );
-					dialog.showModal();
-
-				};
+					modal.show( content );
 
-				signals.showDialog.add( showDialog );
-				*/
+				} );
 
 			} );
 
@@ -278,11 +271,11 @@
 
 			}, false );
 
-			var onWindowResize = function ( event ) {
+			function onWindowResize( event ) {
 
 				editor.signals.windowResize.dispatch();
 
-			};
+			}
 
 			window.addEventListener( 'resize', onWindowResize, false );
 

+ 1 - 0
editor/js/Config.js

@@ -12,6 +12,7 @@ var Config = function () {
 
 		'project/renderer': 'WebGLRenderer',
 		'project/renderer/antialias': true,
+		'project/renderer/shadows': true,
 		'project/vr': false,
 
 		'ui/sidebar/animation/collapsed': true,

+ 3 - 9
editor/js/Editor.js

@@ -19,7 +19,7 @@ var Editor = function () {
 
 		// actions
 
-		// showDialog: new SIGNALS.Signal(),
+		showModal: new SIGNALS.Signal(),
 
 		// notifications
 
@@ -102,14 +102,6 @@ Editor.prototype = {
 
 	},
 
-	/*
-	showDialog: function ( value ) {
-
-		this.signals.showDialog.dispatch( value );
-
-	},
-	*/
-
 	//
 
 	setScene: function ( scene ) {
@@ -411,6 +403,7 @@ Editor.prototype = {
 	clear: function () {
 
 		this.history.clear();
+		this.storage.clear();
 
 		this.camera.position.set( 500, 250, 500 );
 		this.camera.lookAt( new THREE.Vector3() );
@@ -469,6 +462,7 @@ Editor.prototype = {
 		return {
 
 			project: {
+				shadows: this.config.getKey( 'project/renderer/shadows' ),
 				vr: this.config.getKey( 'project/vr' )
 			},
 			camera: this.camera.toJSON(),

+ 41 - 8
editor/js/Loader.js

@@ -16,6 +16,22 @@ var Loader = function ( editor ) {
 
 		switch ( extension ) {
 
+			case 'amf':
+
+				var reader = new FileReader();
+				reader.addEventListener( 'load', function ( event ) {
+
+					var loader = new THREE.AMFLoader();
+					var amfobject = loader.parse( event.target.result );
+
+					editor.addObject( amfobject );
+					editor.select( amfobject );
+
+				}, false );
+				reader.readAsArrayBuffer( file );
+
+				break;
+
 			case 'awd':
 
 				var reader = new FileReader();
@@ -111,11 +127,8 @@ var Loader = function ( editor ) {
 
 					var contents = event.target.result;
 
-					var parser = new DOMParser();
-					var xml = parser.parseFromString( contents, 'text/xml' );
-
 					var loader = new THREE.ColladaLoader();
-					var collada = loader.parse( xml );
+					var collada = loader.parse( contents );
 
 					collada.scene.name = filename;
 
@@ -184,6 +197,25 @@ var Loader = function ( editor ) {
 
 				break;
 
+
+				case 'kmz':
+
+					var reader = new FileReader();
+					reader.addEventListener( 'load', function ( event ) {
+
+						var loader = new THREE.KMZLoader();
+						var collada = loader.parse( event.target.result );
+
+						collada.scene.name = filename;
+
+						editor.addObject( collada.scene );
+						editor.select( collada.scene );
+
+					}, false );
+					reader.readAsArrayBuffer( file );
+
+					break;
+
 				case 'md2':
 
 					var reader = new FileReader();
@@ -197,11 +229,12 @@ var Loader = function ( editor ) {
 							morphNormals: true
 						} );
 
-						var object = new THREE.MorphAnimMesh( geometry, material );
-						object.name = filename;
+						var mesh = new THREE.Mesh( geometry, material );
+						mesh.mixer = new THREE.AnimationMixer( mesh )
+						mesh.name = filename;
 
-						editor.addObject( object );
-						editor.select( object );
+						editor.addObject( mesh );
+						editor.select( mesh );
 
 					}, false );
 					reader.readAsArrayBuffer( file );

+ 2 - 0
editor/js/Menubar.Add.js

@@ -236,6 +236,7 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
+	/*
 	// Teapot
 
 	var option = new UI.Panel();
@@ -263,6 +264,7 @@ Menubar.Add = function ( editor ) {
 
 	} );
 	options.add( option );
+	*/
 
 	// Sprite
 

+ 21 - 21
editor/js/Menubar.File.js

@@ -86,8 +86,13 @@ Menubar.File = function ( editor ) {
 		}
 
 		var output = geometry.toJSON();
-		output = JSON.stringify( output, null, '\t' );
-		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+
+		try {
+			output = JSON.stringify( output, null, '\t' );
+			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+		} catch ( e ) {
+			output = JSON.stringify( output );
+		}
 
 		exportString( output, 'geometry.json' );
 
@@ -111,8 +116,13 @@ Menubar.File = function ( editor ) {
 		}
 
 		var output = object.toJSON();
-		output = JSON.stringify( output, null, '\t' );
-		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+
+		try {
+			output = JSON.stringify( output, null, '\t' );
+			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+		} catch ( e ) {
+			output = JSON.stringify( output );
+		}
 
 		exportString( output, 'model.json' );
 
@@ -127,8 +137,13 @@ Menubar.File = function ( editor ) {
 	option.onClick( function () {
 
 		var output = editor.scene.toJSON();
-		output = JSON.stringify( output, null, '\t' );
-		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+
+		try {
+			output = JSON.stringify( output, null, '\t' );
+			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
+		} catch ( e ) {
+			output = JSON.stringify( output );
+		}
 
 		exportString( output, 'scene.json' );
 
@@ -260,21 +275,6 @@ Menubar.File = function ( editor ) {
 	} );
 	options.add( option );
 
-	/*
-	// Test
-
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Test' );
-	option.onClick( function () {
-
-		var text = new UI.Text( 'blah' );
-		editor.showDialog( text );
-
-	} );
-	options.add( option );
-	*/
-
 
 	//
 

+ 10 - 6
editor/js/Menubar.Status.js

@@ -23,23 +23,27 @@ Menubar.Status = function ( editor ) {
 	} );
 	container.add( checkbox );
 
-	var title = new UI.Panel();
-	title.setClass( 'title' );
-	title.setTextContent( 'Autosave' );
-	container.add( title );
+	var text = new UI.Text( 'autosave' );
+	text.setClass( 'title' );
+	container.add( text );
 
 	editor.signals.savingStarted.add( function () {
 
-		title.setTextDecoration( 'underline' );
+		text.setTextDecoration( 'underline' );
 
 	} );
 
 	editor.signals.savingFinished.add( function () {
 
-		title.setTextDecoration( 'none' );
+		text.setTextDecoration( 'none' );
 
 	} );
 
+	var version = new UI.Text( 'r' + THREE.REVISION );
+	version.setClass( 'title' );
+	version.setOpacity( 0.5 );
+	container.add( version );
+
 	return container;
 
 };

+ 4 - 0
editor/js/Sidebar.Animation.js

@@ -24,6 +24,8 @@ Sidebar.Animation = function ( editor ) {
 	var animationsRow = new UI.Panel();
 	container.add( animationsRow );
 
+	/*
+
 	var animations = {};
 
 	signals.objectAdded.add( function ( object ) {
@@ -105,6 +107,8 @@ Sidebar.Animation = function ( editor ) {
 
 	} );
 
+	*/
+
 	return container;
 
 }

+ 23 - 3
editor/js/Sidebar.Geometry.CircleGeometry.js

@@ -28,6 +28,26 @@ Sidebar.Geometry.CircleGeometry = function ( signals, object ) {
 
 	container.add( segmentsRow );
 
+	// thetaStart
+
+	var thetaStartRow = new UI.Panel();
+	var thetaStart = new UI.Number( parameters.thetaStart ).onChange( update );
+
+	thetaStartRow.add( new UI.Text( 'Theta start' ).setWidth( '90px' ) );
+	thetaStartRow.add( thetaStart );
+
+	container.add( thetaStartRow );
+
+	// thetaLength
+
+	var thetaLengthRow = new UI.Panel();
+	var thetaLength = new UI.Number( parameters.thetaLength ).onChange( update );
+
+	thetaLengthRow.add( new UI.Text( 'Theta length' ).setWidth( '90px' ) );
+	thetaLengthRow.add( thetaLength );
+
+	container.add( thetaLengthRow );
+
 	//
 
 	function update() {
@@ -36,11 +56,11 @@ Sidebar.Geometry.CircleGeometry = function ( signals, object ) {
 
 		object.geometry = new THREE.CircleGeometry(
 			radius.getValue(),
-			segments.getValue()
+			segments.getValue(),
+			thetaStart.getValue(),
+			thetaLength.getValue()
 		);
 
-		object.geometry.computeBoundingSphere();
-
 		signals.geometryChanged.dispatch( object );
 
 	}

+ 48 - 1
editor/js/Sidebar.Material.js

@@ -223,6 +223,20 @@ Sidebar.Material = function ( editor ) {
 
 	container.add( materialNormalMapRow );
 
+	// displacement map
+
+	var materialDisplacementMapRow = new UI.Panel();
+	var materialDisplacementMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialDisplacementMap = new UI.Texture().onChange( update );
+	var materialDisplacementScale = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
+
+	materialDisplacementMapRow.add( new UI.Text( 'Displace Map' ).setWidth( '90px' ) );
+	materialDisplacementMapRow.add( materialDisplacementMapEnabled );
+	materialDisplacementMapRow.add( materialDisplacementMap );
+	materialDisplacementMapRow.add( materialDisplacementScale );
+
+	container.add( materialDisplacementMapRow );
+
 	// specular map
 
 	var materialSpecularMapRow = new UI.Panel();
@@ -329,7 +343,7 @@ Sidebar.Material = function ( editor ) {
 	// opacity
 
 	var materialOpacityRow = new UI.Panel();
-	var materialOpacity = new UI.Number().setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
+	var materialOpacity = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
 
 	materialOpacityRow.add( new UI.Text( 'Opacity' ).setWidth( '90px' ) );
 	materialOpacityRow.add( materialOpacity );
@@ -517,6 +531,24 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
+			if ( material.displacementMap !== undefined ) {
+
+				var displacementMapEnabled = materialDisplacementMapEnabled.getValue() === true;
+
+				if ( objectHasUvs ) {
+
+					material.displacementMap = displacementMapEnabled ? materialDisplacementMap.getValue() : null;
+					material.displacementScale = materialDisplacementScale.getValue();
+					material.needsUpdate = true;
+
+				} else {
+
+					if ( displacementMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
 			if ( material.specularMap !== undefined ) {
 
 				var specularMapEnabled = materialSpecularMapEnabled.getValue() === true;
@@ -659,6 +691,7 @@ Sidebar.Material = function ( editor ) {
 			'alphaMap': materialAlphaMapRow,
 			'bumpMap': materialBumpMapRow,
 			'normalMap': materialNormalMapRow,
+			'displacementMap': materialDisplacementMapRow,
 			'specularMap': materialSpecularMapRow,
 			'envMap': materialEnvMapRow,
 			'lightMap': materialLightMapRow,
@@ -787,6 +820,20 @@ Sidebar.Material = function ( editor ) {
 
 		}
 
+		if ( material.displacementMap !== undefined ) {
+
+			materialDisplacementMapEnabled.setValue( material.displacementMap !== null );
+
+			if ( material.displacementMap !== null || resetTextureSelectors ) {
+
+				materialDisplacementMap.setValue( material.displacementMap );
+
+			}
+
+			materialDisplacementScale.setValue( material.displacementScale );
+
+		}
+
 		if ( material.specularMap !== undefined ) {
 
 			materialSpecularMapEnabled.setValue( material.specularMap !== null );

+ 67 - 2
editor/js/Sidebar.Object3D.js

@@ -95,6 +95,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	container.add( objectNameRow );
 
+	/*
 	// parent
 
 	var objectParentRow = new UI.Panel();
@@ -104,6 +105,7 @@ Sidebar.Object3D = function ( editor ) {
 	objectParentRow.add( objectParent );
 
 	container.add( objectParentRow );
+	*/
 
 	// position
 
@@ -243,6 +245,30 @@ Sidebar.Object3D = function ( editor ) {
 
 	container.add( objectDecayRow );
 
+	// shadow
+
+	var objectShadowRow = new UI.Panel();
+
+	objectShadowRow.add( new UI.Text( 'Shadow' ).setWidth( '90px' ) );
+
+	var objectCastShadowSpan = new UI.Span().setMarginRight( '10px' );
+	var objectCastShadow = new UI.Checkbox().onChange( update );
+
+	objectCastShadowSpan.add( objectCastShadow );
+	objectCastShadowSpan.add( new UI.Text( 'cast' ).setMarginLeft( '3px' ) );
+
+	objectShadowRow.add( objectCastShadowSpan );
+
+	var objectReceiveShadowSpan = new UI.Span();
+	var objectReceiveShadow = new UI.Checkbox().onChange( update );
+
+	objectReceiveShadowSpan.add( objectReceiveShadow );
+	objectReceiveShadowSpan.add( new UI.Text( 'receive' ).setMarginLeft( '3px' ) );
+
+	objectShadowRow.add( objectReceiveShadowSpan );
+
+	container.add( objectShadowRow );
+
 	// visible
 
 	var objectVisibleRow = new UI.Panel();
@@ -342,6 +368,7 @@ Sidebar.Object3D = function ( editor ) {
 
 		if ( object !== null ) {
 
+			/*
 			if ( object.parent !== null ) {
 
 				var newParentId = parseInt( objectParent.getValue() );
@@ -353,6 +380,7 @@ Sidebar.Object3D = function ( editor ) {
 				}
 
 			}
+			*/
 
 			object.position.x = objectPositionX.getValue();
 			object.position.y = objectPositionY.getValue();
@@ -427,6 +455,25 @@ Sidebar.Object3D = function ( editor ) {
 
 			}
 
+			if ( object.castShadow !== undefined ) {
+
+				object.castShadow = objectCastShadow.getValue();
+
+			}
+
+			if ( object.receiveShadow !== undefined ) {
+
+				var value = objectReceiveShadow.getValue();
+
+				if ( value !== object.receiveShadow ) {
+
+					object.receiveShadow = value;
+					object.material.needsUpdate = true;
+
+				}
+
+			}
+
 			object.visible = objectVisible.getValue();
 
 			try {
@@ -448,7 +495,7 @@ Sidebar.Object3D = function ( editor ) {
 	function updateRows( object ) {
 
 		var properties = {
-			'parent': objectParentRow,
+			// 'parent': objectParentRow,
 			'fov': objectFovRow,
 			'near': objectNearRow,
 			'far': objectFarRow,
@@ -458,7 +505,9 @@ Sidebar.Object3D = function ( editor ) {
 			'distance' : objectDistanceRow,
 			'angle' : objectAngleRow,
 			'exponent' : objectExponentRow,
-			'decay' : objectDecayRow
+			'decay' : objectDecayRow,
+			'castShadow' : objectShadowRow,
+			'receiveShadow' : objectReceiveShadowSpan
 		};
 
 		for ( var property in properties ) {
@@ -505,6 +554,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	} );
 
+	/*
 	signals.sceneGraphChanged.add( function () {
 
 		var scene = editor.scene;
@@ -519,6 +569,7 @@ Sidebar.Object3D = function ( editor ) {
 		objectParent.setOptions( options );
 
 	} );
+	*/
 
 	signals.objectChanged.add( function ( object ) {
 
@@ -535,11 +586,13 @@ Sidebar.Object3D = function ( editor ) {
 		objectUUID.setValue( object.uuid );
 		objectName.setValue( object.name );
 
+		/*
 		if ( object.parent !== null ) {
 
 			objectParent.setValue( object.parent.id );
 
 		}
+		*/
 
 		objectPositionX.setValue( object.position.x );
 		objectPositionY.setValue( object.position.y );
@@ -613,6 +666,18 @@ Sidebar.Object3D = function ( editor ) {
 
 		}
 
+		if ( object.castShadow !== undefined ) {
+
+			objectCastShadow.setValue( object.castShadow );
+
+		}
+
+		if ( object.receiveShadow !== undefined ) {
+
+			objectReceiveShadow.setValue( object.receiveShadow );
+
+		}
+
 		objectVisible.setValue( object.visible );
 
 		try {

+ 43 - 16
editor/js/Sidebar.Project.js

@@ -4,6 +4,7 @@
 
 Sidebar.Project = function ( editor ) {
 
+	var config = editor.config;
 	var signals = editor.signals;
 
 	var rendererTypes = {
@@ -17,10 +18,10 @@ Sidebar.Project = function ( editor ) {
 	};
 
 	var container = new UI.CollapsiblePanel();
-	container.setCollapsed( editor.config.getKey( 'ui/sidebar/project/collapsed' ) );
+	container.setCollapsed( config.getKey( 'ui/sidebar/project/collapsed' ) );
 	container.onCollapsedChange( function ( boolean ) {
 
-		editor.config.setKey( 'ui/sidebar/project/collapsed', boolean );
+		config.setKey( 'ui/sidebar/project/collapsed', boolean );
 
 	} );
 
@@ -42,7 +43,10 @@ Sidebar.Project = function ( editor ) {
 	var rendererTypeRow = new UI.Panel();
 	var rendererType = new UI.Select().setOptions( options ).setWidth( '150px' ).onChange( function () {
 
-		editor.config.setKey( 'project/renderer', this.getValue() );
+		var value = this.getValue();
+
+		config.setKey( 'project/renderer', value );
+
 		updateRenderer();
 
 	} );
@@ -52,33 +56,53 @@ Sidebar.Project = function ( editor ) {
 
 	container.add( rendererTypeRow );
 
-	if ( editor.config.getKey( 'project/renderer' ) !== undefined ) {
+	if ( config.getKey( 'project/renderer' ) !== undefined ) {
 
-		rendererType.setValue( editor.config.getKey( 'project/renderer' ) );
+		rendererType.setValue( config.getKey( 'project/renderer' ) );
 
 	}
 
 	// antialiasing
 
-	var rendererAntialiasRow = new UI.Panel();
-	var rendererAntialias = new UI.Checkbox( editor.config.getKey( 'project/renderer/antialias' ) ).setLeft( '100px' ).onChange( function () {
+	var rendererPropertiesRow = new UI.Panel();
+	rendererPropertiesRow.add( new UI.Text( '' ).setWidth( '90px' ) );
 
-		editor.config.setKey( 'project/renderer/antialias', this.getValue() );
+	var rendererAntialiasSpan = new UI.Span().setMarginRight( '10px' );
+	var rendererAntialias = new UI.Checkbox( config.getKey( 'project/renderer/antialias' ) ).setLeft( '100px' ).onChange( function () {
+
+		config.setKey( 'project/renderer/antialias', this.getValue() );
 		updateRenderer();
 
 	} );
 
-	rendererAntialiasRow.add( new UI.Text( 'Antialias' ).setWidth( '90px' ) );
-	rendererAntialiasRow.add( rendererAntialias );
+	rendererAntialiasSpan.add( rendererAntialias );
+	rendererAntialiasSpan.add( new UI.Text( 'antialias' ).setMarginLeft( '3px' ) );
+
+	rendererPropertiesRow.add( rendererAntialiasSpan );
 
-	container.add( rendererAntialiasRow );
+	// shadow
+
+	var rendererShadowsSpan = new UI.Span();
+	var rendererShadows = new UI.Checkbox( config.getKey( 'project/renderer/shadows' ) ).setLeft( '100px' ).onChange( function () {
+
+		config.setKey( 'project/renderer/shadows', this.getValue() );
+		updateRenderer();
+
+	} );
+
+	rendererShadowsSpan.add( rendererShadows );
+	rendererShadowsSpan.add( new UI.Text( 'shadows' ).setMarginLeft( '3px' ) );
+
+	rendererPropertiesRow.add( rendererShadowsSpan );
+
+	container.add( rendererPropertiesRow );
 
 	// VR
 
 	var vrRow = new UI.Panel();
-	var vr = new UI.Checkbox( editor.config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () {
+	var vr = new UI.Checkbox( config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () {
 
-		editor.config.setKey( 'project/vr', this.getValue() );
+		config.setKey( 'project/vr', this.getValue() );
 		// updateRenderer();
 
 	} );
@@ -92,11 +116,11 @@ Sidebar.Project = function ( editor ) {
 
 	function updateRenderer() {
 
-		createRenderer( rendererType.getValue(), rendererAntialias.getValue() );
+		createRenderer( rendererType.getValue(), rendererAntialias.getValue(), rendererShadows.getValue() );
 
 	}
 
-	function createRenderer( type, antialias ) {
+	function createRenderer( type, antialias, shadows ) {
 
 		if ( type === 'WebGLRenderer' && System.support.webgl === false ) {
 
@@ -104,12 +128,15 @@ Sidebar.Project = function ( editor ) {
 
 		}
 
+		rendererPropertiesRow.setDisplay( type === 'WebGLRenderer' ? '' : 'none' );
+
 		var renderer = new rendererTypes[ type ]( { antialias: antialias } );
+		if ( shadows && renderer.shadowMap ) renderer.shadowMap.enabled = true;
 		signals.rendererChanged.dispatch( renderer );
 
 	}
 
-	createRenderer( editor.config.getKey( 'project/renderer' ), editor.config.getKey( 'project/renderer/antialias' ) );
+	createRenderer( config.getKey( 'project/renderer' ), config.getKey( 'project/renderer/antialias' ), config.getKey( 'project/renderer/shadows' ) );
 
 	return container;
 

+ 2 - 2
editor/js/Storage.js

@@ -76,14 +76,14 @@ var Storage = function () {
 
 		},
 
-		clear: function ( callback ) {
+		clear: function () {
 
 			var transaction = database.transaction( [ 'states' ], 'readwrite' );
 			var objectStore = transaction.objectStore( 'states' );
 			var request = objectStore.clear();
 			request.onsuccess = function ( event ) {
 
-				callback();
+				console.log( '[' + /\d\d\:\d\d\:\d\d/.exec( new Date() )[ 0 ] + ']', 'Cleared IndexedDB.' );
 
 			};
 

+ 7 - 8
editor/js/Toolbar.js

@@ -37,22 +37,21 @@ var Toolbar = function ( editor ) {
 
 	// grid
 
-	var grid = new UI.Number( 25 ).onChange( update );
-	grid.dom.style.width = '42px';
+	var grid = new UI.Number( 25 ).setWidth( '40px' ).onChange( update );
 	buttons.add( new UI.Text( 'Grid: ' ) );
 	buttons.add( grid );
 
-	var snap = new UI.Checkbox( false ).onChange( update );
+	var snap = new UI.Checkbox( false ).onChange( update ).setMarginLeft( '10px' );
 	buttons.add( snap );
-	buttons.add( new UI.Text( 'snap' ) );
+	buttons.add( new UI.Text( 'snap' ).setMarginLeft( '3px' ) );
 
-	var local = new UI.Checkbox( false ).onChange( update );
+	var local = new UI.Checkbox( false ).onChange( update ).setMarginLeft( '10px' );
 	buttons.add( local );
-	buttons.add( new UI.Text( 'local' ) );
+	buttons.add( new UI.Text( 'local' ).setMarginLeft( '3px' ) );
 
-	var showGrid = new UI.Checkbox().onChange( update ).setValue( true );
+	var showGrid = new UI.Checkbox().onChange( update ).setValue( true ).setMarginLeft( '10px' );
 	buttons.add( showGrid );
-	buttons.add( new UI.Text( 'show' ) );
+	buttons.add( new UI.Text( 'show' ).setMarginLeft( '3px' ) );
 
 	function update() {
 

+ 5 - 1
editor/js/Viewport.js

@@ -283,7 +283,7 @@ var Viewport = function ( editor ) {
 
 	signals.snapChanged.add( function ( dist ) {
 
-		transformControls.setSnap( dist );
+		transformControls.setTranslationSnap( dist );
 
 	} );
 
@@ -555,6 +555,8 @@ var Viewport = function ( editor ) {
 
 		requestAnimationFrame( animate );
 
+		/*
+
 		// animations
 
 		if ( THREE.AnimationHandler.animations.length > 0 ) {
@@ -577,6 +579,8 @@ var Viewport = function ( editor ) {
 
 		}
 
+		*/
+
 	}
 
 	function render() {

+ 21 - 21
editor/js/libs/app.js

@@ -27,6 +27,7 @@ var APP = {
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
 			renderer.setClearColor( 0x000000 );
 			renderer.setPixelRatio( window.devicePixelRatio );
+			if ( json.project.shadows ) renderer.shadowMap.enabled = true;
 			this.dom = renderer.domElement;
 
 			this.setScene( loader.parse( json.scene ) );
@@ -98,7 +99,6 @@ var APP = {
 			camera.aspect = this.width / this.height;
 			camera.updateProjectionMatrix();
 
-
 			if ( vr === true ) {
 
 				if ( camera.parent === null ) {
@@ -157,7 +157,7 @@ var APP = {
 
 		};
 
-		var dispatch = function ( array, event ) {
+		function dispatch( array, event ) {
 
 			for ( var i = 0, l = array.length; i < l; i ++ ) {
 
@@ -173,11 +173,11 @@ var APP = {
 
 			}
 
-		};
+		}
 
 		var prevTime, request;
 
-		var animate = function ( time ) {
+		function animate( time ) {
 
 			request = requestAnimationFrame( animate );
 
@@ -196,7 +196,7 @@ var APP = {
 
 			prevTime = time;
 
-		};
+		}
 
 		this.play = function () {
 
@@ -233,53 +233,53 @@ var APP = {
 
 		//
 
-		var onDocumentKeyDown = function ( event ) {
+		function onDocumentKeyDown( event ) {
 
 			dispatch( events.keydown, event );
 
-		};
+		}
 
-		var onDocumentKeyUp = function ( event ) {
+		function onDocumentKeyUp( event ) {
 
 			dispatch( events.keyup, event );
 
-		};
+		}
 
-		var onDocumentMouseDown = function ( event ) {
+		function onDocumentMouseDown( event ) {
 
 			dispatch( events.mousedown, event );
 
-		};
+		}
 
-		var onDocumentMouseUp = function ( event ) {
+		function onDocumentMouseUp( event ) {
 
 			dispatch( events.mouseup, event );
 
-		};
+		}
 
-		var onDocumentMouseMove = function ( event ) {
+		function onDocumentMouseMove( event ) {
 
 			dispatch( events.mousemove, event );
 
-		};
+		}
 
-		var onDocumentTouchStart = function ( event ) {
+		function onDocumentTouchStart( event ) {
 
 			dispatch( events.touchstart, event );
 
-		};
+		}
 
-		var onDocumentTouchEnd = function ( event ) {
+		function onDocumentTouchEnd( event ) {
 
 			dispatch( events.touchend, event );
 
-		};
+		}
 
-		var onDocumentTouchMove = function ( event ) {
+		function onDocumentTouchMove( event ) {
 
 			dispatch( events.touchmove, event );
 
-		};
+		}
 
 	}
 

+ 3 - 163
editor/js/libs/tern-threejs/threejs.js

@@ -409,10 +409,6 @@
           "!type": "[]",
           "!doc": "Array of morph targets. Each morph target is a Javascript object:\n\t\t<code>{ name: \"targetName\", vertices: [ new THREE.Vector3(), ... ] }</code>\n\t\tMorph vertices match number and order of primary vertices."
         },
-        "morphColors": {
-          "!type": "[]",
-          "!doc": "Array of morph colors. Morph colors have similar structure as morph targets, each color set is a Javascript object:\n\t\t<code>morphColor = { name: \"colorName\", colors: [ new THREE.Color(), ... ] }</code>\n\t\tMorph colors can match either the number and order of faces (face colors) or the number of vertices (vertex colors)."
-        },
         "morphNormals": {
           "!type": "[]",
           "!doc": "Array of morph normals. Morph normals have similar structure as morph targets, each normal set is a Javascript object:\n\t\t<code>morphNormal = { name: \"NormalName\", normals: [ new THREE.Vector3(), ... ] }</code>"
@@ -2088,106 +2084,6 @@
         "intensity": {
           "!type": "number",
           "!doc": "Light's intensity.<br>\n\t\t\tDefault — *1.0*."
-        },
-        "onlyShadow": {
-          "!type": "bool",
-          "!doc": "If set to *true* light will only cast shadow but not contribute any lighting (as if *intensity* was 0 but cheaper to compute).<br>\n\t\t\tDefault — *false*."
-        },
-        "shadowCameraNear": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *50*."
-        },
-        "shadowCameraFar": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *5000*."
-        },
-        "shadowCameraLeft": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *-500*."
-        },
-        "shadowCameraRight": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *500*."
-        },
-        "shadowCameraTop": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *500*."
-        },
-        "shadowCameraBottom": {
-          "!type": "number",
-          "!doc": "Orthographic shadow camera frustum parameter.<br>\n\t\t\tDefault — *-500*."
-        },
-        "shadowCameraVisible": {
-          "!type": "bool",
-          "!doc": "Show debug shadow camera frustum.<br>\n\t\t\tDefault — *false*."
-        },
-        "shadowBias": {
-          "!type": "number",
-          "!doc": "Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.<br>\n\t\t\tDefault — *0*."
-        },
-        "shadowDarkness": {
-          "!type": "number",
-          "!doc": "Darkness of shadow casted by this light (from *0* to *1*).<br>\n\t\t\tDefault — *0.5*."
-        },
-        "shadowMapWidth": {
-          "!type": "number",
-          "!doc": "Shadow map texture width in pixels.<br>\n\t\t\tDefault — *512*."
-        },
-        "shadowMapHeight": {
-          "!type": "number",
-          "!doc": "Shadow map texture height in pixels.<br>\n\t\t\tDefault — *512*."
-        },
-        "shadowCascade": {
-          "!type": "bool",
-          "!doc": "**Experimental** If true, use a series of shadow maps in a cascade. This can give better z-depth resolution for a directional light. <br>\n\t\t\tDefault — *false*."
-        },
-        "shadowCascadeCount": {
-          "!type": "number",
-          "!doc": "Number of shadow maps to allocate in a cascade (one after another). <br>\n\t\t\tDefault — *2*."
-        },
-        "shadowCascadeOffset": {
-          "!type": "+THREE.Vector3",
-          "!doc": "A relative position to real camera where virtual shadow cameras are attached. A magic vector; scene and light orientation dependent. <br>\n\t\t\tDefault — *Three.Vector3( 0, 0, -1000 )*."
-        },
-        "shadowCascadeBias": {
-          "!type": "[]",
-          "!doc": "An array of shadowMapBias values for the corresponding shadow map in the cascade, near to far. <br>\n\t\t\tDefault — <strong>[ 0, 0, 0 ]</strong>."
-        },
-        "shadowCascadeWidth": {
-          "!type": "[]",
-          "!doc": "An array of shadowMapWidth values for the corresponding shadow map in the cascade, near to far. <br>\n\t\t\tDefault — <strong>[ 512, 512, 512 ]</strong>."
-        },
-        "shadowCascadeHeight": {
-          "!type": "[]",
-          "!doc": "An array of shadowMapHeight values for the corresponding shadow map in the cascade, near to far. <br>\n\t\t\tDefault — <strong>[ 512, 512, 512 ]</strong>."
-        },
-        "shadowCascadeNearZ": {
-          "!type": "[]",
-          "!doc": "An array of shadowMapNear values for the corresponding shadow map in the cascade, near to far. These typically start with -1.0 (near plane) and match with the previous shadowCascadeFarZ array value.<br>\n\t\t\tDefault — <strong>[ -1.000, 0.990, 0.998 ]</strong>."
-        },
-        "shadowCascadeFarZ": {
-          "!type": "[]",
-          "!doc": "An array of shadowMapFar values for the corresponding shadow map in the cascade, near to far. These typically match with the next shadowCascadeNearZ array value, ending in 1.0.<br>\n\t\t\tDefault — <strong>[ 0.990, 0.998, 1.000 ]</strong>."
-        },
-        "shadowCascadeArray": {
-          "!type": "[]",
-          "!doc": "Array of size shadowCascadeCount of [page:DirectionalLight THREE.DirectionalLight] objects. This holds the series of separate shadow maps in a cascade, near to far. Created internally."
-        },
-        "shadowMapSize": {
-          "!type": "+THREE.Vector2",
-          "!doc": "The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering."
-        },
-        "shadowCamera": {
-          "!type": "+THREE.OrthographicCamera",
-          "!doc": "The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings."
-        },
-        "shadowMatrix": {
-          "!type": "+THREE.Matrix4",
-          "!doc": "Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering."
-        },
-        "shadowMap": {
-          "!type": "+THREE.WebGLRenderTarget",
-          "!doc": "The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering."
         }
       },
       "!doc": "Affects objects using [page:MeshLambertMaterial] or [page:MeshPhongMaterial].",
@@ -2260,62 +2156,6 @@
         "exponent": {
           "!type": "number",
           "!doc": "Rapidity of the falloff of light from its target direction.<br>\n\t\t\tDefault — *10.0*."
-        },
-        "castShadow": {
-          "!type": "bool",
-          "!doc": "If set to *true* light will cast dynamic shadows. *Warning*: This is expensive and requires tweaking to get shadows looking right.<br>\n\t\t\tDefault — *false*."
-        },
-        "onlyShadow": {
-          "!type": "bool",
-          "!doc": "If set to *true* light will only cast shadow but not contribute any lighting (as if *intensity* was 0 but cheaper to compute).<br>\n\t\t\tDefault — *false*."
-        },
-        "shadowCameraNear": {
-          "!type": "number",
-          "!doc": "Perspective shadow camera frustum <em>near</em> parameter.<br>\n\t\t\tDefault — *50*."
-        },
-        "shadowCameraFar": {
-          "!type": "number",
-          "!doc": "Perspective shadow camera frustum <em>far</em> parameter.<br>\n\t\t\tDefault — *5000*."
-        },
-        "shadowCameraFov": {
-          "!type": "number",
-          "!doc": "Perspective shadow camera frustum <em>field of view</em> parameter.<br>\n\t\t\tDefault — *50*."
-        },
-        "shadowCameraVisible": {
-          "!type": "bool",
-          "!doc": "Show debug shadow camera frustum.<br>\n\t\t\tDefault — *false*."
-        },
-        "shadowBias": {
-          "!type": "number",
-          "!doc": "Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.<br>\n\t\t\tDefault — *0*."
-        },
-        "shadowDarkness": {
-          "!type": "number",
-          "!doc": "Darkness of shadow casted by this light (from *0* to *1*).<br>\n\t\t\tDefault — *0.5*."
-        },
-        "shadowMapWidth": {
-          "!type": "number",
-          "!doc": "Shadow map texture width in pixels.<br>\n\t\t\tDefault — *512*."
-        },
-        "shadowMapHeight": {
-          "!type": "number",
-          "!doc": "Shadow map texture height in pixels.<br>\n\t\t\tDefault — *512*."
-        },
-        "shadowMapSize": {
-          "!type": "+THREE.Vector2",
-          "!doc": "The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering."
-        },
-        "shadowCamera": {
-          "!type": "+THREE.PerspectiveCamera",
-          "!doc": "The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings."
-        },
-        "shadowMatrix": {
-          "!type": "+THREE.Matrix4",
-          "!doc": "Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering."
-        },
-        "shadowMap": {
-          "!type": "+THREE.WebGLRenderTarget",
-          "!doc": "The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering."
         }
       },
       "!doc": "A point light that can cast shadow in one direction.",
@@ -2399,7 +2239,7 @@
         },
         "setPreferredShading": {
           "!type": "fn(shading: number)",
-          "!doc": "Set the .[page:Integer shading] property on the resource's materials.<br>\n\t\tOptions are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading]."
+          "!doc": "Set the .[page:Integer shading] property on the resource's materials.<br>\n\t\tOptions are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading]."
         },
         "applySkin": {
           "!type": "fn(geometry: +THREE.Geometry, instanceCtrl: object, frame: number)",
@@ -3068,7 +2908,7 @@
         },
         "shading": {
           "!type": "number",
-          "!doc": "Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading]."
+          "!doc": "Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading]."
         },
         "wireframe": {
           "!type": "bool",
@@ -3212,7 +3052,7 @@
         },
         "shading": {
           "!type": "number",
-          "!doc": "Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading], [page:Materials THREE.NoShading]."
+          "!doc": "Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading]."
         },
         "wireframe": {
           "!type": "bool",

+ 103 - 74
editor/js/libs/ui.js

@@ -12,6 +12,60 @@ UI.Element = function ( dom ) {
 
 UI.Element.prototype = {
 
+	add: function () {
+
+		for ( var i = 0; i < arguments.length; i ++ ) {
+
+			var argument = arguments[ i ];
+
+			if ( argument instanceof UI.Element ) {
+
+				this.dom.appendChild( argument.dom );
+
+			} else {
+
+				console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' )
+
+			}
+
+		}
+
+		return this;
+
+	},
+
+	remove: function () {
+
+		for ( var i = 0; i < arguments.length; i ++ ) {
+
+			var argument = arguments[ i ];
+
+			if ( argument instanceof UI.Element ) {
+
+				this.dom.removeChild( argument.dom );
+
+			} else {
+
+				console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' )
+
+			}
+
+		}
+
+		return this;
+
+	},
+
+	clear: function () {
+
+		while ( this.dom.children.length ) {
+
+			this.dom.removeChild( this.dom.lastChild );
+
+		}
+
+	},
+
 	setId: function ( id ) {
 
 		this.dom.id = id;
@@ -36,6 +90,8 @@ UI.Element.prototype = {
 
 		}
 
+		return this;
+
 	},
 
 	setDisabled: function ( value ) {
@@ -69,6 +125,7 @@ properties.forEach( function ( property ) {
 	UI.Element.prototype[ method ] = function () {
 
 		this.setStyle( property, arguments );
+
 		return this;
 
 	};
@@ -93,78 +150,39 @@ events.forEach( function ( event ) {
 
 } );
 
+// Span
 
-// Panel
-
-UI.Panel = function () {
+UI.Span = function () {
 
 	UI.Element.call( this );
 
-	var dom = document.createElement( 'div' );
-	dom.className = 'Panel';
-
-	this.dom = dom;
-
-	return this;
-};
-
-UI.Panel.prototype = Object.create( UI.Element.prototype );
-UI.Panel.prototype.constructor = UI.Panel;
-
-UI.Panel.prototype.add = function () {
-
-	for ( var i = 0; i < arguments.length; i ++ ) {
-
-		var argument = arguments[ i ];
-
-		if ( argument instanceof UI.Element ) {
-
-			this.dom.appendChild( argument.dom );
-
-		} else {
-
-			console.error( 'UI.Panel:', argument, 'is not an instance of UI.Element.' )
-
-		}
-
-	}
+	this.dom = document.createElement( 'span' );
 
 	return this;
 
 };
 
+UI.Span.prototype = Object.create( UI.Element.prototype );
+UI.Span.prototype.constructor = UI.Span;
 
-UI.Panel.prototype.remove = function () {
-
-	for ( var i = 0; i < arguments.length; i ++ ) {
-
-		var argument = arguments[ i ];
 
-		if ( argument instanceof UI.Element ) {
-
-			this.dom.removeChild( argument.dom );
+// Panel
 
-		} else {
+UI.Panel = function () {
 
-			console.error( 'UI.Panel:', argument, 'is not an instance of UI.Element.' )
+	UI.Element.call( this );
 
-		}
+	var dom = document.createElement( 'div' );
+	dom.className = 'Panel';
 
-	}
+	this.dom = dom;
 
 	return this;
 
 };
 
-UI.Panel.prototype.clear = function () {
-
-	while ( this.dom.children.length ) {
-
-		this.dom.removeChild( this.dom.lastChild );
-
-	}
-
-};
+UI.Panel.prototype = Object.create( UI.Element.prototype );
+UI.Panel.prototype.constructor = UI.Panel;
 
 
 // Collapsible Panel
@@ -996,47 +1014,58 @@ UI.Button.prototype.setLabel = function ( value ) {
 };
 
 
-// Dialog
+// Modal
 
-UI.Dialog = function ( value ) {
+UI.Modal = function ( value ) {
 
 	var scope = this;
 
-	var dom = document.createElement( 'dialog' );
+	var dom = document.createElement( 'div' );
 
-	if ( dom.showModal === undefined ) {
+	dom.style.position = 'absolute';
+	dom.style.width = '100%';
+	dom.style.height = '100%';
+	dom.style.backgroundColor = 'rgba(0,0,0,0.5)';
+	dom.style.display = 'none';
+	dom.style.alignItems = 'center';
+	dom.style.justifyContent = 'center';
+	dom.addEventListener( 'click', function ( event ) {
 
-		// fallback
+		scope.hide();
 
-		dom = document.createElement( 'div' );
-		dom.style.display = 'none';
+	} );
 
-		dom.showModal = function () {
+	this.dom = dom;
 
-			dom.style.position = 'absolute';
-			dom.style.left = '100px';
-			dom.style.top = '100px';
-			dom.style.zIndex = 1;
-			dom.style.display = '';
+	this.container = new UI.Panel();
+	this.container.dom.style.width = '200px';
+	this.container.dom.style.padding = '20px';
+	this.container.dom.style.backgroundColor = '#ffffff';
+	this.container.dom.style.boxShadow = '0px 5px 10px rgba(0,0,0,0.5)';
 
-		};
+	this.add( this.container );
 
-	}
+	return this;
 
-	dom.className = 'Dialog';
+};
 
-	this.dom = dom;
+UI.Modal.prototype = Object.create( UI.Element.prototype );
+UI.Modal.prototype.constructor = UI.Modal;
+
+UI.Modal.prototype.show = function ( content ) {
+
+	this.container.clear();
+	this.container.add( content );
+
+	this.dom.style.display = 'flex';
 
 	return this;
 
 };
 
-UI.Dialog.prototype = Object.create( UI.Panel.prototype );
-UI.Dialog.prototype.constructor = UI.Dialog;
-
-UI.Dialog.prototype.showModal = function () {
+UI.Modal.prototype.hide = function () {
 
-	this.dom.showModal();
+	this.dom.style.display = 'none';
 
 	return this;
 

+ 1 - 1
examples/canvas_geometry_panorama_fisheye.html

@@ -103,7 +103,7 @@
 				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
 				document.addEventListener( 'mouseup', onDocumentMouseUp, false );
 				document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
-				document.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
+				document.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);
 
 				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
 				document.addEventListener( 'touchmove', onDocumentTouchMove, false );

+ 8 - 4
examples/canvas_geometry_text.html

@@ -23,8 +23,8 @@
 
 		<script src="js/libs/stats.min.js"></script>
 
-		<!-- load the font file from canvas-text -->
-
+		<script src="js/geometries/TextGeometry.js"></script>
+		<script src="js/utils/FontUtils.js"></script>
 		<script src="fonts/helvetiker_regular.typeface.js"></script>
 
 
@@ -90,8 +90,12 @@
 				text3d.computeBoundingBox();
 				var centerOffset = -0.5 * ( text3d.boundingBox.max.x - text3d.boundingBox.min.x );
 
-				var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } );
-				text = new THREE.Mesh( text3d, textMaterial );
+				var material = new THREE.MeshFaceMaterial( [
+					new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } ),
+					new THREE.MeshBasicMaterial( { color: 0x000000, overdraw: 0.5 } )
+				] );
+
+				text = new THREE.Mesh( text3d, material );
 
 				text.position.x = centerOffset;
 				text.position.y = 100;

+ 2 - 2
examples/canvas_interactive_cubes.html

@@ -139,8 +139,8 @@
 
 				event.preventDefault();
 
-				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
-				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
+				mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
 
 				raycaster.setFromCamera( mouse, camera );
 

+ 2 - 2
examples/canvas_interactive_cubes_tween.html

@@ -119,8 +119,8 @@
 
 				event.preventDefault();
 
-				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
-				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
+				mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
 
 				raycaster.setFromCamera( mouse, camera );
 

+ 2 - 2
examples/canvas_interactive_voxelpainter.html

@@ -141,8 +141,8 @@
 
 				event.preventDefault();
 
-				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
-				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
+				mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
 
 				raycaster.setFromCamera( mouse, camera );
 

+ 0 - 1
examples/canvas_materials.html

@@ -73,7 +73,6 @@
 					new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.AdditiveBlending } ),
 					new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: 0.5 } ),
 					new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.SmoothShading, overdraw: 0.5 } ),
-					new THREE.MeshDepthMaterial( { overdraw: 0.5 } ),
 					new THREE.MeshNormalMaterial( { overdraw: 0.5 } ),
 					new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/land_ocean_ice_cloud_2048.jpg' ) } ),
 					new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'textures/envmap.png', THREE.SphericalReflectionMapping ), overdraw: 0.5 } )

+ 0 - 238
examples/canvas_materials_depth.html

@@ -1,238 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js canvas - depth material</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<style>
-			body {
-				font-family: Monospace;
-				background-color: #000000;
-				margin: 0px;
-				overflow: hidden;
-			}
-		</style>
-	</head>
-	<body>
-
-		<script src="../build/three.min.js"></script>
-
-		<script src="js/renderers/Projector.js"></script>
-		<script src="js/renderers/CanvasRenderer.js"></script>
-
-		<script src="js/libs/stats.min.js"></script>
-
-		<script>
-
-			var container, stats;
-
-			var camera, scene, renderer;
-
-			var cube, plane, objects = [];
-
-			var targetRotation = 0;
-			var targetRotationOnMouseDown = 0;
-
-			var mouseX = 0;
-			var mouseXOnMouseDown = 0;
-
-			var moveForward = false;
-			var moveBackwards = false;
-			var moveLeft = false;
-			var moveRight = false;
-			var moveUp = false;
-			var moveDown = false;
-
-			var targetMoveLeft = false;
-			var targetMoveRight = false;
-
-			var debugContext;
-
-			init();
-			animate();
-
-			function init() {
-
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
-				camera.position.set( 1000, 1000, 1000 );
-				camera.target = new THREE.Vector3( 0, 150, 0 );
-
-				scene = new THREE.Scene();
-
-				// Plane
-
-				var material = new THREE.MeshDepthMaterial( { side: THREE.DoubleSide, overdraw: 0.5 } );
-
-				plane = new THREE.Mesh( new THREE.PlaneBufferGeometry( 1000, 1000, 10, 10 ), material );
-				plane.position.y = - 100;
-				plane.rotation.x = - Math.PI / 2;
-				scene.add( plane );
-
-				// Cubes
-
-				geometry = new THREE.BoxGeometry( 100, 100, 100 );
-				material = new THREE.MeshDepthMaterial( { overdraw: 0.5 } );
-
-				for ( var i = 0; i < 20; i ++ ) {
-
-					cube = new THREE.Mesh( geometry, material );
-
-					cube.position.x = ( i % 5 ) * 200 - 400;
-					cube.position.z = Math.floor( i / 5 ) * 200 - 350;
-
-					cube.rotation.x = Math.random() * 200 - 100;
-					cube.rotation.y = Math.random() * 200 - 100;
-					cube.rotation.z = Math.random() * 200 - 100;
-
-					scene.add( cube );
-
-					objects.push( cube );
-
-				}
-
-				renderer = new THREE.CanvasRenderer();
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				container.appendChild( renderer.domElement );
-
-				var debugCanvas = document.createElement( 'canvas' );
-				debugCanvas.width = 512;
-				debugCanvas.height = 512;
-				debugCanvas.style.position = 'absolute';
-				debugCanvas.style.top = '0px';
-				debugCanvas.style.left = '0px';
-
-				container.appendChild( debugCanvas );
-
-				debugContext = debugCanvas.getContext( '2d' );
-				debugContext.setTransform( 1, 0, 0, 1, 256, 256 );
-				debugContext.strokeStyle = '#808080';
-
-				stats = new Stats();
-				stats.domElement.style.position = 'absolute';
-				stats.domElement.style.top = '0px';
-				container.appendChild(stats.domElement);
-
-				document.addEventListener( 'keydown', onDocumentKeyDown, false );
-				document.addEventListener( 'keyup', onDocumentKeyUp, false );
-
-				//
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function onWindowResize() {
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-			}
-
-			function onDocumentKeyDown( event ) {
-
-				switch ( event.keyCode ) {
-
-					case 38: moveForward = true; break; // up
-					case 40: moveBackwards = true; break; // down
-					case 37: moveLeft = true; break; // left
-					case 39: moveRight = true; break; // right
-					case 87: moveUp = true; break; // w
-					case 83: moveDown = true; break; // s
-					case 65: targetMoveLeft = true; break; // a
-					case 68: targetMoveRight = true; break; // d
-
-				}
-
-			}
-
-			function onDocumentKeyUp( event ) {
-
-				switch ( event.keyCode ) {
-
-					case 38: moveForward = false; break; // up
-					case 40: moveBackwards = false; break; // down
-					case 37: moveLeft = false; break; // left
-					case 39: moveRight = false; break; // right
-					case 87: moveUp = false; break; // w
-					case 83: moveDown = false; break; // s
-					case 65: targetMoveLeft = false; break; // a
-					case 68: targetMoveRight = false; break; // d
-
-				}
-
-			}
-
-			//
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				render();
-				stats.update();
-
-			}
-
-			function render() {
-
-				if ( moveForward ) camera.position.z -= 10;
-				if ( moveBackwards ) camera.position.z += 10;
-
-				if ( moveLeft ) camera.position.x -= 10;
-				if ( moveRight ) camera.position.x += 10;
-
-				if ( moveUp ) camera.position.y += 10;
-				if ( moveDown ) camera.position.y -= 10;
-
-				if ( targetMoveLeft ) camera.target.x -= 10;
-				if ( targetMoveRight ) camera.target.x += 10;
-
-				camera.lookAt( camera.target );
-
-				debugContext.clearRect( - 256, - 256, 512, 512 );
-
-				debugContext.beginPath();
-
-				// center
-				debugContext.moveTo( - 10, 0 );
-				debugContext.lineTo( 10, 0 );
-				debugContext.moveTo( 0, - 10 );
-				debugContext.lineTo( 0, 10 );
-
-				// camera
-
-				debugContext.moveTo( camera.position.x * 0.1, camera.position.z * 0.1 );
-				debugContext.lineTo( camera.target.x * 0.1, camera.target.z * 0.1 );
-				debugContext.rect( camera.position.x * 0.1 - 5, camera.position.z * 0.1 - 5, 10, 10 );
-				debugContext.rect( camera.target.x * 0.1 - 5, camera.target.z * 0.1 - 5, 10, 10 );
-				debugContext.rect( - 50, - 50, 100, 100 );
-
-				for ( var i = 0; i < objects.length; i++ ) {
-
-					var object = objects[ i ];
-
-					object.rotation.x += 0.01;
-					object.rotation.y += 0.005;
-					object.position.y = Math.sin( object.rotation.x ) * 200 + 200;
-
-					debugContext.rect( object.position.x * 0.1 - 5, object.position.z * 0.1 - 5, 10, 10 );
-
-				}
-
-				debugContext.closePath();
-				debugContext.stroke();
-
-				renderer.render( scene, camera );
-
-			}
-
-		</script>
-
-	</body>
-</html>

+ 10 - 4
examples/canvas_morphtargets_horse.html

@@ -54,25 +54,31 @@
 
 				//
 
-				var light = new THREE.DirectionalLight( 0xefefff, 2 );
+				var light = new THREE.DirectionalLight( 0xefefff, 1.5 );
 				light.position.set( 1, 1, 1 ).normalize();
 				scene.add( light );
 
-				var light = new THREE.DirectionalLight( 0xffefef, 2 );
+				var light = new THREE.DirectionalLight( 0xffefef, 1.5 );
 				light.position.set( -1, -1, -1 ).normalize();
 				scene.add( light );
 
 				var loader = new THREE.JSONLoader();
 				loader.load( "models/animated/horse.js", function ( geometry ) {
 
-					mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x606060, morphTargets: true, overdraw: 0.5 } ) );
+					var material = new THREE.MeshLambertMaterial( {
+						vertexColors: THREE.FaceColors,
+						morphTargets: true,
+						overdraw: 0.5
+					} );
+
+					mesh = new THREE.Mesh( geometry, material );
 					mesh.scale.set( 1.5, 1.5, 1.5 );
 					scene.add( mesh );
 
 					mixer = new THREE.AnimationMixer( mesh );
 
 					var clip = THREE.AnimationClip.CreateFromMorphTargetSequence( 'gallop', geometry.morphTargets, 30 );
-					mixer.addAction( new THREE.AnimationAction( clip ).warpToDuration( 1.5 ) );
+					mixer.addAction( new THREE.AnimationAction( clip ).warpToDuration( 1 ) );
 
 				} );
 

+ 4 - 6
examples/css3d_youtube.html

@@ -69,7 +69,7 @@
 				image.style.position = 'absolute';
 				image.style.width = '480px';
 				image.style.height = '360px';
-				image.src = entry.media$group.media$thumbnail[ 2 ].url;
+				image.src = entry.snippet.thumbnails.default.url;
 				dom.appendChild( image );
 
 				var button = document.createElement( 'img' );
@@ -140,7 +140,7 @@
 					player.style.width = '480px';
 					player.style.height = '360px';
 					player.style.border = '0px';
-					player.src = 'http://www.youtube.com/embed/' + entry.id.$t.split( ':' ).pop() + '?rel=0&autoplay=1&controls=1&showinfo=0';
+					player.src = 'http://www.youtube.com/embed/' + entry.id.videoId + '?rel=0&autoplay=1&controls=1&showinfo=0';
 					this.appendChild( player );
 
 					//
@@ -265,7 +265,7 @@
 
 				var request = new XMLHttpRequest();
 				request.addEventListener( 'load', onData, false );
-				request.open( 'GET', 'https://gdata.youtube.com/feeds/api/videos?v=2&alt=json&max-results=50&q=' + query, true );
+				request.open( 'GET', 'https://www.googleapis.com/youtube/v3/search?key={YOUR_API_KEY}&part=snippet&q=' + query, true );
 				request.send( null );
 
 			}
@@ -273,9 +273,7 @@
 			function onData( event ) {
 
 				var data = JSON.parse( event.target.responseText );
-				var entries = data.feed.entry;
-
-				// console.log( entries );
+				var entries = data.items;
 
 				for ( var i = 0; i < entries.length; i ++ ) {
 

+ 21 - 15
examples/index.html

@@ -13,7 +13,7 @@
 				font-style: normal;
 			}
 
-			*{
+			* {
 				box-sizing: border-box;
 			}
 
@@ -190,6 +190,7 @@
 		var files = {
 			"webgl": [
 				"webgl_animation_cloth",
+				"webgl_animation_scene",
 				"webgl_animation_skinning_blending",
 				"webgl_animation_skinning_morph",
 				"webgl_camera",
@@ -219,11 +220,13 @@
 				"webgl_geometry_nurbs",
 				"webgl_geometry_shapes",
 				"webgl_geometry_spline_editor",
+				"webgl_geometry_teapot",
 				"webgl_geometry_terrain",
 				"webgl_geometry_terrain_fog",
 				"webgl_geometry_terrain_raycast",
 				"webgl_geometry_text",
-				"webgl_geometry_text2",
+				"webgl_geometry_text_earcut",
+				"webgl_geometry_text_pnltri",
 				"webgl_gpgpu_birds",
 				"webgl_gpu_particle_system",
 				"webgl_hdr",
@@ -234,8 +237,8 @@
 				"webgl_interactive_cubes_ortho",
 				"webgl_interactive_draggablecubes",
 				"webgl_interactive_lines",
-				"webgl_interactive_particles",
-				"webgl_interactive_raycasting_pointcloud",
+				"webgl_interactive_points",
+				"webgl_interactive_raycasting_points",
 				"webgl_interactive_voxelpainter",
 				"webgl_kinect",
 				"webgl_lensflares",
@@ -247,6 +250,7 @@
 				"webgl_lines_dashed",
 				"webgl_lines_sphere",
 				"webgl_lines_splines",
+				"webgl_loader_amf",
 				"webgl_loader_assimp2json",
 				"webgl_loader_awd",
 				"webgl_loader_babylon",
@@ -294,6 +298,7 @@
 				"webgl_materials_cubemap_dynamic2",
 				"webgl_materials_cubemap_escher",
 				"webgl_materials_cubemap_refraction",
+				"webgl_materials_displacementmap",
 				"webgl_materials_envmaps",
 				"webgl_materials_grass",
 				"webgl_materials_lightmap",
@@ -328,14 +333,14 @@
 				"webgl_octree",
 				"webgl_octree_raycasting",
 				"webgl_panorama_equirectangular",
-				"webgl_particles_billboards",
-				"webgl_particles_billboards_colors",
-				"webgl_particles_dynamic",
-				"webgl_particles_random",
-				"webgl_particles_sprites",
 				"webgl_performance",
 				"webgl_performance_doublesided",
 				"webgl_performance_static",
+				"webgl_points_billboards",
+				"webgl_points_billboards_colors",
+				"webgl_points_dynamic",
+				"webgl_points_random",
+				"webgl_points_sprites",
 				"webgl_postprocessing",
 				"webgl_postprocessing_advanced",
 				"webgl_postprocessing_crossfade",
@@ -345,6 +350,7 @@
 				"webgl_postprocessing_godrays",
 				"webgl_postprocessing_ssao",
 				"webgl_raycast_texture",
+				"webgl_read_float_buffer",
 				"webgl_rtt",
 				"webgl_sandbox",
 				"webgl_shader",
@@ -358,6 +364,7 @@
 				"webgl_shading_physical",
 				"webgl_shadowmap",
 				"webgl_shadowmap_performance",
+				"webgl_shadowmap_pointlight",
 				"webgl_shadowmap_viewer",
 				"webgl_shadowmesh",
 				"webgl_skinning_simple",
@@ -379,15 +386,15 @@
 				"webgl_buffergeometry_instancing_interleaved_dynamic",
 				"webgl_buffergeometry_lines",
 				"webgl_buffergeometry_lines_indexed",
-				"webgl_buffergeometry_particles",
+				"webgl_buffergeometry_points",
 				"webgl_buffergeometry_rawshader",
-				"webgl_buffergeometry_teapot",
+				"webgl_buffergeometry_selective_draw",
 				"webgl_buffergeometry_uint",
 				"webgl_custom_attributes",
 				"webgl_custom_attributes_lines",
-				"webgl_custom_attributes_particles",
-				"webgl_custom_attributes_particles2",
-				"webgl_custom_attributes_particles3"
+				"webgl_custom_attributes_points",
+				"webgl_custom_attributes_points2",
+				"webgl_custom_attributes_points3"
 			],
 			"vr": [
 				"vr_cubes",
@@ -447,7 +454,6 @@
 				"canvas_lines_dashed",
 				"canvas_lines_sphere",
 				"canvas_materials",
-				"canvas_materials_depth",
 				"canvas_materials_normal",
 				"canvas_materials_reflection",
 				"canvas_materials_video",

+ 0 - 170
examples/js/AudioObject.js

@@ -1,170 +0,0 @@
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * AudioObject
- *
- *	- 3d spatialized sound with Doppler-shift effect
- *
- *	- uses Audio API (currently supported in WebKit-based browsers)
- *		https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
- *
- *	- based on Doppler effect demo from Chromium
- * 		http://chromium.googlecode.com/svn/trunk/samples/audio/doppler.html
- *
- * - parameters
- *
- *		- listener
- *			dopplerFactor	// A constant used to determine the amount of pitch shift to use when rendering a doppler effect.
- *			speedOfSound	// The speed of sound used for calculating doppler shift. The default value is 343.3 meters / second.
- *
- *		- panner
- *			refDistance		// A reference distance for reducing volume as source move further from the listener.
- *			maxDistance		// The maximum distance between source and listener, after which the volume will not be reduced any further.
- *			rolloffFactor	// Describes how quickly the volume is reduced as source moves away from listener.
- * 			coneInnerAngle	// An angle inside of which there will be no volume reduction.
- *			coneOuterAngle 	// An angle outside of which the volume will be reduced to a constant value of coneOuterGain.
- *			coneOuterGain	// Amount of volume reduction outside of the coneOuterAngle.
- */
-
-THREE.AudioObject = function ( url, volume, playbackRate, loop ) {
-
-	THREE.Object3D.call( this );
-
-	if ( playbackRate === undefined ) playbackRate = 1;
-	if ( volume === undefined ) volume = 1;
-	if ( loop === undefined ) loop = true;
-
-	if ( ! this.context ) {
-
-		try {
-
-			THREE.AudioObject.prototype.context = new webkitAudioContext();
-
-		} catch ( error ) {
-
-			console.warn( "THREE.AudioObject: webkitAudioContext not found" );
-			return this;
-
-		}
-
-	}
-
-	this.directionalSource = false;
-
-	this.listener = this.context.listener;
-	this.panner = this.context.createPanner();
-	this.source = this.context.createBufferSource();
-
-	this.masterGainNode = this.context.createGainNode();
-	this.dryGainNode = this.context.createGainNode();
-
-	// Setup initial gains
-
-	this.masterGainNode.gain.value = volume;
-	this.dryGainNode.gain.value = 3.0;
-
-	// Connect dry mix
-
-	this.source.connect( this.panner );
-	this.panner.connect( this.dryGainNode );
-	this.dryGainNode.connect( this.masterGainNode );
-
-	// Connect master gain
-
-	this.masterGainNode.connect( this.context.destination );
-
-	// Set source parameters and load sound
-
-	this.source.playbackRate.value = playbackRate;
-	this.source.loop = loop;
-
-	loadBufferAndPlay( url );
-
-	// private properties
-
-	var soundPosition = new THREE.Vector3(),
-	cameraPosition = new THREE.Vector3(),
-	oldSoundPosition = new THREE.Vector3(),
-	oldCameraPosition = new THREE.Vector3(),
-
-	soundDelta = new THREE.Vector3(),
-	cameraDelta = new THREE.Vector3(),
-
-	soundFront = new THREE.Vector3(),
-	cameraFront = new THREE.Vector3(),
-	soundUp = new THREE.Vector3(),
-	cameraUp = new THREE.Vector3();
-
-	var _this = this;
-
-	// API
-
-	this.setVolume = function ( volume ) {
-
-		this.masterGainNode.gain.value = volume;
-
-	};
-
-	this.update = function ( camera ) {
-
-		oldSoundPosition.copy( soundPosition );
-		oldCameraPosition.copy( cameraPosition );
-
-		soundPosition.setFromMatrixPosition( this.matrixWorld );
-		cameraPosition.setFromMatrixPosition( camera.matrixWorld );
-
-		soundDelta.subVectors( soundPosition, oldSoundPosition );
-		cameraDelta.subVectors( cameraPosition, oldCameraPosition );
-
-		cameraUp.copy( camera.up );
-
-		cameraFront.set( 0, 0, - 1 );
-		cameraFront.transformDirection( camera.matrixWorld );
-
-		this.listener.setPosition( cameraPosition.x, cameraPosition.y, cameraPosition.z );
-		this.listener.setVelocity( cameraDelta.x, cameraDelta.y, cameraDelta.z );
-		this.listener.setOrientation( cameraFront.x, cameraFront.y, cameraFront.z, cameraUp.x, cameraUp.y, cameraUp.z );
-
-		this.panner.setPosition( soundPosition.x, soundPosition.y, soundPosition.z );
-		this.panner.setVelocity( soundDelta.x, soundDelta.y, soundDelta.z );
-
-		if ( this.directionalSource ) {
-
-			soundFront.set( 0, 0, - 1 );
-			soundFront.transformDirection( this.matrixWorld );
-
-			soundUp.copy( this.up );
-			this.panner.setOrientation( soundFront.x, soundFront.y, soundFront.z, soundUp.x, soundUp.y, soundUp.z );
-
-		}
-
-
-	};
-
-	function loadBufferAndPlay( url ) {
-
-		// Load asynchronously
-
-		var request = new XMLHttpRequest();
-		request.open( "GET", url, true );
-		request.responseType = "arraybuffer";
-
-		request.onload = function() {
-
-			_this.source.buffer = _this.context.createBuffer( request.response, true );
-			_this.source.noteOn( 0 );
-
-		};
-
-		request.send();
-
-	}
-
-};
-
-THREE.AudioObject.prototype = Object.create( THREE.Object3D.prototype );
-THREE.AudioObject.prototype.constructor = THREE.AudioObject;
-
-THREE.AudioObject.prototype.context = null;
-THREE.AudioObject.prototype.type = null;
-

+ 9 - 9
examples/js/BlendCharacter.js

@@ -4,7 +4,7 @@
 
 THREE.BlendCharacter = function () {
 
-	this.clips = {};
+	this.animations = {};
 	this.weightSchedule = [];
 	this.warpSchedule = [];
 
@@ -23,10 +23,10 @@ THREE.BlendCharacter = function () {
 			scope.mixer = new THREE.AnimationMixer( scope );
 
 			// Create the animations		
-			for ( var i = 0; i < geometry.clips.length; ++ i ) {
+			for ( var i = 0; i < geometry.animations.length; ++ i ) {
 
-				var animName = geometry.clips[ i ].name;
-				scope.clips[ animName ] = geometry.clips[ i ];
+				var animName = geometry.animations[ i ].name;
+				scope.animations[ animName ] = geometry.animations[ i ];
 
 			}
 
@@ -47,7 +47,7 @@ THREE.BlendCharacter = function () {
 
 		this.mixer.removeAllActions();
 		
-		this.mixer.play( new THREE.AnimationAction( this.clips[ animName ] ) );
+		this.mixer.play( new THREE.AnimationAction( this.animations[ animName ] ) );
 
 	};
 
@@ -55,8 +55,8 @@ THREE.BlendCharacter = function () {
 
 		this.mixer.removeAllActions();
  
-		var fromAction = new THREE.AnimationAction( this.clips[ fromAnimName ] );
-		var toAction = new THREE.AnimationAction( this.clips[ toAnimName ] );
+		var fromAction = new THREE.AnimationAction( this.animations[ fromAnimName ] );
+		var toAction = new THREE.AnimationAction( this.animations[ toAnimName ] );
 
 		this.mixer.play( fromAction );
 		this.mixer.play( toAction );
@@ -69,8 +69,8 @@ THREE.BlendCharacter = function () {
 
 		this.mixer.removeAllActions();
 
-		var fromAction = new THREE.AnimationAction( this.clips[ fromAnimName ] );
-		var toAction = new THREE.AnimationAction( this.clips[ toAnimName ] );
+		var fromAction = new THREE.AnimationAction( this.animations[ fromAnimName ] );
+		var toAction = new THREE.AnimationAction( this.animations[ toAnimName ] );
 
 		this.mixer.play( fromAction );
 		this.mixer.play( toAction );

+ 1 - 1
examples/js/GPUParticleSystem.js

@@ -370,7 +370,7 @@ THREE.GPUParticleContainer = function(maxParticles, particleSystem) {
   self.particleShaderMat = self.GPUParticleSystem.particleShaderMat;
 
   this.init = function() {
-    self.particleSystem = new THREE.PointCloud(self.particleShaderGeo, self.particleShaderMat);
+    self.particleSystem = new THREE.Points(self.particleShaderGeo, self.particleShaderMat);
     self.particleSystem.frustumCulled = false;
     this.add(self.particleSystem);
   };

+ 5 - 5
examples/js/MD2Character.js

@@ -56,7 +56,7 @@ THREE.MD2Character = function () {
 			scope.meshBody = mesh;
 
 			scope.meshBody.clipOffset = 0;
-			scope.activeAnimationClipName = mesh.geometry.clips[0].name;
+			scope.activeAnimationClipName = mesh.geometry.animations[0].name;
 
 			scope.mixer = new THREE.AnimationMixer( mesh );
 
@@ -158,7 +158,7 @@ THREE.MD2Character = function () {
 				this.meshBody.activeAction = null;
 			}
 
-			var clip = THREE.AnimationClip.findByName( this.meshBody.geometry.clips, clipName );
+			var clip = THREE.AnimationClip.findByName( this.meshBody.geometry.animations, clipName );
 			if( clip ) {
 
 				var action = new THREE.AnimationAction( clip, this.mixer.time ).setLocalRoot( this.meshBody );
@@ -187,7 +187,7 @@ THREE.MD2Character = function () {
 				this.meshWeapon.activeAction = null;
 			}
 
-			var clip = THREE.AnimationClip.findByName( this.meshWeapon.geometry.clips, clipName );
+			var clip = THREE.AnimationClip.findByName( this.meshWeapon.geometry.animations, clipName );
 			if( clip ) {
 
 				var action = new THREE.AnimationAction( clip ).syncWith( this.meshBody.activeAction ).setLocalRoot( this.meshWeapon );
@@ -225,8 +225,8 @@ THREE.MD2Character = function () {
 
 	function createPart( geometry, skinMap ) {
 
-		var materialWireframe = new THREE.MeshLambertMaterial( { color: 0xffaa00, wireframe: true, shading: THREE.SmoothShading, morphTargets: true, morphNormals: true } );
-		var materialTexture = new THREE.MeshLambertMaterial( { color: 0xffffff, wireframe: false, shading: THREE.SmoothShading, map: skinMap, morphTargets: true, morphNormals: true } );
+		var materialWireframe = new THREE.MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+		var materialTexture = new THREE.MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
 
 		//
 

+ 2 - 2
examples/js/MD2CharacterComplex.js

@@ -522,8 +522,8 @@ THREE.MD2CharacterComplex = function () {
 
 	function createPart( geometry, skinMap ) {
 
-		var materialWireframe = new THREE.MeshLambertMaterial( { color: 0xffaa00, wireframe: true, shading: THREE.SmoothShading, morphTargets: true, morphNormals: true } );
-		var materialTexture = new THREE.MeshLambertMaterial( { color: 0xffffff, wireframe: false, shading: THREE.SmoothShading, map: skinMap, morphTargets: true, morphNormals: true } );
+		var materialWireframe = new THREE.MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+		var materialTexture = new THREE.MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
 
 		//
 

+ 1 - 3
examples/js/MarchingCubes.js

@@ -7,9 +7,7 @@
 
 THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors ) {
 
-	THREE.ImmediateRenderObject.call( this );
-
-	this.material = material;
+	THREE.ImmediateRenderObject.call( this, material );
 
 	this.enableUvs = enableUvs !== undefined ? enableUvs : false;
 	this.enableColors = enableColors !== undefined ? enableColors : false;

+ 2 - 2
examples/js/MorphAnimMesh.js

@@ -36,7 +36,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
 		
 	}
 
-	var clip = THREE.AnimationClip.findByName( this.geometry.clips, label );
+	var clip = THREE.AnimationClip.findByName( this.geometry.animations, label );
 
 	if ( clip ) {
 
@@ -47,7 +47,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
 
 	} else {
 
-		throw new Error( 'THREE.MorphAnimMesh: clips[' + label + '] undefined in .playAnimation()' );
+		throw new Error( 'THREE.MorphAnimMesh: animations[' + label + '] undefined in .playAnimation()' );
 
 	}
 

+ 54 - 60
examples/js/ShaderSkin.js

@@ -160,6 +160,7 @@ THREE.ShaderSkin = {
 
 				"vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
 				"vec4 diffuseColor = vec4( diffuse, opacity );",
+				"vec3 shadowMask = vec3( 1.0 );",
 
 				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
 				"colDiffuse.rgb *= colDiffuse.rgb;",
@@ -167,7 +168,7 @@ THREE.ShaderSkin = {
 				"diffuseColor = diffuseColor * colDiffuse;",
 
 				"vec3 normal = normalize( vNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
+				"vec3 viewerDirection = normalize( vViewPosition );",
 
 				"float specularStrength;",
 
@@ -207,10 +208,10 @@ THREE.ShaderSkin = {
 						"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, lVector ) + 0.5, 0.0 );",
 						"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), uWrapRGB );",
 
-						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewerDirection, uRoughness, uSpecularBrightness );",
 
-						"totalDiffuseLight += attenuation * pointLightColor[ i ] * pointDiffuseWeight;",
-						"totalSpecularLight += attenuation * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
+						"totalDiffuseLight += pointLightColor[ i ] * ( pointDiffuseWeight * attenuation );",
+						"totalSpecularLight += pointLightColor[ i ] * specular * ( pointSpecularWeight * specularStrength * attenuation );",
 
 					"}",
 
@@ -222,16 +223,16 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
+						"vec3 dirVector = directionalLightDirection[ i ];",
 
 						"float dirDiffuseWeightFull = max( dot( normal, dirVector ), 0.0 );",
 						"float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
 						"vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), uWrapRGB );",
 
-						"float dirSpecularWeight = KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"float dirSpecularWeight = KS_Skin_Specular( normal, dirVector, viewerDirection, uRoughness, uSpecularBrightness );",
 
 						"totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
-						"totalSpecularLight += specular * directionalLightColor[ i ] * dirSpecularWeight * specularStrength;",
+						"totalSpecularLight += directionalLightColor[ i ] * ( dirSpecularWeight * specularStrength );",
 
 					"}",
 
@@ -243,7 +244,7 @@ THREE.ShaderSkin = {
 
 					"for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
-						"vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );",
+						"vec3 lVector = hemisphereLightDirection[ i ];",
 
 						"float dotProduct = dot( normal, lVector );",
 						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
@@ -253,22 +254,28 @@ THREE.ShaderSkin = {
 						// specular (sky light)
 
 						"float hemiSpecularWeight = 0.0;",
-						"hemiSpecularWeight += KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"hemiSpecularWeight += KS_Skin_Specular( normal, lVector, viewerDirection, uRoughness, uSpecularBrightness );",
 
 						// specular (ground light)
 
 						"vec3 lVectorGround = -lVector;",
-						"hemiSpecularWeight += KS_Skin_Specular( normal, lVectorGround, viewPosition, uRoughness, uSpecularBrightness );",
+						"hemiSpecularWeight += KS_Skin_Specular( normal, lVectorGround, viewerDirection, uRoughness, uSpecularBrightness );",
 
-						"totalSpecularLight += specular * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * specularStrength;",
+						"vec3 hemiSpecularColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
+
+						"totalSpecularLight += hemiSpecularColor * specular * ( hemiSpecularWeight * specularStrength );",
 
 					"}",
 
 				"#endif",
 
+				THREE.ShaderChunk[ "shadowmap_fragment" ],
+
+				"totalDiffuseLight *= shadowMask;",
+				"totalSpecularLight *= shadowMask;",
+
 				"outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor * diffuse ) + totalSpecularLight;",
 
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
 				THREE.ShaderChunk[ "fog_fragment" ],
 
@@ -384,8 +391,6 @@ THREE.ShaderSkin = {
 
 			"uniform float uNormalScale;",
 
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
 			"varying vec3 vNormal;",
 			"varying vec2 vUv;",
 
@@ -453,20 +458,29 @@ THREE.ShaderSkin = {
 
 				"vec4 mSpecular = vec4( specular, opacity );",
 
-				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
-				"normalTex.xy *= uNormalScale;",
-				"normalTex = normalize( normalTex );",
-
 				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
 				"colDiffuse *= colDiffuse;",
 
 				"diffuseColor *= colDiffuse;",
 
-				"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
+				// normal mapping
+
+				"vec4 posAndU = vec4( -vViewPosition, vUv.x );",
+				"vec4 posAndU_dx = dFdx( posAndU ),  posAndU_dy = dFdy( posAndU );",
+				"vec3 tangent = posAndU_dx.w * posAndU_dx.xyz + posAndU_dy.w * posAndU_dy.xyz;",
+				"vec3 normal = normalize( vNormal );",
+				"vec3 binormal = normalize( cross( tangent, normal ) );",
+				"tangent = cross( normal, binormal );",	// no normalization required
+				"mat3 tsb = mat3( tangent, binormal, normal );",
+
+				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
+				"normalTex.xy *= uNormalScale;",
+				"normalTex = normalize( normalTex );",
+
 				"vec3 finalNormal = tsb * normalTex;",
+				"normal = normalize( finalNormal );",
 
-				"vec3 normal = normalize( finalNormal );",
-				"vec3 viewPosition = normalize( vViewPosition );",
+				"vec3 viewerDirection = normalize( vViewPosition );",
 
 				// point lights
 
@@ -478,14 +492,19 @@ THREE.ShaderSkin = {
 					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
 						"vec3 pointVector = normalize( vPointLight[ i ].xyz );",
-						"float pointDistance = vPointLight[ i ].w;",
+						"float attenuation = vPointLight[ i ].w;",
 
 						"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
 
-						"totalDiffuseLight += pointDistance * pointLightColor[ i ] * pointDiffuseWeight;",
+						"totalDiffuseLight += pointLightColor[ i ] * ( pointDiffuseWeight * attenuation );",
+
+						"if ( passID == 1 ) {",
+
+							"float pointSpecularWeight = KS_Skin_Specular( normal, pointVector, viewerDirection, uRoughness, uSpecularBrightness );",
+
+							"totalSpecularLight += pointLightColor[ i ] * mSpecular.xyz * ( pointSpecularWeight * attenuation );",
 
-						"if ( passID == 1 )",
-							"totalSpecularLight += pointDistance * mSpecular.xyz * pointLightColor[ i ] * KS_Skin_Specular( normal, pointVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"}",
 
 					"}",
 
@@ -497,14 +516,19 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
+						"vec3 dirVector = directionalLightDirection[ i ];",
 
 						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
 
 						"totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
 
-						"if ( passID == 1 )",
-							"totalSpecularLight += mSpecular.xyz * directionalLightColor[ i ] * KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"if ( passID == 1 ) {",
+
+							"float dirSpecularWeight = KS_Skin_Specular( normal, dirVector, viewerDirection, uRoughness, uSpecularBrightness );",
+
+							"totalSpecularLight += directionalLightColor[ i ] * mSpecular.xyz * dirSpecularWeight;",
+
+						"}",
 
 					"}",
 
@@ -572,8 +596,6 @@ THREE.ShaderSkin = {
 
 		vertexShader: [
 
-			"attribute vec4 tangent;",
-
 			"#ifdef VERTEX_TEXTURES",
 
 				"uniform sampler2D tDisplacement;",
@@ -582,8 +604,6 @@ THREE.ShaderSkin = {
 
 			"#endif",
 
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
 			"varying vec3 vNormal;",
 			"varying vec2 vUv;",
 
@@ -611,13 +631,6 @@ THREE.ShaderSkin = {
 
 				"vNormal = normalize( normalMatrix * normal );",
 
-				// tangent and binormal vectors
-
-				"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
-				"vBinormal = normalize( vBinormal );",
-
 				"vUv = uv;",
 
 				// point lights
@@ -626,7 +639,7 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
 
-						"vec3 lVector = pointLightPosition[ i ] - mvPosition.xyz;",
+						"vec3 lVector = pointLightPosition[ i ] - vViewPosition;",
 
 						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 
@@ -659,18 +672,6 @@ THREE.ShaderSkin = {
 
 		vertexShaderUV: [
 
-			"attribute vec4 tangent;",
-
-			"#ifdef VERTEX_TEXTURES",
-
-				"uniform sampler2D tDisplacement;",
-				"uniform float uDisplacementScale;",
-				"uniform float uDisplacementBias;",
-
-			"#endif",
-
-			"varying vec3 vTangent;",
-			"varying vec3 vBinormal;",
 			"varying vec3 vNormal;",
 			"varying vec2 vUv;",
 
@@ -698,13 +699,6 @@ THREE.ShaderSkin = {
 
 				"vNormal = normalize( normalMatrix * normal );",
 
-				// tangent and binormal vectors
-
-				"vTangent = normalize( normalMatrix * tangent.xyz );",
-
-				"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
-				"vBinormal = normalize( vBinormal );",
-
 				"vUv = uv;",
 
 				// point lights
@@ -713,7 +707,7 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
 
-						"vec3 lVector = pointLightPosition[ i ] - mvPosition.xyz;",
+						"vec3 lVector = pointLightPosition[ i ] - vViewPosition;",
 
 						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 

+ 1 - 1
examples/js/UCSCharacter.js

@@ -55,7 +55,7 @@ THREE.UCSCharacter = function() {
 			mesh.castShadow = true;
 			mesh.receiveShadow = true;
 
-			scope.mixer.addAction( new THREE.AnimationAction( geometry.clips[0] ).setLocalRoot( mesh ) );
+			scope.mixer.addAction( new THREE.AnimationAction( geometry.animations[0] ).setLocalRoot( mesh ) );
 			
 			scope.setSkin( 0 );
 			

+ 2 - 2
examples/js/controls/EditorControls.js

@@ -214,7 +214,7 @@ THREE.EditorControls = function ( object, domElement ) {
 		domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		domElement.removeEventListener( 'mousedown', onMouseDown, false );
 		domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
-		domElement.removeEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
+		domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
 
 		domElement.removeEventListener( 'mousemove', onMouseMove, false );
 		domElement.removeEventListener( 'mouseup', onMouseUp, false );
@@ -229,7 +229,7 @@ THREE.EditorControls = function ( object, domElement ) {
 	domElement.addEventListener( 'contextmenu', contextmenu, false );
 	domElement.addEventListener( 'mousedown', onMouseDown, false );
 	domElement.addEventListener( 'mousewheel', onMouseWheel, false );
-	domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
+	domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
 
 	// touch
 

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

@@ -778,7 +778,7 @@
 			this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
 			this.domElement.removeEventListener( 'mousedown', onMouseDown, false );
 			this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
-			this.domElement.removeEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
+			this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
 
 			this.domElement.removeEventListener( 'touchstart', touchstart, false );
 			this.domElement.removeEventListener( 'touchend', touchend, false );
@@ -795,7 +795,7 @@
 
 		this.domElement.addEventListener( 'mousedown', onMouseDown, false );
 		this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
-		this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
+		this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
 
 		this.domElement.addEventListener( 'touchstart', touchstart, false );
 		this.domElement.addEventListener( 'touchend', touchend, false );

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

@@ -245,7 +245,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 			if ( Math.abs( factor - 1.0 ) > EPS && factor > 0.0 ) {
 
-				_this.object.zoom *= factor;
+				_this.object.zoom /= factor;
 
 				if ( _this.staticMoving ) {
 
@@ -617,7 +617,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		this.domElement.removeEventListener( 'mousedown', mousedown, false );
 		this.domElement.removeEventListener( 'mousewheel', mousewheel, false );
-		this.domElement.removeEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
+		this.domElement.removeEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
 
 		this.domElement.removeEventListener( 'touchstart', touchstart, false );
 		this.domElement.removeEventListener( 'touchend', touchend, false );
@@ -635,7 +635,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 	this.domElement.addEventListener( 'contextmenu', contextmenu, false );
 	this.domElement.addEventListener( 'mousedown', mousedown, false );
 	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
-	this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
+	this.domElement.addEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
 
 	this.domElement.addEventListener( 'touchstart', touchstart, false );
 	this.domElement.addEventListener( 'touchend', touchend, false );

+ 2 - 2
examples/js/controls/TrackballControls.js

@@ -597,7 +597,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 		this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
 		this.domElement.removeEventListener( 'mousedown', mousedown, false );
 		this.domElement.removeEventListener( 'mousewheel', mousewheel, false );
-		this.domElement.removeEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
+		this.domElement.removeEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
 
 		this.domElement.removeEventListener( 'touchstart', touchstart, false );
 		this.domElement.removeEventListener( 'touchend', touchend, false );
@@ -614,7 +614,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 	this.domElement.addEventListener( 'contextmenu', contextmenu, false );
 	this.domElement.addEventListener( 'mousedown', mousedown, false );
 	this.domElement.addEventListener( 'mousewheel', mousewheel, false );
-	this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
+	this.domElement.addEventListener( 'MozMousePixelScroll', mousewheel, false ); // firefox
 
 	this.domElement.addEventListener( 'touchstart', touchstart, false );
 	this.domElement.addEventListener( 'touchend', touchend, false );

+ 54 - 13
examples/js/controls/TransformControls.js

@@ -617,7 +617,8 @@
 
 		this.object = undefined;
 		this.visible = false;
-		this.snap = null;
+		this.translationSnap = null;
+		this.rotationSnap = null;
 		this.space = "world";
 		this.size = 1;
 		this.axis = null;
@@ -750,9 +751,15 @@
 
 		};
 
-		this.setSnap = function ( snap ) {
+		this.setTranslationSnap = function ( translationSnap ) {
 
-			scope.snap = snap;
+			scope.translationSnap = translationSnap;
+
+		};
+
+		this.setRotationSnap = function ( rotationSnap ) {
+
+			scope.rotationSnap = rotationSnap;
 
 		};
 
@@ -930,11 +937,23 @@
 
 				}
 
-				if ( scope.snap !== null ) {
+				if ( scope.translationSnap !== null ) {
 
-					if ( scope.axis.search( "X" ) !== - 1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.snap ) * scope.snap;
-					if ( scope.axis.search( "Y" ) !== - 1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.snap ) * scope.snap;
-					if ( scope.axis.search( "Z" ) !== - 1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.snap ) * scope.snap;
+					if ( scope.space === "local" ) {
+
+						scope.object.position.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
+
+					}
+
+					if ( scope.axis.search( "X" ) !== - 1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.translationSnap ) * scope.translationSnap;
+					if ( scope.axis.search( "Y" ) !== - 1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.translationSnap ) * scope.translationSnap;
+					if ( scope.axis.search( "Z" ) !== - 1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.translationSnap ) * scope.translationSnap;
+
+					if ( scope.space === "local" ) {
+
+						scope.object.position.applyMatrix4( worldRotationMatrix );
+
+					}
 
 				}
 
@@ -1013,9 +1032,20 @@
 					offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) );
 
 					quaternionXYZ.setFromRotationMatrix( oldRotationMatrix );
-					quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
-					quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
-					quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
+
+					if ( scope.rotationSnap !== null ) {
+
+						quaternionX.setFromAxisAngle( unitX, Math.round( ( rotation.x - offsetRotation.x ) / scope.rotationSnap ) * scope.rotationSnap );
+						quaternionY.setFromAxisAngle( unitY, Math.round( ( rotation.y - offsetRotation.y ) / scope.rotationSnap ) * scope.rotationSnap );
+						quaternionZ.setFromAxisAngle( unitZ, Math.round( ( rotation.z - offsetRotation.z ) / scope.rotationSnap ) * scope.rotationSnap );
+
+					} else {
+
+						quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
+						quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
+						quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
+
+					}
 
 					if ( scope.axis === "X" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX );
 					if ( scope.axis === "Y" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY );
@@ -1030,9 +1060,20 @@
 
 					tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
 
-					quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
-					quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
-					quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
+					if ( scope.rotationSnap !== null ) {
+
+						quaternionX.setFromAxisAngle( unitX, Math.round( ( rotation.x - offsetRotation.x ) / scope.rotationSnap ) * scope.rotationSnap );
+						quaternionY.setFromAxisAngle( unitY, Math.round( ( rotation.y - offsetRotation.y ) / scope.rotationSnap ) * scope.rotationSnap );
+						quaternionZ.setFromAxisAngle( unitZ, Math.round( ( rotation.z - offsetRotation.z ) / scope.rotationSnap ) * scope.rotationSnap );
+
+					} else {
+
+						quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
+						quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
+						quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
+
+					}
+
 					quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
 
 					if ( scope.axis === "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );

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

@@ -721,7 +721,7 @@ THREE.TeapotBufferGeometry = function ( size, segments, bottom, lid, body, fitLi
 
 	}
 
-	this.addIndex( new THREE.BufferAttribute( indices, 1 ) );
+	this.setIndex( new THREE.BufferAttribute( indices, 1 ) );
 	this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
 	this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
 	this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

+ 0 - 0
src/extras/geometries/TextGeometry.js → examples/js/geometries/TextGeometry.js


+ 674 - 0
examples/js/libs/earcut.js

@@ -0,0 +1,674 @@
+/**
+ *
+ * Earcut https://github.com/mapbox/earcut
+ *
+ * Copyright (c) 2015, Mapbox
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose
+ * with or without fee is hereby granted, provided that the above copyright notice
+ * and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+'use strict';
+
+//module.exports = earcut;
+
+function earcut(data, holeIndices, dim) {
+
+    dim = dim || 2;
+
+    var hasHoles = holeIndices && holeIndices.length,
+        outerLen = hasHoles ? holeIndices[0] * dim : data.length,
+        outerNode = filterPoints(data, linkedList(data, 0, outerLen, dim, true)),
+        triangles = [];
+
+    if (!outerNode) return triangles;
+
+    var minX, minY, maxX, maxY, x, y, size;
+
+    if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
+
+    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
+    if (data.length > 80 * dim) {
+        minX = maxX = data[0];
+        minY = maxY = data[1];
+
+        for (var i = dim; i < outerLen; i += dim) {
+            x = data[i];
+            y = data[i + 1];
+            if (x < minX) minX = x;
+            if (y < minY) minY = y;
+            if (x > maxX) maxX = x;
+            if (y > maxY) maxY = y;
+        }
+
+        // minX, minY and size are later used to transform coords into integers for z-order calculation
+        size = Math.max(maxX - minX, maxY - minY);
+    }
+
+    earcutLinked(data, outerNode, triangles, dim, minX, minY, size);
+
+    return triangles;
+}
+
+// create a circular doubly linked list from polygon points in the specified winding order
+function linkedList(data, start, end, dim, clockwise) {
+    var sum = 0,
+        i, j, last;
+
+    // calculate original winding order of a polygon ring
+    for (i = start, j = end - dim; i < end; i += dim) {
+        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
+        j = i;
+    }
+
+    // link points into circular doubly-linked list in the specified winding order
+    if (clockwise === (sum > 0)) {
+        for (i = start; i < end; i += dim) last = insertNode(i, last);
+    } else {
+        for (i = end - dim; i >= start; i -= dim) last = insertNode(i, last);
+    }
+
+    return last;
+}
+
+// eliminate colinear or duplicate points
+function filterPoints(data, start, end) {
+    if (!start) return start;
+    if (!end) end = start;
+
+    var node = start,
+        again;
+    do {
+        again = false;
+
+        if (!node.steiner && (equals(data, node.i, node.next.i) || orient(data, node.prev.i, node.i, node.next.i) === 0)) {
+            removeNode(node);
+            node = end = node.prev;
+            if (node === node.next) return null;
+            again = true;
+
+        } else {
+            node = node.next;
+        }
+    } while (again || node !== end);
+
+    return end;
+}
+
+// main ear slicing loop which triangulates a polygon (given as a linked list)
+function earcutLinked(data, ear, triangles, dim, minX, minY, size, pass) {
+    if (!ear) return;
+
+    // interlink polygon nodes in z-order
+    if (!pass && minX !== undefined) indexCurve(data, ear, minX, minY, size);
+
+    var stop = ear,
+        prev, next;
+
+    // iterate through ears, slicing them one by one
+    while (ear.prev !== ear.next) {
+        prev = ear.prev;
+        next = ear.next;
+
+        if (isEar(data, ear, minX, minY, size)) {
+            // cut off the triangle
+            triangles.push(prev.i / dim);
+            triangles.push(ear.i / dim);
+            triangles.push(next.i / dim);
+
+            removeNode(ear);
+
+            // skipping the next vertice leads to less sliver triangles
+            ear = next.next;
+            stop = next.next;
+
+            continue;
+        }
+
+        ear = next;
+
+        // if we looped through the whole remaining polygon and can't find any more ears
+        if (ear === stop) {
+            // try filtering points and slicing again
+            if (!pass) {
+                earcutLinked(data, filterPoints(data, ear), triangles, dim, minX, minY, size, 1);
+
+            // if this didn't work, try curing all small self-intersections locally
+            } else if (pass === 1) {
+                ear = cureLocalIntersections(data, ear, triangles, dim);
+                earcutLinked(data, ear, triangles, dim, minX, minY, size, 2);
+
+            // as a last resort, try splitting the remaining polygon into two
+            } else if (pass === 2) {
+                splitEarcut(data, ear, triangles, dim, minX, minY, size);
+            }
+
+            break;
+        }
+    }
+}
+
+// check whether a polygon node forms a valid ear with adjacent nodes
+function isEar(data, ear, minX, minY, size) {
+
+    var a = ear.prev.i,
+        b = ear.i,
+        c = ear.next.i,
+
+        ax = data[a], ay = data[a + 1],
+        bx = data[b], by = data[b + 1],
+        cx = data[c], cy = data[c + 1],
+
+        abd = ax * by - ay * bx,
+        acd = ax * cy - ay * cx,
+        cbd = cx * by - cy * bx,
+        A = abd - acd - cbd;
+
+    if (A <= 0) return false; // reflex, can't be an ear
+
+    // now make sure we don't have other points inside the potential ear;
+    // the code below is a bit verbose and repetitive but this is done for performance
+
+    var cay = cy - ay,
+        acx = ax - cx,
+        aby = ay - by,
+        bax = bx - ax,
+        i, px, py, s, t, k, node;
+
+    // if we use z-order curve hashing, iterate through the curve
+    if (minX !== undefined) {
+
+        // triangle bbox; min & max are calculated like this for speed
+        var minTX = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
+            minTY = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
+            maxTX = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
+            maxTY = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy),
+
+            // z-order range for the current triangle bbox;
+            minZ = zOrder(minTX, minTY, minX, minY, size),
+            maxZ = zOrder(maxTX, maxTY, minX, minY, size);
+
+        // first look for points inside the triangle in increasing z-order
+        node = ear.nextZ;
+
+        while (node && node.z <= maxZ) {
+            i = node.i;
+            node = node.nextZ;
+            if (i === a || i === c) continue;
+
+            px = data[i];
+            py = data[i + 1];
+
+            s = cay * px + acx * py - acd;
+            if (s >= 0) {
+                t = aby * px + bax * py + abd;
+                if (t >= 0) {
+                    k = A - s - t;
+                    if ((k >= 0) && ((s && t) || (s && k) || (t && k))) return false;
+                }
+            }
+        }
+
+        // then look for points in decreasing z-order
+        node = ear.prevZ;
+
+        while (node && node.z >= minZ) {
+            i = node.i;
+            node = node.prevZ;
+            if (i === a || i === c) continue;
+
+            px = data[i];
+            py = data[i + 1];
+
+            s = cay * px + acx * py - acd;
+            if (s >= 0) {
+                t = aby * px + bax * py + abd;
+                if (t >= 0) {
+                    k = A - s - t;
+                    if ((k >= 0) && ((s && t) || (s && k) || (t && k))) return false;
+                }
+            }
+        }
+
+    // if we don't use z-order curve hash, simply iterate through all other points
+    } else {
+        node = ear.next.next;
+
+        while (node !== ear.prev) {
+            i = node.i;
+            node = node.next;
+
+            px = data[i];
+            py = data[i + 1];
+
+            s = cay * px + acx * py - acd;
+            if (s >= 0) {
+                t = aby * px + bax * py + abd;
+                if (t >= 0) {
+                    k = A - s - t;
+                    if ((k >= 0) && ((s && t) || (s && k) || (t && k))) return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+// go through all polygon nodes and cure small local self-intersections
+function cureLocalIntersections(data, start, triangles, dim) {
+    var node = start;
+    do {
+        var a = node.prev,
+            b = node.next.next;
+
+        // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
+        if (a.i !== b.i && intersects(data, a.i, node.i, node.next.i, b.i) &&
+                locallyInside(data, a, b) && locallyInside(data, b, a) &&
+                orient(data, a.i, node.i, b.i) && orient(data, a.i, node.next.i, b.i)) {
+
+            triangles.push(a.i / dim);
+            triangles.push(node.i / dim);
+            triangles.push(b.i / dim);
+
+            // remove two nodes involved
+            removeNode(node);
+            removeNode(node.next);
+
+            node = start = b;
+        }
+        node = node.next;
+    } while (node !== start);
+
+    return node;
+}
+
+// try splitting polygon into two and triangulate them independently
+function splitEarcut(data, start, triangles, dim, minX, minY, size) {
+    // look for a valid diagonal that divides the polygon into two
+    var a = start;
+    do {
+        var b = a.next.next;
+        while (b !== a.prev) {
+            if (a.i !== b.i && isValidDiagonal(data, a, b)) {
+                // split the polygon in two by the diagonal
+                var c = splitPolygon(a, b);
+
+                // filter colinear points around the cuts
+                a = filterPoints(data, a, a.next);
+                c = filterPoints(data, c, c.next);
+
+                // run earcut on each half
+                earcutLinked(data, a, triangles, dim, minX, minY, size);
+                earcutLinked(data, c, triangles, dim, minX, minY, size);
+                return;
+            }
+            b = b.next;
+        }
+        a = a.next;
+    } while (a !== start);
+}
+
+// link every hole into the outer loop, producing a single-ring polygon without holes
+function eliminateHoles(data, holeIndices, outerNode, dim) {
+    var queue = [],
+        i, len, start, end, list;
+
+    for (i = 0, len = holeIndices.length; i < len; i++) {
+        start = holeIndices[i] * dim;
+        end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
+        list = linkedList(data, start, end, dim, false);
+        if (list === list.next) list.steiner = true;
+        list = filterPoints(data, list);
+        if (list) queue.push(getLeftmost(data, list));
+    }
+
+    queue.sort(function (a, b) {
+        return data[a.i] - data[b.i];
+    });
+
+    // process holes from left to right
+    for (i = 0; i < queue.length; i++) {
+        eliminateHole(data, queue[i], outerNode);
+        outerNode = filterPoints(data, outerNode, outerNode.next);
+    }
+
+    return outerNode;
+}
+
+// find a bridge between vertices that connects hole with an outer ring and and link it
+function eliminateHole(data, holeNode, outerNode) {
+    outerNode = findHoleBridge(data, holeNode, outerNode);
+    if (outerNode) {
+        var b = splitPolygon(outerNode, holeNode);
+        filterPoints(data, b, b.next);
+    }
+}
+
+// David Eberly's algorithm for finding a bridge between hole and outer polygon
+function findHoleBridge(data, holeNode, outerNode) {
+    var node = outerNode,
+        i = holeNode.i,
+        px = data[i],
+        py = data[i + 1],
+        qMax = -Infinity,
+        mNode, a, b;
+
+    // find a segment intersected by a ray from the hole's leftmost point to the left;
+    // segment's endpoint with lesser x will be potential connection point
+    do {
+        a = node.i;
+        b = node.next.i;
+
+        if (py <= data[a + 1] && py >= data[b + 1]) {
+            var qx = data[a] + (py - data[a + 1]) * (data[b] - data[a]) / (data[b + 1] - data[a + 1]);
+            if (qx <= px && qx > qMax) {
+                qMax = qx;
+                mNode = data[a] < data[b] ? node : node.next;
+            }
+        }
+        node = node.next;
+    } while (node !== outerNode);
+
+    if (!mNode) return null;
+
+    // look for points strictly inside the triangle of hole point, segment intersection and endpoint;
+    // if there are no points found, we have a valid connection;
+    // otherwise choose the point of the minimum angle with the ray as connection point
+
+    var bx = data[mNode.i],
+        by = data[mNode.i + 1],
+        pbd = px * by - py * bx,
+        pcd = px * py - py * qMax,
+        cpy = py - py,
+        pcx = px - qMax,
+        pby = py - by,
+        bpx = bx - px,
+        A = pbd - pcd - (qMax * by - py * bx),
+        sign = A <= 0 ? -1 : 1,
+        stop = mNode,
+        tanMin = Infinity,
+        mx, my, amx, s, t, tan;
+
+    node = mNode.next;
+
+    while (node !== stop) {
+
+        mx = data[node.i];
+        my = data[node.i + 1];
+        amx = px - mx;
+
+        if (amx >= 0 && mx >= bx) {
+            s = (cpy * mx + pcx * my - pcd) * sign;
+            if (s >= 0) {
+                t = (pby * mx + bpx * my + pbd) * sign;
+
+                if (t >= 0 && A * sign - s - t >= 0) {
+                    tan = Math.abs(py - my) / amx; // tangential
+                    if ((tan < tanMin || (tan === tanMin && mx > bx)) &&
+                            locallyInside(data, node, holeNode)) {
+                        mNode = node;
+                        tanMin = tan;
+                    }
+                }
+            }
+        }
+
+        node = node.next;
+    }
+
+    return mNode;
+}
+
+// interlink polygon nodes in z-order
+function indexCurve(data, start, minX, minY, size) {
+    var node = start;
+
+    do {
+        if (node.z === null) node.z = zOrder(data[node.i], data[node.i + 1], minX, minY, size);
+        node.prevZ = node.prev;
+        node.nextZ = node.next;
+        node = node.next;
+    } while (node !== start);
+
+    node.prevZ.nextZ = null;
+    node.prevZ = null;
+
+    sortLinked(node);
+}
+
+// Simon Tatham's linked list merge sort algorithm
+// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
+function sortLinked(list) {
+    var i, p, q, e, tail, numMerges, pSize, qSize,
+        inSize = 1;
+
+    do {
+        p = list;
+        list = null;
+        tail = null;
+        numMerges = 0;
+
+        while (p) {
+            numMerges++;
+            q = p;
+            pSize = 0;
+            for (i = 0; i < inSize; i++) {
+                pSize++;
+                q = q.nextZ;
+                if (!q) break;
+            }
+
+            qSize = inSize;
+
+            while (pSize > 0 || (qSize > 0 && q)) {
+
+                if (pSize === 0) {
+                    e = q;
+                    q = q.nextZ;
+                    qSize--;
+                } else if (qSize === 0 || !q) {
+                    e = p;
+                    p = p.nextZ;
+                    pSize--;
+                } else if (p.z <= q.z) {
+                    e = p;
+                    p = p.nextZ;
+                    pSize--;
+                } else {
+                    e = q;
+                    q = q.nextZ;
+                    qSize--;
+                }
+
+                if (tail) tail.nextZ = e;
+                else list = e;
+
+                e.prevZ = tail;
+                tail = e;
+            }
+
+            p = q;
+        }
+
+        tail.nextZ = null;
+        inSize *= 2;
+
+    } while (numMerges > 1);
+
+    return list;
+}
+
+// z-order of a point given coords and size of the data bounding box
+function zOrder(x, y, minX, minY, size) {
+    // coords are transformed into non-negative 15-bit integer range
+    x = 32767 * (x - minX) / size;
+    y = 32767 * (y - minY) / size;
+
+    x = (x | (x << 8)) & 0x00FF00FF;
+    x = (x | (x << 4)) & 0x0F0F0F0F;
+    x = (x | (x << 2)) & 0x33333333;
+    x = (x | (x << 1)) & 0x55555555;
+
+    y = (y | (y << 8)) & 0x00FF00FF;
+    y = (y | (y << 4)) & 0x0F0F0F0F;
+    y = (y | (y << 2)) & 0x33333333;
+    y = (y | (y << 1)) & 0x55555555;
+
+    return x | (y << 1);
+}
+
+// find the leftmost node of a polygon ring
+function getLeftmost(data, start) {
+    var node = start,
+        leftmost = start;
+    do {
+        if (data[node.i] < data[leftmost.i]) leftmost = node;
+        node = node.next;
+    } while (node !== start);
+
+    return leftmost;
+}
+
+// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
+function isValidDiagonal(data, a, b) {
+    return a.next.i !== b.i && a.prev.i !== b.i &&
+           !intersectsPolygon(data, a, a.i, b.i) &&
+           locallyInside(data, a, b) && locallyInside(data, b, a) &&
+           middleInside(data, a, a.i, b.i);
+}
+
+// winding order of triangle formed by 3 given points
+function orient(data, p, q, r) {
+    var o = (data[q + 1] - data[p + 1]) * (data[r] - data[q]) - (data[q] - data[p]) * (data[r + 1] - data[q + 1]);
+    return o > 0 ? 1 :
+           o < 0 ? -1 : 0;
+}
+
+// check if two points are equal
+function equals(data, p1, p2) {
+    return data[p1] === data[p2] && data[p1 + 1] === data[p2 + 1];
+}
+
+// check if two segments intersect
+function intersects(data, p1, q1, p2, q2) {
+    return orient(data, p1, q1, p2) !== orient(data, p1, q1, q2) &&
+           orient(data, p2, q2, p1) !== orient(data, p2, q2, q1);
+}
+
+// check if a polygon diagonal intersects any polygon segments
+function intersectsPolygon(data, start, a, b) {
+    var node = start;
+    do {
+        var p1 = node.i,
+            p2 = node.next.i;
+
+        if (p1 !== a && p2 !== a && p1 !== b && p2 !== b && intersects(data, p1, p2, a, b)) return true;
+
+        node = node.next;
+    } while (node !== start);
+
+    return false;
+}
+
+// check if a polygon diagonal is locally inside the polygon
+function locallyInside(data, a, b) {
+    return orient(data, a.prev.i, a.i, a.next.i) === -1 ?
+        orient(data, a.i, b.i, a.next.i) !== -1 && orient(data, a.i, a.prev.i, b.i) !== -1 :
+        orient(data, a.i, b.i, a.prev.i) === -1 || orient(data, a.i, a.next.i, b.i) === -1;
+}
+
+// check if the middle point of a polygon diagonal is inside the polygon
+function middleInside(data, start, a, b) {
+    var node = start,
+        inside = false,
+        px = (data[a] + data[b]) / 2,
+        py = (data[a + 1] + data[b + 1]) / 2;
+    do {
+        var p1 = node.i,
+            p2 = node.next.i;
+
+        if (((data[p1 + 1] > py) !== (data[p2 + 1] > py)) &&
+                (px < (data[p2] - data[p1]) * (py - data[p1 + 1]) / (data[p2 + 1] - data[p1 + 1]) + data[p1]))
+            inside = !inside;
+
+        node = node.next;
+    } while (node !== start);
+
+    return inside;
+}
+
+// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
+// if one belongs to the outer ring and another to a hole, it merges it into a single ring
+function splitPolygon(a, b) {
+    var a2 = new Node(a.i),
+        b2 = new Node(b.i),
+        an = a.next,
+        bp = b.prev;
+
+    a.next = b;
+    b.prev = a;
+
+    a2.next = an;
+    an.prev = a2;
+
+    b2.next = a2;
+    a2.prev = b2;
+
+    bp.next = b2;
+    b2.prev = bp;
+
+    return b2;
+}
+
+// create a node and optionally link it with previous one (in a circular doubly linked list)
+function insertNode(i, last) {
+    var node = new Node(i);
+
+    if (!last) {
+        node.prev = node;
+        node.next = node;
+
+    } else {
+        node.next = last.next;
+        node.prev = last;
+        last.next.prev = node;
+        last.next = node;
+    }
+    return node;
+}
+
+function removeNode(node) {
+    node.next.prev = node.prev;
+    node.prev.next = node.next;
+
+    if (node.prevZ) node.prevZ.nextZ = node.nextZ;
+    if (node.nextZ) node.nextZ.prevZ = node.prevZ;
+}
+
+function Node(i) {
+    // vertex coordinates
+    this.i = i;
+
+    // previous and next vertice nodes in a polygon ring
+    this.prev = null;
+    this.next = null;
+
+    // z-order curve value
+    this.z = null;
+
+    // previous and next nodes in z-order
+    this.prevZ = null;
+    this.nextZ = null;
+
+    // indicates whether this is a steiner point
+    this.steiner = false;
+}

+ 0 - 0
editor/js/libs/jszip.min.js → examples/js/libs/jszip.min.js


+ 502 - 0
examples/js/loaders/AMFLoader.js

@@ -0,0 +1,502 @@
+/*
+ * @author tamarintech / https://tamarintech.com
+ *
+ * Description: Early release of an AMF Loader following the pattern of the
+ * example loaders in the three.js project.
+ *
+ * More information about the AMF format: http://amf.wikispaces.com
+ *
+ * Usage:
+ *	var loader = new AMFLoader();
+ *	loader.load('/path/to/project.amf', function(objecttree) {
+ *		scene.add(objecttree);
+ *	});
+ *
+ * Materials now supported, material colors supported
+ * Zip support, requires jszip
+ * TextDecoder polyfill required by some browsers (particularly IE, Edge)
+ * No constellation support (yet)!
+ *
+ */
+
+THREE.AMFLoader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+};
+
+THREE.AMFLoader.prototype = {
+
+	constructor: THREE.AMFLoader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new THREE.XHRLoader( scope.manager );
+		loader.setCrossOrigin( this.crossOrigin );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function( text ) {
+
+			onLoad( scope.parse( text ) );
+
+		}, onProgress, onError );
+
+	},
+
+	parse: function ( data ) {
+
+		function loadDocument( data ) {
+
+			var view = new DataView( data );
+			var magic = String.fromCharCode( view.getUint8( 0 ), view.getUint8( 1 ) );
+
+			if ( magic === "PK" ) {
+
+				var zip = null;
+				var file = null;
+
+				console.log( "Loading Zip" );
+
+				try {
+
+					zip = new JSZip( data );
+
+				} catch ( e ) {
+
+					if ( e instanceof ReferenceError ) {
+
+						console.log( "	jszip missing and file is compressed." );
+						return null;
+
+					}
+
+				}
+
+				for ( file in zip.files ) {
+
+					if ( file.toLowerCase().substr( - 4 ) === '.amf' ) {
+
+						break;
+
+					}
+
+				}
+
+				console.log( "	Trying to load file asset: " + file );
+				view = new DataView( zip.file( file ).asArrayBuffer() );
+
+			}
+
+			if ( TextDecoder === undefined ) {
+
+				console.log( "	TextDecoder not present.	Please use TextDecoder polyfill." );
+				return null;
+
+			}
+
+			var fileText = new TextDecoder( 'utf-8' ).decode( view );
+			var xmlData = new DOMParser().parseFromString( fileText, 'application/xml' );
+
+			if ( xmlData.documentElement.nodeName.toLowerCase() !== "amf" ) {
+
+				console.log( "	Error loading AMF - no AMF document found." );
+				return null;
+
+			}
+
+			return xmlData;
+
+		}
+
+		function loadDocumentScale( node ) {
+
+			var scale = 1.0;
+			var unit = 'millimeter';
+
+			if ( node.documentElement.attributes[ 'unit' ] !== undefined ) {
+
+				unit = node.documentElement.attributes[ 'unit' ].value.toLowerCase();
+
+			}
+
+			var scaleUnits = {
+				'millimeter': 1.0,
+				'inch': 25.4,
+				'feet': 304.8,
+				'meter': 1000.0,
+				'micron': 0.001
+			};
+
+			if ( scaleUnits[ unit ] !== undefined ) {
+
+				scale = scaleUnits[ unit ];
+
+			}
+
+			console.log( "	Unit scale: " + scale );
+			return scale;
+
+		}
+
+		function loadMaterials( node ) {
+
+			var matName = "AMF Material";
+			var matId = node.attributes[ 'id' ].textContent;
+			var color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
+
+			var loadedMaterial = null;
+
+			for ( var i = 0; i < node.children.length; i ++ ) {
+
+				var matChildEl = node.children[ i ];
+
+				if ( matChildEl.nodeName === "metadata" && matChildEl.attributes[ 'type' ] !== undefined ) {
+
+					if ( matChildEl.attributes[ 'type' ].value === 'name' ) {
+
+						matname = matChildEl.textContent;
+
+					}
+
+				} else if ( matChildEl.nodeName === 'color' ) {
+
+					color = loadColor( matChildEl );
+
+				}
+
+			}
+
+			loadedMaterial = new THREE.MeshPhongMaterial( {
+				shading: THREE.FlatShading,
+				color: new THREE.Color( color.r, color.g, color.b ),
+				name: matName
+			} );
+
+			if ( color.a !== 1.0 ) {
+
+				loadedMaterial.transparent = true;
+				loadedMaterial.opacity = color.a;
+
+			}
+
+			return { 'id': matId, 'material': loadedMaterial };
+
+		}
+
+		function loadColor( node ) {
+
+			var color = { 'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0 };
+
+			for ( var i = 0; i < node.children.length; i ++ ) {
+
+				var matColor = node.children[ i ];
+
+				if ( matColor.nodeName === 'r' ) {
+
+					color.r = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'g' ) {
+
+					color.g = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'b' ) {
+
+					color.b = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'a' ) {
+
+					color.a = matColor.textContent;
+
+				}
+
+			}
+
+			return color;
+
+		}
+
+		function loadMeshVolume( node ) {
+
+			var volume = { "name": "", "triangles": [], "materialid": null };
+
+			var currVolumeNode = node.firstElementChild;
+
+			if ( node.attributes[ 'materialid' ] !== undefined ) {
+
+				volume.materialId = node.attributes[ 'materialid' ].nodeValue;
+
+			}
+
+			while ( currVolumeNode ) {
+
+				if ( currVolumeNode.nodeName === "metadata" ) {
+
+					if ( currVolumeNode.attributes[ 'type' ] !== undefined ) {
+
+						if ( currVolumeNode.attributes[ 'type' ].value === 'name' ) {
+
+							volume.name = currVolumeNode.textContent;
+
+						}
+
+					}
+
+				} else if ( currVolumeNode.nodeName === "triangle" ) {
+
+					var v1 = currVolumeNode.getElementsByTagName("v1")[0].textContent;
+					var v2 = currVolumeNode.getElementsByTagName("v2")[0].textContent;
+					var v3 = currVolumeNode.getElementsByTagName("v3")[0].textContent;
+
+					volume.triangles.push( v1 );
+					volume.triangles.push( v2 );
+					volume.triangles.push( v3 );
+
+				}
+
+				currVolumeNode = currVolumeNode.nextElementSibling;
+
+			}
+
+			return volume;
+
+		}
+
+		function loadMeshVertices( node ) {
+
+			var vertArray = [];
+			var normalArray = [];
+			var currVerticesNode = node.firstElementChild;
+
+			while ( currVerticesNode ) {
+
+				if ( currVerticesNode.nodeName === "vertex" ) {
+
+					var vNode = currVerticesNode.firstElementChild;
+
+					while ( vNode ) {
+
+						if ( vNode.nodeName === "coordinates" ) {
+
+							var x = vNode.getElementsByTagName("x")[0].textContent;
+							var y = vNode.getElementsByTagName("y")[0].textContent;
+							var z = vNode.getElementsByTagName("z")[0].textContent;
+
+							vertArray.push(x);
+							vertArray.push(y);
+							vertArray.push(z);
+
+						} else if ( vNode.nodeName === "normal" ) {
+
+							var nx = vNode.getElementsByTagName("nx")[0].textContent;
+							var ny = vNode.getElementsByTagName("ny")[0].textContent;
+							var nz = vNode.getElementsByTagName("nz")[0].textContent;
+
+							normalArray.push(nx);
+							normalArray.push(ny);
+							normalArray.push(nz);
+
+						}
+
+						vNode = vNode.nextElementSibling;
+
+					}
+
+				}
+				currVerticesNode = currVerticesNode.nextElementSibling;
+
+			}
+
+			return { "vertices": vertArray, "normals": normalArray };
+
+		}
+
+		function loadObject( node ) {
+
+			var objId = node.attributes[ 'id' ].textContent;
+			var loadedObject = { "name": "amfobject", "meshes": [] };
+			var currColor = null;
+			var currObjNode = node.firstElementChild;
+
+			while ( currObjNode ) {
+
+				if ( currObjNode.nodeName === "metadata" ) {
+
+					if ( currObjNode.attributes[ 'type' ] !== undefined ) {
+
+						if ( currObjNode.attributes[ 'type' ].value === 'name' ) {
+
+							loadedObject.name = currObjNode.textContent;
+
+						}
+
+					}
+
+				} else if ( currObjNode.nodeName === "color" ) {
+
+					currColor = loadColor( currObjNode );
+
+				} else if ( currObjNode.nodeName === "mesh" ) {
+
+					var currMeshNode = currObjNode.firstElementChild;
+					var mesh = { "vertices": [], "normals": [], "volumes": [], "color": currColor };
+
+					while ( currMeshNode ) {
+
+						if ( currMeshNode.nodeName === "vertices" ) {
+
+							var loadedVertices = loadMeshVertices( currMeshNode );
+
+							mesh.normals = mesh.normals.concat( loadedVertices.normals );
+							mesh.vertices = mesh.vertices.concat( loadedVertices.vertices );
+
+						} else if ( currMeshNode.nodeName === "volume" ) {
+
+							mesh.volumes.push( loadMeshVolume( currMeshNode ) );
+
+						}
+
+						currMeshNode = currMeshNode.nextElementSibling;
+
+					}
+
+					loadedObject.meshes.push( mesh );
+
+				}
+
+				currObjNode = currObjNode.nextElementSibling;
+
+			}
+
+			return { 'id': objId, 'obj': loadedObject };
+
+		}
+
+		var xmlData = loadDocument( data );
+		var amfName = "";
+		var amfAuthor = "";
+		var amfScale = loadDocumentScale( xmlData );
+		var amfMaterials = {};
+		var amfObjects = {};
+		var children = xmlData.documentElement.children;
+
+		for ( var i = 0; i < children.length; i ++ ) {
+
+			var child = children[ i ];
+
+			if ( child.nodeName === 'metadata' ) {
+
+				if ( child.attributes[ 'type' ] !== undefined ) {
+
+					if ( child.attributes[ 'type' ].value === 'name' ) {
+
+						amfName = child.textContent;
+
+					} else if ( child.attributes[ 'type' ].value === 'author' ) {
+
+						amfAuthor = child.textContent;
+
+					}
+
+				}
+
+			} else if ( child.nodeName === 'material' ) {
+
+				var loadedMaterial = loadMaterials( child );
+
+				amfMaterials[ loadedMaterial.id ] = loadedMaterial.material;
+
+			} else if ( child.nodeName === 'object' ) {
+
+				var loadedObject = loadObject( child );
+
+				amfObjects[ loadedObject.id ] = loadedObject.obj;
+
+			}
+
+		}
+
+		var sceneObject = new THREE.Group();
+		var defaultMaterial = new THREE.MeshPhongMaterial( { color: 0xaaaaff, shading: THREE.FlatShading } );
+
+		sceneObject.name = amfName;
+		sceneObject.userData.author = amfAuthor;
+		sceneObject.userData.loader = "AMF";
+
+		for ( var id in amfObjects ) {
+
+			var meshes = amfObjects[ id ].meshes;
+			var newObject = new THREE.Group();
+
+			for ( var i = 0; i < meshes.length; i ++ ) {
+
+				var objDefaultMaterial = defaultMaterial;
+				var mesh = meshes[ i ];
+				var meshVertices = Float32Array.from( mesh.vertices );
+				var vertices = new THREE.BufferAttribute( Float32Array.from( meshVertices ), 3 );
+				var meshNormals = null;
+				var normals = null;
+
+				if ( mesh.normals.length ) {
+
+					meshNormals = Float32Array.from( mesh.normals );
+					normals = new THREE.BufferAttribute( Float32Array.from( meshNormals ), 3 );
+
+				}
+
+				if ( mesh.color ) {
+
+					var color = mesh.color;
+
+					objDefaultMaterial = defaultMaterial.clone();
+					objDefaultMaterial.color = new THREE.Color( color.r, color.g, color.b );
+
+					if ( color.a !== 1.0 ) {
+
+						objDefaultMaterial.transparent = true;
+						objDefaultMaterial.opacity = color.a;
+
+					}
+
+				}
+
+				var volumes = mesh.volumes;
+
+				for ( var j = 0; j < volumes.length; j ++ ) {
+
+					var volume = volumes[ j ];
+					var newGeometry = new THREE.BufferGeometry();
+					var indexes = Uint32Array.from( volume.triangles );
+					var material = objDefaultMaterial;
+
+					newGeometry.setIndex( new THREE.BufferAttribute( indexes, 1 ) );
+					newGeometry.addAttribute( 'position', vertices.clone() );
+
+					if( normals ) {
+
+						newGeometry.addAttribute( 'normal', normals.clone() );
+
+					}
+
+					if ( amfMaterials[ volume.materialId ] !== undefined ) {
+
+						material = amfMaterials[ volume.materialId ];
+
+					}
+
+					newGeometry.scale( amfScale, amfScale, amfScale );
+					newObject.add( new THREE.Mesh( newGeometry, material.clone() ) );
+
+				}
+
+			}
+
+			sceneObject.add( newObject );
+
+		}
+
+		return sceneObject;
+
+	}
+
+};

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

@@ -764,7 +764,7 @@
 
 						buffer = new Uint16Array( str_len / 2 );
 						attrib = new THREE.BufferAttribute( buffer, 1 );
-						geom.addIndex( attrib );
+						geom.setIndex( attrib );
 
 						idx = 0;
 

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

@@ -87,7 +87,7 @@ THREE.BabylonLoader.prototype = {
 
 		var indices = new Uint16Array( json.indices );
 
-		geometry.addIndex( new THREE.BufferAttribute( indices, 1 ) );
+		geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
 
 		// positions
 

+ 22 - 0
examples/js/loaders/BinaryLoader.js

@@ -4,6 +4,13 @@
 
 THREE.BinaryLoader = function ( manager ) {
 
+	if ( typeof manager === 'boolean' ) {
+
+		console.warn( 'THREE.BinaryLoader: showStatus parameter has been removed from constructor.' );
+		manager = undefined;
+
+	}
+
 	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
 
 };
@@ -12,6 +19,21 @@ THREE.BinaryLoader.prototype = {
 
 	constructor: THREE.BinaryLoader,
 
+	// Deprecated
+	
+	get statusDomElement () {
+
+		if ( this._statusDomElement === undefined ) {
+
+			this._statusDomElement = document.createElement( 'div' );
+
+		}
+
+		console.warn( 'THREE.BinaryLoader: .statusDomElement has been removed.' );
+		return this._statusDomElement;
+
+	},
+
 	// Load models generated by slim OBJ converter with BINARY option (converter_obj_three_slim.py -t binary)
 	//  - binary models consist of two files: JS and BIN
 	//  - parameters

+ 3 - 5
examples/js/loaders/ColladaLoader.js

@@ -100,9 +100,7 @@
 					parts.pop();
 					baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
 
-					var xmlParser = new DOMParser();
-					var responseXML = xmlParser.parseFromString( text, "application/xml" );
-					onLoad( scope.parse( responseXML, url ) );
+					onLoad( scope.parse( text, url ) );
 
 				}, onProgress, onError );
 
@@ -120,9 +118,9 @@
 
 		},
 
-		parse: function( doc ) {
+		parse: function( text ) {
 
-			COLLADA = doc;
+			COLLADA = new DOMParser().parseFromString( text, 'application/xml' );
 
 			this.parseAsset();
 			this.setUpConversion();

+ 865 - 0
examples/js/loaders/ColladaLoader2.js

@@ -0,0 +1,865 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.ColladaLoader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+};
+
+THREE.ColladaLoader.prototype = {
+
+	constructor: THREE.ColladaLoader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		function getBaseUrl( url ) {
+
+			var parts = url.split( '/' );
+			parts.pop();
+			return ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
+
+		}
+
+		var scope = this;
+
+		var loader = new THREE.XHRLoader( scope.manager );
+		loader.setCrossOrigin( scope.crossOrigin );
+		loader.load( url, function ( text ) {
+
+			onLoad( scope.parse( text, getBaseUrl( url ) ) );
+
+		}, onProgress, onError );
+
+	},
+
+	options: {
+
+		set convertUpAxis ( value ) {
+			console.log( 'ColladaLoder.options.convertUpAxis: TODO' );
+		}
+
+	},
+
+	setCrossOrigin: function ( value ) {
+
+		this.crossOrigin = value;
+
+	},
+
+	parse: function ( text, baseUrl ) {
+
+		function parseFloats( text ) {
+
+			var parts = text.trim().split( /\s+/ );
+			var array = new Array( parts.length );
+
+			for ( var i = 0, l = parts.length; i < l; i ++ ) {
+				array[ i ] = parseFloat( parts[ i ] );
+			}
+
+			return array;
+
+		}
+
+		function parseInts( text ) {
+
+			var parts = text.trim().split( /\s+/ );
+			var array = new Array( parts.length );
+
+			for ( var i = 0, l = parts.length; i < l; i ++ ) {
+				array[ i ] = parseInt( parts[ i ] );
+			}
+
+			return array;
+
+		}
+
+		function parseId( text ) {
+
+			return text.substring( 1 );
+
+		}
+
+		// asset
+
+		function parseAsset( xml ) {
+
+			return {
+				upAxis: parseAssetUpAxis( xml.getElementsByTagName( 'up_axis' )[ 0 ] )
+			};
+
+		}
+
+		function parseAssetUpAxis( xml ) {
+
+			return xml !== undefined ? xml.textContent : 'Y_UP';
+
+		}
+
+		// library
+
+		function parseLibrary( data, libraryName, nodeName, parser ) {
+
+			var library = xml.getElementsByTagName( libraryName )[ 0 ];
+
+			if ( library !== undefined ) {
+
+				var elements = library.getElementsByTagName( nodeName );
+
+				for ( var i = 0; i < elements.length; i ++ ) {
+
+					parser( elements[ i ] );
+
+				}
+
+			}
+
+		}
+
+		function buildLibrary( data, builder ) {
+
+			for ( var name in data ) {
+
+				var object = data[ name ];
+				object.build = builder( data[ name ] );
+
+			}
+
+		}
+
+		// get
+
+		function getBuild( data, builder ) {
+
+			if ( data.build !== undefined ) return data.build;
+
+			data.build = builder( data );
+
+			return data.build;
+
+		}
+
+		// image
+
+		var imageLoader = new THREE.ImageLoader();
+
+		function parseImage( xml ) {
+
+			var data = {
+				url: xml.getElementsByTagName( 'init_from' )[ 0 ].textContent
+			};
+
+			library.images[ xml.getAttribute( 'id' ) ] = data;
+
+		}
+
+		function buildImage( data ) {
+
+			if ( data.build !== undefined ) return data.build;
+
+			var url = data.url;
+
+			if ( baseUrl !== undefined ) url = baseUrl + url;
+
+			return imageLoader.load( url );
+
+		}
+
+		function getImage( id ) {
+
+			return getBuild( library.images[ id ], buildImage );
+
+		}
+
+		// effect
+
+		function parseEffect( xml ) {
+
+		}
+
+		function buildEffect( data ) {
+
+		}
+
+		function getEffect( id ) {
+
+			return getBuild( library.effects[ id ], buildEffect );
+
+		}
+
+		// camera
+
+		function parseCamera( xml ) {
+
+			var data = {
+				name: xml.getAttribute( 'name' )
+			};
+
+			library.cameras[ xml.getAttribute( 'id' ) ] = {};
+
+		}
+
+		function buildCamera( data ) {
+
+			var camera = new THREE.PerspectiveCamera();
+			camera.name = data.name;
+
+			return camera;
+
+		}
+
+		function getCamera( id ) {
+
+			return getBuild( library.cameras[ id ], buildCamera );
+
+		}
+
+		// light
+
+		function parseLight( xml ) {
+
+			var data = {};
+
+			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'technique_common':
+						data = parseLightTechnique( child );
+						break;
+
+				}
+
+			}
+
+			library.lights[ xml.getAttribute( 'id' ) ] = data;
+
+		}
+
+		function parseLightTechnique( xml ) {
+
+			var data = {};
+
+			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'directional':
+					case 'point':
+					case 'spot':
+					case 'ambient':
+
+						data.technique = child.nodeName;
+						data.parameters = parseLightParameters( child );
+
+				}
+
+			}
+
+			return data;
+
+		}
+
+		function parseLightParameters( xml ) {
+
+			var data = {};
+
+			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'color':
+						var array = parseFloats( child.textContent );
+						data.color = new THREE.Color().fromArray( array );
+						break;
+
+					case 'falloff_angle':
+						data.falloffAngle = parseFloat( child.textContent );
+						break;
+
+					case 'quadratic_attenuation':
+						var f = parseFloat( child.textContent );
+						data.distance = f ? Math.sqrt( 1 / f ) : 0;
+						break;
+
+				}
+
+			}
+
+			return data;
+
+		}
+
+		function buildLight( data ) {
+
+			var light;
+
+			switch ( data.technique ) {
+
+				case 'directional':
+					light = new THREE.DirectionalLight();
+					break;
+
+				case 'point':
+					light = new THREE.PointLight();
+					break;
+
+				case 'spot':
+					light = new THREE.SpotLight();
+					break;
+
+				case 'ambient':
+					light = new THREE.AmbientLight();
+					break;
+
+			}
+
+			if ( data.parameters.color ) light.color.copy( data.parameters.color );
+			if ( data.parameters.distance ) light.distance = data.parameters.distance;
+
+			return light;
+
+		}
+
+		function getLight( id ) {
+
+			return getBuild( library.lights[ id ], buildLight );
+
+		}
+
+		// geometry
+
+		function parseGeometry( xml ) {
+
+			var data = {
+				name: xml.getAttribute( 'name' ),
+				sources: {},
+				primitives: []
+			};
+
+			var mesh = xml.getElementsByTagName( 'mesh' )[ 0 ];
+
+			for ( var i = 0; i < mesh.childNodes.length; i ++ ) {
+
+				var child = mesh.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'source':
+						data.sources[ child.getAttribute( 'id' ) ] = parseFloats( child.getElementsByTagName( 'float_array' )[ 0 ].textContent );
+						break;
+
+					case 'vertices':
+						data.sources[ child.getAttribute( 'id' ) ] = data.sources[ parseId( child.getElementsByTagName( 'input' )[ 0 ].getAttribute( 'source' ) ) ];
+						break;
+
+					case 'polygons':
+						console.log( 'ColladaLoader: Unsupported primitive type: ', child.nodeName );
+						break;
+
+					case 'lines':
+					case 'linestrips':
+					case 'polylist':
+					case 'triangles':
+						data.primitives.push( parseGeometryPrimitive( child ) );
+						break;
+
+					default:
+						console.log( child );
+
+				}
+
+			}
+
+			library.geometries[ xml.getAttribute( 'id' ) ] = data;
+
+		}
+
+		function parseGeometryPrimitive( xml ) {
+
+			var primitive = {
+				type: xml.nodeName,
+				inputs: {},
+				stride: 0
+			};
+
+			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'input':
+						var id = parseId( child.getAttribute( 'source' ) );
+						var semantic = child.getAttribute( 'semantic' );
+						var offset = parseInt( child.getAttribute( 'offset' ) );
+						primitive.inputs[ semantic ] = { id: id, offset: offset };
+						primitive.stride = Math.max( primitive.stride, offset + 1 );
+						break;
+
+					case 'vcount':
+						primitive.vcount = parseInts( child.textContent );
+						break;
+
+					case 'p':
+						primitive.p = parseInts( child.textContent );
+						break;
+
+				}
+
+			}
+
+			return primitive;
+
+		}
+
+		function buildGeometry( data ) {
+
+			var group = new THREE.Group();
+
+			var sources = data.sources;
+			var primitives = data.primitives;
+
+			if ( primitives.length === 0 ) return group;
+
+			for ( var p = 0; p < primitives.length; p ++ ) {
+
+				var primitive = primitives[ p ];
+
+				var inputs = primitive.inputs;
+				var stride = primitive.stride;
+				var vcount = primitive.vcount;
+
+				var indices = primitive.p;
+				var vcount = primitive.vcount;
+
+				var maxcount = 0;
+
+				var geometry = new THREE.BufferGeometry();
+				if ( data.name ) geometry.name = data.name;
+
+				for ( var name in inputs ) {
+
+					var input = inputs[ name ];
+
+					var source = sources[ input.id ];
+					var offset = input.offset;
+
+					var array = [];
+
+					function pushVector( i ) {
+
+						var index = indices[ i + offset ] * 3;
+
+						if ( asset.upAxis === 'Z_UP' ) {
+							array.push( source[ index + 0 ], source[ index + 2 ], - source[ index + 1 ] );
+						} else {
+							array.push( source[ index + 0 ], source[ index + 1 ], source[ index + 2 ] );
+						}
+
+					}
+
+					if ( primitive.vcount !== undefined ) {
+
+						var index = 0;
+
+						for ( var i = 0, l = vcount.length; i < l; i ++ ) {
+
+							var count = vcount[ i ];
+
+							if ( count === 4 ) {
+
+								var a = index + stride * 0;
+								var b = index + stride * 1;
+								var c = index + stride * 2;
+								var d = index + stride * 3;
+
+								pushVector( a ); pushVector( b ); pushVector( d );
+								pushVector( b ); pushVector( c ); pushVector( d );
+
+							} else if ( count === 3 ) {
+
+								var a = index + stride * 0;
+								var b = index + stride * 1;
+								var c = index + stride * 2;
+
+								pushVector( a ); pushVector( b ); pushVector( c );
+
+							} else {
+
+								maxcount = Math.max( maxcount, count );
+
+							}
+
+							index += stride * count;
+
+						}
+
+					} else {
+
+						for ( var i = 0, l = indices.length; i < l; i += stride ) {
+
+							pushVector( i );
+
+						}
+
+					}
+
+					switch ( name )	{
+
+						case 'VERTEX':
+							geometry.addAttribute( 'position', new THREE.Float32Attribute( array, 3 ) );
+							break;
+
+						case 'NORMAL':
+							geometry.addAttribute( 'normal', new THREE.Float32Attribute( array, 3 ) );
+							break;
+
+					}
+
+				}
+
+				if ( maxcount > 0 ) {
+
+					console.log( 'ColladaLoader: Geometry', data.id, 'has faces with more than 4 vertices.' );
+
+				}
+
+				switch ( primitive.type ) {
+
+					case 'lines':
+						group.add( new THREE.LineSegments( geometry ) );
+						break;
+
+					case 'linestrips':
+						group.add( new THREE.Line( geometry ) );
+						break;
+
+					case 'triangles':
+					case 'polylist':
+						group.add( new THREE.Mesh( geometry ) );
+						break;
+
+				}
+
+			}
+
+			// flatten
+
+			if ( group.children.length === 1 ) {
+
+				return group.children[ 0 ];
+
+			}
+
+			return group;
+
+		}
+
+		function getGeometry( id ) {
+
+			return getBuild( library.geometries[ id ], buildGeometry );
+
+		}
+
+		// nodes
+
+		var matrix = new THREE.Matrix4();
+		var vector = new THREE.Vector3();
+
+		function parseNode( xml ) {
+
+			var data = {
+				name: xml.getAttribute( 'name' ),
+				matrix: new THREE.Matrix4(),
+				nodes: [],
+				instanceCameras: [],
+				instanceLights: [],
+				instanceGeometries: [],
+				instanceNodes: []
+			};
+
+			for ( var i = 0; i < xml.childNodes.length; i ++ ) {
+
+				var child = xml.childNodes[ i ];
+
+				if ( child.nodeType !== 1 ) continue;
+
+				switch ( child.nodeName ) {
+
+					case 'node':
+						parseNode( child );
+						data.nodes.push( child.getAttribute( 'id' ) );
+						break;
+
+					case 'instance_camera':
+						data.instanceCameras.push( parseId( child.getAttribute( 'url' ) ) );
+						break;
+
+					case 'instance_light':
+						data.instanceLights.push( parseId( child.getAttribute( 'url' ) ) );
+						break;
+
+					case 'instance_geometry':
+						data.instanceGeometries.push( parseId( child.getAttribute( 'url' ) ) );
+						break;
+
+					case 'instance_node':
+						data.instanceNodes.push( parseId( child.getAttribute( 'url' ) ) );
+						break;
+
+					case 'matrix':
+						var array = parseFloats( child.textContent );
+						data.matrix.multiply( matrix.fromArray( array ).transpose() ); // .transpose() when Z_UP?
+						break;
+
+					case 'translate':
+						var array = parseFloats( child.textContent );
+						vector.fromArray( array );
+						data.matrix.multiply( matrix.makeTranslation( vector.x, vector.y, vector.z ) );
+						break;
+
+					case 'rotate':
+						var array = parseFloats( child.textContent );
+						var angle = THREE.Math.degToRad( array[ 3 ] );
+						data.matrix.multiply( matrix.makeRotationAxis( vector.fromArray( array ), angle ) );
+						break;
+
+					case 'scale':
+						var array = parseFloats( child.textContent );
+						data.matrix.scale( vector.fromArray( array ) );
+						break;
+
+					case 'extra':
+						break;
+
+					default:
+						console.log( child );
+						break;
+
+				}
+
+			}
+
+			if ( xml.getAttribute( 'id' ) !== null ) {
+
+				library.nodes[ xml.getAttribute( 'id' ) ] = data;
+
+			}
+
+			return data;
+
+		}
+
+		function buildNode( data ) {
+
+			var objects = [];
+
+			var matrix = data.matrix;
+			var nodes = data.nodes;
+			var instanceCameras = data.instanceCameras;
+			var instanceLights = data.instanceLights;
+			var instanceGeometries = data.instanceGeometries;
+			var instanceNodes = data.instanceNodes;
+
+			for ( var i = 0, l = nodes.length; i < l; i ++ ) {
+
+				objects.push( getNode( nodes[ i ] ).clone() );
+
+			}
+
+			for ( var i = 0, l = instanceCameras.length; i < l; i ++ ) {
+
+				objects.push( getCamera( instanceCameras[ i ] ).clone() );
+
+			}
+
+			for ( var i = 0, l = instanceLights.length; i < l; i ++ ) {
+
+				objects.push( getLight( instanceLights[ i ] ).clone() );
+
+			}
+
+			for ( var i = 0, l = instanceGeometries.length; i < l; i ++ ) {
+
+				objects.push( getGeometry( instanceGeometries[ i ] ).clone() );
+
+			}
+
+			for ( var i = 0, l = instanceNodes.length; i < l; i ++ ) {
+
+				objects.push( getNode( instanceNodes[ i ] ).clone() );
+
+			}
+
+			var object;
+
+			if ( objects.length === 1 ) {
+
+				object = objects[ 0 ];
+
+			} else {
+
+				object = new THREE.Group();
+
+				for ( var i = 0; i < objects.length; i ++ ) {
+
+					object.add( objects[ i ] );
+
+				}
+
+			}
+
+			object.name = data.name;
+			matrix.decompose( object.position, object.quaternion, object.scale );
+
+			return object;
+
+		}
+
+		function getNode( id ) {
+
+			return getBuild( library.nodes[ id ], buildNode );
+
+		}
+
+		// visual scenes
+
+		function parseVisualScene( xml ) {
+
+			var data = {
+				name: xml.getAttribute( 'name' ),
+				children: []
+			};
+
+			var elements = xml.getElementsByTagName( 'node' );
+
+			for ( var i = 0; i < elements.length; i ++ ) {
+
+				data.children.push( parseNode( elements[ i ] ) );
+
+			}
+
+			library.visualScenes[ xml.getAttribute( 'id' ) ] = data;
+
+		}
+
+		function buildVisualScene( data ) {
+
+			var group = new THREE.Group();
+			group.name = data.name;
+
+			var children = data.children;
+
+			for ( var i = 0; i < children.length; i ++ ) {
+
+				group.add( buildNode( children[ i ] ) );
+
+			}
+
+			return group;
+
+		}
+
+		function getVisualScene( id ) {
+
+			return getBuild( library.visualScenes[ id ], buildVisualScene );
+
+		}
+
+		// scenes
+
+		function parseScene( xml ) {
+
+			var scene = xml.getElementsByTagName( 'scene' )[ 0 ];
+			var instance = scene.getElementsByTagName( 'instance_visual_scene' )[ 0 ];
+			return getVisualScene( parseId( instance.getAttribute( 'url' ) ) );
+
+		}
+
+		console.time( 'ColladaLoader' );
+
+		console.time( 'ColladaLoader: DOMParser' );
+
+		var xml = new DOMParser().parseFromString( text, 'application/xml' );
+
+		console.timeEnd( 'ColladaLoader: DOMParser' );
+
+		// metadata
+
+		var version = xml.getElementsByTagName( 'COLLADA' )[ 0 ].getAttribute( 'version' );
+		console.log( 'ColladaLoader: File version', version );
+
+		var asset = parseAsset( xml.getElementsByTagName( 'asset' )[ 0 ] );
+
+		//
+
+		var library = {
+			images: {},
+			// effects: {},
+			cameras: {},
+			lights: {},
+			geometries: {},
+			nodes: {},
+			visualScenes: {}
+		};
+
+		console.time( 'ColladaLoader: Parse' );
+
+		parseLibrary( library.images, 'library_images', 'image', parseImage );
+		// parseLibrary( library.effects, 'library_effects', 'effect', parseEffect );
+		parseLibrary( library.cameras, 'library_cameras', 'camera', parseCamera );
+		parseLibrary( library.lights, 'library_lights', 'light', parseLight );
+		parseLibrary( library.geometries, 'library_geometries', 'geometry', parseGeometry );
+		parseLibrary( library.nodes, 'library_nodes', 'node', parseNode );
+		parseLibrary( library.visualScenes, 'library_visual_scenes', 'visual_scene', parseVisualScene );
+
+		console.timeEnd( 'ColladaLoader: Parse' );
+
+		console.time( 'ColladaLoader: Build' );
+
+		// buildLibrary( library.images, buildImage );
+		// buildLibrary( library.effects, buildEffect );
+		buildLibrary( library.cameras, buildCamera );
+		buildLibrary( library.lights, buildLight );
+		buildLibrary( library.geometries, buildGeometry );
+		buildLibrary( library.nodes, buildNode );
+		buildLibrary( library.visualScenes, buildVisualScene );
+
+		console.timeEnd( 'ColladaLoader: Build' );
+
+		// console.log( library );
+
+		var scene = parseScene( xml );
+
+		console.timeEnd( 'ColladaLoader' );
+
+		// console.log( scene );
+
+		return {
+			animations: [],
+			kinematics: { joints: [] },
+			scene: scene
+		};
+
+	}
+
+};

+ 54 - 0
examples/js/loaders/KMZLoader.js

@@ -0,0 +1,54 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.KMZLoader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+};
+
+THREE.KMZLoader.prototype = {
+
+	constructor: THREE.KMZLoader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new THREE.XHRLoader( scope.manager );
+		loader.setCrossOrigin( this.crossOrigin );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function ( text ) {
+
+			onLoad( scope.parse( text ) );
+
+		}, onProgress, onError );
+
+	},
+
+	parse: function ( data ) {
+
+		var zip = new JSZip( data );
+
+		// console.log( zip );
+
+		for ( var name in zip.files ) {
+
+			if ( name.toLowerCase().substr( - 4 ) === '.dae' ) {
+
+				return new THREE.ColladaLoader().parse( zip.file( name ).asText() );
+
+			}
+
+		}
+
+		console.error( 'KZMLoader: Couldn\'t find .dae file.' );
+
+		return {
+			scene: new THREE.Group()
+		}
+
+	}
+
+};

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

@@ -305,7 +305,7 @@ THREE.MD2Loader.prototype = {
 
 			}
 
-			geometry.clips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 )
+			geometry.animations = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 )
 
 			console.timeEnd( 'MD2Loader' );
 

+ 2 - 8
examples/js/loaders/MTLLoader.js

@@ -319,7 +319,7 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					// Diffuse color (color under white light) using RGB values
 
-					params[ 'diffuse' ] = new THREE.Color().fromArray( value );
+					params[ 'color' ] = new THREE.Color().fromArray( value );
 
 					break;
 
@@ -351,7 +351,7 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 					// The specular exponent (defines the focus of the specular highlight)
 					// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
 
-					params[ 'shininess' ] = value;
+					params[ 'shininess' ] = parseFloat( value );
 
 					break;
 
@@ -390,12 +390,6 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 		}
 
-		if ( params[ 'diffuse' ] ) {
-
-			params[ 'color' ] = params[ 'diffuse' ];
-
-		}
-
 		this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
 		return this.materials[ materialName ];
 

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

@@ -25,7 +25,7 @@ THREE.SVGLoader.prototype = {
 
 			var doc = parser.parseFromString( svgString, 'image/svg+xml' );  // application/xml
 
-			onLoad( doc.firstChild );
+			onLoad( doc.documentElement );
 
 		}, onProgress, onError );
 

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

@@ -94,7 +94,7 @@ THREE.UTF8Loader.BufferGeometryCreator.prototype.create = function ( attribArray
 
 	}
 
-	geometry.addIndex( new THREE.BufferAttribute( indices, 1 ) );
+	geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
 	geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
 	geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
 	geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

+ 146 - 32
examples/js/loaders/VRMLLoader.js

@@ -44,10 +44,14 @@ THREE.VRMLLoader.prototype = {
 
 		this.crossOrigin = value;
 
+		THREE.ImageUtils.crossOrigin = value;
+
 	},
 
 	parse: function ( data ) {
 
+		var texturePath = this.texturePath || '';
+
 		var parseV1 = function ( lines, scene ) {
 
 			console.warn( 'VRML V1.0 not supported yet' );
@@ -58,6 +62,7 @@ THREE.VRMLLoader.prototype = {
 
 			var defines = {};
 			var float_pattern = /(\b|\-|\+)([\d\.e]+)/;
+			var float2_pattern = /([\d\.\+\-e]+)\s+([\d\.\+\-e]+)/g;
 			var float3_pattern = /([\d\.\+\-e]+)\s+([\d\.\+\-e]+)\s+([\d\.\+\-e]+)/g;
 
 			/**
@@ -239,10 +244,10 @@ THREE.VRMLLoader.prototype = {
 						this.points = [];
 						break;
 					case 'coordIndex':
+					case 'texCoordIndex':
 						this.recordingFieldname = fieldName;
 						this.isRecordingFaces = true;
 						this.indexes = [];
-						break;
 				}
 
 				if ( this.isRecordingFaces ) {
@@ -287,12 +292,14 @@ THREE.VRMLLoader.prototype = {
 					if ( /]/.exec( line ) ) {
 
 						this.isRecordingFaces = false;
-						node.coordIndex = this.indexes;
+						node[this.recordingFieldname] = this.indexes;
 
 					}
 
 				} else if ( this.isRecordingPoints ) {
 
+					if ( node.nodeType == 'Coordinate' )
+
 					while ( null !== ( parts = float3_pattern.exec( line ) ) ) {
 
 						point = {
@@ -305,6 +312,19 @@ THREE.VRMLLoader.prototype = {
 
 					}
 
+					if ( node.nodeType == 'TextureCoordinate' )
+
+					while ( null !== ( parts = float2_pattern.exec( line ) ) ) {
+
+						point = {
+							x: parseFloat( parts[ 1 ] ),
+							y: parseFloat( parts[ 2 ] )
+						};
+
+						this.points.push( point );
+
+					}
+
 					// end
 					if ( /]/.exec( line ) ) {
 
@@ -505,7 +525,7 @@ THREE.VRMLLoader.prototype = {
 
 					}
 
-					if ( matches = /([^\s]*){1}\s?{/.exec( line ) ) {
+					if ( matches = /([^\s]*){1}(?:\s+)?{/.exec( line ) ) {
 
 						// first subpattern should match the Node name
 
@@ -637,7 +657,7 @@ THREE.VRMLLoader.prototype = {
 
 					if ( /DEF/.exec( data.string ) ) {
 
-						object.name = /DEF (\w+)/.exec( data.string )[ 1 ];
+						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
 
 						defines[ object.name ] = object;
 
@@ -710,7 +730,7 @@ THREE.VRMLLoader.prototype = {
 
 						var geometry = new THREE.Geometry();
 
-						var indexes;
+						var indexes, uvIndexes, uvs;
 
 						for ( var i = 0, j = data.children.length; i < j; i ++ ) {
 
@@ -718,53 +738,102 @@ THREE.VRMLLoader.prototype = {
 
 							var vec;
 
+							if ( 'TextureCoordinate' === child.nodeType ) {
+
+								uvs = child.points;
+
+							}
+
+
 							if ( 'Coordinate' === child.nodeType ) {
 
-								for ( var k = 0, l = child.points.length; k < l; k ++ ) {
+								if ( child.points ) {
+
+									for ( var k = 0, l = child.points.length; k < l; k ++ ) {
 
-									var point = child.points[ k ];
+										var point = child.points[ k ];
 
-									vec = new THREE.Vector3( point.x, point.y, point.z );
+										vec = new THREE.Vector3( point.x, point.y, point.z );
 
-									geometry.vertices.push( vec );
+										geometry.vertices.push( vec );
+
+									}
 
 								}
 
-								break;
+								if ( child.string.indexOf ( 'DEF' ) > -1 ) {
 
-							}
+									var name = /DEF\s+(\w+)/.exec( child.string )[ 1 ];
 
-						}
+									defines[ name ] = geometry.vertices;
 
-						var skip = 0;
+								}
+
+								if ( child.string.indexOf ( 'USE' ) > -1 ) {
 
-						// read this: http://math.hws.edu/eck/cs424/notes2013/16_Threejs_Advanced.html
-						for ( var i = 0, j = data.coordIndex.length; i < j; i ++ ) {
+									var defineKey = /USE\s+(\w+)/.exec( child.string )[ 1 ];
 
-							indexes = data.coordIndex[ i ];
+									geometry.vertices = defines[ defineKey ];
+								}
 
-							// vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
-							skip = 0;
+							}
 
-							// todo: this is the time to check if the faces are ordered ccw or not (cw)
+						}
 
-							// Face3 only works with triangles, but IndexedFaceSet allows shapes with more then three vertices, build them of triangles
-							while ( indexes.length >= 3 && skip < ( indexes.length - 2 ) ) {
+						var skip = 0;
 
-								var face = new THREE.Face3(
-									indexes[ 0 ],
-									indexes[ skip + 1 ],
-									indexes[ skip + 2 ],
-									null // normal, will be added later
-									// todo: pass in the color, if a color index is present
-								);
+						// some shapes only have vertices for use in other shapes
+						if ( data.coordIndex ) {
+
+							// read this: http://math.hws.edu/eck/cs424/notes2013/16_Threejs_Advanced.html
+							for ( var i = 0, j = data.coordIndex.length; i < j; i ++ ) {
+
+								indexes = data.coordIndex[ i ]; if ( data.texCoordIndex ) uvIndexes = data.texCoordIndex[ i ];
+
+								// vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+								skip = 0;
+
+								// Face3 only works with triangles, but IndexedFaceSet allows shapes with more then three vertices, build them of triangles
+								while ( indexes.length >= 3 && skip < ( indexes.length - 2 ) ) {
+
+									var face = new THREE.Face3(
+										indexes[ 0 ],
+										indexes[ skip + (data.ccw ? 1 : 2) ],
+										indexes[ skip + (data.ccw ? 2 : 1) ],
+										null // normal, will be added later
+										// todo: pass in the color, if a color index is present
+									);
+
+									if ( uvs && uvIndexes ) {
+										geometry.faceVertexUvs [0].push( [
+											new THREE.Vector2 (
+												uvs[ uvIndexes[ 0 ] ].x ,
+												uvs[ uvIndexes[ 0 ] ].y
+											) ,
+											new THREE.Vector2 (
+												uvs[ uvIndexes[ skip + (data.ccw ? 1 : 2) ] ].x ,
+												uvs[ uvIndexes[ skip + (data.ccw ? 1 : 2) ] ].y
+											) ,
+											new THREE.Vector2 (
+												uvs[ uvIndexes[ skip + (data.ccw ? 2 : 1) ] ].x ,
+												uvs[ uvIndexes[ skip + (data.ccw ? 2 : 1) ] ].y
+											)
+										] );
+									}
+
+									skip ++;
+
+									geometry.faces.push( face );
 
-								skip ++;
+								}
 
-								geometry.faces.push( face );
 
 							}
 
+						} else {
+
+							// do not add dummy mesh to the scene
+							parent.parent.remove( parent );
 
 						}
 
@@ -850,8 +919,19 @@ THREE.VRMLLoader.prototype = {
 
 							parent.material = material;
 
-							// material found, stop looping
-							break;
+						}
+
+						if ( 'ImageTexture' === child.nodeType ) {
+
+							var textureName = /"([^"]+)"/.exec(child.children[ 0 ]);
+
+							if (textureName) {
+
+								parent.material.name = textureName[ 1 ];
+
+								parent.material.map = THREE.ImageUtils.loadTexture (texturePath + textureName[ 1 ]);
+
+							}
 
 						}
 
@@ -879,6 +959,40 @@ THREE.VRMLLoader.prototype = {
 
 		var lines = data.split( '\n' );
 
+		// some lines do not have breaks
+		for (var i = lines.length -1; i > -1; i--) {
+
+			// split lines with {..{ or {..[ - some have both
+			if (/{.*[{\[]/.test (lines[i])) {
+				var parts = lines[i].split ('{').join ('{\n').split ('\n');
+				parts.unshift(1);
+				parts.unshift(i);
+				lines.splice.apply(lines, parts);
+			} else
+
+			// split lines with ]..}
+			if (/\].*}/.test (lines[i])) {
+				var parts = lines[i].split (']').join (']\n').split ('\n');
+				parts.unshift(1);
+				parts.unshift(i);
+				lines.splice.apply(lines, parts);
+			}
+
+			// split lines with }..}
+			if (/}.*}/.test (lines[i])) {
+				var parts = lines[i].split ('}').join ('}\n').split ('\n');
+				parts.unshift(1);
+				parts.unshift(i);
+				lines.splice.apply(lines, parts);
+			}
+
+			// force the parser to create Coordinate node for empty coords
+			// coord USE something -> coord USE something Coordinate {}
+			if((lines[i].indexOf ('coord') > -1) && (lines[i].indexOf ('[') < 0) && (lines[i].indexOf ('{') < 0)) {
+				lines[i] += ' Coordinate {}';
+			}
+		}
+
 		var header = lines.shift();
 
 		if ( /V1.0/.exec( header ) ) {

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

@@ -101,7 +101,7 @@ THREE.VTKLoader.prototype = {
 		}
 
 		var geometry = new THREE.BufferGeometry();
-		geometry.addIndex( new THREE.BufferAttribute( new ( indices.length > 65535 ? Uint32Array : Uint16Array )( indices ), 1 ) );
+		geometry.setIndex( new THREE.BufferAttribute( new ( indices.length > 65535 ? Uint32Array : Uint16Array )( indices ), 1 ) );
 		geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
 
 		return geometry;

+ 20 - 1
examples/js/loaders/ctm/CTMLoader.js

@@ -12,6 +12,25 @@ THREE.CTMLoader = function () {
 
 	THREE.Loader.call( this );
 
+	// Deprecated
+	
+	Object.defineProperties( this, {
+		statusDomElement: {
+			get: function () {
+
+				if ( this._statusDomElement === undefined ) {
+
+					this._statusDomElement = document.createElement( 'div' );
+
+				}
+
+				console.warn( 'THREE.BinaryLoader: .statusDomElement has been removed.' );
+				return this._statusDomElement;
+
+			}
+		},
+	} );
+
 };
 
 THREE.CTMLoader.prototype = Object.create( THREE.Loader.prototype );
@@ -219,7 +238,7 @@ THREE.CTMLoader.prototype.createModel = function ( file, callback ) {
 
 		}
 
-		this.addIndex( new THREE.BufferAttribute( indices, 1 ) );
+		this.setIndex( new THREE.BufferAttribute( indices, 1 ) );
 		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
 
 		if ( normals !== undefined ) {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 716 - 258
examples/js/loaders/sea3d/SEA3D.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 244 - 152
examples/js/loaders/sea3d/SEA3DLoader.js


+ 2 - 2
examples/js/math/Lut.js

@@ -330,7 +330,7 @@ THREE.Lut.prototype = {
 		var txtTitle = new THREE.CanvasTexture( canvasTitle );
 		txtTitle.minFilter = THREE.LinearFilter;
 
-		var spriteMaterialTitle = new THREE.SpriteMaterial( { map: txtTitle, useScreenCoordinates: false } );
+		var spriteMaterialTitle = new THREE.SpriteMaterial( { map: txtTitle } );
 
 		var spriteTitle = new THREE.Sprite( spriteMaterialTitle );
 
@@ -410,7 +410,7 @@ THREE.Lut.prototype = {
 				var txtTick = new THREE.CanvasTexture( canvasTick );
 				txtTick.minFilter = THREE.LinearFilter;
 
-				var spriteMaterialTick = new THREE.SpriteMaterial( { map: txtTick, useScreenCoordinates: false } );
+				var spriteMaterialTick = new THREE.SpriteMaterial( { map: txtTick } );
 
 				var spriteTick = new THREE.Sprite( spriteMaterialTick );
 

+ 0 - 5
examples/js/postprocessing/GlitchPass.js

@@ -21,8 +21,6 @@ THREE.GlitchPass = function ( dt_size ) {
 		fragmentShader: shader.fragmentShader
 	} );
 
-	console.log( this.material );
-	
 	this.enabled = true;
 	this.renderToScreen = false;
 	this.needsSwap = true;
@@ -95,7 +93,6 @@ THREE.GlitchPass.prototype = {
 	generateHeightmap: function( dt_size ) {
 
 		var data_arr = new Float32Array( dt_size * dt_size * 3 );
-		console.log( dt_size );
 		var length = dt_size * dt_size;
 		
 		for ( var i = 0; i < length; i ++ ) {
@@ -108,8 +105,6 @@ THREE.GlitchPass.prototype = {
 		}
 		
 		var texture = new THREE.DataTexture( data_arr, dt_size, dt_size, THREE.RGBFormat, THREE.FloatType );
-		console.log( texture );
-		console.log( dt_size );
 		texture.needsUpdate = true;
 		return texture;
 

+ 1 - 1
examples/js/renderers/CSS3DRenderer.js

@@ -98,7 +98,7 @@ THREE.CSS3DRenderer = function () {
 
 	var epsilon = function ( value ) {
 
-		return Math.abs( value ) < 0.000001 ? 0 : value;
+		return Math.abs( value ) < Number.EPSILON ? 0 : value;
 
 	};
 

+ 1 - 1
examples/js/renderers/CSS3DStereoRenderer.js

@@ -145,7 +145,7 @@ THREE.CSS3DStereoRenderer = function () {
 
 	var epsilon = function ( value ) {
 
-		return Math.abs( value ) < 0.000001 ? 0 : value;
+		return Math.abs( value ) < Number.EPSILON ? 0 : value;
 
 	};
 

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio