Browse Source

Editor: Reverting to simpler version.

Mr.doob 12 years ago
parent
commit
7932fb515d

+ 34 - 80
editor/index.html

@@ -65,11 +65,12 @@
 			}
 
 			.sidebar {
+				width: 300px;
 				background-color: #eee;
 				overflow: auto;
 			}
 
-				.sidebar .Text {
+				.sidebar .Panel {
 					margin-bottom: 10px;
 				}
 
@@ -98,8 +99,7 @@
 		<script src="../examples/js/renderers/SoftwareRenderer.js"></script>
 		<script src="../examples/js/renderers/SVGRenderer.js"></script>
 
-		<script src="../examples/js/loaders/deprecated/ObjectLoader4.js"></script>
-		<script src="../examples/js/loaders/deprecated/ObjectLoader41.js"></script>
+		<!-- WIP -->
 
 		<script src="../examples/js/exporters/GeometryExporter.js"></script>
 		<script src="../examples/js/exporters/MaterialExporter.js"></script>
@@ -110,27 +110,26 @@
 		<script src="js/libs/ui.js"></script>
 		<script src="js/libs/ui.three.js"></script>
 
-		<script src="js/Editor.js"></script>
-
 		<script src="js/Loader.js"></script>
 		<script src="js/Menubar.js"></script>
 		<script src="js/Menubar.File.js"></script>
 		<script src="js/Menubar.Edit.js"></script>
 		<script src="js/Menubar.Add.js"></script>
 		<script src="js/Menubar.Help.js"></script>
-
 		<script src="js/Sidebar.js"></script>
 		<script src="js/Sidebar.Renderer.js"></script>
-
-		<script src="js/Sidebar.Outliner.js"></script>
-		<script src="js/Sidebar.Outliner.Scene.js"></script>
-		<script src="js/Sidebar.Outliner.Geometries.js"></script>
-		<script src="js/Sidebar.Outliner.Materials.js"></script>
-		<script src="js/Sidebar.Outliner.Textures.js"></script>
-
-		<script src="js/Sidebar.Attributes.js"></script>
+		<script src="js/Sidebar.Scene.js"></script>
+		<script src="js/Sidebar.Object3D.js"></script>
+		<script src="js/Sidebar.Geometry.js"></script>
 		<script src="js/Sidebar.Animation.js"></script>
-
+		<script src="js/Sidebar.Geometry.PlaneGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.CubeGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.CylinderGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.SphereGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.IcosahedronGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.TorusGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.TorusKnotGeometry.js"></script>
+		<script src="js/Sidebar.Material.js"></script>
 		<script src="js/Toolbar.js"></script>
 		<script src="js/Viewport.js"></script>
 
@@ -145,66 +144,53 @@
 
 				// actions
 
-				setRenderer: new SIGNALS.Signal(),
-				undo: new SIGNALS.Signal(),
-				redo: new SIGNALS.Signal(),
+				cloneSelectedObject: new SIGNALS.Signal(),
+				removeSelectedObject: new SIGNALS.Signal(),
 				playAnimations: new SIGNALS.Signal(),
-				setTransformMode: new SIGNALS.Signal(),
 
-				// editor events
+				// notifications
 
+				transformModeChanged: new SIGNALS.Signal(),
+				snapChanged: new SIGNALS.Signal(),
+				rendererChanged: new SIGNALS.Signal(),
+				sceneAdded: new SIGNALS.Signal(),
+				sceneChanged: new SIGNALS.Signal(),
 				objectAdded: new SIGNALS.Signal(),
-				geometryAdded: new SIGNALS.Signal(),
-				materialAdded: new SIGNALS.Signal(),
-				textureAdded: new SIGNALS.Signal(),
-
+				objectSelected: new SIGNALS.Signal(),
 				objectChanged: new SIGNALS.Signal(),
-				geometryChanged: new SIGNALS.Signal(),
 				materialChanged: new SIGNALS.Signal(),
-				textureChanged: new SIGNALS.Signal(),
-				sceneChanged: new SIGNALS.Signal(),
-				fogChanged: new SIGNALS.Signal(),
-				
-				objectDeleted: new SIGNALS.Signal(),
-				geometryDeleted: new SIGNALS.Signal(),
-				materialDeleted: new SIGNALS.Signal(),
-				textureDeleted: new SIGNALS.Signal(),
-				selected: new SIGNALS.Signal(),
-
-				/// viewport events
-								
-				snapChanged: new SIGNALS.Signal(),
 				clearColorChanged: new SIGNALS.Signal(),
+				fogTypeChanged: new SIGNALS.Signal(),
+				fogColorChanged: new SIGNALS.Signal(),
+				fogParametersChanged: new SIGNALS.Signal(),
 				windowResize: new SIGNALS.Signal()
 
 			};
 
 			//
 
-			var editor = new Editor();
-
-			var loader = new Loader( editor, signals );
+			var loader = new Loader( signals );
 
-			var viewport = new Viewport( editor, signals );
+			var viewport = new Viewport( signals );
 			viewport.setTop( '32px' );
 			viewport.setLeft( '0px' );
 			viewport.setRight( '300px' );
 			viewport.setBottom( '32px' );
 			document.body.appendChild( viewport.dom );
 
-			var toolbar = new Toolbar( editor, signals );
+			var toolbar = new Toolbar( signals );
 			toolbar.setBottom( '0px' );
 			toolbar.setLeft( '0px' );
 			toolbar.setRight( '300px' );
 			toolbar.setHeight( '32px' );
 			document.body.appendChild( toolbar.dom );
 
-			var menubar = new Menubar( editor, signals );
+			var menubar = new Menubar( signals );
 			menubar.setWidth( '100%' );
 			menubar.setHeight( '32px' );
 			document.body.appendChild( menubar.dom );
 
-			var sidebar = new Sidebar( editor, signals );
+			var sidebar = new Sidebar( signals );
 			sidebar.setRight( '0px' );
 			sidebar.setTop( '32px' );
 			sidebar.setBottom( '0px' );
@@ -217,34 +203,9 @@
 				switch ( event.keyCode ) {
 
 					case 46: // delete
-					case 8: // backspace
-
-						event.preventDefault();
-						editor.delete();
-						break;
-
-					case 37: // left arrow
-
-						event.preventDefault();
-						editor.pickWalk( 'left' );
-						break;
-
-					case 38: // up arrow
-
-						event.preventDefault();
-						editor.pickWalk( 'up' );
-						break;
-
-					case 39: // right arrow
 
-						event.preventDefault();
-						editor.pickWalk( 'right' );
-						break;
+						signals.removeSelectedObject.dispatch();
 
-					case 40: // down arrow
- 
-						event.preventDefault();
-						editor.pickWalk( 'down' );
 						break;
 
 					}
@@ -259,16 +220,9 @@
 
 			window.addEventListener( 'resize', onWindowResize, false );
 
-			document.addEventListener( "DOMContentLoaded", function(){
-    		
-    		onWindowResize();
-
-				loader.loadLocalStorage();
-
-    	}, false );
-
+			onWindowResize();
 
-			
+			loader.loadLocalStorage();
 
 		</script>
 	</body>

+ 0 - 1100
editor/js/Editor.js

