content/hifi-content/brosche/dev/Particle-Sequencer/Particle_Sequencer.js
2022-02-13 21:50:01 +01:00

374 lines
No EOL
14 KiB
JavaScript

/* eslint-disable indent */
// PARTICLE SEQUENCER CONSTS
// ////////////////////////////////////////////////////////////////////////
var
LOOP = "loop",
POSITION = "position",
ROTATION = "rotation"
;
// Init
// ////////////////////////////////////////////////////////////////////////
var
_this
;
// HELPER FUNCTIONS
// ////////////////////////////////////////////////////////////////////////
function log(label, value, isActive){
if (!isActive) {
return;
}
print("\n" + label + "\n" + "***************************************\n", JSON.stringify(value));
}
// Get Particle in front of you
function getPosition(x, y, z) {
var localOffset = { x: x, y: y, z: z };
var worldOffset = Vec3.multiplyQbyV(MyAvatar.orientation, localOffset);
return Vec3.sum(MyAvatar.position, worldOffset);
}
// GROUP DEFINITIONS
// ////////////////////////////////////////////////////////////////////////
var _Sequence = function () {
this._entities = {};
this._nameMap = {};
this._sequences = {};
this._anchorPosition = {};
this._totalDelta = 0;
this._currentSequence;
this._isRunning = false;
this._textures = null;
_this = this;
};
_Sequence.prototype = {
add: function(entity){
this._entities[entity.getID()] = entity;
},
addSequence: function(name) {
this._sequences[name] = {
start: [],
stop: []
};
},
addTextures: function(textures) {
this._textures = textures;
},
remove: function(){},
getAll: function(){},
removeAll: function(){},
getIsRunning: function(){
return this._isRunning;
},
getHooks: function(){
var hookObject = {};
var sequenceKeys = Object.keys(this._sequences);
sequenceKeys.forEach(function(sequence){
// Create an object of the registered hooks
["start", "stop"].forEach(function(type){
this._sequences[sequence][type].forEach(function(hook){
if (!hookObject[hook]) {
hookObject[hook] = {
start: [],
stop: []
};
}
hookObject[hook][type].push(sequence);
});
}, _this);
});
return hookObject;
},
getTexture: function(key){
return this._textures[key];
},
update: function(){},
getAnchorPosition: function(position) {
return this._anchorPosition;
},
setAnchorPosition: function(position) {
this._anchorPosition = position;
},
addNameToMap: function(name, id){
this.nameMap[name] = id;
},
getIdFromNameMap: function(name) {
return _this.nameMap[name];
},
onUpdate: function(delta) {
var deltaInMs = delta * 1000;
var withinMargin = 15;
var entityIDs = Object.keys(_this._entities);
_this._totalDelta += deltaInMs;
// Run through the entities and check if any are ready for edits
entityIDs.forEach(function(ID){
var entity = _this._entities[ID];
var currentIndexTimeStamp = entity._sequenceStartDelta + Number(entity._currentKeys[entity._currentIndex]);
log("CURRENT TIMESTAMP", currentIndexTimeStamp, false);
var timeStampDifference = Math.abs(_this._totalDelta - currentIndexTimeStamp);
log("timeStampDifference", timeStampDifference, false);
if (timeStampDifference <= withinMargin) {
log("entity within timestamp");
entity.editCurrentIndex();
}
});
},
onStart: function(name, hook) {
this._sequences[name].start = this._sequences[name].start.concat(hook);
return this;
},
onStop: function(name, hook) {
this._sequences[name].stop.push(hook);
return this;
},
start: function(){
log("starting animation")
this._isRunning = true;
var entityIDs = Object.keys(_this._entities);
entityIDs.forEach(function(ID){
var entity = _this._entities[ID];
entity.setRunningSequence(this._currentSequence);
entity.updateKeys();
}, this);
Script.update.connect(this.onUpdate);
},
stop: function(){
log("stop is called");
this._totalDelta = 0;
if (this._isRunning) {
log("about to discconect")
Script.update.disconnect(this.onUpdate);
}
var entityIDs = Object.keys(_this._entities);
entityIDs.forEach(function(ID){
var entity = _this._entities[ID];
entity.reset();
}, this);
this._isRunning = false;
},
triggerOn: function(name){
log("trigger on called with", name);
if (this._isRunning) {
return;
}
if (!name) {
name = Object.keys(this._sequences)[0];
}
this._currentSequence = name;
this._isRunning = true;
this.start();
},
triggerOff: function(name){
log("trigger off called with", name);
if (!this._isRunning) {
return;
}
this._currentSequence = null;
this.stop();
this._isRunning = false;
}
};
// SEQUENCER DEFINITIONS
// ////////////////////////////////////////////////////////////////////////
var SEQUENCER = new _Sequence();
SEQUENCER.Particle = function (properties, name) {
log("properties", properties, false)
var orientation = properties.emitOrientation;
log("ORIENTATION:", orientation, false);
orientation = Quat.fromPitchYawRollDegrees(orientation.x,orientation.y,orientation.z);
properties["emitOrientation"] = orientation;
properties.type = "ParticleEffect";
properties.position = SEQUENCER.getAnchorPosition();
properties.name = name;
this._id = Entities.addEntity(properties);
this._name = name;
this._properties = properties;
this._rotation = Entities.getEntityProperties(this._id,'rotation').rotation;
this._currentIndex = 0;
this._currentChangeProperty = null;
this._currentToValue = null;
this._currentSequenceName = null;
this._currentTempSequence = {};
this._runningSequence = null;
this._sequence = {};
this._currentKeys = [];
this._sequenceStartDelta = 0;
this._shouldLoop = false;
this._loopStart = 0;
this._loopEnd = 0;
this._duration = 0;
SEQUENCER.add(this);
};
SEQUENCER.Particle.prototype = {
at: function(time) {
log("AT", time, false);
if (!this._currentTempSequence[String(time)]) {
this._currentTempSequence[String(time)] = [];
}
if (this._currentChangeProperty === LOOP) {
this._shouldLoop = true;
this._loopStart = this.currentToValue;
this._loopEnd = time;
}
this._currentTempSequence[String(time)].push({ change: this._currentChangeProperty, to: this._currentToValue });
this._currentChangeProperty = null;
this._currentToValue = null;
// log("updateKeys", this.currentKeys);
// log("sequence", this.sequence);
return this;
},
change: function (property) {
log("CHANGE", property, false);
this._currentChangeProperty = property;
log("IN CHANGE", this._currentChangeProperty, false);
return this;
},
to: function (value) {
log("IN TO", this._currentChangeProperty, true);
log("VALUE", value, true)
var newValue = value;
if (arguments.length === 3 || (value instanceof Array && value.length > 1)) {
if (this._currentChangeProperty.toLowerCase().indexOf("color") > -1) {
if (arguments.length === 3) {
newValue = {
red: arguments[0],
green: arguments[1],
blue: arguments[2]
};
} else {
newValue = {
red: value[0],
green: value[1],
blue: value[2]
};
}
} else if (
(this._currentChangeProperty.toLowerCase().indexOf("rotation") > -1 ||
this._currentChangeProperty.toLowerCase().indexOf("orientation") > -1) ) {
if (arguments.length === 3) {
newValue = Quat.fromPitchYawRollDegrees(arguments[0], arguments[1], arguments[2]);
} else {
newValue = Quat.fromPitchYawRollDegrees(value[0], value[1], value[2]);
}
} else {
if (arguments.length === 3) {
newValue = {
x: arguments[0],
y: arguments[1],
z: arguments[2]
};
} else {
newValue = {
x: value[0],
y: value[1],
z: value[2]
};
}
}
}
if (this._currentChangeProperty.toLowerCase().indexOf("textures") > -1){
newValue = SEQUENCER.getTexture(value);
log("newValue Texture", newValue, false)
}
this._currentToValue = newValue;
// log("currentToValue", this.currentToValue);
return this;
},
start: function(name) {
log("START", name);
this._sequence[this._currentSequenceName];
this._currentSequenceName = name;
return this;
},
end: function() {
log("END");
this._sequence[this._currentSequenceName] = this._currentTempSequence;
SEQUENCER.addSequence(this._currentSequenceName);
this._currentTempSequence = {};
this._currentSequenceName = null;
this._currentOnHooks = [];
return this;
},
incrementIndex: function() {
this._currentIndex =
this._currentIndex >= this._currentKeys.length - 1
? this._currentIndex = 0
: this._currentIndex += 1;
},
edit: function (propArray) {
var self = this;
var propertiesToChange = propArray.reduce(function (prev, cur) {
var changeAmount = cur.to;
log("CUR.CHANGE", cur.change, true);
if (cur.change === LOOP) {
self._sequenceStartDelta = SEQUENCER._totalDelta;
log("self._sequenceStartDelta", self._sequenceStartDelta);
}
if (cur.change === POSITION) {
var worldOffset = Vec3.multiplyQbyV(self._rotation, cur.to);
var moveTo = Vec3.sum(SEQUENCER.getAnchorPosition(), worldOffset);
changeAmount = moveTo;
}
prev[cur.change] = changeAmount;
return prev;
}, {});
log("propertiesToChange", propertiesToChange, true)
Entities.editEntity(this._id, propertiesToChange);
this.incrementIndex();
},
editCurrentIndex: function() {
this.edit(this._sequence[this._currentSequenceName][this._currentKeys[this._currentIndex]]);
},
getID: function() {
return this._id;
},
sortKeys: function(keys) {
return keys.map(function(key){
return +key
}).sort(function(a, b){return a-b});
},
updateKeys: function() {
log("this.sequence", this._sequence, false);
log("this._currentSequenceName", this._currentSequenceName, false);
this._currentKeys = this.sortKeys(Object.keys(this._sequence[this._currentSequenceName]));
},
reset: function() {
Entities.editEntity(this._id, this._properties);
this._sequenceStartDelta = 0;
},
setName: function(name) {
this._name = name;
},
setRunningSequence: function(name) {
log("setRunningSequence called with", name, false)
this._currentSequenceName = name;
}
};
module.exports = SEQUENCER;