Browse Source

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

repsac 10 năm trước cách đây
mục cha
commit
efb1ee8c71
100 tập tin đã thay đổi với 3313 bổ sung1921 xóa
  1. 1 1
      LICENSE
  2. 3 2
      bower.json
  3. 166 43
      build/three.js
  4. 146 143
      build/three.min.js
  5. 1 1
      docs/api/constants/GLState.html
  6. 1 0
      docs/api/constants/Textures.html
  7. 54 23
      docs/api/core/Object3D.html
  8. 89 9
      docs/api/core/Raycaster.html
  9. 1 1
      docs/api/extras/ImageUtils.html
  10. 3 3
      docs/api/extras/helpers/ArrowHelper.html
  11. 1 1
      docs/api/extras/helpers/BoundingBoxHelper.html
  12. 45 0
      docs/api/extras/helpers/BoxHelper.html
  13. 8 8
      docs/api/extras/helpers/DirectionalLightHelper.html
  14. 21 15
      docs/api/extras/helpers/EdgesHelper.html
  15. 23 11
      docs/api/extras/helpers/FaceNormalsHelper.html
  16. 1 0
      docs/api/extras/helpers/GridHelper.html
  17. 1 0
      docs/api/extras/helpers/PointLightHelper.html
  18. 23 11
      docs/api/extras/helpers/VertexNormalsHelper.html
  19. 22 12
      docs/api/extras/helpers/VertexTangentsHelper.html
  20. 24 15
      docs/api/extras/helpers/WireframeHelper.html
  21. 26 31
      docs/api/lights/DirectionalLight.html
  22. 9 34
      docs/api/lights/SpotLight.html
  23. 2 3
      docs/api/loaders/ColladaLoader.html
  24. 1 1
      docs/api/materials/MeshLambertMaterial.html
  25. 8 0
      docs/api/math/Color.html
  26. 141 138
      docs/api/math/Euler.html
  27. 8 5
      docs/api/math/Quaternion.html
  28. 14 1
      docs/api/math/Vector2.html
  29. 14 1
      docs/api/math/Vector3.html
  30. 14 6
      docs/api/math/Vector4.html
  31. 5 0
      docs/api/objects/Line.html
  32. 6 0
      docs/api/objects/Mesh.html
  33. 5 0
      docs/api/objects/PointCloud.html
  34. 1 1
      docs/api/renderers/WebGLRenderTarget.html
  35. 2 2
      docs/api/renderers/WebGLRenderer.html
  36. 1 0
      docs/list.js
  37. 118 118
      docs/scenes/js/material.js
  38. 39 17
      editor/css/dark.css
  39. 28 14
      editor/css/light.css
  40. 12 6
      editor/css/main.css
  41. 167 0
      editor/examples/arkanoid.app.json
  42. 168 0
      editor/examples/camera.app.json
  43. 97 0
      editor/examples/particles.app.json
  44. 134 0
      editor/examples/pong.app.json
  45. 49 9
      editor/index.html
  46. 6 5
      editor/js/Config.js
  47. 84 6
      editor/js/Editor.js
  48. 29 4
      editor/js/Menubar.Add.js
  49. 6 2
      editor/js/Menubar.Edit.js
  50. 61 0
      editor/js/Menubar.Examples.js
  51. 13 20
      editor/js/Menubar.File.js
  52. 1 0
      editor/js/Menubar.js
  53. 8 0
      editor/js/Player.js
  54. 91 0
      editor/js/Script.js
  55. 2 2
      editor/js/Sidebar.Geometry.BufferGeometry.js
  56. 2 2
      editor/js/Sidebar.Geometry.Geometry.js
  57. 2 2
      editor/js/Sidebar.Geometry.js
  58. 28 39
      editor/js/Sidebar.Material.js
  59. 70 8
      editor/js/Sidebar.Object3D.js
  60. 27 12
      editor/js/Sidebar.Project.js
  61. 4 4
      editor/js/Sidebar.Scene.js
  62. 0 68
      editor/js/Sidebar.Script.Editor.js
  63. 84 3
      editor/js/Sidebar.Script.js
  64. 1 1
      editor/js/Sidebar.js
  65. 0 2
      editor/js/Toolbar.js
  66. 27 16
      editor/js/Viewport.js
  67. 128 16
      editor/js/libs/app.js
  68. 22 14
      editor/js/libs/codemirror/codemirror.css
  69. 344 229
      editor/js/libs/codemirror/codemirror.js
  70. 8 8
      editor/js/libs/codemirror/mode/javascript.js
  71. 31 0
      editor/js/libs/codemirror/theme/monokai.css
  72. 1 0
      editor/js/libs/sortable.min.js
  73. 0 75
      editor/js/libs/ui.editor.js
  74. 31 177
      editor/js/libs/ui.js
  75. 176 0
      editor/js/libs/ui.three.js
  76. 1 0
      examples/canvas_ascii_effect.html
  77. 1 2
      examples/canvas_lines_colors_2d.html
  78. 1 1
      examples/canvas_lines_dashed.html
  79. 4 3
      examples/index.html
  80. 2 1
      examples/js/Mirror.js
  81. 4 3
      examples/js/Ocean.js
  82. 3 5
      examples/js/ShaderDeferred.js
  83. 22 30
      examples/js/ShaderSkin.js
  84. 11 21
      examples/js/ShaderTerrain.js
  85. 0 4
      examples/js/controls/EditorControls.js
  86. 0 61
      examples/js/controls/OculusControls.js
  87. 0 6
      examples/js/controls/OrbitControls.js
  88. 194 105
      examples/js/controls/OrthographicTrackballControls.js
  89. 10 10
      examples/js/controls/TransformControls.js
  90. 12 12
      examples/js/crossfade/scenes.js
  91. 0 220
      examples/js/effects/OculusRiftEffect.js
  92. 5 1
      examples/js/effects/StereoEffect.js
  93. 15 15
      examples/js/exporters/SceneExporter.js
  94. 0 7
      examples/js/loaders/AssimpJSONLoader.js
  95. 0 1
      examples/js/loaders/BabylonLoader.js
  96. 1 2
      examples/js/loaders/ColladaLoader.js
  97. 14 3
      examples/js/loaders/MTLLoader.js
  98. 2 1
      examples/js/loaders/OBJMTLLoader.js
  99. 21 1
      examples/js/loaders/STLLoader.js
  100. 0 5
      examples/js/loaders/gltf/glTFLoader.js

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 The MIT License
 
-Copyright © 2010-2014 three.js authors
+Copyright © 2010-2015 three.js authors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 3 - 2
bower.json

@@ -1,6 +1,6 @@
 {
 	"name": "three.js",
-	"version": "0.0.69",
+	"version": "0.0.70",
 	"homepage": "http://threejs.org/",
 	"description": "JavaScript 3D library",
 	"main": "build/three.js",
@@ -17,7 +17,8 @@
 		"*.md",
 		"docs",
 		"editor",
-		"examples",
+		"examples/*",
+		"!examples/js",
 		"src",
 		"test",
 		"utils",

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 166 - 43
build/three.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 146 - 143
build/three.min.js


+ 1 - 1
docs/api/constants/GLState.html

@@ -7,7 +7,7 @@
 		<link type="text/css" rel="stylesheet" href="../../page.css" />
 	</head>
 	<body>
-		<h1>GL State Conflicts</h1>
+		<h1>GL State Constants</h1>
 
 		<h2>Cull Face</h2>
 		<div>

+ 1 - 0
docs/api/constants/Textures.html

@@ -49,6 +49,7 @@
 		THREE.UnsignedShortType<br />
 		THREE.IntType<br />
 		THREE.UnsignedIntType<br />
+		THREE.HalfFloatType<br />
 		THREE.FloatType
 		</div>
 

+ 54 - 23
docs/api/core/Object3D.html

@@ -25,7 +25,7 @@
 
 		<h3>[property:Integer id]</h3>
 		<div>
-		Unique number for this object instance.
+		readonly – Unique number for this object instance.
 		</div>
 
 		<h3>[property:String uuid]</h3>
@@ -59,11 +59,6 @@
 		Object's local rotation (<a href="https://en.wikipedia.org/wiki/Euler_angles" target="_blank">Euler angles</a>), in radians.
 		</div>
 
-		<h3>[property:String eulerOrder]</h3>
-		<div>
-		Order of axis for Euler angles.
-		</div>
-
 		<h3>[property:Vector3 scale]</h3>
 		<div>
 		Object's local scale.
@@ -81,48 +76,64 @@
 
 		<h3>[property:Quaternion quaternion]</h3>
 		<div>
-		Object's local rotation as [page:Quaternion Quaternion]. Only used when useQuaternion is set to true.
-		</div>
-
-		<h3>[property:Boolean useQuaternion]</h3>
-		<div>
-		Use quaternion instead of Euler angles for specifying local rotation.
+		Object's local rotation as [page:Quaternion Quaternion].
 		</div>
 
 		<h3>[property:Boolean visible]</h3>
 		<div>
 		Object gets rendered if *true*.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean castShadow]</h3>
 		<div>
 		Gets rendered into shadow map.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean receiveShadow]</h3>
 		<div>
 		Material gets baked in shadow receiving.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean frustumCulled]</h3>
 		<div>
 		When this is set, it checks every frame if the object is in the frustum of the camera. Otherwise the object gets drawn every frame even if it isn't visible.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean matrixAutoUpdate]</h3>
 		<div>
 		When this is set, it calculates the matrix of position, (rotation or quaternion) and scale every frame and also recalculates the matrixWorld property.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:Boolean matrixWorldNeedsUpdate]</h3>
 		<div>
 		When this is set, it calculates the matrixWorld in that frame and resets this property to false.
 		</div>
+		<div>
+		default – false
+		</div>
 
 		<h3>[property:Boolean rotationAutoUpdate]</h3>
 		<div>
 		When this is set, then the rotationMatrix gets calculated every frame.
 		</div>
+		<div>
+		default – true
+		</div>
 
 		<h3>[property:object userData]</h3>
 		<div>
@@ -195,29 +206,46 @@
 		Rotates object to face point in space.
 		</div>
 
-		<h3>[method:null add]( [page:Object3D object] )</h3>
+		<h3>[method:null add]( [page:Object3D object], ... )</h3>
 		<div>
 		object - An object.<br />
 		</div>
 		<div>
-		Adds *object* as child of this object.
+		Adds *object* as child of this object. An arbitrary number of objects may be added.
 		</div>
 
-		<h3>[method:null remove]( [page:Object3D object] )</h3>
+		<h3>[method:null remove]( [page:Object3D object], ... )</h3>
 		<div>
 		object - An object.<br />
 		</div>
 		<div>
-		Removes *object* as child of this object.
+		Removes *object* as child of this object. An arbitrary number of objects may be removed.
 		</div>
 
 		<h3>[method:null traverse]( [page:Function callback] )</h3>
 		<div>
-		callback - An Function with as first argument an object3D object.<br />
+		callback - A function with as first argument an object3D object.<br />
 		</div>
 		<div>
 		Executes the callback on this object and all descendants.
 		</div>
+		
+		<h3>[method:null traverseVisible]( [page:Function callback] )</h3>
+		<div>
+		callback - A function with as first argument an object3D object.<br />
+		</div>
+		<div>
+		Like traverse, but the callback will only be executed for visible objects.
+		Descendants of invisible objects are not traversed.
+		</div>
+		
+		<h3>[method:null traverseAncestors]( [page:Function callback] )</h3>
+		<div>
+		callback - A function with as first argument an object3D object.<br />
+		</div>
+		<div>
+		Executes the callback on this object and all ancestors.
+		</div>
 
 		<h3>[method:null updateMatrix]()</h3>
 		<div>
@@ -235,22 +263,20 @@
 		</div>
 
 
-		<h3>[method:Object3D getObjectByName]([page:String name], [page:Boolean recursive])</h3>
+		<h3>[method:Object3D getObjectByName]([page:String name])</h3>
 		<div>
 		name -- String to match to the children's Object3d.name property. <br />
-		recursive -- Boolean whether to search through the children's children. Default is false.
 		</div>
 		<div>
-		Searches through the object's children and returns the first with a matching name, optionally recursive.
+		Searches through the object's children and returns the first with a matching name.
 		</div>
 
-		<h3>[method:Object3D getObjectById]([page:Integer id], [page:Boolean recursive])</h3>
+		<h3>[method:Object3D getObjectById]([page:Integer id])</h3>
 		<div>
 		id -- Unique number of the object instance<br />
-		recursive -- Boolean whether to search through the children's children. Default is false.
 		</div>
 		<div>
-		Searches through the object's children and returns the first with a matching id, optionally recursive.
+		Searches through the object's children and returns the first with a matching id.
 		</div>
 
 		<h3>[method:Object3D translateOnAxis]([page:Vector3 axis], [page:Float distance])</h3>
@@ -271,6 +297,11 @@
 		Rotate an object along an axis in object space. The axis is assumed to be normalized.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Abstract method to get intersections between a casted ray and this object. Subclasses such as [page:Mesh], [page:Line], and [page:PointCloud] implement this method in order to participate in raycasting.
+		</div>
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 89 - 9
docs/api/core/Raycaster.html

@@ -11,18 +11,67 @@
 
 		<div class="desc">
 		This class makes raycasting easier. Raycasting is used for picking and more.
+		</div>
+
+		<h2>Example</h2>
+		<code>
+		var raycaster = new THREE.Raycaster();
+		var mouse = new THREE.Vector2();
+
+		function onMouseMove( event ) {
+
+			// calculate mouse position in normalized device coordinates
+			// (-1 to +1) for both components
+
+			mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1
+			mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1		
+		
+		}
+
+		function render() {
+
+			// update the picking ray with the camera and mouse position	
+			raycaster.setFromCamera( mouse, camera );	
+
+			// calculate objects intersecting the picking ray
+			var intersects = raycaster.intersectObjects( scene.children );
+
+			for ( var intersect in intersects ) {
+
+				intersect.object.material.color = new THREE.Color( 0xff0000 );
 			
+			}
+			
+			renderer.render( scene, camera );
+
+		}
+
+		window.addEventListener( 'mousemove', onMouseMove, false );
+
+		window.requestAnimationFrame(render);
+
+		</code>
+		<div>Examples: [example:webgl_interactive_cubes Raycasting to a Mesh], 
+			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera], 
+			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry], 
+			[example:webgl_interactive_lines Raycasting to a Line], 
+			[example:webgl_interactive_raycasting_pointcloud Raycasting to a PointCloud], 
+			[example:webgl_geometry_terrain_raycast Terrain raycasting], 
+			[example:webgl_octree_raycasting Raycasting using an octree],
+			[example:webgl_interactive_voxelpainter Raycasting to paint voxels]</div>
+
+
+		<div>
 		</div>
 
 
 		<h2>Constructor</h2>
 
-
 		<h3>[name]( [page:Vector3 origin], [page:Vector3 direction], [page:Float near], [page:Float far] ) {</h3>
 		<div>
 		[page:Vector3 origin] — The origin vector where the ray casts from.<br />
 		[page:Vector3 direction] — The direction vector that  gives direction to the ray.<br />
-		[page:Float near] — All results returned are further away then near. Near can't be negative. Default value is 0.<br />
+		[page:Float near] — All results returned are further away than near. Near can't be negative. Default value is 0.<br />
 		[page:Float far] — All results returned are closer then far. Far can't be lower then near . Default value is Infinity.
 		</div>
 		<div>
@@ -51,7 +100,12 @@
 
 		<h3>[property:float precision]</h3>
 		<div>
-		The precision factor of the raycaster. 
+		The precision factor of the raycaster when intersecting [page:Mesh] objects. 
+		</div>
+
+		<h3>.[page:float linePrecision]</h3>
+		<div>
+		The precision factor of the raycaster when intersecting [page:Line] objects. 
 		</div>
 
 		<h2>Methods</h2>
@@ -65,16 +119,45 @@
 		Updates the ray with a new origin and direction.
 		</div>
 
+		<h3>[method:null setFromCamera]( [page:Vector2 coords], [page:Camera camera] )</h3>
+		<div>
+		[page:Vector2 coords] — 2D coordinates of the mouse, in normalized device coordinates (NDC)---X and Y components should be between -1 and 1.<br />
+		[page:Camera camera] — camera from which the ray should originate
+		</div>
+		<div>
+		Updates the ray with a new origin and direction.
+		</div>
+
+
 		<h3>[method:Array intersectObject]( [page:Object3D object], [page:Boolean recursive] )</h3>
 		<div>
+		<p>
 		[page:Object3D object] — The object to check for intersection with the ray.<br />
 		[page:Boolean recursive] — If set, it also checks all descendants. Otherwise it only checks intersecton with the object.
+		</p>
 		</div>
 		<div>
-		checks all intersection between the ray and the object with or without the descendants. Intersections are returned sorted by distance, closest first.
+		Checks all intersection between the ray and the object with or without the descendants. Intersections are returned sorted by distance, closest first. An array of intersections is returned...
         <code>
-            [ { distance, point, face, faceIndex, object }, ... ]
+            [ { distance, point, face, faceIndex, indices, object }, ... ]
         </code>
+        <p>
+        [page:Float distance] – distance between the origin of the ray and the intersection<br />
+        [page:Vector3 point] – point of intersection, in world coordinates<br />
+        [page:Face3 face] – intersected face<br />
+        [page:Integer faceIndex] – index of the intersected face<br />
+        [page:Array indices] – indices of vertices comprising the intersected face<br />
+        [page:Object3D object] – the intersected object
+    	</p>
+        <p>
+        When intersecting a [page:Mesh] with a [page:BufferGeometry], the *faceIndex* will be *undefined*, and *indices* will be set; when intersecting a [page:Mesh] with a [page:Geometry], *indices* will be *undefined*. 
+        </p>
+		<p>
+		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:PointCloud pointclouds].
+		</p>
+		<p>
+		*Note* that for meshes, faces must be pointed towards the origin of the [page:.ray ray] in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the [page:Mesh.material material]'s [page:Material.side side] property to *THREE.DoubleSide*.  
+		</p>
 		</div>
 
 		<h3>[method:Array intersectObjects]( [page:Array objects], [page:Boolean recursive] )</h3>
@@ -83,10 +166,7 @@
 		[page:Boolean recursive] — If set, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects.
 		</div>
 		<div>
-		checks all intersection between the ray and the objects with or without the descendants. Intersections are returned sorted by distance, closest first.
-        <code>
-            [ { distance, point, face, faceIndex, object }, ... ]
-        </code>
+		Checks all intersection between the ray and the objects with or without the descendants. Intersections are returned sorted by distance, closest first. Intersections are of the same form as those returned by [page:.intersectObject].
 		</div>
 
 

+ 1 - 1
docs/api/extras/ImageUtils.html

@@ -58,7 +58,7 @@
 		<h3>[method:todo loadTexture]([page:String url], [page:UVMapping mapping], [page:Function onLoad], [page:Function onError])</h3>
 		<div>
 		url -- the url of the texture<br />
-		mapping -- Can be an instance of [page:UVMapping THREE.UVMapping], [page:CubeReflectionMapping THREE.CubeReflectionMapping] or [page:SphericalReflectionMapping THREE.SphericalReflectionMapping]. Describes how the image is applied to the object.<br />Use undefined instead of null as a default value. See mapping property of [page:Texture texture] for more details.
+		mapping -- Can be an instance of [page:UVMapping THREE.UVMapping], [page:CubeReflectionMapping THREE.CubeReflectionMapping] or [page:SphericalReflectionMapping THREE.SphericalReflectionMapping]. Describes how the image is applied to the object.<br />Use undefined instead of null as a default value. See mapping property of [page:Texture texture] for more details. <br/>
 		onLoad -- callback function<br />
 		onError -- callback function
 		</div>

+ 3 - 3
docs/api/extras/helpers/ArrowHelper.html

@@ -74,15 +74,15 @@
 		<div>
 		length -- The desired length<br />
 		headLength -- The length of the head of the arrow<br />
-		headWidth -- The length of the width of the arrow		
+		headWidth -- The length of the width of the arrow
 		</div>
 		<div>
 		Sets the length of the arrowhelper.
 		</div>
 
-		<h3>[method:null setDirection]([page:vector3 dir])</h3>
+		<h3>[method:null setDirection]([page:Vector3 dir])</h3>
 		<div>
-		dir -- The desired direction in euler format.
+		dir -- The desired direction. Must be a unit vector.
 		</div>
 		<div>
 		Sets the direction of the arrowhelper.

+ 1 - 1
docs/api/extras/helpers/BoundingBoxHelper.html

@@ -26,7 +26,7 @@
 		bbox.update();
 		scene.add( bbox );
 		</code>
-
+		<div>Note that this helper will create a wireframe [page:Mesh] object with a [page:BoxGeometry]; the resulting bounding box object will therefore have face diagonals. You may want to use [page:BoxHelper], which generates a [page:Line] object without face diagonals.</div>
 
 
 		<h2>Constructor</h2>

+ 45 - 0
docs/api/extras/helpers/BoxHelper.html

@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<script src="../../../list.js"></script>
+		<script src="../../../page.js"></script>
+		<link type="text/css" rel="stylesheet" href="../../../page.css" />
+	</head>
+	<body>
+		[page:Line] &rarr;
+		
+		<h1>[name]</h1>
+
+		<div class="desc">Helper object to show a wireframe box (with no face diagonals) around an object</div>
+
+
+		<h2>Example</h2>
+
+		<code>var sphere = new THREE.SphereGeometry();
+		var object = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial(0xff0000) );
+		var box = new THREE.BoxHelper( object );
+		scene.add( box );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [page:Object3D object] )</h3>
+		<div>Creates a new wireframe box matching the size of the passed box.</div>
+
+		<h2>Properties</h2>
+
+		<div>(none)</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:null update]( [page:Object3D object] )</h3>
+		<div>
+		Updates the helper's geometry to match the dimensions of the [page:Geometry.boundingBox bounding box] of the passed object's geometry.
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 8 - 8
docs/api/extras/helpers/DirectionalLightHelper.html

@@ -11,26 +11,26 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Visualize a [page:DirectionalLight]'s effect on the scene</div>
 
 
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:todo light], [page:todo sphereSize])</h3>
+		<h3>[name]([DirectionalLight:todo light], [page:Number size])</h3>
 		<div>
-		light -- todo <br />
-		sphereSize -- todo
+		light -- [page:DirectionalLight] -- Light to visualize <br />
+		size -- dimensions of the plane
 		</div>
 		<div>
-		todo
+		Creates a line and plane to visualize the light's position and direction
 		</div>
 
 
 		<h2>Properties</h2>
 		
 
-		<h3>[property:Mesh lightSphere]</h3>
+		<h3>[property:Line lightPlane]</h3>
 		<div>
 		todo
 		</div> 
@@ -48,9 +48,9 @@
 		<h2>Methods</h2>
 
 
-		<h3>.update() [page:todo]</h3>
+		<h3>.[method:null update]()</h3>
 		<div>
-		todo
+		Updates the helper to match the position and direction of the [page:.light].
 		</div>
 
 		<h2>Source</h2>

+ 21 - 15
docs/api/extras/helpers/EdgesHelper.html

@@ -11,36 +11,42 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Creates a wireframe object that shows the "hard" edges of another object's geometry. To draw a full wireframe image of an object, see [page:WireframeHelper].</div>
 
 		<h2>Example</h2>
 
-		<code>todo</code>
+		<code>
+		geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 );
+		material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
+		object = new THREE.Mesh( geometry, material );
 
-		<h2>Constructor</h2>
+		edges = new THREE.EdgesHelper( object, 0x00ff00 );
 
+		scene.add( object );
+		scene.add( edges );
+		</code>
 
-		<h3>todo</h3>
-		<div></div>
+		<h2>Constructor</h2>
+		<h3>[name]( [page:Object3D object], [page:Color color] )</h3>
+		<div>
+		object -- Object of which to draw edges <br />
+		color -- Color of the edges.
+		</div>
+		<div>
+		Creates a [page:Line], showing only the "hard" edges of the passed object; specifically, no edge will be drawn between faces which are adjacent and coplanar (or nearly coplanar).
+		</div>
 
 
 		<h2>Properties</h2>
 
-		<h3>todo</h3>
-		<div>
-		todo
-		</div> 
+		<div>none</div>
 
 
 		<h2>Methods</h2>
 		
-
-		<h3>todo</h3>
-		<div>todo</div>
-		<div>
-		todo
-		</div>
+		<div>none</div>
 		
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 23 - 11
docs/api/extras/helpers/FaceNormalsHelper.html

@@ -11,35 +11,47 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Renders [page:ArrowHelper arrows] to visualize an object's [page:Face3 face] normals. Requires that the object's geometry be an instance of [page:Geometry] (does not work with [page:BufferGeometry]), and that face normals have been specified on all [page:Face3 faces] or calculated with [page:Geometry.computeFaceNormals computeFaceNormals].</div>
 
 		<h2>Example</h2>
 
-		<code>todo</code>
+		<code>
+		geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 );
+		material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
+		object = new THREE.Mesh( geometry, material );
+
+		edges = new THREE.FaceNormalsHelper( object, 2, 0x00ff00, 1 );
+
+		scene.add( object );
+		scene.add( edges );
+		</code>
+		[example:webgl_helpers Example using various helpers]
 
 		<h2>Constructor</h2>
 
 
-		<h3>todo</h3>
-		<div></div>
+		<h3>[name]( [page:Object3D object], [page:Number size], [page:Color color], [page:Number linewidth] )</h3>
+		<div>object -- object for which to render face normals
+		size -- size (length) of the arrows
+		color -- color of the arrows
+		linewidth -- width of the arrow lines
+		</div>
 
 
 		<h2>Properties</h2>
 
-		<h3>todo</h3>
+		<h3>[property:Object3D object]</h3>
 		<div>
-		todo
+		The attached object
 		</div> 
 
 
 		<h2>Methods</h2>
 		
 
-		<h3>todo</h3>
-		<div>todo</div>
-		<div>
-		todo
-		</div>
+		<h3>[method:null update]()</h3>
+		<div>Updates the face normal preview based on movement of the object.</div>
+
 		
 		<h2>Source</h2>
 

+ 1 - 0
docs/api/extras/helpers/GridHelper.html

@@ -22,6 +22,7 @@
 		var gridHelper = new THREE.GridHelper( size, step );		
 		scene.add( gridHelper );
 		</code>
+		[example:webgl_helpers Example using various helpers]
 
 
 		<h2>Constructor</h2>

+ 1 - 0
docs/api/extras/helpers/PointLightHelper.html

@@ -24,6 +24,7 @@
 		var pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
 		scene.add( pointLightHelper );
 		</code>
+		[example:webgl_helpers Example using various helpers]
 
 
 		<h2>Constructor</h2>

+ 23 - 11
docs/api/extras/helpers/VertexNormalsHelper.html

@@ -11,35 +11,47 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Renders [page:ArrowHelper arrows] to visualize an object's vertex normal vectors. Requires that normals have been specified in a [page:BufferAttribute custom attribute] or have been calculated using [page:Geometry.computeVertexNormals computeVertexNormals]. </div>
 
 		<h2>Example</h2>
 
-		<code>todo</code>
+		<code>
+		geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 );
+		material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
+		object = new THREE.Mesh( geometry, material );
+
+		edges = new THREE.VertexNormalsHelper( object, 2, 0x00ff00, 1 );
+
+		scene.add( object );
+		scene.add( edges );
+		</code>
+		[example:webgl_helpers Example using various helpers]
 
 		<h2>Constructor</h2>
 
 
-		<h3>todo</h3>
-		<div></div>
+		<h3>[name]( [page:Object3D object], [page:Number size], [page:Color color], [page:Number linewidth] )</h3>
+		<div>object -- object for which to render vertex normals
+		size -- size (length) of the arrows
+		color -- color of the arrows
+		linewidth -- width of the arrow lines
+		</div>
 
 
 		<h2>Properties</h2>
 
-		<h3>todo</h3>
+		<h3>[property:Object3D object]</h3>
 		<div>
-		todo
+		The attached object
 		</div> 
 
 
 		<h2>Methods</h2>
 		
 
-		<h3>todo</h3>
-		<div>todo</div>
-		<div>
-		todo
-		</div>
+		<h3>[method:null update]()</h3>
+		<div>Updates the vertex normal preview based on movement of the object.</div>
+
 		
 		<h2>Source</h2>
 

+ 22 - 12
docs/api/extras/helpers/VertexTangentsHelper.html

@@ -11,36 +11,46 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Renders [page:ArrowHelper arrows] to visualize an object's vertex tangent vectors. Requires that tangents have been specified in a [page:BufferAttribute custom attribute] or have been computed using [page:Geometry.computeTangents computeTangents]. </div>
 
 		<h2>Example</h2>
 
-		<code>todo</code>
+		<code>
+		geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 );
+		material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
+		object = new THREE.Mesh( geometry, material );
+
+		edges = new THREE.VertexTangentsHelper( object, 2, 0x00ff00, 1 );
+
+		scene.add( object );
+		scene.add( edges );
+		</code>
 
 		<h2>Constructor</h2>
 
 
-		<h3>todo</h3>
-		<div></div>
+		<h3>[name]( [page:Object3D object], [page:Number size], [page:Color color], [page:Number linewidth] )</h3>
+		<div>object -- object for which to render vertex tangents
+		size -- size (length) of the arrows
+		color -- color of the arrows
+		linewidth -- width of the arrow lines
+		</div>
 
 
 		<h2>Properties</h2>
 
-		<h3>todo</h3>
+		<h3>[property:Object3D object]</h3>
 		<div>
-		todo
+		The attached object
 		</div> 
 
 
 		<h2>Methods</h2>
 		
 
-		<h3>todo</h3>
-		<div>todo</div>
-		<div>
-		todo
-		</div>
-		
+		<h3>[method:null update]()</h3>
+		<div>Updates the vertex tangent preview arrows based on the new position and tangents of the object.</div>
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 24 - 15
docs/api/extras/helpers/WireframeHelper.html

@@ -11,36 +11,45 @@
 		
 		<h1>[name]</h1>
 
-		<div class="desc">todo</div>
+		<div class="desc">Creates a wireframe object that shows the edges of another object's geometry. To draw a  wireframe image showing only "hard" edges (edges between non-coplanar faces), see [page:EdgesHelper].</div>
 
 		<h2>Example</h2>
 
-		<code>todo</code>
+		<code>
+		geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 );
+		material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
+		object = new THREE.Mesh( geometry, material );
 
-		<h2>Constructor</h2>
+		wireframe = new THREE.WireframeHelper( object, 0x00ff00 );
+
+		scene.add( object );
+		scene.add( wireframe );
 
+		</code>
+		[example:webgl_helpers Example using various helpers], [example:webgl_materials_wireframe Alternative approach using a shader.]
 
-		<h3>todo</h3>
-		<div></div>
+		<h2>Constructor</h2>
+		<h3>[name]( [page:Object3D object], [page:Color color] )</h3>
+		<div>
+		object -- Object of which to draw edges <br />
+		color -- Color of the edges.
+		</div>
+		<div>
+		Creates a [page:Line], showing only the edges between vertices of an object.
+		</div>
 
 
 		<h2>Properties</h2>
 
-		<h3>todo</h3>
-		<div>
-		todo
-		</div> 
+		<div>none</div>
 
 
 		<h2>Methods</h2>
 		
-
-		<h3>todo</h3>
-		<div>todo</div>
-		<div>
-		todo
-		</div>
+		<div>none</div>
 		
+
+		<h2>Source</h2>
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 26 - 31
docs/api/lights/DirectionalLight.html

@@ -103,7 +103,7 @@ scene.add( directionalLight );</code>
 
 		<h3>[property:Float shadowBias]</h3>
 		<div>
-			Shadow map bias.<br />
+			Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.<br />
 			Default — *0*.
 		</div>
 
@@ -127,81 +127,76 @@ scene.add( directionalLight );</code>
 
 		<h3>[property:Boolean shadowCascade]</h3>
 		<div>
-			??? <br />
+			**Experimental** If true, use a series of shadow maps in a cascade. This can give better z-depth resolution for a directional light. <br />
 			Default — *false*.
 		</div>
 
-		<h3>[property:Vector3 shadowCascadeOffset]</h3>
+		<h3>[property:Integer shadowCascadeCount]</h3>
 		<div>
-			??? <br />
-			Default — *Three.Vector3( 0, 0, -1000 )*.
+			Number of shadow maps to allocate in a cascade (one after another). <br />
+			Default — *2*.
 		</div>
 
-		<h3>[property:Integer shadowCascadeCount]</h3>
+		<h3>[property:Vector3 shadowCascadeOffset]</h3>
 		<div>
-			??? <br />
-			Default — *2*.
+			A relative position to real camera where virtual shadow cameras are attached. A magic vector; scene and light orientation dependent. <br />
+			Default — *Three.Vector3( 0, 0, -1000 )*.
 		</div>
 
 		<h3>[property:Array shadowCascadeBias]</h3>
 		<div>
-			??? <br />
+			An array of shadowMapBias values for the corresponding shadow map in the cascade, near to far. <br />
 			Default — <strong>[ 0, 0, 0 ]</strong>.
 		</div>
 
 		<h3>[property:Array shadowCascadeWidth]</h3>
 		<div>
-			??? <br />
+			An array of shadowMapWidth values for the corresponding shadow map in the cascade, near to far. <br />
 			Default — <strong>[ 512, 512, 512 ]</strong>.
 		</div>
 
 		<h3>[property:Array shadowCascadeHeight]</h3>
 		<div>
-			??? <br />
+			An array of shadowMapHeight values for the corresponding shadow map in the cascade, near to far. <br />
 			Default — <strong>[ 512, 512, 512 ]</strong>.
 		</div>
 
 		<h3>[property:Array shadowCascadeNearZ]</h3>
 		<div>
-			??? <br />
+			An array of shadowMapNear values for the corresponding shadow map in the cascade, near to far. These typically start with -1.0 (near plane) and match with the previous shadowCascadeFarZ array value.<br />
 			Default — <strong>[ -1.000, 0.990, 0.998 ]</strong>.
 		</div>
 
 		<h3>[property:Array shadowCascadeFarZ]</h3>
 		<div>
-			??? <br />
+			An array of shadowMapFar values for the corresponding shadow map in the cascade, near to far. These typically match with the next shadowCascadeNearZ array value, ending in 1.0.<br />
 			Default — <strong>[ 0.990, 0.998, 1.000 ]</strong>.
 		</div>
 
 		<h3>[property:Array shadowCascadeArray]</h3>
 		<div>
-			??? <br />
-			Default — <strong>[ ]</strong>.
+			Array of size shadowCascadeCount of [page:DirectionalLight THREE.DirectionalLight] objects. This holds the series of separate shadow maps in a cascade, near to far. Created internally.
 		</div>
 
-		<h3>[property:RenderTarget shadowMap]</h3>
+		<h3>[property:Vector2 shadowMapSize]</h3>
 		<div>
-			??? <br />
-			Default — *null*.
-		</div>
+			The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering.
+		</div> 
 
-		<h3>[property:Integer shadowMapSize]</h3>
+		<h3>[property:OrthographicCamera shadowCamera]</h3>
 		<div>
-			??? <br />
-			Default — *null*.
-		</div>
+			The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings.
+		</div> 
 
-		<h3>[property:Camera shadowCamera]</h3>
+		<h3>[property:Matrix4 shadowMatrix]</h3>
 		<div>
-			??? <br />
-			Default — *null*.
-		</div>
+			Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering.
+		</div> 
 
-		<h3>[property:Matrix shadowMatrix]</h3>
+		<h3>[property:WebGLRenderTarget shadowMap]</h3>
 		<div>
-			??? <br />
-			Default — *null*.
-		</div>
+		    The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering.
+		</div> 
 		
 		<h2>Methods</h2>
 

+ 9 - 34
docs/api/lights/SpotLight.html

@@ -121,7 +121,7 @@ scene.add( spotLight );</code>
 		
 		<h3>[property:Float shadowBias]</h3>
 		<div>
-			Shadow map bias.<br />
+			Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.<br />
 			Default — *0*.
 		</div>
 
@@ -143,49 +143,24 @@ scene.add( spotLight );</code>
 			Default — *512*.
 		</div>
 		
-		<h3>[property:Float shadowBias]</h3>
-		<div>
-			Shadow map bias.<br />
-			Default — *0*.
-		</div>
-
-		<h3>[property:Float shadowDarkness]</h3>
-		<div>
-			Darkness of shadow casted by this light (from *0* to *1*).<br />
-			Default — *0.5*.
-		</div>
-
-		<h3>[property:Integer shadowMapWidth]</h3>
-		<div>
-			Shadow map texture width in pixels.<br />
-			Default — *512*.
-		</div>
-
-		<h3>[property:Integer shadowMapHeight]</h3>
-		<div>
-			Shadow map texture height in pixels.<br />
-			Default — *512*.
-		</div>
-
-
-		<h3>[property:object shadowMatrix]</h3>
+		<h3>[property:Vector2 shadowMapSize]</h3>
 		<div>
-		todo
+			The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering.
 		</div> 
 
-		<h3>[property:object shadowMapSize]</h3>
+		<h3>[property:PerspectiveCamera shadowCamera]</h3>
 		<div>
-		todo
+			The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings.
 		</div> 
 
-		<h3>[property:object shadowCamera]</h3>
+		<h3>[property:Matrix4 shadowMatrix]</h3>
 		<div>
-		todo
+			Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering.
 		</div> 
 
-		<h3>[property:object shadowMap]</h3>
+		<h3>[property:WebGLRenderTarget shadowMap]</h3>
 		<div>
-		todo
+		    The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering.
 		</div> 
 
 		<h2>Methods</h2>		

+ 2 - 3
docs/api/loaders/ColladaLoader.html

@@ -10,7 +10,7 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">A loader for loading an <em>.babylon</em> resource.</div>
+		<div class="desc">A loader for <em>Collada</em> files.</div>
 
 
 		<h2>Constructor</h2>
@@ -86,7 +86,6 @@
 		// instantiate a loader
 		var loader = new THREE.ColladaLoader();
 
-		// load a Babylon resource
 		loader.load(
 			// resource URL
 			'models/collada/monster/monster.dae',
@@ -109,6 +108,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js examples/js/loaders/BabylonLoader.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/ColladaLoader.js examples/js/loaders/ColladaLoader.js]
 	</body>
 </html>

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

@@ -29,7 +29,7 @@
 		specularMap — Set specular map. Default is null.<br />
 		alphaMap — Set alpha map. Default is null.<br />
 		envMap — Set env map. Default is null.<br />
-		fog — Define whether the material color is affected by global fog settings. Default is false.
+		fog — Define whether the material color is affected by global fog settings. Default is false.<br />
 		shading — How the triangles of a curved surface are rendered. Default is [page:Materials THREE.SmoothShading].<br/>
 		wireframe — Render geometry as wireframe. Default is false (i.e. render as smooth shaded).<br/>
 		wireframeLinewidth — Controls wireframe thickness. Default is 1.<br/>

+ 8 - 0
docs/api/math/Color.html

@@ -176,6 +176,14 @@
 		Linear interpolation of this colors rgb values and the rgb values of the first argument. The alpha argument can be thought of as the percent between the two colors, where 0 is this color and 1 is the first argument.
 		</div>
 
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Optional array to store the color.
+		</div>
+		<div>
+		Returns an array [r,g,b]
+		</div>
+
 		<h3>[method:Color equals]( [page:Color c] ) [page:Color this]</h3>
 		<div>
 		Compares this color and c and returns true if they are the same, false otherwise.

+ 141 - 138
docs/api/math/Euler.html

@@ -1,141 +1,144 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <script src="../../list.js"></script>
-    <script src="../../page.js"></script>
-    <link type="text/css" rel="stylesheet" href="../../page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
-
-    <div class="desc">Euler Angles. <br/><br/>
-    
-    Euler angles describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order.
-    (More information on <a href='http://en.wikipedia.org/wiki/Euler_angles' target='blank'>Wikipedia</a>)</div>
-
-    <h2>Example</h2>
-
-    <code>var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' );
-    var b = new THREE.Vector3( 1, 0, 1 );
-    b.applyEuler(a);
-    </code>
-
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:Float x], [page:Float y], [page:Float z], [page:String order] )</h3>
-    <div>
-    x -- [page:Float] the angle of the x axis in radians<br />
-    y -- [page:Float] the angle of the y axis in radians<br />
-    z -- [page:Float] the angle of the z axis in radians<br />
-    order -- [page:String] A string representing the order that the rotations are applied, defaults to 'XYZ' (must be upper case).
-    </div>
-    <div>
-    A euler angle for transforming
-    </div>
-
-
-    <h2>Properties</h2>
-
-    <h3>[property:Float x]</h3>
-
-    <h3>[property:Float y]</h3>
-
-    <h3>[property:Float z]</h3>
-
-    <h3>[property:String order]</h3>
-
-
-
-    <h2>Methods</h2>
-
-    <h3>[method:Euler set]( [page:Float x], [page:Float y], [page:Float z], [page:String order] ) [page:Euler this]</h3>
-    <div>
-    x -- [page:Float] Angle in x axis in radians<br />
-    y -- [page:Float] Angle in y axis in radians<br />
-    z -- [page:Float] Angle in z axis in radians<br />
-    order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
-    </div>
-    <div>
-    Sets the angles of this euler transform.
-    </div>
-
-    <h3>[method:Euler copy]( [page:Euler euler] ) [page:Euler this]</h3>
-    <div>
-    Copies value of *euler* to this euler.
-    </div>
-
-    <h3>[method:Euler setFromRotationMatrix]( [page:Matrix4 m], [page:String order] ) [page:Euler this]</h3>
-    <div>
-    m -- [page:Matrix4] assumes upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled)<br />
-    order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
-    </div>
-    <div>
-    Sets the angles of this euler transform from a pure rotation matrix based on the orientation specified by order.
-    </div>
-
-    <h3>[method:Euler setFromQuaternion]( [page:Quaternion q], [page:String order] ) [page:Euler this]</h3>
-    <div>
-    q -- [page:Quaternion] quaternion must be normalized<br />
-    order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
-    </div>
-    <div>
-    Sets the angles of this euler transform from a normalized quaternion based on the orientation specified by order.
-    </div>
-
-    <h3>[method:Euler reorder]( [page:String newOrder] ) [page:Euler this]</h3>
-    <div>
-    Resets the euler angle with a new order by creating a quaternion from this euler angle and then setting this euler angle with the quaternion and the new order. <br />
-    WARNING: this discards revolution information.
-    </div>
-
-    <h3>[method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]</h3>
-    <div>
-    vector -- [page:Vector3].
-    order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
-    </div>
-    <div>
-    Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property.
-    </div>
-
-    <h3>[method:Vector3 toVector3]()</h3>
-    <div>
-    Returns the Euler's XYZ properties as a Vector3.
-    </div>
-
-    <h3>[method:Euler fromArray]([page:Array array]) [page:Euler this]</h3>
-    <div>
-    array -- [page:Array] of length 3 or 4. array[3] is an optional order argument.
-    </div>
-    <div>
-    Assigns this euler's x angle to array[0]. <br />
-    Assigns this euler's y angle to array[1]. <br />
-    Assigns this euler's z angle to array[2]. <br />
-    Optionally assigns this euler's order to array[3].
-    </div>
-
-    <h3>[method:Array toArray]()</h3>
-    <div>
-    Returns an array [x, y, z, order].
-    </div>
-
-    <h3>[method:Boolean equals]( [page:Euler euler] )</h3>
-    <div>
-    Checks for strict equality of this euler and *euler*.
-    </div>
-
-    <h3>[method:Euler clone]()</h3>
-    <div>
-    Returns a new euler created from this euler.
-    </div>
-
-
-
-
-    <h2>Source</h2>
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+	<head>
+		<meta charset="utf-8" />
+		<script src="../../list.js"></script>
+		<script src="../../page.js"></script>
+		<link type="text/css" rel="stylesheet" href="../../page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">Euler Angles. <br/><br/>
+
+		Euler angles describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order.
+		(More information on <a href='http://en.wikipedia.org/wiki/Euler_angles' target='blank'>Wikipedia</a>)</div>
+
+		<h2>Example</h2>
+
+		<code>var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' );
+		var b = new THREE.Vector3( 1, 0, 1 );
+		b.applyEuler(a);
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:Float x], [page:Float y], [page:Float z], [page:String order] )</h3>
+		<div>
+		x -- [page:Float] the angle of the x axis in radians<br />
+		y -- [page:Float] the angle of the y axis in radians<br />
+		z -- [page:Float] the angle of the z axis in radians<br />
+		order -- [page:String] A string representing the order that the rotations are applied, defaults to 'XYZ' (must be upper case).
+		</div>
+		<div>
+		A euler angle for transforming
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>[property:Float x]</h3>
+
+		<h3>[property:Float y]</h3>
+
+		<h3>[property:Float z]</h3>
+
+		<h3>[property:String order]</h3>
+
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:Euler set]( [page:Float x], [page:Float y], [page:Float z], [page:String order] ) [page:Euler this]</h3>
+		<div>
+		x -- [page:Float] Angle in x axis in radians<br />
+		y -- [page:Float] Angle in y axis in radians<br />
+		z -- [page:Float] Angle in z axis in radians<br />
+		order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
+		</div>
+		<div>
+		Sets the angles of this euler transform.
+		</div>
+
+		<h3>[method:Euler copy]( [page:Euler euler] ) [page:Euler this]</h3>
+		<div>
+		Copies value of *euler* to this euler.
+		</div>
+
+		<h3>[method:Euler setFromRotationMatrix]( [page:Matrix4 m], [page:String order] ) [page:Euler this]</h3>
+		<div>
+		m -- [page:Matrix4] assumes upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled)<br />
+		order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
+		</div>
+		<div>
+		Sets the angles of this euler transform from a pure rotation matrix based on the orientation specified by order.
+		</div>
+
+		<h3>[method:Euler setFromQuaternion]( [page:Quaternion q], [page:String order] ) [page:Euler this]</h3>
+		<div>
+		q -- [page:Quaternion] quaternion must be normalized<br />
+		order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
+		</div>
+		<div>
+		Sets the angles of this euler transform from a normalized quaternion based on the orientation specified by order.
+		</div>
+
+		<h3>[method:Euler reorder]( [page:String newOrder] ) [page:Euler this]</h3>
+		<div>
+		Resets the euler angle with a new order by creating a quaternion from this euler angle and then setting this euler angle with the quaternion and the new order. <br />
+		WARNING: this discards revolution information.
+		</div>
+
+		<h3>[method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]</h3>
+		<div>
+		vector -- [page:Vector3].
+		order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
+		</div>
+		<div>
+		Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property.
+		</div>
+
+		<h3>[method:Vector3 toVector3]()</h3>
+		<div>
+		Returns the Euler's XYZ properties as a Vector3.
+		</div>
+
+		<h3>[method:Euler fromArray]([page:Array array]) [page:Euler this]</h3>
+		<div>
+		array -- [page:Array] of length 3 or 4. array[3] is an optional order argument.
+		</div>
+		<div>
+		Assigns this euler's x angle to array[0]. <br />
+		Assigns this euler's y angle to array[1]. <br />
+		Assigns this euler's z angle to array[2]. <br />
+		Optionally assigns this euler's order to array[3].
+		</div>
+
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Optional array to store the euler.
+		</div>
+		<div>
+		Returns an array [x, y, z, order]
+		</div>
+
+		<h3>[method:Boolean equals]( [page:Euler euler] )</h3>
+		<div>
+		Checks for strict equality of this euler and *euler*.
+		</div>
+
+		<h3>[method:Euler clone]()</h3>
+		<div>
+		Returns a new euler created from this euler.
+		</div>
+
+
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 8 - 5
docs/api/math/Quaternion.html

@@ -131,15 +131,18 @@
 		<h3>[method:Quaternion slerp]([page:Quaternion qb], [page:float t])</h3>
 		<div>
 		qb -- Target quaternion rotation.<br />
-		t -- Normalized [0..1] interpolation factor. 
+		t -- Normalized [0..1] interpolation factor.
 		</div>
 		<div>
 		Handles the spherical linear interpolation between this quaternion's configuration
-		and that of *qb*. *t* represents how close to the current (0) or target (1) rotation the 
-		result should be. 
+		and that of *qb*. *t* represents how close to the current (0) or target (1) rotation the
+		result should be.
 		</div>
 
-		<h3>.toArray() [page: Array]</h3>
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Array to store the quaternion.
+		</div>
 		<div>
 		Returns the numerical elements of this quaternion in an array of format (x, y, z, w).
 		</div>
@@ -155,7 +158,7 @@
 
 		<h3>[method:Float lengthSq]()</h3>
 		<div>
-		Calculates the squared length of the quaternion. 
+		Calculates the squared length of the quaternion.
 		</div>
 
 		<h3>[method:Quaternion fromArray]([page:Array array])</h3>

+ 14 - 1
docs/api/math/Vector2.html

@@ -181,6 +181,16 @@
 		Linear interpolation between this vector and v, where alpha is the percent along the line.
 		</div>
 
+		<h3>[method:Vector2 lerpVectors]([page:Vector2 v1], [page:Vector2 v2], [page:Float alpha]) [page:Vector2 this]</h3>
+		<div>
+		v1 -- [page:Vector2] <br />
+		v2 -- [page:Vector2] <br />
+		alpha -- [page:Float] between 0 and 1.
+		</div>
+		<div>
+		Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.
+		</div>
+
 		<h3>[method:undefined setComponent]([page:Integer index], [page:Float value])</h3>
 		<div>
 		index -- 0 or 1 <br />
@@ -216,7 +226,10 @@
 		Sets this vector's x value to be array[0] and y value to be array[1].
 		</div>
 
-		<h3>[method:Array toArray]()</h3>
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Optional array to store the vector.
+		</div>
 		<div>
 		Returns an array [x, y].
 		</div>

+ 14 - 1
docs/api/math/Vector3.html

@@ -342,6 +342,16 @@
 		Linear Interpolation between this vector and vector v, where alpha is the percent along the line.
 		</div>
 
+		<h3>[method:Vector3 lerpVectors]([page:Vector3 v1], [page:Vector3 v2], [page:Float alpha]) [page:Vector3 this]</h3>
+		<div>
+		v1 -- [page:Vector3] <br />
+		v2 -- [page:Vector3] <br />
+		alpha -- [page:Float] between 0 and 1.
+		</div>
+		<div>
+		Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.
+		</div>
+
 		<h3>[method:Float angleTo]([page:Vector3 v])</h3>
 		<div>
 		v -- [page:Vector3]
@@ -391,7 +401,10 @@
 		Multiplies this vector and m, and divides by perspective.
 		</div>
 
-		<h3>[method:Array toArray]()</h3>
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Optional array to store the vector.
+		</div>
 		<div>
 		Assigns this vector's x value to array[0]. <br />
 		Assigns this vector's y value to array[1]. <br />

+ 14 - 6
docs/api/math/Vector4.html

@@ -113,6 +113,11 @@
 		Linearly interpolate between this vector and *v* with *alpha* factor.
 		</div>
 
+		<h3>[method:Vector4 lerpVectors]( [page:Vector4 v1], [page:Vector4 v2], [page:Float alpha] ) [page:Vector4 this]</h3>
+		<div>
+		Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.
+		</div>
+
 		<h3>[method:Vector4 clone]()</h3>
 		<div>
 		Clones this vector.
@@ -181,7 +186,7 @@
 		v -- [page:Vector4]
 		</div>
 		<div>
-		If this vector's x, y, z, or w value is greater than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value. 
+		If this vector's x, y, z, or w value is greater than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value.
 		</div>
 
 		<h3>[method:Vector4 addScalar]([page:Float s]) [page:Vector4 this]</h3>
@@ -199,7 +204,7 @@
 		<div>
 		Checks to see if this vector matches vector v.
 		</div>
-		
+
 		<h3>[method:Vector4 setAxisAngleFromRotationMatrix]([page:Matrix4 m]) [page:Vector4 this]</h3>
 		<div>
 		m -- [page:Matrix4]
@@ -231,7 +236,7 @@
 		Index 1: y<br/>
 		Index 2: z<br/>
 		Index 3: w<br/>
- 
+
 		</div>
 
 		<h3>[method:null setComponent]([page:Integer index], [page:Float value])</h3>
@@ -241,13 +246,13 @@
 		</div>
 		<div>
 		Sets the value of the vector component	x, y, or z by an index.<br/><br/>
-		
+
 		Index 0: x<br/>
 		Index 1: y<br/>
 		Index 2: z<br/>
 		Index 3: w<br/>
 		</div>
-		
+
 		<h3>[method:Vector4 fromArray]([page:Array array]) [page:Vector4 this]</h3>
 		<div>
 		array -- [page:Array] An array formatted [x, y, z, w]
@@ -256,7 +261,10 @@
 		Sets the vector's components based on an array formatted like [x, y, z, w]
 		</div>
 
-		<h3>[method:Array toArray]()</h3>
+		<h3>[method:Array toArray]( [page:Array array] )</h3>
+		<div>
+		array -- Optional array to store the vector.
+		</div>
 		<div>
 		Returns an array in the format [x, y, z, w]
 		</div>

+ 5 - 0
docs/api/objects/Line.html

@@ -70,6 +70,11 @@
 
 		<h2>Methods</h2>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this Line. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 6 - 0
docs/api/objects/Mesh.html

@@ -60,6 +60,12 @@
 		Updates the morphtargets to have no influence on the object.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this mesh. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 5 - 0
docs/api/objects/PointCloud.html

@@ -42,6 +42,11 @@
 		This creates a clone of the particle system.
 		</div>
 
+		<h3>[method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])</h3>
+		<div>
+		Get intersections between a casted ray and this PointCloud. [page:Raycaster.intersectObject] will call this method.
+		</div>
+
 
 		<h2>Source</h2>
 

+ 1 - 1
docs/api/renderers/WebGLRenderTarget.html

@@ -69,7 +69,7 @@
 
 		<h3>[property:number type]</h3>
 		<div>
-		The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type.
+		The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.HalfFloatType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type.
 		</div>
 		
 		<h3>[property:boolean depthBuffer]</h3>

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

@@ -184,8 +184,8 @@
 
 		<code>// Creates a renderer with red background
 		var renderer = new THREE.WebGLRenderer();
-		renderer.setSize(200, 100);
-		renderer.setClearColor(0xff0000, 1);
+		renderer.setSize( 200, 100 );
+		renderer.setClearColor( 0xff0000 );
 		</code>
 
 		<h3>[method:Color getClearColor]()</h3>

+ 1 - 0
docs/list.js

@@ -219,6 +219,7 @@ var list = {
 			[ "ArrowHelper", "api/extras/helpers/ArrowHelper" ],
 			[ "AxisHelper", "api/extras/helpers/AxisHelper" ],
 			[ "BoundingBoxHelper", "api/extras/helpers/BoundingBoxHelper" ],
+			[ "BoxHelper", "api/extras/helpers/BoxHelper" ],
 			[ "CameraHelper", "api/extras/helpers/CameraHelper" ],
 			[ "DirectionalLightHelper", "api/extras/helpers/DirectionalLightHelper" ],
 			[ "EdgesHelper", "api/extras/helpers/EdgesHelper" ],

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

@@ -3,60 +3,60 @@
  */
 
 var constants = {
-	
+
 	combine: {
-		
+
 		"THREE.MultiplyOperation" : THREE.MultiplyOperation,
 		"THREE.MixOperation" : THREE.MixOperation,
 		"THREE.AddOperation" : THREE.AddOperation
-		
+
 	},
-	
+
 	side : {
-		
+
 		"THREE.FrontSide" : THREE.FrontSide,
 		"THREE.BackSide" : THREE.BackSide,
 		"THREE.DoubleSide" : THREE.DoubleSide
-		
+
 	},
-	
+
 	shading : {
-		
+
 		"THREE.NoShading" : THREE.NoShading,
 		"THREE.FlatShading" : THREE.FlatShading,
 		"THREE.SmoothShading" : THREE.SmoothShading
-		
+
 	},
 
 	colors : {
-		
+
 		"THREE.NoColors" : THREE.NoColors,
 		"THREE.FaceColors" : THREE.FaceColors,
 		"THREE.VertexColors" : THREE.VertexColors
-		
+
 	},
-	
+
 	blendingMode : {
-		
+
 		"THREE.NoBlending" : THREE.NoBlending,
 		"THREE.NormalBlending" : THREE.NormalBlending,
 		"THREE.AdditiveBlending" : THREE.AdditiveBlending,
 		"THREE.SubtractiveBlending" : THREE.SubtractiveBlending,
 		"THREE.MultiplyBlending" : THREE.MultiplyBlending,
 		"THREE.CustomBlending" : THREE.CustomBlending
-		
+
 	},
-	
+
 	equations : {
-		
+
 		"THREE.AddEquation" : THREE.AddEquation,
 		"THREE.SubtractEquation" : THREE.SubtractEquation,
 		"THREE.ReverseSubtractEquation" : THREE.ReverseSubtractEquation
-		
+
 	},
-	
+
 	destinationFactors : {
-		
+
 		"THREE.ZeroFactor" : THREE.ZeroFactor,
 		"THREE.OneFactor" : THREE.OneFactor,
 		"THREE.SrcColorFactor" : THREE.SrcColorFactor,
@@ -65,38 +65,38 @@ var constants = {
 		"THREE.OneMinusSrcAlphaFactor" : THREE.OneMinusSrcAlphaFactor,
 		"THREE.DstAlphaFactor" : THREE.DstAlphaFactor,
 		"THREE.OneMinusDstAlphaFactor" : THREE.OneMinusDstAlphaFactor
-		
+
 	},
-	
+
 	sourceFactors : {
-		
+
 		"THREE.DstColorFactor" : THREE.DstColorFactor,
 		"THREE.OneMinusDstColorFactor" : THREE.OneMinusDstColorFactor,
 		"THREE.SrcAlphaSaturateFactor" : THREE.SrcAlphaSaturateFactor
-		
+
 	}
-	
+
 }
 
 function getObjectsKeys( obj ) {
-	
+
 	var keys = [];
-	
+
 	for ( var key in obj ) {
-		
+
 		if ( obj.hasOwnProperty( key ) ) {
-			
+
 			keys.push( key );
-			
+
 		}
-		
+
 	}
-	
+
 	return keys;
 }
 
 var envMaps = (function () {
-	
+
 	var path = "../../examples/textures/cube/SwedishRoyalCastle/";
 	var format = '.jpg';
 	var urls = [
@@ -111,32 +111,32 @@ var envMaps = (function () {
 
 	var refractionCube = new THREE.Texture( reflectionCube.image, THREE.CubeRefractionMapping );
 	reflectionCube.format = THREE.RGBFormat;
-	
+
 	return {
 		none : null,
 		reflection : reflectionCube,
 		refraction : refractionCube
 	};
-	
+
 })();
 
 var envMapKeys = getObjectsKeys( envMaps );
 
 var textureMaps = (function () {
-	
+
 	return {
 		none : null,
 		grass : THREE.ImageUtils.loadTexture( "../../examples/textures/terrain/grasslight-thin.jpg" )
 	};
-	
+
 })();
 
 var textureMapKeys = getObjectsKeys( textureMaps );
 
 function generateVertexColors ( geometry ) {
-	
+
 	for ( var i=0, il = geometry.faces.length; i < il; i++ ) {
-				
+
 		geometry.faces[i].vertexColors.push( new THREE.Color().setHSL(
 			i / il * Math.random(),
 			0.5,
@@ -152,15 +152,15 @@ function generateVertexColors ( geometry ) {
 			0.5,
 			0.5
 		) );
-		
+
 		geometry.faces[i].color = new THREE.Color().setHSL(
 			i / il * Math.random(),
 			0.5,
 			0.5
 		);
-		
+
 	}
-	
+
 }
 
 function generateMorphTargets ( mesh, geometry ) {
@@ -172,7 +172,7 @@ function generateMorphTargets ( mesh, geometry ) {
 		vertices.push( geometry.vertices[ i ].clone() );
 
 		scale = 1 + Math.random() * 0.3;
-		
+
 		vertices[ vertices.length - 1 ].x *= scale;
 		vertices[ vertices.length - 1 ].y *= scale;
 		vertices[ vertices.length - 1 ].z *= scale;
@@ -180,31 +180,31 @@ function generateMorphTargets ( mesh, geometry ) {
 	}
 
 	geometry.morphTargets.push( { name: "target1", vertices: vertices } );
-	
+
 	geometry.update
 
 }
 
 function handleColorChange ( color ) {
-	
+
 	return function ( value ){
-		
+
 		if (typeof value === "string") {
-			
+
 			value = value.replace('#', '0x');
-			
+
 		}
-		
+
 		color.setHex( value );
-		
+
     };
-	
+
 }
 
 function needsUpdate ( material, geometry ) {
-	
+
 	return function () {
-		
+
 		material.shading = +material.shading; //Ensure number
 		material.vertexColors = +material.vertexColors; //Ensure number
 		material.side = +material.side; //Ensure number
@@ -212,63 +212,63 @@ function needsUpdate ( material, geometry ) {
 		geometry.verticesNeedUpdate = true;
 		geometry.normalsNeedUpdate = true;
 		geometry.colorsNeedUpdate = true;
-		
+
 	};
-	
+
 };
 
 function updateMorphs ( torus, material ) {
 
 	return function () {
-		
+
 		torus.updateMorphTargets();
 		material.needsUpdate = true;
-		
+
 	};
-	
+
 }
 
 function updateTexture ( material, materialKey, textures ) {
 
 	return function ( key ) {
-		
+
 		material[materialKey] = textures[key];
 		material.needsUpdate = true;
-		
+
 	};
-	
+
 }
 
 function guiScene ( gui, scene ) {
-	
+
 	var folder = gui.addFolder('Scene');
-	
+
 	var data = {
 		background : "#000000",
 		"ambient light" : ambientLight.color.getHex()
 	}
-	
+
 	var color = new THREE.Color();
 	var colorConvert = handleColorChange( color );
-	
+
 	folder.addColor( data, "background" ).onChange( function ( value ) {
-		
+
 		colorConvert( value );
-		
-		renderer.setClearColor(color.getHex(), 1);
-		
+
+		renderer.setClearColor( color.getHex() );
+
 	} );
-	
+
 	folder.addColor( data, "ambient light" ).onChange( handleColorChange( ambientLight.color ) )
-	
+
 	guiSceneFog( folder, scene );
-	
+
 }
 
 function guiSceneFog ( folder, scene ) {
-	
+
 	var fogFolder = folder.addFolder('scene.fog');
-	
+
 	var fog = new THREE.Fog( 0x3f7b9d, 0, 60 );
 
 	var data = {
@@ -277,29 +277,29 @@ function guiSceneFog ( folder, scene ) {
 			"scene.fog.color" : fog.color.getHex()
 		}
 	};
-	
+
 	fogFolder.add( data.fog, 'THREE.Fog()' ).onChange( function ( useFog ) {
-		
+
 		if ( useFog ) {
-			
+
 			scene.fog = fog;
-			
+
 		} else {
-			
+
 			scene.fog = null;
-			
+
 		}
-		
+
 	} );
-	
+
 	fogFolder.addColor( data.fog, 'scene.fog.color').onChange( handleColorChange( fog.color ) );
-	
+
 }
 
 function guiMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.Material');
-	
+
 	folder.add( material, 'transparent' );
 	folder.add( material, 'opacity', 0, 1 );
 	// folder.add( material, 'blending', constants.blendingMode );
@@ -315,11 +315,11 @@ function guiMaterial ( gui, mesh, material, geometry ) {
 	// folder.add( material, 'overdraw', 0, 5 );
 	folder.add( material, 'visible' );
 	folder.add( material, 'side', constants.side ).onChange( needsUpdate( material, geometry ) );
-	
+
 }
 
 function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		envMaps : envMapKeys,
@@ -328,7 +328,7 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-		
+
 	var folder = gui.addFolder('THREE.MeshBasicMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -337,7 +337,7 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'shading', constants.shading);
 	folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'fog' );
-	
+
 	folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
 	folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) );
 	folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) );
@@ -348,36 +348,36 @@ function guiMeshBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'reflectivity', 0, 1 );
 	folder.add( material, 'refractionRatio', 0, 1 );
 	//folder.add( material, 'skinning' );
-	
+
 }
 
 function guiMeshDepthMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.MeshDepthMaterial');
-		
+
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
 	folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) );
-	
+
 }
 
 function guiMeshNormalMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var folder = gui.addFolder('THREE.MeshNormalMaterial');
-	
+
 	folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
 	folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) );
-	
+
 }
 
 function guiLineBasicMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex()
 	};
-		
+
 	var folder = gui.addFolder('THREE.LineBasicMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -386,11 +386,11 @@ function guiLineBasicMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'linejoin', ["round", "bevel", "miter"] );
 	folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'fog' );
-	
+
 }
 
 function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		ambient : material.ambient.getHex(),
@@ -401,15 +401,15 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-	
+
 	var envObj = {};
-			
+
 	var folder = gui.addFolder('THREE.MeshLambertMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
 	folder.addColor( data, 'ambient' ).onChange( handleColorChange( material.ambient ) );
 	folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
-	
+
 	folder.add( material, 'shading', constants.shading ).onChange( needsUpdate( material, geometry ) );
 	folder.add( material, 'wireframe' );
 	folder.add( material, 'wireframeLinewidth', 0, 10 );
@@ -426,11 +426,11 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) {
 	folder.add( material, 'reflectivity', 0, 1 );
 	folder.add( material, 'refractionRatio', 0, 1 );
 	//folder.add( material, 'skinning' );
-	
+
 }
 
 function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
-	
+
 	var data = {
 		color : material.color.getHex(),
 		ambient : material.ambient.getHex(),
@@ -442,7 +442,7 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 		specularMap : textureMapKeys,
 		alphaMap : textureMapKeys
 	};
-		
+
 	var folder = gui.addFolder('THREE.MeshPhongMaterial');
 
 	folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
@@ -461,16 +461,16 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) {
 	folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) );
 	folder.add( data, 'specularMap', textureMapKeys ).onChange( updateTexture( material, 'specularMap', textureMaps ) );
 	folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) );
-	
+
 }
 
 function chooseFromHash ( gui, mesh, geometry ) {
 
 	var selectedMaterial = window.location.hash.substring(1) || "MeshBasicMaterial";
 	var material;
-	
+
 	switch (selectedMaterial) {
-		
+
 	case "MeshBasicMaterial" :
 
 		material = new THREE.MeshBasicMaterial({color: 0x2194CE});
@@ -480,7 +480,7 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshLambertMaterial" :
 
 		material = new THREE.MeshLambertMaterial({color: 0x2194CE});
@@ -490,7 +490,7 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshPhongMaterial" :
 
 		material = new THREE.MeshPhongMaterial({color: 0x2194CE});
@@ -500,27 +500,27 @@ function chooseFromHash ( gui, mesh, geometry ) {
 		return material;
 
 		break;
-	
+
 	case "MeshDepthMaterial" :
-		
+
 		material = new THREE.MeshDepthMaterial({color: 0x2194CE});
 		guiMaterial( gui, mesh, material, geometry );
 		guiMeshDepthMaterial( gui, mesh, material, geometry );
 
 		return material;
-		
+
 		break;
-	
+
 	case "MeshNormalMaterial" :
-		
+
 		material = new THREE.MeshNormalMaterial();
 		guiMaterial( gui, mesh, material, geometry );
 		guiMeshNormalMaterial( gui, mesh, material, geometry );
 
 		return material;
-		
+
 		break;
-		
+
 	case "LineBasicMaterial" :
 
 		material = new THREE.LineBasicMaterial({color: 0x2194CE});
@@ -531,5 +531,5 @@ function chooseFromHash ( gui, mesh, geometry ) {
 
 		break;
 	}
-	
+
 }

+ 39 - 17
editor/css/dark.css

@@ -1,23 +1,34 @@
-.FancySelect {
+.Outliner {
+	color: #868686;
 	background: #222;
-	border: 1px solid #3C3C3C;
 	padding: 0;
+	width: 100%;
+	height: 140px;
+	font-size: 12px;
 	cursor: default;
 	overflow: auto;
 	outline: none;
 }
 
-	.FancySelect .option {
+	.Outliner .option {
 		padding: 4px;
 		white-space: nowrap;
 	}
 
-	.FancySelect .option.active {
+	.Outliner .option.active {
 		background-color: #153C5E;
 	}
 
+.Panel.Collapsible.collapsed .Static .Button {
+	border-left-color: #444;
+}
+
+.Panel.Collapsible:not(.collapsed) .Static .Button {
+	border-top-color: #444;
+}
+
 input.Number {
-	color: #2A75B7;
+	color: #2A75B7!important;
 	font-size: 12px;							/** TODO: Use of !imporant is not ideal **/
 	background-color: transparent!important;	/* For now this is a quick fix a rendering issue due to inherited background */
 	border: 1px solid transparent;
@@ -37,6 +48,15 @@ input.Number {
 		text-shadow: 1px 1px 0px rgba(0,0,0,0.25);
 	}
 
+#script {
+	position: absolute;
+	top: 32px;
+	left: 0px;
+	right: 300px;
+	bottom: 32px;
+	opacity: 0.9;
+}
+
 #player {
 	position: absolute;
 	top: 32px;
@@ -80,7 +100,7 @@ input.Number {
 			display: none;
 			padding: 5px 0px;
 			background: #111;
-			width: 140px;
+			width: 150px;
 		}
 
 		#menubar .menu:hover .options {
@@ -88,11 +108,11 @@ input.Number {
 		}
 
 			#menubar .menu .options hr {
-				border-color: #444;
+				border-color: #333;
 			}
 
 			#menubar .menu .options .option {
-				color: #666;
+				color: #888;
 				background-color: transparent;
 				padding: 5px 10px;
 				margin: 0px !important;
@@ -104,7 +124,6 @@ input.Number {
 				}
 
 				#menubar .menu .options .option:active {
-					color: #666;
 					background: transparent;
 				}
 
@@ -118,10 +137,16 @@ input.Number {
 	overflow: auto;
 }
 
+	#sidebar * {
+		vertical-align: middle;
+	}
+
 	#sidebar input,
 	#sidebar textarea,
 	#sidebar select {
-		background: #ccc;
+		background: #222;
+		border: 1px solid transparent;
+		color: #888;
 	}
 
 	#sidebar .Panel {
@@ -138,13 +163,6 @@ input.Number {
 		border-top: 1px solid #333;
 	}
 
-	#sidebar #outliner {
-		width: 100%;
-		height: 140px;
-		color: #868686;
-		font-size: 12px;
-	}
-
 	#sidebar .Panel.Material canvas {
 
 		border: solid 1px #5A5A5A;
@@ -161,6 +179,10 @@ input.Number {
 	color: #333;
 }
 
+	#toolbar * {
+		vertical-align: middle;
+	}
+
 	#toolbar .Panel {
 		padding: 4px;
 		color: #888;

+ 28 - 14
editor/css/light.css

@@ -1,24 +1,27 @@
-.FancySelect {
+.Outliner {
+	color: #444;
 	background: #fff;
-	border: 1px solid #ccc;
 	padding: 0;
+	width: 100%;
+	height: 140px;
+	font-size: 12px;
 	cursor: default;
 	overflow: auto;
 	outline: none;
 }
 
-	.FancySelect .option {
+	.Outliner .option {
 		padding: 4px;
 		color: #666;
 		white-space: nowrap;
 	}
 
-	.FancySelect .option.active {
+	.Outliner .option.active {
 		background-color: #f8f8f8;
 	}
 
 input.Number {
-	color: #0080f0;
+	color: #0080f0!important;
 	font-size: 12px;							/** TODO: Use of !imporant is not ideal **/
 	background-color: transparent!important;	/* For now this is a quick fix a rendering issue due to inherited background */
 	border: 1px solid transparent;
@@ -38,6 +41,15 @@ input.Number {
 		text-shadow: 1px 1px 0px rgba(0,0,0,0.25);
 	}
 
+#script {
+	position: absolute;
+	top: 32px;
+	left: 0px;
+	right: 300px;
+	bottom: 32px;
+	opacity: 0.9;
+}
+
 #player {
 	position: absolute;
 	top: 32px;
@@ -81,7 +93,7 @@ input.Number {
 			display: none;
 			padding: 5px 0px;
 			background: #eee;
-			width: 140px;
+			width: 150px;
 		}
 
 		#menubar .menu:hover .options {
@@ -119,10 +131,15 @@ input.Number {
 	overflow: auto;
 }
 
+	#sidebar * {
+		vertical-align: middle;
+	}
+
 	#sidebar input,
 	#sidebar textarea,
 	#sidebar select {
-		/* background: #ccc; */
+		border: 1px solid transparent;
+		color: #444;
 	}
 
 	#sidebar .Panel {
@@ -139,13 +156,6 @@ input.Number {
 		border-top: 1px solid #ccc;
 	}
 
-	#sidebar #outliner {
-		width: 100%;
-		height: 140px;
-		color: #444;
-		font-size: 12px;
-	}
-
 #toolbar {
 	position: absolute;
 	left: 0px;
@@ -156,6 +166,10 @@ input.Number {
 	color: #333;
 }
 
+	#toolbar * {
+		vertical-align: middle;
+	}
+
 	#toolbar .Panel {
 		padding: 4px;
 		color: #888;

+ 12 - 6
editor/css/main.css

@@ -1,7 +1,3 @@
-* {
-	vertical-align: middle;
-}
-
 body {
 	font-family: Helvetica, Arial, sans-serif;
 	font-size: 14px;
@@ -19,6 +15,7 @@ button {
 }
 
 textarea {
+	tab-size: 4;
 	white-space: pre;
 	word-wrap: normal;
 }
@@ -70,6 +67,15 @@ textarea, input { outline: none; } /* osx */
 		display: none;
 	}
 
+.CodeMirror {
+
+	position: absolute !important;
+	top: 37px;
+	width: 100% !important;
+	height: calc(100% - 37px) !important;
+
+}
+
 /* scene types */
 
 .type {
@@ -110,7 +116,7 @@ textarea, input { outline: none; } /* osx */
 	color: #bbeebb;
 }
 .TorusGeometry {
-	color: #aaeeaa;	
+	color: #aaeeaa;
 }
 
 /* */
@@ -121,4 +127,4 @@ textarea, input { outline: none; } /* osx */
 
 .MeshPhongMaterial {
 	color: #ffaa88;
-}
+}

+ 167 - 0
editor/examples/arkanoid.app.json

@@ -0,0 +1,167 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "A32F9E56-4DDC-442E-8A0D-F23B9E93EEA9",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.536388140161725,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.9392361044883728,-1.2050817232989175e-8,-0.34327182173728943,0,-0.15080472826957703,0.8983326554298401,-0.41262128949165344,0,0.30837228894233704,0.4393158257007599,0.8437464833259583,0,142.32125854492188,202.75485229492188,389.40936279296875,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A",
+				"type": "PlaneGeometry",
+				"width": 300,
+				"height": 400,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "7149652B-DBD7-4CB7-A600-27A9AC005C95",
+				"type": "BoxGeometry",
+				"width": 20,
+				"height": 10,
+				"depth": 10,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			},
+			{
+				"uuid": "CABCC711-1331-4D4C-9FF6-409299F10C68",
+				"type": "SphereGeometry",
+				"radius": 5,
+				"widthSegments": 32,
+				"heightSegments": 16,
+				"phiStart": 0,
+				"phiLength": 6.28,
+				"thetaStart": 0,
+				"thetaLength": 3.14
+			},
+			{
+				"uuid": "A1D8B049-74DD-4B08-B5BC-8DCEC9AF0222",
+				"type": "BoxGeometry",
+				"width": 40,
+				"height": 10,
+				"depth": 10,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			}],
+		"materials": [
+			{
+				"uuid": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF",
+				"type": "MeshPhongMaterial",
+				"color": 86015,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "CFBEAD4C-6695-4A99-887B-8161E2947225",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "043B208C-1F83-42C6-802C-E0E35621C27C",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB",
+				"type": "MeshPhongMaterial",
+				"color": 13486790,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			}],
+		"object": {
+			"uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "EBBB1E63-6318-4752-AE2E-440A4E0B3EF3",
+					"type": "Mesh",
+					"name": "Ground",
+					"geometry": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A",
+					"material": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF",
+					"matrix": [1,0,0,0,0,0.0007962886593304574,-0.9999997019767761,0,0,0.9999997019767761,0.0007962886593304574,0,0,0,0,1]
+				},
+				{
+					"uuid": "6EE2E764-43E0-48E0-85F2-E0C8823C20DC",
+					"type": "DirectionalLight",
+					"name": "DirectionalLight 1",
+					"color": 16777215,
+					"intensity": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1]
+				},
+				{
+					"uuid": "38219749-1E67-45F2-AB15-E64BA0940CAD",
+					"type": "Mesh",
+					"name": "Brick",
+					"geometry": "7149652B-DBD7-4CB7-A600-27A9AC005C95",
+					"material": "CFBEAD4C-6695-4A99-887B-8161E2947225",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,0,1]
+				},
+				{
+					"uuid": "18FFA67C-F893-4E7A-8A76-8D996DEBE0C6",
+					"type": "Mesh",
+					"name": "Ball",
+					"geometry": "CABCC711-1331-4D4C-9FF6-409299F10C68",
+					"material": "043B208C-1F83-42C6-802C-E0E35621C27C",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,35.54999923706055,1]
+				},
+				{
+					"uuid": "6D660D49-39B8-40C3-95F6-E4E007AA8D79",
+					"type": "Mesh",
+					"name": "Paddle",
+					"geometry": "A1D8B049-74DD-4B08-B5BC-8DCEC9AF0222",
+					"material": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,159.54217529296875,1]
+				},
+				{
+					"uuid": "B0BEAF69-8B5D-4D87-ADCA-FDE83A02762D",
+					"type": "PointLight",
+					"name": "PointLight 2",
+					"color": 16777215,
+					"intensity": 1,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-116.54356384277344,69.48957061767578,-206.8248291015625,1]
+				}]
+		}
+	},
+	"scripts": {
+		"6D660D49-39B8-40C3-95F6-E4E007AA8D79": [
+			{
+				"name": "User",
+				"source": "function mousemove( event ) {\n\n\tthis.position.x = ( event.clientX / player.width ) * 300 - 150;\n\n}\n\n// function update( event ) {}"
+			}],
+		"31517222-A9A7-4EAF-B5F6-60751C0BABA3": [
+			{
+				"name": "Game Logic",
+				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.material = material;\n\t\tobject.position.x = i * 22 - 120;\n\t\tobject.position.z = j * 14 - 120;\n\t\tgroup.add( object );\n\t\t\n\t}\n\t\n}\n\nbrick.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 150 || ball.position.x > 150 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 200 || ball.position.z > 200 ) direction.z = - direction.z;\n\n\tball.position.add( speed.copy( direction ).multiplyScalar( 4 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}"
+			}]
+	}
+}

+ 168 - 0
editor/examples/camera.app.json

