diff --git a/support/client/lib/vwf.js b/support/client/lib/vwf.js index 36e3e758a..f6b369ee0 100644 --- a/support/client/lib/vwf.js +++ b/support/client/lib/vwf.js @@ -194,18 +194,6 @@ this.moniker_ = undefined; - /// Nodes that are receiving ticks. - /// - /// @name module:vwf.tickable - /// - /// @private - - this.tickable = { - // models: [], - // views: [], - nodeIDs: [], - }; - // == Private variables ==================================================================== /// @name module:vwf.private @@ -405,6 +393,7 @@ { library: "vwf/view/cesium", active: false }, { library: "vwf/view/kineticjs", active: false }, { library: "vwf/view/mil-sym", active: false }, + { library: "vwf/view/jiglib", active: false }, { library: "vwf/view/audio", active: false }, { library: "vwf/kernel/utility", active: true }, { library: "vwf/utility", active: true }, @@ -461,6 +450,7 @@ { library: "vwf/view/kineticjs", active: false }, { library: "vwf/view/mil-sym", active: false }, { library: "vwf/view/audio", active: false }, + { library: "vwf/view/jiglib", active: false }, { library: "vwf/view/webrtc", active: false} ] }; @@ -948,10 +938,11 @@ fields.origin = "reflector"; - // Update the queue. Messages in the queue are ordered by time, then by order of arrival. - // Time is only advanced if the message has no action, meaning it is a tick. + // Update the queue. Insert the message (unless it is only a time tick), and + // advance the queue's record of the current time. Messages in the queue are + // ordered by time, then by order of arrival. - queue.insert( fields, !fields.action ); // may invoke dispatch(), so call last before returning to the host + queue.insert( fields, true ); // may invoke dispatch(), so call last before returning to the host // Each message from the server allows us to move time forward. Parse the // timestamp from the message and call dispatch() to execute all queued @@ -1224,34 +1215,20 @@ // Advance time to the message time. - if ( this.now != fields.time ) { - this.sequence_ = undefined; // clear after the previous action - this.client_ = undefined; // clear after the previous action + if ( this.now !== fields.time ) { this.now = fields.time; this.tock(); } - // Perform the action. + // Set the per-action kernel globals. - if ( fields.action ) { // TODO: don't put ticks on the queue but just use them to fast-forward to the current time (requires removing support for passing ticks to the drivers and nodes) - this.sequence_ = fields.sequence; // note the message's queue sequence number for the duration of the action - this.client_ = fields.client; // ... and note the originating client - this.receive( fields.node, fields.action, fields.member, fields.parameters, fields.respond, fields.origin ); - } - else { - this.tick(); - } + this.sequence_ = fields.sequence; // note the message's queue sequence number for the duration of the action + this.client_ = fields.client; // ... and note the originating client - } + // Perform the action. - // Advance time to the most recent time received from the server. Tick if the time - // changed. + this.receive( fields.node, fields.action, fields.member, fields.parameters, fields.respond, fields.origin ); - if ( queue.ready() && this.now != queue.time ) { - this.sequence_ = undefined; // clear after the previous action - this.client_ = undefined; // clear after the previous action - this.now = queue.time; - this.tock(); } }; @@ -1279,24 +1256,12 @@ this.tick = function() { - // Call ticking() on each model. - - this.models.forEach( function( model ) { - model.ticking && model.ticking( this.now ); // TODO: maintain a list of tickable models and only call those - }, this ); - // Call ticked() on each view. this.views.forEach( function( view ) { view.ticked && view.ticked( this.now ); // TODO: maintain a list of tickable views and only call those }, this ); - // Call tick() on each tickable node. - - this.tickable.nodeIDs.forEach( function( nodeID ) { - this.callMethod( nodeID, "tick", [ this.now ] ); - }, this ); - }; // -- tock --------------------------------------------------------------------------------- @@ -2708,13 +2673,8 @@ if ( ! childComponent.source ) { vwf.setProperty( childID, propertyName, deferredInitializations[propertyName] ); } ); - // TODO: Adding the node to the tickable list here if it contains a tick() function in JavaScript at initialization time. Replace with better control of ticks on/off and the interval by the node. - - if ( vwf.execute( childID, "Boolean( this.tick )" ) ) { - vwf.tickable.nodeIDs.push( childID ); - } - // Restore kernel reentry. + replicating && vwf.models.kernel.enable(); }, function() { @@ -5400,7 +5360,7 @@ if ( ! childComponent.source ) { // reinserted. return object.filter( function( fields ) { - return ! ( fields.origin === "reflector" && fields.sequence > vwf.sequence_ ) && fields.action; // TODO: fields.action is here to filter out tick messages // TODO: don't put ticks on the queue but just use them to fast-forward to the current time (requires removing support for passing ticks to the drivers and nodes) + return ! ( fields.origin === "reflector" && fields.sequence > vwf.sequence_ ); } ).sort( function( fieldsA, fieldsB ) { return fieldsA.sequence - fieldsB.sequence; } ); @@ -5408,8 +5368,8 @@ if ( ! childComponent.source ) { } else if ( depth == 1 ) { // Remove the sequence fields since they're just local annotations used to keep - // messages ordered by insertion order and aren't directly meaniful outside of this - // client. + // messages ordered by insertion order. They aren't directly meaningful outside of + // this client. var filtered = {}; @@ -6832,12 +6792,10 @@ if ( ! childComponent.source ) { messages.forEach( function( fields ) { - // if ( fields.action ) { // TODO: don't put ticks on the queue but just use them to fast-forward to the current time (requires removing support for passing ticks to the drivers and nodes) - + if ( fields.action ) { fields.sequence = ++this.sequence; // track the insertion order for use as a sort key this.queue.push( fields ); - - // } + } if ( chronic ) { this.time = Math.max( this.time, fields.time ); // save the latest allowed time for suspend/resume @@ -6868,6 +6826,21 @@ if ( ! childComponent.source ) { } ); + // Tick the views on each idle message. + + if ( chronic && ! fields.action ) { + + // Clear the per-action kernel globals. `tick` isn't an action. + + vwf.sequence_ = undefined; + vwf.client_ = undefined; + + // Tick the views. + + vwf.tick(); + + } + // Execute the simulation through the new time. // To prevent actions from executing out of order, callers should immediately return diff --git a/support/client/lib/vwf/model/blockly.js b/support/client/lib/vwf/model/blockly.js index 5bdea9eac..7e1a2026b 100644 --- a/support/client/lib/vwf/model/blockly.js +++ b/support/client/lib/vwf/model/blockly.js @@ -23,7 +23,9 @@ define( [ "module", "vwf/model", "vwf/utility", ], function( module, model, utility, acorn, Blockly ) { - var self; + var modelDriver; + var updateTime = -0.05; + var startUpdate = false; return model.load( module, { @@ -33,13 +35,13 @@ define( [ "module", "vwf/model", "vwf/utility", initialize: function( options ) { - self = this; + modelDriver = this; this.arguments = Array.prototype.slice.call( arguments ); - if ( options === undefined ) { - options = {}; - } + this.options = options || {}; + + updateTime = this.options.updateTime || -0.05; this.state = { "nodes": {}, @@ -138,6 +140,13 @@ define( [ "module", "vwf/model", "vwf/utility", this.logger.infox( "initializingNode", nodeID, childID, childExtendsID, childImplementsIDs, childSource, childType, childName ); } + var appID = this.kernel.application(); + if ( childID === appID ) { + if ( !startUpdate ) { + this.kernel.callMethod( appID, "update", [], updateTime ); + startUpdate = true; + } + } }, @@ -308,13 +317,14 @@ define( [ "module", "vwf/model", "vwf/utility", // -- callingMethod -------------------------------------------------------------------------- callingMethod: function( nodeID, methodName /* [, parameter1, parameter2, ... ] */ ) { // TODO: parameters + var appID = this.kernel.application(); var node = this.state.nodes[ nodeID ]; if ( this.debug.methods ) { this.logger.infox( " M === callingMethod ", nodeID, methodName ); } - if ( nodeID == this.kernel.application() ) { + if ( nodeID == appID ) { switch ( methodName ) { @@ -333,6 +343,11 @@ define( [ "module", "vwf/model", "vwf/utility", } break; + case "update": + executeBlocks(); + this.kernel.callMethod( appID, "update", [], updateTime ); + break; + } } else if ( node !== undefined ) { @@ -346,7 +361,7 @@ define( [ "module", "vwf/model", "vwf/utility", break; } } - }, + } // TODO: creatingEvent, deltetingEvent, firingEvent @@ -357,45 +372,6 @@ define( [ "module", "vwf/model", "vwf/utility", // return undefined; //}, - // == ticking ============================================================================= - - ticking: function( vwfTime ) { - - if ( this.state.executingBlocks !== undefined ) { - var blocklyNode = undefined; - - for ( var nodeID in this.state.executingBlocks ) { - - blocklyNode = this.state.executingBlocks[ nodeID ]; - var executeNextLine = false; - - if ( blocklyNode.interpreter === undefined || - blocklyNode.interpreterStatus === "completed" ) { - blocklyNode.interpreter = createInterpreter( acorn, blocklyNode.code ); - blocklyNode.interpreterStatus = "created"; - blocklyNode.lastLineExeTime = vwfTime; - executeNextLine = true; - } else { - var elaspedTime = vwfTime - blocklyNode.lastLineExeTime; - if ( elaspedTime >= blocklyNode.timeBetweenLines ) { - executeNextLine = true; - blocklyNode.lastLineExeTime = vwfTime; - } - } - - if ( executeNextLine ) { - - self.state.executionHalted = false; - - nextStep( blocklyNode ); - - this.kernel.fireEvent( nodeID, "blocklyExecuted", [ blocklyNode.interpreter.value ] ); - } - } - } - - } - } ); function getPrototypes( extendsID ) { @@ -404,14 +380,14 @@ define( [ "module", "vwf/model", "vwf/utility", while ( id !== undefined ) { prototypes.push( id ); - id = self.kernel.prototype( id ); + id = modelDriver.kernel.prototype( id ); } return prototypes; } function isBlockly3Node( nodeID ) { - return self.kernel.test( nodeID, + return modelDriver.kernel.test( nodeID, "self::element(*,'http://vwf.example.com/blockly/controller.vwf')", nodeID ); } @@ -426,6 +402,43 @@ define( [ "module", "vwf/model", "vwf/utility", return found; } + function executeBlocks() { + + if ( modelDriver.state.executingBlocks !== undefined ) { + var blocklyNode = undefined; + + for ( var nodeID in modelDriver.state.executingBlocks ) { + + blocklyNode = modelDriver.state.executingBlocks[ nodeID ]; + var executeNextLine = false; + + if ( blocklyNode.interpreter === undefined || + blocklyNode.interpreterStatus === "completed" ) { + blocklyNode.interpreter = createInterpreter( acorn, blocklyNode.code ); + blocklyNode.interpreterStatus = "created"; + blocklyNode.lastLineExeTime = vwfTime; + executeNextLine = true; + } else { + var elaspedTime = vwfTime - blocklyNode.lastLineExeTime; + if ( elaspedTime >= blocklyNode.timeBetweenLines ) { + executeNextLine = true; + blocklyNode.lastLineExeTime = vwfTime; + } + } + + if ( executeNextLine ) { + + modelDriver.state.executionHalted = false; + + nextStep( blocklyNode ); + + modelDriver.kernel.fireEvent( nodeID, "blocklyExecuted", [ blocklyNode.interpreter.value ] ); + } + } + } + + } + function getJavaScript( node ) { var xml = Blockly.Xml.workspaceToDom( Blockly.getMainWorkspace() ); @@ -459,10 +472,10 @@ define( [ "module", "vwf/model", "vwf/utility", if ( node.interpreter !== undefined ) { var stepType = node.interpreter.step(); - while ( stepType && !self.state.executionHalted ) { + while ( stepType && !modelDriver.state.executionHalted ) { if ( stepType === "stepProgram" ) { if ( node.interpreterStatus === "created" ) { - self.kernel.fireEvent( node.ID, "blocklyStarted", [ true ] ); + modelDriver.kernel.fireEvent( node.ID, "blocklyStarted", [ true ] ); node.interpreterStatus = "started"; } } @@ -470,8 +483,8 @@ define( [ "module", "vwf/model", "vwf/utility", } if ( stepType === false ) { if ( node.interpreterStatus === "started" ) { - self.kernel.setProperty( node.ID, "blockly_executing", false ); - self.kernel.fireEvent( node.ID, "blocklyStopped", [ true ] ); + modelDriver.kernel.setProperty( node.ID, "blockly_executing", false ); + modelDriver.kernel.fireEvent( node.ID, "blocklyStopped", [ true ] ); node.interpreterStatus = "completed"; } } @@ -495,7 +508,7 @@ define( [ "module", "vwf/model", "vwf/utility", for ( var j = 0; j < arguments.length; j++) { parms.push( arguments[ j ].toString() ); } - self.state.executionHalted = true; + modelDriver.state.executionHalted = true; return interpreter.createPrimitive( nativeFunc.apply( vwf, parms ) ); }; } )( vwf[ vwfKernelFunctions[ i ] ] ); @@ -516,7 +529,7 @@ define( [ "module", "vwf/model", "vwf/utility", parms.push( arguments[ j ].toString() ); } } - self.state.executionHalted = true; + modelDriver.state.executionHalted = true; return interpreter.createPrimitive( nativeFunc.apply( vwf, parms ) ); }; } )( vwf[ vwfKernelFunctions[ i ] ] ); diff --git a/support/client/lib/vwf/model/buzz.js b/support/client/lib/vwf/model/buzz.js index c0c010feb..ae175b85b 100644 --- a/support/client/lib/vwf/model/buzz.js +++ b/support/client/lib/vwf/model/buzz.js @@ -394,7 +394,7 @@ define( [ } - }, + } // TODO: creatingEvent, deltetingEvent, firingEvent @@ -405,13 +405,6 @@ define( [ // return undefined; // }, - // == ticking ============================================================================= - - // ticking: function( vwfTime ) { - - // } - - } ); diff --git a/support/client/lib/vwf/model/cesium.js b/support/client/lib/vwf/model/cesium.js index d47a142dd..7b912cd53 100644 --- a/support/client/lib/vwf/model/cesium.js +++ b/support/client/lib/vwf/model/cesium.js @@ -1966,7 +1966,7 @@ define( [ "module", } return value; - }, + } // TODO: deletingMethod @@ -1986,8 +1986,6 @@ define( [ "module", // return undefined; //}, - // == ticking ============================================================================= - } ); // == PRIVATE ======================================================================================== diff --git a/support/client/lib/vwf/model/glge.js b/support/client/lib/vwf/model/glge.js index 137175fa0..d6c1550d6 100644 --- a/support/client/lib/vwf/model/glge.js +++ b/support/client/lib/vwf/model/glge.js @@ -802,7 +802,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili return value; - }, + } // TODO: deletingMethod @@ -822,10 +822,6 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili // return undefined; // }, - // == ticking ============================================================================= - -// ticking: function( vwfTime ) { -// }, } ); diff --git a/support/client/lib/vwf/model/jiglib.js b/support/client/lib/vwf/model/jiglib.js index d6c85dedf..b8290642c 100644 --- a/support/client/lib/vwf/model/jiglib.js +++ b/support/client/lib/vwf/model/jiglib.js @@ -16,7 +16,9 @@ /// @module vwf/model/jiglib /// @requires vwf/model -define( [ "module", "vwf/model" ], function( module, model ) { +define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utility ) { + + var modelDriver; return model.load( module, { @@ -26,13 +28,29 @@ define( [ "module", "vwf/model" ], function( module, model ) { initialize: function() { - this.nodes = {}; // maps id => { property: value, ... } - this.scenes = {}; - this.active = {}; - this.enabled = false; - this.lastTime = 0; - this.delayedProperties = {}; - this.updating = false; + modelDriver = this; + + this.state = { + "nodes": {}, + "scenes": {}, + "active": {}, + "enabled": false, + "delayedProperties": {}, + "updating": false + } + + // turns on logger debugger console messages + this.debug = { + "creation": false, + "initializing": false, + "parenting": false, + "deleting": false, + "properties": false, + "setting": false, + "getting": false, + "prototypes": false, + "loading": false + }; }, @@ -44,40 +62,41 @@ define( [ "module", "vwf/model" ], function( module, model ) { childSource, childType, childIndex, childName, callback /* ( ready ) */) { var kernel = this.kernel; - //this.logger.enable = true; - //this.logger.infox( "creatingNode", nodeID, childID, childExtendsID, childImplementsIDs, - // childSource, childType, childIndex, childName ); - //this.logger.enabled = false; + + if ( this.debug.creation ) { + this.logger.infox( "creatingNode", nodeID, childID, childExtendsID, childImplementsIDs, childSource, childType, childName ); + } if ( childExtendsID && this.kernel.test( childExtendsID, "self::element(*,'http://vwf.example.com/scene.vwf')", childExtendsID ) ) { - this.scenes[ childID ] = {}; - this.scenes[ childID ].ID = childID; - this.scenes[ childID ].extendsID = childExtendsID; - this.scenes[ childID ].implementsIDs = childImplementsIDs; - this.scenes[ childID ].source = childSource; - this.scenes[ childID ].type = childType; - this.scenes[ childID ].system = jigLib.PhysicsSystem.getInstance(); - this.scenes[ childID ].initialized = false; - this.scenes[ childID ].propertyMap = {}; - + this.state.scenes[ childID ] = { + "ID": childID, + "extendsID": childExtendsID, + "implementsIDs": childImplementsIDs, + "source": childSource, + "type": childType, + "system": jigLib.PhysicsSystem.getInstance(), + "initialized": false, + "propertyMap": {} + }; } else { - switch ( childExtendsID && this.kernel.uri( childExtendsID ) ) { + switch ( childExtendsID && this.kernel.uri( childExtendsID ) ) { case "http://vwf.example.com/physics3.vwf": case "http://vwf.example.com/node3.vwf": case "http://vwf.example.com/mesh.vwf": - this.nodes[ childID ] = {}; - this.nodes[ childID ].sceneID = this.kernel.application(); - this.nodes[ childID ].name = childName; - this.nodes[ childID ].ID = childID; - this.nodes[ childID ].parentID = nodeID; - this.nodes[ childID ].extendsID = childExtendsID; - this.nodes[ childID ].implementsIDs = childImplementsIDs; - this.nodes[ childID ].source = childSource; - this.nodes[ childID ].type = childType; - + this.state.nodes[ childID ] = { + "sceneID": this.kernel.application(), + "name": childName, + "ID": childID, + "parentID": nodeID, + "extendsID": childExtendsID, + "implementsIDs": childImplementsIDs, + "source": childSource, + "type": childType + }; + break; } } @@ -90,14 +109,18 @@ define( [ "module", "vwf/model" ], function( module, model ) { initializingNode: function( nodeID, childID ) { - var scene = this.scenes[ childID ]; - var node = this.nodes[ childID ]; + var scene = this.state.scenes[ childID ]; + var node = this.state.nodes[ childID ]; + + if ( this.debug.initializing ) { + this.logger.infox( "initializingNode", nodeID, childID, childExtendsID, childImplementsIDs, childSource, childType, childName ); + } if ( scene && scene.system ) { if ( !scene.initialized ) { initializeScene.call( this, scene ); } - this.enabled = true; + this.state.enabled = true; } else if ( node ) { if ( node.jigLibObj && node.jigLibInternals ) { @@ -129,13 +152,17 @@ define( [ "module", "vwf/model" ], function( module, model ) { deletingNode: function( nodeID ) { - if ( this.active[ nodeID ] ) { - delete this.active[ nodeID ]; + if ( this.debug.deleting ) { + this.logger.infox( "deletingNode", nodeID ); + } + + if ( this.state.active[ nodeID ] ) { + delete this.state.active[ nodeID ]; } - if ( this.nodes[ nodeID ] ) { - var node = this.nodes[ nodeID ]; - var scene = this.scenes[ node.sceneID ]; + if ( this.state.nodes[ nodeID ] ) { + var node = this.state.nodes[ nodeID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( node.jigLibObj ) { if ( node.jigLibObj ) { if ( scene ) scene.system.removeBody( node.jigLibObj ); @@ -148,7 +175,7 @@ define( [ "module", "vwf/model" ], function( module, model ) { } node.jigLibMeshes = undefined; } - delete this.nodes[ nodeID ]; + delete this.state.nodes[ nodeID ]; } }, @@ -171,6 +198,9 @@ define( [ "module", "vwf/model" ], function( module, model ) { // -- creatingProperty --------------------------------------------------------------------- creatingProperty: function( nodeID, propertyName, propertyValue ) { + if ( this.debug.properties ) { + this.logger.infox( "C === creatingProperty ", nodeID, propertyName, propertyValue ); + } return this.initializingProperty( nodeID, propertyName, propertyValue ); }, @@ -179,14 +209,15 @@ define( [ "module", "vwf/model" ], function( module, model ) { initializingProperty: function( nodeID, propertyName, propertyValue ) { var value = undefined; - //this.logger.enabled = true; - //this.logger.infox( "creatingProperty", nodeID, propertyName, propertyValue ); - //this.logger.enabled = false; + + if ( this.debug.properties ) { + this.logger.infox( " I === initializingProperty ", nodeID, propertyName, propertyValue ); + } if ( !( propertyValue === undefined ) ) { - var node = this.nodes[ nodeID ]; + var node = this.state.nodes[ nodeID ]; if ( node ) { - var scene = this.scenes[ node.sceneID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( scene && !scene.initialized ) { var pm; if ( !scene.propertyMap[ nodeID ] ) { @@ -204,25 +235,25 @@ define( [ "module", "vwf/model" ], function( module, model ) { } else { if ( propertyName == "physics" ) { this.settingProperty( nodeID, propertyName, propertyValue ); - if ( this.delayedProperties[ nodeID ] ) { + if ( this.state.delayedProperties[ nodeID ] ) { var propValue; - for ( propName in this.delayedProperties[ nodeID ] ) { - propValue = this.delayedProperties[ nodeID ][ propName ]; + for ( propName in this.state.delayedProperties[ nodeID ] ) { + propValue = this.state.delayedProperties[ nodeID ][ propName ]; this.settingProperty( nodeID, propName, propValue ); } - delete this.delayedProperties[ nodeID ]; + delete this.state.delayedProperties[ nodeID ]; } } else { - if ( !this.delayedProperties[ nodeID ] ) { - this.delayedProperties[ nodeID ] = {}; + if ( !this.state.delayedProperties[ nodeID ] ) { + this.state.delayedProperties[ nodeID ] = {}; } - this.delayedProperties[ nodeID ][ propertyName ] = propertyValue; + this.state.delayedProperties[ nodeID ][ propertyName ] = propertyValue; } } } } else { - var scene = this.scenes[ nodeID ]; + var scene = this.state.scenes[ nodeID ]; if ( scene ) { this.settingProperty( nodeID, propertyName, propertyValue ); } @@ -240,10 +271,14 @@ define( [ "module", "vwf/model" ], function( module, model ) { var value = undefined; - if ( propertyValue === undefined ) + if ( ( this.debug.properties || this.debug.setting ) && ( propertyName !== "transform" ) ) { + this.logger.infox( " S === settingProperty ", nodeID, propertyName, propertyValue ); + } + + if ( !utility.validObject( propertyValue ) ) return value; - if ( this.updating ) { + if ( this.state.updating ) { switch ( propertyName ) { case "transform": return; @@ -251,13 +286,13 @@ define( [ "module", "vwf/model" ], function( module, model ) { } } - var activeNode = this.active[ nodeID ]; - var node = this.nodes[ nodeID ]; - var scene = this.scenes[ nodeID ]; + var activeNode = this.state.active[ nodeID ]; + var node = this.state.nodes[ nodeID ]; + var scene = this.state.scenes[ nodeID ]; if ( node && node.jigLibObj ) { - scene = this.scenes[ node.sceneID ]; + scene = this.state.scenes[ node.sceneID ]; switch ( propertyName ) { case "transform": if ( activeNode && activeNode.jlObj ) { @@ -308,7 +343,7 @@ define( [ "module", "vwf/model" ], function( module, model ) { break; } } else if ( node && !scene ) { - scene = this.scenes[ node.sceneID ]; + scene = this.state.scenes[ node.sceneID ]; if ( propertyName == "physics" ) { if ( scene && scene.system && propertyValue ) { var type = ( propertyValue.constructor == Array ) ? propertyValue[0] : propertyValue; @@ -331,21 +366,21 @@ define( [ "module", "vwf/model" ], function( module, model ) { } } - if ( this.delayedProperties[nodeID] ) { - var props = this.delayedProperties[nodeID]; + if ( this.state.delayedProperties[nodeID] ) { + var props = this.state.delayedProperties[nodeID]; for ( var propName in props ) { this.settingProperty( nodeID, propName, props[propName] ); } - delete this.delayedProperties[nodeID]; + delete this.state.delayedProperties[nodeID]; } } else { if ( node ) { var propArray; - if ( !this.delayedProperties[nodeID] ) { - this.delayedProperties[nodeID] = {}; + if ( !this.state.delayedProperties[nodeID] ) { + this.state.delayedProperties[nodeID] = {}; } - propArray = this.delayedProperties[nodeID]; + propArray = this.state.delayedProperties[nodeID]; propArray[ propertyName ] = propertyValue; } @@ -383,8 +418,12 @@ define( [ "module", "vwf/model" ], function( module, model ) { propertyValue = undefined; - if ( this.nodes[ nodeID ] ) { - var node = this.nodes[ nodeID ]; + if ( this.debug.properties || this.debug.getting ) { + this.logger.infox( " G === gettingProperty ", nodeID, propertyName ); + } + + if ( this.state.nodes[ nodeID ] ) { + var node = this.state.nodes[ nodeID ]; if ( node && node.jigLibObj ) { switch ( propertyName ) { case "physics": @@ -436,8 +475,8 @@ define( [ "module", "vwf/model" ], function( module, model ) { break; } } - } else if ( this.scenes[ nodeID ] ) { - var sceneNode = this.scenes[ nodeID ]; + } else if ( this.state.scenes[ nodeID ] ) { + var sceneNode = this.state.scenes[ nodeID ]; if ( sceneNode && sceneNode.system ) { switch ( propertyName ) { case "gravity": @@ -462,8 +501,20 @@ define( [ "module", "vwf/model" ], function( module, model ) { // -- callingMethod ------------------------------------------------------------------------ - //callingMethod: function( nodeID, methodName, methodParameters ) { - //}, + callingMethod: function( nodeID, methodName, methodParameters ) { + + var sceneID = this.kernel.application(); + if ( nodeID === sceneID ) { + switch ( methodName ) { + + case "update": + updateScene( 0.05 ); + this.kernel.callMethod( sceneID, "update", [], -0.05 ); + break; + + } + } + } // -- creatingEvent ------------------------------------------------------------------------ @@ -482,35 +533,6 @@ define( [ "module", "vwf/model" ], function( module, model ) { // return undefined; //}, - // == ticking ============================================================================= - - ticking: function( vwfTime ) { - - var elaspedTime = vwfTime - this.lastTime; - this.lastTime = vwfTime; - - if ( this.enabled ) { - if ( elaspedTime > 0 ) { - if (elaspedTime > 0.05) elaspedTime = 0.05; - var activeObj, posRotProp, pos, rot, posRot; - var sceneNode = this.scenes[this.kernel.application()]; - - if ( sceneNode && sceneNode.system ) { - sceneNode.system.integrate( elaspedTime ); - this.updating = true; - for ( var nodeID in this.active ) { - activeObj = this.active[nodeID]; - if ( activeObj && activeObj.jlObj ) { - var trans = activeObj.jlObj.get_Transform(); - this.kernel.setProperty( nodeID, "transform", trans ); - } - } - this.updating = false; - } - } - } - }, - } ); // == Private functions ================================================================== @@ -537,9 +559,9 @@ define( [ "module", "vwf/model" ], function( module, model ) { function createJBox( nodeID, scale, def ) { - var node = this.nodes[ nodeID ]; + var node = this.state.nodes[ nodeID ]; if ( node ) { - var scene = this.scenes[ node.sceneID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( scene ) { var v1, v2; var width = 1; @@ -569,9 +591,9 @@ define( [ "module", "vwf/model" ], function( module, model ) { if ( node.jigLibObj ) { scene.system.addBody( node.jigLibObj ); if ( pos ) node.jigLibObj.moveTo( [ pos[0], pos[1], pos[2] ] ); - this.active[ nodeID ] = {}; - this.active[ nodeID ].jlObj = node.jigLibObj; - this.active[ nodeID ].offset = offset; + this.state.active[ nodeID ] = {}; + this.state.active[ nodeID ].jlObj = node.jigLibObj; + this.state.active[ nodeID ].offset = offset; } } } @@ -582,9 +604,9 @@ define( [ "module", "vwf/model" ], function( module, model ) { function createJSphere( nodeID, scale, def ) { - var node = this.nodes[ nodeID ]; + var node = this.state.nodes[ nodeID ]; if ( node ) { - var scene = this.scenes[ node.sceneID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( scene ) { var v1, v2; var verts = this.kernel.getProperty( nodeID, "vertices" ); @@ -619,10 +641,10 @@ define( [ "module", "vwf/model" ], function( module, model ) { node.jigLibObj = new jigLib.JSphere( null, raduis ); if ( node.jigLibObj ) { scene.system.addBody( node.jigLibObj ); - if ( pos ) node.jigLibObj.moveTo( [ pos[0], pos[1], pos[2] ] ); - this.active[ nodeID ] = {}; - this.active[ nodeID ].jlObj = node.jigLibObj; - this.active[ nodeID ].offset = this.kernel.getProperty( nodeID, "centerOffset" ) || [ 0, 0, 0 ]; + if ( pos ) node.jigLibObj.moveTo( [ pos[0], pos[1], pos[2] ] ); + this.state.active[ nodeID ] = {}; + this.state.active[ nodeID ].jlObj = node.jigLibObj; + this.state.active[ nodeID ].offset = this.kernel.getProperty( nodeID, "centerOffset" ) || [ 0, 0, 0 ]; } } } @@ -634,9 +656,9 @@ define( [ "module", "vwf/model" ], function( module, model ) { function createJMesh( nodeID, scale ) { - var node = this.nodes[ nodeID ]; + var node = this.state.nodes[ nodeID ]; if ( node ) { - var scene = this.scenes[ node.sceneID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( scene ) { if ( node.jigLibMeshes ) { for ( var j = 0; j < node.jigLibMeshes.length; j++ ) { @@ -678,13 +700,13 @@ define( [ "module", "vwf/model" ], function( module, model ) { function createJPlane( nodeID, physicsDef ) { - var node = this.nodes[ nodeID ]; + var node = this.state.nodes[ nodeID ]; if ( node ) { - var scene = this.scenes[ node.sceneID ]; + var scene = this.state.scenes[ node.sceneID ]; if ( scene ) { var normal = [0, 0, 1, 0]; - - var pos = this.kernel.getProperty( nodeID, "translation" )|| [ 0, 0, 0 ]; + + var pos = this.kernel.getProperty( nodeID, "translation" )|| [ 0, 0, 0 ]; if ( physicsDef.constructor == Array ) { switch ( physicsDef.length ) { case 2: @@ -709,7 +731,7 @@ define( [ "module", "vwf/model" ], function( module, model ) { node.jigLibObj = new jigLib.JPlane( null, normal ); scene.system.addBody( node.jigLibObj ); - if ( pos ) node.jigLibObj.moveTo( [ pos[0], pos[1], pos[2] ] ); + if ( pos ) node.jigLibObj.moveTo( [ pos[0], pos[1], pos[2] ] ); } } } @@ -747,6 +769,7 @@ define( [ "module", "vwf/model" ], function( module, model ) { } scene.propertyMap = {}; scene.initialized = true; + this.kernel.callMethod( this.kernel.application(), "update", [], -0.05 ) } // == initializeObject =================================================================== @@ -812,4 +835,35 @@ define( [ "module", "vwf/model" ], function( module, model ) { } } + // == updateScene =================================================================== + + function updateScene( elaspedTime ) { + + if ( modelDriver.state.enabled ) { + + var activeObj, trans; + var sceneNode = modelDriver.state.scenes[ modelDriver.kernel.application() ]; + + if ( sceneNode && sceneNode.system ) { + sceneNode.system.integrate( elaspedTime ); + + var activeKeys = Object.keys( modelDriver.state.active ); + if ( activeKeys !== undefined ) { + modelDriver.state.updating = true; + for ( var i = 0; i < activeKeys.length; i++ ) { + activeObj = modelDriver.state.active[ activeKeys[ i ] ]; + if ( activeObj && activeObj.jlObj ) { + trans = activeObj.jlObj.get_Transform(); + modelDriver.kernel.setProperty( activeKeys[ i ], "transform", trans ); + } + } + modelDriver.state.updating = false; + } + + } + + } + } + + } ); diff --git a/support/client/lib/vwf/model/kineticjs.js b/support/client/lib/vwf/model/kineticjs.js index dd7f3bdaf..d08eedaad 100644 --- a/support/client/lib/vwf/model/kineticjs.js +++ b/support/client/lib/vwf/model/kineticjs.js @@ -2062,18 +2062,18 @@ define( [ "module", } return value; - }, + } // TODO: deletingMethod // -- callingMethod -------------------------------------------------------------------------- - callingMethod: function( nodeID, methodName, methodParameters, methodValue ) { - if ( this.debug.methods ) { - this.logger.infox( " M === callingMethod ", nodeID, methodName ); - } - }, + // callingMethod: function( nodeID, methodName, methodParameters, methodValue ) { + // if ( this.debug.methods ) { + // this.logger.infox( " M === callingMethod ", nodeID, methodName ); + // } + // }, // -- executing ------------------------------------------------------------------------------ @@ -2081,9 +2081,6 @@ define( [ "module", // return undefined; // }, - // ticking: function( vwfTime ) { - // } - } ); // == PRIVATE ======================================================================================== diff --git a/support/client/lib/vwf/model/mil-sym.js b/support/client/lib/vwf/model/mil-sym.js index f30941d0e..4566ea477 100644 --- a/support/client/lib/vwf/model/mil-sym.js +++ b/support/client/lib/vwf/model/mil-sym.js @@ -403,7 +403,7 @@ define( [ "module", } return value; - }, + } // TODO: creatingEvent, deltetingEvent, firingEvent @@ -414,14 +414,6 @@ define( [ "module", // return undefined; // }, - // == ticking ============================================================================= - - // ticking: function( vwfTime ) { - - // } - - - } ); function getPrototypes( extendsID ) { diff --git a/support/client/lib/vwf/model/threejs.js b/support/client/lib/vwf/model/threejs.js index 2c16019b8..d50b5fc4b 100644 --- a/support/client/lib/vwf/model/threejs.js +++ b/support/client/lib/vwf/model/threejs.js @@ -59,7 +59,6 @@ define( [ "module", var self; var checkLights = true; - var sceneCreated = false; return model.load( module, { @@ -73,8 +72,9 @@ define( [ "module", checkCompatibility.call(this); - this.state.scenes = {}; // id => { glgeDocument: new GLGE.Document(), glgeRenderer: new GLGE.Renderer(), glgeScene: new GLGE.Scene() } - this.state.nodes = {}; // id => { name: string, glgeObject: GLGE.Object, GLGE.Collada, GLGE.Light, or other...? } + this.state.scenes = {}; + this.state.nodes = {}; + this.state.animatedNodes = {}; this.state.prototypes = {}; this.state.kernel = this.kernel.kernel.kernel; this.state.lights = {}; @@ -110,7 +110,8 @@ define( [ "module", "properties": false, "setting": false, "getting": false, - "prototypes": false + "prototypes": false, + "loading": false }; }, @@ -180,13 +181,13 @@ define( [ "module", var kernel = this.kernel.kernel.kernel; var protos = getPrototypes.call( this, kernel, childExtendsID ); - if ( isSceneDefinition.call(this, protos) && childID == this.kernel.application() ) + if ( isSceneDefinition.call(this, protos) && childID == appID ) { var sceneNode = CreateThreeJSSceneNode( nodeID, childID, childExtendsID ); this.state.scenes[ childID ] = sceneNode; this.state.cameraInUse = sceneNode.camera.defaultCamera; - sceneCreated = true; + createDefaultLighting.call( this, sceneLights.call( this ) ); if ( childImplementsIDs && childImplementsIDs.length > 0 ) { for ( var i = 0; i < childImplementsIDs.length; i++ ) { @@ -2704,29 +2705,16 @@ define( [ "module", } return undefined; - }, + } // TODO: creatingEvent, deltetingEvent, firingEvent // -- executing ------------------------------------------------------------------------------ - executing: function( nodeID, scriptText, scriptType ) { - return undefined; - }, - - // == ticking ============================================================================= - - ticking: function( vwfTime ) { - - if ( checkLights && this.state.appInitialized && sceneCreated ) { - - var lightsInScene = sceneLights.call( this ); - - createDefaultLighting.call( this, lightsInScene ); - checkLights = false; - } - } + // executing: function( nodeID, scriptText, scriptType ) { + // return undefined; + // } } ); @@ -2735,7 +2723,7 @@ define( [ "module", function checkCompatibility() { this.compatibilityStatus = { compatible:true, errors:{} } var contextNames = ["webgl","experimental-webgl","moz-webgl","webkit-3d"]; - for(var i = 0; i < contextNames.length; i++){ + for( var i = 0; i < contextNames.length; i++){ try{ var canvas = document.createElement('canvas'); var gl = canvas.getContext(contextNames[i]); @@ -3547,7 +3535,10 @@ define( [ "module", var threeModel = this; var sceneNode = this.state.scenes[ this.kernel.application() ]; var parentObject3 = parentNode.threeObject ? parentNode.threeObject : parentNode.threeScene; - //console.info( "---- loadAsset( "+parentNode.name+", "+node.name+", "+childType+" )" ); + + if ( this.debug.loading ) { + this.logger.infox( "loadAsset", parentNode.ID, node.ID, childType ); + } node.assetLoaded = function( geometry , materials) { //console.info( "++++ assetLoaded( "+parentNode.name+", "+node.name+", "+childType+" )" ); diff --git a/support/client/lib/vwf/view/threejs.js b/support/client/lib/vwf/view/threejs.js index ff60f2c51..bf6ce1867 100644 --- a/support/client/lib/vwf/view/threejs.js +++ b/support/client/lib/vwf/view/threejs.js @@ -146,7 +146,7 @@ define( [ "module", raycaster = new THREE.Raycaster(); window._dView = this; - this.nodes = {}; + this.interpolateTransforms = true; this.tickTime = 0; this.realTickDif = 50; @@ -163,8 +163,8 @@ define( [ "module", //how/when does the model set the state object? if ( this.state.scenes[ childID ] ) { - this.canvasQuery = $(this.rootSelector).append("" - ).children(":last"); + var canvasDef = "" + this.canvasQuery = $(this.rootSelector).append( canvasDef ).children(":last"); initScene.call(this,this.state.scenes[childID]); } @@ -175,9 +175,6 @@ define( [ "module", } } - if(this.state.nodes[childID] && this.state.nodes[childID].threeObject instanceof THREE.Object3D) { - this.nodes[childID] = {id:childID,extends:childExtendsID}; - } }, initializedNode: function( nodeID, childID ) { @@ -240,7 +237,9 @@ define( [ "module", deletedNode: function(childID) { - delete this.nodes[childID]; + if ( this.state.animatedNodes[ childID ] !== undefined ) { + delete this.state.animatedNodes[ childID ]; + } }, // -- addedChild ------------------------------------------------------------------------------- @@ -251,16 +250,18 @@ define( [ "module", //removedChild: function( nodeID, childID ) { }, - // -- createdProperty -------------------------------------------------------------------------- - - //createdProperty: function (nodeID, propertyName, propertyValue) { }, - // -- initializedProperty ---------------------------------------------------------------------- initializedProperty: function ( nodeID, propertyName, propertyValue ) { this.satProperty(nodeID, propertyName, propertyValue); }, + // -- createdProperty -------------------------------------------------------------------------- + + createdProperty: function (nodeID, propertyName, propertyValue) { + this.satProperty(nodeID, propertyName, propertyValue); + }, + // TODO: deletedProperty // -- satProperty ------------------------------------------------------------------------------ @@ -307,7 +308,8 @@ define( [ "module", if ( node ) { nodeLookAt( node ); } - } + + } }, // -- gotProperty ------------------------------------------------------------------------------ @@ -422,7 +424,23 @@ define( [ "module", // -- calledMethod ----------------------------------------------------------------------------- calledMethod: function( nodeID, methodName, methodParameters, methodValue ) { - switch(methodName) { + + switch( methodName ) { + + case "animationPlay": + if ( navObject === undefined || navObject.ID !== nodeID ) { + if ( this.state.animatedNodes[ nodeID ] === undefined ) { + this.state.animatedNodes[ nodeID ] = { + "id": nodeID, + "lastAnimationFrame": getAnimationFrame( nodeID ), + "thisAnimationFrame": getAnimationFrame( nodeID ), + "thisTickTransform": getTransform( nodeID ), + "lastTickTransform": getTransform( nodeID ) + } + } + } + break; + case "translateBy": case "translateTo": // No need for rotateBy or rotateTo because they call the quaternion methods @@ -434,9 +452,16 @@ define( [ "module", case "transformTo": case "worldTransformTo": // If the duration of the transform is 0, set the transforms to their final value so it doesn't interpolate - if(methodParameters.length < 2 || methodParameters[1] == 0) { - this.nodes[nodeID].lastTickTransform = getTransform(nodeID); - this.nodes[nodeID].selfTickTransform = goog.vec.Mat4.clone(this.nodes[nodeID].lastTickTransform); + if ( ( methodParameters.length >= 2 ) && ( methodParameters[ 1 ] !== 0 && methodParameters[ 1 ] !== undefined ) ) { + if ( navObject === undefined || navObject.ID !== nodeID ) { + this.state.animatedNodes[ nodeID ] = { + "id": nodeID, + "thisTickTransform": getTransform( nodeID ), + "lastTickTransform": getTransform( nodeID ) + } + } + } else if ( this.state.animatedNodes[ nodeID ] !== undefined ) { + delete this.state.animatedNodes[ nodeID ]; } break; } @@ -489,7 +514,7 @@ define( [ "module", // -- firedEvent ----------------------------------------------------------------------------- - firedEvent: function( nodeID, eventName ) { + firedEvent: function( nodeID, eventName, eventParameters ) { if ( eventName == "changingTransformFromView" ) { var clientThatSatProperty = self.kernel.client(); var me = self.kernel.moniker(); @@ -504,7 +529,11 @@ define( [ "module", if(this.state.scenes[nodeID]) { this.state.scenes[nodeID].renderer.setViewport(0,0,window.innerWidth,window.innerHeight); } - } + } else if ( eventName === "animationStopped" ) { + if ( this.state.animatedNodes[ nodeID ] !== undefined ) { + delete this.state.animatedNodes[ nodeID ]; + } + } }, // -- ticked ----------------------------------------------------------------------------------- @@ -522,7 +551,7 @@ define( [ "module", findNavObject(); } - lerpTick(); + }, // -- render ----------------------------------------------------------------------------------- @@ -889,22 +918,7 @@ define( [ "module", var navObject = undefined; var cameraNode = undefined; - function lerpTick () { - var now = performance.now(); - self.realTickDif = now - self.lastRealTick; - - self.lastRealTick = now; - - //reset - loading can cause us to get behind and always but up against the max prediction value - self.tickTime = 0; - - for ( var nodeID in self.nodes ) { - if ( self.state.nodes[nodeID] ) { - self.nodes[nodeID].lastTickTransform = self.nodes[nodeID].selfTickTransform; - self.nodes[nodeID].selfTickTransform = getTransform(nodeID); - } - } - } + function lerp(a,b,l,c) { if(c) l = Math.min(1,Math.max(l,0)); return (b*l) + a*(1.0-l); @@ -948,7 +962,19 @@ define( [ "module", } } - function matrixLerp( a, b, l ) { + function matset(newv, old) { + if (!old) { + newv = old; + return; + } + if (!newv) + newv = []; + for (var i = 0; i < old.length; i++) + newv[i] = old[i]; + return newv; + } + + function matrixLerp( a, b, l,n ) { // If either of the matrices is not left-handed or not orthogonal, interpolation won't work // Just return the second matrix @@ -956,7 +982,7 @@ define( [ "module", return b; } - var n = goog.vec.Mat4.clone(a); + if (!n) n = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; n[12] = lerp(a[12],b[12],l); n[13] = lerp(a[13],b[13],l); n[14] = lerp(a[14],b[14],l); @@ -1016,45 +1042,122 @@ define( [ "module", return nqm; } - function getTransform(id) { - var interp = goog.vec.Mat4.clone(self.state.nodes[id].threeObject.matrix.elements); + function getAnimationFrame( id ) { + var interp = vwf.getProperty( id, 'animationFrame' ); return interp; } - function setTransform(id,interp) { - interp = goog.vec.Mat4.clone(interp) - self.state.nodes[id].threeObject.matrix.elements = interp; - self.state.nodes[id].threeObject.updateMatrixWorld(true); + function setAnimationFrame( id, val ) { + //NOTE: this can cause state errors. Need a layer in VWF to abstract the set of this + //property from the VWF model state. + vwf.setProperty( id, 'animationFrame', val ); + } + function getTransform( id ) { + var interp = goog.vec.Mat4.clone( self.state.nodes[ id ].threeObject.matrix.elements ); + return interp; + } + function setTransform( id, interp ) { + interp = goog.vec.Mat4.clone( interp ) + self.state.nodes[ id ].threeObject.matrix.elements = interp; + self.state.nodes[ id ].threeObject.updateMatrixWorld( true ); } function setInterpolatedTransforms(deltaTime) { - var step = (self.tickTime) / (self.realTickDif); - step = Math.min(step,1); - deltaTime = Math.min(deltaTime, self.realTickDif) - self.tickTime += deltaTime || 0; - for(var nodeID in self.nodes) { - var last = self.nodes[nodeID].lastTickTransform; - var now = self.nodes[nodeID].selfTickTransform; - if(last && now && !matCmp(last,now,.0001) ) { - var interp = matrixLerp(last, now, step || 0); + //smooth over local time + self.tickTime += deltaTime || 0; + var hit = 0; + + //how many ticks has it been? + while (self.tickTime > 50) { + hit++; + self.tickTime -= 50; + } + var step = (self.tickTime) / (50); + var keys, id, j, nd; + //if the tick is exactly one, we reset + if (hit === 1) { + + //NOTE: we use this construct because V8 will not optimize a function with a for in loop + keys = Object.keys( self.state.animatedNodes ); + for ( j = 0; j < keys.length; j++) { + id = keys[ j ]; + nd = self.state.animatedNodes[ id ]; - var objectIsControlledByUser = ( ( navmode !== "none" ) && - ( ( navObject && ( nodeID === navObject.ID ) ) || - ( cameraNode && ( nodeID === cameraNode.ID ) ) ) ); - if ( !objectIsControlledByUser ) { - setTransform(nodeID, interp); - self.nodes[nodeID].needTransformRestore = true; + if ( self.state.nodes[ id ] ) { + if ( nd.lastTickTransform !== undefined && nd.thisTickTransform !== undefined ) { + nd.lastTickTransform = matset( nd.lastTickTransform, nd.thisTickTransform ); + nd.thisTickTransform = matset( nd.thisTickTransform, getTransform( id ) ); + } + + if ( nd.lastAnimationFrame !== undefined && nd.thisAnimationFrame !== undefined ) { + nd.lastAnimationFrame = nd.thisAnimationFrame; + nd.thisAnimationFrame = getAnimationFrame( id ); + } } } + + } + + //this is where we trade off between responsive and smooth. This is sort of a magic number picked + //empirically. + //try the duck example with this set to 1, and then again set to .01 + var LERPFACTOR = .15; + var lerpStep = Math.min(1, LERPFACTOR * (deltaTime / 16.6)); //the slower the frames ,the more we have to move per frame. Should feel the same at 60 0r 20 + keys = Object.keys( self.state.animatedNodes ); + //reuse local variables where possible, especially if they are arrays + var interp = null; + var last, now; + for ( j = 0; j < keys.length; j++) { + id = keys[j]; + nd = self.state.animatedNodes[ id ]; + last = nd.lastTickTransform; + now = nd.thisTickTransform; + if (last && now) { + //use matset to keep data in temp variables + interp = matset(interp, last); + interp = matrixLerp(last, now, step, interp); + + nd.currentTickTransform = matset( nd.currentTickTransform, getTransform( id ) ); + + if ( nd.lastFrameInterp ) + interp = matrixLerp( nd.lastFrameInterp, now, lerpStep, interp ); + setTransform( id, interp ); + nd.lastFrameInterp = matset( nd.lastFrameInterp || [], interp ); + } + + last = nd.lastAnimationFrame; + now = nd.thisAnimationFrame; + //If the delta in animation frames is greater than 3, treat is as discontinuous + if ( last && now && Math.abs(now - last) < 3) { + var interpA = 0; + interpA = lerp(last, now, step); + nd.currentAnimationFrame = getAnimationFrame(id); + + if (self.state.nodes[id].lastAnimationInterp) + interpA = lerp(self.state.nodes[id].lastAnimationInterp, now, lerpStep); + setAnimationFrame(id,interpA); + self.state.nodes[id].lastAnimationInterp = interpA || 0; + + } else if (self.state.nodes[id]) { + self.state.nodes[id].lastAnimationInterp = null; + } + } } function restoreTransforms() { - for(var nodeID in self.nodes) { - var now = self.nodes[nodeID].selfTickTransform; - - if(self.node != navObject && now && self.nodes[nodeID].needTransformRestore) { - self.state.nodes[nodeID].threeObject.matrix.elements = goog.vec.Mat4.clone(now); - self.state.nodes[nodeID].threeObject.updateMatrixWorld(true); - self.nodes[nodeID].needTransformRestore = false; + var keys, id, j, now, nd; + keys = Object.keys( self.state.animatedNodes ); + for ( j = 0; j < keys.length; j++) { + id = keys[j]; + nd = self.state.animatedNodes[ id ]; + if ( nd.currentTickTransform != null ) { + now = nd.currentTickTransform; + nd.currentTickTransform = null; + setTransform( id, now ); + } + if ( nd.currentAnimationFrame != null ) { + now = nd.currentAnimationFrame; + nd.currentAnimationFrame = null; + setAnimationFrame( id, now ); } } } diff --git a/support/proxy/vwf.example.com/node3.vwf.yaml b/support/proxy/vwf.example.com/node3.vwf.yaml index 574d7844d..fac18eaa5 100644 --- a/support/proxy/vwf.example.com/node3.vwf.yaml +++ b/support/proxy/vwf.example.com/node3.vwf.yaml @@ -274,45 +274,6 @@ properties: ## @name node3.vwf#vertices ## @property - vertices: - set: | - this.logger.info( "WARNING: node3 vertices cannot be set" ) - - ## Vertex indices of 3D node - ## - ## @name node3.vwf#vertexIndices - ## @property - - vertexIndices: - set: | - this.logger.info( "WARNING: node3 vertexIndices cannot be set" ) - - ## Speed value - ## - ## @name node3.vwf#speed - ## @property - - speed: 1 - - ## Playing value - ## - ## @name node3.vwf#playing - ## @property - - playing: false - - ## Looping value - ## - ## @name node3.vwf#looping - ## @property - - looping: false - - ## Look at value - ## - ## @name lookAt - ## @property - lookAt: "" ## Visible value diff --git a/support/proxy/vwf.example.com/node3/animation.vwf.yaml b/support/proxy/vwf.example.com/node3/animation.vwf.yaml index 57504dd43..4492ed099 100644 --- a/support/proxy/vwf.example.com/node3/animation.vwf.yaml +++ b/support/proxy/vwf.example.com/node3/animation.vwf.yaml @@ -416,5 +416,5 @@ methods: } this.transformTo( stopTransform, duration ); //@ sourceURL=node3.animation.worldTransformTo.vwf -event: +events: changingTransformFromView: