瀏覽代碼

Merge branch 'dev' of https://github.com/mrdoob/three.js into dev

Elijah Snyder 9 年之前
父節點
當前提交
a0a6a94a29
共有 100 個文件被更改,包括 2789 次插入1781 次删除
  1. 228 170
      build/three.js
  2. 71 76
      build/three.min.js
  3. 2 2
      docs/api/extras/geometries/TextGeometry.html
  4. 77 89
      docs/api/loaders/JSONLoader.html
  5. 1 1
      docs/api/materials/MeshPhongMaterial.html
  6. 1 1
      docs/api/math/Matrix4.html
  7. 161 161
      docs/api/renderers/CanvasRenderer.html
  8. 1 1
      docs/scenes/js/material.js
  9. 12 0
      editor/css/main.css
  10. 4 3
      editor/index.html
  11. 1 0
      editor/js/Editor.js
  12. 25 8
      editor/js/Loader.js
  13. 9 1
      editor/js/Sidebar.Object3D.js
  14. 2 2
      editor/js/Storage.js
  15. 2 2
      examples/canvas_interactive_cubes.html
  16. 2 2
      examples/canvas_interactive_cubes_tween.html
  17. 2 2
      examples/canvas_interactive_voxelpainter.html
  18. 0 1
      examples/canvas_materials.html
  19. 0 238
      examples/canvas_materials_depth.html
  20. 0 1
      examples/index.html
  21. 21 29
      examples/js/loaders/AMFLoader.js
  22. 3 5
      examples/js/loaders/ColladaLoader.js
  23. 860 0
      examples/js/loaders/ColladaLoader2.js
  24. 54 0
      examples/js/loaders/KMZLoader.js
  25. 1 1
      examples/js/loaders/MTLLoader.js
  26. 0 5
      examples/js/postprocessing/GlitchPass.js
  27. 0 10
      examples/js/renderers/CanvasRenderer.js
  28. 0 6
      examples/js/renderers/SVGRenderer.js
  29. 1 0
      examples/misc_controls_pointerlock.html
  30. 1 1
      examples/misc_lookat.html
  31. 0 0
      examples/models/md2/ratamahatta/w_chaingun.md2
  32. 1 0
      examples/webgl_camera_logarithmicdepthbuffer.html
  33. 0 1
      examples/webgl_geometry_extrude_splines.html
  34. 2 3
      examples/webgl_geometry_terrain_raycast.html
  35. 1 1
      examples/webgl_interactive_raycasting_points.html
  36. 2 2
      examples/webgl_loader_amf.html
  37. 3 0
      examples/webgl_loader_sea3d.html
  38. 5 0
      examples/webgl_loader_sea3d_hierarchy.html
  39. 4 0
      examples/webgl_loader_sea3d_keyframe.html
  40. 4 0
      examples/webgl_loader_sea3d_morph.html
  41. 3 0
      examples/webgl_loader_sea3d_skinning.html
  42. 7 3
      examples/webgl_loader_sea3d_sound.html
  43. 1 1
      examples/webgl_performance.html
  44. 1 1
      examples/webgl_performance_static.html
  45. 256 0
      examples/webgl_read_float_buffer.html
  46. 33 33
      examples/webgl_shadowmap_pointlight.html
  47. 25 1
      src/Three.js
  48. 21 22
      src/animation/AnimationAction.js
  49. 39 41
      src/animation/AnimationClip.js
  50. 32 32
      src/animation/AnimationMixer.js
  51. 35 39
      src/animation/AnimationUtils.js
  52. 27 27
      src/animation/KeyframeTrack.js
  53. 96 98
      src/animation/PropertyBinding.js
  54. 3 4
      src/animation/tracks/BooleanKeyframeTrack.js
  55. 4 5
      src/animation/tracks/ColorKeyframeTrack.js
  56. 3 4
      src/animation/tracks/NumberKeyframeTrack.js
  57. 7 8
      src/animation/tracks/QuaternionKeyframeTrack.js
  58. 3 4
      src/animation/tracks/StringKeyframeTrack.js
  59. 4 5
      src/animation/tracks/VectorKeyframeTrack.js
  60. 3 3
      src/cameras/CubeCamera.js
  61. 16 1
      src/core/BufferGeometry.js
  62. 2 10
      src/core/Clock.js
  63. 2 2
      src/core/Geometry.js
  64. 49 16
      src/core/Object3D.js
  65. 2 2
      src/core/Raycaster.js
  66. 6 7
      src/extras/FontUtils.js
  67. 8 8
      src/extras/ImageUtils.js
  68. 1 1
      src/extras/core/Path.js
  69. 1 1
      src/extras/geometries/CircleBufferGeometry.js
  70. 3 2
      src/extras/geometries/EdgesGeometry.js
  71. 1 1
      src/extras/geometries/SphereBufferGeometry.js
  72. 10 1
      src/extras/geometries/TubeGeometry.js
  73. 3 2
      src/extras/geometries/WireframeGeometry.js
  74. 2 2
      src/extras/helpers/CameraHelper.js
  75. 0 10
      src/lights/AmbientLight.js
  76. 0 11
      src/lights/DirectionalLight.js
  77. 0 12
      src/lights/HemisphereLight.js
  78. 21 4
      src/lights/Light.js
  79. 0 13
      src/lights/PointLight.js
  80. 0 14
      src/lights/SpotLight.js
  81. 2 2
      src/loaders/AnimationLoader.js
  82. 8 0
      src/loaders/ImageLoader.js
  83. 8 9
      src/loaders/JSONLoader.js
  84. 8 6
      src/loaders/ObjectLoader.js
  85. 4 2
      src/loaders/XHRLoader.js
  86. 3 3
      src/math/Color.js
  87. 0 25
      src/objects/Line.js
  88. 7 32
      src/objects/Mesh.js
  89. 0 25
      src/objects/Points.js
  90. 0 17
      src/objects/Sprite.js
  91. 165 29
      src/renderers/WebGLRenderTarget.js
  92. 98 60
      src/renderers/WebGLRenderer.js
  93. 2 2
      src/renderers/shaders/ShaderChunk/envmap_vertex.glsl
  94. 1 1
      src/renderers/shaders/ShaderChunk/hemilight_fragment.glsl
  95. 1 1
      src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl
  96. 175 215
      src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl
  97. 9 40
      src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl
  98. 1 33
      src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl
  99. 2 2
      src/renderers/webgl/WebGLGeometries.js
  100. 1 1
      src/renderers/webgl/WebGLProperties.js

文件差異過大導致無法顯示
+ 228 - 170
build/three.js


文件差異過大導致無法顯示
+ 71 - 76
build/three.min.js


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

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

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

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

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

@@ -68,7 +68,7 @@
 		</div>
 
 		<h3>[property:Float shininess]</h3>
-		<div>How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*. It should not be set to 0.</div>
+		<div>How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*.</div>
 
 		<h3>[property:boolean metal]</h3>
 		<div>

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

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

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

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

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

@@ -439,7 +439,7 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
 	folder.addColor( data, 'specular' ).onChange( handleColorChange( material.specular ) );
 
-	folder.add( material, 'shininess', 1, 100);
+	folder.add( material, 'shininess', 0, 100);
 	folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );

+ 12 - 0
editor/css/main.css

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

+ 4 - 3
editor/index.html

@@ -14,10 +14,13 @@
 
 		<script src="../examples/js/controls/EditorControls.js"></script>
 		<script src="../examples/js/controls/TransformControls.js"></script>
+
+		<script src="../examples/js/libs/jszip.min.js"></script>
 		<script src="../examples/js/loaders/AMFLoader.js"></script>
 		<script src="../examples/js/loaders/AWDLoader.js"></script>
 		<script src="../examples/js/loaders/BabylonLoader.js"></script>
 		<script src="../examples/js/loaders/ColladaLoader.js"></script>
+		<script src="../examples/js/loaders/KMZLoader.js"></script>
 		<script src="../examples/js/loaders/MD2Loader.js"></script>
 		<script src="../examples/js/loaders/OBJLoader.js"></script>
 		<script src="../examples/js/loaders/PLYLoader.js"></script>
@@ -68,7 +71,6 @@
 		<script src="js/libs/ternjs/doc_comment.js"></script>
 		<script src="js/libs/tern-threejs/threejs.js"></script>
 
-		<script src="../examples/js/libs/jszip.min.js"></script>
 		<script src="js/libs/sortable.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>
 		<script src="js/libs/ui.js"></script>
@@ -185,7 +187,7 @@
 
 				var timeout;
 