@@ -0,0 +1,168 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "F0D8434F-4603-415B-8024-792FE97B9600",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.2252042007001167,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.9700406789779663,-5.500052080442686e-10,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.19256223738193512,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,159.0158233642578,132.5708465576172,634.9312744140625,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
+				"type": "BoxGeometry",
+				"width": 100,
+				"height": 100,
+				"depth": 100,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			},
+			{
+				"uuid": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
+				"type": "CylinderGeometry",
+				"radiusTop": 0,
+				"radiusBottom": 40,
+				"height": 75,
+				"radialSegments": 4,
+				"heightSegments": 1,
+				"openEnded": false
+			},
+			{
+				"uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
+				"type": "PlaneGeometry",
+				"width": 1000,
+				"height": 1000,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
+				"type": "IcosahedronGeometry",
+				"radius": 40,
+				"detail": 2
+			}],
+		"materials": [
+			{
+				"uuid": "B5943856-E404-45D9-A427-4774202C2CD0",
+				"type": "MeshPhongMaterial",
+				"color": 37119,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E",
+				"type": "MeshPhongMaterial",
+				"color": 15859456,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "4AE8130E-B6A8-47BC-ACCF-060973C74044",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "E1826901-7922-4584-A25D-6D487E2C9BBD",
+				"type": "MeshPhongMaterial",
+				"color": 16711680,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			}],
+		"object": {
+			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE",
+					"type": "PerspectiveCamera",
+					"name": "PerspectiveCamera 1",
+					"fov": 50,
+					"aspect": 1,
+					"near": 100,
+					"far": 10000,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1]
+				},
+				{
+					"uuid": "26DAAD69-725D-43B7-AF9D-990A99DEF8C5",
+					"type": "Mesh",
+					"name": "Box 1",
+					"geometry": "D8E200D3-27BC-49F8-A5C5-7384206E70FE",
+					"material": "B5943856-E404-45D9-A427-4774202C2CD0",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "AAAFF2D6-4725-4AFC-A9FE-26419B11011F",
+					"type": "Mesh",
+					"name": "Cylinder 3",
+					"geometry": "25BA32DB-8B02-4ABA-A77C-69868C464A1A",
+					"material": "3F872310-2067-4BE4-9250-5B3F4E43797E",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-130,-15,0,1]
+				},
+				{
+					"uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED",
+					"type": "Mesh",
+					"name": "Plane 4",
+					"geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5",
+					"material": "4AE8130E-B6A8-47BC-ACCF-060973C74044",
+					"matrix": [1,0,0,0,0,0.040785059332847595,-0.9991679191589355,0,0,0.9991679191589355,0.040785059332847595,0,0,-50,0,1]
+				},
+				{
+					"uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6",
+					"type": "PointLight",
+					"name": "PointLight 2",
+					"color": 12773063,
+					"intensity": 1,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1]
+				},
+				{
+					"uuid": "E2939A7B-5E40-438A-8C1B-32126FBC6892",
+					"type": "PointLight",
+					"name": "PointLight 1",
+					"color": 9474221,
+					"intensity": 0.75,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-93.86000061035156,127.12999725341797,-114.30000305175781,1]
+				},
+				{
+					"uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA",
+					"type": "Mesh",
+					"name": "Icosahedron 1",
+					"geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA",
+					"material": "E1826901-7922-4584-A25D-6D487E2C9BBD",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1]
+				}]
+		}
+	},
+	"scripts": {
+		"60B69C58-4201-43FD-815E-AD2EDFBBD0CE": [
+			{
+				"name": "Camera Orbit",
+				"source": "player.setCamera( this );\n\nfunction update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}"
+			}]
+	}
+}

+ 97 - 0
editor/examples/particles.app.json

@@ -0,0 +1,97 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "D722B468-8D40-4CAB-82D6-944D2D5A8D35",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.2237762237762237,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.7071067690849304,-2.468905080377226e-9,-0.7071068286895752,0,-0.2357022613286972,0.9428090453147888,-0.235702246427536,0,0.6666666865348816,0.3333333134651184,0.6666666269302368,0,500,250,500,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "5009F17C-E9D3-4D0E-82A6-2E23159128FB",
+				"type": "PlaneGeometry",
+				"width": 600,
+				"height": 600,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "8693E7B2-0009-4C4C-94C5-8E031557AEC2",
+				"type": "BoxGeometry",
+				"width": 4,
+				"height": 4,
+				"depth": 4,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			}],
+		"materials": [
+			{
+				"uuid": "6EDB0369-7E11-4B0F-BF98-4BD761846D65",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "F5361474-F5F1-412F-8D99-3699B868092D",
+				"type": "SpriteMaterial",
+				"color": 16777215
+			}],
+		"object": {
+			"uuid": "3741222A-BD8F-401C-A5D2-5A907E891896",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "05B57416-1BE5-4A96-BB05-9D9CD112D52B",
+					"type": "Mesh",
+					"name": "Ground",
+					"geometry": "5009F17C-E9D3-4D0E-82A6-2E23159128FB",
+					"material": "6EDB0369-7E11-4B0F-BF98-4BD761846D65",
+					"matrix": [1,0,0,0,0,0.0007962886593304574,-0.9999997019767761,0,0,0.9999997019767761,0.0007962886593304574,0,0,-2,0,1]
+				},
+				{
+					"uuid": "0A3CB873-07E6-4EEB-830B-68192504111B",
+					"type": "Sprite",
+					"name": "Particle",
+					"material": "F5361474-F5F1-412F-8D99-3699B868092D",
+					"matrix": [3,0,0,0,0,3,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "40E5CDA4-0E39-4265-9293-3E9EC3207F61",
+					"type": "PointLight",
+					"name": "PointLight",
+					"color": 16777215,
+					"intensity": 10,
+					"distance": 0,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				}]
+		}
+	},
+	"scripts": {
+		"3741222A-BD8F-401C-A5D2-5A907E891896": [
+			{
+				"name": "Particle Fountain",
+				"source": "var original = this.getObjectByName( 'Particle' );\n\nvar particles = [];\n\nfunction update( event ) {\n\n\tif ( particles.length < 200 ) {\n\n\t\tvar velocity = new THREE.Vector3();\n\t\tvelocity.x = Math.random() * 10 - 5;\n\t\tvelocity.y = Math.random() * 10 + 10;\n\t\tvelocity.z = Math.random() * 10 - 5;\n\n\t\tvar particle = original.clone();\n\t\tparticle.userData.velocity = velocity;\n\t\tparticles.push( particle );\n\n\t\tthis.add( particle );\n\n\t}\n\n\tfor ( var i = 0; i < particles.length; i ++ ) {\n\n\t\tvar particle = particles[ i ];\n\n\t\tvar velocity = particle.userData.velocity;\n\n\t\tvelocity.y -= 0.98;\n\n\t\tparticle.position.add( velocity );\n\n\t\tif ( particle.position.y < 0 ) {\n\n\t\t\tparticle.position.y = 0;\n\n\t\t\tvelocity.y = - velocity.y;\n\t\t\tvelocity.multiplyScalar( 0.6 );\n\n\t\t}\n\n\t}\n\n}"
+			}]
+	}
+}

+ 134 - 0
editor/examples/pong.app.json

@@ -0,0 +1,134 @@
+{
+	"camera": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"object": {
+			"uuid": "E5C76691-3D55-4E26-862E-24BADC21F4D7",
+			"type": "PerspectiveCamera",
+			"name": "Camera",
+			"fov": 50,
+			"aspect": 1.3291139240506329,
+			"near": 0.1,
+			"far": 100000,
+			"matrix": [0.9522120356559753,4.209433246415983e-9,-0.3054378032684326,0,-0.17742955684661865,0.8139731884002686,-0.553142249584198,0,0.24861818552017212,0.5809023976325989,0.7750750780105591,0,186.46363830566406,435.67681884765625,581.3063354492188,1]
+		}
+	},
+	"scene": {
+		"metadata": {
+			"version": 4.3,
+			"type": "Object",
+			"generator": "ObjectExporter"
+		},
+		"geometries": [
+			{
+				"uuid": "77B20ED1-2871-4B14-A652-8F823B2A817E",
+				"type": "PlaneGeometry",
+				"width": 600,
+				"height": 400,
+				"widthSegments": 1,
+				"heightSegments": 1
+			},
+			{
+				"uuid": "7ADE0D01-A56A-4D33-869A-6C360E096EF7",
+				"type": "BoxGeometry",
+				"width": 10,
+				"height": 10,
+				"depth": 10,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			},
+			{
+				"uuid": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+				"type": "BoxGeometry",
+				"width": 20,
+				"height": 20,
+				"depth": 100,
+				"widthSegments": 1,
+				"heightSegments": 1,
+				"depthSegments": 1
+			}],
+		"materials": [
+			{
+				"uuid": "7EDF7C08-6325-418A-BBAB-89341C694730",
+				"type": "MeshPhongMaterial",
+				"color": 16777215,
+				"emissive": 0,
+				"specular": 16777215,
+				"shininess": 30
+			},
+			{
+				"uuid": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC",
+				"type": "MeshPhongMaterial",
+				"color": 16711680,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			},
+			{
+				"uuid": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+				"type": "MeshPhongMaterial",
+				"color": 2752767,
+				"emissive": 0,
+				"specular": 1118481,
+				"shininess": 30
+			}],
+		"object": {
+			"uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3",
+			"type": "Scene",
+			"name": "Scene",
+			"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
+			"children": [
+				{
+					"uuid": "B47D0BFC-D63A-4CBB-985E-9C4DBDF086E4",
+					"type": "Mesh",
+					"name": "Ground",
+					"geometry": "77B20ED1-2871-4B14-A652-8F823B2A817E",
+					"material": "7EDF7C08-6325-418A-BBAB-89341C694730",
+					"matrix": [1,0,0,0,0,0.0007961748051457107,-0.9999997019767761,0,0,0.9999997019767761,0.0007961748051457107,0,0,-10,0,1]
+				},
+				{
+					"uuid": "CE13E58A-4E8B-4F72-9E2E-7DE57C58F989",
+					"type": "Mesh",
+					"name": "Ball",
+					"geometry": "7ADE0D01-A56A-4D33-869A-6C360E096EF7",
+					"material": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+				},
+				{
+					"uuid": "2AAEA3AA-EC45-492B-B450-10473D1EC6C5",
+					"type": "Mesh",
+					"name": "Pad 1",
+					"geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-240,0,0,1]
+				},
+				{
+					"uuid": "F1DD46A7-6584-4A37-BC76-852C3911077E",
+					"type": "Mesh",
+					"name": "Pad 2",
+					"geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C",
+					"material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46",
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,240,0,0,1]
+				},
+				{
+					"uuid": "C62AAE9F-9E51-46A5-BD2B-71BA804FC0B3",
+					"type": "DirectionalLight",
+					"name": "DirectionalLight 3",
+					"color": 16777215,
+					"intensity": 1,
+					"matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1]
+				}]
+		}
+	},
+	"scripts": {
+		"31517222-A9A7-4EAF-B5F6-60751C0BABA3": [
+			{
+				"name": "Game logic",
+				"source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 300 - 150;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\n\tif ( position.x < -300 || position.x > 300 ) {\n\t\t\n\t\tdirection.x = - direction.x;\n\t\t\n\t}\n\n\tif ( position.z < -200 || position.z > 200 ) {\n\t\t\n\t\tdirection.z = - direction.z;\n\t\t\n\t}\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 10 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( 8 ) );\n\n}"
+			}]
+	}
+}

+ 49 - 9
editor/index.html

@@ -36,14 +36,20 @@
 		<script src="../examples/js/renderers/SoftwareRenderer.js"></script>
 		<script src="../examples/js/renderers/SVGRenderer.js"></script>
 
+		<link rel="stylesheet" href="js/libs/codemirror/codemirror.css">
+		<link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css">
+		<script src="js/libs/codemirror/codemirror.js"></script>
+		<script src="js/libs/codemirror/mode/javascript.js"></script>
+
 		<script src="js/libs/jszip.min.js"></script>
+		<script src="js/libs/sortable.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>
 		<script src="js/libs/ui.js"></script>
-		<script src="js/libs/ui.editor.js"></script>
 		<script src="js/libs/ui.three.js"></script>
 
 		<script src="js/libs/app.js"></script>
 		<script src="js/Player.js"></script>
+		<script src="js/Script.js"></script>
 
 		<script src="js/Storage.js"></script>
 
@@ -56,10 +62,11 @@
 		<script src="js/Menubar.Add.js"></script>
 		<script src="js/Menubar.Play.js"></script>
 		<script src="js/Menubar.View.js"></script>
+		<script src="js/Menubar.Examples.js"></script>
 		<script src="js/Menubar.Help.js"></script>
 		<script src="js/Menubar.Status.js"></script>
 		<script src="js/Sidebar.js"></script>
-		<script src="js/Sidebar.Renderer.js"></script>
+		<script src="js/Sidebar.Project.js"></script>
 		<script src="js/Sidebar.Scene.js"></script>
 		<script src="js/Sidebar.Object3D.js"></script>
 		<script src="js/Sidebar.Animation.js"></script>
@@ -77,7 +84,6 @@
 		<script src="js/Sidebar.Geometry.TorusKnotGeometry.js"></script>
 		<script src="js/Sidebar.Material.js"></script>
 		<script src="js/Sidebar.Script.js"></script>
-		<script src="js/Sidebar.Script.Editor.js"></script>
 		<script src="js/Toolbar.js"></script>
 		<script src="js/Viewport.js"></script>
 		<script src="js/Viewport.Info.js"></script>
@@ -98,6 +104,9 @@
 			var viewport = new Viewport( editor );
 			document.body.appendChild( viewport.dom );
 
+			var script = new Script( editor );
+			document.body.appendChild( script.dom );
+
 			var player = new Player( editor );
 			document.body.appendChild( player.dom );
 
@@ -169,13 +178,16 @@
 
 				var signals = editor.signals;
 
+				signals.editorCleared.add( saveState );
 				signals.geometryChanged.add( saveState );
 				signals.objectAdded.add( saveState );
 				signals.objectChanged.add( saveState );
 				signals.objectRemoved.add( saveState );
 				signals.materialChanged.add( saveState );
 				signals.sceneGraphChanged.add( saveState );
+				signals.scriptChanged.add( saveState );
 
+				/*
 				var showDialog = function ( content ) {
 
 					dialog.clear();
@@ -186,6 +198,7 @@
 				};
 
 				signals.showDialog.add( showDialog );
+				*/
 
 			} );
 
@@ -201,7 +214,12 @@
 			document.addEventListener( 'drop', function ( event ) {
 
 				event.preventDefault();
-				editor.loader.loadFile( event.dataTransfer.files[ 0 ] );
+
+				if ( event.dataTransfer.files.length > 0 ) {
+
+					editor.loader.loadFile( event.dataTransfer.files[ 0 ] );
+
+				}
 
 			}, false );
 
@@ -212,11 +230,6 @@
 					case 8: // prevent browser back
 						event.preventDefault();
 						break;
-					case 46: // delete
-						var parent = editor.selected.parent;
-						editor.removeObject( editor.selected );
-						editor.select( parent );
-						break;
 
 				}
 
@@ -232,6 +245,33 @@
 
 			onWindowResize();
 
+			//
+
+			var file = null;
+			var hash = window.location.hash;
+
+			if ( hash.substr( 1, 4 ) === 'app=' ) file = hash.substr( 5 );
+			if ( hash.substr( 1, 6 ) === 'scene=' ) file = hash.substr( 7 );
+
+			if ( file !== null ) {
+
+				if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
+
+					var loader = new THREE.XHRLoader();
+					loader.crossOrigin = '';
+					loader.load( file, function ( text ) {
+
+						var json = JSON.parse( text );
+
+						editor.clear();
+						editor.fromJSON( json );
+
+					} );
+
+				}
+
+			}
+
 		</script>
 	</body>
 </html>

+ 6 - 5
editor/js/Config.js

