var Viewport = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setPosition( 'absolute' ); var info = new UI.Text(); info.setPosition( 'absolute' ); info.setRight( '5px' ); info.setBottom( '5px' ); info.setFontSize( '12px' ); info.setColor( '#ffffff' ); info.setValue( 'objects: 0, vertices: 0, faces: 0' ); container.add( info ); var scene = editor.scene; var sceneHelpers = editor.sceneHelpers; var objects = []; // helpers var grid = new THREE.GridHelper( 500, 25 ); sceneHelpers.add( grid ); // var camera = new THREE.PerspectiveCamera( 50, 1, 1, 5000 ); camera.position.fromArray( editor.config.getKey( 'camera' ).position ); camera.lookAt( new THREE.Vector3().fromArray( editor.config.getKey( 'camera' ).target ) ); // var selectionBox = new THREE.BoxHelper(); selectionBox.material.depthTest = false; selectionBox.material.transparent = true; selectionBox.visible = false; sceneHelpers.add( selectionBox ); var transformControls = new THREE.TransformControls( camera, container.dom ); transformControls.addEventListener( 'change', function () { controls.enabled = true; if ( transformControls.axis !== null ) { controls.enabled = false; } if ( editor.selected !== null ) { signals.objectChanged.dispatch( editor.selected ); } } ); sceneHelpers.add( transformControls ); // fog 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(); // events var getIntersects = function ( event, object ) { var rect = container.dom.getBoundingClientRect(); x = ( event.clientX - rect.left ) / rect.width; y = ( event.clientY - rect.top ) / rect.height; var vector = new THREE.Vector3( ( x ) * 2 - 1, - ( y ) * 2 + 1, 0.5 ); projector.unprojectVector( vector, camera ); ray.set( camera.position, vector.sub( camera.position ).normalize() ); if ( object instanceof Array ) { return ray.intersectObjects( object ); } return ray.intersectObject( object ); }; var onMouseDownPosition = new THREE.Vector2(); var onMouseUpPosition = new THREE.Vector2(); var onMouseDown = function ( event ) { event.preventDefault(); var rect = container.dom.getBoundingClientRect(); x = (event.clientX - rect.left) / rect.width; y = (event.clientY - rect.top) / rect.height; onMouseDownPosition.set( x, y ); document.addEventListener( 'mouseup', onMouseUp, false ); }; var onMouseUp = function ( event ) { var rect = container.dom.getBoundingClientRect(); x = (event.clientX - rect.left) / rect.width; y = (event.clientY - rect.top) / rect.height; onMouseUpPosition.set( x, y ); if ( onMouseDownPosition.distanceTo( onMouseUpPosition ) == 0 ) { var intersects = getIntersects( event, objects ); if ( intersects.length > 0 ) { var object = intersects[ 0 ].object; if ( object.userData.object !== undefined ) { // helper editor.select( object.userData.object ); } else { editor.select( object ); } } else { editor.select( null ); } render(); } document.removeEventListener( 'mouseup', onMouseUp ); }; var onDoubleClick = function ( event ) { var intersects = getIntersects( event, objects ); if ( intersects.length > 0 && intersects[ 0 ].object === editor.selected ) { controls.focus( editor.selected ); } }; container.dom.addEventListener( 'mousedown', onMouseDown, false ); container.dom.addEventListener( 'dblclick', onDoubleClick, false ); // controls need to be added *after* main logic, // otherwise controls.enabled doesn't work. var controls = new THREE.EditorControls( camera, container.dom ); controls.center.fromArray( editor.config.getKey( 'camera' ).target ) controls.addEventListener( 'change', function () { transformControls.update(); signals.cameraChanged.dispatch( camera ); } ); // signals signals.themeChanged.add( function ( value ) { switch ( value ) { case 'css/light.css': grid.setColors( 0x444444, 0x888888 ); clearColor = 0xaaaaaa; break; case 'css/dark.css': grid.setColors( 0xbbbbbb, 0x888888 ); clearColor = 0x333333; break; } renderer.setClearColor( clearColor ); render(); } ); signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); } ); signals.snapChanged.add( function ( dist ) { transformControls.setSnap( dist ); } ); signals.spaceChanged.add( function ( space ) { transformControls.setSpace( space ); } ); signals.rendererChanged.add( function ( type ) { container.dom.removeChild( renderer.domElement ); renderer = new THREE[ type ]( { antialias: true } ); renderer.autoClear = false; renderer.autoUpdateScene = false; renderer.setClearColor( clearColor ); renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); container.dom.appendChild( renderer.domElement ); render(); } ); signals.sceneGraphChanged.add( function () { render(); updateInfo(); } ); var saveTimeout; signals.cameraChanged.add( function () { if ( saveTimeout !== undefined ) { clearTimeout( saveTimeout ); } saveTimeout = setTimeout( function () { editor.config.setKey( 'camera', { position: camera.position.toArray(), target: controls.center.toArray() } ); }, 1000 ); render(); } ); signals.objectSelected.add( function ( object ) { selectionBox.visible = false; transformControls.detach(); if ( object !== null ) { if ( object.geometry !== undefined && object instanceof THREE.Sprite === false ) { selectionBox.update( object ); selectionBox.visible = true; } if ( object instanceof THREE.PerspectiveCamera === false ) { transformControls.attach( object ); } } render(); } ); signals.objectAdded.add( function ( object ) { var materialsNeedUpdate = false; object.traverse( function ( child ) { if ( child instanceof THREE.Light ) materialsNeedUpdate = true; objects.push( child ); } ); if ( materialsNeedUpdate === true ) updateMaterials(); } ); signals.objectChanged.add( function ( object ) { transformControls.update(); if ( object !== camera ) { if ( object.geometry !== undefined ) { selectionBox.update( object ); } if ( editor.helpers[ object.id ] !== undefined ) { editor.helpers[ object.id ].update(); } updateInfo(); } render(); } ); signals.objectRemoved.add( function ( object ) { var materialsNeedUpdate = false; object.traverse( function ( child ) { if ( child instanceof THREE.Light ) materialsNeedUpdate = true; objects.splice( objects.indexOf( child ), 1 ); } ); if ( materialsNeedUpdate === true ) updateMaterials(); } ); signals.helperAdded.add( function ( object ) { objects.push( object.getObjectByName( 'picker' ) ); } ); signals.helperRemoved.add( function ( object ) { objects.splice( objects.indexOf( object.getObjectByName( 'picker' ) ), 1 ); } ); signals.materialChanged.add( function ( material ) { render(); } ); 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(); 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(); } ); signals.windowResize.add( function () { camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; camera.updateProjectionMatrix(); renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); render(); } ); signals.playAnimations.add( function (animations) { function animate() { requestAnimationFrame( animate ); for ( var i = 0; i < animations.length ; i ++ ) { animations[i].update(0.016); } render(); } animate(); } ); // var clearColor, renderer; if ( editor.config.getKey( 'renderer' ) !== undefined ) { renderer = new THREE[ editor.config.getKey( 'renderer' ) ]( { antialias: true } ); } else { if ( System.support.webgl === true ) { renderer = new THREE.WebGLRenderer( { antialias: true } ); } else { renderer = new THREE.CanvasRenderer(); } } renderer.autoClear = false; renderer.autoUpdateScene = false; container.dom.appendChild( renderer.domElement ); animate(); // function updateInfo() { var objects = 0; var vertices = 0; var faces = 0; scene.traverse( function ( object ) { if ( object instanceof THREE.Mesh ) { objects ++; var geometry = object.geometry; if ( geometry instanceof THREE.Geometry ) { vertices += geometry.vertices.length; faces += geometry.faces.length; } else if ( geometry instanceof THREE.Geometry2 ) { vertices += geometry.vertices.length / 3; faces += geometry.vertices.length / 9; } else if ( geometry instanceof THREE.BufferGeometry ) { vertices += geometry.attributes.position.array.length / 3; if ( geometry.attributes.index !== undefined ) { faces += geometry.attributes.index.array.length / 3; } else { faces += geometry.attributes.position.array.length / 9; } } } } ); info.setValue( 'objects: ' + objects + ', vertices: ' + vertices + ', faces: ' + faces ); } function updateMaterials() { editor.scene.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 ); } function render() { sceneHelpers.updateMatrixWorld(); scene.updateMatrixWorld(); renderer.clear(); renderer.render( scene, camera ); renderer.render( sceneHelpers, camera ); } return container; }