Browse Source

Merge remote-tracking branch 'greggman/add-multiple-window-example' into dev

Mr.doob 12 years ago
parent
commit
49f2df3448
1 changed files with 732 additions and 0 deletions
  1. 732 0
      examples/webgl_multiple_windows.html

+ 732 - 0
examples/webgl_multiple_windows.html

@@ -0,0 +1,732 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - multiple windows</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body, html {
+				color: #000;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				width: 100%;
+				height: 100%;
+
+				background-color: #fff;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#container {
+				width: 100%;
+				height: 100%;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+
+			a {
+				color: #0080ff;
+			}
+
+			#newview {
+				position: absolute;
+				top: 10px;
+				left: 10px;
+				background-color: rgba(0,0,0,0.5);
+				color: white;
+				font-weight: bold;
+				padding: 1em;
+			}
+
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - multiple windows - webgl</div>
+		<div id="newview">Click for new Window</div>
+		<script src="../build/three.js"></script>
+		<script src="js/controls/TransformControls.js"></script>
+		<script src="js/Detector.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, windowManager, viewCount = 0;
+
+			var views, scene, renderer;
+
+			var mesh, group1, group2, group3, light;
+
+			var mouseX = 0, mouseY = 0;
+
+			var windowWidth = 1, windowHeight = 1;
+
+			/**
+			 * Makes one class inherit from another.
+			 * @param {!Object} subClass Class that wants to inherit.
+			 * @param {!Object} superClass Class to inherit from.
+			 */
+
+			var inherit = function( subClass, superClass ) {
+
+				var TmpClass = function() { };
+				TmpClass.prototype = superClass.prototype;
+				subClass.prototype = new TmpClass();
+
+			};
+
+			/**
+			 * Represents a popup window.
+			 */
+
+			var ViewWindow = function( manager, id, window, container ) {
+				var self = this;
+				this.manager = manager;
+				this.id = id;
+				this.window = window;
+				this.renderQueued = false;
+				this.width = 300;
+				this.height = 150;
+				this.container = container;
+				this.closed = false;
+				this.devicePixelRatio = 1;//window.devicePixelRatio || 1;
+				var document = window.document
+				this.document = document;
+				this.canvas = this.document.createElement( 'canvas' );
+				var style = this.canvas.style;
+				style.width = "100%";
+				style.height = "100%";
+				this.container.appendChild( this.canvas );
+				this.ctx = this.canvas.getContext( '2d' );
+
+				// TODO: should probably make the polyfill take a window?
+				this.window.requestAnimFrame = (function() {
+
+					return this.window.requestAnimationFrame ||
+							this.window.webkitRequestAnimationFrame ||
+							this.window.mozRequestAnimationFrame ||
+							function( callback ){
+
+								this.window.setTimeout( callback, 1000 / 60 );
+
+							};
+
+				})();
+
+				this.window.addEventListener( 'resize', this.constructor.prototype.updateSize.bind( this ) );
+				this.window.addEventListener( 'unload', this.constructor.prototype.close.bind( this ) );
+				this.window.addEventListener( 'focus', this.constructor.prototype.focus.bind( this ) );
+
+				var rand = function() {
+
+					return Math.random() * 0.2 + 0.5;
+
+				};
+
+				var view = {
+
+					background: new THREE.Color().setRGB( rand(), rand(), rand() ),
+					fov: 30,
+
+				};
+
+				this.view = view;
+
+				var camera = new THREE.PerspectiveCamera( 30, 1, 1, 10000 );
+				var angle = 0.2;
+				var distance = 1500;
+				camera.position.z = Math.cos(Math.PI * angle) * distance;
+				camera.position.x = Math.sin(Math.PI * angle) * distance;
+				camera.position.y = distance * 0.1;
+				camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+				view.camera = camera;
+
+				camera.updateFromCanvas = (function( camera ) {
+
+					return function( canvas ) {
+
+						camera.aspect = canvas.width / canvas.height;
+						camera.updateProjectionMatrix();
+
+
+					};
+
+				}( camera ));
+
+				this.perspectiveCamera = camera;
+
+				var camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 1, 10000 );
+				camera.position.z = 1500;
+
+				camera.updateFromCanvas = (function( camera ) {
+
+					return function ( canvas ) {
+
+						var width  = canvas.width;
+						var height = canvas.height;
+						camera.left    = -width;
+						camera.right   =  width;
+						camera.top     =  height;
+						camera.bottom  = -height;
+						camera.updateProjectionMatrix();
+
+					};
+
+				}( camera ));
+
+				this.orthographicCamera = camera;
+
+				this.currentCamera = this.perspectiveCamera;
+
+				// Is this in three.js?
+				var copyOrientation = function( src, dst ) {
+
+					dst.up.copy( src.up );
+					dst.position.copy( src.position );
+					dst.scale.copy( src.scale );
+					dst.eulerOrder = src.eulerOrder;
+					dst.quaternion.copy( src.quaternion );
+
+				};
+
+				var setCamera = function( camera ) {
+
+					self.currentCamera = camera;
+
+				};
+
+				var buttonsElem = document.createElement( 'div' );
+				var style = buttonsElem.style;
+				style.position = 'absolute';
+				style.top = '10px';
+				style.padding = '1em';
+				style.right = '10px';
+				style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
+
+				var views = [
+					{
+						name: 'perspective 1',
+						func: function() {
+
+							setCamera( self.perspectiveCamera );
+
+							var angle = 0.2;
+							var distance = 1500;
+							var x = Math.sin(Math.PI * angle) * distance;
+							var y = distance * 0.1;
+							var z = Math.cos(Math.PI * angle) * distance;
+							self.currentCamera.position.set( x, y, z );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+
+					{
+						name: 'perspective 2',
+						func: function() {
+
+							setCamera( self.perspectiveCamera );
+
+							var angle = -0.4;
+							var distance = 2500;
+							var x = Math.sin(Math.PI * angle) * distance;
+							var y = distance * 0.2;
+							var z = Math.cos(Math.PI * angle) * distance;
+							self.currentCamera.position.set( x, y, z );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+
+					{
+						name: 'perspective 3',
+						func: function() {
+
+							setCamera( self.perspectiveCamera );
+
+							var angle = 0.25;
+							var distance = 1500;
+							var x = Math.sin(Math.PI * angle) * distance;
+							var y = distance * 0.6;
+							var z = Math.cos(Math.PI * angle) * distance;
+							self.currentCamera.position.set( x, y, z );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+/*
+					{
+						name: 'left',
+						func: function() {
+
+							setCamera( self.orthographicCamera );
+
+							self.currentCamera.position.set( -1500, 0, 0 );
+							self.currentCamera.up.set( 0, 1, 0 );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+
+					{
+						name: 'top',
+						func: function() {
+
+							setCamera( self.orthographicCamera );
+
+							self.currentCamera.position.set( 0, 1500, 0 );
+							self.currentCamera.up.set( 0, 0, -1 );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+
+					{
+						name: 'front',
+						func: function() {
+
+							setCamera( self.orthographicCamera );
+
+							self.currentCamera.position.set( 0, 0, 1500 );
+							self.currentCamera.up.set( 0, 1, 0 );
+							self.currentCamera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
+
+						},
+					},
+*/
+				];
+				var updateViewHandler = function( button, view ) {
+
+					if ( self.oldButton ) {
+
+						self.oldButton.style.color = 'black';
+
+					}
+
+					view.func();
+					self.manager.updateControlCamera( self.currentCamera );
+					self.queueRender();
+
+					self.oldButton = button,
+					button.style.color = 'white';
+
+				};
+
+				var buttons = [];
+				views.forEach(function( view ) {
+
+					var button = document.createElement( 'div' );
+					button.appendChild( document.createTextNode( view.name ) );
+					button.addEventListener( 'click', function( button, view ) {
+
+					  return function() {
+
+						  updateViewHandler( button, view );
+
+					  };
+
+					}( button, view ) );
+					buttonsElem.appendChild( button );
+					buttons.push( button );
+
+				});
+
+				this.container.appendChild( buttonsElem );
+				this.updateSize();
+				var viewNdx = (viewCount++) % buttons.length;
+				updateViewHandler( buttons[viewNdx], views[viewNdx] );
+			};
+
+			ViewWindow.prototype.focus = function() {
+
+				this.manager.makeWindowCurrent( this );
+
+			};
+
+			ViewWindow.prototype.updateSize = function() {
+
+				var desiredWidth  = this.canvas.clientWidth  * this.devicePixelRatio;
+				var desiredHeight = this.canvas.clientHeight * this.devicePixelRatio;
+
+				if ( this.canvas.width != desiredWidth || this.canvas.height != desiredHeight ) {
+
+					this.canvas.width  = desiredWidth;
+					this.canvas.height = desiredHeight;
+					this.width = desiredWidth;
+					this.height = desiredHeight;
+					this.manager.updateMaxSize();
+
+					this.queueRender();
+
+				}
+			};
+
+			ViewWindow.prototype.close = function() {
+				if ( !this.closed ) {
+					this.manager.removeWindow( this, this.id );
+				}
+			};
+
+			ViewWindow.prototype.closeImmediately = function() {
+
+				this.closed = true;
+				this.window.close();
+
+			};
+
+			ViewWindow.prototype.queueRender = function() {
+
+				if ( ! this.renderQueued ) {
+
+				  this.renderQueued = true;
+				  this.window.requestAnimFrame( this.constructor.prototype.render.bind( this ) );
+
+				}
+
+			};
+
+			ViewWindow.prototype.render = function() {
+
+				this.renderQueued = false;
+				var view = this.view;
+				camera = this.currentCamera;
+
+				camera.updateFromCanvas( this.canvas );
+
+				this.manager.renderSceneToCanvas( this, camera, view, this.ctx );
+
+			};
+
+			/**
+			 * Represents the main window.
+			 */
+
+			MainViewWindow = function() {
+
+				ViewWindow.apply( this, arguments );
+
+			};
+
+			inherit( MainViewWindow, ViewWindow );
+
+			MainViewWindow.prototype.close = function() {
+
+			};
+
+			MainViewWindow.prototype.closeImmediately = function() {
+
+			};
+
+			/**
+			 * Manages the windows.
+			 */
+			var WindowManager = function( container, scene ) {
+
+				this.windows = [];
+				this.controls = [];
+				this.maxWidth = 0;
+				this.maxHeight = 0;
+				this.newWindowId = 0;
+				this.scene = scene;
+
+				this.renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false, devicePixelRatio: 1 } );
+
+				window.addEventListener( 'unload', this.constructor.prototype.closeAllWindows.bind( this ) );
+
+				// Main window has to be created last.
+				this.windows.push( new MainViewWindow( this, 0, window, container ) );
+				this.currentWindow = this.windows[0];
+			};
+
+
+			WindowManager.prototype.createWindow = function() {
+
+				var id = ++this.newWindowId;
+				var subWindow = window.open( '', 'view#' + id, 'width=400,height=400,location=no,resizable=yes' );
+				var document = subWindow.document;
+				var body = document.body;
+				var style = body.style;
+				style.width = '100%';
+				style.height = '100%';
+				style.padding = '0px';
+				style.margin = '0px';
+				style.overflow = 'hidden';
+				style.fontFamily = 'Monospace';
+				style.fontSize = '13px';
+				this.windows.push( new ViewWindow( this, id, subWindow, body ) );
+
+			};
+
+			WindowManager.prototype.removeWindow = function( window, id ) {
+
+				for ( var ii = 0; ii < this.windows.length; ++ii ) {
+
+					if ( this.windows[ ii ].id == id ) {
+
+						this.windows.splice( ii, 1 );
+						break;
+
+					}
+
+				}
+
+			};
+
+			WindowManager.prototype.closeAllWindows = function() {
+
+				this.windows.forEach( function( window ) {
+
+					window.closeImmediately();
+
+				} );
+
+				this.windows = [];
+
+			};
+
+			WindowManager.prototype.updateMaxSize = function() {
+
+				var maxWidth = 0;
+				var maxHeight = 0;
+				this.windows.forEach( function( window ) {
+
+					maxWidth  = Math.max( window.width,  maxWidth );
+					maxHeight = Math.max( window.height, maxHeight );
+
+				} );
+
+				if ( this.maxWidth != maxWidth || this.maxHeight != maxHeight ) {
+
+					this.renderer.setSize( maxWidth, maxHeight, false );
+					this.maxWidth = maxWidth;
+					this.maxHeight = maxHeight;
+
+				}
+
+			};
+
+			WindowManager.prototype.updateAllWindows = function() {
+
+				this.updateMaxSize();
+
+				this.controls.forEach( function( control ) {
+
+					control.update();
+
+				} );
+
+				var renderer = this.renderer;
+				var self = this;
+				this.windows.forEach( function( window ) {
+
+					window.render();
+
+				} );
+
+			};
+
+			WindowManager.prototype.renderSceneToCanvas = function( window, camera, parameters, ctx ) {
+
+				var renderer = this.renderer;
+				var canvas = ctx.canvas;
+				var scene = this.scene;
+
+				var hide = window !== this.currentWindow;
+				this.controls.forEach( function( control ) {
+
+					if ( hide ) {
+
+						control.hide();
+
+					} else {
+
+						control.setMode( control.mode );
+
+					}
+
+				} );
+
+				renderer.setViewport( 0, 0, canvas.width, canvas.height );
+				renderer.setClearColor( parameters.background );
+				renderer.render( scene, camera );
+
+				var srcX = 0;
+				var srcY = this.maxHeight - canvas.height;
+				var dstX = 0;
+				var dstY = 0;
+				var width = canvas.width;
+				var height = canvas.height;
+
+				if ( srcX >= 0 && srcY >= 0 && width >= 1 && height >= 1 ) {
+
+					ctx.drawImage( renderer.context.canvas,
+								   srcX, srcY, width, height,
+								   dstX, dstY, width, height );
+
+				}
+
+			};
+
+			WindowManager.prototype.makeWindowCurrent = function( window ) {
+
+				if ( window !== this.currentWindow ) {
+
+					this.currentWindow = window;
+					this.attachControlsToWindow( window );
+					this.updateAllWindows();
+
+				}
+
+			};
+
+			WindowManager.prototype.updateControlCamera = function( camera ) {
+
+				this.controls.forEach( function( control ) {
+
+					control.camera = camera;
+					control.update();
+
+				} );
+
+			};
+
+			WindowManager.prototype.attachControlsToWindow = function( window ) {
+
+				this.controls.forEach( function( control ) {
+
+					var object = control.object;
+					if ( object ) {
+
+						control.detatch( object );
+
+					}
+
+					// switch to this window
+					control.domElement = window.container;
+					control.document = window.document;
+					control.camera = window.currentCamera;
+
+					control.attatch( object );
+					control.update();
+
+				} );
+
+			};
+
+			WindowManager.prototype.addTransformControl = function( object ) {
+
+				var window = this.currentWindow;
+				var camera = window.currentCamera;
+				var container = window.container;
+				var control = new THREE.TransformControls( camera, container, window.document );
+				control.addEventListener( 'change', windowManager.__proto__.updateAllWindows.bind( windowManager ));
+				control.attatch( object );
+				control.scale = 0.65;
+				this.scene.add( control.gizmo );
+
+				this.controls.push( control );
+
+			};
+
+			init();
+
+			function init() {
+
+				scene = new THREE.Scene();
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 0, 0, 1 );
+				scene.add( light );
+
+				var faceIndices = [ 'a', 'b', 'c', 'd' ];
+
+				var color, f, f2, f3, p, n, vertexIndex,
+
+					radius = 200,
+
+					geometry  = new THREE.IcosahedronGeometry( radius, 1 ),
+					geometry2 = new THREE.IcosahedronGeometry( radius, 1 ),
+					geometry3 = new THREE.IcosahedronGeometry( radius, 1 );
+
+				for ( var i = 0; i < geometry.faces.length; i ++ ) {
+
+					f  = geometry.faces[ i ];
+					f2 = geometry2.faces[ i ];
+					f3 = geometry3.faces[ i ];
+
+					n = ( f instanceof THREE.Face3 ) ? 3 : 4;
+
+					for( var j = 0; j < n; j++ ) {
+
+						vertexIndex = f[ faceIndices[ j ] ];
+
+						p = geometry.vertices[ vertexIndex ];
+
+						color = new THREE.Color( 0xffffff );
+						color.setHSL( ( p.y / radius + 1 ) / 2, 1.0, 0.5 );
+
+						f.vertexColors[ j ] = color;
+
+						color = new THREE.Color( 0xffffff );
+						color.setHSL( 0.0, ( p.y / radius + 1 ) / 2, 0.5 );
+
+						f2.vertexColors[ j ] = color;
+
+						color = new THREE.Color( 0xffffff );
+						color.setHSL( 0.125 * vertexIndex/geometry.vertices.length, 1.0, 0.5 );
+
+						f3.vertexColors[ j ] = color;
+
+					}
+
+				}
+
+
+				var materials = [
+
+					new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors } ),
+					new THREE.MeshBasicMaterial( { color: 0x000000, shading: THREE.FlatShading, wireframe: true, transparent: true } )
+
+				];
+
+				group1 = THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
+				group1.position.x = -400;
+				group1.rotation.x = -0;
+				scene.add( group1 );
+
+				group2 = THREE.SceneUtils.createMultiMaterialObject( geometry2, materials );
+				group2.position.x = 400;
+				group2.rotation.x = 0;
+				scene.add( group2 );
+
+				group3 = THREE.SceneUtils.createMultiMaterialObject( geometry3, materials );
+				group3.position.x = 0;
+				group3.rotation.x = 0;
+				scene.add( group3 );
+
+				container = document.getElementById( 'container' );
+
+				windowManager = new WindowManager( container, scene );
+				var newViewButton = document.getElementById( 'newview' );
+				newViewButton.addEventListener( 'click', windowManager.__proto__.createWindow.bind( windowManager ) );
+
+				windowManager.addTransformControl( group1 );
+				windowManager.addTransformControl( group2 );
+				windowManager.addTransformControl( group3 );
+
+				windowManager.updateAllWindows();
+
+			}
+
+		</script>
+
+	</body>
+</html>