@@ -9,10 +9,11 @@ var Config = function () {
 	var storage = {
 		'autosave': true,
 		'theme': 'css/light.css',
-		
-		'renderer': 'WebGLRenderer',
-		'renderer/antialias': true,
-	
+
+		'project/renderer': 'WebGLRenderer',
+		'project/renderer/antialias': true,
+		'project/vr': false,
+
 		'camera/position': [ 500, 250, 500 ],
 		'camera/target': [ 0, 0, 0 ],
 
@@ -20,7 +21,7 @@ var Config = function () {
 		'ui/sidebar/geometry/collapsed': true,
 		'ui/sidebar/material/collapsed': true,
 		'ui/sidebar/object3d/collapsed': false,
-		'ui/sidebar/renderer/collapsed': true,
+		'ui/sidebar/project/collapsed': true,
 		'ui/sidebar/scene/collapsed': false,
 		'ui/sidebar/script/collapsed': true
 	};

+ 84 - 6
editor/js/Editor.js

@@ -8,6 +8,10 @@ var Editor = function () {
 
 	this.signals = {
 
+		// script
+
+		editScript: new SIGNALS.Signal(),
+
 		// player
 
 		startPlayer: new SIGNALS.Signal(),
@@ -18,10 +22,12 @@ var Editor = function () {
 		playAnimation: new SIGNALS.Signal(),
 		stopAnimation: new SIGNALS.Signal(),
 
-		showDialog: new SIGNALS.Signal(),
+		// showDialog: new SIGNALS.Signal(),
 
 		// notifications
 
+		editorCleared: new SIGNALS.Signal(),
+
 		savingStarted: new SIGNALS.Signal(),
 		savingFinished: new SIGNALS.Signal(),
 
@@ -49,6 +55,11 @@ var Editor = function () {
 		helperRemoved: new SIGNALS.Signal(),
 
 		materialChanged: new SIGNALS.Signal(),
+
+		scriptAdded: new SIGNALS.Signal(),
+		scriptChanged: new SIGNALS.Signal(),
+		scriptRemoved: new SIGNALS.Signal(),
+
 		fogTypeChanged: new SIGNALS.Signal(),
 		fogColorChanged: new SIGNALS.Signal(),
 		fogParametersChanged: new SIGNALS.Signal(),
@@ -62,7 +73,7 @@ var Editor = function () {
 	this.storage = new Storage();
 	this.loader = new Loader( this );
 
-	this.camera = new THREE.PerspectiveCamera( 50, 1, 0.1, 100000 );
+	this.camera = new THREE.PerspectiveCamera( 50, 1, 1, 100000 );
 	this.camera.name = 'Camera';
 
 	this.scene = new THREE.Scene();
@@ -91,16 +102,19 @@ Editor.prototype = {
 
 	},
 
+	/*
 	showDialog: function ( value ) {
 
 		this.signals.showDialog.dispatch( value );
 
 	},
+	*/
 
 	//
 
 	setScene: function ( scene ) {
 
+		this.scene.uuid = scene.uuid;
 		this.scene.name = scene.name;
 		this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) );
 
@@ -152,8 +166,6 @@ Editor.prototype = {
 
 		if ( object.parent === undefined ) return; // avoid deleting the camera or scene
 
-		if ( confirm( 'Delete ' + object.name + '?' ) === false ) return;
-
 		var scope = this;
 
 		object.traverse( function ( child ) {
@@ -275,7 +287,39 @@ Editor.prototype = {
 
 	//
 
-	parent: function ( object, parent ) {
+	addScript: function ( object, script ) {
+
+		if ( this.scripts[ object.uuid ] === undefined ) {
+
+			this.scripts[ object.uuid ] = [];
+
+		}
+
+		this.scripts[ object.uuid ].push( script );
+
+		this.signals.scriptAdded.dispatch( script );
+
+	},
+
+	removeScript: function ( object, script ) {
+
+		if ( this.scripts[ object.uuid ] === undefined ) return;
+
+		var index = this.scripts[ object.uuid ].indexOf( script );
+
+		if ( index !== - 1 ) {
+
+			this.scripts[ object.uuid ].splice( index, 1 );
+
+		}
+
+		this.signals.scriptRemoved.dispatch( script );
+
+	},
+
+	//
+
+	parent: function ( object, parent, before ) {
 
 		if ( parent === undefined ) {
 
@@ -285,6 +329,16 @@ Editor.prototype = {
 
 		parent.add( object );
 
+		// sort children array
+
+		if ( before !== undefined ) {
+
+			var index = parent.children.indexOf( before );
+			parent.children.splice( index, 0, object );
+			parent.children.pop();
+
+		}
+
 		this.signals.sceneGraphChanged.dispatch();
 
 	},
@@ -357,6 +411,30 @@ Editor.prototype = {
 
 	},
 
+	clear: function () {
+
+		this.camera.position.set( 500, 250, 500 );
+		this.camera.lookAt( new THREE.Vector3() );
+
+		var objects = this.scene.children;
+
+		while ( objects.length > 0 ) {
+
+			this.removeObject( objects[ 0 ] );
+
+		}
+
+		this.geometries = {};
+		this.materials = {};
+		this.textures = {};
+		this.scripts = {};
+
+		this.deselect();
+
+		this.signals.editorCleared.dispatch();
+
+	},
+
 	//
 
 	fromJSON: function ( json ) {
@@ -384,7 +462,7 @@ Editor.prototype = {
 		this.camera.aspect = camera.aspect;
 		this.camera.near = camera.near;
 		this.camera.far = camera.far;
-		
+
 		this.setScene( loader.parse( json.scene ) );
 		this.scripts = json.scripts;
 

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

@@ -20,6 +20,15 @@ Menubar.Add = function ( editor ) {
 
 	var meshCount = 0;
 	var lightCount = 0;
+	var cameraCount = 0;
+
+	editor.signals.editorCleared.add( function () {
+
+		meshCount = 0;
+		lightCount = 0;
+		cameraCount = 0;
+
+	} );
 
 	// Group
 
@@ -227,10 +236,6 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
-	//
-
-	options.add( new UI.HorizontalRule() );
-
 	// Sprite
 
 	var option = new UI.Panel();
@@ -358,6 +363,26 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
+	//
+
+	options.add( new UI.HorizontalRule() );
+
+	// PerspectiveCamera
+
+	var option = new UI.Panel();
+	option.setClass( 'option' );
+	option.setTextContent( 'PerspectiveCamera' );
+	option.onClick( function() {
+
+		var camera = new THREE.PerspectiveCamera( 50, 1, 1, 10000 );
+		camera.name = 'PerspectiveCamera ' + ( ++ cameraCount );
+
+		editor.addObject( camera );
+		editor.select( camera );
+
+	} );
+	options.add( option );
+
 	return container;
 
 }

+ 6 - 2
editor/js/Menubar.Edit.js

@@ -41,9 +41,13 @@ Menubar.Edit = function ( editor ) {
 	option.setClass( 'option' );
 	option.setTextContent( 'Delete' );
 	option.onClick( function () {
+	
+		var object = editor.selected;
+
+		if ( confirm( 'Delete ' + object.name + '?' ) === false ) return;
 
-		var parent = editor.selected.parent;
-		editor.removeObject( editor.selected );
+		var parent = object.parent;
+		editor.removeObject( object );
 		editor.select( parent );
 
 	} );

+ 61 - 0
editor/js/Menubar.Examples.js

@@ -0,0 +1,61 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+Menubar.Examples = function ( editor ) {
+
+	var container = new UI.Panel();
+	container.setClass( 'menu' );
+
+	var title = new UI.Panel();
+	title.setClass( 'title' );
+	title.setTextContent( 'Examples' );
+	container.add( title );
+
+	var options = new UI.Panel();
+	options.setClass( 'options' );
+	container.add( options );
+
+	// Examples
+
+	var items = [
+		{ title: 'Arkanoid', file: 'arkanoid.app.json' },
+		{ title: 'Camera', file: 'camera.app.json' },
+		{ title: 'Particles', file: 'particles.app.json' },
+		{ title: 'Pong', file: 'pong.app.json' }
+	];
+
+	var loader = new THREE.XHRLoader();
+
+	for ( var i = 0; i < items.length; i ++ ) {
+
+		( function ( i ) {
+
+			var item = items[ i ];
+
+			var option = new UI.Panel();
+			option.setClass( 'option' );
+			option.setTextContent( item.title );
+			option.onClick( function () {
+
+				if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
+
+					loader.load( 'examples/' + item.file, function ( text ) {
+
+						editor.clear();
+						editor.fromJSON( JSON.parse( text ) );
+
+					} );
+
+				}
+
+			} );
+			options.add( option );
+
+		} )( i )
+
+	}
+
+	return container;
+
+};

+ 13 - 20
editor/js/Menubar.File.js

@@ -23,18 +23,9 @@ Menubar.File = function ( editor ) {
 	option.setTextContent( 'New' );
 	option.onClick( function () {
 
-		if ( confirm( 'Are you sure?' ) ) {
+		if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
 
-			editor.config.setKey(
-				'camera/position', [ 500, 250, 500 ],
-				'camera/target', [ 0, 0, 0 ]
-			);
-
-			editor.storage.clear( function () {
-
-				location.href = location.pathname;
-
-			} );
+			editor.clear();
 
 		}
 
@@ -98,7 +89,7 @@ Menubar.File = function ( editor ) {
 		output = JSON.stringify( output, null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
-		exportString( output );
+		exportString( output, 'geometry.json' );
 
 	} );
 	options.add( option );
@@ -123,7 +114,7 @@ Menubar.File = function ( editor ) {
 		output = JSON.stringify( output, null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
-		exportString( output );
+		exportString( output, 'model.json' );
 
 	} );
 	options.add( option );
@@ -139,7 +130,7 @@ Menubar.File = function ( editor ) {
 		output = JSON.stringify( output, null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
-		exportString( output );
+		exportString( output, 'scene.json' );
 
 	} );
 	options.add( option );
@@ -162,7 +153,7 @@ Menubar.File = function ( editor ) {
 
 		var exporter = new THREE.OBJExporter();
 
-		exportString( exporter.parse( object ) );
+		exportString( exporter.parse( object ), 'model.obj' );
 
 	} );
 	options.add( option );
@@ -176,7 +167,7 @@ Menubar.File = function ( editor ) {
 
 		var exporter = new THREE.STLExporter();
 
-		exportString( exporter.parse( editor.scene ) );
+		exportString( exporter.parse( editor.scene ), 'model.stl' );
 
 	} );
 	options.add( option );
@@ -281,16 +272,18 @@ Menubar.File = function ( editor ) {
 	*/
 
 
-
 	//
 
-	var exportString = function ( output ) {
+	var exportString = function ( output, filename ) {
 
 		var blob = new Blob( [ output ], { type: 'text/plain' } );
 		var objectURL = URL.createObjectURL( blob );
 
-		window.open( objectURL, '_blank' );
-		window.focus();
+		var link = document.createElement( 'a' );
+		link.href = objectURL;
+		link.download = filename || 'data.json';
+		link.target = '_blank';
+		link.click();
 
 	};
 

+ 1 - 0
editor/js/Menubar.js

@@ -11,6 +11,7 @@ var Menubar = function ( editor ) {
 	container.add( new Menubar.Edit( editor ) );
 	container.add( new Menubar.Add( editor ) );
 	container.add( new Menubar.Play( editor ) );
+	container.add( new Menubar.Examples( editor ) );
 	container.add( new Menubar.View( editor ) );
 	container.add( new Menubar.Help( editor ) );
 

+ 8 - 0
editor/js/Player.js

@@ -15,6 +15,14 @@ var Player = function ( editor ) {
 
 	var player = new APP.Player();
 
+	window.addEventListener( 'resize', function () {
+
+		if ( player.dom === undefined ) return;
+
+		player.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
+
+	} );
+
 	signals.startPlayer.add( function () {
 
 		container.setDisplay( '' );

+ 91 - 0
editor/js/Script.js

@@ -0,0 +1,91 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+var Script = function ( editor ) {
+
+	var signals = editor.signals;
+
+	var container = new UI.Panel();
+	container.setId( 'script' );
+	container.setPosition( 'absolute' );
+	container.setBackgroundColor( '#272822' );
+	container.setDisplay( 'none' );
+
+	var header = new UI.Panel();
+	header.setPadding( '10px' );
+	container.add( header );
+	
+	var title = new UI.Text().setColor( '#fff' );
+	header.add( title );
+
+	var buttonSVG = ( function () {
+		var svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
+		svg.setAttribute( 'width', 32 );
+		svg.setAttribute( 'height', 32 );
+		var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
+		path.setAttribute( 'd', 'M 12,12 L 22,22 M 22,12 12,22' );
+		path.setAttribute( 'stroke', '#fff' );
+		svg.appendChild( path );
+		return svg;
+	} )();
+
+	var close = new UI.Element( buttonSVG );
+	close.setPosition( 'absolute' );
+	close.setTop( '3px' );
+	close.setRight( '1px' );
+	close.setCursor( 'pointer' );
+	close.onClick( function () {
+
+		container.setDisplay( 'none' );
+
+	} );
+	header.add( close );
+
+	var delay;
+	var currentScript;
+
+	var codemirror = CodeMirror( container.dom, {
+		value: '',
+		lineNumbers: true,
+		matchBrackets: true,
+		indentWithTabs: true,
+		tabSize: 4,
+		indentUnit: 4
+	} );
+	codemirror.setOption( 'theme', 'monokai' );
+	codemirror.on( 'change', function () {
+
+		clearTimeout( delay );
+		delay = setTimeout( function () {
+
+			currentScript.source = codemirror.getValue();
+
+			signals.scriptChanged.dispatch( currentScript );
+
+		}, 300 );
+
+	});
+
+	//
+	
+	signals.editorCleared.add( function () {
+
+		container.setDisplay( 'none' );
+
+	} );
+
+	signals.editScript.add( function ( object, script ) {
+
+		container.setDisplay( '' );
+
+		currentScript = script;
+
+		title.setValue( object.name + ' / ' + script.name );
+		codemirror.setValue( script.source );
+
+	} );
+
+	return container;
+
+};

+ 2 - 2
editor/js/Sidebar.Geometry.BufferGeometry.js

@@ -9,7 +9,7 @@ Sidebar.Geometry.BufferGeometry = function ( signals ) {
 	// vertices
 
 	var verticesRow = new UI.Panel();
-	var vertices = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+	var vertices = new UI.Text().setFontSize( '12px' );
 
 	verticesRow.add( new UI.Text( 'Vertices' ).setWidth( '90px' ) );
 	verticesRow.add( vertices );
@@ -19,7 +19,7 @@ Sidebar.Geometry.BufferGeometry = function ( signals ) {
 	// faces
 
 	var facesRow = new UI.Panel();
-	var faces = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+	var faces = new UI.Text().setFontSize( '12px' );
 
 	facesRow.add( new UI.Text( 'Faces' ).setWidth( '90px' ) );
 	facesRow.add( faces );

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

@@ -9,7 +9,7 @@ Sidebar.Geometry.Geometry = function ( signals ) {
 	// vertices
 
 	var verticesRow = new UI.Panel();
-	var vertices = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+	var vertices = new UI.Text().setFontSize( '12px' );
 
 	verticesRow.add( new UI.Text( 'Vertices' ).setWidth( '90px' ) );
 	verticesRow.add( vertices );
@@ -19,7 +19,7 @@ Sidebar.Geometry.Geometry = function ( signals ) {
 	// faces
 
 	var facesRow = new UI.Panel();
-	var faces = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+	var faces = new UI.Text().setFontSize( '12px' );
 
 	facesRow.add( new UI.Text( 'Faces' ).setWidth( '90px' ) );
 	facesRow.add( faces );

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

@@ -22,7 +22,7 @@ Sidebar.Geometry = function ( editor ) {
 	// uuid
 
 	var geometryUUIDRow = new UI.Panel();
-	var geometryUUID = new UI.Input().setWidth( '115px' ).setColor( '#444' ).setFontSize( '12px' ).setDisabled( true );
+	var geometryUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true );
 	var geometryUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () {
 
 		geometryUUID.setValue( THREE.Math.generateUUID() );
@@ -40,7 +40,7 @@ Sidebar.Geometry = function ( editor ) {
 	// name
 
 	var geometryNameRow = new UI.Panel();
-	var geometryName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( function () {
+	var geometryName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
 
 		editor.setGeometryName( editor.selected.geometry, geometryName.getValue() );
 

+ 28 - 39
editor/js/Sidebar.Material.js

@@ -40,7 +40,7 @@ Sidebar.Material = function ( editor ) {
 	// uuid
 
 	var materialUUIDRow = new UI.Panel();
-	var materialUUID = new UI.Input().setWidth( '115px' ).setColor( '#444' ).setFontSize( '12px' ).setDisabled( true );
+	var materialUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true );
 	var materialUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () {
 
 		materialUUID.setValue( THREE.Math.generateUUID() );
@@ -57,7 +57,7 @@ Sidebar.Material = function ( editor ) {
 	// name
 
 	var materialNameRow = new UI.Panel();
-	var materialName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( function () {
+	var materialName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
 
 		editor.setMaterialName( editor.selected.material, materialName.getValue() );
 
@@ -84,7 +84,7 @@ Sidebar.Material = function ( editor ) {
 		'ShaderMaterial': 'ShaderMaterial',
 		'SpriteMaterial': 'SpriteMaterial'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	} ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	materialClassRow.add( new UI.Text( 'Type' ).setWidth( '90px' ) );
 	materialClassRow.add( materialClass );
@@ -101,16 +101,6 @@ Sidebar.Material = function ( editor ) {
 
 	container.add( materialColorRow );
 
-	// ambient
-
-	var materialAmbientRow = new UI.Panel();
-	var materialAmbient = new UI.Color().onChange( update );
-
-	materialAmbientRow.add( new UI.Text( 'Ambient' ).setWidth( '90px' ) );
-	materialAmbientRow.add( materialAmbient );
-
-	container.add( materialAmbientRow );
-
 	// emissive
 
 	var materialEmissiveRow = new UI.Panel();
@@ -204,7 +194,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialMapRow = new UI.Panel();
 	var materialMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialMap = new UI.Texture().onChange( update );
 
 	materialMapRow.add( new UI.Text( 'Map' ).setWidth( '90px' ) );
 	materialMapRow.add( materialMapEnabled );
@@ -216,7 +206,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialAlphaMapRow = new UI.Panel();
 	var materialAlphaMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialAlphaMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialAlphaMap = new UI.Texture().onChange( update );
 
 	materialAlphaMapRow.add( new UI.Text( 'Alpha Map' ).setWidth( '90px' ) );
 	materialAlphaMapRow.add( materialAlphaMapEnabled );
@@ -228,7 +218,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialLightMapRow = new UI.Panel();
 	var materialLightMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialLightMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialLightMap = new UI.Texture().onChange( update );
 
 	materialLightMapRow.add( new UI.Text( 'Light Map' ).setWidth( '90px' ) );
 	materialLightMapRow.add( materialLightMapEnabled );
@@ -240,7 +230,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialBumpMapRow = new UI.Panel();
 	var materialBumpMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialBumpMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialBumpMap = new UI.Texture().onChange( update );
 	var materialBumpScale = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
 
 	materialBumpMapRow.add( new UI.Text( 'Bump Map' ).setWidth( '90px' ) );
@@ -254,7 +244,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialNormalMapRow = new UI.Panel();
 	var materialNormalMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialNormalMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialNormalMap = new UI.Texture().onChange( update );
 
 	materialNormalMapRow.add( new UI.Text( 'Normal Map' ).setWidth( '90px' ) );
 	materialNormalMapRow.add( materialNormalMapEnabled );
@@ -266,7 +256,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialSpecularMapRow = new UI.Panel();
 	var materialSpecularMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialSpecularMap = new UI.Texture().setColor( '#444' ).onChange( update );
+	var materialSpecularMap = new UI.Texture().onChange( update );
 
 	materialSpecularMapRow.add( new UI.Text( 'Specular Map' ).setWidth( '90px' ) );
 	materialSpecularMapRow.add( materialSpecularMapEnabled );
@@ -278,7 +268,7 @@ Sidebar.Material = function ( editor ) {
 
 	var materialEnvMapRow = new UI.Panel();
 	var materialEnvMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialEnvMap = new UI.Texture( THREE.SphericalReflectionMapping ).setColor( '#444' ).onChange( update );
+	var materialEnvMap = new UI.Texture( THREE.SphericalReflectionMapping ).onChange( update );
 	var materialReflectivity = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
 
 	materialEnvMapRow.add( new UI.Text( 'Env Map' ).setWidth( '90px' ) );
@@ -297,7 +287,7 @@ Sidebar.Material = function ( editor ) {
 		1: 'Back',
 		2: 'Double'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	} ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	materialSideRow.add( new UI.Text( 'Side' ).setWidth( '90px' ) );
 	materialSideRow.add( materialSide );
@@ -313,7 +303,7 @@ Sidebar.Material = function ( editor ) {
 		1: 'Flat',
 		2: 'Smooth'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	} ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	materialShadingRow.add( new UI.Text( 'Shading' ).setWidth( '90px' ) );
 	materialShadingRow.add( materialShading );
@@ -332,7 +322,7 @@ Sidebar.Material = function ( editor ) {
 		4: 'Multiply',
 		5: 'Custom'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	} ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	materialBlendingRow.add( new UI.Text( 'Blending' ).setWidth( '90px' ) );
 	materialBlendingRow.add( materialBlending );
@@ -379,7 +369,7 @@ Sidebar.Material = function ( editor ) {
 
 		var geometry = object.geometry;
 		var material = object.material;
-		
+
 		var textureWarning = false;
 		var objectHasUvs = false;
 
@@ -408,12 +398,6 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
-			if ( material.ambient !== undefined ) {
-
-				material.ambient.setHex( materialAmbient.getHexValue() );
-
-			}
-
 			if ( material.emissive !== undefined ) {
 
 				material.emissive.setHex( materialEmissive.getHexValue() );
@@ -452,8 +436,20 @@ Sidebar.Material = function ( editor ) {
 
 			if ( material.vertexColors !== undefined ) {
 
-				material.vertexColors = parseInt( materialVertexColors.getValue() );
-				material.needsUpdate = true;
+				var vertexColors = parseInt( materialVertexColors.getValue() );
+
+				if ( material.vertexColors !== vertexColors ) {
+
+					if ( geometry instanceof THREE.Geometry ) {
+
+						geometry.groupsNeedUpdate = true;
+
+					}
+
+					material.vertexColors = vertexColors;
+					material.needsUpdate = true;
+
+				}
 
 			}
 
@@ -639,7 +635,6 @@ Sidebar.Material = function ( editor ) {
 		var properties = {
 			'name': materialNameRow,
 			'color': materialColorRow,
-			'ambient': materialAmbientRow,
 			'emissive': materialEmissiveRow,
 			'specular': materialSpecularRow,
 			'shininess': materialShininessRow,
@@ -703,12 +698,6 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
-			if ( material.ambient !== undefined ) {
-
-				materialAmbient.setHexValue( material.ambient.getHexString() );
-
-			}
-
 			if ( material.emissive !== undefined ) {
 
 				materialEmissive.setHexValue( material.emissive.getHexString() );

+ 70 - 8
editor/js/Sidebar.Object3D.js

@@ -17,12 +17,51 @@ Sidebar.Object3D = function ( editor ) {
 
 	var objectType = new UI.Text().setTextTransform( 'uppercase' );
 	container.addStatic( objectType );
+
+	var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' );
+	objectActions.setOptions( {
+
+		'Actions': 'Actions',
+		'Reset Position': 'Reset Position',
+		'Reset Rotation': 'Reset Rotation',
+		'Reset Scale': 'Reset Scale'
+
+	} );
+	objectActions.onClick( function ( event ) {
+
+		event.stopPropagation();
+
+		var object = editor.selected;
+
+		switch ( this.getValue() ) {
+
+			case 'Reset Position':
+				object.position.set( 0, 0, 0 );
+				break;
+
+			case 'Reset Rotation':
+				object.rotation.set( 0, 0, 0 );
+				break;
+
+			case 'Reset Scale':
+				object.scale.set( 1, 1, 1 );
+				break;
+
+		}
+
+		this.setValue( 'Actions' );
+
+		signals.objectChanged.dispatch( object );
+
+	} );
+	container.addStatic( objectActions );
+
 	container.add( new UI.Break() );
 
 	// uuid
 
 	var objectUUIDRow = new UI.Panel();
-	var objectUUID = new UI.Input().setWidth( '115px' ).setColor( '#444' ).setFontSize( '12px' ).setDisabled( true );
+	var objectUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true );
 	var objectUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () {
 
 		objectUUID.setValue( THREE.Math.generateUUID() );
@@ -40,7 +79,7 @@ Sidebar.Object3D = function ( editor ) {
 	// name
 
 	var objectNameRow = new UI.Panel();
-	var objectName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( function () {
+	var objectName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
 
 			editor.setObjectName( editor.selected, objectName.getValue() );
 
@@ -54,7 +93,7 @@ Sidebar.Object3D = function ( editor ) {
 	// parent
 
 	var objectParentRow = new UI.Panel();
-	var objectParent = new UI.Select().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	var objectParent = new UI.Select().setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
 
 	objectParentRow.add( new UI.Text( 'Parent' ).setWidth( '90px' ) );
 	objectParentRow.add( objectParent );
@@ -189,6 +228,16 @@ Sidebar.Object3D = function ( editor ) {
 
 	container.add( objectExponentRow );
 
+	// decay
+
+	var objectDecayRow = new UI.Panel();
+	var objectDecay = new UI.Number().setRange( 0, Infinity ).onChange( update );
+
+	objectDecayRow.add( new UI.Text( 'Decay' ).setWidth( '90px' ) );
+	objectDecayRow.add( objectDecay );
+
+	container.add( objectDecayRow );
+
 	// visible
 
 	var objectVisibleRow = new UI.Panel();
@@ -200,11 +249,11 @@ Sidebar.Object3D = function ( editor ) {
 	container.add( objectVisibleRow );
 
 	// user data
-	
+
 	var timeout;
 
 	var objectUserDataRow = new UI.Panel();
-	var objectUserData = new UI.TextArea().setWidth( '150px' ).setHeight( '40px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	var objectUserData = new UI.TextArea().setWidth( '150px' ).setHeight( '40px' ).setFontSize( '12px' ).onChange( update );
 	objectUserData.onKeyUp( function () {
 
 		try {
@@ -294,7 +343,7 @@ Sidebar.Object3D = function ( editor ) {
 
 				if ( object.parent.id !== newParentId && object.id !== newParentId ) {
 
-					editor.parent( object, editor.scene.getObjectById( newParentId, true ) );
+					editor.parent( object, editor.scene.getObjectById( newParentId ) );
 
 				}
 
@@ -367,6 +416,12 @@ Sidebar.Object3D = function ( editor ) {
 
 			}
 
+			if ( object.decay !== undefined ) {
+
+				object.decay = objectDecay.getValue();
+
+			}
+
 			object.visible = objectVisible.getValue();
 
 			try {
@@ -397,7 +452,8 @@ Sidebar.Object3D = function ( editor ) {
 			'groundColor': objectGroundColorRow,
 			'distance' : objectDistanceRow,
 			'angle' : objectAngleRow,
-			'exponent' : objectExponentRow
+			'exponent' : objectExponentRow,
+			'decay' : objectDecayRow
 		};
 
 		for ( var property in properties ) {
@@ -546,6 +602,12 @@ Sidebar.Object3D = function ( editor ) {
 
 		}
 
+		if ( object.decay !== undefined ) {
+
+			objectDecay.setValue( object.decay );
+
+		}
+
 		objectVisible.setValue( object.visible );
 
 		try {
@@ -558,7 +620,7 @@ Sidebar.Object3D = function ( editor ) {
 
 		}
 
-		objectUserData.setBorderColor( '#ccc' );
+		objectUserData.setBorderColor( 'transparent' );
 		objectUserData.setBackgroundColor( '' );
 
 		updateTransformRows( object );

+ 27 - 12
editor/js/Sidebar.Renderer.js → editor/js/Sidebar.Project.js

@@ -2,7 +2,7 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-Sidebar.Renderer = function ( editor ) {
+Sidebar.Project = function ( editor ) {
 
 	var signals = editor.signals;
 
@@ -17,14 +17,14 @@ Sidebar.Renderer = function ( editor ) {
 	};
 
 	var container = new UI.CollapsiblePanel();
-	container.setCollapsed( editor.config.getKey( 'ui/sidebar/renderer/collapsed' ) );
+	container.setCollapsed( editor.config.getKey( 'ui/sidebar/project/collapsed' ) );
 	container.onCollapsedChange( function ( boolean ) {
 
-		editor.config.setKey( 'ui/sidebar/renderer/collapsed', boolean );
+		editor.config.setKey( 'ui/sidebar/project/collapsed', boolean );
 
 	} );
 
-	container.addStatic( new UI.Text( 'RENDERER' ) );
+	container.addStatic( new UI.Text( 'PROJECT' ) );
 	container.add( new UI.Break() );
 
 	// class
@@ -40,30 +40,30 @@ Sidebar.Renderer = function ( editor ) {
 	}
 
 	var rendererTypeRow = new UI.Panel();
-	var rendererType = new UI.Select().setOptions( options ).setWidth( '150px' ).setColor( '#444' ).onChange( function () {
+	var rendererType = new UI.Select().setOptions( options ).setWidth( '150px' ).onChange( function () {
 
-		editor.config.setKey( 'renderer', this.getValue() );
+		editor.config.setKey( 'project/renderer', this.getValue() );
 		updateRenderer();
 
 	} );
 
-	rendererTypeRow.add( new UI.Text( 'Type' ).setWidth( '90px' ) );
+	rendererTypeRow.add( new UI.Text( 'Renderer' ).setWidth( '90px' ) );
 	rendererTypeRow.add( rendererType );
 
 	container.add( rendererTypeRow );
 
-	if ( editor.config.getKey( 'renderer' ) !== undefined ) {
+	if ( editor.config.getKey( 'project/renderer' ) !== undefined ) {
 
-		rendererType.setValue( editor.config.getKey( 'renderer' ) );
+		rendererType.setValue( editor.config.getKey( 'project/renderer' ) );
 
 	}
-	
+
 	// antialiasing
 
 	var rendererAntialiasRow = new UI.Panel();
-	var rendererAntialias = new UI.Checkbox( editor.config.getKey( 'renderer/antialias' ) ).setLeft( '100px' ).onChange( function () {
+	var rendererAntialias = new UI.Checkbox( editor.config.getKey( 'project/renderer/antialias' ) ).setLeft( '100px' ).onChange( function () {
 
-		editor.config.setKey( 'renderer/antialias', this.getValue() );
+		editor.config.setKey( 'project/renderer/antialias', this.getValue() );
 		// updateRenderer();
 
 	} );
@@ -73,6 +73,21 @@ Sidebar.Renderer = function ( editor ) {
 
 	container.add( rendererAntialiasRow );
 
+	// VR
+
+	var vrRow = new UI.Panel();
+	var vr = new UI.Checkbox( editor.config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () {
+
+		editor.config.setKey( 'project/vr', this.getValue() );
+		// updateRenderer();
+
+	} );
+
+	vrRow.add( new UI.Text( 'VR' ).setWidth( '90px' ) );
+	vrRow.add( vr );
+
+	container.add( vrRow );
+
 	//
 
 	function updateRenderer() {

+ 4 - 4
editor/js/Sidebar.Scene.js

@@ -19,7 +19,7 @@ Sidebar.Scene = function ( editor ) {
 
 	var ignoreObjectSelectedSignal = false;
 
-	var outliner = new UI.FancySelect().setId( 'outliner' );
+	var outliner = new UI.Outliner( editor );
 	outliner.onChange( function () {
 
 		ignoreObjectSelectedSignal = true;
@@ -56,7 +56,7 @@ Sidebar.Scene = function ( editor ) {
 		'Fog': 'Linear',
 		'FogExp2': 'Exponential'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' )
+	} ).setWidth( '150px' );
 	fogType.onChange( function () {
 
 		var type = fogType.getValue();
@@ -133,8 +133,8 @@ Sidebar.Scene = function ( editor ) {
 
 		var options = [];
 
-		options.push( { value: camera.id, html: '<span class="type ' + camera.type + '"></span> ' + camera.name } );
-		options.push( { value: scene.id, html: '<span class="type ' + scene.type + '"></span> ' + scene.name } );
+		// options.push( { value: camera.id, html: '<span class="type ' + camera.type + '"></span> ' + camera.name } );
+		options.push( { static: true, value: scene.id, html: '<span class="type ' + scene.type + '"></span> ' + scene.name } );
 
 		( function addObjects( objects, pad ) {
 

+ 0 - 68
editor/js/Sidebar.Script.Editor.js

@@ -1,68 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-Sidebar.Script.Editor = function ( editor ) {
-
-	var signals = editor.signals;
-
-	var timeout;
-
-	var scriptSource = new UI.TextArea( 'javascript' ).setWidth( '240px' ).setHeight( '180px' ).setFontSize( '12px' );
-	scriptSource.onKeyUp( function () {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			var object = editor.selected;
-			var source = scriptSource.getValue();
-
-			try {
-
-				var script = new Function( 'scene', 'time', source ).bind( object.clone() );
-				script( new THREE.Scene(), 0 );
-
-				scriptSource.dom.classList.add( 'success' );
-				scriptSource.dom.classList.remove( 'fail' );
-
-			} catch ( error ) {
-
-				scriptSource.dom.classList.remove( 'success' );
-				scriptSource.dom.classList.add( 'fail' );
-
-				return;
-
-			}
-
-			editor.scripts[ object.uuid ] = source;
-
-			editor.signals.objectChanged.dispatch( object );
-
-		}, 500 );
-
-	} );
-
-	signals.objectSelected.add( function ( object ) {
-
-		if ( object !== null ) {
-
-			var script = editor.scripts[ object.uuid ];
-
-			if ( script !== undefined ) {
-
-				scriptSource.setValue( script );
-
-			} else {
-
-				scriptSource.setValue( '' );
-
-			}
-
-		}
-
-	} );
-
-	return scriptSource;
-
-}

+ 84 - 3
editor/js/Sidebar.Script.js

@@ -18,8 +18,84 @@ Sidebar.Script = function ( editor ) {
 	container.addStatic( new UI.Text( 'Script' ).setTextTransform( 'uppercase' ) );
 	container.add( new UI.Break() );
 
-	var source = new Sidebar.Script.Editor( editor );
-	container.add( source );
+	//
+
+	var scriptsContainer = new UI.Panel();
+	container.add( scriptsContainer );
+
+	var newScript = new UI.Button( 'New' );
+	newScript.onClick( function () {
+
+		var script = { name: '', source: 'function update( event ) {}' };
+		editor.addScript( editor.selected, script );
+
+	} );
+	container.add( newScript );
+
+	/*
+	var loadScript = new UI.Button( 'Load' );
+	loadScript.setMarginLeft( '4px' );
+	container.add( loadScript );
+	*/
+
+	//
+
+	function update() {
+
+		scriptsContainer.clear();
+
+		var object = editor.selected;
+		var scripts = editor.scripts[ object.uuid ];
+
+		if ( scripts !== undefined ) {
+
+			for ( var i = 0; i < scripts.length; i ++ ) {
+
+				( function ( object, script ) {
+
+					var name = new UI.Input( script.name ).setWidth( '130px' ).setFontSize( '12px' );
+					name.onChange( function () {
+
+						script.name = this.getValue();
+
+						signals.scriptChanged.dispatch();
+
+					} );
+					scriptsContainer.add( name );
+
+					var edit = new UI.Button( 'Edit' );
+					edit.setMarginLeft( '4px' );
+					edit.onClick( function () {
+
+						signals.editScript.dispatch( object, script );
+
+					} );
+					scriptsContainer.add( edit );
+
+					var remove = new UI.Button( 'Remove' );
+					remove.setMarginLeft( '4px' );
+					remove.onClick( function () {
+
+						if ( confirm( 'Are you sure?' ) ) {
+
+							editor.removeScript( editor.selected, script );
+
+						}
+
+					} );
+					scriptsContainer.add( remove );
+					
+					scriptsContainer.add( new UI.Break() );
+
+				} )( object, scripts[ i ] )
+
+			}
+
+		}
+
+	}
+
+	// signals
 
 	signals.objectSelected.add( function ( object ) {
 
@@ -27,6 +103,8 @@ Sidebar.Script = function ( editor ) {
 
 			container.setDisplay( 'block' );
 
+			update();
+
 		} else {
 
 			container.setDisplay( 'none' );
@@ -35,6 +113,9 @@ Sidebar.Script = function ( editor ) {
 
 	} );
 
+	signals.scriptAdded.add( update );
+	signals.scriptRemoved.add( update );
+
 	return container;
 
-}
+};

+ 1 - 1
editor/js/Sidebar.js

@@ -7,7 +7,7 @@ var Sidebar = function ( editor ) {
 	var container = new UI.Panel();
 	container.setId( 'sidebar' );
 
-	container.add( new Sidebar.Renderer( editor ) );
+	container.add( new Sidebar.Project( editor ) );
 	container.add( new Sidebar.Scene( editor ) );
 	container.add( new Sidebar.Object3D( editor ) );
 	container.add( new Sidebar.Geometry( editor ) );

+ 0 - 2
editor/js/Toolbar.js

@@ -62,8 +62,6 @@ var Toolbar = function ( editor ) {
 
 	}
 
-	update();
-
 	return container;
 
 }

+ 27 - 16
editor/js/Viewport.js

@@ -225,6 +225,13 @@ var Viewport = function ( editor ) {
 
 	// signals
 
+	signals.editorCleared.add( function () {
+
+		controls.center.set( 0, 0, 0 );
+		render();
+
+	} );
+
 	signals.themeChanged.add( function ( value ) {
 
 		switch ( value ) {
@@ -269,8 +276,6 @@ var Viewport = function ( editor ) {
 		container.dom.removeChild( renderer.domElement );
 
 		renderer = createRenderer( type, antialias );
-		renderer.setClearColor( clearColor );
-		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 
 		container.dom.appendChild( renderer.domElement );
@@ -323,11 +328,7 @@ var Viewport = function ( editor ) {
 
 			}
 
-			if ( object instanceof THREE.PerspectiveCamera === false ) {
-
-				transformControls.attach( object );
-
-			}
+			transformControls.attach( object );
 
 		}
 
@@ -341,7 +342,13 @@ var Viewport = function ( editor ) {
 
 	} );
 
-	signals.geometryChanged.add( render );
+	signals.geometryChanged.add( function ( geometry ) {
+
+		selectionBox.update( editor.selected );
+
+		render();
+
+	} );
 
 	signals.objectAdded.add( function ( object ) {
 
@@ -363,19 +370,21 @@ var Viewport = function ( editor ) {
 
 		transformControls.update();
 
-		if ( object !== camera ) {
+		if ( object.geometry !== undefined ) {
 
-			if ( object.geometry !== undefined ) {
+			selectionBox.update( object );
 
-				selectionBox.update( object );
+		}
 
-			}
+		if ( object instanceof THREE.PerspectiveCamera ) {
 
-			if ( editor.helpers[ object.id ] !== undefined ) {
+			object.updateProjectionMatrix();
 
-				editor.helpers[ object.id ].update();
+		}
 
-			}
+		if ( editor.helpers[ object.id ] !== undefined ) {
+
+			editor.helpers[ object.id ].update();
 
 		}
 
@@ -516,6 +525,8 @@ var Viewport = function ( editor ) {
 		}
 
 		var renderer = new THREE[ type ]( { antialias: antialias } );
+		renderer.setClearColor( clearColor );
+		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.autoClear = false;
 		renderer.autoUpdateScene = false;
 
@@ -524,7 +535,7 @@ var Viewport = function ( editor ) {
 	};
 
 	var clearColor;
-	var renderer = createRenderer( editor.config.getKey( 'renderer' ), editor.config.getKey( 'renderer/antialias' ) );
+	var renderer = createRenderer( editor.config.getKey( 'project/renderer' ), editor.config.getKey( 'project/renderer/antialias' ) );
 	container.dom.appendChild( renderer.domElement );
 
 	animate();

+ 128 - 16
editor/js/libs/app.js

@@ -9,33 +9,60 @@ var APP = {
 		var loader = new THREE.ObjectLoader();
 		var camera, scene, renderer;
 
-		var scripts = {
-			update: []
-		};
-	
+		var events = {};
+
 		this.dom = undefined;
 
+		this.width = 500;
+		this.height = 500;
+
 		this.load = function ( json ) {
 
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
+			renderer.setClearColor( 0x000000 );
 			renderer.setPixelRatio( window.devicePixelRatio );
 
 			camera = loader.parse( json.camera );
-
 			scene = loader.parse( json.scene );
 
-			scripts.update = [];
+			events = {
+				keydown: [],
+				keyup: [],
+				mousedown: [],
+				mouseup: [],
+				mousemove: [],
+				touchstart: [],
+				touchend: [],
+				touchmove: [],
+				update: []
+			};
 
 			for ( var uuid in json.scripts ) {
 
-				var source = json.scripts[ uuid ];
 				var object = scene.getObjectByProperty( 'uuid', uuid, true );
 
-				var script = ( new Function( 'scene', 'time', source ).bind( object ) )();
+				var scripts = json.scripts[ uuid ];
+
+				for ( var i = 0; i < scripts.length; i ++ ) {
+
+					var script = scripts[ i ];
+
+					var functions = ( new Function( 'player, scene, keydown, keyup, mousedown, mouseup, mousemove, touchstart, touchend, touchmove, update', script.source + '\nreturn { keydown: keydown, keyup: keyup, mousedown: mousedown, mouseup: mouseup, mousemove: mousemove, touchstart: touchstart, touchend: touchend, touchmove: touchmove, update: update };' ).bind( object ) )( this, scene );
+
+					for ( var name in functions ) {
 
-				if ( script.update !== undefined ) {
+						if ( functions[ name ] === undefined ) continue;
 
-					scripts.update.push( script.update );
+						if ( events[ name ] === undefined ) {
+
+							console.warn( 'APP.Player: event type not supported (', name, ')' );
+							continue;
+
+						}
+
+						events[ name ].push( functions[ name ].bind( object ) );
+
+					}
 
 				}
 
@@ -45,26 +72,43 @@ var APP = {
 
 		};
 
+		this.setCamera = function ( value ) {
+
+			camera = value;
+			camera.aspect = this.width / this.height;
+			camera.updateProjectionMatrix();
+
+		};
+
 		this.setSize = function ( width, height ) {
 
-			camera.aspect = width / height;
+			this.width = width;
+			this.height = height;
+
+			camera.aspect = this.width / this.height;
 			camera.updateProjectionMatrix();
 
 			renderer.setSize( width, height );
 
 		};
 
+		var dispatch = function ( array, event ) {
+
+			for ( var i = 0, l = array.length; i < l; i ++ ) {
+
+				array[ i ]( event );
+
+			}
+
+		};
+
 		var request;
 
 		var animate = function ( time ) {
 
 			request = requestAnimationFrame( animate );
 
-			for ( var i = 0, l = scripts.update.length; i < l; i ++ ) {
-
-				scripts.update[ i ]( scene, time );
-
-			}
+			dispatch( events.update, { time: time } );
 
 			renderer.render( scene, camera );
 
@@ -72,16 +116,84 @@ var APP = {
 
 		this.play = function () {
 
+			document.addEventListener( 'keydown', onDocumentKeyDown );
+			document.addEventListener( 'keyup', onDocumentKeyUp );
+			document.addEventListener( 'mousedown', onDocumentMouseDown );
+			document.addEventListener( 'mouseup', onDocumentMouseUp );
+			document.addEventListener( 'mousemove', onDocumentMouseMove );
+			document.addEventListener( 'touchstart', onDocumentTouchStart );
+			document.addEventListener( 'touchend', onDocumentTouchEnd );
+			document.addEventListener( 'touchmove', onDocumentTouchMove );
+
 			request = requestAnimationFrame( animate );
 
 		};
 
 		this.stop = function () {
 
+			document.removeEventListener( 'keydown', onDocumentKeyDown );
+			document.removeEventListener( 'keyup', onDocumentKeyUp );
+			document.removeEventListener( 'mousedown', onDocumentMouseDown );
+			document.removeEventListener( 'mouseup', onDocumentMouseUp );
+			document.removeEventListener( 'mousemove', onDocumentMouseMove );
+			document.removeEventListener( 'touchstart', onDocumentTouchStart );
+			document.removeEventListener( 'touchend', onDocumentTouchEnd );
+			document.removeEventListener( 'touchmove', onDocumentTouchMove );
+
 			cancelAnimationFrame( request );
 
 		};
 
+		//
+
+		var onDocumentKeyDown = function ( event ) {
+
+			dispatch( events.keydown, event );
+
+		};
+
+		var onDocumentKeyUp = function ( event ) {
+
+			dispatch( events.keyup, event );
+
+		};
+
+		var onDocumentMouseDown = function ( event ) {
+
+			dispatch( events.mousedown, event );
+
+		};
+
+		var onDocumentMouseUp = function ( event ) {
+
+			dispatch( events.mouseup, event );
+
+		};
+
+		var onDocumentMouseMove = function ( event ) {
+
+			dispatch( events.mousemove, event );
+
+		};
+
+		var onDocumentTouchStart = function ( event ) {
+
+			dispatch( events.touchstart, event );
+
+		};
+
+		var onDocumentTouchEnd = function ( event ) {
+
+			dispatch( events.touchend, event );
+
+		};
+
+		var onDocumentTouchMove = function ( event ) {
+
+			dispatch( events.touchmove, event );
+
+		};
+
 	}
 
 };

+ 22 - 14
editor/js/libs/codemirror/codemirror.css

@@ -5,10 +5,6 @@
   font-family: monospace;
   height: 300px;
 }
-.CodeMirror-scroll {
-  /* Set scrolling behaviour here */
-  overflow: auto;
-}
 
 /* PADDING */
 
@@ -52,11 +48,15 @@
 .CodeMirror div.CodeMirror-secondarycursor {
   border-left: 1px solid silver;
 }
-.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
   width: auto;
   border: 0;
   background: #7e7;
 }
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
 .cm-animate-fat-cursor {
   width: auto;
   border: 0;
@@ -83,7 +83,7 @@
 /* Can style cursor different in overwrite (non-insert) mode */
 div.CodeMirror-overwrite div.CodeMirror-cursor {}
 
-.cm-tab { display: inline-block; }
+.cm-tab { display: inline-block; text-decoration: inherit; }
 
 .CodeMirror-ruler {
   border-left: 1px solid #ccc;
@@ -121,6 +121,7 @@ div.CodeMirror-overwrite div.CodeMirror-cursor {}
 .cm-header, .cm-strong {font-weight: bold;}
 .cm-em {font-style: italic;}
 .cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
 
 .cm-s-default .cm-error {color: #f00;}
 .cm-invalidchar {color: #f00;}
@@ -146,6 +147,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 }
 
 .CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
   /* 30px is the magic margin used to hide the element's real scrollbars */
   /* See overflow: hidden in .CodeMirror */
   margin-bottom: -30px; margin-right: -30px;
@@ -190,7 +192,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-gutters {
   position: absolute; left: 0; top: 0;
-  padding-bottom: 30px;
   z-index: 3;
 }
 .CodeMirror-gutter {
@@ -198,13 +199,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
   height: 100%;
   -moz-box-sizing: content-box;
   box-sizing: content-box;
-  padding-bottom: 30px;
-  margin-bottom: -32px;
   display: inline-block;
+  margin-bottom: -30px;
   /* Hack to make IE7 behave */
   *zoom:1;
   *display:inline;
 }
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  height: 100%;
+}
 .CodeMirror-gutter-elt {
   position: absolute;
   cursor: default;
@@ -213,6 +218,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-lines {
   cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
 }
 .CodeMirror pre {
   /* Reset some styles that the rest of the page might have set */
@@ -250,10 +256,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 
 .CodeMirror-widget {}
 
-.CodeMirror-wrap .CodeMirror-scroll {
-  overflow-x: hidden;
-}
-
 .CodeMirror-measure {
   position: absolute;
   width: 100%;
@@ -272,7 +274,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 div.CodeMirror-cursors {
   visibility: hidden;
   position: relative;
-  z-index: 1;
+  z-index: 3;
 }
 .CodeMirror-focused div.CodeMirror-cursors {
   visibility: visible;
@@ -299,3 +301,9 @@ div.CodeMirror-cursors {
     visibility: hidden;
   }
 }
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 344 - 229
editor/js/libs/codemirror/codemirror.js


+ 8 - 8
editor/js/libs/codemirror/modes/javascript.js → editor/js/libs/codemirror/mode/javascript.js

@@ -19,7 +19,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   var jsonldMode = parserConfig.jsonld;
   var jsonMode = parserConfig.json || jsonldMode;
   var isTS = parserConfig.typescript;
-  var wordRE = parserConfig.wordCharacters || /[\w$]/;
+  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
 
   // Tokenizer
 
@@ -205,6 +205,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
         ++depth;
       } else if (wordRE.test(ch)) {
         sawSomething = true;
+      } else if (/["'\/]/.test(ch)) {
+        return;
       } else if (sawSomething && !depth) {
         ++pos;
         break;
@@ -391,7 +393,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   function maybeoperatorNoComma(type, value, noComma) {
     var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
     var expr = noComma == false ? expression : expressionNoComma;
-    if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
+    if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
     if (type == "operator") {
       if (/\+\+|--/.test(value)) return cont(me);
       if (value == "?") return cont(expression, expect(":"), expr);
@@ -417,13 +419,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   }
   function arrowBody(type) {
     findFatArrow(cx.stream, cx.state);
-    if (type == "{") return pass(statement);
-    return pass(expression);
+    return pass(type == "{" ? statement : expression);
   }
   function arrowBodyNoComma(type) {
     findFatArrow(cx.stream, cx.state);
-    if (type == "{") return pass(statement);
-    return pass(expressionNoComma);
+    return pass(type == "{" ? statement : expressionNoComma);
   }
   function maybelabel(type) {
     if (type == ":") return cont(poplex, statement);
@@ -592,7 +592,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
   }
   function maybeArrayComprehension(type) {
     if (type == "for") return pass(comprehension, expect("]"));
-    if (type == ",") return cont(commasep(expressionNoComma, "]"));
+    if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
     return pass(commasep(expressionNoComma, "]"));
   }
   function comprehension(type) {
@@ -658,7 +658,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
       else return lexical.indented + (closing ? 0 : indentUnit);
     },
 
-    electricChars: ":{}",
+    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
     blockCommentStart: jsonMode ? null : "/*",
     blockCommentEnd: jsonMode ? null : "*/",
     lineComment: jsonMode ? null : "//",

+ 31 - 0
editor/js/libs/codemirror/theme/monokai.css

@@ -0,0 +1,31 @@
+/* Based on Sublime Text's Monokai theme */
+
+.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;}
+.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
+.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;}
+.cm-s-monokai .CodeMirror-guttermarker { color: white; }
+.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;}
+.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
+
+.cm-s-monokai span.cm-comment {color: #75715e;}
+.cm-s-monokai span.cm-atom {color: #ae81ff;}
+.cm-s-monokai span.cm-number {color: #ae81ff;}
+
+.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
+.cm-s-monokai span.cm-keyword {color: #f92672;}
+.cm-s-monokai span.cm-string {color: #e6db74;}
+
+.cm-s-monokai span.cm-variable {color: #a6e22e;}
+.cm-s-monokai span.cm-variable-2 {color: #9effff;}
+.cm-s-monokai span.cm-def {color: #fd971f;}
+.cm-s-monokai span.cm-bracket {color: #f8f8f2;}
+.cm-s-monokai span.cm-tag {color: #f92672;}
+.cm-s-monokai span.cm-link {color: #ae81ff;}
+.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
+
+.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}
+.cm-s-monokai .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
editor/js/libs/sortable.min.js


+ 0 - 75
editor/js/libs/ui.editor.js

@@ -1,75 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-UI.CodeEditor = function ( mode ) {
-
-	UI.Element.call( this );
-
-	var scope = this;
-
-	var dom = document.createElement( 'div' );
-	dom.className = 'CodeEditor';
-
-	var editor = CodeMirror( dom, { mode: mode, indentWithTabs: true, lineWrapping: true, matchBrackets: true } );
-	editor.onKeyUp( 'keyup', function () {
-
-		if ( scope.onKeyUpCallback !== undefined ) {
-
-			scope.onKeyUpCallback();
-
-		}
-
-	});
-
-	this.dom = dom;
-	this.editor = editor;
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype = Object.create( UI.Element.prototype );
-UI.CodeEditor.prototype.constructor = UI.CodeEditor;
-
-UI.CodeEditor.prototype.setWidth = function ( value ) {
-
-	UI.Element.prototype.setWidth.call( this, value );
-
-	this.editor.setSize( this.dom.style.width, this.dom.style.height );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.setHeight = function ( value ) {
-
-	UI.Element.prototype.setHeight.call( this, value );
-
-	this.editor.setSize( this.dom.style.width, this.dom.style.height );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.getValue = function () {
-
-	return this.editor.getValue();
-
-};
-
-UI.CodeEditor.prototype.setValue = function ( value ) {
-
-	this.editor.setValue( value );
-
-	return this;
-
-};
-
-UI.CodeEditor.prototype.onKeyUp = function ( callback ) {
-
-	this.onKeyUpCallback = callback;
-
-	return this;
-
-};

+ 31 - 177
editor/js/libs/ui.js

@@ -4,14 +4,18 @@
 
 var UI = {};
 
-UI.Element = function () {};
+UI.Element = function ( dom ) {
+
+	this.dom = dom;
+
+};
 
 UI.Element.prototype = {
 
 	setId: function ( id ) {
 
 		this.dom.id = id;
-		
+
 		return this;
 
 	},
@@ -56,7 +60,7 @@ UI.Element.prototype = {
 
 var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
 'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
-'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor' ];
+'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
 
 properties.forEach( function ( property ) {
 
@@ -133,7 +137,7 @@ UI.Panel.prototype.add = function () {
 UI.Panel.prototype.remove = function () {
 
 	for ( var i = 0; i < arguments.length; i ++ ) {
-	
+
 		var argument = arguments[ i ];
 
 		if ( argument instanceof UI.Element ) {
@@ -307,6 +311,12 @@ UI.Text = function ( text ) {
 UI.Text.prototype = Object.create( UI.Element.prototype );
 UI.Text.prototype.constructor = UI.Text;
 
+UI.Text.prototype.getValue = function () {
+
+	return this.dom.textContent;
+
+};
+
 UI.Text.prototype.setValue = function ( value ) {
 
 	if ( value !== undefined ) {
@@ -322,7 +332,7 @@ UI.Text.prototype.setValue = function ( value ) {
 
 // Input
 
-UI.Input = function () {
+UI.Input = function ( text ) {
 
 	UI.Element.call( this );
 
@@ -331,7 +341,7 @@ UI.Input = function () {
 	var dom = document.createElement( 'input' );
 	dom.className = 'Input';
 	dom.style.padding = '2px';
-	dom.style.border = '1px solid #ccc';
+	dom.style.border = '1px solid transparent';
 
 	dom.addEventListener( 'keydown', function ( event ) {
 
@@ -340,6 +350,7 @@ UI.Input = function () {
 	}, false );
 
 	this.dom = dom;
+	this.setValue( text );
 
 	return this;
 
@@ -374,7 +385,6 @@ UI.TextArea = function () {
 	var dom = document.createElement( 'textarea' );
 	dom.className = 'TextArea';
 	dom.style.padding = '2px';
-	dom.style.border = '1px solid #ccc';
 	dom.spellcheck = false;
 
 	dom.addEventListener( 'keydown', function ( event ) {
@@ -429,10 +439,7 @@ UI.Select = function () {
 
 	var dom = document.createElement( 'select' );
 	dom.className = 'Select';
-	dom.style.width = '64px';
-	dom.style.height = '16px';
-	dom.style.border = '0px';
-	dom.style.padding = '0px';
+	dom.style.padding = '2px';
 
 	this.dom = dom;
 
@@ -496,159 +503,6 @@ UI.Select.prototype.setValue = function ( value ) {
 
 };
 
-// FancySelect
-
-UI.FancySelect = function () {
-
-	UI.Element.call( this );
-
-	var scope = this;
-
-	var dom = document.createElement( 'div' );
-	dom.className = 'FancySelect';
-	dom.tabIndex = 0;	// keyup event is ignored without setting tabIndex
-
-	// Broadcast for object selection after arrow navigation
-	var changeEvent = document.createEvent('HTMLEvents');
-	changeEvent.initEvent( 'change', true, true );
-
-	// Prevent native scroll behavior
-	dom.addEventListener( 'keydown', function (event) {
-
-		switch ( event.keyCode ) {
-			case 38: // up
-			case 40: // down
-				event.preventDefault();
-				event.stopPropagation();
-				break;
-		}
-
-	}, false);
-
-	// Keybindings to support arrow navigation
-	dom.addEventListener( 'keyup', function (event) {
-
-		switch ( event.keyCode ) {
-			case 38: // up
-			case 40: // down
-				scope.selectedIndex += ( event.keyCode == 38 ) ? -1 : 1;
-
-				if ( scope.selectedIndex >= 0 && scope.selectedIndex < scope.options.length ) {
-
-					// Highlight selected dom elem and scroll parent if needed
-					scope.setValue( scope.options[ scope.selectedIndex ].value );
-
-					scope.dom.dispatchEvent( changeEvent );
-
-				}
-
-				break;
-		}
-
-	}, false);
-
-	this.dom = dom;
-
-	this.options = [];
-	this.selectedIndex = -1;
-	this.selectedValue = null;
-
-	return this;
-
-};
-
-UI.FancySelect.prototype = Object.create( UI.Element.prototype );
-UI.FancySelect.prototype.constructor = UI.FancySelect;
-
-UI.FancySelect.prototype.setOptions = function ( options ) {
-
-	var scope = this;
-
-	var changeEvent = document.createEvent( 'HTMLEvents' );
-	changeEvent.initEvent( 'change', true, true );
-
-	while ( scope.dom.children.length > 0 ) {
-
-		scope.dom.removeChild( scope.dom.firstChild );
-
-	}
-
-	scope.options = [];
-
-	for ( var i = 0; i < options.length; i ++ ) {
-
-		var option = options[ i ];
-
-		var div = document.createElement( 'div' );
-		div.className = 'option';
-		div.innerHTML = option.html;
-		div.value = option.value;
-		scope.dom.appendChild( div );
-
-		scope.options.push( div );
-
-		div.addEventListener( 'click', function ( event ) {
-
-			scope.setValue( this.value );
-			scope.dom.dispatchEvent( changeEvent );
-
-		}, false );
-
-	}
-
-	return scope;
-
-};
-
-UI.FancySelect.prototype.getValue = function () {
-
-	return this.selectedValue;
-
-};
-
-UI.FancySelect.prototype.setValue = function ( value ) {
-
-	for ( var i = 0; i < this.options.length; i ++ ) {
-
-		var element = this.options[ i ];
-
-		if ( element.value === value ) {
-
-			element.classList.add( 'active' );
-
-			// scroll into view
-
-			var y = element.offsetTop - this.dom.offsetTop;
-			var bottomY = y + element.offsetHeight;
-			var minScroll = bottomY - this.dom.offsetHeight;
-
-			if ( this.dom.scrollTop > y ) {
-
-				this.dom.scrollTop = y
-
-			} else if ( this.dom.scrollTop < minScroll ) {
-
-				this.dom.scrollTop = minScroll;
-
-			}
-
-			this.selectedIndex = i;
-
-		} else {
-
-			element.classList.remove( 'active' );
-
-		}
-
-	}
-
-	this.selectedValue = value;
-
-	return this;
-
-};
-
-
 // Checkbox
 
 UI.Checkbox = function ( boolean ) {
@@ -786,8 +640,8 @@ UI.Number = function ( number ) {
 	var distance = 0;
 	var onMouseDownValue = 0;
 
-	var pointer = new THREE.Vector2();
-	var prevPointer = new THREE.Vector2();
+	var pointer = [ 0, 0 ];
+	var prevPointer = [ 0, 0 ];
 
 	var onMouseDown = function ( event ) {
 
@@ -797,7 +651,7 @@ UI.Number = function ( number ) {
 
 		onMouseDownValue = parseFloat( dom.value );
 
-		prevPointer.set( event.clientX, event.clientY );
+		prevPointer = [ event.clientX, event.clientY ];
 
 		document.addEventListener( 'mousemove', onMouseMove, false );
 		document.addEventListener( 'mouseup', onMouseUp, false );
@@ -808,9 +662,9 @@ UI.Number = function ( number ) {
 
 		var currentValue = dom.value;
 
-		pointer.set( event.clientX, event.clientY );
+		pointer = [ event.clientX, event.clientY ];
 
-		distance += ( pointer.x - prevPointer.x ) - ( pointer.y - prevPointer.y );
+		distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] );
 
 		var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step;
 
@@ -818,7 +672,7 @@ UI.Number = function ( number ) {
 
 		if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent );
 
-		prevPointer.set( event.clientX, event.clientY );
+		prevPointer = [ event.clientX, event.clientY ];
 
 	};
 
@@ -950,8 +804,8 @@ UI.Integer = function ( number ) {
 	var distance = 0;
 	var onMouseDownValue = 0;
 
-	var pointer = new THREE.Vector2();
-	var prevPointer = new THREE.Vector2();
+	var pointer = [ 0, 0 ];
+	var prevPointer = [ 0, 0 ];
 
 	var onMouseDown = function ( event ) {
 
@@ -961,7 +815,7 @@ UI.Integer = function ( number ) {
 
 		onMouseDownValue = parseFloat( dom.value );
 
-		prevPointer.set( event.clientX, event.clientY );
+		prevPointer = [ event.clientX, event.clientY ];
 
 		document.addEventListener( 'mousemove', onMouseMove, false );
 		document.addEventListener( 'mouseup', onMouseUp, false );
@@ -972,9 +826,9 @@ UI.Integer = function ( number ) {
 
 		var currentValue = dom.value;
 
-		pointer.set( event.clientX, event.clientY );
+		pointer = [ event.clientX, event.clientY ];
 
-		distance += ( pointer.x - prevPointer.x ) - ( pointer.y - prevPointer.y );
+		distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] );
 
 		var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step;
 
@@ -982,7 +836,7 @@ UI.Integer = function ( number ) {
 
 		if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent );
 
-		prevPointer.set( event.clientX, event.clientY );
+		prevPointer = [ event.clientX, event.clientY ];
 
 	};
 
@@ -1147,7 +1001,7 @@ UI.Button.prototype.setLabel = function ( value ) {
 UI.Dialog = function ( value ) {
 
 	var scope = this;
-	
+
 	var dom = document.createElement( 'dialog' );
 
 	if ( dom.showModal === undefined ) {

+ 176 - 0
editor/js/libs/ui.three.js

@@ -133,3 +133,179 @@ UI.Texture.prototype.onChange = function ( callback ) {
 	return this;
 
 };
+
+// Outliner
+
+UI.Outliner = function ( editor ) {
+
+	UI.Element.call( this );
+
+	var scope = this;
+
+	var dom = document.createElement( 'div' );
+	dom.className = 'Outliner';
+	dom.tabIndex = 0;	// keyup event is ignored without setting tabIndex
+
+	var scene = editor.scene;
+
+	var sortable = Sortable.create( dom, {
+		draggable: '.draggable',
+		onUpdate: function ( event ) {
+
+			var item = event.item;
+
+			var object = scene.getObjectById( item.value );
+
+			if ( item.nextSibling === null ) {
+
+				editor.parent( object, editor.scene );
+
+			} else {
+
+				var nextObject = scene.getObjectById( item.nextSibling.value );
+				editor.parent( object, nextObject.parent, nextObject );
+
+			}
+
+		}
+	} );
+
+	// Broadcast for object selection after arrow navigation
+	var changeEvent = document.createEvent('HTMLEvents');
+	changeEvent.initEvent( 'change', true, true );
+
+	// Prevent native scroll behavior
+	dom.addEventListener( 'keydown', function (event) {
+
+		switch ( event.keyCode ) {
+			case 38: // up
+			case 40: // down
+			event.preventDefault();
+			event.stopPropagation();
+			break;
+		}
+
+	}, false);
+
+	// Keybindings to support arrow navigation
+	dom.addEventListener( 'keyup', function (event) {
+
+		switch ( event.keyCode ) {
+			case 38: // up
+			case 40: // down
+			scope.selectedIndex += ( event.keyCode == 38 ) ? -1 : 1;
+
+			if ( scope.selectedIndex >= 0 && scope.selectedIndex < scope.options.length ) {
+
+				// Highlight selected dom elem and scroll parent if needed
+				scope.setValue( scope.options[ scope.selectedIndex ].value );
+
+				scope.dom.dispatchEvent( changeEvent );
+
+			}
+
+			break;
+		}
+
+	}, false);
+
+	this.dom = dom;
+
+	this.options = [];
+	this.selectedIndex = -1;
+	this.selectedValue = null;
+
+	return this;
+
+};
+
+UI.Outliner.prototype = Object.create( UI.Element.prototype );
+UI.Outliner.prototype.constructor = UI.Outliner;
+
+UI.Outliner.prototype.setOptions = function ( options ) {
+
+	var scope = this;
+
+	var changeEvent = document.createEvent( 'HTMLEvents' );
+	changeEvent.initEvent( 'change', true, true );
+
+	while ( scope.dom.children.length > 0 ) {
+
+		scope.dom.removeChild( scope.dom.firstChild );
+
+	}
+
+	scope.options = [];
+
+	for ( var i = 0; i < options.length; i ++ ) {
+
+		var option = options[ i ];
+
+		var div = document.createElement( 'div' );
+		div.className = 'option ' + ( option.static === true ? '': 'draggable' );
+		div.innerHTML = option.html;
+		div.value = option.value;
+		scope.dom.appendChild( div );
+
+		scope.options.push( div );
+
+		div.addEventListener( 'click', function ( event ) {
+
+			scope.setValue( this.value );
+			scope.dom.dispatchEvent( changeEvent );
+
+		}, false );
+
+	}
+
+	return scope;
+
+};
+
+UI.Outliner.prototype.getValue = function () {
+
+	return this.selectedValue;
+
+};
+
+UI.Outliner.prototype.setValue = function ( value ) {
+
+	for ( var i = 0; i < this.options.length; i ++ ) {
+
+		var element = this.options[ i ];
+
+		if ( element.value === value ) {
+
+			element.classList.add( 'active' );
+
+			// scroll into view
+
+			var y = element.offsetTop - this.dom.offsetTop;
+			var bottomY = y + element.offsetHeight;
+			var minScroll = bottomY - this.dom.offsetHeight;
+
+			if ( this.dom.scrollTop > y ) {
+
+				this.dom.scrollTop = y
+
+			} else if ( this.dom.scrollTop < minScroll ) {
+
+				this.dom.scrollTop = minScroll;
+
+			}
+
+			this.selectedIndex = i;
+
+		} else {
+
+			element.classList.remove( 'active' );
+
+		}
+
+	}
+
+	this.selectedValue = value;
+
+	return this;
+
+};

+ 1 - 0
examples/canvas_ascii_effect.html

@@ -82,6 +82,7 @@
 				scene.add( plane );
 
 				renderer = new THREE.CanvasRenderer();
+				renderer.setClearColor( 0xf0f0f0 );
 				renderer.setSize( width, height );
 				// container.appendChild( renderer.domElement );
 

+ 1 - 2
examples/canvas_lines_colors_2d.html

@@ -80,8 +80,7 @@
 
 				scene = new THREE.Scene();
 
-				renderer = new THREE.CanvasRenderer( { antialias: false } );
-				renderer.setClearColor( 0x000000, 1 );
+				renderer = new THREE.CanvasRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/canvas_lines_dashed.html

@@ -99,7 +99,7 @@
 				scene.add( object );
 
 				renderer = new THREE.CanvasRenderer();
-				renderer.setClearColor( 0x111111, 1 );
+				renderer.setClearColor( 0x111111 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( WIDTH, HEIGHT );
 

+ 4 - 3
examples/index.html

@@ -209,10 +209,8 @@
 				"webgl_custom_attributes_particles3",
 				"webgl_decals",
 				"webgl_effects_anaglyph",
-				"webgl_effects_oculusrift",
 				"webgl_effects_parallaxbarrier",
 				"webgl_effects_stereo",
-				"webgl_effects_vr",
 				"webgl_geometries",
 				"webgl_geometries2",
 				"webgl_geometry_colors",
@@ -359,6 +357,7 @@
 				"webgl_shaders_vector",
 				"webgl_shadowmap",
 				"webgl_shadowmap_performance",
+				"webgl_shadowmap_viewer",
 				"webgl_sprites",
 				"webgl_terrain_dynamic",
 				"webgl_test_memory",
@@ -371,6 +370,9 @@
 				"webgldeferred_arealights",
 				"webgldeferred_pointlights"
 			],
+			"vr": [
+				"vr_cubes"
+			],
 			"css3d": [
 				"css3d_molecules",
 				"css3d_panorama",
@@ -386,7 +388,6 @@
 				"misc_animation_keys",
 				"misc_controls_deviceorientation",
 				"misc_controls_fly",
-				"misc_controls_oculusrift",
 				"misc_controls_orbit",
 				"misc_controls_pointerlock",
 				"misc_controls_trackball",

+ 2 - 1
examples/js/Mirror.js

@@ -110,6 +110,7 @@ THREE.Mirror = function ( renderer, camera, options ) {
 	this.textureMatrix = new THREE.Matrix4();
 
 	this.mirrorCamera = this.camera.clone();
+	this.mirrorCamera.matrixAutoUpdate = true;
 
 	this.texture = new THREE.WebGLRenderTarget( width, height );
 	this.tempTexture = new THREE.WebGLRenderTarget( width, height );
@@ -142,7 +143,7 @@ THREE.Mirror = function ( renderer, camera, options ) {
 };
 
 THREE.Mirror.prototype = Object.create( THREE.Object3D.prototype );
-THREE.Mirror.prototype.constructor = THREE.Mirror;
+THREE.Mirror.prototype.constructor = THREE.Mirror;
 
 THREE.Mirror.prototype.renderWithMirror = function ( otherMirror ) {
 

+ 4 - 3
examples/js/Ocean.js

@@ -41,6 +41,7 @@
 	this.matrixNeedsUpdate = false;
 	
 	// Setup framebuffer pipeline
+	var renderTargetType = optionalParameter(options.USE_HALF_FLOAT, false) ? THREE.HalfFloatType : THREE.FloatType;
 	var LinearClampParams = {
 		minFilter: THREE.LinearFilter,
 		magFilter: THREE.LinearFilter,
@@ -50,7 +51,7 @@
 		stencilBuffer: false,
 		depthBuffer: false,
 		premultiplyAlpha: false,
-		type: THREE.FloatType
+		type: renderTargetType
 	};
 	var NearestClampParams = {
 		minFilter: THREE.NearestFilter,
@@ -61,7 +62,7 @@
 		stencilBuffer: false,
 		depthBuffer: false,
 		premultiplyAlpha:false,
-		type: THREE.FloatType
+		type: renderTargetType
 	};
 	var NearestRepeatParams = {
 		minFilter: THREE.NearestFilter,
@@ -72,7 +73,7 @@
 		stencilBuffer: false,
 		depthBuffer: false,
 		premultiplyAlpha: false,
-		type: THREE.FloatType
+		type: renderTargetType
 	};
 	this.initialSpectrumFramebuffer = new THREE.WebGLRenderTarget(this.resolution, this.resolution, NearestRepeatParams);
 	this.spectrumFramebuffer = new THREE.WebGLRenderTarget(this.resolution, this.resolution, NearestClampParams);

+ 3 - 5
examples/js/ShaderDeferred.js

@@ -147,6 +147,7 @@ THREE.ShaderDeferred = {
 			"uniform float wrapAround;",
 			"uniform float additiveSpecular;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "color_pars_fragment" ],
 			THREE.ShaderChunk[ "map_pars_fragment" ],
 			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
@@ -225,11 +226,7 @@ THREE.ShaderDeferred = {
 
 					"#endif",
 
-					"#ifdef GAMMA_INPUT",
-
-						"cubeColor.xyz *= cubeColor.xyz;",
-
-					"#endif",
+					"cubeColor.xyz = inputToLinear( cubeColor.xyz );",
 
 					"if ( combine == 1 ) {",
 
@@ -308,6 +305,7 @@ THREE.ShaderDeferred = {
 
 		vertexShader : [
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "map_pars_vertex" ],
 			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
 			THREE.ShaderChunk[ "color_pars_vertex" ],

+ 22 - 30
examples/js/ShaderSkin.js

@@ -38,7 +38,6 @@ THREE.ShaderSkin = {
 
 			"diffuse":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
 			"specular": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"ambient":  { type: "c", value: new THREE.Color( 0x050505 ) },
 			"opacity": 	  { type: "f", value: 1 },
 
 			"uRoughness": 	  		{ type: "f", value: 0.15 },
@@ -65,7 +64,6 @@ THREE.ShaderSkin = {
 			"uniform bool enableBump;",
 			"uniform bool enableSpecular;",
 
-			"uniform vec3 ambient;",
 			"uniform vec3 diffuse;",
 			"uniform vec3 specular;",
 			"uniform float opacity;",
@@ -105,11 +103,13 @@ THREE.ShaderSkin = {
 				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecay[ MAX_POINT_LIGHTS ];",
 
 			"#endif",
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
@@ -202,10 +202,7 @@ THREE.ShaderSkin = {
 
 						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
 
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 
 						"lVector = normalize( lVector );",
 
@@ -215,8 +212,8 @@ THREE.ShaderSkin = {
 
 						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
 
-						"pointTotal    += lDistance * diffuse * pointLightColor[ i ] * pointDiffuseWeight;",
-						"specularTotal += lDistance * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
+						"pointTotal    += attenuation * diffuse * pointLightColor[ i ] * pointDiffuseWeight;",
+						"specularTotal += attenuation * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
 
 					"}",
 
@@ -230,9 +227,7 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
+						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
 
 						"float dirDiffuseWeightFull = max( dot( normal, dirVector ), 0.0 );",
 						"float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
@@ -255,8 +250,7 @@ THREE.ShaderSkin = {
 
 					"for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
-						"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-						"vec3 lVector = normalize( lDirection.xyz );",
+						"vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );",
 
 						"float dotProduct = dot( normal, lVector );",
 						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
@@ -295,7 +289,7 @@ THREE.ShaderSkin = {
 					"totalLight += hemiTotal;",
 				"#endif",
 
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalLight + ambientLightColor * ambient ) + specularTotal;",
+				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalLight + ambientLightColor * diffuse ) + specularTotal;",
 
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
@@ -314,6 +308,7 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
 
 			"void main() {",
@@ -377,7 +372,6 @@ THREE.ShaderSkin = {
 
 			"diffuse":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
 			"specular": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"ambient":  { type: "c", value: new THREE.Color( 0x050505 ) },
 			"opacity": 	  { type: "f", value: 1 },
 
 			"uRoughness": 	  		{ type: "f", value: 0.15 },
@@ -389,7 +383,6 @@ THREE.ShaderSkin = {
 
 		fragmentShader: [
 
-			"uniform vec3 ambient;",
 			"uniform vec3 diffuse;",
 			"uniform vec3 specular;",
 			"uniform float opacity;",
@@ -430,6 +423,7 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 
 			"float fresnelReflectance( vec3 H, vec3 V, float F0 ) {",
@@ -526,9 +520,7 @@ THREE.ShaderSkin = {
 
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
+						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
 
 						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
 
@@ -595,7 +587,7 @@ THREE.ShaderSkin = {
 
 					"gl_FragColor.xyz *= pow( colDiffuse.xyz, vec3( 0.5 ) );",
 
-					"gl_FragColor.xyz += ambientLightColor * ambient * colDiffuse.xyz + specularTotal;",
+					"gl_FragColor.xyz += ambientLightColor * diffuse * colDiffuse.xyz + specularTotal;",
 
 					"#ifndef VERSION1",
 
@@ -632,6 +624,7 @@ THREE.ShaderSkin = {
 
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecay[ MAX_POINT_LIGHTS ];",
 
 				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
 
@@ -639,6 +632,8 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
+
 			"void main() {",
 
 				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
@@ -668,14 +663,11 @@ THREE.ShaderSkin = {
 
 						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
 
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 
 						"lVector = normalize( lVector );",
 
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
+						"vPointLight[ i ] = vec4( lVector, attenuation );",
 
 					"}",
 
@@ -721,6 +713,7 @@ THREE.ShaderSkin = {
 
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecay[ MAX_POINT_LIGHTS ];",
 
 				"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
 
@@ -728,6 +721,8 @@ THREE.ShaderSkin = {
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
+
 			"void main() {",
 
 				"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
@@ -757,14 +752,11 @@ THREE.ShaderSkin = {
 
 						"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
 
-						"float lDistance = 1.0;",
-
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 
 						"lVector = normalize( lVector );",
 
-						"vPointLight[ i ] = vec4( lVector, lDistance );",
+						"vPointLight[ i ] = vec4( lVector, attenuation );",
 
 					"}",
 

+ 11 - 21
examples/js/ShaderTerrain.js

@@ -42,7 +42,6 @@ THREE.ShaderTerrain = {
 
 			"diffuse": { type: "c", value: new THREE.Color( 0xeeeeee ) },
 			"specular": { type: "c", value: new THREE.Color( 0x111111 ) },
-			"ambient": { type: "c", value: new THREE.Color( 0x050505 ) },
 			"shininess": { type: "f", value: 30 },
 			"opacity": { type: "f", value: 1 },
 
@@ -57,7 +56,6 @@ THREE.ShaderTerrain = {
 
 		fragmentShader: [
 
-			"uniform vec3 ambient;",
 			"uniform vec3 diffuse;",
 			"uniform vec3 specular;",
 			"uniform float shininess;",
@@ -108,11 +106,13 @@ THREE.ShaderTerrain = {
 				"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
 				"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
 				"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
+				"uniform float pointLightDecay[ MAX_POINT_LIGHTS ];",
 
 			"#endif",
 
 			"varying vec3 vViewPosition;",
 
+			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 
@@ -134,12 +134,8 @@ THREE.ShaderTerrain = {
 					"vec4 colDiffuse1 = texture2D( tDiffuse1, uvOverlay );",
 					"vec4 colDiffuse2 = texture2D( tDiffuse2, uvOverlay );",
 
-					"#ifdef GAMMA_INPUT",
-
-						"colDiffuse1.xyz *= colDiffuse1.xyz;",
-						"colDiffuse2.xyz *= colDiffuse2.xyz;",
-
-					"#endif",
+					"colDiffuse1.xyz = inputToLinear( colDiffuse1.xyz );",
+					"colDiffuse2.xyz = inputToLinear( colDiffuse2.xyz );",
 
 					"gl_FragColor = gl_FragColor * mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );",
 
@@ -174,22 +170,19 @@ THREE.ShaderTerrain = {
 						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
 						"vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
 
-						"float lDistance = 1.0;",
-						"if ( pointLightDistance[ i ] > 0.0 )",
-							"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
+						"float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[i] );",
 
 						"lVector = normalize( lVector );",
 
 						"vec3 pointHalfVector = normalize( lVector + viewPosition );",
-						"float pointDistance = lDistance;",
 
 						"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
 						"float pointDiffuseWeight = max( dot( normal, lVector ), 0.0 );",
 
 						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
 
-						"pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
-						"pointSpecular += pointDistance * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
+						"pointDiffuse += attenuation * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
+						"pointSpecular += attenuation * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
 
 					"}",
 
@@ -204,9 +197,7 @@ THREE.ShaderTerrain = {
 
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
-						"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-
-						"vec3 dirVector = normalize( lDirection.xyz );",
+						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
 						"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
 
 						"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
@@ -230,8 +221,7 @@ THREE.ShaderTerrain = {
 
 					"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
-						"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-						"vec3 lVector = normalize( lDirection.xyz );",
+						"vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );",
 
 						// diffuse
 
@@ -288,8 +278,8 @@ THREE.ShaderTerrain = {
 
 				"#endif",
 
-				//"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient) + totalSpecular;",
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );",
+				//"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse ) + totalSpecular;",
+				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse + totalSpecular );",
 
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

+ 0 - 4
examples/js/controls/EditorControls.js

@@ -116,8 +116,6 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		if ( scope.enabled === false ) return;
 
-		event.preventDefault();
-
 		if ( event.button === 0 ) {
 
 			state = STATE.ROTATE;
@@ -145,8 +143,6 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		if ( scope.enabled === false ) return;
 
-		event.preventDefault();
-
 		pointer.set( event.clientX, event.clientY );
 
 		var movementX = pointer.x - pointerOld.x;

+ 0 - 61
examples/js/controls/OculusControls.js

@@ -1,61 +0,0 @@
-/**
- * @author possan / http://possan.se/
- *
- * Oculus headtracking control
- * - use together with the oculus-rest project to get headtracking
- *   coordinates from the rift: http://github.com/possan/oculus-rest
- */
-
-THREE.OculusControls = function ( object ) {
-
-	this.object = object;
-	this.target = new THREE.Vector3( 0, 0, 0 );
-
-	this.enabled = true;
-	this.headquat = new THREE.Quaternion();
-
-	this.loadAjaxJSON = function ( url, callback ) {
-		var xhr = new XMLHttpRequest();
-		xhr.onreadystatechange = function () {
-			if ( xhr.readyState === xhr.DONE ) {
-				if ( xhr.status === 200 || xhr.status === 0 ) {
-					if ( xhr.responseText ) {
-						var json = JSON.parse( xhr.responseText );
-						callback( json );
-					}
-				}
-			}
-		};
-		xhr.open( "GET", url, true );
-		xhr.withCredentials = false;
-		xhr.send( null );
-	};
-
-	this.gotCoordinates = function( r ) {
-		this.headquat.set(r.quat.x, r.quat.y, r.quat.z, r.quat.w);
-		this.queuePoll();
-	}
-
-	this.pollOnce = function() {
-		this.loadAjaxJSON('http://localhost:50000', bind(this, this.gotCoordinates));
-	}
-
-	this.queuePoll = function() {
-		setTimeout(bind(this, this.pollOnce), 10);
-	}
-
-	this.update = function( delta ) {
-		if ( this.enabled === false ) return;
-		this.object.quaternion.multiply(this.headquat);
-	};
-
-	function bind( scope, fn ) {
-		return function () {
-			fn.apply( scope, arguments );
-		};
-	};
-
-	this.connect = function() {
-		this.queuePoll();
-	};
-};

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

@@ -14,12 +14,6 @@
 //    Orbit - left mouse / touch: one finger move
 //    Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
 //    Pan - right mouse, or arrow keys / touch: three finter swipe
-//
-// This is a drop-in replacement for (most) TrackballControls used in examples.
-// That is, include this js file and wherever you see:
-//    	controls = new THREE.TrackballControls( camera );
-//      controls.target.z = 150;
-// Simple substitute "OrbitControls" and the control should work as-is.
 
 THREE.OrbitControls = function ( object, domElement ) {
 

+ 194 - 105
examples/js/controls/OrthographicTrackballControls.js

@@ -1,12 +1,14 @@
 /**
  * @author Eberhard Graether / http://egraether.com/
+ * @author Mark Lundin 	/ http://mark-lundin.com
  * @author Patrick Fuller / http://patrick-fuller.com
+ * @author Max Smolens / https://github.com/msmolens
  */
 
 THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	var _this = this;
-	var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };
+	var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
 
 	this.object = object;
 	this.domElement = ( domElement !== undefined ) ? domElement : document;
@@ -15,16 +17,17 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	this.enabled = true;
 
-	this.screen = { width: 0, height: 0, offsetLeft: 0, offsetTop: 0 };
-	this.radius = ( this.screen.width + this.screen.height ) / 4;
+	this.screen = { left: 0, top: 0, width: 0, height: 0 };
+
+	this.radius = 0;
 
 	this.rotateSpeed = 1.0;
 	this.zoomSpeed = 1.2;
-	this.panSpeed = 0.3;
 
 	this.noRotate = false;
 	this.noZoom = false;
 	this.noPan = false;
+	this.noRoll = false;
 
 	this.staticMoving = false;
 	this.dynamicDampingFactor = 0.2;
@@ -35,7 +38,9 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	this.target = new THREE.Vector3();
 
-	var lastPosition = new THREE.Vector3();
+	var EPS = 0.000001;
+
+	var _changed = true;
 
 	var _state = STATE.NONE,
 	_prevState = STATE.NONE,
@@ -47,7 +52,6 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	_zoomStart = new THREE.Vector2(),
 	_zoomEnd = new THREE.Vector2(),
-	_zoomFactor = 1,
 
 	_touchZoomDistanceStart = 0,
 	_touchZoomDistanceEnd = 0,
@@ -65,24 +69,43 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 	this.right0 = this.object.right;
 	this.top0 = this.object.top;
 	this.bottom0 = this.object.bottom;
-	this.center0 = new THREE.Vector2((this.left0 + this.right0) / 2.0, (this.top0 + this.bottom0) / 2.0);
 
 	// events
 
 	var changeEvent = { type: 'change' };
+	var startEvent = { type: 'start'};
+	var endEvent = { type: 'end'};
 
 
 	// methods
 
 	this.handleResize = function () {
 
-		this.screen.width = window.innerWidth;
-		this.screen.height = window.innerHeight;
+		if ( this.domElement === document ) {
+
+			this.screen.left = 0;
+			this.screen.top = 0;
+			this.screen.width = window.innerWidth;
+			this.screen.height = window.innerHeight;
+
+		} else {
+
+			var box = this.domElement.getBoundingClientRect();
+			// adjustments come from similar code in the jquery offset() function
+			var d = this.domElement.ownerDocument.documentElement;
+			this.screen.left = box.left + window.pageXOffset - d.clientLeft;
+			this.screen.top = box.top + window.pageYOffset - d.clientTop;
+			this.screen.width = box.width;
+			this.screen.height = box.height;
+
+		}
 
-		this.screen.offsetLeft = 0;
-		this.screen.offsetTop = 0;
+		this.radius = 0.5 * Math.min( this.screen.width, this.screen.height );
 
-		this.radius = ( this.screen.width + this.screen.height ) / 4;
+		this.left0 = this.object.left;
+		this.right0 = this.object.right;
+		this.top0 = this.object.top;
+		this.bottom0 = this.object.bottom;
 
 	};
 
@@ -96,102 +119,132 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	};
 
-	this.getMouseOnScreen = function ( clientX, clientY ) {
+	var getMouseOnScreen = ( function () {
 
-		return new THREE.Vector2(
-			( clientX - _this.screen.offsetLeft ) / _this.radius * 0.5,
-			( clientY - _this.screen.offsetTop ) / _this.radius * 0.5
-		);
+		var vector = new THREE.Vector2();
 
-	};
+		return function ( pageX, pageY ) {
 
-	this.getMouseProjectionOnBall = function ( clientX, clientY ) {
+			vector.set(
+				( pageX - _this.screen.left ) / _this.screen.width,
+				( pageY - _this.screen.top ) / _this.screen.height
+			);
 
-		var mouseOnBall = new THREE.Vector3(
-			( clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft ) / _this.radius,
-			( _this.screen.height * 0.5 + _this.screen.offsetTop - clientY ) / _this.radius,
-			0.0
-		);
+			return vector;
 
-		var length = mouseOnBall.length();
+		};
 
-		if ( length > 1.0 ) {
+	}() );
 
-			mouseOnBall.normalize();
+	var getMouseProjectionOnBall = ( function () {
 
-		} else {
+		var vector = new THREE.Vector3();
+		var objectUp = new THREE.Vector3();
+		var mouseOnBall = new THREE.Vector3();
 
-			mouseOnBall.z = Math.sqrt( 1.0 - length * length );
+		return function ( pageX, pageY ) {
 
-		}
+			mouseOnBall.set(
+				( pageX - _this.screen.width * 0.5 - _this.screen.left ) / _this.radius,
+				( _this.screen.height * 0.5 + _this.screen.top - pageY ) / _this.radius,
+				0.0
+			);
 
-		_eye.copy( _this.object.position ).sub( _this.target );
+			var length = mouseOnBall.length();
 
-		var projection = _this.object.up.clone().setLength( mouseOnBall.y );
-		projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) );
-		projection.add( _eye.setLength( mouseOnBall.z ) );
+			if ( _this.noRoll ) {
 
-		return projection;
+				if ( length < Math.SQRT1_2 ) {
 
-	};
+					mouseOnBall.z = Math.sqrt( 1.0 - length*length );
+
+				} else {
+
+					mouseOnBall.z = .5 / length;
+
+				}
 
-	this.rotateCamera = function () {
+			} else if ( length > 1.0 ) {
 
-		var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
+				mouseOnBall.normalize();
 
-		if ( angle ) {
+			} else {
 
-			var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(),
-				quaternion = new THREE.Quaternion();
+				mouseOnBall.z = Math.sqrt( 1.0 - length * length );
 
-			angle *= _this.rotateSpeed;
+			}
 
-			quaternion.setFromAxisAngle( axis, -angle );
+			_eye.copy( _this.object.position ).sub( _this.target );
 
-			_eye.applyQuaternion( quaternion );
-			_this.object.up.applyQuaternion( quaternion );
+			vector.copy( _this.object.up ).setLength( mouseOnBall.y )
+			vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );
+			vector.add( _eye.setLength( mouseOnBall.z ) );
 
-			_rotateEnd.applyQuaternion( quaternion );
+			return vector;
 
-			if ( _this.staticMoving ) {
+		};
 
-				_rotateStart.copy( _rotateEnd );
+	}() );
 
-			} else {
+	this.rotateCamera = (function(){
 
-				quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
-				_rotateStart.applyQuaternion( quaternion );
+		var axis = new THREE.Vector3(),
+			quaternion = new THREE.Quaternion();
 
-			}
 
+		return function () {
+
+			var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
+
+			if ( angle ) {
+
+				axis.crossVectors( _rotateStart, _rotateEnd ).normalize();
+
+				angle *= _this.rotateSpeed;
+
+				quaternion.setFromAxisAngle( axis, -angle );
+
+				_eye.applyQuaternion( quaternion );
+				_this.object.up.applyQuaternion( quaternion );
+
+				_rotateEnd.applyQuaternion( quaternion );
+
+				if ( _this.staticMoving ) {
+
+					_rotateStart.copy( _rotateEnd );
+
+				} else {
+
+					quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
+					_rotateStart.applyQuaternion( quaternion );
+
+				}
+
+				_changed = true;
+
+			}
 		}
 
-	};
+	}());
 
 	this.zoomCamera = function () {
 
-		if ( _state === STATE.TOUCH_ZOOM ) {
+		if ( _state === STATE.TOUCH_ZOOM_PAN ) {
 
-			var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
+			var factor = _touchZoomDistanceEnd / _touchZoomDistanceStart;
 			_touchZoomDistanceStart = _touchZoomDistanceEnd;
-			_zoomFactor *= factor;
 
-			_this.object.left = _zoomFactor * _this.left0 + ( 1 - _zoomFactor ) *  _this.center0.x;
-			_this.object.right = _zoomFactor * _this.right0 + ( 1 - _zoomFactor ) *  _this.center0.x;
-			_this.object.top = _zoomFactor * _this.top0 + ( 1 - _zoomFactor ) *  _this.center0.y;
-			_this.object.bottom = _zoomFactor * _this.bottom0 + ( 1 - _zoomFactor ) *  _this.center0.y;
+			_this.object.zoom *= factor;
+
+			_changed = true;
 
 		} else {
 
 			var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
 
-			if ( factor !== 1.0 && factor > 0.0 ) {
-				_zoomFactor *= factor;
+			if ( Math.abs( factor - 1.0 ) > EPS && factor > 0.0 ) {
 
-				_this.object.left = _zoomFactor * _this.left0 + ( 1 - _zoomFactor ) *  _this.center0.x;
-				_this.object.right = _zoomFactor * _this.right0 + ( 1 - _zoomFactor ) *  _this.center0.x;
-				_this.object.top = _zoomFactor * _this.top0 + ( 1 - _zoomFactor ) *  _this.center0.y;
-				_this.object.bottom = _zoomFactor * _this.bottom0 + ( 1 - _zoomFactor ) *  _this.center0.y;
+				_this.object.zoom *= factor;
 
 				if ( _this.staticMoving ) {
 
@@ -203,39 +256,54 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 				}
 
+				_changed = true;
+
 			}
 
 		}
 
 	};
 
-	this.panCamera = function () {
+	this.panCamera = (function(){
 
-		var mouseChange = _panEnd.clone().sub( _panStart );
+		var mouseChange = new THREE.Vector2(),
+			objectUp = new THREE.Vector3(),
+			pan = new THREE.Vector3();
 
-		if ( mouseChange.lengthSq() ) {
+		return function () {
 
-			mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
+			mouseChange.copy( _panEnd ).sub( _panStart );
 
-			var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x );
-			pan.add( _this.object.up.clone().setLength( mouseChange.y ) );
+			if ( mouseChange.lengthSq() ) {
 
-			_this.object.position.add( pan );
-			_this.target.add( pan );
+				// Scale movement to keep clicked/dragged position under cursor
+				var scale_x = ( _this.object.right - _this.object.left ) / _this.object.zoom;
+				var scale_y = ( _this.object.top - _this.object.bottom ) / _this.object.zoom;
+				mouseChange.x *= scale_x;
+				mouseChange.y *= scale_y;
 
-			if ( _this.staticMoving ) {
+				pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
+				pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );
 
-				_panStart = _panEnd;
+				_this.object.position.add( pan );
+				_this.target.add( pan );
 
-			} else {
+				if ( _this.staticMoving ) {
 
-				_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
+					_panStart.copy( _panEnd );
 
-			}
+				} else {
+
+					_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
 
+				}
+
+				_changed = true;
+
+			}
 		}
 
-	};
+	}());
 
 	this.update = function () {
 
@@ -250,7 +318,12 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		if ( !_this.noZoom ) {
 
 			_this.zoomCamera();
-			_this.object.updateProjectionMatrix();
+
+			if ( _changed ) {
+
+				_this.object.updateProjectionMatrix();
+
+			}
 
 		}
 
@@ -264,11 +337,11 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		_this.object.lookAt( _this.target );
 
-		if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {
+		if ( _changed ) {
 
 			_this.dispatchEvent( changeEvent );
 
-			lastPosition.copy( _this.object.position );
+			_changed = false;
 
 		}
 
@@ -294,7 +367,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		_this.dispatchEvent( changeEvent );
 
-		lastPosition.copy( _this.object.position );
+		_changed = false;
 
 	};
 
@@ -353,21 +426,26 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		if ( _state === STATE.ROTATE && !_this.noRotate ) {
 
-			_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
+			_rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );
+			_rotateEnd.copy( _rotateStart );
 
 		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {
 
-			_zoomStart = _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
+			_zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
+			_zoomEnd.copy(_zoomStart);
 
 		} else if ( _state === STATE.PAN && !_this.noPan ) {
 
-			_panStart = _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
+			_panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
+			_panEnd.copy(_panStart)
 
 		}
 
 		document.addEventListener( 'mousemove', mousemove, false );
 		document.addEventListener( 'mouseup', mouseup, false );
 
+		_this.dispatchEvent( startEvent );
+
 	}
 
 	function mousemove( event ) {
@@ -379,15 +457,15 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		if ( _state === STATE.ROTATE && !_this.noRotate ) {
 
-			_rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
+			_rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );
 
 		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {
 
-			_zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
+			_zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
 
 		} else if ( _state === STATE.PAN && !_this.noPan ) {
 
-			_panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
+			_panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
 
 		}
 
@@ -404,6 +482,7 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 		document.removeEventListener( 'mousemove', mousemove );
 		document.removeEventListener( 'mouseup', mouseup );
+		_this.dispatchEvent( endEvent );
 
 	}
 
@@ -427,6 +506,8 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		}
 
 		_zoomStart.y += delta * 0.01;
+		_this.dispatchEvent( startEvent );
+		_this.dispatchEvent( endEvent );
 
 	}
 
@@ -438,25 +519,27 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 			case 1:
 				_state = STATE.TOUCH_ROTATE;
-				_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				_rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
+				_rotateEnd.copy( _rotateStart );
 				break;
 
 			case 2:
-				_state = STATE.TOUCH_ZOOM;
+				_state = STATE.TOUCH_ZOOM_PAN;
 				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
 				_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
-				break;
 
-			case 3:
-				_state = STATE.TOUCH_PAN;
-				_panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
+				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
+				_panStart.copy( getMouseOnScreen( x, y ) );
+				_panEnd.copy( _panStart );
 				break;
 
 			default:
 				_state = STATE.NONE;
 
 		}
+		_this.dispatchEvent( startEvent );
 
 	}
 
@@ -470,17 +553,17 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		switch ( event.touches.length ) {
 
 			case 1:
-				_rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
 				break;
 
 			case 2:
 				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
 				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
-				_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
-				break;
+				_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
 
-			case 3:
-				_panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
+				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
+				_panEnd.copy( getMouseOnScreen( x, y ) );
 				break;
 
 			default:
@@ -497,20 +580,23 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 		switch ( event.touches.length ) {
 
 			case 1:
-				_rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
+				_rotateStart.copy( _rotateEnd );
 				break;
 
 			case 2:
 				_touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
-				break;
 
-			case 3:
-				_panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
+				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
+				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
+				_panEnd.copy( getMouseOnScreen( x, y ) );
+				_panStart.copy( _panEnd );
 				break;
 
 		}
 
 		_state = STATE.NONE;
+		_this.dispatchEvent( endEvent );
 
 	}
 
@@ -530,6 +616,9 @@ THREE.OrthographicTrackballControls = function ( object, domElement ) {
 
 	this.handleResize();
 
+	// force an update at start
+	this.update();
+
 };
 
 THREE.OrthographicTrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );

+ 10 - 10
examples/js/controls/TransformControls.js

@@ -97,7 +97,7 @@
 
 			//// PLANES
 
-			var planeGeometry = new THREE.PlaneGeometry( 50, 50, 2, 2 );
+			var planeGeometry = new THREE.PlaneBufferGeometry( 50, 50, 2, 2 );
 			var planeMaterial = new THREE.MeshBasicMaterial( { wireframe: true } );
 			planeMaterial.side = THREE.DoubleSide;
 
@@ -154,10 +154,10 @@
 				if (child instanceof THREE.Mesh) {
 					child.updateMatrix();
 
-					var tempGeometry = new THREE.Geometry();
-					tempGeometry.merge( child.geometry, child.matrix );
-
+					var tempGeometry = child.geometry.clone();
+					tempGeometry.applyMatrix( child.matrix );
 					child.geometry = tempGeometry;
+
 					child.position.set( 0, 0, 0 );
 					child.rotation.set( 0, 0, 0 );
 					child.scale.set( 1, 1, 1 );
@@ -251,13 +251,13 @@
 				[ new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, 0, 0 ] ]
 			],
 			XY: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.15, 0.15, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.15, 0.15, 0 ] ]
 			],
 			YZ: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.15, 0.15 ], [ 0, Math.PI/2, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.15, 0.15 ], [ 0, Math.PI/2, 0 ] ]
 			],
 			XZ: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.15, 0, 0.15 ], [ -Math.PI/2, 0, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.15, 0, 0.15 ], [ -Math.PI/2, 0, 0 ] ]
 			]
 		};
 
@@ -275,13 +275,13 @@
 				[ new THREE.Mesh( new THREE.OctahedronGeometry( 0.2, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ]
 			],
 			XY: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.2, 0.2, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.2, 0.2, 0 ] ]
 			],
 			YZ: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.2, 0.2 ], [ 0, Math.PI/2, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.2, 0.2 ], [ 0, Math.PI/2, 0 ] ]
 			],
 			XZ: [
-				[ new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.2, 0, 0.2 ], [ -Math.PI/2, 0, 0 ] ]
+				[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.2, 0, 0.2 ], [ -Math.PI/2, 0, 0 ] ]
 			]
 		};
 

+ 12 - 12
examples/js/crossfade/scenes.js

@@ -1,7 +1,7 @@
 function generateGeometry(objectType, numObjects) {
 
 	var geometry = new THREE.Geometry();
-	
+
 	function applyVertexColors( g, c ) {
 
 		g.faces.forEach( function( f ) {
@@ -19,7 +19,7 @@ function generateGeometry(objectType, numObjects) {
 	}
 
 	for ( var i = 0; i < numObjects; i ++ ) {
-	
+
 		var position = new THREE.Vector3();
 
 		position.x = Math.random() * 10000 - 5000;
@@ -51,7 +51,7 @@ function generateGeometry(objectType, numObjects) {
 			scale.y = scale.z = scale.x;
 			color.setRGB( Math.random()+0.1, 0, 0 );
 		}
-		
+
 		// give the geom's vertices a random color, to be displayed
 		applyVertexColors( geom, color );
 
@@ -70,12 +70,12 @@ function generateGeometry(objectType, numObjects) {
 }
 
 function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
-	
+
 	this.clearColor = clearColor;
-	
+
 	this.camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 10000 );
 	this.camera.position.z = cameraZ;
-	
+
 	// Setup scene
 	this.scene = new THREE.Scene();
 	this.scene.add( new THREE.AmbientLight( 0x555555 ) );
@@ -91,19 +91,19 @@ function Scene ( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
 
 	renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
 	this.fbo = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
-	
+
 	this.render = function( delta, rtt ) {
-		
+
 		this.mesh.rotation.x += delta*this.rotationSpeed.x;
 		this.mesh.rotation.y += delta*this.rotationSpeed.y;
 		this.mesh.rotation.z += delta*this.rotationSpeed.z;
-		
-		renderer.setClearColor( this.clearColor, 1 );
-		
+
+		renderer.setClearColor( this.clearColor );
+
 		if (rtt)
 			renderer.render( this.scene, this.camera, this.fbo, true );
 		else
 			renderer.render( this.scene, this.camera );
-		
+
 	};
 }

+ 0 - 220
examples/js/effects/OculusRiftEffect.js

@@ -1,220 +0,0 @@
-/**
- * @author troffmo5 / http://github.com/troffmo5
- *
- * Effect to render the scene in stereo 3d side by side with lens distortion.
- * It is written to be used with the Oculus Rift (http://www.oculusvr.com/) but
- * it works also with other HMD using the same technology
- */
-
-THREE.OculusRiftEffect = function ( renderer, options ) {
-	// worldFactor indicates how many units is 1 meter
-	var worldFactor = (options && options.worldFactor) ? options.worldFactor: 1.0;
-
-	// Specific HMD parameters
-	var HMD = (options && options.HMD) ? options.HMD: {
-		// DK1
-		/*
-		hResolution: 1280,
-		vResolution: 800,
-		hScreenSize: 0.14976,
-		vScreenSize: 0.0936,
-		interpupillaryDistance: 0.064,
-		lensSeparationDistance: 0.064,
-		eyeToScreenDistance: 0.041,
-		distortionK : [1.0, 0.22, 0.24, 0.0],
-		chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
-		*/
-		// DK2
-		hResolution: 1920,
-		vResolution: 1080,
-		hScreenSize: 0.12576,
-		vScreenSize: 0.07074,
-		interpupillaryDistance: 0.0635,
-		lensSeparationDistance: 0.0635,
-		eyeToScreenDistance: 0.041,
-		distortionK : [1.0, 0.22, 0.24, 0.0],
-		chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
-	};
-	this.HMD = HMD;
-
-	// Perspective camera
-	var pCamera = new THREE.PerspectiveCamera();
-	pCamera.matrixAutoUpdate = false;
-	pCamera.target = new THREE.Vector3();
-
-	// Orthographic camera
-	var oCamera = new THREE.OrthographicCamera( -1, 1, 1, -1, 1, 1000 );
-	oCamera.position.z = 1;
-
-	// pre-render hooks
-	this.preLeftRender = function() {};
-	this.preRightRender = function() {};
-
-	renderer.autoClear = false;
-	var emptyColor = new THREE.Color("black");
-
-	// Render target
-	var RTParams = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };
-	var renderTarget = new THREE.WebGLRenderTarget( 640, 800, RTParams );
-	var RTMaterial = new THREE.ShaderMaterial( {
-		uniforms: {
-			"texid": { type: "t", value: renderTarget },
-			"scale": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
-			"scaleIn": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
-			"lensCenter": { type: "v2", value: new THREE.Vector2(0.0,0.0) },
-			"hmdWarpParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) },
-			"chromAbParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) }
-		},
-		vertexShader: [
-			"varying vec2 vUv;",
-			"void main() {",
-			" vUv = uv;",
-			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
-			"}"
-		].join("\n"),
-
-		fragmentShader: [
-			"uniform vec2 scale;",
-			"uniform vec2 scaleIn;",
-			"uniform vec2 lensCenter;",
-			"uniform vec4 hmdWarpParam;",
-			'uniform vec4 chromAbParam;',
-			"uniform sampler2D texid;",
-			"varying vec2 vUv;",
-			"void main()",
-			"{",
-			"  vec2 uv = (vUv*2.0)-1.0;", // range from [0,1] to [-1,1]
-			"  vec2 theta = (uv-lensCenter)*scaleIn;",
-			"  float rSq = theta.x*theta.x + theta.y*theta.y;",
-			"  vec2 rvector = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq);",
-			'  vec2 rBlue = rvector * (chromAbParam.z + chromAbParam.w * rSq);',
-			"  vec2 tcBlue = (lensCenter + scale * rBlue);",
-			"  tcBlue = (tcBlue+1.0)/2.0;", // range from [-1,1] to [0,1]
-			"  if (any(bvec2(clamp(tcBlue, vec2(0.0,0.0), vec2(1.0,1.0))-tcBlue))) {",
-			"    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);",
-			"    return;}",
-			"  vec2 tcGreen = lensCenter + scale * rvector;",
-			"  tcGreen = (tcGreen+1.0)/2.0;", // range from [-1,1] to [0,1]
-			"  vec2 rRed = rvector * (chromAbParam.x + chromAbParam.y * rSq);",
-			"  vec2 tcRed = lensCenter + scale * rRed;",
-			"  tcRed = (tcRed+1.0)/2.0;", // range from [-1,1] to [0,1]
-			"  gl_FragColor = vec4(texture2D(texid, tcRed).r, texture2D(texid, tcGreen).g, texture2D(texid, tcBlue).b, 1);",
-			"}"
-		].join("\n")
-	} );
-
-	var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), RTMaterial );
-
-	// Final scene
-	var finalScene = new THREE.Scene();
-	finalScene.add( oCamera );
-	finalScene.add( mesh );
-
-    var left = {}, right = {};
-    var distScale = 1.0;
-	this.setHMD = function(v) {
-		HMD = v;
-		// Compute aspect ratio and FOV
-		var aspect = HMD.hResolution / (2*HMD.vResolution);
-
-		// Fov is normally computed with:
-		//   THREE.Math.radToDeg( 2*Math.atan2(HMD.vScreenSize,2*HMD.eyeToScreenDistance) );
-		// But with lens distortion it is increased (see Oculus SDK Documentation)
-		var r = -1.0 - (4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize);
-		distScale = (HMD.distortionK[0] + HMD.distortionK[1] * Math.pow(r,2) + HMD.distortionK[2] * Math.pow(r,4) + HMD.distortionK[3] * Math.pow(r,6));
-		var fov = THREE.Math.radToDeg(2*Math.atan2(HMD.vScreenSize*distScale, 2*HMD.eyeToScreenDistance));
-
-		// Compute camera projection matrices
-		var proj = (new THREE.Matrix4()).makePerspective( fov, aspect, 0.3, 10000 );
-		var h = 4 * (HMD.hScreenSize/4 - HMD.interpupillaryDistance/2) / HMD.hScreenSize;
-		left.proj = ((new THREE.Matrix4()).makeTranslation( h, 0.0, 0.0 )).multiply(proj);
-		right.proj = ((new THREE.Matrix4()).makeTranslation( -h, 0.0, 0.0 )).multiply(proj);
-
-		// Compute camera transformation matrices
-		left.tranform = (new THREE.Matrix4()).makeTranslation( -worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
-		right.tranform = (new THREE.Matrix4()).makeTranslation( worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
-
-		// Compute Viewport
-		left.viewport = [0, 0, HMD.hResolution/2, HMD.vResolution];
-		right.viewport = [HMD.hResolution/2, 0, HMD.hResolution/2, HMD.vResolution];
-
-		// Distortion shader parameters
-		var lensShift = 4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize;
-		left.lensCenter = new THREE.Vector2(lensShift, 0.0);
-		right.lensCenter = new THREE.Vector2(-lensShift, 0.0);
-
-		RTMaterial.uniforms['hmdWarpParam'].value = new THREE.Vector4(HMD.distortionK[0], HMD.distortionK[1], HMD.distortionK[2], HMD.distortionK[3]);
-		RTMaterial.uniforms['chromAbParam'].value = new THREE.Vector4(HMD.chromaAbParameter[0], HMD.chromaAbParameter[1], HMD.chromaAbParameter[2], HMD.chromaAbParameter[3]);
-		RTMaterial.uniforms['scaleIn'].value = new THREE.Vector2(1.0,1.0/aspect);
-		RTMaterial.uniforms['scale'].value = new THREE.Vector2(1.0/distScale, 1.0*aspect/distScale);
-
-		// Create render target
-		if ( renderTarget ) renderTarget.dispose();
-		renderTarget = new THREE.WebGLRenderTarget( HMD.hResolution * distScale / 2, HMD.vResolution * distScale, RTParams );
-		RTMaterial.uniforms[ "texid" ].value = renderTarget;
-
-	}
-	this.getHMD = function() {return HMD};
-
-	this.setHMD(HMD);
-
-	this.setSize = function ( width, height ) {
-		left.viewport = [width/2 - HMD.hResolution/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
-		right.viewport = [width/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
-
-		renderer.setSize( width, height );
-	};
-
-	this.render = function ( scene, camera ) {
-		var cc = renderer.getClearColor().clone();
-
-		// Clear
-		renderer.setClearColor(emptyColor);
-		renderer.clear();
-		renderer.setClearColor(cc);
-
-		// camera parameters
-		if (camera.matrixAutoUpdate) camera.updateMatrix();
-
-		// Render left
-		this.preLeftRender();
-
-		pCamera.projectionMatrix.copy(left.proj);
-
-		pCamera.matrix.copy(camera.matrix).multiply(left.tranform);
-		pCamera.matrixWorldNeedsUpdate = true;
-
-		renderer.setViewport(left.viewport[0], left.viewport[1], left.viewport[2], left.viewport[3]);
-
-		RTMaterial.uniforms['lensCenter'].value = left.lensCenter;
-		renderer.render( scene, pCamera, renderTarget, true );
-
-		renderer.render( finalScene, oCamera );
-
-		// Render right
-		this.preRightRender();
-
-		pCamera.projectionMatrix.copy(right.proj);
-
-		pCamera.matrix.copy(camera.matrix).multiply(right.tranform);
-		pCamera.matrixWorldNeedsUpdate = true;
-
-		renderer.setViewport(right.viewport[0], right.viewport[1], right.viewport[2], right.viewport[3]);
-
-		RTMaterial.uniforms['lensCenter'].value = right.lensCenter;
-
-		renderer.render( scene, pCamera, renderTarget, true );
-		renderer.render( finalScene, oCamera );
-
-	};
-
-	this.dispose = function() {
-		if ( RTMaterial ) {
-			RTMaterial.dispose();
-		}
-		if ( renderTarget ) {
-			renderTarget.dispose();
-		}
-	};
-
-};

+ 5 - 1
examples/js/effects/StereoEffect.js

@@ -122,15 +122,19 @@ THREE.StereoEffect = function ( renderer ) {
 
 		//
 
-		renderer.setViewport( 0, 0, _width * 2, _height );
 		renderer.clear();
+		renderer.enableScissorTest( true );
 
+		renderer.setScissor( 0, 0, _width, _height );
 		renderer.setViewport( 0, 0, _width, _height );
 		renderer.render( scene, _cameraL );
 
+		renderer.setScissor( _width, 0, _width, _height );
 		renderer.setViewport( _width, 0, _width, _height );
 		renderer.render( scene, _cameraR );
 
+		renderer.enableScissorTest( false );
+
 	};
 
 };

+ 15 - 15
examples/js/exporters/SceneExporter.js

@@ -238,11 +238,12 @@ THREE.SceneExporter.prototype = {
 				var output = [
 
 				'\t\t' + LabelString( getObjectName( o ) ) + ' : {',
-				'	"type"      : "PointLight",',
-				'	"color"     : ' + o.color.getHex() + ',',
-				'	"intensity" : ' + o.intensity + ',',
-				'	"position"  : ' + Vector3String( o.position ) + ',',
-				'	"distance"  : ' + o.distance + ( o.children.length ? ',' : '' )
+				'	"type"           : "PointLight",',
+				'	"color"          : ' + o.color.getHex() + ',',
+				'	"intensity"      : ' + o.intensity + ',',
+				'	"position"       : ' + Vector3String( o.position ) + ',',
+				'	"decay"          : ' + o.decay + ',',
+				'	"distance"       : ' + o.distance + ( o.children.length ? ',' : '' )
 
 				];
 
@@ -251,14 +252,15 @@ THREE.SceneExporter.prototype = {
 				var output = [
 
 				'\t\t' + LabelString( getObjectName( o ) ) + ' : {',
-				'	"type"      : "SpotLight",',
-				'	"color"     : ' + o.color.getHex() + ',',
-				'	"intensity" : ' + o.intensity + ',',
-				'	"position"  : ' + Vector3String( o.position ) + ',',
-				'	"distance"  : ' + o.distance + ',',
-				'	"angle"     : ' + o.angle + ',',
-				'	"exponent"  : ' + o.exponent + ',',
-				'	"target"    : ' + LabelString( getObjectName( o.target ) ) + ( o.children.length ? ',' : '' )
+				'	"type"           : "SpotLight",',
+				'	"color"          : ' + o.color.getHex() + ',',
+				'	"intensity"      : ' + o.intensity + ',',
+				'	"position"       : ' + Vector3String( o.position ) + ',',
+				'	"distance"       : ' + o.distance + ',',
+				'	"angle"          : ' + o.angle + ',',
+				'	"exponent"       : ' + o.exponent + ',',
+				'	"decay"          : ' + o.decay + ',',
+				'	"target"         : ' + LabelString( getObjectName( o.target ) ) + ( o.children.length ? ',' : '' )
 
 				];
 
@@ -472,7 +474,6 @@ THREE.SceneExporter.prototype = {
 				'	"type"    : "MeshLambertMaterial",',
 				'	"parameters"  : {',
 				'		"color"  : ' 	+ m.color.getHex() + ',',
-				'		"ambient"  : ' 	+ m.ambient.getHex() + ',',
 				'		"emissive"  : ' + m.emissive.getHex() + ',',
 
 				m.map ? 		'		"map" : ' + LabelString( getTextureName( m.map ) ) + ',' : '',
@@ -498,7 +499,6 @@ THREE.SceneExporter.prototype = {
 				'	"type"    : "MeshPhongMaterial",',
 				'	"parameters"  : {',
 				'		"color"  : ' 	+ m.color.getHex() + ',',
-				'		"ambient"  : ' 	+ m.ambient.getHex() + ',',
 				'		"emissive"  : ' + m.emissive.getHex() + ',',
 				'		"specular"  : ' + m.specular.getHex() + ',',
 				'		"shininess" : ' + m.shininess + ',',

+ 0 - 7
examples/js/loaders/AssimpJSONLoader.js

@@ -264,9 +264,6 @@ THREE.AssimpJSONLoader.prototype = {
 			else if(prop.key === '$clr.specular') {
 				init_props.specular = toColor(prop.value);
 			}
-			else if(prop.key === '$clr.ambient') {
-				init_props.ambient = toColor(prop.value);
-			}
 			else if(prop.key === '$clr.emissive') {
 				init_props.emissive = toColor(prop.value);
 			}
@@ -281,10 +278,6 @@ THREE.AssimpJSONLoader.prototype = {
 			}
 		}
 
-		if(!init_props.ambient) {
-			init_props.ambient = init_props.color;
-		}
-
 		// note: three.js does not like it when a texture is added after the geometry
 		// has been rendered once, see http://stackoverflow.com/questions/16531759/.
 		// for this reason we fill all slots upfront with default textures

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

@@ -51,7 +51,6 @@ THREE.BabylonLoader.prototype = {
 
 			var material = new THREE.MeshPhongMaterial();
 			material.name = data.name;
-			material.ambient.fromArray( data.ambient );
 			material.color.fromArray( data.diffuse );
 			material.emissive.fromArray( data.emissive );
 			material.specular.fromArray( data.specular );

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

@@ -25,7 +25,7 @@ THREE.ColladaLoader = function () {
 	var animData;
 	var kinematics;
 	var visualScenes;
-	var kinematicsModel;
+	var kinematicsModels;
 	var baseUrl;
 	var morphs;
 	var skins;
@@ -3584,7 +3584,6 @@ THREE.ColladaLoader = function () {
 
 			switch ( child.nodeName ) {
 
-				case 'ambient':
 				case 'emission':
 				case 'diffuse':
 				case 'specular':

+ 14 - 3
examples/js/loaders/MTLLoader.js

@@ -87,6 +87,7 @@ THREE.MTLLoader.prototype = {
 		}
 
 		var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
+		materialCreator.crossOrigin = this.crossOrigin
 		materialCreator.setMaterials( materialsInfo );
 		return materialCreator;
 
@@ -296,8 +297,6 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					// Ambient color (color under shadow) using RGB values
 
-					params[ 'ambient' ] = new THREE.Color().fromArray( value );
-
 					break;
 
 				case 'ks':
@@ -341,6 +340,19 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					break;
 
+				case 'map_bump':
+				case 'bump':
+
+					// Bump texture map
+
+					if ( params[ 'bumpMap' ] ) break; // Avoid loading twice.
+
+					params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value );
+					params[ 'bumpMap' ].wrapS = this.wrap;
+					params[ 'bumpMap' ].wrapT = this.wrap;
+
+					break;
+
 				default:
 					break;
 
@@ -350,7 +362,6 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 		if ( params[ 'diffuse' ] ) {
 
-			if ( !params[ 'ambient' ]) params[ 'ambient' ] = params[ 'diffuse' ];
 			params[ 'color' ] = params[ 'diffuse' ];
 
 		}

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

@@ -20,13 +20,14 @@ THREE.OBJMTLLoader.prototype = {
 		var scope = this;
 
 		var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) );
+		mtlLoader.crossOrigin = scope.crossOrigin;
 		mtlLoader.load( mtlurl, function ( materials ) {
 
 			var materialsCreator = materials;
 			materialsCreator.preload();
 
 			var loader = new THREE.XHRLoader( scope.manager );
-			loader.setCrossOrigin( this.crossOrigin );
+			loader.setCrossOrigin( scope.crossOrigin );
 			loader.load( url, function ( text ) {
 
 				var object = scope.parse( text );

+ 21 - 1
examples/js/loaders/STLLoader.js

@@ -61,7 +61,27 @@ THREE.STLLoader.prototype = {
 			face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);
 			n_faces = reader.getUint32(80,true);
 			expect = 80 + (32 / 8) + (n_faces * face_size);
-			return expect === reader.byteLength;
+			
+			if ( expect === reader.byteLength ) {
+				
+				return true;
+				
+			}
+
+			// some binary files will have different size from expected,
+			// checking characters higher than ASCII to confirm is binary
+			var fileLength = reader.byteLength;
+			for ( var index = 0; index < fileLength; index ++ ) {
+
+				if ( reader.getUint8(index, false) > 127 ) {
+					
+					return true;
+					
+				}
+
+			}
+
+			return false;
 
 		};
 

+ 0 - 5
examples/js/loaders/gltf/glTFLoader.js

@@ -785,11 +785,6 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
                 	params.shininess = shininess;
                 }
                 
-                if (!(values.ambient === undefined) && !(typeof(values.ambient) == 'string'))
-                {
-                	params.ambient = RgbArraytoHex(values.ambient);
-                }
-
                 if (!(values.emission === undefined))
                 {
                 	params.emissive = RgbArraytoHex(values.emission);

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác