diff --git a/lib/nodejs/serve.js b/lib/nodejs/serve.js
index 5413ac069..9a1b56767 100755
--- a/lib/nodejs/serve.js
+++ b/lib/nodejs/serve.js
@@ -98,7 +98,8 @@ function ServeYAML( filename, response, URL ) {
try {
var deYAML = JSON.stringify( YAML.load( file ) );
} catch ( e ) {
- global.log( "error parsing YAML " + filename );
+ global.log( "error parsing YAML " + filename);
+ global.log("" + e);
_404( response );
return;
}
diff --git a/support/client/lib/vwf.js b/support/client/lib/vwf.js
index 36e3e758a..b74d5f56b 100644
--- a/support/client/lib/vwf.js
+++ b/support/client/lib/vwf.js
@@ -697,7 +697,7 @@
var model = require( modelName ).create(
this.models.kernel, // model's kernel access
- [ require( "vwf/model/stage/log" ) ], // stages between the kernel and model
+ [], // stages between the kernel and model
{}, // state shared with a paired view
[].concat( modelArguments || [] ) // arguments for initialize()
);
@@ -716,11 +716,16 @@
while ( this.models.object.model ) this.models.object = this.models.object.model;
}
- if(model.model.compatibilityStatus) {
+ if(model.model && model.model.compatibilityStatus) {
if(!model.model.compatibilityStatus.compatible) {
compatibilityStatus.compatible = false;
jQuery.extend(compatibilityStatus.errors, model.model.compatibilityStatus.errors);
}
+ } else if(model.compatibilityStatus) {
+ if(!model.compatibilityStatus.compatible) {
+ compatibilityStatus.compatible = false;
+ jQuery.extend(compatibilityStatus.errors, model.compatibilityStatus.errors);
+ }
}
}
@@ -3177,73 +3182,87 @@ if ( ! childComponent.source ) {
var delegated = false, assigned = false;
- // Call settingProperty() on each model. The first model to return a non-undefined value
- // has performed the set and dictates the return value. The property is considered set
- // after all models have run.
+ if ( propertyName[ propertyName.length - 1 ] !== "$" ) {
- this.models.some( function( model, index ) {
+ // Call settingProperty() on each model. The first model to return a non-undefined value
+ // has performed the set and dictates the return value. The property is considered set
+ // after all models have run.
- // Skip initial models that an outer call has already invoked for this node and
- // property (if any). If an inner call completed for this node and property, skip
- // the remaining models.
+ this.models.some( function( model, index ) {
- if ( ( ! reentered || index > entry.index ) && ! reentry.completed ) {
+ // Skip initial models that an outer call has already invoked for this node and
+ // property (if any). If an inner call completed for this node and property, skip
+ // the remaining models.
- // Record the active model number.
-
- reentry.index = index;
+ if ( ( ! reentered || index > entry.index ) && ! reentry.completed ) {
- // Record the number of assignments made since the outermost call. When
- // `entrants.assignments` increases, a driver has called `setProperty` to make
- // an assignment elsewhere.
+ // Record the active model number.
- var assignments = entrants.assignments;
+ reentry.index = index;
- // Make the call.
+ // Record the number of assignments made since the outermost call. When
+ // `entrants.assignments` increases, a driver has called `setProperty` to make
+ // an assignment elsewhere.
- if ( ! delegated && ! assigned ) {
- var value = model[settingPropertyEtc] && model[settingPropertyEtc]( nodeID, propertyName, propertyValue );
- } else {
- model[settingPropertyEtc] && model[settingPropertyEtc]( nodeID, propertyName, undefined );
- }
+ var assignments = entrants.assignments;
- // Ignore the result if reentry is disabled and the driver attempted to call
- // back into the kernel. Kernel reentry is disabled during replication to
- // prevent coloring from accessor scripts.
+ // Make the call.
- if ( this.models.kernel.blocked() ) { // TODO: this might be better handled wholly in vwf/kernel/model by converting to a stage and clearing blocked results on the return
- value = undefined;
- }
+ if ( ! delegated && ! assigned ) {
+ var value = model[settingPropertyEtc] && model[settingPropertyEtc]( nodeID, propertyName, propertyValue );
+ } else {
+ model[settingPropertyEtc] && model[settingPropertyEtc]( nodeID, propertyName, undefined );
+ }
- // The property was delegated if the call made any assignments.
+ // Ignore the result if reentry is disabled and the driver attempted to call
+ // back into the kernel. Kernel reentry is disabled during replication to
+ // prevent coloring from accessor scripts.
- if ( entrants.assignments !== assignments ) {
- delegated = true;
- }
+ if ( this.models.kernel.blocked() ) { // TODO: this might be better handled wholly in vwf/kernel/model by converting to a stage and clearing blocked results on the return
+ value = undefined;
+ }
- // Otherwise if the call returned a value, the property was assigned here.
+ // The property was delegated if the call made any assignments.
- else if ( value !== undefined ) {
- entrants.assignments++;
- assigned = true;
- }
+ if ( entrants.assignments !== assignments ) {
+ delegated = true;
+ }
- // Record the value actually assigned. This may differ from the incoming value
- // if it was range limited, quantized, etc. by the model. This is the value
- // passed to the views.
+ // Otherwise if the call returned a value, the property was assigned here.
- if ( value !== undefined ) {
- propertyValue = value;
+ else if ( value !== undefined ) {
+ entrants.assignments++;
+ assigned = true;
+ }
+
+ // Record the value actually assigned. This may differ from the incoming value
+ // if it was range limited, quantized, etc. by the model. This is the value
+ // passed to the views.
+
+ if ( value !== undefined ) {
+ propertyValue = value;
+ }
+
+ // If we are setting, exit from the this.models.some() iterator once the value
+ // has been set. Don't exit early if we are creating or initializing since every
+ // model needs the opportunity to register the property.
+
+ return settingPropertyEtc == "settingProperty" && ( delegated || assigned );
}
- // If we are setting, exit from the this.models.some() iterator once the value
- // has been set. Don't exit early if we are creating or initializing since every
- // model needs the opportunity to register the property.
+ }, this );
- return settingPropertyEtc == "settingProperty" && ( delegated || assigned );
+ } else {
+
+ var value = this.models.object[settingPropertyEtc]( nodeID, propertyName, propertyValue );
+
+ if ( value !== undefined ) {
+ entrants.assignments++;
+ assigned = true;
+ propertyValue = value;
}
- }, this );
+ }
// Record the change if the property was assigned here.
@@ -3258,7 +3277,7 @@ if ( ! childComponent.source ) {
// ephemeral, and views on late-joining clients would never see it, it's best to never
// send those notifications.
- if ( assigned ) {
+ if ( assigned && propertyName[ propertyName.length - 1 ] !== "$" ) {
this.views.forEach( function( view ) {
view[satPropertyEtc] && view[satPropertyEtc]( nodeID, propertyName, propertyValue );
} );
@@ -3350,65 +3369,78 @@ if ( ! childComponent.source ) {
var delegated = false, retrieved = false;
- // Call gettingProperty() on each model. The first model to return a non-undefined value
- // dictates the return value.
+ if ( propertyName[ propertyName.length - 1 ] !== "$" ) {
- this.models.some( function( model, index ) {
+ // Call gettingProperty() on each model. The first model to return a non-undefined value
+ // dictates the return value.
- // Skip initial models that an outer call has already invoked for this node and
- // property (if any). If an inner call completed for this node and property, skip
- // the remaining models.
+ this.models.some( function( model, index ) {
- if ( ( ! reentered || index > entry.index ) && ! reentry.completed ) {
+ // Skip initial models that an outer call has already invoked for this node and
+ // property (if any). If an inner call completed for this node and property, skip
+ // the remaining models.
- // Record the active model number.
-
- reentry.index = index;
+ if ( ( ! reentered || index > entry.index ) && ! reentry.completed ) {
- // Record the number of retrievals made since the outermost call. When
- // `entrants.retrievals` increases, a driver has called `getProperty` to make
- // a retrieval elsewhere.
+ // Record the active model number.
- var retrievals = entrants.retrievals;
+ reentry.index = index;
- // Make the call.
+ // Record the number of retrievals made since the outermost call. When
+ // `entrants.retrievals` increases, a driver has called `getProperty` to make
+ // a retrieval elsewhere.
- var value = model.gettingProperty &&
- model.gettingProperty( nodeID, propertyName, propertyValue ); // TODO: probably don't need propertyValue here
+ var retrievals = entrants.retrievals;
- // Ignore the result if reentry is disabled and the driver attempted to call
- // back into the kernel. Kernel reentry is disabled during replication to
- // prevent coloring from accessor scripts.
+ // Make the call.
- if ( this.models.kernel.blocked() ) { // TODO: this might be better handled wholly in vwf/kernel/model by converting to a stage and clearing blocked results on the return
- value = undefined;
- }
+ var value = model.gettingProperty &&
+ model.gettingProperty( nodeID, propertyName, propertyValue ); // TODO: probably don't need propertyValue here
- // The property was delegated if the call made any retrievals.
+ // Ignore the result if reentry is disabled and the driver attempted to call
+ // back into the kernel. Kernel reentry is disabled during replication to
+ // prevent coloring from accessor scripts.
- if ( entrants.retrievals !== retrievals ) {
- delegated = true;
- }
+ if ( this.models.kernel.blocked() ) { // TODO: this might be better handled wholly in vwf/kernel/model by converting to a stage and clearing blocked results on the return
+ value = undefined;
+ }
- // Otherwise if the call returned a value, the property was retrieved here.
+ // The property was delegated if the call made any retrievals.
- else if ( value !== undefined ) {
- entrants.retrievals++;
- retrieved = true;
- }
+ if ( entrants.retrievals !== retrievals ) {
+ delegated = true;
+ }
+
+ // Otherwise if the call returned a value, the property was retrieved here.
+
+ else if ( value !== undefined ) {
+ entrants.retrievals++;
+ retrieved = true;
+ }
+
+ // Record the value retrieved.
+
+ if ( value !== undefined ) {
+ propertyValue = value;
+ }
- // Record the value retrieved.
+ // Exit from the this.models.some() iterator once we have a return value.
- if ( value !== undefined ) {
- propertyValue = value;
+ return delegated || retrieved;
}
- // Exit from the this.models.some() iterator once we have a return value.
+ }, this );
+
+ } else {
+
+ var value = this.models.object.gettingProperty( nodeID, propertyName, propertyValue ); // TODO: probably don't need propertyValue here
- return delegated || retrieved;
+ if ( value !== undefined ) {
+ entrants.retrievals++;
+ propertyValue = value;
}
- }, this );
+ }
if ( reentered ) {
@@ -3447,9 +3479,11 @@ if ( ! childComponent.source ) {
// Call gotProperty() on each view.
- this.views.forEach( function( view ) {
- view.gotProperty && view.gotProperty( nodeID, propertyName, propertyValue ); // TODO: be sure this is the value actually gotten and not an intermediate value from above
- } );
+ if ( propertyName[ propertyName.length - 1 ] !== "$" ) {
+ this.views.forEach( function( view ) {
+ view.gotProperty && view.gotProperty( nodeID, propertyName, propertyValue ); // TODO: be sure this is the value actually gotten and not an intermediate value from above
+ } );
+ }
}
@@ -4319,8 +4353,12 @@ if ( ! childComponent.source ) {
///
/// @see {@link module:vwf/api/kernel.application}
+this.applicationID = undefined;
+
this.application = function( initializedOnly ) {
+if ( this.applicationID ) return this.applicationID;
+
var applicationID;
Object.keys( nodes.globals ).forEach( function( globalID ) {
@@ -4330,6 +4368,8 @@ if ( ! childComponent.source ) {
}
}, this );
+this.applicationID = applicationID;
+
return applicationID;
};
diff --git a/support/client/lib/vwf/model/blockly.js b/support/client/lib/vwf/model/blockly.js
index 5bdea9eac..ac4c45f74 100644
--- a/support/client/lib/vwf/model/blockly.js
+++ b/support/client/lib/vwf/model/blockly.js
@@ -398,18 +398,6 @@ define( [ "module", "vwf/model", "vwf/utility",
} );
- function getPrototypes( extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = self.kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function isBlockly3Node( nodeID ) {
return self.kernel.test( nodeID,
"self::element(*,'http://vwf.example.com/blockly/controller.vwf')",
diff --git a/support/client/lib/vwf/model/buzz.js b/support/client/lib/vwf/model/buzz.js
index c0c010feb..b5559311f 100644
--- a/support/client/lib/vwf/model/buzz.js
+++ b/support/client/lib/vwf/model/buzz.js
@@ -112,7 +112,7 @@ define( [
return;
}
- var protos = getPrototypes( this.kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
var node;
if ( this.state.isSoundComponent( protos ) ) {
@@ -415,18 +415,6 @@ define( [
} );
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function createSound( node, url ) {
var soundProps;
diff --git a/support/client/lib/vwf/model/cesium.js b/support/client/lib/vwf/model/cesium.js
index d47a142dd..72ede50c9 100644
--- a/support/client/lib/vwf/model/cesium.js
+++ b/support/client/lib/vwf/model/cesium.js
@@ -306,7 +306,7 @@ define( [ "module",
}
var node = undefined, parentNode, sceneNode;
- var protos = getPrototypes.call( this, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
var createNode = function() {
return {
@@ -626,7 +626,7 @@ define( [ "module",
// there, too
function notifyDriverOfPrototypeAndBehaviorProps() {
var ptPropValue;
- var protos = getPrototypes.call( self, childExtendsID );
+ var protos = self.kernel.prototypes( childID );
protos.forEach( function( prototypeID ) {
for ( var propertyName in kernel.getProperties( prototypeID ) ) {
//console.info( " 1 getting "+propertyName+" of: " + childExtendsID );
@@ -2011,18 +2011,6 @@ define( [ "module",
}
- function getPrototypes( extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = this.kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function findParent( ID ) {
var retNode = this.state.nodes[ ID ];
if ( retNode === undefined ) {
@@ -2037,7 +2025,7 @@ define( [ "module",
var protos = undefined;
var parent = findParent.call( this, parentID );
while ( parent && sceneNode === undefined ) {
- protos = getPrototypes.call( this, parent.extendsID );
+ protos = this.kernel.prototypes( parent.ID );
if ( protos && isCesium.call( this, protos ) ) {
sceneNode = parent;
} else {
diff --git a/support/client/lib/vwf/model/glge.js b/support/client/lib/vwf/model/glge.js
index 137175fa0..1966cdd14 100644
--- a/support/client/lib/vwf/model/glge.js
+++ b/support/client/lib/vwf/model/glge.js
@@ -75,7 +75,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
var node, parentNode, glgeChild, glgeParent;
var kernel = this.kernel;
- var prototypes = getPrototypes.call( this, kernel, childExtendsID );
+ var prototypes = this.kernel.prototypes( childID );
// this.logger.enabled = true;
// this.logger.infox( "creatingNode", nodeID, childID, childExtendsID, childImplementsIDs,
@@ -328,7 +328,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
// there, too
function notifyDriverOfPrototypeAndBehaviorProps() {
var ptPropValue;
- var protos = getPrototypes.call( this, kernel, childExtendsID );
+ var protos = self.kernel.prototypes( childID );
protos.forEach( function( prototypeID ) {
for ( var propertyName in kernel.getProperties( prototypeID ) ) {
//console.info( " 1 getting "+propertyName+" of: " + childExtendsID );
@@ -620,7 +620,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
break;
default:
- prototypes = getPrototypes.call( this, this.kernel.kernel.kernel, node["type"] );
+ prototypes = this.kernel.prototypes( node.ID );
if ( isGlgeMaterialDefinition.call( this, prototypes ) ){
value = setMaterialProperty.call( this, nodeID, propertyName, propertyValue );
} else if ( isGlgeCameraDefinition.call( this, prototypes ) ) {
@@ -773,7 +773,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
default:
// handle all of the other types
- prototypes = getPrototypes.call( this, this.kernel.kernel.kernel, node["type"] );
+ prototypes = this.kernel.prototypes( node.ID );
if ( isGlgeMaterialDefinition.call( this, prototypes ) ){
value = getMaterialProperty.call( this, nodeID, propertyName, propertyValue );
} else if ( isGlgeCameraDefinition.call( this, prototypes ) ) {
@@ -2222,20 +2222,6 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
return vertexIndices;
}
- // get the list of types this ID extends
-
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function isPrototype( nodeID, childID ) {
var ptID;
if ( ( nodeID == 0 && childID != this.kernel.application() ) || this.state.prototypes[ nodeID ] !== undefined ) {
diff --git a/support/client/lib/vwf/model/graphtool.js b/support/client/lib/vwf/model/graphtool.js
index 791c6348d..6fca7b781 100644
--- a/support/client/lib/vwf/model/graphtool.js
+++ b/support/client/lib/vwf/model/graphtool.js
@@ -20,7 +20,6 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
self = this;
this.state.graphs = {};
this.state.objects = {};
- this.state.kernel = this.kernel.kernel.kernel;
},
// == Model API ============================================================================
@@ -31,8 +30,7 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
childSource, childType, childIndex, childName, callback /* ( ready ) */ ) {
var node = undefined;
- var kernel = this.state.kernel;
- var protos = getPrototypes.call( this, kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
if ( protos && isGraph( protos ) ) {
@@ -318,18 +316,6 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
return threejs;
}
-
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
function isGraph( prototypes ) {
diff --git a/support/client/lib/vwf/model/heightmap.js b/support/client/lib/vwf/model/heightmap.js
index 106620309..c8e162ad5 100644
--- a/support/client/lib/vwf/model/heightmap.js
+++ b/support/client/lib/vwf/model/heightmap.js
@@ -18,14 +18,14 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
creatingNode: function( nodeID, childID, childExtendsID, childImplementsIDs,
childSource, childType, childIndex, childName, callback ) {
- var protos = getPrototypes( this.kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
if ( isHeightmap( protos ) ) {
var node = this.nodes[ childID ];
// Create the local copy of the node properties
- if ( this.nodes[ childID ] === undefined ){
+ if ( this.nodes[ childID ] === undefined && childSource !== undefined ){
// Suspend the queue until the load is complete
callback( false );
@@ -86,18 +86,6 @@ define( [ "module", "vwf/model", "vwf/utility" ], function( module, model, utili
} );
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function isHeightmap( prototypes ) {
var found = false;
if ( prototypes ) {
diff --git a/support/client/lib/vwf/model/jPlayer.js b/support/client/lib/vwf/model/jPlayer.js
index 6debc886e..15abb073f 100644
--- a/support/client/lib/vwf/model/jPlayer.js
+++ b/support/client/lib/vwf/model/jPlayer.js
@@ -120,7 +120,7 @@ define( [
return;
}
- var protos = getPrototypes( this.kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
var isAudioManager = this.state.isAudioManager( protos );
var isVideoManager = this.state.isVideoManager( protos );
@@ -342,18 +342,6 @@ define( [
} );
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function setWithPrototypeProperties( proto ) {
if ( proto.url !== null ) {
vwf.setProperty( node.ID, "url", proto.url );
diff --git a/support/client/lib/vwf/model/kineticjs.js b/support/client/lib/vwf/model/kineticjs.js
index 8088f51bd..978a10114 100644
--- a/support/client/lib/vwf/model/kineticjs.js
+++ b/support/client/lib/vwf/model/kineticjs.js
@@ -118,7 +118,7 @@ define( [ "module",
return;
}
- var protos = getPrototypes( this.kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
var node;
@@ -2097,18 +2097,6 @@ define( [ "module",
} );
// == PRIVATE ========================================================================================
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function createKineticObject( node, config ) {
var protos = node.prototypes;
var kineticObj = undefined;
diff --git a/support/client/lib/vwf/model/mil-sym.js b/support/client/lib/vwf/model/mil-sym.js
index 9e139303f..2d7278f38 100644
--- a/support/client/lib/vwf/model/mil-sym.js
+++ b/support/client/lib/vwf/model/mil-sym.js
@@ -106,7 +106,7 @@ define( [ "module",
return;
}
- var protos = getPrototypes( childExtendsID );
+ var protos = this.kernel.prototypes( childID );
var node = this.state.nodes[ childID ];
if ( node === undefined ) {
@@ -424,18 +424,6 @@ define( [ "module",
} );
- function getPrototypes( extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = modelDriver.kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function isUnitNode( prototypes ) {
var found = false;
if ( prototypes ) {
diff --git a/support/client/lib/vwf/model/sound.js b/support/client/lib/vwf/model/sound.js
index f824ad00a..46582f4db 100644
--- a/support/client/lib/vwf/model/sound.js
+++ b/support/client/lib/vwf/model/sound.js
@@ -356,8 +356,9 @@ define( [ "module", "vwf/model" ], function( module, model ) {
}
if ( !this.allowMultiplay && this.isPlaying() ) {
+ var instance = Object.keys( this.playingInstances )[ 0 ];
return { soundName: this.name,
- instanceID: this.playingInstances[ 0 ] };
+ instanceID: this.playingInstances[ instance ].id };
}
var id = this.instanceIDCounter;
diff --git a/support/client/lib/vwf/model/threejs.js b/support/client/lib/vwf/model/threejs.js
index 2c16019b8..f39c119d6 100644
--- a/support/client/lib/vwf/model/threejs.js
+++ b/support/client/lib/vwf/model/threejs.js
@@ -50,11 +50,12 @@
define( [ "module",
"vwf/model",
"vwf/utility",
+ "vwf/kernel/utility",
"vwf/utility/color",
"jquery"
],
- function( module, model, utility, Color, $ ) {
+ function( module, model, utility, kutility, Color, $ ) {
var self;
@@ -76,7 +77,6 @@ define( [ "module",
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.prototypes = {};
- this.state.kernel = this.kernel.kernel.kernel;
this.state.lights = {};
this.state.setMeshPropertyRecursively = function( threeObject, propertyName, value ) {
@@ -177,9 +177,8 @@ define( [ "module",
}
}
}
- var kernel = this.kernel.kernel.kernel;
- var protos = getPrototypes.call( this, kernel, childExtendsID );
+ var protos = this.kernel.prototypes( childID );
if ( isSceneDefinition.call(this, protos) && childID == this.kernel.application() )
{
var sceneNode = CreateThreeJSSceneNode( nodeID, childID, childExtendsID );
@@ -499,7 +498,7 @@ define( [ "module",
// If we do not have a load a model for this node, then we are almost done, so we can update all
// the driver properties w/ the stop-gap function below.
// Else, it will be called at the end of the assetLoaded callback
- if ( ! supportedFileType( childType ) ) {
+ if ( node && node.threeObject && !supportedFileType( childType ) ) {
notifyDriverOfPrototypeAndBehaviorProps();
}
@@ -511,18 +510,18 @@ define( [ "module",
// there, too
function notifyDriverOfPrototypeAndBehaviorProps() {
var ptPropValue;
- var protos = getPrototypes.call( this, kernel, childExtendsID );
+ var protos = self.kernel.prototypes( childID );
protos.forEach( function( prototypeID ) {
- for ( var propertyName in kernel.getProperties( prototypeID ) ) {
- ptPropValue = kernel.getProperty( childExtendsID, propertyName );
+ for ( var propertyName in self.kernel.getProperties( prototypeID ) ) {
+ ptPropValue = self.kernel.getProperty( childExtendsID, propertyName );
if ( ptPropValue !== undefined && ptPropValue !== null && childID !== undefined && childID !== null) {
self.settingProperty( childID, propertyName, ptPropValue );
}
}
} );
childImplementsIDs.forEach( function( behaviorID ) {
- for ( var propertyName in kernel.getProperties( behaviorID ) ) {
- ptPropValue = kernel.getProperty( behaviorID, propertyName );
+ for ( var propertyName in self.kernel.getProperties( behaviorID ) ) {
+ ptPropValue = self.kernel.getProperty( behaviorID, propertyName );
if ( ptPropValue !== undefined && ptPropValue !== null && childID !== undefined && childID !== null) {
self.settingProperty( childID, propertyName, ptPropValue );
}
@@ -1282,12 +1281,12 @@ define( [ "module",
// Skeletal Animations (takes precedence over Morph Target)
if ( node.threeObject.bones && node.threeObject.bones.length > 0 ) {
- var animRate = this.state.kernel.getProperty( nodeID, "animationRate" ) || 1;
+ var animRate = this.kernel.getProperty( nodeID, "animationRate" ) || 1;
THREE.AnimationHandler.update(animRate);
}
// Morph Target Animations
else if ( node.threeObject.animatedMesh && node.threeObject.animatedMesh.length && propertyValue !== undefined ) {
- var fps = this.state.kernel.getProperty( nodeID, "animationFPS" ) || 30;
+ var fps = this.kernel.getProperty( nodeID, "animationFPS" ) || 30;
for( var i = 0; i < node.threeObject.animatedMesh.length; i++ ) {
if ( node.threeObject.animatedMesh[i].morphTargetInfluences ) {
for( var j = 0; j < node.threeObject.animatedMesh[i].morphTargetInfluences.length; j++ ) {
@@ -1724,7 +1723,7 @@ define( [ "module",
}
// Need to reset the viewport or you just get a blank screen
- this.state.kernel.dispatchEvent( nodeID, "resetViewport" );
+ this.kernel.dispatchEvent( nodeID, "resetViewport" );
}
if ( propertyName == 'shadowMapCullFace') {
var shadowMapCullFace;
@@ -2012,7 +2011,8 @@ define( [ "module",
if ( propertyValue instanceof Array ) {
value = propertyValue;
if ( threeObject.target ) {
- threeObject.target.position.set( value[ 0 ], value[ 1 ], value[ 2 ] );
+ threeObject.target.position.set( value[ 0 ], value[ 1 ], value[ 2 ] );
+ threeObject.target.updateMatrixWorld();
}
} else if ( this.state.nodes[ propertyValue ] ) {
value = propertyValue;
@@ -2101,7 +2101,7 @@ define( [ "module",
value = animationDuration;
}
else if ( node.threeObject.animatedMesh && node.threeObject.animatedMesh.length ) {
- var fps = this.state.kernel.getProperty( nodeID, "animationFPS") || 30;
+ var fps = this.kernel.getProperty( nodeID, "animationFPS") || 30;
for(var i=0, il = node.threeObject.animatedMesh.length; i < il; i++) {
if (node.threeObject.animatedMesh[i].bones) {
@@ -2699,7 +2699,30 @@ define( [ "module",
var raycaster = new THREE.Raycaster( origin, direction, near, far );
var intersects = raycaster.intersectObjects( objects, recursive );
- return intersects;
+
+ // clean up results before passing back to applications
+ var results = [];
+ var result, intersectedNode;
+ for ( var i = 0; i < intersects.length; i++ ) {
+ result = {};
+ result[ "distance" ] = intersects[ i ].distance;
+ result[ "point" ] = [
+ intersects[ i ].point.x,
+ intersects[ i ].point.y,
+ intersects[ i ].point.z ];
+ intersectedNode = intersects[ i ].object;
+ while ( !intersectedNode.vwfID ) {
+ intersectedNode = intersectedNode.parent;
+ }
+ result[ "node" ] = kutility.nodeReference( intersectedNode.vwfID );
+ result[ "normal" ] = [
+ intersects[ i ].face.normal.x,
+ intersects[ i ].face.normal.y,
+ intersects[ i ].face.normal.z ];
+ results[ i ] = result;
+ }
+
+ return results;
}
@@ -2750,18 +2773,6 @@ define( [ "module",
return false;
}
- function getPrototypes( kernel, extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function getThreeScene( id ) {
if ( id === undefined ) {
id = this.kernel.application();
@@ -3492,51 +3503,51 @@ define( [ "module",
//walk the graph of an object, and set all materials to new material clones
function cloneMaterials( nodein ) {
-
- //sort the materials in the model, and when cloneing, make the new model share the same material setup as the old.
- var materialMap = {};
-
+
+ //sort the materials in the model, and when cloneing, make the new model share the same material setup as the old.
+ var materialMap = {};
+
walkGraph( nodein, function( node ) {
if(node.material) {
if ( node.material instanceof THREE.Material ) {
if(!materialMap[node.material.uuid]) {
- materialMap[node.material.uuid] = [];
+ materialMap[node.material.uuid] = [];
}
- materialMap[node.material.uuid].push( [ node, -1 ] );
+ materialMap[node.material.uuid].push( [ node, -1 ] );
}
else if ( node.material instanceof THREE.MeshFaceMaterial ) {
if ( node.material.materials ) {
for ( var index = 0; index < node.material.materials.length; index++ ) {
if ( node.material.materials[ index ] instanceof THREE.Material ) {
if(!materialMap[node.material.materials[ index ].uuid]) {
- materialMap[node.material.materials[ index ].uuid] = [];
+ materialMap[node.material.materials[ index ].uuid] = [];
}
- materialMap[node.material.materials[ index ].uuid].push( [ node, index ] );
+ materialMap[node.material.materials[ index ].uuid].push( [ node, index ] );
}
}
}
}
}
});
-
- for(var i in materialMap)
- {
- var newmat;
+
+ for(var i in materialMap)
+ {
+ var newmat;
if ( materialMap[ i ][ 0 ][ 1 ] < 0 ) {
newmat = materialMap[ i ][ 0 ][ 0 ].material.clone( );
}
else {
newmat = materialMap[ i ][ 0 ][ 0 ].material.materials[ materialMap[ i ][ 0 ][ 1 ] ].clone( );
}
- for ( var j =0; j < materialMap[i].length; j++ ) {
+ for ( var j =0; j < materialMap[i].length; j++ ) {
if ( materialMap[ i ][ j ][ 1 ] < 0 ) {
- materialMap[ i ][ j ][ 0 ].material = newmat;
+ materialMap[ i ][ j ][ 0 ].material = newmat;
}
else {
materialMap[ i ][ j ][ 0 ].material.materials[ materialMap[ i ][ j ][ 1 ] ] = newmat;
}
}
- }
+ }
}
function loadAsset( parentNode, node, childType, propertyNotifyCallback ) {
@@ -3642,7 +3653,7 @@ define( [ "module",
//find and bind the animations
//NOTE: this would probably be better handled by walking and finding the animations and skins only on the
//property setter when needed.
-
+
animatedMesh = [];
walkGraph(nodeCopy.threeObject,function( node ){
if( node instanceof THREE.SkinnedMesh || node instanceof THREE.MorphAnimMesh ) {
@@ -3857,7 +3868,7 @@ define( [ "module",
//no download or parse necessary
else if( reg.loaded == true && reg.pending == false ) {
var asset = (reg.node.clone());
-
+
// make sure the materails are unique
cloneMaterials( asset );
@@ -4049,60 +4060,60 @@ define( [ "module",
//default material expects all computation done cpu side, just renders
- // note that since the color, size, spin and orientation are just linear
- // interpolations, they can be done in the shader
+ // note that since the color, size, spin and orientation are just linear
+ // interpolations, they can be done in the shader
var vertShader_default =
"attribute float size; \n"+
"attribute vec4 vertexColor;\n"+
"varying vec4 vColor;\n"+
- "attribute vec4 random;\n"+
- "varying vec4 vRandom;\n"+
- "uniform float sizeRange;\n"+
- "uniform vec4 colorRange;\n"+
+ "attribute vec4 random;\n"+
+ "varying vec4 vRandom;\n"+
+ "uniform float sizeRange;\n"+
+ "uniform vec4 colorRange;\n"+
"void main() {\n"+
" vColor = vertexColor + (random -0.5) * colorRange;\n"+
" vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n"+
- " float psize = size + (random.y -0.5) * sizeRange;\n"+
+ " float psize = size + (random.y -0.5) * sizeRange;\n"+
" gl_PointSize = psize * ( 1000.0/ length( mvPosition.xyz ) );\n"+
" gl_Position = projectionMatrix * mvPosition;\n"+
- " vRandom = random;"+
+ " vRandom = random;"+
"} \n";
var fragShader_default =
"uniform float useTexture;\n"+
"uniform sampler2D texture;\n"+
"varying vec4 vColor;\n"+
- "varying vec4 vRandom;\n"+
- "uniform float time;\n"+
+ "varying vec4 vRandom;\n"+
+ "uniform float time;\n"+
"uniform float maxSpin;\n"+
"uniform float minSpin;\n"+
- "uniform float maxOrientation;\n"+
+ "uniform float maxOrientation;\n"+
"uniform float minOrientation;\n"+
- "uniform float textureTiles;\n"+
+ "uniform float textureTiles;\n"+
"void main() {\n"+
- " vec2 coord = vec2(0.0,0.0);"+
- " vec2 orig_coord = vec2(gl_PointCoord.s,1.0-gl_PointCoord.t);"+
+ " vec2 coord = vec2(0.0,0.0);"+
+ " vec2 orig_coord = vec2(gl_PointCoord.s,1.0-gl_PointCoord.t);"+
" float spin = mix(maxSpin,minSpin,vRandom.x);"+
" float orientation = mix(maxOrientation,minOrientation,vRandom.y);"+
" coord.s = (orig_coord.s-.5)*cos(time*spin+orientation)-(orig_coord.t-.5)*sin(time*spin+orientation);"+
" coord.t = (orig_coord.t-.5)*cos(time*spin+orientation)+(orig_coord.s-.5)*sin(time*spin+orientation);"+
- " coord = coord + vec2(.5,.5);\n"+
- " coord = coord/textureTiles;\n"+
- " coord.x = clamp(coord.x,0.0,1.0/textureTiles);\n"+
- " coord.y = clamp(coord.y,0.0,1.0/textureTiles);\n"+
- " coord += vec2(floor(vRandom.x*textureTiles)/textureTiles,floor(vRandom.y*textureTiles)/textureTiles);\n"+
+ " coord = coord + vec2(.5,.5);\n"+
+ " coord = coord/textureTiles;\n"+
+ " coord.x = clamp(coord.x,0.0,1.0/textureTiles);\n"+
+ " coord.y = clamp(coord.y,0.0,1.0/textureTiles);\n"+
+ " coord += vec2(floor(vRandom.x*textureTiles)/textureTiles,floor(vRandom.y*textureTiles)/textureTiles);\n"+
" vec4 outColor = (vColor * texture2D( texture, coord )) *useTexture + vColor * (1.0-useTexture);\n"+
" gl_FragColor = outColor;\n"+
"}\n";
-
- //the default shader - the one used by the analytic solver, just has some simple stuff
- //note that this could be changed to do just life and lifespan, and calculate the
- //size and color from to uniforms. Im not going to bother
+
+ //the default shader - the one used by the analytic solver, just has some simple stuff
+ //note that this could be changed to do just life and lifespan, and calculate the
+ //size and color from to uniforms. Im not going to bother
var attributes_default = {
size: { type: 'f', value: [] },
vertexColor: { type: 'v4', value: [] },
- random: { type: 'v4', value: [] },
-
+ random: { type: 'v4', value: [] },
+
};
var uniforms_default = {
amplitude: { type: "f", value: 1.0 },
@@ -4110,14 +4121,14 @@ define( [ "module",
useTexture: { type: "f", value: 0.0 },
maxSpin: { type: "f", value: 0.0 },
minSpin: { type: "f", value: 0.0 },
- maxOrientation: { type: "f", value: 0.0 },
+ maxOrientation: { type: "f", value: 0.0 },
minOrientation: { type: "f", value: 0.0 },
- time: { type: "f", value: 0.0 },
- fractime: { type: "f", value: 0.0 },
- sizeRange: { type: "f", value: 0.0 },
- textureTiles: { type: "f", value: 1.0 },
- colorRange: { type: 'v4', value: new THREE.Vector4(0,0,0,0) },
- startColor:{type: "v4", value:new THREE.Vector4()},
+ time: { type: "f", value: 0.0 },
+ fractime: { type: "f", value: 0.0 },
+ sizeRange: { type: "f", value: 0.0 },
+ textureTiles: { type: "f", value: 1.0 },
+ colorRange: { type: 'v4', value: new THREE.Vector4(0,0,0,0) },
+ startColor:{type: "v4", value:new THREE.Vector4()},
endColor:{type: "v4", value:new THREE.Vector4()},
startSize:{type:"f", value:1},
endSize:{type:"f", value:1},
@@ -4131,40 +4142,40 @@ define( [ "module",
});
- //the interpolate shader blends from one simulation step to the next on the shader
- //this allows for a complex sim to run at a low framerate, but still have smooth motion
- //this is very efficient, as it only requires sending data up to the gpu on each sim tick
- //reuse the frag shader from the normal material
+ //the interpolate shader blends from one simulation step to the next on the shader
+ //this allows for a complex sim to run at a low framerate, but still have smooth motion
+ //this is very efficient, as it only requires sending data up to the gpu on each sim tick
+ //reuse the frag shader from the normal material
var vertShader_interpolate =
- "attribute float age; \n"+
- "attribute float lifespan; \n"+
- "attribute vec3 previousPosition;\n"+
+ "attribute float age; \n"+
+ "attribute float lifespan; \n"+
+ "attribute vec3 previousPosition;\n"+
"varying vec4 vColor;\n"+
- "attribute vec4 random;\n"+
- "varying vec4 vRandom;\n"+
- "uniform float sizeRange;\n"+
- "uniform vec4 colorRange;\n"+
- "uniform float fractime;\n"+
- "uniform float startSize;\n"+
+ "attribute vec4 random;\n"+
+ "varying vec4 vRandom;\n"+
+ "uniform float sizeRange;\n"+
+ "uniform vec4 colorRange;\n"+
+ "uniform float fractime;\n"+
+ "uniform float startSize;\n"+
"uniform float endSize;\n"+
"uniform vec4 startColor;\n"+
"uniform vec4 endColor;\n"+
"void main() {\n"+
" vColor = mix(startColor,endColor,(age+fractime*3.33)/lifespan) + (random -0.5) * colorRange;\n"+
" vec4 mvPosition = modelViewMatrix * vec4(mix(previousPosition,position,fractime), 1.0 );\n"+
- " float psize = mix(startSize,endSize,(age+fractime*3.33)/lifespan) + (random.y -0.5) * sizeRange;\n"+
+ " float psize = mix(startSize,endSize,(age+fractime*3.33)/lifespan) + (random.y -0.5) * sizeRange;\n"+
" gl_PointSize = psize * ( 1000.0/ length( mvPosition.xyz ) );\n"+
" gl_Position = projectionMatrix * mvPosition;\n"+
- " vRandom = random;"+
+ " vRandom = random;"+
"} \n";
- //the interpolation does need to remember the previous position
- var attributes_interpolate = {
- random: attributes_default.random,
- previousPosition: { type: 'v3', value: [] },
- age: { type: 'f', value: [] },
- lifespan: { type: 'f', value: [] }
+ //the interpolation does need to remember the previous position
+ var attributes_interpolate = {
+ random: attributes_default.random,
+ previousPosition: { type: 'v3', value: [] },
+ age: { type: 'f', value: [] },
+ lifespan: { type: 'f', value: [] }
};
var shaderMaterial_interpolate = new THREE.ShaderMaterial( {
uniforms: uniforms_default,
@@ -4176,12 +4187,12 @@ define( [ "module",
//analytic shader does entire simulation on GPU
- //it cannot account for drag, gravity. nor can it generate new randomness. Each particle has it's randomness assigned and it
- //just repeats the same motion over and over. Also, the other solvers can hold a particle until
- //it can be reused based on the emitRate. This cannot, as the entire life of the particle must be
- //computed from an equation given just time t. It does offset them in time to avoid all the particles
- //being generated at once. Also, it does not account for emitter motion.
- //upside : very very efficient. No CPU intervention required
+ //it cannot account for drag, gravity. nor can it generate new randomness. Each particle has it's randomness assigned and it
+ //just repeats the same motion over and over. Also, the other solvers can hold a particle until
+ //it can be reused based on the emitRate. This cannot, as the entire life of the particle must be
+ //computed from an equation given just time t. It does offset them in time to avoid all the particles
+ //being generated at once. Also, it does not account for emitter motion.
+ //upside : very very efficient. No CPU intervention required
var vertShader_analytic =
"attribute float size; \n"+
"attribute vec4 vertexColor;\n"+
@@ -4196,20 +4207,20 @@ define( [ "module",
"uniform vec4 endColor;\n"+
"varying vec4 vColor;\n"+
"varying vec4 vRandom;\n"+
- "uniform float sizeRange;\n"+
- "uniform vec4 colorRange;\n"+
+ "uniform float sizeRange;\n"+
+ "uniform vec4 colorRange;\n"+
"void main() {\n"+
- //randomly offset in time
+ //randomly offset in time
" float lifetime = mod( random.x * lifespan + time, lifespan );"+
- //solve for position
+ //solve for position
" vec3 pos2 = position.xyz + velocity*lifetime + (acceleration*lifetime*lifetime)/2.0;"+ // ;
" vec4 mvPosition = modelViewMatrix * vec4( pos2.xyz, 1.0 );\n"+
- //find random size based on randomness, start and end size, and size range
- " float psize = mix(startSize,endSize,lifetime/lifespan) + (random.y -0.5) * sizeRange;\n"+
+ //find random size based on randomness, start and end size, and size range
+ " float psize = mix(startSize,endSize,lifetime/lifespan) + (random.y -0.5) * sizeRange;\n"+
" gl_PointSize = psize * ( 1000.0/ length( mvPosition.xyz ) );\n"+
" gl_Position = projectionMatrix * mvPosition;\n"+
- " vec4 nR = (random -0.5);\n"+
- //find random color based on start and endcolor, time and colorRange
+ " vec4 nR = (random -0.5);\n"+
+ //find random color based on start and endcolor, time and colorRange
" vColor = mix(startColor,endColor,lifetime/lifespan) + nR * colorRange;\n"+
" vRandom = random;"+
"} \n";
@@ -4221,27 +4232,27 @@ define( [ "module",
"uniform float minSpin;\n"+
"varying vec4 vColor;\n"+
"varying vec4 vRandom;\n"+
- "uniform float maxOrientation;\n"+
+ "uniform float maxOrientation;\n"+
"uniform float minOrientation;\n"+
- "uniform float textureTiles;\n"+
+ "uniform float textureTiles;\n"+
"void main() {\n"+
- //bit of drama for dividing into 4 or 9 'virtual' textures
- //nice to be able to have different images on particles
- " vec2 coord = vec2(0.0,0.0);"+
- " vec2 orig_coord = vec2(gl_PointCoord.s,1.0-gl_PointCoord.t);"+
+ //bit of drama for dividing into 4 or 9 'virtual' textures
+ //nice to be able to have different images on particles
+ " vec2 coord = vec2(0.0,0.0);"+
+ " vec2 orig_coord = vec2(gl_PointCoord.s,1.0-gl_PointCoord.t);"+
" float spin = mix(maxSpin,minSpin,vRandom.x);"+
" float orientation = mix(maxOrientation,minOrientation,vRandom.y);"+
" coord.s = (orig_coord.s-.5)*cos(time*spin+orientation)-(orig_coord.t-.5)*sin(time*spin+orientation);"+
" coord.t = (orig_coord.t-.5)*cos(time*spin+orientation)+(orig_coord.s-.5)*sin(time*spin+orientation);"+
- " coord = coord + vec2(.5,.5);\n"+
- " coord = coord/textureTiles;\n"+
- " coord.x = clamp(coord.x,0.0,1.0/textureTiles);\n"+
- " coord.y = clamp(coord.y,0.0,1.0/textureTiles);\n"+
- " coord += vec2(floor(vRandom.x*textureTiles)/textureTiles,floor(vRandom.y*textureTiles)/textureTiles);\n"+
+ " coord = coord + vec2(.5,.5);\n"+
+ " coord = coord/textureTiles;\n"+
+ " coord.x = clamp(coord.x,0.0,1.0/textureTiles);\n"+
+ " coord.y = clamp(coord.y,0.0,1.0/textureTiles);\n"+
+ " coord += vec2(floor(vRandom.x*textureTiles)/textureTiles,floor(vRandom.y*textureTiles)/textureTiles);\n"+
- //get the color from the texture and blend with the vertexColor.
- " vec4 outColor = (vColor * texture2D( texture, coord )) *useTexture + vColor * (1.0-useTexture);\n"+
+ //get the color from the texture and blend with the vertexColor.
+ " vec4 outColor = (vColor * texture2D( texture, coord )) *useTexture + vColor * (1.0-useTexture);\n"+
" gl_FragColor = outColor;\n"+
"}\n";
@@ -4263,12 +4274,12 @@ define( [ "module",
// create the particle system
var particleSystem = new THREE.PointCloud( particles, shaderMaterial_default );
- //keep track of the shaders
+ //keep track of the shaders
particleSystem.shaderMaterial_analytic = shaderMaterial_analytic;
particleSystem.shaderMaterial_default = shaderMaterial_default;
- particleSystem.shaderMaterial_interpolate = shaderMaterial_interpolate;
+ particleSystem.shaderMaterial_interpolate = shaderMaterial_interpolate;
- //setup all the default values
+ //setup all the default values
particleSystem.minVelocity = [0,0,0];
particleSystem.maxVelocity = [0,0,0];
particleSystem.maxAcceleration = [0,0,0];
@@ -4285,54 +4296,54 @@ define( [ "module",
particleSystem.damping = 0;
particleSystem.startSize = 3;
particleSystem.endSize = 3;
- particleSystem.gravity = 0;
- particleSystem.gravityCenter = [0,0,0];
+ particleSystem.gravity = 0;
+ particleSystem.gravityCenter = [0,0,0];
particleSystem.velocityMode = 'cartesian';
- particleSystem.temp = new THREE.Vector3();
+ particleSystem.temp = new THREE.Vector3();
- //create a new particle. create and store all the values for vertex attributes in each shader
- particleSystem.createParticle = function(i)
+ //create a new particle. create and store all the values for vertex attributes in each shader
+ particleSystem.createParticle = function(i)
{
var particle = new THREE.Vector3(0,0,0);
this.geometry.vertices.push(particle);
particle.i = i;
- //the world space position
+ //the world space position
particle.world = new THREE.Vector3();
- //the previous !tick! (not frame) position
+ //the previous !tick! (not frame) position
particle.prevworld = new THREE.Vector3();
- this.shaderMaterial_interpolate.attributes.previousPosition.value.push(particle.prevworld);
+ this.shaderMaterial_interpolate.attributes.previousPosition.value.push(particle.prevworld);
//the color
- var color = new THREE.Vector4(1,1,1,1);
+ var color = new THREE.Vector4(1,1,1,1);
this.shaderMaterial_default.attributes.vertexColor.value.push(color);
- //age
- this.shaderMaterial_interpolate.attributes.age.value.push(1);
+ //age
+ this.shaderMaterial_interpolate.attributes.age.value.push(1);
particle.color = color;
-
- //the sise
+
+ //the sise
this.shaderMaterial_default.attributes.size.value.push(1);
var self = this;
- //set the size - stored per vertex
+ //set the size - stored per vertex
particle.setSize = function(s)
{
self.material.attributes.size.value[this.i] = s;
}
- //set the age - stored per vertex
- particle.setAge = function(a)
- {
- this.age = a;
- self.shaderMaterial_interpolate.attributes.age.value[this.i] = this.age;
- }
- //the lifespan - stored per vertex
- particle.setLifespan = function(a)
- {
- this.lifespan = a;
- self.shaderMaterial_interpolate.attributes.lifespan.value[this.i] = this.a;
- }
+ //set the age - stored per vertex
+ particle.setAge = function(a)
+ {
+ this.age = a;
+ self.shaderMaterial_interpolate.attributes.age.value[this.i] = this.age;
+ }
+ //the lifespan - stored per vertex
+ particle.setLifespan = function(a)
+ {
+ this.lifespan = a;
+ self.shaderMaterial_interpolate.attributes.lifespan.value[this.i] = this.a;
+ }
- //This looks like it could be computed from the start and end plus random on the shader
- //doing this saves computetime on the shader at expense of gpu mem
+ //This looks like it could be computed from the start and end plus random on the shader
+ //doing this saves computetime on the shader at expense of gpu mem
shaderMaterial_analytic.attributes.acceleration.value.push(new THREE.Vector3());
shaderMaterial_analytic.attributes.velocity.value.push(new THREE.Vector3());
shaderMaterial_analytic.attributes.lifespan.value.push(1);
@@ -4340,17 +4351,17 @@ define( [ "module",
return particle;
}
- //Generate a new point in space based on the emitter type and size
+ //Generate a new point in space based on the emitter type and size
particleSystem.generatePoint = function()
{
- //generate from a point
- //TODO: specify point?
+ //generate from a point
+ //TODO: specify point?
if(this.emitterType.toLowerCase() == 'point')
{
return new THREE.Vector3(0,0,0);
}
- //Generate in a box
- //assumes centered at 0,0,0
+ //Generate in a box
+ //assumes centered at 0,0,0
if(this.emitterType.toLowerCase() == 'box')
{
var x = this.emitterSize[0] * Math.random() - this.emitterSize[0]/2;
@@ -4359,8 +4370,8 @@ define( [ "module",
return new THREE.Vector3(x,y,z);
}
- //Generate in a sphere
- //assumes centered at 0,0,0
+ //Generate in a sphere
+ //assumes centered at 0,0,0
if(this.emitterType.toLowerCase() == 'sphere')
{
var u2 = Math.random();
@@ -4377,31 +4388,31 @@ define( [ "module",
}
}
- //setup the particles with new values
+ //setup the particles with new values
particleSystem.rebuildParticles = function()
{
- for(var i = 0; i < this.geometry.vertices.length; i++)
+ for ( var i = 0; i < this.geometry.vertices.length; i++ )
{
- this.setupParticle(this.geometry.vertices[i],this.matrix);
+ this.setupParticle( this.geometry.vertices[ i ], this.matrix );
}
}
- //set the particles initial values. Used when creating and resuing particles
- particleSystem.setupParticle = function(particle,mat,inv)
+ //set the particles initial values. Used when creating and resuing particles
+ particleSystem.setupParticle = function( particle, mat, inv )
{
particle.x = 0;
particle.y = 0;
particle.z = 0;
- //generate a point in objects space, the move to world space
+ //generate a point in objects space, the move to world space
particle.world = this.generatePoint().applyMatrix4( mat );
- //back up initial (needed by the analyticShader)
+ //back up initial (needed by the analyticShader)
particle.initialx = particle.world.x;
particle.initialy = particle.world.y;
particle.initialz = particle.world.z;
- //start at initial pos
+ //start at initial pos
particle.x = particle.initialx;
particle.y = particle.initialy;
particle.z = particle.initialz;
@@ -4413,16 +4424,16 @@ define( [ "module",
particle.acceleration = new THREE.Vector3( 0,0,0);
particle.lifespan = 1;
- //Generate the initial velocity
- //In this mode, you specify a min and max x,y,z
+ //Generate the initial velocity
+ //In this mode, you specify a min and max x,y,z
if(this.velocityMode == 'cartesian')
{
particle.velocity.x = this.minVelocity[0] + (this.maxVelocity[0] - this.minVelocity[0]) * Math.random();
particle.velocity.y = this.minVelocity[1] + (this.maxVelocity[1] - this.minVelocity[1]) * Math.random();
particle.velocity.z = this.minVelocity[2] + (this.maxVelocity[2] - this.minVelocity[2]) * Math.random();
}
- //In this mode, you give a pitch and yaw from 0,1, and a min and max length.
- //This is easier to emit into a circle, or a cone section
+ //In this mode, you give a pitch and yaw from 0,1, and a min and max length.
+ //This is easier to emit into a circle, or a cone section
if(this.velocityMode == 'spherical')
{
@@ -4434,7 +4445,7 @@ define( [ "module",
particle.velocity.y = r * Math.sin(t)*Math.sin(w);
particle.velocity.z = r * Math.cos(t); */
- //better distribution
+ //better distribution
var o = this.minVelocity[0] + (this.maxVelocity[0] - this.minVelocity[0]) * Math.random() * Math.PI*2;
var u = this.minVelocity[1] + (this.maxVelocity[1] - this.minVelocity[1]) * Math.random() * 2 - 1;
var u2 = Math.random();
@@ -4446,8 +4457,8 @@ define( [ "module",
particle.velocity.setLength(r);
}
- //The velocity should be in world space, but is generated in local space for
- //ease of use
+ //The velocity should be in world space, but is generated in local space for
+ //ease of use
mat = mat.clone();
mat.elements[12] = 0;
mat.elements[13] = 0;
@@ -4460,13 +4471,13 @@ define( [ "module",
particle.acceleration.z = this.minAcceleration[2] + (this.maxAcceleration[2] - this.minAcceleration[2]) * Math.random();
particle.setLifespan(this.minLifeTime + (this.maxLifeTime - this.minLifeTime) * Math.random());
- //color is start color
- particle.color.x = this.startColor[0];
+ //color is start color
+ particle.color.x = this.startColor[0];
particle.color.y = this.startColor[1];
particle.color.z = this.startColor[2];
particle.color.w = this.startColor[3];
- //save the values into the attributes
+ //save the values into the attributes
shaderMaterial_analytic.attributes.acceleration.value[particle.i] = (particle.acceleration);
shaderMaterial_analytic.attributes.velocity.value[particle.i] = (particle.velocity);
shaderMaterial_analytic.attributes.lifespan.value[particle.i] = (particle.lifespan);
@@ -4483,53 +4494,58 @@ define( [ "module",
}
- //when updating in AnalyticShader mode, is very simple, just inform the shader of new time.
- particleSystem.updateAnalyticShader = function(time)
+ //when updating in AnalyticShader mode, is very simple, just inform the shader of new time.
+ particleSystem.updateAnalyticShader = function( time )
{
- particleSystem.material.uniforms.time.value += time/1000;
+ particleSystem.material.uniforms.time.value += time / 1000;
}
- //In Analytic mode, run the equation for the position
- particleSystem.updateAnalytic =function(time)
+ //In Analytic mode, run the equation for the position
+ particleSystem.updateAnalytic = function( time )
{
- particleSystem.material.uniforms.time.value += time/3333.0;
-
- var time_in_ticks = time/33.333;
+ var timeInSeconds = time / 1000;
+ particleSystem.material.uniforms.time.value += timeInSeconds;
var inv = this.matrix.clone();
- inv = inv.getInverse(inv);
+ inv = inv.getInverse( inv );
var particles = this.geometry;
-
- //update each particle
+
+ //update each particle
var pCount = this.geometry.vertices.length;
- while(pCount--)
+ while ( pCount-- )
{
- var particle =particles.vertices[pCount];
- this.updateParticleAnalytic(particle,this.matrix,inv,time_in_ticks);
+ var particle = particles.vertices[ pCount ];
+ this.updateParticleAnalytic( particle, this.matrix, inv, timeInSeconds );
}
//examples developed with faster tick - maxrate *33 is scale to make work
//with new timing
- //Reuse up to maxRate particles, sliced for delta_time
- //Once a particle reaches it's end of life, its available to be regenerated.
- //We hold extras in limbo with alpha 0 until they can be regenerated
- //Note the maxRate never creates or destroys particles, just manages when they will restart
- //after dying
- var len = Math.min(this.regenParticles.length,this.maxRate*15*time_in_ticks);
- for(var i =0; i < len; i++)
+ //Reuse up to maxRate particles, sliced for delta_time
+ //Once a particle reaches it's end of life, its available to be regenerated.
+ //We hold extras in limbo with alpha 0 until they can be regenerated
+ //Note the maxRate never creates or destroys particles, just manages when they will restart
+ //after dying
+ if ( this.timeSinceLastSpawn === undefined ) {
+ this.timeSinceLastSpawn = 0;
+ } else {
+ this.timeSinceLastSpawn += timeInSeconds;
+ }
+ var maxParticlesToSpawn = Math.floor( this.timeSinceLastSpawn * this.maxRate );
+ var len = Math.min( this.regenParticles.length, maxParticlesToSpawn );
+ for ( var i = 0; i < len; i++ )
{
-
- //setup with new random values, and move randomly forward in time one step
+ //setup with new random values, and move randomly forward in time one step
var particle = this.regenParticles.shift();
- this.setupParticle(particle,this.matrix,inv);
- this.updateParticleAnalytic(particle,this.matrix,inv,Math.random()*3.33);
+ this.setupParticle( particle, this.matrix, inv );
+ this.updateParticleAnalytic( particle, this.matrix, inv, Math.random() * timeInSeconds );
particle.waitForRegen = false;
}
-
-
- //only these things change, other properties are in the shader as they are linear WRT time
+
+ this.timeSinceLastSpawn = Boolean( len ) ? 0 : this.timeSinceLastSpawn;
+
+ //only these things change, other properties are in the shader as they are linear WRT time
this.geometry.verticesNeedUpdate = true;
this.geometry.colorsNeedUpdate = true;
this.material.attributes.vertexColor.needsUpdate = true;
@@ -4541,156 +4557,156 @@ define( [ "module",
particleSystem.totaltime = 0;
//timesliced Euler integrator
//todo: switch to RK4
- //This can do more complex sim, maybe even a cloth sim or such. It ticks 10 times a second, and blends tick with previous via a shader
+ //This can do more complex sim, maybe even a cloth sim or such. It ticks 10 times a second, and blends tick with previous via a shader
particleSystem.updateEuler = function(time)
{
- particleSystem.material.uniforms.time.value += time/3333.0;
+ particleSystem.material.uniforms.time.value += time/3333.0;
var time_in_ticks = time/100.0;
if(this.lastTime === undefined) this.lastTime = 0;
this.lastTime += time_in_ticks;//ticks - Math.floor(ticks);
- var inv = this.matrix.clone();
- inv = inv.getInverse(inv);
-
- var particles = this.geometry;
-
- //timesliced tick give up after 5 steps - just cant go fast enough
- if(Math.floor(this.lastTime) > 5)
- this.lastTime = 1;
- for(var i=0; i < Math.floor(this.lastTime) ; i++)
- {
- this.lastTime--;
-
- var pCount = this.geometry.vertices.length;
- while(pCount--)
- {
- var particle =particles.vertices[pCount];
- this.updateParticleEuler(particle,this.matrix,inv,3.333);
- }
-
- //examples developed with faster tick - maxrate *33 is scale to make work
- //with new timing
-
- //Reuse up to maxRate particles, sliced for delta_time
- //Once a particle reaches it's end of life, its available to be regenerated.
- //We hold extras in limbo with alpha 0 until they can be regenerated
- //Note the maxRate never creates or destroys particles, just manages when they will restart
- //after dying
- var len = Math.min(this.regenParticles.length,this.maxRate*333);
- for(var i =0; i < len; i++)
- {
-
- particle.waitForRegen = false;
- var particle = this.regenParticles.shift();
- this.setupParticle(particle,this.matrix,inv);
- this.updateParticleEuler(particle,this.matrix,inv,Math.random()*3.33);
- this.material.attributes.lifespan.needsUpdate = true;
- }
-
- //only need to send up the age, position, and previous position. other props handled in the shader
- this.geometry.verticesNeedUpdate = true;
- this.material.attributes.previousPosition.needsUpdate = true;
-
- this.material.attributes.age.needsUpdate = true;
-
- }
-
- //even if this is not a sim tick, we need to send the fractional time up to the shader for the interpolation
- this.material.uniforms.fractime.value = this.lastTime;
-
- }
-
- //Update a particle from the Analytic solver
- particleSystem.updateParticleAnalytic = function(particle,mat,inv,delta_time)
- {
- particle.age += delta_time;
-
- //Make the particle dead. Hide it until it can be reused
- if(particle.age >= particle.lifespan && !particle.waitForRegen)
- {
- this.regenParticles.push(particle);
- particle.waitForRegen = true;
- particle.x = 0;
- particle.y = 0;
- particle.z = 0;
- particle.color.w = 0.0;
- }else
- {
- //Run the formula to get position.
- var percent = particle.age/particle.lifespan;
- particle.world.x = particle.initialx + (particle.velocity.x * particle.age) + 0.5*(particle.acceleration.x * particle.age * particle.age)
- particle.world.y = particle.initialy + (particle.velocity.y * particle.age) + 0.5*(particle.acceleration.y * particle.age * particle.age)
- particle.world.z = particle.initialz + (particle.velocity.z * particle.age) + 0.5*(particle.acceleration.z * particle.age * particle.age)
-
- this.temp.x = particle.world.x;
- this.temp.y = particle.world.y;
- this.temp.z = particle.world.z;
-
- //need to specify in object space, event though comptued in local
- this.temp.applyMatrix4( inv );
- particle.x = this.temp.x;
- particle.y = this.temp.y;
- particle.z = this.temp.z;
-
- //Should probably move this to the shader. Linear with time, no point in doing on CPU
- particle.color.x = this.startColor[0] + (this.endColor[0] - this.startColor[0]) * percent;
- particle.color.y = this.startColor[1] + (this.endColor[1] - this.startColor[1]) * percent;
- particle.color.z = this.startColor[2] + (this.endColor[2] - this.startColor[2]) * percent;
- particle.color.w = this.startColor[3] + (this.endColor[3] - this.startColor[3]) * percent;
-
- particle.setSize(this.startSize + (this.endSize - this.startSize) * percent);
- }
- }
-
- //updtae a partilce with the Euler solver
- particleSystem.updateParticleEuler = function(particle,mat,inv,step_dist)
- {
- particle.prevage = particle.age;
- particle.age += step_dist;
- particle.setAge(particle.age + step_dist);
-
- //If the particle is dead ,hide it unitl it can be reused
- if(particle.age >= particle.lifespan && !particle.waitForRegen)
- {
-
- this.regenParticles.push(particle);
- particle.waitForRegen = true;
- particle.x = 0;
- particle.y = 0;
- particle.z = 0;
- particle.world.x = 0;
- particle.world.y = 0;
- particle.world.z = 0;
- particle.prevworld.x = 0;
- particle.prevworld.y = 0;
- particle.prevworld.z = 0;
- particle.color.w = 1.0;
- particle.size = 100;
- }else
- {
-
-
- // and the position
- particle.prevworld.x = particle.world.x;
- particle.prevworld.y = particle.world.y;
- particle.prevworld.z = particle.world.z;
-
- //find direction to center for gravity
- var gravityAccel = new THREE.Vector3(particle.world.x,particle.world.y,particle.world.z);
- gravityAccel.x -= this.gravityCenter[0];
- gravityAccel.y -= this.gravityCenter[1];
- gravityAccel.z -= this.gravityCenter[2];
- var len = gravityAccel.length()+.1;
- gravityAccel.normalize();
- gravityAccel.multiplyScalar(-Math.min(1/(len*len),100));
- gravityAccel.multiplyScalar(this.gravity);
-
- //update position
- particle.world.x += particle.velocity.x * step_dist + (particle.acceleration.x + gravityAccel.x)* step_dist * step_dist;
- particle.world.y += particle.velocity.y * step_dist + (particle.acceleration.y + gravityAccel.y )* step_dist * step_dist;;
- particle.world.z += particle.velocity.z * step_dist + (particle.acceleration.z + gravityAccel.z )* step_dist * step_dist;;
+ var inv = this.matrix.clone();
+ inv = inv.getInverse(inv);
+
+ var particles = this.geometry;
+
+ //timesliced tick give up after 5 steps - just cant go fast enough
+ if(Math.floor(this.lastTime) > 5)
+ this.lastTime = 1;
+ for(var i=0; i < Math.floor(this.lastTime) ; i++)
+ {
+ this.lastTime--;
+
+ var pCount = this.geometry.vertices.length;
+ while(pCount--)
+ {
+ var particle =particles.vertices[pCount];
+ this.updateParticleEuler(particle,this.matrix,inv,3.333);
+ }
+
+ //examples developed with faster tick - maxrate *33 is scale to make work
+ //with new timing
+
+ //Reuse up to maxRate particles, sliced for delta_time
+ //Once a particle reaches it's end of life, its available to be regenerated.
+ //We hold extras in limbo with alpha 0 until they can be regenerated
+ //Note the maxRate never creates or destroys particles, just manages when they will restart
+ //after dying
+ var len = Math.min(this.regenParticles.length,this.maxRate*333);
+ for(var i =0; i < len; i++)
+ {
+
+ particle.waitForRegen = false;
+ var particle = this.regenParticles.shift();
+ this.setupParticle(particle,this.matrix,inv);
+ this.updateParticleEuler(particle,this.matrix,inv,Math.random()*3.33);
+ this.material.attributes.lifespan.needsUpdate = true;
+ }
+
+ //only need to send up the age, position, and previous position. other props handled in the shader
+ this.geometry.verticesNeedUpdate = true;
+ this.material.attributes.previousPosition.needsUpdate = true;
+
+ this.material.attributes.age.needsUpdate = true;
+
+ }
+
+ //even if this is not a sim tick, we need to send the fractional time up to the shader for the interpolation
+ this.material.uniforms.fractime.value = this.lastTime;
+
+ }
+
+ //Update a particle from the Analytic solver
+ particleSystem.updateParticleAnalytic = function( particle, mat, inv, delta_time )
+ {
+ particle.age += delta_time;
+
+ //Make the particle dead. Hide it until it can be reused
+ if ( particle.age >= particle.lifespan ) // && !particle.waitForRegen )
+ {
+ this.regenParticles.push( particle );
+ particle.waitForRegen = true;
+ particle.x = 0;
+ particle.y = 0;
+ particle.z = 0;
+ particle.color.w = 0.0;
+ }else
+ {
+ //Run the formula to get position.
+ var percent = particle.age / particle.lifespan;
+ particle.world.x = particle.initialx + ( particle.velocity.x * particle.age ) + 0.5 * ( particle.acceleration.x * particle.age * particle.age )
+ particle.world.y = particle.initialy + ( particle.velocity.y * particle.age ) + 0.5 * ( particle.acceleration.y * particle.age * particle.age )
+ particle.world.z = particle.initialz + ( particle.velocity.z * particle.age ) + 0.5 * ( particle.acceleration.z * particle.age * particle.age )
+
+ this.temp.x = particle.world.x;
+ this.temp.y = particle.world.y;
+ this.temp.z = particle.world.z;
+
+ //need to specify in object space, event though comptued in local
+ this.temp.applyMatrix4( inv );
+ particle.x = this.temp.x;
+ particle.y = this.temp.y;
+ particle.z = this.temp.z;
+
+ //Should probably move this to the shader. Linear with time, no point in doing on CPU
+ particle.color.x = this.startColor[ 0 ] + ( this.endColor[ 0 ] - this.startColor[ 0 ] ) * percent;
+ particle.color.y = this.startColor[ 1 ] + ( this.endColor[ 1 ] - this.startColor[ 1 ] ) * percent;
+ particle.color.z = this.startColor[ 2 ] + ( this.endColor[ 2 ] - this.startColor[ 2 ] ) * percent;
+ particle.color.w = this.startColor[ 3 ] + ( this.endColor[ 3 ] - this.startColor[ 3 ] ) * percent;
+
+ particle.setSize( this.startSize + ( this.endSize - this.startSize ) * percent );
+ }
+ }
+
+ //updtae a partilce with the Euler solver
+ particleSystem.updateParticleEuler = function(particle,mat,inv,step_dist)
+ {
+ particle.prevage = particle.age;
+ particle.age += step_dist;
+ particle.setAge(particle.age + step_dist);
+
+ //If the particle is dead ,hide it unitl it can be reused
+ if(particle.age >= particle.lifespan && !particle.waitForRegen)
+ {
+
+ this.regenParticles.push(particle);
+ particle.waitForRegen = true;
+ particle.x = 0;
+ particle.y = 0;
+ particle.z = 0;
+ particle.world.x = 0;
+ particle.world.y = 0;
+ particle.world.z = 0;
+ particle.prevworld.x = 0;
+ particle.prevworld.y = 0;
+ particle.prevworld.z = 0;
+ particle.color.w = 1.0;
+ particle.size = 100;
+ }else
+ {
+
+
+ // and the position
+ particle.prevworld.x = particle.world.x;
+ particle.prevworld.y = particle.world.y;
+ particle.prevworld.z = particle.world.z;
+
+ //find direction to center for gravity
+ var gravityAccel = new THREE.Vector3(particle.world.x,particle.world.y,particle.world.z);
+ gravityAccel.x -= this.gravityCenter[0];
+ gravityAccel.y -= this.gravityCenter[1];
+ gravityAccel.z -= this.gravityCenter[2];
+ var len = gravityAccel.length()+.1;
+ gravityAccel.normalize();
+ gravityAccel.multiplyScalar(-Math.min(1/(len*len),100));
+ gravityAccel.multiplyScalar(this.gravity);
+
+ //update position
+ particle.world.x += particle.velocity.x * step_dist + (particle.acceleration.x + gravityAccel.x)* step_dist * step_dist;
+ particle.world.y += particle.velocity.y * step_dist + (particle.acceleration.y + gravityAccel.y )* step_dist * step_dist;;
+ particle.world.z += particle.velocity.z * step_dist + (particle.acceleration.z + gravityAccel.z )* step_dist * step_dist;;
//update velocity
particle.velocity.x += (particle.acceleration.x + gravityAccel.x) * step_dist * step_dist;
@@ -4698,30 +4714,30 @@ define( [ "module",
particle.velocity.z += (particle.acceleration.z + gravityAccel.z) * step_dist * step_dist
var damping = 1-(this.damping * step_dist);
-
- //drag
+
+ //drag
particle.velocity.x *= damping;
particle.velocity.y *= damping;
particle.velocity.z *= damping;
-
- //move from world to local space
- this.temp.x = particle.world.x ;
- this.temp.y = particle.world.y ;
- this.temp.z = particle.world.z;
- this.temp.applyMatrix4( inv );
- particle.x = this.temp.x;
- particle.y = this.temp.y;
- particle.z = this.temp.z;
- //careful to have prev and current pos in same space!!!!
- particle.prevworld.applyMatrix4( inv );
+
+ //move from world to local space
+ this.temp.x = particle.world.x ;
+ this.temp.y = particle.world.y ;
+ this.temp.z = particle.world.z;
+ this.temp.applyMatrix4( inv );
+ particle.x = this.temp.x;
+ particle.y = this.temp.y;
+ particle.z = this.temp.z;
+ //careful to have prev and current pos in same space!!!!
+ particle.prevworld.applyMatrix4( inv );
}
}
//Change the solver type for the system
particleSystem.setSolverType =function(type)
{
- this.solver = type;
+ this.solver = type;
if(type == 'Euler')
{
particleSystem.update = particleSystem.updateEuler;
@@ -4743,63 +4759,65 @@ define( [ "module",
}
- //If you move a system, all the particles need to be recomputed to look like they stick in world space
- //not that we pointedly dont do this for the AnalyticShader. We could, but that solver is ment to be very high performance, do we dont
+ //If you move a system, all the particles need to be recomputed to look like they stick in world space
+ //not that we pointedly dont do this for the AnalyticShader. We could, but that solver is ment to be very high performance, do we dont
particleSystem.updateTransform = function(newtransform)
{
-
- //Get he current transform, and invert new one
- var inv = new THREE.Matrix4();
- var newt = new THREE.Matrix4();
- inv.elements = matCpy(newtransform);
- newt = newt.copy(this.matrix);
- inv = inv.getInverse(inv);
-
-
- //don't adjust for the high performance shader
- if(particleSystem.solver == 'AnalyticShader')
- {
- return;
- }
-
- //Move all particles out of old space to world, then back into new space.
- //this will make it seem like they stay at the correct position in the world, though
- //acutally they change position
- //note that it would actually be more efficient to leave the matrix as identity, and change the position of the
- //emitters for this...... Could probably handle it in the model setter actually... would be much more efficient, but linking
- //a system to a moving object would break.
- for(var i =0; i < this.geometry.vertices.length; i++)
- {
- this.geometry.vertices[ i ].applyMatrix4( inv );
- this.shaderMaterial_interpolate.attributes.previousPosition.value[ i ].applyMatrix4( inv );
- this.geometry.vertices[ i ].applyMatrix4( newt );
- this.shaderMaterial_interpolate.attributes.previousPosition.value[ i ].applyMatrix4( newt );
- }
- this.geometry.verticesNeedUpdate = true;
- this.shaderMaterial_interpolate.attributes.previousPosition.needsUpdate = true;
-
+
+ //Get he current transform, and invert new one
+ var inv = new THREE.Matrix4();
+ var newt = new THREE.Matrix4();
+ inv.elements = matCpy(newtransform);
+ newt = newt.copy(this.matrix);
+ inv = inv.getInverse(inv);
+
+
+ //don't adjust for the high performance shader
+ if(particleSystem.solver == 'AnalyticShader')
+ {
+ return;
+ }
+
+ //Move all particles out of old space to world, then back into new space.
+ //this will make it seem like they stay at the correct position in the world, though
+ //acutally they change position
+ //note that it would actually be more efficient to leave the matrix as identity, and change the position of the
+ //emitters for this...... Could probably handle it in the model setter actually... would be much more efficient, but linking
+ //a system to a moving object would break.
+ for(var i =0; i < this.geometry.vertices.length; i++)
+ {
+ this.geometry.vertices[ i ].applyMatrix4( inv );
+ this.shaderMaterial_interpolate.attributes.previousPosition.value[ i ].applyMatrix4( inv );
+ this.geometry.vertices[ i ].applyMatrix4( newt );
+ this.shaderMaterial_interpolate.attributes.previousPosition.value[ i ].applyMatrix4( newt );
+ }
+ this.geometry.verticesNeedUpdate = true;
+ this.shaderMaterial_interpolate.attributes.previousPosition.needsUpdate = true;
+
}
- //Change the system count. Note that this must be set before the first frame renders, cant be changed at runtime.
- particleSystem.setParticleCount = function(newcount)
+ //Change the system count. Note that this must be set before the first frame renders, cant be changed at runtime.
+ particleSystem.setParticleCount = function( newcount )
{
var inv = this.matrix.clone();
- inv = inv.getInverse(inv);
+ inv = inv.getInverse( inv );
var particles = this.geometry;
- while(this.geometry.vertices.length > newcount)
+ particles.vertices.length = 0;
+ // while(this.geometry.vertices.length > newcount)
+ // {
+ // this.geometry.vertices.pop();
+ // }
+ this.regenParticles.length = 0;
+ while ( this.geometry.vertices.length < newcount )
{
- this.geometry.vertices.pop();
- }
- while(this.geometry.vertices.length < newcount)
- {
- var particle = particleSystem.createParticle(this.geometry.vertices.length);
- particleSystem.setupParticle(particle,particleSystem.matrix,inv);
+ var particle = particleSystem.createParticle( this.geometry.vertices.length );
+ particleSystem.setupParticle( particle, particleSystem.matrix, inv );
particle.age = Infinity;
- this.regenParticles.push(particle);
+ this.regenParticles.push( particle );
particle.waitForRegen = true;
}
- this.geometry.verticesNeedUpdate = true;
- this.geometry.colorsNeedUpdate = true;
+ this.geometry.verticesNeedUpdate = true;
+ this.geometry.colorsNeedUpdate = true;
this.shaderMaterial_default.attributes.vertexColor.needsUpdate = true;
this.particleCount = newcount;
}
@@ -5382,9 +5400,9 @@ define( [ "module",
if(node.name && newnode)
newnode.name = node.name;
- if(newnode && newnode.children && newnode.children.length == 1 && isIdentityMatrix(newnode.matrix.elements))
- return newnode.children[0];
-
+ if(newnode && newnode.children && newnode.children.length == 1 && isIdentityMatrix(newnode.matrix.elements))
+ return newnode.children[0];
+
return newnode;
}
var blobsfound = 0;
diff --git a/support/client/lib/vwf/model/threejs/js/loaders/ColladaLoader.js b/support/client/lib/vwf/model/threejs/js/loaders/ColladaLoader.js
index 33f0b5745..f57dcca25 100644
--- a/support/client/lib/vwf/model/threejs/js/loaders/ColladaLoader.js
+++ b/support/client/lib/vwf/model/threejs/js/loaders/ColladaLoader.js
@@ -1153,7 +1153,7 @@ THREE.ColladaLoader = function () {
}
- material3js.opacity = !material3js.opacity ? 1 : material3js.opacity;
+ material3js.opacity = material3js.opacity === undefined ? 1 : material3js.opacity;
used_materials[ instance_material.symbol ] = num_materials;
used_materials_array.push( material3js );
first_material = material3js;
@@ -3577,6 +3577,7 @@ THREE.ColladaLoader = function () {
case 'emission':
case 'diffuse':
case 'specular':
+ case 'specularLevel':
case 'transparent':
this[ child.nodeName ] = ( new ColorOrTexture() ).parse( child );
@@ -3633,26 +3634,40 @@ THREE.ColladaLoader = function () {
var props = {};
- var transparent = false;
-
- if (this['transparency'] !== undefined && this['transparent'] !== undefined) {
+ if ( this[ 'transparency' ] !== undefined && this[ 'transparent' ] !== undefined ) {
// convert transparent color RBG to average value
- var transparentColor = this['transparent'];
- var transparencyLevel = (this.transparent.color.r + this.transparent.color.g + this.transparent.color.b) / 3 * this.transparency;
-
- if (transparencyLevel > 0) {
- transparent = true;
+ var transparentColor = this[ 'transparent' ];
+ var transparencyLevel = 0;
+ // Determine transparency level based on opaque mode
+ if ( transparentColor.opaque == "RGB_ONE" ) {
+ transparencyLevel = ( 3 - this.transparent.color.r -
+ this.transparent.color.g -
+ this.transparent.color.b ) /
+ 3 * this.transparency;
+ } else if ( transparentColor.opaque == "RGB_ZERO" ) {
+ transparencyLevel = ( this.transparent.color.r +
+ this.transparent.color.g +
+ this.transparent.color.b ) /
+ 3 * this.transparency;
+ } else if ( transparentColor.opaque == "A_ONE" ) {
+ transparencyLevel = ( 1 - this.transparent.color.a ) * this.transparency;
+ } else { // A_ZERO (default in collada 1.5.0) - http://www.khronos.org/files/collada_1_5_release_notes.pdf (pg 16)
+ transparencyLevel = this.transparent.color.a * this.transparency;
+ }
+ // Assumes all texures in the 'transparent' field will have an alpha channel
+ if ( transparentColor.isTexture() || transparencyLevel > 0 ) {
props[ 'transparent' ] = true;
- props[ 'opacity' ] = 1 - transparencyLevel;
-
+ } else {
+ props[ 'transparent' ] = false;
}
-
+ props[ 'opacity' ] = 1 - transparencyLevel;
}
var keys = {
'diffuse':'map',
'ambient':'lightMap' ,
'specular':'specularMap',
+ 'specularLevel':'specularMap',
'emission':'emissionMap',
'bump':'bumpMap',
'normal':'normalMap'
@@ -3666,6 +3681,7 @@ THREE.ColladaLoader = function () {
case 'emission':
case 'diffuse':
case 'specular':
+ case 'specularLevel':
case 'bump':
case 'normal':
@@ -3722,7 +3738,7 @@ THREE.ColladaLoader = function () {
}
- } else if ( prop === 'diffuse' || !transparent ) {
+ } else {
if ( prop === 'emission' ) {
diff --git a/support/client/lib/vwf/view/cesium.js b/support/client/lib/vwf/view/cesium.js
index f139c0a09..252f24cf8 100644
--- a/support/client/lib/vwf/view/cesium.js
+++ b/support/client/lib/vwf/view/cesium.js
@@ -121,7 +121,7 @@ define( [ "module", "vwf/view", "vwf/utility", "vwf/model/cesium/Cesium", "jquer
};
var kernel = this.kernel;
- var protos = getPrototypes.call( this, childExtendsID )
+ var protos = this.kernel.prototypes( childID );
var node = undefined;
if ( isCesiumDefinition.call( this, protos ) ) {
@@ -362,18 +362,6 @@ define( [ "module", "vwf/view", "vwf/utility", "vwf/model/cesium/Cesium", "jquer
} );
- function getPrototypes( extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = this.kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function isCesiumDefinition( prototypes ) {
var foundCesium = false;
if ( prototypes ) {
diff --git a/support/client/lib/vwf/view/threejs.js b/support/client/lib/vwf/view/threejs.js
index ff60f2c51..ed56f7880 100644
--- a/support/client/lib/vwf/view/threejs.js
+++ b/support/client/lib/vwf/view/threejs.js
@@ -49,6 +49,7 @@ define( [ "module",
var boundingBox = undefined;
var userObjectRequested = false;
var usersShareView = true;
+ var enableRenderer = true;
var degreesToRadians = Math.PI / 180;
var movingForward = false;
var movingBack = false;
@@ -86,6 +87,8 @@ define( [ "module",
var enableStereo = false;
+ var sceneRootID = undefined;
+
return view.load( module, {
initialize: function( options ) {
@@ -95,7 +98,7 @@ define( [ "module",
checkCompatibility.call(this);
this.state.appInitialized = false;
-
+ sceneRootID = this.kernel.application();
this.pickInterval = 10;
this.enableInputs = true;
this.applicationWantsPointerEvents = false;
@@ -159,17 +162,18 @@ define( [ "module",
createdNode: function( nodeID, childID, childExtendsID, childImplementsIDs,
childSource, childType, childIndex, childName, callback /* ( ready ) */) {
+ sceneRootID = this.kernel.application();
//the created node is a scene, and has already been added to the state by the model.
//how/when does the model set the state object?
if ( this.state.scenes[ childID ] )
{
- this.canvasQuery = $(this.rootSelector).append(""
+ this.canvasQuery = $(this.rootSelector).append(""
).children(":last");
initScene.call(this,this.state.scenes[childID]);
}
- else if ( this.state.scenes[ this.kernel.application() ] ) {
- var sceneNode = this.state.scenes[ this.kernel.application() ];
+ else if ( this.state.scenes[ sceneRootID ] ) {
+ var sceneNode = this.state.scenes[ sceneRootID ];
if ( sceneNode.camera.ID == childID ) {
setActiveCamera.call( this, sceneNode.camera.ID );
}
@@ -183,7 +187,8 @@ define( [ "module",
initializedNode: function( nodeID, childID ) {
// If the node that was initialized is the application node, find the user's navigation object
- var appID = this.kernel.application();
+ var appID = sceneRootID;
+
if ( childID == appID ) {
if ( enableStereo ) {
@@ -207,6 +212,7 @@ define( [ "module",
}
this.state.appInitialized = true;
+
} else {
//TODO: This is a temporary workaround until the callback functionality is implemented for
@@ -289,9 +295,11 @@ define( [ "module",
} else if ( propertyName == "boundingBox" ) {
boundingBox = propertyValue;
} else if ( propertyName == "activeCamera" ) {
- setActiveCamera.call( this, this.state.scenes[ this.kernel.application() ].camera.ID );
+ setActiveCamera.call( this, this.state.scenes[ sceneRootID ].camera.ID );
} else if ( propertyName == "usersShareView" ) {
usersShareView = propertyValue;
+ } else if ( propertyName == "enableRenderer" ) {
+ enableRenderer = propertyValue;
}
}
@@ -315,7 +323,7 @@ define( [ "module",
gotProperty: function ( nodeID, propertyName, propertyValue ) {
var clientThatGotProperty = this.kernel.client();
var me = this.kernel.moniker();
- var sceneRootID = this.kernel.application();
+
if ( clientThatGotProperty == me ) {
if ( propertyName == "owner") {
@@ -358,7 +366,7 @@ define( [ "module",
// Retrieve the userObject property so we may create a navigation object from
// it for this user (the rest of the logic is in the gotProperty call for
// userObject)
- this.kernel.getProperty( this.kernel.application(), "userObject" );
+ this.kernel.getProperty( sceneRootID, "userObject" );
userObjectRequested = true;
}
}
@@ -388,7 +396,7 @@ define( [ "module",
// TODO: The callback function is commented out because callbacks have not yet been
// implemented for createChild - see workaround in initializedNode
- this.kernel.createChild( this.kernel.application(), navObjectName, userObject, undefined, undefined /*,
+ this.kernel.createChild( sceneRootID, navObjectName, userObject, undefined, undefined /*,
function( nodeID ) {
controlNavObject( this.state.nodes[ nodeID ] );
} */ );
@@ -1117,6 +1125,11 @@ define( [ "module",
return;
}
+ // Return if rendering is suppressed in the application scene.
+ if ( ! enableRenderer ) {
+ return;
+ }
+
// Verify that there is a camera to render from before going any farther
var camera = self.state.cameraInUse;
if ( !camera ) {
diff --git a/support/client/lib/vwf/view/webrtc.js b/support/client/lib/vwf/view/webrtc.js
index 4b6188682..068a04ae7 100644
--- a/support/client/lib/vwf/view/webrtc.js
+++ b/support/client/lib/vwf/view/webrtc.js
@@ -75,7 +75,7 @@ define( [ "module", "vwf/view", "vwf/utility", "vwf/utility/color", "jquery" ],
var self = this, node;
- var protos = getPrototypes.call( self, childExtendsID )
+ var protos = this.kernel.prototypes( childID );
if ( isClientInstanceDef.call( this, protos ) && childName ) {
@@ -338,18 +338,6 @@ define( [ "module", "vwf/view", "vwf/utility", "vwf/utility/color", "jquery" ],
} );
- function getPrototypes( extendsID ) {
- var prototypes = [];
- var id = extendsID;
-
- while ( id !== undefined ) {
- prototypes.push( id );
- id = this.kernel.prototype( id );
- }
-
- return prototypes;
- }
-
function getPeer( moniker ) {
var clientNode;
for ( var id in this.state.clients ) {
diff --git a/support/proxy/vwf.example.com/scene.vwf.yaml b/support/proxy/vwf.example.com/scene.vwf.yaml
index 76ec85ddf..4ff3f58cf 100644
--- a/support/proxy/vwf.example.com/scene.vwf.yaml
+++ b/support/proxy/vwf.example.com/scene.vwf.yaml
@@ -155,6 +155,13 @@ properties:
}
value: "PCFSoft"
+ ## Set `enableRenderer` to `false` to disable rendering for this scene. Defaults to `true`.
+ ##
+ ## @name scene.vwf#enableRenderer
+ ## @property
+
+ enableRenderer: true
+
methods:
initializeActiveCamera:
getActiveCameraComp: