123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- # Copyright 2012 United States Government, as represented by the Secretary of Defense, Under
- # Secretary of Defense (Personnel & Readiness).
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- # in compliance with the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software distributed under the License
- # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- # or implied. See the License for the specific language governing permissions and limitations under
- # the License.
- ## The component representation of a navigation scene
- ##
- ## @name navscene.vwf
- ## @namespace
- ---
- extends: http://vwf.example.com/scene.vwf
- properties:
-
- ## Navigation mode. Default value is 'walk.' Other options include 'orbit' and 'none.'
- ##
- ## @name navscene.vwf#navmode
- ## @property
- navmode:
- set: |
- switch ( value ) {
- case "walk":
- case "orbit":
- case "none":
- if ( this.setNavMode ) {
- this.setNavMode( value );
- }
- this.navmode = value;
- break;
- }
- value: "walk"
- ## Orbit radius
- ##
- ## @name navscene.vwf#orbitRadius
- ## @property
- orbitRadius: -1
- ## A node.vwf#find search pattern identifying the object to orbit.
- ##
- ## @name navscene.vwf#orbitObjectPattern
- ## @property
- orbitObjectPattern: "sceneCenter"
- ## Rotation speed. At a speed of 1, will take 4 seconds to go around 360 degrees.
- ##
- ## @name navscene.vwf#rotationSpeed
- ## @property
- rotationSpeed: 1.0
- ## Translation speed
- ##
- ## @name navscene.vwf#translationSpeed
- ## @property
- translationSpeed: 1.0
- ## Maximum speed
- ##
- ## @name navscene.vwf#maxSpeed
- ## @property
- maxSpeed: 500
- ## Drag mode move boolean. Default value is false.
- ##
- ## @name navscene.vwf#dragModeMove
- ## @property
- dragModeMove: false
- events:
- keyUp:
- keyDown:
- pointerDown:
- pointerUp:
- pointerMove:
- pointerOut:
- pointerWheel:
- methods:
-
- ## Updates scene
- ##
- ## @name navscene.vwf#update
- ## @function
- ##
- ## @returns undefined
- update:
- ## Gets camera at vector
- ##
- ## @name navscene.vwf#getCameraAt
- ## @function
- ##
- ## @returns camera at vector
- getCameraAt:
- ## For internal use only - needs to be public for future calls
- ##
- ## @name navscene.vwf#disableViewSideNav
- ## @function
- ##
- ## @returns undefined
- disableViewSideNav:
- ## For internal use only - needs to be public for future calls
- ##
- ## @name navscene.vwf#setNavMode
- ## @function
- ##
- ## @returns undefined
- setNavMode:
- scripts:
- - |
- var counter = 1;
- var _piDiv180 = Math.PI / 180;
- var _180DivPI = 180 / Math.PI;
- var _2PI = 2 * Math.PI;
- var _85 = 85.0 * _piDiv180;
- var _10 = 10.0 * _piDiv180;
- var phi, theta;
- this.initialize = function() {
- this.input = {
- futureActive: function() {
- return ( this.lookActive || this.moveActive || this.button1Down || this.button2Down || this.keysAreDown() );
- },
- timeSinceLastEvent: function() { return this.time - this.pointerEventTime; },
- timeSinceDownEvent: function() { return this.time - this.pointerDownTime; },
- pointerDelta: function() {
- if ( this.pointerInfo && this.lastPointerInfo ) {
- return [ (this.lastPointerInfo.position[0] - this.pointerInfo.position[0]) * 50,
- (this.lastPointerInfo.position[1] - this.pointerInfo.position[1]) * 50
- ];
- }
- return undefined;
- },
- keysAreDown: function() { return ( this.keyInfo && Object.keys( this.keyInfo.keysDown ).length > 0 ); },
- keyInfo: undefined,
- pointerInfo: undefined,
- lastPointerInfo: undefined,
- pickInfo: undefined,
- lastPickInfo: undefined,
- pointerDownTime: undefined,
- pointerEventTime: undefined,
- lookActive: false,
- moveActive: false,
- look: [ 0, 0 ],
- move: [ 0, 0 ],
- button1Down: false,
- button2Down: false,
- turnLeftDown: false,
- turnRightDown: false,
- lastUpdateTime: undefined,
- lastInputTime: undefined,
- };
- // Wait until the queue resumes to set the navigation mode, so that we are sure that the camera has been
- // created
- // TODO: When we can assume that initialize doesn't complete until all created nodes are in place, this
- // will no longer need to be a future call because we will be able to assume that the camera exists
-
- // Disable view-side navigation so navscene.vwf can do the navigation
- this.future( 0 ).disableViewSideNav();
- this.future( 0 ).setNavMode( this.navmode );
- }
- this.timeElapsed = function() {
- var timeElapsed = this.time - this.input.lastInputTime;
- if ( !this.input.lastInputTime || timeElapsed > 1 ) {
- timeElapsed = 1;
- }
- return timeElapsed;
- }
- this.disableViewSideNav = function() {
- if ( this.camera )
- this.camera.navmode = "none";
- }
- this.setNavMode = function( mode ) {
- if (!this.activeCameraComp) {
- this.getActiveCamera();
- }
- if ( this.activeCameraComp ) {
- switch( mode ) {
- case "orbit":
- if ( this.orbitObjectPattern ) {
- this.find( this.orbitObjectPattern, function( orbitObject ) {
- this.activeCameraComp.lookAt = orbitObject.id;
- this.updateRadius();
- } );
- }
- break;
- default:
- this.activeCameraComp.lookAt = "";
- break;
- }
- }
- }
- this.changeNavMode = function( state ) {
- if ( state == 1 ) {
- if ( this.navmode == "walk" ) this.navmode = "orbit";
- else if ( this.navmode == "orbit" ) this.navmode = "walk";
- }
- }
- this.raiseOrZoomIn = function( state ) {
- var active = this.input.futureActive();
- if ( this.navMode == "walk" ) {
- this.cameraZ( 1.0 );
- } else if ( this.navMode == "orbit" ) {
- this.zoom( true );
- }
- this.input.button1Down = state;
- if ( state && !active ) {
- this.future( 0.1 ).update();
- }
- }
- this.lowerOrZoomOut = function( state ) {
- var active = this.input.futureActive();
- if ( this.navMode == "walk" ) {
- this.cameraZ( -1.0 );
- } else if ( this.navMode == "orbit" ) {
- this.zoom( false );
- }
- this.input.button2Down = state;
- if ( state && !active ) {
- this.future( 0.1 ).update();
- }
- }
- this.pointerIsDown = function() {
- if ( this.input && this.input.pointerInfo ) {
- var bInfo = this.input.pointerInfo.buttons;
- if ( bInfo ) {
- return bInfo.left || bInfo.right || bInfo.middle;
- }
- }
- return false;
- }
- this.pointerDown = function( parms, pickInfo ){
- this.input.lastPointerInfo = undefined;
- this.input.pointerInfo = parms;
- this.input.lastPickInfo = undefined;
- this.input.pickInfo = pickInfo;
- this.input.pointerDownTime = this.time;
- this.input.lastInputTime = this.time;
- }
- this.pointerUp = function( parms, pickInfo ){
- this.input.lastPointerInfo = this.input.pointerInfo;
- this.input.pointerInfo = undefined;
- this.input.lastPickInfo = this.input.pickInfo;
- this.input.pickInfo = undefined;
- this.input.lastInputTime = this.time;
- }
- this.pointerMove = function( parms, pickInfo ){
- this.input.pointerEventTime = this.time;
- this.input.lastPointerInfo = this.input.pointerInfo;
- this.input.pointerInfo = parms;
- this.input.lastPickInfo = this.input.pickInfo;
- this.input.pickInfo = pickInfo;
-
- if ( this.pointerIsDown() /* && this.input.pointerEventTime - this.input.pointerDownTime > 6 */ ) {
- var active = this.input.futureActive();
- var delta = this.input.pointerDelta();
- var valid = this.navmode == "none" ? false : true;
- if ( valid && !active ) {
- this.future( 1/30 ).update();
- }
- }
- this.input.lastInputTime = this.time;
- }
- this.pointerOut = function( parms ){
- this.input.lastPointerInfo = this.input.pointerInfo;
- this.input.pointerInfo = undefined;
- this.input.lastPickInfo = this.input.pickInfo;
- this.input.pickInfo = undefined;
- this.input.lastInputTime = this.time;
- }
- this.pointerWheel = function( parms, pickInfo ) {
- this.input.pointerEventTime = this.time;
- this.input.lastPointerInfo = this.input.pointerInfo;
- this.input.pointerInfo = parms;
- this.input.lastPickInfo = this.input.pickInfo;
- this.input.pickInfo = pickInfo;
- if (!this.activeCameraComp) {
- this.getActiveCamera();
- }
- if ( this.activeCameraComp ) {
- var cameraPos = this.activeCameraComp.translation;
- var cameraAt = this.getCameraAt();
- if ( this.orbitRadius == -1 || this.input.pointerEventTime - this.input.lastUpdateTime > 0.5 ) {
- this.updateRadius();
- }
- cameraAt = goog.vec.Vec3.scale(
- cameraAt,
- this.input.pickInfo.wheel.deltaY * -1,
- cameraAt
- );
-
- if ( goog.vec.Vec3.magnitudeSquared( cameraAt ) > goog.vec.EPSILON ) {
- this.activeCameraComp.translation = goog.vec.Vec3.add(
- this.activeCameraComp.translation,
- goog.vec.Vec3.scale(
- goog.vec.Vec3.normalize( cameraAt, cameraAt ),
- this.distance(),
- cameraAt
- ),
- cameraAt
- );
- }
- }
- this.input.lastInputTime = this.time;
- }
- this.keyDown = function( parms ) {
- var active = this.input.futureActive();
- // capture the event input locally
- this.input.keyInfo = $.extend(true, {}, parms);;
- // store the current Time
- this.input.lastInputTime = this.time;
- // call future.update if update was not currently occurring
- if ( !active ) {
- this.future( 0.1 ).update();
- }
-
- }
- this.keyUp = function( parms ) {
- this.input.keyInfo = $.extend(true, {}, parms);
- if ( Object.keys( parms.keysDown ).length == 0 ){
- this.handleKeyDown();
- }
- this.input.lastInputTime = this.time;
- }
- this.handleKeyDown = function() {
- if (!this.activeCameraComp) {
- this.getActiveCamera();
- }
- if ( this.activeCameraComp ) {
- var deltaZ = 0;
- var kd = $.extend(true, {}, this.input.keyInfo.keysDown, this.input.keyInfo.keysUp);
- this.input.look = [ 0, 0 ];
- this.input.move = [ 0, 0 ];
-
- var temp;
- for ( var keyPress in kd ) {
- switch ( Number( kd[ keyPress ].code ) ) {
- case 87: //w
- case 38: //up
- this.input.move[1] += 1;
- break;
- case 83: //s
- case 40: //down
- this.input.move[1] += -1;
- break;
- case 37: // left
- case 65: //a
- this.input.move[0] += -1;
- break;
- case 39: // right
- case 68: //d
- this.input.move[0] += 1;
- break;
- case 81: // q
- this.input.look[0] += -1;
- break;
- case 69: // e
- this.input.look[0] += 1;
- break;
- case 90: // z
- temp = this.logger.enabled;
- this.logger.enabled = true;
- this.logger.info( "translation: [ " + Array.prototype.slice.call( this.activeCameraComp.translation ) + " ]" );
- this.logger.info( " quaternion: [ " + Array.prototype.slice.call( this.activeCameraComp.quaternion ) + " ]" );
- this.logger.info( " rotation: [ " + Array.prototype.slice.call( this.activeCameraComp.rotation ) + " ]" );
- this.logger.info( " transform: [ " + Array.prototype.slice.call( this.activeCameraComp.transform ) + " ]" );
- this.logger.info( " worldTransform: [ " + Array.prototype.slice.call( this.activeCameraComp.worldTransform ) + " ]" );
- this.logger.enabled = temp;
- break;
- case 88: // x
- break;
- case 82: // r
- deltaZ += 1.0;
- break;
- case 67: // c
- deltaZ += - 1.0;
- break;
- default:
- break;
- }
- }
- this.input.keyInfo.keysUp = {};
-
- if ( this.input.look[0] != 0 || this.input.look[1] != 0 ) {
- this.look( this.input.look[0], this.input.look[1] );
- }
- if ( this.input.move[0] != 0 || this.input.move[1] != 0 ) {
- this.move( this.input.move[0], this.input.move[1] );
- }
- if ( deltaZ != 0 ) {
- if ( this.navmode == "walk" ) {
- this.cameraZ( deltaZ );
- }
- }
-
- }
- }
- this.onMove = function( x, y ) {
- if ( Math.abs( x ) < 0.1 && Math.abs( y ) < 0.1 ) {
- if ( this.input.moveActive ) {
- this.input.moveActive = false;
- this.input.move = [ 0, 0 ];
- }
- return;
- }
- this.input.move = [ x, y ];
- var active = this.input.futureActive();
- if ( !this.input.moveActive ) {
- this.input.moveActive = true;
- this.move( x, y );
- }
- if ( !active ) {
- this.future( 0.1 ).update();
- }
- }
- this.move = function( x, y ) {
- if ( this.navmode == "walk" ) {
- this.translate( x, y );
- } else if ( this.navmode == "orbit" ) {
- this.orbit( x, y );
- }
- }
- this.onLook = function( x, y ) {
- if ( Math.abs( x ) < 0.1 && Math.abs( y ) < 0.1 ) {
- if ( this.input.lookActive ) {
- this.input.lookActive = false;
- this.input.look = [ 0, 0 ];
- }
- return;
- }
- this.input.look = [ x, y ];
- var active = this.input.futureActive();
- if ( !this.input.lookActive ) {
- this.input.lookActive = true;
- this.look( x, y );
- }
- if ( !active ) {
- this.future( 0.1 ).update();
- }
- }
- this.look = function( x, y ) {
- if (!this.activeCameraComp)
- this.getActiveCamera();
- if ( this.activeCameraComp ) {
- if ( this.input.pointerInfo && this.input.pointerInfo.modifiers.ctrl ) {
- if ( y != 0 ) { this.activeCameraComp.rotateBy( [ 1, 0, 0, -y * this.angularDistance() ], 0 ) }
- } else {
- if ( x != 0 ) { this.activeCameraComp.rotateBy( [ 0, 0, 1, -x * this.angularDistance() ], 0 ) }
- }
- }
- }
- this.zoom = function( dirIn ) {
- if (!this.activeCameraComp) {
- this.getActiveCamera();
- }
- if ( this.activeCameraComp ) {
- var camerapos = this.activeCameraComp.translation;
- var camerarot = this.getCameraAt();
-
- var yinc = 0;
- var xinc = 0;
- var zinc = 0;
- var speed = this.distance();
- if ( !dirIn ) speed = -speed;
- yinc = yinc + parseFloat( camerarot[1] ) * speed;
- xinc = xinc + parseFloat( camerarot[0] ) * speed;
- if ( this.orbitRadius == -1 || this.time - this.input.lastUpdateTime > 0.5 ) {
- this.updateRadius();
- }
-
- if ( xinc != 0 || yinc != 0 ) {
- var origX, origY, origZ;
- var x, y, z, atBounds = false;
-
- origX = camerapos[0];
- origY = camerapos[1];
- origZ = camerapos[2];
-
- x = origX + xinc * this.distance() * mult;
- y = origY + yinc * this.distance() * mult;
- z = origZ;
- var ratioHR = camerapos[2] / this.orbitRadius;
- zinc = Math.sqrt( Math.pow( x-origX, 2 ) + Math.pow( y-origY, 2 ) ) * ratioHR;
- if ( parms.wheelDeltaY > 0 ) zinc *= -1;
- z = origZ + zinc;
-
- this.activeCameraComp.translation = [ x, y, z ];
- }
- }
- }
- this.distance = function(){
- var dist = this.translationSpeed * 10 * this.timeElapsed();
- return dist;
- }
- this.angularDistance = function() {
- // Should take 4 seconds to go around 360 degrees
- var dist = this.rotationSpeed * 90 * this.timeElapsed();
- return dist;
- }
- this.cameraZ = function( dir ) {
- if (!this.activeCameraComp) this.getActiveCamera();
-
- if ( this.activeCameraComp ) {
- var pos = this.activeCameraComp.translation;
-
- this.activeCameraComp.translation = [ pos[0], pos[1], pos[2] + ( this.distance() * dir ) ];
- }
- }
- this.updateRadius = function() {
- var pos = this.activeCameraComp.translation || [ 1, 1, 1 ];
- var oldRadius = this.orbitRadius;
- // Assuming the orbit center is the origin, the radius is just the length of the line segment from the
- // origin to the active camera component
- this.orbitRadius = Math.sqrt( (pos[0] * pos[0]) + (pos[1] * pos[1]) + (pos[2] * pos[2]) );
- var dist2D = Math.sqrt( (pos[0] * pos[0]) + (pos[1] * pos[1]) );
-
- phi = Math.acos( pos[2] / this.orbitRadius );
- if ( 0 <= pos[0] ) theta = Math.asin( pos[1]/dist2D );
- else theta = Math.PI - Math.asin( pos[1]/dist2D );
- this.input.lastUpdateTime = this.time;
- }
- this.orbit = function( xDelta, yDelta ){
- if (!this.activeCameraComp) this.getActiveCamera();
- if ( this.activeCameraComp ) {
- this.updateRadius();
- var pixelToRadian = _2PI * this.angularDistance() / 360;
- var phiDelta = -yDelta * pixelToRadian;
- var thetaDelta = -xDelta * pixelToRadian;
-
- phi = phi - phiDelta;
- theta = theta - thetaDelta;
-
- if ( theta >= _2PI ) theta -= _2PI;
- else if ( theta < 0 ) theta += _2PI;
- if ( phi > _85 ) phi = _85;
- else if ( phi < _10 ) phi = _10;
-
- // Spherical to Cartesian
- var x = this.orbitRadius * Math.sin( phi ) * Math.cos( theta );
- var y = this.orbitRadius * Math.sin( phi ) * Math.sin( theta );
- var z = this.orbitRadius * Math.cos( phi );
- this.activeCameraComp.translation = [ x, y, z ];
- }
- }
- this.getCameraAt = function() {
- var camRotMat = this.activeCameraComp.rotationMatrix;
- return goog.vec.Vec3.createFromValues( camRotMat[4], camRotMat[5], camRotMat[6] );
- }
- this.getCameraUp = function() {
- var camRotMat = this.activeCameraComp.rotationMatrix;
- return goog.vec.Vec3.createFromValues( camRotMat[8], camRotMat[9], camRotMat[10] );
- }
- this.getCameraRight = function() {
- var camRotMat = this.activeCameraComp.rotationMatrix;
- return goog.vec.Vec3.createFromValues( camRotMat[0], camRotMat[1], camRotMat[2] );
- }
- this.getCameraVec = function( x, y, z ) {
- var camRotMat = this.activeCameraComp.rotationMatrix;
- var camAt = goog.vec.Mat4.multVec4(
- camRotMat,
- goog.vec.Vec4.createFromValues( x, y, z, 1 ),
- goog.vec.Vec3.create()
- );
- return camAt;
- }
- this.translate = function( x, y ) {
- if (!this.activeCameraComp)
- this.getActiveCamera();
- if ( this.activeCameraComp ) {
- var trans = this.getCameraVec( x, y, 0 );
- trans[2] = 0;
- if ( goog.vec.Vec3.magnitudeSquared( trans ) > goog.vec.EPSILON ) {
- // TODO: Clean this up - right now the two vectors are added together and both vectors are replaced
- // w/ the result. That's probably not the desired behavior.
- this.activeCameraComp.translation = goog.vec.Vec3.add(
- this.activeCameraComp.translation,
- goog.vec.Vec3.scale(
- goog.vec.Vec3.normalize( trans, trans ),
- this.distance(),
- trans
- ),
- trans
- );
- }
- }
- }
- this.update = function() {
- if ( this.input ) {
- var delta = this.input.pointerDelta();
- var pi = this.input.pointerInfo;
- if ( delta ) {
- if ( this.pointerIsDown() ) {
- if ( this.input.pointerInfo.buttons.left ) {
- var pi = this.input.pointerInfo;
- switch( this.navmode ) {
- case "orbit":
- this.orbit( delta[0], delta[1] );
- break;
- case "walk":
- if ( this.dragModeMove )
- this.move( (pi.position[0]*2.0)-1,(pi.position[1]*2.0)-1 );
- else
- this.look( (pi.position[0]*2.0)-1,(pi.position[1]*2.0)-1 );
- break;
- }
- }
- }
- if ( this.input.lookActive ) {
- this.look( (pi.position[0]*2.0)-1,(pi.position[1]*2.0)-1 );
- }
- if ( this.input.moveActive ) {
- this.move( (pi.position[0]*2.0)-1,(pi.position[1]*2.0)-1 );
- }
- }
- if ( this.input.keysAreDown() ) {
- this.handleKeyDown();
- }
- if ( this.input.button1Down ) {
- if ( this.navMode == "walk" ) {
- this.cameraZ( 1.0 );
- } else if ( this.navMode == "orbit" ) {
- this.zoom( true );
- }
- }
- if ( this.input.button2Down ) {
- if ( this.navMode == "walk" ) {
- this.cameraZ( -1.0 );
- } else if ( this.navMode == "orbit" ) {
- this.zoom( false );
- }
- }
- if ( this.input.futureActive() ) {
- this.future( 0.1 ).update();
- }
- }
- this.input.lastInputTime = this.time;
- } //@ sourceURL=navscene.vwf
|