Browse Source

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

spite 11 years ago
parent
commit
fa5398be8a
100 changed files with 3131 additions and 2353 deletions
  1. 1 1
      .gitignore
  2. 5 5
      README.md
  3. 349 1434
      build/three.js
  4. 218 248
      build/three.min.js
  5. 1 1
      docs/api/math/Box2.html
  6. 103 67
      docs/api/math/Box3.html
  7. 2 2
      docs/api/renderers/WebGLRenderer.html
  8. 4 2
      docs/index.html
  9. 3 3
      docs/manual/introduction/Creating-a-scene.html
  10. 1 1
      docs/page.css
  11. 26 0
      editor/css/dark.css
  12. 26 0
      editor/css/light.css
  13. 1 1
      editor/js/Menubar.View.js
  14. 3 3
      editor/js/Sidebar.Geometry.js
  15. 3 3
      editor/js/Sidebar.Material.js
  16. 3 3
      editor/js/Sidebar.Object3D.js
  17. 4 3
      editor/js/Sidebar.Renderer.js
  18. 11 3
      editor/js/Sidebar.Scene.js
  19. 129 1
      editor/js/libs/ui.js
  20. 1 1
      examples/css3d_periodictable.html
  21. 38 27
      examples/css3d_sandbox.html
  22. 4 1
      examples/index.html
  23. 271 0
      examples/js/BlendCharacter.js
  24. 214 0
      examples/js/BlendCharacterGui.js
  25. 11 4
      examples/js/controls/TransformControls.js
  26. 9 11
      examples/js/loaders/STLLoader.js
  27. 1 1
      examples/js/loaders/VTKLoader.js
  28. 2 2
      examples/js/loaders/gltf/glTFLoader.js
  29. 75 0
      examples/js/wip/CircleGeometry2.js
  30. 109 7
      examples/js/wip/Geometry2.js
  31. 0 0
      examples/js/wip/GeometryEditor.js
  32. 14 3
      examples/js/wip/IndexedGeometry2.js
  33. 57 41
      examples/js/wip/PlaneGeometry2.js
  34. 0 0
      examples/js/wip/ProxyGeometry.js
  35. 0 0
      examples/js/wip/benchmark/BoxGeometry2.js
  36. 19 0
      examples/js/wip/benchmark/Geometry2.js
  37. 0 0
      examples/js/wip/benchmark/Geometry2Loader.js
  38. 0 0
      examples/js/wip/benchmark/Geometry3.js
  39. 0 0
      examples/js/wip/benchmark/Geometry4.js
  40. 0 0
      examples/js/wip/benchmark/Geometry5.js
  41. 0 0
      examples/js/wip/benchmark/Geometry5b.js
  42. 0 0
      examples/js/wip/benchmark/IndexedGeometry3.js
  43. 0 0
      examples/js/wip/benchmark/IndexedGeometry5.js
  44. 0 0
      examples/js/wip/benchmark/IndexedPlaneGeometry5.js
  45. 0 0
      examples/js/wip/benchmark/PlaneBufferGeometry.js
  46. 0 0
      examples/js/wip/benchmark/PlaneGeometry.js
  47. 75 0
      examples/js/wip/benchmark/PlaneGeometry2.js
  48. 0 0
      examples/js/wip/benchmark/PlaneGeometry2b.js
  49. 0 0
      examples/js/wip/benchmark/PlaneGeometry3.js
  50. 0 0
      examples/js/wip/benchmark/PlaneGeometry5.js
  51. 0 0
      examples/js/wip/benchmark/PlaneGeometry6.js
  52. 0 0
      examples/js/wip/benchmark/PlaneGeometry99.js
  53. 0 0
      examples/js/wip/benchmark/TypedGeometry.js
  54. 0 0
      examples/js/wip/proxies/MultiColor.js
  55. 0 0
      examples/js/wip/proxies/MultiVector3.js
  56. 0 0
      examples/js/wip/proxies/ProxyColor.js
  57. 0 0
      examples/js/wip/proxies/ProxyFace3.js
  58. 0 0
      examples/js/wip/proxies/ProxyVector2.js
  59. 0 0
      examples/js/wip/proxies/ProxyVector3.js
  60. 0 0
      examples/js/wip/proxies/ProxyVector4.js
  61. BIN
      examples/models/skinned/marine/M4.png
  62. BIN
      examples/models/skinned/marine/MarineCv2_color.jpg
  63. BIN
      examples/models/skinned/marine/m4.blend
  64. 37 0
      examples/models/skinned/marine/m4.js
  65. 37 0
      examples/models/skinned/marine/marine.js
  66. BIN
      examples/models/skinned/marine/marine_anims.blend
  67. 37 0
      examples/models/skinned/marine/marine_anims.js
  68. BIN
      examples/models/skinned/marine/marine_fbx.blend
  69. BIN
      examples/models/skinned/marine/marine_fk.blend
  70. BIN
      examples/models/skinned/marine/marine_ikrig.blend
  71. 37 0
      examples/models/skinned/marine/marine_ikrig.js
  72. 265 0
      examples/webgl_animation_skinning_blending.html
  73. 34 2
      examples/webgl_animation_skinning_morph.html
  74. 14 10
      examples/webgl_geometry_minecraft.html
  75. 275 0
      examples/webgl_loader_pdb.html
  76. 7 2
      src/core/Geometry.js
  77. 0 41
      src/core/Geometry2.js
  78. 2 2
      src/extras/GeometryUtils.js
  79. 9 12
      src/extras/ImageUtils.js
  80. 165 95
      src/extras/animation/Animation.js
  81. 3 3
      src/extras/animation/AnimationHandler.js
  82. 1 1
      src/extras/animation/KeyFrameAnimation.js
  83. 19 36
      src/extras/geometries/CircleGeometry.js
  84. 32 40
      src/extras/geometries/PlaneGeometry.js
  85. 8 8
      src/extras/helpers/ArrowHelper.js
  86. 69 0
      src/extras/helpers/SkeletonHelper.js
  87. 2 0
      src/extras/renderers/plugins/ShadowMapPlugin.js
  88. 6 0
      src/loaders/Loader.js
  89. 1 0
      src/materials/MeshDepthMaterial.js
  90. 2 0
      src/math/Box3.js
  91. 12 9
      src/math/Matrix3.js
  92. 12 9
      src/math/Matrix4.js
  93. 10 0
      src/objects/Bone.js
  94. 135 0
      src/objects/Skeleton.js
  95. 17 122
      src/objects/SkinnedMesh.js
  96. 79 79
      src/renderers/WebGLRenderer.js
  97. 6 2
      src/renderers/shaders/ShaderLib.js
  98. 3 0
      src/renderers/webgl/WebGLShader.js
  99. 1 1
      utils/build/build.js
  100. 1 0
      utils/build/includes/canvas.json

+ 1 - 1
.gitignore

@@ -1,4 +1,4 @@
 .DS_Store
 *.swp
 .project
