Browse Source

Editor: Yet more rework.

Mr.doob 12 years ago
parent
commit
7d2617636f

+ 2 - 1
editor/index.html

@@ -184,7 +184,8 @@
 
 					case 46: // delete
 
-						editor.signals.removeSelectedObject.dispatch();
+						editor.removeObject( editor.selected );
+						editor.deselect();
 
 						break;
 

+ 30 - 54
editor/js/Editor.js

@@ -13,12 +13,13 @@ var Editor = function () {
 		transformModeChanged: new SIGNALS.Signal(),
 		snapChanged: new SIGNALS.Signal(),
 		rendererChanged: new SIGNALS.Signal(),
-		sceneChanged: new SIGNALS.Signal(),
 
+		objectSelected: new SIGNALS.Signal(),
 		objectAdded: new SIGNALS.Signal(),
 		objectChanged: new SIGNALS.Signal(),
 		objectRemoved: new SIGNALS.Signal(),
-		objectSelected: new SIGNALS.Signal(),
+
+		helperAdded: new SIGNALS.Signal(),
 
 		materialChanged: new SIGNALS.Signal(),
 		clearColorChanged: new SIGNALS.Signal(),
@@ -55,8 +56,6 @@ Editor.prototype = {
 
 		}
 
-		this.signals.sceneChanged.dispatch( this.scene );
-
 	},
 
 	//
@@ -67,23 +66,19 @@ Editor.prototype = {
 		this.addHelper( object );
 
 		this.signals.objectAdded.dispatch( object );
-		this.signals.sceneChanged.dispatch();
 
 	},
 
 	removeObject: function ( object ) {
 
-		if ( object === this.scene ) return;
+		if ( object.parent === undefined ) return; // avoid deleting the camera or scene
 
-		var name = object.name ?  '"' + object.name + '"': "selected object";
-
-		if ( confirm( 'Delete ' + name + '?' ) === false ) return;
+		if ( confirm( 'Delete ' + object.name + '?' ) === false ) return;
 
 		this.scene.remove( object );
 		this.removeHelper( object );
 
 		this.signals.objectRemoved.dispatch( object );
-		this.signals.sceneChanged.dispatch();
 
 	},
 
@@ -117,31 +112,41 @@ Editor.prototype = {
 
 		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;
+			var helper = new THREE.PointLightHelper( object, 10 );
+			helper.lightSphere.id = object.id;
+			this.sceneHelpers.add( helper );
+
+			this.helpers[ object.id ] = helper;
+			this.signals.helperAdded.dispatch( helper );
 
 		} 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;
+			var helper = new THREE.DirectionalLightHelper( object, 10 );
+			helper.lightSphere.id = object.id;
+			this.sceneHelpers.add( helper );
+
+			this.helpers[ object.id ] = helper;
+			this.signals.helperAdded.dispatch( helper );
 
 		} 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;
+			var helper = new THREE.SpotLightHelper( object, 10 );
+			helper.lightSphere.id = object.id;
+			this.sceneHelpers.add( helper );
+
+			this.helpers[ object.id ] = helper;
+			this.signals.helperAdded.dispatch( helper );
 
 		} 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;
+			var helper = new THREE.HemisphereLightHelper( object, 10 );
+			helper.lightSphere.id = object.id;
+			this.sceneHelpers.add( helper );
 
-		}
+			this.helpers[ object.id ] = helper;
+			this.signals.helperAdded.dispatch( helper );
 
-		this.signals.sceneChanged.dispatch();
+		}
 
 	},
 