-				var saveState = function ( scene ) {
+				function saveState( scene ) {
 
 					if ( editor.config.getKey( 'autosave' ) === false ) {
 
@@ -213,7 +215,6 @@
 
 				var signals = editor.signals;
 
-				signals.editorCleared.add( saveState );
 				signals.geometryChanged.add( saveState );
 				signals.objectAdded.add( saveState );
 				signals.objectChanged.add( saveState );

+ 1 - 0
editor/js/Editor.js

@@ -411,6 +411,7 @@ Editor.prototype = {
 	clear: function () {
 
 		this.history.clear();
+		this.storage.clear();
 
 		this.camera.position.set( 500, 250, 500 );
 		this.camera.lookAt( new THREE.Vector3() );

+ 25 - 8
editor/js/Loader.js

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

+ 9 - 1
editor/js/Sidebar.Object3D.js

@@ -95,6 +95,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	container.add( objectNameRow );
 
+	/*
 	// parent
 
 	var objectParentRow = new UI.Panel();
@@ -104,6 +105,7 @@ Sidebar.Object3D = function ( editor ) {
 	objectParentRow.add( objectParent );
 
 	container.add( objectParentRow );
+	*/
 
 	// position
 
@@ -342,6 +344,7 @@ Sidebar.Object3D = function ( editor ) {
 
 		if ( object !== null ) {
 
+			/*
 			if ( object.parent !== null ) {
 
 				var newParentId = parseInt( objectParent.getValue() );
@@ -353,6 +356,7 @@ Sidebar.Object3D = function ( editor ) {
 				}
 
 			}
+			*/
 
 			object.position.x = objectPositionX.getValue();
 			object.position.y = objectPositionY.getValue();
@@ -448,7 +452,7 @@ Sidebar.Object3D = function ( editor ) {
 	function updateRows( object ) {
 
 		var properties = {
-			'parent': objectParentRow,
+			// 'parent': objectParentRow,
 			'fov': objectFovRow,
 			'near': objectNearRow,
 			'far': objectFarRow,
@@ -505,6 +509,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	} );
 
+	/*
 	signals.sceneGraphChanged.add( function () {
 
 		var scene = editor.scene;
@@ -519,6 +524,7 @@ Sidebar.Object3D = function ( editor ) {
 		objectParent.setOptions( options );
 
 	} );
+	*/
 
 	signals.objectChanged.add( function ( object ) {
 
@@ -535,11 +541,13 @@ Sidebar.Object3D = function ( editor ) {
 		objectUUID.setValue( object.uuid );
 		objectName.setValue( object.name );
 
+		/*
 		if ( object.parent !== null ) {
 
 			objectParent.setValue( object.parent.id );
 
 		}
+		*/
 
 		objectPositionX.setValue( object.position.x );
 		objectPositionY.setValue( object.position.y );

+ 2 - 2
editor/js/Storage.js

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

+ 2 - 2
examples/canvas_interactive_cubes.html

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

+ 2 - 2
examples/canvas_interactive_cubes_tween.html

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

+ 2 - 2
examples/canvas_interactive_voxelpainter.html

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

+ 0 - 1
examples/canvas_materials.html

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

+ 0 - 238
examples/canvas_materials_depth.html

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

+ 0 - 1
examples/index.html

@@ -450,7 +450,6 @@
 				"canvas_lines_dashed",
 				"canvas_lines_sphere",
 				"canvas_materials",
-				"canvas_materials_depth",
 				"canvas_materials_normal",
 				"canvas_materials_reflection",
 				"canvas_materials_video",

+ 21 - 29
examples/js/loaders/AMFLoader.js

@@ -36,11 +36,9 @@ THREE.AMFLoader.prototype = {
 		var loader = new THREE.XHRLoader( scope.manager );
 		loader.setCrossOrigin( this.crossOrigin );
 		loader.setResponseType( 'arraybuffer' );
-
 		loader.load( url, function( text ) {
 
-			var amfObject = scope.parse( text );
-			onLoad( amfObject );
+			onLoad( scope.parse( text ) );
 
 		}, onProgress, onError );
 
@@ -77,7 +75,7 @@ THREE.AMFLoader.prototype = {
 
 				for ( file in zip.files ) {
 
-					if ( file.toLowerCase().endsWith( ".amf" ) ) {
+					if ( file.toLowerCase().substr( - 4 ) === '.amf' ) {
 
 						break;
 
@@ -246,21 +244,13 @@ THREE.AMFLoader.prototype = {
 
 				} else if ( currVolumeNode.nodeName === "triangle" ) {
 
-					var triangleNode = currVolumeNode.firstElementChild;
-
-					while ( triangleNode ) {
-
-						if ( triangleNode.nodeName === "v1" ||
-								triangleNode.nodeName === "v2" ||
-								triangleNode.nodeName === "v3" ) {
+					var v1 = currVolumeNode.getElementsByTagName("v1")[0].textContent;
+					var v2 = currVolumeNode.getElementsByTagName("v2")[0].textContent;
+					var v3 = currVolumeNode.getElementsByTagName("v3")[0].textContent;
 
-							volume.triangles.push( triangleNode.textContent );
-
-						}
-
-						triangleNode = triangleNode.nextElementSibling;
-
-					}
+					volume.triangles.push( v1 );
+					volume.triangles.push( v2 );
+					volume.triangles.push( v3 );
 
 				}
 
@@ -288,21 +278,23 @@ THREE.AMFLoader.prototype = {
 
 						if ( vNode.nodeName === "coordinates" ) {
 
-							var coordNode = vNode.firstElementChild;
-
-							while ( coordNode ) {
+							var x = vNode.getElementsByTagName("x")[0].textContent;
+							var y = vNode.getElementsByTagName("y")[0].textContent;
+							var z = vNode.getElementsByTagName("z")[0].textContent;
 
-								if ( coordNode.nodeName === "x" ||
-										 coordNode.nodeName === "y" ||
-										 coordNode.nodeName === "z" ) {
+							vertArray.push(x);
+							vertArray.push(y);
+							vertArray.push(z);
 
-									vertArray.push( coordNode.textContent );
-
-								}
+						} else if ( vNode.nodeName === "normal" ) {
 
-								coordNode = coordNode.nextElementSibling;
+							var nx = vNode.getElementsByTagName("nx")[0].textContent;
+							var ny = vNode.getElementsByTagName("ny")[0].textContent;
+							var nz = vNode.getElementsByTagName("nz")[0].textContent;
 
-							}
+							normalArray.push(nx);
+							normalArray.push(ny);
+							normalArray.push(nz);
 
 						} else if ( vNode.nodeName === "normal" ) {
 

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

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

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

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

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

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

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

@@ -351,7 +351,7 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 					// The specular exponent (defines the focus of the specular highlight)
 					// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
 
-					params[ 'shininess' ] = value;
+					params[ 'shininess' ] = parseFloat( value );
 
 					break;
 

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

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

+ 0 - 10
examples/js/renderers/CanvasRenderer.js

@@ -36,8 +36,6 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	console.log( 'THREE.CanvasRenderer', THREE.REVISION );
 
-	var smoothstep = THREE.Math.smoothstep;
-
 	parameters = parameters || {};
 
 	var _this = this,
@@ -760,14 +758,6 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			}
 
-		} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-			_color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far );
-
-			material.wireframe === true
-					 ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
-					 : fillPath( _color );
-
 		} else if ( material instanceof THREE.MeshNormalMaterial ) {
 
 			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );

+ 0 - 6
examples/js/renderers/SVGRenderer.js

@@ -36,7 +36,6 @@ THREE.SVGRenderer = function () {
 	_clearColor = new THREE.Color(),
 	_clearAlpha = 1,
 
-	_w, // z-buffer to w-buffer
 	_vector3 = new THREE.Vector3(), // Needed for PointLight
 	_centroid = new THREE.Vector3(),
 	_normal = new THREE.Vector3(),
@@ -383,11 +382,6 @@ THREE.SVGRenderer = function () {
 
 			_color.multiply( _diffuseColor ).add( material.emissive );
 
-		} else if ( material instanceof THREE.MeshDepthMaterial ) {
-
-			_w = 1 - ( material.__2near / ( material.__farPlusNear - element.z * material.__farMinusNear ) );
-			_color.setRGB( _w, _w, _w );
-
 		} else if ( material instanceof THREE.MeshNormalMaterial ) {
 
 			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );

+ 1 - 0
examples/misc_controls_pointerlock.html

@@ -181,6 +181,7 @@
 			var moveBackward = false;
 			var moveLeft = false;
 			var moveRight = false;
+			var canJump = false;
 
 			var prevTime = performance.now();
 			var velocity = new THREE.Vector3();

+ 1 - 1
examples/misc_lookat.html

@@ -64,7 +64,7 @@
 
 				scene = new THREE.Scene();
 
-				sphere = new THREE.Mesh( new THREE.SphereGeometry( 100, 20, 20 ), new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } ) );
+				sphere = new THREE.Mesh( new THREE.SphereGeometry( 100, 20, 20 ), new THREE.MeshNormalMaterial() );
 				scene.add( sphere );
 
 				var geometry = new THREE.CylinderGeometry( 0, 10, 100, 3 );

+ 0 - 0
examples/models/md2/ratamahatta/w_chaingun.MD2 → examples/models/md2/ratamahatta/w_chaingun.md2


+ 1 - 0
examples/webgl_camera_logarithmicdepthbuffer.html

@@ -337,6 +337,7 @@
 			}
 			function onMouseWheel(ev) {
 				var amount = -ev.wheelDeltaY || ev.detail;
+				if ( amount === 0 ) return;
 				var dir = amount / Math.abs(amount);
 				zoomspeed = dir/10;
 

+ 0 - 1
examples/webgl_geometry_extrude_splines.html

@@ -105,7 +105,6 @@
 
 			var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
 
-			console.log('adding tube', value, closed2, radiusSegments);
 			if (tubeMesh) parent.remove(tubeMesh);
 
 			extrudePath = splines[value];

+ 2 - 3
examples/webgl_geometry_terrain_raycast.html

@@ -252,9 +252,8 @@
 
 			function onMouseMove( event ) {
 
-				mouse.x = ( event.clientX / renderer.domElement.width ) * 2 - 1;
-				mouse.y = - ( event.clientY / renderer.domElement.height ) * 2 + 1;
-
+				mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
+				mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
 				raycaster.setFromCamera( mouse, camera );
 
 				// See if the ray from the camera into the world hits one of our meshes

+ 1 - 1
examples/webgl_interactive_raycasting_points.html

@@ -271,7 +271,7 @@
 				//
 
 				raycaster = new THREE.Raycaster();
-				raycaster.params.PointCloud.threshold = threshold;
+				raycaster.params.Points.threshold = threshold;
 
 				//
 

+ 2 - 2
examples/webgl_loader_amf.html

@@ -40,8 +40,8 @@
 		<div id="info">
 			<a href="http://threejs.org" target="_blank">three.js</a>
 			<a href="http://amf.wikispaces.com" target="_blank">AMF File format</a>
-			<div>AMF loader test by <a href="https://github.com/tamarintech">tamarintech</a></div>
-			<div>Rook manufacturing file from <a href="http://amf.wikispaces.com/AMF+test+files">AMF test files</a></div>
+			<div>AMF loader test by <a href="https://github.com/tamarintech" target="_blank">tamarintech</a></div>
+			<div>Rook manufacturing file from <a href="http://amf.wikispaces.com/AMF+test+files" target="_blank">AMF test files</a></div>
 		</div>
 
 		<script src="../build/three.min.js"></script>

+ 3 - 0
examples/webgl_loader_sea3d.html

@@ -32,6 +32,8 @@
 		</div>
 
 		<script src="../build/three.min.js"></script>
+
+		<script src="js/MorphAnimMesh.js"></script>
 		<script src="js/loaders/collada/Animation.js"></script>
 		<script src="js/loaders/collada/AnimationHandler.js"></script>
 		<script src="js/loaders/collada/KeyFrameAnimation.js"></script>
@@ -156,6 +158,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 5 - 0
examples/webgl_loader_sea3d_hierarchy.html

@@ -43,10 +43,14 @@
 		<script src="js/shaders/ColorCorrectionShader.js"></script>
 		<script src="js/shaders/VignetteShader.js"></script>
 
+		<script src="js/MorphAnimMesh.js"></script>
+		<script src="js/loaders/collada/animation.js"></script>
+
 		<script src="js/loaders/sea3d/SEA3D.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLZMA.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLoader.js"></script>
 
+
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 
@@ -157,6 +161,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 4 - 0
examples/webgl_loader_sea3d_keyframe.html

@@ -44,6 +44,9 @@
 		<script src="js/shaders/ColorCorrectionShader.js"></script>
 		<script src="js/shaders/VignetteShader.js"></script>
 
+		<script src="js/MorphAnimMesh.js"></script>
+		<script src="js/loaders/collada/animation.js"></script>
+
 		<script src="js/loaders/sea3d/SEA3D.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLZMA.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLoader.js"></script>
@@ -197,6 +200,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 4 - 0
examples/webgl_loader_sea3d_morph.html

@@ -43,6 +43,9 @@
 		<script src="js/shaders/ColorCorrectionShader.js"></script>
 		<script src="js/shaders/VignetteShader.js"></script>
 
+		<script src="js/MorphAnimMesh.js"></script>
+		<script src="js/loaders/collada/animation.js"></script>
+
 		<script src="js/loaders/sea3d/SEA3D.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLZMA.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLoader.js"></script>
@@ -171,6 +174,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 3 - 0
examples/webgl_loader_sea3d_skinning.html

@@ -48,6 +48,8 @@
 		<script src="js/shaders/ColorCorrectionShader.js"></script>
 		<script src="js/shaders/VignetteShader.js"></script>
 
+		<script src="js/MorphAnimMesh.js"></script>
+
 		<script src="js/loaders/sea3d/SEA3D.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLZMA.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLoader.js"></script>
@@ -189,6 +191,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 7 - 3
examples/webgl_loader_sea3d_sound.html

@@ -92,6 +92,9 @@
 		<script src="js/shaders/ColorCorrectionShader.js"></script>
 		<script src="js/shaders/VignetteShader.js"></script>
 
+		<script src="js/MorphAnimMesh.js"></script>
+		<script src="js/loaders/collada/animation.js"></script>
+
 		<script src="js/loaders/sea3d/SEA3D.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLZMA.js"></script>
 		<script src="js/loaders/sea3d/SEA3DLoader.js"></script>
@@ -249,7 +252,7 @@
 
 			function initKeyDown() {
 
-				var onKeyDown = function ( event ) {
+				function onKeyDown( event ) {
 
 					switch ( event.keyCode ) {
 
@@ -277,9 +280,9 @@
 
 				};
 
-				var onKeyUp = function ( event ) {
+				function onKeyUp( event ) {
 
-					switch( event.keyCode ) {
+					switch ( event.keyCode ) {
 
 						case 38: // up
 						case 87: // w
@@ -373,6 +376,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
+				composer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}

+ 1 - 1
examples/webgl_performance.html

@@ -50,7 +50,7 @@
 
 				objects = [];
 
-				var material = new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } );
+				var material = new THREE.MeshNormalMaterial();
 
 				var loader = new THREE.JSONLoader();
 				loader.load( 'obj/Suzanne.js', function ( geometry ) {

+ 1 - 1
examples/webgl_performance_static.html

@@ -48,7 +48,7 @@
 
 				scene = new THREE.Scene();
 
-				var material = new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } );
+				var material = new THREE.MeshNormalMaterial();
 
 				var loader = new THREE.JSONLoader();
 				loader.load( 'obj/Suzanne.js', function ( geometry ) {

+ 256 - 0
examples/webgl_read_float_buffer.html

@@ -0,0 +1,256 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - read float pixels</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				color: #ffffff;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+
+			a {
+				color: #ffffff;
+			}
+
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> read float pixels webgl example</div>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script id="fragment_shader_screen" type="x-shader/x-fragment">
+
+			varying vec2 vUv;
+			uniform sampler2D tDiffuse;
+
+			void main() {
+
+				gl_FragColor = texture2D( tDiffuse, vUv );
+
+			}
+
+		</script>
+
+		<script id="fragment_shader_pass_1" type="x-shader/x-fragment">
+
+			varying vec2 vUv;
+			uniform float time;
+
+			void main() {
+
+				float r = vUv.x;
+				if( vUv.y < 0.5 ) r = 0.0;
+				float g = vUv.y;
+				if( vUv.x < 0.5 ) g = 0.0;
+
+				gl_FragColor = vec4( r, g, time, 1.0 );
+
+			}
+
+		</script>
+
+		<script id="vertexShader" type="x-shader/x-vertex">
+
+			varying vec2 vUv;
+
+			void main() {
+
+				vUv = uv;
+				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+
+			}
+
+		</script>
+
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var cameraRTT, sceneRTT, sceneScreen, renderer, zmesh1, zmesh2;
+
+			var mouseX = 0, mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			var rtTexture, material, quad;
+
+			var delta = 0.01;
+			var valueNode;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.getElementById( 'container' );
+
+				cameraRTT = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 );
+				cameraRTT.position.z = 100;
+
+				//
+
+				sceneRTT = new THREE.Scene();
+				sceneScreen = new THREE.Scene();
+
+				var light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 0, 0, 1 ).normalize();
+				sceneRTT.add( light );
+
+				light = new THREE.DirectionalLight( 0xffaaaa, 1.5 );
+				light.position.set( 0, 0, - 1 ).normalize();
+				sceneRTT.add( light );
+
+				rtTexture = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, type: THREE.FloatType } );
+
+				material = new THREE.ShaderMaterial( {
+
+					uniforms: { time: { type: "f", value: 0.0 } },
+					vertexShader: document.getElementById( 'vertexShader' ).textContent,
+					fragmentShader: document.getElementById( 'fragment_shader_pass_1' ).textContent
+
+				} );
+
+				var materialScreen = new THREE.ShaderMaterial( {
+
+					uniforms: { tDiffuse: { type: "t", value: rtTexture } },
+					vertexShader: document.getElementById( 'vertexShader' ).textContent,
+					fragmentShader: document.getElementById( 'fragment_shader_screen' ).textContent,
+
+					depthWrite: false
+
+				} );
+
+				var plane = new THREE.PlaneBufferGeometry( window.innerWidth, window.innerHeight );
+
+				quad = new THREE.Mesh( plane, material );
+				quad.position.z = - 100;
+				sceneRTT.add( quad );
+
+				var geometry = new THREE.TorusGeometry( 100, 25, 15, 30 );
+
+				var mat1 = new THREE.MeshPhongMaterial( { color: 0x555555, specular: 0xffaa00, shininess: 5 } );
+				var mat2 = new THREE.MeshPhongMaterial( { color: 0x550000, specular: 0xff2200, shininess: 5 } );
+
+				zmesh1 = new THREE.Mesh( geometry, mat1 );
+				zmesh1.position.set( 0, 0, 100 );
+				zmesh1.scale.set( 1.5, 1.5, 1.5 );
+				sceneRTT.add( zmesh1 );
+
+				zmesh2 = new THREE.Mesh( geometry, mat2 );
+				zmesh2.position.set( 0, 150, 100 );
+				zmesh2.scale.set( 0.75, 0.75, 0.75 );
+				sceneRTT.add( zmesh2 );
+
+				quad = new THREE.Mesh( plane, materialScreen );
+				quad.position.z = - 100;
+				sceneScreen.add( quad );
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.autoClear = false;
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				var valueDiv = document.createElement( 'div' );
+				valueDiv.style.position = 'absolute';
+				valueDiv.style.top = '0px';
+				valueDiv.style.right = '0px';
+				valueDiv.style.width = '500px';
+				valueDiv.style.height = '300px';
+				valueDiv.style.fontSize = '60px';
+				container.appendChild( valueDiv );
+				valueNode = document.createTextNode( '' );
+				valueDiv.appendChild( valueNode );
+
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+			}
+
+			function onDocumentMouseMove( event ) {
+
+				mouseX = ( event.clientX - windowHalfX );
+				mouseY = ( event.clientY - windowHalfY );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				var time = Date.now() * 0.0015;
+
+				if ( zmesh1 && zmesh2 ) {
+
+					zmesh1.rotation.y = - time;
+					zmesh2.rotation.y = - time + Math.PI / 2;
+
+				}
+
+				if ( material.uniforms.time.value > 1 || material.uniforms.time.value < 0 ) {
+
+					delta *= - 1;
+
+				}
+
+				material.uniforms.time.value += delta;
+
+				renderer.clear();
+
+				// Render first scene into texture
+
+				renderer.render( sceneRTT, cameraRTT, rtTexture, true );
+
+				// Render full screen quad with generated texture
+
+				renderer.render( sceneScreen, cameraRTT );
+
+				var read = new Float32Array( 4 );
+				renderer.readRenderTargetPixels( rtTexture, windowHalfX + mouseX, windowHalfY - mouseY, 1, 1, read );
+
+				valueNode.nodeValue = 'r:' + read[ 0 ] + ' g:' + read[ 1 ] + ' b:' + read[ 2 ];
+
+			}
+
+		</script>
+	</body>
+</html>

+ 33 - 33
examples/webgl_shadowmap_pointlight.html

@@ -36,7 +36,7 @@
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 			var camera, scene, renderer, stats;
-			var dirLight, pointLight;
+			var pointLight, pointLight2;
 			var torusKnot;
 			var cubeMaterial;
 			var wallMaterial;
@@ -67,40 +67,34 @@
 				var ambient = new THREE.AmbientLight( 0x404040 );
 				scene.add( ambient );
 
-				pointLight = new THREE.PointLight( 0xffffff );
-				pointLight.castShadow = true;
-				pointLight.shadowCameraNear = 1;
-				pointLight.shadowCameraFar = 30;
-				pointLight.shadowDarkness = 0.5;
-				// pointLight.shadowCameraVisible = true;
-				pointLight.shadowMapWidth = 2048;
-				pointLight.shadowMapHeight = 1024;
-				pointLight.shadowBias = 0.01;
-				scene.add( pointLight );
+				function createLight( color ) {
 
-				var geometry = new THREE.SphereGeometry( 0.3, 32, 32 );
-				var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
-				var sphere = new THREE.Mesh( geometry, material );
-				sphere.castShadow = false;
-				sphere.receiveShadow = false;
-				pointLight.add( sphere );
+					var pointLight = new THREE.PointLight( color );
+					pointLight.castShadow = true;
+					pointLight.shadowCameraNear = 1;
+					pointLight.shadowCameraFar = 30;
+					pointLight.shadowDarkness = 0.5;
+					// pointLight.shadowCameraVisible = true;
+					pointLight.shadowMapWidth = 2048;
+					pointLight.shadowMapHeight = 1024;
+					pointLight.shadowBias = 0.01;
 
-				/*
-				dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
-				dirLight.position.set( 0, 50, 0 );
-				dirLight.castShadow = true;
-				dirLight.shadowCameraNear = 1;
-				dirLight.shadowCameraFar = 100;
-				dirLight.shadowCameraRight = 15;
-				dirLight.shadowCameraLeft = -15;
-				dirLight.shadowCameraTop = 15;
-				dirLight.shadowCameraBottom = -15;
-				dirLight.shadowDarkness = 0.5;
-				dirLight.shadowCameraVisible = true;
-				dirLight.shadowMapWidth = 1024;
-				dirLight.shadowMapHeight = 1024;
-				scene.add( dirLight );
-				*/
+					var geometry = new THREE.SphereGeometry( 0.3, 32, 32 );
+					var material = new THREE.MeshBasicMaterial( { color: color } );
+					var sphere = new THREE.Mesh( geometry, material );
+					sphere.castShadow = false;
+					sphere.receiveShadow = false;
+					pointLight.add( sphere );
+
+					return pointLight
+
+				}
+
+				pointLight = createLight( 0xffffff );
+				scene.add( pointLight );
+
+				pointLight2 = createLight( 0xff0000 );
+				scene.add( pointLight2 );
 
 				cubeMaterial = new THREE.MeshPhongMaterial( {
 					color: 0xff0000,
@@ -227,6 +221,12 @@
 				pointLight.position.y = Math.sin( time * 1.1 ) * 9 + 5;
 				pointLight.position.z = Math.sin( time * 1.2 ) * 9;
 
+				time += 10000;
+
+				pointLight2.position.x = Math.sin( time ) * 9;
+				pointLight2.position.y = Math.sin( time * 1.1 ) * 9 + 5;
+				pointLight2.position.z = Math.sin( time * 1.2 ) * 9;
+
 				renderScene();
 
 				torusKnot.rotation.y = time * 0.1;

+ 25 - 1
src/Three.js

@@ -62,7 +62,31 @@ if ( self.requestAnimationFrame === undefined || self.cancelAnimationFrame === u
 
 		}
 
-	}() );
+	} )();
+
+}
+
+//
+
+if ( self.performance === undefined ) {
+
+	self.performance = {};
+
+}
+
+if ( self.performance.now === undefined ) {
+
+	( function () {
+
+		var start = Date.now();
+
+		self.performance.now = function () {
+
+			return Date.now() - start;
+
+		}
+
+	} )();
 
 }
 

+ 21 - 22
src/animation/AnimationAction.js

@@ -1,14 +1,14 @@
 /**
  *
  * A clip that has been explicitly scheduled.
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
 
 THREE.AnimationAction = function ( clip, startTime, timeScale, weight, loop ) {
 
-	if( clip === undefined ) throw new Error( 'clip is null' );
+	if ( clip === undefined ) throw new Error( 'clip is null' );
 	this.clip = clip;
 	this.localRoot = null;
 	this.startTime = startTime || 0;
@@ -39,7 +39,7 @@ THREE.AnimationAction.prototype = {
 		this.localRoot = localRoot;
 
 		return this;
-		
+
 	},
 
 	updateTime: function( clipDeltaTime ) {
@@ -49,23 +49,22 @@ THREE.AnimationAction.prototype = {
    		var previousActionTime = this.actionTime;
 
 		var duration = this.clip.duration;
-	
+
 		this.actionTime = this.actionTime + clipDeltaTime;
-	
-		if( this.loop === THREE.LoopOnce ) {
+
+		if ( this.loop === THREE.LoopOnce ) {
 
 			this.loopCount = 0;
 			this.clipTime = Math.min( Math.max( this.actionTime, 0 ), duration );
-	
+
 			// if time is changed since last time, see if we have hit a start/end limit
-			if( this.clipTime !== previousClipTime ) {
+			if ( this.clipTime !== previousClipTime ) {
 
-				if( this.clipTime === duration ) {
+				if ( this.clipTime === duration ) {
 
 					this.mixer.dispatchEvent( { type: 'finished', action: this, direction: 1 } );
 
-				}
-				else if( this.clipTime === 0 ) {
+				} else if ( this.clipTime === 0 ) {
 
 					this.mixer.dispatchEvent( { type: 'finished', action: this, direction: -1 } );
 
@@ -73,20 +72,20 @@ THREE.AnimationAction.prototype = {
 
 			}
 
-		
+
 			return this.clipTime;
 
 		}
-		
+
 		this.loopCount = Math.floor( this.actionTime / duration );
-	
+
 		var newClipTime = this.actionTime - this.loopCount * duration;
 		newClipTime = newClipTime % duration;
-	
+
 		// if we are ping pong looping, ensure that we go backwards when appropriate
-		if( this.loop == THREE.LoopPingPong ) {
+		if ( this.loop == THREE.LoopPingPong ) {
 
-			if( Math.abs( this.loopCount % 2 ) === 1 ) {
+			if ( Math.abs( this.loopCount % 2 ) === 1 ) {
 
 				newClipTime = duration - newClipTime;
 
@@ -96,12 +95,12 @@ THREE.AnimationAction.prototype = {
 
 		this.clipTime = newClipTime;
 
-		if( this.loopCount !== previousLoopCount ) {
+		if ( this.loopCount !== previousLoopCount ) {
 
    			this.mixer.dispatchEvent( { type: 'loop', action: this, loopDelta: ( this.loopCount - this.loopCount ) } );
 
    		}
-	
+
 	   	return this.clipTime;
 
 	},
@@ -136,12 +135,12 @@ THREE.AnimationAction.prototype = {
 		var clipResults = this.clip.getAt( this.clipTime );
 
 		return clipResults;
-		
+
 	},
 
 	getTimeScaleAt: function( time ) {
 
-		if( this.timeScale.getAt ) {
+		if ( this.timeScale.getAt ) {
 			// pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip
 			return this.timeScale.getAt( time );
 
@@ -153,7 +152,7 @@ THREE.AnimationAction.prototype = {
 
 	getWeightAt: function( time ) {
 
-		if( this.weight.getAt ) {
+		if ( this.weight.getAt ) {
 			// pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip
 			return this.weight.getAt( time );
 

+ 39 - 41
src/animation/AnimationClip.js

@@ -1,7 +1,7 @@
 /**
  *
  * Reusable set of Tracks that represent an animation.
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -13,8 +13,8 @@ THREE.AnimationClip = function ( name, duration, tracks ) {
 	this.duration = ( duration !== undefined ) ? duration : -1;
 
 	// this means it should figure out its duration by scanning the tracks
-	if( this.duration < 0 ) {
-		for( var i = 0; i < this.tracks.length; i ++ ) {
+	if ( this.duration < 0 ) {
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
 			var track = this.tracks[i];
 			this.duration = Math.max( track.keys[ track.keys.length - 1 ].time );
 		}
@@ -26,7 +26,7 @@ THREE.AnimationClip = function ( name, duration, tracks ) {
 	this.optimize();
 
 	this.results = [];
-	
+
 };
 
 THREE.AnimationClip.prototype = {
@@ -37,7 +37,7 @@ THREE.AnimationClip.prototype = {
 
 		clipTime = Math.max( 0, Math.min( clipTime, this.duration ) );
 
-		for( var i = 0; i < this.tracks.length; i ++ ) {
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
 
 			var track = this.tracks[ i ];
 
@@ -50,7 +50,7 @@ THREE.AnimationClip.prototype = {
 
 	trim: function() {
 
-		for( var i = 0; i < this.tracks.length; i ++ ) {
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
 
 			this.tracks[ i ].trim( 0, this.duration );
 
@@ -62,7 +62,7 @@ THREE.AnimationClip.prototype = {
 
 	optimize: function() {
 
-		for( var i = 0; i < this.tracks.length; i ++ ) {
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
 
 			this.tracks[ i ].optimize();
 
@@ -81,7 +81,7 @@ THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetS
 	var numMorphTargets = morphTargetSequence.length;
 	var tracks = [];
 
-	for( var i = 0; i < numMorphTargets; i ++ ) {
+	for ( var i = 0; i < numMorphTargets; i ++ ) {
 
 		var keys = [];
 
@@ -92,7 +92,7 @@ THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetS
 		keys.sort( THREE.KeyframeTrack.keyComparer );
 
 		// if there is a key at the first frame, duplicate it as the last frame as well for perfect loop.
-		if( keys[0].time === 0 ) {
+		if ( keys[0].time === 0 ) {
 			keys.push( {
 				time: numMorphTargets,
 				value: keys[0].value
@@ -108,9 +108,9 @@ THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetS
 
 THREE.AnimationClip.findByName = function( clipArray, name ) {
 
-	for( var i = 0; i < clipArray.length; i ++ ) {
+	for ( var i = 0; i < clipArray.length; i ++ ) {
 
-		if( clipArray[i].name === name ) {
+		if ( clipArray[i].name === name ) {
 
 			return clipArray[i];
 
@@ -122,7 +122,7 @@ THREE.AnimationClip.findByName = function( clipArray, name ) {
 };
 
 THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets, fps ) {
-	
+
 	var animationToMorphTargets = {};
 
 	// tested with https://regex101.com/ on trick sequences such flamingo_flyA_003, flamingo_run1_003, crdeath0059
@@ -133,13 +133,13 @@ THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets
 
 		var morphTarget = morphTargets[ i ];
 		var parts = morphTarget.name.match( pattern );
-	
+
 		if ( parts && parts.length > 1 ) {
 
 			var name = parts[ 1 ];
 
 			var animationMorphTargets = animationToMorphTargets[ name ];
-			if( ! animationMorphTargets ) {
+			if ( ! animationMorphTargets ) {
 				animationToMorphTargets[ name ] = animationMorphTargets = [];
 			}
 
@@ -151,7 +151,7 @@ THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets
 
 	var clips = [];
 
-	for( var name in animationToMorphTargets ) {
+	for ( var name in animationToMorphTargets ) {
 
 		clips.push( THREE.AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps ) );
 	}
@@ -165,7 +165,7 @@ THREE.AnimationClip.parse = function( json ) {
 
 	var tracks = [];
 
-	for( var i = 0; i < json.tracks.length; i ++ ) {
+	for ( var i = 0; i < json.tracks.length; i ++ ) {
 
 		tracks.push( THREE.KeyframeTrack.parse( json.tracks[i] ).scale( 1.0 / json.fps ) );
 
@@ -179,7 +179,7 @@ THREE.AnimationClip.parse = function( json ) {
 // parse the animation.hierarchy format
 THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 
-	if( ! animation ) {
+	if ( ! animation ) {
 		console.error( "  no animation in JSONLoader data" );
 		return null;
 	}
@@ -188,20 +188,20 @@ THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 
 		var keys = [];
 
-		for( var k = 0; k < animationKeys.length; k ++ ) {
+		for ( var k = 0; k < animationKeys.length; k ++ ) {
 
 			var animationKey = animationKeys[k];
 
-			if( animationKey[propertyName] !== undefined ) {
+			if ( animationKey[propertyName] !== undefined ) {
 
 				keys.push( { time: animationKey.time, value: animationKeyToValueFunc( animationKey ) } );
 			}
-	
+
 		}
 
 		// only return track if there are actually keys.
-		if( keys.length > 0 ) {
-		
+		if ( keys.length > 0 ) {
+
 			return new trackType( trackName, keys );
 
 		}
@@ -223,19 +223,19 @@ THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 		var animationKeys = hierarchyTracks[ h ].keys;
 
 		// skip empty tracks
-		if( ! animationKeys || animationKeys.length == 0 ) {
+		if ( ! animationKeys || animationKeys.length == 0 ) {
 			continue;
 		}
 
 		// process morph targets in a way exactly compatible with AnimationHandler.init( animation )
-		if( animationKeys[0].morphTargets ) {
+		if ( animationKeys[0].morphTargets ) {
 
 			// figure out all morph targets used in this track
 			var morphTargetNames = {};
-			for( var k = 0; k < animationKeys.length; k ++ ) {
+			for ( var k = 0; k < animationKeys.length; k ++ ) {
 
-				if( animationKeys[k].morphTargets ) {
-					for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
+				if ( animationKeys[k].morphTargets ) {
+					for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
 
 						morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1;
 					}
@@ -244,11 +244,11 @@ THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 			}
 
 			// create a track for each morph target with all zero morphTargetInfluences except for the keys in which the morphTarget is named.
-			for( var morphTargetName in morphTargetNames ) {
+			for ( var morphTargetName in morphTargetNames ) {
 
 				var keys = [];
 
-				for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
+				for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
 
 					var animationKey = animationKeys[k];
 
@@ -256,7 +256,7 @@ THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 							time: animationKey.time,
 							value: (( animationKey.morphTarget === morphTargetName ) ? 1 : 0 )
 						});
-				
+
 				}
 
 				tracks.push( new THREE.NumberKeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) );
@@ -265,41 +265,39 @@ THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) {
 
 			duration = morphTargetNames.length * ( fps || 1.0 );
 
-		}
-		else {
+		} else {
 
 			var boneName = nodeName + '.bones[' + bones[ h ].name + ']';
-		
+
 			// track contains positions...
 			var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', THREE.VectorKeyframeTrack, function( animationKey ) {
 					return new THREE.Vector3().fromArray( animationKey.pos )
 				} );
 
-			if( positionTrack ) tracks.push( positionTrack );
-			
+			if ( positionTrack ) tracks.push( positionTrack );
+
 			// track contains quaternions...
 			var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', THREE.QuaternionKeyframeTrack, function( animationKey ) {
-					if( animationKey.rot.slerp ) {
+					if ( animationKey.rot.slerp ) {
 						return animationKey.rot.clone();
-					}
-					else {
+					} else {
 						return new THREE.Quaternion().fromArray( animationKey.rot );
 					}
 				} );
 
-			if( quaternionTrack ) tracks.push( quaternionTrack );
+			if ( quaternionTrack ) tracks.push( quaternionTrack );
 
 			// track contains quaternions...
 			var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', THREE.VectorKeyframeTrack, function( animationKey ) {
 					return new THREE.Vector3().fromArray( animationKey.scl )
 				} );
 
-			if( scaleTrack ) tracks.push( scaleTrack );
+			if ( scaleTrack ) tracks.push( scaleTrack );
 
 		}
 	}
 
-	if( tracks.length === 0 ) {
+	if ( tracks.length === 0 ) {
 
 		return null;
 

+ 32 - 32
src/animation/AnimationMixer.js

@@ -33,23 +33,23 @@ THREE.AnimationMixer.prototype = {
 
 		var root = action.localRoot || this.root;
 
-		for( var i = 0; i < tracks.length; i ++ ) {
+		for ( var i = 0; i < tracks.length; i ++ ) {
 
 			var track = tracks[ i ];
 
-			var propertyBindingKey = root.uuid + '-' + track.name;			
+			var propertyBindingKey = root.uuid + '-' + track.name;
 			var propertyBinding = this.propertyBindingMap[ propertyBindingKey ];
 
-			if( propertyBinding === undefined ) {
-			
+			if ( propertyBinding === undefined ) {
+
 				propertyBinding = new THREE.PropertyBinding( root, track.name );
 				this.propertyBindingMap[ propertyBindingKey ] = propertyBinding;
-			
+
 			}
 
 			// push in the same order as the tracks.
 			action.propertyBindings.push( propertyBinding );
-			
+
 			// track usages of shared property bindings, because if we leave too many around, the mixer can get slow
 			propertyBinding.referenceCount += 1;
 
@@ -59,14 +59,14 @@ THREE.AnimationMixer.prototype = {
 
 	removeAllActions: function() {
 
-		for( var i = 0; i < this.actions.length; i ++ ) {
+		for ( var i = 0; i < this.actions.length; i ++ ) {
 
 			this.actions[i].mixer = null;
-			
+
 		}
 
 		// unbind all property bindings
-		for( var properyBindingKey in this.propertyBindingMap ) {
+		for ( var properyBindingKey in this.propertyBindingMap ) {
 
 			this.propertyBindingMap[ properyBindingKey ].unbind();
 
@@ -95,16 +95,16 @@ THREE.AnimationMixer.prototype = {
 		var root = action.localRoot || this.root;
 		var tracks = action.clip.tracks;
 
-		for( var i = 0; i < tracks.length; i ++ ) {
-		
+		for ( var i = 0; i < tracks.length; i ++ ) {
+
 			var track = tracks[ i ];
 
-			var propertyBindingKey = root.uuid + '-' + track.name;			
+			var propertyBindingKey = root.uuid + '-' + track.name;
 			var propertyBinding = this.propertyBindingMap[ propertyBindingKey ];
-	
+
 			propertyBinding.referenceCount -= 1;
 
-			if( propertyBinding.referenceCount <= 0 ) {
+			if ( propertyBinding.referenceCount <= 0 ) {
 
 				propertyBinding.unbind();
 
@@ -120,9 +120,9 @@ THREE.AnimationMixer.prototype = {
 	// can be optimized if needed
 	findActionByName: function( name ) {
 
-		for( var i = 0; i < this.actions.length; i ++ ) {
+		for ( var i = 0; i < this.actions.length; i ++ ) {
 
-			if( this.actions[i].name === name ) return this.actions[i];
+			if ( this.actions[i].name === name ) return this.actions[i];
 
 		}
 
@@ -145,7 +145,7 @@ THREE.AnimationMixer.prototype = {
 
 		keys.push( { time: this.time, value: 1 } );
 		keys.push( { time: this.time + duration, value: 0 } );
-		
+
 		action.weight = new THREE.NumberKeyframeTrack( "weight", keys );
 
 		return this;
@@ -153,12 +153,12 @@ THREE.AnimationMixer.prototype = {
 	},
 
 	fadeIn: function( action, duration ) {
-		
+
 		var keys = [];
-		
+
 		keys.push( { time: this.time, value: 0 } );
 		keys.push( { time: this.time + duration, value: 1 } );
-		
+
 		action.weight = new THREE.NumberKeyframeTrack( "weight", keys );
 
 		return this;
@@ -168,10 +168,10 @@ THREE.AnimationMixer.prototype = {
 	warp: function( action, startTimeScale, endTimeScale, duration ) {
 
 		var keys = [];
-		
+
 		keys.push( { time: this.time, value: startTimeScale } );
 		keys.push( { time: this.time + duration, value: endTimeScale } );
-		
+
 		action.timeScale = new THREE.NumberKeyframeTrack( "timeScale", keys );
 
 		return this;
@@ -183,8 +183,8 @@ THREE.AnimationMixer.prototype = {
 		this.fadeOut( fadeOutAction, duration );
 		this.fadeIn( fadeInAction, duration );
 
-		if( warp ) {
-	
+		if ( warp ) {
+
 			var startEndRatio = fadeOutAction.clip.duration / fadeInAction.clip.duration;
 			var endStartRatio = 1.0 / startEndRatio;
 
@@ -194,7 +194,7 @@ THREE.AnimationMixer.prototype = {
 		}
 
 		return this;
-		
+
 	},
 
 	update: function( deltaTime ) {
@@ -202,7 +202,7 @@ THREE.AnimationMixer.prototype = {
 		var mixerDeltaTime = deltaTime * this.timeScale;
 		this.time += mixerDeltaTime;
 
-		for( var i = 0; i < this.actions.length; i ++ ) {
+		for ( var i = 0; i < this.actions.length; i ++ ) {
 
 			var action = this.actions[i];
 
@@ -210,12 +210,12 @@ THREE.AnimationMixer.prototype = {
 
 			var actionTimeScale = action.getTimeScaleAt( this.time );
 			var actionDeltaTime = mixerDeltaTime * actionTimeScale;
-		
+
 			var actionResults = action.update( actionDeltaTime );
 
-			if( action.weight <= 0 || ! action.enabled ) continue;
+			if ( action.weight <= 0 || ! action.enabled ) continue;
 
-			for( var j = 0; j < actionResults.length; j ++ ) {
+			for ( var j = 0; j < actionResults.length; j ++ ) {
 
 				var name = action.clip.tracks[j].name;
 
@@ -224,16 +224,16 @@ THREE.AnimationMixer.prototype = {
 			}
 
 		}
-	
+
 		// apply to nodes
-		for( var propertyBindingKey in this.propertyBindingMap ) {
+		for ( var propertyBindingKey in this.propertyBindingMap ) {
 
 			this.propertyBindingMap[ propertyBindingKey ].apply();
 
 		}
 
 		return this;
-		
+
 	}
 
 };

+ 35 - 39
src/animation/AnimationUtils.js

@@ -3,27 +3,27 @@
  * @author David Sarno / http://lighthaus.us/
  */
 
- THREE.AnimationUtils = {
+THREE.AnimationUtils = {
 
- 	getEqualsFunc: function( exemplarValue ) {
+	getEqualsFunc: function( exemplarValue ) {
 
-		if( exemplarValue.equals ) {
+		if ( exemplarValue.equals ) {
 			return function equals_object( a, b ) {
 				return a.equals( b );
 			}
 		}
 
 		return function equals_primitive( a, b ) {
-			return ( a === b );	
+			return ( a === b );
 		};
 
 	},
 
- 	clone: function( exemplarValue ) {
+	clone: function( exemplarValue ) {
 
- 		var typeName = typeof exemplarValue;
-		if( typeName === "object" ) {
-			if( exemplarValue.clone ) {
+		var typeName = typeof exemplarValue;
+		if ( typeName === "object" ) {
+			if ( exemplarValue.clone ) {
 				return exemplarValue.clone();
 			}
 			console.error( "can not figure out how to copy exemplarValue", exemplarValue );
@@ -33,7 +33,7 @@
 
 	},
 
- 	lerp: function( a, b, alpha, interTrack ) {
+	lerp: function( a, b, alpha, interTrack ) {
 
 		var lerpFunc = THREE.AnimationUtils.getLerpFunc( a, interTrack );
 
@@ -44,7 +44,7 @@
 	lerp_object: function( a, b, alpha ) {
 		return a.lerp( b, alpha );
 	},
-	
+
 	slerp_object: function( a, b, alpha ) {
 		return a.slerp( b, alpha );
 	},
@@ -60,57 +60,53 @@
 	lerp_boolean_immediate: function( a, b, alpha ) {
 		return a;
 	},
-	
+
 	lerp_string: function( a, b, alpha ) {
 		return ( alpha < 0.5 ) ? a : b;
 	},
-	
+
 	lerp_string_immediate: function( a, b, alpha ) {
- 		return a;		 		
+ 		return a;
  	},
 
-	// NOTE: this is an accumulator function that modifies the first argument (e.g. a).  This is to minimize memory alocations.
+	// NOTE: this is an accumulator function that modifies the first argument (e.g. a).	This is to minimize memory alocations.
 	getLerpFunc: function( exemplarValue, interTrack ) {
 
-		if( exemplarValue === undefined || exemplarValue === null ) throw new Error( "examplarValue is null" );
+		if ( exemplarValue === undefined || exemplarValue === null ) throw new Error( "examplarValue is null" );
 
 		var typeName = typeof exemplarValue;
-		switch( typeName ) {
-		 	case "object": {
 
-				if( exemplarValue.lerp ) {
+		switch( typeName ) {
 
+			case "object":
+				if ( exemplarValue.lerp ) {
 					return THREE.AnimationUtils.lerp_object;
-
 				}
-				if( exemplarValue.slerp ) {
 
+				if ( exemplarValue.slerp ) {
 					return THREE.AnimationUtils.slerp_object;
-
 				}
 				break;
-			}
-		 	case "number": {
+
+			case "number":
 				return THREE.AnimationUtils.lerp_number;
-		 	}	
-		 	case "boolean": {
-		 		if( interTrack ) {
+
+			case "boolean":
+				if ( interTrack ) {
 					return THREE.AnimationUtils.lerp_boolean;
-		 		}
-		 		else {
+				} else {
 					return THREE.AnimationUtils.lerp_boolean_immediate;
-		 		}
-		 	}
-		 	case "string": {
-		 		if( interTrack ) {
+				}
+
+			case "string":
+				if ( interTrack ) {
 					return THREE.AnimationUtils.lerp_string;
-		 		}
-		 		else {
+				} else {
 					return THREE.AnimationUtils.lerp_string_immediate;
-			 	}
-		 	}
-		};
+				}
+
+		}
 
 	}
-	
-};
+
+};

+ 27 - 27
src/animation/KeyframeTrack.js

@@ -8,8 +8,8 @@
 
 THREE.KeyframeTrack = function ( name, keys ) {
 
-	if( name === undefined ) throw new Error( "track name is undefined" );
-	if( keys === undefined || keys.length === 0 ) throw new Error( "no keys in track named " + name );
+	if ( name === undefined ) throw new Error( "track name is undefined" );
+	if ( keys === undefined || keys.length === 0 ) throw new Error( "no keys in track named " + name );
 
 	this.name = name;
 	this.keys = keys;	// time in seconds, value as value
@@ -19,6 +19,7 @@ THREE.KeyframeTrack = function ( name, keys ) {
 
 	this.validate();
 	this.optimize();
+
 };
 
 THREE.KeyframeTrack.prototype = {
@@ -38,7 +39,7 @@ THREE.KeyframeTrack.prototype = {
 			this.lastIndex --;
 		}
 
-		if( this.lastIndex >= this.keys.length ) {
+		if ( this.lastIndex >= this.keys.length ) {
 
 			this.setResult( this.keys[ this.keys.length - 1 ].value );
 
@@ -46,7 +47,7 @@ THREE.KeyframeTrack.prototype = {
 
 		}
 
-		if( this.lastIndex === 0 ) {
+		if ( this.lastIndex === 0 ) {
 
 			this.setResult( this.keys[ 0 ].value );
 
@@ -58,7 +59,7 @@ THREE.KeyframeTrack.prototype = {
 		this.setResult( prevKey.value );
 
 		// if true, means that prev/current keys are identical, thus no interpolation required.
-		if( prevKey.constantToNext ) {
+		if ( prevKey.constantToNext ) {
 
 			return this.result;
 
@@ -76,9 +77,9 @@ THREE.KeyframeTrack.prototype = {
 	// move all keyframes either forwards or backwards in time
 	shift: function( timeOffset ) {
 
-		if( timeOffset !== 0.0 ) {
+		if ( timeOffset !== 0.0 ) {
 
-			for( var i = 0; i < this.keys.length; i ++ ) {
+			for ( var i = 0; i < this.keys.length; i ++ ) {
 				this.keys[i].time += timeOffset;
 			}
 
@@ -91,9 +92,9 @@ THREE.KeyframeTrack.prototype = {
 	// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
 	scale: function( timeScale ) {
 
-		if( timeScale !== 1.0 ) {
+		if ( timeScale !== 1.0 ) {
 
-			for( var i = 0; i < this.keys.length; i ++ ) {
+			for ( var i = 0; i < this.keys.length; i ++ ) {
 				this.keys[i].time *= timeScale;
 			}
 
@@ -108,24 +109,23 @@ THREE.KeyframeTrack.prototype = {
  	trim: function( startTime, endTime ) {
 
 		var firstKeysToRemove = 0;
-		for( var i = 1; i < this.keys.length; i ++ ) {
-			if( this.keys[i] <= startTime ) {
+		for ( var i = 1; i < this.keys.length; i ++ ) {
+			if ( this.keys[i] <= startTime ) {
 				firstKeysToRemove ++;
 			}
 		}
 
 		var lastKeysToRemove = 0;
-		for( var i = this.keys.length - 2; i > 0; i ++ ) {
-			if( this.keys[i] >= endTime ) {
+		for ( var i = this.keys.length - 2; i > 0; i ++ ) {
+			if ( this.keys[i] >= endTime ) {
 				lastKeysToRemove ++;
-			}
-			else {
+			} else {
 				break;
 			}
 		}
 
 		// remove last keys first because it doesn't affect the position of the first keys (the otherway around doesn't work as easily)
-		if( ( firstKeysToRemove + lastKeysToRemove ) > 0 ) {
+		if ( ( firstKeysToRemove + lastKeysToRemove ) > 0 ) {
 			this.keys = this.keys.splice( firstKeysToRemove, this.keys.length - lastKeysToRemove - firstKeysToRemove );;
 		}
 
@@ -149,31 +149,31 @@ THREE.KeyframeTrack.prototype = {
 
 		var prevKey = null;
 
-		if( this.keys.length === 0 ) {
+		if ( this.keys.length === 0 ) {
 			console.error( "  track is empty, no keys", this );
 			return;
 		}
 
-		for( var i = 0; i < this.keys.length; i ++ ) {
+		for ( var i = 0; i < this.keys.length; i ++ ) {
 
 			var currKey = this.keys[i];
 
-			if( ! currKey ) {
+			if ( ! currKey ) {
 				console.error( "  key is null in track", this, i );
 				return;
 			}
 
-			if( ( typeof currKey.time ) !== 'number' || Number.isNaN( currKey.time ) ) {
+			if ( ( typeof currKey.time ) !== 'number' || Number.isNaN( currKey.time ) ) {
 				console.error( "  key.time is not a valid number", this, i, currKey );
 				return;
 			}
 
-			if( currKey.value === undefined || currKey.value === null) {
+			if ( currKey.value === undefined || currKey.value === null) {
 				console.error( "  key.value is null in track", this, i, currKey );
 				return;
 			}
 
-			if( prevKey && prevKey.time > currKey.time ) {
+			if ( prevKey && prevKey.time > currKey.time ) {
 				console.error( "  key.time is less than previous key time, out of order keys", this, i, currKey, prevKey );
 				return;
 			}
@@ -195,20 +195,20 @@ THREE.KeyframeTrack.prototype = {
 
 		var equalsFunc = THREE.AnimationUtils.getEqualsFunc( prevKey.value );
 
-		for( var i = 1; i < this.keys.length - 1; i ++ ) {
+		for ( var i = 1; i < this.keys.length - 1; i ++ ) {
 			var currKey = this.keys[i];
 			var nextKey = this.keys[i+1];
 
 			// if prevKey & currKey are the same time, remove currKey.  If you want immediate adjacent keys, use an epsilon offset
 			// it is not possible to have two keys at the same time as we sort them.  The sort is not stable on keys with the same time.
-			if( ( prevKey.time === currKey.time ) ) {
+			if ( ( prevKey.time === currKey.time ) ) {
 
 				continue;
 
 			}
 
 			// remove completely unnecessary keyframes that are the same as their prev and next keys
-			if( this.compareValues( prevKey.value, currKey.value ) && this.compareValues( currKey.value, nextKey.value ) ) {
+			if ( this.compareValues( prevKey.value, currKey.value ) && this.compareValues( currKey.value, nextKey.value ) ) {
 
 				continue;
 
@@ -236,7 +236,7 @@ THREE.KeyframeTrack.keyComparer = function keyComparator(key0, key1) {
 
 THREE.KeyframeTrack.parse = function( json ) {
 
-	if( json.type === undefined ) throw new Error( "track type undefined, can not parse" );
+	if ( json.type === undefined ) throw new Error( "track type undefined, can not parse" );
 
 	var trackType = THREE.KeyframeTrack.GetTrackTypeForTypeName( json.type );
 
@@ -271,4 +271,4 @@ THREE.KeyframeTrack.GetTrackTypeForTypeName = function( typeName ) {
 	};
 
 	throw new Error( "Unsupported typeName: " + typeName );
-};
+};

+ 96 - 98
src/animation/PropertyBinding.js

@@ -1,7 +1,7 @@
 /**
  *
  * A track bound to a real value in the scene graph.
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -23,7 +23,7 @@ THREE.PropertyBinding = function ( rootNode, trackName ) {
 	this.propertyIndex = parseResults.propertyIndex;
 
 	this.node = THREE.PropertyBinding.findNode( rootNode, this.nodeName ) || rootNode;
-	
+
 	this.cumulativeValue = null;
 	this.cumulativeWeight = 0;
 };
@@ -40,22 +40,21 @@ THREE.PropertyBinding.prototype = {
 	},
 
 	accumulate: function( value, weight ) {
-		
-		if( ! this.isBound ) this.bind();
 
-		if( this.cumulativeWeight === 0 ) {
+		if ( ! this.isBound ) this.bind();
+
+		if ( this.cumulativeWeight === 0 ) {
 
-			if( weight > 0 ) {
+			if ( weight > 0 ) {
 
-				if( this.cumulativeValue === null ) {
+				if ( this.cumulativeValue === null ) {
 					this.cumulativeValue = THREE.AnimationUtils.clone( value );
 				}
 				this.cumulativeWeight = weight;
 
 			}
 
-		}
-		else {
+		} else {
 
 			var lerpAlpha = weight / ( this.cumulativeWeight + weight );
 			this.cumulativeValue = this.lerpValue( this.cumulativeValue, value, lerpAlpha );
@@ -67,7 +66,7 @@ THREE.PropertyBinding.prototype = {
 
 	unbind: function() {
 
-		if( ! this.isBound ) return;
+		if ( ! this.isBound ) return;
 
 		this.setValue( this.originalValue );
 
@@ -75,7 +74,7 @@ THREE.PropertyBinding.prototype = {
 		this.getValue = null;
 		this.lerpValue = null;
 		this.equalsValue = null;
-		this.triggerDirty = null;	
+		this.triggerDirty = null;
 		this.isBound = false;
 
 	},
@@ -83,59 +82,57 @@ THREE.PropertyBinding.prototype = {
 	// bind to the real property in the scene graph, remember original value, memorize various accessors for speed/inefficiency
 	bind: function() {
 
-		if( this.isBound ) return;
+		if ( this.isBound ) return;
 
 		var targetObject = this.node;
 
  		// ensure there is a value node
-		if( ! targetObject ) {
+		if ( ! targetObject ) {
 			console.error( "  trying to update node for track: " + this.trackName + " but it wasn't found." );
 			return;
 		}
 
-		if( this.objectName ) {
+		if ( this.objectName ) {
 			// special case were we need to reach deeper into the hierarchy to get the face materials....
-			if( this.objectName === "materials" ) {
-				if( ! targetObject.material ) {
+			if ( this.objectName === "materials" ) {
+				if ( ! targetObject.material ) {
 					console.error( '  can not bind to material as node does not have a material', this );
-					return;				
+					return;
 				}
-				if( ! targetObject.material.materials ) {
+				if ( ! targetObject.material.materials ) {
 					console.error( '  can not bind to material.materials as node.material does not have a materials array', this );
-					return;				
+					return;
 				}
 				targetObject = targetObject.material.materials;
-			}
-			else if( this.objectName === "bones" ) {
-				if( ! targetObject.skeleton ) {
+			} else if ( this.objectName === "bones" ) {
+				if ( ! targetObject.skeleton ) {
 					console.error( '  can not bind to bones as node does not have a skeleton', this );
 					return;
 				}
 				// potential future optimization: skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
-				
+
 				targetObject = targetObject.skeleton.bones;
 
 				// support resolving morphTarget names into indices.
-				for( var i = 0; i < targetObject.length; i ++ ) {
-					if( targetObject[i].name === this.objectIndex ) {
+				for ( var i = 0; i < targetObject.length; i ++ ) {
+					if ( targetObject[i].name === this.objectIndex ) {
 						this.objectIndex = i;
 						break;
 					}
 				}
-			}
-			else {
+			} else {
 
-				if( targetObject[ this.objectName ] === undefined ) {
-					console.error( '  can not bind to objectName of node, undefined', this );			
+				if ( targetObject[ this.objectName ] === undefined ) {
+					console.error( '  can not bind to objectName of node, undefined', this );
 					return;
 				}
 				targetObject = targetObject[ this.objectName ];
 			}
-			
-			if( this.objectIndex !== undefined ) {
-				if( targetObject[ this.objectIndex ] === undefined ) {
+
+			if ( this.objectIndex !== undefined ) {
+				if ( targetObject[ this.objectIndex ] === undefined ) {
 					console.error( "  trying to bind to objectIndex of objectName, but is undefined:", this, targetObject );
-					return;				
+					return;
 				}
 
 				targetObject = targetObject[ this.objectIndex ];
@@ -145,27 +142,27 @@ THREE.PropertyBinding.prototype = {
 
  		// special case mappings
  		var nodeProperty = targetObject[ this.propertyName ];
-		if( ! nodeProperty ) {
-			console.error( "  trying to update property for track: " + this.nodeName + '.' + this.propertyName + " but it wasn't found.", targetObject );				
+		if ( ! nodeProperty ) {
+			console.error( "  trying to update property for track: " + this.nodeName + '.' + this.propertyName + " but it wasn't found.", targetObject );
 			return;
 		}
 
 		// access a sub element of the property array (only primitives are supported right now)
-		if( this.propertyIndex !== undefined ) {
+		if ( this.propertyIndex !== undefined ) {
 
-			if( this.propertyName === "morphTargetInfluences" ) {
+			if ( this.propertyName === "morphTargetInfluences" ) {
 				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
-				
+
 				// support resolving morphTarget names into indices.
-				if( ! targetObject.geometry ) {
-					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry', this );				
+				if ( ! targetObject.geometry ) {
+					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry', this );
 				}
-				if( ! targetObject.geometry.morphTargets ) {
-					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );				
+				if ( ! targetObject.geometry.morphTargets ) {
+					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );
 				}
-				
-				for( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
-					if( targetObject.geometry.morphTargets[i].name === this.propertyIndex ) {
+
+				for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
+					if ( targetObject.geometry.morphTargets[i].name === this.propertyIndex ) {
 						this.propertyIndex = i;
 						break;
 					}
@@ -173,7 +170,7 @@ THREE.PropertyBinding.prototype = {
 			}
 
 			this.setValue = function setValue_propertyIndexed( value ) {
-				if( ! this.equalsValue( nodeProperty[ this.propertyIndex ], value ) ) {
+				if ( ! this.equalsValue( nodeProperty[ this.propertyIndex ], value ) ) {
 					nodeProperty[ this.propertyIndex ] = value;
 					return true;
 				}
@@ -185,11 +182,11 @@ THREE.PropertyBinding.prototype = {
 			};
 
 		}
-		// must use copy for Object3D.Euler/Quaternion		
-		else if( nodeProperty.copy ) {
-			
+		// must use copy for Object3D.Euler/Quaternion
+		else if ( nodeProperty.copy ) {
+
 			this.setValue = function setValue_propertyObject( value ) {
-				if( ! this.equalsValue( nodeProperty, value ) ) {
+				if ( ! this.equalsValue( nodeProperty, value ) ) {
 					nodeProperty.copy( value );
 					return true;
 				}
@@ -205,8 +202,8 @@ THREE.PropertyBinding.prototype = {
 		else {
 
 			this.setValue = function setValue_property( value ) {
-				if( ! this.equalsValue( targetObject[ this.propertyName ], value ) ) {
-					targetObject[ this.propertyName ] = value;	
+				if ( ! this.equalsValue( targetObject[ this.propertyName ], value ) ) {
+					targetObject[ this.propertyName ] = value;
 					return true;
 				}
 				return false;
@@ -218,16 +215,15 @@ THREE.PropertyBinding.prototype = {
 
 		}
 
-		// trigger node dirty			
-		if( targetObject.needsUpdate !== undefined ) { // material
-			
+		// trigger node dirty
+		if ( targetObject.needsUpdate !== undefined ) { // material
+
 			this.triggerDirty = function triggerDirty_needsUpdate() {
 				this.node.needsUpdate = true;
 			}
 
-		}			
-		else if( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
-			
+		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
+
 			this.triggerDirty = function triggerDirty_matrixWorldNeedsUpdate() {
 				targetObject.matrixWorldNeedsUpdate = true;
 			}
@@ -246,13 +242,13 @@ THREE.PropertyBinding.prototype = {
 	apply: function() {
 
 		// for speed capture the setter pattern as a closure (sort of a memoization pattern: https://en.wikipedia.org/wiki/Memoization)
-		if( ! this.isBound ) this.bind();
+		if ( ! this.isBound ) this.bind();
 
 		// early exit if there is nothing to apply.
-		if( this.cumulativeWeight > 0 ) {
-		
+		if ( this.cumulativeWeight > 0 ) {
+
 			// blend with original value
-			if( this.cumulativeWeight < 1 ) {
+			if ( this.cumulativeWeight < 1 ) {
 
 				var remainingWeight = 1 - this.cumulativeWeight;
 				var lerpAlpha = remainingWeight / ( this.cumulativeWeight + remainingWeight );
@@ -262,7 +258,7 @@ THREE.PropertyBinding.prototype = {
 
 			var valueChanged = this.setValue( this.cumulativeValue );
 
-			if( valueChanged && this.triggerDirty ) {
+			if ( valueChanged && this.triggerDirty ) {
 				this.triggerDirty();
 			}
 
@@ -289,10 +285,10 @@ THREE.PropertyBinding.parseTrackName = function( trackName ) {
 	//	  .bone[Armature.DEF_cog].position
 	// created and tested via https://regex101.com/#javascript
 
-	var re = /^(([\w]+\/)*)([\w-\d]+)?(\.([\w]+)(\[([\w\d\[\]\_. ]+)\])?)?(\.([\w.]+)(\[([\w\d\[\]\_. ]+)\])?)$/; 
+	var re = /^(([\w]+\/)*)([\w-\d]+)?(\.([\w]+)(\[([\w\d\[\]\_. ]+)\])?)?(\.([\w.]+)(\[([\w\d\[\]\_. ]+)\])?)$/;
 	var matches = re.exec(trackName);
 
-	if( ! matches ) {
+	if ( ! matches ) {
 		throw new Error( "cannot parse trackName at all: " + trackName );
 	}
 
@@ -309,7 +305,7 @@ THREE.PropertyBinding.parseTrackName = function( trackName ) {
 		propertyIndex: matches[11]	// allowed to be null, specifies that the whole property is set.
 	};
 
-	if( results.propertyName === null || results.propertyName.length === 0 ) {
+	if ( results.propertyName === null || results.propertyName.length === 0 ) {
 		throw new Error( "can not parse propertyName from trackName: " + trackName );
 	}
 
@@ -319,69 +315,71 @@ THREE.PropertyBinding.parseTrackName = function( trackName ) {
 
 THREE.PropertyBinding.findNode = function( root, nodeName ) {
 
-	if( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
+	function searchSkeleton( skeleton ) {
 
-		return root;
+		for ( var i = 0; i < skeleton.bones.length; i ++ ) {
 
-	}
+			var bone = skeleton.bones[i];
 
-	// search into skeleton bones.
-	if( root.skeleton ) {
+			if ( bone.name === nodeName ) {
 
-		var searchSkeleton = function( skeleton ) {
+				return bone;
 
-			for( var i = 0; i < skeleton.bones.length; i ++ ) {
+			}
+		}
 
-				var bone = skeleton.bones[i];
+		return null;
 
-				if( bone.name === nodeName ) {
+	}
 
-					return bone;
+	function searchNodeSubtree( children ) {
 
-				}
-			}
+		for ( var i = 0; i < children.length; i ++ ) {
 
-			return null;
+			var childNode = children[i];
 
-		};
+			if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
 
-		var bone = searchSkeleton( root.skeleton );
+				return childNode;
 
-		if( bone ) {
+			}
 
-			return bone;
+			var result = searchNodeSubtree( childNode.children );
+
+			if ( result ) return result;
 
 		}
-	}
 
-	// search into node subtree.
-	if( root.children ) {
+		return null;
 
-		var searchNodeSubtree = function( children ) {
+	}
 
-			for( var i = 0; i < children.length; i ++ ) {
+	//
 
-				var childNode = children[i];
+	if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
 
-				if( childNode.name === nodeName || childNode.uuid === nodeName ) {
+		return root;
 
-					return childNode;
+	}
 
-				}
+	// search into skeleton bones.
+	if ( root.skeleton ) {
 
-				var result = searchNodeSubtree( childNode.children );
+		var bone = searchSkeleton( root.skeleton );
 
-				if( result ) return result;
+		if ( bone ) {
 
-			}
+			return bone;
 
-			return null;	
+		}
+	}
 
-		};
+	// search into node subtree.
+	if ( root.children ) {
 
 		var subTreeNode = searchNodeSubtree( root.children );
 
-		if( subTreeNode ) {
+		if ( subTreeNode ) {
 
 			return subTreeNode;
 

+ 3 - 4
src/animation/tracks/BooleanKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Boolean
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -43,8 +43,8 @@ THREE.BooleanKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -61,4 +61,3 @@ THREE.BooleanKeyframeTrack.parse = function( json ) {
 	return new THREE.BooleanKeyframeTrack( json.name, json.keys );
 
 };
- 

+ 4 - 5
src/animation/tracks/ColorKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Color
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -43,8 +43,8 @@ THREE.ColorKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -60,7 +60,7 @@ THREE.ColorKeyframeTrack.parse = function( json ) {
 
 	var keys = [];
 
-	for( var i = 0; i < json.keys.length; i ++ ) {
+	for ( var i = 0; i < json.keys.length; i ++ ) {
 		var jsonKey = json.keys[i];
 		keys.push( {
 			value: new THREE.Color().fromArray( jsonKey.value ),
@@ -71,4 +71,3 @@ THREE.ColorKeyframeTrack.parse = function( json ) {
 	return new THREE.ColorKeyframeTrack( json.name, keys );
 
 };
- 

+ 3 - 4
src/animation/tracks/NumberKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Numbers
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -43,8 +43,8 @@ THREE.NumberKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -61,4 +61,3 @@ THREE.NumberKeyframeTrack.parse = function( json ) {
 	return new THREE.NumberKeyframeTrack( json.name, json.keys );
 
 };
- 

+ 7 - 8
src/animation/tracks/QuaternionKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Quaternion
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -14,7 +14,7 @@ THREE.QuaternionKeyframeTrack = function ( name, keys ) {
 	this.result = this.keys[0].value.clone();
 
 };
- 
+
 THREE.QuaternionKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype );
 
 THREE.QuaternionKeyframeTrack.prototype.constructor = THREE.QuaternionKeyframeTrack;
@@ -41,10 +41,10 @@ THREE.QuaternionKeyframeTrack.prototype.compareValues = function( value0, value1
 
 THREE.QuaternionKeyframeTrack.prototype.multiply = function( quat ) {
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
+	for ( var i = 0; i < this.keys.length; i ++ ) {
 
 		this.keys[i].value.multiply( quat );
-		
+
 	}
 
 	return this;
@@ -55,8 +55,8 @@ THREE.QuaternionKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -72,7 +72,7 @@ THREE.QuaternionKeyframeTrack.parse = function( json ) {
 
 	var keys = [];
 
-	for( var i = 0; i < json.keys.length; i ++ ) {
+	for ( var i = 0; i < json.keys.length; i ++ ) {
 		var jsonKey = json.keys[i];
 		keys.push( {
 			value: new THREE.Quaternion().fromArray( jsonKey.value ),
@@ -83,4 +83,3 @@ THREE.QuaternionKeyframeTrack.parse = function( json ) {
 	return new THREE.QuaternionKeyframeTrack( json.name, keys );
 
 };
- 

+ 3 - 4
src/animation/tracks/StringKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Strings
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -43,8 +43,8 @@ THREE.StringKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -61,4 +61,3 @@ THREE.StringKeyframeTrack.parse = function( json ) {
 	return new THREE.StringKeyframeTrack( json.name, json.keys );
 
 };
- 

+ 4 - 5
src/animation/tracks/VectorKeyframeTrack.js

@@ -1,7 +1,7 @@
 /**
  *
  * A Track that interpolates Vectors
- * 
+ *
  * @author Ben Houston / http://clara.io/
  * @author David Sarno / http://lighthaus.us/
  */
@@ -43,8 +43,8 @@ THREE.VectorKeyframeTrack.prototype.clone = function() {
 
 	var clonedKeys = [];
 
-	for( var i = 0; i < this.keys.length; i ++ ) {
-		
+	for ( var i = 0; i < this.keys.length; i ++ ) {
+
 		var key = this.keys[i];
 		clonedKeys.push( {
 			time: key.time,
@@ -63,7 +63,7 @@ THREE.VectorKeyframeTrack.parse = function( json ) {
 
 	var keys = [];
 
-	for( var i = 0; i < json.keys.length; i ++ ) {
+	for ( var i = 0; i < json.keys.length; i ++ ) {
 		var jsonKey = json.keys[i];
 		keys.push( {
 			value: new valueType().fromArray( jsonKey.value ),
@@ -74,4 +74,3 @@ THREE.VectorKeyframeTrack.parse = function( json ) {
 	return new THREE.VectorKeyframeTrack( json.name, keys );
 
 };
- 

+ 3 - 3
src/cameras/CubeCamera.js

@@ -50,9 +50,9 @@ THREE.CubeCamera = function ( near, far, cubeResolution ) {
 		if ( this.parent === null ) this.updateMatrixWorld();
 
 		var renderTarget = this.renderTarget;
-		var generateMipmaps = renderTarget.generateMipmaps;
+		var generateMipmaps = renderTarget.texture.generateMipmaps;
 
-		renderTarget.generateMipmaps = false;
+		renderTarget.texture.generateMipmaps = false;
 
 		renderTarget.activeCubeFace = 0;
 		renderer.render( scene, cameraPX, renderTarget );
@@ -69,7 +69,7 @@ THREE.CubeCamera = function ( near, far, cubeResolution ) {
 		renderTarget.activeCubeFace = 4;
 		renderer.render( scene, cameraPZ, renderTarget );
 
-		renderTarget.generateMipmaps = generateMipmaps;
+		renderTarget.texture.generateMipmaps = generateMipmaps;
 
 		renderTarget.activeCubeFace = 5;
 		renderer.render( scene, cameraNZ, renderTarget );

+ 16 - 1
src/core/BufferGeometry.js

@@ -329,7 +329,7 @@ THREE.BufferGeometry.prototype = {
 
 				var lineDistances = new THREE.Float32Attribute( geometry.lineDistances.length, 1 );
 
-				this.addAttribute( 'lineDistance',  lineDistances.copyArray( geometry.lineDistances ) );
+				this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
 
 			}
 
@@ -434,6 +434,21 @@ THREE.BufferGeometry.prototype = {
 
 		}
 
+		if ( geometry.uvsNeedUpdate ) {
+
+				var attribute = this.attributes.uv;
+
+				if ( attribute !== undefined ) {
+
+						attribute.copyVector2sArray( geometry.uvs );
+						attribute.needsUpdate = true;
+
+				}
+
+				geometry.uvsNeedUpdate = false;
+
+		}
+
 		if ( geometry.lineDistancesNeedUpdate ) {
 
 			var attribute = this.attributes.lineDistance;

+ 2 - 10
src/core/Clock.js

@@ -18,17 +18,9 @@ THREE.Clock.prototype = {
 
 	constructor: THREE.Clock,
 
-	_now: function () {
-
-		return self.performance !== undefined && self.performance.now !== undefined
-			? self.performance.now()
-			: Date.now();
-
-	},
-
 	start: function () {
 
-		this.startTime = this._now();
+		this.startTime = self.performance.now();
 
 		this.oldTime = this.startTime;
 		this.running = true;
@@ -61,7 +53,7 @@ THREE.Clock.prototype = {
 
 		if ( this.running ) {
 
-			var newTime = this._now();
+			var newTime = self.performance.now();
 
 			diff = 0.001 * ( newTime - this.oldTime );
 			this.oldTime = newTime;

+ 2 - 2
src/core/Geometry.js

@@ -865,11 +865,11 @@ THREE.Geometry.prototype = {
 
 	sortFacesByMaterialIndex: function () {
 
-		// tag faces
-
 		var faces = this.faces;
 		var length = faces.length;
 
+		// tag faces
+
 		for ( var i = 0; i < length; i ++ ) {
 
 			faces[ i ]._id = i;

+ 49 - 16
src/core/Object3D.js

@@ -25,17 +25,17 @@ THREE.Object3D = function () {
 	var quaternion = new THREE.Quaternion();
 	var scale = new THREE.Vector3( 1, 1, 1 );
 
-	var onRotationChange = function () {
+	function onRotationChange() {
 
 		quaternion.setFromEuler( rotation, false );
 
-	};
+	}
 
-	var onQuaternionChange = function () {
+	function onQuaternionChange() {
 
 		rotation.setFromQuaternion( quaternion, undefined, false );
 
-	};
+	}
 
 	rotation.onChange( onRotationChange );
 	quaternion.onChange( onQuaternionChange );
@@ -94,7 +94,7 @@ THREE.Object3D.prototype = {
 
 	get eulerOrder () {
 
-		console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );
+		console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
 
 		return this.rotation.order;
 
@@ -102,7 +102,7 @@ THREE.Object3D.prototype = {
 
 	set eulerOrder ( value ) {
 
-		console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' );
+		console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
 
 		this.rotation.order = value;
 
@@ -126,6 +126,8 @@ THREE.Object3D.prototype = {
 
 	},
 
+	//
+
 	applyMatrix: function ( matrix ) {
 
 		this.matrix.multiplyMatrices( matrix, this.matrix );
@@ -595,8 +597,7 @@ THREE.Object3D.prototype = {
 
 		var isRootObject = ( meta === undefined );
 
-		var data = {};
-		var output = { object: data };
+		var output = {};
 
 		// meta is a hash used to collect geometries, materials.
 		// not providing it implies that this is the root object
@@ -621,22 +622,52 @@ THREE.Object3D.prototype = {
 
 		// standard Object3D serialization
 
-		data.uuid = this.uuid;
-		data.type = this.type;
+		var object = {};
+
+		object.uuid = this.uuid;
+		object.type = this.type;
+
+		if ( this.name !== '' ) object.name = this.name;
+		if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
+		if ( this.visible !== true ) object.visible = this.visible;
+
+		object.matrix = this.matrix.toArray();
 
-		if ( this.name !== '' ) data.name = this.name;
-		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
-		if ( this.visible !== true ) data.visible = this.visible;
+		//
 
-		data.matrix = this.matrix.toArray();
+		if ( this.geometry !== undefined ) {
+
+			if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
+
+				meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
+
+			}
+
+			object.geometry = this.geometry.uuid;
+
+		}
+
+		if ( this.material !== undefined ) {
+
+			if ( meta.materials[ this.material.uuid ] === undefined ) {
+
+				meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
+
+			}
+
+			object.material = this.material.uuid;
+
+		}
+
+		//
 
 		if ( this.children.length > 0 ) {
 
-			data.children = [];
+			object.children = [];
 
 			for ( var i = 0; i < this.children.length; i ++ ) {
 
-				data.children.push( this.children[ i ].toJSON( meta ).object );
+				object.children.push( this.children[ i ].toJSON( meta ).object );
 
 			}
 
@@ -656,6 +687,8 @@ THREE.Object3D.prototype = {
 
 		}
 
+		output.object = object;
+
 		return output;
 
 		// extract data from the cache hash

+ 2 - 2
src/core/Raycaster.js

@@ -39,7 +39,7 @@
 
 	}
 
-	var intersectObject = function ( object, raycaster, intersects, recursive ) {
+	function intersectObject( object, raycaster, intersects, recursive ) {
 
 		if ( object.visible === false ) return;
 
@@ -57,7 +57,7 @@
 
 		}
 
-	};
+	}
 
 	//
 

+ 6 - 7
src/extras/FontUtils.js

@@ -289,7 +289,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) {
 
 	// takes in an contour array and returns
 
-	var process = function ( contour, indices ) {
+	function process( contour, indices ) {
 
 		var n = contour.length;
 
@@ -383,11 +383,11 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) {
 		if ( indices ) return vertIndices;
 		return result;
 
-	};
+	}
 
 	// calculate area of the contour polygon
 
-	var area = function ( contour ) {
+	function area( contour ) {
 
 		var n = contour.length;
 		var a = 0.0;
@@ -400,9 +400,9 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) {
 
 		return a * 0.5;
 
-	};
+	}
 
-	var snip = function ( contour, u, v, w, n, verts ) {
+	function snip( contour, u, v, w, n, verts ) {
 
 		var p;
 		var ax, ay, bx, by;
@@ -452,8 +452,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) {
 
 		return true;
 
-	};
-
+	}
 
 	namespace.Triangulate = process;
 	namespace.Triangulate.area = area;

+ 8 - 8
src/extras/ImageUtils.js

@@ -45,7 +45,7 @@ THREE.ImageUtils = {
 
 		var loaded = 0;
 
-		var loadTexture = function ( i ) {
+		function loadTexture( i ) {
 
 			loader.load( array[ i ], function ( image ) {
 
@@ -63,7 +63,7 @@ THREE.ImageUtils = {
 
 			}, undefined, onError );
 
-		};
+		}
 
 		for ( var i = 0, il = array.length; i < il; ++ i ) {
 
@@ -91,24 +91,24 @@ THREE.ImageUtils = {
 
 		// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
 
-		var cross = function ( a, b ) {
+		function cross( a, b ) {
 
 			return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
 
-		};
+		}
 
-		var subtract = function ( a, b ) {
+		function subtract( a, b ) {
 
 			return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
 
-		};
+		}
 
-		var normalize = function ( a ) {
+		function normalize( a ) {
 
 			var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
 			return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
 
-		};
+		}
 
 		depth = depth | 1;
 

+ 1 - 1
src/extras/core/Path.js

@@ -197,7 +197,7 @@ THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
 
 		points.push( this.getPoint( i / divisions ) );
 
-		//if( !this.getPoint( i / divisions ) ) throw "DIE";
+		//if ( !this.getPoint( i / divisions ) ) throw "DIE";
 
 	}
 

+ 1 - 1
src/extras/geometries/CircleBufferGeometry.js

@@ -28,7 +28,7 @@ THREE.CircleBufferGeometry = function ( radius, segments, thetaStart, thetaLengt
 	var uvs = new Float32Array( vertices * 2 );
 
 	// center data is already zero, but need to set a few extras
-	normals[ 3 ] = 1.0;
+	normals[ 2 ] = 1.0;
 	uvs[ 0 ] = 0.5;
 	uvs[ 1 ] = 0.5;
 

+ 3 - 2
src/extras/geometries/EdgesGeometry.js

@@ -11,11 +11,12 @@ THREE.EdgesGeometry = function ( geometry, thresholdAngle ) {
 	var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) );
 
 	var edge = [ 0, 0 ], hash = {};
-	var sortFunction = function ( a, b ) {
+
+	function sortFunction( a, b ) {
 
 		return a - b;
 
-	};
+	}
 
 	var keys = [ 'a', 'b', 'c' ];
 

+ 1 - 1
src/extras/geometries/SphereBufferGeometry.js

@@ -88,7 +88,7 @@ THREE.SphereBufferGeometry = function ( radius, widthSegments, heightSegments, p
 
 	}
 
-	this.setIndex( new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) );
+	this.setIndex( new ( positions.count > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( indices, 1 ) );
 	this.addAttribute( 'position', positions );
 	this.addAttribute( 'normal', normals );
 	this.addAttribute( 'uv', uvs );

+ 10 - 1
src/extras/geometries/TubeGeometry.js

@@ -23,7 +23,8 @@ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed,
 		segments: segments,
 		radius: radius,
 		radialSegments: radialSegments,
-		closed: closed
+		closed: closed,
+		taper: taper
 	};
 
 	segments = segments || 64;
@@ -138,6 +139,14 @@ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed,
 
 THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
 THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry;
+THREE.TubeGeometry.prototype.clone = function() {
+
+	return new this.constructor( this.parameters.path,
+		this.parameters.segments, this.parameters.radius, this.parameters.radialSegments,
+		this.parameters.closed, this.parameters.taper
+	);
+
+};
 
 THREE.TubeGeometry.NoTaper = function ( u ) {
 

+ 3 - 2
src/extras/geometries/WireframeGeometry.js

@@ -7,11 +7,12 @@ THREE.WireframeGeometry = function ( geometry ) {
 	THREE.BufferGeometry.call( this );
 
 	var edge = [ 0, 0 ], hash = {};
-	var sortFunction = function ( a, b ) {
+
+	function sortFunction( a, b ) {
 
 		return a - b;
 
-	};
+	}
 
 	var keys = [ 'a', 'b', 'c' ];
 

+ 2 - 2
src/extras/helpers/CameraHelper.js

@@ -113,7 +113,7 @@ THREE.CameraHelper.prototype.update = function () {
 	var vector = new THREE.Vector3();
 	var camera = new THREE.Camera();
 
-	var setPoint = function ( point, x, y, z ) {
+	function setPoint( point, x, y, z ) {
 
 		vector.set( x, y, z ).unproject( camera );
 
@@ -129,7 +129,7 @@ THREE.CameraHelper.prototype.update = function () {
 
 		}
 
-	};
+	}
 
 	return function () {
 

+ 0 - 10
src/lights/AmbientLight.js

@@ -12,13 +12,3 @@ THREE.AmbientLight = function ( color ) {
 
 THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
 THREE.AmbientLight.prototype.constructor = THREE.AmbientLight;
-
-THREE.AmbientLight.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	data.object.color = this.color.getHex();
-
-	return data;
-
-};

+ 0 - 11
src/lights/DirectionalLight.js

@@ -74,14 +74,3 @@ THREE.DirectionalLight.prototype.copy = function ( source ) {
 	return this;
 
 };
-
-THREE.DirectionalLight.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	data.object.color = this.color.getHex();
-	data.object.intensity = this.intensity;
-
-	return data;
-
-};

+ 0 - 12
src/lights/HemisphereLight.js

@@ -29,15 +29,3 @@ THREE.HemisphereLight.prototype.copy = function ( source ) {
 	return this;
 
 };
-
-THREE.HemisphereLight.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	data.object.color = this.color.getHex();
-	data.object.groundColor = this.groundColor.getHex();
-	data.object.intensity = this.intensity;
-
-	return data;
-
-};

+ 21 - 4
src/lights/Light.js

@@ -17,11 +17,28 @@ THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
 THREE.Light.prototype.constructor = THREE.Light;
 
 THREE.Light.prototype.copy = function ( source ) {
-	
+
 	THREE.Object3D.prototype.copy.call( this, source );
-	
+
 	this.color.copy( source.color );
-	
+
 	return this;
 
-};
+};
+
+THREE.Light.prototype.toJSON = function ( meta ) {
+
+	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
+
+	data.object.color = this.color.getHex();
+	if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
+
+	if ( this.intensity !== undefined ) data.object.intensity = this.intensity;
+	if ( this.distance !== undefined ) data.object.distance = this.distance;
+	if ( this.angle !== undefined ) data.object.angle = this.angle;
+	if ( this.decay !== undefined ) data.object.decay = this.decay;
+	if ( this.exponent !== undefined ) data.object.exponent = this.exponent;
+
+	return data;
+
+};

+ 0 - 13
src/lights/PointLight.js

@@ -68,16 +68,3 @@ THREE.PointLight.prototype.copy = function ( source ) {
 	return this;
 
 };
-
-THREE.PointLight.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	data.object.color = this.color.getHex();
-	data.object.intensity = this.intensity;
-	data.object.distance = this.distance;
-	data.object.decay = this.decay;
-
-	return data;
-
-};

+ 0 - 14
src/lights/SpotLight.js

@@ -72,19 +72,5 @@ THREE.SpotLight.prototype.copy = function ( source ) {
 	this.shadowMapHeight = source.shadowMapHeight;
 
 	return this;
-}
-
-THREE.SpotLight.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	data.object.color = this.color.getHex();
-	data.object.intensity = this.intensity;
-	data.object.distance = this.distance;
-	data.object.angle = this.angle;
-	data.object.exponent = this.exponent;
-	data.object.decay = this.decay;
-
-	return data;
 
 };

+ 2 - 2
src/loaders/AnimationLoader.js

@@ -36,7 +36,7 @@ THREE.AnimationLoader.prototype = {
 
 		var animations = [];
 
-		for( var i = 0; i < json.length; i ++ ) {
+		for ( var i = 0; i < json.length; i ++ ) {
 
 			var clip = THREE.AnimationClip.parse( json[i] );
 
@@ -48,4 +48,4 @@ THREE.AnimationLoader.prototype = {
 
 	}
 
-};
+};

+ 8 - 0
src/loaders/ImageLoader.js

@@ -20,14 +20,22 @@ THREE.ImageLoader.prototype = {
 
 		if ( cached !== undefined ) {
 
+			scope.manager.itemStart( url );
+
 			if ( onLoad ) {
 
 				setTimeout( function () {
 
 					onLoad( cached );
 
+					scope.manager.itemEnd( url );
+
 				}, 0 );
 
+			} else {
+
+				scope.manager.itemEnd( url );
+
 			}
 
 			return cached;

+ 8 - 9
src/loaders/JSONLoader.js

@@ -509,27 +509,26 @@ THREE.JSONLoader.prototype = {
 
 			// parse old style Bone/Hierarchy animations
 			var animations = [];
-			if( json.animation !== undefined ) {
+			if ( json.animation !== undefined ) {
 				animations.push( json.animation );
 			}
-			if( json.animations !== undefined ) {
-				if( json.animations.length ) {
+			if ( json.animations !== undefined ) {
+				if ( json.animations.length ) {
 					animations = animations.concat( json.animations );
-				}
-				else {
+				} else {
 					animations.push( json.animations );
 				}
 			}
 
-			for( var i = 0; i < animations.length; i ++ ) {
+			for ( var i = 0; i < animations.length; i ++ ) {
 
 				var clip = THREE.AnimationClip.parseAnimation( animations[i], geometry.bones );
-				if( clip ) outputAnimations.push( clip );
+				if ( clip ) outputAnimations.push( clip );
 
 			}
 
 			// parse implicit morph animations
-			if( geometry.morphTargets ) {
+			if ( geometry.morphTargets ) {
 
 				// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
 				var morphAnimationClips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
@@ -537,7 +536,7 @@ THREE.JSONLoader.prototype = {
 
 			}
 
-			if( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
+			if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
 
 		};
 

+ 8 - 6
src/loaders/ObjectLoader.js

@@ -60,7 +60,7 @@ THREE.ObjectLoader.prototype = {
 
 		var object = this.parseObject( json.object, geometries, materials );
 
-		if( json.animations ) {
+		if ( json.animations ) {
 
 			object.animations = this.parseAnimations( json.animations );
 
@@ -327,7 +327,7 @@ THREE.ObjectLoader.prototype = {
 
 		var animations = [];
 
-		for( var i = 0; i < json.length; i ++ ) {
+		for ( var i = 0; i < json.length; i ++ ) {
 
 			var clip = THREE.AnimationClip.parse( json[i] );
 
@@ -447,7 +447,7 @@ THREE.ObjectLoader.prototype = {
 
 			var object;
 
-			var getGeometry = function ( name ) {
+			function getGeometry( name ) {
 
 				if ( geometries[ name ] === undefined ) {
 
@@ -457,9 +457,11 @@ THREE.ObjectLoader.prototype = {
 
 				return geometries[ name ];
 
-			};
+			}
+
+			function getMaterial( name ) {
 
-			var getMaterial = function ( name ) {
+				if ( name === undefined ) return undefined;
 
 				if ( materials[ name ] === undefined ) {
 
@@ -469,7 +471,7 @@ THREE.ObjectLoader.prototype = {
 
 				return materials[ name ];
 
-			};
+			}
 
 			switch ( data.type ) {
 

+ 4 - 2
src/loaders/XHRLoader.js

@@ -39,9 +39,11 @@ THREE.XHRLoader.prototype = {
 
 		request.addEventListener( 'load', function ( event ) {
 
-			THREE.Cache.add( url, this.response );
+			var response = event.target.response;
 
-			if ( onLoad ) onLoad( this.response );
+			THREE.Cache.add( url, response );
+
+			if ( onLoad ) onLoad( response );
 
 			scope.manager.itemEnd( url );
 

+ 3 - 3
src/math/Color.js

@@ -6,7 +6,7 @@ THREE.Color = function ( color ) {
 
 	if ( arguments.length === 3 ) {
 
-		return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] );
+		return this.fromArray( arguments );
 
 	}
 
@@ -64,7 +64,7 @@ THREE.Color.prototype = {
 
 	setHSL: function () {
 
-		function hue2rgb ( p, q, t ) {
+		function hue2rgb( p, q, t ) {
 
 			if ( t < 0 ) t += 1;
 			if ( t > 1 ) t -= 1;
@@ -105,7 +105,7 @@ THREE.Color.prototype = {
 
 	setStyle: function ( style ) {
 
-		var parseAlpha = function ( strAlpha ) {
+		function parseAlpha( strAlpha ) {
 
 			var alpha = parseFloat( strAlpha );
 

+ 0 - 25
src/objects/Line.js

@@ -181,31 +181,6 @@ THREE.Line.prototype.clone = function () {
 
 };
 
-THREE.Line.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	// only serialize if not in meta geometries cache
-	if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
-
-		meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON();
-
-	}
-
-	// only serialize if not in meta materials cache
-	if ( meta.materials[ this.material.uuid ] === undefined ) {
-
-		meta.materials[ this.material.uuid ] = this.material.toJSON();
-
-	}
-
-	data.object.geometry = this.geometry.uuid;
-	data.object.material = this.material.uuid;
-
-	return data;
-
-};
-
 // DEPRECATED
 
 THREE.LineStrip = 0;

+ 7 - 32
src/objects/Mesh.js

@@ -218,22 +218,22 @@ THREE.Mesh.prototype.raycast = ( function () {
 
 					if ( distance < raycaster.near || distance > raycaster.far ) continue;
 
+					a = i / 3;
+					b = a + 1;
+					c = a + 2;
+
 					var uv;
 
 					if ( attributes.uv !== undefined ) {
 
 						var uvs = attributes.uv.array;
-						uvA.fromArray( uvs, i );
-						uvB.fromArray( uvs, i + 2 );
-						uvC.fromArray( uvs, i + 4 );
+						uvA.fromArray( uvs, a * 2 );
+						uvB.fromArray( uvs, b * 2 );
+						uvC.fromArray( uvs, c * 2 );
 						uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );
 
 					}
 
-					a = i / 3;
-					b = a + 1;
-					c = a + 2;
-
 					intersects.push( {
 
 						distance: distance,
@@ -354,28 +354,3 @@ THREE.Mesh.prototype.clone = function () {
 	return new this.constructor( this.geometry, this.material ).copy( this );
 
 };
-
-THREE.Mesh.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	// only serialize if not in meta geometries cache
-	if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
-
-		meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
-
-	}
-
-	// only serialize if not in meta materials cache
-	if ( meta.materials[ this.material.uuid ] === undefined ) {
-
-		meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
-
-	}
-
-	data.object.geometry = this.geometry.uuid;
-	data.object.material = this.material.uuid;
-
-	return data;
-
-};

+ 0 - 25
src/objects/Points.js

@@ -126,31 +126,6 @@ THREE.Points.prototype.clone = function () {
 
 };
 
-THREE.Points.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	// only serialize if not in meta geometries cache
-	if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
-
-		meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON();
-
-	}
-
-	// only serialize if not in meta materials cache
-	if ( meta.materials[ this.material.uuid ] === undefined ) {
-
-		meta.materials[ this.material.uuid ] = this.material.toJSON();
-
-	}
-
-	data.object.geometry = this.geometry.uuid;
-	data.object.material = this.material.uuid;
-
-	return data;
-
-};
-
 // Backwards compatibility
 
 THREE.PointCloud = function ( geometry, material ) {

+ 0 - 17
src/objects/Sprite.js

@@ -66,23 +66,6 @@ THREE.Sprite.prototype.clone = function () {
 
 };
 
-THREE.Sprite.prototype.toJSON = function ( meta ) {
-
-	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
-
-	// only serialize if not in meta materials cache
-	if ( meta.materials[ this.material.uuid ] === undefined ) {
-
-		meta.materials[ this.material.uuid ] = this.material.toJSON();
-
-	}
-
-	data.object.material = this.material.uuid;
-
-	return data;
-
-};
-
 // Backwards compatibility
 
 THREE.Particle = THREE.Sprite;

+ 165 - 29
src/renderers/WebGLRenderTarget.js

@@ -12,25 +12,13 @@ THREE.WebGLRenderTarget = function ( width, height, options ) {
 
 	options = options || {};
 
-	this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping;
-	this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping;
+	if ( options.minFilter === undefined ) options.minFilter = THREE.LinearFilter;
 
-	this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter;
-	this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter;
-
-	this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1;
-
-	this.offset = new THREE.Vector2( 0, 0 );
-	this.repeat = new THREE.Vector2( 1, 1 );
-
-	this.format = options.format !== undefined ? options.format : THREE.RGBAFormat;
-	this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType;
+	this.texture = new THREE.Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy );
 
 	this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
 	this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
 
-	this.generateMipmaps = true;
-
 	this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null;
 
 };
@@ -39,6 +27,168 @@ THREE.WebGLRenderTarget.prototype = {
 
 	constructor: THREE.WebGLRenderTarget,
 
+	get wrapS() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
+
+		return this.texture.wrapS;
+
+	},
+
+	set wrapS( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
+
+		this.texture.wrapS = value;
+
+	},
+
+	get wrapT() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
+
+		return this.texture.wrapT;
+
+	},
+
+	set wrapT( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
+
+		this.texture.wrapT = value;
+
+	},
+
+	get magFilter() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
+
+		return this.texture.magFilter;
+
+	},
+
+	set magFilter( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
+
+		this.texture.magFilter = value;
+
+	},
+
+	get minFilter() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
+
+		return this.texture.minFilter;
+
+	},
+
+	set minFilter( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
+
+		this.texture.minFilter = value;
+
+	},
+
+	get anisotropy() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
+
+		return this.texture.anisotropy;
+
+	},
+
+	set anisotropy( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
+
+		this.texture.anisotropy = value;
+
+	},
+
+	get offset() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
+
+		return this.texture.offset;
+
+	},
+
+	set offset( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
+
+		this.texture.offset = value;
+
+	},
+
+	get repeat() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
+
+		return this.texture.repeat;
+
+	},
+
+	set repeat( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
+
+		this.texture.repeat = value;
+
+	},
+
+	get format() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
+
+		return this.texture.format;
+
+	},
+
+	set format( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
+
+		this.texture.format = value;
+
+	},
+
+	get type() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
+
+		return this.texture.type;
+
+	},
+
+	set type( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
+
+		this.texture.type = value;
+
+	},
+
+	get generateMipmaps() {
+
+		console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
+
+		return this.texture.generateMipmaps;
+
+	},
+
+	set generateMipmaps( value ) {
+
+		console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
+
+		this.texture.generateMipmaps = value;
+
+	},
+
+	//
+
 	setSize: function ( width, height ) {
 
 		if ( this.width !== width || this.height !== height ) {
@@ -63,25 +213,11 @@ THREE.WebGLRenderTarget.prototype = {
 		this.width = source.width;
 		this.height = source.height;
 
-		this.wrapS = source.wrapS;
-		this.wrapT = source.wrapT;
-
-		this.magFilter = source.magFilter;
-		this.minFilter = source.minFilter;
-
-		this.anisotropy = source.anisotropy;
-
-		this.offset.copy( source.offset );
-		this.repeat.copy( source.repeat );
-
-		this.format = source.format;
-		this.type = source.type;
+		this.texture = source.texture.clone();
 
 		this.depthBuffer = source.depthBuffer;
 		this.stencilBuffer = source.stencilBuffer;
 
-		this.generateMipmaps = source.generateMipmaps;
-
 		this.shareDepthFrom = source.shareDepthFrom;
 
 		return this;

+ 98 - 60
src/renderers/WebGLRenderer.js

@@ -32,9 +32,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 	var lights = [];
 
 	var opaqueObjects = [];
-	var opaqueObjectsLastIndex = -1;
+	var opaqueObjectsLastIndex = - 1;
 	var transparentObjects = [];
-	var transparentObjectsLastIndex = -1;
+	var transparentObjectsLastIndex = - 1;
 
 	var morphInfluences = new Float32Array( 8 );
 
@@ -376,11 +376,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.getViewport = function ( dimensions ) {
 
-		dimensions.x = _viewportX;
-		dimensions.y = _viewportY;
+		dimensions.x = _viewportX / pixelRatio;
+		dimensions.y = _viewportY / pixelRatio;
 
-		dimensions.z = _viewportWidth;
-		dimensions.w = _viewportHeight;
+		dimensions.z = _viewportWidth / pixelRatio;
+		dimensions.w = _viewportHeight / pixelRatio;
 
 	};
 
@@ -551,17 +551,18 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 
 		// remove all webgl properties
-		properties.delete( texture );
+		properties.remove( texture );
 
 	}
 
 	function deallocateRenderTarget( renderTarget ) {
 
 		var renderTargetProperties = properties.get( renderTarget );
+		var textureProperties = properties.get( renderTarget.texture );
 
-		if ( ! renderTarget || renderTargetProperties.__webglTexture === undefined ) return;
+		if ( ! renderTarget || textureProperties.__webglTexture === undefined ) return;
 
-		_gl.deleteTexture( renderTargetProperties.__webglTexture );
+		_gl.deleteTexture( textureProperties.__webglTexture );
 
 		if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
 
@@ -579,7 +580,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		properties.delete( renderTarget );
+		properties.remove( renderTarget.texture );
+		properties.remove( renderTarget );
 
 	}
 
@@ -587,7 +589,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		releaseMaterialProgramReference( material );
 
-		properties.delete( material );
+		properties.remove( material );
 
 	}
 
@@ -601,6 +603,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( programInfo !== undefined ) {
 
 			programCache.releaseProgram( programInfo );
+
 		}
 
 	}
@@ -1091,8 +1094,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		lights.length = 0;
 
-		opaqueObjectsLastIndex = -1;
-		transparentObjectsLastIndex = -1;
+		opaqueObjectsLastIndex = - 1;
+		transparentObjectsLastIndex = - 1;
 
 		sprites.length = 0;
 		lensFlares.length = 0;
@@ -1157,9 +1160,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		// Generate mipmap if we're using any kind of mipmap filtering
 
-		if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) {
+		if ( renderTarget ) {
+
+			var texture = renderTarget.texture;
+			var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height );
+			if ( texture.generateMipmaps && isTargetPowerOfTwo && texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) {
+
+				 updateRenderTargetMipmap( renderTarget );
 
-			updateRenderTargetMipmap( renderTarget );
+			}
 
 		}
 
@@ -1328,17 +1337,17 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			if ( object instanceof THREE.ImmediateRenderObject ) {
 
-					setMaterial( material );
+				setMaterial( material );
 
-					var program = setProgram( camera, lights, fog, material, object );
+				var program = setProgram( camera, lights, fog, material, object );
 
-					_currentGeometryProgram = '';
+				_currentGeometryProgram = '';
 
-					object.render( function ( object ) {
+				object.render( function ( object ) {
 
-						_this.renderBufferImmediate( object, program, material );
+					_this.renderBufferImmediate( object, program, material );
 
-					} );
+				} );
 
 			} else {
 
@@ -1800,6 +1809,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( uvScaleMap !== undefined ) {
 
+			if ( uvScaleMap instanceof THREE.WebGLRenderTarget ) uvScaleMap = uvScaleMap.texture;
 			var offset = uvScaleMap.offset;
 			var repeat = uvScaleMap.repeat;
 
@@ -1870,7 +1880,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	function refreshUniformsPhong ( uniforms, material ) {
 
 		uniforms.specular.value = material.specular;
-		uniforms.shininess.value = material.shininess;
+		uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
 
 		if ( material.lightMap ) {
 
@@ -1979,17 +1989,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					if ( light instanceof THREE.PointLight ) {
 
+						// for point lights we set the shadow matrix to be a translation-only matrix
+						// equal to inverse of the light's position
+						_vector3.setFromMatrixPosition( light.matrixWorld ).negate();
+						light.shadowMatrix.identity().setPosition( _vector3 );
+
 						// for point lights we set the sign of the shadowDarkness uniform to be negative
 						uniforms.shadowDarkness.value[ j ] = - light.shadowDarkness;
 
 					} else {
-						
+
 						uniforms.shadowDarkness.value[ j ] = light.shadowDarkness;
 
 					}
 
 					uniforms.shadowMatrix.value[ j ] = light.shadowMatrix;
-					uniforms.shadowMap.value[ j ] =  light.shadowMap;
+					uniforms.shadowMap.value[ j ] = light.shadowMap;
 					uniforms.shadowMapSize.value[ j ] = light.shadowMapSize;
 					uniforms.shadowBias.value[ j ] = light.shadowBias;
 
@@ -2314,7 +2329,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
 
-						setCubeTextureDynamic( texture, textureUnit );
+						setCubeTextureDynamic( texture.texture, textureUnit );
+
+					} else if ( texture instanceof THREE.WebGLRenderTarget ) {
+
+						_this.setTexture( texture.texture, textureUnit );
 
 					} else {
 
@@ -2350,15 +2369,19 @@ THREE.WebGLRenderer = function ( parameters ) {
 						if ( ! texture ) continue;
 
 						if ( texture instanceof THREE.CubeTexture ||
-						   ( texture.image instanceof Array && texture.image.length === 6 ) ) {
+							 ( texture.image instanceof Array && texture.image.length === 6 ) ) {
 
 							// CompressedTexture can have Array in image :/
 
 							setCubeTexture( texture, textureUnit );
 
+						} else if ( texture instanceof THREE.WebGLRenderTarget ) {
+
+							_this.setTexture( texture.texture, textureUnit );
+
 						} else if ( texture instanceof THREE.WebGLRenderTargetCube ) {
 
-							setCubeTextureDynamic( texture, textureUnit );
+							setCubeTextureDynamic( texture.texture, textureUnit );
 
 						} else {
 
@@ -2975,7 +2998,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
 
 		_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, properties.get( renderTarget ).__webglTexture, 0 );
+		_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
 
 	}
 
@@ -3015,30 +3038,31 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
 
 			var renderTargetProperties = properties.get( renderTarget );
+			var textureProperties = properties.get( renderTarget.texture );
 
 			if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
 			if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
 
 			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
 
-			renderTargetProperties.__webglTexture = _gl.createTexture();
+			textureProperties.__webglTexture = _gl.createTexture();
 
 			_infoMemory.textures ++;
 
 			// Setup texture, create render and frame buffers
 
 			var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ),
-				glFormat = paramThreeToGL( renderTarget.format ),
-				glType = paramThreeToGL( renderTarget.type );
+				glFormat = paramThreeToGL( renderTarget.texture.format ),
+				glType = paramThreeToGL( renderTarget.texture.type );
 
 			if ( isCube ) {
 
 				renderTargetProperties.__webglFramebuffer = [];
 				renderTargetProperties.__webglRenderbuffer = [];
 
-				state.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTargetProperties.__webglTexture );
+				state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
 
-				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
+				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
 
 				for ( var i = 0; i < 6; i ++ ) {
 
@@ -3051,7 +3075,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				if ( renderTarget.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
+				if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
 
 			} else {
 
@@ -3067,8 +3091,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				state.bindTexture( _gl.TEXTURE_2D, renderTargetProperties.__webglTexture );
-				setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
+				state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
+				setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
 
 				state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 
@@ -3092,7 +3116,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				if ( renderTarget.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
+				if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
 
 			}
 
@@ -3158,8 +3182,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( isCube ) {
 
-			var renderTargetProperties = properties.get( renderTarget );
-			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0,  _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, renderTargetProperties.__webglTexture, 0 );
+			var textureProperties = properties.get( renderTarget.texture );
+			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, 0 );
 
 		}
 
@@ -3168,54 +3192,68 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
-	this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) {
+	this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {
 
-		if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) {
+		if ( renderTarget instanceof THREE.WebGLRenderTarget === false ) {
 
 			console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
 			return;
 
 		}
 
-		if ( properties.get( renderTarget ).__webglFramebuffer ) {
+		var framebuffer = properties.get( renderTarget ).__webglFramebuffer;
+
+		if ( framebuffer ) {
 
 			var restore = false;
 
-			if ( properties.get( renderTarget ).__webglFramebuffer !== _currentFramebuffer ) {
+			if ( framebuffer !== _currentFramebuffer ) {
 
-				_gl.bindFramebuffer( _gl.FRAMEBUFFER, properties.get( renderTarget ).__webglFramebuffer );
+				_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 
 				restore = true;
 
 			}
 
-			if ( renderTarget.format !== THREE.RGBAFormat && paramThreeToGL( renderTarget.format ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
+			try {
 
-				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
-				return;
+				var texture = renderTarget.texture;
 
-			}
+				if ( texture.format !== THREE.RGBAFormat
+					&& paramThreeToGL( texture.format ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
 
-			if ( renderTarget.type !== THREE.UnsignedByteType && paramThreeToGL( renderTarget.type ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) ) {
+					console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
+					return;
 
-				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
-				return;
+				}
 
-			}
+				if ( texture.type !== THREE.UnsignedByteType
+					&& paramThreeToGL( texture.type ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE )
+					&& ! ( texture.type === THREE.FloatType && extensions.get( 'WEBGL_color_buffer_float' ) )
+					&& ! ( texture.type === THREE.HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {
 
-			if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
+					console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
+					return;
 
-				_gl.readPixels( x, y, width, height, paramThreeToGL( renderTarget.format ), paramThreeToGL( renderTarget.type ), buffer );
+				}
 
-			} else {
+				if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
 
-				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
+					_gl.readPixels( x, y, width, height, paramThreeToGL( texture.format ), paramThreeToGL( texture.type ), buffer );
 
-			}
+				} else {
+
+					console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
+
+				}
 
-			if ( restore ) {
+			} finally {
 
-				_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
+				if ( restore ) {
+
+					_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
+
+				}
 
 			}
 
@@ -3226,7 +3264,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	function updateRenderTargetMipmap( renderTarget ) {
 
 		var target = renderTarget instanceof THREE.WebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
-		var texture = properties.get( renderTarget ).__webglTexture;
+		var texture = properties.get( renderTarget.texture ).__webglTexture;
 
 		state.bindTexture( target, texture );
 		_gl.generateMipmap( target );

+ 2 - 2
src/renderers/shaders/ShaderChunk/envmap_vertex.glsl

@@ -1,9 +1,9 @@
 #if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )
 
-	vec3 worldNormal = transformDirection( objectNormal, modelMatrix );
-
 	vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );
 
+	vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );
+
 	#ifdef ENVMAP_MODE_REFLECTION
 
 		vReflect = reflect( cameraToVertex, worldNormal );

+ 1 - 1
src/renderers/shaders/ShaderChunk/hemilight_fragment.glsl

@@ -1,6 +1,6 @@
 #if MAX_HEMI_LIGHTS > 0
 
-	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
+	for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
 
 		vec3 lightDir = hemisphereLightDirection[ i ];
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl

@@ -76,7 +76,7 @@ vec3 totalSpecularLight = vec3( 0.0 );
 
 #if MAX_DIR_LIGHTS > 0
 
-	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
+	for ( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 		vec3 lightColor = directionalLightColor[ i ];
 

+ 175 - 215
src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl

@@ -1,306 +1,266 @@
 #ifdef USE_SHADOWMAP
 
-	#ifdef SHADOWMAP_DEBUG
+	vec3 shadowMask = vec3( 1.0 );
 
-		vec3 frustumColors[3];
-		frustumColors[0] = vec3( 1.0, 0.5, 0.0 );
-		frustumColors[1] = vec3( 0.0, 1.0, 0.8 );
-		frustumColors[2] = vec3( 0.0, 0.5, 1.0 );
-
-	#endif
+	for ( int i = 0; i < MAX_SHADOWS; i ++ ) {
+		
+		float texelSizeY =  1.0 / shadowMapSize[ i ].y;
 
-	float fDepth;
-	vec3 shadowColor = vec3( 1.0 );
+		float shadow = 0.0;	
 
-	for( int i = 0; i < MAX_SHADOWS; i ++ ) {
+#if defined( POINT_LIGHT_SHADOWS )
 
 		// to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine
 		// whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light)
-		bool isPointLight = shadowDarkness[ i ] < 0.0;
-
-		// get the real shadow darkness
-		float realShadowDarkness = abs( shadowDarkness[ i ] );
-
-		// for point lights, the uniform @vShadowCoord is re-purposed to hold
-		// the distance from the light to the world-space position of the fragment.
-		vec3 lightToPosition = vShadowCoord[ i ].xyz;
-
-		float texelSizeX =  1.0 / shadowMapSize[ i ].x;
-		float texelSizeY =  1.0 / shadowMapSize[ i ].y;
+		bool isPointLight = shadowDarkness[ i ] < 0.0;	
 
-		vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
-		float shadow = 0.0;
+		if ( isPointLight ) {
 
-		// if ( something && something ) breaks ATI OpenGL shader compiler
-		// if ( all( something, something ) ) using this instead
+			// get the real shadow darkness
+			float realShadowDarkness = abs( shadowDarkness[ i ] );
 
-		bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
-		bool inFrustum = all( inFrustumVec );
+			// for point lights, the uniform @vShadowCoord is re-purposed to hold
+			// the distance from the light to the world-space position of the fragment.
+			vec3 lightToPosition = vShadowCoord[ i ].xyz;
 
-		bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
+	#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )
 
-		bool frustumTest = all( frustumTestVec );
+			// bd3D = base direction 3D
+			vec3 bd3D = normalize( lightToPosition );
+			// dp = distance from light to fragment position
+			float dp = length( lightToPosition );
 
-		if ( frustumTest || isPointLight ) {			
+			// base measurement
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow );
 
-			#if defined( SHADOWMAP_TYPE_PCF )
+			// Dr = disk radius
 
-				#if defined(POINT_LIGHT_SHADOWS)
-
-					if( isPointLight ) {
-
-						float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );
-						vec3 baseDirection3D = normalize( lightToPosition );
-						vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );
-
-						initGridSamplingDisk();
-
-						float diskRadius = 1.25;
-						float numSamples = 1.0;
-						shadow = 0.0;
-
-						vec3 baseDirection = normalize( lightToPosition );
-						float curDistance = length( lightToPosition );
-
-						float dist = unpack1K( texture2D( shadowMap[ i ],  baseDirection2D ) ) + 0.1;
-						if ( curDistance >= dist )
-							shadow += 1.0;
-						
-						// evaluate each sampling direction
-						for( int s = 0; s < 20; s++ ) {
-						 
-							vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;
-							vec3 adjustedBaseDirection3D = baseDirection3D + offset;
-							vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeY );
-							dist = unpack1K( texture2D( shadowMap[ i ],  adjustedBaseDirection2D ) ) + shadowBias[ i ];
-							if ( curDistance >= dist )
-								shadow += 1.0;
-							numSamples += 1.0;
+	#if defined( SHADOWMAP_TYPE_PCF )
+			const float Dr = 1.25;
+	#elif defined( SHADOWMAP_TYPE_PCF_SOFT )
+			const float Dr = 2.25;
+	#endif
 
-						}
+			// os = offset scale
+			float os = Dr *  2.0 * texelSizeY;
 
-						shadow /= numSamples;
+			const vec3 Gsd = vec3( - 1, 0, 1 );
 
-					} else {
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzy * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxy * os, texelSizeY ) ), shadowBias[ i ], shadow );
 
-				#endif
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxy * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzy * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxz * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxx * os, texelSizeY ) ), shadowBias[ i ], shadow );
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzx * os, texelSizeY ) ), shadowBias[ i ], shadow );
 
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
-						
-						/*
-								// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
-								// must enroll loop manually
-							for ( float y = -1.25; y <= 1.25; y += 1.25 )
-								for ( float x = -1.25; x <= 1.25; x += 1.25 ) {
-									vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );
-											// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup
-											//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );
-									float fDepth = unpackDepth( rgbaDepth );
-									if ( fDepth < shadowCoord.z )
-										shadow += 1.0;
-							}
-							shadow /= 9.0;
-						*/
+			shadow *= realShadowDarkness * ( 1.0 / 21.0 );
 
-						shadowCoord.z += shadowBias[ i ];
+	#else // no percentage-closer filtering:
 
-						const float shadowDelta = 1.0 / 9.0;
+			vec3 bd3D = normalize( lightToPosition );
+			float dp = length( lightToPosition );
 
-						float xPixelOffset = texelSizeX;
-						float yPixelOffset = texelSizeY;
+			adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow );
 
-						float dx0 = -1.25 * xPixelOffset;
-						float dy0 = -1.25 * yPixelOffset;
-						float dx1 = 1.25 * xPixelOffset;
-						float dy1 = 1.25 * yPixelOffset;
+			shadow *= realShadowDarkness;
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+	#endif
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+		} else {
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+#endif // POINT_LIGHT_SHADOWS
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			float texelSizeX =  1.0 / shadowMapSize[ i ].x;
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			// if ( something && something ) breaks ATI OpenGL shader compiler
+			// if ( all( something, something ) ) using this instead
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
+			bool inFrustum = all( inFrustumVec );
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
 
-						fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
-						if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+			bool frustumTest = all( frustumTestVec );
 
-				#if defined(POINT_LIGHT_SHADOWS)
+			if ( frustumTest ) {
 
+	#if defined( SHADOWMAP_TYPE_PCF )
+		
+				// Percentage-close filtering
+				// (9 pixel kernel)
+				// http://fabiensanglard.net/shadowmappingPCF/
+				
+				/*
+						// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
+						// must enroll loop manually
+					for ( float y = -1.25; y <= 1.25; y += 1.25 )
+						for ( float x = -1.25; x <= 1.25; x += 1.25 ) {
+							vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );
+									// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup
+									//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );
+							float fDepth = unpackDepth( rgbaDepth );
+							if ( fDepth < shadowCoord.z )
+								shadow += 1.0;
 					}
+					shadow /= 9.0;
+				*/
 
-				#endif
-
-				shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
+				shadowCoord.z += shadowBias[ i ];
 
-			#elif defined( SHADOWMAP_TYPE_PCF_SOFT )
+				const float ShadowDelta = 1.0 / 9.0;
 
-				#if defined(POINT_LIGHT_SHADOWS)
+				float xPixelOffset = texelSizeX;
+				float yPixelOffset = texelSizeY;
 
-					if( isPointLight ) {
+				float dx0 = - 1.25 * xPixelOffset;
+				float dy0 = - 1.25 * yPixelOffset;
+				float dx1 = 1.25 * xPixelOffset;
+				float dy1 = 1.25 * yPixelOffset;
 
-						float cubeTexelSize = 1.0 / ( shadowMapSize[ i ].x * 0.25 );
-						vec3 baseDirection3D = normalize( lightToPosition );
-						vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );
+				float fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						initGridSamplingDisk();
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						float diskRadius = 2.25;
-						float numSamples = 1.0;
-						shadow = 0.0;
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						vec3 baseDirection = normalize( lightToPosition );
-						float curDistance = length( lightToPosition );
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						float dist = unpack1K( texture2D( shadowMap[ i ],  baseDirection2D ) ) + 0.1;
-						if ( curDistance >= dist )
-							shadow += 1.0;
-
-						// evaluate each sampling direction
-						for( int s = 0; s < 20; s++ ) {
-
-							vec3 offset = gridSamplingDisk[ s ] * diskRadius * cubeTexelSize;
-							vec3 adjustedBaseDirection3D = baseDirection3D + offset;
-							vec2 adjustedBaseDirection2D = cubeToUV( adjustedBaseDirection3D, texelSizeY );
-							dist = unpack1K( texture2D( shadowMap[ i ],  adjustedBaseDirection2D ) ) + shadowBias[ i ];
-							if ( curDistance >= dist )
-								shadow += 1.0;
-							numSamples += 1.0;
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						}
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						shadow /= numSamples;
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-					} else {
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-				#endif
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += ShadowDelta;
 
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
+				shadow *= shadowDarkness[ i ];
 
-						shadowCoord.z += shadowBias[ i ];
+	#elif defined( SHADOWMAP_TYPE_PCF_SOFT )				
 
-						float xPixelOffset = texelSizeX;
-						float yPixelOffset = texelSizeY;
+				// Percentage-close filtering
+				// (9 pixel kernel)
+				// http://fabiensanglard.net/shadowmappingPCF/
 
-						float dx0 = -1.0 * xPixelOffset;
-						float dy0 = -1.0 * yPixelOffset;
-						float dx1 = 1.0 * xPixelOffset;
-						float dy1 = 1.0 * yPixelOffset;
+				shadowCoord.z += shadowBias[ i ];
 
-						mat3 shadowKernel;
-						mat3 depthKernel;
+				float xPixelOffset = texelSizeX;
+				float yPixelOffset = texelSizeY;
 
-						depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
-						depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
-						depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
-						depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
-						depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
-						depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
-						depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
-						depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
-						depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
+				float dx0 = - 1.0 * xPixelOffset;
+				float dy0 = - 1.0 * yPixelOffset;
+				float dx1 = 1.0 * xPixelOffset;
+				float dy1 = 1.0 * yPixelOffset;
 
-						vec3 shadowZ = vec3( shadowCoord.z );
-						shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));
-						shadowKernel[0] *= vec3(0.25);
+				mat3 shadowKernel;
+				mat3 depthKernel;
 
-						shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));
-						shadowKernel[1] *= vec3(0.25);
+				depthKernel[ 0 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
+				depthKernel[ 0 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
+				depthKernel[ 0 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
+				depthKernel[ 1 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
+				depthKernel[ 1 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
+				depthKernel[ 1 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
+				depthKernel[ 2 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
+				depthKernel[ 2 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
+				depthKernel[ 2 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
 
-						shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));
-						shadowKernel[2] *= vec3(0.25);
+				vec3 shadowZ = vec3( shadowCoord.z );
+				shadowKernel[ 0 ] = vec3( lessThan( depthKernel[ 0 ], shadowZ ) );
+				shadowKernel[ 0 ] *= vec3( 0.25 );
 
-						vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );
+				shadowKernel[ 1 ] = vec3( lessThan( depthKernel[ 1 ], shadowZ ) );
+				shadowKernel[ 1 ] *= vec3( 0.25 );
 
-						shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );
-						shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );
+				shadowKernel[ 2 ] = vec3( lessThan( depthKernel[ 2 ], shadowZ ) );
+				shadowKernel[ 2 ] *= vec3( 0.25 );
 
-						vec4 shadowValues;
-						shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );
-						shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );
-						shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );
-						shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );
+				vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[ i ].xy );
 
-						shadow = dot( shadowValues, vec4( 1.0 ) );
+				shadowKernel[ 0 ] = mix( shadowKernel[ 1 ], shadowKernel[ 0 ], fractionalCoord.x );
+				shadowKernel[ 1 ] = mix( shadowKernel[ 2 ], shadowKernel[ 1 ], fractionalCoord.x );
 
-				#if defined(POINT_LIGHT_SHADOWS)
-					
-					}
+				vec4 shadowValues;
+				shadowValues.x = mix( shadowKernel[ 0 ][ 1 ], shadowKernel[ 0 ][ 0 ], fractionalCoord.y );
+				shadowValues.y = mix( shadowKernel[ 0 ][ 2 ], shadowKernel[ 0 ][ 1 ], fractionalCoord.y );
+				shadowValues.z = mix( shadowKernel[ 1 ][ 1 ], shadowKernel[ 1 ][ 0 ], fractionalCoord.y );
+				shadowValues.w = mix( shadowKernel[ 1 ][ 2 ], shadowKernel[ 1 ][ 1 ], fractionalCoord.y );
 
-				#endif
+				shadow = dot( shadowValues, vec4( 1.0 ) ) * shadowDarkness[ i ];
 
-				shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) );
+	#else // no percentage-closer filtering:
+				
+				shadowCoord.z += shadowBias[ i ];
 
-			#else
+				vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );
+				float fDepth = unpackDepth( rgbaDepth );
 
-				#if defined(POINT_LIGHT_SHADOWS)
+				if ( fDepth < shadowCoord.z )
+					shadow = shadowDarkness[ i ];				
 
-					if( isPointLight ) {
+	#endif
 
-						vec3 baseDirection3D = normalize( lightToPosition );
-						vec2 baseDirection2D = cubeToUV( baseDirection3D, texelSizeY );
-						vec4 data = texture2D( shadowMap[ i ],  baseDirection2D );
-						float dist = unpack1K( data ) + shadowBias[ i ];
-						if ( length( lightToPosition ) >= dist)
-							shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
+			}
 
-					} else {
+#ifdef SHADOWMAP_DEBUG
 
-				#endif
-						shadowCoord.z += shadowBias[ i ];
+			if ( inFrustum ) {
 
-						vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );
-						float fDepth = unpackDepth( rgbaDepth );
+				if ( i == 0 ) {
 
-						if ( fDepth < shadowCoord.z )
+					outgoingLight *= vec3( 1.0, 0.5, 0.0 );
 
-						// spot with multiple shadows is darker
+				} else if ( i == 1 ) {
 
-						shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness );
+					outgoingLight *= vec3( 0.0, 1.0, 0.8 );
 
-						// spot with multiple shadows has the same color as single shadow spot
+				} else {
 
-						// 	shadowColor = min( shadowColor, vec3( realShadowDarkness ) );
+					outgoingLight *= vec3( 0.0, 0.5, 1.0 );
 
-				#if defined(POINT_LIGHT_SHADOWS)
+				}
 
-					}
+			}
 
-				#endif
+#endif
 
-			#endif
+#if defined( POINT_LIGHT_SHADOWS )
 
 		}
 
+#endif
 
-		#ifdef SHADOWMAP_DEBUG
-
-			if ( inFrustum ) outgoingLight *= frustumColors[ i ];
-
-		#endif
+		shadowMask = shadowMask * vec3( 1.0 - shadow );	
 
 	}
 
-	outgoingLight = outgoingLight * shadowColor;
+	outgoingLight = outgoingLight * shadowMask;
 
 #endif

+ 9 - 40
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl

@@ -18,10 +18,15 @@
 
 	#if defined(POINT_LIGHT_SHADOWS)
 
-		float unpack1K ( vec4 color ) {
+		// adjustShadowValue1K() upacks the depth value stored in @textureData, adds @bias to it, and then
+		// comapres the result with @testDepth. If @testDepth is larger than or equal to that result, then
+		// @shadowValue is incremented by 1.0.
 
-			const vec4 bitSh = vec4( 1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0 );
-			return dot( color, bitSh ) * 1000.0;
+		void adjustShadowValue1K( const float testDepth, const vec4 textureData, const float bias, inout float shadowValue ) {
+
+			const vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );
+			if ( testDepth >= dot( textureData, bitSh ) * 1000.0 + bias )
+				shadowValue += 1.0;
 
 		}
 
@@ -56,7 +61,7 @@
 			// Apply scale to avoid seams
 
 			// two texels less per square (one texel will do for NEAREST)
-			v *= scaleToCube * ( 1.0 - 4.0 * texelSizeY );
+			v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );
 
 			// Unwrap
 
@@ -96,42 +101,6 @@
 
 		}
 
-		vec3 gridSamplingDisk[ 20 ];
-		bool gridSamplingInitialized = false;
-
-		void initGridSamplingDisk() {
-
-			if( gridSamplingInitialized ) {
-
-				return;
-
-			}
-
-			gridSamplingDisk[0] = vec3(1, 1, 1);
-			gridSamplingDisk[1] = vec3(1, -1, 1);
-			gridSamplingDisk[2] = vec3(-1, -1, 1);
-			gridSamplingDisk[3] = vec3(-1, 1, 1);
-			gridSamplingDisk[4] = vec3(1, 1, -1);
-			gridSamplingDisk[5] = vec3(1, -1, -1);
-			gridSamplingDisk[6] = vec3(-1, -1, -1);
-			gridSamplingDisk[7] = vec3(-1, 1, -1);
-			gridSamplingDisk[8] = vec3(1, 1, 0);
-			gridSamplingDisk[9] = vec3(1, -1, 0);
-			gridSamplingDisk[10] = vec3(-1, -1, 0);
-			gridSamplingDisk[11] = vec3(-1, 1, 0);
-			gridSamplingDisk[12] = vec3(1, 0, 1);
-			gridSamplingDisk[13] = vec3(-1, 0, 1);
-			gridSamplingDisk[14] = vec3(1, 0, -1);
-			gridSamplingDisk[15] = vec3(-1, 0, -1);
-			gridSamplingDisk[16] = vec3(0, 1, 1);
-			gridSamplingDisk[17] = vec3(0, -1, 1);
-			gridSamplingDisk[18] = vec3(0, -1, -1);
-			gridSamplingDisk[19] = vec3(0, 1, -1);
-
-			gridSamplingInitialized = true;
-
-		}
-
 	#endif
 
 #endif

+ 1 - 33
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl

@@ -1,41 +1,9 @@
 #ifdef USE_SHADOWMAP
 
-	for( int i = 0; i < MAX_SHADOWS; i ++ ) {
-
-		#if defined(POINT_LIGHT_SHADOWS)
-
-			// if shadowDarkness[ i ] < 0.0, that means we have a point light with a cube
-			// shadow map
-			if( shadowDarkness[ i ] < 0.0 ) {
-
-				// calculate vector from light to vertex in view space
-
-				vec3 fromLight = mvPosition.xyz - pointLightPosition[ i ];
-
-				// Transform 'fromLight' into world space by multiplying it on the left
-				// side of 'viewMatrix'. This is equivalent to multiplying it on the right
-				// side of the transpose of 'viewMatrix'. Since 'viewMatrix' is orthogonal, 
-				// its transpose is the same as its inverse.
-
-				fromLight = fromLight * mat3( viewMatrix );
-
-				// We repurpose vShadowCoord to hold the distance in world space from the
-				// light to the vertex. This value will be interpolated correctly in the fragment shader.
-
-				vShadowCoord[ i ] = vec4( fromLight, 1.0 );
-
-			} else {
-
-				vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
-
-			}
-
-		#else
+	for ( int i = 0; i < MAX_SHADOWS; i ++ ) {
 
 			vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
 
-		#endif
-
 	}
 
 #endif

+ 2 - 2
src/renderers/webgl/WebGLGeometries.js

@@ -101,11 +101,11 @@ THREE.WebGLGeometries = function ( gl, properties, info ) {
 
 		if ( attribute instanceof THREE.InterleavedBufferAttribute ) {
 
-			properties.delete( attribute.data );
+			properties.remove( attribute.data );
 
 		} else {
 
-			properties.delete( attribute );
+			properties.remove( attribute );
 
 		}
 

+ 1 - 1
src/renderers/webgl/WebGLProperties.js

@@ -22,7 +22,7 @@ THREE.WebGLProperties = function () {
 
 	};
 
-	this.delete = function ( object ) {
+	this.remove = function ( object ) {
 
 		delete properties[ object.uuid ];
 

部分文件因文件數量過多而無法顯示