Browse Source

Merge pull request #1 from mrdoob/master

Update from original
Tony Parisi 9 years ago
parent
commit
a44d9fe70c
100 changed files with 8457 additions and 2854 deletions
  1. 1 1
      .github/ISSUE_TEMPLATE.md
  2. 345 170
      build/three.js
  3. 171 167
      build/three.min.js
  4. 9 19
      docs/api/core/BufferGeometry.html
  5. 58 0
      docs/api/extras/geometries/BoxBufferGeometry.html
  6. 44 0
      docs/api/extras/geometries/CircleBufferGeometry.html
  7. 4 9
      docs/api/extras/geometries/CircleGeometry.html
  8. 56 0
      docs/api/extras/geometries/CylinderBufferGeometry.html
  9. 52 0
      docs/api/extras/geometries/LatheBufferGeometry.html
  10. 6 5
      docs/api/extras/geometries/LatheGeometry.html
  11. 50 0
      docs/api/extras/geometries/PlaneBufferGeometry.html
  12. 45 0
      docs/api/extras/geometries/RingBufferGeometry.html
  13. 57 0
      docs/api/extras/geometries/SphereBufferGeometry.html
  14. 51 0
      docs/api/extras/geometries/TorusBufferGeometry.html
  15. 57 0
      docs/api/extras/geometries/TorusKnotBufferGeometry.html
  16. 9 8
      docs/api/extras/geometries/TorusKnotGeometry.html
  17. 1 1
      docs/api/extras/geometries/TubeGeometry.html
  18. 14 4
      docs/api/lights/AmbientLight.html
  19. 1 0
      docs/api/lights/DirectionalLight.html
  20. 6 5
      docs/api/lights/HemisphereLight.html
  21. 15 6
      docs/api/lights/PointLight.html
  22. 14 6
      docs/api/lights/SpotLight.html
  23. 0 88
      docs/api/loaders/OBJMTLLoader.html
  24. 2 1
      docs/api/materials/LineBasicMaterial.html
  25. 5 6
      docs/api/materials/LineDashedMaterial.html
  26. 20 16
      docs/api/materials/MeshBasicMaterial.html
  27. 8 8
      docs/api/materials/MeshDepthMaterial.html
  28. 24 10
      docs/api/materials/MeshLambertMaterial.html
  29. 1 1
      docs/api/materials/MeshNormalMaterial.html
  30. 45 25
      docs/api/materials/MeshPhongMaterial.html
  31. 221 0
      docs/api/materials/MeshStandardMaterial.html
  32. 9 8
      docs/api/materials/PointsMaterial.html
  33. 1 0
      docs/api/materials/ShaderMaterial.html
  34. 3 3
      docs/api/materials/SpriteMaterial.html
  35. 4 4
      docs/api/objects/LineSegments.html
  36. 0 5
      docs/api/renderers/WebGLRenderTarget.html
  37. 5 0
      docs/api/textures/Texture.html
  38. 1 1
      docs/index.html
  39. 10 1
      docs/list.js
  40. 7 12
      docs/manual/introduction/Creating-a-scene.html
  41. 1 0
      docs/page.css
  42. 10 10
      docs/scenes/bones-browser.html
  43. 21 19
      docs/scenes/geometry-browser.html
  44. 357 10
      docs/scenes/js/geometry.js
  45. 43 0
      docs/scenes/js/material.js
  46. 12 12
      docs/scenes/material-browser.html
  47. 3 4
      editor/js/Menubar.Add.js
  48. 10 2
      editor/js/Sidebar.Geometry.LatheGeometry.js
  49. 12 23
      editor/js/Sidebar.Geometry.TorusKnotGeometry.js
  50. 10 10
      editor/js/libs/app.js
  51. 0 4
      editor/js/libs/tern-threejs/threejs.js
  52. 2 1
      examples/canvas_ascii_effect.html
  53. 2 1
      examples/canvas_camera_orthographic.html
  54. 2 1
      examples/canvas_camera_orthographic2.html
  55. 2 1
      examples/canvas_geometry_birds.html
  56. 2 1
      examples/canvas_geometry_cube.html
  57. 11 3
      examples/files.js
  58. 1 4
      examples/index.html
  59. 26 0
      examples/js/Encodings.js
  60. 51 0
      examples/js/Half.js
  61. 0 4
      examples/js/Ocean.js
  62. 6 8
      examples/js/ParametricGeometries.js
  63. 544 0
      examples/js/RollerCoaster.js
  64. 4 10
      examples/js/ShaderSkin.js
  65. 0 2
      examples/js/ShaderTerrain.js
  66. 448 0
      examples/js/Volume.js
  67. 217 0
      examples/js/VolumeSlice.js
  68. 97 0
      examples/js/WebVR.js
  69. 6 12
      examples/js/controls/EditorControls.js
  70. 21 39
      examples/js/controls/OrbitControls.js
  71. 19 0
      examples/js/controls/TrackballControls.js
  72. 5 3
      examples/js/effects/AnaglyphEffect.js
  73. 4 2
      examples/js/effects/CardboardEffect.js
  74. 5 3
      examples/js/effects/ParallaxBarrierEffect.js
  75. 71 4
      examples/js/exporters/OBJExporter.js
  76. 25 19
      examples/js/exporters/STLBinaryExporter.js
  77. 15 0
      examples/js/libs/inflate.min.js
  78. 51 0
      examples/js/libs/zlib_and_gzip.min.js
  79. 4 0
      examples/js/libs/zlib_and_gzip.min.js.map
  80. 99 6
      examples/js/loaders/ColladaLoader2.js
  81. 83 0
      examples/js/loaders/HDRCubeTextureLoader.js
  82. 0 2
      examples/js/loaders/MMDLoader.js
  83. 591 0
      examples/js/loaders/NRRDLoader.js
  84. 2 2
      examples/js/loaders/OBJLoader.js
  85. 2 2
      examples/js/loaders/PCDLoader.js
  86. 7 7
      examples/js/loaders/VRMLLoader.js
  87. 982 147
      examples/js/loaders/VTKLoader.js
  88. 317 307
      examples/js/loaders/gltf/glTF-parser.js
  89. 13 13
      examples/js/loaders/gltf/glTFAnimation.js
  90. 1466 1103
      examples/js/loaders/gltf/glTFLoader.js
  91. 185 106
      examples/js/loaders/gltf/glTFLoaderUtils.js
  92. 145 0
      examples/js/loaders/gltf/glTFShaders.js
  93. 204 0
      examples/js/loaders/gltf/gltfUtilities.js
  94. 1 2
      examples/js/materials/ShadowMaterial.js
  95. 0 1
      examples/js/modifiers/ExplodeModifier.js
  96. 387 350
      examples/js/modifiers/SubdivisionModifier.js
  97. 0 2
      examples/js/nodes/materials/PhongNode.js
  98. 0 2
      examples/js/nodes/materials/StandardNode.js
  99. 177 0
      examples/js/pmrem/PMREMCubeUVPacker.js
  100. 244 0
      examples/js/pmrem/PMREMGenerator.js

+ 1 - 1
.github/ISSUE_TEMPLATE.md

@@ -5,7 +5,7 @@
 ##### Three.js version
 
 - [ ] Dev
-- [ ] r74
+- [ ] r75
 - [ ] ...
 
 ##### Browser

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


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


+ 9 - 19
docs/api/core/BufferGeometry.html

@@ -27,25 +27,15 @@
 		var geometry = new THREE.BufferGeometry();
 		// create a simple square shape. We duplicate the top left and bottom right
 		// vertices because each vertex needs to appear once per triangle.
-		var vertexPositions = [
-			[-1.0, -1.0,  1.0],
-			[ 1.0, -1.0,  1.0],
-			[ 1.0,  1.0,  1.0],
-
-			[ 1.0,  1.0,  1.0],
-			[-1.0,  1.0,  1.0],
-			[-1.0, -1.0,  1.0]
-		];
-		var vertices = new Float32Array( vertexPositions.length * 3 ); // three components per vertex
-
-		// components of the position vector for each vertex are stored
-		// contiguously in the buffer.
-		for ( var i = 0; i < vertexPositions.length; i++ )
-		{
-			vertices[ i*3 + 0 ] = vertexPositions[i][0];
-			vertices[ i*3 + 1 ] = vertexPositions[i][1];
-			vertices[ i*3 + 2 ] = vertexPositions[i][2];
-		}
+		var vertices = new Float32Array( [
+			-1.0, -1.0,  1.0,
+			 1.0, -1.0,  1.0,
+			 1.0,  1.0,  1.0,
+
+			 1.0,  1.0,  1.0,
+			-1.0,  1.0,  1.0,
+			-1.0, -1.0,  1.0
+		] );
 
 		// itemSize = 3 because there are 3 values (components) per vertex
 		geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );

+ 58 - 0
docs/api/extras/geometries/BoxBufferGeometry.html

@@ -0,0 +1,58 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:BoxGeometry].</div>
+
+		<iframe src='scenes/geometry-browser.html#BoxBufferGeometry'></iframe>
+
+		<h2>Example</h2>
+
+		<code>var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
+		var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
+		var cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float width], [page:Float height], [page:Float depth], [page:Integer widthSegments], [page:Integer heightSegments], [page:Integer depthSegments])</h3>
+		<div>
+		width — Width of the sides on the X axis.<br />
+		height — Height of the sides on the Y axis.<br />
+		depth — Depth of the sides on the Z axis.<br />
+		widthSegments — Optional. Number of segmented faces along the width of the sides. Default is 1.<br />
+		heightSegments — Optional. Number of segmented faces along the height of the sides. Default is 1.<br />
+		depthSegments — Optional. Number of segmented faces along the depth of the sides. Default is 1.
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>.parameters</h3>
+ 		<div>
+			<p>Using the above example code above as our basis:</p>
+			<code>
+		geometry.parameters; // outputs an object {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined}
+		cube.geometry.parameters; // as above
+		cube.geometry.parameters.width; // === 1
+		cube.geometry.parameters.widthSegments // === undefined.
+			</code>
+ 		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 44 - 0
docs/api/extras/geometries/CircleBufferGeometry.html

@@ -0,0 +1,44 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:CircleGeometry].</div>
+
+		<h2>Example</h2>
+
+		<iframe src='scenes/geometry-browser.html#CircleBufferGeometry'></iframe>
+
+		<code>
+		var geometry = new THREE.CircleBufferGeometry( 5, 32 );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
+		var circle = new THREE.Mesh( geometry, material );
+		scene.add( circle );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]([page:Float radius], [page:Integer segments], [page:Float thetaStart], [page:Float thetaLength])</h3>
+		<div>
+		radius — Radius of the circle, default = 50.<br />
+		segments — Number of segments (triangles), minimum = 3, default = 8.<br />
+		thetaStart — Start angle for first segment, default = 0 (three o'clock position).<br />
+		thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete circle.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 4 - 9
docs/api/extras/geometries/CircleGeometry.html

@@ -19,15 +19,10 @@
 
 		<iframe src='scenes/geometry-browser.html#CircleGeometry'></iframe>
 
-		<code>var material = new THREE.MeshBasicMaterial({
-			color: 0x0000ff
-		});
-
-		var radius = 5;
-		var segments = 32;
-
-		var circleGeometry = new THREE.CircleGeometry( radius, segments );
-		var circle = new THREE.Mesh( circleGeometry, material );
+		<code>
+		var geometry = new THREE.CircleGeometry( 5, 32 );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
+		var circle = new THREE.Mesh( geometry, material );
 		scene.add( circle );
 		</code>
 

+ 56 - 0
docs/api/extras/geometries/CylinderBufferGeometry.html

@@ -0,0 +1,56 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:CylinderGeometry].</div>
+
+
+		<h2>Example</h2>
+
+		<iframe src='scenes/geometry-browser.html#CylinderBufferGeometry'></iframe>
+
+		<code>var geometry = new THREE.CylinderBufferGeometry( 5, 5, 20, 32 );
+		var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
+		var cylinder = new THREE.Mesh( geometry, material );
+		scene.add( cylinder );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float radiusTop], [page:Float radiusBottom], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])</h3>
+		<div>
+		radiusTop — Radius of the cylinder at the top. Default is 20.<br />
+		radiusBottom — Radius of the cylinder at the bottom. Default is 20.<br />
+		height — Height of the cylinder. Default is 100.<br />
+		radiusSegments — Number of segmented faces around the circumference of the cylinder. Default is 8<br />
+		heightSegments — Number of rows of faces along the height of the cylinder. Default is 1.<br />
+		openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped.<br />
+		thetaStart — Start angle for first segment, default = 0 (three o'clock position).<br />
+		thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete cylinder.
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<div>
+		Each of the constructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 52 - 0
docs/api/extras/geometries/LatheBufferGeometry.html

@@ -0,0 +1,52 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:LatheGeometry].</div>
+
+
+		<h2>Example</h2>
+
+		<iframe src='scenes/geometry-browser.html#LatheBufferGeometry'></iframe>
+
+		<code>
+		var points = [];
+		for ( var i = 0; i < 10; i ++ ) {
+			points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
+		}
+		var geometry = new THREE.LatheBufferGeometry( points );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
+		var lathe = new THREE.Mesh( geometry, material );
+		scene.add( lathe );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Array points], [page:Integer segments], [page:Float phiStart], [page:Float phiLength])</h3>
+		<div>
+		points — Array of Vector2s. The x-coordinate of each point must be greater than zero.<br />
+		segments — the number of circumference segments to generate. Default is 12.<br />
+		phiStart — the starting angle in radians. Default is 0.<br />
+		phiLength — the radian (0 to 2PI) range of the lathed section 2PI is a closed lathe, less than 2PI is a portion. Default is 2PI.
+		</div>
+		<div>
+		This creates a LatheBufferGeometry based on the parameters.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 6 - 5
docs/api/extras/geometries/LatheGeometry.html

@@ -17,11 +17,12 @@
 
 		<h2>Example</h2>
 
+		<iframe src='scenes/geometry-browser.html#LatheGeometry'></iframe>
+
 		<code>
 		var points = [];
 		for ( var i = 0; i < 10; i ++ ) {
-			points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 15 + 50, ( i - 5 ) * 2 ) );
-
+			points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
 		}
 		var geometry = new THREE.LatheGeometry( points );
 		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
@@ -34,13 +35,13 @@
 
 		<h3>[name]([page:Array points], [page:Integer segments], [page:Float phiStart], [page:Float phiLength])</h3>
 		<div>
-		points — Array of Vector2s.<br />
+		points — Array of Vector2s. The x-coordinate of each point must be greater than zero.<br />
 		segments — the number of circumference segments to generate. Default is 12.<br />
 		phiStart — the starting angle in radians. Default is 0.<br />
-		phiLength — the radian (0 to 2*PI) range of the lathed section 2*PI is a closed lathe, less than 2PI is a portion. Default is 2*PI
+		phiLength — the radian (0 to 2PI) range of the lathed section 2PI is a closed lathe, less than 2PI is a portion. Default is 2PI.
 		</div>
 		<div>
-		This creates a LatheGeometry based on the parameters.
+		This creates a LatheBufferGeometry based on the parameters.
 		</div>
 
 

+ 50 - 0
docs/api/extras/geometries/PlaneBufferGeometry.html

@@ -0,0 +1,50 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:PlaneGeometry].</div>
+
+		<h2>Example</h2>
+
+		<iframe src='scenes/geometry-browser.html#PlaneBufferGeometry'></iframe>
+
+		<code>var geometry = new THREE.PlaneBufferGeometry( 5, 20, 32 );
+		var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
+		var plane = new THREE.Mesh( geometry, material );
+		scene.add( plane );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float width], [page:Float height], [page:Integer widthSegments], [page:Integer heightSegments])</h3>
+		<div>
+		width — Width along the X axis.<br />
+		height — Height along the Y axis.<br />
+		widthSegments — Optional. Default is 1. <br />
+		heightSegments — Optional. Default is 1.
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<div>
+		Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 45 - 0
docs/api/extras/geometries/RingBufferGeometry.html

@@ -0,0 +1,45 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:RingGeometry].</div>
+
+		<iframe src='scenes/geometry-browser.html#RingBufferGeometry'></iframe>
+
+		<h2>Example</h2>
+
+		<code>var geometry = new THREE.RingBufferGeometry( 1, 5, 32 );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } );
+		var mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float innerRadius], [page:Float outerRadius], [page:Integer thetaSegments], [page:Integer phiSegments], [page:Float thetaStart], [page:Float thetaLength])</h3>
+		<div>
+		innerRadius — Default is 0, but it doesn't work right when innerRadius is set to 0.<br />
+		outerRadius — Default is 50. <br />
+		thetaSegments — Number of segments.  A higher number means the ring will be more round.  Minimum is 3.  Default is 8. <br />
+		phiSegments — Minimum is 1.  Default is 8.<br />
+		thetaStart — Starting angle. Default is 0. <br />
+		thetaLength — Central angle.  Default is Math.PI * 2.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 57 - 0
docs/api/extras/geometries/SphereBufferGeometry.html

@@ -0,0 +1,57 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:SphereGeometry].</div>
+
+		<h2>Example</h2>
+
+		<iframe src='scenes/geometry-browser.html#SphereBufferGeometry'></iframe>
+
+		<code>var geometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
+		var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
+		var sphere = new THREE.Mesh( geometry, material );
+		scene.add( sphere );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float radius], [page:Integer widthSegments], [page:Integer heightSegments], [page:Float phiStart], [page:Float phiLength], [page:Float thetaStart], [page:Float thetaLength])</h3>
+
+		<div>
+		radius — sphere radius. Default is 50.<br />
+		widthSegments — number of horizontal segments. Minimum value is 3, and the default is 8.<br />
+		heightSegments — number of vertical segments. Minimum value is 2, and the default is 6.<br />
+		phiStart — specify horizontal starting angle. Default is 0.<br />
+		phiLength — specify horizontal sweep angle size. Default is Math.PI * 2.<br />
+		thetaStart — specify vertical starting angle. Default is 0.<br />
+		thetaLength — specify vertical sweep angle size. Default is Math.PI.<br />
+		</div>
+
+		<div>
+		The geometry is created by sweeping and calculating vertexes around the Y axis (horizontal sweep) and the Z axis (vertical sweep). Thus, incomplete spheres (akin to <em>'sphere slices'</em>) can be created through the use of different values of phiStart, phiLength, thetaStart and thetaLength, in order to define the points in which we start (or end) calculating those vertices.
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<div>
+		Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 51 - 0
docs/api/extras/geometries/TorusBufferGeometry.html

@@ -0,0 +1,51 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:TorusGeometry].</div>
+
+		<iframe src='scenes/geometry-browser.html#TorusBufferGeometry'></iframe>
+
+		<h2>Example</h2>
+
+		<code>var geometry = new THREE.TorusBufferGeometry( 10, 3, 16, 100 );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
+		var torus = new THREE.Mesh( geometry, material );
+		scene.add( torus );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Float arc])</h3>
+		<div>
+		radius — Default is 100. <br />
+		tube — Diameter of the tube.  Default is 40. <br />
+		radialSegments — Default is 8 <br />
+		tubularSegments — Default is 6. <br />
+		arc — Central angle.  Default is Math.PI * 2.
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<div>
+		Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 57 - 0
docs/api/extras/geometries/TorusKnotBufferGeometry.html

@@ -0,0 +1,57 @@
+<!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:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">This is the [page:BufferGeometry] port of [page:TorusKnotGeometry].</div>
+
+		<iframe src='scenes/geometry-browser.html#TorusKnotBufferGeometry'></iframe>
+
+
+		<h2>Example</h2>
+
+		<code>var geometry = new THREE.TorusKnotBufferGeometry( 10, 3, 100, 16 );
+		var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
+		var torusKnot = new THREE.Mesh( geometry, material );
+		scene.add( torusKnot );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Float radius], [page:Float tube], [page:Integer tubularSegments], [page:Integer radialSegments], [page:Integer p], [page:Integer q])</h3>
+		<div>
+			<ul>
+				<li>radius — Default is 100.</li>
+				<li>tube — Diameter of the tube. Default is 40.</li>
+				<li>tubularSegments — Default is 64.</li>
+				<li>radialSegments — Default is 8.</li>
+				<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
+				<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
+			</ul>
+		</div>
+
+
+		<h2>Properties</h2>
+
+
+		<div>
+		Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 9 - 8
docs/api/extras/geometries/TorusKnotGeometry.html

@@ -29,15 +29,16 @@
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale])</h3>
+		<h3>[name]([page:Float radius], [page:Float tube], [page:Integer tubularSegments], [page:Integer radialSegments], [page:Integer p], [page:Integer q])</h3>
 		<div>
-		radius — Default is 100. <br />
-		tube — Default is 40. <br />
-		radialSegments — Default is 64. <br />
-		tubularSegments — Default is 8. <br />
-		p — Default is 2. <br />
-		q — Default is 3. <br />
-		heightScale — Default is 1.
+			<ul>
+				<li>radius — Default is 100.</li>
+				<li>tube — Diameter of the tube. Default is 40.</li>
+				<li>tubularSegments — Default is 64.</li>
+				<li>radialSegments — Default is 8.</li>
+				<li>p — This value determines, how many times the geometry winds around its axis of rotational symmetry. Default is 2.</li>
+				<li>q — This value determines, how many times the geometry winds around a circle in the interior of the torus. Default is 3.</li>
+			</ul>
 		</div>
 
 

+ 1 - 1
docs/api/extras/geometries/TubeGeometry.html

@@ -51,7 +51,7 @@ var geometry = new THREE.TubeGeometry(
 		segments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
 		radius — [page:Float] - The radius of the tube, default is 1<br />
 		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
-		closed — [page:Float] Is the tube open or closed, default is false <br />
+		closed — [page:Boolean] Is the tube open or closed, default is false <br />
 		</div>
 
 

+ 14 - 4
docs/api/lights/AmbientLight.html

@@ -24,7 +24,7 @@
 		<div>[example:canvas_sandbox sandbox ]</div>
 		<div>[example:webgl_animation_cloth animation / cloth ]</div>
 		<div>[example:webgl_animation_skinning_blending animation / skinning / blending ]</div>
-		
+
 <code>var light = new THREE.AmbientLight( 0x404040 ); // soft white light
 scene.add( light );</code>
 
@@ -39,19 +39,29 @@ scene.add( light );</code>
 		This creates an Ambientlight with a color.
 		</div>
 
+		<h2>Properties</h2>
+
+		<h3>[property:Float intensity]</h3>
+		<div>
+			Light's intensity.<br />
+			In "physically correct" mode, the product of color * intensity is interpreted as luminous irradiance measured in lux at the material surface.<br/>
+			Default — *1.0*.
+		</div>
+
+
 		<h2>Methods</h2>
-		
+
 		<h3>[method:AmbientLight clone]()</h3>
 		<div>
 		<br />
 		It returns a clone of Ambientlight.
 		</div>
-		
+
 		<h3>[method:JSON toJSON]()</h3>
 		<div>
 		Return Ambientlight data in JSON format.
 		</div>
-		
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

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

@@ -60,6 +60,7 @@ scene.add( directionalLight );</code>
 		<h3>[property:Float intensity]</h3>
 		<div>
 			Light's intensity.<br />
+			In "physically correct" mode, the product of intensity * color is interpreted as luminous irradiance measured in lux at the material's surface.<br/>
 			Default — *1.0*.
 		</div>
 

+ 6 - 5
docs/api/lights/HemisphereLight.html

@@ -13,16 +13,16 @@
 		<h1>[name]</h1>
 
 		<div class="desc">A light source positioned directly above the scene.</div>
-		
+
 		<h2>Example</h2>
-		
+
 		<div>[example:webgl_lights_hemisphere lights / hemisphere ]</div>
 		<div>[example:misc_controls_pointerlock controls / pointerlock ]</div>
 		<div>[example:webgl_decals decals ]</div>
 		<div>[example:webgl_loader_collada_kinematics loader / collada / kinematics ]</div>
 		<div>[example:webgl_materials_lightmap materials / lightmap ]</div>
 		<div>[example:webgl_shaders_ocean shaders / ocean ]</div>
-		
+
 <code>var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
 scene.add( light );</code>
 
@@ -47,17 +47,18 @@ scene.add( light );</code>
 		<h3>[property:Float intensity]</h3>
 		<div>
 			Light's intensity.<br />
+			In "physically correct" mode, the product of intensity * color (or intensity * groundColor) is interpreted as luminous irradiance measured in lux at the material's surface.<br/>
 			Default — *1.0*.
 		</div>
 
 		<h2>Methods</h2>
-		
+
 		<h3>[method:HemisphereLight clone]()</h3>
 		<div>
 		<br />
 		It returns a clone of HemisphereLight.
 		</div>
-		
+
 		<h3>[method:JSON toJSON]()</h3>
 		<div>
 		Return HemisphereLight data in JSON format.

+ 15 - 6
docs/api/lights/PointLight.html

@@ -28,7 +28,7 @@
 		<div>[example:webgl_geometry_large_mesh geometry / large / mesh ]</div>
 		<div>[example:webgl_geometry_text geometry / text ]</div>
 		<div>[example:webgl_lensflares lensflares ]</div>
-		
+
 		<code>var light = new THREE.PointLight( 0xff0000, 1, 100 );
 light.position.set( 50, 50, 50 );
 scene.add( light );</code>
@@ -46,7 +46,7 @@ scene.add( light );</code>
 		</div>
 		<div>
 		Creates a light at a specific position in the scene.  The light shines in all directions (roughly similar to a light bulb.)
-	
+
 		</div>
 
 
@@ -55,29 +55,38 @@ scene.add( light );</code>
 		<h3>[property:Float intensity]</h3>
 		<div>
 			Light's intensity.<br />
+			In "physically correct" mode, the product of color * intensity is interpreted as luminous intensity measured in candela.<br/>
 			Default - *1.0*.
 		</div>
 
+		<h3>[property:Float power]</h3>
+		<div>
+			Light's power.<br />
+			In "physically correct" mode, the luminous power of the light measured in lumens.<br/>
+			Default - *4PI*.
+		</div>
+
 		<h3>[property:Float distance]</h3>
 		<div>
 			If non-zero, light will attenuate linearly from maximum intensity at light *position* down to zero at *distance*.<br />
 			Default — *0.0*.
 		</div>
-		
+
 		<h3>[property:Float decay]</h3>
 		<div>
 			The amount the light dims along the distance of the light<br />
+			In "physically correct" mode, decay = 2 leads to physically realistic light falloff.<br/>
 			Default — *1*.
 		</div>
-		
+
 		<h2>Methods</h2>
-		
+
 		<h3>[method:PointLight clone]()</h3>
 		<div>
 		<br />
 		It returns a clone of PointLight.
 		</div>
-		
+
 		<h3>[method:JSON toJSON]()</h3>
 		<div>
 		Return PointLight data in JSON format.

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

@@ -55,13 +55,13 @@
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:Integer hex], [page:Float intensity], [page:Float distance], [page:Radians angle], [page:Float exponent], [page:Float decay])</h3>
+		<h3>[name]([page:Integer hex], [page:Float intensity], [page:Float distance], [page:Radians angle], [page:Float penumbra], [page:Float decay])</h3>
 		<div>
 		[page:Integer hex] — Numeric value of the RGB component of the color. <br />
 		[page:Float intensity] — Numeric value of the light's strength/intensity. <br />
 		[page:Float distance] -- Maximum distance from origin where light will shine whose intensity is attenuated linearly based on distance from origin. <br />
 		[page:Radians angle] -- Maximum angle of light dispersion from its direction whose upper bound is Math.PI/2.<br />
-		[page:Float exponent] -- Rapidity of the falloff of light from its target direction.<br />
+		[page:Float penumbra] -- Percent of the spotlight cone that is attenuated due to penumbra. Takes values between zero and 1. Default is zero.<br />
 		[page:Float decay] -- The amount the light dims along the distance of the light.
 		</div>
 
@@ -77,9 +77,17 @@
 		<h3>[property:Float intensity]</h3>
 		<div>
 			Light's intensity.<br />
+			In "physically correct" mode, the product of color * intensity is interpreted as luminous intensity measured in candela.<br/>
 			Default — *1.0*.
 		</div>
 
+		<h3>[property:Float power]</h3>
+		<div>
+			Light's power.<br />
+			In "physically correct" mode, the luminous power of the light measured in lumens.<br/>
+			Default - *4PI*.
+		</div>
+
 		<h3>[property:Float distance]</h3>
 		<div>
 			If non-zero, light will attenuate linearly from maximum intensity at light *position* down to zero at *distance*.<br />
@@ -92,16 +100,16 @@
 			Default — *Math.PI/3*.
 		</div>
 
-		<h3>[property:Float exponent]</h3>
+		<h3>[property:Float penumbra]</h3>
 		<div>
-			Rapidity of the falloff of light from its target direction. A lower value spreads out the light, while a higher
-			focuses it towards the center.<br />
-			Default — *10.0*.
+			Percent of the spotlight cone that is attenuated due to penumbra. Takes values between zero and 1.<br />
+			Default — *0.0*.
 		</div>
 
 		<h3>[property:Float decay]</h3>
 		<div>
 			The amount the light dims along the distance of the light<br />
+			In "physically correct" mode, decay = 2 leads to physically realistic light falloff.<br/>
 			Default — *1*.
 		</div>
 

+ 0 - 88
docs/api/loaders/OBJMTLLoader.html

@@ -1,88 +0,0 @@
-<!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">A loader for loading a <em>.obj</em> and its <em>.mtl</em> together.</div>
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]( [page:LoadingManager manager] )</h3>
-		<div>
-		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
-		</div>
-		<div>
-		Creates a new [name].
-		</div>
-
-		<h2>Properties</h2>
-
-
-		<h2>Methods</h2>
-
-		<h3>[method:null load]( [page:String objUrl], [page:String mtlUrl], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )</h3>
-		<div>
-		[page:String objUrl] — required. URL to the <em>.obj</em> resource<br />
-		[page:String mtlUrl] — required. URL to the <em>.mtl</em> resource<br />
-		[page:Function onLoad] — Will be called when both resources load complete. The argument will be the loaded [page:Object3D].<br />
-		[page:Function onProgress] — Will be called while both load progress. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.<br />
-		[page:Function onError] — Will be called when load errors.<br />
-		</div>
-		<div>
-		Begin loading from urls and call onLoad with the parsed response content.
-		</div>
-
-		<h3>[method:Object3D parse]( [page:String text], [page:Function mtllibCallback] )</h3>
-		<div>
-		[page:String text] — required. The textual <em>obj</em> structure to parse.<br/>
-		[page:Function mtllibCallback] — optional. Callback to handle <em>mtllib</em> declaration.<br/>
-		</div>
-		<div>
-		Parse an <em>obj</em> text structure and return an [page:Object3D].<br />
-		Found objects are converted to a [page:Mesh] and materials are converted to [page:MeshLambertMaterial].
-		</div>
-
-		<h2>Example</h2>
-
-		<code>
-		// instantiate a loader
-		var loader = new THREE.OBJMTLLoader();
-
-		// load an obj / mtl resource pair
-		loader.load(
-			// OBJ resource URL
-			'obj/male02/male02.obj',
-			// MTL resource URL
-			'obj/male02/male02_dds.mtl',
-			// Function when both resources are loaded
-			function ( object ) {
-				scene.add( object );
-			},
-			// Function called when downloads progress
-			function ( xhr ) {
-				console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
-			},
-			// Function called when downloads error
-			function ( xhr ) {
-				console.log( 'An error happened' );
-			}
-		);
-		</code>
-
-		[example:webgl_loader_obj_mtl]
-
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJMTLLoader.js examples/js/loaders/OBJMTLLoader.js]
-	</body>
-</html>

+ 2 - 1
docs/api/materials/LineBasicMaterial.html

@@ -31,6 +31,7 @@
 		</div>
 
 		<h2>Properties</h2>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Integer color]</h3>
 		<div>Sets the color of the line. Default is 0xffffff.</div>
@@ -55,7 +56,7 @@
 		<div>Define whether the material color is affected by global fog settings.</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>
 
-		
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 5 - 6
docs/api/materials/LineDashedMaterial.html

@@ -32,13 +32,12 @@
 
 
 		<h2>Properties</h2>
-
-
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Color color]</h3>
 		<div>
 		Sets the color of the line. Default is 0xffffff.
-		</div> 
+		</div>
 
 		<h3>[property:number linewidth]</h3>
 		<div>Controls line thickness. Default is 1.</div>
@@ -47,17 +46,17 @@
 		<h3>[property:number scale]</h3>
 		<div>
 		The scale of the dashed part of a line.
-		</div> 
+		</div>
 
 		<h3>[property:number dashSize]</h3>
 		<div>
 		The size of the dash. This is both the gap with the stroke. Default is 3.
-		</div> 
+		</div>
 
 		<h3>[property:number gapSize]</h3>
 		<div>
 		The size of the gap. Default is 1.
-		</div> 
+		</div>
 
 		<h3>[property:boolean vertexColors]</h3>
 		<div>Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.</div>

+ 20 - 16
docs/api/materials/MeshBasicMaterial.html

@@ -26,10 +26,14 @@
 		<div>
 		color — geometry color in hexadecimal. Default is 0xffffff.<br />
 		map — Set texture map. Default is null <br />
-		aoMap — Set ambient occlusion map. Default is null <br />
+		aoMap — Set ao map. Default is null.<br />
+		aoMapIntensity — Set ao map intensity. Default is 1.<br />
 		specularMap — Set specular map. Default is null.<br />
 		alphaMap — Set alpha map. Default is null.<br />
 		envMap — Set env map. Default is null.<br />
+		combine — Set combine operation. Default is THREE.MultiplyOperation.<br />
+		reflectivity — Set reflectivity. Default is 1.<br />
+		refractionRatio — Set refraction ratio. Default is 0.98.<br />
 		fog — Define whether the material color is affected by global fog settings. Default is true.<br />
 		shading — Define shading type. Default is THREE.SmoothShading.<br />
 		wireframe — render geometry as wireframe. Default is false.<br />
@@ -42,6 +46,7 @@
 		</div>
 
 		<h2>Properties</h2>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Integer color]</h3>
 		<div>Sets the color of the geometry. Default is 0xffffff.</div>
@@ -54,6 +59,9 @@
 		<h3>[property:Texture aoMap]</h3>
 		<div>Set ambient occlusion map. Default is null.</div>
 
+		<h3>[property:Float aoMapIntensity]</h3>
+		<div>TODO</div>
+
 		<h3>[property:Texture specularMap]</h3>
 		<div>Set specular map. Default is null.</div>
 
@@ -64,6 +72,17 @@
 		<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>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>
+
+		<h3>[property:Float refractionRatio]</h3>
+		<div>The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.</div>
+
 		<h3>[property:Boolean fog]</h3>
 		<div>Define whether the material color is affected by global fog settings.</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>
@@ -96,21 +115,6 @@
 		<h3>[property:Boolean morphTargets]</h3>
 		<div>Define whether the material uses morphTargets. Default is false.</div>
 
-		<h3>[property:number combine]</h3>
-		<div>
-		How to combine the result of the surface's color with the environment map, if any.
-		</div>
-
-		<h3>[property:number reflectivity]</h3>
-		<div>
-		How much the environment map affects the surface; also see "combine".
-		</div>
-
-		<h3>[property:number refractionRatio]</h3>
-		<div>
-		The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.
-		</div>
-
 		<h2>Methods</h2>
 
 		<h2>Source</h2>

+ 8 - 8
docs/api/materials/MeshDepthMaterial.html

@@ -13,7 +13,7 @@
 		<h1>[name]</h1>
 
 		<div class="desc">A material for drawing geometry by depth. Depth is based off of the camera near and far plane. White is nearest, black is farthest.</div>
-		
+
 		<iframe src='scenes/material-browser.html#MeshDepthMaterial'></iframe>
 
 		<h2>Constructor</h2>
@@ -21,7 +21,7 @@
 
 		<h3>[name]([page:Object parameters])</h3>
 		<div>
-		parameters is an object with one or more properties defining the material's appearance. 
+		parameters is an object with one or more properties defining the material's appearance.
 		</div>
 		<div>
 		morphTargets -- Define whether the material uses morphTargets. Default is false.<br/>
@@ -31,20 +31,20 @@
 
 
 		<h2>Properties</h2>
-
+		<div>See the base [page:Material] class for common properties.</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 wireframe]</h3>
-		<div>Render geometry as wireframe. Default is false (i.e. render as smooth shaded).</div> 
-		
+		<div>Render geometry as wireframe. Default is false (i.e. render as smooth shaded).</div>
+
 		<h3>[property:number wireframeLinewidth]</h3>
 		<div>
 			Controls wireframe thickness. Default is 1.<br/><br/>
 			Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.
-		</div> 
-		
+		</div>
+
 		<h2>Methods</h2>
 
 

+ 24 - 10
docs/api/materials/MeshLambertMaterial.html

@@ -27,11 +27,18 @@
 		color — Line color in hexadecimal. Default is 0xffffff.<br />
 		map — Sets the texture map. Default is null <br />
 		lightMap — Set light map. Default is null.<br />
+		lightMapIntensity — Set light map intensity. Default is 1.<br />
 		aoMap — Set ao map. Default is null.<br />
+		aoMapIntensity — Set ao map intensity. Default is 1.<br />
+		emissive - Set emissive color. Default is 0x000000.<br />
 		emissiveMap — Set emissive map. Default is null.<br />
+		emissiveIntensity — Set emissive map intensity. Default is 1.<br />
 		specularMap — Set specular map. Default is null.<br />
 		alphaMap — Set alpha map. Default is null.<br />
 		envMap — Set env map. Default is null.<br />
+		combine — Set combine operation. Default is THREE.MultiplyOperation.<br />
+		reflectivity — Set reflectivity. Default is 1.<br />
+		refractionRatio — Set refraction ratio. Default is 0.98.<br />
 		fog — Define whether the material color is affected by global fog settings. Default is false.<br />
 		wireframe — Render geometry as wireframe. Default is false (i.e. render as smooth shaded).<br/>
 		wireframeLinewidth — Controls wireframe thickness. Default is 1.<br/>
@@ -39,38 +46,45 @@
 		wireframeLinejoin — Define appearance of line joints. Default is 'round'.<br />
 		vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.<br />
 		skinning — Define whether the material uses skinning. Default is false.<br />
-		morphTargets — Define whether the material uses morphTargets. Default is false.<br/>
+		morphTargets — Define whether the material uses morphTargets. Default is false.<br />
+		morphNormals — Define whether the material uses morphNormals. Default is false.
 		</div>
 
 
 		<h2>Properties</h2>
-		<div>See the base [page:Material] class for common parameters.</div>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Color color]</h3>
 		<div>
 		Diffuse color of the material. Default is white.<br />
 		</div>
 
-		<h3>[property:Color emissive]</h3>
-		<div>
-		Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.<br />
-		</div>
-
-		<h3>[property:Float emissiveIntensity]</h3>
-		<div>Intensity of the emissive light. Modulates the emissive color. Default is 1.</div>
-
 		<h3>[property:Texture map]</h3>
 		<div>Set color texture map. Default is null.</div>
 
 		<h3>[property:Texture lightMap]</h3>
 		<div>Set light map. Default is null. The lightMap requires a second set of UVs.</div>
 
+		<h3>[property:Float lightMapIntensity]</h3>
+		<div>TODO</div>
+
 		<h3>[property:Texture aoMap]</h3>
 		<div>Set ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
 
+		<h3>[property:Float aoMapIntensity]</h3>
+		<div>TODO</div>
+
+		<h3>[property:Color emissive]</h3>
+		<div>
+		Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.<br />
+		</div>
+
 		<h3>[property:Texture emissiveMap]</h3>
 		<div>Set emisssive (glow) map. Default is null. The emissive map color is modulated by the emissive color and the emissive intensity. If you have an emissive map, be sure to set the emissive color to something other than black.</div>
 
+		<h3>[property:Float emissiveIntensity]</h3>
+		<div>Intensity of the emissive light. Modulates the emissive color. Default is 1.</div>
+
 		<h3>[property:Texture specularMap]</h3>
 		<div>Since this material does not have a specular component, the specular value affects only how much of the environment map affects the surface. Default is null.</div>
 

+ 1 - 1
docs/api/materials/MeshNormalMaterial.html

@@ -32,7 +32,7 @@
 
 
 		<h2>Properties</h2>
-
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:boolean wireframe]</h3>
 		<div>

+ 45 - 25
docs/api/materials/MeshPhongMaterial.html

@@ -21,20 +21,33 @@
 
 		<h3>[name]([page:Object parameters])</h3>
 		<div>
-		parameters -- an object with one or more of the material's properties defining the its appearance.
+		parameters -- an object with one or more of the material's properties defining the material's appearance.
 		</div>
 		<div>
 		color — geometry color in hexadecimal. Default is 0xffffff.<br />
-		map — Set texture map. Default is null <br />
+		specular — Set specular color. Default is 0x111111 .<br />
+		shininess — Set shininess Default is 30.<br />
+		map — Set texture map. Default is null.<br />
 		lightMap — Set light map. Default is null.<br />
+		lightMapIntensity — Set light map intensity. Default is 1.<br />
 		aoMap — Set ao map. Default is null.<br />
+		aoMapIntensity — Set ao map intensity. Default is 1.<br />
+		emissive - Set emissive color. Default is 0x000000.<br />
 		emissiveMap — Set emissive map. Default is null.<br />
-		specularMap — Set specular map. Default is null.<br />
-		alphaMap — Set alpha map. Default is null.<br />
+		emissiveIntensity — Set emissive map intensity. Default is 1.<br />
+		bumpMap — Set bump map. Default is null.<br />
+		bumpMapScale — Set bump map scale. Default is 1.<br />
+		normalMap — Set normal map. Default is null.<br />
+		normalMapScale — Set normal map scale. Default is (1, 1).<br />
 		displacementMap — Set displacement map. Default is null.<br />
 		displacementScale — Set displacement scale. Default is 1.<br />
 		displacementBias — Set displacement offset. Default is 0.<br />
+		specularMap — Set specular map. Default is null.<br />
+		alphaMap — Set alpha map. Default is null.<br />
 		envMap — Set env map. Default is null.<br />
+		combine — Set combine operation. Default is THREE.MultiplyOperation.<br />
+		reflectivity — Set reflectivity. Default is 1.<br />
+		refractionRatio — Set refraction ratio. Default is 0.98.<br />
 		fog — Define whether the material color is affected by global fog settings. Default is true.<br />
 		shading — Define shading type. Default is THREE.SmoothShading.<br />
 		wireframe — render geometry as wireframe. Default is false.<br />
@@ -43,7 +56,8 @@
 		wireframeLinejoin — Define appearance of line joints. Default is 'round'.<br />
 		vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.<br />
 		skinning — Define whether the material uses skinning. Default is false.<br />
-		morphTargets — Define whether the material uses morphTargets. Default is false.
+		morphTargets — Define whether the material uses morphTargets. Default is false.<br />
+		morphNormals — Define whether the material uses morphNormals. Default is false.
 		</div>
 		<div>
 		Example:<br>
@@ -53,21 +67,13 @@
 
 
 		<h2>Properties</h2>
-		<div>See the base [page:Material] class for common parameters.</div>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Color color]</h3>
 		<div>
 		Diffuse color of the material. Default is white.<br />
 		</div>
 
-		<h3>[property:Color emissive]</h3>
-		<div>
-		Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.<br />
-		</div>
-
-		<h3>[property:Float emissiveIntensity]</h3>
-		<div>Intensity of the emissive light. Modulates the emissive color. Default is 1.</div>
-
 		<h3>[property:Color specular]</h3>
 		<div>
 		Specular color of the material, i.e., how shiny the material is and the color of its shine. Setting this the same color as the diffuse value (times some intensity) makes the material more metallic-looking; setting this to some gray makes the material look more plastic. Default is dark gray.<br />
@@ -82,12 +88,26 @@
 		<h3>[property:Texture lightMap]</h3>
 		<div>Set light map. Default is null. The lightMap requires a second set of UVs.</div>
 
+		<h3>[property:Float lightMapIntensity]</h3>
+		<div>TODO</div>
+
 		<h3>[property:Texture aoMap]</h3>
 		<div>Set ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
 
+		<h3>[property:Float aoMapIntensity]</h3>
+		<div>TODO</div>
+
+		<h3>[property:Color emissive]</h3>
+		<div>
+		Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.<br />
+		</div>
+
 		<h3>[property:Texture emissiveMap]</h3>
 		<div>Set emisssive (glow) map. Default is null. The emissive map color is modulated by the emissive color and the emissive intensity. If you have an emissive map, be sure to set the emissive color to something other than black.</div>
 
+		<h3>[property:Float emissiveIntensity]</h3>
+		<div>Intensity of the emissive light. Modulates the emissive color. Default is 1.</div>
+
 		<h3>[property:Texture bumpMap]</h3>
 		<div>
 			The texture to create a bump map. The black and white values map to the perceived depth in relation to the lights.
@@ -111,29 +131,29 @@
 			How much the normal map affects the material. Typical ranges are 0-1. Default is (1,1).
 		</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>
-
-		<h3>[property:Texture alphaMap]</h3>
-		<div>The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.</div>
-		<div>Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.</div>
-
 		<h3>[property:Texture displacementMap]</h3>
 		<div>
-			The displacement map affects the position of the mesh's vertices. Unlike other maps which only affect the light and shade of the material the displaced vertices can cast shadows, block other objects, and otherwise act as real geometry. 
+			The displacement map affects the position of the mesh's vertices. Unlike other maps which only affect the light and shade of the material the displaced vertices can cast shadows, block other objects, and otherwise act as real geometry.
 			The displacement texture is an image where the value of each pixel (white being the highest) is mapped against, and repositions, the vertices of the mesh.
 		</div>
-		
+
 		<h3>[property:Float displacementScale]</h3>
 		<div>
 			How much the displacement map affects the mesh (where black is no displacement, and white is maximum displacement). Without a displacement map set, this value is not applied. Default is 1.
 		</div>
-		
+
 		<h3>[property:Float displacementBias]</h3>
 		<div>
 			The offset of the displacement map's values on the mesh's vertices. Without a displacement map set, this value is not applied. Default is 0.
 		</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>
+
+		<h3>[property:Texture alphaMap]</h3>
+		<div>The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.</div>
+		<div>Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.</div>
+
 		<h3>[property:TextureCube envMap]</h3>
 		<div>Set env map. Default is null.</div>
 

+ 221 - 0
docs/api/materials/MeshStandardMaterial.html

@@ -0,0 +1,221 @@
+<!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:Material] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">TODO</div>
+
+		<iframe src='scenes/material-browser.html#MeshStandardMaterial'></iframe>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Object parameters])</h3>
+		<div>
+		parameters -- an object with one or more of the material's properties defining the material's appearance.
+		</div>
+		<div>
+		color — geometry color in hexadecimal. Default is 0xffffff.<br />
+		roughness — Set roughness. Default is 0.5.<br />
+		metalness — Set metalness. Default is 0.5.<br />
+		map — Set texture map. Default is null.<br />
+		lightMap — Set light map. Default is null.<br />
+		lightMapIntensity — Set light map intensity. Default is 1.<br />
+		aoMap — Set ao map. Default is null.<br />
+		aoMapIntensity — Set ao map intensity. Default is 1.<br />
+		emissive - Set emissive color. Default is 0x000000.<br />
+		emissiveMap — Set emissive map. Default is null.<br />
+		emissiveIntensity — Set emissive map intensity. Default is 1.<br />
+		bumpMap — Set bump map. Default is null.<br />
+		bumpMapScale — Set bump map scale. Default is 1.<br />
+		normalMap — Set normal map. Default is null.<br />
+		normalMapScale — Set normal map scale. Default is (1, 1).<br />
+		displacementMap — Set displacement map. Default is null.<br />
+		displacementScale — Set displacement scale. Default is 1.<br />
+		displacementBias — Set displacement offset. Default is 0.<br />
+		roughnessMap - Set roughness map. Default is null.<br />
+		metalnessMap - Set metalness map. Default is null.<br />
+		alphaMap — Set alpha map. Default is null.<br />
+		envMap — Set env map. Default is null.<br />
+		envMapIntensity — Set env map intensity. Default is 1.0.<br />
+		refractionRatio — Set refraction ratio. Default is 0.98.<br />
+		fog — Define whether the material color is affected by global fog settings. Default is true.<br />
+		shading — Define shading type. Default is THREE.SmoothShading.<br />
+		wireframe — render geometry as wireframe. Default is false.<br />
+		wireframeLinewidth — Line thickness. Default is 1.<br />
+		wireframeLinecap — Define appearance of line ends. Default is 'round'.<br />
+		wireframeLinejoin — Define appearance of line joints. Default is 'round'.<br />
+		vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.<br />
+		skinning — Define whether the material uses skinning. Default is false.<br />
+		morphTargets — Define whether the material uses morphTargets. Default is false.<br />
+		morphNormals — Define whether the material uses morphNormals. Default is false.
+		</div>
+		<div>
+		Example:<br>
+		materials.push( new THREE.MeshStandardMaterial( { color: 0x550000, envMap: reflectionCube, roughness: 0.1, metalness: 1.0 } ) );
+
+		</div>
+
+
+		<h2>Properties</h2>
+		<div>See the base [page:Material] class for common properties.</div>
+
+		<h3>[property:Color color]</h3>
+		<div>
+		Diffuse color of the material. Default is white.<br />
+		</div>
+
+		<h3>[property:Float roughness]</h3>
+		<div>
+		TODO.<br />
+		</div>
+
+		<h3>[property:Float metalness]</h3>
+		<div>
+		TODO<br />
+		</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>
+
+		<h3>[property:Texture lightMap]</h3>
+		<div>Set light map. Default is null. The lightMap requires a second set of UVs.</div>
+
+		<h3>[property:Float lightMapIntensity]</h3>
+		<div>TODO</div>
+
+		<h3>[property:Texture aoMap]</h3>
+		<div>Set ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
+
+		<h3>[property:Float aoMapIntensity]</h3>
+		<div>TODO</div>
+
+		<h3>[property:Color emissive]</h3>
+		<div>
+			Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.<br />
+		</div>
+
+		<h3>[property:Texture emissiveMap]</h3>
+		<div>Set emisssive (glow) map. Default is null. The emissive map color is modulated by the emissive color and the emissive intensity. If you have an emissive map, be sure to set the emissive color to something other than black.</div>
+
+		<h3>[property:Float emissiveIntensity]</h3>
+		<div>Intensity of the emissive light. Modulates the emissive color. Default is 1.</div>
+
+		<h3>[property:Texture bumpMap]</h3>
+		<div>
+			The texture to create a bump map. The black and white values map to the perceived depth in relation to the lights.
+			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.
+		</div>
+
+		<h3>[property:Texture normalMap]</h3>
+		<div>
+			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>
+
+		<h3>[property:Texture displacementMap]</h3>
+		<div>
+			The displacement map affects the position of the mesh's vertices. Unlike other maps which only affect the light and shade of the material the displaced vertices can cast shadows, block other objects, and otherwise act as real geometry.
+			The displacement texture is an image where the value of each pixel (white being the highest) is mapped against, and repositions, the vertices of the mesh.
+		</div>
+
+		<h3>[property:Float displacementScale]</h3>
+		<div>
+			How much the displacement map affects the mesh (where black is no displacement, and white is maximum displacement). Without a displacement map set, this value is not applied. Default is 1.
+		</div>
+
+		<h3>[property:Float displacementBias]</h3>
+		<div>
+			The offset of the displacement map's values on the mesh's vertices. Without a displacement map set, this value is not applied. Default is 0.
+		</div>
+
+		<h3>[property:Texture roughnessMap]</h3>
+		<div>
+			TODO.
+		</div>
+
+		<h3>[property:Texture metalnessMap]</h3>
+		<div>
+			TODO.
+		</div>
+
+		<h3>[property:Texture alphaMap]</h3>
+		<div>The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.</div>
+		<div>Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.</div>
+
+		<h3>[property:TextureCube envMap]</h3>
+		<div>Set env map. Default is null.</div>
+
+		<h3>[property:Float envMapIntensity]</h3>
+		<div>TODO</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>
+
+		<h3>[property:Boolean fog]</h3>
+		<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].</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>
+
+		<h3>[property:String wireframeLinecap]</h3>
+		<div>Define appearance of line ends. Possible values are "butt", "round" and "square". Default is 'round'.</div>
+		<div>This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.</div>
+
+		<h3>[property:String wireframeLinejoin]</h3>
+		<div>Define appearance of line joints. Possible values are "round", "bevel" and "miter". Default is 'round'.</div>
+		<div>This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.</div>
+
+		<h3>[property:Integer vertexColors]</h3>
+		<div>Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.</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: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>
+
+		<h3>[property:boolean morphNormals]</h3>
+		<div>
+			Defines whether the material uses morphNormals. Set as true to pass morphNormal attributes from the [page:Geometry]
+			to the shader. Default is *false*.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 9 - 8
docs/api/materials/PointsMaterial.html

@@ -20,7 +20,7 @@
 		<h3>[name]( [page:Object parameters] )</h3>
 
 		<div>parameters is an object with one or more properties defining the material's appearance.</div>
-		
+
 		<div>
 		color — Particle color in hexadecimal. Default is 0xffffff.<br />
 		map — a [page:Texture texture].If defined, then a point has the data from texture as colors. Default is null.<br />
@@ -31,27 +31,28 @@
 		</div>
 
 		<h2>Properties</h2>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Number color]</h3>
-		
+
 		<div>Sets the color of the particles. Default is 0xffffff.</div>
-		
+
 		<h3>[property:Texture map]</h3>
-		
+
 		<div>Sets the color of the particles using data from a texture.</div>
-		
+
 		<h3>[property:Number size]</h3>
-		
+
 		<div>Sets the size of the particles. Default is 1.0.</div>
 
 		<h3>[property:Boolean sizeAttenuation]</h3>
-		
+
 		<div>Specify whether particles' size will get smaller with the distance. Default is true.</div>
 
 		<h3>[property:Boolean vertexColors]</h3>
 		<div>Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.</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:Boolean fog]</h3>
 		<div>Define whether the material color is affected by global fog settings.</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>

+ 1 - 0
docs/api/materials/ShaderMaterial.html

@@ -211,6 +211,7 @@
 		</div>
 
 		<h2>Properties</h2>
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Object uniforms]</h3>
 		<div>

+ 3 - 3
docs/api/materials/SpriteMaterial.html

@@ -31,13 +31,13 @@
 
 
 		<h2>Properties</h2>
-
+		<div>See the base [page:Material] class for common properties.</div>
 
 		<h3>[property:Color color]</h3>
-		<div>The texture is multiplied by this color. The default is 0xffffff</div> 
+		<div>The texture is multiplied by this color. The default is 0xffffff</div>
 
 		<h3>[property:Texture map]</h3>
-		<div>The texture map. Default is null.</div> 
+		<div>The texture map. Default is null.</div>
 
 		<h3>[property:Radians rotation]</h3>
 		<div>The rotation of the sprite in radians. Default is 0.</div>

+ 4 - 4
docs/api/objects/LineSegments.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">A series of lines.</div>
+		<div class="desc">A series of lines drawn between pairs of vertices.</div>
 
 
 		<h2>Constructor</h2>
@@ -20,7 +20,7 @@
 		<h3>[name]( [page:Geometry geometry], [page:Material material] )</h3>
 
 		<div>
-		geometry — Vertices representing the line segment(s).<br />
+		geometry — Pair(s) of vertices representing each line segment(s).<br />
 		material — Material for the line. Default is [page:LineBasicMaterial LineBasicMaterial].
 		</div>
 
@@ -31,7 +31,7 @@
 
 		<h3>[property:Geometry geometry]</h3>
 		<div>
-		Vertices representing the line segment(s).
+		Pair(s) of vertices representing the line segment(s).
 		</div>
 
 		<h3>[property:Material material]</h3>

+ 0 - 5
docs/api/renderers/WebGLRenderTarget.html

@@ -88,11 +88,6 @@
 		Whether to generate mipmaps (if possible) for a texture. True by default.
 		</div>
 
-		<h3>[property:WebGLRenderTarget shareDepthFrom]</h3>
-		<div>
-		Shares the depth from another WebGLRenderTarget. Default is null.
-		</div>
-
 		
 		<h2>Methods</h2>
 		

+ 5 - 0
docs/api/textures/Texture.html

@@ -128,6 +128,11 @@
 		False by default, which is the norm for PNG images. Set to true if the RGB values have been stored premultiplied by alpha.
 		</div>
 
+		<h3>[property:number encoding]</h3>
+		<div>
+		Set to THREE.LinearEncoding by default, but supports sRGB, RGBE, RGBM, RGBD, LogLuv and Gamma corrected encodings.  IMPORTANT: If this value is changed on a texture after the material has been used, it is necessary to trigger a Material.needsUpdate for this value to be realized in the shader.
+		</div>
+
 		<h3>[property:object onUpdate]</h3>
 		<div>
 		A callback function, called when the texture is updated (e.g., when needsUpdate has been set to true and then the texture is used).

+ 1 - 1
docs/index.html

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

+ 10 - 1
docs/list.js

@@ -57,7 +57,6 @@ var list = {
 			[ "MaterialLoader", "api/loaders/MaterialLoader" ],
 			[ "MTLLoader", "api/loaders/MTLLoader" ],
 			[ "OBJLoader", "api/loaders/OBJLoader" ],
-			[ "OBJMTLLoader", "api/loaders/OBJMTLLoader" ],
 			[ "ObjectLoader", "api/loaders/ObjectLoader" ],
 			[ "PDBLoader", "api/loaders/PDBLoader" ],
 			[ "SVGLoader", "api/loaders/SVGLoader" ],
@@ -76,6 +75,7 @@ var list = {
 			[ "MeshLambertMaterial", "api/materials/MeshLambertMaterial" ],
 			[ "MeshNormalMaterial", "api/materials/MeshNormalMaterial" ],
 			[ "MeshPhongMaterial", "api/materials/MeshPhongMaterial" ],
+			[ "MeshStandardMaterial", "api/materials/MeshStandardMaterial" ],
 			[ "PointsMaterial", "api/materials/PointsMaterial" ],
 			[ "RawShaderMaterial", "api/materials/RawShaderMaterial" ],
 			[ "ShaderMaterial", "api/materials/ShaderMaterial" ],
@@ -191,23 +191,32 @@ var list = {
 		],
 
 		"Extras / Geometries": [
+			[ "BoxBufferGeometry", "api/extras/geometries/BoxBufferGeometry" ],
 			[ "BoxGeometry", "api/extras/geometries/BoxGeometry" ],
+			[ "CircleBufferGeometry", "api/extras/geometries/CircleBufferGeometry" ],
 			[ "CircleGeometry", "api/extras/geometries/CircleGeometry" ],
+			[ "CylinderBufferGeometry", "api/extras/geometries/CylinderBufferGeometry" ],
 			[ "CylinderGeometry", "api/extras/geometries/CylinderGeometry" ],
 			[ "DodecahedronGeometry", "api/extras/geometries/DodecahedronGeometry" ],
 			[ "ExtrudeGeometry", "api/extras/geometries/ExtrudeGeometry" ],
 			[ "IcosahedronGeometry", "api/extras/geometries/IcosahedronGeometry" ],
+			[ "LatheBufferGeometry", "api/extras/geometries/LatheBufferGeometry" ],
 			[ "LatheGeometry", "api/extras/geometries/LatheGeometry" ],
 			[ "OctahedronGeometry", "api/extras/geometries/OctahedronGeometry" ],
 			[ "ParametricGeometry", "api/extras/geometries/ParametricGeometry" ],
+			[ "PlaneBufferGeometry", "api/extras/geometries/PlaneBufferGeometry" ],
 			[ "PlaneGeometry", "api/extras/geometries/PlaneGeometry" ],
 			[ "PolyhedronGeometry", "api/extras/geometries/PolyhedronGeometry" ],
+			[ "RingBufferGeometry", "api/extras/geometries/RingBufferGeometry" ],
 			[ "RingGeometry", "api/extras/geometries/RingGeometry" ],
 			[ "ShapeGeometry", "api/extras/geometries/ShapeGeometry" ],
+			[ "SphereBufferGeometry", "api/extras/geometries/SphereBufferGeometry" ],
 			[ "SphereGeometry", "api/extras/geometries/SphereGeometry" ],
 			[ "TetrahedronGeometry", "api/extras/geometries/TetrahedronGeometry" ],
 			[ "TextGeometry", "api/extras/geometries/TextGeometry" ],
+			[ "TorusBufferGeometry", "api/extras/geometries/TorusBufferGeometry" ],
 			[ "TorusGeometry", "api/extras/geometries/TorusGeometry" ],
+			[ "TorusKnotBufferGeometry", "api/extras/geometries/TorusKnotBufferGeometry" ],
 			[ "TorusKnotGeometry", "api/extras/geometries/TorusKnotGeometry" ],
 			[ "TubeGeometry", "api/extras/geometries/TubeGeometry" ]
 		],

+ 7 - 12
docs/manual/introduction/Creating-a-scene.html

@@ -8,18 +8,13 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>[name]</h1><br />
 
 		<div>The goal of this section is to give a brief introduction to Three.js. We will start by setting up a scene, with a spinning cube. A working example is provided at the bottom of the page in case you get stuck and need help.</div>
 
-		<h2>What is Three.js?</h2>
-
-		<div>Let's try to describe it briefly:</div>
-
-		<div>Three.js is a library that makes WebGL - 3D in the browser - easy to use. While a simple cube in raw WebGL would turn out hundreds of lines of Javascript and shader code, a Three.js equivalent is only a fraction of that.</div>
-
 		<h2>Before we start</h2>
-		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of <a href="http://threejs.org/build/three.min.js">three.min.js</a> in the js/ directory, and open it in your browser.</div>
+
+		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of <a href="http://threejs.org/build/three.js">three.js</a> in the js/ directory, and open it in your browser.</div>
 
 		<code>
 		&lt;!DOCTYPE html&gt;
@@ -33,7 +28,7 @@
 				&lt;/style&gt;
 			&lt;/head&gt;
 			&lt;body&gt;
-				&lt;script src="js/three.min.js"&gt;&lt;/script&gt;
+				&lt;script src="js/three.js"&gt;&lt;/script&gt;
 				&lt;script&gt;
 					// Our Javascript will go here.
 				&lt;/script&gt;
@@ -65,9 +60,9 @@
 		<div>Next up is the renderer. This is where the magic happens. In addition to the WebGLRenderer we use here, Three.js comes with a few others, often used as fallbacks for users with older browsers or for those who don't have WebGL support for some reason.</div>
 
 		<div>In addition to creating the renderer instance, we also need to set the size at which we want it to render our app. It's a good idea to use the width and height of the area we want to fill with our app - in this case, the width and height of the browser window. For performance intensive apps, you can also give <strong>setSize</strong> smaller values, like <strong>window.innerWidth/2</strong> and <strong>window.innerHeight/2</strong>, which will make the app render at half size.</div>
-		
+
 		<div>If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling <strong>setSize</strong> with false as <strong>updateStyle</strong>. For example, <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong> will render your app at half resolution, given that your &lt;canvas&gt; has 100% width and height.</div>
-		
+
 		<div>Last but not least, we add the <strong>renderer</strong> element to our HTML document. This is a &lt;canvas&gt; element the renderer uses to display the scene to us.</div>
 
 		<div><em>"That's all good, but where's that cube you promised?"</em> Let's add it now.</div>
@@ -132,7 +127,7 @@
 				&lt;/style&gt;
 			&lt;/head&gt;
 			&lt;body&gt;
-				&lt;script src="js/three.min.js"&gt;&lt;/script&gt;
+				&lt;script src="js/three.js"&gt;&lt;/script&gt;
 				&lt;script&gt;
 					var scene = new THREE.Scene();
 					var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

+ 1 - 0
docs/page.css

@@ -11,6 +11,7 @@ body {
 	font-family: 'inconsolata';
 	font-size: 15px;
 	line-height: 18px;
+	tab-size: 4;
 	overflow: auto;
 }
 

+ 10 - 10
docs/scenes/bones-browser.html

@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
 	<head>
 		<meta charset="utf-8">
@@ -57,7 +57,7 @@
 				camera.position.y = 30;
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );				
+				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 
@@ -74,7 +74,7 @@
 
 				lights[ 0 ].position.set( 0, 200, 0 );
 				lights[ 1 ].position.set( 100, 200, 100 );
-				lights[ 2 ].position.set( -100, -200, -100 );
+				lights[ 2 ].position.set( - 100, - 200, - 100 );
 
 				scene.add( lights[ 0 ] );
 				scene.add( lights[ 1 ] );
@@ -128,7 +128,7 @@
 
 				var prevBone = new THREE.Bone();
 				bones.push( prevBone );
-				prevBone.position.y = -sizing.halfHeight;
+				prevBone.position.y = - sizing.halfHeight;
 
 				for ( var i = 0; i < sizing.segmentCount; i ++ ) {
 
@@ -187,13 +187,13 @@
 
 					folder = gui.addFolder( "Bone " + i );
 
-					folder.add( bone.position, 'x', -10 + bone.position.x, 10 + bone.position.x );
-					folder.add( bone.position, 'y', -10 + bone.position.y, 10 + bone.position.y );
-					folder.add( bone.position, 'z', -10 + bone.position.z, 10 + bone.position.z );
+					folder.add( bone.position, 'x', - 10 + bone.position.x, 10 + bone.position.x );
+					folder.add( bone.position, 'y', - 10 + bone.position.y, 10 + bone.position.y );
+					folder.add( bone.position, 'z', - 10 + bone.position.z, 10 + bone.position.z );
 
-					folder.add( bone.rotation, 'x', -Math.PI * 0.5, Math.PI * 0.5 );
-					folder.add( bone.rotation, 'y', -Math.PI * 0.5, Math.PI * 0.5 );
-					folder.add( bone.rotation, 'z', -Math.PI * 0.5, Math.PI * 0.5 );
+					folder.add( bone.rotation, 'x', - Math.PI * 0.5, Math.PI * 0.5 );
+					folder.add( bone.rotation, 'y', - Math.PI * 0.5, Math.PI * 0.5 );
+					folder.add( bone.rotation, 'z', - Math.PI * 0.5, Math.PI * 0.5 );
 
 					folder.add( bone.scale, 'x', 0, 2 );
 					folder.add( bone.scale, 'y', 0, 2 );

+ 21 - 19
docs/scenes/geometry-browser.html

@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
 	<head>
 		<meta charset="utf-8">
@@ -42,11 +42,11 @@
 
 		<script>
 
-			document.getElementById('newWindow').href += window.location.hash;
+			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 );
+			var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 50 );
 			camera.position.z = 30;
 
 			var renderer = new THREE.WebGLRenderer( { antialias: true } );
@@ -61,17 +61,17 @@
 			scene.add( ambientLight );
 
 			var lights = [];
-			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 ] = 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 );
+			lights[ 0 ].position.set( 0, 200, 0 );
+			lights[ 1 ].position.set( 100, 200, 100 );
+			lights[ 2 ].position.set( - 100, - 200, - 100 );
 
-			scene.add( lights[0] );
-			scene.add( lights[1] );
-			scene.add( lights[2] );
+			scene.add( lights[ 0 ] );
+			scene.add( lights[ 1 ] );
+			scene.add( lights[ 2 ] );
 
 			var mesh = new THREE.Object3D()
 
@@ -79,26 +79,26 @@
 
 				new THREE.Geometry(),
 
-				new THREE.LineBasicMaterial({
+				new THREE.LineBasicMaterial( {
 					color: 0xffffff,
 					transparent: true,
 					opacity: 0.5
-				})
+				} )
 
-			));
+			) );
 
 			mesh.add( new THREE.Mesh(
 
 				new THREE.Geometry(),
 
-				new THREE.MeshPhongMaterial({
+				new THREE.MeshPhongMaterial( {
 					color: 0x156289,
 					emissive: 0x072534,
 					side: THREE.DoubleSide,
 					shading: THREE.FlatShading
-				})
+				} )
 
-			));
+			) );
 
 			var options = chooseFromHash( mesh );
 
@@ -112,9 +112,11 @@
 
 				var time = Date.now() * 0.001;
 
-				if( !options.fixed ) {
+				if ( ! options.fixed ) {
+
 					mesh.rotation.x += 0.005;
 					mesh.rotation.y += 0.005;
+
 				}
 
 				renderer.render( scene, camera );

+ 357 - 10
docs/scenes/js/geometry.js

@@ -93,6 +93,40 @@ function updateGroupGeometry( mesh, geometry ) {
 
 var guis = {
 
+	BoxBufferGeometry : function( mesh ) {
+
+		var data = {
+			width : 15,
+			height : 15,
+			depth : 15,
+			widthSegments : 1,
+			heightSegments : 1,
+			depthSegments : 1
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.BoxBufferGeometry(
+					data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.BoxBufferGeometry' );
+
+		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();
+
+	},
+
 	BoxGeometry : function( mesh ) {
 
 		var data = {
@@ -127,6 +161,52 @@ var guis = {
 
 	},
 
+	CylinderBufferGeometry : function( mesh ) {
+
+		var data = {
+			radiusTop : 5,
+			radiusBottom : 5,
+			height : 10,
+			radiusSegments : 8,
+			heightSegments : 1,
+			openEnded : false,
+			thetaStart : 0,
+			thetaLength : twoPi,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.CylinderBufferGeometry(
+					data.radiusTop,
+					data.radiusBottom,
+					data.height,
+					data.radiusSegments,
+					data.heightSegments,
+					data.openEnded,
+					data.thetaStart,
+					data.thetaLength
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.CylinderBufferGeometry' );
+
+		folder.add( data, 'radiusTop', 1, 30 ).onChange( generateGeometry );
+		folder.add( data, 'radiusBottom', 1, 30 ).onChange( generateGeometry );
+		folder.add( data, 'height', 1, 50 ).onChange( generateGeometry );
+		folder.add( data, 'radiusSegments', 3, 64 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'heightSegments', 1, 64 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'openEnded' ).onChange( generateGeometry );
+		folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry );
+		folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry );
+
+
+		generateGeometry();
+
+	},
+
 	CylinderGeometry : function( mesh ) {
 
 		var data = {
@@ -173,6 +253,36 @@ var guis = {
 
 	},
 
+	CircleBufferGeometry : function( mesh ) {
+
+		var data = {
+			radius : 10,
+			segments : 32,
+			thetaStart : 0,
+			thetaLength : twoPi,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.CircleBufferGeometry(
+					data.radius, data.segments, data.thetaStart, data.thetaLength
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.CircleBufferGeometry' );
+
+		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();
+
+	},
+
 	CircleGeometry : function( mesh ) {
 
 		var data = {
@@ -255,6 +365,78 @@ var guis = {
 
 	},
 
+	LatheBufferGeometry : function() {
+
+		var points = [];
+
+		for ( var i = 0; i < 10; i ++ ) {
+
+			points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
+
+		}
+
+		var data = {
+			segments : 12,
+			phiStart : 0,
+			phiLength : twoPi,
+		};
+
+		function generateGeometry() {
+
+			var geometry = new THREE.LatheBufferGeometry(
+				points, data.segments, data.phiStart, data.phiLength
+			);
+
+			updateGroupGeometry( mesh, geometry );
+
+		}
+
+		var folder = gui.addFolder( 'THREE.LatheBufferGeometry' );
+
+		folder.add( data, 'segments', 1, 30 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'phiStart', 0, twoPi ).onChange( generateGeometry );
+		folder.add( data, 'phiLength', 0, twoPi ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	LatheGeometry : function() {
+
+		var points = [];
+
+		for ( var i = 0; i < 10; i ++ ) {
+
+			points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
+
+		}
+
+		var data = {
+			segments : 12,
+			phiStart : 0,
+			phiLength : twoPi,
+		};
+
+		function generateGeometry() {
+
+			var geometry = new THREE.LatheGeometry(
+				points, data.segments, data.phiStart, data.phiLength
+			);
+
+			updateGroupGeometry( mesh, geometry );
+
+		}
+
+		var folder = gui.addFolder( 'THREE.LatheGeometry' );
+
+		folder.add( data, 'segments', 1, 30 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'phiStart', 0, twoPi ).onChange( generateGeometry );
+		folder.add( data, 'phiLength', 0, twoPi ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	OctahedronGeometry : function() {
 
 		var data = {
@@ -281,6 +463,36 @@ var guis = {
 
 	},
 
+	PlaneBufferGeometry : function( mesh ) {
+
+		var data = {
+			width : 10,
+			height : 10,
+			widthSegments : 1,
+			heightSegments : 1
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.PlaneBufferGeometry(
+					data.width, data.height, data.widthSegments, data.heightSegments
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.PlaneBufferGeometry' );
+
+		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();
+
+	},
+
 	PlaneGeometry : function( mesh ) {
 
 		var data = {
@@ -311,6 +523,40 @@ var guis = {
 
 	},
 
+	RingBufferGeometry : function( mesh ) {
+
+		var data = {
+			innerRadius : 5,
+			outerRadius : 10,
+			thetaSegments : 8,
+			phiSegments : 8,
+			thetaStart : 0,
+			thetaLength : twoPi,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.RingBufferGeometry(
+					data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.RingBufferGeometry' );
+
+		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();
+
+	},
+
 	RingGeometry : function( mesh ) {
 
 		var data = {
@@ -345,6 +591,42 @@ var guis = {
 
 	},
 
+	SphereBufferGeometry : function( mesh ) {
+
+		var data = {
+			radius : 15,
+			widthSegments : 8,
+			heightSegments : 6,
+			phiStart : 0,
+			phiLength : twoPi,
+			thetaStart : 0,
+			thetaLength : Math.PI,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.SphereBufferGeometry(
+					data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.SphereBufferGeometry' );
+
+		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 );
+		folder.add( data, 'phiStart', 0, twoPi ).onChange( generateGeometry );
+		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();
+
+	},
+
 	SphereGeometry : function( mesh ) {
 
 		var data = {
@@ -473,6 +755,38 @@ var guis = {
 
 	},
 
+	TorusBufferGeometry : function( mesh ) {
+
+		var data = {
+			radius : 10,
+			tube : 3,
+			radialSegments : 16,
+			tubularSegments : 100,
+			arc : twoPi
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.TorusBufferGeometry(
+					data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.TorusBufferGeometry' );
+
+		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();
+
+	},
+
 	TorusGeometry : function( mesh ) {
 
 		var data = {
@@ -505,38 +819,71 @@ var guis = {
 
 	},
 
+	TorusKnotBufferGeometry : function( mesh ) {
+
+		var data = {
+			radius : 10,
+			tube : 3,
+			tubularSegments : 64,
+			radialSegments : 8,
+			p : 2,
+			q : 3
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.TorusKnotBufferGeometry(
+					data.radius, data.tube, data.tubularSegments, data.radialSegments,
+					data.p, data.q
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.TorusKnotBufferGeometry' );
+
+		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
+		folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry );
+		folder.add( data, 'tubularSegments', 3, 300 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'radialSegments', 3, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'p', 1, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'q', 1, 20 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	TorusKnotGeometry : function( mesh ) {
 
 		var data = {
 			radius : 10,
 			tube : 3,
-			radialSegments : 64,
-			tubularSegments : 8,
+			tubularSegments : 64,
+			radialSegments : 8,
 			p : 2,
-			q : 3,
-			heightScale : 1
+			q : 3
 		};
 
 		function generateGeometry() {
 
 			updateGroupGeometry( mesh,
 				new THREE.TorusKnotGeometry(
-					data.radius, data.tube, data.radialSegments, data.tubularSegments,
-					data.p, data.q, data.heightScale
+					data.radius, data.tube, data.tubularSegments, data.radialSegments,
+					data.p, data.q
 				)
 			);
 
 		}
 
-		var folder = gui.addFolder( 'THREE.TorusGeometry' );
+		var folder = gui.addFolder( 'THREE.TorusKnotGeometry' );
 
 		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 );
-		folder.add( data, 'tubularSegments', 3, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'tubularSegments', 3, 300 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'radialSegments', 3, 20 ).step( 1 ).onChange( generateGeometry );
 		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();
 

+ 43 - 0
docs/scenes/js/material.js

@@ -453,6 +453,39 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 
 }
 
+function guiMeshStandardMaterial ( gui, mesh, material, geometry ) {
+
+	var data = {
+		color : material.color.getHex(),
+		emissive : material.emissive.getHex(),
+		envMaps : envMapKeys,
+		map : textureMapKeys,
+		lightMap : textureMapKeys,
+		specularMap : textureMapKeys,
+		alphaMap : textureMapKeys
+	};
+
+	var folder = gui.addFolder('THREE.MeshStandardMaterial');
+
+	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
+	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
+
+	folder.add( material, 'roughness', 0, 1 );
+	folder.add( material, 'metalness', 0, 1 );
+	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);
+	folder.add( material, 'fog' );
+	folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
+	folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) );
+	folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) );
+	folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) );
+
+	// TODO roughnessMap and metalnessMap
+
+}
+
 function chooseFromHash ( gui, mesh, geometry ) {
 
 	var selectedMaterial = window.location.hash.substring(1) || "MeshBasicMaterial";
@@ -490,6 +523,16 @@ function chooseFromHash ( gui, mesh, geometry ) {
 
 		break;
 
+	case "MeshStandardMaterial" :
+
+		material = new THREE.MeshStandardMaterial({color: 0x2194CE});
+		guiMaterial( gui, mesh, material, geometry );
+		guiMeshStandardMaterial( gui, mesh, material, geometry );
+
+		return material;
+
+		break;
+
 	case "MeshDepthMaterial" :
 
 		material = new THREE.MeshDepthMaterial({color: 0x2194CE});

+ 12 - 12
docs/scenes/material-browser.html

@@ -1,4 +1,4 @@
-<!doctype html>
+<!DOCTYPE html>
 <html lang="en">
 	<head>
 		<meta charset="utf-8">
@@ -40,11 +40,11 @@
 
 		<script>
 
-			document.getElementById('newWindow').href += window.location.hash;
+			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 );
+			var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 50 );
 			camera.position.z = 30;
 
 			var renderer = new THREE.WebGLRenderer( { antialias: true } );
@@ -56,17 +56,17 @@
 			scene.add( ambientLight );
 
 			var lights = [];
-			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 ] = 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 );
+			lights[ 0 ].position.set( 0, 200, 0 );
+			lights[ 1 ].position.set( 100, 200, 100 );
+			lights[ 2 ].position.set( - 100, - 200, - 100 );
 
-			scene.add( lights[0] );
-			scene.add( lights[1] );
-			scene.add( lights[2] );
+			scene.add( lights[ 0 ] );
+			scene.add( lights[ 1 ] );
+			scene.add( lights[ 2 ] );
 
 			guiScene( gui, scene, camera );
 

+ 3 - 4
editor/js/Menubar.Add.js

@@ -198,13 +198,12 @@ Menubar.Add = function ( editor ) {
 
 		var radius = 2;
 		var tube = 0.8;
-		var radialSegments = 64;
-		var tubularSegments = 12;
+		var tubularSegments = 64;
+		var radialSegments = 12;
 		var p = 2;
 		var q = 3;
-		var heightScale = 1;
 
-		var geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale );
+		var geometry = new THREE.TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q );
 		var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 		mesh.name = 'TorusKnot ' + ( ++ meshCount );
 

+ 10 - 2
editor/js/Sidebar.Geometry.LatheGeometry.js

@@ -63,9 +63,17 @@ Sidebar.Geometry.LatheGeometry = function( editor, object ) {
 
 	var addPointButton = new UI.Button( '+' ).onClick( function() {
 
-		var point = pointsUI[ pointsUI.length - 1 ];
+		if( pointsUI.length === 0 ){
 
-		pointsList.add( createPointRow( point.x.getValue(), point.y.getValue() ) );
+			pointsList.add( createPointRow( 0, 0 ) );
+
+		} else {
+
+			var point = pointsUI[ pointsUI.length - 1 ];
+
+			pointsList.add( createPointRow( point.x.getValue(), point.y.getValue() ) );
+
+		}
 
 		update();
 

+ 12 - 23
editor/js/Sidebar.Geometry.TorusKnotGeometry.js

@@ -30,16 +30,6 @@ Sidebar.Geometry.TorusKnotGeometry = function ( editor, object ) {
 
 	container.add( tubeRow );
 
-	// radialSegments
-
-	var radialSegmentsRow = new UI.Row();
-	var radialSegments = new UI.Integer( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update );
-
-	radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ) );
-	radialSegmentsRow.add( radialSegments );
-
-	container.add( radialSegmentsRow );
-
 	// tubularSegments
 
 	var tubularSegmentsRow = new UI.Row();
@@ -50,6 +40,16 @@ Sidebar.Geometry.TorusKnotGeometry = function ( editor, object ) {
 
 	container.add( tubularSegmentsRow );
 
+	// radialSegments
+
+	var radialSegmentsRow = new UI.Row();
+	var radialSegments = new UI.Integer( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update );
+
+	radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ) );
+	radialSegmentsRow.add( radialSegments );
+
+	container.add( radialSegmentsRow );
+
 	// p
 
 	var pRow = new UI.Row();
@@ -70,16 +70,6 @@ Sidebar.Geometry.TorusKnotGeometry = function ( editor, object ) {
 
 	container.add( qRow );
 
-	// heightScale
-
-	var heightScaleRow = new UI.Row();
-	var heightScale = new UI.Number( parameters.heightScale ).onChange( update );
-
-	pRow.add( new UI.Text( 'Height scale' ).setWidth( '90px' ) );
-	pRow.add( heightScale );
-
-	container.add( heightScaleRow );
-
 
 	//
 
@@ -88,11 +78,10 @@ Sidebar.Geometry.TorusKnotGeometry = function ( editor, object ) {
 		editor.execute( new SetGeometryCommand( object, new THREE.TorusKnotGeometry(
 			radius.getValue(),
 			tube.getValue(),
-			radialSegments.getValue(),
 			tubularSegments.getValue(),
+			radialSegments.getValue(),
 			p.getValue(),
-			q.getValue(),
-			heightScale.getValue()
+			q.getValue()
 		) ) );
 
 	}

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

@@ -177,15 +177,7 @@ var APP = {
 
 			for ( var i = 0, l = array.length; i < l; i ++ ) {
 
-				try {
-
-					array[ i ]( event );
-
-				} catch ( e ) {
-
-					console.error( ( e.message || e ), ( e.stack || "" ) );
-
-				}
+				array[ i ]( event );
 
 			}
 
@@ -197,7 +189,15 @@ var APP = {
 
 			request = requestAnimationFrame( animate );
 
-			dispatch( events.update, { time: time, delta: time - prevTime } );
+			try {
+
+				dispatch( events.update, { time: time, delta: time - prevTime } );
+
+			} catch ( e ) {
+
+				console.error( ( e.message || e ), ( e.stack || "" ) );
+
+			}
 
 			if ( vr === true ) {
 

+ 0 - 4
editor/js/libs/tern-threejs/threejs.js

@@ -5292,10 +5292,6 @@
           "!type": "boolean",
           "!doc": "Whether to generate mipmaps (if possible) for a texture. True by default."
         },
-        "shareDepthFrom": {
-          "!type": "+THREE.WebGLRenderTarget",
-          "!doc": "Shares the depth from another WebGLRenderTarget. Default is null."
-        },
         "setSize": {
           "!type": "fn(width: number, height: number)",
           "!doc": "Sets the size of the renderTarget."

+ 2 - 1
examples/canvas_ascii_effect.html

@@ -116,8 +116,9 @@
 
 				requestAnimationFrame( animate );
 
+				stats.begin();
 				render();
-				stats.update();
+				stats.end();
 
 			}
 

+ 2 - 1
examples/canvas_camera_orthographic.html

@@ -145,8 +145,9 @@
 
 				requestAnimationFrame( animate );
 
+				stats.begin();
 				render();
-				stats.update();
+				stats.end();
 
 			}
 

+ 2 - 1
examples/canvas_camera_orthographic2.html

@@ -208,8 +208,9 @@
 
 				requestAnimationFrame( animate );
 
+				stats.begin();
 				render();
-				stats.update();
+				stats.end();
 
 			}
 

+ 2 - 1
examples/canvas_geometry_birds.html

@@ -420,8 +420,9 @@
 
 				requestAnimationFrame( animate );
 
+				stats.begin();
 				render();
-				stats.update();
+				stats.end();
 
 			}
 

+ 2 - 1
examples/canvas_geometry_cube.html

@@ -193,8 +193,9 @@
 
 				requestAnimationFrame( animate );
 
+				stats.begin();
 				render();
-				stats.update();
+				stats.end();
 
 			}
 

+ 11 - 3
examples/files.js

@@ -57,6 +57,7 @@ var files = {
 		"webgl_kinect",
 		"webgl_lensflares",
 		"webgl_lights_hemisphere",
+		"webgl_lights_physical",
 		"webgl_lights_pointlights",
 		"webgl_lights_pointlights2",
 		"webgl_lines_colors",
@@ -88,6 +89,7 @@ var files = {
 		"webgl_loader_msgpack",
 		"webgl_loader_obj",
 		"webgl_loader_obj_mtl",
+		"webgl_loader_nrrd",
 		"webgl_loader_pcd",
 		"webgl_loader_pdb",
 		"webgl_loader_ply",
@@ -119,6 +121,7 @@ var files = {
 		"webgl_materials_cubemap_refraction",
 		"webgl_materials_displacementmap",
 		"webgl_materials_envmaps",
+		"webgl_materials_envmaps_hdr",
 		"webgl_materials_grass",
 		"webgl_materials_lightmap",
 		"webgl_materials_nodes",
@@ -134,11 +137,11 @@ var files = {
 		"webgl_materials_texture_manualmipmap",
 		"webgl_materials_texture_pvrtc",
 		"webgl_materials_texture_tga",
+		"webgl_materials_transparency",
 		"webgl_materials_variations_basic",
 		"webgl_materials_variations_lambert",
 		"webgl_materials_variations_phong",
 		"webgl_materials_variations_standard",
-		"webgl_materials_variations_standard2",
 		"webgl_materials_video",
 		"webgl_materials_wireframe",
 		"webgl_mirror",
@@ -159,6 +162,7 @@ var files = {
 		"webgl_objects_update",
 		"webgl_octree",
 		"webgl_octree_raycasting",
+		"webgl_panorama_dualfisheye",
 		"webgl_panorama_equirectangular",
 		"webgl_particles_general",
 		"webgl_performance",
@@ -177,9 +181,11 @@ var files = {
 		"webgl_postprocessing_glitch",
 		"webgl_postprocessing_godrays",
 		"webgl_postprocessing_masking",
+		"webgl_postprocessing_msaa",
 		"webgl_postprocessing_nodes",
 		"webgl_postprocessing_smaa",
 		"webgl_postprocessing_ssao",
+		"webgl_postprocessing_taa",
 		"webgl_raycast_texture",
 		"webgl_read_float_buffer",
 		"webgl_rtt",
@@ -203,6 +209,7 @@ var files = {
 		"webgl_terrain_dynamic",
 		"webgl_test_memory",
 		"webgl_test_memory2",
+		"webgl_tonemapping",
 		"webgl_trails",
 		"webgl_video_panorama_equirectangular"
 	],
@@ -230,8 +237,9 @@ var files = {
 	],
 	"webvr": [
 		"webvr_cubes",
-		"webvr_video",
-		"webvr_stereo_pano"
+		"webvr_panorama",
+		"webvr_rollercoaster",
+		"webvr_video"
 	],
 	"css3d": [
 		"css3d_molecules",

+ 1 - 4
examples/index.html

@@ -276,10 +276,7 @@
 		button.textContent = 'View source';
 		button.addEventListener( 'click', function ( event ) {
 
-			var array = location.href.split( '/' );
-			array.pop();
-
-			window.open( 'view-source:' + array.join( '/' ) + '/' + selected + '.html' );
+			window.open( 'https://github.com/mrdoob/three.js/blob/master/examples/' + selected + '.html' );
 
 		}, false );
 		button.style.display = 'none';

+ 26 - 0
examples/js/Encodings.js

@@ -0,0 +1,26 @@
+/**
+ * @author Ben Houston / http://clara.io / bhouston
+ * @author Prashant Sharma / spidersharma03
+ */
+
+THREE.Encodings = function() {
+  if( THREE.toHalf === undefined ) throw new Error("THREE.Encodings is required for HDRCubeMapLoader when loading half data.");
+}
+
+THREE.Encodings.RGBEByteToRGBFloat = function( sourceArray, sourceOffset, destArray, destOffset ) {
+  var e = sourceArray[sourceOffset+3];
+  var scale = Math.pow(2.0, e - 128.0) / 255.0;
+
+  destArray[destOffset+0] = sourceArray[sourceOffset+0] * scale;
+  destArray[destOffset+1] = sourceArray[sourceOffset+1] * scale;
+  destArray[destOffset+2] = sourceArray[sourceOffset+2] * scale;
+}
+
+THREE.Encodings.RGBEByteToRGBHalf = function( sourceArray, sourceOffset, destArray, destOffset ) {
+  var e = sourceArray[sourceOffset+3];
+  var scale = Math.pow(2.0, e - 128.0) / 255.0;
+
+  destArray[destOffset+0] = THREE.toHalf( sourceArray[sourceOffset+0] * scale );
+  destArray[destOffset+1] = THREE.toHalf( sourceArray[sourceOffset+1] * scale );
+  destArray[destOffset+2] = THREE.toHalf( sourceArray[sourceOffset+2] * scale );
+}

+ 51 - 0
examples/js/Half.js

@@ -0,0 +1,51 @@
+/**
+ * Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
+ */
+
+THREE.toHalf = (function() {
+  var floatView = new Float32Array(1);
+  var int32View = new Int32Array(floatView.buffer);
+
+  /* This method is faster than the OpenEXR implementation (very often
+   * used, eg. in Ogre), with the additional benefit of rounding, inspired
+   * by James Tursa?s half-precision code. */
+  return function toHalf(val) {
+
+    floatView[0] = val;
+    var x = int32View[0];
+
+    var bits = (x >> 16) & 0x8000; /* Get the sign */
+    var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
+    var e = (x >> 23) & 0xff; /* Using int is faster here */
+
+    /* If zero, or denormal, or exponent underflows too much for a denormal
+     * half, return signed zero. */
+    if (e < 103) {
+      return bits;
+    }
+
+    /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
+    if (e > 142) {
+      bits |= 0x7c00;
+      /* If exponent was 0xff and one mantissa bit was set, it means NaN,
+           * not Inf, so make sure we set one mantissa bit too. */
+      bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
+      return bits;
+    }
+
+    /* If exponent underflows but not too much, return a denormal */
+    if (e < 113) {
+      m |= 0x0800;
+      /* Extra rounding may overflow and set mantissa to 0 and exponent
+       * to 1, which is OK. */
+      bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
+      return bits;
+    }
+
+    bits |= ((e - 112) << 10) | (m >> 1);
+    /* Extra rounding. An overflow will set mantissa to 0 and increment
+     * the exponent, which is OK. */
+    bits += m & 1;
+    return bits;
+  };
+}());

+ 0 - 4
examples/js/Ocean.js

@@ -12,10 +12,6 @@
 
 	this.scene = new THREE.Scene();
 
-	// Enable necessary extensions
-	this.renderer.context.getExtension( 'OES_texture_float' );
-	this.renderer.context.getExtension( 'OES_texture_float_linear' );
-
 	// Assign optional parameters as variables and object properties
 	function optionalParameter( value, defaultValue ) {
 

+ 6 - 8
examples/js/ParametricGeometries.js

@@ -170,18 +170,16 @@ THREE.ParametricGeometries.TubeGeometry.prototype.constructor = THREE.Parametric
   * Parametric Replacement for TorusKnotGeometry
   *
   *********************************************/
-THREE.ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segmentsR, segmentsT, p, q, heightScale ) {
+THREE.ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segmentsT, segmentsR, p, q ) {
 
 	var scope = this;
 
 	this.radius = radius || 200;
 	this.tube = tube || 40;
-	this.segmentsR = segmentsR || 64;
-	this.segmentsT = segmentsT || 8;
+	this.segmentsT = segmentsT || 64;
+	this.segmentsR = segmentsR || 8;
 	this.p = p || 2;
 	this.q = q || 3;
-	this.heightScale = heightScale || 1;
-
 
 	var TorusKnotCurve = THREE.Curve.create(
 
@@ -198,13 +196,13 @@ THREE.ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segments
 				ty = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t ),
 				tz = r * Math.sin( q * t );
 
-			return new THREE.Vector3( tx, ty * heightScale, tz ).multiplyScalar( radius );
+			return new THREE.Vector3( tx, ty, tz ).multiplyScalar( radius );
 
 		}
 
 	);
-	var segments = segmentsR;
-	var radiusSegments = segmentsT;
+	var segments = segmentsT;
+	var radiusSegments = segmentsR;
 	var extrudePath = new TorusKnotCurve();
 
 	THREE.ParametricGeometries.TubeGeometry.call( this, extrudePath, segments, tube, radiusSegments, true, false );

+ 544 - 0
examples/js/RollerCoaster.js

@@ -0,0 +1,544 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+var RollerCoasterGeometry = function ( curve, size ) {
+
+	THREE.BufferGeometry.call( this );
+
+	var vertices = [];
+	var normals = [];
+	var colors = [];
+
+	var color1 = [ 1, 1, 1 ];
+	var color2 = [ 1, 1, 0 ];
+
+	var up = new THREE.Vector3( 0, 1, 0 );
+	var forward = new THREE.Vector3();
+	var right = new THREE.Vector3();
+
+	var quaternion = new THREE.Quaternion();
+	var prevQuaternion = new THREE.Quaternion();
+	prevQuaternion.setFromAxisAngle( up , Math.PI / 2 );
+
+	var point = new THREE.Vector3();
+	var prevPoint = new THREE.Vector3();
+	prevPoint.copy( curve.getPointAt( 0 ) );
+
+	// shapes
+
+	var step = [
+		new THREE.Vector3( -2.25,  0, 0 ),
+		new THREE.Vector3(  0,  -0.5, 0 ),
+		new THREE.Vector3(  0, -1.75, 0 ),
+
+		new THREE.Vector3(  0,  -0.5, 0 ),
+		new THREE.Vector3(  2.25,  0, 0 ),
+		new THREE.Vector3(  0, -1.75, 0 )
+	];
+
+	var PI2 = Math.PI * 2;
+
+	var sides = 5;
+	var tube1 = [];
+
+	for ( var i = 0; i < sides; i ++ ) {
+
+		var angle = ( i / sides ) * PI2;
+		tube1.push( new THREE.Vector3( Math.sin( angle ) * 0.6, Math.cos( angle ) * 0.6, 0 ) );
+
+	}
+
+	var sides = 6;
+	var tube2 = [];
+
+	for ( var i = 0; i < sides; i ++ ) {
+
+		var angle = ( i / sides ) * PI2;
+		tube2.push( new THREE.Vector3( Math.sin( angle ) * 0.25, Math.cos( angle ) * 0.25, 0 ) );
+
+	}
+
+	var vector = new THREE.Vector3();
+	var normal = new THREE.Vector3();
+
+	var drawShape = function ( shape, color ) {
+
+		normal.set( 0, 0, -1 ).applyQuaternion( quaternion );
+
+		for ( var j = 0; j < shape.length; j ++ ) {
+
+			vector.copy( shape[ j ] );
+			vector.applyQuaternion( quaternion );
+			vector.add( point );
+
+			vertices.push( vector.x, vector.y, vector.z );
+			normals.push( normal.x, normal.y, normal.z );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+		}
+
+		normal.set( 0, 0, 1 ).applyQuaternion( quaternion );
+
+		for ( var j = shape.length - 1; j >= 0; j -- ) {
+
+			vector.copy( shape[ j ] );
+			vector.applyQuaternion( quaternion );
+			vector.add( point );
+
+			vertices.push( vector.x, vector.y, vector.z );
+			normals.push( normal.x, normal.y, normal.z );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+		}
+
+	};
+
+	var vector1 = new THREE.Vector3();
+	var vector2 = new THREE.Vector3();
+	var vector3 = new THREE.Vector3();
+	var vector4 = new THREE.Vector3();
+
+	var normal1 = new THREE.Vector3();
+	var normal2 = new THREE.Vector3();
+	var normal3 = new THREE.Vector3();
+	var normal4 = new THREE.Vector3();
+
+	var extrudeShape = function ( shape, offset, color ) {
+
+		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+
+			var point1 = shape[ j ];
+			var point2 = shape[ ( j + 1 ) % jl ];
+
+			vector1.copy( point1 ).add( offset );
+			vector1.applyQuaternion( quaternion );
+			vector1.add( point );
+
+			vector2.copy( point2 ).add( offset );
+			vector2.applyQuaternion( quaternion );
+			vector2.add( point );
+
+			vector3.copy( point2 ).add( offset );
+			vector3.applyQuaternion( prevQuaternion );
+			vector3.add( prevPoint );
+
+			vector4.copy( point1 ).add( offset );
+			vector4.applyQuaternion( prevQuaternion );
+			vector4.add( prevPoint );
+
+			vertices.push( vector1.x, vector1.y, vector1.z );
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
+
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector3.x, vector3.y, vector3.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
+
+			//
+
+			normal1.copy( point1 );
+			normal1.applyQuaternion( quaternion );
+			normal1.normalize();
+
+			normal2.copy( point2 );
+			normal2.applyQuaternion( quaternion );
+			normal2.normalize();
+
+			normal3.copy( point2 );
+			normal3.applyQuaternion( prevQuaternion );
+			normal3.normalize();
+
+			normal4.copy( point1 );
+			normal4.applyQuaternion( prevQuaternion );
+			normal4.normalize();
+
+			normals.push( normal1.x, normal1.y, normal1.z );
+			normals.push( normal2.x, normal2.y, normal2.z );
+			normals.push( normal4.x, normal4.y, normal4.z );
+
+			normals.push( normal2.x, normal2.y, normal2.z );
+			normals.push( normal3.x, normal3.y, normal3.z );
+			normals.push( normal4.x, normal4.y, normal4.z );
+
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+		}
+
+	};
+
+	var offset = new THREE.Vector3();
+
+	for ( var i = 1; i <= size; i ++ ) {
+
+		point.copy( curve.getPointAt( i / size ) );
+
+		up.set( 0, 1, 0 );
+
+		forward.subVectors( point, prevPoint ).normalize();
+		right.crossVectors( up, forward ).normalize();
+		up.crossVectors( forward, right );
+
+		var angle = Math.atan2( forward.x, forward.z );
+
+		quaternion.setFromAxisAngle( up, angle );
+
+		if ( i % 2 === 0 ) {
+
+			drawShape( step, color2 );
+
+		}
+
+		extrudeShape( tube1, offset.set( 0, -1.25, 0 ), color2 );
+		extrudeShape( tube2, offset.set( 2, 0, 0 ), color1 );
+		extrudeShape( tube2, offset.set( -2, 0, 0 ), color1 );
+
+		prevPoint.copy( point );
+		prevQuaternion.copy( quaternion );
+
+	}
+
+	// console.log( vertices.length );
+
+	this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+	this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
+	this.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+
+};
+
+RollerCoasterGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+var RollerCoasterLiftersGeometry = function ( curve, size ) {
+
+	THREE.BufferGeometry.call( this );
+
+	var vertices = [];
+	var normals = [];
+
+	var quaternion = new THREE.Quaternion();
+
+	var up = new THREE.Vector3( 0, 1, 0 );
+
+	var point = new THREE.Vector3();
+	var tangent = new THREE.Vector3();
+
+	// shapes
+
+	var tube1 = [
+		new THREE.Vector3(  0,  0.5, -0.5 ),
+		new THREE.Vector3(  0,  0.5,  0.5 ),
+		new THREE.Vector3(  0, -0.5,  0 )
+	];
+
+	var tube2 = [
+		new THREE.Vector3( -0.5, 0,  0.5 ),
+		new THREE.Vector3( -0.5, 0, -0.5 ),
+		new THREE.Vector3(  0.5, 0,  0 )
+	];
+
+	var tube3 = [
+		new THREE.Vector3(  0.5, 0, -0.5 ),
+		new THREE.Vector3(  0.5, 0,  0.5 ),
+		new THREE.Vector3( -0.5, 0,  0 )
+	];
+
+	var vector1 = new THREE.Vector3();
+	var vector2 = new THREE.Vector3();
+	var vector3 = new THREE.Vector3();
+	var vector4 = new THREE.Vector3();
+
+	var normal1 = new THREE.Vector3();
+	var normal2 = new THREE.Vector3();
+	var normal3 = new THREE.Vector3();
+	var normal4 = new THREE.Vector3();
+
+	var extrudeShape = function ( shape, fromPoint, toPoint ) {
+
+		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+
+			var point1 = shape[ j ];
+			var point2 = shape[ ( j + 1 ) % jl ];
+
+			vector1.copy( point1 )
+			vector1.applyQuaternion( quaternion );
+			vector1.add( fromPoint );
+
+			vector2.copy( point2 )
+			vector2.applyQuaternion( quaternion );
+			vector2.add( fromPoint );
+
+			vector3.copy( point2 )
+			vector3.applyQuaternion( quaternion );
+			vector3.add( toPoint );
+
+			vector4.copy( point1 )
+			vector4.applyQuaternion( quaternion );
+			vector4.add( toPoint );
+
+			vertices.push( vector1.x, vector1.y, vector1.z );
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
+
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector3.x, vector3.y, vector3.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
+
+			//
+
+			normal1.copy( point1 );
+			normal1.applyQuaternion( quaternion );
+			normal1.normalize();
+
+			normal2.copy( point2 );
+			normal2.applyQuaternion( quaternion );
+			normal2.normalize();
+
+			normal3.copy( point2 );
+			normal3.applyQuaternion( quaternion );
+			normal3.normalize();
+
+			normal4.copy( point1 );
+			normal4.applyQuaternion( quaternion );
+			normal4.normalize();
+
+			normals.push( normal1.x, normal1.y, normal1.z );
+			normals.push( normal2.x, normal2.y, normal2.z );
+			normals.push( normal4.x, normal4.y, normal4.z );
+
+			normals.push( normal2.x, normal2.y, normal2.z );
+			normals.push( normal3.x, normal3.y, normal3.z );
+			normals.push( normal4.x, normal4.y, normal4.z );
+
+		}
+
+	};
+
+	var fromPoint = new THREE.Vector3();
+	var toPoint = new THREE.Vector3();
+
+	for ( var i = 1; i <= size; i ++ ) {
+
+		point.copy( curve.getPointAt( i / size ) );
+		tangent.copy( curve.getTangentAt( i / size ) );
+
+		var angle = Math.atan2( tangent.x, tangent.z );
+
+		quaternion.setFromAxisAngle( up, angle );
+
+		//
+
+		if ( point.y > 100 ) {
+
+			fromPoint.set( -7.5, -3.5, 0 );
+			fromPoint.applyQuaternion( quaternion );
+			fromPoint.add( point );
+
+			toPoint.set( 7.5, -3.5, 0 );
+			toPoint.applyQuaternion( quaternion );
+			toPoint.add( point );
+
+			extrudeShape( tube1, fromPoint, toPoint );
+
+			fromPoint.set( -7, -3, 0 );
+			fromPoint.applyQuaternion( quaternion );
+			fromPoint.add( point );
+
+			toPoint.set( -7, -point.y, 0 );
+			toPoint.applyQuaternion( quaternion );
+			toPoint.add( point );
+
+			extrudeShape( tube2, fromPoint, toPoint );
+
+			fromPoint.set( 7, -3, 0 );
+			fromPoint.applyQuaternion( quaternion );
+			fromPoint.add( point );
+
+			toPoint.set( 7, -point.y, 0 );
+			toPoint.applyQuaternion( quaternion );
+			toPoint.add( point );
+
+			extrudeShape( tube3, fromPoint, toPoint );
+
+		} else {
+
+			fromPoint.set( 0, -2, 0 );
+			fromPoint.applyQuaternion( quaternion );
+			fromPoint.add( point );
+
+			toPoint.set( 0, -point.y, 0 );
+			toPoint.applyQuaternion( quaternion );
+			toPoint.add( point );
+
+			extrudeShape( tube3, fromPoint, toPoint );
+
+		}
+
+	}
+
+	this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+	this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
+
+};
+
+RollerCoasterLiftersGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+var RollerCoasterShadowGeometry = function ( curve, size ) {
+
+	THREE.BufferGeometry.call( this );
+
+	var vertices = [];
+
+	var up = new THREE.Vector3( 0, 1, 0 );
+	var forward = new THREE.Vector3();
+
+	var quaternion = new THREE.Quaternion();
+	var prevQuaternion = new THREE.Quaternion();
+	prevQuaternion.setFromAxisAngle( up , Math.PI / 2 );
+
+	var point = new THREE.Vector3();
+
+	var prevPoint = new THREE.Vector3();
+	prevPoint.copy( curve.getPointAt( 0 ) );
+	prevPoint.y = 0;
+
+	var vector1 = new THREE.Vector3();
+	var vector2 = new THREE.Vector3();
+	var vector3 = new THREE.Vector3();
+	var vector4 = new THREE.Vector3();
+
+	for ( var i = 1; i <= size; i ++ ) {
+
+		point.copy( curve.getPointAt( i / size ) );
+		point.y = 0;
+
+		forward.subVectors( point, prevPoint );
+
+		var angle = Math.atan2( forward.x, forward.z );
+
+		quaternion.setFromAxisAngle( up, angle );
+
+		vector1.set( -3, 0, 0 );
+		vector1.applyQuaternion( quaternion );
+		vector1.add( point );
+
+		vector2.set(  3, 0, 0 );
+		vector2.applyQuaternion( quaternion );
+		vector2.add( point );
+
+		vector3.set(  3, 0, 0 );
+		vector3.applyQuaternion( prevQuaternion );
+		vector3.add( prevPoint );
+
+		vector4.set( -3, 0, 0 );
+		vector4.applyQuaternion( prevQuaternion );
+		vector4.add( prevPoint );
+
+		vertices.push( vector1.x, vector1.y, vector1.z );
+		vertices.push( vector2.x, vector2.y, vector2.z );
+		vertices.push( vector4.x, vector4.y, vector4.z );
+
+		vertices.push( vector2.x, vector2.y, vector2.z );
+		vertices.push( vector3.x, vector3.y, vector3.z );
+		vertices.push( vector4.x, vector4.y, vector4.z );
+
+		prevPoint.copy( point );
+		prevQuaternion.copy( quaternion );
+
+	}
+
+	this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+
+};
+
+RollerCoasterShadowGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+var SkyGeometry = function () {
+
+	THREE.BufferGeometry.call( this );
+
+	var vertices = [];
+
+	for ( var i = 0; i < 100; i ++ ) {
+
+		var x = Math.random() * 8000 - 4000;
+		var y = Math.random() * 500 + 500;
+		var z = Math.random() * 8000 - 4000;
+
+		var size = Math.random() * 400 + 200;
+
+		vertices.push( x - size, y, z - size );
+		vertices.push( x + size, y, z - size );
+		vertices.push( x - size, y, z + size );
+
+		vertices.push( x + size, y, z - size );
+		vertices.push( x + size, y, z + size );
+		vertices.push( x - size, y, z + size );
+
+	}
+
+
+	this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+
+};
+
+SkyGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+var TreesGeometry = function ( landscape ) {
+
+	THREE.BufferGeometry.call( this );
+
+	var vertices = [];
+	var colors = [];
+
+	var raycaster = new THREE.Raycaster();
+	raycaster.ray.direction.set( 0, -1, 0 );
+
+	for ( var i = 0; i < 2000; i ++ ) {
+
+		var x = Math.random() * 5000 - 2500;
+		var z = Math.random() * 5000 - 2500;
+
+		raycaster.ray.origin.set( x, 500, z );
+
+		var intersections = raycaster.intersectObject( landscape );
+
+		if ( intersections.length === 0 ) continue;
+
+		var y = intersections[ 0 ].point.y;
+
+		var height = Math.random() * 50 + 5;
+
+		var angle = Math.random() * Math.PI * 2;
+
+		vertices.push( x + Math.sin( angle ) * 10, y, z + Math.cos( angle ) * 10 );
+		vertices.push( x, y + height, z );
+		vertices.push( x + Math.sin( angle + Math.PI ) * 10, y, z + Math.cos( angle + Math.PI ) * 10 );
+
+		angle += Math.PI / 2;
+
+		vertices.push( x + Math.sin( angle ) * 10, y, z + Math.cos( angle ) * 10 );
+		vertices.push( x, y + height, z );
+		vertices.push( x + Math.sin( angle + Math.PI ) * 10, y, z + Math.cos( angle + Math.PI ) * 10 );
+
+		var random = Math.random() * 0.1;
+
+		for ( var j = 0; j < 6; j ++ ) {
+
+			colors.push( 0.2 + random, 0.4 + random, 0 );
+
+		}
+
+	}
+
+	this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+	this.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+
+};
+
+TreesGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );

+ 4 - 10
examples/js/ShaderSkin.js

@@ -25,7 +25,6 @@ THREE.ShaderSkin = {
 		uniforms: THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ],
 
 			{
@@ -84,7 +83,6 @@ THREE.ShaderSkin = {
 
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
@@ -247,11 +245,9 @@ THREE.ShaderSkin = {
 
 				"outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor * diffuse ) + totalSpecularLight;",
 
-				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
-				THREE.ShaderChunk[ "fog_fragment" ],
-
-				"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+				"gl_FragColor = linearToOutputTexel( vec4( outgoingLight, diffuseColor.a ) );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
 
+				THREE.ShaderChunk[ "fog_fragment" ],
 
 			"}"
 
@@ -311,7 +307,6 @@ THREE.ShaderSkin = {
 		uniforms: THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ],
 
 			{
@@ -370,7 +365,6 @@ THREE.ShaderSkin = {
 			"varying vec3 vViewPosition;",
 
 			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 
@@ -550,10 +544,10 @@ THREE.ShaderSkin = {
 
 				"}",
 
-				THREE.ShaderChunk[ "fog_fragment" ],
-
 				"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
 
+				THREE.ShaderChunk[ "fog_fragment" ],
+
 			"}"
 
 		].join( "\n" ),

+ 0 - 2
examples/js/ShaderTerrain.js

@@ -18,7 +18,6 @@ THREE.ShaderTerrain = {
 		uniforms: THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ],
 
 			{
@@ -88,7 +87,6 @@ THREE.ShaderTerrain = {
 
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],

+ 448 - 0
examples/js/Volume.js

@@ -0,0 +1,448 @@
+/**
+ * This class had been written to handle the output of the NRRD loader.
+ * It contains a volume of data and informations about it.
+ * For now it only handles 3 dimensional data.
+ * See the webgl_loader_nrrd.html example and the loaderNRRD.js file to see how to use this class.
+ * @class
+ * @author Valentin Demeusy / https://github.com/stity
+ * @param   {number}        xLength         Width of the volume
+ * @param   {number}        yLength         Length of the volume
+ * @param   {number}        zLength         Depth of the volume
+ * @param   {string}        type            The type of data (uint8, uint16, ...)
+ * @param   {ArrayBuffer}   arrayBuffer     The buffer with volume data
+ */
+THREE.Volume = function( xLength, yLength, zLength, type, arrayBuffer ) {
+
+	if ( arguments.length > 0 ) {
+
+		/**
+		 * @member {number} xLength Width of the volume in the IJK coordinate system
+		 */
+		this.xLength = Number( xLength ) || 1;
+		/**
+		 * @member {number} yLength Height of the volume in the IJK coordinate system
+		 */
+		this.yLength = Number( yLength ) || 1;
+		/**
+		 * @member {number} zLength Depth of the volume in the IJK coordinate system
+		 */
+		this.zLength = Number( zLength ) || 1;
+
+		/**
+		 * @member {TypedArray} data Data of the volume
+		 */
+
+		switch ( type ) {
+
+			case 'Uint8' :
+			case 'uint8' :
+			case 'uchar' :
+			case 'unsigned char' :
+			case 'uint8_t' :
+				this.data = new Uint8Array( arrayBuffer );
+				break;
+			case 'Int8' :
+			case 'int8' :
+			case 'signed char' :
+			case 'int8_t' :
+				this.data = new Int8Array( arrayBuffer );
+				break;
+			case 'Int16' :
+			case 'int16' :
+			case 'short' :
+			case 'short int' :
+			case 'signed short' :
+			case 'signed short int' :
+			case 'int16_t' :
+				this.data = new Int16Array( arrayBuffer );
+				break;
+			case 'Uint16' :
+			case 'uint16' :
+			case 'ushort' :
+			case 'unsigned short' :
+			case 'unsigned short int' :
+			case 'uint16_t' :
+				this.data = new Uint16Array( arrayBuffer );
+				break;
+			case 'Int32' :
+			case 'int32' :
+			case 'int' :
+			case 'signed int' :
+			case 'int32_t' :
+				this.data = new Int32Array( arrayBuffer );
+				break;
+			case 'Uint32' :
+			case 'uint32' :
+			case 'uint' :
+			case 'unsigned int' :
+			case 'uint32' :
+			case 'uint32_t' :
+				this.data = new Uint32Array( arrayBuffer );
+				break;
+			case 'longlong' :
+			case 'long long' :
+			case 'long long int' :
+			case 'signed long long' :
+			case 'signed long long int' :
+			case 'int64' :
+			case 'int64_t' :
+			case 'ulonglong' :
+			case 'unsigned long long' :
+			case 'unsigned long long int' :
+			case 'uint64' :
+			case 'uint64_t' :
+				throw 'Error in THREE.Volume constructor : this type is not supported in JavaScript';
+				break;
+			case 'Float32' :
+			case 'float32' :
+			case 'float' :
+				this.data = new Float32Array( arrayBuffer );
+				break;
+			case 'Float64' :
+			case 'float64' :
+			case 'double' :
+				this.data = new Float64Array( arrayBuffer );
+				break;
+			default :
+				this.data = new Uint8Array( arrayBuffer );
+
+		}
+
+		if ( this.data.length !== this.xLength * this.yLength * this.zLength ) {
+
+			throw 'Error in THREE.Volume constructor, lengths are not matching arrayBuffer size';
+
+		}
+
+	}
+
+	/**
+	 * @member {Array}  spacing Spacing to apply to the volume from IJK to RAS coordinate system
+	 */
+	this.spacing = [ 1, 1, 1 ];
+	/**
+	 * @member {Array}  offset Offset of the volume in the RAS coordinate system
+	 */
+	this.offset = [ 0, 0, 0 ];
+	/**
+	 * @member {THREE.Martrix3} matrix The IJK to RAS matrix
+	 */
+	this.matrix = new THREE.Matrix3();
+	this.matrix.identity();
+	/**
+	 * @member {THREE.Martrix3} inverseMatrix The RAS to IJK matrix
+	 */
+	/**
+	 * @member {number} lowerThreshold The voxels with values under this threshold won't appear in the slices.
+	 *                      If changed, geometryNeedsUpdate is automatically set to true on all the slices associated to this volume
+	 */
+	var lowerThreshold = - Infinity;
+	Object.defineProperty( this, 'lowerThreshold', {
+		get : function() {
+
+			return lowerThreshold;
+
+		},
+		set : function( value ) {
+
+			lowerThreshold = value;
+			this.sliceList.forEach( function( slice ) {
+
+				slice.geometryNeedsUpdate = true
+
+			} );
+
+		}
+	} );
+	/**
+	 * @member {number} upperThreshold The voxels with values over this threshold won't appear in the slices.
+	 *                      If changed, geometryNeedsUpdate is automatically set to true on all the slices associated to this volume
+	 */
+	var upperThreshold = Infinity;
+	Object.defineProperty( this, 'upperThreshold', {
+		get : function() {
+
+			return upperThreshold;
+
+		},
+		set : function( value ) {
+
+			upperThreshold = value;
+			this.sliceList.forEach( function( slice ) {
+
+				slice.geometryNeedsUpdate = true;
+
+			} );
+
+		}
+	} );
+
+
+	/**
+	 * @member {Array} sliceList The list of all the slices associated to this volume
+	 */
+	this.sliceList = [];
+
+
+	/**
+	 * @member {Array} RASDimensions This array holds the dimensions of the volume in the RAS space
+	 */
+
+}
+
+THREE.Volume.prototype = {
+
+	constructor : THREE.Volume,
+
+	/**
+	 * @member {Function} getData Shortcut for data[access(i,j,k)]
+	 * @memberof THREE.Volume
+	 * @param {number} i    First coordinate
+	 * @param {number} j    Second coordinate
+	 * @param {number} k    Third coordinate
+	 * @returns {number}  value in the data array
+	 */
+	getData : function( i, j, k ) {
+
+		return this.data[ k * this.xLength * this.yLength + j * this.xLength + i ];
+
+	},
+
+	/**
+	 * @member {Function} access compute the index in the data array corresponding to the given coordinates in IJK system
+	 * @memberof THREE.Volume
+	 * @param {number} i    First coordinate
+	 * @param {number} j    Second coordinate
+	 * @param {number} k    Third coordinate
+	 * @returns {number}  index
+	 */
+	access : function( i, j, k ) {
+
+		return k * this.xLength * this.yLength + j * this.xLength + i;
+
+	},
+
+	/**
+	 * @member {Function} reverseAccess Retrieve the IJK coordinates of the voxel corresponding of the given index in the data
+	 * @memberof THREE.Volume
+	 * @param {number} index index of the voxel
+	 * @returns {Array}  [x,y,z]
+	 */
+	reverseAccess : function( index ) {
+
+		var z = Math.floor( index / ( this.yLength * this.xLength ) );
+		var y = Math.floor( ( index - z * this.yLength * this.xLength ) / this.xLength );
+		var x = index - z * this.yLength * this.xLength - y * this.xLength;
+		return [ x, y, z ];
+
+	},
+
+	/**
+	 * @member {Function} map Apply a function to all the voxels, be careful, the value will be replaced
+	 * @memberof THREE.Volume
+	 * @param {Function} functionToMap A function to apply to every voxel, will be called with the following parameters :
+	 *                                 value of the voxel
+	 *                                 index of the voxel
+	 *                                 the data (TypedArray)
+	 * @param {Object}   context    You can specify a context in which call the function, default if this Volume
+	 * @returns {THREE.Volume}   this
+	 */
+	map : function( functionToMap, context ) {
+
+		var length = this.data.length;
+		context = context || this;
+
+		for ( var i = 0; i < length; i ++ ) {
+
+			this.data[ i ] = functionToMap.call( context, this.data[ i ], i, this.data );
+
+		}
+
+		return this;
+
+	},
+
+	/**
+	 * @member {Function} extractPerpendicularPlane Compute the orientation of the slice and returns all the information relative to the geometry such as sliceAccess, the plane matrix (orientation and position in RAS coordinate) and the dimensions of the plane in both coordinate system.
+	 * @memberof THREE.Volume
+	 * @param {string}            axis  the normal axis to the slice 'x' 'y' or 'z'
+	 * @param {number}            index the index of the slice
+	 * @returns {Object} an object containing all the usefull information on the geometry of the slice
+	 */
+	extractPerpendicularPlane : function( axis, RASIndex ) {
+
+		var iLength,
+		jLength,
+		sliceAccess,
+		planeMatrix = ( new THREE.Matrix4() ).identity(),
+		volume = this,
+		planeWidth,
+		planeHeight,
+		firstSpacing,
+		secondSpacing,
+		positionOffset,
+		IJKIndex;
+
+		var axisInIJK = new THREE.Vector3(),
+		firstDirection = new THREE.Vector3(),
+		secondDirection = new THREE.Vector3();
+
+		var dimensions = new THREE.Vector3( this.xLength, this.yLength, this.zLength );
+
+
+		switch ( axis ) {
+
+			case 'x' :
+				axisInIJK.set( 1, 0, 0 );
+				firstDirection.set( 0, 0, - 1 );
+				secondDirection.set( 0, - 1, 0 );
+				firstSpacing = this.spacing[ 2 ];
+				secondSpacing = this.spacing[ 1 ];
+				IJKIndex = new THREE.Vector3( RASIndex, 0, 0 );
+
+				planeMatrix.multiply( ( new THREE.Matrix4() ).makeRotationY( Math.PI / 2 ) );
+				positionOffset = ( volume.RASDimensions[ 0 ] - 1 ) / 2;
+				planeMatrix.setPosition( new THREE.Vector3( RASIndex - positionOffset, 0, 0 ) );
+				break;
+			case 'y' :
+				axisInIJK.set( 0, 1, 0 );
+				firstDirection.set( 1, 0, 0 );
+				secondDirection.set( 0, 0, 1 );
+				firstSpacing = this.spacing[ 0 ];
+				secondSpacing = this.spacing[ 2 ];
+				IJKIndex = new THREE.Vector3( 0, RASIndex, 0 );
+
+				planeMatrix.multiply( ( new THREE.Matrix4() ).makeRotationX( - Math.PI / 2 ) );
+				positionOffset = ( volume.RASDimensions[ 1 ] - 1 ) / 2;
+				planeMatrix.setPosition( new THREE.Vector3( 0, RASIndex - positionOffset, 0 ) );
+				break;
+			case 'z' :
+			default :
+				axisInIJK.set( 0, 0, 1 );
+				firstDirection.set( 1, 0, 0 );
+				secondDirection.set( 0, - 1, 0 );
+				firstSpacing = this.spacing[ 0 ];
+				secondSpacing = this.spacing[ 1 ];
+				IJKIndex = new THREE.Vector3( 0, 0, RASIndex );
+
+				positionOffset = ( volume.RASDimensions[ 2 ] - 1 ) / 2;
+				planeMatrix.setPosition( new THREE.Vector3( 0, 0, RASIndex - positionOffset ) );
+				break;
+		}
+
+		firstDirection.applyMatrix4( volume.inverseMatrix ).normalize();
+		firstDirection.argVar = 'i';
+		secondDirection.applyMatrix4( volume.inverseMatrix ).normalize();
+		secondDirection.argVar = 'j';
+		axisInIJK.applyMatrix4( volume.inverseMatrix ).normalize();
+		iLength = Math.floor( Math.abs( firstDirection.dot( dimensions ) ) );
+		jLength = Math.floor( Math.abs( secondDirection.dot( dimensions ) ) );
+		planeWidth = Math.abs( iLength * firstSpacing );
+		planeHeight = Math.abs( jLength * secondSpacing );
+
+		IJKIndex = Math.abs( Math.round( IJKIndex.applyMatrix4( volume.inverseMatrix ).dot( axisInIJK ) ) );
+		var base = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ];
+		var iDirection = [ firstDirection, secondDirection, axisInIJK ].find( function( x ) {
+
+			return Math.abs( x.dot( base[ 0 ] ) ) > 0.9;
+
+		} );
+		var jDirection = [ firstDirection, secondDirection, axisInIJK ].find( function( x ) {
+
+			return Math.abs( x.dot( base[ 1 ] ) ) > 0.9;
+
+		} );
+		var kDirection = [ firstDirection, secondDirection, axisInIJK ].find( function( x ) {
+
+			return Math.abs( x.dot( base[ 2 ] ) ) > 0.9;
+
+		} );
+		var argumentsWithInversion = [ 'volume.xLength-1-', 'volume.yLength-1-', 'volume.zLength-1-' ];
+		var arguments = [ 'i', 'j', 'k' ];
+		var argArray = [ iDirection, jDirection, kDirection ].map( function( direction, n ) {
+
+			return ( direction.dot( base[ n ] ) > 0 ? '' : argumentsWithInversion[ n ] ) + ( direction === axisInIJK ? 'IJKIndex' : direction.argVar )
+
+		} );
+		var argString = argArray.join( ',' );
+		sliceAccess = eval( '(function sliceAccess (i,j) {return volume.access( ' + argString + ');})' );
+
+
+		return {
+			iLength : iLength,
+			jLength : jLength,
+			sliceAccess : sliceAccess,
+			matrix : planeMatrix,
+			planeWidth : planeWidth,
+			planeHeight : planeHeight
+		}
+
+	},
+
+	/**
+	 * @member {Function} extractSlice Returns a slice corresponding to the given axis and index
+	 *                        The coordinate are given in the Right Anterior Superior coordinate format
+	 * @memberof THREE.Volume
+	 * @param {string}            axis  the normal axis to the slice 'x' 'y' or 'z'
+	 * @param {number}            index the index of the slice
+	 * @returns {THREE.VolumeSlice} the extracted slice
+	 */
+	extractSlice : function( axis, index ) {
+
+		var slice = new THREE.VolumeSlice( this, index, axis );
+		this.sliceList.push( slice );
+		return slice;
+
+	},
+
+	/**
+	 * @member {Function} repaintAllSlices Call repaint on all the slices extracted from this volume
+	 * @see THREE.VolumeSlice.repaint
+	 * @memberof THREE.Volume
+	 * @returns {THREE.Volume} this
+	 */
+	repaintAllSlices : function() {
+
+		this.sliceList.forEach( function( slice ) {
+
+			slice.repaint();
+
+		} );
+
+		return this;
+
+	},
+
+	/**
+	 * @member {Function} computeMinMax Compute the minimum and the maximum of the data in the volume
+	 * @memberof THREE.Volume
+	 * @returns {Array} [min,max]
+	 */
+	computeMinMax : function() {
+
+		var min = Infinity;
+		var max = - Infinity;
+
+		// buffer the length
+		var datasize = this.data.length;
+
+		var i = 0;
+		for ( i = 0; i < datasize; i ++ ) {
+
+			if ( ! isNaN( this.data[ i ] ) ) {
+
+				var value = this.data[ i ];
+				min = Math.min( min, value );
+				max = Math.max( max, value );
+
+			}
+
+		}
+		this.min = min;
+		this.max = max;
+
+		return [ min, max ];
+
+	}
+
+}

+ 217 - 0
examples/js/VolumeSlice.js

@@ -0,0 +1,217 @@
+/**
+ * This class has been made to hold a slice of a volume data
+ * @class
+ * @author Valentin Demeusy / https://github.com/stity
+ * @param   {THREE.Volume} volume    The associated volume
+ * @param   {number}       [index=0] The index of the slice
+ * @param   {string}       [axis='z']      For now only 'x', 'y' or 'z' but later it will change to a normal vector
+ * @see THREE.Volume
+ */
+THREE.VolumeSlice = function( volume, index, axis ) {
+
+	var slice = this;
+	/**
+	 * @member {THREE.Volume} volume The associated volume
+	 */
+	this.volume = volume;
+	/**
+	 * @member {Number} index The index of the slice, if changed, will automatically call updateGeometry at the next repaint
+	 */
+	index = index || 0;
+	Object.defineProperty( this, 'index', {
+		get : function() {
+
+			return index;
+
+		},
+		set : function( value ) {
+
+			index = value;
+			slice.geometryNeedsUpdate = true;
+			return index;
+
+		}
+	} );
+	/**
+	 * @member {String} axis The normal axis
+	 */
+	this.axis = axis || 'z';
+
+	/**
+	 * @member {HTMLCanvasElement} canvas The final canvas used for the texture
+	 */
+	/**
+	 * @member {CanvasRenderingContext2D} ctx Context of the canvas
+	 */
+	this.canvas = document.createElement( 'canvas' );
+	/**
+	 * @member {HTMLCanvasElement} canvasBuffer The intermediary canvas used to paint the data
+	 */
+	/**
+	 * @member {CanvasRenderingContext2D} ctxBuffer Context of the canvas buffer
+	 */
+	this.canvasBuffer = document.createElement( 'canvas' );
+	this.updateGeometry();
+
+
+	var canvasMap = new THREE.Texture( this.canvas );
+	canvasMap.minFilter = THREE.LinearFilter;
+	canvasMap.wrapS = canvasMap.wrapT = THREE.ClampToEdgeWrapping;
+	var material = new THREE.MeshBasicMaterial( { map: canvasMap, side: THREE.DoubleSide, transparent : true } );
+	/**
+	 * @member {THREE.Mesh} mesh The mesh ready to get used in the scene
+	 */
+	this.mesh = new THREE.Mesh( this.geometry, material );
+	/**
+	 * @member {Boolean} geometryNeedsUpdate If set to true, updateGeometry will be triggered at the next repaint
+	 */
+	this.geometryNeedsUpdate = true;
+	this.repaint();
+
+	/**
+	 * @member {Number} iLength Width of slice in the original coordinate system, corresponds to the width of the buffer canvas
+	 */
+
+	/**
+	 * @member {Number} jLength Height of slice in the original coordinate system, corresponds to the height of the buffer canvas
+	 */
+
+	/**
+	 * @member {Function} sliceAccess Function that allow the slice to access right data
+	 * @see THREE.Volume.extractPerpendicularPlane
+	 * @param {Number} i The first coordinate
+	 * @param {Number} j The second coordinate
+	 * @returns {Number} the index corresponding to the voxel in volume.data of the given position in the slice
+	 */
+
+
+}
+
+THREE.VolumeSlice.prototype = {
+
+	constructor : THREE.VolumeSlice,
+
+	/**
+	 * @member {Function} repaint Refresh the texture and the geometry if geometryNeedsUpdate is set to true
+	 * @memberof THREE.VolumeSlice
+	 */
+	repaint : function() {
+
+		if ( this.geometryNeedsUpdate ) {
+
+			this.updateGeometry();
+
+		}
+
+		var iLength = this.iLength,
+		jLength = this.jLength,
+		sliceAccess = this.sliceAccess,
+		volume = this.volume,
+		axis = this.axis,
+		index = this.index,
+		canvas = this.canvasBuffer,
+		ctx = this.ctxBuffer;
+
+
+		// get the imageData and pixel array from the canvas
+		var imgData = ctx.getImageData( 0, 0, iLength, jLength );
+		var data = imgData.data;
+		var volumeData = volume.data;
+		var upperThreshold = volume.upperThreshold;
+		var lowerThreshold = volume.lowerThreshold;
+		var windowLow = volume.windowLow;
+		var windowHigh = volume.windowHigh;
+
+		// manipulate some pixel elements
+		var pixelCount = 0;
+
+		if ( volume.dataType === 'label' ) {
+
+			//this part is currently useless but will be used when colortables will be handled
+			for ( var j = 0; j < jLength; j ++ ) {
+
+				for ( var i = 0; i < iLength; i ++ ) {
+
+					var label = volumeData[ sliceAccess( i, j ) ];
+					label = label >= this.colorMap.length ? ( label % this.colorMap.length ) + 1 : label;
+					var color = this.colorMap[ label ];
+					data[ 4 * pixelCount ] = ( color >> 24 ) & 0xff;
+					data[ 4 * pixelCount + 1 ] = ( color >> 16 ) & 0xff;
+					data[ 4 * pixelCount + 2 ] = ( color >> 8 ) & 0xff;
+					data[ 4 * pixelCount + 3 ] = color & 0xff;
+					pixelCount ++;
+
+				}
+
+			}
+
+		}
+		else {
+
+			for ( var j = 0; j < jLength; j ++ ) {
+
+				for ( var i = 0; i < iLength; i ++ ) {
+
+					var value = volumeData[ sliceAccess( i, j ) ];
+					var alpha = 0xff;
+					//apply threshold
+					alpha = upperThreshold >= value ? ( lowerThreshold <= value ? alpha : 0 ) : 0;
+					//apply window level
+					value = Math.floor( 255 * ( value - windowLow ) / ( windowHigh - windowLow ) );
+					value = value > 255 ? 255 : ( value < 0 ? 0 : value | 0 );
+
+					data[ 4 * pixelCount ] = value;
+					data[ 4 * pixelCount + 1 ] = value;
+					data[ 4 * pixelCount + 2 ] = value;
+					data[ 4 * pixelCount + 3 ] = alpha;
+					pixelCount ++;
+
+				}
+
+			}
+
+		}
+		ctx.putImageData( imgData, 0, 0 );
+		this.ctx.drawImage( canvas, 0, 0, iLength, jLength, 0, 0, this.canvas.width, this.canvas.height );
+
+
+		this.mesh.material.map.needsUpdate = true;
+
+	},
+
+	/**
+	 * @member {Function} Refresh the geometry according to axis and index
+	 * @see THREE.Volume.extractPerpendicularPlane
+	 * @memberof THREE.VolumeSlice
+	 */
+	updateGeometry : function() {
+
+		var extracted = this.volume.extractPerpendicularPlane( this.axis, this.index );
+		this.sliceAccess = extracted.sliceAccess;
+		this.jLength = extracted.jLength;
+		this.iLength = extracted.iLength;
+		this.matrix = extracted.matrix;
+
+		this.canvas.width = extracted.planeWidth;
+		this.canvas.height = extracted.planeHeight;
+		this.canvasBuffer.width = this.iLength;
+		this.canvasBuffer.height = this.jLength;
+		this.ctx = this.canvas.getContext( '2d' );
+		this.ctxBuffer = this.canvasBuffer.getContext( '2d' );
+
+		this.geometry = new THREE.PlaneGeometry( extracted.planeWidth, extracted.planeHeight );
+
+		if ( this.mesh ) {
+
+			this.mesh.geometry = this.geometry;
+			//reset mesh matrix
+			this.mesh.matrix = ( new THREE.Matrix4() ).identity();
+			this.mesh.applyMatrix( this.matrix );
+
+		}
+
+		this.geometryNeedsUpdate = false;
+
+	}
+
+}

+ 97 - 0
examples/js/WebVR.js

@@ -0,0 +1,97 @@
+/**
+ * @author mrdoob / http://mrdoob.com
+ * Based on @tojiro's vr-samples-utils.js
+ */
+
+var WEBVR = {
+
+	isLatestAvailable: function () {
+
+		return navigator.getVRDisplays !== undefined;
+
+	},
+
+	isAvailable: function () {
+
+		return navigator.getVRDisplays !== undefined || navigator.getVRDevices !== undefined;
+
+	},
+
+	getMessage: function () {
+
+		var message;
+
+		if ( navigator.getVRDisplays ) {
+
+			navigator.getVRDisplays().then( function ( displays ) {
+
+				if ( displays.length === 0 ) message = 'WebVR supported, but no VRDisplays found.';
+
+			} );
+
+		} else if ( navigator.getVRDevices ) {
+
+			message = 'Your browser supports WebVR but not the latest version. See <a href="http://webvr.info">webvr.info</a> for more info.';
+
+		} else {
+
+			message = 'Your browser does not support WebVR. See <a href="http://webvr.info">webvr.info</a> for assistance.';
+
+		}
+
+		if ( message !== undefined ) {
+
+			var container = document.createElement( 'div' );
+			container.style.position = 'absolute';
+			container.style.left = '0';
+			container.style.top = '0';
+			container.style.right = '0';
+			container.style.zIndex = '999';
+			container.align = 'center';
+
+			var error = document.createElement( 'div' );
+			error.style.fontFamily = 'sans-serif';
+			error.style.fontSize = '16px';
+			error.style.fontStyle = 'normal';
+			error.style.lineHeight = '26px';
+			error.style.backgroundColor = '#fff';
+			error.style.color = '#000';
+			error.style.padding = '10px 20px';
+			error.style.margin = '50px';
+			error.style.display = 'inline-block';
+			error.innerHTML = message;
+			container.appendChild( error );
+
+			return container;
+
+		}
+
+	},
+
+	getButton: function ( effect ) {
+
+		var button = document.createElement( 'button' );
+		button.style.position = 'absolute';
+		button.style.left = 'calc(50% - 30px)';
+		button.style.bottom = '20px';
+		button.style.border = '0';
+		button.style.padding = '8px';
+		button.style.cursor = 'pointer';
+		button.style.backgroundColor = '#000';
+		button.style.color = '#fff';
+		button.style.fontFamily = 'sans-serif';
+		button.style.fontSize = '13px';
+		button.style.fontStyle = 'normal';
+		button.style.zIndex = '999';
+		button.textContent = 'ENTER VR';
+		button.onclick = function() {
+
+			effect.setFullScreen( true );
+
+		};
+
+		return button;
+
+	}
+
+};

+ 6 - 12
examples/js/controls/EditorControls.js

@@ -26,6 +26,7 @@ THREE.EditorControls = function ( object, domElement ) {
 	var normalMatrix = new THREE.Matrix3();
 	var pointer = new THREE.Vector2();
 	var pointerOld = new THREE.Vector2();
+	var spherical = new THREE.Spherical();
 
 	// events
 
@@ -86,21 +87,14 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		vector.copy( object.position ).sub( center );
 
-		var theta = Math.atan2( vector.x, vector.z );
-		var phi = Math.atan2( Math.sqrt( vector.x * vector.x + vector.z * vector.z ), vector.y );
+		spherical.setFromVector3( vector );
 
-		theta += delta.x;
-		phi += delta.y;
+		spherical.theta += delta.x;
+		spherical.phi += delta.y;
 
-		var EPS = 0.000001;
+		spherical.makeSafe();
 
-		phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
-
-		var radius = vector.length();
-
-		vector.x = radius * Math.sin( phi ) * Math.sin( theta );
-		vector.y = radius * Math.cos( phi );
-		vector.z = radius * Math.sin( phi ) * Math.cos( theta );
+		vector.setFromSpherical( spherical );
 
 		object.position.copy( center ).add( vector );
 

+ 21 - 39
examples/js/controls/OrbitControls.js

@@ -133,12 +133,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 			offset.applyQuaternion( quat );
 
 			// angle from z-axis around y-axis
-
-			theta = Math.atan2( offset.x, offset.z );
-
-			// angle from y-axis
-
-			phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
+			spherical.setFromVector3( offset );
 
 			if ( scope.autoRotate && state === STATE.NONE ) {
 
@@ -146,29 +141,27 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 			}
 
-			theta += thetaDelta;
-			phi += phiDelta;
+			spherical.theta += sphericalDelta.theta;
+			spherical.phi += sphericalDelta.phi;
 
 			// restrict theta to be between desired limits
-			theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, theta ) );
+			spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
 
 			// restrict phi to be between desired limits
-			phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, phi ) );
+			spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
+
+			spherical.makeSafe();
 
-			// restrict phi to be betwee EPS and PI-EPS
-			phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
 
-			var radius = offset.length() * scale;
+			spherical.radius *= scale;
 
 			// restrict radius to be between desired limits
-			radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, radius ) );
+			spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
 
 			// move target to panned location
 			scope.target.add( panOffset );
 
-			offset.x = radius * Math.sin( phi ) * Math.sin( theta );
-			offset.y = radius * Math.cos( phi );
-			offset.z = radius * Math.sin( phi ) * Math.cos( theta );
+			offset.setFromSpherical( spherical );
 
 			// rotate offset back to "camera-up-vector-is-up" space
 			offset.applyQuaternion( quatInverse );
@@ -179,13 +172,12 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 			if ( scope.enableDamping === true ) {
 
-				thetaDelta *= ( 1 - scope.dampingFactor );
-				phiDelta *= ( 1 - scope.dampingFactor );
+				sphericalDelta.theta *= ( 1 - scope.dampingFactor );
+				sphericalDelta.phi *= ( 1 - scope.dampingFactor );
 
 			} else {
 
-				thetaDelta = 0;
-				phiDelta = 0;
+				sphericalDelta.set( 0, 0, 0 );
 
 			}
 
@@ -254,11 +246,9 @@ THREE.OrbitControls = function ( object, domElement ) {
 	var EPS = 0.000001;
 
 	// current position in spherical coordinates
-	var theta;
-	var phi;
+	var spherical = new THREE.Spherical();
+	var sphericalDelta = new THREE.Spherical();
 
-	var phiDelta = 0;
-	var thetaDelta = 0;
 	var scale = 1;
 	var panOffset = new THREE.Vector3();
 	var zoomChanged = false;
@@ -289,13 +279,13 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function rotateLeft( angle ) {
 
-		thetaDelta -= angle;
+		sphericalDelta.theta -= angle;
 
 	}
 
 	function rotateUp( angle ) {
 
-		phiDelta -= angle;
+		sphericalDelta.phi -= angle;
 
 	}
 
@@ -305,11 +295,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		return function panLeft( distance, objectMatrix ) {
 
-			var te = objectMatrix.elements;
-
-			// get X column of objectMatrix
-			v.set( te[ 0 ], te[ 1 ], te[ 2 ] );
-
+			v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
 			v.multiplyScalar( - distance );
 
 			panOffset.add( v );
@@ -324,11 +310,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		return function panUp( distance, objectMatrix ) {
 
-			var te = objectMatrix.elements;
-
-			// get Y column of objectMatrix
-			v.set( te[ 4 ], te[ 5 ], te[ 6 ] );
-
+			v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix
 			v.multiplyScalar( distance );
 
 			panOffset.add( v );
@@ -363,8 +345,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 			} else if ( scope.object instanceof THREE.OrthographicCamera ) {
 
 				// orthographic
-				panLeft( deltaX * ( scope.object.right - scope.object.left ) / element.clientWidth, scope.object.matrix );
-				panUp( deltaY * ( scope.object.top - scope.object.bottom ) / element.clientHeight, scope.object.matrix );
+				panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
+				panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
 
 			} else {
 

+ 19 - 0
examples/js/controls/TrackballControls.js

@@ -356,6 +356,8 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( _this.enabled === false ) return;
 
+		window.removeEventListener( 'keydown', keydown );
+
 		_prevState = _state;
 
 		if ( _state !== STATE.NONE ) {
@@ -384,12 +386,17 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		_state = _prevState;
 
+		window.addEventListener( 'keydown', keydown, false );
+
 	}
 
 	function mousedown( event ) {
 
 		if ( _this.enabled === false ) return;
 
+		event.preventDefault();
+		event.stopPropagation();
+
 		if ( _state === STATE.NONE ) {
 
 			_state = event.button;
@@ -424,6 +431,9 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( _this.enabled === false ) return;
 
+		event.preventDefault();
+		event.stopPropagation();
+
 		if ( _state === STATE.ROTATE && ! _this.noRotate ) {
 
 			_movePrev.copy( _moveCurr );
@@ -445,6 +455,9 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( _this.enabled === false ) return;
 
+		event.preventDefault();
+		event.stopPropagation();
+
 		_state = STATE.NONE;
 
 		document.removeEventListener( 'mousemove', mousemove );
@@ -457,6 +470,9 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( _this.enabled === false ) return;
 
+		event.preventDefault();
+		event.stopPropagation();
+
 		var delta = 0;
 
 		if ( event.wheelDelta ) {
@@ -513,6 +529,9 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 		if ( _this.enabled === false ) return;
 
+		event.preventDefault();
+		event.stopPropagation();
+
 		switch ( event.touches.length ) {
 
 			case 1:

+ 5 - 3
examples/js/effects/AnaglyphEffect.js

@@ -71,11 +71,13 @@ THREE.AnaglyphEffect = function ( renderer, width, height ) {
 
 	this.setSize = function ( width, height ) {
 
-		_renderTargetL.setSize( width, height );
-		_renderTargetR.setSize( width, height );
-
 		renderer.setSize( width, height );
 
+		var pixelRatio = renderer.getPixelRatio();
+
+		_renderTargetL.setSize( width * pixelRatio, height * pixelRatio );
+		_renderTargetR.setSize( width * pixelRatio, height * pixelRatio );
+
 	};
 
 	this.render = function ( scene, camera ) {

+ 4 - 2
examples/js/effects/CardboardEffect.js

@@ -70,10 +70,12 @@ THREE.CardboardEffect = function ( renderer ) {
 
 	this.setSize = function ( width, height ) {
 
-		_renderTarget.setSize( width, height );
-
 		renderer.setSize( width, height );
 
+		var pixelRatio = renderer.getPixelRatio();
+
+		_renderTarget.setSize( width * pixelRatio, height * pixelRatio );
+
 	};
 
 	this.render = function ( scene, camera ) {

+ 5 - 3
examples/js/effects/ParallaxBarrierEffect.js

@@ -70,11 +70,13 @@ THREE.ParallaxBarrierEffect = function ( renderer ) {
 
 	this.setSize = function ( width, height ) {
 
-		_renderTargetL.setSize( width, height );
-		_renderTargetR.setSize( width, height );
-
 		renderer.setSize( width, height );
 
+		var pixelRatio = renderer.getPixelRatio();
+
+		_renderTargetL.setSize( width * pixelRatio, height * pixelRatio );
+		_renderTargetR.setSize( width * pixelRatio, height * pixelRatio );
+
 	};
 
 	this.render = function ( scene, camera ) {

+ 71 - 4
examples/js/exporters/OBJExporter.js

@@ -123,11 +123,11 @@ THREE.OBJExporter.prototype = {
 					var face = faces[ i ];
 
 					for ( var m = 0; m < 3; m ++ ) {
-					
+
 					    indices[ m ] = ( indexVertex + face[ faceVertexKeys[ m ] ] + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + m + 1 ) : '' ) + '/' + ( indexNormals + j + m + 1 );
-					
+
 					}
-					
+
 					output += 'f ' + indices.join( ' ' ) + "\n";
 
 				}
@@ -145,9 +145,76 @@ THREE.OBJExporter.prototype = {
 
 		};
 
+		var parseLine = function( line ) {
+
+			var geometry = line.geometry;
+			var type = line.type;
+
+			if ( geometry instanceof THREE.BufferGeometry ) {
+
+				geometry = new THREE.Geometry().fromBufferGeometry( geometry );
+
+			}
+
+			if ( geometry instanceof THREE.Geometry ) {
+
+				output += 'o ' + line.name + '\n';
+
+				var vertices = geometry.vertices;
+
+				for ( var i = 0, l = vertices.length; i < l; i++ ) {
+
+					var vertex = vertices[ i ].clone();
+					vertex.applyMatrix4( line.matrixWorld );
+
+					output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
+
+				}
+
+				if ( type === 'Line' ) {
+
+					output += 'l ';
+
+					for ( var j = 1, m = vertices.length; j <= m; j++ ) {
+
+						output += j + ' ';
+
+					}
+
+					output += '\n';
+
+				}
+
+				if ( type === 'LineSegments' ) {
+
+					for ( var j = 1, k = j + 1, m = vertices.length; j < m; j += 2, k = j + 1 ) {
+
+						output += 'l ' + j + ' ' + k + '\n';
+
+					}
+
+				}
+
+			} else {
+
+				console.warn('THREE.OBJExporter.parseLine(): geometry type unsupported', line);
+
+			}
+		};
+
 		object.traverse( function ( child ) {
 
-			if ( child instanceof THREE.Mesh ) parseMesh( child );
+			if ( child instanceof THREE.Mesh ) {
+
+				parseMesh( child );
+
+			}
+
+			if ( child instanceof THREE.Line ) {
+
+				parseLine( child );
+
+			}
 
 		} );
 

+ 25 - 19
examples/js/exporters/STLBinaryExporter.js

@@ -17,11 +17,29 @@ THREE.STLBinaryExporter.prototype = {
 
 		return function parse( scene ) {
 
+			// We collect objects first, as we may need to convert from BufferGeometry to Geometry
+			var objects = [];
 			var triangles = 0;
 			scene.traverse( function ( object ) {
 
 				if ( ! ( object instanceof THREE.Mesh ) ) return;
-				triangles += object.geometry.faces.length;
+
+				var geometry = object.geometry;
+				if ( geometry instanceof THREE.BufferGeometry ) {
+
+					geometry = new THREE.Geometry().fromBufferGeometry( geometry );
+
+				}
+
+				if ( ! ( geometry instanceof THREE.Geometry ) ) return;
+				triangles += geometry.faces.length;
+
+				objects.push( {
+
+					geometry: geometry,
+					matrix: object.matrixWorld
+
+				} );
 
 			} );
 
@@ -31,25 +49,13 @@ THREE.STLBinaryExporter.prototype = {
 			var output = new DataView( arrayBuffer );
 			output.setUint32( offset, triangles, true ); offset += 4;
 
-			scene.traverse( function ( object ) {
-
-				if ( ! ( object instanceof THREE.Mesh ) ) return;
-
-				var geometry = object.geometry;
-				if ( geometry instanceof THREE.BufferGeometry ) {
-                            
-					geometry = new THREE.Geometry().fromBufferGeometry( geometry );
-                            
-				}
-
-				if ( ! ( geometry instanceof THREE.Geometry ) ) return;
-
-				var matrixWorld = object.matrixWorld;
+			// Traversing our collected objects
+			objects.forEach( function ( object ) {
 
-				var vertices = geometry.vertices;
-				var faces = geometry.faces;
+				var vertices = object.geometry.vertices;
+				var faces = object.geometry.faces;
 
-				normalMatrixWorld.getNormalMatrix( matrixWorld );
+				normalMatrixWorld.getNormalMatrix( object.matrix );
 
 				for ( var i = 0, l = faces.length; i < l; i ++ ) {
 
@@ -65,7 +71,7 @@ THREE.STLBinaryExporter.prototype = {
 
 					for ( var j = 0; j < 3; j ++ ) {
 
-						vector.copy( vertices[ indices[ j ] ] ).applyMatrix4( matrixWorld );
+						vector.copy( vertices[ indices[ j ] ] ).applyMatrix4( object.matrix );
 
 						output.setFloat32( offset, vector.x, true ); offset += 4; // vertices
 						output.setFloat32( offset, vector.y, true ); offset += 4;

+ 15 - 0
examples/js/libs/inflate.min.js

@@ -0,0 +1,15 @@
+/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var m=this;function q(c,d){var a=c.split("."),b=m;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&void 0!==d?b[e]=d:b=b[e]?b[e]:b[e]={}};var s="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function t(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,l,p,n,r,K;for(n=0;n<d;++n)c[n]>a&&(a=c[n]),c[n]<b&&(b=c[n]);e=1<<a;f=new (s?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(n=0;n<d;++n)if(c[n]===g){l=0;p=h;for(r=0;r<g;++r)l=l<<1|p&1,p>>=1;K=g<<16|n;for(r=l;r<e;r+=k)f[r]=K;++h}++g;h<<=1;k<<=1}return[f,a,b]};function u(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=s?new Uint8Array(c):c;this.m=!1;this.i=v;this.s=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.s=d.resize);switch(this.i){case w:this.b=32768;this.c=new (s?Uint8Array:Array)(32768+this.h+258);break;case v:this.b=0;this.c=new (s?Uint8Array:Array)(this.h);this.e=this.A;this.n=this.w;this.j=this.z;break;default:throw Error("invalid inflate mode");
+}}var w=0,v=1,x={u:w,t:v};
+u.prototype.k=function(){for(;!this.m;){var c=y(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=void 0,h=void 0,k=b.length,l=void 0;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case w:for(;e+
+g>b.length;){l=k-e;g-=l;if(s)b.set(d.subarray(a,a+l),e),e+=l,a+=l;else for(;l--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case v:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(s)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(z,A);break;case 2:B(this);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()};
+var C=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=s?new Uint16Array(C):C,E=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],F=s?new Uint16Array(E):E,G=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],H=s?new Uint8Array(G):G,I=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],J=s?new Uint16Array(I):I,L=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,
+13],M=s?new Uint8Array(L):L,N=new (s?Uint8Array:Array)(288),O,P;O=0;for(P=N.length;O<P;++O)N[O]=143>=O?8:255>=O?9:279>=O?7:8;var z=t(N),Q=new (s?Uint8Array:Array)(30),R,S;R=0;for(S=Q.length;R<S;++R)Q[R]=5;var A=t(Q);function y(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h}
+function T(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],l,p;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;l=h[a&(1<<k)-1];p=l>>>16;c.f=a>>p;c.d=b-p;c.a=f;return l&65535}
+function B(c){function d(a,c,b){var d,e=this.q,f,g;for(g=0;g<a;)switch(d=T(this,c),d){case 16:for(f=3+y(this,2);f--;)b[g++]=e;break;case 17:for(f=3+y(this,3);f--;)b[g++]=0;e=0;break;case 18:for(f=11+y(this,7);f--;)b[g++]=0;e=0;break;default:e=b[g++]=d}this.q=e;return b}var a=y(c,5)+257,b=y(c,5)+1,e=y(c,4)+4,f=new (s?Uint8Array:Array)(D.length),g,h,k,l;for(l=0;l<e;++l)f[D[l]]=y(c,3);if(!s){l=e;for(e=f.length;l<e;++l)f[D[l]]=0}g=t(f);h=new (s?Uint8Array:Array)(a);k=new (s?Uint8Array:Array)(b);c.q=0;
+c.j(t(d.call(c,a,g,h)),t(d.call(c,b,g,k)))}u.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=T(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=T(this,d);h=J[f];0<M[f]&&(h+=y(this,M[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
+u.prototype.z=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=T(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=T(this,d);h=J[f];0<M[f]&&(h+=y(this,M[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
+u.prototype.e=function(){var c=new (s?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(s)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(s)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e};
+u.prototype.A=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.v&&(a+=c.v));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;s?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d};
+u.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (s?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return s?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
+u.prototype.w=function(){var c,d=this.b;s?this.s?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function U(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.B=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case V:this.method=V;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.r=new u(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
+U.prototype.k=function(){var c=this.input,d,a;d=this.r.k();this.a=this.r.a;if(this.B){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,l=b.length,p,n=0;0<l;){p=1024<l?1024:l;l-=p;do h+=b[n++],k+=h;while(--p);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var V=8;q("Zlib.Inflate",U);q("Zlib.Inflate.prototype.decompress",U.prototype.k);var W={ADAPTIVE:x.t,BLOCK:x.u},X,Y,Z,$;if(Object.keys)X=Object.keys(W);else for(Y in X=[],Z=0,W)X[Z++]=Y;Z=0;for($=X.length;Z<$;++Z)Y=X[Z],q("Zlib.Inflate.BufferType."+Y,W[Y]);}).call(this);

+ 51 - 0
examples/js/libs/zlib_and_gzip.min.js

@@ -0,0 +1,51 @@
+/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';function q(b){throw b;}var t=void 0,u=!0,aa=this;function A(b,a){var c=b.split("."),d=aa;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&a!==t?d[e]=a:d=d[e]?d[e]:d[e]={}};var B="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function F(b,a){this.index="number"===typeof a?a:0;this.m=0;this.buffer=b instanceof(B?Uint8Array:Array)?b:new (B?Uint8Array:Array)(32768);2*this.buffer.length<=this.index&&q(Error("invalid index"));this.buffer.length<=this.index&&this.f()}F.prototype.f=function(){var b=this.buffer,a,c=b.length,d=new (B?Uint8Array:Array)(c<<1);if(B)d.set(b);else for(a=0;a<c;++a)d[a]=b[a];return this.buffer=d};
+F.prototype.d=function(b,a,c){var d=this.buffer,e=this.index,f=this.m,g=d[e],k;c&&1<a&&(b=8<a?(H[b&255]<<24|H[b>>>8&255]<<16|H[b>>>16&255]<<8|H[b>>>24&255])>>32-a:H[b]>>8-a);if(8>a+f)g=g<<a|b,f+=a;else for(k=0;k<a;++k)g=g<<1|b>>a-k-1&1,8===++f&&(f=0,d[e++]=H[g],g=0,e===d.length&&(d=this.f()));d[e]=g;this.buffer=d;this.m=f;this.index=e};F.prototype.finish=function(){var b=this.buffer,a=this.index,c;0<this.m&&(b[a]<<=8-this.m,b[a]=H[b[a]],a++);B?c=b.subarray(0,a):(b.length=a,c=b);return c};
+var ba=new (B?Uint8Array:Array)(256),ca;for(ca=0;256>ca;++ca){for(var K=ca,da=K,ea=7,K=K>>>1;K;K>>>=1)da<<=1,da|=K&1,--ea;ba[ca]=(da<<ea&255)>>>0}var H=ba;function ja(b,a,c){var d,e="number"===typeof a?a:a=0,f="number"===typeof c?c:b.length;d=-1;for(e=f&7;e--;++a)d=d>>>8^O[(d^b[a])&255];for(e=f>>3;e--;a+=8)d=d>>>8^O[(d^b[a])&255],d=d>>>8^O[(d^b[a+1])&255],d=d>>>8^O[(d^b[a+2])&255],d=d>>>8^O[(d^b[a+3])&255],d=d>>>8^O[(d^b[a+4])&255],d=d>>>8^O[(d^b[a+5])&255],d=d>>>8^O[(d^b[a+6])&255],d=d>>>8^O[(d^b[a+7])&255];return(d^4294967295)>>>0}
+var ka=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,
+2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,
+2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,
+2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,
+3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,
+936918E3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117],O=B?new Uint32Array(ka):ka;function P(){}P.prototype.getName=function(){return this.name};P.prototype.getData=function(){return this.data};P.prototype.Y=function(){return this.Z};A("Zlib.GunzipMember",P);A("Zlib.GunzipMember.prototype.getName",P.prototype.getName);A("Zlib.GunzipMember.prototype.getData",P.prototype.getData);A("Zlib.GunzipMember.prototype.getMtime",P.prototype.Y);function la(b){this.buffer=new (B?Uint16Array:Array)(2*b);this.length=0}la.prototype.getParent=function(b){return 2*((b-2)/4|0)};la.prototype.push=function(b,a){var c,d,e=this.buffer,f;c=this.length;e[this.length++]=a;for(e[this.length++]=b;0<c;)if(d=this.getParent(c),e[c]>e[d])f=e[c],e[c]=e[d],e[d]=f,f=e[c+1],e[c+1]=e[d+1],e[d+1]=f,c=d;else break;return this.length};
+la.prototype.pop=function(){var b,a,c=this.buffer,d,e,f;a=c[0];b=c[1];this.length-=2;c[0]=c[this.length];c[1]=c[this.length+1];for(f=0;;){e=2*f+2;if(e>=this.length)break;e+2<this.length&&c[e+2]>c[e]&&(e+=2);if(c[e]>c[f])d=c[f],c[f]=c[e],c[e]=d,d=c[f+1],c[f+1]=c[e+1],c[e+1]=d;else break;f=e}return{index:b,value:a,length:this.length}};function ma(b){var a=b.length,c=0,d=Number.POSITIVE_INFINITY,e,f,g,k,h,l,s,p,m,n;for(p=0;p<a;++p)b[p]>c&&(c=b[p]),b[p]<d&&(d=b[p]);e=1<<c;f=new (B?Uint32Array:Array)(e);g=1;k=0;for(h=2;g<=c;){for(p=0;p<a;++p)if(b[p]===g){l=0;s=k;for(m=0;m<g;++m)l=l<<1|s&1,s>>=1;n=g<<16|p;for(m=l;m<e;m+=h)f[m]=n;++k}++g;k<<=1;h<<=1}return[f,c,d]};function na(b,a){this.k=qa;this.I=0;this.input=B&&b instanceof Array?new Uint8Array(b):b;this.b=0;a&&(a.lazy&&(this.I=a.lazy),"number"===typeof a.compressionType&&(this.k=a.compressionType),a.outputBuffer&&(this.a=B&&a.outputBuffer instanceof Array?new Uint8Array(a.outputBuffer):a.outputBuffer),"number"===typeof a.outputIndex&&(this.b=a.outputIndex));this.a||(this.a=new (B?Uint8Array:Array)(32768))}var qa=2,ra={NONE:0,v:1,o:qa,ba:3},sa=[],S;
+for(S=0;288>S;S++)switch(u){case 143>=S:sa.push([S+48,8]);break;case 255>=S:sa.push([S-144+400,9]);break;case 279>=S:sa.push([S-256+0,7]);break;case 287>=S:sa.push([S-280+192,8]);break;default:q("invalid literal: "+S)}
+na.prototype.g=function(){var b,a,c,d,e=this.input;switch(this.k){case 0:c=0;for(d=e.length;c<d;){a=B?e.subarray(c,c+65535):e.slice(c,c+65535);c+=a.length;var f=a,g=c===d,k=t,h=t,l=t,s=t,p=t,m=this.a,n=this.b;if(B){for(m=new Uint8Array(this.a.buffer);m.length<=n+f.length+5;)m=new Uint8Array(m.length<<1);m.set(this.a)}k=g?1:0;m[n++]=k|0;h=f.length;l=~h+65536&65535;m[n++]=h&255;m[n++]=h>>>8&255;m[n++]=l&255;m[n++]=l>>>8&255;if(B)m.set(f,n),n+=f.length,m=m.subarray(0,n);else{s=0;for(p=f.length;s<p;++s)m[n++]=
+f[s];m.length=n}this.b=n;this.a=m}break;case 1:var r=new F(B?new Uint8Array(this.a.buffer):this.a,this.b);r.d(1,1,u);r.d(1,2,u);var v=ta(this,e),x,Q,y;x=0;for(Q=v.length;x<Q;x++)if(y=v[x],F.prototype.d.apply(r,sa[y]),256<y)r.d(v[++x],v[++x],u),r.d(v[++x],5),r.d(v[++x],v[++x],u);else if(256===y)break;this.a=r.finish();this.b=this.a.length;break;case qa:var E=new F(B?new Uint8Array(this.a.buffer):this.a,this.b),Ka,R,X,Y,Z,pb=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],fa,La,ga,Ma,oa,wa=Array(19),
+Na,$,pa,C,Oa;Ka=qa;E.d(1,1,u);E.d(Ka,2,u);R=ta(this,e);fa=ua(this.W,15);La=va(fa);ga=ua(this.V,7);Ma=va(ga);for(X=286;257<X&&0===fa[X-1];X--);for(Y=30;1<Y&&0===ga[Y-1];Y--);var Pa=X,Qa=Y,J=new (B?Uint32Array:Array)(Pa+Qa),w,L,z,ha,I=new (B?Uint32Array:Array)(316),G,D,M=new (B?Uint8Array:Array)(19);for(w=L=0;w<Pa;w++)J[L++]=fa[w];for(w=0;w<Qa;w++)J[L++]=ga[w];if(!B){w=0;for(ha=M.length;w<ha;++w)M[w]=0}w=G=0;for(ha=J.length;w<ha;w+=L){for(L=1;w+L<ha&&J[w+L]===J[w];++L);z=L;if(0===J[w])if(3>z)for(;0<
+z--;)I[G++]=0,M[0]++;else for(;0<z;)D=138>z?z:138,D>z-3&&D<z&&(D=z-3),10>=D?(I[G++]=17,I[G++]=D-3,M[17]++):(I[G++]=18,I[G++]=D-11,M[18]++),z-=D;else if(I[G++]=J[w],M[J[w]]++,z--,3>z)for(;0<z--;)I[G++]=J[w],M[J[w]]++;else for(;0<z;)D=6>z?z:6,D>z-3&&D<z&&(D=z-3),I[G++]=16,I[G++]=D-3,M[16]++,z-=D}b=B?I.subarray(0,G):I.slice(0,G);oa=ua(M,7);for(C=0;19>C;C++)wa[C]=oa[pb[C]];for(Z=19;4<Z&&0===wa[Z-1];Z--);Na=va(oa);E.d(X-257,5,u);E.d(Y-1,5,u);E.d(Z-4,4,u);for(C=0;C<Z;C++)E.d(wa[C],3,u);C=0;for(Oa=b.length;C<
+Oa;C++)if($=b[C],E.d(Na[$],oa[$],u),16<=$){C++;switch($){case 16:pa=2;break;case 17:pa=3;break;case 18:pa=7;break;default:q("invalid code: "+$)}E.d(b[C],pa,u)}var Ra=[La,fa],Sa=[Ma,ga],N,Ta,ia,za,Ua,Va,Wa,Xa;Ua=Ra[0];Va=Ra[1];Wa=Sa[0];Xa=Sa[1];N=0;for(Ta=R.length;N<Ta;++N)if(ia=R[N],E.d(Ua[ia],Va[ia],u),256<ia)E.d(R[++N],R[++N],u),za=R[++N],E.d(Wa[za],Xa[za],u),E.d(R[++N],R[++N],u);else if(256===ia)break;this.a=E.finish();this.b=this.a.length;break;default:q("invalid compression type")}return this.a};
+function xa(b,a){this.length=b;this.Q=a}
+var ya=function(){function b(a){switch(u){case 3===a:return[257,a-3,0];case 4===a:return[258,a-4,0];case 5===a:return[259,a-5,0];case 6===a:return[260,a-6,0];case 7===a:return[261,a-7,0];case 8===a:return[262,a-8,0];case 9===a:return[263,a-9,0];case 10===a:return[264,a-10,0];case 12>=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,
+a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:q("invalid length: "+a)}}var a=[],c,d;for(c=3;258>=c;c++)d=b(c),a[c]=d[2]<<24|d[1]<<
+16|d[0];return a}(),Aa=B?new Uint32Array(ya):ya;
+function ta(b,a){function c(a,c){var b=a.Q,d=[],e=0,f;f=Aa[a.length];d[e++]=f&65535;d[e++]=f>>16&255;d[e++]=f>>24;var g;switch(u){case 1===b:g=[0,b-1,0];break;case 2===b:g=[1,b-2,0];break;case 3===b:g=[2,b-3,0];break;case 4===b:g=[3,b-4,0];break;case 6>=b:g=[4,b-5,1];break;case 8>=b:g=[5,b-7,1];break;case 12>=b:g=[6,b-9,2];break;case 16>=b:g=[7,b-13,2];break;case 24>=b:g=[8,b-17,3];break;case 32>=b:g=[9,b-25,3];break;case 48>=b:g=[10,b-33,4];break;case 64>=b:g=[11,b-49,4];break;case 96>=b:g=[12,b-
+65,5];break;case 128>=b:g=[13,b-97,5];break;case 192>=b:g=[14,b-129,6];break;case 256>=b:g=[15,b-193,6];break;case 384>=b:g=[16,b-257,7];break;case 512>=b:g=[17,b-385,7];break;case 768>=b:g=[18,b-513,8];break;case 1024>=b:g=[19,b-769,8];break;case 1536>=b:g=[20,b-1025,9];break;case 2048>=b:g=[21,b-1537,9];break;case 3072>=b:g=[22,b-2049,10];break;case 4096>=b:g=[23,b-3073,10];break;case 6144>=b:g=[24,b-4097,11];break;case 8192>=b:g=[25,b-6145,11];break;case 12288>=b:g=[26,b-8193,12];break;case 16384>=
+b:g=[27,b-12289,12];break;case 24576>=b:g=[28,b-16385,13];break;case 32768>=b:g=[29,b-24577,13];break;default:q("invalid distance")}f=g;d[e++]=f[0];d[e++]=f[1];d[e++]=f[2];var h,k;h=0;for(k=d.length;h<k;++h)m[n++]=d[h];v[d[0]]++;x[d[3]]++;r=a.length+c-1;p=null}var d,e,f,g,k,h={},l,s,p,m=B?new Uint16Array(2*a.length):[],n=0,r=0,v=new (B?Uint32Array:Array)(286),x=new (B?Uint32Array:Array)(30),Q=b.I,y;if(!B){for(f=0;285>=f;)v[f++]=0;for(f=0;29>=f;)x[f++]=0}v[256]=1;d=0;for(e=a.length;d<e;++d){f=k=0;
+for(g=3;f<g&&d+f!==e;++f)k=k<<8|a[d+f];h[k]===t&&(h[k]=[]);l=h[k];if(!(0<r--)){for(;0<l.length&&32768<d-l[0];)l.shift();if(d+3>=e){p&&c(p,-1);f=0;for(g=e-d;f<g;++f)y=a[d+f],m[n++]=y,++v[y];break}0<l.length?(s=Ba(a,d,l),p?p.length<s.length?(y=a[d-1],m[n++]=y,++v[y],c(s,0)):c(p,-1):s.length<Q?p=s:c(s,0)):p?c(p,-1):(y=a[d],m[n++]=y,++v[y])}l.push(d)}m[n++]=256;v[256]++;b.W=v;b.V=x;return B?m.subarray(0,n):m}
+function Ba(b,a,c){var d,e,f=0,g,k,h,l,s=b.length;k=0;l=c.length;a:for(;k<l;k++){d=c[l-k-1];g=3;if(3<f){for(h=f;3<h;h--)if(b[d+h-1]!==b[a+h-1])continue a;g=f}for(;258>g&&a+g<s&&b[d+g]===b[a+g];)++g;g>f&&(e=d,f=g);if(258===g)break}return new xa(f,a-e)}
+function ua(b,a){var c=b.length,d=new la(572),e=new (B?Uint8Array:Array)(c),f,g,k,h,l;if(!B)for(h=0;h<c;h++)e[h]=0;for(h=0;h<c;++h)0<b[h]&&d.push(h,b[h]);f=Array(d.length/2);g=new (B?Uint32Array:Array)(d.length/2);if(1===f.length)return e[d.pop().index]=1,e;h=0;for(l=d.length/2;h<l;++h)f[h]=d.pop(),g[h]=f[h].value;k=Ca(g,g.length,a);h=0;for(l=f.length;h<l;++h)e[f[h].index]=k[h];return e}
+function Ca(b,a,c){function d(b){var c=h[b][l[b]];c===a?(d(b+1),d(b+1)):--g[c];++l[b]}var e=new (B?Uint16Array:Array)(c),f=new (B?Uint8Array:Array)(c),g=new (B?Uint8Array:Array)(a),k=Array(c),h=Array(c),l=Array(c),s=(1<<c)-a,p=1<<c-1,m,n,r,v,x;e[c-1]=a;for(n=0;n<c;++n)s<p?f[n]=0:(f[n]=1,s-=p),s<<=1,e[c-2-n]=(e[c-1-n]/2|0)+a;e[0]=f[0];k[0]=Array(e[0]);h[0]=Array(e[0]);for(n=1;n<c;++n)e[n]>2*e[n-1]+f[n]&&(e[n]=2*e[n-1]+f[n]),k[n]=Array(e[n]),h[n]=Array(e[n]);for(m=0;m<a;++m)g[m]=c;for(r=0;r<e[c-1];++r)k[c-
+1][r]=b[r],h[c-1][r]=r;for(m=0;m<c;++m)l[m]=0;1===f[c-1]&&(--g[0],++l[c-1]);for(n=c-2;0<=n;--n){v=m=0;x=l[n+1];for(r=0;r<e[n];r++)v=k[n+1][x]+k[n+1][x+1],v>b[m]?(k[n][r]=v,h[n][r]=a,x+=2):(k[n][r]=b[m],h[n][r]=m,++m);l[n]=0;1===f[n]&&d(n)}return g}
+function va(b){var a=new (B?Uint16Array:Array)(b.length),c=[],d=[],e=0,f,g,k,h;f=0;for(g=b.length;f<g;f++)c[b[f]]=(c[b[f]]|0)+1;f=1;for(g=16;f<=g;f++)d[f]=e,e+=c[f]|0,e<<=1;f=0;for(g=b.length;f<g;f++){e=d[b[f]];d[b[f]]+=1;k=a[f]=0;for(h=b[f];k<h;k++)a[f]=a[f]<<1|e&1,e>>>=1}return a};function Da(b,a){this.input=b;this.b=this.c=0;this.i={};a&&(a.flags&&(this.i=a.flags),"string"===typeof a.filename&&(this.filename=a.filename),"string"===typeof a.comment&&(this.A=a.comment),a.deflateOptions&&(this.l=a.deflateOptions));this.l||(this.l={})}
+Da.prototype.g=function(){var b,a,c,d,e,f,g,k,h=new (B?Uint8Array:Array)(32768),l=0,s=this.input,p=this.c,m=this.filename,n=this.A;h[l++]=31;h[l++]=139;h[l++]=8;b=0;this.i.fname&&(b|=Ea);this.i.fcomment&&(b|=Fa);this.i.fhcrc&&(b|=Ga);h[l++]=b;a=(Date.now?Date.now():+new Date)/1E3|0;h[l++]=a&255;h[l++]=a>>>8&255;h[l++]=a>>>16&255;h[l++]=a>>>24&255;h[l++]=0;h[l++]=Ha;if(this.i.fname!==t){g=0;for(k=m.length;g<k;++g)f=m.charCodeAt(g),255<f&&(h[l++]=f>>>8&255),h[l++]=f&255;h[l++]=0}if(this.i.comment){g=
+0;for(k=n.length;g<k;++g)f=n.charCodeAt(g),255<f&&(h[l++]=f>>>8&255),h[l++]=f&255;h[l++]=0}this.i.fhcrc&&(c=ja(h,0,l)&65535,h[l++]=c&255,h[l++]=c>>>8&255);this.l.outputBuffer=h;this.l.outputIndex=l;e=new na(s,this.l);h=e.g();l=e.b;B&&(l+8>h.buffer.byteLength?(this.a=new Uint8Array(l+8),this.a.set(new Uint8Array(h.buffer)),h=this.a):h=new Uint8Array(h.buffer));d=ja(s,t,t);h[l++]=d&255;h[l++]=d>>>8&255;h[l++]=d>>>16&255;h[l++]=d>>>24&255;k=s.length;h[l++]=k&255;h[l++]=k>>>8&255;h[l++]=k>>>16&255;h[l++]=
+k>>>24&255;this.c=p;B&&l<h.length&&(this.a=h=h.subarray(0,l));return h};var Ha=255,Ga=2,Ea=8,Fa=16;A("Zlib.Gzip",Da);A("Zlib.Gzip.prototype.compress",Da.prototype.g);function T(b,a){this.p=[];this.q=32768;this.e=this.j=this.c=this.u=0;this.input=B?new Uint8Array(b):b;this.w=!1;this.r=Ia;this.M=!1;if(a||!(a={}))a.index&&(this.c=a.index),a.bufferSize&&(this.q=a.bufferSize),a.bufferType&&(this.r=a.bufferType),a.resize&&(this.M=a.resize);switch(this.r){case Ja:this.b=32768;this.a=new (B?Uint8Array:Array)(32768+this.q+258);break;case Ia:this.b=0;this.a=new (B?Uint8Array:Array)(this.q);this.f=this.U;this.B=this.R;this.s=this.T;break;default:q(Error("invalid inflate mode"))}}
+var Ja=0,Ia=1,Ya={O:Ja,N:Ia};
+T.prototype.h=function(){for(;!this.w;){var b=U(this,3);b&1&&(this.w=u);b>>>=1;switch(b){case 0:var a=this.input,c=this.c,d=this.a,e=this.b,f=a.length,g=t,k=t,h=d.length,l=t;this.e=this.j=0;c+1>=f&&q(Error("invalid uncompressed block header: LEN"));g=a[c++]|a[c++]<<8;c+1>=f&&q(Error("invalid uncompressed block header: NLEN"));k=a[c++]|a[c++]<<8;g===~k&&q(Error("invalid uncompressed block header: length verify"));c+g>a.length&&q(Error("input buffer is broken"));switch(this.r){case Ja:for(;e+g>d.length;){l=
+h-e;g-=l;if(B)d.set(a.subarray(c,c+l),e),e+=l,c+=l;else for(;l--;)d[e++]=a[c++];this.b=e;d=this.f();e=this.b}break;case Ia:for(;e+g>d.length;)d=this.f({F:2});break;default:q(Error("invalid inflate mode"))}if(B)d.set(a.subarray(c,c+g),e),e+=g,c+=g;else for(;g--;)d[e++]=a[c++];this.c=c;this.b=e;this.a=d;break;case 1:this.s(Za,$a);break;case 2:ab(this);break;default:q(Error("unknown BTYPE: "+b))}}return this.B()};
+var bb=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],cb=B?new Uint16Array(bb):bb,db=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],eb=B?new Uint16Array(db):db,fb=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],gb=B?new Uint8Array(fb):fb,hb=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],ib=B?new Uint16Array(hb):hb,jb=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,
+10,11,11,12,12,13,13],kb=B?new Uint8Array(jb):jb,lb=new (B?Uint8Array:Array)(288),V,mb;V=0;for(mb=lb.length;V<mb;++V)lb[V]=143>=V?8:255>=V?9:279>=V?7:8;var Za=ma(lb),nb=new (B?Uint8Array:Array)(30),ob,qb;ob=0;for(qb=nb.length;ob<qb;++ob)nb[ob]=5;var $a=ma(nb);function U(b,a){for(var c=b.j,d=b.e,e=b.input,f=b.c,g=e.length,k;d<a;)f>=g&&q(Error("input buffer is broken")),c|=e[f++]<<d,d+=8;k=c&(1<<a)-1;b.j=c>>>a;b.e=d-a;b.c=f;return k}
+function rb(b,a){for(var c=b.j,d=b.e,e=b.input,f=b.c,g=e.length,k=a[0],h=a[1],l,s;d<h&&!(f>=g);)c|=e[f++]<<d,d+=8;l=k[c&(1<<h)-1];s=l>>>16;b.j=c>>s;b.e=d-s;b.c=f;return l&65535}
+function ab(b){function a(a,b,c){var d,e=this.J,f,g;for(g=0;g<a;)switch(d=rb(this,b),d){case 16:for(f=3+U(this,2);f--;)c[g++]=e;break;case 17:for(f=3+U(this,3);f--;)c[g++]=0;e=0;break;case 18:for(f=11+U(this,7);f--;)c[g++]=0;e=0;break;default:e=c[g++]=d}this.J=e;return c}var c=U(b,5)+257,d=U(b,5)+1,e=U(b,4)+4,f=new (B?Uint8Array:Array)(cb.length),g,k,h,l;for(l=0;l<e;++l)f[cb[l]]=U(b,3);if(!B){l=e;for(e=f.length;l<e;++l)f[cb[l]]=0}g=ma(f);k=new (B?Uint8Array:Array)(c);h=new (B?Uint8Array:Array)(d);
+b.J=0;b.s(ma(a.call(b,c,g,k)),ma(a.call(b,d,g,h)))}T.prototype.s=function(b,a){var c=this.a,d=this.b;this.C=b;for(var e=c.length-258,f,g,k,h;256!==(f=rb(this,b));)if(256>f)d>=e&&(this.b=d,c=this.f(),d=this.b),c[d++]=f;else{g=f-257;h=eb[g];0<gb[g]&&(h+=U(this,gb[g]));f=rb(this,a);k=ib[f];0<kb[f]&&(k+=U(this,kb[f]));d>=e&&(this.b=d,c=this.f(),d=this.b);for(;h--;)c[d]=c[d++-k]}for(;8<=this.e;)this.e-=8,this.c--;this.b=d};
+T.prototype.T=function(b,a){var c=this.a,d=this.b;this.C=b;for(var e=c.length,f,g,k,h;256!==(f=rb(this,b));)if(256>f)d>=e&&(c=this.f(),e=c.length),c[d++]=f;else{g=f-257;h=eb[g];0<gb[g]&&(h+=U(this,gb[g]));f=rb(this,a);k=ib[f];0<kb[f]&&(k+=U(this,kb[f]));d+h>e&&(c=this.f(),e=c.length);for(;h--;)c[d]=c[d++-k]}for(;8<=this.e;)this.e-=8,this.c--;this.b=d};
+T.prototype.f=function(){var b=new (B?Uint8Array:Array)(this.b-32768),a=this.b-32768,c,d,e=this.a;if(B)b.set(e.subarray(32768,b.length));else{c=0;for(d=b.length;c<d;++c)b[c]=e[c+32768]}this.p.push(b);this.u+=b.length;if(B)e.set(e.subarray(a,a+32768));else for(c=0;32768>c;++c)e[c]=e[a+c];this.b=32768;return e};
+T.prototype.U=function(b){var a,c=this.input.length/this.c+1|0,d,e,f,g=this.input,k=this.a;b&&("number"===typeof b.F&&(c=b.F),"number"===typeof b.P&&(c+=b.P));2>c?(d=(g.length-this.c)/this.C[2],f=258*(d/2)|0,e=f<k.length?k.length+f:k.length<<1):e=k.length*c;B?(a=new Uint8Array(e),a.set(k)):a=k;return this.a=a};
+T.prototype.B=function(){var b=0,a=this.a,c=this.p,d,e=new (B?Uint8Array:Array)(this.u+(this.b-32768)),f,g,k,h;if(0===c.length)return B?this.a.subarray(32768,this.b):this.a.slice(32768,this.b);f=0;for(g=c.length;f<g;++f){d=c[f];k=0;for(h=d.length;k<h;++k)e[b++]=d[k]}f=32768;for(g=this.b;f<g;++f)e[b++]=a[f];this.p=[];return this.buffer=e};
+T.prototype.R=function(){var b,a=this.b;B?this.M?(b=new Uint8Array(a),b.set(this.a.subarray(0,a))):b=this.a.subarray(0,a):(this.a.length>a&&(this.a.length=a),b=this.a);return this.buffer=b};function sb(b){this.input=b;this.c=0;this.t=[];this.D=!1}sb.prototype.X=function(){this.D||this.h();return this.t.slice()};
+sb.prototype.h=function(){for(var b=this.input.length;this.c<b;){var a=new P,c=t,d=t,e=t,f=t,g=t,k=t,h=t,l=t,s=t,p=this.input,m=this.c;a.G=p[m++];a.H=p[m++];(31!==a.G||139!==a.H)&&q(Error("invalid file signature:"+a.G+","+a.H));a.z=p[m++];switch(a.z){case 8:break;default:q(Error("unknown compression method: "+a.z))}a.n=p[m++];l=p[m++]|p[m++]<<8|p[m++]<<16|p[m++]<<24;a.Z=new Date(1E3*l);a.fa=p[m++];a.ea=p[m++];0<(a.n&4)&&(a.aa=p[m++]|p[m++]<<8,m+=a.aa);if(0<(a.n&Ea)){h=[];for(k=0;0<(g=p[m++]);)h[k++]=
+String.fromCharCode(g);a.name=h.join("")}if(0<(a.n&Fa)){h=[];for(k=0;0<(g=p[m++]);)h[k++]=String.fromCharCode(g);a.A=h.join("")}0<(a.n&Ga)&&(a.S=ja(p,0,m)&65535,a.S!==(p[m++]|p[m++]<<8)&&q(Error("invalid header crc16")));c=p[p.length-4]|p[p.length-3]<<8|p[p.length-2]<<16|p[p.length-1]<<24;p.length-m-4-4<512*c&&(f=c);d=new T(p,{index:m,bufferSize:f});a.data=e=d.h();m=d.c;a.ca=s=(p[m++]|p[m++]<<8|p[m++]<<16|p[m++]<<24)>>>0;ja(e,t,t)!==s&&q(Error("invalid CRC-32 checksum: 0x"+ja(e,t,t).toString(16)+
+" / 0x"+s.toString(16)));a.da=c=(p[m++]|p[m++]<<8|p[m++]<<16|p[m++]<<24)>>>0;(e.length&4294967295)!==c&&q(Error("invalid input size: "+(e.length&4294967295)+" / "+c));this.t.push(a);this.c=m}this.D=u;var n=this.t,r,v,x=0,Q=0,y;r=0;for(v=n.length;r<v;++r)Q+=n[r].data.length;if(B){y=new Uint8Array(Q);for(r=0;r<v;++r)y.set(n[r].data,x),x+=n[r].data.length}else{y=[];for(r=0;r<v;++r)y[r]=n[r].data;y=Array.prototype.concat.apply([],y)}return y};A("Zlib.Gunzip",sb);A("Zlib.Gunzip.prototype.decompress",sb.prototype.h);A("Zlib.Gunzip.prototype.getMembers",sb.prototype.X);function tb(b){if("string"===typeof b){var a=b.split(""),c,d;c=0;for(d=a.length;c<d;c++)a[c]=(a[c].charCodeAt(0)&255)>>>0;b=a}for(var e=1,f=0,g=b.length,k,h=0;0<g;){k=1024<g?1024:g;g-=k;do e+=b[h++],f+=e;while(--k);e%=65521;f%=65521}return(f<<16|e)>>>0};function ub(b,a){var c,d;this.input=b;this.c=0;if(a||!(a={}))a.index&&(this.c=a.index),a.verify&&(this.$=a.verify);c=b[this.c++];d=b[this.c++];switch(c&15){case vb:this.method=vb;break;default:q(Error("unsupported compression method"))}0!==((c<<8)+d)%31&&q(Error("invalid fcheck flag:"+((c<<8)+d)%31));d&32&&q(Error("fdict flag is not supported"));this.L=new T(b,{index:this.c,bufferSize:a.bufferSize,bufferType:a.bufferType,resize:a.resize})}
+ub.prototype.h=function(){var b=this.input,a,c;a=this.L.h();this.c=this.L.c;this.$&&(c=(b[this.c++]<<24|b[this.c++]<<16|b[this.c++]<<8|b[this.c++])>>>0,c!==tb(a)&&q(Error("invalid adler-32 checksum")));return a};var vb=8;function wb(b,a){this.input=b;this.a=new (B?Uint8Array:Array)(32768);this.k=W.o;var c={},d;if((a||!(a={}))&&"number"===typeof a.compressionType)this.k=a.compressionType;for(d in a)c[d]=a[d];c.outputBuffer=this.a;this.K=new na(this.input,c)}var W=ra;
+wb.prototype.g=function(){var b,a,c,d,e,f,g,k=0;g=this.a;b=vb;switch(b){case vb:a=Math.LOG2E*Math.log(32768)-8;break;default:q(Error("invalid compression method"))}c=a<<4|b;g[k++]=c;switch(b){case vb:switch(this.k){case W.NONE:e=0;break;case W.v:e=1;break;case W.o:e=2;break;default:q(Error("unsupported compression type"))}break;default:q(Error("invalid compression method"))}d=e<<6|0;g[k++]=d|31-(256*c+d)%31;f=tb(this.input);this.K.b=k;g=this.K.g();k=g.length;B&&(g=new Uint8Array(g.buffer),g.length<=
+k+4&&(this.a=new Uint8Array(g.length+4),this.a.set(g),g=this.a),g=g.subarray(0,k+4));g[k++]=f>>24&255;g[k++]=f>>16&255;g[k++]=f>>8&255;g[k++]=f&255;return g};function xb(b,a){var c,d,e,f;if(Object.keys)c=Object.keys(a);else for(d in c=[],e=0,a)c[e++]=d;e=0;for(f=c.length;e<f;++e)d=c[e],A(b+"."+d,a[d])};A("Zlib.Inflate",ub);A("Zlib.Inflate.prototype.decompress",ub.prototype.h);xb("Zlib.Inflate.BufferType",{ADAPTIVE:Ya.N,BLOCK:Ya.O});A("Zlib.Deflate",wb);A("Zlib.Deflate.compress",function(b,a){return(new wb(b,a)).g()});A("Zlib.Deflate.prototype.compress",wb.prototype.g);xb("Zlib.Deflate.CompressionType",{NONE:W.NONE,FIXED:W.v,DYNAMIC:W.o});}).call(this); //@ sourceMappingURL=zlib_and_gzip.min.js.map

File diff suppressed because it is too large
+ 4 - 0
examples/js/libs/zlib_and_gzip.min.js.map


+ 99 - 6
examples/js/loaders/ColladaLoader2.js

@@ -420,7 +420,87 @@ THREE.ColladaLoader.prototype = {
 						break;
 
 					case 'texture':
-						data[ child.nodeName ] = child.getAttribute( 'texture' );
+						data[ child.nodeName ] = { id: child.getAttribute( 'texture' ), extra: parseEffectParameterTexture( child ) };
+						break;
+
+				}
+
+			}
+
+			return data;
+
+		}
+
+		function parseEffectParameterTexture( 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 'extra':
+						data = parseEffectParameterTextureExtra( child );
+						break;
+
+				}
+
+			}
+
+			return data;
+
+		}
+
+		function parseEffectParameterTextureExtra( 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':
+						data[ child.nodeName ] = parseEffectParameterTextureExtraTechnique( child );
+						break;
+
+				}
+
+			}
+
+			return data;
+
+		}
+
+		function parseEffectParameterTextureExtraTechnique( 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 'repeatU':
+					case 'repeatV':
+					case 'offsetU':
+					case 'offsetV':
+						data[ child.nodeName ] = parseFloat( child.textContent );
+						break;
+
+					case 'wrapU':
+					case 'wrapV':
+						data[ child.nodeName ] = parseInt( child.textContent );
 						break;
 
 				}
@@ -497,24 +577,37 @@ THREE.ColladaLoader.prototype = {
 
 			material.name = data.name;
 
-			function getTexture( sid ) {
+			function getTexture( textureObject ) {
 
-				var sampler = effect.profile.samplers[ sid ];
+				var sampler = effect.profile.samplers[ textureObject.id ];
 
 				if ( sampler !== undefined ) {
 
 					var surface = effect.profile.surfaces[ sampler.source ];
 
 					var texture = new THREE.Texture( getImage( surface.init_from ) );
-					texture.wrapS = THREE.RepeatWrapping;
-					texture.wrapT = THREE.RepeatWrapping;
+
+					var extra = textureObject.extra;
+
+					if ( extra !== undefined && extra.technique !== undefined ) {
+
+						var technique = extra.technique;
+
+						texture.wrapS = technique.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
+						texture.wrapT = technique.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
+
+						texture.offset.set( technique.offsetU, technique.offsetV );
+						texture.repeat.set( technique.repeatU, technique.repeatV );
+
+					}
+
 					texture.needsUpdate = true;
 
 					return texture;
 
 				}
 
-				console.error( 'ColladaLoder: Undefined sampler', sid );
+				console.error( 'ColladaLoder: Undefined sampler', textureObject.id );
 
 				return null;
 

+ 83 - 0
examples/js/loaders/HDRCubeTextureLoader.js

@@ -0,0 +1,83 @@
+/**
+* @author Prashant Sharma / spidersharma03
+* @author Ben Houston / http://clara.io / bhouston
+*/
+
+THREE.HDRCubeTextureLoader = function (manager) {
+  this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+  // override in sub classes
+  this.hdrLoader = new THREE.RGBELoader();
+
+  if( THREE.Encodings === undefined ) throw new Error( "HDRCubeMapLoader requires THREE.Encodings" );
+}
+
+THREE.HDRCubeTextureLoader.prototype.load = function(type, urls, onLoad, onProgress, onError) {
+  var texture = new THREE.CubeTexture();
+
+  texture.type = type;
+  texture.encoding = (type === THREE.UnsignedByteType) ? THREE.RGBEEncoding : THREE.LinearEncoding;
+  texture.format = (type === THREE.UnsignedByteType ) ? THREE.RGBAFormat : THREE.RGBFormat;
+  texture.minFilter = (texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
+  texture.magFilter = (texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
+  texture.generateMipmaps = (texture.encoding !== THREE.RGBEEncoding );
+  texture.anisotropy = 0;
+
+  var scope = this.hdrLoader;
+
+  var loaded = 0;
+
+  function loadHDRData(i, onLoad, onProgress, onError) {
+    var loader = new THREE.XHRLoader( this.manager );
+    loader.setResponseType( 'arraybuffer' );
+
+    loader.load( urls[i], function ( buffer ) {
+      loaded++;
+
+      var texData = scope._parser( buffer );
+
+      if ( ! texData ) return;
+
+      if(type === THREE.FloatType) {
+        var numElements = ( texData.data.length / 4 )*3;
+        var floatdata = new Float32Array( numElements );
+        for( var j=0; j<numElements; j++) {
+          THREE.Encodings.RGBEByteToRGBFloat( texData.data, j*4, floatdata, j*3 );
+        }
+        texData.data = floatdata;
+      }
+      else if(type === THREE.HalfFloatType) {
+        var numElements = ( texData.data.length / 4 )*3;
+        var halfdata = new Uint16Array( numElements );
+        for( var j=0; j<numElements; j++) {
+          THREE.Encodings.RGBEByteToRGBHalf( texData.data, j*4, halfdata, j*3 );
+        }
+        texData.data = halfdata;
+      }
+
+      if ( undefined !== texData.image ) {
+        texture[i].images = texData.image;
+      }
+      else if ( undefined !== texData.data ) {
+        var dataTexture = new THREE.DataTexture(texData.data, texData.width, texData.height);
+        dataTexture.format = texture.format;
+        dataTexture.type = texture.type;
+        dataTexture.encoding = texture.encoding;
+        dataTexture.minFilter = texture.minFilter;
+        dataTexture.magFilter = texture.magFilter;
+        dataTexture.generateMipmaps = texture.generateMipmaps;
+
+        texture.images[i] = dataTexture;
+      }
+
+      if(loaded === 6) {
+        texture.needsUpdate = true;
+        if ( onLoad ) onLoad( texture );
+      }
+    }, onProgress, onError );
+  }
+
+  for(var i=0; i<urls.length; i++) {
+    loadHDRData(i, onLoad, onProgress, onError);
+  }
+  return texture;
+};

+ 0 - 2
examples/js/loaders/MMDLoader.js

@@ -3634,7 +3634,6 @@ THREE.ShaderLib[ 'mmd' ] = {
 		THREE.UniformsLib[ "normalmap" ],
 		THREE.UniformsLib[ "displacementmap" ],
 		THREE.UniformsLib[ "fog" ],
-		THREE.UniformsLib[ "ambient" ],
 		THREE.UniformsLib[ "lights" ],
 
 		{
@@ -3755,7 +3754,6 @@ THREE.ShaderLib[ 'mmd' ] = {
 		THREE.ShaderChunk[ "envmap_pars_fragment" ],
 		THREE.ShaderChunk[ "fog_pars_fragment" ],
 		THREE.ShaderChunk[ "bsdfs" ],
-		THREE.ShaderChunk[ "ambient_pars" ],
 		THREE.ShaderChunk[ "lights_pars" ],
 		THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
 		THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

+ 591 - 0
examples/js/loaders/NRRDLoader.js

@@ -0,0 +1,591 @@
+THREE.NRRDLoader = function( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+
+};
+
+THREE.NRRDLoader.prototype = {
+
+	constructor: THREE.NRRDLoader,
+
+	load: function( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new THREE.XHRLoader( scope.manager );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function( data ) {
+
+			onLoad( scope.parse( data ) );
+
+		}, onProgress, onError );
+
+	},
+
+	//this parser is largely inspired from the XTK NRRD parser : https://github.com/xtk/X
+	parse: function( data ) {
+
+
+		var _data = data;
+
+		var _dataPointer = 0;
+
+		var _nativeLittleEndian = new Int8Array( new Int16Array( [ 1 ] ).buffer )[ 0 ] > 0;
+
+		var _littleEndian = true;
+
+		var _lastMin = - Infinity;
+
+		var _lastMax = Infinity;
+
+		var headerObject = {};
+
+		function scan( type, chunks ) {
+
+			if ( chunks === undefined || chunks === null ) {
+
+				chunks = 1;
+
+			}
+
+			var _chunkSize = 1;
+			var _array_type = Uint8Array;
+
+			switch ( type ) {
+
+			// 1 byte data types
+				case 'uchar':
+					break;
+				case 'schar':
+					_array_type = Int8Array;
+					break;
+					// 2 byte data types
+				case 'ushort':
+					_array_type = Uint16Array;
+					_chunkSize = 2;
+					break;
+				case 'sshort':
+					_array_type = Int16Array;
+					_chunkSize = 2;
+					break;
+					// 4 byte data types
+				case 'uint':
+					_array_type = Uint32Array;
+					_chunkSize = 4;
+					break;
+				case 'sint':
+					_array_type = Int32Array;
+					_chunkSize = 4;
+					break;
+				case 'float':
+					_array_type = Float32Array;
+					_chunkSize = 4;
+					break;
+				case 'complex':
+					_array_type = Float64Array;
+					_chunkSize = 8;
+					break;
+				case 'double':
+					_array_type = Float64Array;
+					_chunkSize = 8;
+					break;
+
+			}
+
+			// increase the data pointer in-place
+			var _bytes = new _array_type( _data.slice( _dataPointer,
+			_dataPointer += chunks * _chunkSize ) );
+
+			// if required, flip the endianness of the bytes
+			if ( _nativeLittleEndian != _littleEndian ) {
+
+				// we need to flip here since the format doesn't match the native endianness
+				_bytes = flipEndianness( _bytes, _chunkSize );
+
+			}
+
+			if ( chunks == 1 ) {
+
+				// if only one chunk was requested, just return one value
+				return _bytes[ 0 ];
+
+			}
+
+			// return the byte array
+			return _bytes;
+
+		}
+
+		//Flips typed array endianness in-place. Based on https://github.com/kig/DataStream.js/blob/master/DataStream.js.
+
+		function flipEndianness( array, chunkSize ) {
+
+			var u8 = new Uint8Array( array.buffer, array.byteOffset, array.byteLength );
+			for ( var i = 0; i < array.byteLength; i += chunkSize ) {
+
+				for ( var j = i + chunkSize - 1, k = i; j > k; j --, k ++ ) {
+
+					var tmp = u8[ k ];
+					u8[ k ] = u8[ j ];
+					u8[ j ] = tmp;
+
+				}
+
+			}
+
+			return array;
+
+		}
+
+		//parse the header
+		function parseHeader( header ) {
+
+			var data, field, fn, i, l, lines, m, _i, _len;
+			lines = header.split( /\r?\n/ );
+			for ( _i = 0, _len = lines.length; _i < _len; _i ++ ) {
+
+				l = lines[ _i ];
+				if ( l.match( /NRRD\d+/ ) ) {
+
+					headerObject.isNrrd = true;
+
+				} else if ( l.match( /^#/ ) ) {
+				} else if ( m = l.match( /(.*):(.*)/ ) ) {
+
+					field = m[ 1 ].trim();
+					data = m[ 2 ].trim();
+					fn = THREE.NRRDLoader.prototype.fieldFunctions[ field ];
+					if ( fn ) {
+
+						fn.call( headerObject, data );
+
+					} else {
+
+						headerObject[ field ] = data;
+
+					}
+
+				}
+
+			}
+			if ( ! headerObject.isNrrd ) {
+
+				throw new Error( 'Not an NRRD file' );
+
+			}
+			if ( headerObject.encoding === 'bz2' || headerObject.encoding === 'bzip2' ) {
+
+				throw new Error( 'Bzip is not supported' );
+
+			}
+			if ( ! headerObject.vectors ) {
+
+				//if no space direction is set, let's use the identity
+				headerObject.vectors = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ];
+				//apply spacing if defined
+				if ( headerObject.spacings ) {
+
+					for ( i = 0; i <= 2; i ++ ) {
+
+						if ( ! isNaN( headerObject.spacings[ i ] ) ) {
+
+							headerObject.vectors[ i ].multiplyScalar( headerObject.spacings[ i ] );
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
+		//parse the data when registred as one of this type : 'text', 'ascii', 'txt'
+		function parseDataAsText( data, start, end ) {
+
+			var number = '';
+			start = start || 0;
+			end = end || data.length;
+			var lastSpace = start;
+			var value;
+			//length of the result is the product of the sizes
+			var lengthOfTheResult = headerObject.sizes.reduce( function( previous, current ) {
+
+				return previous * current;
+
+			}, 1 );
+
+			var base = 10;
+			if ( headerObject.encoding === 'hex' ) {
+
+				base = 16;
+
+			}
+
+			var result = new headerObject.__array( lengthOfTheResult );
+			var resultIndex = 0;
+			var parsingFunction = parseInt;
+			if ( headerObject.__array === Float32Array || headerObject.__array === Float64Array ) {
+
+				parsingFunction = parseFloat;
+
+			}
+			for ( var i = start; i < end; i ++ ) {
+
+				value = data[ i ];
+				//if value is not a space
+				if ( ( value < 9 || value > 13 ) && value !== 32 ) {
+
+					number += String.fromCharCode( value );
+
+				}
+				else {
+
+					if ( number !== '' ) {
+
+						result[ resultIndex ] = parsingFunction( number, base );
+						resultIndex ++;
+
+					}
+					number = '';
+
+				}
+
+			}
+			if ( number !== '' ) {
+
+				result[ resultIndex ] = parsingFunction( number, base );
+				resultIndex ++;
+
+			}
+			return result;
+
+		}
+
+		var _bytes = scan( 'uchar', data.byteLength );
+		var _length = _bytes.length;
+		var _header = null;
+		var _data_start = 0;
+		var i;
+		for ( i = 1; i < _length; i ++ ) {
+
+			if ( _bytes[ i - 1 ] == 10 && _bytes[ i ] == 10 ) {
+
+				// we found two line breaks in a row
+				// now we know what the header is
+				_header = this.parseChars( _bytes, 0, i - 2 );
+				// this is were the data starts
+				_data_start = i + 1;
+				break;
+
+			}
+
+		}
+		// parse the header
+		parseHeader( _header );
+
+		var _data = _bytes.subarray( _data_start ); // the data without header
+		if ( headerObject.encoding === 'gzip' || headerObject.encoding === 'gz' ) {
+
+			// we need to decompress the datastream
+			// here we start the unzipping and get a typed Uint8Array back
+			var inflate = new Zlib.Gunzip( new Uint8Array( _data ) );
+			_data = inflate.decompress();
+
+		}
+		else if ( headerObject.encoding === 'ascii' || headerObject.encoding === 'text' || headerObject.encoding === 'txt' || headerObject.encoding === 'hex' ) {
+
+			_data = parseDataAsText( _data );
+
+		}
+		// .. let's use the underlying array buffer
+		_data = _data.buffer;
+
+		var volume = new THREE.Volume();
+		volume.header = headerObject;
+		//
+		// parse the (unzipped) data to a datastream of the correct type
+		//
+		volume.data = new headerObject.__array( _data );
+		// get the min and max intensities
+		var min_max = volume.computeMinMax();
+		var min = min_max[ 0 ];
+		var max = min_max[ 1 ];
+		// attach the scalar range to the volume
+		volume.windowLow = min;
+		volume.windowHigh = max;
+
+		// get the image dimensions
+		volume.dimensions = [ headerObject.sizes[ 0 ], headerObject.sizes[ 1 ], headerObject.sizes[ 2 ] ];
+		volume.xLength = volume.dimensions[ 0 ];
+		volume.yLength = volume.dimensions[ 1 ];
+		volume.zLength = volume.dimensions[ 2 ];
+		// spacing
+		var spacingX = ( new THREE.Vector3( headerObject.vectors[ 0 ][ 0 ], headerObject.vectors[ 0 ][ 1 ],
+		headerObject.vectors[ 0 ][ 2 ] ) ).length();
+		var spacingY = ( new THREE.Vector3( headerObject.vectors[ 1 ][ 0 ], headerObject.vectors[ 1 ][ 1 ],
+		headerObject.vectors[ 1 ][ 2 ] ) ).length();
+		var spacingZ = ( new THREE.Vector3( headerObject.vectors[ 2 ][ 0 ], headerObject.vectors[ 2 ][ 1 ],
+		headerObject.vectors[ 2 ][ 2 ] ) ).length();
+		volume.spacing = [ spacingX, spacingY, spacingZ ];
+
+
+		// Create IJKtoRAS matrix
+		volume.matrix = new THREE.Matrix4();
+
+		var _spaceX = 1;
+		var _spaceY = 1;
+		var _spaceZ = 1;
+
+		if ( headerObject.space == "left-posterior-superior" ) {
+
+			_spaceX = - 1;
+			_spaceY = - 1;
+
+		}
+		else if ( headerObject.space === 'left-anterior-superior' ) {
+
+			_spaceX = - 1
+
+		}
+
+
+		if ( ! headerObject.vectors ) {
+
+			volume.matrix.set( _spaceX, 0, 0, 0,
+			0, _spaceY, 0, 0,
+			0, 0, _spaceZ, 0,
+			0, 0, 0, 1 );
+
+		}
+		else {
+
+			var v = headerObject.vectors;
+			var origin = headerObject.space_origin;
+
+			if ( ! origin ) {
+
+				origin = [ 0, 0, 0 ];
+
+			}
+
+			volume.matrix.set( _spaceX * v[ 0 ][ 0 ], _spaceX * v[ 1 ][ 0 ], _spaceX * v[ 2 ][ 0 ], 0,
+			_spaceY * v[ 0 ][ 1 ], _spaceY * v[ 1 ][ 1 ], _spaceY * v[ 2 ][ 1 ], 0,
+			_spaceZ * v[ 0 ][ 2 ], _spaceZ * v[ 1 ][ 2 ], _spaceZ * v[ 2 ][ 2 ], 0,
+			0, 0, 0, 1 );
+
+		}
+
+		volume.inverseMatrix = new THREE.Matrix4();
+		volume.inverseMatrix.getInverse( volume.matrix );
+		volume.RASDimensions = ( new THREE.Vector3( volume.xLength, volume.yLength, volume.zLength ) ).applyMatrix4( volume.matrix ).round().toArray().map( Math.abs );
+
+		// .. and set the default threshold
+		// only if the threshold was not already set
+		if ( volume.lowerThreshold === - Infinity ) {
+
+			volume.lowerThreshold = min;
+
+		}
+		if ( volume.upperThreshold === Infinity ) {
+
+			volume.upperThreshold = max;
+
+		}
+
+		return volume;
+
+	},
+
+	parseChars: function( array, start, end ) {
+
+		// without borders, use the whole array
+		if ( start === undefined ) {
+
+			start = 0;
+
+		}
+		if ( end === undefined ) {
+
+			end = array.length;
+
+		}
+
+		var output = '';
+		// create and append the chars
+		var i = 0;
+		for ( i = start; i < end; ++ i ) {
+
+			output += String.fromCharCode( array[ i ] );
+
+		}
+
+		return output;
+
+	},
+
+	fieldFunctions: {
+
+		type: function( data ) {
+
+			switch ( data ) {
+				case 'uchar':
+				case 'unsigned char':
+				case 'uint8':
+				case 'uint8_t':
+					this.__array = Uint8Array;
+					break;
+				case 'signed char':
+				case 'int8':
+				case 'int8_t':
+					this.__array = Int8Array;
+					break;
+				case 'short':
+				case 'short int':
+				case 'signed short':
+				case 'signed short int':
+				case 'int16':
+				case 'int16_t':
+					this.__array = Int16Array;
+					break;
+				case 'ushort':
+				case 'unsigned short':
+				case 'unsigned short int':
+				case 'uint16':
+				case 'uint16_t':
+					this.__array = Uint16Array;
+					break;
+				case 'int':
+				case 'signed int':
+				case 'int32':
+				case 'int32_t':
+					this.__array = Int32Array;
+					break;
+				case 'uint':
+				case 'unsigned int':
+				case 'uint32':
+				case 'uint32_t':
+					this.__array = Uint32Array;
+					break;
+				case 'float':
+					this.__array = Float32Array;
+					break;
+				case 'double':
+					this.__array = Float64Array;
+					break;
+				default:
+					throw new Error( 'Unsupported NRRD data type: ' + data );
+			}
+			return this.type = data;
+
+		},
+
+		endian: function( data ) {
+
+			return this.endian = data;
+
+		},
+
+		encoding: function( data ) {
+
+			return this.encoding = data;
+
+		},
+
+		dimension: function( data ) {
+
+			return this.dim = parseInt( data, 10 );
+
+		},
+
+		sizes: function( data ) {
+
+			var i;
+			return this.sizes = ( function() {
+
+				var _i, _len, _ref, _results;
+				_ref = data.split( /\s+/ );
+				_results = [];
+				for ( _i = 0, _len = _ref.length; _i < _len; _i ++ ) {
+
+					i = _ref[ _i ];
+					_results.push( parseInt( i, 10 ) );
+
+				}
+				return _results;
+
+			} )();
+
+		},
+
+		space: function( data ) {
+
+			return this.space = data;
+
+		},
+
+		'space origin' : function( data ) {
+
+			return this.space_origin = data.split( "(" )[ 1 ].split( ")" )[ 0 ].split( "," );
+
+		},
+
+		'space directions' : function( data ) {
+
+			var f, parts, v;
+			parts = data.match( /\(.*?\)/g );
+			return this.vectors = ( function() {
+
+				var _i, _len, _results;
+				_results = [];
+				for ( _i = 0, _len = parts.length; _i < _len; _i ++ ) {
+
+					v = parts[ _i ];
+					_results.push( ( function() {
+
+						var _j, _len2, _ref, _results2;
+						_ref = v.slice( 1, - 1 ).split( /,/ );
+						_results2 = [];
+						for ( _j = 0, _len2 = _ref.length; _j < _len2; _j ++ ) {
+
+							f = _ref[ _j ];
+							_results2.push( parseFloat( f ) );
+
+						}
+						return _results2;
+
+					} )() );
+
+				}
+				return _results;
+
+			} )();
+
+		},
+
+		spacings: function( data ) {
+
+			var f, parts;
+			parts = data.split( /\s+/ );
+			return this.spacings = ( function() {
+
+				var _i, _len, _results;
+				_results = [];
+				for ( _i = 0, _len = parts.length; _i < _len; _i ++ ) {
+
+					f = parts[ _i ];
+					_results.push( parseFloat( f ) );
+
+				}
+				return _results;
+
+			} )();
+
+		}
+	}
+
+};
+
+THREE.EventDispatcher.prototype.apply( THREE.NRRDLoader.prototype );

+ 2 - 2
examples/js/loaders/OBJLoader.js

@@ -215,7 +215,7 @@ THREE.OBJLoader.prototype = {
 		// f vertex//normal vertex//normal vertex//normal ...
 		var face_pattern4 = /^f\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))(?:\s+((-?\d+)\/\/(-?\d+)))?/;
 
-		var object_pattern = /^[og]\s+(.+)/;
+		var object_pattern = /^[og]\s*(.+)?/;
 
 		var smoothing_pattern = /^s\s+(\d+|on|off)/;
 
@@ -306,7 +306,7 @@ THREE.OBJLoader.prototype = {
 				// or
 				// g group_name
 
-				var name = result[ 1 ].trim();
+				var name = result[ 0 ].substr( 1 ).trim();
 
 				if ( foundObjects === false ) {
 

+ 2 - 2
examples/js/loaders/PCDLoader.js

@@ -33,7 +33,7 @@ THREE.PCDLoader.prototype = {
 
 	binarryToStr: function( data ) {
 
-		text = "";
+		var text = "";
 		var charArray = new Uint8Array( data );
 		for ( var i = 0; i < data.byteLength; i ++ ) {
 
@@ -125,7 +125,7 @@ THREE.PCDLoader.prototype = {
 
 	parse: function( data, url ) {
 
-		textData = this.binarryToStr( data );
+		var textData = this.binarryToStr( data );
 
 		// Parse the header
 		// Header is always ascii format

+ 7 - 7
examples/js/loaders/VRMLLoader.js

@@ -582,7 +582,7 @@ THREE.VRMLLoader.prototype = {
 
 					if ( /USE/.exec( data ) ) {
 
-						var defineKey = /USE\s+?(\w+)/.exec( data )[ 1 ];
+						var defineKey = /USE\s+?([^\s]+)/.exec( data )[ 1 ];
 
 						if ( undefined == defines[ defineKey ] ) {
 
@@ -629,7 +629,7 @@ THREE.VRMLLoader.prototype = {
 
 					if ( /DEF/.exec( data.string ) ) {
 
-						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
+						object.name = /DEF\s+([^\s]+)/.exec( data.string )[ 1 ];
 						defines[ object.name ] = object;
 
 					}
@@ -666,7 +666,7 @@ THREE.VRMLLoader.prototype = {
 
 					if ( /DEF/.exec( data.string ) ) {
 
-						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
+						object.name = /DEF\s+([^\s]+)/.exec( data.string )[ 1 ];
 
 						defines[ object.name ] = object;
 
@@ -772,7 +772,7 @@ THREE.VRMLLoader.prototype = {
 
 								if ( child.string.indexOf ( 'DEF' ) > -1 ) {
 
-									var name = /DEF\s+(\w+)/.exec( child.string )[ 1 ];
+									var name = /DEF\s+([^\s]+)/.exec( child.string )[ 1 ];
 
 									defines[ name ] = geometry.vertices;
 
@@ -780,7 +780,7 @@ THREE.VRMLLoader.prototype = {
 
 								if ( child.string.indexOf ( 'USE' ) > -1 ) {
 
-									var defineKey = /USE\s+(\w+)/.exec( child.string )[ 1 ];
+									var defineKey = /USE\s+([^\s]+)/.exec( child.string )[ 1 ];
 
 									geometry.vertices = defines[ defineKey ];
 								}
@@ -862,7 +862,7 @@ THREE.VRMLLoader.prototype = {
 						// see if it's a define
 						if ( /DEF/.exec( data.string ) ) {
 
-							geometry.name = /DEF (\w+)/.exec( data.string )[ 1 ];
+							geometry.name = /DEF ([^\s]+)/.exec( data.string )[ 1 ];
 							defines[ geometry.name ] = geometry;
 
 						}
@@ -920,7 +920,7 @@ THREE.VRMLLoader.prototype = {
 
 							if ( /DEF/.exec( data.string ) ) {
 
-								material.name = /DEF (\w+)/.exec( data.string )[ 1 ];
+								material.name = /DEF ([^\s]+)/.exec( data.string )[ 1 ];
 
 								defines[ material.name ] = material;
 

+ 982 - 147
examples/js/loaders/VTKLoader.js

@@ -3,7 +3,7 @@
  * @author Alex Pletzer
  */
 
-THREE.VTKLoader = function ( manager ) {
+THREE.VTKLoader = function( manager ) {
 
 	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
 
@@ -15,261 +15,1096 @@ THREE.VTKLoader.prototype = {
 
 	load: function ( url, onLoad, onProgress, onError ) {
 
-		// Will we bump into trouble reading the whole file into memory?
 		var scope = this;
+
 		var loader = new THREE.XHRLoader( scope.manager );
-		loader.load( url, function ( text ) {
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function( text ) {
 
 			onLoad( scope.parse( text ) );
 
-		},
-
-		onProgress, onError );
+		}, onProgress, onError );
 
 	},
 
 	parse: function ( data ) {
 
-		// connectivity of the triangles
-		var indices = [];
+		function parseASCII( data ) {
 
-		// triangles vertices
-		var positions = [];
+			// connectivity of the triangles
+			var indices = [];
 
-		// red, green, blue colors in the range 0 to 1
-		var colors = [];
+			// triangles vertices
+			var positions = [];
 
-		// normal vector, one per vertex
-		var normals = [];
+			// red, green, blue colors in the range 0 to 1
+			var colors = [];
 
-		var result;
+			// normal vector, one per vertex
+			var normals = [];
 
-		// pattern for reading vertices, 3 floats or integers
-		var pat3Floats = /(\-?\d+\.?[\d\-\+e]*)\s+(\-?\d+\.?[\d\-\+e]*)\s+(\-?\d+\.?[\d\-\+e]*)/g;
+			var result;
 
-		// pattern for connectivity, an integer followed by any number of ints
-		// the first integer is the number of polygon nodes
-		var patConnectivity = /^(\d+)\s+([\s\d]*)/;
+			// pattern for reading vertices, 3 floats or integers
+			var pat3Floats = /(\-?\d+\.?[\d\-\+e]*)\s+(\-?\d+\.?[\d\-\+e]*)\s+(\-?\d+\.?[\d\-\+e]*)/g;
 
-		// indicates start of vertex data section
-		var patPOINTS = /^POINTS /;
+			// pattern for connectivity, an integer followed by any number of ints
+			// the first integer is the number of polygon nodes
+			var patConnectivity = /^(\d+)\s+([\s\d]*)/;
 
-		// indicates start of polygon connectivity section
-		var patPOLYGONS = /^POLYGONS /;
+			// indicates start of vertex data section
+			var patPOINTS = /^POINTS /;
 
-		// POINT_DATA number_of_values
-		var patPOINT_DATA = /^POINT_DATA[ ]+(\d+)/;
+			// indicates start of polygon connectivity section
+			var patPOLYGONS = /^POLYGONS /;
 
-		// CELL_DATA number_of_polys
-		var patCELL_DATA = /^CELL_DATA[ ]+(\d+)/;
+			// indicates start of triangle strips section
+			var patTRIANGLE_STRIPS = /^TRIANGLE_STRIPS /;
 
-		// Start of color section
-		var patCOLOR_SCALARS = /^COLOR_SCALARS[ ]+(\w+)[ ]+3/;
+			// POINT_DATA number_of_values
+			var patPOINT_DATA = /^POINT_DATA[ ]+(\d+)/;
 
-		// NORMALS Normals float
-		var patNORMALS = /^NORMALS[ ]+(\w+)[ ]+(\w+)/;
+			// CELL_DATA number_of_polys
+			var patCELL_DATA = /^CELL_DATA[ ]+(\d+)/;
 
-		var inPointsSection = false;
-		var inPolygonsSection = false;
-		var inPointDataSection = false;
-		var inCellDataSection = false;
-		var inColorSection = false;
-		var inNormalsSection = false;
+			// Start of color section
+			var patCOLOR_SCALARS = /^COLOR_SCALARS[ ]+(\w+)[ ]+3/;
 
-		var lines = data.split( '\n' );
+			// NORMALS Normals float
+			var patNORMALS = /^NORMALS[ ]+(\w+)[ ]+(\w+)/;
 
-		for ( var i in lines ) {
+			var inPointsSection = false;
+			var inPolygonsSection = false;
+			var inTriangleStripSection = false;
+			var inPointDataSection = false;
+			var inCellDataSection = false;
+			var inColorSection = false;
+			var inNormalsSection = false;
 
-			var line = lines[ i ];
+			var lines = data.split( '\n' );
 
-			if ( inPointsSection ) {
+			for ( var i in lines ) {
 
-				// get the vertices
-				while ( ( result = pat3Floats.exec( line ) ) !== null ) {
+				var line = lines[ i ];
 
-					var x = parseFloat( result[ 1 ] );
-					var y = parseFloat( result[ 2 ] );
-					var z = parseFloat( result[ 3 ] );
-					positions.push( x, y, z );
+				if ( inPointsSection ) {
 
-				}
+					// get the vertices
+					while ( ( result = pat3Floats.exec( line ) ) !== null ) {
+
+						var x = parseFloat( result[ 1 ] );
+						var y = parseFloat( result[ 2 ] );
+						var z = parseFloat( result[ 3 ] );
+						positions.push( x, y, z );
+
+					}
 
-			} else if ( inPolygonsSection ) {
+				} else if ( inPolygonsSection ) {
 
-				if ( ( result = patConnectivity.exec( line ) ) !== null ) {
+					if ( ( result = patConnectivity.exec( line ) ) !== null ) {
 
-					// numVertices i0 i1 i2 ...
-					var numVertices = parseInt( result[ 1 ] );
-					var inds = result[ 2 ].split( /\s+/ );
+						// numVertices i0 i1 i2 ...
+						var numVertices = parseInt( result[ 1 ] );
+						var inds = result[ 2 ].split( /\s+/ );
 
-					if ( numVertices >= 3 ) {
+						if ( numVertices >= 3 ) {
 
-						var i0 = parseInt( inds[ 0 ] );
-						var i1, i2;
-						var k = 1;
-						// split the polygon in numVertices - 2 triangles
-						for ( var j = 0; j < numVertices - 2; ++ j ) {
+							var i0 = parseInt( inds[ 0 ] );
+							var i1, i2;
+							var k = 1;
+							// split the polygon in numVertices - 2 triangles
+							for ( var j = 0; j < numVertices - 2; ++ j ) {
 
-							i1 = parseInt( inds[ k ] );
-							i2 = parseInt( inds[ k  + 1 ] );
-							indices.push( i0, i1, i2 );
-							k ++;
+								i1 = parseInt( inds[ k ] );
+								i2 = parseInt( inds[ k + 1 ] );
+								indices.push( i0, i1, i2 );
+								k ++;
+
+							}
 
 						}
 
 					}
 
-				}
+				} else if ( inTriangleStripSection ) {
 
-			} else if ( inPointDataSection || inCellDataSection ) {
+					if ( ( result = patConnectivity.exec( line ) ) !== null ) {
 
-				if ( inColorSection ) {
+						// numVertices i0 i1 i2 ...
+						var numVertices = parseInt( result[ 1 ] );
+						var inds = result[ 2 ].split( /\s+/ );
 
-					// Get the colors
+						if ( numVertices >= 3 ) {
 
-					while ( ( result = pat3Floats.exec( line ) ) !== null ) {
+							var i0, i1, i2;
+							// split the polygon in numVertices - 2 triangles
+							for ( var j = 0; j < numVertices - 2; j ++ ) {
+
+								if ( j % 2 === 1 ) {
+
+									i0 = parseInt( inds[ j ] );
+									i1 = parseInt( inds[ j + 2 ] );
+									i2 = parseInt( inds[ j + 1 ] );
+									indices.push( i0, i1, i2 );
+
+								} else {
 
-						var r = parseFloat( result[ 1 ] );
-						var g = parseFloat( result[ 2 ] );
-						var b = parseFloat( result[ 3 ] );
-						colors.push( r, g, b );
+									i0 = parseInt( inds[ j ] );
+									i1 = parseInt( inds[ j + 1 ] );
+									i2 = parseInt( inds[ j + 2 ] );
+									indices.push( i0, i1, i2 );
+
+								}
+
+							}
+
+						}
 
 					}
 
-				} else if ( inNormalsSection ) {
+				} else if ( inPointDataSection || inCellDataSection ) {
 
-					// Get the normal vectors
+					if ( inColorSection ) {
 
-					while ( ( result = pat3Floats.exec( line ) ) !== null ) {
+						// Get the colors
+
+						while ( ( result = pat3Floats.exec( line ) ) !== null ) {
 
-						var nx = parseFloat( result[ 1 ] );
-						var ny = parseFloat( result[ 2 ] );
-						var nz = parseFloat( result[ 3 ] );
-						normals.push( nx, ny, nz );
+							var r = parseFloat( result[ 1 ] );
+							var g = parseFloat( result[ 2 ] );
+							var b = parseFloat( result[ 3 ] );
+							colors.push( r, g, b );
+
+						}
+
+					} else if ( inNormalsSection ) {
+
+						// Get the normal vectors
+
+						while ( ( result = pat3Floats.exec( line ) ) !== null ) {
+
+							var nx = parseFloat( result[ 1 ] );
+							var ny = parseFloat( result[ 2 ] );
+							var nz = parseFloat( result[ 3 ] );
+							normals.push( nx, ny, nz );
+
+						}
 
 					}
 
 				}
 
+				if ( patPOLYGONS.exec( line ) !== null ) {
+
+					inPolygonsSection = true;
+					inPointsSection = false;
+					inTriangleStripSection = false;
+
+				} else if ( patPOINTS.exec( line ) !== null ) {
+
+					inPolygonsSection = false;
+					inPointsSection = true;
+					inTriangleStripSection = false;
+
+				} else if ( patTRIANGLE_STRIPS.exec( line ) !== null ) {
+
+					inPolygonsSection = false;
+					inPointsSection = false;
+					inTriangleStripSection = true;
+
+				} else if ( patPOINT_DATA.exec( line ) !== null ) {
+
+					inPointDataSection = true;
+					inPointsSection = false;
+					inPolygonsSection = false;
+					inTriangleStripSection = false;
+
+				} else if ( patCELL_DATA.exec( line ) !== null ) {
+
+					inCellDataSection = true;
+					inPointsSection = false;
+					inPolygonsSection = false;
+					inTriangleStripSection = false;
+
+				} else if ( patCOLOR_SCALARS.exec( line ) !== null ) {
+
+					inColorSection = true;
+					inNormalsSection = false;
+					inPointsSection = false;
+					inPolygonsSection = false;
+					inTriangleStripSection = false;
+
+				} else if ( patNORMALS.exec( line ) !== null ) {
+
+					inNormalsSection = true;
+					inColorSection = false;
+					inPointsSection = false;
+					inPolygonsSection = false;
+					inTriangleStripSection = false;
+
+				}
+
+			}
+
+			var geometry;
+			var stagger = 'point';
+
+			if ( colors.length == indices.length ) {
+
+				stagger = 'cell';
+
 			}
 
-			if ( patPOLYGONS.exec( line ) !== null ) {
+			if ( stagger == 'point' ) {
 
-				inPolygonsSection = true;
-				inPointsSection = false;
+				// Nodal. Use BufferGeometry
+				geometry = new THREE.BufferGeometry();
+				geometry.setIndex( new THREE.BufferAttribute( new Uint32Array( indices ), 1 ) );
+				geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
 
-			} else if ( patPOINTS.exec( line ) !== null ) {
+				if ( colors.length == positions.length ) {
 
-				inPolygonsSection = false;
-				inPointsSection = true;
+					geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
 
-			} else if ( patPOINT_DATA.exec( line ) !== null ) {
+				}
+
+				if ( normals.length == positions.length ) {
 
-				inPointDataSection = true;
-				inPointsSection = false;
-				inPolygonsSection = false;
+					geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
 
-			} else if ( patCELL_DATA.exec( line ) !== null ) {
+				}
 
-				inCellDataSection = true;
-				inPointsSection = false;
-				inPolygonsSection = false;
+			} else {
 
-			} else if ( patCOLOR_SCALARS.exec( line ) !== null ) {
+				// Cell centered colors. The only way to attach a solid color to each triangle
+				// is to use Geometry, which is less efficient than BufferGeometry
+				geometry = new THREE.Geometry();
 
-				inColorSection = true;
-				inNormalsSection = false;
-				inPointsSection = false;
-				inPolygonsSection = false;
+				var numTriangles = indices.length / 3;
+				var numPoints = positions.length / 3;
+				var va, vb, vc;
+				var face;
+				var ia, ib, ic;
+				var x, y, z;
+				var r, g, b;
 
-			} else if ( patNORMALS.exec( line ) !== null ) {
+				for ( var j = 0; j < numPoints; ++ j ) {
 
-				inNormalsSection = true;
-				inColorSection = false;
-				inPointsSection = false;
-				inPolygonsSection = false;
+					x = positions[ 3 * j + 0 ];
+					y = positions[ 3 * j + 1 ];
+					z = positions[ 3 * j + 2 ];
+					geometry.vertices.push( new THREE.Vector3( x, y, z ) );
+
+				}
+
+				for ( var i = 0; i < numTriangles; ++ i ) {
+
+					ia = indices[ 3 * i + 0 ];
+					ib = indices[ 3 * i + 1 ];
+					ic = indices[ 3 * i + 2 ];
+					geometry.faces.push( new THREE.Face3( ia, ib, ic ) );
+
+				}
+
+				if ( colors.length == numTriangles * 3 ) {
+
+					for ( var i = 0; i < numTriangles; ++ i ) {
+
+						face = geometry.faces[ i ];
+						r = colors[ 3 * i + 0 ];
+						g = colors[ 3 * i + 1 ];
+						b = colors[ 3 * i + 2 ];
+						face.color = new THREE.Color().setRGB( r, g, b );
+
+					}
+
+				}
 
 			}
 
+			return geometry;
+
 		}
 
-		var geometry;
-		var stagger = 'point';
+		function parseBinary( data ) {
+
+			var count, pointIndex, i, numberOfPoints, pt, s;
+			var buffer = new Uint8Array ( data );
+			var dataView = new DataView ( data );
+
+			// Points and normals, by default, are empty
+			var points = [];
+			var normals = [];
+			var indices = [];
+
+			// Going to make a big array of strings
+			var vtk = [];
+			var index = 0;
+
+			function findString( buffer, start ) {
+
+				var index = start;
+				var c = buffer[ index ];
+				var s = [];
+				while ( c != 10 ) {
+
+					s.push ( String.fromCharCode ( c ) );
+					index ++;
+					c = buffer[ index ];
+
+				}
+
+				return { start: start,
+						end: index,
+						next: index + 1,
+						parsedString: s.join( '' ) };
+
+			}
+
+			var state, line;
+
+			while ( true ) {
+
+				// Get a string
+				state = findString ( buffer, index );
+				line = state.parsedString;
+
+				if ( line.indexOf ( 'POINTS' ) === 0 ) {
+
+					vtk.push ( line );
+					// Add the points
+					numberOfPoints = parseInt ( line.split( ' ' )[ 1 ], 10 );
+
+					// Each point is 3 4-byte floats
+					count = numberOfPoints * 4 * 3;
+
+					points = new Float32Array( numberOfPoints * 3 );
+
+					pointIndex = state.next;
+					for ( i = 0; i < numberOfPoints; i ++ ) {
+
+						points[ 3 * i ] = dataView.getFloat32( pointIndex, false );
+						points[ 3 * i + 1 ] = dataView.getFloat32( pointIndex + 4, false );
+						points[ 3 * i + 2 ] = dataView.getFloat32( pointIndex + 8, false );
+						pointIndex = pointIndex + 12;
+
+					}
+					// increment our next pointer
+					state.next = state.next + count + 1;
+
+				} else if ( line.indexOf ( 'TRIANGLE_STRIPS' ) === 0 ) {
+
+					var numberOfStrips = parseInt ( line.split( ' ' )[ 1 ], 10 );
+					var size = parseInt ( line.split ( ' ' )[ 2 ], 10 );
+					// 4 byte integers
+					count = size * 4;
+
+					indices = new Uint32Array( 3 * size - 9 * numberOfStrips );
+					var indicesIndex = 0;
+
+					pointIndex = state.next;
+					for ( i = 0; i < numberOfStrips; i ++ ) {
+
+						// For each strip, read the first value, then record that many more points
+						var indexCount = dataView.getInt32( pointIndex, false );
+						var strip = [];
+						pointIndex += 4;
+						for ( s = 0; s < indexCount; s ++ ) {
+
+							strip.push ( dataView.getInt32( pointIndex, false ) );
+							pointIndex += 4;
+
+						}
+
+						// retrieves the n-2 triangles from the triangle strip
+						for ( var j = 0; j < indexCount - 2; j ++ ) {
+
+							if ( j % 2 ) {
+
+								indices[ indicesIndex ++ ] = strip[ j ];
+								indices[ indicesIndex ++ ] = strip[ j + 2 ];
+								indices[ indicesIndex ++ ] = strip[ j + 1 ];
+
+							} else {
+
 
-		if ( colors.length == indices.length ) {
+								indices[ indicesIndex ++ ] = strip[ j ];
+								indices[ indicesIndex ++ ] = strip[ j + 1 ];
+								indices[ indicesIndex ++ ] = strip[ j + 2 ];
 
-			stagger = 'cell';
+							}
+
+						}
+
+					}
+					// increment our next pointer
+					state.next = state.next + count + 1;
+
+				} else if ( line.indexOf ( 'POLYGONS' ) === 0 ) {
+
+					var numberOfStrips = parseInt ( line.split( ' ' )[ 1 ], 10 );
+					var size = parseInt ( line.split ( ' ' )[ 2 ], 10 );
+					// 4 byte integers
+					count = size * 4;
+
+					indices = new Uint32Array( 3 * size - 9 * numberOfStrips );
+					var indicesIndex = 0;
+
+					pointIndex = state.next;
+					for ( i = 0; i < numberOfStrips; i ++ ) {
+
+						// For each strip, read the first value, then record that many more points
+						var indexCount = dataView.getInt32( pointIndex, false );
+						var strip = [];
+						pointIndex += 4;
+						for ( s = 0; s < indexCount; s ++ ) {
+
+							strip.push ( dataView.getInt32( pointIndex, false ) );
+							pointIndex += 4;
+
+						}
+						var i0 = strip[ 0 ];
+						// divide the polygon in n-2 triangle
+						for ( var j = 1; j < indexCount - 1; j ++ ) {
+
+							indices[ indicesIndex ++ ] = strip[ 0 ];
+							indices[ indicesIndex ++ ] = strip[ j ];
+							indices[ indicesIndex ++ ] = strip[ j + 1 ];
+
+						}
+
+					}
+					// increment our next pointer
+					state.next = state.next + count + 1;
+
+				} else if ( line.indexOf ( 'POINT_DATA' ) === 0 ) {
+
+					numberOfPoints = parseInt ( line.split( ' ' )[ 1 ], 10 );
+
+					// Grab the next line
+					state = findString ( buffer, state.next );
+
+					// Now grab the binary data
+					count = numberOfPoints * 4 * 3;
+
+					normals = new Float32Array( numberOfPoints * 3 );
+					pointIndex = state.next;
+					for ( i = 0; i < numberOfPoints; i ++ ) {
+
+						normals[ 3 * i ] = dataView.getFloat32( pointIndex, false );
+						normals[ 3 * i + 1 ] = dataView.getFloat32( pointIndex + 4, false );
+						normals[ 3 * i + 2 ] = dataView.getFloat32( pointIndex + 8, false );
+						pointIndex += 12;
+
+					}
+
+					// Increment past our data
+					state.next = state.next + count;
+
+				}
+
+				// Increment index
+				index = state.next;
+
+				if ( index >= buffer.byteLength ) {
+
+					break;
+
+				}
+
+			}
+
+			var geometry = new THREE.BufferGeometry();
+			geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
+			geometry.addAttribute( 'position', new THREE.BufferAttribute( points, 3 ) );
+
+			if ( normals.length == points.length ) {
+
+				geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
+
+			}
+
+			return geometry;
 
 		}
 
-		if ( stagger == 'point' ) {
+		function parseXML( stringFile ) {
+
+			// Changes XML to JSON, based on https://davidwalsh.name/convert-xml-json
+
+			function xmlToJson( xml ) {
+
+				// Create the return object
+				var obj = {};
+
+				if ( xml.nodeType == 1 ) { // element
+
+					// do attributes
+
+					if ( xml.attributes ) {
+
+						if ( xml.attributes.length > 0 ) {
+
+							obj[ 'attributes' ] = {};
+
+							for ( var j = 0; j < xml.attributes.length; j ++ ) {
 
-			// Nodal. Use BufferGeometry
-			geometry = new THREE.BufferGeometry();
-			geometry.setIndex( new THREE.BufferAttribute( new ( indices.length > 65535 ? Uint32Array : Uint16Array )( indices ), 1 ) );
-			geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
+								var attribute = xml.attributes.item( j );
+								obj[ 'attributes' ][ attribute.nodeName ] = attribute.nodeValue.trim();
 
-			if ( colors.length == positions.length ) {
+							}
 
-				geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+						}
+
+					}
+
+				} else if ( xml.nodeType == 3 ) { // text
+
+					obj = xml.nodeValue.trim();
+
+				}
+
+				// do children
+				if ( xml.hasChildNodes() ) {
+
+					for ( var i = 0; i < xml.childNodes.length; i ++ ) {
+
+						var item = xml.childNodes.item( i );
+						var nodeName = item.nodeName;
+
+						if ( typeof( obj[ nodeName ] ) === 'undefined' ) {
+
+							var tmp = xmlToJson( item );
+
+							if ( tmp !== '' ) obj[ nodeName ] = tmp;
+
+						} else {
+
+							if ( typeof( obj[ nodeName ].push ) === 'undefined' ) {
+
+								var old = obj[ nodeName ];
+								obj[ nodeName ] = [ old ];
+
+							}
+
+							var tmp = xmlToJson( item );
+
+							if ( tmp !== '' ) obj[ nodeName ].push( tmp );
+
+						}
+
+					}
+
+				}
+
+				return obj;
 
 			}
 
-			if ( normals.length == positions.length ) {
+			// Taken from Base64-js
+			function Base64toByteArray( b64 ) {
+
+				var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
+				var i;
+				var lookup = [];
+				var revLookup = [];
+				var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+				var len = code.length;
+
+				for ( i = 0; i < len; i ++ ) {
+
+					lookup[ i ] = code[ i ];
+
+				}
+
+				for ( i = 0; i < len; ++ i ) {
+
+					revLookup[ code.charCodeAt( i ) ] = i;
+
+				}
+
+				revLookup[ '-'.charCodeAt( 0 ) ] = 62;
+				revLookup[ '_'.charCodeAt( 0 ) ] = 63;
+
+				var j, l, tmp, placeHolders, arr;
+				var len = b64.length;
+
+				if ( len % 4 > 0 ) {
+
+					throw new Error( 'Invalid string. Length must be a multiple of 4' );
+
+				}
+
+				placeHolders = b64[ len - 2 ] === '=' ? 2 : b64[ len - 1 ] === '=' ? 1 : 0;
+				arr = new Arr( len * 3 / 4 - placeHolders );
+				l = placeHolders > 0 ? len - 4 : len;
+
+				var L = 0;
+
+				for ( i = 0, j = 0; i < l; i += 4, j += 3 ) {
+
+					tmp = ( revLookup[ b64.charCodeAt( i ) ] << 18 ) | ( revLookup[ b64.charCodeAt( i + 1 ) ] << 12 ) | ( revLookup[ b64.charCodeAt( i + 2 ) ] << 6 ) | revLookup[ b64.charCodeAt( i + 3 ) ];
+					arr[ L ++ ] = ( tmp & 0xFF0000 ) >> 16;
+					arr[ L ++ ] = ( tmp & 0xFF00 ) >> 8;
+					arr[ L ++ ] = tmp & 0xFF;
+
+				}
+
+				if ( placeHolders === 2 ) {
+
+					tmp = ( revLookup[ b64.charCodeAt( i ) ] << 2 ) | ( revLookup[ b64.charCodeAt( i + 1 ) ] >> 4 );
+					arr[ L ++ ] = tmp & 0xFF;
+
+				} else if ( placeHolders === 1 ) {
 
-				geometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
+					tmp = ( revLookup[ b64.charCodeAt( i ) ] << 10 ) | ( revLookup[ b64.charCodeAt( i + 1 ) ] << 4 ) | ( revLookup[ b64.charCodeAt( i + 2 ) ] >> 2 );
+					arr[ L ++ ] = ( tmp >> 8 ) & 0xFF;
+					arr[ L ++ ] = tmp & 0xFF;
+
+				}
+
+				return arr;
 
 			}
 
-		} else {
+			function parseDataArray( ele, compressed ) {
+
+				// Check the format
+
+				if ( ele.attributes.format == 'binary' ) {
+
+					if ( compressed ) {
+
+						// Split the blob_header and compressed Data
+						if ( ele[ '#text' ].indexOf( '==' ) != - 1 ) {
+
+							var data = ele[ '#text' ].split( '==' );
+
+							// console.log( data );
+
+							if ( data.length == 2 ) {
+
+								var blob = data.shift();
+								var content = data.shift();
+
+								if ( content === '' ) {
+
+									content = blob + '==';
+
+								}
+
+							} else if ( data.length > 2 ) {
+
+								var blob = data.shift();
+								var content = data.shift();
+								content = content + '==';
+
+							} else if ( data.length < 2 ) {
+
+								var content = data.shift();
+								content = content + '==';
+
+							}
+
+							// Convert to bytearray
+							var arr = Base64toByteArray( content );
+
+							// decompress
+							var inflate = new Zlib.Inflate( arr, { resize: true, verify: true } );
+							var content = inflate.decompress();
+
+						} else {
+
+							var content = Base64toByteArray( ele[ '#text' ] );
+
+						}
+
+					} else {
+
+						var content = Base64toByteArray( ele[ '#text' ] );
+
+					}
+
+					var content = content.buffer;
+
+				} else {
+
+					if ( ele[ '#text' ] ) {
+
+						var content = ele[ '#text' ].replace( /\n/g, ' ' ).split( ' ' ).filter( function ( el, idx, arr ) {
+
+							if ( el !== '' ) return el;
+
+						} );
+
+					} else {
+
+						var content = new Int32Array( 0 ).buffer;
+
+					}
+
+				}
+
+				delete ele[ '#text' ];
+
+				// Get the content and optimize it
+
+				if ( ele.attributes.type == 'Float32' ) {
+
+					var txt = new Float32Array( content );
+
+					if ( ele.attributes.format == 'binary' ) {
+
+						if ( ! compressed ) {
+
+							txt = txt.filter( function( el, idx, arr ) {
+
+								if ( idx !== 0 ) return true;
 
-			// Cell centered colors. The only way to attach a solid color to each triangle
-			// is to use Geometry, which is less efficient than BufferGeometry
-			geometry = new THREE.Geometry();
+							} );
 
-			var numTriangles = indices.length / 3;
-			var numPoints = positions.length / 3;
-			var va, vb, vc;
-			var face;
-			var ia, ib, ic;
-			var x, y, z;
-			var r, g, b;
+						}
+
+					}
+
+				} else if ( ele.attributes.type === 'Int64' ) {
+
+					var txt = new Int32Array( content );
+
+					if ( ele.attributes.format == 'binary' ) {
+
+						if ( ! compressed ) {
+
+							txt = txt.filter( function ( el, idx, arr ) {
+
+								if ( idx !== 0 ) return true;
+
+							} );
+
+						}
+
+						txt = txt.filter( function ( el, idx, arr ) {
 
-			for ( var j = 0; j < numPoints; ++ j ) {
+							if ( idx % 2 !== 1 ) return true;
 
-				x = positions[ 3 * j + 0 ];
-				y = positions[ 3 * j + 1 ];
-				z = positions[ 3 * j + 2 ];
-				geometry.vertices.push( new THREE.Vector3( x, y, z ) );
+						} );
+
+					}
+
+				}
+
+				// console.log( txt );
+
+				return txt;
 
 			}
 
-			for ( var i = 0; i < numTriangles; ++ i ) {
+			// Main part
+			// Get Dom
+			var dom = null;
+
+			if ( window.DOMParser ) {
+
+				try {
+
+					dom = ( new DOMParser() ).parseFromString( stringFile, 'text/xml' );
+
+				} catch ( e ) {
+
+					dom = null;
+
+				}
+
+			} else if ( window.ActiveXObject ) {
+
+				try {
+
+					dom = new ActiveXObject( 'Microsoft.XMLDOM' );
+					dom.async = false;
+
+					if ( ! dom.loadXML( xml ) ) {
+
+						throw new Error( dom.parseError.reason + dom.parseError.srcText );
+
+					}
+
+				} catch ( e ) {
+
+					dom = null;
+
+				}
+
+			} else {
 
-				ia = indices[ 3 * i + 0 ];
-				ib = indices[ 3 * i + 1 ];
-				ic = indices[ 3 * i + 2 ];
-				geometry.faces.push( new THREE.Face3( ia, ib, ic ) );
+				throw new Error( 'Cannot parse xml string!' );
 
 			}
 
-			if ( colors.length == numTriangles * 3 ) {
+			// Get the doc
+			var doc = dom.documentElement;
+			// Convert to json
+			var json = xmlToJson( doc );
+			var points = [];
+			var normals = [];
+			var indices = [];
 
-				for ( var i = 0; i < numTriangles; ++ i ) {
+			if ( json.PolyData ) {
+
+				var piece = json.PolyData.Piece;
+				var compressed = json.attributes.hasOwnProperty( 'compressor' );
+
+				// Can be optimized
+				// Loop through the sections
+				var sections = [ 'PointData', 'Points', 'Strips', 'Polys' ];// +['CellData', 'Verts', 'Lines'];
+				var sectionIndex = 0, numberOfSections = sections.length;
+
+				while ( sectionIndex < numberOfSections ) {
+
+					var section = piece[ sections[ sectionIndex ] ];
+
+					// If it has a DataArray in it
+
+					if ( section.DataArray ) {
+
+						// Depending on the number of DataArrays
+
+						if ( Object.prototype.toString.call( section.DataArray ) === '[object Array]' ) {
+
+							var arr = section.DataArray;
+
+						} else {
+
+							var arr = [ section.DataArray ];
 
-					face = geometry.faces[ i ];
-					r = colors[ 3 * i + 0 ];
-					g = colors[ 3 * i + 1 ];
-					b = colors[ 3 * i + 2 ];
-					face.color = new THREE.Color().setRGB( r, g, b );
+						}
+
+						var dataArrayIndex = 0, numberOfDataArrays = arr.length;
+
+						while ( dataArrayIndex < numberOfDataArrays ) {
+
+							// Parse the DataArray
+							arr[ dataArrayIndex ].text = parseDataArray( arr[ dataArrayIndex ], compressed );
+							dataArrayIndex ++;
+
+						}
+
+						switch ( sections[ sectionIndex ] ) {
+
+							// if iti is point data
+							case 'PointData':
+
+								var numberOfPoints = parseInt( piece.attributes.NumberOfPoints );
+								var normalsName = section.attributes.Normals;
+
+								if ( numberOfPoints > 0 ) {
+
+									for ( var i = 0, len = arr.length; i < len; i ++ ) {
+
+										if ( normalsName == arr[ i ].attributes.Name ) {
+
+											var components = arr[ i ].attributes.NumberOfComponents;
+											normals = new Float32Array( numberOfPoints * components );
+											normals.set( arr[ i ].text, 0 );
+
+										}
+
+									}
+
+								}
+
+								// console.log('Normals', normals);
+
+								break;
+
+							// if it is points
+							case 'Points':
+
+								var numberOfPoints = parseInt( piece.attributes.NumberOfPoints );
+
+								if ( numberOfPoints > 0 ) {
+
+									var components = section.DataArray.attributes.NumberOfComponents;
+									points = new Float32Array( numberOfPoints * components );
+									points.set( section.DataArray.text, 0 );
+
+								}
+
+								// console.log('Points', points);
+
+								break;
+
+							// if it is strips
+							case 'Strips':
+
+								var numberOfStrips = parseInt( piece.attributes.NumberOfStrips );
+
+								if ( numberOfStrips > 0 ) {
+
+									var connectivity = new Int32Array( section.DataArray[ 0 ].text.length );
+									var offset = new Int32Array( section.DataArray[ 1 ].text.length );
+									connectivity.set( section.DataArray[ 0 ].text, 0 );
+									offset.set( section.DataArray[ 1 ].text, 0 );
+
+									var size = numberOfStrips + connectivity.length;
+									indices = new Uint32Array( 3 * size - 9 * numberOfStrips );
+
+									var indicesIndex = 0;
+
+									for ( var i = 0,len = numberOfStrips; i < len; i ++ ) {
+
+										var strip = [];
+
+										for ( var s = 0, len1 = offset[ i ], len0 = 0; s < len1 - len0; s ++ ) {
+
+											strip.push ( connectivity[ s ] );
+
+											if ( i > 0 ) len0 = offset[ i - 1 ];
+
+										}
+
+										for ( var j = 0, len1 = offset[ i ], len0 = 0; j < len1 - len0 - 2; j ++ ) {
+
+											if ( j % 2 ) {
+
+												indices[ indicesIndex ++ ] = strip[ j ];
+												indices[ indicesIndex ++ ] = strip[ j + 2 ];
+												indices[ indicesIndex ++ ] = strip[ j + 1 ];
+
+											} else {
+
+												indices[ indicesIndex ++ ] = strip[ j ];
+												indices[ indicesIndex ++ ] = strip[ j + 1 ];
+												indices[ indicesIndex ++ ] = strip[ j + 2 ];
+
+											}
+
+											if ( i > 0 ) len0 = offset[ i - 1 ];
+
+										}
+
+									}
+
+								}
+
+								//console.log('Strips', indices);
+
+								break;
+
+							// if it is polys
+							case 'Polys':
+
+								var numberOfPolys = parseInt( piece.attributes.NumberOfPolys );
+
+								if ( numberOfPolys > 0 ) {
+
+									var connectivity = new Int32Array( section.DataArray[ 0 ].text.length );
+									var offset = new Int32Array( section.DataArray[ 1 ].text.length );
+									connectivity.set( section.DataArray[ 0 ].text, 0 );
+									offset.set( section.DataArray[ 1 ].text, 0 );
+
+									var size = numberOfPolys + connectivity.length;
+									indices = new Uint32Array( 3 * size - 9 * numberOfPolys );
+									var indicesIndex = 0, connectivityIndex = 0;
+									var i = 0,len = numberOfPolys, len0 = 0;
+
+									while ( i < len ) {
+
+										var poly = [];
+										var s = 0, len1 = offset[ i ];
+
+										while ( s < len1 - len0 ) {
+
+											poly.push( connectivity[ connectivityIndex ++ ] );
+											s ++;
+
+										}
+
+										var j = 1;
+
+										while ( j < len1 - len0 - 1 ) {
+
+											indices[ indicesIndex ++ ] = poly[ 0 ];
+											indices[ indicesIndex ++ ] = poly[ j ];
+											indices[ indicesIndex ++ ] = poly[ j + 1 ];
+											j ++;
+
+										}
+
+										i ++;
+										len0 = offset[ i - 1 ];
+
+									}
+
+								}
+								//console.log('Polys', indices);
+								break;
+
+							default:
+								break;
+
+						}
+
+					}
+
+					sectionIndex ++;
+
+				}
+
+				var geometry = new THREE.BufferGeometry();
+				geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
+				geometry.addAttribute( 'position', new THREE.BufferAttribute( points, 3 ) );
+
+				if ( normals.length == points.length ) {
+
+					geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
 
 				}
 
-			 }
+				// console.log( json );
+
+				return geometry;
+
+			} else {
+
+				// TODO for vtu,vti,and other xml formats
+
+			}
 
 		}
 
-		return geometry;
+		function getStringFile( data ) {
+
+			var stringFile = '';
+			var charArray = new Uint8Array( data );
+			var i = 0;
+			var len = charArray.length;
+
+			while ( len -- ) {
+
+				stringFile += String.fromCharCode( charArray[ i ++ ] );
+
+			}
+
+			return stringFile;
+
+		}
+
+		// get the 5 first lines of the files to check if there is the key word binary
+		var meta = String.fromCharCode.apply( null, new Uint8Array( data, 0, 250 ) ).split( '\n' );
+
+		if ( meta[ 0 ].indexOf( 'xml' ) !== - 1 ) {
+
+			return parseXML( getStringFile( data ) );
+
+		} else if ( meta[ 2 ].includes( 'ASCII' ) ) {
+
+			return parseASCII( getStringFile( data ) );
+
+		} else {
+
+			return parseBinary( data );
+
+		}
 
 	}
 

+ 317 - 307
examples/js/loaders/gltf/glTF-parser.js

@@ -22,364 +22,374 @@
 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /*
-    The Abstract Loader has two modes:
-        #1: [static] load all the JSON at once [as of now]
-        #2: [stream] stream and parse JSON progressively [not yet supported]
+	The Abstract Loader has two modes:
+		#1: [static] load all the JSON at once [as of now]
+		#2: [stream] stream and parse JSON progressively [not yet supported]
 
-    Whatever is the mechanism used to parse the JSON (#1 or #2),
-    The loader starts by resolving the paths to binaries and referenced json files (by replace the value of the path property with an absolute path if it was relative).
+	Whatever is the mechanism used to parse the JSON (#1 or #2),
+	The loader starts by resolving the paths to binaries and referenced json files (by replace the value of the path property with an absolute path if it was relative).
 
-    In case #1: it is guaranteed to call the concrete loader implementation methods in a order that solves the dependencies between the entries.
-    only the nodes requires an extra pass to set up the hirerarchy.
-    In case #2: the concrete implementation will have to solve the dependencies. no order is guaranteed.
+	In case #1: it is guaranteed to call the concrete loader implementation methods in a order that solves the dependencies between the entries.
+	only the nodes requires an extra pass to set up the hirerarchy.
+	In case #2: the concrete implementation will have to solve the dependencies. no order is guaranteed.
 
-    When case #1 is used the followed dependency order is:
+	When case #1 is used the followed dependency order is:
 
-    scenes -> nodes -> meshes -> materials -> techniques -> shaders
-                    -> buffers
-                    -> cameras
-                    -> lights
+	scenes -> nodes -> meshes -> materials -> techniques -> shaders
+					-> buffers
+					-> cameras
+					-> lights
 
-    The readers starts with the leafs, i.e:
-        shaders, techniques, materials, meshes, buffers, cameras, lights, nodes, scenes
+	The readers starts with the leafs, i.e:
+		shaders, techniques, materials, meshes, buffers, cameras, lights, nodes, scenes
 
-    For each called handle method called the client should return true if the next handle can be call right after returning,
-    or false if a callback on client side will notify the loader that the next handle method can be called.
+	For each called handle method called the client should return true if the next handle can be call right after returning,
+	or false if a callback on client side will notify the loader that the next handle method can be called.
 
 */
 var global = window;
 (function (root, factory) {
 	if (typeof exports === 'object') {
-        // Node. Does not work with strict CommonJS, but
-        // only CommonJS-like enviroments that support module.exports,
-        // like Node.
+		// Node. Does not work with strict CommonJS, but
+		// only CommonJS-like enviroments that support module.exports,
+		// like Node.
 		factory(module.exports);
 	} else if (typeof define === 'function' && define.amd) {
-        // AMD. Register as an anonymous module.
+		// AMD. Register as an anonymous module.
 		define([], function () {
 			return factory(root);
 		});
 	} else {
-        // Browser globals
+		// Browser globals
 		factory(root);
 	}
 }(this, function (root) {
 	"use strict";
 
-	var categoriesDepsOrder = [ "buffers", "bufferViews", "images",  "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "scenes", "animations" ];
+	var categoriesDepsOrder = ["extensions", "buffers", "bufferViews", "images",  "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "animations", "scenes"];
 
 	var glTFParser = Object.create(Object.prototype, {
 
-        _rootDescription: { value: null, writable: true },
+		_rootDescription: { value: null, writable: true },
 
-        rootDescription: {
-            set: function(value) {
-	this._rootDescription = value;
-            },
-            get: function() {
-	return this._rootDescription;
-            }
-        },
-
-        baseURL: { value: null, writable: true },
+		rootDescription: {
+			set: function(value) {
+				this._rootDescription = value;
+			},
+			get: function() {
+				return this._rootDescription;
+			}
+		},
 
-        //detect absolute path following the same protocol than window.location
-        _isAbsolutePath: {
-            value: function(path) {
-	var isAbsolutePathRegExp = new RegExp("^" + window.location.protocol, "i");
+		baseURL: { value: null, writable: true },
 
-	return path.match(isAbsolutePathRegExp) ? true : false;
-            }
-        },
+		//detect absolute path following the same protocol than window.location
+		_isAbsolutePath: {
+			value: function(path) {
+				var isAbsolutePathRegExp = new RegExp("^"+window.location.protocol, "i");
 
-        resolvePathIfNeeded: {
-            value: function(path) {
-	if (this._isAbsolutePath(path)) {
-		return path;
-	}
+				return path.match(isAbsolutePathRegExp) ? true : false;
+			}
+		},
 
-	return this.baseURL + path;
-            }
-        },
-
-        _resolvePathsForCategories: {
-            value: function(categories) {
-	categories.forEach( function(category) {
-		var descriptions = this.json[category];
-		if (descriptions) {
-			var descriptionKeys = Object.keys(descriptions);
-			descriptionKeys.forEach( function(descriptionKey) {
-				var description = descriptions[descriptionKey];
-				description.path = this.resolvePathIfNeeded(description.path);
-			}, this);
-		}
-	}, this);
-            }
-        },
-
-        _json: {
-            value: null,
-            writable: true
-        },
-
-        json: {
-            enumerable: true,
-            get: function() {
-	return this._json;
-            },
-            set: function(value) {
-	if (this._json !== value) {
-		this._json = value;
-		this._resolvePathsForCategories([ "buffers", "shaders", "images", "videos" ]);
-	}
-            }
-        },
-
-        _path: {
-            value: null,
-            writable: true
-        },
-
-        getEntryDescription: {
-            value: function (entryID, entryType) {
-	var entries = null;
-
-	var category = entryType;
-	entries = this.rootDescription[category];
-	if (!entries) {
-		console.log("ERROR:CANNOT find expected category named:" + category);
-		return null;
-	}
+		resolvePathIfNeeded: {
+			value: function(path) {
+				if (this._isAbsolutePath(path)) {
+					return path;
+				}
 
-	return entries ? entries[entryID] : null;
-            }
-        },
+				var isDataUriRegex = /^data:/;
+				if (isDataUriRegex.test(path)) {
+					return path;
+				}
+				
+				return this.baseURL + path;
+			}
+		},
+
+		_resolvePathsForCategories: {
+			value: function(categories) {
+				categories.forEach( function(category) {
+					var descriptions = this.json[category];
+					if (descriptions) {
+						var descriptionKeys = Object.keys(descriptions);
+						descriptionKeys.forEach( function(descriptionKey) {
+							var description = descriptions[descriptionKey];
+							description.uri = this.resolvePathIfNeeded(description.uri);
+						}, this);
+					}
+				}, this);
+			}
+		},
+
+		_json: {
+			value: null,
+			writable: true
+		},
+
+		json: {
+			enumerable: true,
+			get: function() {
+				return this._json;
+			},
+			set: function(value) {
+				if (this._json !== value) {
+					this._json = value;
+					this._resolvePathsForCategories(["buffers", "shaders", "images", "videos"]);
+				}
+			}
+		},
+
+		_path: {
+			value: null,
+			writable: true
+		},
+
+		getEntryDescription: {
+			value: function (entryID, entryType) {
+				var entries = null;
+
+				var category = entryType;
+				entries = this.rootDescription[category];
+				if (!entries) {
+					console.log("ERROR:CANNOT find expected category named:"+category);
+					return null;
+				}
 
-        _stepToNextCategory: {
-            value: function() {
-	this._state.categoryIndex = this.getNextCategoryIndex(this._state.categoryIndex + 1);
-	if (this._state.categoryIndex !== -1) {
-		this._state.categoryState.index = 0;
-		return true;
-	}
+				return entries ? entries[entryID] : null;
+			}
+		},
+
+		_stepToNextCategory: {
+			value: function() {
+				this._state.categoryIndex = this.getNextCategoryIndex(this._state.categoryIndex + 1);
+				if (this._state.categoryIndex !== -1) {
+					this._state.categoryState.index = 0;
+					return true;
+				}
 
-	return false;
-            }
-        },
-
-        _stepToNextDescription: {
-            enumerable: false,
-            value: function() {
-	var categoryState = this._state.categoryState;
-	var keys = categoryState.keys;
-	if (!keys) {
-		console.log("INCONSISTENCY ERROR");
-		return false;
-	}
+				return false;
+			}
+		},
+
+		_stepToNextDescription: {
+			enumerable: false,
+			value: function() {
+				var categoryState = this._state.categoryState;
+				var keys = categoryState.keys;
+				if (!keys) {
+					console.log("INCONSISTENCY ERROR");
+					return false;
+				}
 
-	categoryState.index ++;
-	categoryState.keys = null;
-	if (categoryState.index >= keys.length) {
-		return this._stepToNextCategory();
-	}
-	return false;
-            }
-        },
-
-        hasCategory: {
-            value: function(category) {
-	return this.rootDescription[category] ? true : false;
-            }
-        },
-
-        _handleState: {
-            value: function() {
-
-	var methodForType = {
-                    "buffers" : this.handleBuffer,
-                    "bufferViews" : this.handleBufferView,
-                    "shaders" : this.handleShader,
-                    "programs" : this.handleProgram,
-                    "techniques" : this.handleTechnique,
-                    "materials" : this.handleMaterial,
-                    "meshes" : this.handleMesh,
-                    "cameras" : this.handleCamera,
-                    "lights" : this.handleLight,
-                    "nodes" : this.handleNode,
-                    "scenes" : this.handleScene,
-                    "images" : this.handleImage,
-                    "animations" : this.handleAnimation,
-                    "accessors" : this.handleAccessor,
-                    "skins" : this.handleSkin,
-                    "samplers" : this.handleSampler,
-                    "textures" : this.handleTexture,
-                    "videos" : this.handleVideo
-
-                };
-
-	var success = true;
-	while (this._state.categoryIndex !== -1) {
-		var category = categoriesDepsOrder[this._state.categoryIndex];
-		var categoryState = this._state.categoryState;
-		var keys = categoryState.keys;
-		if (!keys) {
-			categoryState.keys = keys = Object.keys(this.rootDescription[category]);
-			if (keys) {
-				if (keys.length == 0) {
-					this._stepToNextDescription();
-					continue;
+				categoryState.index++;
+				categoryState.keys = null;
+				if (categoryState.index >= keys.length) {
+					return this._stepToNextCategory();
 				}
+				return false;
 			}
-		}
+		},
 
-		var type = category;
-		var entryID = keys[categoryState.index];
-		var description = this.getEntryDescription(entryID, type);
-		if (!description) {
-			if (this.handleError) {
-				this.handleError("INCONSISTENCY ERROR: no description found for entry " + entryID);
-				success = false;
-				break;
+		hasCategory: {
+			value: function(category) {
+				return this.rootDescription[category] ? true : false;
 			}
-		} else {
+		},
+
+		_handleState: {
+			value: function() {
+
+				var methodForType = {
+					"buffers" : this.handleBuffer,
+					"bufferViews" : this.handleBufferView,
+					"shaders" : this.handleShader,
+					"programs" : this.handleProgram,
+					"techniques" : this.handleTechnique,
+					"materials" : this.handleMaterial,
+					"meshes" : this.handleMesh,
+					"cameras" : this.handleCamera,
+					"lights" : this.handleLight,
+					"nodes" : this.handleNode,
+					"scenes" : this.handleScene,
+					"images" : this.handleImage,
+					"animations" : this.handleAnimation,
+					"accessors" : this.handleAccessor,
+					"skins" : this.handleSkin,
+					"samplers" : this.handleSampler,
+					"textures" : this.handleTexture,
+					"videos" : this.handleVideo,
+					"extensions" : this.handleExtension,
+
+				};
+
+				var success = true;
+				while (this._state.categoryIndex !== -1) {
+					var category = categoriesDepsOrder[this._state.categoryIndex];
+					var categoryState = this._state.categoryState;
+					var keys = categoryState.keys;
+					if (!keys) {
+						categoryState.keys = keys = Object.keys(this.rootDescription[category]);
+						if (keys) {
+							if (keys.length == 0) {
+								this._stepToNextDescription();
+								continue;
+							}
+						}
+					}
+
+					var type = category;
+					var entryID = keys[categoryState.index];
+					var description = this.getEntryDescription(entryID, type);
+					if (!description) {
+						if (this.handleError) {
+							this.handleError("INCONSISTENCY ERROR: no description found for entry "+entryID);
+							success = false;
+							break;
+						}
+					} else {
+
+						if (methodForType[type]) {
+							if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
+								success = false;
+								break;
+							}
+						}
+
+						this._stepToNextDescription();
+					}
+				}
 
-			if (methodForType[type]) {
-				if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
-					success = false;
-					break;
+				if (this.handleLoadCompleted) {
+					this.handleLoadCompleted(success);
 				}
-			}
 
-			this._stepToNextDescription();
-		}
-	}
+			}
+		},
+
+		_loadJSONIfNeeded: {
+			enumerable: true,
+			value: function(callback) {
+				var self = this;
+				//FIXME: handle error
+				if (!this._json)  {
+					var jsonPath = this._path;
+					var i = jsonPath.lastIndexOf("/");
+					this.baseURL = (i !== 0) ? jsonPath.substring(0, i + 1) : '';
+					var jsonfile = new XMLHttpRequest();
+					jsonfile.open("GET", jsonPath, true);
+					jsonfile.onreadystatechange = function() {
+						if (jsonfile.readyState == 4) {
+							if (jsonfile.status == 200) {
+								self.json = JSON.parse(jsonfile.responseText);
+								if (callback) {
+									callback(self.json);
+								}
+							}
+						}
+					};
+					jsonfile.send(null);
+			   } else {
+					if (callback) {
+						callback(this.json);
+					}
+				}
+			}
+		},
+
+		/* load JSON and assign it as description to the reader */
+		_buildLoader: {
+			value: function(callback) {
+				var self = this;
+				function JSONReady(json) {
+					self.rootDescription = json;
+					if (callback)
+						callback(this);
+				}
 
-	if (this.handleLoadCompleted) {
-		this.handleLoadCompleted(success);
-	}
+				this._loadJSONIfNeeded(JSONReady);
+			}
+		},
+
+		_state: { value: null, writable: true },
+
+		_getEntryType: {
+			value: function(entryID) {
+				var rootKeys = categoriesDepsOrder;
+				for (var i = 0 ;  i < rootKeys.length ; i++) {
+					var rootValues = this.rootDescription[rootKeys[i]];
+					if (rootValues) {
+						return rootKeys[i];
+					}
+				}
+				return null;
+			}
+		},
+
+		getNextCategoryIndex: {
+			value: function(currentIndex) {
+				for (var i = currentIndex ; i < categoriesDepsOrder.length ; i++) {
+					if (this.hasCategory(categoriesDepsOrder[i])) {
+						return i;
+					}
+				}
 
-            }
-        },
-
-        _loadJSONIfNeeded: {
-            enumerable: true,
-            value: function(callback) {
-	var self = this;
-                //FIXME: handle error
-	if (!this._json) {
-		var jsonPath = this._path;
-		var i = jsonPath.lastIndexOf("/");
-		this.baseURL = (i !== 0) ? jsonPath.substring(0, i + 1) : '';
-		var jsonfile = new XMLHttpRequest();
-		jsonfile.open("GET", jsonPath, true);
-		jsonfile.addEventListener( 'load', function ( event ) {
-			self.json = JSON.parse(jsonfile.responseText);
-			if (callback) {
-				callback(self.json);
+				return -1;
 			}
-		}, false );
-		jsonfile.send(null);
-	} else {
-		if (callback) {
-			callback(this.json);
-		}
-	}
-            }
-        },
-
-        /* load JSON and assign it as description to the reader */
-        _buildLoader: {
-            value: function(callback) {
-	var self = this;
-	function JSONReady(json) {
-		self.rootDescription = json;
-		if (callback)
-                        callback(this);
-	}
+		},
+
+		load: {
+			enumerable: true,
+			value: function(userInfo, options) {
+				var self = this;
+				this._buildLoader(function loaderReady(reader) {
+					var startCategory = self.getNextCategoryIndex.call(self,0);
+					if (startCategory !== -1) {
+						self._state = { "userInfo" : userInfo,
+										"options" : options,
+										"categoryIndex" : startCategory,
+										"categoryState" : { "index" : "0" } };
+						self._handleState();
+					}
+				});
+			}
+		},
 
-	this._loadJSONIfNeeded(JSONReady);
-            }
-        },
+		initWithPath: {
+			value: function(path) {
+				this._path = path;
+				this._json = null;
+				return this;
+			}
+		},
 
-        _state: { value: null, writable: true },
+		//this is meant to be global and common for all instances
+		_knownURLs: { writable: true, value: {} },
 
-        _getEntryType: {
-            value: function(entryID) {
-	var rootKeys = categoriesDepsOrder;
-	for (var i = 0 ; i < rootKeys.length ; i ++) {
-		var rootValues = this.rootDescription[rootKeys[i]];
-		if (rootValues) {
-			return rootKeys[i];
-		}
-	}
-	return null;
-            }
-        },
-
-        getNextCategoryIndex: {
-            value: function(currentIndex) {
-	for (var i = currentIndex ; i < categoriesDepsOrder.length ; i ++) {
-		if (this.hasCategory(categoriesDepsOrder[i])) {
-			return i;
+		//to be invoked by subclass, so that ids can be ensured to not overlap
+		loaderContext: {
+			value: function() {
+				if (typeof this._knownURLs[this._path] === "undefined") {
+					this._knownURLs[this._path] = Object.keys(this._knownURLs).length;
+				}
+				return "__" + this._knownURLs[this._path];
+			}
+		},
+
+		initWithJSON: {
+			value: function(json, baseURL) {
+				this.json = json;
+				this.baseURL = baseURL;
+				if (!baseURL) {
+					console.log("WARNING: no base URL passed to Reader:initWithJSON");
+				}
+				return this;
+			}
 		}
-	}
 
-	return -1;
-            }
-        },
-
-        load: {
-            enumerable: true,
-            value: function(userInfo, options) {
-	var self = this;
-	this._buildLoader(function loaderReady(reader) {
-		var startCategory = self.getNextCategoryIndex.call(self, 0);
-		if (startCategory !== -1) {
-			self._state = { "userInfo" : userInfo,
-                                        "options" : options,
-                                        "categoryIndex" : startCategory,
-                                        "categoryState" : { "index" : "0" } };
-			self._handleState();
-		}
 	});
-            }
-        },
-
-        initWithPath: {
-            value: function(path) {
-	this._path = path;
-	this._json = null;
-	return this;
-            }
-        },
-
-        //this is meant to be global and common for all instances
-        _knownURLs: { writable: true, value: {} },
-
-        //to be invoked by subclass, so that ids can be ensured to not overlap
-        loaderContext: {
-            value: function() {
-	if (typeof this._knownURLs[this._path] === "undefined") {
-		this._knownURLs[this._path] = Object.keys(this._knownURLs).length;
-	}
-	return "__" + this._knownURLs[this._path];
-            }
-        },
-
-        initWithJSON: {
-            value: function(json, baseURL) {
-	this.json = json;
-	this.baseURL = baseURL;
-	if (!baseURL) {
-		console.log("WARNING: no base URL passed to Reader:initWithJSON");
-	}
-	return this;
-            }
-        }
-
-    });
 
-	if (root) {
+	if(root) {
 		root.glTFParser = glTFParser;
 	}
 

+ 13 - 13
examples/js/loaders/gltf/glTFAnimation.js

@@ -24,7 +24,7 @@ THREE.glTFAnimator = ( function () {
 
 		update : function()
 		{
-			for (i = 0; i < animators.length; i ++)
+			for (i = 0; i < animators.length; i++)
 			{
 				animators[i].update();
 			}
@@ -45,18 +45,18 @@ THREE.glTFAnimation = function(interps)
 	{
 		this.createInterpolators(interps);
 	}
-};
+}
 
 THREE.glTFAnimation.prototype.createInterpolators = function(interps)
 {
 	var i, len = interps.length;
-	for (i = 0; i < len; i ++)
+	for (i = 0; i < len; i++)
 	{
 		var interp = new THREE.glTFInterpolator(interps[i]);
 		this.interps.push(interp);
 		this.duration = Math.max(this.duration, interp.duration);
 	}
-};
+}
 
 // Start/stop
 THREE.glTFAnimation.prototype.play = function()
@@ -67,13 +67,13 @@ THREE.glTFAnimation.prototype.play = function()
 	this.startTime = Date.now();
 	this.running = true;
 	THREE.glTFAnimator.add(this);
-};
+}
 
 THREE.glTFAnimation.prototype.stop = function()
 {
 	this.running = false;
 	THREE.glTFAnimator.remove(this);
-};
+}
 
 // Update - drive key frame evaluation
 THREE.glTFAnimation.prototype.update = function()
@@ -90,7 +90,7 @@ THREE.glTFAnimation.prototype.update = function()
 	{
 		this.running = false;
 		var i, len = this.interps.length;
-		for (i = 0; i < len; i ++)
+		for (i = 0; i < len; i++)
 		{
 			this.interps[i].interp(this.duration);
 		}
@@ -100,12 +100,12 @@ THREE.glTFAnimation.prototype.update = function()
 	else
 	{
 		var i, len = this.interps.length;
-		for (i = 0; i < len; i ++)
+		for (i = 0; i < len; i++)
 		{
 			this.interps[i].interp(t);
 		}
 	}
-};
+}
 
 //Interpolator class
 //Construction/initialization
@@ -147,7 +147,7 @@ THREE.glTFInterpolator = function(param)
 	this.quat1 = new THREE.Quaternion;
 	this.quat2 = new THREE.Quaternion;
 	this.quat3 = new THREE.Quaternion;
-};
+}
 
 //Interpolation and tweening methods
 THREE.glTFInterpolator.prototype.interp = function(t)
@@ -202,7 +202,7 @@ THREE.glTFInterpolator.prototype.interp = function(t)
 	}
 	else
 	{
-		for (i = 0; i < this.count - 1; i ++)
+		for (i = 0; i < this.count - 1; i++)
 		{
 			var key1 = this.keys[i];
 			var key2 = this.keys[i + 1];
@@ -238,7 +238,7 @@ THREE.glTFInterpolator.prototype.interp = function(t)
 	{
 		this.copyValue(this.target);
 	}
-};
+}
 
 THREE.glTFInterpolator.prototype.copyValue = function(target) {
 	
@@ -248,4 +248,4 @@ THREE.glTFInterpolator.prototype.copyValue = function(target) {
 	else {
 		target.copy(this.vec3);
 	}		
-};
+}

File diff suppressed because it is too large
+ 1466 - 1103
examples/js/loaders/gltf/glTFLoader.js


+ 185 - 106
examples/js/loaders/gltf/glTFLoaderUtils.js

@@ -26,8 +26,8 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
         value: function() {
 	        this._streams = {};
 	        this._streamsStatus = {};
-	this._resources = {};
-	this._resourcesStatus = {};
+            this._resources = {};
+            this._resourcesStatus = {};
         }
     },
 
@@ -35,60 +35,119 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
     _containsResource: {
         enumerable: false,
         value: function(resourceID) {
-	return this._resources[resourceID] ? true : false;
+            return this._resources[resourceID] ? true : false;
         }
     },
 
     _storeResource: {
         enumerable: false,
         value: function(resourceID, resource) {
-	if (!resourceID) {
-		console.log("ERROR: entry does not contain id, cannot store");
-		return;
-	}
+            if (!resourceID) {
+                console.log("ERROR: entry does not contain id, cannot store");
+                return;
+            }
 
-	if (this._containsResource[resourceID]) {
-		console.log("WARNING: resource:" + resourceID + " is already stored, overriding");
-	}
+            if (this._containsResource[resourceID]) {
+                console.log("WARNING: resource:"+resourceID+" is already stored, overriding");
+            }
 
-	this._resources[resourceID] = resource;
+           this._resources[resourceID] = resource;
         }
     },
 
     _getResource: {
         enumerable: false,
         value: function(resourceID) {
-	return this._resources[resourceID];
+            return this._resources[resourceID];
         }
     },
 
     _loadStream: {
         value: function(path, type, delegate) {
-	var self = this;
 
-	if (!type) {
-		delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE, null);
-		return;
-	}
 
-	if (!path) {
-		delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH);
-		return;
-	}
 
-	var xhr = new XMLHttpRequest();
-	xhr.open('GET', path, true);
-	xhr.responseType = (type === this.ARRAY_BUFFER) ? "arraybuffer" : "text";
+            var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
+
+            function decodeDataUriText(isBase64, data) {
+                var result = decodeURIComponent(data);
+                if (isBase64) {
+                    return atob(result);
+                }
+                return result;
+            }
+
+            function decodeDataUriArrayBuffer(isBase64, data) {
+                var byteString = decodeDataUriText(isBase64, data);
+                var buffer = new ArrayBuffer(byteString.length);
+                var view = new Uint8Array(buffer);
+                for (var i = 0; i < byteString.length; i++) {
+                    view[i] = byteString.charCodeAt(i);
+                }
+                return buffer;
+            }
+
+            function decodeDataUri(dataUriRegexResult, responseType) {
+                responseType = typeof responseType !== 'undefined' ? responseType : '';
+                var mimeType = dataUriRegexResult[1];
+                var isBase64 = !!dataUriRegexResult[2];
+                var data = dataUriRegexResult[3];
+
+                switch (responseType) {
+                case '':
+                case 'text':
+                    return decodeDataUriText(isBase64, data);
+                case 'ArrayBuffer':
+                    return decodeDataUriArrayBuffer(isBase64, data);
+                case 'blob':
+                    var buffer = decodeDataUriArrayBuffer(isBase64, data);
+                    return new Blob([buffer], {
+                        type : mimeType
+                    });
+                case 'document':
+                    var parser = new DOMParser();
+                    return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
+                case 'json':
+                    return JSON.parse(decodeDataUriText(isBase64, data));
+                default:
+                    throw 'Unhandled responseType: ' + responseType;
+                }
+            }
+
+            var dataUriRegexResult = dataUriRegex.exec(path);
+            if (dataUriRegexResult !== null) {
+                delegate.streamAvailable(path, decodeDataUri(dataUriRegexResult, type));
+                return;
+            }
+
+            var self = this;
+
+            if (!type) {
+                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE, null);
+                return;
+            }
+
+            if (!path) {
+                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH);
+                return;
+            }
+
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', path, true);
+            xhr.responseType = (type === this.ARRAY_BUFFER) ? "arraybuffer" : "text";
 
             //if this is not specified, 1 "big blob" scenes fails to load.
-	xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
-	xhr.addEventListener( 'load', function ( event ) {
-		delegate.streamAvailable(path, xhr.response);
-	}, false );
-	xhr.addEventListener( 'error', function ( event ) {
-		delegate.handleError(THREE.GLTFLoaderUtils.XMLHTTPREQUEST_STATUS_ERROR, xhr.status);
-	}, false );
-	xhr.send(null);
+            xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
+            xhr.onload = function(e) {
+                if ((xhr.status == 200) || (xhr.status == 206)) {
+
+                    delegate.streamAvailable(path, xhr.response);
+
+                } else {
+                    delegate.handleError(THREE.GLTFLoaderUtils.XMLHTTPREQUEST_STATUS_ERROR, this.status);
+                }
+            };
+            xhr.send(null);
         }
     },
 
@@ -97,89 +156,109 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
 
     _handleRequest: {
         value: function(request) {
-	var resourceStatus = this._resourcesStatus[request.id];
-	if (resourceStatus)
+            var resourceStatus = this._resourcesStatus[request.id];
+            if (resourceStatus)
             {
-		this._resourcesStatus[request.id] ++;
-	}
+            	this._resourcesStatus[request.id]++;
+            }
             else
-	{
-		this._resourcesStatus[request.id] = 1;
-	}
+            {
+            	this._resourcesStatus[request.id] = 1;
+            }
             
-	var streamStatus = this._streamsStatus[request.path];
-	if (streamStatus && streamStatus.status === "loading" )
+            var streamStatus = this._streamsStatus[request.uri];
+            if (streamStatus && streamStatus.status === "loading" )
             {
-		streamStatus.requests.push(request);
-		return;
-	}
+            	streamStatus.requests.push(request);
+                return;
+            }
             
-	this._streamsStatus[request.path] = { status : "loading", requests : [ request ] };
+            this._streamsStatus[request.uri] = { status : "loading", requests : [request] };
     		
-	var self = this;
-	var processResourceDelegate = {};
-
-	processResourceDelegate.streamAvailable = function(path, res_) {
-		var streamStatus = self._streamsStatus[path];
-		var requests = streamStatus.requests;
-		requests.forEach( function(req_) {
-			var subArray = res_.slice(req_.range[0], req_.range[1]);
-			var convertedResource = req_.delegate.convert(subArray, req_.ctx);
-			self._storeResource(req_.id, convertedResource);
-			req_.delegate.resourceAvailable(convertedResource, req_.ctx);
-			-- self._resourcesStatus[req_.id];
-
-		}, this);
+            var self = this;
+            var processResourceDelegate = {};
+
+            processResourceDelegate.streamAvailable = function(path, res_) {
+            	var streamStatus = self._streamsStatus[path];
+            	var requests = streamStatus.requests;
+                requests.forEach( function(req_) {
+                    var subArray = res_.slice(req_.range[0], req_.range[1]);
+                    var convertedResource = req_.delegate.convert(subArray, req_.ctx);
+                    self._storeResource(req_.id, convertedResource);
+                    req_.delegate.resourceAvailable(convertedResource, req_.ctx);
+                    --self._resourcesStatus[req_.id];
+
+                }, this);
             	
-		delete self._streamsStatus[path];
+                delete self._streamsStatus[path];
 
-	};
+            };
 
-	processResourceDelegate.handleError = function(errorCode, info) {
-		request.delegate.handleError(errorCode, info);
-	};
+            processResourceDelegate.handleError = function(errorCode, info) {
+                request.delegate.handleError(errorCode, info);
+            }
 
-	this._loadStream(request.path, request.type, processResourceDelegate);
+            this._loadStream(request.uri, request.type, processResourceDelegate);
         }
     },
 
 
     _elementSizeForGLType: {
-        value: function(glType) {
-	switch (glType) {
-		case WebGLRenderingContext.FLOAT :
-			return Float32Array.BYTES_PER_ELEMENT;
-		case WebGLRenderingContext.UNSIGNED_BYTE :
-			return Uint8Array.BYTES_PER_ELEMENT;
-		case WebGLRenderingContext.UNSIGNED_SHORT :
-			return Uint16Array.BYTES_PER_ELEMENT;
-		case WebGLRenderingContext.FLOAT_VEC2 :
-			return Float32Array.BYTES_PER_ELEMENT * 2;
-		case WebGLRenderingContext.FLOAT_VEC3 :
-			return Float32Array.BYTES_PER_ELEMENT * 3;
-		case WebGLRenderingContext.FLOAT_VEC4 :
-			return Float32Array.BYTES_PER_ELEMENT * 4;
-		case WebGLRenderingContext.FLOAT_MAT3 :
-			return Float32Array.BYTES_PER_ELEMENT * 9;
-		case WebGLRenderingContext.FLOAT_MAT4 :
-			return Float32Array.BYTES_PER_ELEMENT * 16;
-		default:
-			return null;
-	}
+        value: function(componentType, type) {
+    	
+    		var nElements = 0;
+    		switch(type) {    		
+	            case "SCALAR" :
+	                nElements = 1;
+	                break;
+	            case "VEC2" :
+	                nElements = 2;
+	                break;
+	            case "VEC3" :
+	                nElements = 3;
+	                break;
+	            case "VEC4" :
+	                nElements = 4;
+	                break;
+	            case "MAT2" :
+	                nElements = 4;
+	                break;
+	            case "MAT3" :
+	                nElements = 9;
+	                break;
+	            case "MAT4" :
+	                nElements = 16;
+	                break;
+	            default :
+	            	debugger;
+	            	break;
+    		}
+    		
+            switch (componentType) {
+                case WebGLRenderingContext.FLOAT :
+                    return Float32Array.BYTES_PER_ELEMENT * nElements;
+                case WebGLRenderingContext.UNSIGNED_BYTE :
+                    return Uint8Array.BYTES_PER_ELEMENT * nElements;
+                case WebGLRenderingContext.UNSIGNED_SHORT :
+                    return Uint16Array.BYTES_PER_ELEMENT * nElements;
+                default :
+                	debugger;
+                    return null;
+            }
         }
     },
 
     _handleWrappedBufferViewResourceLoading: {
         value: function(wrappedBufferView, delegate, ctx) {
-	var bufferView = wrappedBufferView.bufferView;
-	var buffer = bufferView.buffer;
-	var byteOffset = wrappedBufferView.byteOffset + bufferView.description.byteOffset;
-	var range = [ byteOffset, (this._elementSizeForGLType(wrappedBufferView.type) * wrappedBufferView.count) + byteOffset ];
+            var bufferView = wrappedBufferView.bufferView;
+            var buffer = bufferView.buffer;
+            var byteOffset = wrappedBufferView.byteOffset + bufferView.description.byteOffset;
+            var range = [byteOffset , (this._elementSizeForGLType(wrappedBufferView.componentType, wrappedBufferView.type) * wrappedBufferView.count) + byteOffset];
 
-	this._handleRequest({ "id" : wrappedBufferView.id,
+            this._handleRequest({   "id" : wrappedBufferView.id,
                                     "range" : range,
                                     "type" : buffer.description.type,
-                                    "path" : buffer.description.path,
+                                    "uri" : buffer.description.uri,
                                     "delegate" : delegate,
                                     "ctx" : ctx }, null);
         }
@@ -189,14 +268,14 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
     	
             value: function(wrappedBufferView, delegate, ctx) {
 
-	var savedBuffer = this._getResource(wrappedBufferView.id);
-	if (savedBuffer) {
-		return savedBuffer;
-	} else {
-		this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
-	}
+            var savedBuffer = this._getResource(wrappedBufferView.id);
+            if (false) { // savedBuffer) {
+                return savedBuffer;
+            } else {
+                this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
+            }
 
-	return null;
+            return null;
         }
     },
 
@@ -204,17 +283,17 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
     	
         value: function(request, delegate, ctx) {
 
-	request.delegate = delegate;
-	request.ctx = ctx;
+    		request.delegate = delegate;
+    		request.ctx = ctx;
 
-	this._handleRequest({ "id" : request.id,
-                "path" : request.path,
-                "range" : [ 0 ],
+            this._handleRequest({   "id" : request.id,
+                "uri" : request.uri,
+                "range" : [0],
                 "type" : "text",
                 "delegate" : delegate,
                 "ctx" : ctx }, null);
     	
-	return null;
-}
+            return null;
+	    }
 	},    
 });

+ 145 - 0
examples/js/loaders/gltf/glTFShaders.js

@@ -0,0 +1,145 @@
+/**
+ * @author Tony Parisi / http://www.tonyparisi.com/
+ */
+
+THREE.glTFShaders = ( function () {
+
+	var shaders = [];
+
+	return	{
+		add : function(shader) {
+			shaders.push(shader);
+		},
+
+		remove: function(shader) {
+
+			var i = shaders.indexOf(shader);
+
+			if ( i !== -1 ) {
+				shaders.splice( i, 1 );
+			}
+		},
+
+		removeAll: function(shader) {
+
+			// probably want to clean up the shaders, too, but not for now
+			shaders = [];
+		},
+
+		bindShaderParameters: function(scene) {
+			for (i = 0; i < shaders.length; i++)
+			{
+				shaders[i].bindParameters(scene);
+			}
+		},
+
+		update : function(scene, camera) {
+			for (i = 0; i < shaders.length; i++)
+			{
+				shaders[i].update(scene, camera);
+			}
+		},
+	};
+})();
+
+// Construction/initialization
+THREE.glTFShader = function(material, params, object, scene) {
+	this.material = material;
+	this.parameters = params.technique.parameters;
+	this.uniforms = params.technique.uniforms;
+	this.joints = params.joints;
+	this.object = object;
+	this.semantics = {};
+	this.m4 = new THREE.Matrix4;
+}
+
+
+// bindParameters - connect the uniform values to their source parameters
+THREE.glTFShader.prototype.bindParameters = function(scene) {
+
+	function findObject(o, p) { 
+		if (o.glTFID == param.node) {
+			p.sourceObject = o;
+		}
+	}
+
+	for (var uniform in this.uniforms) {
+		var pname = this.uniforms[uniform];
+		var param = this.parameters[pname];
+		if (param.semantic) {
+
+			var p = { 
+				semantic : param.semantic,
+				uniform: this.material.uniforms[uniform] 
+			};
+
+			if (param.node) {
+				scene.traverse(function(o) { findObject(o, p)});
+			}
+			else {
+				p.sourceObject = this.object;
+			}			
+
+			this.semantics[pname] = p;
+
+		}
+	}
+
+}
+
+// Update - update all the uniform values
+THREE.glTFShader.prototype.update = function(scene, camera) {
+
+	// update scene graph
+
+	scene.updateMatrixWorld();
+
+	// update camera matrices and frustum
+	camera.updateMatrixWorld();
+	camera.matrixWorldInverse.getInverse( camera.matrixWorld );
+
+	for (var sname in this.semantics) {
+		var semantic = this.semantics[sname];
+        if (semantic) {
+	        switch (semantic.semantic) {
+	            case "MODELVIEW" :
+	            	var m4 = semantic.uniform.value;
+	            	m4.multiplyMatrices(camera.matrixWorldInverse, 
+	            		semantic.sourceObject.matrixWorld);
+	                break;
+
+	            case "MODELVIEWINVERSETRANSPOSE" :
+	            	var m3 = semantic.uniform.value;
+	            	this.m4.multiplyMatrices(camera.matrixWorldInverse, 
+	            		semantic.sourceObject.matrixWorld);
+					m3.getNormalMatrix(this.m4);
+	                break;
+
+	            case "PROJECTION" :
+	            	var m4 = semantic.uniform.value;
+	            	m4.copy(camera.projectionMatrix);            		
+	                break;
+
+	            case "JOINTMATRIX" :
+	            
+	            	var m4v = semantic.uniform.value;
+					for (var mi = 0; mi < m4v.length; mi++) {
+						// So it goes like this:
+						// SkinnedMesh world matrix is already baked into MODELVIEW;
+						// ransform joints to local space,
+						// then transform using joint's inverse
+						m4v[mi].getInverse(semantic.sourceObject.matrixWorld).
+							multiply(this.joints[mi].matrixWorld).
+							multiply(this.object.skeleton.boneInverses[mi]);
+					}
+	            
+	                //console.log("Joint:", semantic)
+	                break;
+
+	            default :
+	                throw new Error("Unhandled shader semantic" + semantic);
+	                break;
+	        }
+        }
+	}
+}

+ 204 - 0
examples/js/loaders/gltf/gltfUtilities.js

@@ -0,0 +1,204 @@
+/**
+gltfUtilities
+@license
+The MIT License (MIT)
+Copyright (c) 2014 Analytical Graphics, Inc.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+(function(root, factory) {
+    "use strict";
+    /*global define*/
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define([], factory);
+    } else {
+        // Browser globals
+        root.gltfUtilities = factory();
+    }
+}(this, function() {
+    "use strict";
+
+    /**
+     * Given a URL, determine whether that URL is considered cross-origin to the current page.
+     */
+    var isCrossOriginUrl = function(url) {
+        var location = window.location;
+        var a = document.createElement('a');
+
+        a.href = url;
+
+        // host includes both hostname and port if the port is not standard
+        return location.protocol !== a.protocol || location.host !== a.host;
+    };
+
+    var isDataUriRegex = /^data:/;
+
+    /**
+     * Asynchronously loads the given image URL.  Attempts to load cross-origin images using CORS.
+     *
+     * @param {String} url The source of the image.
+     * @param {Function} success A function that will be called with an Image object
+     *                           once the image has loaded successfully.
+     * @param {Function} [error] A function that will be called if the request fails.
+     *
+     * @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
+     */
+    var loadImage = function(url, success, error) {
+        var image = new Image();
+
+        image.onload = function() {
+            success(image);
+        };
+
+        if (typeof error !== 'undefined') {
+            image.onerror = error;
+        }
+
+        var crossOrigin;
+        if (isDataUriRegex.test(url)) {
+            crossOrigin = false;
+        } else {
+            crossOrigin = isCrossOriginUrl(url);
+        }
+
+        if (crossOrigin) {
+            image.crossOrigin = '';
+        }
+
+        image.src = url;
+    };
+
+    var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
+
+    function decodeDataUriText(isBase64, data) {
+        var result = decodeURIComponent(data);
+        if (isBase64) {
+            return atob(result);
+        }
+        return result;
+    }
+
+    function decodeDataUriArrayBuffer(isBase64, data) {
+        var byteString = decodeDataUriText(isBase64, data);
+        var buffer = new ArrayBuffer(byteString.length);
+        var view = new Uint8Array(buffer);
+        for (var i = 0; i < byteString.length; i++) {
+            view[i] = byteString.charCodeAt(i);
+        }
+        return buffer;
+    }
+
+    function decodeDataUri(dataUriRegexResult, responseType) {
+        responseType = typeof responseType !== 'undefined' ? responseType : '';
+        var mimeType = dataUriRegexResult[1];
+        var isBase64 = !!dataUriRegexResult[2];
+        var data = dataUriRegexResult[3];
+
+        switch (responseType) {
+        case '':
+        case 'text':
+            return decodeDataUriText(isBase64, data);
+        case 'arraybuffer':
+            return decodeDataUriArrayBuffer(isBase64, data);
+        case 'blob':
+            var buffer = decodeDataUriArrayBuffer(isBase64, data);
+            return new Blob([buffer], {
+                type : mimeType
+            });
+        case 'document':
+            var parser = new DOMParser();
+            return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType);
+        case 'json':
+            return JSON.parse(decodeDataUriText(isBase64, data));
+        default:
+            throw 'Unhandled responseType: ' + responseType;
+        }
+    }
+
+    var loadWithXhr = function(url, responseType, success, error) {
+        var dataUriRegexResult = dataUriRegex.exec(url);
+        if (dataUriRegexResult !== null) {
+            success(decodeDataUri(dataUriRegexResult, responseType));
+            return;
+        }
+
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+
+        if (typeof responseType !== 'undefined') {
+            xhr.responseType = responseType;
+        }
+
+        xhr.onload = function(e) {
+            if (xhr.status === 200) {
+                success(xhr.response);
+            } else {
+                error(xhr);
+            }
+        };
+
+        xhr.onerror = function(e) {
+            error(xhr);
+        };
+
+        xhr.send();
+    };
+
+    /**
+     * Asynchronously loads the given URL as raw binary data.  The data is loaded
+     * using XMLHttpRequest, which means that in order to make requests to another origin,
+     * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
+     *
+     * @param {String} url The URL of the binary data.
+     * @param {Function} success A function that will be called with an ArrayBuffer object
+     *                           once the data has loaded successfully.
+     * @param {Function} [error] A function that will be called with the XMLHttpRequest object
+     *                           if the request fails.
+     *
+     * @see <a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest</a>
+     * @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
+     */
+    var loadArrayBuffer = function(url, success, error) {
+        loadWithXhr(url, 'arraybuffer', success, error);
+    };
+
+    /**
+     * Asynchronously loads the given URL as text.  The data is loaded
+     * using XMLHttpRequest, which means that in order to make requests to another origin,
+     * the server must have Cross-Origin Resource Sharing (CORS) headers enabled.
+     *
+     * @param {String} url The URL to request.
+     * @param {Function} success A function that will be called with a String
+     *                           once the data has loaded successfully.
+     * @param {Function} [error] A function that will be called with the XMLHttpRequest object
+     *                           if the request fails.
+     *
+     * @see <a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest</a>
+     * @see <a href='http://www.w3.org/TR/cors/'>Cross-Origin Resource Sharing</a>
+     */
+    var loadText = function(url, success, error) {
+        return loadWithXhr(url, undefined, success, error);
+    };
+
+    return {
+        loadImage : loadImage,
+        loadArrayBuffer : loadArrayBuffer,
+        loadText : loadText
+    };
+}));
+
+

+ 1 - 2
examples/js/materials/ShadowMaterial.js

@@ -6,7 +6,6 @@ THREE.ShadowMaterial = function () {
 
 	THREE.ShaderMaterial.call( this, {
 		uniforms: THREE.UniformsUtils.merge( [
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ],
 			{
 				opacity:  { type: 'f', value: 1.0 }
@@ -29,7 +28,7 @@ THREE.ShadowMaterial = function () {
 			THREE.ShaderChunk[ "shadowmask_pars_fragment" ],
 			"uniform float opacity;",
 			"void main() {",
-			"	gl_FragColor = vec4( 0.0, 0.0, 0.0, opacity - getShadowMask() );",
+			"	gl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0  - getShadowMask() ) );",
 			"}"
 		].join( '\n' )
 	} );

+ 0 - 1
examples/js/modifiers/ExplodeModifier.js

@@ -38,6 +38,5 @@ THREE.ExplodeModifier.prototype.modify = function ( geometry ) {
 	}
 
 	geometry.vertices = vertices;
-	delete geometry.__tmpVertices;
 
 };

+ 387 - 350
examples/js/modifiers/SubdivisionModifier.js

@@ -1,350 +1,387 @@
-/*
- *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog 
- *
- *	Subdivision Geometry Modifier 
- *		using Loop Subdivision Scheme
- *
- *	References:
- *		http://graphics.stanford.edu/~mdfisher/subdivision.html
- *		http://www.holmes3d.net/graphics/subdivision/
- *		http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
- *
- *	Known Issues:
- *		- currently doesn't handle UVs
- *		- currently doesn't handle "Sharp Edges"
- *
- */
-
-THREE.SubdivisionModifier = function ( subdivisions ) {
-
-	this.subdivisions = ( subdivisions === undefined ) ? 1 : subdivisions;
-
-};
-
-// Applies the "modify" pattern
-THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
-
-	var repeats = this.subdivisions;
-
-	while ( repeats -- > 0 ) {
-
-		this.smooth( geometry );
-
-	}
-
-	delete geometry.__tmpVertices;
-
-	geometry.computeFaceNormals();
-	geometry.computeVertexNormals();
-
-};
-
-( function() {
-
-	// Some constants
-	var WARNINGS = ! true; // Set to true for development
-	var ABC = [ 'a', 'b', 'c' ];
-	
-
-	function getEdge( a, b, map ) {
-
-		var vertexIndexA = Math.min( a, b );
-		var vertexIndexB = Math.max( a, b );
-
-		var key = vertexIndexA + "_" + vertexIndexB;
-
-		return map[ key ];
-
-	}
-
-
-	function processEdge( a, b, vertices, map, face, metaVertices ) {
-
-		var vertexIndexA = Math.min( a, b );
-		var vertexIndexB = Math.max( a, b );
-
-		var key = vertexIndexA + "_" + vertexIndexB;
-
-		var edge;
-
-		if ( key in map ) {
-
-			edge = map[ key ];
-
-		} else {
-			
-			var vertexA = vertices[ vertexIndexA ];
-			var vertexB = vertices[ vertexIndexB ];
-
-			edge = {
-
-				a: vertexA, // pointer reference
-				b: vertexB,
-				newEdge: null,
-				// aIndex: a, // numbered reference
-				// bIndex: b,
-				faces: [] // pointers to face
-
-			};
-
-			map[ key ] = edge;
-
-		}
-
-		edge.faces.push( face );
-
-		metaVertices[ a ].edges.push( edge );
-		metaVertices[ b ].edges.push( edge );
-		
-
-	}
-
-	function generateLookups( vertices, faces, metaVertices, edges ) {
-
-		var i, il, face, edge;
-
-		for ( i = 0, il = vertices.length; i < il; i ++ ) {
-
-			metaVertices[ i ] = { edges: [] };
-
-		}
-		
-		for ( i = 0, il = faces.length; i < il; i ++ ) {
-
-			face = faces[ i ];
-
-			processEdge( face.a, face.b, vertices, edges, face, metaVertices );
-			processEdge( face.b, face.c, vertices, edges, face, metaVertices );
-			processEdge( face.c, face.a, vertices, edges, face, metaVertices );
-
-		}
-
-	}
-
-	function newFace( newFaces, a, b, c ) {
-
-		newFaces.push( new THREE.Face3( a, b, c ) );
-
-	}
-
-
-	/////////////////////////////
-
-	// Performs one iteration of Subdivision
-	THREE.SubdivisionModifier.prototype.smooth = function ( geometry ) {
-
-		var tmp = new THREE.Vector3();
-
-		var oldVertices, oldFaces;
-		var newVertices, newFaces; // newUVs = [];
-
-		var n, l, i, il, j, k;
-		var metaVertices, sourceEdges;
-
-		// new stuff.
-		var sourceEdges, newEdgeVertices, newSourceVertices;
-
-		oldVertices = geometry.vertices; // { x, y, z}
-		oldFaces = geometry.faces; // { a: oldVertex1, b: oldVertex2, c: oldVertex3 }
-
-		/******************************************************
-		 *
-		 * Step 0: Preprocess Geometry to Generate edges Lookup
-		 *
-		 *******************************************************/
-
-		metaVertices = new Array( oldVertices.length );
-		sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[]  }
-
-		generateLookups( oldVertices, oldFaces, metaVertices, sourceEdges );
-
-
-		/******************************************************
-		 *
-		 *	Step 1. 
-		 *	For each edge, create a new Edge Vertex,
-		 *	then position it.
-		 *
-		 *******************************************************/
-
-		newEdgeVertices = [];
-		var other, currentEdge, newEdge, face;
-		var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
-
-		for ( i in sourceEdges ) {
-
-			currentEdge = sourceEdges[ i ];
-			newEdge = new THREE.Vector3();
-
-			edgeVertexWeight = 3 / 8;
-			adjacentVertexWeight = 1 / 8;
-
-			connectedFaces = currentEdge.faces.length;
-
-			// check how many linked faces. 2 should be correct.
-			if ( connectedFaces != 2 ) {
-
-				// if length is not 2, handle condition
-				edgeVertexWeight = 0.5;
-				adjacentVertexWeight = 0;
-
-				if ( connectedFaces != 1 ) {
-					
-					if ( WARNINGS ) console.warn( 'Subdivision Modifier: Number of connected faces != 2, is: ', connectedFaces, currentEdge );
-			
-				}
-
-			}
-
-			newEdge.addVectors( currentEdge.a, currentEdge.b ).multiplyScalar( edgeVertexWeight );
-
-			tmp.set( 0, 0, 0 );
-
-			for ( j = 0; j < connectedFaces; j ++ ) {
-
-				face = currentEdge.faces[ j ];
-				
-				for ( k = 0; k < 3; k ++ ) {
-
-					other = oldVertices[ face[ ABC[ k ] ] ];
-					if ( other !== currentEdge.a && other !== currentEdge.b ) break;
-
-				}
-
-				tmp.add( other );
-
-			}
-
-			tmp.multiplyScalar( adjacentVertexWeight );
-			newEdge.add( tmp );
-
-			currentEdge.newEdge = newEdgeVertices.length;
-			newEdgeVertices.push( newEdge );
-
-			// console.log(currentEdge, newEdge);
-
-		}
-
-		/******************************************************
-		 *
-		 *	Step 2. 
-		 *	Reposition each source vertices.
-		 *
-		 *******************************************************/
-
-		var beta, sourceVertexWeight, connectingVertexWeight;
-		var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
-		newSourceVertices = [];
-
-		for ( i = 0, il = oldVertices.length; i < il; i ++ ) {
-
-			oldVertex = oldVertices[ i ];
-
-			// find all connecting edges (using lookupTable)
-			connectingEdges = metaVertices[ i ].edges;
-			n = connectingEdges.length;
-			beta;
-
-			if ( n == 3 ) {
-
-				beta = 3 / 16;
-
-			} else if ( n > 3 ) {
-
-				beta = 3 / ( 8 * n ); // Warren's modified formula
-
-			}
-
-			// Loop's original beta formula
-			// beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
-
-			sourceVertexWeight = 1 - n * beta;
-			connectingVertexWeight = beta;
-
-			if ( n <= 2 ) {
-				
-				// crease and boundary rules
-				// console.warn('crease and boundary rules');
-
-				if ( n == 2 ) {
-
-					if ( WARNINGS ) console.warn( '2 connecting edges', connectingEdges );
-					sourceVertexWeight = 3 / 4;
-					connectingVertexWeight = 1 / 8;
-
-					// sourceVertexWeight = 1;
-					// connectingVertexWeight = 0;
-
-				} else if ( n == 1 ) {
-
-					if ( WARNINGS ) console.warn( 'only 1 connecting edge' );
-
-				} else if ( n == 0 ) {
-
-					if ( WARNINGS ) console.warn( '0 connecting edges' );
-			
-				}
-			
-			}
-
-			newSourceVertex = oldVertex.clone().multiplyScalar( sourceVertexWeight );
-
-			tmp.set( 0, 0, 0 );
-
-			for ( j = 0; j < n; j ++ ) {
-
-				connectingEdge = connectingEdges[ j ];
-				other = connectingEdge.a !== oldVertex ? connectingEdge.a : connectingEdge.b;
-				tmp.add( other );
-
-			}
-
-			tmp.multiplyScalar( connectingVertexWeight );
-			newSourceVertex.add( tmp );
-			
-			newSourceVertices.push( newSourceVertex );
-
-		}
-
-							   
-		/******************************************************
-		 *
-		 *	Step 3. 
-		 *	Generate Faces between source vertecies
-		 *	and edge vertices.
-		 *
-		 *******************************************************/
-
-		newVertices = newSourceVertices.concat( newEdgeVertices );
-		var sl = newSourceVertices.length, edge1, edge2, edge3;
-		newFaces = [];
-
-		for ( i = 0, il = oldFaces.length; i < il; i ++ ) {
-
-			face = oldFaces[ i ];
-
-			// find the 3 new edges vertex of each old face
-
-			edge1 = getEdge( face.a, face.b, sourceEdges ).newEdge + sl;
-			edge2 = getEdge( face.b, face.c, sourceEdges ).newEdge + sl;
-			edge3 = getEdge( face.c, face.a, sourceEdges ).newEdge + sl;
-
-			// create 4 faces.
-
-			newFace( newFaces, edge1, edge2, edge3 );
-			newFace( newFaces, face.a, edge1, edge3 );
-			newFace( newFaces, face.b, edge2, edge1 );
-			newFace( newFaces, face.c, edge3, edge2 );
-
-		}
-
-		// Overwrite old arrays
-		geometry.vertices = newVertices;
-		geometry.faces = newFaces;
-
-		// console.log('done');
-
-	};
-
-
-} )();
+/*
+ *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
+ *	@author centerionware / http://www.centerionware.com
+ *
+ *	Subdivision Geometry Modifier
+ *		using Loop Subdivision Scheme
+ *
+ *	References:
+ *		http://graphics.stanford.edu/~mdfisher/subdivision.html
+ *		http://www.holmes3d.net/graphics/subdivision/
+ *		http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
+ *
+ *	Known Issues:
+ *		- currently doesn't handle "Sharp Edges"
+ */
+
+THREE.SubdivisionModifier = function ( subdivisions ) {
+
+	this.subdivisions = ( subdivisions === undefined ) ? 1 : subdivisions;
+
+};
+
+// Applies the "modify" pattern
+THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
+
+	var repeats = this.subdivisions;
+
+	while ( repeats -- > 0 ) {
+
+		this.smooth( geometry );
+
+	}
+
+	geometry.computeFaceNormals();
+	geometry.computeVertexNormals();
+
+};
+
+( function() {
+
+	// Some constants
+	var WARNINGS = ! true; // Set to true for development
+	var ABC = [ 'a', 'b', 'c' ];
+
+
+	function getEdge( a, b, map ) {
+
+		var vertexIndexA = Math.min( a, b );
+		var vertexIndexB = Math.max( a, b );
+
+		var key = vertexIndexA + "_" + vertexIndexB;
+
+		return map[ key ];
+
+	}
+
+
+	function processEdge( a, b, vertices, map, face, metaVertices ) {
+
+		var vertexIndexA = Math.min( a, b );
+		var vertexIndexB = Math.max( a, b );
+
+		var key = vertexIndexA + "_" + vertexIndexB;
+
+		var edge;
+
+		if ( key in map ) {
+
+			edge = map[ key ];
+
+		} else {
+
+			var vertexA = vertices[ vertexIndexA ];
+			var vertexB = vertices[ vertexIndexB ];
+
+			edge = {
+
+				a: vertexA, // pointer reference
+				b: vertexB,
+				newEdge: null,
+				// aIndex: a, // numbered reference
+				// bIndex: b,
+				faces: [] // pointers to face
+
+			};
+
+			map[ key ] = edge;
+
+		}
+
+		edge.faces.push( face );
+
+		metaVertices[ a ].edges.push( edge );
+		metaVertices[ b ].edges.push( edge );
+
+
+	}
+
+	function generateLookups( vertices, faces, metaVertices, edges ) {
+
+		var i, il, face, edge;
+
+		for ( i = 0, il = vertices.length; i < il; i ++ ) {
+
+			metaVertices[ i ] = { edges: [] };
+
+		}
+
+		for ( i = 0, il = faces.length; i < il; i ++ ) {
+
+			face = faces[ i ];
+
+			processEdge( face.a, face.b, vertices, edges, face, metaVertices );
+			processEdge( face.b, face.c, vertices, edges, face, metaVertices );
+			processEdge( face.c, face.a, vertices, edges, face, metaVertices );
+
+		}
+
+	}
+
+	function newFace( newFaces, a, b, c ) {
+
+		newFaces.push( new THREE.Face3( a, b, c ) );
+
+	}
+
+	function midpoint( a, b ) {
+
+		return ( Math.abs( b - a ) / 2 ) + Math.min( a, b );
+
+	}
+
+	function newUv( newUvs, a, b, c ) {
+
+		newUvs.push( [ a.clone(), b.clone(), c.clone() ] );
+
+	}
+
+	/////////////////////////////
+
+	// Performs one iteration of Subdivision
+	THREE.SubdivisionModifier.prototype.smooth = function ( geometry ) {
+
+		var tmp = new THREE.Vector3();
+
+		var oldVertices, oldFaces, oldUvs;
+		var newVertices, newFaces, newUVs = [];
+
+		var n, l, i, il, j, k;
+		var metaVertices, sourceEdges;
+
+		// new stuff.
+		var sourceEdges, newEdgeVertices, newSourceVertices;
+
+		oldVertices = geometry.vertices; // { x, y, z}
+		oldFaces = geometry.faces; // { a: oldVertex1, b: oldVertex2, c: oldVertex3 }
+		oldUvs = geometry.faceVertexUvs[ 0 ];
+
+		var hasUvs = oldUvs !== undefined && oldUvs.length > 0;
+
+		/******************************************************
+		 *
+		 * Step 0: Preprocess Geometry to Generate edges Lookup
+		 *
+		 *******************************************************/
+
+		metaVertices = new Array( oldVertices.length );
+		sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[]  }
+
+		generateLookups( oldVertices, oldFaces, metaVertices, sourceEdges );
+
+
+		/******************************************************
+		 *
+		 *	Step 1.
+		 *	For each edge, create a new Edge Vertex,
+		 *	then position it.
+		 *
+		 *******************************************************/
+
+		newEdgeVertices = [];
+		var other, currentEdge, newEdge, face;
+		var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
+
+		for ( i in sourceEdges ) {
+
+			currentEdge = sourceEdges[ i ];
+			newEdge = new THREE.Vector3();
+
+			edgeVertexWeight = 3 / 8;
+			adjacentVertexWeight = 1 / 8;
+
+			connectedFaces = currentEdge.faces.length;
+
+			// check how many linked faces. 2 should be correct.
+			if ( connectedFaces != 2 ) {
+
+				// if length is not 2, handle condition
+				edgeVertexWeight = 0.5;
+				adjacentVertexWeight = 0;
+
+				if ( connectedFaces != 1 ) {
+
+					if ( WARNINGS ) console.warn( 'Subdivision Modifier: Number of connected faces != 2, is: ', connectedFaces, currentEdge );
+
+				}
+
+			}
+
+			newEdge.addVectors( currentEdge.a, currentEdge.b ).multiplyScalar( edgeVertexWeight );
+
+			tmp.set( 0, 0, 0 );
+
+			for ( j = 0; j < connectedFaces; j ++ ) {
+
+				face = currentEdge.faces[ j ];
+
+				for ( k = 0; k < 3; k ++ ) {
+
+					other = oldVertices[ face[ ABC[ k ] ] ];
+					if ( other !== currentEdge.a && other !== currentEdge.b ) break;
+
+				}
+
+				tmp.add( other );
+
+			}
+
+			tmp.multiplyScalar( adjacentVertexWeight );
+			newEdge.add( tmp );
+
+			currentEdge.newEdge = newEdgeVertices.length;
+			newEdgeVertices.push( newEdge );
+
+			// console.log(currentEdge, newEdge);
+
+		}
+
+		/******************************************************
+		 *
+		 *	Step 2.
+		 *	Reposition each source vertices.
+		 *
+		 *******************************************************/
+
+		var beta, sourceVertexWeight, connectingVertexWeight;
+		var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
+		newSourceVertices = [];
+
+		for ( i = 0, il = oldVertices.length; i < il; i ++ ) {
+
+			oldVertex = oldVertices[ i ];
+
+			// find all connecting edges (using lookupTable)
+			connectingEdges = metaVertices[ i ].edges;
+			n = connectingEdges.length;
+
+			if ( n == 3 ) {
+
+				beta = 3 / 16;
+
+			} else if ( n > 3 ) {
+
+				beta = 3 / ( 8 * n ); // Warren's modified formula
+
+			}
+
+			// Loop's original beta formula
+			// beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
+
+			sourceVertexWeight = 1 - n * beta;
+			connectingVertexWeight = beta;
+
+			if ( n <= 2 ) {
+
+				// crease and boundary rules
+				// console.warn('crease and boundary rules');
+
+				if ( n == 2 ) {
+
+					if ( WARNINGS ) console.warn( '2 connecting edges', connectingEdges );
+					sourceVertexWeight = 3 / 4;
+					connectingVertexWeight = 1 / 8;
+
+					// sourceVertexWeight = 1;
+					// connectingVertexWeight = 0;
+
+				} else if ( n == 1 ) {
+
+					if ( WARNINGS ) console.warn( 'only 1 connecting edge' );
+
+				} else if ( n == 0 ) {
+
+					if ( WARNINGS ) console.warn( '0 connecting edges' );
+
+				}
+
+			}
+
+			newSourceVertex = oldVertex.clone().multiplyScalar( sourceVertexWeight );
+
+			tmp.set( 0, 0, 0 );
+
+			for ( j = 0; j < n; j ++ ) {
+
+				connectingEdge = connectingEdges[ j ];
+				other = connectingEdge.a !== oldVertex ? connectingEdge.a : connectingEdge.b;
+				tmp.add( other );
+
+			}
+
+			tmp.multiplyScalar( connectingVertexWeight );
+			newSourceVertex.add( tmp );
+
+			newSourceVertices.push( newSourceVertex );
+
+		}
+
+
+		/******************************************************
+		 *
+		 *	Step 3.
+		 *	Generate Faces between source vertices
+		 *	and edge vertices.
+		 *
+		 *******************************************************/
+
+		newVertices = newSourceVertices.concat( newEdgeVertices );
+		var sl = newSourceVertices.length, edge1, edge2, edge3;
+		newFaces = [];
+
+		var uv, x0, x1, x2;
+		var x3 = new THREE.Vector2();
+		var x4 = new THREE.Vector2();
+		var x5 = new THREE.Vector2();
+
+		for ( i = 0, il = oldFaces.length; i < il; i ++ ) {
+
+			face = oldFaces[ i ];
+
+			// find the 3 new edges vertex of each old face
+
+			edge1 = getEdge( face.a, face.b, sourceEdges ).newEdge + sl;
+			edge2 = getEdge( face.b, face.c, sourceEdges ).newEdge + sl;
+			edge3 = getEdge( face.c, face.a, sourceEdges ).newEdge + sl;
+
+			// create 4 faces.
+
+			newFace( newFaces, edge1, edge2, edge3 );
+			newFace( newFaces, face.a, edge1, edge3 );
+			newFace( newFaces, face.b, edge2, edge1 );
+			newFace( newFaces, face.c, edge3, edge2 );
+
+			// create 4 new uv's
+
+			if ( hasUvs ) {
+
+				uv = oldUvs[ i ];
+
+				x0 = uv[ 0 ];
+				x1 = uv[ 1 ];
+				x2 = uv[ 2 ];
+
+				x3.set( midpoint( x0.x, x1.x ), midpoint( x0.y, x1.y ) );
+				x4.set( midpoint( x1.x, x2.x ), midpoint( x1.y, x2.y ) );
+				x5.set( midpoint( x0.x, x2.x ), midpoint( x0.y, x2.y ) );
+
+				newUv( newUVs, x3, x4, x5 );
+				newUv( newUVs, x0, x3, x5 );
+
+				newUv( newUVs, x1, x4, x3 );
+				newUv( newUVs, x2, x5, x4 );
+
+			}
+
+		}
+
+		// Overwrite old arrays
+		geometry.vertices = newVertices;
+		geometry.faces = newFaces;
+		if ( hasUvs ) geometry.faceVertexUvs[ 0 ] = newUVs;
+
+		// console.log('done');
+
+	};
+
+} )();

+ 0 - 2
examples/js/nodes/materials/PhongNode.js

@@ -32,7 +32,6 @@ THREE.PhongNode.prototype.build = function( builder ) {
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
@@ -146,7 +145,6 @@ THREE.PhongNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

+ 0 - 2
examples/js/nodes/materials/StandardNode.js

@@ -32,7 +32,6 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
 			THREE.UniformsLib[ "fog" ],
-			THREE.UniformsLib[ "ambient" ],
 			THREE.UniformsLib[ "lights" ]
 
 		] ) );
@@ -159,7 +158,6 @@ THREE.StandardNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_standard_pars_fragment" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],

+ 177 - 0
examples/js/pmrem/PMREMCubeUVPacker.js

@@ -0,0 +1,177 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ * @author Ben Houston / bhouston, https://clara.io
+ *
+ * This class takes the cube lods(corresponding to different roughness values), and creates a single cubeUV
+ * Texture. The format for a given roughness set of faces is simply::
+ * +X+Y+Z
+ * -X-Y-Z
+ * For every roughness a mip map chain is also saved, which is essential to remove the texture artifacts due to
+ * minification.
+ * Right now for every face a PlaneMesh is drawn, which leads to a lot of geometry draw calls, but can be replaced
+ * later by drawing a single buffer and by sending the appropriate faceIndex via vertex attributes.
+ * The arrangement of the faces is fixed, as assuming this arrangement, the sampling function has been written.
+ */
+
+
+THREE.PMREMCubeUVPacker = function( cubeTextureLods, numLods ) {
+
+	this.cubeLods = cubeTextureLods;
+	this.numLods = numLods;
+	var size = cubeTextureLods[ 0 ].width * 4;
+
+	this.CubeUVRenderTarget = new THREE.WebGLRenderTarget( size, size,
+	{ format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter, type: cubeTextureLods[ 0 ].texture.type } );
+	this.CubeUVRenderTarget.texture.generateMipmaps = false;
+  this.CubeUVRenderTarget.mapping = THREE.CubeUVReflectionMapping;
+	this.camera = new THREE.OrthographicCamera( - size * 0.5, size * 0.5, - size * 0.5, size * 0.5, 0.0, 1000 );
+
+	this.scene = new THREE.Scene();
+	this.scene.add( this.camera );
+
+	this.objects = [];
+	var xOffset = 0;
+	var faceOffsets = [];
+	faceOffsets.push( new THREE.Vector2( 0, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 1, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 2, 0 ) );
+	faceOffsets.push( new THREE.Vector2( 0, 1 ) );
+	faceOffsets.push( new THREE.Vector2( 1, 1 ) );
+	faceOffsets.push( new THREE.Vector2( 2, 1 ) );
+	var yOffset = 0;
+	var textureResolution = size;
+	size = cubeTextureLods[ 0 ].width;
+
+	var offset2 = 0;
+	var c = 4.0;
+	this.numLods = Math.log2( cubeTextureLods[ 0 ].width ) - 2;
+	for ( var i = 0; i < this.numLods; i ++ ) {
+
+		var offset1 = ( textureResolution - textureResolution / c ) * 0.5;
+		if ( size > 16 )
+		c *= 2;
+		var nMips = size > 16 ? 6 : 1;
+		var mipOffsetX = 0;
+		var mipOffsetY = 0;
+		var mipSize = size;
+
+		for ( var j = 0; j < nMips; j ++ ) {
+
+			// Mip Maps
+			for ( var k = 0; k < 6; k ++ ) {
+
+				// 6 Cube Faces
+				var material = this.getShader();
+				material.uniforms[ "envMap" ].value = this.cubeLods[ i ];
+				material.envMap = this.cubeLods[ i ]
+				material.uniforms[ "faceIndex" ].value = k;
+				material.uniforms[ "mapSize" ].value = mipSize;
+				var color = material.uniforms[ "testColor" ].value;
+				//color.copy(testColor[j]);
+				var planeMesh = new THREE.Mesh(
+				new THREE.PlaneGeometry( mipSize, mipSize, 0 ),
+				material );
+				planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX;
+				planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY;
+				planeMesh.material.side = THREE.DoubleSide;
+				this.scene.add( planeMesh );
+				this.objects.push( planeMesh );
+
+			}
+			mipOffsetY += 1.75 * mipSize;
+			mipOffsetX += 1.25 * mipSize;
+			mipSize /= 2;
+
+		}
+		offset2 += 2 * size;
+		if ( size > 16 )
+		size /= 2;
+
+	}
+
+};
+
+THREE.PMREMCubeUVPacker.prototype = {
+
+	constructor : THREE.PMREMCubeUVPacker,
+
+	update: function( renderer ) {
+
+		var gammaInput = renderer.gammaInput;
+    var gammaOutput = renderer.gammaOutput;
+    renderer.gammaInput = false;
+    renderer.gammaOutput = false;
+
+		renderer.render( this.scene, this.camera, this.CubeUVRenderTarget, true );
+
+    renderer.gammaInput = renderer.gammaInput;
+    renderer.gammaOutput = renderer.gammaOutput;
+	},
+
+  getShader: function() {
+
+    var shaderMaterial = new THREE.ShaderMaterial( {
+
+      uniforms: {
+       	"faceIndex": { type: 'i', value: 0 },
+       	"mapSize": { type: 'f', value: 0 },
+       	"envMap": { type: 't', value: null },
+       	"testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
+      },
+
+      vertexShader:
+        "precision highp float;\
+         varying vec2 vUv;\
+         void main() {\
+            vUv = uv;\
+            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\
+         }",
+
+      fragmentShader:
+       "precision highp float;\
+        varying vec2 vUv;\
+        uniform samplerCube envMap;\
+        uniform float mapSize;\
+        uniform vec3 testColor;\
+        uniform int faceIndex;\
+        \
+        void main() {\
+          vec3 sampleDirection;\
+          vec2 uv = vUv;\
+          uv = uv * 2.0 - 1.0;\
+          uv.y *= -1.0;\
+          if(faceIndex == 0) {\
+              sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\
+          }\
+          else if(faceIndex == 1) {\
+              sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\
+          }\
+          else if(faceIndex == 2) {\
+              sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\
+          }\
+          else if(faceIndex == 3) {\
+              sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\
+          }\
+          else if(faceIndex == 4) {\
+              sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\
+          }\
+          else {\
+              sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\
+          }\
+          vec4 color = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\
+          gl_FragColor = linearToOutputTexel( color * vec4(testColor, 1.0) );\
+        }",
+
+			blending: THREE.CustomBlending,
+			blendSrc: THREE.OneFactor,
+			blendDst: THREE.ZeroFactor,
+			blendSrcAlpha: THREE.OneFactor,
+			blendDstAlpha: THREE.ZeroFactor,
+			blendEquation: THREE.AddEquation
+    });
+
+		return shaderMaterial;
+
+  }
+
+};

+ 244 - 0
examples/js/pmrem/PMREMGenerator.js

@@ -0,0 +1,244 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ * @author Ben Houston / bhouston, https://clara.io
+ *
+ * To avoid cube map seams, I create an extra pixel around each face. This way when the cube map is
+ * sampled by an application later(with a little care by sampling the centre of the texel), the extra 1 border
+ *  of pixels makes sure that there is no seams artifacts present. This works perfectly for cubeUV format as
+ *  well where the 6 faces can be arranged in any manner whatsoever.
+ * Code in the beginning of fragment shader's main function does this job for a given resolution.
+ *  Run Scene_PMREM_Test.html in the examples directory to see the sampling from the cube lods generated
+ *  by this class.
+ */
+
+THREE.PMREMGenerator = function( sourceTexture ) {
+
+	this.sourceTexture = sourceTexture;
+  this.resolution = 256; // NODE: 256 is currently hard coded in the glsl code for performance reasons
+
+  var monotonicEncoding = ( sourceTexture.encoding === THREE.LinearEncoding ) ||
+    ( sourceTexture.encoding === THREE.GammaEncoding ) || ( sourceTexture.encoding === THREE.sRGBEncoding );
+
+  this.sourceTexture.minFilter = ( monotonicEncoding ) ? THREE.LinearFilter : THREE.NearestFilter;
+  this.sourceTexture.magFilter = ( monotonicEncoding ) ? THREE.LinearFilter : THREE.NearestFilter;
+  this.sourceTexture.generateMipmaps = this.sourceTexture.generateMipmaps && monotonicEncoding;
+
+	this.cubeLods = [];
+
+	var size = this.resolution;
+  var params = { format: this.sourceTexture.format, magFilter: this.sourceTexture.magFilter, minFilter: this.sourceTexture.minFilter, type: this.sourceTexture.type };
+
+  // how many LODs fit in the given CubeUV Texture.
+	this.numLods = Math.log2( size ) - 2;
+  for ( var i = 0; i < this.numLods; i ++ ) {
+		var renderTarget = new THREE.WebGLRenderTargetCube( size, size, params );
+		renderTarget.texture.generateMipmaps = this.sourceTexture.generateMipmaps;
+    renderTarget.texture.anisotropy = this.sourceTexture.anisotropy;
+    renderTarget.texture.encoding = this.sourceTexture.encoding;
+    renderTarget.texture.minFilter = this.sourceTexture.minFilter;
+    renderTarget.texture.magFilter = this.sourceTexture.magFilter;
+		this.cubeLods.push( renderTarget );
+		size = Math.max( 16, size / 2 );
+	}
+
+	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0.0, 1000 );
+
+  this.shader = this.getShader();
+	this.planeMesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2, 0 ), this.shader );
+	this.planeMesh.material.side = THREE.DoubleSide;
+	this.scene = new THREE.Scene();
+	this.scene.add( this.planeMesh );
+	this.scene.add( this.camera );
+
+	this.shader.uniforms[ "envMap" ].value = this.sourceTexture;
+  this.shader.envMap = this.sourceTexture;
+};
+
+THREE.PMREMGenerator.prototype = {
+
+	constructor : THREE.PMREMGenerator,
+
+  /*
+   * Prashant Sharma / spidersharma03: More thought and work is needed here.
+   * Right now it's a kind of a hack to use the previously convolved map to convolve the current one.
+   * I tried to use the original map to convolve all the lods, but for many textures(specially the high frequency)
+   * even a high number of samples(1024) dosen't lead to satisfactory results.
+   * By using the previous convolved maps, a lower number of samples are generally sufficient(right now 32, which
+   * gives okay results unless we see the reflection very carefully, or zoom in too much), however the math
+   * goes wrong as the distribution function tries to sample a larger area than what it should be. So I simply scaled
+   * the roughness by 0.9(totally empirical) to try to visually match the original result.
+   * The condition "if(i <5)" is also an attemt to make the result match the original result.
+   * This method requires the most amount of thinking I guess. Here is a paper which we could try to implement in future::
+   * http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
+   */
+	update: function( renderer ) {
+
+		this.shader.uniforms[ "envMap" ].value = this.sourceTexture;
+    this.shader.envMap = this.sourceTexture;
+
+    var gammaInput = renderer.gammaInput;
+    var gammaOutput = renderer.gammaOutput;
+    renderer.gammaInput = false;
+    renderer.gammaOutput = false;
+		for ( var i = 0; i < this.numLods; i ++ ) {
+
+			var r = i / ( this.numLods - 1 );
+			this.shader.uniforms[ "roughness" ].value = r * 0.9; // see comment above, pragmatic choice
+			var size = this.cubeLods[ i ].width;
+			this.shader.uniforms[ "mapSize" ].value = size;
+			this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] );
+			if ( i < 5 )
+			this.shader.uniforms[ "envMap" ].value = this.cubeLods[ i ];
+
+		}
+
+    renderer.gammaInput = renderer.gammaInput;
+    renderer.gammaOutput = renderer.gammaOutput;
+
+	},
+
+	renderToCubeMapTarget: function( renderer, renderTarget ) {
+
+		for ( var i = 0; i < 6; i ++ ) {
+		  this.renderToCubeMapTargetFace( renderer, renderTarget, i )
+    }
+
+	},
+
+	renderToCubeMapTargetFace: function( renderer, renderTarget, faceIndex ) {
+		renderTarget.activeCubeFace = faceIndex;
+		this.shader.uniforms[ "faceIndex" ].value = faceIndex;
+		renderer.render( this.scene, this.camera, renderTarget, true );
+
+	},
+
+  getShader: function() {
+
+    return new THREE.ShaderMaterial( {
+
+      uniforms: {
+        "faceIndex": { type: 'i', value: 0 },
+        "roughness": { type: 'f', value: 0.5 },
+        "mapSize": { type: 'f', value: 0.5 },
+        "envMap": { type: 't', value: null },
+        "testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
+      },
+
+      vertexShader:
+        "varying vec2 vUv;\n\
+        void main() {\n\
+           vUv = uv;\n\
+           gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
+        }",
+
+      fragmentShader:
+        "varying vec2 vUv;\n\
+        uniform int faceIndex;\n\
+        uniform float roughness;\n\
+        uniform samplerCube envMap;\n\
+        uniform float mapSize;\n\
+        uniform vec3 testColor;\n\
+        \n\
+        float rnd(vec2 uv) {\n\
+           return fract(sin(dot(uv, vec2(12.9898, 78.233) * 2.0)) * 43758.5453);\n\
+        }\n\
+        float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\
+           float a = ggxRoughness + 0.0001;\n\
+           a *= a;\n\
+           return ( 2.0 / a - 2.0 );\n\
+        }\n\
+        const float PI = 3.14159265358979;\n\
+        vec3 ImportanceSamplePhong(vec2 uv, mat3 vecSpace, float specPow) {\n\
+           float phi = uv.y * 2.0 * PI;\n\
+           float cosTheta = pow(1.0 - uv.x, 1.0 / (specPow + 1.0));\n\
+           float sinTheta = sqrt(1.0 - cosTheta * cosTheta);\n\
+           vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\n\
+           return vecSpace * sampleDir;\n\
+        }\n\
+        vec3 ImportanceSampleGGX( vec2 uv, mat3 vecSpace, float Roughness )\n\
+        {\n\
+               float a = Roughness * Roughness;\n\
+               float Phi = 2.0 * PI * uv.x;\n\
+               float CosTheta = sqrt( (1.0 - uv.y) / ( 1.0 + (a*a - 1.0) * uv.y ) );\n\
+               float SinTheta = sqrt( 1.0 - CosTheta * CosTheta );\n\
+               return vecSpace * vec3(SinTheta * cos( Phi ), SinTheta * sin( Phi ), CosTheta);\n\
+        }\n\
+        mat3 matrixFromVector(vec3 n) {\n\
+           float a = 1.0 / (1.0 + n.z);\n\
+           float b = -n.x * n.y * a;\n\
+           vec3 b1 = vec3(1.0 - n.x * n.x * a, b, -n.x);\n\
+           vec3 b2 = vec3(b, 1.0 - n.y * n.y * a, -n.y);\n\
+           return mat3(b1, b2, n);\n\
+        }\n\
+        \n\
+        vec4 testColorMap(float Roughness) {\n\
+           vec4 color;\n\
+           if(faceIndex == 0)\n\
+               color = vec4(1.0,0.0,0.0,1.0);\n\
+           else if(faceIndex == 1)\n\
+               color = vec4(0.0,1.0,0.0,1.0);\n\
+           else if(faceIndex == 2)\n\
+               color = vec4(0.0,0.0,1.0,1.0);\n\
+           else if(faceIndex == 3)\n\
+               color = vec4(1.0,1.0,0.0,1.0);\n\
+           else if(faceIndex == 4)\n\
+               color = vec4(0.0,1.0,1.0,1.0);\n\
+           else\n\
+               color = vec4(1.0,0.0,1.0,1.0);\n\
+           color *= ( 1.0 - Roughness );\n\
+           return color;\n\
+        }\n\
+        void main() {\n\
+           vec3 sampleDirection;\n\
+           vec2 uv = vUv*2.0 - 1.0;\n\
+           float offset = -1.0/mapSize;\n\
+           const float a = -1.0;\n\
+           const float b = 1.0;\n\
+           float c = -1.0 + offset;\n\
+           float d = 1.0 - offset;\n\
+           float bminusa = b - a;\n\
+           uv.x = (uv.x - a)/bminusa * d - (uv.x - b)/bminusa * c;\n\
+           uv.y = (uv.y - a)/bminusa * d - (uv.y - b)/bminusa * c;\n\
+           if (faceIndex==0) {\n\
+               sampleDirection = vec3(1.0, -uv.y, -uv.x);\n\
+           }\n\
+           else if (faceIndex==1) {\n\
+               sampleDirection = vec3(-1.0, -uv.y, uv.x);\n\
+           } else if (faceIndex==2) {\n\
+               sampleDirection = vec3(uv.x, 1.0, uv.y);\n\
+           } else if (faceIndex==3) {\n\
+               sampleDirection = vec3(uv.x, -1.0, -uv.y);\n\
+           } else if (faceIndex==4) {\n\
+               sampleDirection = vec3(uv.x, -uv.y, 1.0);\n\
+           } else {\n\
+               sampleDirection = vec3(-uv.x, -uv.y, -1.0);\n\
+           }\n\
+           mat3 vecSpace = matrixFromVector(normalize(sampleDirection));\n\
+           vec3 rgbColor = vec3(0.0);\n\
+           const int NumSamples = 1024;\n\
+           vec3 vect;\n\
+           float weight = 0.0;\n\
+           for(int i=0; i<NumSamples; i++) {\n\
+               float sini = sin(float(i));\n\
+               float cosi = cos(float(i));\n\
+               float rand = rnd(vec2(sini, cosi));\n\
+               vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), rand), vecSpace, roughness);\n\
+               float dotProd = dot(vect, normalize(sampleDirection));\n\
+               weight += dotProd;\n\
+               vec3 color = envMapTexelToLinear(textureCube(envMap,vect)).rgb;\n\
+               rgbColor.rgb += color;\n\
+           }\n\
+           rgbColor /= float(NumSamples);\n\
+           //rgbColor = testColorMap( roughness ).rgb;\n\
+           gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\
+        }",
+        blending: THREE.CustomBlending,
+        blendSrc: THREE.OneFactor,
+        blendDst: THREE.ZeroFactor,
+        blendSrcAlpha: THREE.OneFactor,
+        blendDstAlpha: THREE.ZeroFactor,
+        blendEquation: THREE.AddEquation
+      }
+    );
+  }
+};

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