-utils/npm/node_modules/*
+node_modules

+ 5 - 5
README.md

@@ -17,12 +17,12 @@ Alternatively see [how to build the library yourself](https://github.com/mrdoob/
 <script src="js/three.min.js"></script>
 ```
 
-This code creates a scene, then creates a camera, adds the camera and cube to the scene, creates a &lt;canvas&gt; renderer and adds its viewport in the document.body element.
+This code creates a scene, a camera, and a geometric cube, and it adds the cube to the scene. It then creates a &lt;canvas&gt; renderer for the scene and camera, and it adds that viewport to the document.body element. Finally it animates the cube within the scene for the camera.
 
 ```html
 <script>
 
-	var camera, scene, renderer;
+	var scene, camera, renderer;
 	var geometry, material, mesh;
 
 	init();
@@ -30,15 +30,15 @@ This code creates a scene, then creates a camera, adds the camera and cube to th
 
 	function init() {
 
+		scene = new THREE.Scene();
+		
 		camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
 		camera.position.z = 1000;
 
-		scene = new THREE.Scene();
-
 		geometry = new THREE.BoxGeometry( 200, 200, 200 );
 		material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
-
 		mesh = new THREE.Mesh( geometry, material );
+		
 		scene.add( mesh );
 
 		renderer = new THREE.CanvasRenderer();

File diff suppressed because it is too large
+ 349 - 1434
build/three.js


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


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

@@ -212,7 +212,7 @@
 
 		<h3>.containsPoint([page:Vector2 point]) [page:Boolean]</h3>
 		<div>
-		point -- Point to check for inclusion.
+		point -- [page:Vector2] to check for inclusion.
 		</div>
 		<div>
 		Returns true if the specified point lies within the boundaries of this box.

+ 103 - 67
docs/api/math/Box3.html

@@ -17,11 +17,11 @@
 
 		<h3>[name]([page:Vector3 min], [page:Vector3 max])</h3>
 		<div>
-		min -- Lower (x, y, z) boundary of the box.  <br />
+		min -- Lower (x, y, z) boundary of the box.<br />
 		max -- Upper (x, y, z) boundary of the box.
 		</div>
 		<div>
-		Creates a box bounded by min and max
+		Creates a box bounded by min and max. 
 		</div>
 
 		<h2>Properties</h2>
@@ -36,7 +36,7 @@
 		<h3>.[page:Vector3 min]</h3>
 		<div>
 		Lower (x, y, z) boundary of this box.
-		</div> 
+		</div>
 
 		<h2>Methods</h2>
 
@@ -44,113 +44,134 @@
 
 		<h3>.set([page:Vector3 min], [page:Vector3 max]) [page:Box3 this]</h3>
 		<div>
-		min -- Upper (x, y, z) boundary of this box. <br />
-		max -- Lower (x, y, z) boundary of this box.
+		min -- Lower (x, y, z) boundary of the box. <br />
+		max -- Upper (x, y, z) boundary of the box.
 		</div>
 		<div>
 		Sets the lower and upper (x, y, z) boundaries of this box.
 		</div>
-
-		<h3>.applyMatrix4([page:Matrix4 matrix]) [page:Box3 this]</h3>
+		
+		<h3>.addPoint([page:Vector3 point]) [page:Box3 this]</h3>
 		<div>
-		matrix -- [page:Matrix4].
+		point -- [page:Vector3] to add to the box <br />
 		</div>
 		<div>
-		Transform the box with a Matrix4.
+		If the *point* is outside the bounds of the box, the bounds are expanded
+		so that the point is within the bounds.
+		</div>
+		
+		<h3>.applyMatrix4([page:Matrix4 matrix]) [page:Box3 this]</h3>
+		<div>
+		matrix -- The [page:Matrix4] to apply
 		</div>
-
-		<h3>.expandByPoint([page:Vector3 point]) [page:Box3 this]</h3>
 		<div>
-		Expands the box outwards by the point. It takes the min and max values of the box.
+		Transforms this Box3 with the supplied matrix.
 		</div>
 
 		<h3>.clampPoint([page:Vector3 point], [page:Vector3 optionalTarget]) [page:Vector3]</h3>
 		<div>
-		point -- [page:Vector3] <br />
-		optionalTarget -- [page:Vector3] An optional target point.
+		point -- Position to clamp. <br />
+		optionalTarget -- If specified, the clamped result will be copied here.
 		</div>
 		<div>
-		Clamp a point within the min and max boundaries of the box. Returns either a new point or the modified passed target.
+		Clamps *point* within the bounds of this box.
 		</div>
 
 		<h3>.isIntersectionBox([page:Box3 box]) [page:Boolean]</h3>
 		<div>
-		box -- [page:Box3]
+		box -- Box to check for intersection against.
 		</div>
 		<div>
-		Return whether or not the passed box intersects with this Box3.
+		Determines whether or not this box intersects *box*.
 		</div>
 
-		<h3>.setFromPoints([page:Array points])</h3>
+		<h3>.setFromPoints([page:Array points]) [page:Box3 this]</h3>
 		<div>
-		points -- [page:Array] of [page:Vector3] points
+		points -- Set of points that the resulting box will envelop.
 		</div>
 		<div>
-		Sets this box to the min value and max value of all the points in the array. If the array is empty, then it sets the box as empty.
+		Sets the upper and lower bounds of this box to include all of the points in *points*.
 		</div>
-
-		<h3>.size([page:Vector3 optionalTarget]) [page:Vector3]</h3>
+		
+		<h3>.setFromObject([page:Object3D object]) [page:Box3 this]</h3>
 		<div>
-		optionalTarget -- [page:Vector3] (optional)
+		object -- [page:Object3D] to compute the bounding box for.
 		</div>
 		<div>
-		Returns either a new Vector3 or the target Vector3 that represents the size of the box from the min point to max point.
+		Computes the world-axis-aligned bounding box of an object (including its children),
+		accounting for both the object's, and childrens', world transforms
 		</div>
+		
+		
 
-		<h3>.union([page:Box3 box]) [page:Box3 this]</h3>
+		<h3>.size([page:Vector3 optionalTarget]) [page:Vector3]</h3>
 		<div>
-		box -- [page:Box3]
+		optionalTarget -- If specified, the result will be copied here.
 		</div>
 		<div>
-		Sets the box's min and max boundaries to union of the two boxes.
+		Returns the width, height, and depth of this box.
 		</div>
 
-		<h3>.getParameter([page:Vector3 point], [page:Vector3 optionalTarget]) [page:Vector3]</h3>
+		<h3>.union([page:Box3 box]) [page:Box3]</h3>
 		<div>
-		point -- [page:Vector3]<br/>
-		optionalTarget -- [page:Vector3]
+		box -- Box that will be unioned with this box.
 		</div>
 		<div>
-		Returns a point as a proportion of this box's width, height, and depth. If the point is contained by the box the x, y, and z of the returned vector will be between 0 and 1.
+		Unions this box with *box* setting the upper bound of this box to the greater of the 
+		two boxes' upper bounds and the lower bound of this box to the lesser of the two boxes'
+		lower bounds.
 		</div>
 
-		<h3>.expandByScalar([page:Float scalar]) [page:Box3 this]</h3>
+		<h3>.getParameter([page:Vector3 point], [page:Vector3 optionalTarget]) [page:Vector3]</h3>
 		<div>
-		scalar -- [page:Float] representing the distance to expand
+		point -- Point to parametrize.
+		optionalTarget -- If specified, the result will be copied here.
 		</div>
 		<div>
-		Expands or contracts the box by adding the scalar value to the box's min and max vectors.
+		Returns point as a proportion of this box's width and height.
 		</div>
 
 		<h3>.intersect([page:Box3 box]) [page:Box3 this]</h3>
 		<div>
-		box -- [page:Box3]
+		box -- Box to intersect with.
 		</div>
 		<div>
-		Returns the intersection of the two boxes, setting the upper bound of this box to the lesser of the two boxes' upper bounds and the lower bound of this box to the greater of the two boxes' lower bounds.
- 
+		Returns the intersection of this and *box*, setting the upper bound of this box to the lesser </br>
+		of the two boxes' upper bounds and the lower bound of this box to the greater of the two boxes' </br>
+		lower bounds.
 		</div>
 
 		<h3>.containsBox([page:Box3 box]) [page:Boolean]</h3>
 		<div>
-		box -- [page:Box3]
+		box -- Box to test for inclusion.
 		</div>
 		<div>
-		Returns true if this box includes the entirety of box. If this and box overlap exactly, this function also returns true.
- 
+		Returns true if this box includes the entirety of *box*. If this and *box* overlap exactly,</br>
+		this function also returns true. 
 		</div>
 
+		<h3>.containsPoint([page:Vector3 point]) [page:Boolean]</h3>
+		<div>
+		point -- [page:Vector3] to check for inclusion.
+		</div>
+		<div>
+		Returns true if the specified point lies within the boundaries of this box.
+		</div>
+		
 		<h3>.translate([page:Vector3 offset]) [page:Box3 this]</h3>
 		<div>
-		offset -- [page:Vector3]
+		offset -- Direction and distance of offset.
 		</div>
 		<div>
-		Translates the box the distance of the offset.
+		Adds *offset* to both the upper and lower bounds of this box, effectively moving this box </br>
+		*offset* units in 3D space.
 		</div>
 
 		<h3>.empty() [page:Boolean]</h3>
 		<div>
-		Checks to see if the box is empty. If the lower and upper bounds of the box are equal, this function still returns false as the box would still contain one point.
+		Returns true if this box includes zero points within its bounds.</br>
+		Note that a box with equal lower and upper bounds still includes one point, the
+		one both bounds share.
 		</div>
 
 		<h3>.clone() [page:Box3]</h3>
@@ -160,72 +181,87 @@
 
 		<h3>.equals([page:Box3 box]) [page:Boolean]</h3>
 		<div>
-		box -- [page:Box3]
+		box -- Box to compare.
 		</div>
 		<div>
-		Returns true if the boes share the same lower and upper bounds. 
+		Returns true if this box and *box* share the same lower and upper bounds.
 		</div>
 
+		<h3>.expandByPoint([page:Vector3 point]) [page:Box3 this]</h3>
+		<div>
+		point -- Point that should be included in the box.
+		</div>
+		<div>
+		Expands the boundaries of this box to include *point*.
+		</div>
+		
+		<h3>.expandByScalar([page:float scalar]) [page:Box3 this]</h3>
+		<div>
+		scalar -- Distance to expand.
+		</div>
+		<div>
+		Expands each dimension of the box by *scalar*. If negative, the dimensions of the box <br/>
+		will be contracted.
+		</div>
+		
 		<h3>.expandByVector([page:Vector3 vector]) [page:Box3 this]</h3>
 		<div>
-		vector -- [page:Vector3] representing the amount to expand this box in each dimension.
+		vector -- Amount to expand this box in each dimension.
 		</div>
 		<div>
-		Adds the passed vector to the upper boundary, and subtracts it from the lower boundary.
+		Expands this box equilaterally by *vector*. The width of this box will be
+		expanded by the x component of *vector* in both directions. The height of 
+		this box will be expanded by the y component of *vector* in both directions.
+		The depth of this box will be expanded by the z component of *vector* in
+		both directions.
 		</div>
 
 		<h3>.copy([page:Box3 box]) [page:Box3 this]</h3>
 		<div>
-		box -- [page:Box3] to copy.
+		box -- Box to copy.
 		</div>
 		<div>
-		Copies the values of the passed box to this box.
+		Copies the values of *box* to this box.
 		</div>
 
 		<h3>.makeEmpty() [page:Box3 this]</h3>
 		<div>
-		Makes this box empty so that it cannot contain any points.
+		Makes this box empty.
 		</div>
 
 		<h3>.center([page:Vector3 optionalTarget]) [page:Vector3]</h3>
 		<div>
-		optionalTarget -- [page:Vector3] If specified, the result will be copied here.
+		optionalTarget -- If specified, the result will be copied here.
 		</div>
 		<div>
-		Returns the center point of this box. 
+		Returns the center point of this box.
 		</div>
 
 		<h3>.getBoundingSphere([page:Sphere optionalTarget]) [page:Sphere]</h3>
 		<div>
-		optionalTarget -- [page:Sphere]
+		optionalTarget -- [page:Sphere] to optionally set the result to.
 		</div>
 		<div>
-		Returns a bounding sphere.
+		Gets a sphere that bounds the box.
 		</div>
 
 		<h3>.distanceToPoint([page:Vector3 point]) [page:Float]</h3>
 		<div>
-		point -- [page:Vector3]
+		point -- Point to measure distance to.
 		</div>
 		<div>
-		Returns the distance from any edge of this box to the specified point. If the point lies inside of this box, the distance will be 0.
-		</div>
-
-		<h3>.containsPoint([page:Vector3 point]) [page:Boolean]</h3>
-		<div>
-		point -- [page:Vector3]
-		</div>
-		<div>
-		Returns true if the specified point lies within the boundaries of this box.
+		Returns the distance from any edge of this box to the specified point. </br>
+		If the point lies inside of this box, the distance will be 0.
 		</div>
 
 		<h3>.setFromCenterAndSize([page:Vector3 center], [page:Vector3 size]) [page:Box3 this]</h3>
 		<div>
-		center -- [page:Vector3] representing the center position.<br />
-		size -- [page:Vector3] representing the dimensions of the box.
+		center -- Desired center position of the box. <br />
+		size -- Desired x and y dimensions of the box. 
 		</div>
 		<div>
-		Sets this box based on a center vector, and width, height, and depth vector.
+		Centers this box on *center* and sets this box's width and height to the values specified
+		in *size*.
 		</div>
 
 		<h2>Source</h2>

+ 2 - 2
docs/api/renderers/WebGLRenderer.html

@@ -126,7 +126,7 @@
 
 		<h3>.[page:Boolean autoScaleCubemaps]</h3>
 
-		<div>Default is true. If set, then Cubemaps are scaled, when the are bigger the the maximum size, to make sure that they aren't bigger then the maximum size.</div>
+		<div>Default is true. If set, then Cubemaps are scaled, when they are bigger than the maximum size, to make sure that they aren't bigger than the maximum size.</div>
 
 
 		<h3>.[page:Boolean renderPluginsPre]</h3>
@@ -253,7 +253,7 @@
 		<h3>.render( [page:Scene scene], [page:Camera camera], [page:WebGLRenderTarget renderTarget], [page:Boolean forceClear] )</h3>
 		<div>Render a scene using a camera.</div>
 		<div>The render is done to the renderTarget (if specified) or to the canvas as usual.</div>
-        <div>If forceClear is true the depth, stencil and color buffers will be cleared before rendering even if the renderer's autoClear property is false.</div>
+        <div>If forceClear is true, the depth, stencil and color buffers will be cleared before rendering even if the renderer's autoClear property is false.</div>
         <div>Even with forceClear set to true you can prevent certain buffers being cleared by setting either the .autoClearColor, .autoClearStencil or .autoClearDepth properties to false.</div>
 
 		<h3>.renderImmediateObject( camera, lights, fog, material, object )</h3>

+ 4 - 2
docs/index.html

@@ -16,6 +16,7 @@
 			}
 
 			body {
+				background-color: #ffffff;
 				margin: 0;
 				padding: 0 0 0 260px;
 				height: 100%;
@@ -33,14 +34,15 @@
 
 			#panel	{
 				position: fixed;
-				left: 0;
+				left: 0px;
 				width: 260px;
 				height: 100%;
 				overflow: auto;
+				background: #fafafa;
 			}
 
 				#panel h1 {
-					margin-top: 20px;
+					margin-top: 30px;
 					margin-bottom: 40px;
 					margin-left: 20px;
 					font-size: 25px;

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

@@ -18,7 +18,7 @@
 		<div>Three.js is a library that makes WebGL - 3D in the browser - very easy. While a simple cube in raw WebGL would turn out hundreds of lines of Javascript and shader code, a Three.js equivalent is only a fraction of that.</div>
 
 		<h2>Before we start</h2>
-		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, and open it in your browser.</div>
+		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of <a href="http://threejs.org/build/three.min.js">three.min.js</a> in the js/ directory, and open it in your browser.</div>
 
 		<code>
 		&lt;html&gt;
@@ -27,7 +27,7 @@
 				&lt;style&gt;canvas { width: 100%; height: 100% }&lt;/style&gt;
 			&lt;/head&gt;
 			&lt;body&gt;
-				&lt;script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"&gt;&lt;/script&gt;
+				&lt;script src="js/three.min.js"&gt;&lt;/script&gt;
 				&lt;script&gt;
 					// Our Javascript will go here.
 				&lt;/script&gt;
@@ -121,7 +121,7 @@
 				&lt;style&gt;canvas { width: 100%; height: 100% }&lt;/style&gt;
 			&lt;/head&gt;
 			&lt;body&gt;
-				&lt;script src="three.min.js"&gt;&lt;/script&gt;
+				&lt;script src="js/three.min.js"&gt;&lt;/script&gt;
 				&lt;script&gt;
 					var scene = new THREE.Scene();
 					var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

+ 1 - 1
docs/page.css

@@ -6,7 +6,7 @@
 }
 
 body {
-	margin: 25px 20px;
+	margin: 30px 20px;
 	color: #555;
 	font-family: 'inconsolata';
 	font-size: 15px;

+ 26 - 0
editor/css/dark.css

@@ -55,6 +55,28 @@ button {
 	user-select: none;
 }
 
+.CollapsiblePanel .CollapsiblePanelButton {
+	float: left;
+	margin-right: 6px;
+	width: 0px;
+	height: 0px;
+	border: 6px solid transparent;
+}
+
+.CollapsiblePanel.collapsed .CollapsiblePanelButton {
+	margin-top: 2px;
+	border-left-color: #555;
+}
+
+.CollapsiblePanel:not(.collapsed) .CollapsiblePanelButton {
+	margin-top: 6px;
+	border-top-color: #555;
+}
+
+.CollapsiblePanel.collapsed .CollapsibleContent {
+	display: none;
+}
+
 .FancySelect {
 	background: #222;
 	border: 1px solid #3C3C3C;
@@ -158,6 +180,10 @@ input.Number {
 		margin-bottom: 10px;
 	}
 
+	#sidebar .Panel.collapsed {
+		margin-bottom: 0px;
+	}
+
 	#sidebar > .Panel {
 		color: #888;
 		padding: 10px;

+ 26 - 0
editor/css/light.css

@@ -28,6 +28,28 @@ button {
 	user-select: none;
 }
 
+.CollapsiblePanel .CollapsiblePanelButton {
+	float: left;
+	margin-right: 6px;
+	width: 0px;
+	height: 0px;
+	border: 6px solid transparent;
+}
+
+.CollapsiblePanel.collapsed .CollapsiblePanelButton {
+	margin-top: 2px;
+	border-left-color: #bbb;
+}
+
+.CollapsiblePanel:not(.collapsed) .CollapsiblePanelButton {
+	margin-top: 6px;
+	border-top-color: #bbb;
+}
+
+.CollapsiblePanel.collapsed .CollapsibleContent {
+	display: none;
+}
+
 .FancySelect {
 	background: #fff;
 	border: 1px solid #ccc;
@@ -131,6 +153,10 @@ input.Number {
 		margin-bottom: 10px;
 	}
 
+	#sidebar .Panel.collapsed {
+		margin-bottom: 0px;
+	}
+
 	#sidebar > .Panel {
 		color: #888;
 		padding: 10px;

+ 1 - 1
editor/js/Menubar.View.js

@@ -32,6 +32,6 @@ Menubar.View = function ( editor ) {
 
 	optionsPanel = UI.MenubarHelper.createOptionsPanel( menuConfig );
 
-	return UI.MenubarHelper.createMenuContainer( 'Help', optionsPanel );
+	return UI.MenubarHelper.createMenuContainer( 'View', optionsPanel );
 
 }

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

@@ -2,11 +2,11 @@ Sidebar.Geometry = function ( editor ) {
 
 	var signals = editor.signals;
 
-	var container = new UI.Panel();
+	var container = new UI.CollapsiblePanel();
 	container.setDisplay( 'none' );
 
-	container.add( new UI.Text().setValue( 'GEOMETRY' ) );
-	container.add( new UI.Break(), new UI.Break() );
+	container.addStatic( new UI.Text().setValue( 'GEOMETRY' ) );
+	container.add( new UI.Break() );
 
 	// uuid
 

+ 3 - 3
editor/js/Sidebar.Material.js

@@ -20,12 +20,12 @@ Sidebar.Material = function ( editor ) {
 
 	};
 
-	var container = new UI.Panel();
+	var container = new UI.CollapsiblePanel();
 	container.setDisplay( 'none' );
 	container.dom.classList.add( 'Material' );
 
-	container.add( new UI.Text().setValue( 'MATERIAL' ) );
-	container.add( new UI.Break(), new UI.Break() );
+	container.addStatic( new UI.Text().setValue( 'MATERIAL' ) );
+	container.add( new UI.Break() );
 
 	// uuid
 

+ 3 - 3
editor/js/Sidebar.Object3D.js

@@ -2,12 +2,12 @@ Sidebar.Object3D = function ( editor ) {
 
 	var signals = editor.signals;
 
-	var container = new UI.Panel();
+	var container = new UI.CollapsiblePanel();
 	container.setDisplay( 'none' );
 
 	var objectType = new UI.Text().setTextTransform( 'uppercase' );
-	container.add( objectType );
-	container.add( new UI.Break(), new UI.Break() );
+	container.addStatic( objectType );
+	container.add( new UI.Break() );
 
 	// uuid
 

+ 4 - 3
editor/js/Sidebar.Renderer.js

@@ -13,10 +13,11 @@ Sidebar.Renderer = function ( editor ) {
 
 	};
 
-	var container = new UI.Panel();
+	var container = new UI.CollapsiblePanel();
+	container.setCollapsed( true );
 
-	container.add( new UI.Text( 'RENDERER' ) );
-	container.add( new UI.Break(), new UI.Break() );
+	container.addStatic( new UI.Text( 'RENDERER' ) );
+	container.add( new UI.Break() );
 
 	// class
 

+ 11 - 3
editor/js/Sidebar.Scene.js

@@ -2,16 +2,22 @@ Sidebar.Scene = function ( editor ) {
 
 	var signals = editor.signals;
 
-	var container = new UI.Panel();
+	var container = new UI.CollapsiblePanel();
 
-	container.add( new UI.Text( 'SCENE' ) );
-	container.add( new UI.Break(), new UI.Break() );
+	container.addStatic( new UI.Text( 'SCENE' ) );
+	container.add( new UI.Break() );
+
+	var ignoreObjectSelectedSignal = false;
 
 	var outliner = new UI.FancySelect().setId( 'outliner' );
 	outliner.onChange( function () {
 
+		ignoreObjectSelectedSignal = true;
+
 		editor.selectById( parseInt( outliner.getValue() ) );
 
+		ignoreObjectSelectedSignal = false;
+
 	} );
 	container.add( outliner );
 	container.add( new UI.Break() );
@@ -194,6 +200,8 @@ Sidebar.Scene = function ( editor ) {
 
 	signals.objectSelected.add( function ( object ) {
 
+		if ( ignoreObjectSelectedSignal === true ) return;
+
 		outliner.setValue( object !== null ? object.id : null );
 
 	} );

+ 129 - 1
editor/js/libs/ui.js

@@ -137,6 +137,134 @@ UI.Panel.prototype.clear = function () {
 
 };
 
+
+// Collapsible Panel
+
+UI.CollapsiblePanel = function () {
+
+	UI.Panel.call( this );
+
+	this.dom.className = 'Panel CollapsiblePanel';
+
+	this.button = document.createElement( 'div' );
+	this.button.className = 'CollapsiblePanelButton';
+	this.dom.appendChild( this.button );
+
+	var scope = this;
+	this.button.addEventListener( 'click', function ( event ) {
+
+		scope.toggle();
+
+	}, false );
+
+	this.content = document.createElement( 'div' );
+	this.content.className = 'CollapsibleContent';
+	this.dom.appendChild( this.content );
+
+	this.isCollapsed = false;
+
+	return this;
+
+};
+
+UI.CollapsiblePanel.prototype = Object.create( UI.Panel.prototype );
+
+UI.CollapsiblePanel.prototype.addStatic = function () {
+
+	for ( var i = 0; i < arguments.length; i ++ ) {
+
+		this.dom.insertBefore( arguments[ i ].dom, this.content );
+
+	}
+
+	return this;
+
+};
+
+UI.CollapsiblePanel.prototype.removeStatic = UI.Panel.prototype.remove;
+
+UI.CollapsiblePanel.prototype.clearStatic = function () {
+
+	this.dom.childNodes.forEach( function ( child ) {
+
+		if ( child !== this.content ) {
+
+			this.dom.removeChild( child );
+
+		}
+
+	});
+
+};
+
+UI.CollapsiblePanel.prototype.add = function () {
+
+	for ( var i = 0; i < arguments.length; i ++ ) {
+
+		this.content.appendChild( arguments[ i ].dom );
+
+	}
+
+	return this;
+
+};
+
+UI.CollapsiblePanel.prototype.remove = function () {
+
+	for ( var i = 0; i < arguments.length; i ++ ) {
+
+		this.content.removeChild( arguments[ i ].dom );
+
+	}
+
+	return this;
+
+};
+
+UI.CollapsiblePanel.prototype.clear = function () {
+
+	while ( this.content.children.length ) {
+
+		this.content.removeChild( this.content.lastChild );
+
+	}
+
+};
+
+UI.CollapsiblePanel.prototype.toggle = function() {
+
+	this.setCollapsed( !this.isCollapsed );
+
+};
+
+UI.CollapsiblePanel.prototype.collapse = function() {
+
+	this.setCollapsed( true );
+
+};
+
+UI.CollapsiblePanel.prototype.expand = function() {
+
+	this.setCollapsed( false );
+
+};
+
+UI.CollapsiblePanel.prototype.setCollapsed = function( setCollapsed ) {
+
+	if ( setCollapsed ) {
+
+		this.dom.classList.add('collapsed');
+
+	} else {
+
+		this.dom.classList.remove('collapsed');
+
+	}
+
+	this.isCollapsed = setCollapsed;
+
+};
+
 // Text
 
 UI.Text = function ( text ) {
@@ -367,13 +495,13 @@ UI.FancySelect = function () {
 					// Highlight selected dom elem and scroll parent if needed
 					scope.setValue( scope.options[ scope.selectedIndex ].value );
 
-					// Invoke object/helper/mesh selection logic
 					scope.dom.dispatchEvent( changeEvent );
 
 				}
 
 				break;
 		}
+
 	}, false);
 
 	this.dom = dom;

+ 1 - 1
examples/css3d_periodictable.html

@@ -262,7 +262,7 @@
 
 					var number = document.createElement( 'div' );
 					number.className = 'number';
-					number.textContent = i + 1;
+					number.textContent = (i/5) + 1;
 					element.appendChild( number );
 
 					var symbol = document.createElement( 'div' );

+ 38 - 27
examples/css3d_sandbox.html

@@ -8,9 +8,27 @@
 				margin: 0;
 				overflow: hidden;
 			}
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				color: #000000;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+				z-index: 1;
+			}
+
+			a {
+				color: #000000;
+			}
+
 		</style>
 	</head>
 	<body>
+		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - css3d sandbox</div>
+
 		<script src="../build/three.min.js"></script>
 
 		<script src="js/controls/TrackballControls.js"></script>
@@ -20,7 +38,6 @@
 		<script>
 
 			var camera, scene, renderer;
-			var geometry, material, mesh;
 
 			var scene2, renderer2;
 
@@ -31,59 +48,53 @@
 
 			function init() {
 
-				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
 				camera.position.set( 200, 200, 200 );
 
 				controls = new THREE.TrackballControls( camera );
 
-				controls.rotateSpeed = 1.0;
-				controls.zoomSpeed = 1.2;
-				controls.panSpeed = 0.8;
-
-				controls.noZoom = false;
-				controls.noPan = false;
-
-				controls.staticMoving = false;
-				controls.dynamicDampingFactor = 0.3;
-
-				controls.keys = [ 65, 83, 68 ];
-
 				scene = new THREE.Scene();
+				scene2 = new THREE.Scene();
 
-				geometry = new THREE.BoxGeometry( 200, 200, 200 );
-				material = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 1 } );
-
-				mesh = new THREE.Mesh( geometry, material );
-				scene.add( mesh );
-
-				renderer = new THREE.CanvasRenderer();
-				renderer.setClearColor( 0xffffff );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				document.body.appendChild( renderer.domElement );
+				var material = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 1, side: THREE.DoubleSide } );
 
 				//
 
-				scene2 = new THREE.Scene();
-
-				for ( var i = 0; i < 20; i ++ ) {
+				for ( var i = 0; i < 10; i ++ ) {
 
 					var element = document.createElement( 'div' );
 					element.style.width = '100px';
 					element.style.height = '100px';
+					element.style.opacity = 0.5;
 					element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle();
 
 					var object = new THREE.CSS3DObject( element );
 					object.position.x = Math.random() * 200 - 100;
 					object.position.y = Math.random() * 200 - 100;
 					object.position.z = Math.random() * 200 - 100;
+					object.rotation.x = Math.random();
+					object.rotation.y = Math.random();
+					object.rotation.z = Math.random();
 					object.scale.x = Math.random() + 0.5;
 					object.scale.y = Math.random() + 0.5;
 					scene2.add( object );
 
+					var geometry = new THREE.PlaneGeometry( 100, 100 );
+					var mesh = new THREE.Mesh( geometry, material );
+					mesh.position.copy( object.position );
+					mesh.rotation.copy( object.rotation );
+					mesh.scale.copy( object.scale );
+					scene.add( mesh );
+
 				}
 
 				//
 
+				renderer = new THREE.CanvasRenderer();
+				renderer.setClearColor( 0xf0f0f0 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
 				renderer2 = new THREE.CSS3DRenderer();
 				renderer2.setSize( window.innerWidth, window.innerHeight );
 				renderer2.domElement.style.position = 'absolute';

+ 4 - 1
examples/index.html

@@ -26,7 +26,7 @@
 			}
 
 			h1 {
-				margin-top: 20px;
+				margin-top: 30px;
 				margin-bottom: 40px;
 				font-size: 25px;
 				font-weight: normal;
@@ -42,6 +42,7 @@
 				width: 310px;
 				height: 100%;
 				overflow: scroll;
+				background: #fafafa;
 			}
 
 				#panel #list {
@@ -103,6 +104,7 @@
 		var files = {
 			"webgl": [
 				"webgl_animation_cloth",
+				"webgl_animation_skinning_blending",
 				"webgl_animation_skinning_morph",
 				"webgl_buffergeometry",
 				"webgl_buffergeometry_custom_attributes_particles",
@@ -177,6 +179,7 @@
 				"webgl_loader_json_objconverter",
 				"webgl_loader_obj",
 				"webgl_loader_obj_mtl",
+				"webgl_loader_pdb",	
 				"webgl_loader_ply",
 				"webgl_loader_scene",
 				"webgl_loader_scene_blender",

+ 271 - 0
examples/js/BlendCharacter.js

@@ -0,0 +1,271 @@
+/**
+ * @author Michael Guerrero / http://realitymeltdown.com
+ */
+
+THREE.BlendCharacter = function () {
+
+	this.animations = {};
+	this.weightSchedule = [];
+	this.warpSchedule = [];
+
+	this.load = function( url, onLoad ) {
+
+		var scope = this;
+
+		var loader = new THREE.JSONLoader();
+		loader.load( url, function( geometry, materials ) {
+
+			var originalMaterial = materials[ 0 ];
+			originalMaterial.skinning = true;
+
+			THREE.SkinnedMesh.call( scope, geometry, originalMaterial );
+
+			// Create the animations
+
+			for ( var i = 0; i < geometry.animations.length; ++i ) {
+
+				THREE.AnimationHandler.add( geometry.animations[ i ] );
+
+				var animName = geometry.animations[ i ].name;
+				scope.animations[ animName ] = new THREE.Animation( scope, animName );
+
+			}
+
+			// Create the debug visualization
+
+			scope.skeletonHelper = new THREE.SkeletonHelper( scope );
+			scope.skeletonHelper.material.linewidth = 3;
+			scope.add( scope.skeletonHelper );
+
+			scope.showSkeleton( false );
+
+			// Loading is complete, fire the callback
+			if ( onLoad !== undefined ) onLoad();
+
+		} );
+
+	};
+
+	this.update = function( dt ) {
+
+		for ( var i = this.weightSchedule.length - 1; i >= 0; --i ) {
+
+			var data = this.weightSchedule[ i ];
+			data.timeElapsed += dt;
+
+			// If the transition is complete, remove it from the schedule
+
+			if ( data.timeElapsed > data.duration ) {
+
+				data.anim.weight = data.endWeight;
+				this.weightSchedule.splice( i, 1 );
+
+				// If we've faded out completely, stop the animation
+
+				if ( data.anim.weight == 0 ) {
+
+					data.anim.stop( 0 );
+
+				}
+
+			} else {
+
+				// interpolate the weight for the current time
+
+				data.anim.weight = data.startWeight + (data.endWeight - data.startWeight) * data.timeElapsed / data.duration;
+
+			}
+
+		}
+
+		this.updateWarps( dt );
+		this.skeletonHelper.update();
+
+	};
+
+	this.updateWarps = function( dt ) {
+
+		// Warping modifies the time scale over time to make 2 animations of different
+		// lengths match. This is useful for smoothing out transitions that get out of
+		// phase such as between a walk and run cycle
+
+		for ( var i = this.warpSchedule.length - 1; i >= 0; --i ) {
+
+			var data = this.warpSchedule[ i ];
+			data.timeElapsed += dt;
+
+			if ( data.timeElapsed > data.duration ) {
+
+				data.to.weight = 1;
+				data.to.timeScale = 1;
+				data.from.weight = 0;
+				data.from.timeScale = 1;
+				data.from.stop( 0 );
+
+				this.warpSchedule.splice( i, 1 );
+
+			} else {
+
+				var alpha = data.timeElapsed / data.duration;
+
+				var fromLength = data.from.data.length;
+				var toLength = data.to.data.length;
+
+				var fromToRatio = fromLength / toLength;
+				var toFromRatio = toLength / fromLength;
+
+				// scale from each time proportionally to the other animation
+
+				data.from.timeScale = ( 1 - alpha ) + fromToRatio * alpha;
+				data.to.timeScale = alpha + toFromRatio * ( 1 - alpha );
+
+				data.from.weight = 1 - alpha;
+				data.to.weight = alpha;
+
+			}
+
+		}
+
+	}
+
+	this.play = function(animName, weight) {
+
+		this.animations[ animName ].play( 0, weight );
+
+	};
+
+	this.crossfade = function( fromAnimName, toAnimName, duration ) {
+
+		var fromAnim = this.animations[ fromAnimName ];
+		var toAnim = this.animations[ toAnimName ];
+
+		fromAnim.play( 0, 1 );
+		toAnim.play( 0, 0 );
+
+		this.weightSchedule.push( {
+
+			anim: fromAnim,
+			startWeight: 1,
+			endWeight: 0,
+			timeElapsed: 0,
+			duration: duration
+
+		} );
+
+		this.weightSchedule.push( {
+
+			anim: toAnim,
+			startWeight: 0,
+			endWeight: 1,
+			timeElapsed: 0,
+			duration: duration
+
+		} );
+
+	};
+
+	this.warp = function( fromAnimName, toAnimName, duration ) {
+
+		var fromAnim = this.animations[ fromAnimName ];
+		var toAnim = this.animations[ toAnimName ];
+
+		fromAnim.play( 0, 1 );
+		toAnim.play( 0, 0 );
+
+		this.warpSchedule.push( {
+
+			from: fromAnim,
+			to: toAnim,
+			timeElapsed: 0,
+			duration: duration
+
+		} );
+
+	};
+
+	this.applyWeight = function(animName, weight) {
+
+		this.animations[ animName ].weight = weight;
+
+	};
+
+	this.pauseAll = function() {
+
+		for ( var a in this.animations ) {
+
+			if ( this.animations[ a ].isPlaying ) {
+
+				this.animations[ a ].pause();
+
+			}
+
+		}
+
+	};
+
+	this.unPauseAll = function() {
+
+	for ( var a in this.animations ) {
+
+	  if ( this.animations[ a ].isPlaying && this.animations[ a ].isPaused ) {
+
+		this.animations[ a ].pause();
+
+	  }
+
+	}
+
+  };
+
+
+	this.stopAll = function() {
+
+		for ( a in this.animations ) {
+
+			if ( this.animations[ a ].isPlaying ) {
+				this.animations[ a ].stop(0);
+			}
+
+			this.animations[ a ].weight = 0;
+
+		}
+
+		this.weightSchedule.length = 0;
+		this.warpSchedule.length = 0;
+
+	}
+
+	this.showSkeleton = function( boolean ) {
+
+		this.skeletonHelper.visible = boolean;
+
+	}
+
+	this.showModel = function( boolean ) {
+
+		this.visible = boolean;
+
+	}
+
+};
+
+
+THREE.BlendCharacter.prototype = Object.create( THREE.SkinnedMesh.prototype );
+
+THREE.BlendCharacter.prototype.getForward = function() {
+
+	var forward = new THREE.Vector3();
+
+	return function() {
+
+		// pull the character's forward basis vector out of the matrix
+		forward.set(
+			-this.matrix.elements[ 8 ],
+			-this.matrix.elements[ 9 ],
+			-this.matrix.elements[ 10 ]
+		);
+
+		return forward;
+	}
+}
+

