blob: 2ee0e272298e5615a6f3c303a4558920d8592419 [file] [log] [blame]
(function addPropertyDecorator() {
function getStaticValueAtTime() {
return this.pv;
}
function loopOut(type,duration,durationFlag){
if(!this.k || !this.keyframes){
return this.pv;
}
type = type ? type.toLowerCase() : '';
var currentFrame = this.comp.renderedFrame;
var keyframes = this.keyframes;
var lastKeyFrame = keyframes[keyframes.length - 1].t;
if(currentFrame<=lastKeyFrame){
return this.pv;
}else{
var cycleDuration, firstKeyFrame;
if(!durationFlag){
if(!duration || duration > keyframes.length - 1){
duration = keyframes.length - 1;
}
firstKeyFrame = keyframes[keyframes.length - 1 - duration].t;
cycleDuration = lastKeyFrame - firstKeyFrame;
} else {
if(!duration){
cycleDuration = Math.max(0,lastKeyFrame - this.elem.data.ip);
} else {
cycleDuration = Math.abs(lastKeyFrame - elem.comp.globalData.frameRate*duration);
}
firstKeyFrame = lastKeyFrame - cycleDuration;
}
var i, len, ret;
if(type === 'pingpong') {
var iterations = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
if(iterations % 2 !== 0){
return this.getValueAtTime(((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0);
}
} else if(type === 'offset'){
var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0);
var repeats = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
if(this.pv.length){
ret = new Array(initV.length);
len = ret.length;
for(i=0;i<len;i+=1){
ret[i] = (endV[i]-initV[i])*repeats + current[i];
}
return ret;
}
return (endV-initV)*repeats + current;
} else if(type === 'continue'){
var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0);
if(this.pv.length){
ret = new Array(lastValue.length);
len = ret.length;
for(i=0;i<len;i+=1){
ret[i] = lastValue[i] + (lastValue[i]-nextLastValue[i])*((currentFrame - lastKeyFrame)/ this.comp.globalData.frameRate)/0.0005;
}
return ret;
}
return lastValue + (lastValue-nextLastValue)*(((currentFrame - lastKeyFrame))/0.001);
}
return this.getValueAtTime((((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0);
}
}
function loopIn(type,duration, durationFlag) {
if(!this.k){
return this.pv;
}
type = type ? type.toLowerCase() : '';
var currentFrame = this.comp.renderedFrame;
var keyframes = this.keyframes;
var firstKeyFrame = keyframes[0].t;
if(currentFrame>=firstKeyFrame){
return this.pv;
}else{
var cycleDuration, lastKeyFrame;
if(!durationFlag){
if(!duration || duration > keyframes.length - 1){
duration = keyframes.length - 1;
}
lastKeyFrame = keyframes[duration].t;
cycleDuration = lastKeyFrame - firstKeyFrame;
} else {
if(!duration){
cycleDuration = Math.max(0,this.elem.data.op - firstKeyFrame);
} else {
cycleDuration = Math.abs(elem.comp.globalData.frameRate*duration);
}
lastKeyFrame = firstKeyFrame + cycleDuration;
}
var i, len, ret;
if(type === 'pingpong') {
var iterations = Math.floor((firstKeyFrame - currentFrame)/cycleDuration);
if(iterations % 2 === 0){
return this.getValueAtTime((((firstKeyFrame - currentFrame)%cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0);
}
} else if(type === 'offset'){
var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
var current = this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame)%cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0);
var repeats = Math.floor((firstKeyFrame - currentFrame)/cycleDuration)+1;
if(this.pv.length){
ret = new Array(initV.length);
len = ret.length;
for(i=0;i<len;i+=1){
ret[i] = current[i]-(endV[i]-initV[i])*repeats;
}
return ret;
}
return current-(endV-initV)*repeats;
} else if(type === 'continue'){
var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0);
if(this.pv.length){
ret = new Array(firstValue.length);
len = ret.length;
for(i=0;i<len;i+=1){
ret[i] = firstValue[i] + (firstValue[i]-nextFirstValue[i])*(firstKeyFrame - currentFrame)/0.001;
}
return ret;
}
return firstValue + (firstValue-nextFirstValue)*(firstKeyFrame - currentFrame)/0.001;
}
return this.getValueAtTime(((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0);
}
}
function getValueAtTime(frameNum) {
//TODO this shouldn't be necessary anymore
if(!this._cachingAtTime) {
this._cachingAtTime = {lastValue:initialDefaultFrame,lastIndex:0};
}
if(frameNum !== this._cachingAtTime.lastFrame) {
frameNum *= this.elem.globalData.frameRate;
frameNum -= this.offsetTime;
this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0;
this._cachingAtTime.value = this.interpolateValue(frameNum, this.pv, this._cachingAtTime);
this._cachingAtTime.lastFrame = frameNum;
}
return this._cachingAtTime.value;
}
function getVelocityAtTime(frameNum) {
if(this.vel !== undefined){
return this.vel;
}
var delta = -0.01;
//frameNum += this.elem.data.st;
var v1 = this.getValueAtTime(frameNum);
var v2 = this.getValueAtTime(frameNum + delta);
var velocity;
if(v1.length){
velocity = createTypedArray('float32', v1.length);
var i;
for(i=0;i<v1.length;i+=1){
//removing frameRate
//if needed, don't add it here
//velocity[i] = this.elem.globalData.frameRate*((v2[i] - v1[i])/delta);
velocity[i] = (v2[i] - v1[i])/delta;
}
} else {
velocity = (v2 - v1)/delta;
}
return velocity;
};
function setGroupProperty(propertyGroup){
this.propertyGroup = propertyGroup;
}
function searchExpressions(elem,data,prop){
if(data.x){
prop.k = true;
prop.x = true;
if(prop.getValue) {
prop.getPreValue = prop.getValue;
}
prop.initiateExpression = ExpressionManager.initiateExpression;
prop.getValue = prop.initiateExpression(elem,data,prop);
}
}
function getTransformValueAtTime(time) {
//console.log('time:', time)
}
function getTransformStaticValueAtTime(time) {
}
var TextExpressionSelectorProp = (function(){
function getValueProxy(index,total){
this.textIndex = index+1;
this.textTotal = total;
this.getValue();
return this.v;
}
return function TextExpressionSelectorProp(elem,data){
this.pv = 1;
this.comp = elem.comp;
this.elem = elem;
this.mult = .01;
this.propType = 'textSelector';
this.textTotal = data.totalChars;
this.selectorValue = 100;
this.lastValue = [1,1,1];
searchExpressions.bind(this)(elem,data,this);
this.getMult = getValueProxy;
this.getVelocityAtTime = getVelocityAtTime;
if(this.kf){
this.getValueAtTime = getValueAtTime.bind(this);
} else {
this.getValueAtTime = getStaticValueAtTime.bind(this);
}
this.setGroupProperty = setGroupProperty;
}
}());
var getTransformProperty = TransformPropertyFactory.getTransformProperty;
TransformPropertyFactory.getTransformProperty = function(elem, data, arr) {
var prop = getTransformProperty(elem, data, arr);
if(prop.dynamicProperties.length) {
prop.getValueAtTime = getTransformValueAtTime.bind(prop);
} else {
prop.getValueAtTime = getTransformStaticValueAtTime.bind(prop);
}
prop.setGroupProperty = setGroupProperty;
return prop;
}
var propertyGetProp = PropertyFactory.getProp;
PropertyFactory.getProp = function(elem,data,type, mult, arr){
var prop = propertyGetProp(elem,data,type, mult, arr);
//prop.getVelocityAtTime = getVelocityAtTime;
//prop.loopOut = loopOut;
//prop.loopIn = loopIn;
if(prop.kf){
prop.getValueAtTime = getValueAtTime.bind(prop);
} else {
prop.getValueAtTime = getStaticValueAtTime.bind(prop);
}
prop.setGroupProperty = setGroupProperty;
prop.loopOut = loopOut;
prop.loopIn = loopIn;
prop.getVelocityAtTime = getVelocityAtTime;
prop.numKeys = data.a === 1 ? data.k.length : 0;
var isAdded = prop.k;
prop.propertyIndex = data.ix;
prop._cachingAtTime={lastFrame:initialDefaultFrame,lastIndex:0,value:type === 0 ? 0 : createTypedArray('float32', 3)}
searchExpressions(elem,data,prop);
if(!isAdded && prop.x){
arr.push(prop);
}
return prop;
}
function getShapeValueAtTime(frameNum) {
//TODO test this
if (!this._cachingAtTime) {
this._cachingAtTime = {
shapeValue: shape_pool.clone(this.pv),
lastIndex: 0,
lastTime: initialDefaultFrame
}
}
if(frameNum !== this._cachingAtTime.lastTime) {
this._cachingAtTime.lastTime = frameNum;
frameNum *= this.elem.globalData.frameRate;
this.interpolateShape(frameNum, this._cachingAtTime.shapeValue, false, this._cachingAtTime);
}
return this._cachingAtTime.shapeValue;
}
var ShapePropertyConstructorFunction = ShapePropertyFactory.getConstructorFunction();
var KeyframedShapePropertyConstructorFunction = ShapePropertyFactory.getKeyframedConstructorFunction();
function ShapeExpressions(){}
ShapeExpressions.prototype = {
vertices: function(prop, time){
var shapePath = this.v;
if(time !== undefined) {
shapePath = this.getValueAtTime(time, 0);
}
var i, len = shapePath._length;
var vertices = shapePath[prop];
var points = shapePath.v;
var arr = createSizedArray(len);
for(i = 0; i < len; i += 1) {
if(prop === 'i' || prop === 'o') {
arr[i] = [vertices[i][0] - points[i][0], vertices[i][1] - points[i][1]]
} else {
arr[i] = [vertices[i][0], vertices[i][1]]
}
}
return arr;
},
points: function(time){
return this.vertices('v', time);
},
inTangents: function(time){
return this.vertices('i', time);
},
outTangents: function(time){
return this.vertices('o', time);
},
isClosed: function(){
return this.v.c;
},
pointOnPath: function(perc, time){
var shapePath = this.v;
if(time !== undefined) {
shapePath = this.getValueAtTime(time, 0);
}
if(!this._segmentsLength) {
this._segmentsLength = bez.getSegmentsLength(shapePath);
}
var segmentsLength = this._segmentsLength;
var lengths = segmentsLength.lengths;
var lengthPos = segmentsLength.totalLength * perc;
var i = 0, len = lengths.length;
var j = 0, jLen;
var accumulatedLength = 0;
while(i < len) {
if(accumulatedLength + lengths[i].addedLength > lengthPos) {
var initIndex = i;
var endIndex = (shapePath.c && i === len - 1) ? 0 : i + 1;
var segmentPerc = (lengthPos - accumulatedLength)/lengths[i].addedLength;
var pt = bez.getPointInSegment(shapePath.v[initIndex], shapePath.v[endIndex], shapePath.o[initIndex], shapePath.i[endIndex], segmentPerc, lengths[i])
break;
} else {
accumulatedLength += lengths[i].addedLength;
}
i += 1;
}
if(!pt){
pt = shapePath.c ? [shapePath.v[0][0],shapePath.v[0][1]]:[shapePath.v[shapePath._length-1][0],shapePath.v[shapePath._length-1][1]]
}
return pt;
},
vectorOnPath: function(perc, time, vectorType){
//perc doesn't use triple equality because it can be a Number object as well as a primitive.
perc = perc == 1 ? this.v.c ? 0 : 0.999 : perc;
var pt1 = this.pointOnPath(perc, time);
var pt2 = this.pointOnPath(perc + 0.001, time);
var xLength = pt2[0] - pt1[0];
var yLength = pt2[1] - pt1[1];
var magnitude = Math.sqrt(Math.pow(xLength,2) + Math.pow(yLength,2));
var unitVector = vectorType === 'tangent' ? [xLength/magnitude, yLength/magnitude] : [-yLength/magnitude, xLength/magnitude];
return unitVector;
},
tangentOnPath: function(perc, time){
return this.vectorOnPath(perc, time, 'tangent');
},
normalOnPath: function(perc, time){
return this.vectorOnPath(perc, time, 'normal');
},
setGroupProperty: setGroupProperty,
getValueAtTime: getStaticValueAtTime
}
extendPrototype([ShapeExpressions], ShapePropertyConstructorFunction);
extendPrototype([ShapeExpressions], KeyframedShapePropertyConstructorFunction);
KeyframedShapePropertyConstructorFunction.prototype.getValueAtTime = getShapeValueAtTime;
KeyframedShapePropertyConstructorFunction.prototype.initiateExpression = ExpressionManager.initiateExpression;
var propertyGetShapeProp = ShapePropertyFactory.getShapeProp;
ShapePropertyFactory.getShapeProp = function(elem,data,type, arr, trims){
var prop = propertyGetShapeProp(elem,data,type, arr, trims);
var isAdded = prop.k;
prop.propertyIndex = data.ix;
prop.lock = false;
if(type === 3){
searchExpressions(elem,data.pt,prop);
} else if(type === 4){
searchExpressions(elem,data.ks,prop);
}
if(!isAdded && prop.x){
arr.push(prop);
}
return prop;
}
var propertyGetTextProp = TextSelectorProp.getTextSelectorProp;
TextSelectorProp.getTextSelectorProp = function(elem, data,arr){
if(data.t === 1){
return new TextExpressionSelectorProp(elem, data,arr);
} else {
return propertyGetTextProp(elem,data,arr);
}
}
}());