@@ -1,1100 +0,0 @@
-var Editor = function ( scene ) {
-
-	this.geometries = {};
-	this.materials = {};
-	this.textures = {};
-	this.objects = {};
-
-	this.selected = {};
-	this.helpers = {};
-
-	this.scene = new THREE.Scene();
-	this.scene.name = ( scene && scene.name ) ? scene.name : 'Scene';
-	this.addObject( this.scene );
-
-	this.sceneHelpers = new THREE.Scene();
-
-	this.defaultMaterial = new THREE.MeshPhongMaterial();
-	this.defaultMaterial.name = 'Default Material';
-	this.addMaterial( this.defaultMaterial );
-
-}
-
-Editor.prototype = {
-
-	// Assets
-
-	setScene: function( scene ) {
-
-		this.deleteAll(); // WARNING! deletes everything 
-
-		if ( scene ) {
-
-			this.scene.name = scene.name;
-			this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) );
-
-			if ( scene.children.length ) this.addObject( scene.children );
-
-		}
-
-		signals.sceneChanged.dispatch( this.scene );
-
-		return this.scene 
-
-	},
-
-	createObject: function( type, parameters, material ) {
-
-		type = type ? type : 'Group';
-
-		var object;
-		var geometry;
-
-		material = material ? material : this.defaultMaterial;
-
-		parameters = parameters ? parameters : {};
-
-		var name = parameters.name ? parameters.name : this.incrementName( type, 'object' );
-		var color = parameters.color ? parameters.color : null;
-		var groundColor = parameters.groundColor ? parameters.groundColor : null;
-		var intensity = parameters.intensity ? parameters.intensity : null;
-		var distance = parameters.distance ? parameters.distance : null;
-		var angle = parameters.angle ? parameters.angle : null;
-		var exponent = parameters.exponent ? parameters.exponent : null;
-
-		if ( type == 'Group' ) {
-
-			object = new THREE.Object3D();
-
-		} else if ( type == 'Plane' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-			object.rotation.x = - Math.PI/2;
-
-		} else if ( type == 'Cube' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'Cylinder' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'Sphere' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'Icosahedron' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'Torus' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'TorusKnot' ) {
-
-			geometry = this.createGeometry( type, parameters );
-			object = new THREE.Mesh( geometry, this.defaultMaterial );
-
-		} else if ( type == 'PointLight' ) {
-
-			color = color ? color : 0xffffff;
-			intensity = intensity ? intensity : 1;
-			distance = distance ? distance : 0;
-
-			object = new THREE.PointLight( color, intensity, distance );
-
-		} else if ( type == 'SpotLight' ) {
-
-			color = color ? color : 0xffffff;
-			intensity = intensity ? intensity : 1;
-			distance = distance ? distance : 0;
-			angle = angle ? angle : Math.PI * 0.1;
-			exponent = exponent ? exponent : 10;
-
-			object = new THREE.SpotLight( color, intensity, distance, angle, exponent );
-			object.target.name = object.name + ' Target';
-
-			object.position.set( 0, 1, 0 ).multiplyScalar( 200 );
-
-		} else if ( type == 'DirectionalLight' ) {
-
-			color = color ? color : 0xffffff;
-			intensity = intensity ? intensity : 1;
-
-			object = new THREE.DirectionalLight( color, intensity );
-			object.target.name = object.name + ' Target';
-
-			object.position.set( 1, 1, 1 ).multiplyScalar( 200 );
-
-		} else if ( type == 'HemisphereLight' ) {
-
-			color = color ? color : 0x00aaff;
-			groundColor = groundColor ? groundColor : 0xffaa00;
-			intensity = intensity ? intensity : 1;
-
-			object = new THREE.HemisphereLight( color, groundColor, intensity );
-
-			object.position.set( 1, 1, 1 ).multiplyScalar( 200 );
-
-		} else if ( type == 'AmbientLight' ) {
-
-			color = color ? color : 0x222222;
-
-			object = new THREE.AmbientLight( color );
-
-		}
-
-		object.name = name;
-		this.addObject( object );
-
-		return object;
-
-	},
-
-	createGeometry: function( type, parameters ) {
-
-		type = type ? type : 'Geometry';
-		parameters = parameters ? parameters : {};
-
-		var name = parameters.name ? parameters.name : this.incrementName( type + 'Geometry', 'geometry' );
-		var width = parameters.width ? parameters.width : null;
-		var height = parameters.height ? parameters.height : null;
-		var depth = parameters.depth ? parameters.depth : null;
-		var widthSegments = parameters.widthSegments ? parameters.widthSegments : null;
-		var heightSegments = parameters.heightSegments ? parameters.heightSegments : null;
-		var depthSegments = parameters.depthSegments ? parameters.depthSegments : null;
-		var radialSegments = parameters.radialSegments ? parameters.radialSegments : null;
-		var tubularSegments = parameters.tubularSegments ? parameters.tubularSegments : null;
-		var radius = parameters.radius ? parameters.radius : null;
-		var radiusTop = parameters.radiusTop ? parameters.radiusTop : null;
-		var radiusBottom = parameters.radiusBottom ? parameters.radiusBottom : null;
-		var phiStart = parameters.phiStart ? parameters.phiStart : null;
-		var phiLength = parameters.phiLength ? parameters.phiLength : null;
-		var thetaStart = parameters.thetaStart ? parameters.thetaStart : null;
-		var thetaLength = parameters.thetaLength ? parameters.thetaLength : null;
-		var tube = parameters.tube ? parameters.tube : null;
-		var arc = parameters.arc ? parameters.arc : null;
-		var detail = parameters.detail ? parameters.detail : null;
-		var p = parameters.p ? parameters.p : null;
-		var q = parameters.q ? parameters.q : null;
-		var heightScale = parameters.heightScale ? parameters.heightScale : null;
-		var openEnded = parameters.openEnded ? parameters.openEnded : false;
-
-		var geometry;
-
-		if ( type == 'Geometry' ) {
-
-			geometry = new THREE.Geometry();
-
-		} else if ( type == 'Plane' ) {
-
-			width = width ? width : 200;
-			height = height ? height : 200;
-			widthSegments = widthSegments ? widthSegments : 1;
-			heightSegments = heightSegments ? heightSegments : 1;
-
-			geometry = new THREE.PlaneGeometry( width, height, widthSegments, heightSegments );
-
-		} else if ( type == 'Cube' ) {
-
-			width = width ? width : 100;
-			height = height ? height : 100;
-			depth = depth ? depth : 100;
-			widthSegments = widthSegments ? widthSegments : 1;
-			heightSegments = heightSegments ? heightSegments : 1;
-			depthSegments = depthSegments ? depthSegments : 1;
-
-			geometry = new THREE.CubeGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
-
-		} else if ( type == 'Cylinder' ) {
-
-			radiusTop = radiusTop ? radiusTop : 20;
-			radiusBottom = radiusBottom ? radiusBottom : 20;
-			height = height ? height : 100;
-			radialSegments = radialSegments ? radialSegments : 8;
-			heightSegments = heightSegments ? heightSegments : 1;
-			openEnded = openEnded ? openEnded : false;
-
-			geometry = new THREE.CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded );
-
-		} else if ( type == 'Sphere' ) {
-
-			radius = radius ? radius : 75;
-			widthSegments = widthSegments ? widthSegments : 32;
-			heightSegments = heightSegments ? heightSegments : 16;
-			widthSegments = widthSegments ? widthSegments : 32;
-			heightSegments = heightSegments ? heightSegments : 16;
-			phiStart = phiStart ? phiStart : 0;
-			phiLength = phiLength ? phiLength : Math.PI * 2;
-			thetaStart = thetaStart ? thetaStart : 0;
-			thetaLength = thetaLength ? thetaLength : Math.PI;
-
-			geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength );
-
-		} else if ( type == 'Icosahedron' ) {
-
-			radius = radius ? radius : 75;
-			detail = detail ? detail : 2;
-
-			geometry = new THREE.IcosahedronGeometry ( radius, detail );
-
-		} else if ( type == 'Torus' ) {
-
-			radius = radius ? radius : 100;
-			tube = tube ? tube : 40;
-			radialSegments = radialSegments ? radialSegments : 8;
-			tubularSegments = tubularSegments ? tubularSegments : 6;
-			arc = arc ? arc : Math.PI * 2;
-
-			geometry = new THREE.TorusGeometry( radius, tube, radialSegments, tubularSegments, arc );
-
-		} else if ( type == 'TorusKnot' ) {
-
-			radius = radius ? radius : 100;
-			tube = tube ? tube : 40;
-			radialSegments = radialSegments ? radialSegments : 64;
-			tubularSegments = tubularSegments ? tubularSegments : 8;
-			p = p ? p : 2;
-			q = q ? q : 3;
-			heightScale = heightScale ? heightScale : 1;
-
-			geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale );
-
-		}
-
-		geometry.name = name;
-		geometry.computeBoundingSphere();
-
-		return geometry;
-
-	},
-
-	createMaterial: function( type, parameters ) {
-
-		type = type ? type : 'MeshPhongMaterial';
-
-		parameters = parameters ? parameters : {};
-
-		var material;
-		var name = parameters.name ? parameters.name : this.incrementName( type, 'material' );
-
-		if ( type == 'MeshPhongMaterial' ) {
-
-			material = new THREE.MeshPhongMaterial( parameters );
-
-		} else if ( type == 'MeshLambertMaterial' ) {
-
-			material = new THREE.MeshLambertMaterial( parameters );
-
-		} else if ( type == 'MeshNormalMaterial' ) {
-
-			material = new THREE.MeshNormalMaterial( parameters );
-
-		} else if ( type == 'MeshBasicMaterial' ) {
-
-			material = new THREE.MeshBasicMaterial( parameters );
-
-		}
-
-		material.name = name;
-		this.addMaterial( material );
-		return material;
-
-	},
-
-	createTexture: function( image, parameters ) {
-
-		image = image ? image : '../examples/textures/ash_uvgrid01.jpg';
-
-		parameters = parameters ? parameters : {};
-
-		// TODO: implement parameters
-
-		var texture = THREE.ImageUtils.loadTexture( image );
-		texture.name = parameters.name ? parameters.name : this.incrementName( 'Texture', 'texture' );
-
-		this.addTexture( texture );
-		return texture;
-
-	},
-
-	addObject: function( list, parent ) {
-
-		list = ( list instanceof Array ) ? [].concat( list ) : [ list ];
-
-		parent = parent ? parent : this.scene;
-
-		for ( var i in list ) {
-
-			this.objects[ list[ i ].id ] = list[ i ];
-			this.addHelper( list[ i ] );
-
-			if ( list[ i ].target ) {
-
-				this.objects[ list[ i ].target.id ] = list[ i ].target;
-
-			}
-
-			if ( list[ i ].material ) this.addMaterial( list[ i ].material );
-			if ( list[ i ].geometry ) this.addGeometry( list[ i ].geometry );
-
-			if ( parent != list[ i ] ) {
-
-				// Add object to the scene
-
-				parent.add( list[ i ] );
-
-				if ( list[ i ] instanceof THREE.Light ) this.updateMaterials();
-
-				signals.objectAdded.dispatch( list[ i ] );
-
-				// Continue adding children
-
-				if ( list[ i ].children && list[ i ].children.length ) {
-
-					this.addObject( list[ i ].children, list[ i ] );
-
-				}
-
-			}
-
-		}
-
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	addHelper: function( object ) {
-
-		if ( object instanceof THREE.PointLight ) {
-
-			this.helpers[ object.id ] = new THREE.PointLightHelper( object, 10 );
-			this.sceneHelpers.add( this.helpers[ object.id ] );
-			this.helpers[ object.id ].lightSphere.id = object.id;
-
-		} else if ( object instanceof THREE.DirectionalLight ) {
-
-			this.helpers[ object.id ] = new THREE.DirectionalLightHelper( object, 10 );
-			this.sceneHelpers.add( this.helpers[ object.id ] );
-			this.helpers[ object.id ].lightSphere.id = object.id;
-
-		} else if ( object instanceof THREE.SpotLight ) {
-
-			this.helpers[ object.id ] = new THREE.SpotLightHelper( object, 10 );
-			this.sceneHelpers.add( this.helpers[ object.id ] );
-			// this.helpers[ object.id ].lightSphere.id = object.id;
-
-		} else if ( object instanceof THREE.HemisphereLight ) {
-
-			this.helpers[ object.id ] = new THREE.HemisphereLightHelper( object, 10 );
-			this.sceneHelpers.add( this.helpers[ object.id ] );
-			this.helpers[ object.id ].lightSphere.id = object.id;
-
-		}
-
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	deleteHelper: function( object ) {
-
-		if ( this.helpers[ object.id ] ) {
-
-			this.helpers[ object.id ].parent.remove( this.helpers[ object.id ] );
-			delete this.helpers[ object.id ];
-
-		}
-
-	},
-
-	addGeometry: function( geometry ) {
-
-		this.geometries[ geometry.id ] = geometry;
-		signals.geometryAdded.dispatch( geometry );
-
-	},
-
-	addMaterial: function( material ) {
-
-		if ( material.name == 'Default Material' ) {
-			this.delete( this.defaultMaterial );
-			this.defaultMaterial = material;
-		}
-
-		this.materials[ material.id ] = material;
-		signals.materialAdded.dispatch( material );
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	addTexture: function( texture ) {
-
-		this.textures[ texture.id ] = texture;
-		signals.textureAdded.dispatch( texture );
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	// Selection
-
-	select: function( list, additive ) {
-
-		//TODO toggle
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		if ( !additive ) this.selected = {};
-
-		for ( var i in list ) {
-
-			this.selected[ list[ i ].id ] = list[ i ];
-
-		}
-
-		signals.selected.dispatch( this.selected );
-
-	},
-
-	selectById: function( id, additive ) {
-
-		var list = this.list();
-
-		if ( !additive ) this.selected = {};
-
-		for ( var i in list ) {
-
-			if ( list[ i ].id == id ) this.select( list[ i ], true );
-
-		}
-
-	},
-
-	selectByName: function( name, type, additive ) {
-
-		type = type ? type : "all";
-
-		this.select( this.listByName( name, type ), additive );
-
-	},
-
-	selectAll: function( type, additive ) {
-
-		type = type ? type : "all";
-
-		this.select( this.listByName( '*', type ), additive );
-
-	},
-
-	deselect: function( list ) {
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		for ( var i in list ) {
-
-			if ( this.selected[ list[ i ].id ] ) delete this.selected[ list[ i ].id ];
-
-		}
-
-		signals.selected.dispatch( this.selected );
-
-	},
-
-	deselectById: function( id ) {
-
-		if ( this.selected[ id ] ) delete this.selected[ id ];
-
-	},
-
-	deselectByName: function( name, type ) {
-
-		type = type ? type : "all";
-
-		this.deselect( this.listByName( name, type ) );
-
-	},
-
-	deselectAll: function( type ) {
-
-		type = type ? type : "all";
-
-		this.deselect( this.list( "all" ) );
-
-	},
-
-	pickWalk: function( direction ) {
-
-		direction = direction.toLowerCase();
-
-		var selection = this.listSelected();
-		var newSelection = [];
-
-		if ( direction === 'up' ) {
-
-			for ( var i in selection ) {
-
-				if ( selection[ i ].parent )
-					newSelection.push( selection[ i ].parent );
-
-				else newSelection.push( selection[ i ] );
-
-			}
-
-		} else if ( direction === 'down' ) {
-
-			for ( var i in selection ) {
-
-				if ( selection[ i ].children && selection[ i ].children.length )
-					newSelection.push( selection[ i ].children[0] );
-
-				else newSelection.push( selection[ i ] );
-
-			}
-
-		} else if ( direction === 'left' || direction === 'right' ) {
-
-			for ( var i in selection ) {
-
-				var siblings = null;
-				var index = null;
-				var newIndex = null;
-
-				if ( selection[ i ].parent ) {
-
-					siblings = selection[ i ].parent.children;
-					index = selection[ i ].parent.children.indexOf( selection[ i ] );
-					newIndex = index;
-
-					if ( siblings.length > 1 && direction === 'left' )
-						newIndex = ( index + siblings.length + 1 ) % siblings.length;
-
-					else if ( siblings.length > 1 && direction === 'right' )
-						newIndex = ( index + siblings.length - 1 ) % siblings.length;
-
-					newSelection.push( siblings[ newIndex ] );
-
-				} else {
-
-					newSelection.push( selection[ i ] );
-
-				}
-
-			}
-
-		}
-
-		if ( newSelection.length ) this.select( newSelection );
-
-	},
-
-	// List
-
-	list: function( type ) {
-
-		type = type ? type : "all";
-
-		var list = this.listByName( '*', type );
-
-		return list;
-
-	},
-
-	listSelected: function( type ) {
-
-		var list = this.listByName( '*', 'selected' );
-
-		if ( type ) {
-
-			var typeList = this.listByName( '*', type );
-
-			var list = list.filter(function(n) {
-				if(typeList.indexOf(n) == -1) return false;
-				return true;
-			});
-
-		} 
-
-		return list;
-
-	},
-
-	listByName: function( name, type ) {
-
-		type = type ? type.toLowerCase() : "all";
-
-		var scope = this;
-		var list = [];
-
-		function listFromMap( map, name ) {
-
-			for ( var id in map ) {
-
-				if ( scope.regexMatch( map[ id ].name, name ) ) {
-
-					list.push( map[ id ] );
-
-				}
-
-
-			}
-
-		}
-
-		if ( type == 'all' || type == 'object' ) {
-
-			listFromMap( this.objects, name );
-
-		}
-
-		if ( type == 'all' || type == 'geometry' ) {
-
-			listFromMap( this.geometries, name );
-
-		}
-
-		if ( type == 'all' || type == 'material' ) {
-
-			listFromMap( this.materials, name );
-
-		}
-
-		if ( type == 'all' || type == 'texture' ) {
-
-			listFromMap( this.textures, name );
-
-		}
-
-		if ( type == 'all' || type == 'selected' ) {
-
-			listFromMap( this.selected, name );
-
-		}
-
-		return list;
-
-	},
-
-	// Delete
-
-	delete: function( list ) {
-
-		list = list ? list : this.list( 'selected' );
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		this.deselect( list );
-
-		var deletedObjects = {};
-
-		for ( var i in list ) {
-
-			if ( this.objects[ list[ i ].id ] && list[ i ] != this.scene ) {
-
-				delete this.objects[ list[ i ].id ];
-				this.deleteHelper( list[ i ] );
-
-				deletedObjects[ list[ i ].id ] = list[ i ];
-
-				if ( list[ i ] instanceof THREE.Light ) this.updateMaterials();
-
-				signals.objectDeleted.dispatch();
-
-				if ( list[ i ].children.length ) this.delete( list[ i ].children );
-
-			}
-
-			if ( this.geometries[ list[ i ].id ] ) {
-
-				delete this.geometries[ list[ i ].id ];
-				signals.objectDeleted.dispatch();
-
-			}
-
-			if ( this.materials[ list[ i ].id ] ) {
-
-				delete this.materials[ list[ i ].id ];
-				signals.materialDeleted.dispatch();
-
-			}
-
-			if ( this.textures[ list[ i ].id ] ) {
-
-				delete this.textures[ list[ i ].id ];
-				signals.textureDeleted.dispatch();
-
-			}
-
-		} 
-
-		for ( var i in deletedObjects ) {
-
-			if ( deletedObjects[ i ].parent ) {
-
-				deletedObjects[ i ].parent.remove( deletedObjects[ i ] );
-
-			}
-
-		}
-
-		delete deletedObjects;
-
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	deleteByName: function( name, type ) {
-
-		type = type ? type : "all";
-
-		this.delete( this.listByName( name, type ) );
-
-	},
-
-	deleteAll: function( type ) {
-
-		type = type ? type : 'all';
-
-		this.delete( this.listByName( '*', type ) );
-
-	},
-
-	deleteUnused: function( type ) {
-
-		// TODO: test with textures
-
-		type = type ? type.toLowerCase() : 'all';
-
-		var used = {};
-
-		this.scene.traverse( function( object ) {
-
-			used[ object.id ] = object; 
-
-			if ( object.geometry ) used[ object.geometry.id ] = object.geometry; 
-
-			if ( object.material ) {
-
-				used[ object.material.id ] = object.material;
-
-				for ( var i in object.material ){
-
-					if ( object.material[ i ] instanceof THREE.Texture ) {
-
-						used[ object.material[ i ].id ] = object.material[ i ];
-
-					}
-
-				}
-
-			}
-
-		} );
-
-		if ( !type || type == 'object' ) {
-			for ( var id in this.objects ) {
-				if ( !used[ id ] ) this.delete( this.objects[ id ] );
-			}
-		}
-
-		if ( !type || type == 'geometry' ) {
-			for ( var id in this.geometries ) {
-				if ( !used[ id ] ) this.delete( this.geometries[ id ] );
-			}
-		}
-
-		if ( !type || type == 'material' ) {
-			for ( var id in this.materials ) {
-				if ( !used[ id ] ) this.delete( this.materials[ id ] );
-			}
-		}
-
-		if ( !type || type == 'texture' ) {
-			for ( var id in this.textures ) {
-				if ( !used[ id ] ) this.delete( this.textures[ id ] );
-			}
-		}
-
-		delete used;
-
-	},
-
-	// Hierarchy
-
-	clone: function( assets, recursive, deep ) {
-
-		// TODO: consider using list
-
-		// TODO: Implement non-recursive and deep
-
-		var assets = assets ? assets : this.selected;
-		// recursive = recursive ? recursive : true;
-		// deep = deep ? deep : false;
-
-		var clones = {};
-
-		for ( var i in assets ){
-
-			if ( this.objects[ i ] ) {
-
-				var clonedObject = this.objects[assets[ i ].id ].clone();
-
-				clonedObject.traverse( function( child ) {
-
-					child.name += ' Clone';
-
-				} );
-
-				this.addObject( clonedObject, assets[ i ].parent );
-				clones[ clonedObject.id ] = clonedObject;
-
-			}
-
-		}
-
-		return clones;
-
-	},
-
-	parent: function( list, parent, locked ) {
-
-		//TODO: implement locked
-
-		list = list ? list : this.list( 'selected' );
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		parent = parent ? parent : this.scene;
-
-		for ( var i in list ) {
-
-			if ( list[ i ] !== parent && list[ i ] !== this.scene ) {
-
-				parent.add( list[ i ] );
-				signals.objectChanged.dispatch( list[ i ] );
-
-			}
-
-		}
-
-		signals.sceneChanged.dispatch( this.scene );
-
-	},
-
-	unparent: function( list ) {
-
-		this.parent( list, this.scene );
-
-	},
-
-	group: function( list ) {
-
-		list = list ? list : this.listSelected( 'objects' );
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		var parent = ( list.length && list[0].parent ) ? list[0].parent : this.scene;
-
-		var group = this.createObject();
-
-		this.parent( group, parent );
-
-		this.parent( list, group );
-
-	},
-
-	// Utils
-
-	updateObject: function( object, parameters ) {
-
-		parameters = parameters ? parameters : {};
-
-		if ( parameters.parent && object.parent && object.parent != parameters.parent)
-			editor.parent( object, parameters.parent );
-
-		if ( parameters.geometry && object.geometry && object.geometry != parameters.geometry) {
-			object.geometry = parameters.geometry;
-			this.updateGeometry( object.geometry );
-		}
-
-		if ( parameters.material && object.material && object.material != parameters.material)
-			object.material = parameters.material;
-
-		if ( parameters.name !== undefined ) object.name = parameters.name;
-
-		if ( parameters.position !== undefined ) object.position = parameters.position;
-		if ( parameters.rotation !== undefined ) object.rotation = parameters.rotation;
-		if ( parameters.scale !== undefined ) object.scale = parameters.scale;
-
-		if ( object.fov !== undefined && parameters.fov !== undefined ) object.fov = parameters.fov;
-		if ( object.near !== undefined && parameters.near !== undefined ) object.near = parameters.near;
-		if ( object.far !== undefined && parameters.far !== undefined ) object.far = parameters.far;
-		if ( object.intensity !== undefined && parameters.intensity !== undefined ) object.intensity = parameters.intensity;
-
-		if ( object.color && parameters.color !== undefined ) object.color.setHex( parameters.color );
-		if ( object.groundColor && parameters.groundColor !== undefined ) object.groundColor.setHex( parameters.groundColor );
-
-		if ( object.distance !== undefined && parameters.distance !== undefined ) object.distance = parameters.distance;
-		if ( object.angle !== undefined && parameters.angle !== undefined ) object.angle = parameters.angle;
-		if ( object.exponent !== undefined && parameters.exponent !== undefined ) object.exponent = parameters.exponent;
-		if ( object.visible !== undefined && parameters.visible !== undefined ) object.visible = parameters.visible;
-
-		if ( parameters.userData !== undefined ) {
-
-			try {
-
-				object.userData = JSON.parse( parameters.userData );
-
-			} catch ( error ) {
-
-			 console.log( error );
-
-			}
-
-		};
-
-		if ( object.updateProjectionMatrix ) object.updateProjectionMatrix();
-
-		signals.objectChanged.dispatch( object );
-
-	},
-
-	updateMaterials: function( list ) {
-
-		list = list ? list : this.list( 'material' );
-
-		list = ( list instanceof Array ) ? list : [ list ];
-
-		for ( var i in list ) {
-
-			list[ i ].needsUpdate = true;
-
-			if ( list[ i ] instanceof THREE.MeshFaceMaterial ) {
-
-				for ( var j in list[ i ].materials ) {
-
-					list[ i ].materials[ j ].needsUpdate = true;
-
-				}
-
-			}
-
-		}
-
-	},
-
-	updateGeometry: function( geometry, parameters ) {
-
-		parameters = parameters ? parameters : {};
-
-		var id = geometry.id;
-		var name = geometry.name;
-
-		if ( geometry instanceof THREE.PlaneGeometry )
-			geometry = this.createGeometry( 'Plane', parameters );
-
-		if ( geometry instanceof THREE.CubeGeometry )
-			geometry = this.createGeometry( 'Cube', parameters );
-
-		if ( geometry instanceof THREE.CylinderGeometry )
-			geometry = this.createGeometry( 'Cylinder', parameters );
-
-		if ( geometry instanceof THREE.SphereGeometry )
-			geometry = this.createGeometry( 'Sphere', parameters );
-
-		if ( geometry instanceof THREE.IcosahedronGeometry )
-			geometry = this.createGeometry( 'Icosahedron', parameters );
-
-		if ( geometry instanceof THREE.TorusGeometry )
-			geometry = this.createGeometry( 'Torus', parameters );
-
-		if ( geometry instanceof THREE.TorusKnotGeometry )
-			geometry = this.createGeometry( 'Torusknot', parameters );
-
-		geometry.computeBoundingSphere();
-		geometry.id = id;
-		geometry.name = name;
-
-		for ( var i in editor.objects ) {
-
-			var object = editor.objects[i];
-
-			if ( object.geometry && object.geometry.id == id ) {
-
-				delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-				object.geometry.dispose();
-
-				object.geometry = geometry;
-
-				signals.objectChanged.dispatch( object );
-
-			}
-
-		}
-
-	},
-
-	setFog: function( parameters ) {
-
-		var fogType = parameters.fogType ? parameters.fogType : null;
-		var near = parameters.near ? parameters.near : null;
-		var far = parameters.far ? parameters.far : null;
-		var density = parameters.density ? parameters.density : null;
-		var color = parameters.color ? parameters.color : null;
-
-		if ( fogType ) {
-
-			if ( fogType === "None" ) this.scene.fog = null;
-
-			else if ( fogType === "Fog" ) this.scene.fog = new THREE.Fog();
-
-			else if ( fogType === "FogExp2" ) this.scene.fog = new THREE.FogExp2();
-
-		}
-
-		if ( this.scene.fog ) {
-
-			if ( fogType ) this.scene.fog.fogType = fogType;
-			if ( near ) this.scene.fog.near = near;
-			if ( far ) this.scene.fog.far = far;
-			if ( density ) this.scene.fog.density = density;
-			if ( color ) this.scene.fog.color.setHex( color );
-
-		}
-
-		this.updateMaterials();
-		signals.fogChanged.dispatch( this.scene.fog );
-
-	},
-
-	regexMatch: function( name, filter ) {
-
-		name = name.toLowerCase();
-		filter = '^' + filter.toLowerCase().replace(/\*/g, '.*').replace(/\?/g, '.') + '$';
-
-		var regex = new RegExp(filter);
-		return regex.test( name );
-
-	},
-
-	incrementName: function( name, type ) {
-
-		var list = this.listByName( name+'\\d+', type );
-		var lastIncrement = 0;
-
-		for ( var i in list ) {
-			var Increment = parseFloat( list[i].name.replace( name, '' ) );
-			if ( Increment > lastIncrement ) lastIncrement = Increment;
-		}
-
-		return name + ( lastIncrement + 1 );
-
-	}
-
-}

+ 25 - 40
editor/js/Loader.js

@@ -1,6 +1,7 @@
-var Loader = function ( editor, signals ) {
 
-	var scope = this;
+var Loader = function ( signals ) {
+
+	scope = this;
 
 	var sceneExporter = new THREE.ObjectExporter();
 
@@ -27,20 +28,18 @@ var Loader = function ( editor, signals ) {
 
 	var timeout;
 
-	signals.objectChanged.add( function () {
+	signals.sceneChanged.add( function ( scene ) {
 
 		clearTimeout( timeout );
 
 		timeout = setTimeout( function () {
 
-			console.log( "Saving to localStorage." );
-			scope.saveLocalStorage( editor.scene );
+			scope.saveLocalStorage( scene );
 
 		}, 3000 );
 
 	} );
 
-
 	this.loadLocalStorage = function () {
 
 		if ( localStorage.threejsEditor !== undefined ) {
@@ -50,7 +49,7 @@ var Loader = function ( editor, signals ) {
 				var loader = new THREE.ObjectLoader();
 				var scene = loader.parse( JSON.parse( localStorage.threejsEditor ) );
 
-				editor.setScene( scene );
+				signals.sceneAdded.dispatch( scene );
 
 			} catch ( e ) {
 
@@ -104,40 +103,20 @@ var Loader = function ( editor, signals ) {
 			var mesh = new THREE.Mesh( geometry, material );
 			mesh.name = filename;
 
-			editor.addObject( mesh );
+			signals.objectAdded.dispatch( mesh );
 
 		} else if ( data.metadata.type === 'object' ) {
 
-			var loader;
-
-			switch ( data.metadata.version ) {
-
-				case 4:
-					console.log( 'Loading Object format 4.0');
-					loader = new THREE.ObjectLoader4(); // DEPRECATED
-					break;
-
-				case 4.1:
-					console.log( 'Loading Object format 4.1');
-					loader = new THREE.ObjectLoader41(); // DEPRECATED
-					break;
-
-				default:
-					console.log( 'Loading Object format 4.2');
-					loader = new THREE.ObjectLoader();
-					break;
-
-			}
-
+			var loader = new THREE.ObjectLoader();
 			var result = loader.parse( data );
 
 			if ( result instanceof THREE.Scene ) {
 
-				editor.setScene( result );
+				signals.sceneAdded.dispatch( result );
 
 			} else {
 
-				editor.addObject( result );
+				signals.objectAdded.dispatch( result );
 
 			}
 
@@ -148,7 +127,13 @@ var Loader = function ( editor, signals ) {
 			var loader = new THREE.SceneLoader();
 			loader.parse( data, function ( result ) {
 
-				editor.addObject( result.scene );
+				var scene = result.scene;
+
+				while ( scene.children.length > 0 ) {
+
+					signals.objectAdded.dispatch( scene.children[ 0 ] );
+
+				}
 
 			}, '' );
 
@@ -181,7 +166,7 @@ var Loader = function ( editor, signals ) {
 						var mesh = new THREE.Mesh( geometry, material );
 						mesh.name = filename;
 
-						editor.addObject( mesh );
+						signals.objectAdded.dispatch( mesh );
 
 					} );
 
@@ -205,7 +190,7 @@ var Loader = function ( editor, signals ) {
 
 						collada.scene.name = filename;
 
-						editor.addObject( collada.scene );
+						signals.objectAdded.dispatch( collada.scene );
 
 					} );
 
@@ -279,7 +264,7 @@ var Loader = function ( editor, signals ) {
 					var object = new THREE.OBJLoader().parse( contents );
 					object.name = filename;
 
-					editor.addObject( object );
+					signals.objectAdded.dispatch( object );
 
 				}, false );
 				reader.readAsText( file );
@@ -304,7 +289,7 @@ var Loader = function ( editor, signals ) {
 					var mesh = new THREE.Mesh( geometry, material );
 					mesh.name = filename;
 
-					editor.addObject( mesh );
+					signals.objectAdded.dispatch( mesh );
 
 				}, false );
 				reader.readAsText( file );
@@ -327,7 +312,7 @@ var Loader = function ( editor, signals ) {
 					var mesh = new THREE.Mesh( geometry, material );
 					mesh.name = filename;
 
-					editor.addObject( mesh );
+					signals.objectAdded.dispatch( mesh );
 
 				}, false );
 
@@ -356,7 +341,7 @@ var Loader = function ( editor, signals ) {
 
 					var mesh = new THREE.Mesh( geometry, material );
 
-					editor.addObject( mesh );
+					signals.objectAdded.dispatch( mesh );
 
 				}, false );
 				reader.readAsBinaryString( file );
@@ -380,7 +365,7 @@ var Loader = function ( editor, signals ) {
 					var mesh = new THREE.Mesh( geometry, material );
 					mesh.name = filename;
 
-					editor.addObject( mesh );
+					signals.objectAdded.dispatch( mesh );
 
 				}, false );
 				reader.readAsText( file );
@@ -396,7 +381,7 @@ var Loader = function ( editor, signals ) {
 
 					var result = new THREE.VRMLLoader().parse( contents );
 
-					editor.addObject( result );
+					signals.sceneAdded.dispatch( result );
 
 				}, false );
 				reader.readAsText( file );

+ 132 - 83
editor/js/Menubar.Add.js

@@ -4,7 +4,7 @@ Menubar.Add = function ( signals ) {
 	container.setClass( 'menu' );
 	container.onMouseOver( function () { options.setDisplay( 'block' ) } );
 	container.onMouseOut( function () { options.setDisplay( 'none' ) } );
-	container.onClick( function () { options.setDisplay( 'none' ) } );
+	container.onClick( function () { options.setDisplay( 'block' ) } );
 
 	var title = new UI.Panel();
 	title.setTextContent( 'Add' ).setColor( '#666' );
@@ -26,7 +26,19 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Plane' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Plane' ) );
+		var width = 200;
+		var height = 200;
+
+		var widthSegments = 1;
+		var heightSegments = 1;
+
+		var geometry = new THREE.PlaneGeometry( width, height, widthSegments, heightSegments );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Plane ' + mesh.id;
+
+		mesh.rotation.x = - Math.PI/2;
+
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -38,7 +50,20 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Cube' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Cube' ) );
+		var width = 100;
+		var height = 100;
+		var depth = 100;
+
+		var widthSegments = 1;
+		var heightSegments = 1;
+		var depthSegments = 1;
+
+		var geometry = new THREE.CubeGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Cube ' + mesh.id;
+
+		signals.objectAdded.dispatch( mesh );
+
 
 	} );
 	options.add( option );
@@ -50,7 +75,18 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Cylinder' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Cylinder' ) );
+		var radiusTop = 20;
+		var radiusBottom = 20;
+		var height = 100;
+		var radiusSegments = 8;
+		var heightSegments = 1;
+		var openEnded = false;
+
+		var geometry = new THREE.CylinderGeometry( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Cylinder ' + mesh.id;
+
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -62,7 +98,15 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Sphere' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Sphere' ) );
+		var radius = 75;
+		var widthSegments = 32;
+		var heightSegments = 16;
+
+		var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Sphere ' + mesh.id;
+
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -74,7 +118,14 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Icosahedron' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Icosahedron' ) );
+		var radius = 75;
+		var detail = 2;
+
+		var geometry = new THREE.IcosahedronGeometry ( radius, detail );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Icosahedron ' + mesh.id;
+
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -86,7 +137,17 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Torus' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'Torus' ) );
+		var radius = 100;
+		var tube = 40;
+		var radialSegments = 8;
+		var tubularSegments = 6;
+		var arc = Math.PI * 2;
+
+		var geometry = new THREE.TorusGeometry( radius, tube, radialSegments, tubularSegments, arc );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'Torus ' + mesh.id;
+
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -98,19 +159,19 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'TorusKnot' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'TorusKnot' ) );
+		var radius = 100;
+		var tube = 40;
+		var radialSegments = 64;
+		var tubularSegments = 8;
+		var p = 2;
+		var q = 3;
+		var heightScale = 1;
 
-	} );
-	options.add( option );
+		var geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale );
+		var mesh = new THREE.Mesh( geometry, createDummyMaterial( geometry ) );
+		mesh.name = 'TorusKnot ' + mesh.id;
 
-	// add group
-
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Group' );
-	option.onClick( function () {
-
-		editor.select( editor.createObject() );
+		signals.objectAdded.dispatch( mesh );
 
 	} );
 	options.add( option );
@@ -126,120 +187,108 @@ Menubar.Add = function ( signals ) {
 	option.setTextContent( 'Point light' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'PointLight' ) );
+		var color = 0xffffff;
+		var intensity = 1;
+		var distance = 0;
+
+		var light = new THREE.PointLight( color, intensity, distance );
+		light.name = 'PointLight ' + light.id;
+
+		signals.objectAdded.dispatch( light );
 
 	} );
 	options.add( option );
 
-	// // add spot light
+	// add spot light
 
-	// var option = new UI.Panel();
-	// option.setClass( 'option' );
-	// option.setTextContent( 'Spot light' );
-	// option.onClick( function () {
-
-	// 	editor.select( editor.createObject( 'SpotLight' ) );
+	var option = new UI.Panel();
+	option.setClass( 'option' );
+	option.setTextContent( 'Spot light' );
+	option.onClick( function () {
 
-	// } );
-	// options.add( option );
+		var color = 0xffffff;
+		var intensity = 1;
+		var distance = 0;
+		var angle = Math.PI * 0.1;
+		var exponent = 10;
 
-	// // add directional light
+		var light = new THREE.SpotLight( color, intensity, distance, angle, exponent );
+		light.name = 'SpotLight ' + light.id;
+		light.target.name = 'SpotLight ' + light.id + ' Target';
 
-	// var option = new UI.Panel();
-	// option.setClass( 'option' );
-	// option.setTextContent( 'Directional light' );
-	// option.onClick( function () {
+		light.position.set( 0, 1, 0 ).multiplyScalar( 200 );
 
-	// 	editor.select( editor.createObject( 'DirectionalLight' ) );
+		signals.objectAdded.dispatch( light );
 
-	// } );
-	// options.add( option );
+	} );
+	options.add( option );
 
-	// add hemisphere light
+	// add directional light
 
 	var option = new UI.Panel();
 	option.setClass( 'option' );
-	option.setTextContent( 'Hemisphere light' );
+	option.setTextContent( 'Directional light' );
 	option.onClick( function () {
 
-		editor.select( editor.createObject( 'HemisphereLight' ) );
+		var color = 0xffffff;
+		var intensity = 1;
 
-	} );
-	options.add( option );
+		var light = new THREE.DirectionalLight( color, intensity );
+		light.name = 'DirectionalLight ' + light.id;
+		light.target.name = 'DirectionalLight ' + light.id + ' Target';
 
-	// add ambient light
+		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );
 
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Ambient light' );
-	option.onClick( function () {
-
-		editor.select( editor.createObject( 'AmbientLight' ) );
+		signals.objectAdded.dispatch( light );
 
 	} );
 	options.add( option );
 
-	//
-
-	options.add( new UI.HorizontalRule() );
-
-	// add material
+	// add hemisphere light
 
 	var option = new UI.Panel();
 	option.setClass( 'option' );
-	option.setTextContent( 'Phong material' );
+	option.setTextContent( 'Hemisphere light' );
 	option.onClick( function () {
 
-		editor.select( editor.createMaterial( 'MeshPhongMaterial' ) );
+		var skyColor = 0x00aaff;
+		var groundColor = 0xffaa00;
+		var intensity = 1;
 
-	} );
-	options.add( option );
+		var light = new THREE.HemisphereLight( skyColor, groundColor, intensity );
+		light.name = 'HemisphereLight ' + light.id;
 
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Lambert material' );
-	option.onClick( function () {
+		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );
 
-		editor.select( editor.createMaterial( 'MeshLambertMaterial' ) );
+		signals.objectAdded.dispatch( light );
 
 	} );
 	options.add( option );
 
+	// add ambient light
+
 	var option = new UI.Panel();
 	option.setClass( 'option' );
-	option.setTextContent( 'Normal material' );
+	option.setTextContent( 'Ambient light' );
 	option.onClick( function () {
 
-		editor.select( editor.createMaterial( 'MeshNormalMaterial' ) );
+		var color = 0x222222;
 
-	} );
-	options.add( option );
-
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Basic material' );
-	option.onClick( function () {
+		var light = new THREE.AmbientLight( color );
+		light.name = 'AmbientLight ' + light.id;
 
-		editor.select( editor.createMaterial( 'MeshBasicMaterial' ) );
+		signals.objectAdded.dispatch( light );
 
 	} );
 	options.add( option );
 
 	//
 
-	options.add( new UI.HorizontalRule() );
-
-	// add texture
-
-	var option = new UI.Panel();
-	option.setClass( 'option' );
-	option.setTextContent( 'Texture' );
-	option.onClick( function () {
+	function createDummyMaterial() {
 
-		editor.select( editor.createTexture() );
+		return new THREE.MeshPhongMaterial();
 
-	} );
-	options.add( option );
+	};
 
 	return container;
 

+ 3 - 11
editor/js/Menubar.Edit.js

@@ -4,7 +4,7 @@ Menubar.Edit = function ( signals ) {
 	container.setClass( 'menu' );
 	container.onMouseOver( function () { options.setDisplay( 'block' ) } );
 	container.onMouseOut( function () { options.setDisplay( 'none' ) } );
-	container.onClick( function () { options.setDisplay( 'none' ) } );
+	container.onClick( function () { options.setDisplay( 'block' ) } );
 
 	var title = new UI.Panel();
 	title.setTextContent( 'Edit' ).setColor( '#666' );
@@ -24,11 +24,7 @@ Menubar.Edit = function ( signals ) {
 	var option = new UI.Panel();
 	option.setClass( 'option' );
 	option.setTextContent( 'Clone' );
-	option.onClick( function () {
-
-		editor.clone();
-
-	} );
+	option.onClick( function () { signals.cloneSelectedObject.dispatch(); } );
 	options.add( option );
 
 	// delete
@@ -36,11 +32,7 @@ Menubar.Edit = function ( signals ) {
 	var option = new UI.Panel();
 	option.setClass( 'option' );
 	option.setTextContent( 'Delete' );
-	option.onClick( function () { 
-
-		editor.delete();
-
-	} );
+	option.onClick( function () { signals.removeSelectedObject.dispatch(); } );
 	options.add( option );
 
 	//

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

@@ -4,7 +4,7 @@ Menubar.File = function ( signals ) {
 	container.setClass( 'menu' );
 	container.onMouseOver( function () { options.setDisplay( 'block' ) } );
 	container.onMouseOut( function () { options.setDisplay( 'none' ) } );
-	container.onClick( function () { options.setDisplay( 'none' ) } );
+	container.onClick( function () { options.setDisplay( 'block' ) } );
 
 	var title = new UI.Panel();
 	title.setTextContent( 'File' ).setColor( '#666' );
@@ -14,6 +14,9 @@ Menubar.File = function ( signals ) {
 
 	//
 
+	var selectedObject;
+	var scene;
+
 	var options = new UI.Panel();
 	options.setClass( 'options' );
 	options.setDisplay( 'none' );
@@ -44,7 +47,7 @@ Menubar.File = function ( signals ) {
 
 			}
 
-			location.replace( location.origin + location.pathname );
+			location.reload();
 
 		}
 
@@ -117,14 +120,7 @@ Menubar.File = function ( signals ) {
 
 	var exportGeometry = function ( exporterClass ) {
 
-		var selected;
-		// TODO: handle multiple selection
-		for ( var i in editor.selected ) {
-			if ( editor.objects[ editor.selected[ i ].id ] ) selected = editor.selected[ i ];
-		}
-		if ( !selected ) return;
-
-		if ( selected.geometry === undefined ) {
+		if ( selectedObject.geometry === undefined ) {
 
 			alert( "Selected object doesn't have any geometry" );
 			return;
@@ -137,12 +133,12 @@ Menubar.File = function ( signals ) {
 
 		if ( exporter instanceof THREE.GeometryExporter ) {
 
-			output = JSON.stringify( exporter.parse( selected.geometry ), null, '\t' );
+			output = JSON.stringify( exporter.parse( selectedObject.geometry ), null, '\t' );
 			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
 		} else {
 
-			output = exporter.parse( selected.geometry );
+			output = exporter.parse( selectedObject.geometry );
 
 		}
 
@@ -156,16 +152,9 @@ Menubar.File = function ( signals ) {
 
 	var exportObject = function ( exporterClass ) {
 
-		var selected;
-		// TODO: handle multiple selection
-		for ( var i in editor.selected ) {
-			if ( editor.objects[ editor.selected[ i ].id ] ) selected = editor.selected[ i ];
-		}
-		if ( !selected ) return;
-
 		var exporter = new exporterClass();
 
-		var output = JSON.stringify( exporter.parse( selected ), null, '\t' );
+		var output = JSON.stringify( exporter.parse( selectedObject ), null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
 		var blob = new Blob( [ output ], { type: 'text/plain' } );
@@ -180,7 +169,7 @@ Menubar.File = function ( signals ) {
 
 		var exporter = new exporterClass();
 
-		var output = JSON.stringify( exporter.parse( editor.scene ), null, '\t' );
+		var output = JSON.stringify( exporter.parse( scene ), null, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
 		var blob = new Blob( [ output ], { type: 'text/plain' } );
@@ -191,6 +180,19 @@ Menubar.File = function ( signals ) {
 
 	};
 
+	// signals
+
+	signals.objectSelected.add( function ( object ) {
+
+		selectedObject = object;
+
+	} );
+
+	signals.sceneChanged.add( function ( object ) {
+
+		scene = object;
+
+	} );
 
 	return container;
 

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

@@ -4,7 +4,7 @@ Menubar.Help = function ( signals ) {
 	container.setClass( 'menu' );
 	container.onMouseOver( function () { options.setDisplay( 'block' ) } );
 	container.onMouseOut( function () { options.setDisplay( 'none' ) } );
-	container.onClick( function () { options.setDisplay( 'none' ) } );
+	container.onClick( function () { options.setDisplay( 'block' ) } );
 
 	var title = new UI.Panel();
 	title.setTextContent( 'Help' ).setColor( '#666' );

+ 1 - 1
editor/js/Menubar.js

@@ -1,4 +1,4 @@
-var Menubar = function ( editor, signals ) {
+var Menubar = function ( signals ) {
 
 	var container = new UI.Panel();
 	container.setPosition( 'absolute' );

+ 37 - 14
editor/js/Sidebar.Animation.js

@@ -23,38 +23,49 @@ Sidebar.Animation = function ( signals ) {
 	container.add( PlayRow );
 	container.add( new UI.Break() );
 
-	function play(){
+	function play() {
 
 		var value = Animations.getValue();
-		if (possibleAnimations[value]){
+
+		if ( possibleAnimations[ value ] ) {
+
 			var anims = possibleAnimations[value]
-			for ( var i = 0;i < anims.length;i++){
-				anims[i].play();
+
+			for ( var i = 0; i < anims.length; i ++ ) {
+
+				anims[ i ].play();
+
 			}
+
 			signals.playAnimations.dispatch( anims );
+
 		};
 
 	}
 
 	signals.objectAdded.add( function ( object ) {
 
-		if (object instanceof THREE.Mesh){
+		if ( object instanceof THREE.Mesh ) {
 
-			if (object.geometry && object.geometry.animation){
+			if ( object.geometry && object.geometry.animation ) {
 
 				var name = object.geometry.animation.name;
 				options[name] = name
-				Animations.setOptions(options);
 
-				THREE.AnimationHandler.add(object.geometry.animation);
-				var animation = new THREE.Animation(object, 
-     				name, 
-     				THREE.AnimationHandler.CATMULLROM)
+				Animations.setOptions( options );
+
+				THREE.AnimationHandler.add( object.geometry.animation );
+
+				var animation = new THREE.Animation( object, name, THREE.AnimationHandler.CATMULLROM );
+
+				if ( possibleAnimations[ name ] ){
+
+					possibleAnimations[ name ].push( animation );
 
-				if (possibleAnimations[name]){
-					possibleAnimations[name].push(animation);
 				} else {
-					possibleAnimations[name] = [animation];
+
+					possibleAnimations[ name ] = [ animation ];
+
 				}
 
 			}
@@ -63,6 +74,18 @@ Sidebar.Animation = function ( signals ) {
 
 	} );
 
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object.geometry && object.geometry.animation ) {
+
+		} else {
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
 	return container;
 
 }

+ 0 - 462
editor/js/Sidebar.Attributes.js

@@ -1,462 +0,0 @@
-Sidebar.Attributes = function ( signals ) {
-
-	var scope = this;
-	var model;
-	var param = {};
-
-	var primaryParams = [ 'name', 'parent', 'geometry', 'material', 'position', 'rotation', 'scale', 'width', 'height', 'depth',
-	'widthSegments', 'heightSegments', 'depthSegments', 'radialSegments', 'tubularSegments', 'radius', 'radiusTop', 'radiusBottom',
-	'phiStart', 'phiLength', 'thetaStart', 'thetaLength', 'tube', 'arc', 'detail', 'p', 'q', 'heightScale', 'openEnded',
-	'image', 'sourceFile', 'wrapS', 'wrapT', 'minFilter', 'magFilter', 'format', 'repeat', 'offset', 'flipY', 'type', 'color',
-	'groundColor', 'ambient', 'emissive', 'specular', 'reflectivity', 'shininess', 'intensity', 'opacity', 'transparent', 'metal',
-	'wireframe', 'wireframeLinewidth', 'linewidth', 'visible', 'fog', 'near', 'far', 'exponent', 'map', 'lightMap', 'bumpMap',
-	'normalMap', 'specularMap', 'envMap', 'normalScale', 'bumpScale', 'userData' ];
-
-	var secondaryParams = [ 'quaternion', 'up', 'distance', 'castShadow', 'receiveShadow', 'useQuaternion', 'depthTest', 'depthWrite',
-	'dynamic', 'children', 'elements', 'vertices', 'normals', 'colors', 'faces', 'faceUvs', 'faceVertexUvs', 'boundingBox',
-	'boundingSphere', 'verticesNeedUpdate', 'elementsNeedUpdate', 'uvsNeedUpdate', 'normalsNeedUpdate', 'tangentsNeedUpdate',
-	'colorsNeedUpdate', 'lineDistancesNeedUpdate', 'buffersNeedUpdate', 'matrix', 'matrixWorld', 'blending', 'side', 'blendSrc',
-	'blendDst', 'blendEquation', 'generateMipmaps', 'premultiplyAlpha', 'needsUpdate', 'anisothropy' ];
-
-	var integerParams = [ 'widthSegments', 'heightSegments', 'depthSegments', 'radialSegments', 'tubularSegments' ];
-
-	var textureParams = [ 'map', 'lightMap', 'bumpMap', 'normalMap', 'specularMap', 'envMap' ];
-
-	var multiOptions = {
-		'blending': {
-			'NoBlending': THREE.NoBlending,
-			'NormalBlending': THREE.NormalBlending,
-			'AdditiveBlending': THREE.AdditiveBlending,
-			'SubtractiveBlending': THREE.SubtractiveBlending,
-			'MultiplyBlending': THREE.MultiplyBlending,
-			'CustomBlending': THREE.CustomBlending
-		}
-		,
-		'side': {
-			'FrontSide': THREE.FrontSide,
-			'BackSide': THREE.BackSide,
-			'DoubleSide': THREE.DoubleSide
-		},
-		'blendSrc': {
-			'ZeroFactor': THREE.ZeroFactor,
-			'OneFactor': THREE.OneFactor,
-			'SrcAlphaFactor': THREE.SrcAlphaFactor,
-			'OneMinusSrcAlphaFactor': THREE.OneMinusSrcAlphaFactor,
-			'DstAlphaFactor': THREE.DstAlphaFactor,
-			'OneMinusDstAlphaFactor': THREE.OneMinusDstAlphaFactor,			
-			'DstColorFactor': THREE.DstColorFactor,
-			'OneMinusDstColorFactor': THREE.OneMinusDstColorFactor,
-			'SrcAlphaSaturateFactor': THREE.SrcAlphaSaturateFactor
-		},
-		'blendDst': {
-			'ZeroFactor': THREE.ZeroFactor,
-			'OneFactor': THREE.OneFactor,
-			'SrcColorFactor': THREE.SrcColorFactor,
-			'OneMinusSrcColorFactor': THREE.OneMinusSrcColorFactor,
-			'SrcAlphaFactor': THREE.SrcAlphaFactor,
-			'OneMinusSrcAlphaFactor': THREE.OneMinusSrcAlphaFactor,
-			'DstAlphaFactor': THREE.DstAlphaFactor,
-			'OneMinusDstAlphaFactor': THREE.OneMinusDstAlphaFactor
-		},
-		'blendEquation': {
-			'AddEquation': THREE.AddEquation,
-			'SubtractEquation': THREE.SubtractEquation,
-			'ReverseSubtractEquation': THREE.ReverseSubtractEquation
-		},
-		'wrapS': {
-			'RepeatWrapping': THREE.RepeatWrapping,
-			'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
-			'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
-		},
-		'wrapT': {
-			'RepeatWrapping': THREE.RepeatWrapping,
-			'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
-			'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
-		},
-		'magFilter': {
-			'NearestFilter': THREE.NearestFilter,
-			'NearestMipMapNearestFilter': THREE.NearestMipMapNearestFilter,
-			'NearestMipMapLinearFilter': THREE.NearestMipMapLinearFilter,
-			'LinearFilter': THREE.LinearFilter,
-			'LinearMipMapNearestFilter': THREE.LinearMipMapNearestFilter,
-			'LinearMipMapLinearFilter': THREE.LinearMipMapLinearFilter,
-		},
-		'minFilter': {
-			'NearestFilter': THREE.NearestFilter,
-			'NearestMipMapNearestFilter': THREE.NearestMipMapNearestFilter,
-			'NearestMipMapLinearFilter': THREE.NearestMipMapLinearFilter,
-			'LinearFilter': THREE.LinearFilter,
-			'LinearMipMapNearestFilter': THREE.LinearMipMapNearestFilter,
-			'LinearMipMapLinearFilter': THREE.LinearMipMapLinearFilter,
-		},
-		'type': {
-			'UnsignedByteType': THREE.UnsignedByteType,
-			'ByteType': THREE.ByteType,
-			'ShortType': THREE.ShortType,
-			'UnsignedShortType': THREE.UnsignedShortType,
-			'IntType': THREE.IntType,
-			'UnsignedIntType': THREE.UnsignedIntType,
-			'FloatType': THREE.FloatType
-		},
-		'format': {
-			'AlphaFormat': THREE.AlphaFormat,
-			'RGBFormat': THREE.RGBFormat,
-			'RGBAFormat': THREE.RGBAFormat,
-			'LuminanceFormat': THREE.LuminanceFormat,
-			'LuminanceAlphaFormat': THREE.LuminanceAlphaFormat,
-			'RGB_S3TC_DXT1_Format': THREE.RGB_S3TC_DXT1_Format,
-			'RGBA_S3TC_DXT1_Format': THREE.RGBA_S3TC_DXT1_Format,
-			'RGBA_S3TC_DXT3_Format': THREE.RGBA_S3TC_DXT3_Format,
-			'RGBA_S3TC_DXT5_Format': THREE.RGBA_S3TC_DXT5_Format,
-			'RGB_PVRTC_4BPPV1_Format': THREE.RGB_PVRTC_4BPPV1_Format,
-			'RGB_PVRTC_2BPPV1_Format': THREE.RGB_PVRTC_2BPPV1_Format,
-			'RGBA_PVRTC_4BPPV1_Format': THREE.RGBA_PVRTC_4BPPV1_Format,
-			'RGBA_PVRTC_2BPPV1_Format': THREE.RGBA_PVRTC_2BPPV1_Format,
-		}
-	}
-
-	var container = new UI.Panel();
-
-	var group1 = new UI.Panel().setBorderTop( '1px solid #ccc' ).setPadding( '10px' ).setBackgroundColor( '#ddd' ); // Primary parameters
-	var group2 = new UI.Panel().setBorderTop( '1px solid #ccc' ).setPadding( '10px' ); // Secondary params 
-	var group3 = new UI.Panel().setBorderTop( '1px solid #ccc' ).setPadding( '10px' ).setBackgroundColor( '#ddd' ).setOpacity( 0.25 );//.setDisplay( 'none' ); // everything else
-
-	container.add( group1, group2, group3 );
-
-	signals.objectChanged.add( function ( changed ) {
-
-		if ( model === changed ) updateUI();
-
-	} );
-
-	signals.selected.add( function ( selected ) {
-
-		var selected = editor.listSelected();
-		var firstSelected = ( selected.length ) ? selected[0] : null;
-		createUI( firstSelected );
-
-	} );
-
-	function createUI( newModel ) {
-
-		model = newModel;
-
-		param = {};
-
-		while ( group1.dom.hasChildNodes() ) group1.dom.removeChild( group1.dom.lastChild );
-		while ( group2.dom.hasChildNodes() ) group2.dom.removeChild( group2.dom.lastChild );
-		while ( group3.dom.hasChildNodes() ) group3.dom.removeChild( group3.dom.lastChild );
-
-		if ( model ) {
-			for ( var i in primaryParams ) addElement( primaryParams[i], group1 );
-			for ( var i in secondaryParams ) addElement( secondaryParams[i], group2 );
-			for ( var key in model ) addElement( key, group3 );
-		}
-
-		updateUI();
-
-	}
-
-	function addElement( key, parent ) {
-
-		if ( model[ key ] !== undefined && param[ key ] === undefined ) {
-
-			// Params from multiOptions
-
-			for ( var i in multiOptions ) {
-				if ( i == key ) {
-					param[ key ] = new UI.ParamSelect( key ).onChange( updateParam );
-					parent.add( param[ key ] );
-					return;
-				}
-			}
-
-			// Special params
-
-			if ( key === 'parent' ) {
-
-				param[ key ] = new UI.ParamSelect( key ).onChange( updateParam );
-				param[ key ].name.setColor( '#0080f0' ).onClick( function(){ createUI( editor.objects[ param[ key ].getValue() ] ) } );
-				parent.add( param[ key ] );
-				return;
-
-			}
-
-			if ( key === 'geometry' ) {
-
-				param[ key ] = new UI.ParamSelect( key ).onChange( updateParam );
-				param[ key ].name.setColor( '#0080f0' ).onClick( function(){	createUI( editor.geometries[ param[ key ].getValue() ] ) } );
-				parent.add( param[ key ] );
-				return;
-
-			}
-
-			if ( key == 'material' ) {
-
-				param[ key ] = new UI.ParamSelect( key ).onChange( updateParam );
-				param[ key ].name.setColor( '#0080f0' ).onClick( function(){	createUI( editor.materials[ param[ key ].getValue() ] ) } );
-				parent.add( param[ key ] );
-				return;
-
-			}
-
-			if ( key == 'userData' ) {
-
-				param[ key ] = new UI.ParamJson( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-				return;
-
-			}
-
-			// Texture params
-
-			for ( var i in textureParams ) {
-
-				if ( key == textureParams[ i ] ) {
-
-					param[ key ] = new UI.ParamSelect( key ).onChange( updateParam );
-					param[ key ].name.setColor( '#0080f0' ).onClick( function(){
-
-						var value = param[ key ].getValue();
-						if ( value == 'new' ) {
-
-							var texture = editor.createTexture();
-							model[ key ] = texture;
-							createUI( texture );
-
-						} else createUI( editor.textures[ value ] )
-
-					} );
-					parent.add( param[ key ] );
-					return;
-
-				}
-
-			}
-
-			// Params by type
-
-			if ( typeof model[ key ] === 'string' ) {
-
-				param[ key ] = new UI.ParamString( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( typeof model[ key ] === 'boolean' ) {
-
-				param[ key ] = new UI.ParamBool( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( typeof model[ key ] === 'number' ) {
-
-				if ( integerParams.indexOf( key ) != -1 )
-					param[ key ] = new UI.ParamInteger( key ).onChange( updateParam );
-
-				else
-					param[ key ] = new UI.ParamFloat( key ).onChange( updateParam );
-
-				parent.add( param[ key ] );
-
-			} else if ( model[ key ] instanceof THREE.Vector2 ) {
-
-				param[ key ] = new UI.ParamVector2( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( model[ key ] instanceof THREE.Vector3 ) {
-
-				param[ key ] = new UI.ParamVector3( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( model[ key ] instanceof THREE.Vector4 || model[ key ] instanceof THREE.Quaternion ) {
-
-				param[ key ] = new UI.ParamVector4( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( model[ key ] instanceof THREE.Color ) {
-
-				param[ key ] = new UI.ParamColor( key ).onChange( updateParam );
-				parent.add( param[ key ] );
-
-			} else if ( model[ key ] instanceof Array ) {
-
-				if ( model[ key ].length ) {
-
-					param[ key ] = new UI.Text( key ).setColor( '#0080f0' ).onClick( function(){	createUI( model[ key ] ) } );
-					parent.add( param[ key ], new UI.Break() );
-
-				}
-
-			} else if ( typeof model[ key ] !== 'function' ) {
-
-				param[ key ] = new UI.Text( key ).setColor( '#0080f0' ).onClick( function(){	createUI( model[ key ] ) } );
-				parent.add( param[ key ], new UI.Break() );
-
-			}
-
-		}
-
-	}
-
-	function updateUI() {
-
-		if ( model ) {
-
-			for ( var key in model ) {
-
-				if ( param[ key ] === undefined ) continue;
-
-				// Params from multiOptions
-
-				for ( var i in multiOptions ) {
-					if ( i == key ) {
-						for ( var j in multiOptions[ i ] ) {
-
-							var options = {};
-
-							for ( var j in multiOptions[ i ] ) options[ multiOptions[ i ][ j ] ] = j;
-
-							param[ key ].setOptions( options );
-							param[ key ].setValue( model[ key ] );
-							break;
-
-						}
-					}
-				}
-
-				// Special params
-
-				if ( key === 'parent' ) {
-
-					var options = {};
-					for ( var id in editor.objects ) if ( model.id != id ) options[ id ] = editor.objects[ id ].name;
-					param[ key ].setOptions( options );
-					if ( model[ key ] !== undefined ) param[ key ].setValue( model[ key ].id );
-
-				} else if ( key === 'geometry' ) {
-
-					var options = {};
-					for ( var id in editor.geometries ) options[ id ] = editor.geometries[ id ].name;
-					param[ key ].setOptions( options );
-					if ( model[ key ] !== undefined ) param[ key ].setValue( model[ key ].id );
-
-				} else if ( key === 'material' ) {
-
-					var options = {};
-					for ( var id in editor.materials ) options[ id ] = editor.materials[ id ].name;
-					param[ key ].setOptions( options );
-					if ( model[ key ] !== undefined ) param[ key ].setValue( model[ key ].id );
-
-				} else if ( key == 'userData' ) {
-
-					try {
-
-						param[ key ].setValue( JSON.stringify( model.userData, null, '	' ) );
-
-					} catch ( error ) {
-
-						console.log( error );
-
-					}
-
-				// Texture params
-
-				} else if ( textureParams.indexOf( key ) != -1 ) {
-
-					var options = {};
-					options[ 'new' ] = 'New texture';
-					for ( var id in editor.textures ) options[ id ] = editor.textures[ id ].name;
-					param[ key ].setOptions( options );
-
-					param[ key ].setValue( 'new' );
-					if ( model[ key ] ) param[ key ].setValue( model[ key ].id );
-
-				} 
-
-				// Params by type
-
-				else if ( typeof model[ key ] === 'string' ) param[ key ].setValue( model[ key ] );
-
-				else if ( typeof model[ key ] === 'boolean' ) param[ key ].setValue( model[ key ] );
-
-				else if ( typeof model[ key ] === 'number' ) param[ key ].setValue( model[ key ] );
-
-				else if ( model[ key ] instanceof THREE.Vector3 ) param[ key ].setValue( model[ key ] );
-
-				else if ( model[ key ] instanceof THREE.Color ) param[ key ].setValue( model[ key ] );
-
-			}
-
-		}
-
-	}
-
-	function updateParam( event ) {
-
-		var key = event.srcElement.name;
-		var value = ( param[ key ].getValue ) ? param[ key ].getValue() : null;
-
-		// Special params
-
-		if ( key === 'parent' ) editor.parent( object, editor.objects[ value ] );
-
-		else if ( key === 'geometry' ) model[ key ] = editor.geometries[ value ];
-
-		else if ( key === 'material' ) model[ key ] = editor.materials[ value ];
-
-		else if ( key === 'userData' ) {
-
-			try {
-				 model[ key ] = JSON.parse( value );
-			} catch ( error ) {
-				console.log( error );
-			}
-
-		} else if ( textureParams.indexOf( key ) != -1 ) {
-
-			if ( value == 'new' ) {
-
-				var texture = editor.createTexture();
-				model[ key ] = texture;
-				createUI( texture );
-
-			} else model[ key ] = editor.textures[ value ];
-
-		}
-
-		// Params by type
-
-		else if ( typeof model[ key ] === 'string' ) model[ key ] = value;
-
-		else if ( typeof model[ key ] === 'boolean' ) model[ key ] = value;
-
-		else if ( typeof model[ key ] === 'number' ) model[ key ] = parseFloat( value );
-
-		else if ( model[ key ] instanceof THREE.Color ) model[ key ].setHex( value );
-
-		else if ( model[ key ] instanceof THREE.Vector3 ) model[ key ].copy( value );
-
-		// Post actions
-
-		if ( model instanceof THREE.Object3D ) {
-
-			signals.objectChanged.dispatch( model );
-
-		} else if ( model instanceof THREE.Geometry ) {
-
-			var geoParams = {};
-			for ( var i in param )
-				if ( param[ i ].getValue ) geoParams[ i ] = param[ i ].getValue();
-			editor.updateGeometry( model, geoParams );
-
-		} else if ( model instanceof THREE.Material ) {
-
-			signals.materialChanged.dispatch( model );
-
-		}
-
-		signals.sceneChanged.dispatch( editor.scene );
-
-	}
-
-	return container;
-
-}

+ 94 - 0
editor/js/Sidebar.Geometry.CubeGeometry.js

@@ -0,0 +1,94 @@
+Sidebar.Geometry.CubeGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// width
+
+	var widthRow = new UI.Panel();
+	var width = new UI.Number( geometry.width ).onChange( update );
+
+	widthRow.add( new UI.Text( 'Width' ).setWidth( '90px' ).setColor( '#666' ) );
+	widthRow.add( width );
+
+	container.add( widthRow );
+
+	// height
+
+	var heightRow = new UI.Panel();
+	var height = new UI.Number( geometry.height ).onChange( update );
+
+	heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightRow.add( height );
+
+	container.add( heightRow );
+
+	// depth
+
+	var depthRow = new UI.Panel();
+	var depth = new UI.Number( geometry.depth ).onChange( update );
+
+	depthRow.add( new UI.Text( 'Depth' ).setWidth( '90px' ).setColor( '#666' ) );
+	depthRow.add( depth );
+
+	container.add( depthRow );
+
+	// widthSegments
+
+	var widthSegmentsRow = new UI.Panel();
+	var widthSegments = new UI.Integer( geometry.widthSegments ).setRange( 1, Infinity ).onChange( update );
+
+	widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	widthSegmentsRow.add( widthSegments );
+
+	container.add( widthSegmentsRow );
+
+	// heightSegments
+
+	var heightSegmentsRow = new UI.Panel();
+	var heightSegments = new UI.Integer( geometry.heightSegments ).setRange( 1, Infinity ).onChange( update );
+
+	heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightSegmentsRow.add( heightSegments );
+
+	container.add( heightSegmentsRow );
+
+	// depthSegments
+
+	var depthSegmentsRow = new UI.Panel();
+	var depthSegments = new UI.Integer( geometry.depthSegments ).setRange( 1, Infinity ).onChange( update );
+
+	depthSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	depthSegmentsRow.add( depthSegments );
+
+	container.add( depthSegmentsRow );
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.CubeGeometry(
+			width.getValue(),
+			height.getValue(),
+			depth.getValue(),
+			widthSegments.getValue(),
+			heightSegments.getValue(),
+			depthSegments.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 94 - 0
editor/js/Sidebar.Geometry.CylinderGeometry.js

@@ -0,0 +1,94 @@
+Sidebar.Geometry.CylinderGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// radiusTop
+
+	var radiusTopRow = new UI.Panel();
+	var radiusTop = new UI.Number( geometry.radiusTop ).onChange( update );
+
+	radiusTopRow.add( new UI.Text( 'Radius top' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusTopRow.add( radiusTop );
+
+	container.add( radiusTopRow );
+
+	// radiusBottom
+
+	var radiusBottomRow = new UI.Panel();
+	var radiusBottom = new UI.Number( geometry.radiusBottom ).onChange( update );
+
+	radiusBottomRow.add( new UI.Text( 'Radius bottom' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusBottomRow.add( radiusBottom );
+
+	container.add( radiusBottomRow );
+
+	// height
+
+	var heightRow = new UI.Panel();
+	var height = new UI.Number( geometry.height ).onChange( update );
+
+	heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightRow.add( height );
+
+	container.add( heightRow );
+
+	// radiusSegments
+
+	var radiusSegmentsRow = new UI.Panel();
+	var radiusSegments = new UI.Integer( geometry.radiusSegments ).setRange( 1, Infinity ).onChange( update );
+
+	radiusSegmentsRow.add( new UI.Text( 'Radius segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusSegmentsRow.add( radiusSegments );
+
+	container.add( radiusSegmentsRow );
+
+	// heightSegments
+
+	var heightSegmentsRow = new UI.Panel();
+	var heightSegments = new UI.Integer( geometry.heightSegments ).setRange( 1, Infinity ).onChange( update );
+
+	heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightSegmentsRow.add( heightSegments );
+
+	container.add( heightSegmentsRow );
+
+	// openEnded
+
+	var openEndedRow = new UI.Panel();
+	var openEnded = new UI.Checkbox( geometry.openEnded ).onChange( update );
+
+	openEndedRow.add( new UI.Text( 'Open ended' ).setWidth( '90px' ).setColor( '#666' ) );
+	openEndedRow.add( openEnded );
+
+	container.add( openEndedRow );
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.CylinderGeometry(
+			radiusTop.getValue(),
+			radiusBottom.getValue(),
+			height.getValue(),
+			radiusSegments.getValue(),
+			heightSegments.getValue(),
+			openEnded.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 51 - 0
editor/js/Sidebar.Geometry.IcosahedronGeometry.js

@@ -0,0 +1,51 @@
+Sidebar.Geometry.IcosahedronGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// radius
+
+	var radiusRow = new UI.Panel();
+	var radius = new UI.Number( geometry.radius ).onChange( update );
+
+	radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// detail
+
+	var detailRow = new UI.Panel();
+	var detail = new UI.Integer( geometry.detail ).setRange( 0, Infinity ).onChange( update );
+
+	detailRow.add( new UI.Text( 'Detail' ).setWidth( '90px' ).setColor( '#666' ) );
+	detailRow.add( detail );
+
+	container.add( detailRow );
+
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.IcosahedronGeometry(
+			radius.getValue(),
+			detail.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 73 - 0
editor/js/Sidebar.Geometry.PlaneGeometry.js

@@ -0,0 +1,73 @@
+Sidebar.Geometry.PlaneGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// width
+
+	var widthRow = new UI.Panel();
+	var width = new UI.Number( geometry.width ).onChange( update );
+
+	widthRow.add( new UI.Text( 'Width' ).setWidth( '90px' ).setColor( '#666' ) );
+	widthRow.add( width );
+
+	container.add( widthRow );
+
+	// height
+
+	var heightRow = new UI.Panel();
+	var height = new UI.Number( geometry.height ).onChange( update );
+
+	heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightRow.add( height );
+
+	container.add( heightRow );
+
+	// widthSegments
+
+	var widthSegmentsRow = new UI.Panel();
+	var widthSegments = new UI.Integer( geometry.widthSegments ).setRange( 1, Infinity ).onChange( update );
+
+	widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	widthSegmentsRow.add( widthSegments );
+
+	container.add( widthSegmentsRow );
+
+	// heightSegments
+
+	var heightSegmentsRow = new UI.Panel();
+	var heightSegments = new UI.Integer( geometry.heightSegments ).setRange( 1, Infinity ).onChange( update );
+
+	heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightSegmentsRow.add( heightSegments );
+
+	container.add( heightSegmentsRow );
+
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.PlaneGeometry(
+			width.getValue(),
+			height.getValue(),
+			widthSegments.getValue(),
+			heightSegments.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 106 - 0
editor/js/Sidebar.Geometry.SphereGeometry.js

@@ -0,0 +1,106 @@
+Sidebar.Geometry.SphereGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// radius
+
+	var radiusRow = new UI.Panel();
+	var radius = new UI.Number( geometry.radius ).onChange( update );
+
+	radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// widthSegments
+
+	var widthSegmentsRow = new UI.Panel();
+	var widthSegments = new UI.Integer( geometry.widthSegments ).setRange( 1, Infinity ).onChange( update );
+
+	widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	widthSegmentsRow.add( widthSegments );
+
+	container.add( widthSegmentsRow );
+
+	// heightSegments
+
+	var heightSegmentsRow = new UI.Panel();
+	var heightSegments = new UI.Integer( geometry.heightSegments ).setRange( 1, Infinity ).onChange( update );
+
+	heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	heightSegmentsRow.add( heightSegments );
+
+	container.add( heightSegmentsRow );
+
+	// phiStart
+
+	var phiStartRow = new UI.Panel();
+	var phiStart = new UI.Number( geometry.phiStart ).onChange( update );
+
+	phiStartRow.add( new UI.Text( 'Phi start' ).setWidth( '90px' ).setColor( '#666' ) );
+	phiStartRow.add( phiStart );
+
+	container.add( phiStartRow );
+
+	// phiLength
+
+	var phiLengthRow = new UI.Panel();
+	var phiLength = new UI.Number( geometry.phiLength ).onChange( update );
+
+	phiLengthRow.add( new UI.Text( 'Phi length' ).setWidth( '90px' ).setColor( '#666' ) );
+	phiLengthRow.add( phiLength );
+
+	container.add( phiLengthRow );
+
+	// thetaStart
+
+	var thetaStartRow = new UI.Panel();
+	var thetaStart = new UI.Number( geometry.thetaStart ).onChange( update );
+
+	thetaStartRow.add( new UI.Text( 'Theta start' ).setWidth( '90px' ).setColor( '#666' ) );
+	thetaStartRow.add( thetaStart );
+
+	container.add( thetaStartRow );
+
+	// thetaLength
+
+	var thetaLengthRow = new UI.Panel();
+	var thetaLength = new UI.Number( geometry.thetaLength ).onChange( update );
+
+	thetaLengthRow.add( new UI.Text( 'Theta length' ).setWidth( '90px' ).setColor( '#666' ) );
+	thetaLengthRow.add( thetaLength );
+
+	container.add( thetaLengthRow );
+
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.SphereGeometry(
+			radius.getValue(),
+			widthSegments.getValue(),
+			heightSegments.getValue(),
+			phiStart.getValue(),
+			phiLength.getValue(),
+			thetaStart.getValue(),
+			thetaLength.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 84 - 0
editor/js/Sidebar.Geometry.TorusGeometry.js

@@ -0,0 +1,84 @@
+Sidebar.Geometry.TorusGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// radius
+
+	var radiusRow = new UI.Panel();
+	var radius = new UI.Number( geometry.radius ).onChange( update );
+
+	radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// tube
+
+	var tubeRow = new UI.Panel();
+	var tube = new UI.Number( geometry.tube ).onChange( update );
+
+	tubeRow.add( new UI.Text( 'Tube' ).setWidth( '90px' ).setColor( '#666' ) );
+	tubeRow.add( tube );
+
+	container.add( tubeRow );
+
+	// radialSegments
+
+	var radialSegmentsRow = new UI.Panel();
+	var radialSegments = new UI.Integer( geometry.radialSegments ).setRange( 1, Infinity ).onChange( update );
+
+	radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	radialSegmentsRow.add( radialSegments );
+
+	container.add( radialSegmentsRow );
+
+	// tubularSegments
+
+	var tubularSegmentsRow = new UI.Panel();
+	var tubularSegments = new UI.Integer( geometry.tubularSegments ).setRange( 1, Infinity ).onChange( update );
+
+	tubularSegmentsRow.add( new UI.Text( 'Tubular segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	tubularSegmentsRow.add( tubularSegments );
+
+	container.add( tubularSegmentsRow );
+
+	// arc
+
+	var arcRow = new UI.Panel();
+	var arc = new UI.Number( geometry.arc ).onChange( update );
+
+	arcRow.add( new UI.Text( 'Arc' ).setWidth( '90px' ).setColor( '#666' ) );
+	arcRow.add( arc );
+
+	container.add( arcRow );
+
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.TorusGeometry(
+			radius.getValue(),
+			tube.getValue(),
+			radialSegments.getValue(),
+			tubularSegments.getValue(),
+			arc.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 106 - 0
editor/js/Sidebar.Geometry.TorusKnotGeometry.js

@@ -0,0 +1,106 @@
+Sidebar.Geometry.TorusKnotGeometry = function ( signals, object ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPaddingTop( '10px' );
+
+	var geometry = object.geometry;
+
+	// radius
+
+	var radiusRow = new UI.Panel();
+	var radius = new UI.Number( geometry.radius ).onChange( update );
+
+	radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ).setColor( '#666' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// tube
+
+	var tubeRow = new UI.Panel();
+	var tube = new UI.Number( geometry.tube ).onChange( update );
+
+	tubeRow.add( new UI.Text( 'Tube' ).setWidth( '90px' ).setColor( '#666' ) );
+	tubeRow.add( tube );
+
+	container.add( tubeRow );
+
+	// radialSegments
+
+	var radialSegmentsRow = new UI.Panel();
+	var radialSegments = new UI.Integer( geometry.radialSegments ).setRange( 1, Infinity ).onChange( update );
+
+	radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	radialSegmentsRow.add( radialSegments );
+
+	container.add( radialSegmentsRow );
+
+	// tubularSegments
+
+	var tubularSegmentsRow = new UI.Panel();
+	var tubularSegments = new UI.Integer( geometry.tubularSegments ).setRange( 1, Infinity ).onChange( update );
+
+	tubularSegmentsRow.add( new UI.Text( 'Tubular segments' ).setWidth( '90px' ).setColor( '#666' ) );
+	tubularSegmentsRow.add( tubularSegments );
+
+	container.add( tubularSegmentsRow );
+
+	// p
+
+	var pRow = new UI.Panel();
+	var p = new UI.Number( geometry.p ).onChange( update );
+
+	pRow.add( new UI.Text( 'P' ).setWidth( '90px' ).setColor( '#666' ) );
+	pRow.add( p );
+
+	container.add( pRow );
+
+	// q
+
+	var qRow = new UI.Panel();
+	var q = new UI.Number( geometry.q ).onChange( update );
+
+	pRow.add( new UI.Text( 'Q' ).setWidth( '90px' ).setColor( '#666' ) );
+	pRow.add( q );
+
+	container.add( qRow );
+
+	// heightScale
+
+	var heightScaleRow = new UI.Panel();
+	var heightScale = new UI.Number( geometry.heightScale ).onChange( update );
+
+	pRow.add( new UI.Text( 'Height scale' ).setWidth( '90px' ).setColor( '#666' ) );
+	pRow.add( heightScale );
+
+	container.add( heightScaleRow );
+
+
+	//
+
+	function update() {
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		object.geometry.dispose();
+
+		object.geometry = new THREE.TorusKnotGeometry(
+			radius.getValue(),
+			tube.getValue(),
+			radialSegments.getValue(),
+			tubularSegments.getValue(),
+			p.getValue(),
+			q.getValue(),
+			heightScale.getValue()
+		);
+
+		object.geometry.computeBoundingSphere();
+
+		signals.objectChanged.dispatch( object );
+
+	}
+
+	return container;
+
+}

+ 185 - 0
editor/js/Sidebar.Geometry.js

@@ -0,0 +1,185 @@
+Sidebar.Geometry = function ( signals ) {
+
+	var geometryClasses = {
+
+		"CircleGeometry": THREE.CircleGeometry,
+		"ConvexGeometry": THREE.ConvexGeometry,
+		"CubeGeometry": THREE.CubeGeometry,
+		"CylinderGeometry": THREE.CylinderGeometry,
+		"ExtrudeGeometry": THREE.ExtrudeGeometry,
+		"IcosahedronGeometry": THREE.IcosahedronGeometry,
+		"LatheGeometry": THREE.LatheGeometry,
+		"OctahedronGeometry": THREE.OctahedronGeometry,
+		"ParametricGeometry": THREE.ParametricGeometry,
+		"PlaneGeometry": THREE.PlaneGeometry,
+		"PolyhedronGeometry": THREE.PolyhedronGeometry,
+		"ShapeGeometry": THREE.ShapeGeometry,
+		"SphereGeometry": THREE.SphereGeometry,
+		"TetrahedronGeometry": THREE.TetrahedronGeometry,
+		"TextGeometry": THREE.TextGeometry,
+		"TorusGeometry": THREE.TorusGeometry,
+		"TorusKnotGeometry": THREE.TorusKnotGeometry,
+		"TubeGeometry": THREE.TubeGeometry,
+		"Geometry": THREE.Geometry
+
+	};
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setDisplay( 'none' );
+	container.setPadding( '10px' );
+
+	var objectType = new UI.Text().setColor( '#666' ).setTextTransform( 'uppercase' );
+	container.add( objectType );
+	container.add( new UI.Break(), new UI.Break() );
+
+	// name
+
+	var geometryNameRow = new UI.Panel();
+	var geometryName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+
+	geometryNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ).setColor( '#666' ) );
+	geometryNameRow.add( geometryName );
+
+	container.add( geometryNameRow );
+
+	// vertices
+
+	var geometryVerticesRow = new UI.Panel();
+	var geometryVertices = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+
+	geometryVerticesRow.add( new UI.Text( 'Vertices' ).setWidth( '90px' ).setColor( '#666' ) );
+	geometryVerticesRow.add( geometryVertices );
+
+	container.add( geometryVerticesRow );
+
+	// faces
+
+	var geometryFacesRow = new UI.Panel();
+	var geometryFaces = new UI.Text().setColor( '#444' ).setFontSize( '12px' );
+
+	geometryFacesRow.add( new UI.Text( 'Faces' ).setWidth( '90px' ).setColor( '#666' ) );
+	geometryFacesRow.add( geometryFaces );
+
+	container.add( geometryFacesRow );
+
+	// parameters
+
+	var parameters;
+
+
+	//
+
+	var selected = null;
+
+	function update() {
+
+		if ( selected ) {
+
+			selected.name = geometryName.getValue();
+
+		}
+
+	}
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object && object.geometry ) {
+
+			selected = object.geometry;
+
+			container.setDisplay( 'block' );
+
+			objectType.setValue( getGeometryInstanceName( object.geometry ) );
+
+			updateFields( selected );
+
+			//
+
+			if ( parameters !== undefined ) {
+
+				container.remove( parameters );
+				parameters = undefined;
+
+			}
+
+			if ( selected instanceof THREE.PlaneGeometry ) {
+
+				parameters = new Sidebar.Geometry.PlaneGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.CubeGeometry ) {
+
+				parameters = new Sidebar.Geometry.CubeGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.CylinderGeometry ) {
+
+				parameters = new Sidebar.Geometry.CylinderGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.SphereGeometry ) {
+
+				parameters = new Sidebar.Geometry.SphereGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.IcosahedronGeometry ) {
+
+				parameters = new Sidebar.Geometry.IcosahedronGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.TorusGeometry ) {
+
+				parameters = new Sidebar.Geometry.TorusGeometry( signals, object );
+				container.add( parameters );
+
+			} else if ( selected instanceof THREE.TorusKnotGeometry ) {
+
+				parameters = new Sidebar.Geometry.TorusKnotGeometry( signals, object );
+				container.add( parameters );
+
+			}
+
+		} else {
+
+			selected = null;
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	signals.objectChanged.add( function ( object ) {
+
+		if ( object && object.geometry ) {
+
+			updateFields( object.geometry );
+
+		}
+
+	} );
+
+	//
+
+	function updateFields( geometry ) {
+
+		geometryName.setValue( geometry.name );
+		geometryVertices.setValue( geometry.vertices.length );
+		geometryFaces.setValue( geometry.faces.length );
+
+	}
+
+	function getGeometryInstanceName( geometry ) {
+
+		for ( var key in geometryClasses ) {
+
+			if ( geometry instanceof geometryClasses[ key ] ) return key;
+
+		}
+
+	}
+
+	return container;
+
+}

+ 603 - 0
editor/js/Sidebar.Material.js

@@ -0,0 +1,603 @@
+Sidebar.Material = function ( signals ) {
+
+	var materialClasses = {
+
+		'LineBasicMaterial': THREE.LineBasicMaterial,
+		'LineDashedMaterial': THREE.LineDashedMaterial,
+		'MeshBasicMaterial': THREE.MeshBasicMaterial,
+		'MeshDepthMaterial': THREE.MeshDepthMaterial,
+		'MeshFaceMaterial': THREE.MeshFaceMaterial,
+		'MeshLambertMaterial': THREE.MeshLambertMaterial,
+		'MeshNormalMaterial': THREE.MeshNormalMaterial,
+		'MeshPhongMaterial': THREE.MeshPhongMaterial,
+		'ParticleBasicMaterial': THREE.ParticleBasicMaterial,
+		'ParticleCanvasMaterial': THREE.ParticleCanvasMaterial,
+		'ShaderMaterial': THREE.ShaderMaterial,
+		'Material': THREE.Material
+
+	};
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setDisplay( 'none' );
+	container.setPadding( '10px' );
+
+	container.add( new UI.Text().setValue( 'MATERIAL' ).setColor( '#666' ) );
+	container.add( new UI.Break(), new UI.Break() );
+
+	// name
+
+	var materialNameRow = new UI.Panel();
+	var materialName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+
+	materialNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialNameRow.add( materialName );
+
+	container.add( materialNameRow );
+
+	// class
+
+	var materialClassRow = new UI.Panel();
+	var materialClass = new UI.Select().setOptions( {
+
+		'LineBasicMaterial': 'LineBasicMaterial',
+		'LineDashedMaterial': 'LineDashedMaterial',
+		'MeshBasicMaterial': 'MeshBasicMaterial',
+		'MeshDepthMaterial': 'MeshDepthMaterial',
+		'MeshFaceMaterial': 'MeshFaceMaterial',
+		'MeshLambertMaterial': 'MeshLambertMaterial',
+		'MeshNormalMaterial': 'MeshNormalMaterial',
+		'MeshPhongMaterial': 'MeshPhongMaterial'
+
+	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+
+	materialClassRow.add( new UI.Text( 'Class' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialClassRow.add( materialClass );
+
+	container.add( materialClassRow );
+
+	// color
+
+	var materialColorRow = new UI.Panel();
+	var materialColor = new UI.Color().onChange( update );
+
+	materialColorRow.add( new UI.Text( 'Color' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialColorRow.add( materialColor );
+
+	container.add( materialColorRow );
+
+	// ambient
+
+	var materialAmbientRow = new UI.Panel();
+	var materialAmbient = new UI.Color().onChange( update );
+
+	materialAmbientRow.add( new UI.Text( 'Ambient' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialAmbientRow.add( materialAmbient );
+
+	container.add( materialAmbientRow );
+
+	// emissive
+
+	var materialEmissiveRow = new UI.Panel();
+	var materialEmissive = new UI.Color().onChange( update );
+
+	materialEmissiveRow.add( new UI.Text( 'Emissive' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialEmissiveRow.add( materialEmissive );
+
+	container.add( materialEmissiveRow );
+
+	// specular
+
+	var materialSpecularRow = new UI.Panel();
+	var materialSpecular = new UI.Color().onChange( update );
+
+	materialSpecularRow.add( new UI.Text( 'Specular' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialSpecularRow.add( materialSpecular );
+
+	container.add( materialSpecularRow );
+
+	// shininess
+
+	var materialShininessRow = new UI.Panel();
+	var materialShininess = new UI.Number( 30 ).onChange( update );
+
+	materialShininessRow.add( new UI.Text( 'Shininess' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialShininessRow.add( materialShininess );
+
+	container.add( materialShininessRow );
+
+	// map
+
+	var materialMapRow = new UI.Panel();
+	var materialMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialMap = new UI.Texture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+
+	materialMapRow.add( new UI.Text( 'Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialMapRow.add( materialMapEnabled );
+	materialMapRow.add( materialMap );
+
+	container.add( materialMapRow );
+
+	// light map
+
+	var materialLightMapRow = new UI.Panel();
+	var materialLightMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialLightMap = new UI.Texture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+
+	materialLightMapRow.add( new UI.Text( 'Light Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialLightMapRow.add( materialLightMapEnabled );
+	materialLightMapRow.add( materialLightMap );
+
+	container.add( materialLightMapRow );
+
+	// bump map
+
+	var materialBumpMapRow = new UI.Panel();
+	var materialBumpMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialBumpMap = new UI.Texture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+	var materialBumpScale = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
+
+	materialBumpMapRow.add( new UI.Text( 'Bump Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialBumpMapRow.add( materialBumpMapEnabled );
+	materialBumpMapRow.add( materialBumpScale );
+	materialBumpMapRow.add( materialBumpMap );
+
+	container.add( materialBumpMapRow );
+
+	// normal map
+
+	var materialNormalMapRow = new UI.Panel();
+	var materialNormalMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialNormalMap = new UI.Texture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+
+	materialNormalMapRow.add( new UI.Text( 'Normal Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialNormalMapRow.add( materialNormalMapEnabled );
+	materialNormalMapRow.add( materialNormalMap );
+
+	container.add( materialNormalMapRow );
+
+	// specular map
+
+	var materialSpecularMapRow = new UI.Panel();
+	var materialSpecularMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialSpecularMap = new UI.Texture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+
+	materialSpecularMapRow.add( new UI.Text( 'Specular Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialSpecularMapRow.add( materialSpecularMapEnabled );
+	materialSpecularMapRow.add( materialSpecularMap );
+
+	container.add( materialSpecularMapRow );
+
+	// env map
+
+	var materialEnvMapRow = new UI.Panel();
+	var materialEnvMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialEnvMap = new UI.CubeTexture().setColor( '#444' ).setWidth( '100px' ).onChange( update );
+	var materialReflectivity = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
+
+
+	materialEnvMapRow.add( new UI.Text( 'Env Map' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialEnvMapRow.add( materialEnvMapEnabled );
+	materialEnvMapRow.add( materialReflectivity );
+	materialEnvMapRow.add( materialEnvMap );
+
+	container.add( materialEnvMapRow );
+
+	// opacity
+
+	var materialOpacityRow = new UI.Panel();
+	var materialOpacity = new UI.Number().setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
+
+	materialOpacityRow.add( new UI.Text( 'Opacity' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialOpacityRow.add( materialOpacity );
+
+	container.add( materialOpacityRow );
+
+	// transparent
+
+	var materialTransparentRow = new UI.Panel();
+	var materialTransparent = new UI.Checkbox().setLeft( '100px' ).onChange( update );
+
+	materialTransparentRow.add( new UI.Text( 'Transparent' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialTransparentRow.add( materialTransparent );
+
+	container.add( materialTransparentRow );
+
+	// wireframe
+
+	var materialWireframeRow = new UI.Panel();
+	var materialWireframe = new UI.Checkbox( false ).onChange( update );
+	var materialWireframeLinewidth = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 100 ).onChange( update );
+
+	materialWireframeRow.add( new UI.Text( 'Wireframe' ).setWidth( '90px' ).setColor( '#666' ) );
+	materialWireframeRow.add( materialWireframe );
+	materialWireframeRow.add( materialWireframeLinewidth );
+
+	container.add( materialWireframeRow );
+
+
+	//
+
+	var selected = null;
+	var selectedHasUvs = false;
+
+	function update() {
+
+		var material = selected.material;
+		var textureWarning = false;
+
+		if ( material ) {
+
+			material.name = materialName.getValue();
+
+			if ( material instanceof materialClasses[ materialClass.getValue() ] == false ) {
+
+				material = new materialClasses[ materialClass.getValue() ]();
+				selected.material = material;
+
+			}
+
+			if ( material.color !== undefined ) {
+
+				material.color.setHex( materialColor.getHexValue() );
+
+			}
+
+			if ( material.ambient !== undefined ) {
+
+				material.ambient.setHex( materialAmbient.getHexValue() );
+
+			}
+
+			if ( material.emissive !== undefined ) {
+
+				material.emissive.setHex( materialEmissive.getHexValue() );
+
+			}
+
+			if ( material.specular !== undefined ) {
+
+				material.specular.setHex( materialSpecular.getHexValue() );
+
+			}
+
+			if ( material.shininess !== undefined ) {
+
+				material.shininess = materialShininess.getValue();
+
+			}
+
+			if ( material.map !== undefined ) {
+
+				var mapEnabled = materialMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.map = mapEnabled ? materialMap.getValue() : null;
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( mapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
+			/*
+			if ( material.lightMap !== undefined ) {
+
+				var lightMapEnabled = materialLightMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.lightMap = lightMapEnabled ? materialLightMap.getValue() : null;
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( lightMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+			*/
+
+			if ( material.bumpMap !== undefined ) {
+
+				var bumpMapEnabled = materialBumpMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.bumpMap = bumpMapEnabled ? materialBumpMap.getValue() : null;
+					material.bumpScale = materialBumpScale.getValue();
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( bumpMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
+			if ( material.normalMap !== undefined ) {
+
+				var normalMapEnabled = materialNormalMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.normalMap = normalMapEnabled ? materialNormalMap.getValue() : null;
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( normalMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
+			if ( material.specularMap !== undefined ) {
+
+				var specularMapEnabled = materialSpecularMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.specularMap = specularMapEnabled ? materialSpecularMap.getValue() : null;
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( specularMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
+			if ( material.envMap !== undefined ) {
+
+				var envMapEnabled = materialEnvMapEnabled.getValue() === true;
+
+				if ( selectedHasUvs )  {
+
+					material.envMap = envMapEnabled ? materialEnvMap.getValue() : null;
+					material.reflectivity = materialReflectivity.getValue();
+					material.needsUpdate = true;
+					selected.geometry.buffersNeedUpdate = true;
+					selected.geometry.uvsNeedUpdate = true;
+
+				} else {
+
+					if ( envMapEnabled ) textureWarning = true;
+
+				}
+
+			}
+
+			if ( material.opacity !== undefined ) {
+
+				material.opacity = materialOpacity.getValue();
+
+			}
+
+			if ( material.transparent !== undefined ) {
+
+				material.transparent = materialTransparent.getValue();
+
+			}
+
+			if ( material.wireframe !== undefined ) {
+
+				material.wireframe = materialWireframe.getValue();
+
+			}
+
+			if ( material.wireframeLinewidth !== undefined ) {
+
+				material.wireframeLinewidth = materialWireframeLinewidth.getValue();
+
+			}
+
+			updateRows();
+
+			signals.materialChanged.dispatch( material );
+
+		}
+
+		if ( textureWarning ) {
+
+			console.warn( "Can't set texture, model doesn't have texture coordinates" );
+
+		}
+
+	};
+
+	function updateRows() {
+
+		var properties = {
+			'color': materialColorRow,
+			'ambient': materialAmbientRow,
+			'emissive': materialEmissiveRow,
+			'specular': materialSpecularRow,
+			'shininess': materialShininessRow,
+			'map': materialMapRow,
+			'lightMap': materialLightMapRow,
+			'bumpMap': materialBumpMapRow,
+			'normalMap': materialNormalMapRow,
+			'specularMap': materialSpecularMapRow,
+			'envMap': materialEnvMapRow,
+			'opacity': materialOpacityRow,
+			'transparent': materialTransparentRow,
+			'wireframe': materialWireframeRow
+
+		};
+
+		for ( var property in properties ) {
+
+			properties[ property ].setDisplay( selected.material[ property ] !== undefined ? '' : 'none' );
+
+		}
+
+	};
+
+	function getMaterialInstanceName( material ) {
+
+		for ( var key in materialClasses ) {
+
+			if ( material instanceof materialClasses[ key ] ) return key;
+
+		}
+
+	}
+
+	// events
+
+	signals.objectSelected.add( function ( object ) {
+
+		if ( object && object.material ) {
+
+			selected = object;
+			selectedHasUvs = object.geometry.faceVertexUvs[ 0 ].length > 0;
+
+			container.setDisplay( '' );
+
+			var material = object.material;
+
+			materialName.setValue( material.name );
+			materialClass.setValue( getMaterialInstanceName( material ) );
+
+			if ( material.color !== undefined ) {
+
+				materialColor.setValue( '#' + material.color.getHexString() );
+
+			}
+
+			if ( material.ambient !== undefined ) {
+
+				materialAmbient.setValue( '#' + material.ambient.getHexString() );
+
+			}
+
+			if ( material.emissive !== undefined ) {
+
+				materialEmissive.setValue( '#' + material.emissive.getHexString() );
+
+			}
+
+			if ( material.specular !== undefined ) {
+
+				materialSpecular.setValue( '#' + material.specular.getHexString() );
+
+			}
+
+			if ( material.shininess !== undefined ) {
+
+				materialShininess.setValue( material.shininess );
+
+			}
+
+			if ( material.map !== undefined ) {
+
+				if ( selectedHasUvs ) {
+
+					materialMapEnabled.setValue( material.map !== null );
+					materialMap.setValue( material.map );
+
+				} else {
+
+					console.warn( "Can't set texture, model doesn't have texture coordinates" );
+
+				}
+
+			}
+
+			/*
+			if ( material.lightMap !== undefined ) {
+
+				materialLightMapEnabled.setValue( material.lightMap !== null );
+				materialLightMap.setValue( material.lightMap );
+
+			}
+			*/
+
+			if ( material.bumpMap !== undefined ) {
+
+				materialBumpMapEnabled.setValue( material.bumpMap !== null );
+				materialBumpMap.setValue( material.bumpMap );
+				materialBumpScale.setValue( material.bumpScale );
+
+			}
+
+			if ( material.normalMap !== undefined ) {
+
+				materialNormalMapEnabled.setValue( material.normalMap !== null );
+				materialNormalMap.setValue( material.normalMap );
+
+			}
+
+			if ( material.specularMap !== undefined ) {
+
+				materialSpecularMapEnabled.setValue( material.specularMap !== null );
+				materialSpecularMap.setValue( material.specularMap );
+
+			}
+
+			if ( material.envMap !== undefined ) {
+
+				materialEnvMapEnabled.setValue( material.envMap !== null );
+				materialEnvMap.setValue( material.envMap );
+				materialReflectivity.setValue( material.reflectivity );
+
+			}
+
+			if ( material.opacity !== undefined ) {
+
+				materialOpacity.setValue( material.opacity );
+
+			}
+
+			if ( material.transparent !== undefined ) {
+
+				materialTransparent.setValue( material.transparent );
+
+			}
+
+			if ( material.wireframe !== undefined ) {
+
+				materialWireframe.setValue( material.wireframe );
+
+			}
+
+			if ( material.wireframeLinewidth !== undefined ) {
+
+				materialWireframeLinewidth.setValue( material.wireframeLinewidth );
+
+			}
+
+			updateRows();
+
+		} else {
+
+			selected = null;
+			selectedHasUvs = false;
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	return container;
+
+}

+ 568 - 0
editor/js/Sidebar.Object3D.js

@@ -0,0 +1,568 @@
+Sidebar.Object3D = function ( signals ) {
+
+	var container = new UI.Panel();
+	container.setBorderTop( '1px solid #ccc' );
+	container.setPadding( '10px' );
+	container.setDisplay( 'none' );
+
+	var objectType = new UI.Text().setColor( '#666' ).setTextTransform( 'uppercase' );
+	container.add( objectType );
+	container.add( new UI.Break(), new UI.Break() );
+
+	// parent
+
+	var objectParentRow = new UI.Panel();
+	var objectParent = new UI.Select().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+
+	objectParentRow.add( new UI.Text( 'Parent' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectParentRow.add( objectParent );
+
+	container.add( objectParentRow );
+
+	// name
+
+	var objectNameRow = new UI.Panel();
+	var objectName = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+
+	objectNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectNameRow.add( objectName );
+
+	container.add( objectNameRow );
+
+	// position
+
+	var objectPositionRow = new UI.Panel();
+	var objectPositionX = new UI.Number().setWidth( '50px' ).onChange( update );
+	var objectPositionY = new UI.Number().setWidth( '50px' ).onChange( update );
+	var objectPositionZ = new UI.Number().setWidth( '50px' ).onChange( update );
+
+	objectPositionRow.add( new UI.Text( 'Position' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectPositionRow.add( objectPositionX, objectPositionY, objectPositionZ );
+
+	container.add( objectPositionRow );
+
+	// rotation
+
+	var objectRotationRow = new UI.Panel();
+	var objectRotationX = new UI.Number().setWidth( '50px' ).onChange( update );
+	var objectRotationY = new UI.Number().setWidth( '50px' ).onChange( update );
+	var objectRotationZ = new UI.Number().setWidth( '50px' ).onChange( update );
+
+	objectRotationRow.add( new UI.Text( 'Rotation' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectRotationRow.add( objectRotationX, objectRotationY, objectRotationZ );
+
+	container.add( objectRotationRow );
+
+	// scale
+
+	var objectScaleRow = new UI.Panel();
+	var objectScaleLock = new UI.Checkbox().setPosition( 'absolute' ).setLeft( '75px' );
+	var objectScaleX = new UI.Number( 1 ).setWidth( '50px' ).onChange( updateScaleX );
+	var objectScaleY = new UI.Number( 1 ).setWidth( '50px' ).onChange( updateScaleY );
+	var objectScaleZ = new UI.Number( 1 ).setWidth( '50px' ).onChange( updateScaleZ );
+
+	objectScaleRow.add( new UI.Text( 'Scale' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectScaleRow.add( objectScaleLock );
+	objectScaleRow.add( objectScaleX, objectScaleY, objectScaleZ );
+
+	container.add( objectScaleRow );
+
+	// fov
+
+	var objectFovRow = new UI.Panel();
+	var objectFov = new UI.Number().onChange( update );
+
+	objectFovRow.add( new UI.Text( 'Fov' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectFovRow.add( objectFov );
+
+	container.add( objectFovRow );
+
+	// near
+
+	var objectNearRow = new UI.Panel();
+	var objectNear = new UI.Number().onChange( update );
+
+	objectNearRow.add( new UI.Text( 'Near' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectNearRow.add( objectNear );
+
+	container.add( objectNearRow );
+
+	// far
+
+	var objectFarRow = new UI.Panel();
+	var objectFar = new UI.Number().onChange( update );
+
+	objectFarRow.add( new UI.Text( 'Far' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectFarRow.add( objectFar );
+
+	container.add( objectFarRow );
+
+	// intensity
+
+	var objectIntensityRow = new UI.Panel();
+	var objectIntensity = new UI.Number().setRange( 0, Infinity ).onChange( update );
+
+	objectIntensityRow.add( new UI.Text( 'Intensity' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectIntensityRow.add( objectIntensity );
+
+	container.add( objectIntensityRow );
+
+	// color
+
+	var objectColorRow = new UI.Panel();
+	var objectColor = new UI.Color().onChange( update );
+
+	objectColorRow.add( new UI.Text( 'Color' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectColorRow.add( objectColor );
+
+	container.add( objectColorRow );
+
+	// ground color
+
+	var objectGroundColorRow = new UI.Panel();
+	var objectGroundColor = new UI.Color().onChange( update );
+
+	objectGroundColorRow.add( new UI.Text( 'Ground color' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectGroundColorRow.add( objectGroundColor );
+
+	container.add( objectGroundColorRow );
+
+	// distance
+
+	var objectDistanceRow = new UI.Panel();
+	var objectDistance = new UI.Number().setRange( 0, Infinity ).onChange( update );
+
+	objectDistanceRow.add( new UI.Text( 'Distance' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectDistanceRow.add( objectDistance );
+
+	container.add( objectDistanceRow );
+
+	// angle
+
+	var objectAngleRow = new UI.Panel();
+	var objectAngle = new UI.Number().setPrecision( 3 ).setRange( 0, Math.PI / 2 ).onChange( update );
+
+	objectAngleRow.add( new UI.Text( 'Angle' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectAngleRow.add( objectAngle );
+
+	container.add( objectAngleRow );
+
+	// exponent
+
+	var objectExponentRow = new UI.Panel();
+	var objectExponent = new UI.Number().setRange( 0, Infinity ).onChange( update );
+
+	objectExponentRow.add( new UI.Text( 'Exponent' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectExponentRow.add( objectExponent );
+
+	container.add( objectExponentRow );
+
+	// visible
+
+	var objectVisibleRow = new UI.Panel();
+	var objectVisible = new UI.Checkbox().onChange( update );
+
+	objectVisibleRow.add( new UI.Text( 'Visible' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectVisibleRow.add( objectVisible );
+
+	container.add( objectVisibleRow );
+
+	// user data
+
+	var objectUserDataRow = new UI.Panel();
+	var objectUserData = new UI.TextArea().setWidth( '150px' ).setHeight( '40px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( update );
+	objectUserData.onKeyUp( function () {
+
+		try {
+
+			JSON.parse( objectUserData.getValue() );
+			objectUserData.setBorderColor( '#ccc' );
+			objectUserData.setBackgroundColor( '' );
+
+		} catch ( error ) {
+
+			objectUserData.setBorderColor( '#f00' );
+			objectUserData.setBackgroundColor( 'rgba(255,0,0,0.25)' );
+
+		}
+
+	} );
+
+	objectUserDataRow.add( new UI.Text( 'User data' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectUserDataRow.add( objectUserData );
+
+	container.add( objectUserDataRow );
+
+
+	//
+
+	var selected = null;
+
+	var scene = null;
+
+	function updateScaleX() {
+
+		if ( objectScaleLock.getValue() === true ) {
+
+			var scale = objectScaleX.getValue() / selected.scale.x;
+
+			objectScaleY.setValue( objectScaleY.getValue() * scale );
+			objectScaleZ.setValue( objectScaleZ.getValue() * scale );
+
+		}
+
+		update();
+
+	}
+
+	function updateScaleY() {
+
+		if ( objectScaleLock.getValue() === true ) {
+
+			var scale = objectScaleY.getValue() / selected.scale.y;
+
+			objectScaleX.setValue( objectScaleX.getValue() * scale );
+			objectScaleZ.setValue( objectScaleZ.getValue() * scale );
+
+		}
+
+		update();
+
+	}
+
+	function updateScaleZ() {
+
+		if ( objectScaleLock.getValue() === true ) {
+
+			var scale = objectScaleZ.getValue() / selected.scale.z;
+
+			objectScaleX.setValue( objectScaleX.getValue() * scale );
+			objectScaleY.setValue( objectScaleY.getValue() * scale );
+
+		}
+
+		update();
+
+	}
+
+	function update() {
+
+		if ( selected ) {
+
+			selected.name = objectName.getValue();
+
+			if ( selected.parent !== undefined ) {
+
+				var newParentId = parseInt( objectParent.getValue() );
+
+				if ( selected.parent.id !== newParentId && selected.id !== newParentId ) {
+
+					var parent = scene.getObjectById( newParentId, true );
+
+					if ( parent === undefined ) {
+
+						parent = scene;
+
+					}
+
+					parent.add( selected );
+
+					signals.sceneChanged.dispatch( scene );
+
+				}
+
+			}
+
+			selected.position.x = objectPositionX.getValue();
+			selected.position.y = objectPositionY.getValue();
+			selected.position.z = objectPositionZ.getValue();
+
+			selected.rotation.x = objectRotationX.getValue();
+			selected.rotation.y = objectRotationY.getValue();
+			selected.rotation.z = objectRotationZ.getValue();
+
+			selected.scale.x = objectScaleX.getValue();
+			selected.scale.y = objectScaleY.getValue();
+			selected.scale.z = objectScaleZ.getValue();
+
+			if ( selected.fov !== undefined ) {
+
+				selected.fov = objectFov.getValue();
+				selected.updateProjectionMatrix();
+
+			}
+
+			if ( selected.near !== undefined ) {
+
+				selected.near = objectNear.getValue();
+
+			}
+
+			if ( selected.far !== undefined ) {
+
+				selected.far = objectFar.getValue();
+
+			}
+
+			if ( selected.intensity !== undefined ) {
+
+				selected.intensity = objectIntensity.getValue();
+
+			}
+
+			if ( selected.color !== undefined ) {
+
+				selected.color.setHex( objectColor.getHexValue() );
+
+			}
+
+			if ( selected.groundColor !== undefined ) {
+
+				selected.groundColor.setHex( objectGroundColor.getHexValue() );
+
+			}
+
+			if ( selected.distance !== undefined ) {
+
+				selected.distance = objectDistance.getValue();
+
+			}
+
+			if ( selected.angle !== undefined ) {
+
+				selected.angle = objectAngle.getValue();
+
+			}
+
+			if ( selected.exponent !== undefined ) {
+
+				selected.exponent = objectExponent.getValue();
+
+			}
+
+			selected.visible = objectVisible.getValue();
+
+			try {
+
+				selected.userData = JSON.parse( objectUserData.getValue() );
+
+			} catch ( error ) {
+
+				console.log( error );
+
+			}
+
+			signals.objectChanged.dispatch( selected );
+
+		}
+
+	}
+
+	function updateRows() {
+
+		var properties = {
+			'parent': objectParentRow,
+			'fov': objectFovRow,
+			'near': objectNearRow,
+			'far': objectFarRow,
+			'intensity': objectIntensityRow,
+			'color': objectColorRow,
+			'groundColor': objectGroundColorRow,
+			'distance' : objectDistanceRow,
+			'angle' : objectAngleRow,
+			'exponent' : objectExponentRow
+		};
+
+		for ( var property in properties ) {
+
+			properties[ property ].setDisplay( selected[ property ] !== undefined ? '' : 'none' );
+
+		}
+
+	}
+
+	function updateTransformRows() {
+
+		if ( selected instanceof THREE.Light || ( selected instanceof THREE.Object3D && selected.userData.targetInverse ) ) {
+
+			objectRotationRow.setDisplay( 'none' );
+			objectScaleRow.setDisplay( 'none' );
+
+		} else {
+
+			objectRotationRow.setDisplay( '' );
+			objectScaleRow.setDisplay( '' );
+
+		}
+
+	}
+
+	function getObjectInstanceName( object ) {
+
+		var objects = {
+
+			'Scene': THREE.Scene,
+			'PerspectiveCamera': THREE.PerspectiveCamera,
+			'AmbientLight': THREE.AmbientLight,
+			'DirectionalLight': THREE.DirectionalLight,
+			'HemisphereLight': THREE.HemisphereLight,
+			'PointLight': THREE.PointLight,
+			'SpotLight': THREE.SpotLight,
+			'Mesh': THREE.Mesh,
+			'Object3D': THREE.Object3D
+
+		};
+
+		for ( var key in objects ) {
+
+			if ( object instanceof objects[ key ] ) return key;
+
+		}
+
+	}
+
+	// events
+
+	signals.sceneChanged.add( function ( object ) {
+
+		scene = object;
+
+		var options = {};
+
+		options[ scene.id ] = 'Scene';
+
+		( function addObjects( objects ) {
+
+			for ( var i = 0, l = objects.length; i < l; i ++ ) {
+
+				var object = objects[ i ];
+
+				options[ object.id ] = object.name;
+
+				addObjects( object.children );
+
+			}
+
+		} )( object.children );
+
+		objectParent.setOptions( options );
+
+	} );
+
+	signals.objectSelected.add( function ( object ) {
+
+		selected = object;
+		updateUI();
+
+	} );
+	signals.objectChanged.add( function ( object ) {
+
+		if ( selected === object ) updateUI();
+
+	} );
+
+	function updateUI() {
+
+		container.setDisplay( 'block' );
+
+		var object = selected;
+
+		objectType.setValue( getObjectInstanceName( object ) );
+
+		if ( object.parent !== undefined ) {
+
+			objectParent.setValue( object.parent.id );
+
+		}
+
+		objectName.setValue( object.name );
+
+		objectPositionX.setValue( object.position.x );
+		objectPositionY.setValue( object.position.y );
+		objectPositionZ.setValue( object.position.z );
+
+		objectRotationX.setValue( object.rotation.x );
+		objectRotationY.setValue( object.rotation.y );
+		objectRotationZ.setValue( object.rotation.z );
+
+		objectScaleX.setValue( object.scale.x );
+		objectScaleY.setValue( object.scale.y );
+		objectScaleZ.setValue( object.scale.z );
+
+		if ( object.fov !== undefined ) {
+
+			objectFov.setValue( object.fov );
+
+		}
+
+		if ( object.near !== undefined ) {
+
+			objectNear.setValue( object.near );
+
+		}
+
+		if ( object.far !== undefined ) {
+
+			objectFar.setValue( object.far );
+
+		}
+
+		if ( object.intensity !== undefined ) {
+
+			objectIntensity.setValue( object.intensity );
+
+		}
+
+		if ( object.color !== undefined ) {
+
+			objectColor.setValue( '#' + object.color.getHexString() );
+
+		}
+
+		if ( object.groundColor !== undefined ) {
+
+			objectGroundColor.setValue( '#' + object.groundColor.getHexString() );
+
+		}
+
+		if ( object.distance !== undefined ) {
+
+			objectDistance.setValue( object.distance );
+
+		}
+
+		if ( object.angle !== undefined ) {
+
+			objectAngle.setValue( object.angle );
+
+		}
+
+		if ( object.exponent !== undefined ) {
+
+			objectExponent.setValue( object.exponent );
+
+		}
+
+		objectVisible.setValue( object.visible );
+
+		try {
+
+			objectUserData.setValue( JSON.stringify( object.userData, null, '  ' ) );
+
+		} catch ( error ) {
+
+			console.log( error );
+
+		}
+
+		objectUserData.setBorderColor( '#ccc' );
+		objectUserData.setBackgroundColor( '' );
+
+		updateRows();
+		updateTransformRows();
+
+	}
+
+	return container;
+
+}

+ 0 - 71
editor/js/Sidebar.Outliner.Geometries.js

@@ -1,71 +0,0 @@
-Sidebar.Outliner.Geometries = function ( signals ) {
-
-	var container = new UI.Panel();
-	container.name = "GEO";
-	container.setPadding( '10px' );
-
-	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('170px').setColor( '#444' ).setFontSize( '12px' ).onChange( selectFromOutliner );
-	container.add( outliner );
-
-	var geometries = null;
-
-	function getGeometries() {
-
-		var options = {};
-
-		for ( var i in editor.geometries ) {
-
-			var geometry = editor.geometries[ i ];
-			options[ i ] = '- ' + geometry.name;
-
-		}
-
-		outliner.setOptions( options );
-		getSelected();
-
-	}
-
-	function getSelected() {
-
-		var selectedIds = [];
-
-		for ( var id in editor.selected ) {
-
-			if ( editor.geometries[ id ] ) selectedIds.push( id );
-
-		}
-
-		// TODO: implement multiple selection
-		outliner.setValue( selectedIds.length ? selectedIds[0] : null );
-
-	}
-
-	function selectFromOutliner() {
-
-		var id = outliner.getValue();
-
-		editor.select( editor.geometries[ id ] );
-
-	}
-
-	// events
-
-	var timeout;
-
-	signals.sceneChanged.add( function () {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			getGeometries();
-
-		}, 100 );
-
-	} );
-
-	signals.selected.add( getSelected );
-
-	return container;
-
-}

+ 0 - 71
editor/js/Sidebar.Outliner.Materials.js

@@ -1,71 +0,0 @@
-Sidebar.Outliner.Materials = function ( signals ) {
-
-	var container = new UI.Panel();
-	container.name = "MAT";
-	container.setPadding( '10px' );
-
-	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('170px').setColor( '#444' ).setFontSize( '12px' ).onChange( selectFromOutliner );
-	container.add( outliner );
-
-	var materials = null;
-
-	function getMaterials() {
-
-		var options = {};
-
-		for ( var i in editor.materials ) {
-
-			var material = editor.materials[ i ];
-			options[ i ] = '- ' + material.name;
-
-		}
-
-		outliner.setOptions( options );
-		getSelected();
-
-	}
-
-	function getSelected() {
-
-		var selectedIds = [];
-
-		for ( var id in editor.selected ) {
-
-			if ( editor.materials[ id ] ) selectedIds.push( id );
-
-		}
-
-		// TODO: implement multiple selection
-		outliner.setValue( selectedIds.length ? selectedIds[0] : null );
-
-	}
-
-	function selectFromOutliner() {
-
-		var id = outliner.getValue();
-
-		editor.select( editor.materials[ id ] );
-
-	}
-
-	// events
-
-	var timeout;
-
-	signals.sceneChanged.add( function () {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			getMaterials();
-
-		}, 100 );
-
-	} );
-
-	signals.selected.add( getSelected );
-
-	return container;
-
-}

+ 0 - 154
editor/js/Sidebar.Outliner.Scene.js

@@ -1,154 +0,0 @@
-Sidebar.Outliner.Scene = function ( signals ) {
-
-	var container = new UI.Panel();
-	container.name = "SCENE";
-	container.setPadding( '10px' );
-
-	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('128px').setColor( '#444' ).setFontSize( '12px' ).onChange( selectFromOutliner );
-	container.add( outliner );
-	container.add( new UI.Break() );
-
-	// fog
-
-	var fogTypeRow = new UI.Panel();
-	var fogType = new UI.Select().setOptions( {
-
-		'None': 'None',
-		'Fog': 'Linear',
-		'FogExp2': 'Exponential'
-
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange(
-		function() { editor.setFog( { fogType: fogType.getValue() } ) }
-	);
-	fogTypeRow.add( new UI.Text( 'Fog' ).setWidth( '90px' ).setColor( '#666' ) );
-	fogTypeRow.add( fogType );
-	container.add( fogTypeRow );
-
-	//
-
-	var scene = null;
-
-	function getObjectType( object ) {
-
-		var objects = {
-
-			'Scene': THREE.Scene,
-			'PerspectiveCamera': THREE.PerspectiveCamera,
-			'AmbientLight': THREE.AmbientLight,
-			'DirectionalLight': THREE.DirectionalLight,
-			'HemisphereLight': THREE.HemisphereLight,
-			'PointLight': THREE.PointLight,
-			'SpotLight': THREE.SpotLight,
-			'Mesh': THREE.Mesh,
-			'Object3D': THREE.Object3D
-
-		};
-
-		for ( var type in objects ) {
-
-			if ( object instanceof objects[ type ] ) return type;
-
-		}
-
-	}
-
-	function selectFromOutliner() {
-
-		var id = outliner.getValue();
-
-		editor.select( editor.objects[ id ] );
-
-	}
-
-	function getScene() {
-
-		var options = {};
-
-		var scene = editor.scene;
-
-		options[ scene.id ] = scene.name + ' <span style="color: #aaa">- ' + getObjectType( scene ) + '</span>';
-
-		( function addObjects( objects, pad ) {
-
-			for ( var i = 0, l = objects.length; i < l; i ++ ) {
-
-				var object = objects[ i ];
-
-				options[ object.id ] = pad + object.name + ' <span style="color: #aaa">- ' + getObjectType( object ) + '</span>';
-
-				addObjects( object.children, pad + '&nbsp;&nbsp;&nbsp;' );
-
-			}
-
-		} )( scene.children, '&nbsp;&nbsp;&nbsp;' );
-
-		outliner.setOptions( options );
-		getSelected();
-		getFog();
-
-	}
-
-	function getSelected() {
-
-		var selectedIds = [];
-
-		for ( var id in editor.selected ) {
-
-			if ( editor.objects[ id ] ) selectedIds.push( id );
-
-		}
-
-		outliner.setValue( selectedIds.length ? selectedIds : null );
-
-	}
-
-	function getFog() {
-
-		var scene = editor.scene;
-
-		if ( scene.fog ) {
-
-			if ( scene.fog instanceof THREE.Fog ) {
-
-				fogType.setValue( "Fog" );
-
-			} else if ( scene.fog instanceof THREE.FogExp2 ) {
-
-				fogType.setValue( "FogExp2" );
-
-			}
-
-		} else {
-
-			fogType.setValue( "None" );
-
-		}
-
-		var type = fogType.getValue();
-
-	}
-
-	// events
-
-	var timeout;
-
-	signals.sceneChanged.add( function ( object ) {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			getScene();
-
-		}, 100 );
-
-	} );
-
-
-	signals.fogChanged.add( getFog );
-
-	signals.selected.add( getSelected );
-
-	return container;
-
-}

+ 0 - 71
editor/js/Sidebar.Outliner.Textures.js

@@ -1,71 +0,0 @@
-Sidebar.Outliner.Textures = function ( signals ) {
-
-	var container = new UI.Panel();
-	container.name = "TEX";
-	container.setPadding( '10px' );
-
-	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('170px').setColor( '#444' ).setFontSize( '12px' ).onChange( selectFromOutliner );
-	container.add( outliner );
-
-	var textures = null;
-
-	function getTextures() {
-
-		var options = {};
-
-		for ( var i in editor.textures ) {
-
-			var texture = editor.textures[ i ];
-			options[ i ] = '- ' + texture.name;
-
-		}
-
-		outliner.setOptions( options );
-		getSelected();
-
-	}
-
-	function selectFromOutliner() {
-
-		var id = outliner.getValue();
-
-		editor.select( editor.textures[ id ] );
-
-	}
-
-	function getSelected() {
-
-		var selectedIds = [];
-
-		for ( var id in editor.selected ) {
-
-			if ( editor.textures[ id ] ) selectedIds.push( id );
-
-		}
-
-		// TODO: implement multiple selection
-		outliner.setValue( selectedIds.length ? selectedIds[0] : null );
-
-	}
-
-	// events
-
-	var timeout;
-
-	signals.sceneChanged.add( function () {
-
-		clearTimeout( timeout );
-
-		timeout = setTimeout( function () {
-
-			getTextures();
-
-		}, 100 );
-
-	} );
-
-	signals.selected.add( getSelected );
-
-	return container;
-
-}

+ 0 - 12
editor/js/Sidebar.Outliner.js

@@ -1,12 +0,0 @@
-Sidebar.Outliner = function ( signals ) {
-
-	var container = new UI.TabbedPanel();
-
-	container.add( new Sidebar.Outliner.Scene( signals ) );
-	container.add( new Sidebar.Outliner.Geometries( signals ) );
-	container.add( new Sidebar.Outliner.Materials( signals ) );
-	container.add( new Sidebar.Outliner.Textures( signals ) );
-
-	return container;
-
-}

+ 1 - 1
editor/js/Sidebar.Renderer.js

@@ -57,7 +57,7 @@ Sidebar.Renderer = function ( signals ) {
 			clearColor: clearColor.getHexValue(),
 			clearAlpha: 1
 		} );
-		signals.setRenderer.dispatch( renderer );
+		signals.rendererChanged.dispatch( renderer );
 
 	}
 

+ 218 - 0
editor/js/Sidebar.Scene.js

@@ -0,0 +1,218 @@
+Sidebar.Scene = function ( signals ) {
+
+	var selected = null;
+
+	var container = new UI.Panel();
+	container.setPadding( '10px' );
+	container.setBorderTop( '1px solid #ccc' );
+
+	container.add( new UI.Text( 'SCENE' ).setColor( '#666' ) );
+	container.add( new UI.Break(), new UI.Break() );
+
+	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('140px').setColor( '#444' ).setFontSize( '12px' ).onChange( updateOutliner );
+	container.add( outliner );
+	container.add( new UI.Break() );
+
+	// fog
+
+	var fogTypeRow = new UI.Panel();
+	var fogType = new UI.Select().setOptions( {
+
+		'None': 'None',
+		'Fog': 'Linear',
+		'FogExp2': 'Exponential'
+
+	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( updateFogType );
+
+	fogTypeRow.add( new UI.Text( 'Fog' ).setWidth( '90px' ).setColor( '#666' ) );
+	fogTypeRow.add( fogType );
+
+	container.add( fogTypeRow );
+
+	// fog color
+
+	var fogColorRow = new UI.Panel();
+	fogColorRow.setDisplay( 'none' );
+
+	var fogColor = new UI.Color().setValue( '#aaaaaa' ).onChange( updateFogColor );
+
+	fogColorRow.add( new UI.Text( 'Fog color' ).setWidth( '90px' ).setColor( '#666' ) );
+	fogColorRow.add( fogColor );
+
+	container.add( fogColorRow );
+
+	// fog near
+
+	var fogNearRow = new UI.Panel();
+	fogNearRow.setDisplay( 'none' );
+
+	var fogNear = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, Infinity ).onChange( updateFogParameters );
+
+	fogNearRow.add( new UI.Text( 'Fog near' ).setWidth( '90px' ).setColor( '#666' ) );
+	fogNearRow.add( fogNear );
+
+	container.add( fogNearRow );
+
+	var fogFarRow = new UI.Panel();
+	fogFarRow.setDisplay( 'none' );
+
+	// fog far
+
+	var fogFar = new UI.Number( 5000 ).setWidth( '60px' ).setRange( 0, Infinity ).onChange( updateFogParameters );
+
+	fogFarRow.add( new UI.Text( 'Fog far' ).setWidth( '90px' ).setColor( '#666' ) );
+	fogFarRow.add( fogFar );
+
+	container.add( fogFarRow );
+
+	// fog density
+
+	var fogDensityRow = new UI.Panel();
+	fogDensityRow.setDisplay( 'none' );
+
+	var fogDensity = new UI.Number( 0.00025 ).setWidth( '60px' ).setRange( 0, 0.1 ).setPrecision( 5 ).onChange( updateFogParameters );
+
+	fogDensityRow.add( new UI.Text( 'Fog density' ).setWidth( '90px' ).setColor( '#666' ) );
+	fogDensityRow.add( fogDensity );
+
+	container.add( fogDensityRow );
+
+	//
+
+	var scene = null;
+
+	function getObjectType( object ) {
+
+		var objects = {
+
+			'Scene': THREE.Scene,
+			'PerspectiveCamera': THREE.PerspectiveCamera,
+			'AmbientLight': THREE.AmbientLight,
+			'DirectionalLight': THREE.DirectionalLight,
+			'HemisphereLight': THREE.HemisphereLight,
+			'PointLight': THREE.PointLight,
+			'SpotLight': THREE.SpotLight,
+			'Mesh': THREE.Mesh,
+			'Object3D': THREE.Object3D
+
+		};
+
+		for ( var type in objects ) {
+
+			if ( object instanceof objects[ type ] ) return type;
+
+		}
+
+	}
+
+	function updateOutliner() {
+
+		var id = parseInt( outliner.getValue() );
+
+		scene.traverse( function ( node ) {
+
+			if ( node.id === id ) {
+
+				signals.objectSelected.dispatch( node );
+				return;
+
+			}
+
+		} );
+
+	}
+
+	function updateFogType() {
+
+		var type = fogType.getValue();
+		signals.fogTypeChanged.dispatch( type );
+
+		refreshFogUI();
+
+	}
+
+	function refreshFogUI() {
+
+		var type = fogType.getValue();
+
+		fogColorRow.setDisplay( type === 'None' ? 'none' : '' );
+		fogNearRow.setDisplay( type === 'Fog' ? '' : 'none' );
+		fogFarRow.setDisplay( type === 'Fog' ? '' : 'none' );
+		fogDensityRow.setDisplay( type === 'FogExp2' ? '' : 'none' );
+
+	}
+
+	function updateFogColor() {
+
+		signals.fogColorChanged.dispatch( fogColor.getHexValue() );
+
+	}
+
+	function updateFogParameters() {
+
+		signals.fogParametersChanged.dispatch( fogNear.getValue(), fogFar.getValue(), fogDensity.getValue() );
+
+	}
+
+	// events
+
+	signals.sceneChanged.add( function ( object ) {
+
+		scene = object;
+
+		var options = {};
+
+		options[ scene.id ] = scene.name + ' <span style="color: #aaa">- ' + getObjectType( scene ) + '</span>';
+
+		( function addObjects( objects, pad ) {
+
+			for ( var i = 0, l = objects.length; i < l; i ++ ) {
+
+				var object = objects[ i ];
+
+				options[ object.id ] = pad + object.name + ' <span style="color: #aaa">- ' + getObjectType( object ) + '</span>';
+
+				addObjects( object.children, pad + '&nbsp;&nbsp;&nbsp;' );
+
+			}
+
+		} )( scene.children, '&nbsp;&nbsp;&nbsp;' );
+
+		outliner.setOptions( options );
+
+		if ( scene.fog ) {
+
+			fogColor.setHexValue( scene.fog.color.getHex() );
+
+			if ( scene.fog instanceof THREE.Fog ) {
+
+				fogType.setValue( "Fog" );
+				fogNear.setValue( scene.fog.near );
+				fogFar.setValue( scene.fog.far );
+
+			} else if ( scene.fog instanceof THREE.FogExp2 ) {
+
+				fogType.setValue( "FogExp2" );
+				fogDensity.setValue( scene.fog.density );
+
+			}
+
+		} else {
+
+			fogType.setValue( "None" );
+
+		}
+
+		refreshFogUI();
+
+	} );
+
+	signals.objectSelected.add( function ( object ) {
+
+		outliner.setValue( object !== null ? object.id : null );
+
+	} );
+
+	return container;
+
+}

+ 6 - 4
editor/js/Sidebar.js

@@ -1,12 +1,14 @@
-var Sidebar = function ( editor, signals ) {
+var Sidebar = function ( signals ) {
 
-	var container = new UI.Panel().setWidth('300px');
+	var container = new UI.Panel();
 	container.setPosition( 'absolute' );
 	container.setClass( 'sidebar' );
 
 	container.add( new Sidebar.Renderer( signals ) );
-	container.add( new Sidebar.Outliner( signals ) );
-	container.add( new Sidebar.Attributes( signals ) );
+	container.add( new Sidebar.Scene( signals ) );
+	container.add( new Sidebar.Object3D( signals ) );
+	container.add( new Sidebar.Geometry( signals ) );
+	container.add( new Sidebar.Material( signals ) );
 	container.add( new Sidebar.Animation( signals ) );
 
 	return container;

+ 4 - 4
editor/js/Toolbar.js

@@ -1,4 +1,4 @@
-var Toolbar = function ( editor, signals ) {
+var Toolbar = function ( signals ) {
 
 	var container = new UI.Panel();
 	container.setPosition( 'absolute' );
@@ -12,21 +12,21 @@ var Toolbar = function ( editor, signals ) {
 
 	var translate = new UI.Button( 'translate' ).onClick( function () {
 
-		signals.setTransformMode.dispatch( 'translate' );
+		signals.transformModeChanged.dispatch( 'translate' );
 
 	} );
 	buttons.add( translate );
 
 	var rotate = new UI.Button( 'rotate' ).onClick( function () {
 
-		signals.setTransformMode.dispatch( 'rotate' );
+		signals.transformModeChanged.dispatch( 'rotate' );
 
 	} );
 	buttons.add( rotate );
 
 	var scale = new UI.Button( 'scale' ).onClick( function () {
 
-		signals.setTransformMode.dispatch( 'scale' );
+		signals.transformModeChanged.dispatch( 'scale' );
 
 	} );
 	buttons.add( scale );

+ 308 - 77
editor/js/Viewport.js

@@ -1,4 +1,4 @@
-var Viewport = function ( editor, signals ) {
+var Viewport = function ( signals ) {
 
 	var container = new UI.Panel();
 	container.setPosition( 'absolute' );
@@ -12,22 +12,27 @@ var Viewport = function ( editor, signals ) {
 	info.setColor( '#ffffff' );
 	container.add( info );
 
-	var scene = editor.scene;
-	var sceneHelpers = editor.sceneHelpers;
-
 	var clearColor = 0xAAAAAA;
+	var objects = [];
+
+	// helpers
+
+	var helpersToObjects = {};
+	var objectsToHelpers = {};
+
+	var sceneHelpers = new THREE.Scene();
 
 	var grid = new THREE.GridHelper( 500, 25 );
 	sceneHelpers.add( grid );
 
 	//
 
+	var scene = new THREE.Scene();
+
 	var camera = new THREE.PerspectiveCamera( 50, container.dom.offsetWidth / container.dom.offsetHeight, 1, 5000 );
 	camera.position.set( 500, 250, 500 );
 	camera.lookAt( scene.position );
 
-	editor.select( camera );
-
 	//
 
 	var selectionBox = new THREE.BoxHelper();
@@ -36,26 +41,30 @@ var Viewport = function ( editor, signals ) {
 	selectionBox.visible = false;
 	sceneHelpers.add( selectionBox );
 
-	//
-
 	var transformControls = new THREE.TransformControls( camera, container.dom );
 	transformControls.addEventListener( 'change', function () {
 
-		signals.objectChanged.dispatch( this.object );
+		signals.objectChanged.dispatch( selected );
 
 	} );
 	sceneHelpers.add( transformControls.gizmo );
 	transformControls.hide();
 
-	//
+	// fog
 
-	var selected;
+	var oldFogType = "None";
+	var oldFogColor = 0xaaaaaa;
+	var oldFogNear = 1;
+	var oldFogFar = 5000;
+	var oldFogDensity = 0.00025;
 
 	// object picking
 
 	var ray = new THREE.Raycaster();
 	var projector = new THREE.Projector();
 
+	var selected = camera;
+
 	// events
 
 	var getIntersects = function ( event, object ) {
@@ -104,27 +113,33 @@ var Viewport = function ( editor, signals ) {
 
 		if ( onMouseDownPosition.distanceTo( onMouseUpPosition ) < 1 ) {
 
-			var hit;
+			var intersects = getIntersects( event, objects );
 
-			var intersect = getIntersects( event, [ scene, sceneHelpers ] );
+			if ( intersects.length > 0 ) {
 
-			for ( var i in intersect ) {
+				selected = intersects[ 0 ].object;
 
-				if ( editor.objects[ intersect[i].object.id ] ) {
+				if ( helpersToObjects[ selected.id ] !== undefined ) {
 
-					editor.selectById( intersect[i].object.id );
-					hit = true;
-					break;
+					selected = helpersToObjects[ selected.id ];
 
 				}
 
+				signals.objectSelected.dispatch( selected );
+
+			} else {
+
+				selected = camera;
+
+				signals.objectSelected.dispatch( selected );
+
 			}
 
-			if ( !hit ) editor.deselectAll();
+			render();
 
 		}
 
-		controls.enabled = false; // ?
+		controls.enabled = false;
 
 		document.removeEventListener( 'mouseup', onMouseUp );
 
@@ -132,21 +147,13 @@ var Viewport = function ( editor, signals ) {
 
 	var onDoubleClick = function ( event ) {
 
-		var intersect = getIntersects( event, [ scene, sceneHelpers ] );
-
-			for ( var i in intersect ) {
-
-				if ( editor.objects[ intersect[i].object.id ] ) {
-
-					editor.selectById( intersect[i].object.id );
-
-					controls.focus( editor.objects[ intersect[i].object.id ] );
+		var intersects = getIntersects( event, objects );
 
-					break;
+		if ( intersects.length > 0 && intersects[ 0 ].object === selected ) {
 
-				}
+			controls.focus( selected );
 
-			}
+		}
 
 	};
 
@@ -165,24 +172,9 @@ var Viewport = function ( editor, signals ) {
 	} );
 	controls.enabled = false;
 
-
-	function updateHelpers( object ) {
-
-		if ( object.geometry !== undefined ) {
-
-			selectionBox.visible = true;
-			selectionBox.update( object );
-			transformControls.update();
-
-		}
-
-		if ( editor.helpers[ object.id ] ) editor.helpers[ object.id ].update();
-
-	} 
-
 	// signals
 
-	signals.setTransformMode.add( function ( mode ) {
+	signals.transformModeChanged.add( function ( mode ) {
 
 		transformControls.setMode( mode );
 		render();
@@ -195,7 +187,13 @@ var Viewport = function ( editor, signals ) {
 
 	} );
 
-	signals.setRenderer.add( function ( object ) {
+	signals.snapChanged.add( function ( dist ) {
+
+		snapDist = dist;
+
+	} );
+
+	signals.rendererChanged.add( function ( object ) {
 
 		container.dom.removeChild( renderer.domElement );
 
@@ -211,64 +209,214 @@ var Viewport = function ( editor, signals ) {
 
 	} );
 
-	signals.selected.add( function () {
+	signals.sceneAdded.add( function ( object ) {
 
-		selectionBox.visible = false;
-		transformControls.detach();
+		scene.userData = JSON.parse( JSON.stringify( object.userData ) );
+
+		while ( object.children.length > 0 ) {
+
+			signals.objectAdded.dispatch( object.children[ 0 ] );
+
+		}
+
+	} );
+
+	signals.objectAdded.add( function ( object ) {
+
+		// handle children
 
-		selected = editor.listSelected( 'object' );
-		object = ( selected.length ) ? selected[0] : null;
+		object.traverse( function ( object ) {
 
-		if ( object && object !== scene ) {
+			// create helpers for invisible object types (lights, cameras, targets)
 
-			transformControls.attach( object );
-			updateHelpers( object );
+			if ( object instanceof THREE.PointLight ) {
+
+				var helper = new THREE.PointLightHelper( object, 10 );
+				sceneHelpers.add( helper );
+
+				objectsToHelpers[ object.id ] = helper;
+				helpersToObjects[ helper.lightSphere.id ] = object;
+
+				objects.push( helper.lightSphere );
+
+			} else if ( object instanceof THREE.DirectionalLight ) {
+
+				var helper = new THREE.DirectionalLightHelper( object, 10 );
+				sceneHelpers.add( helper );
+
+				objectsToHelpers[ object.id ] = helper;
+				helpersToObjects[ helper.lightSphere.id ] = object;
+
+				objects.push( helper.lightSphere );
+
+			} else if ( object instanceof THREE.SpotLight ) {
+
+				var helper = new THREE.SpotLightHelper( object, 10 );
+				sceneHelpers.add( helper );
+
+				objectsToHelpers[ object.id ] = helper;
+				helpersToObjects[ helper.lightSphere.id ] = object;
+
+				objects.push( helper.lightSphere );
+
+			} else if ( object instanceof THREE.HemisphereLight ) {
+
+				var helper = new THREE.HemisphereLightHelper( object, 10 );
+				sceneHelpers.add( helper );
+
+				objectsToHelpers[ object.id ] = helper;
+				helpersToObjects[ helper.lightSphere.id ] = object;
+
+				objects.push( helper.lightSphere );
+
+			} else {
+
+				// add to picking list
+
+				objects.push( object );
+
+			}
+
+		} );
+
+		scene.add( object );
+
+		// TODO: Add support for hierarchies with lights
+
+		if ( object instanceof THREE.Light )  {
+
+			updateMaterials( scene );
 
 		}
 
-		render();
+		updateInfo();
+
+		signals.sceneChanged.dispatch( scene );
+		signals.objectSelected.dispatch( object );
 
 	} );
 
-	signals.sceneChanged.add( function () {
+	signals.objectSelected.add( function ( object ) {
 
-		render();
+		selectionBox.visible = false;
+		transformControls.detach();
 
-	} );
+		if ( object !== null ) {
 
-	signals.objectAdded.add( function ( object ) {
+			if ( object.geometry !== undefined ) {
+
+				selectionBox.update( object );
+				selectionBox.visible = true;
+
+			}
+
+			selected = object;
+
+			if ( selected instanceof THREE.PerspectiveCamera === false ) {
+
+				transformControls.attach(object);
+
+			}
+
+		}
 
-		updateHelpers( object );
-		updateInfo();
 		render();
 
 	} );
 
 	signals.objectChanged.add( function ( object ) {
 
-		updateHelpers( object );
-		transformControls.update();
-		updateInfo();
+		if ( object.geometry !== undefined ) {
+
+			selectionBox.update( object );
+			transformControls.update();
+			updateInfo();
+
+		}
+
+		if ( objectsToHelpers[ object.id ] !== undefined ) {
+
+			objectsToHelpers[ object.id ].update();
+
+		}
+
 		render();
 
+		signals.sceneChanged.dispatch( scene );
+
 	} );
 
-	signals.objectDeleted.add( function () {
+	signals.cloneSelectedObject.add( function () {
 
-		updateInfo();
-		render();
+		if ( selected === camera ) return;
+
+		var object = selected.clone();
+
+		signals.objectAdded.dispatch( object );
 
 	} );
 
-	signals.materialChanged.add( function ( material ) {
+	signals.removeSelectedObject.add( function () {
 
-		render();
+		if ( selected.parent === undefined ) return;
+
+		var name = selected.name ?  '"' + selected.name + '"': "selected object";
+
+		if ( confirm( 'Delete ' + name + '?' ) === false ) return;
+
+		var parent = selected.parent;
+
+		if ( selected instanceof THREE.PointLight ||
+		     selected instanceof THREE.DirectionalLight ||
+		     selected instanceof THREE.SpotLight ||
+		     selected instanceof THREE.HemisphereLight ) {
+
+			var helper = objectsToHelpers[ selected.id ];
+
+			objects.splice( objects.indexOf( helper.lightSphere ), 1 );
+
+			helper.parent.remove( helper );
+			selected.parent.remove( selected );
+
+			delete objectsToHelpers[ selected.id ];
+			delete helpersToObjects[ helper.id ];
+
+			if ( selected instanceof THREE.DirectionalLight ||
+			     selected instanceof THREE.SpotLight ) {
+
+				selected.target.parent.remove( selected.target );
+
+			}
+
+			updateMaterials( scene );
+
+		} else {
+
+			selected.traverse( function ( object ) {
+
+				var index = objects.indexOf( object );
+
+				if ( index !== -1 ) {
+
+					objects.splice( index, 1 )
+
+				}
+
+			} );
+
+			selected.parent.remove( selected );
+
+			updateInfo();
+
+		}
+
+		signals.sceneChanged.dispatch( scene );
+		signals.objectSelected.dispatch( parent );
 
 	} );
 
-	signals.geometryChanged.add( function ( material ) {
+	signals.materialChanged.add( function ( material ) {
 
-		updateInfo();
 		render();
 
 	} );
@@ -282,7 +430,51 @@ var Viewport = function ( editor, signals ) {
 
 	} );
 
-	signals.fogChanged.add( function () {
+	signals.fogTypeChanged.add( function ( fogType ) {
+
+		if ( fogType !== oldFogType ) {
+
+			if ( fogType === "None" ) {
+
+				scene.fog = null;
+
+			} else if ( fogType === "Fog" ) {
+
+				scene.fog = new THREE.Fog( oldFogColor, oldFogNear, oldFogFar );
+
+			} else if ( fogType === "FogExp2" ) {
+
+				scene.fog = new THREE.FogExp2( oldFogColor, oldFogDensity );
+
+			}
+
+			updateMaterials( scene );
+
+			oldFogType = fogType;
+
+		}
+
+		render();
+
+	} );
+
+	signals.fogColorChanged.add( function ( fogColor ) {
+
+		oldFogColor = fogColor;
+
+		updateFog( scene );
+
+		render();
+
+	} );
+
+	signals.fogParametersChanged.add( function ( near, far, density ) {
+
+		oldFogNear = near;
+		oldFogFar = far;
+		oldFogDensity = density;
+
+		updateFog( scene );
 
 		render();
 
@@ -300,14 +492,15 @@ var Viewport = function ( editor, signals ) {
 	} );
 
 	signals.playAnimations.add( function (animations) {
-
+		
 		function animate() {
 			requestAnimationFrame( animate );
-
+			
 			for (var i = 0; i < animations.length ; i++ ){
 				animations[i].update(0.016);
 			} 
 
+
 			render();
 		}
 
@@ -360,6 +553,44 @@ var Viewport = function ( editor, signals ) {
 
 	}
 
+	function updateMaterials( root ) {
+
+		root.traverse( function ( node ) {
+
+			if ( node.material ) {
+
+				node.material.needsUpdate = true;
+
+				if ( node.material instanceof THREE.MeshFaceMaterial ) {
+
+					for ( var i = 0; i < node.material.materials.length; i ++ ) {
+
+						node.material.materials[ i ].needsUpdate = true;
+
+					}
+
+				}
+
+			}
+
+		} );
+
+	}
+
+	function updateFog( root ) {
+
+		if ( root.fog ) {
+
+			root.fog.color.setHex( oldFogColor );
+
+			if ( root.fog.near !== undefined ) root.fog.near = oldFogNear;
+			if ( root.fog.far !== undefined ) root.fog.far = oldFogFar;
+			if ( root.fog.density !== undefined ) root.fog.density = oldFogDensity;
+
+		}
+
+	}
+
 	function animate() {
 
 		requestAnimationFrame( animate );

+ 25 - 104
editor/js/libs/ui.js

@@ -12,14 +12,6 @@ UI.Element.prototype = {
 
 	},
 
-	setId: function ( name ) {
-
-		this.dom.id = name;
-
-		return this;
-
-	},
-
 	setStyle: function ( style, array ) {
 
 		for ( var i = 0; i < array.length; i ++ ) {
@@ -43,7 +35,7 @@ UI.Element.prototype = {
 // properties
 
 var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
-'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'boxSizing', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
+'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textTransform', 'cursor' ];
 
 properties.forEach( function ( property ) {
@@ -92,7 +84,6 @@ UI.Panel = function () {
 	this.dom = dom;
 
 	return this;
-
 };
 
 UI.Panel.prototype = Object.create( UI.Element.prototype );
@@ -109,6 +100,7 @@ UI.Panel.prototype.add = function () {
 
 };
 
+
 UI.Panel.prototype.remove = function () {
 
 	for ( var i = 0; i < arguments.length; i ++ ) {
@@ -121,73 +113,6 @@ UI.Panel.prototype.remove = function () {
 
 };
 
-// Tabbed Panel
-
-UI.TabbedPanel = function () {
-
-	UI.Panel.call( this );
-
-	var header = new UI.Panel();
-	header.setBorderBottom( '1px solid #ccc' );
-
-	this.dom.appendChild( header.dom );
-	
-	this.header = header.dom;
-
-	this.tabs = [];
-	this.contents = [];
-
-	return this;
-
-};
-
-UI.TabbedPanel.prototype = Object.create( UI.Panel.prototype );
-
-UI.TabbedPanel.prototype.add = function () {
-
-	for ( var i = 0; i < arguments.length; i ++ ) {
-
-		var tab = new UI.Text( arguments[ i ].name ).setColor( '#666' );
-		tab.setPadding( '5px 10px' );
-		tab.setBorder( '1px solid #ccc' );
-		tab.setMargin( '0 0 -1px 5px' );
-		this.header.appendChild( tab.dom );
-
-		var content = arguments[ i ];
-		this.dom.appendChild( content.dom );
-		content.setDisplay( 'none' );
-
-		this.tabs.push(tab);
-		this.contents.push(content);
-
-		var scope = this;
-
-		tab.onClick( function() {
-
-			for (var j in scope.contents ){
-				scope.contents[j].setDisplay( 'none' );
-				scope.tabs[j].setBorderBottom( '1px solid #ccc' );
-			}
-			content.setDisplay( ' block ');
-			tab.setBorderBottom( '1px solid #eee' );
-
-		} );
-
-	}
-
-	this.contents[0].setDisplay( 'block' );
-	this.tabs[0].setBorderBottom( '1px solid #eee' );
-
-	return this;
-
-};
-
-UI.TabbedPanel.prototype.remove = function () {
-
-	return this;
-
-};
-
 // Text
 
 UI.Text = function ( text ) {
@@ -199,7 +124,6 @@ UI.Text = function ( text ) {
 	dom.style.cursor = 'default';
 	dom.style.display = 'inline-block';
 	dom.style.verticalAlign = 'top';
-	dom.style.overflow = 'hidden';
 
 	this.dom = dom;
 	this.setValue( text );
@@ -234,7 +158,6 @@ UI.Input = function () {
 	var dom = document.createElement( 'input' );
 	dom.className = 'Input';
 	dom.style.padding = '2px';
-	// dom.style.boxSizing = 'border-box';
 	dom.style.marginTop = '-2px';
 	dom.style.marginLeft = '-2px';
 	dom.style.border = '1px solid #ccc';
@@ -401,7 +324,7 @@ UI.FancySelect = function () {
 	this.dom = dom;
 
 	this.options = [];
-	this.selectedKeys = null;
+	this.selectedValue = null;
 
 	return this;
 
@@ -424,11 +347,19 @@ UI.FancySelect.prototype.setOptions = function ( options ) {
 
 	scope.options = [];
 
-	var generateOptionCallback = function ( element, key ) {
+	var generateOptionCallback = function ( element, value ) {
 
 		return function ( event ) {
 
-			scope.selectedKeys = [key];
+			for ( var i = 0; i < scope.options.length; i ++ ) {
+
+				scope.options[ i ].style.backgroundColor = '#f0f0f0';
+
+			}
+
+			element.style.backgroundColor = '#f0f0f0';
+
+			scope.selectedValue = value;
 
 			scope.dom.dispatchEvent( changeEvent );
 
@@ -456,40 +387,34 @@ UI.FancySelect.prototype.setOptions = function ( options ) {
 
 UI.FancySelect.prototype.getValue = function () {
 
-	return this.selectedKeys;
+	return this.selectedValue;
 
 };
 
-UI.FancySelect.prototype.setValue = function ( keys ) {
+UI.FancySelect.prototype.setValue = function ( value ) {
 
-	// must convert raw keys into string for compatibility with UI.Select
-	// which uses string keys (initialized from options keys)
+	// must convert raw value into string for compatibility with UI.Select
+	// which uses string values (initialized from options keys)
 
-	keys = ( keys instanceof Array ) ? keys : [keys];
+	var key = value ? value.toString() : value;
 
 	for ( var i = 0; i < this.options.length; i ++ ) {
 
-		this.options[ i ].style.backgroundColor = '';
-
-	}
+		var element = this.options[ i ];
 
-	for ( var i in keys ) {
+		if ( element.value === key ) {
 
-		var key = keys[ i ] ? keys[ i ].toString() : keys[ i ];
+			element.style.backgroundColor = '#f0f0f0';
 
-		for ( var j = 0; j < this.options.length; j ++ ) {
+		} else {
 
-			if ( this.options[ j ].value === key ) {
-
-				this.options[ j ].style.backgroundColor = '#f0f0f0';
-
-			}
+			element.style.backgroundColor = '';
 
 		}
 
 	}
 
-	this.selectedKeys = keys;
+	this.selectedValue = value;
 
 	return this;
 
@@ -677,14 +602,10 @@ UI.Number = function ( number ) {
 
 	var onChange = function ( event ) {
 
-
-
 		var number = parseFloat( dom.value );
 
 		if ( isNaN( number ) === false ) {
 
-		  dom.oldValue = dom.newValue;
-		  dom.newValue = number;
 			dom.value = number;
 
 		}
@@ -967,4 +888,4 @@ UI.Button.prototype.setLabel = function ( value ) {
 
 	return this;
 
-};
+};

+ 5 - 459
editor/js/libs/ui.three.js

@@ -1,417 +1,8 @@
-// String
-
-UI.ParamString = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.string = new UI.Input().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' );
-	this.string.dom.name = name;
-
-	row.add( this.name, this.string );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamString.prototype = Object.create( UI.Panel.prototype );
-
-
-UI.ParamString.prototype.setValue = function ( model ) {
-
-	this.string.setValue( model );
-
-};
-
-
-UI.ParamString.prototype.getValue = function ( value ) {
-
-	return this.string.getValue( value );
-
-};
-
-// Integer
-
-UI.ParamInteger = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.integer = new UI.Integer();
-	this.integer.dom.name = name;
-	
-	row.add( this.name, this.integer );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamInteger.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamInteger.prototype.setValue = function ( model ) {
-
-	this.integer.setValue( model );
-
-};
-
-UI.ParamInteger.prototype.getValue = function () {
-
-	return this.integer.getValue();
-
-};
-
-// Float
-
-UI.ParamFloat = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.float = new UI.Number();
-	this.float.dom.name = name;
-	
-	row.add( this.name, this.float );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamFloat.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamFloat.prototype.setValue = function ( model ) {
-
-	this.float.setValue( model );
-
-};
-
-UI.ParamFloat.prototype.getValue = function () {
-
-	return this.float.getValue();
-
-};
-
-// Bool
-
-UI.ParamBool = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( 'auto' ).setColor( '#666' ).setPosition( 'relative' ).setLeft( '25px' );
-	this.bool = new UI.Checkbox().setPosition( 'absolute' ).setLeft( '10px' );
-	this.bool.dom.name = name;
-
-	row.add( this.name, this.bool );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamBool.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamBool.prototype.setValue = function ( model ) {
-
-	this.bool.setValue( model );
-
-};
-
-
-UI.ParamBool.prototype.getValue = function () {
-
-	return this.bool.getValue();
-
-};
-
-// Vector2
-
-UI.ParamVector2 = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-
-	this.x = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.y ] ) } );
-	this.y = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x ] ) } );
-
-	this.x.dom.name = name;
-	this.y.dom.name = name;
-	
-	row.add( this.name, this.x, this.y );
-	
-	this.scaleLock = new UI.Checkbox().setPosition( 'absolute' ).setRight( '10px' );
-	row.add( this.scaleLock );
-
-	this.add( row );
-
-	function scaleProportionately( event, targets ) {
-
-		if ( scope.scaleLock && scope.scaleLock.getValue() && event.srcElement.oldValue ) {
-
-			var scale = event.srcElement.value / event.srcElement.oldValue;
-			for ( var i in targets ) {
-
-				targets[ i ].setValue( parseFloat(targets[ i ].getValue()) * scale );
-			
-			}
-
-		}
-
-	}
-
-	return this;
-
-};
-
-UI.ParamVector2.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamVector2.prototype.setValue = function ( model ) {
-
-	this.x.setValue( model.x );
-	this.y.setValue( model.y );
-
-};
-
-UI.ParamVector2.prototype.getValue = function () {
-
-	return new THREE.Vector2( this.x.getValue(), this.y.getValue() );
-
-};
-
-// Vector3
-
-UI.ParamVector3 = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-
-	this.x = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.y, scope.z ] ) } );
-	this.y = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x, scope.z ] ) } );
-	this.z = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x, scope.y ] ) } );
-
-	this.x.dom.name = name;
-	this.y.dom.name = name;
-	this.z.dom.name = name;
-	
-	row.add( this.name, this.x, this.y, this.z );
-	
-	this.scaleLock = new UI.Checkbox().setPosition( 'absolute' ).setRight( '10px' );
-	row.add( this.scaleLock );
-
-
-	this.add( row );
-
-	function scaleProportionately( event, targets ) {
-
-		if ( scope.scaleLock && scope.scaleLock.getValue() && event.srcElement.oldValue ) {
-
-			var scale = event.srcElement.value / event.srcElement.oldValue;
-			for ( var i in targets ) {
-
-				targets[ i ].setValue( parseFloat(targets[ i ].getValue()) * scale );
-			
-			}
-
-		}
-
-	}
-
-	return this;
-
-};
-
-UI.ParamVector3.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamVector3.prototype.setValue = function ( model ) {
-
-	this.x.setValue( model.x );
-	this.y.setValue( model.y );
-	this.z.setValue( model.z );
-
-};
-
-UI.ParamVector3.prototype.getValue = function () {
-
-	return new THREE.Vector3( this.x.getValue(), this.y.getValue(), this.z.getValue() );
-
-};
-
-// Vector4
-
-UI.ParamVector4 = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-
-	this.x = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.y, scope.z, scope.w ] ) } );
-	this.y = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x, scope.z, scope.w ] ) } );
-	this.z = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x, scope.y, scope.w ] ) } );
-	this.w = new UI.Number().setWidth( '35px' ).onChange( function( event ) { scaleProportionately( event, [ scope.x, scope.y, scope.z ] ) } );
-
-	this.x.dom.name = name;
-	this.y.dom.name = name;
-	this.z.dom.name = name;
-	this.w.dom.name = name;
-	
-	row.add( this.name, this.x, this.y, this.z, this.w );
-
-	this.scaleLock = new UI.Checkbox().setPosition( 'absolute' ).setRight( '10px' );
-	row.add( this.scaleLock );
-
-	this.add( row );
-
-	function scaleProportionately( event, targets ) {
-
-		if ( scope.scaleLock && scope.scaleLock.getValue() && event.srcElement.oldValue ) {
-
-			var scale = event.srcElement.value / event.srcElement.oldValue;
-			for ( var i in targets ) {
-
-				targets[ i ].setValue( parseFloat(targets[ i ].getValue()) * scale );
-			
-			}
-
-		}
-
-	}
-
-	return this;
-
-};
-
-UI.ParamVector4.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamVector4.prototype.setValue = function ( model ) {
-
-	this.x.setValue( model.x );
-	this.y.setValue( model.y );
-	this.z.setValue( model.z );
-	this.w.setValue( model.w );
-
-};
-
-UI.ParamVector4.prototype.getValue = function () {
-
-	return new THREE.Vector4( this.x.getValue(), this.y.getValue(), this.z.getValue(), this.w.getValue() );
-
-};
-
-// Color
-
-UI.ParamColor = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.color = new UI.Color();
-	this.color.dom.name = name;
-	
-	row.add( this.name, this.color );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamColor.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamColor.prototype.setValue = function ( color ) {
-
-	this.color.setValue( '#' + color.getHexString() );
-
-};
-
-UI.ParamColor.prototype.getValue = function () {
-
-	return this.color.getHexValue();
-
-};
-
-// Select
-
-UI.ParamSelect = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	this.onChangeCallback;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.select = new UI.Select().setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' );
-	this.select.dom.name = name;
-
-	row.add( this.name, this.select );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamSelect.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamSelect.prototype.setValue = function ( model ) {
-
-	this.select.setValue( model );
-
-};
-
-UI.ParamSelect.prototype.getValue = function ( value ) {
-
-	return this.select.getValue( value );
-
-};
-
-UI.ParamSelect.prototype.setOptions = function ( value ) {
-
-	this.select.setOptions( value );
-
-};
-
-
-// Texture 
+// Texture
 
 UI.Texture = function ( position ) {
 
-  UI.Element.call( this );
+    UI.Element.call( this );
 
 	var scope = this;
 
@@ -490,7 +81,7 @@ UI.Texture.prototype.getValue = function () {
 
 };
 
-UI.Texture.prototype.setValue = function ( model ) {
+UI.Texture.prototype.setValue = function ( value ) {
 
 	this.texture = value;
 
@@ -504,6 +95,7 @@ UI.Texture.prototype.onChange = function ( callback ) {
 
 };
 
+
 // CubeTexture
 
 UI.CubeTexture = function ( position ) {
@@ -559,7 +151,7 @@ UI.CubeTexture.prototype.getValue = function () {
 
 };
 
-UI.CubeTexture.prototype.setValue = function ( model ) {
+UI.CubeTexture.prototype.setValue = function ( value ) {
 
 	this.texture = value;
 
@@ -572,49 +164,3 @@ UI.CubeTexture.prototype.onChange = function ( callback ) {
 	return this;
 
 };
-
-// Json
-
-UI.ParamJson = function ( name ) {
-
-  UI.Panel.call( this );
-
-	var scope = this;
-
-	var row = new UI.Panel();
-
-	this.name = new UI.Text( name ).setWidth( '90px' ).setColor( '#666' );
-	this.json = new UI.TextArea().setWidth( '150px' ).setHeight( '40px' ).setColor( '#444' ).setFontSize( '12px' );
-	this.json.dom.name = name;
-	this.json.onKeyUp( function () {
-		try {
-			JSON.parse( scope.json.getValue() );
-			scope.json.setBorderColor( '#ccc' );
-			scope.json.setBackgroundColor( '' );
-		} catch ( error ) {
-			scope.json.setBorderColor( '#f00' );
-			scope.json.setBackgroundColor( 'rgba(255,0,0,0.25)' );
-		}
-	} );
-	
-	row.add( this.name, this.json );
-	this.add( row );
-
-	return this;
-
-};
-
-UI.ParamJson.prototype = Object.create( UI.Panel.prototype );
-
-UI.ParamJson.prototype.setValue = function ( model ) {
-
-	this.json.setValue( model );
-
-};
-
-UI.ParamJson.prototype.getValue = function () {
-
-	return this.json.getValue();
-
-};
-