+ 214 - 0
examples/js/BlendCharacterGui.js

@@ -0,0 +1,214 @@
+/**
+ * @author Michael Guerrero / http://realitymeltdown.com
+ */
+
+function BlendCharacterGui(animations) {
+
+	var controls = {
+
+		gui: null,
+		"Lock Camera": false,
+		"Show Model": true,
+		"Show Skeleton": false,
+		"Time Scale": 1.0,
+		"Step Size": 0.016,
+		"Crossfade Time": 3.5,
+		"idle": 0.33,
+		"walk": 0.33,
+		"run": 0.33
+
+	};
+
+	var animations = animations;
+
+	this.showModel = function() {
+
+		return controls['Show Model'];
+
+	};
+
+	this.showSkeleton = function() {
+
+		return controls['Show Skeleton'];
+
+	};
+
+	this.getTimeScale = function() {
+
+		return controls['Time Scale'];
+
+	};
+
+	this.update = function() {
+
+		controls[ 'idle'] = animations[ 'idle' ].weight;
+		controls[ 'walk'] = animations[ 'walk' ].weight;
+		controls[ 'run'] = animations[ 'run' ].weight;
+
+	};
+
+	var init = function() {
+
+		controls.gui = new dat.GUI();
+
+		var settings = controls.gui.addFolder( 'Settings' );
+		var playback = controls.gui.addFolder( 'Playback' );
+		var blending = controls.gui.addFolder( 'Blend Tuning' );
+
+		settings.add( controls, "Lock Camera" ).onChange( controls.lockCameraChanged );
+		settings.add( controls, "Show Model" ).onChange( controls.showModelChanged );
+		settings.add( controls, "Show Skeleton" ).onChange( controls.showSkeletonChanged );
+		settings.add( controls, "Time Scale", 0, 1, 0.01 );
+		settings.add( controls, "Step Size", 0.01, 0.1, 0.01 );
+		settings.add( controls, "Crossfade Time", 0.1, 6.0, 0.05 );
+
+		// These controls execute functions
+		playback.add( controls, "start" );
+		playback.add( controls, "pause" );
+		playback.add( controls, "step" );
+		playback.add( controls, "idle to walk" );
+		playback.add( controls, "walk to run" );
+		playback.add( controls, "warp walk to run" );
+
+		blending.add( controls, "idle", 0, 1, 0.01).listen().onChange( controls.weight );
+		blending.add( controls, "walk", 0, 1, 0.01).listen().onChange( controls.weight );
+		blending.add( controls, "run", 0, 1, 0.01).listen().onChange( controls.weight );
+
+		settings.open();
+		playback.open();
+		blending.open();
+
+	}
+
+	var getAnimationData = function() {
+
+		return {
+
+			detail: {
+
+				anims: [ "idle", "walk", "run" ],
+
+				weights: [ controls['idle'],
+						   controls['walk'],
+						   controls['run'] ]
+			}
+
+		};
+	}
+
+	controls.start = function() {
+
+		var startEvent = new CustomEvent( 'start-animation', getAnimationData() );
+		window.dispatchEvent(startEvent);
+
+	};
+
+	controls.stop = function() {
+
+		var stopEvent = new CustomEvent( 'stop-animation' );
+		window.dispatchEvent( stopEvent );
+
+	};
+
+	controls.pause = function() {
+
+		var pauseEvent = new CustomEvent( 'pause-animation' );
+		window.dispatchEvent( pauseEvent );
+
+	};
+
+	controls.step = function() {
+
+		var stepData = { detail: { stepSize: controls['Step Size'] } };
+		window.dispatchEvent( new CustomEvent('step-animation', stepData ));
+
+	};
+
+	controls.weight = function() {
+
+		// renormalize
+		var sum = controls['idle'] + controls['walk'] + controls['run'];
+		controls['idle'] /= sum;
+		controls['walk'] /= sum;
+		controls['run'] /= sum;
+
+		var weightEvent = new CustomEvent( 'weight-animation', getAnimationData() );
+		window.dispatchEvent(weightEvent);
+	};
+
+	controls.crossfade = function( from, to ) {
+
+		var fadeData = getAnimationData();
+		fadeData.detail.from = from;
+		fadeData.detail.to = to;
+		fadeData.detail.time = controls[ "Crossfade Time" ];
+
+		window.dispatchEvent( new CustomEvent( 'crossfade', fadeData ) );
+	}
+
+	controls.warp = function( from, to ) {
+
+		var warpData = getAnimationData();
+		warpData.detail.from = 'walk';
+		warpData.detail.to = 'run';
+		warpData.detail.time = controls[ "Crossfade Time" ];
+
+		window.dispatchEvent( new CustomEvent( 'warp', warpData ) );
+	}
+
+	controls['idle to walk'] = function() {
+
+		controls.crossfade( 'idle', 'walk' );
+
+	};
+
+	controls['walk to run'] = function() {
+
+		controls.crossfade( 'walk', 'run' );
+
+	};
+
+	controls['warp walk to run'] = function() {
+
+		controls.warp( 'walk', 'run' );
+
+	};
+
+	controls.lockCameraChanged = function() {
+
+		var data = {
+			detail: {
+				shouldLock: controls['Lock Camera']
+			}
+		}
+
+		window.dispatchEvent( new CustomEvent( 'toggle-lock-camera', data ) );
+	}
+
+	controls.showSkeletonChanged = function() {
+
+		var data = {
+			detail: {
+				shouldShow: controls['Show Skeleton']
+			}
+		}
+
+		window.dispatchEvent( new CustomEvent( 'toggle-show-skeleton', data ) );
+	}
+
+
+	controls.showModelChanged = function() {
+
+		var data = {
+			detail: {
+				shouldShow: controls['Show Model']
+			}
+		}
+
+		window.dispatchEvent( new CustomEvent( 'toggle-show-model', data ) );
+	}
+
+
+	init.call(this);
+
+}

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

@@ -149,9 +149,12 @@
 			// reset Transformations
 
 			this.traverse(function ( child ) {
-				if (child instanceof THREE.Mesh) {			
+				if (child instanceof THREE.Mesh) {
+					child.updateMatrix();
+
 					var tempGeometry = new THREE.Geometry();
-					// THREE.GeometryUtils.merge( tempGeometry, child );
+					tempGeometry.merge( child.geometry, child.matrix );
+
 					child.geometry = tempGeometry;
 					child.position.set( 0, 0, 0 );
 					child.rotation.set( 0, 0, 0 );
@@ -215,7 +218,9 @@
 		var arrowGeometry = new THREE.Geometry();
 		var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) );
 		mesh.position.y = 0.5;
-		// THREE.GeometryUtils.merge( arrowGeometry, mesh );
+		mesh.updateMatrix();
+
+		arrowGeometry.merge( mesh.geometry, mesh.matrix );
 		
 		var lineXGeometry = new THREE.Geometry();
 		lineXGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ) );
@@ -449,7 +454,9 @@
 		var arrowGeometry = new THREE.Geometry();
 		var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) );
 		mesh.position.y = 0.5;
-		// THREE.GeometryUtils.merge( arrowGeometry, mesh );
+		mesh.updateMatrix();
+
+		arrowGeometry.merge( mesh.geometry, mesh.matrix );
 
 		var lineXGeometry = new THREE.Geometry();
 		lineXGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ) );

+ 9 - 11
examples/js/loaders/STLLoader.js

@@ -106,12 +106,10 @@ THREE.STLLoader.prototype.parseBinary = function ( data ) {
 	var dataOffset = 84;
 	var faceLength = 12 * 4 + 2;
 
-	var vertices = new Float32Array( faces * 3 * 3 );
-	var normals = new Float32Array( faces * 3 * 3 );
-	var uvs = new Float32Array( faces * 3 * 2 );
-
 	var offset = 0;
 
+	var geometry = new THREE.Geometry2( faces );
+
 	for ( var face = 0; face < faces; face ++ ) {
 
 		var start = dataOffset + face * faceLength;
@@ -120,13 +118,13 @@ THREE.STLLoader.prototype.parseBinary = function ( data ) {
 
 			var vertexstart = start + i * 12;
 
-			vertices[ offset     ] = reader.getFloat32( vertexstart, true );
-			vertices[ offset + 1 ] = reader.getFloat32( vertexstart + 4, true );
-			vertices[ offset + 2 ] = reader.getFloat32( vertexstart + 8, true );
+			geometry.vertices[ offset     ] = reader.getFloat32( vertexstart, true );
+			geometry.vertices[ offset + 1 ] = reader.getFloat32( vertexstart + 4, true );
+			geometry.vertices[ offset + 2 ] = reader.getFloat32( vertexstart + 8, true );
 
-			normals[ offset     ] = reader.getFloat32( start    , true );
-			normals[ offset + 1 ] = reader.getFloat32( start + 4, true );
-			normals[ offset + 2 ] = reader.getFloat32( start + 8, true );
+			geometry.normals[ offset     ] = reader.getFloat32( start    , true );
+			geometry.normals[ offset + 1 ] = reader.getFloat32( start + 4, true );
+			geometry.normals[ offset + 2 ] = reader.getFloat32( start + 8, true );
 
 			offset += 3;
 
@@ -134,7 +132,7 @@ THREE.STLLoader.prototype.parseBinary = function ( data ) {
 
 	}
 
-	return new THREE.Geometry2( vertices, normals, uvs );
+	return geometry;
 
 };
 

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

@@ -60,7 +60,7 @@ THREE.VTKLoader.prototype = {
 
 		// float float float
 
-		pattern = /([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)/g;
+		pattern = /([\+|\-]?[\d]+[\.]*[\d|\-|e]*)[ ]+([\+|\-]?[\d]+[\.]*[\d|\-|e]*)[ ]+([\+|\-]?[\d]+[\.]*[\d|\-|e]*)/g;
 
 		while ( ( result = pattern.exec( data ) ) !== null ) {
 

+ 2 - 2
examples/js/loaders/gltf/glTFLoader.js

@@ -1276,7 +1276,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
         	                                	
         	                                	joint.skin = threeMesh;
         	                                    joints.push(joint);
-        	                                    threeMesh.bones.push(joint);
+        	                                    threeMesh.skeleton.bones.push(joint);
         	                                    
         	                                    var m = skin.inverseBindMatrices;
         	                    	            var mat = new THREE.Matrix4(
@@ -1285,7 +1285,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
         	                                            m[i * 16 + 2],  m[i * 16 + 6],  m[i * 16 + 10], m[i * 16 + 14],
         	                                            m[i * 16 + 3],  m[i * 16 + 7],  m[i * 16 + 11], m[i * 16 + 15]
         	                                        );
-        	                                    threeMesh.boneInverses.push(mat);
+        	                                    threeMesh.skeleton.boneInverses.push(mat);
         	                                    threeMesh.pose();
         	                                    
         	                                } else {

+ 75 - 0
examples/js/wip/CircleGeometry2.js

@@ -0,0 +1,75 @@
+/**
+ * @author hughes
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.CircleGeometry2 = function ( radius, segments, thetaStart, thetaLength ) {
+
+	this.parameters = {
+		radius: radius,
+		segments: segments,
+		thetaStart: thetaStart,
+		thetaLength: thetaLength
+	};
+
+	radius = radius || 50;
+	segments = segments !== undefined ? Math.max( 3, segments ) : 8;
+
+	thetaStart = thetaStart !== undefined ? thetaStart : 0;
+	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
+
+	//
+
+	var elements = segments + 2;
+
+	var indices = new Uint16Array( segments * 3 );
+	var vertices = new Float32Array( elements * 3 );
+	var normals = new Float32Array( elements * 3 );
+	var uvs = new Float32Array( elements * 2 );
+
+	// center
+
+	normals[ 2 ] = 1;
+
+	uvs[ 0 ] = 0.5;
+	uvs[ 1 ] = 0.5;
+
+	var offset = 0, offset2 = 2, offset3 = 3;
+
+	for ( var i = 0; i <= segments; i ++ ) {
+
+		var segment = thetaStart + i / segments * thetaLength;
+
+		var x = radius * Math.cos( segment );
+		var y = radius * Math.sin( segment );
+
+		vertices[ offset3     ] = x;
+		vertices[ offset3 + 1 ] = y;
+
+		normals[ offset3 + 2 ] = 1;
+
+		uvs[ offset2     ] = ( x / radius + 1 ) / 2;
+		uvs[ offset2 + 1 ] = ( y / radius + 1 ) / 2;
+
+		offset2 += 2;
+		offset3 += 3;
+
+		//
+
+		indices[ offset     ] = 0;
+		indices[ offset + 1 ] = i + 1;
+		indices[ offset + 2 ] = i + 2;
+
+		offset  += 3;
+
+	}
+
+	THREE.IndexedGeometry2.call( this );
+
+	this.setArrays( indices, vertices, normals, uvs );
+
+	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
+
+};
+
+THREE.CircleGeometry2.prototype = Object.create( THREE.IndexedGeometry2.prototype );

+ 109 - 7
examples/js/wip/Geometry2.js

@@ -6,14 +6,116 @@ THREE.Geometry2 = function ( size ) {
 
 	THREE.BufferGeometry.call( this );
 
-	this.vertices = new THREE.Float32Attribute( size, 3 );
-	this.normals = new THREE.Float32Attribute( size, 3 );
-	this.uvs = new THREE.Float32Attribute( size, 2 );
+	if ( size !== undefined ) {
 
-	this.addAttribute( 'position', this.vertices );
-	this.addAttribute( 'normal', this.normals );
-	this.addAttribute( 'uv', this.uvs );
+		this.vertices = new Float32Array( size * 3 * 3 );
+		this.normals = new Float32Array( size * 3 * 3 );
+		this.uvs = new Float32Array( size * 3 * 2 );
+
+		this.attributes[ 'position' ] = { array: this.vertices, itemSize: 3 };
+		this.attributes[ 'normal' ] = { array: this.normals, itemSize: 3 };
+		this.attributes[ 'uv' ] = { array: this.uvs, itemSize: 2 };
+
+	}
+
+};
+
+THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+THREE.Geometry2.prototype.setArrays = function ( vertices, normals, uvs ) {
+
+	this.vertices = vertices;
+	this.normals = normals;
+	this.uvs = uvs;
+
+	this.attributes[ 'position' ] = { array: vertices, itemSize: 3 };
+	this.attributes[ 'normal' ] = { array: normals, itemSize: 3 };
+	this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 };
+
+	return this;
 
 };
 
-THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );
+THREE.Geometry2.prototype.merge = ( function () {
+
+	var offset = 0;
+	var normalMatrix = new THREE.Matrix3();
+
+	return function ( geometry, matrix, startOffset ) {
+
+		if ( startOffset !== undefined ) offset = startOffset;
+
+		var offset2 = offset * 2;
+		var offset3 = offset * 3;
+
+		var vertices = this.attributes[ 'position' ].array;
+		var normals = this.attributes[ 'normal' ].array;
+		var uvs = this.attributes[ 'uv' ].array;
+
+		if ( geometry instanceof THREE.Geometry2 ) {
+
+			var vertices2 = geometry.attributes[ 'position' ].array;
+			var normals2 = geometry.attributes[ 'normal' ].array;
+			var uvs2 = geometry.attributes[ 'uv' ].array;
+
+			for ( var i = 0, l = vertices2.length; i < l; i += 3 ) {
+
+				vertices[ i + offset3     ] = vertices2[ i     ];
+				vertices[ i + offset3 + 1 ] = vertices2[ i + 1 ];
+				vertices[ i + offset3 + 2 ] = vertices2[ i + 2 ];
+
+				normals[ i + offset3     ] = normals2[ i     ];
+				normals[ i + offset3 + 1 ] = normals2[ i + 1 ];
+				normals[ i + offset3 + 2 ] = normals2[ i + 2 ];
+
+				uvs[ i + offset2     ] = uvs2[ i     ];
+				uvs[ i + offset2 + 1 ] = uvs2[ i + 1 ];
+
+			}
+
+		} else if ( geometry instanceof THREE.IndexedGeometry2 ) {
+
+			var indices2 = geometry.attributes[ 'index' ].array;
+			var vertices2 = geometry.attributes[ 'position' ].array;
+			var normals2 = geometry.attributes[ 'normal' ].array;
+			var uvs2 = geometry.attributes[ 'uv' ].array;
+
+			for ( var i = 0, l = indices2.length; i < l; i ++ ) {
+
+				var index = indices2[ i ];
+
+				var index3 = index * 3;
+				var i3 = i * 3;
+
+				vertices[ i3 + offset3 ] = vertices2[ index3 ];
+				vertices[ i3 + offset3 + 1 ] = vertices2[ index3 + 1 ];
+				vertices[ i3 + offset3 + 2 ] = vertices2[ index3 + 2 ];
+
+				normals[ i3 + offset3 ] = normals2[ index3 ];
+				normals[ i3 + offset3 + 1 ] = normals2[ index3 + 1 ];
+				normals[ i3 + offset3 + 2 ] = normals2[ index3 + 2 ];
+
+				var index2 = index * 2;
+				var i2 = i * 2;
+
+				uvs[ i2 + offset2 ] = uvs2[ index2 ];
+				uvs[ i2 + offset2 + 1 ] = uvs2[ index2 + 1 ];
+
+			}
+
+			if ( matrix !== undefined ) {
+
+				matrix.applyToVector3Array( vertices, offset3, indices2.length * 3 );
+
+				normalMatrix.getNormalMatrix( matrix );
+				normalMatrix.applyToVector3Array( normals, offset3, indices2.length * 3 );
+
+			}
+
+			offset += indices2.length;
+
+		}
+
+	};
+
+} )();

+ 0 - 0
src/core/GeometryEditor.js → examples/js/wip/GeometryEditor.js


+ 14 - 3
src/core/IndexedGeometry2.js → examples/js/wip/IndexedGeometry2.js

@@ -2,15 +2,26 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-THREE.IndexedGeometry2 = function ( indices, vertices, normals, uvs ) {
+THREE.IndexedGeometry2 = function () {
 
 	THREE.BufferGeometry.call( this );
 
+};
+
+THREE.IndexedGeometry2.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+THREE.IndexedGeometry2.prototype.setArrays = function ( indices, vertices, normals, uvs ) {
+
+	this.indices = indices;
+	this.vertices = vertices;
+	this.normals = normals;
+	this.uvs = uvs;
+
 	this.attributes[ 'index' ] = { array: indices, itemSize: 1 };
 	this.attributes[ 'position' ] = { array: vertices, itemSize: 3 };
 	this.attributes[ 'normal' ] = { array: normals, itemSize: 3 };
 	this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 };	
 
-};
+	return this;
 
-THREE.IndexedGeometry2.prototype = Object.create( THREE.BufferGeometry.prototype );
+};

+ 57 - 41
examples/js/wip/PlaneGeometry2.js

@@ -5,71 +5,87 @@
 
 THREE.PlaneGeometry2 = function ( width, height, widthSegments, heightSegments ) {
 
-	THREE.Geometry2.call( this, ( widthSegments * heightSegments ) * 2 * 3 );
+	this.parameters = {
+		width: width,
+		height: height,
+		widthSegments: widthSegments,
+		heightSegments: heightSegments
+	};
 
-	var vertices = this.vertices.array;
-	var normals = this.normals.array;
-	var uvs = this.uvs.array;
+	var width_half = width / 2;
+	var height_half = height / 2;
 
-	this.width = width;
-	this.height = height;
+	var gridX = widthSegments || 1;
+	var gridY = heightSegments || 1;
 
-	this.widthSegments = widthSegments || 1;
-	this.heightSegments = heightSegments || 1;
+	var gridX1 = gridX + 1;
+	var gridY1 = gridY + 1;
 
-	var widthHalf = width / 2;
-	var heightHalf = height / 2;
+	var segment_width = width / gridX;
+	var segment_height = height / gridY;
 
-	var gridX = this.widthSegments;
-	var gridY = this.heightSegments;
-
-	var segmentWidth = this.width / gridX;
-	var segmentHeight = this.height / gridY;
+	var vertices = new Float32Array( gridX1 * gridY1 * 3 );
+	var normals = new Float32Array( gridX1 * gridY1 * 3 );
+	var uvs = new Float32Array( gridX1 * gridY1 * 2 );
 
 	var offset = 0;
+	var offset2 = 0;
 
-	for ( var iy = 0; iy < gridY; iy ++ ) {
+	for ( var iy = 0; iy < gridY1; iy ++ ) {
 
-		var y1 = iy * segmentHeight - heightHalf;
-		var y2 = ( iy + 1 ) * segmentHeight - heightHalf;
+		var y = iy * segment_height - height_half;
 
-		for ( var ix = 0; ix < gridX; ix ++ ) {
+		for ( var ix = 0; ix < gridX1; ix ++ ) {
+
+			var x = ix * segment_width - width_half;
 
-			var x1 = ix * segmentWidth - widthHalf;
-			var x2 = ( ix + 1 ) * segmentWidth - widthHalf;
+			vertices[ offset     ] = x;
+			vertices[ offset + 1 ] = - y;
 
-			vertices[ offset + 0 ] = x1;
-			vertices[ offset + 1 ] = y1;
+			normals[ offset + 2 ] = 1;
 
-			vertices[ offset + 3 ] = x2;
-			vertices[ offset + 4 ] = y1;
+			uvs[ offset2     ] = ix / gridX;
+			uvs[ offset2 + 1 ] = 1 - ( iy / gridY );
 
-			vertices[ offset + 6 ] = x1;
-			vertices[ offset + 7 ] = y2;
+			offset += 3;
+			offset2 += 2;
 
-			normals[ offset + 2 ] = 1;
-			normals[ offset + 5 ] = 1;
-			normals[ offset + 8 ] = 1;
+		}
+
+	}
+
+	offset = 0;
+
+	var indices = new ( vertices.length > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 );
+
+	for ( var iy = 0; iy < gridY; iy ++ ) {
 
-			vertices[ offset + 9 ] = x2;
-			vertices[ offset + 10 ] = y1;
+		for ( var ix = 0; ix < gridX; ix ++ ) {
 
-			vertices[ offset + 12 ] = x2;
-			vertices[ offset + 13 ] = y2;
+			var a = ix + gridX1 * iy;
+			var b = ix + gridX1 * ( iy + 1 );
+			var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
+			var d = ( ix + 1 ) + gridX1 * iy;
 
-			vertices[ offset + 15 ] = x1;
-			vertices[ offset + 16 ] = y2;
+			indices[ offset     ] = a;
+			indices[ offset + 1 ] = b;
+			indices[ offset + 2 ] = d;
 
-			normals[ offset + 11 ] = 1;
-			normals[ offset + 13 ] = 1;
-			normals[ offset + 17 ] = 1;
+			indices[ offset + 3 ] = b;
+			indices[ offset + 4 ] = c;
+			indices[ offset + 5 ] = d;
 
-			offset += 18;
+			offset += 6;
 
 		}
 
 	}
 
+	THREE.IndexedGeometry2.call( this );
+
+	this.setArrays( indices, vertices, normals, uvs );
+	this.computeBoundingSphere();
+
 };
 
-THREE.PlaneGeometry2.prototype = Object.create( THREE.Geometry2.prototype );
+THREE.PlaneGeometry2.prototype = Object.create( THREE.IndexedGeometry2.prototype );

+ 0 - 0
src/core/ProxyGeometry.js → examples/js/wip/ProxyGeometry.js


+ 0 - 0
examples/js/wip/BoxGeometry2.js → examples/js/wip/benchmark/BoxGeometry2.js


+ 19 - 0
examples/js/wip/benchmark/Geometry2.js

@@ -0,0 +1,19 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.Geometry2 = function ( size ) {
+
+	THREE.BufferGeometry.call( this );
+
+	this.vertices = new THREE.Float32Attribute( size, 3 );
+	this.normals = new THREE.Float32Attribute( size, 3 );
+	this.uvs = new THREE.Float32Attribute( size, 2 );
+
+	this.addAttribute( 'position', this.vertices );
+	this.addAttribute( 'normal', this.normals );
+	this.addAttribute( 'uv', this.uvs );
+
+};
+
+THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );

+ 0 - 0
examples/js/wip/Geometry2Loader.js → examples/js/wip/benchmark/Geometry2Loader.js


+ 0 - 0
examples/js/wip/Geometry3.js → examples/js/wip/benchmark/Geometry3.js


+ 0 - 0
examples/js/wip/Geometry4.js → examples/js/wip/benchmark/Geometry4.js


+ 0 - 0
examples/js/wip/Geometry5.js → examples/js/wip/benchmark/Geometry5.js


+ 0 - 0
examples/js/wip/Geometry5b.js → examples/js/wip/benchmark/Geometry5b.js


+ 0 - 0
examples/js/wip/IndexedGeometry3.js → examples/js/wip/benchmark/IndexedGeometry3.js


+ 0 - 0
examples/js/wip/IndexedGeometry5.js → examples/js/wip/benchmark/IndexedGeometry5.js


+ 0 - 0
examples/js/wip/IndexedPlaneGeometry5.js → examples/js/wip/benchmark/IndexedPlaneGeometry5.js


+ 0 - 0
examples/js/wip/PlaneBufferGeometry.js → examples/js/wip/benchmark/PlaneBufferGeometry.js


+ 0 - 0
examples/js/wip/PlaneGeometry.js → examples/js/wip/benchmark/PlaneGeometry.js


+ 75 - 0
examples/js/wip/benchmark/PlaneGeometry2.js

@@ -0,0 +1,75 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
+ */
+
+THREE.PlaneGeometry2 = function ( width, height, widthSegments, heightSegments ) {
+
+	THREE.Geometry2.call( this, ( widthSegments * heightSegments ) * 2 * 3 );
+
+	var vertices = this.vertices.array;
+	var normals = this.normals.array;
+	var uvs = this.uvs.array;
+
+	this.width = width;
+	this.height = height;
+
+	this.widthSegments = widthSegments || 1;
+	this.heightSegments = heightSegments || 1;
+
+	var widthHalf = width / 2;
+	var heightHalf = height / 2;
+
+	var gridX = this.widthSegments;
+	var gridY = this.heightSegments;
+
+	var segmentWidth = this.width / gridX;
+	var segmentHeight = this.height / gridY;
+
+	var offset = 0;
+
+	for ( var iy = 0; iy < gridY; iy ++ ) {
+
+		var y1 = iy * segmentHeight - heightHalf;
+		var y2 = ( iy + 1 ) * segmentHeight - heightHalf;
+
+		for ( var ix = 0; ix < gridX; ix ++ ) {
+
+			var x1 = ix * segmentWidth - widthHalf;
+			var x2 = ( ix + 1 ) * segmentWidth - widthHalf;
+
+			vertices[ offset + 0 ] = x1;
+			vertices[ offset + 1 ] = y1;
+
+			vertices[ offset + 3 ] = x2;
+			vertices[ offset + 4 ] = y1;
+
+			vertices[ offset + 6 ] = x1;
+			vertices[ offset + 7 ] = y2;
+
+			normals[ offset + 2 ] = 1;
+			normals[ offset + 5 ] = 1;
+			normals[ offset + 8 ] = 1;
+
+			vertices[ offset + 9 ] = x2;
+			vertices[ offset + 10 ] = y1;
+
+			vertices[ offset + 12 ] = x2;
+			vertices[ offset + 13 ] = y2;
+
+			vertices[ offset + 15 ] = x1;
+			vertices[ offset + 16 ] = y2;
+
+			normals[ offset + 11 ] = 1;
+			normals[ offset + 13 ] = 1;
+			normals[ offset + 17 ] = 1;
+
+			offset += 18;
+
+		}
+
+	}
+
+};
+
+THREE.PlaneGeometry2.prototype = Object.create( THREE.Geometry2.prototype );

+ 0 - 0
examples/js/wip/PlaneGeometry2b.js → examples/js/wip/benchmark/PlaneGeometry2b.js


+ 0 - 0
examples/js/wip/PlaneGeometry3.js → examples/js/wip/benchmark/PlaneGeometry3.js


+ 0 - 0
examples/js/wip/PlaneGeometry5.js → examples/js/wip/benchmark/PlaneGeometry5.js


+ 0 - 0
examples/js/wip/PlaneGeometry6.js → examples/js/wip/benchmark/PlaneGeometry6.js


+ 0 - 0
examples/js/wip/PlaneGeometry99.js → examples/js/wip/benchmark/PlaneGeometry99.js


+ 0 - 0
examples/js/wip/TypedGeometry.js → examples/js/wip/benchmark/TypedGeometry.js


+ 0 - 0
src/core/proxies/MultiColor.js → examples/js/wip/proxies/MultiColor.js


+ 0 - 0
src/core/proxies/MultiVector3.js → examples/js/wip/proxies/MultiVector3.js


+ 0 - 0
src/core/proxies/ProxyColor.js → examples/js/wip/proxies/ProxyColor.js


+ 0 - 0
src/core/proxies/ProxyFace3.js → examples/js/wip/proxies/ProxyFace3.js


+ 0 - 0
src/core/proxies/ProxyVector2.js → examples/js/wip/proxies/ProxyVector2.js


+ 0 - 0
src/core/proxies/ProxyVector3.js → examples/js/wip/proxies/ProxyVector3.js


+ 0 - 0
src/core/proxies/ProxyVector4.js → examples/js/wip/proxies/ProxyVector4.js


BIN
examples/models/skinned/marine/M4.png


BIN
examples/models/skinned/marine/MarineCv2_color.jpg


BIN
examples/models/skinned/marine/m4.blend


File diff suppressed because it is too large
+ 37 - 0
examples/models/skinned/marine/m4.js


File diff suppressed because it is too large
+ 37 - 0
examples/models/skinned/marine/marine.js


BIN
examples/models/skinned/marine/marine_anims.blend


File diff suppressed because it is too large
+ 37 - 0
examples/models/skinned/marine/marine_anims.js


BIN
examples/models/skinned/marine/marine_fbx.blend


BIN
examples/models/skinned/marine/marine_fk.blend


BIN
examples/models/skinned/marine/marine_ikrig.blend


File diff suppressed because it is too large
+ 37 - 0
examples/models/skinned/marine/marine_ikrig.js


+ 265 - 0
examples/webgl_animation_skinning_blending.html

@@ -0,0 +1,265 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - animation - skinning</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: #000;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+
+				background-color: #fff;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> - Skeletal Animation Blending
+			<br><br> Adjust blend weights to affect the animations that are currently playing.
+			<br> Cross fades (and warping) blend between 2 animations and end with a single animation.
+		</div>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+		<script src="js/Controls/OrbitControls.js"></script>
+		<script src="js/BlendCharacter.js"></script>
+		<script src="js/BlendCharacterGui.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var blendMesh, camera, scene, renderer, controls;
+
+			var clock = new THREE.Clock();
+			var gui = null;
+
+			var isFrameStepping = false;
+			var timeToStep = 0;
+
+			init();
+
+			function init() {
+
+				container = document.getElementById( 'container' );
+
+				scene = new THREE.Scene();
+				scene.add ( new THREE.AmbientLight( 0xaaaaaa ) );
+
+				var light = new THREE.DirectionalLight( 0xffffff, 1.5 );
+				light.position = new THREE.Vector3( 0, 0, 1000.0 );
+				scene.add( light );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } );
+				renderer.setClearColor( '#777777', 1 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.autoClear = true;
+
+				container.appendChild( renderer.domElement );
+
+				//
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				// listen for messages from the gui
+				window.addEventListener( 'start-animation', onStartAnimation );
+				window.addEventListener( 'stop-animation', onStopAnimation );
+				window.addEventListener( 'pause-animation', onPauseAnimation );
+				window.addEventListener( 'step-animation', onStepAnimation );
+				window.addEventListener( 'weight-animation', onWeightAnimation );
+				window.addEventListener( 'crossfade', onCrossfade );
+				window.addEventListener( 'warp', onWarp );
+				window.addEventListener( 'toggle-lock-camera', onLockCameraToggle );
+				window.addEventListener( 'toggle-show-skeleton', onShowSkeleton );
+				window.addEventListener( 'toggle-show-model', onShowModel );
+
+				blendMesh = new THREE.BlendCharacter();
+				blendMesh.load( "models/skinned/marine/marine_anims.js", start );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function onStartAnimation( event ) {
+
+				var data = event.detail;
+
+				blendMesh.stopAll();
+
+				// the blend mesh will combine 1 or more animations
+				for ( var i = 0; i < data.anims.length; ++i ) {
+
+					blendMesh.play(data.anims[i], data.weights[i]);
+
+				}
+
+				isFrameStepping = false;
+
+			}
+
+			function onStopAnimation( event ) {
+
+				blendMesh.stopAll();
+				isFrameStepping = false;
+
+			}
+
+			function onPauseAnimation( event ) {
+
+				( isFrameStepping ) ? blendMesh.unPauseAll(): blendMesh.pauseAll();
+
+				isFrameStepping = false;
+
+			}
+
+			function onStepAnimation( event ) {
+
+				blendMesh.unPauseAll();
+				isFrameStepping = true;
+				timeToStep = event.detail.stepSize;
+			}
+
+			function onWeightAnimation(event) {
+
+				var data = event.detail;
+				for ( var i = 0; i < data.anims.length; ++i ) {
+
+					blendMesh.applyWeight(data.anims[i], data.weights[i]);
+
+				}
+
+			}
+
+			function onCrossfade(event) {
+
+				var data = event.detail;
+
+				blendMesh.stopAll();
+				blendMesh.crossfade( data.from, data.to, data.time );
+
+				isFrameStepping = false;
+
+			}
+
+			function onWarp( event ) {
+
+				var data = event.detail;
+
+				blendMesh.stopAll();
+				blendMesh.warp( data.from, data.to, data.time );
+
+				isFrameStepping = false;
+
+			}
+
+
+			function onLockCameraToggle( event ) {
+
+				var shouldLock = event.detail.shouldLock;
+				controls.enabled = !shouldLock;
+
+			}
+
+			function onShowSkeleton( event ) {
+
+				var shouldShow = event.detail.shouldShow;
+				blendMesh.showSkeleton( shouldShow );
+
+			}
+
+			function onShowModel( event ) {
+
+				var shouldShow = event.detail.shouldShow;
+				blendMesh.showModel( shouldShow );
+
+			}
+
+			function start() {
+
+				blendMesh.rotation.y = Math.PI * -135 / 180;
+				scene.add( blendMesh );
+
+				var aspect = window.innerWidth / window.innerHeight;
+				var radius = blendMesh.geometry.boundingSphere.radius;
+
+				camera = new THREE.PerspectiveCamera( 45, aspect, 1, 10000 );
+				camera.position.set( 0.0, radius, radius * 3.5 );
+
+				controls = new THREE.OrbitControls( camera );
+				controls.target = new THREE.Vector3( 0, radius, 0 );
+				controls.update();
+
+				// Set default weights
+
+				blendMesh.animations[ 'idle' ].weight = 1 / 3;
+				blendMesh.animations[ 'walk' ].weight = 1 / 3;
+				blendMesh.animations[ 'run' ].weight = 1 / 3;
+
+				gui = new BlendCharacterGui(blendMesh.animations);
+
+				animate();
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate, renderer.domElement );
+
+				// step forward in time based on whether we're stepping and scale
+
+				var scale = gui.getTimeScale();
+				var delta = clock.getDelta();
+				var stepSize = (!isFrameStepping) ? delta * scale: timeToStep;
+
+				// modify blend weights
+
+				blendMesh.update( stepSize );
+				gui.update();
+
+				THREE.AnimationHandler.update( stepSize );
+
+				renderer.render( scene, camera );
+				stats.update();
+
+				// if we are stepping, consume time
+				// ( will equal step size next time a single step is desired )
+
+				timeToStep = 0;
+
+			}
+
+		</script>
+
+	</body>
+</html>
+

+ 34 - 2
examples/webgl_animation_skinning_morph.html

@@ -47,6 +47,8 @@
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 
+		<script src="js/libs/dat.gui.min.js"></script>
+
 		<script>
 
 			var SCREEN_WIDTH = window.innerWidth;
@@ -58,7 +60,7 @@
 			var camera, scene;
 			var renderer;
 
-			var mesh;
+			var mesh, helper;
 
 			var mouseX = 0, mouseY = 0;
 
@@ -153,7 +155,15 @@
 				//
 
 				var loader = new THREE.JSONLoader();
-				loader.load( "models/skinned/knight.js", function ( geometry, materials ) { createScene( geometry, materials, 0, FLOOR, -300, 60 ) } );
+				loader.load( "models/skinned/knight.js", function ( geometry, materials ) {
+
+					createScene( geometry, materials, 0, FLOOR, -300, 60 )
+
+				} );
+
+				// GUI
+
+				initGUI();
 
 				//
 
@@ -246,11 +256,31 @@
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 
+				helper = new THREE.SkeletonHelper( mesh );
+				helper.material.linewidth = 3;
+				helper.visible = false;
+				scene.add( helper );
+
 				var animation = new THREE.Animation( mesh, geometry.animation.name );
 				animation.play();
 
 			}
 
+			function initGUI() {
+
+				var API = {
+					'show model'    : true,
+					'show skeleton' : false
+				};
+
+				var gui = new dat.GUI();
+
+				gui.add( API, 'show model' ).onChange( function() { mesh.visible = API[ 'show model' ]; } );
+
+				gui.add( API, 'show skeleton' ).onChange( function() { helper.visible = API[ 'show skeleton' ]; } );
+
+			}
+
 			function onDocumentMouseMove( event ) {
 
 				mouseX = ( event.clientX - windowHalfX );
@@ -282,6 +312,8 @@
 
 				THREE.AnimationHandler.update( delta );
 
+				if ( helper !== undefined ) helper.update();
+
 				// update morphs
 
 				if ( mesh ) {

+ 14 - 10
examples/webgl_geometry_minecraft.html

@@ -49,6 +49,10 @@
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 
+		<script src="js/wip/Geometry2.js"></script>
+		<script src="js/wip/IndexedGeometry2.js"></script>
+		<script src="js/wip/PlaneGeometry2.js"></script>
+
 		<script>
 
 			if ( ! Detector.webgl ) {
@@ -92,34 +96,36 @@
 
 				var matrix = new THREE.Matrix4();
 
-				var pxGeometry = new THREE.PlaneGeometry( 100, 100 );
+				var pxGeometry = new THREE.PlaneGeometry2( 100, 100 );
 				// pxGeometry.faceVertexUvs[ 0 ][ 0 ][ 0 ].y = 0.5;
 				// pxGeometry.faceVertexUvs[ 0 ][ 0 ][ 2 ].y = 0.5;
 				// pxGeometry.faceVertexUvs[ 0 ][ 1 ][ 2 ].y = 0.5;
 				pxGeometry.applyMatrix( matrix.makeRotationY( Math.PI / 2 ) );
 				pxGeometry.applyMatrix( matrix.makeTranslation( 50, 0, 0 ) );
 
-				var nxGeometry = new THREE.PlaneGeometry( 100, 100 );
+				var nxGeometry = new THREE.PlaneGeometry2( 100, 100 );
 				// nxGeometry.faceVertexUvs[ 0 ][ 0 ][ 0 ].y = 0.5;
 				// nxGeometry.faceVertexUvs[ 0 ][ 0 ][ 2 ].y = 0.5;
 				// nxGeometry.faceVertexUvs[ 0 ][ 1 ][ 2 ].y = 0.5;
 				nxGeometry.applyMatrix( matrix.makeRotationY( - Math.PI / 2 ) );
 				nxGeometry.applyMatrix( matrix.makeTranslation( - 50, 0, 0 ) );
 
-				var pyGeometry = new THREE.PlaneGeometry( 100, 100 );
+				var pyGeometry = new THREE.PlaneGeometry2( 100, 100 );
+				pyGeometry.uvs[ 5 ] = 0.5;
+				pyGeometry.uvs[ 7 ] = 0.5;
 				// pyGeometry.faceVertexUvs[ 0 ][ 0 ][ 1 ].y = 0.5;
 				// pyGeometry.faceVertexUvs[ 0 ][ 1 ][ 0 ].y = 0.5;
 				// pyGeometry.faceVertexUvs[ 0 ][ 1 ][ 1 ].y = 0.5;
 				pyGeometry.applyMatrix( matrix.makeRotationX( - Math.PI / 2 ) );
 				pyGeometry.applyMatrix( matrix.makeTranslation( 0, 50, 0 ) );
 
-				var pzGeometry = new THREE.PlaneGeometry( 100, 100 );
+				var pzGeometry = new THREE.PlaneGeometry2( 100, 100 );
 				// pzGeometry.faceVertexUvs[ 0 ][ 0 ][ 0 ].y = 0.5;
 				// pzGeometry.faceVertexUvs[ 0 ][ 0 ][ 2 ].y = 0.5;
 				// pzGeometry.faceVertexUvs[ 0 ][ 1 ][ 2 ].y = 0.5;
 				pzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, 50 ) );
 
-				var nzGeometry = new THREE.PlaneGeometry( 100, 100 );
+				var nzGeometry = new THREE.PlaneGeometry2( 100, 100 );
 				// nzGeometry.faceVertexUvs[ 0 ][ 0 ][ 0 ].y = 0.5;
 				// nzGeometry.faceVertexUvs[ 0 ][ 0 ][ 2 ].y = 0.5;
 				// nzGeometry.faceVertexUvs[ 0 ][ 1 ][ 2 ].y = 0.5;
@@ -128,11 +134,7 @@
 
 				//
 
-				var vertices = new Float32Array( worldWidth * worldDepth * 3 * 3 * 2 );
-				var normals = new Float32Array( worldWidth * worldDepth * 3 * 3 * 2 );
-				var uvs = new Float32Array( worldWidth * worldDepth * 3 * 2 * 2 );
-
-				var geometry = new THREE.Geometry2( vertices, normals, uvs );
+				var geometry = new THREE.Geometry2( worldWidth * worldDepth * 2 ); // 2 triangles
 
 				for ( var z = 0; z < worldDepth; z ++ ) {
 
@@ -181,6 +183,8 @@
 
 				}
 
+				geometry.computeBoundingSphere();
+
 				var texture = THREE.ImageUtils.loadTexture( 'textures/minecraft/atlas.png' );
 				texture.magFilter = THREE.NearestFilter;
 				texture.minFilter = THREE.LinearMipMapLinearFilter;

+ 275 - 0
examples/webgl_loader_pdb.html

@@ -0,0 +1,275 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<title>three.js webgl - molecules</title>
+		<style>
+
+			body {
+				margin: 0;
+				font-family: Arial;
+				overflow: hidden;
+			}
+
+			a {
+				color: #ffffff;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				font-weight: bold;
+				text-align: center;
+				z-index: 1;
+			}
+
+			#menu {
+				position: absolute;
+				bottom: 20px;
+				width: 100%;
+				text-align: center;
+				padding: 0;
+				margin: 0;
+			}
+
+			button {
+				color: rgb(255,255,255);
+				background: transparent;
+				border: 0px;
+				padding: 5px 10px;
+				cursor: pointer;
+			}
+			button:hover {
+				background-color: rgba(0,255,255,0.5);
+			}
+			button:active {
+				color: #000000;
+				background-color: rgba(0,255,255,1);
+			}
+
+			.bond {
+				width: 5px;
+				height: 10px;
+				background: #eee;
+				display: block;
+			}
+		</style>
+	</head>
+	<body>
+		<script src="../build/three.min.js"></script>
+		<script src="js/controls/TrackballControls.js"></script>
+		<script src="js/loaders/PDBLoader.js"></script>
+
+		<div id="container"></div>
+		<div id="info"><a href="http://threejs.org" target="_blank">three.js webgl</a> - molecules</div>
+		<div id="menu"></div>
+
+		<script>
+			var camera, scene, renderer;
+			var controls;
+			var root;
+
+			var MOLECULES = {
+				"Ethanol": "ethanol.pdb",
+				"Aspirin": "aspirin.pdb",
+				"Caffeine": "caffeine.pdb",
+				"Nicotine": "nicotine.pdb",
+				"LSD": "lsd.pdb",
+				"Cocaine": "cocaine.pdb",
+				"Cholesterol": "cholesterol.pdb",
+				"Lycopene": "lycopene.pdb",
+				"Glucose": "glucose.pdb",
+				"Aluminium oxide": "Al2O3.pdb",
+				"Cubane": "cubane.pdb",
+				"Copper": "cu.pdb",
+				"Fluorite": "caf2.pdb",
+				"Salt": "nacl.pdb",
+				"YBCO superconductor": "ybco.pdb",
+				"Buckyball": "buckyball.pdb",
+				//"Diamond": "diamond.pdb",
+				"Graphite": "graphite.pdb"
+			};
+
+			var loader = new THREE.PDBLoader();
+			var colorSpriteMap = {};
+			var baseSprite = document.createElement( 'img' );
+
+			var menu = document.getElementById( "menu" );
+
+			init();
+			animate();
+
+			function init() {
+
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 );
+				camera.position.z = 1500;
+
+				scene = new THREE.Scene();
+
+				var light = new THREE.HemisphereLight( 0xffffff, 0x000000 );
+				light.position.set( 1, 1, 1 );
+				scene.add( light );
+
+				root = new THREE.Object3D();
+				scene.add( root );
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setClearColor( 0x050505 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.getElementById( 'container' ).appendChild( renderer.domElement );
+
+				//
+
+				controls = new THREE.TrackballControls( camera, renderer.domElement );
+				controls.rotateSpeed = 0.5;
+				controls.addEventListener( 'change', render );
+
+				//
+
+				baseSprite.onload = function () {
+
+					loadMolecule( "models/molecules/caffeine.pdb" );
+					createMenu();
+
+				};
+
+				baseSprite.src = 'textures/sprites/ball.png';
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			//
+
+			function generateButtonCallback( url ) {
+
+				return function ( event ) {
+
+					loadMolecule( url );
+
+				}
+
+			}
+
+			function createMenu() {
+
+				for ( var m in MOLECULES ) {
+
+					var button = document.createElement( 'button' );
+					button.innerHTML = m;
+					menu.appendChild( button );
+
+					var url = "models/molecules/" +  MOLECULES[ m ];
+
+					button.addEventListener( 'click', generateButtonCallback( url ), false );
+
+				}
+
+			}
+
+			//
+
+			function loadMolecule( url ) {
+
+				while( root.children.length > 0 ) {
+
+					var object = root.children[ 0 ];
+					object.parent.remove( object );
+
+				}
+
+				loader.load( url, function ( geometry, geometryBonds ) {
+
+					var boxGeometry = new THREE.BoxGeometry( 1, 1, 1 );
+					var sphereGeometry = new THREE.IcosahedronGeometry( 1, 2 );
+
+					var offset = THREE.GeometryUtils.center( geometry );
+					geometryBonds.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
+
+					for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+
+						var position = geometry.vertices[ i ];
+						var color = geometry.colors[ i ];
+						var element = geometry.elements[ i ];
+
+						var material = new THREE.MeshLambertMaterial( { color: color } );
+
+						var object = new THREE.Mesh( sphereGeometry, material );
+						object.position.copy( position );
+						object.position.multiplyScalar( 75 );
+						object.scale.multiplyScalar( 25 );
+						root.add( object );
+
+					}
+
+					for ( var i = 0; i < geometryBonds.vertices.length; i += 2 ) {
+
+						var start = geometryBonds.vertices[ i ];
+						var end = geometryBonds.vertices[ i + 1 ];
+
+						start.multiplyScalar( 75 );
+						end.multiplyScalar( 75 );
+
+						var object = new THREE.Mesh( boxGeometry, new THREE.MeshLambertMaterial( 0xffffff ) );
+						object.position.copy( start );
+						object.position.lerp( end, 0.5 );
+						object.scale.set( 5, 5, start.distanceTo( end ) );
+						object.lookAt( end );
+						root.add( object );
+
+					}
+
+					render();
+
+				} );
+
+
+			}
+
+			//
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				render();
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				controls.update();
+
+				var time = Date.now() * 0.0004;
+
+				root.rotation.x = time;
+				root.rotation.y = time * 0.7;
+
+				render();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+    </script>
+  </body>
+
+</html>

+ 7 - 2
src/core/Geometry.js

@@ -250,8 +250,6 @@ THREE.Geometry.prototype = {
 
 				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 
-					face = this.faces[ f ];
-
 					faceNormal = new THREE.Vector3();
 					vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
 
@@ -457,6 +455,13 @@ THREE.Geometry.prototype = {
 
 	merge: function ( geometry, matrix, materialIndexOffset ) {
 
+		if ( geometry instanceof THREE.Geometry === false ) {
+
+			console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
+			return;
+
+		}
+
 		var normalMatrix,
 		vertexOffset = this.vertices.length,
 		uvPosition = this.faceVertexUvs[ 0 ].length,

+ 0 - 41
src/core/Geometry2.js

@@ -1,41 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Geometry2 = function ( vertices, normals, uvs ) {
-
-	THREE.BufferGeometry.call( this );
-
-	this.attributes[ 'position' ] = { array: vertices, itemSize: 3 };
-	this.attributes[ 'normal' ] = { array: normals, itemSize: 3 };
-	this.attributes[ 'uv' ] = { array: uvs, itemSize: 2 };	
-
-};
-
-THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );
-
-THREE.Geometry2.prototype.merge = function ( geometry, matrix, offset ) {
-
-	if ( offset === undefined ) offset = 0;
-
-	var vertices = this.attributes[ 'position' ].array;
-	var normals = this.attributes[ 'normal' ].array;
-	var uvs = this.attributes[ 'uv' ].array;
-
-	if ( geometry instanceof THREE.Geometry2 ) {
-
-		var vertices2 = geometry.attributes[ 'position' ].array;
-		var normals2 = geometry.attributes[ 'normal' ].array;
-		var uvs2 = geometry.attributes[ 'uv' ].array;
-
-		for ( var i = 0, l = vertices2.length; i < l; i ++ ) {
-
-			vertices[ i + offset ] = vertices2[ i ];
-			normals[ i + offset ] = normals2[ i ];
-			uvs[ i + offset ] = uvs2[ i ];
-
-		}
-
-	}
-
-};

+ 2 - 2
src/extras/GeometryUtils.js

@@ -69,12 +69,12 @@ THREE.GeometryUtils = {
 
 	}(),
 
-	// Get random point in face (triangle / quad)
+	// Get random point in face (triangle)
 	// (uniform distribution)
 
 	randomPointInFace: function ( face, geometry, useCachedAreas ) {
 
-		var vA, vB, vC, vD;
+		var vA, vB, vC;
 
 		vA = geometry.vertices[ face.a ];
 		vB = geometry.vertices[ face.b ];

+ 9 - 12
src/extras/ImageUtils.js

@@ -78,8 +78,12 @@ THREE.ImageUtils = {
 		var images = [];
 		images.loadCount = 0;
 
+		var loader = new THREE.ImageLoader();
+		loader.crossOrigin = this.crossOrigin;
+		
 		var texture = new THREE.Texture();
 		texture.image = images;
+		
 		if ( mapping !== undefined ) texture.mapping = mapping;
 
 		// no flipping needed for cube textures
@@ -88,10 +92,7 @@ THREE.ImageUtils = {
 
 		for ( var i = 0, il = array.length; i < il; ++ i ) {
 
-			var cubeImage = new Image();
-			images[ i ] = cubeImage;
-
-			cubeImage.onload = function () {
+			var cubeImage = loader.load( array[i], function () {
 
 				images.loadCount += 1;
 
@@ -102,15 +103,11 @@ THREE.ImageUtils = {
 
 				}
 
-			};
-
-			cubeImage.onerror = onError;
-
-			cubeImage.crossOrigin = this.crossOrigin;
-			cubeImage.src = array[ i ];
-
+			} );
+			
+			images[ i ] = cubeImage;
 		}
-
+		
 		return texture;
 
 	},

+ 165 - 95
src/extras/animation/Animation.js

@@ -16,26 +16,26 @@ THREE.Animation = function ( root, name ) {
 	this.isPlaying = false;
 	this.isPaused = true;
 	this.loop = true;
+	this.weight = 0;
 
 	this.interpolationType = THREE.AnimationHandler.LINEAR;
 
 };
 
-THREE.Animation.prototype.play = function ( startTime ) {
 
-	this.currentTime = startTime !== undefined ? startTime : 0;
-
-	if ( this.isPlaying === false ) {
+THREE.Animation.prototype.keyTypes = [ "pos", "rot", "scl" ];
 
-		this.isPlaying = true;
 
-		this.reset();
-		this.update( 0 );
+THREE.Animation.prototype.play = function ( startTime, weight ) {
 
-	}
+	this.currentTime = startTime !== undefined ? startTime : 0;
+	this.weight = weight !== undefined ? weight: 1;
 
+	this.isPlaying = true;
 	this.isPaused = false;
 
+	this.reset();
+
 	THREE.AnimationHandler.addToUpdate( this );
 
 };
@@ -77,22 +77,40 @@ THREE.Animation.prototype.reset = function () {
 		if ( object.animationCache === undefined ) {
 
 			object.animationCache = {};
-			object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
-			object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
-			object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
 
 		}
 
-		var prevKey = object.animationCache.prevKey;
-		var nextKey = object.animationCache.nextKey;
+		if ( object.animationCache[this.data.name] === undefined ) {
+
+			object.animationCache[this.data.name] = {};
+			object.animationCache[this.data.name].prevKey = { pos: 0, rot: 0, scl: 0 };
+			object.animationCache[this.data.name].nextKey = { pos: 0, rot: 0, scl: 0 };
+			object.animationCache[this.data.name].originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
+
+		}
+
+		var animationCache = object.animationCache[this.data.name];
+
+		// Get keys to match our current time
+
+		for ( var t = 0; t < 3; t ++ ) {
+
+			var type = this.keyTypes[ t ];
+
+			var prevKey = this.data.hierarchy[ h ].keys[ 0 ];
+			var nextKey = this.getNextKeyWith( type, h, 1 );
 
-		prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
-		prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
-		prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
+			while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
 
-		nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
-		nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
-		nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
+				prevKey = nextKey;
+				nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+
+			}
+
+			animationCache.prevKey[ type ] = prevKey;
+			animationCache.nextKey[ type ] = nextKey;
+
+		}
 
 	}
 
@@ -103,7 +121,9 @@ THREE.Animation.prototype.update = (function(){
 
 	var points = [];
 	var target = new THREE.Vector3();
-	
+	var newVector = new THREE.Vector3();
+	var newQuat = new THREE.Quaternion();
+
 	// Catmull-Rom spline
 
 	var interpolateCatmullRom = function ( points, scale ) {
@@ -111,172 +131,222 @@ THREE.Animation.prototype.update = (function(){
 		var c = [], v3 = [],
 		point, intPoint, weight, w2, w3,
 		pa, pb, pc, pd;
-	
+
 		point = ( points.length - 1 ) * scale;
 		intPoint = Math.floor( point );
 		weight = point - intPoint;
-	
+
 		c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
 		c[ 1 ] = intPoint;
 		c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
 		c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;
-	
+
 		pa = points[ c[ 0 ] ];
 		pb = points[ c[ 1 ] ];
 		pc = points[ c[ 2 ] ];
 		pd = points[ c[ 3 ] ];
-	
+
 		w2 = weight * weight;
 		w3 = weight * w2;
-	
+
 		v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
 		v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
 		v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );
-	
+
 		return v3;
 
 	};
 
 	var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
-	
+
 		var v0 = ( p2 - p0 ) * 0.5,
 			v1 = ( p3 - p1 ) * 0.5;
-	
+
 		return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
-	
+
 	};
-	
+
 	return function ( delta ) {
 		if ( this.isPlaying === false ) return;
-	
+
 		this.currentTime += delta * this.timeScale;
-	
+
+		if ( this.weight === 0 )
+			return;
+
 		//
-	
+
 		var vector;
-		var types = [ "pos", "rot", "scl" ];
-	
 		var duration = this.data.length;
-	
+
 		if ( this.loop === true && this.currentTime > duration ) {
-	
+
 			this.currentTime %= duration;
 			this.reset();
-	
+
 		} else if ( this.loop === false && this.currentTime > duration ) {
-	
+
 			this.stop();
 			return;
-	
+
 		}
-	
-		this.currentTime = Math.min( this.currentTime, duration );
-	
+
 		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
-	
+
 			var object = this.hierarchy[ h ];
-			var animationCache = object.animationCache;
-	
+			var animationCache = object.animationCache[this.data.name];
+
 			// loop through pos/rot/scl
-	
+
 			for ( var t = 0; t < 3; t ++ ) {
-	
+
 				// get keys
-	
-				var type    = types[ t ];
+
+				var type    = this.keyTypes[ t ];
 				var prevKey = animationCache.prevKey[ type ];
 				var nextKey = animationCache.nextKey[ type ];
-	
+
 				if ( nextKey.time <= this.currentTime ) {
-	
+
 					prevKey = this.data.hierarchy[ h ].keys[ 0 ];
 					nextKey = this.getNextKeyWith( type, h, 1 );
-	
+
 					while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
-	
+
 						prevKey = nextKey;
 						nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
-	
+
 					}
-	
+
 					animationCache.prevKey[ type ] = prevKey;
 					animationCache.nextKey[ type ] = nextKey;
-	
+
 				}
-	
+
 				object.matrixAutoUpdate = true;
 				object.matrixWorldNeedsUpdate = true;
-	
+
 				var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
-	
+
 				var prevXYZ = prevKey[ type ];
 				var nextXYZ = nextKey[ type ];
-	
+
 				if ( scale < 0 ) scale = 0;
 				if ( scale > 1 ) scale = 1;
-	
+
 				// interpolate
-	
+
 				if ( type === "pos" ) {
-	
+
 					vector = object.position;
-	
+
 					if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
-	
-						vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
-						vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
-						vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
-	
+
+						newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
+						newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
+						newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
+
+						// blend
+						if (object instanceof THREE.Bone) {
+
+							var proportionalWeight = this.weight / ( this.weight + object.accumulatedPosWeight );
+							vector.lerp( newVector, proportionalWeight );
+							object.accumulatedPosWeight += this.weight;
+
+						} else
+							vector = newVector;
+
 					} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
 						this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-	
+
 						points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
 						points[ 1 ] = prevXYZ;
 						points[ 2 ] = nextXYZ;
 						points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];
-	
+
 						scale = scale * 0.33 + 0.33;
-	
+
 						var currentPoint = interpolateCatmullRom( points, scale );
-	
-						vector.x = currentPoint[ 0 ];
-						vector.y = currentPoint[ 1 ];
-						vector.z = currentPoint[ 2 ];
-	
+
+						if ( object instanceof THREE.Bone ) {
+
+							var proportionalWeight = this.weight / ( this.weight + object.accumulatedPosWeight );
+							object.accumulatedPosWeight += this.weight;
+
+						}
+						else
+							var proportionalWeight = 1;
+
+						// blend
+						vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight;
+						vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight;
+						vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight;
+
 						if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-	
+
 							var forwardPoint = interpolateCatmullRom( points, scale * 1.01 );
-	
+
 							target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
 							target.sub( vector );
 							target.y = 0;
 							target.normalize();
-	
+
 							var angle = Math.atan2( target.x, target.z );
 							object.rotation.set( 0, angle, 0 );
-	
+
 						}
-	
+
 					}
-	
+
 				} else if ( type === "rot" ) {
-	
-					THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );
-	
+
+					THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );
+
+					// Avoid paying the cost of an additional slerp if we don't have to
+					if ( !( object instanceof THREE.Bone ) ) {
+
+						object.quaternion.copy(newQuat);
+
+					}
+					else if ( object.accumulatedRotWeight === 0) {
+
+						object.quaternion.copy(newQuat);
+						object.accumulatedRotWeight = this.weight;
+
+					}
+					else {
+
+						var proportionalWeight = this.weight / ( this.weight + object.accumulatedRotWeight );
+						THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );
+						object.accumulatedRotWeight += this.weight;
+
+					}
+
 				} else if ( type === "scl" ) {
-	
+
 					vector = object.scale;
-	
-					vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
-					vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
-					vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
-	
+
+					newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
+					newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
+					newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
+
+					if ( object instanceof THREE.Bone ) {
+
+						var proportionalWeight = this.weight / ( this.weight + object.accumulatedSclWeight);
+						vector.lerp( newVector, proportionalWeight );
+						object.accumulatedSclWeight += this.weight;
+
+					} else
+						vector = newVector;
+
 				}
-	
+
 			}
-	
+
 		}
 
+		return true;
+
 	};
 
 })();

+ 3 - 3
src/extras/animation/AnimationHandler.js

@@ -60,7 +60,7 @@ THREE.AnimationHandler = ( function () {
 			console.log( "THREE.AnimationHandler.add: Warning! " + name + " doesn't exists in library. Doing nothing." );
 
 		}
-			
+
 		library[ name ] = undefined;
 
 	};
@@ -95,9 +95,9 @@ THREE.AnimationHandler = ( function () {
 
 		if ( root instanceof THREE.SkinnedMesh ) {
 
-			for ( var b = 0; b < root.bones.length; b++ ) {
+			for ( var b = 0; b < root.skeleton.bones.length; b++ ) {
 
-				hierarchy.push( root.bones[ b ] );
+				hierarchy.push( root.skeleton.bones[ b ] );
 
 			}
 

+ 1 - 1
src/extras/animation/KeyFrameAnimation.js

@@ -137,7 +137,7 @@ THREE.KeyFrameAnimation.prototype.stop = function() {
 	// reset JIT matrix and remove cache
 
 	for ( var h = 0; h < this.data.hierarchy.length; h++ ) {
-        
+		
 		var obj = this.hierarchy[ h ];
 		var node = this.data.hierarchy[ h ];
 

+ 19 - 36
src/extras/geometries/CircleGeometry.js

@@ -1,10 +1,11 @@
 /**
  * @author hughes
- * @author mrdoob / http://mrdoob.com/
  */
 
 THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {
 
+	THREE.Geometry.call( this );
+
 	this.parameters = {
 		radius: radius,
 		segments: segments,
@@ -18,56 +19,38 @@ THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {
 	thetaStart = thetaStart !== undefined ? thetaStart : 0;
 	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 
-	//
-
-	var elements = segments + 2;
-
-	var indices = new Uint16Array( segments * 3 );
-	var vertices = new Float32Array( elements * 3 );
-	var normals = new Float32Array( elements * 3 );
-	var uvs = new Float32Array( elements * 2 );
-
-	// center
-
-	normals[ 2 ] = 1;
+	var i, uvs = [],
+	center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 );
 
-	uvs[ 0 ] = 0.5;
-	uvs[ 1 ] = 0.5;
+	this.vertices.push(center);
+	uvs.push( centerUV );
 
-	var offset = 0, offset2 = 2, offset3 = 3;
-
-	for ( var i = 0; i <= segments; i ++ ) {
+	for ( i = 0; i <= segments; i ++ ) {
 
+		var vertex = new THREE.Vector3();
 		var segment = thetaStart + i / segments * thetaLength;
 
-		var x = radius * Math.cos( segment );
-		var y = radius * Math.sin( segment );
-
-		vertices[ offset3     ] = x;
-		vertices[ offset3 + 1 ] = y;
+		vertex.x = radius * Math.cos( segment );
+		vertex.y = radius * Math.sin( segment );
 
-		normals[ offset3 + 2 ] = 1;
+		this.vertices.push( vertex );
+		uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) );
 
-		uvs[ offset2     ] = ( x / radius + 1 ) / 2;
-		uvs[ offset2 + 1 ] = ( y / radius + 1 ) / 2;
-
-		offset2 += 2;
-		offset3 += 3;
+	}
 
-		//
+	var n = new THREE.Vector3( 0, 0, 1 );
 
-		indices[ offset     ] = 0;
-		indices[ offset + 1 ] = i + 1;
-		indices[ offset + 2 ] = i + 2;
+	for ( i = 1; i <= segments; i ++ ) {
 
-		offset  += 3;
+		this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) );
+		this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] );
 
 	}
 
-	THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs );
+	this.computeFaceNormals();
 
 	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
 
 };
 
-THREE.CircleGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype );
+THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );

+ 32 - 40
src/extras/geometries/PlaneGeometry.js

@@ -5,6 +5,8 @@
 
 THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) {
 
+	THREE.Geometry.call( this );
+
 	this.parameters = {
 		width: width,
 		height: height,
@@ -12,77 +14,67 @@ THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments )
 		heightSegments: heightSegments
 	};
 
+	var ix, iz;
 	var width_half = width / 2;
 	var height_half = height / 2;
 
 	var gridX = widthSegments || 1;
-	var gridY = heightSegments || 1;
+	var gridZ = heightSegments || 1;
 
 	var gridX1 = gridX + 1;
-	var gridY1 = gridY + 1;
+	var gridZ1 = gridZ + 1;
 
 	var segment_width = width / gridX;
-	var segment_height = height / gridY;
-
-	var vertices = new Float32Array( gridX1 * gridY1 * 3 );
-	var normals = new Float32Array( gridX1 * gridY1 * 3 );
-	var uvs = new Float32Array( gridX1 * gridY1 * 2 );
+	var segment_height = height / gridZ;
 
-	var offset = 0;
-	var offset2 = 0;
+	var normal = new THREE.Vector3( 0, 0, 1 );
 
-	for ( var iy = 0; iy < gridY1; iy ++ ) {
+	for ( iz = 0; iz < gridZ1; iz ++ ) {
 
-		var y = iy * segment_height - height_half;
+		var y = iz * segment_height - height_half;
 
-		for ( var ix = 0; ix < gridX1; ix ++ ) {
+		for ( ix = 0; ix < gridX1; ix ++ ) {
 
 			var x = ix * segment_width - width_half;
 
-			vertices[ offset     ] = x;
-			vertices[ offset + 1 ] = - y;
-
-			normals[ offset + 2 ] = 1;
-
-			uvs[ offset2     ] = ix / gridX;
-			uvs[ offset2 + 1 ] = 1 - ( iy / gridY );
-
-			offset += 3;
-			offset2 += 2;
+			this.vertices.push( new THREE.Vector3( x, - y, 0 ) );
 
 		}
 
 	}
 
-	offset = 0;
+	for ( iz = 0; iz < gridZ; iz ++ ) {
 
-	var indices = new ( vertices.length > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 );
+		for ( ix = 0; ix < gridX; ix ++ ) {
 
-	for ( var iy = 0; iy < gridY; iy ++ ) {
+			var a = ix + gridX1 * iz;
+			var b = ix + gridX1 * ( iz + 1 );
+			var c = ( ix + 1 ) + gridX1 * ( iz + 1 );
+			var d = ( ix + 1 ) + gridX1 * iz;
 
-		for ( var ix = 0; ix < gridX; ix ++ ) {
+			var uva = new THREE.Vector2( ix / gridX, 1 - iz / gridZ );
+			var uvb = new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ );
+			var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ );
+			var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ );
 
-			var a = ix + gridX1 * iy;
-			var b = ix + gridX1 * ( iy + 1 );
-			var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
-			var d = ( ix + 1 ) + gridX1 * iy;
+			var face = new THREE.Face3( a, b, d );
+			face.normal.copy( normal );
+			face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
 
-			indices[ offset     ] = a;
-			indices[ offset + 1 ] = b;
-			indices[ offset + 2 ] = d;
+			this.faces.push( face );
+			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
 
-			indices[ offset + 3 ] = b;
-			indices[ offset + 4 ] = c;
-			indices[ offset + 5 ] = d;
+			face = new THREE.Face3( b, c, d );
+			face.normal.copy( normal );
+			face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
 
-			offset += 6;
+			this.faces.push( face );
+			this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
 
 		}
 
 	}
 
-	THREE.IndexedGeometry2.call( this, indices, vertices, normals, uvs );
-
 };
 