@@ -183,36 +188,7 @@ Editor.prototype = {
 
 	deselect: function () {
 
-		this.selected = null;
-
-	},
-
-	//
-
-	cloneObject: function ( object ) {
-
-		this.addObject( object.clone() );
-
-	},
-
-	flattenObject: function ( object ) {
-
-		var name = object.name ?  '"' + object.name + '"': "selected object";
-
-		if ( confirm( 'Flatten ' + name + '?' ) === false ) return;
-
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
-		var geometry = object.geometry.clone();
-		geometry.applyMatrix( object.matrix );
-
-		object.geometry = geometry;
-
-		object.position.set( 0, 0, 0 );
-		object.rotation.set( 0, 0, 0 );
-		object.scale.set( 1, 1, 1 );
-
-		this.signals.objectChanged.dispatch( object );
+		this.select( null );
 
 	}
 

+ 3 - 3
editor/js/Loader.js

@@ -3,8 +3,6 @@ var Loader = function ( editor ) {
 	var scope = this;
 	var signals = editor.signals;
 
-	var sceneExporter = new THREE.ObjectExporter();
-
 	document.addEventListener( 'dragover', function ( event ) {
 
 		event.preventDefault();
@@ -47,7 +45,9 @@ var Loader = function ( editor ) {
 
 		timeout = setTimeout( function () {
 
-			localStorage.threejsEditor = JSON.stringify( sceneExporter.parse( scene ) );
+			var exporter = new THREE.ObjectExporter();
+			localStorage.threejsEditor = JSON.stringify( exporter.parse( editor.scene ) );
+
 			console.log( 'Saved state to Local Storage' );
 
 		}, 3000 );

+ 12 - 0
editor/js/Menubar.Add.js

@@ -42,6 +42,7 @@ Menubar.Add = function ( editor ) {
 		mesh.rotation.x = - Math.PI/2;
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -66,6 +67,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'Cube ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -89,6 +91,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'Cylinder ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -109,6 +112,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'Sphere ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -128,6 +132,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'Icosahedron ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -150,6 +155,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'Torus ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -174,6 +180,7 @@ Menubar.Add = function ( editor ) {
 		mesh.name = 'TorusKnot ' + ( ++ meshCount );
 
 		editor.addObject( mesh );
+		editor.select( mesh );
 
 	} );
 	options.add( option );
@@ -197,6 +204,7 @@ Menubar.Add = function ( editor ) {
 		light.name = 'PointLight ' + ( ++ lightCount );
 
 		editor.addObject( light );
+		editor.select( light );
 
 	} );
 	options.add( option );
@@ -221,6 +229,7 @@ Menubar.Add = function ( editor ) {
 		light.position.set( 0, 1, 0 ).multiplyScalar( 200 );
 
 		editor.addObject( light );
+		editor.select( light );
 
 	} );
 	options.add( option );
@@ -242,6 +251,7 @@ Menubar.Add = function ( editor ) {
 		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );
 
 		editor.addObject( light );
+		editor.select( light );
 
 	} );
 	options.add( option );
@@ -263,6 +273,7 @@ Menubar.Add = function ( editor ) {
 		light.position.set( 1, 1, 1 ).multiplyScalar( 200 );
 
 		editor.addObject( light );
+		editor.select( light );
 
 	} );
 	options.add( option );
@@ -280,6 +291,7 @@ Menubar.Add = function ( editor ) {
 		light.name = 'AmbientLight ' + ( ++ lightCount );
 
 		editor.addObject( light );
+		editor.select( light );
 
 	} );
 	options.add( option );

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

