API Docs for: 0.5.5
Show:

File: kick/animation/Curve.js

define(["kick/core/Util", "kick/core/Constants"],
    function (Util, Constants) {
        "use strict";

        var Curve,
            ASSERT = Constants._ASSERT,
            repeat = function(t, length){
                return t - Math.floor(t / length) * length;
            },
            lerpAngle = function(a, b, t){
                var num = repeat(b - a, 360);
                if (num > 180){
                    num -= 360;
                }
                t = Math.max(0,Math.min(1,t));
                return a * num * t;
            };

        /**
         *
         * @class Curve
         * @namespace kick.animation
         * @constructor
         * @param {Config} config defines one or more properties
         */
        Curve = function (config) {
            var controlPoints = [],
                curveType = Curve.NUMBER,
                resArray,
                evaluateTangent = [
                    // number
                    function(value, slope, weight){
                        return value + slope * weight;
                    },
                    // vec2
                    function(value, slope, weight){
                        return [
                            value[0] + slope[0] * weight,
                            value[1] + slope[1] * weight
                        ];
                    },
                    // vec3
                    function(value, slope, weight){
                        return [
                            value[0] + slope[0] * weight,
                            value[1] + slope[1] * weight,
                            value[2] + slope[2] * weight
                        ];
                    },
                    // vec4
                    function(value, slope, weight){
                        return [
                            value[0] + slope[0] * weight,
                            value[1] + slope[1] * weight,
                            value[2] + slope[2] * weight,
                            value[3] + slope[3] * weight
                        ];
                    }/*,
                    // euler
                    function(value, slope, weight){
                        return [
                            value[0] + slope[0] * weight,
                            value[1] + slope[1] * weight,
                            value[2] + slope[2] * weight
                        ];
                    }*/
                ],
                evaluateCurves = [
                    // number
                    function(w1,w2,w3,w4,p1,p2,p3,p4){
                        return w1 * p1 + w2 * p2 + w3 * p3 + w4 * p4;
                    },
                    // vec2
                    function(w1,w2,w3,w4,p1,p2,p3,p4){
                        resArray[0] = w1 * p1[0] + w2 * p2[0] + w3 * p3[0] + w4 * p4[0];
                        resArray[1] = w1 * p1[1] + w2 * p2[1] + w3 * p3[1] + w4 * p4[1];
                        return resArray;
                    },
                    // vec3
                    function(w1,w2,w3,w4,p1,p2,p3,p4){
                        resArray[0] = w1 * p1[0] + w2 * p2[0] + w3 * p3[0] + w4 * p4[0];
                        resArray[1] = w1 * p1[1] + w2 * p2[1] + w3 * p3[1] + w4 * p4[1];
                        resArray[2] = w1 * p1[2] + w2 * p2[2] + w3 * p3[2] + w4 * p4[2];
                        return resArray;
                    },
                    // vec4
                    function(w1,w2,w3,w4,p1,p2,p3,p4){
                        resArray[0] = w1 * p1[0] + w2 * p2[0] + w3 * p3[0] + w4 * p4[0];
                        resArray[1] = w1 * p1[1] + w2 * p2[1] + w3 * p3[1] + w4 * p4[1];
                        resArray[2] = w1 * p1[2] + w2 * p2[2] + w3 * p3[2] + w4 * p4[2];
                        resArray[3] = w1 * p1[3] + w2 * p2[3] + w3 * p3[3] + w4 * p4[3];
                        return resArray;
                    }//,
                    // eulers angels
                    /*function(t,p1,p2,p3,p4){
                        var tmp1,tmp2,tmp3,tmp4,tmp5;

                        tmp1 = [lerpAngle(p1[0], p2[0], t), lerpAngle(p1[1], p2[1], t), lerpAngle(p1[2], p2[2], t)];
                        tmp2 = [lerpAngle(p2[0], p3[0], t), lerpAngle(p2[1], p3[1], t), lerpAngle(p2[2], p3[2], t)];
                        tmp3 = [lerpAngle(p3[0], p4[0], t), lerpAngle(p3[1], p4[1], t), lerpAngle(p3[2], p4[2], t)];

                        tmp4 = [lerpAngle(tmp1[0], tmp2[0], t), lerpAngle(tmp1[1], tmp2[1], t), lerpAngle(tmp1[2], tmp2[2], t)];
                        tmp5 = [lerpAngle(tmp2[0], tmp3[0], t), lerpAngle(tmp2[1], tmp3[1], t), lerpAngle(tmp2[2], tmp3[2], t)];

                        resArray[0] = lerpAngle(tmp4[0], tmp5[0], t);
                        resArray[1] = lerpAngle(tmp4[1], tmp5[1], t);
                        resArray[2] = lerpAngle(tmp4[2], tmp5[2], t);
                        return resArray;
                    }*/
                ],
                currentCurveEvaluation = evaluateCurves[curveType],
                currentEvaluateTangent = evaluateTangent[curveType];

            Object.defineProperties(this, {
                /**
                 * Must be Curve.NUMBER, Curve.VEC2, Curve.VEC3, Curve.EULERS_ANGELS, Curve.VEC4
                 * @property curveType
                 * @type Number
                 */
                curveType: {
                    set: function(newValue){
                        if (curveType === newValue){
                            return;
                        }
                        curveType = newValue;
                        if (curveType === Curve.VEC2){
                            resArray = new Float32Array(2);
                        }
                        if (curveType === Curve.VEC3 || curveType === Curve.EULERS_ANGELS){
                            resArray = new Float32Array(3);
                        }
                        if (curveType === Curve.VEC4){
                            resArray = new Float32Array(4);
                        }

                        if (ASSERT){
                            if (controlPoints.length > 0){
                                Util.warn("Cannot change curvetype when curve is not empty");
                            }
                        }
                        currentCurveEvaluation = evaluateCurves[curveType];
                        currentEvaluateTangent = evaluateTangent[curveType];
                    },
                    get: function(){
                        return curveType;
                    }
                },
                /**
                 * @property startTime
                 * @type Number
                 * @readOnly
                 */
                startTime: {
                    get: function(){
                        return controlPoints[0].time;
                    }
                },
                /**
                 * @property endTime
                 * @type Number
                 * @readOnly
                 */
                endTime: {
                    get: function(){
                        return controlPoints[controlPoints.length-1].time;
                    }
                }
            });

            /**
             * Removes all control points within the curve
             * @method clear
             */
            this.clear = function(){
                controlPoints.length = 0;
            };

            /**
             * @method addControlPoint
             * @param {kick.animation.ControlPoint} controlPoint
             */
            this.addControlPoint = function(controlPoint){
                var i;
                for (i = 0; i < controlPoints.length; i++) {
                    if (controlPoint.time < controlPoints[i]){
                        break;
                    }
                }
                controlPoints.splice(i, 0, controlPoint);
            };

            /**
             * @method evaluate
             * @param time
             * @returns {*}
             */
            this.evaluate = function(time){
                var i,
                    from,
                    to,
                    timeDelta,
                    u,
                    uMinusOne,
                    w1,
                    w2,
                    w3,
                    w4,
                    p0,
                    p1,
                    p2,
                    p3;
                if (time < controlPoints[0].time){
                    return controlPoints[0].time;
                }
                // find two end points
                for (i=1;i < controlPoints.length && controlPoints[i].time<time;i++){
                    // do nothing
                }
                if (i === controlPoints.length) {
                    return controlPoints[i-1].value;
                }
                from = controlPoints[i-1];
                to = controlPoints[i];
                timeDelta = to.time - from.time;
                u = (time - from.time) / timeDelta;
                p0 = from.value;
                p1 = currentEvaluateTangent(from.value,from.outSlope, timeDelta/3);
                p2 = currentEvaluateTangent(to.value,to.inSlope, -timeDelta/3);
                p3 = to.value;
                uMinusOne = 1-u;
                w1 = uMinusOne * uMinusOne * uMinusOne;
                w2 = 3 * u * uMinusOne * uMinusOne;
                w3 = 3 * u * u * uMinusOne;
                w4 = u * u * u;

                return currentCurveEvaluation(w1, w2, w3, w4, p0, p1, p2, p3);
            };
            Util.copyStaticPropertiesToObject(this, Curve);
        };

        /**
         * @property NUMBER
         * @type Number
         * @readOnly
         * @static
         */
        Curve.NUMBER = 0;
        /**
         * @property VEC2
         * @type Number
         * @readOnly
         * @static
         */
        Curve.VEC2 = 1;
        /**
         * @property VEC3
         * @type Number
         * @readOnly
         * @static
         */
        Curve.VEC3 = 2;
        /**
         * @property VEC4
         * @type Number
         * @readOnly
         * @static
         */
        Curve.VEC4 = 3;
//        Curve.EULERS_ANGELS = 4;

        return Curve;
    }
);