-THREE.PlaneGeometry.prototype = Object.create( THREE.IndexedGeometry2.prototype );
+THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype );

+ 8 - 8
src/extras/helpers/ArrowHelper.js

@@ -9,18 +9,18 @@
  *  dir - Vector3
  *  origin - Vector3
  *  length - Number
- *  hex - color in hex value
+ *  color - color in hex value
  *  headLength - Number
  *  headWidth - Number
  */
 
-THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) {
+THREE.ArrowHelper = function ( dir, origin, length, color, headLength, headWidth ) {
 
 	// dir is assumed to be normalized
 
 	THREE.Object3D.call( this );
 
-	if ( hex === undefined ) hex = 0xffff00;
+	if ( color === undefined ) color = 0xffff00;
 	if ( length === undefined ) length = 1;
 	if ( headLength === undefined ) headLength = 0.2 * length;
 	if ( headWidth === undefined ) headWidth = 0.2 * headLength;
@@ -31,14 +31,14 @@ THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth )
 	lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) );
 	lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) );
 
-	this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) );
+	this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) );
 	this.line.matrixAutoUpdate = false;
 	this.add( this.line );
 
 	var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 );
 	coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) );
 
-	this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) );
+	this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) );
 	this.cone.matrixAutoUpdate = false;
 	this.add( this.cone );
 
@@ -94,9 +94,9 @@ THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth
 
 };
 
-THREE.ArrowHelper.prototype.setColor = function ( hex ) {
+THREE.ArrowHelper.prototype.setColor = function ( color ) {
 
-	this.line.material.color.setHex( hex );
-	this.cone.material.color.setHex( hex );
+	this.line.material.color.set( color );
+	this.cone.material.color.set( color );
 
 };

+ 69 - 0
src/extras/helpers/SkeletonHelper.js

@@ -0,0 +1,69 @@
+/**
+ * @author Sean Griffin / http://twitter.com/sgrif
+ * @author Michael Guerrero / http://realitymeltdown.com
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.SkeletonHelper = function ( object ) {
+
+	var skeleton = object.skeleton;
+
+	var geometry = new THREE.Geometry();
+
+	for ( var i = 0; i < skeleton.bones.length; i ++ ) {
+
+		var bone = skeleton.bones[ i ];
+
+		if ( bone.parent instanceof THREE.Bone ) {
+
+			geometry.vertices.push( new THREE.Vector3() );
+			geometry.vertices.push( new THREE.Vector3() );
+			geometry.colors.push( new THREE.Color( 0, 0, 1 ) );
+			geometry.colors.push( new THREE.Color( 0, 1, 0 ) );
+
+		}
+
+	}
+
+	var material = new THREE.LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, transparent: true } );
+
+	THREE.Line.call( this, geometry, material, THREE.LinePieces );
+
+	this.skeleton = skeleton;
+
+	this.matrixWorld = object.matrixWorld;
+	this.matrixAutoUpdate = false;
+
+	this.update();
+
+};
+
+
+THREE.SkeletonHelper.prototype = Object.create( THREE.Line.prototype );
+
+THREE.SkeletonHelper.prototype.update = function () {
+
+	var geometry = this.geometry;
+
+	var j = 0;
+
+	for ( var i = 0; i < this.skeleton.bones.length; i ++ ) {
+
+		var bone = this.skeleton.bones[ i ];
+
+		if ( bone.parent instanceof THREE.Bone ) {
+
+			geometry.vertices[ j ].setFromMatrixPosition( bone.skinMatrix );
+			geometry.vertices[ j + 1 ].setFromMatrixPosition( bone.parent.skinMatrix );
+
+			j += 2;
+
+		}
+
+	}
+
+	geometry.verticesNeedUpdate = true;
+
+	geometry.computeBoundingSphere();
+
+};

+ 2 - 0
src/extras/renderers/plugins/ShadowMapPlugin.js

@@ -298,6 +298,8 @@ THREE.ShadowMapPlugin = function () {
 
 					}
 
+					_renderer.setMaterialFaces( objectMaterial );
+
 					if ( buffer instanceof THREE.BufferGeometry ) {
 
 						_renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );

+ 6 - 0
src/loaders/Loader.js

@@ -306,6 +306,12 @@ THREE.Loader.prototype = {
 
 		}
 
+		if ( m.colorEmissive ) {
+
+			mpars.emissive = rgb2hex( m.colorEmissive );
+
+		}
+
 		// modifiers
 
 		if ( m.transparency ) {

+ 1 - 0
src/materials/MeshDepthMaterial.js

@@ -18,6 +18,7 @@ THREE.MeshDepthMaterial = function ( parameters ) {
 
 	THREE.Material.call( this );
 
+	this.morphTargets = false;
 	this.wireframe = false;
 	this.wireframeLinewidth = 1;
 

+ 2 - 0
src/math/Box3.js

@@ -54,6 +54,8 @@ THREE.Box3.prototype = {
 			this.max.z = point.z;
 
 		}
+		
+		return this;
 
 	},
 

+ 12 - 9
src/math/Matrix3.js

@@ -80,23 +80,26 @@ THREE.Matrix3.prototype = {
 
 		var v1 = new THREE.Vector3();
 
-		return function ( a ) {
+		return function ( array, offset, length ) {
 
-			for ( var i = 0, il = a.length; i < il; i += 3 ) {
+			if ( offset === undefined ) offset = 0;
+			if ( length === undefined ) length = array.length;
 
-				v1.x = a[ i ];
-				v1.y = a[ i + 1 ];
-				v1.z = a[ i + 2 ];
+			for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) {
+
+				v1.x = array[ j ];
+				v1.y = array[ j + 1 ];
+				v1.z = array[ j + 2 ];
 
 				v1.applyMatrix3( this );
 
-				a[ i ]     = v1.x;
-				a[ i + 1 ] = v1.y;
-				a[ i + 2 ] = v1.z;
+				array[ j ]     = v1.x;
+				array[ j + 1 ] = v1.y;
+				array[ j + 2 ] = v1.z;
 
 			}
 
-			return a;
+			return array;
 
 		};
 

+ 12 - 9
src/math/Matrix4.js

@@ -438,23 +438,26 @@ THREE.Matrix4.prototype = {
 
 		var v1 = new THREE.Vector3();
 
-		return function ( a ) {
+		return function ( array, offset, length ) {
 
-			for ( var i = 0, il = a.length; i < il; i += 3 ) {
+			if ( offset === undefined ) offset = 0;
+			if ( length === undefined ) length = array.length;
 
-				v1.x = a[ i ];
-				v1.y = a[ i + 1 ];
-				v1.z = a[ i + 2 ];
+			for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) {
+
+				v1.x = array[ j ];
+				v1.y = array[ j + 1 ];
+				v1.z = array[ j + 2 ];
 
 				v1.applyMatrix4( this );
 
-				a[ i ]     = v1.x;
-				a[ i + 1 ] = v1.y;
-				a[ i + 2 ] = v1.z;
+				array[ j ]     = v1.x;
+				array[ j + 1 ] = v1.y;
+				array[ j + 2 ] = v1.z;
 
 			}
 
-			return a;
+			return array;
 
 		};
 

+ 10 - 0
src/objects/Bone.js

@@ -10,6 +10,10 @@ THREE.Bone = function( belongsToSkin ) {
 	this.skin = belongsToSkin;
 	this.skinMatrix = new THREE.Matrix4();
 
+	this.accumulatedRotWeight = 0;
+	this.accumulatedPosWeight = 0;
+	this.accumulatedSclWeight = 0;
+
 };
 
 THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
@@ -41,6 +45,12 @@ THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) {
 		this.matrixWorldNeedsUpdate = false;
 		forceUpdate = true;
 
+		// Reset weights to be re-accumulated in the next frame
+
+		this.accumulatedRotWeight = 0;
+		this.accumulatedPosWeight = 0;
+		this.accumulatedSclWeight = 0;
+
 	}
 
 	// update children

+ 135 - 0
src/objects/Skeleton.js

@@ -0,0 +1,135 @@
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author michael guerrero / http://realitymeltdown.com
+ */
+
+THREE.Skeleton = function ( boneList, useVertexTexture ) {
+
+	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
+
+	// init bones
+
+	this.bones = [];
+	this.boneMatrices = [];
+
+	var bone, gbone, p, q, s;
+
+	if ( boneList !== undefined ) {
+
+		for ( var b = 0; b < boneList.length; ++b ) {
+
+			gbone = boneList[ b ];
+
+			p = gbone.pos;
+			q = gbone.rotq;
+			s = gbone.scl;
+
+			bone = this.addBone();
+
+			bone.name = gbone.name;
+			bone.position.set( p[0], p[1], p[2] );
+			bone.quaternion.set( q[0], q[1], q[2], q[3] );
+
+			if ( s !== undefined ) {
+
+				bone.scale.set( s[0], s[1], s[2] );
+
+			} else {
+
+				bone.scale.set( 1, 1, 1 );
+
+			}
+
+		}
+
+		for ( var b = 0; b < boneList.length; ++b ) {
+
+			gbone = boneList[ b ];
+
+			if ( gbone.parent !== -1 ) {
+
+				this.bones[ gbone.parent ].add( this.bones[ b ] );
+
+			}
+
+		}
+
+		//
+
+		var nBones = this.bones.length;
+
+		if ( this.useVertexTexture ) {
+
+			// layout (1 matrix = 4 pixels)
+			//  RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
+			//  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
+			//     16x16 pixel texture max   64 bones (16 * 16 / 4)
+			//     32x32 pixel texture max  256 bones (32 * 32 / 4)
+			//     64x64 pixel texture max 1024 bones (64 * 64 / 4)
+
+			var size;
+
+			if ( nBones > 256 )
+				size = 64;
+			else if ( nBones > 64 )
+				size = 32;
+			else if ( nBones > 16 )
+				size = 16;
+			else
+				size = 8;
+
+			this.boneTextureWidth = size;
+			this.boneTextureHeight = size;
+
+			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
+			this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
+			this.boneTexture.minFilter = THREE.NearestFilter;
+			this.boneTexture.magFilter = THREE.NearestFilter;
+			this.boneTexture.generateMipmaps = false;
+			this.boneTexture.flipY = false;
+
+		} else {
+
+			this.boneMatrices = new Float32Array( 16 * nBones );
+
+		}
+
+	}
+
+};
+
+
+THREE.Skeleton.prototype = Object.create( THREE.Mesh.prototype );
+
+
+THREE.Skeleton.prototype.addBone = function( bone ) {
+
+	if ( bone === undefined ) {
+
+		bone = new THREE.Bone( this );
+
+	}
+
+	this.bones.push( bone );
+
+	return bone;
+
+};
+
+
+THREE.Skeleton.prototype.calculateInverses = function( bone ) {
+
+	this.boneInverses = [];
+
+	for ( var b = 0, bl = this.bones.length; b < bl; ++b ) {
+
+		var inverse = new THREE.Matrix4();
+
+		inverse.getInverse( this.bones[ b ].skinMatrix );
+
+		this.boneInverses.push( inverse );
+
+	}
+
+};

+ 17 - 122
src/objects/SkinnedMesh.js

@@ -7,125 +7,30 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
 
 	THREE.Mesh.call( this, geometry, material );
 
-	//
+	this.skeleton = new THREE.Skeleton( this.geometry && this.geometry.bones, useVertexTexture );
 
-	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
+  // Add root level bones as children of the mesh
 
-	// init bones
+	for ( var b = 0; b < this.skeleton.bones.length; ++b ) {
 
-	this.identityMatrix = new THREE.Matrix4();
-
-	this.bones = [];
-	this.boneMatrices = [];
-
-	var b, bone, gbone, p, q, s;
-
-	if ( this.geometry && this.geometry.bones !== undefined ) {
-
-		for ( b = 0; b < this.geometry.bones.length; b ++ ) {
-
-			gbone = this.geometry.bones[ b ];
-
-			p = gbone.pos;
-			q = gbone.rotq;
-			s = gbone.scl;
-
-			bone = this.addBone();
-
-			bone.name = gbone.name;
-			bone.position.set( p[0], p[1], p[2] );
-			bone.quaternion.set( q[0], q[1], q[2], q[3] );
-		
-			if ( s !== undefined ) {
-
-				bone.scale.set( s[0], s[1], s[2] );
-
-			} else {
-
-				bone.scale.set( 1, 1, 1 );
-
-			}
-
-		}
-
-		for ( b = 0; b < this.bones.length; b ++ ) {
-
-			gbone = this.geometry.bones[ b ];
-			bone = this.bones[ b ];
-
-			if ( gbone.parent === -1 ) {
-
-				this.add( bone );
-
-			} else {
-
-				this.bones[ gbone.parent ].add( bone );
-
-			}
-
-		}
-
-		//
-
-		var nBones = this.bones.length;
-
-		if ( this.useVertexTexture ) {
-
-			// layout (1 matrix = 4 pixels)
-			//	RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
-			//  with  8x8  pixel texture max   16 bones  (8 * 8  / 4)
-			//  	 16x16 pixel texture max   64 bones (16 * 16 / 4)
-			//  	 32x32 pixel texture max  256 bones (32 * 32 / 4)
-			//  	 64x64 pixel texture max 1024 bones (64 * 64 / 4)
-
-			var size;
-
-			if ( nBones > 256 )
-				size = 64;
-			else if ( nBones > 64 )
-				size = 32;
-			else if ( nBones > 16 )
-				size = 16;
-			else
-				size = 8;
+		var bone = this.skeleton.bones[ b ];
 
-			this.boneTextureWidth = size;
-			this.boneTextureHeight = size;
+		if ( bone.parent === undefined ) {
 
-			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
-			this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
-			this.boneTexture.minFilter = THREE.NearestFilter;
-			this.boneTexture.magFilter = THREE.NearestFilter;
-			this.boneTexture.generateMipmaps = false;
-			this.boneTexture.flipY = false;
-
-		} else {
-
-			this.boneMatrices = new Float32Array( 16 * nBones );
+			this.add( bone );
 
 		}
 
-		this.pose();
-
 	}
 
-};
-
-THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
-
-THREE.SkinnedMesh.prototype.addBone = function( bone ) {
-
-	if ( bone === undefined ) {
-
-		bone = new THREE.Bone( this );
+	this.identityMatrix = new THREE.Matrix4();
 
-	}
+	this.pose();
 
-	this.bones.push( bone );
+};
 
-	return bone;
 
-};
+THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
 
 THREE.SkinnedMesh.prototype.updateMatrixWorld = function () {
 
@@ -175,25 +80,15 @@ THREE.SkinnedMesh.prototype.updateMatrixWorld = function () {
 
 		// make a snapshot of the bones' rest position
 
-		if ( this.boneInverses == undefined ) {
+		if ( this.skeleton.boneInverses === undefined ) {
 
-			this.boneInverses = [];
-
-			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
-
-				var inverse = new THREE.Matrix4();
-
-				inverse.getInverse( this.bones[ b ].skinMatrix );
-
-				this.boneInverses.push( inverse );
-
-			}
+			this.skeleton.calculateInverses();
 
 		}
 
 		// flatten bone matrices to array
 
-		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+		for ( var b = 0, bl = this.skeleton.bones.length; b < bl; b ++ ) {
 
 			// compute the offset between the current and the original transform;
 
@@ -201,14 +96,14 @@ THREE.SkinnedMesh.prototype.updateMatrixWorld = function () {
 			// was already representing the offset; however, this requires some
 			// major changes to the animation system
 
-			offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] );
-			offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
+			offsetMatrix.multiplyMatrices( this.skeleton.bones[ b ].skinMatrix, this.skeleton.boneInverses[ b ] );
+			offsetMatrix.flattenToArrayOffset( this.skeleton.boneMatrices, b * 16 );
 
 		}
 
-		if ( this.useVertexTexture ) {
+		if ( this.skeleton.useVertexTexture ) {
 
-			this.boneTexture.needsUpdate = true;
+			this.skeleton.boneTexture.needsUpdate = true;
 
 		}
 

+ 79 - 79
src/renderers/WebGLRenderer.js

@@ -186,7 +186,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 	var _glExtensionCompressedTextureS3TC;
 	var _glExtensionElementIndexUint;
 	var _glExtensionFragDepth;
-	
+
 
 	initGL();
 
@@ -606,7 +606,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 				if ( attributes[ key ].buffer !== undefined ) {
 
 					_gl.deleteBuffer( attributes[ key ].buffer );
-		
+
 				}
 
 			}
@@ -787,7 +787,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					attribute.__webglInitialized = true;
 
-					var size = 1;		// "f" and "i"
+					var size = 1;   // "f" and "i"
 
 					if ( attribute.type === "v2" ) size = 2;
 					else if ( attribute.type === "v3" ) size = 3;
@@ -967,7 +967,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					attribute.__webglInitialized = true;
 
-					var size = 1;		// "f" and "i"
+					var size = 1;   // "f" and "i"
 
 					if( attribute.type === "v2" ) size = 2;
 					else if( attribute.type === "v3" ) size = 3;
@@ -1049,11 +1049,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 		// material must use some texture to require uvs
 
 		if ( material.map ||
-		     material.lightMap ||
-		     material.bumpMap ||
-		     material.normalMap ||
-		     material.specularMap ||
-		     material instanceof THREE.ShaderMaterial ) {
+				 material.lightMap ||
+				 material.bumpMap ||
+				 material.normalMap ||
+				 material.specularMap ||
+				 material instanceof THREE.ShaderMaterial ) {
 
 			return true;
 
@@ -1179,7 +1179,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 							value = customAttribute.value[ index ];
 
-							customAttribute.array[ offset ] 	= value.x;
+							customAttribute.array[ offset ]   = value.x;
 							customAttribute.array[ offset + 1 ] = value.y;
 
 							offset += 2;
@@ -1212,7 +1212,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 								value = customAttribute.value[ index ];
 
-								customAttribute.array[ offset ] 	= value.x;
+								customAttribute.array[ offset ]   = value.x;
 								customAttribute.array[ offset + 1 ] = value.y;
 								customAttribute.array[ offset + 2 ] = value.z;
 
@@ -1287,7 +1287,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					if ( customAttribute.needsUpdate &&
 						 ( customAttribute.boundTo === undefined ||
-						   customAttribute.boundTo === "vertices") ) {
+							 customAttribute.boundTo === "vertices") ) {
 
 						cal = customAttribute.value.length;
 
@@ -1307,7 +1307,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 								value = customAttribute.value[ ca ];
 
-								customAttribute.array[ offset ] 	= value.x;
+								customAttribute.array[ offset ]   = value.x;
 								customAttribute.array[ offset + 1 ] = value.y;
 
 								offset += 2;
@@ -1322,7 +1322,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 									value = customAttribute.value[ ca ];
 
-									customAttribute.array[ offset ] 	= value.r;
+									customAttribute.array[ offset ]   = value.r;
 									customAttribute.array[ offset + 1 ] = value.g;
 									customAttribute.array[ offset + 2 ] = value.b;
 
@@ -1336,7 +1336,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 									value = customAttribute.value[ ca ];
 
-									customAttribute.array[ offset ] 	= value.x;
+									customAttribute.array[ offset ]   = value.x;
 									customAttribute.array[ offset + 1 ] = value.y;
 									customAttribute.array[ offset + 2 ] = value.z;
 
@@ -1489,7 +1489,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				if ( customAttribute.needsUpdate &&
 					 ( customAttribute.boundTo === undefined ||
-					   customAttribute.boundTo === "vertices" ) ) {
+						 customAttribute.boundTo === "vertices" ) ) {
 
 					offset = 0;
 
@@ -1509,7 +1509,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 							value = customAttribute.value[ ca ];
 
-							customAttribute.array[ offset ] 	= value.x;
+							customAttribute.array[ offset ]   = value.x;
 							customAttribute.array[ offset + 1 ] = value.y;
 
 							offset += 2;
@@ -1524,7 +1524,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 								value = customAttribute.value[ ca ];
 
-								customAttribute.array[ offset ] 	= value.r;
+								customAttribute.array[ offset ]   = value.r;
 								customAttribute.array[ offset + 1 ] = value.g;
 								customAttribute.array[ offset + 2 ] = value.b;
 
@@ -1538,7 +1538,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 								value = customAttribute.value[ ca ];
 
-								customAttribute.array[ offset ] 	= value.x;
+								customAttribute.array[ offset ]   = value.x;
 								customAttribute.array[ offset + 1 ] = value.y;
 								customAttribute.array[ offset + 2 ] = value.z;
 
@@ -1554,7 +1554,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 							value = customAttribute.value[ ca ];
 
-							customAttribute.array[ offset ] 	 = value.x;
+							customAttribute.array[ offset ]    = value.x;
 							customAttribute.array[ offset + 1  ] = value.y;
 							customAttribute.array[ offset + 2  ] = value.z;
 							customAttribute.array[ offset + 3  ] = value.w;
@@ -1717,7 +1717,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					vka = morphTargetsArrays[ vk ];
 
-					vka[ offset_morphTarget ] 	  = v1.x;
+					vka[ offset_morphTarget ]     = v1.x;
 					vka[ offset_morphTarget + 1 ] = v1.y;
 					vka[ offset_morphTarget + 2 ] = v1.z;
 
@@ -1751,7 +1751,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						nka = morphNormalsArrays[ vk ];
 
-						nka[ offset_morphTarget ] 	  = n1.x;
+						nka[ offset_morphTarget ]     = n1.x;
 						nka[ offset_morphTarget + 1 ] = n1.y;
 						nka[ offset_morphTarget + 2 ] = n1.z;
 
@@ -1789,7 +1789,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-				face = obj_faces[ chunk_faces3[ f ]	];
+				face = obj_faces[ chunk_faces3[ f ] ];
 
 				// weights
 
@@ -1853,7 +1853,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-				face = obj_faces[ chunk_faces3[ f ]	];
+				face = obj_faces[ chunk_faces3[ f ] ];
 
 				vertexColors = face.vertexColors;
 				faceColor = face.color;
@@ -1901,7 +1901,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-				face = obj_faces[ chunk_faces3[ f ]	];
+				face = obj_faces[ chunk_faces3[ f ] ];
 
 				vertexTangents = face.vertexTangents;
 
@@ -1937,7 +1937,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-				face = obj_faces[ chunk_faces3[ f ]	];
+				face = obj_faces[ chunk_faces3[ f ] ];
 
 				vertexNormals = face.vertexNormals;
 				faceNormal = face.normal;
@@ -2045,7 +2045,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-				faceArray[ offset_face ] 	 = vertexIndex;
+				faceArray[ offset_face ]   = vertexIndex;
 				faceArray[ offset_face + 1 ] = vertexIndex + 1;
 				faceArray[ offset_face + 2 ] = vertexIndex + 2;
 
@@ -2091,9 +2091,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-							face = obj_faces[ chunk_faces3[ f ]	];
+							face = obj_faces[ chunk_faces3[ f ] ];
 
-							customAttribute.array[ offset_custom ] 	   = customAttribute.value[ face.a ];
+							customAttribute.array[ offset_custom ]     = customAttribute.value[ face.a ];
 							customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ];
 							customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ];
 
@@ -2107,7 +2107,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 							value = customAttribute.value[ chunk_faces3[ f ] ];
 
-							customAttribute.array[ offset_custom ] 	   = value;
+							customAttribute.array[ offset_custom ]     = value;
 							customAttribute.array[ offset_custom + 1 ] = value;
 							customAttribute.array[ offset_custom + 2 ] = value;
 
@@ -2123,13 +2123,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-							face = obj_faces[ chunk_faces3[ f ]	];
+							face = obj_faces[ chunk_faces3[ f ] ];
 
 							v1 = customAttribute.value[ face.a ];
 							v2 = customAttribute.value[ face.b ];
 							v3 = customAttribute.value[ face.c ];
 
-							customAttribute.array[ offset_custom ] 	   = v1.x;
+							customAttribute.array[ offset_custom ]     = v1.x;
 							customAttribute.array[ offset_custom + 1 ] = v1.y;
 
 							customAttribute.array[ offset_custom + 2 ] = v2.x;
@@ -2152,7 +2152,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 							v2 = value;
 							v3 = value;
 
-							customAttribute.array[ offset_custom ] 	   = v1.x;
+							customAttribute.array[ offset_custom ]     = v1.x;
 							customAttribute.array[ offset_custom + 1 ] = v1.y;
 
 							customAttribute.array[ offset_custom + 2 ] = v2.x;
@@ -2185,13 +2185,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-							face = obj_faces[ chunk_faces3[ f ]	];
+							face = obj_faces[ chunk_faces3[ f ] ];
 
 							v1 = customAttribute.value[ face.a ];
 							v2 = customAttribute.value[ face.b ];
 							v3 = customAttribute.value[ face.c ];
 
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
+							customAttribute.array[ offset_custom ]     = v1[ pp[ 0 ] ];
 							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
 							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
 
@@ -2217,7 +2217,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 							v2 = value;
 							v3 = value;
 
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
+							customAttribute.array[ offset_custom ]     = v1[ pp[ 0 ] ];
 							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
 							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
 
@@ -2243,7 +2243,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 							v2 = value[ 1 ];
 							v3 = value[ 2 ];
 
-							customAttribute.array[ offset_custom ] 	   = v1[ pp[ 0 ] ];
+							customAttribute.array[ offset_custom ]     = v1[ pp[ 0 ] ];
 							customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ];
 							customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ];
 
@@ -2267,13 +2267,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
 
-							face = obj_faces[ chunk_faces3[ f ]	];
+							face = obj_faces[ chunk_faces3[ f ] ];
 
 							v1 = customAttribute.value[ face.a ];
 							v2 = customAttribute.value[ face.b ];
 							v3 = customAttribute.value[ face.c ];
 
-							customAttribute.array[ offset_custom  ] 	= v1.x;
+							customAttribute.array[ offset_custom  ]   = v1.x;
 							customAttribute.array[ offset_custom + 1  ] = v1.y;
 							customAttribute.array[ offset_custom + 2  ] = v1.z;
 							customAttribute.array[ offset_custom + 3  ] = v1.w;
@@ -2302,7 +2302,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 							v2 = value;
 							v3 = value;
 
-							customAttribute.array[ offset_custom  ] 	= v1.x;
+							customAttribute.array[ offset_custom  ]   = v1.x;
 							customAttribute.array[ offset_custom + 1  ] = v1.y;
 							customAttribute.array[ offset_custom + 2  ] = v1.z;
 							customAttribute.array[ offset_custom + 3  ] = v1.w;
@@ -2331,7 +2331,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 							v2 = value[ 1 ];
 							v3 = value[ 2 ];
 
-							customAttribute.array[ offset_custom  ] 	= v1.x;
+							customAttribute.array[ offset_custom  ]   = v1.x;
 							customAttribute.array[ offset_custom + 1  ] = v1.y;
 							customAttribute.array[ offset_custom + 2  ] = v1.z;
 							customAttribute.array[ offset_custom + 3  ] = v1.w;
@@ -2462,7 +2462,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 					ny = ( nay + nby + ncy ) / 3;
 					nz = ( naz + nbz + ncz ) / 3;
 
-					normalArray[ i ] 	 = nx;
+					normalArray[ i ]   = nx;
 					normalArray[ i + 1 ] = ny;
 					normalArray[ i + 2 ] = nz;
 
@@ -2546,7 +2546,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 
 		disableUnusedAttributes();
-		
+
 	}
 
 	this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) {
@@ -2589,17 +2589,17 @@ THREE.WebGLRenderer = function ( parameters ) {
 				// indexed triangles
 
 				var type, size;
-			
+
 				if ( index.array instanceof Uint32Array ) {
-					
+
 					type = _gl.UNSIGNED_INT;
 					size = 4;
-					
+
 				} else {
-					
+
 					type = _gl.UNSIGNED_SHORT;
 					size = 2;
-					
+
 				}
 
 				var offsets = geometry.offsets;
@@ -2698,23 +2698,23 @@ THREE.WebGLRenderer = function ( parameters ) {
 			setLineWidth( material.linewidth );
 
 			var index = geometryAttributes[ "index" ];
-			
+
 			if ( index ) {
 
 				// indexed lines
 
 				var type, size;
-				
+
 				if ( index.array instanceof Uint32Array ){
-					
+
 					type = _gl.UNSIGNED_INT;
 					size = 4;
-					
+
 				} else {
-					
+
 					type = _gl.UNSIGNED_SHORT;
 					size = 2;
-					
+
 				}
 
 				var offsets = geometry.offsets;
@@ -2727,7 +2727,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 						_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
 
 					}
-					
+
 					_gl.drawElements( _gl.LINES, index.array.length, type, 0 ); // 2 bytes per Uint16Array
 
 					_this.info.render.calls ++;
@@ -2753,7 +2753,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 						}
 
 						// render indexed lines
-						
+
 						_gl.drawElements( _gl.LINES, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array
 
 						_this.info.render.calls ++;
@@ -2970,7 +2970,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			var type = geometryGroup.__typeArray === Uint32Array ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;
 
 			// wireframe
-			
+
 			if ( material.wireframe ) {
 
 				setLineWidth( material.wireframeLinewidth );
@@ -4106,7 +4106,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			skinning: material.skinning,
 			maxBones: maxBones,
-			useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture,
+			useVertexTexture: _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture,
 
 			morphTargets: material.morphTargets,
 			morphNormals: material.morphNormals,
@@ -4319,26 +4319,26 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( material.skinning ) {
 
-			if ( _supportsBoneTextures && object.useVertexTexture ) {
+			if ( _supportsBoneTextures && object.skeleton.useVertexTexture ) {
 
 				if ( p_uniforms.boneTexture !== null ) {
 
 					var textureUnit = getTextureUnit();
 
 					_gl.uniform1i( p_uniforms.boneTexture, textureUnit );
-					_this.setTexture( object.boneTexture, textureUnit );
+					_this.setTexture( object.skeleton.boneTexture, textureUnit );
 
 				}
 
 				if ( p_uniforms.boneTextureWidth !== null ) {
 
-					_gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth );
+					_gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth );
 
 				}
 
 				if ( p_uniforms.boneTextureHeight !== null ) {
 
-					_gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight );
+					_gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight );
 
 				}
 
@@ -4346,7 +4346,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				if ( p_uniforms.boneGlobalMatrices !== null ) {
 
-					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices );
+					_gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices );
 
 				}
 
@@ -4510,10 +4510,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 
 		// uv repeat and offset setting priorities
-		//	1. color map
-		//	2. specular map
-		//	3. normal map
-		//	4. bump map
+		//  1. color map
+		//  2. specular map
+		//  3. normal map
+		//  4. bump map
 
 		var uvScaleMap;
 
@@ -4807,7 +4807,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					offset = i * 2;
 
-					uniform._array[ offset ] 	 = value[ i ].x;
+					uniform._array[ offset ]   = value[ i ].x;
 					uniform._array[ offset + 1 ] = value[ i ].y;
 
 				}
@@ -4826,7 +4826,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					offset = i * 3;
 
-					uniform._array[ offset ] 	 = value[ i ].x;
+					uniform._array[ offset ]   = value[ i ].x;
 					uniform._array[ offset + 1 ] = value[ i ].y;
 					uniform._array[ offset + 2 ] = value[ i ].z;
 
@@ -4846,7 +4846,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					offset = i * 4;
 
-					uniform._array[ offset ] 	 = value[ i ].x;
+					uniform._array[ offset ]   = value[ i ].x;
 					uniform._array[ offset + 1 ] = value[ i ].y;
 					uniform._array[ offset + 2 ] = value[ i ].z;
 					uniform._array[ offset + 3 ] = value[ i ].w;
@@ -5663,7 +5663,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 						_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
 
 					} else {
-						
+
 						var mipmap, mipmaps = cubeImage[ i ].mipmaps;
 
 						for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
@@ -5995,7 +5995,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function allocateBones ( object ) {
 
-		if ( _supportsBoneTextures && object && object.useVertexTexture ) {
+		if ( _supportsBoneTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {
 
 			return 1024;
 
@@ -6005,7 +6005,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			// ( for example when prebuilding shader
 			//   to be used with multiple objects )
 			//
-			// 	- leave some extra space for other uniforms
+			//  - leave some extra space for other uniforms
 			//  - limit here is ANGLE's 254 max uniform vectors
 			//    (up to 54 should be safe)
 
@@ -6016,11 +6016,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			if ( object !== undefined && object instanceof THREE.SkinnedMesh ) {
 
-				maxBones = Math.min( object.bones.length, maxBones );
+				maxBones = Math.min( object.skeleton.bones.length, maxBones );
 
-				if ( maxBones < object.bones.length ) {
+				if ( maxBones < object.skeleton.bones.length ) {
 
-					console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
+					console.warn( "WebGLRenderer: too many bones - " + object.skeleton.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" );
 
 				}
 
@@ -6113,8 +6113,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 		_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
 
 		_glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' );
-		
-		
+
+
 		if ( _glExtensionTextureFloat === null ) {
 
 			console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
@@ -6184,7 +6184,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
 
 		_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
-		
+
 		_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
 
 	};

+ 6 - 2
src/renderers/shaders/ShaderLib.js

@@ -488,13 +488,16 @@ THREE.ShaderLib = {
 		},
 
 		vertexShader: [
+
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
 			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],
 
 			"void main() {",
 
-			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "default_vertex" ],
 				THREE.ShaderChunk[ "logdepthbuf_vertex" ],
+
 			"}"
 
 		].join("\n"),
@@ -504,6 +507,7 @@ THREE.ShaderLib = {
 			"uniform float mNear;",
 			"uniform float mFar;",
 			"uniform float opacity;",
+			
 			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],
 
 			"void main() {",

+ 3 - 0
src/renderers/webgl/WebGLShader.js

@@ -34,6 +34,9 @@ THREE.WebGLShader = ( function () {
 
 		}
 
+		// --enable-privileged-webgl-extension
+		// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
+
 		return shader;
 
 	};

+ 1 - 1
utils/build/build.js

@@ -68,7 +68,7 @@ function main() {
 
 		var result = uglify.minify( sources, { outSourceMap: sourcemap } );
 		
-		fs.writeFileSync( output, 'three.js / threejs.org/license\n' + result.code + sourcemapping, 'utf8' );
+		fs.writeFileSync( output, '// three.js / threejs.org/license\n' + result.code + sourcemapping, 'utf8' );
 
 		if ( args.sourcemaps ) {
 

+ 1 - 0
utils/build/includes/canvas.json

@@ -53,6 +53,7 @@
 	"src/objects/Line.js",
 	"src/objects/Mesh.js",
 	"src/objects/Bone.js",
+	"src/objects/Skeleton.js",
 	"src/objects/Sprite.js",
 	"src/scenes/Scene.js",
 	"src/renderers/CanvasRenderer.js",

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