@@ -26,7 +26,14 @@ Menubar.Edit = function ( editor ) {
 	option.setTextContent( 'Clone' );
 	option.onClick( function () {
 
-		editor.cloneObject( editor.selected );
+		var object = editor.selected;
+
+		if ( object.parent === undefined ) return; // avoid cloning the camera or scene
+
+		object = object.clone();
+
+		editor.addObject( object );
+		editor.select( object );
 
 	} );
 	options.add( option );
@@ -38,7 +45,24 @@ Menubar.Edit = function ( editor ) {
 	option.setTextContent( 'Flatten' );
 	option.onClick( function () {
 
-		editor.flattenObject( editor.selected );
+		var object = editor.selected;
+
+		if ( object.parent === undefined ) return; // avoid flattening the camera or scene
+
+		if ( confirm( 'Flatten ' + object.name + '?' ) === false ) return;
+
+		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
+
+		var geometry = object.geometry.clone();
+		geometry.applyMatrix( object.matrix );
+
+		object.geometry = geometry;
+
+		object.position.set( 0, 0, 0 );
+		object.rotation.set( 0, 0, 0 );
+		object.scale.set( 1, 1, 1 );
+
+		editor.signals.objectChanged.dispatch( object );
 
 	} );
 	options.add( option );
@@ -51,6 +75,7 @@ Menubar.Edit = function ( editor ) {
 	option.onClick( function () {
 
 		editor.removeObject( editor.selected );
+		editor.deselect();
 
 	} );
 	options.add( option );

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

@@ -79,7 +79,7 @@ Sidebar.Animation = function ( editor ) {
 
 	signals.objectSelected.add( function ( object ) {
 
-		if ( object.geometry && object.geometry.animation ) {
+		if ( object && object.geometry && object.geometry.animation ) {
 
 			container.setDisplay( 'block' );
 

+ 128 - 107
editor/js/Sidebar.Object3D.js

@@ -22,7 +22,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	} );
 
-	objectUUIDRow.add( new UI.Text( 'Id' ).setWidth( '90px' ).setColor( '#666' ) );
+	objectUUIDRow.add( new UI.Text( 'UUID' ).setWidth( '90px' ).setColor( '#666' ) );
 	objectUUIDRow.add( objectUUID );
 	objectUUIDRow.add( objectUUIDRenew );
 
@@ -215,13 +215,13 @@ Sidebar.Object3D = function ( editor ) {
 
 	//
 
-	var selected = null;
-
 	function updateScaleX() {
 
+		var object = editor.selected;
+
 		if ( objectScaleLock.getValue() === true ) {
 
-			var scale = objectScaleX.getValue() / selected.scale.x;
+			var scale = objectScaleX.getValue() / object.scale.x;
 
 			objectScaleY.setValue( objectScaleY.getValue() * scale );
 			objectScaleZ.setValue( objectScaleZ.getValue() * scale );
@@ -234,9 +234,11 @@ Sidebar.Object3D = function ( editor ) {
 
 	function updateScaleY() {
 
+		var object = editor.selected;
+
 		if ( objectScaleLock.getValue() === true ) {
 
-			var scale = objectScaleY.getValue() / selected.scale.y;
+			var scale = objectScaleY.getValue() / object.scale.y;
 
 			objectScaleX.setValue( objectScaleX.getValue() * scale );
 			objectScaleZ.setValue( objectScaleZ.getValue() * scale );
@@ -249,9 +251,11 @@ Sidebar.Object3D = function ( editor ) {
 
 	function updateScaleZ() {
 
+		var object = editor.selected;
+
 		if ( objectScaleLock.getValue() === true ) {
 
-			var scale = objectScaleZ.getValue() / selected.scale.z;
+			var scale = objectScaleZ.getValue() / object.scale.z;
 
 			objectScaleX.setValue( objectScaleX.getValue() * scale );
 			objectScaleY.setValue( objectScaleY.getValue() * scale );
@@ -264,16 +268,18 @@ Sidebar.Object3D = function ( editor ) {
 
 	function update() {
 
-		if ( selected ) {
+		var object = editor.selected;
 
-			selected.uuid = objectUUID.getValue();
-			selected.name = objectName.getValue();
+		if ( object !== null ) {
 
-			if ( selected.parent !== undefined ) {
+			object.uuid = objectUUID.getValue();
+			object.name = objectName.getValue();
+
+			if ( object.parent !== undefined ) {
 
 				var newParentId = parseInt( objectParent.getValue() );
 
-				if ( selected.parent.id !== newParentId && selected.id !== newParentId ) {
+				if ( object.parent.id !== newParentId && object.id !== newParentId ) {
 
 					var parent = scene.getObjectById( newParentId, true );
 
@@ -283,7 +289,7 @@ Sidebar.Object3D = function ( editor ) {
 
 					}
 
-					parent.add( selected );
+					parent.add( object );
 
 					signals.sceneChanged.dispatch();
 
@@ -291,86 +297,86 @@ Sidebar.Object3D = function ( editor ) {
 
 			}
 
-			selected.position.x = objectPositionX.getValue();
-			selected.position.y = objectPositionY.getValue();
-			selected.position.z = objectPositionZ.getValue();
+			object.position.x = objectPositionX.getValue();
+			object.position.y = objectPositionY.getValue();
+			object.position.z = objectPositionZ.getValue();
 
-			selected.rotation.x = objectRotationX.getValue();
-			selected.rotation.y = objectRotationY.getValue();
-			selected.rotation.z = objectRotationZ.getValue();
+			object.rotation.x = objectRotationX.getValue();
+			object.rotation.y = objectRotationY.getValue();
+			object.rotation.z = objectRotationZ.getValue();
 
-			selected.scale.x = objectScaleX.getValue();
-			selected.scale.y = objectScaleY.getValue();
-			selected.scale.z = objectScaleZ.getValue();
+			object.scale.x = objectScaleX.getValue();
+			object.scale.y = objectScaleY.getValue();
+			object.scale.z = objectScaleZ.getValue();
 
-			if ( selected.fov !== undefined ) {
+			if ( object.fov !== undefined ) {
 
-				selected.fov = objectFov.getValue();
-				selected.updateProjectionMatrix();
+				object.fov = objectFov.getValue();
+				object.updateProjectionMatrix();
 
 			}
 
-			if ( selected.near !== undefined ) {
+			if ( object.near !== undefined ) {
 
-				selected.near = objectNear.getValue();
+				object.near = objectNear.getValue();
 
 			}
 
-			if ( selected.far !== undefined ) {
+			if ( object.far !== undefined ) {
 
-				selected.far = objectFar.getValue();
+				object.far = objectFar.getValue();
 
 			}
 
-			if ( selected.intensity !== undefined ) {
+			if ( object.intensity !== undefined ) {
 
-				selected.intensity = objectIntensity.getValue();
+				object.intensity = objectIntensity.getValue();
 
 			}
 
-			if ( selected.color !== undefined ) {
+			if ( object.color !== undefined ) {
 
-				selected.color.setHex( objectColor.getHexValue() );
+				object.color.setHex( objectColor.getHexValue() );
 
 			}
 
-			if ( selected.groundColor !== undefined ) {
+			if ( object.groundColor !== undefined ) {
 
-				selected.groundColor.setHex( objectGroundColor.getHexValue() );
+				object.groundColor.setHex( objectGroundColor.getHexValue() );
 
 			}
 
-			if ( selected.distance !== undefined ) {
+			if ( object.distance !== undefined ) {
 
-				selected.distance = objectDistance.getValue();
+				object.distance = objectDistance.getValue();
 
 			}
 
-			if ( selected.angle !== undefined ) {
+			if ( object.angle !== undefined ) {
 
-				selected.angle = objectAngle.getValue();
+				object.angle = objectAngle.getValue();
 
 			}
 
-			if ( selected.exponent !== undefined ) {
+			if ( object.exponent !== undefined ) {
 
-				selected.exponent = objectExponent.getValue();
+				object.exponent = objectExponent.getValue();
 
 			}
 
-			selected.visible = objectVisible.getValue();
+			object.visible = objectVisible.getValue();
 
 			try {
 
-				selected.userData = JSON.parse( objectUserData.getValue() );
+				object.userData = JSON.parse( objectUserData.getValue() );
 
-			} catch ( error ) {
+			} catch ( exception ) {
 
-				console.log( error );
+				console.warn( exception );
 
 			}
 
-			signals.objectChanged.dispatch( selected );
+			signals.objectChanged.dispatch( object );
 
 		}
 
@@ -378,6 +384,8 @@ Sidebar.Object3D = function ( editor ) {
 
 	function updateRows() {
 
+		var object = editor.selected;
+
 		var properties = {
 			'parent': objectParentRow,
 			'fov': objectFovRow,
@@ -393,7 +401,7 @@ Sidebar.Object3D = function ( editor ) {
 
 		for ( var property in properties ) {
 
-			properties[ property ].setDisplay( selected[ property ] !== undefined ? '' : 'none' );
+			properties[ property ].setDisplay( object[ property ] !== undefined ? '' : 'none' );
 
 		}
 
@@ -401,7 +409,10 @@ Sidebar.Object3D = function ( editor ) {
 
 	function updateTransformRows() {
 
-		if ( selected instanceof THREE.Light || ( selected instanceof THREE.Object3D && selected.userData.targetInverse ) ) {
+		var object = editor.selected;
+
+		if ( object instanceof THREE.Light ||
+		   ( object instanceof THREE.Object3D && object.userData.targetInverse ) ) {
 
 			objectRotationRow.setDisplay( 'none' );
 			objectScaleRow.setDisplay( 'none' );
@@ -439,9 +450,7 @@ Sidebar.Object3D = function ( editor ) {
 
 	}
 
-	// events
-
-	signals.sceneChanged.add( function () {
+	var updateObjectParent = function () {
 
 		var scene = editor.scene;
 
@@ -465,121 +474,133 @@ Sidebar.Object3D = function ( editor ) {
 
 		objectParent.setOptions( options );
 
-	} );
+	};
+
+	// events
 
 	signals.objectSelected.add( function ( object ) {
 
-		selected = object;
 		updateUI();
 
 	} );
 
+	signals.objectAdded.add( updateObjectParent );
+	signals.objectRemoved.add( updateObjectParent );
+
 	signals.objectChanged.add( function ( object ) {
 
-		if ( selected === object ) updateUI();
+		if ( object !== editor.selected ) return;
+
+		updateUI();
 
 	} );
 
 	function updateUI() {
 
-		container.setDisplay( 'block' );
+		container.setDisplay( 'none' );
 
-		var object = selected;
+		var object = editor.selected;
 
-		objectType.setValue( getObjectInstanceName( object ) );
+		if ( object !== null ) {
 
-		objectUUID.setValue( object.uuid );
-		objectName.setValue( object.name );
+			container.setDisplay( 'block' );
 
-		if ( object.parent !== undefined ) {
+			objectType.setValue( getObjectInstanceName( object ) );
 
-			objectParent.setValue( object.parent.id );
+			objectUUID.setValue( object.uuid );
+			objectName.setValue( object.name );
 
-		}
+			if ( object.parent !== undefined ) {
+
+				objectParent.setValue( object.parent.id );
 
-		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 );
+			objectPositionX.setValue( object.position.x );
+			objectPositionY.setValue( object.position.y );
+			objectPositionZ.setValue( object.position.z );
 
-		objectScaleX.setValue( object.scale.x );
-		objectScaleY.setValue( object.scale.y );
-		objectScaleZ.setValue( object.scale.z );
+			objectRotationX.setValue( object.rotation.x );
+			objectRotationY.setValue( object.rotation.y );
+			objectRotationZ.setValue( object.rotation.z );
 
-		if ( object.fov !== undefined ) {
+			objectScaleX.setValue( object.scale.x );
+			objectScaleY.setValue( object.scale.y );
+			objectScaleZ.setValue( object.scale.z );
 
-			objectFov.setValue( object.fov );
+			if ( object.fov !== undefined ) {
 
-		}
+				objectFov.setValue( object.fov );
 
-		if ( object.near !== undefined ) {
+			}
 
-			objectNear.setValue( object.near );
+			if ( object.near !== undefined ) {
 
-		}
+				objectNear.setValue( object.near );
 
-		if ( object.far !== undefined ) {
+			}
 
-			objectFar.setValue( object.far );
+			if ( object.far !== undefined ) {
 
-		}
+				objectFar.setValue( object.far );
 
-		if ( object.intensity !== undefined ) {
+			}
 
-			objectIntensity.setValue( object.intensity );
+			if ( object.intensity !== undefined ) {
 
-		}
+				objectIntensity.setValue( object.intensity );
 
-		if ( object.color !== undefined ) {
+			}
 
-			objectColor.setValue( '#' + object.color.getHexString() );
+			if ( object.color !== undefined ) {
 
-		}
+				objectColor.setValue( '#' + object.color.getHexString() );
 
-		if ( object.groundColor !== undefined ) {
+			}
 
-			objectGroundColor.setValue( '#' + object.groundColor.getHexString() );
+			if ( object.groundColor !== undefined ) {
 
-		}
+				objectGroundColor.setValue( '#' + object.groundColor.getHexString() );
 
-		if ( object.distance !== undefined ) {
+			}
 
-			objectDistance.setValue( object.distance );
+			if ( object.distance !== undefined ) {
 
-		}
+				objectDistance.setValue( object.distance );
 
-		if ( object.angle !== undefined ) {
+			}
 
-			objectAngle.setValue( object.angle );
+			if ( object.angle !== undefined ) {
 
-		}
+				objectAngle.setValue( object.angle );
 
-		if ( object.exponent !== undefined ) {
+			}
 
-			objectExponent.setValue( object.exponent );
+			if ( object.exponent !== undefined ) {
 
-		}
+				objectExponent.setValue( object.exponent );
 
-		objectVisible.setValue( object.visible );
+			}
 
-		try {
+			objectVisible.setValue( object.visible );
 
-			objectUserData.setValue( JSON.stringify( object.userData, null, '  ' ) );
+			try {
 
-		} catch ( error ) {
+				objectUserData.setValue( JSON.stringify( object.userData, null, '  ' ) );
 
-			console.log( error );
+			} catch ( error ) {
 
-		}
+				console.log( error );
 
-		objectUserData.setBorderColor( '#ccc' );
-		objectUserData.setBackgroundColor( '' );
+			}
+
+			objectUserData.setBorderColor( '#ccc' );
+			objectUserData.setBackgroundColor( '' );
+
+			updateRows();
+			updateTransformRows();
 
-		updateRows();
-		updateTransformRows();
+		}
 
 	}
 

+ 39 - 38
editor/js/Sidebar.Scene.js

@@ -11,12 +11,27 @@ Sidebar.Scene = function ( editor ) {
 	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 );
+	var outliner = new UI.FancySelect().setWidth( '100%' ).setHeight('140px').setColor( '#444' ).setFontSize( '12px' )
+	outliner.onChange( function () {
+
+		editor.selectById( parseInt( outliner.getValue() ) );
+
+	} );
 	container.add( outliner );
 	container.add( new UI.Break() );
 
 	// fog
 
+	var updateFogParameters = function () {
+
+		var near = fogNear.getValue();
+		var far = fogFar.getValue();
+		var density = fogDensity.getValue();
+
+		signals.fogParametersChanged.dispatch( near, far, density );
+
+	};
+
 	var fogTypeRow = new UI.Panel();
 	var fogType = new UI.Select().setOptions( {
 
@@ -24,7 +39,15 @@ Sidebar.Scene = function ( editor ) {
 		'Fog': 'Linear',
 		'FogExp2': 'Exponential'
 
-	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' ).onChange( updateFogType );
+	} ).setWidth( '150px' ).setColor( '#444' ).setFontSize( '12px' )
+	fogType.onChange( function () {
+
+		var type = fogType.getValue();
+		signals.fogTypeChanged.dispatch( type );
+
+		refreshFogUI();
+
+	} );
 
 	fogTypeRow.add( new UI.Text( 'Fog' ).setWidth( '90px' ).setColor( '#666' ) );
 	fogTypeRow.add( fogType );
@@ -36,7 +59,12 @@ Sidebar.Scene = function ( editor ) {
 	var fogColorRow = new UI.Panel();
 	fogColorRow.setDisplay( 'none' );
 
-	var fogColor = new UI.Color().setValue( '#aaaaaa' ).onChange( updateFogColor );
+	var fogColor = new UI.Color().setValue( '#aaaaaa' )
+	fogColor.onChange( function () {
+
+		signals.fogColorChanged.dispatch( fogColor.getHexValue() );
+
+	} );
 
 	fogColorRow.add( new UI.Text( 'Fog color' ).setWidth( '90px' ).setColor( '#666' ) );
 	fogColorRow.add( fogColor );
@@ -81,7 +109,7 @@ Sidebar.Scene = function ( editor ) {
 
 	//
 
-	function getObjectType( object ) {
+	var getObjectType = function ( object ) {
 
 		var objects = {
 
@@ -105,23 +133,7 @@ Sidebar.Scene = function ( editor ) {
 
 	}
 
-	function updateOutliner() {
-
-		var id = parseInt( outliner.getValue() );
-		editor.selectById( id );
-
-	}
-
-	function updateFogType() {
-
-		var type = fogType.getValue();
-		signals.fogTypeChanged.dispatch( type );
-
-		refreshFogUI();
-
-	}
-
-	function refreshFogUI() {
+	var refreshFogUI = function () {
 
 		var type = fogType.getValue();
 
@@ -130,25 +142,11 @@ Sidebar.Scene = function ( editor ) {
 		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
 
-	var selected;
-
-	signals.sceneChanged.add( function () {
+	var updateUI = function () {
 
 		var scene = editor.scene;
 
@@ -198,7 +196,10 @@ Sidebar.Scene = function ( editor ) {
 
 		refreshFogUI();
 
-	} );
+	};
+
+	signals.objectAdded.add( updateUI );
+	signals.objectRemoved.add( updateUI );
 
 	signals.objectSelected.add( function ( object ) {
 

+ 38 - 22
editor/js/Viewport.js

@@ -45,6 +45,8 @@ var Viewport = function ( editor ) {
 	var transformControls = new THREE.TransformControls( camera, container.dom );
 	transformControls.addEventListener( 'change', function () {
 
+		// TODO: Differentiate from transform hovers change and object transform change
+
 		signals.objectChanged.dispatch( editor.selected );
 
 	} );
@@ -64,8 +66,6 @@ var Viewport = function ( editor ) {
 	var ray = new THREE.Raycaster();
 	var projector = new THREE.Projector();
 
-	var selected = camera;
-
 	// events
 
 	var getIntersects = function ( event, object ) {
@@ -118,11 +118,13 @@ var Viewport = function ( editor ) {
 
 			if ( intersects.length > 0 ) {
 
-				editor.select( intersects[ 0 ].object );
+				var object = intersects[ 0 ].object;
+
+				editor.select( object );
 
-				if ( helpersToObjects[ selected.id ] !== undefined ) {
+				if ( helpersToObjects[ object.id ] !== undefined ) {
 
-					editor.select( helpersToObjects[ selected.id ] );
+					editor.select( helpersToObjects[ object.id ] );
 
 				}
 
@@ -171,13 +173,6 @@ var Viewport = function ( editor ) {
 
 	// signals
 
-	signals.sceneChanged.add( function () {
-
-		updateInfo();
-		render();
-
-	} );
-
 	signals.transformModeChanged.add( function ( mode ) {
 
 		transformControls.setMode( mode );
@@ -213,12 +208,6 @@ var Viewport = function ( editor ) {
 
 	} );
 
-	signals.objectAdded.add( function ( object ) {
-
-		objects.push( object );
-
-	} );
-
 	signals.objectSelected.add( function ( object ) {
 
 		selectionBox.visible = false;
@@ -245,6 +234,21 @@ var Viewport = function ( editor ) {
 
 	} );
 
+	signals.objectAdded.add( function ( object ) {
+
+		objects.push( object );
+
+		if ( object instanceof THREE.Light ) {
+
+			updateMaterials();
+
+		}
+
+		render();
+		updateInfo();
+
+	} );
+
 	signals.objectChanged.add( function ( object ) {
 
 		if ( object.geometry !== undefined ) {
@@ -261,8 +265,20 @@ var Viewport = function ( editor ) {
 		}
 
 		render();
+		updateInfo();
 
-		signals.sceneChanged.dispatch( scene );
+	} );
+
+	signals.objectRemoved.add( function ( object ) {
+
+		if ( object instanceof THREE.Light ) {
+
+			updateMaterials();
+
+		}
+
+		render();
+		updateInfo();
 
 	} );
 
@@ -299,7 +315,7 @@ var Viewport = function ( editor ) {
 
 			}
 
-			updateMaterials( scene );
+			updateMaterials();
 
 			oldFogType = fogType;
 
@@ -404,9 +420,9 @@ var Viewport = function ( editor ) {
 
 	}
 
-	function updateMaterials( root ) {
+	function updateMaterials() {
 
-		root.traverse( function ( node ) {
+		editor.scene.traverse( function ( node ) {
 
 			if ( node.material ) {