Source: math/vec3.js

if (typeof(define) !== "function") {
    var define = require("amdefine")(module);
}
define([
        "odin/math/mathf"
    ],
    function(Mathf) {
        "use strict";


        var sqrt = Math.sqrt;

        /**
         * @class Vec3
         * 3d vector
         * @param Number x
         * @param Number y
         * @param Number z
         */
        function Vec3(x, y, z) {

            /**
             * @property Number x
             * @memberof Odin.Vec3
             */
            this.x = x || 0;

            /**
             * @property Number y
             * @memberof Odin.Vec3
             */
            this.y = y || 0;

            /**
             * @property Number z
             * @memberof Odin.Vec3
             */
            this.z = z || 0;
        }

        Mathf._classes["Vec3"] = Vec3;

        /**
         * @method clone
         * @memberof Odin.Vec3
         * returns new instance of this
         * @return Vec3
         */
        Vec3.prototype.clone = function() {

            return new Vec3(this.x, this.y, this.z);
        };

        /**
         * @method copy
         * @memberof Odin.Vec3
         * copies other
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.copy = function(other) {

            this.x = other.x;
            this.y = other.y;
            this.z = other.z;

            return this;
        };

        /**
         * @method set
         * @memberof Odin.Vec3
         * sets values of this
         * @param Number x
         * @param Number y
         * @param Number z
         * @return this
         */
        Vec3.prototype.set = function(x, y, z) {

            this.x = x;
            this.y = y;
            this.z = z;

            return this;
        };

        /**
         * @method add
         * @memberof Odin.Vec3
         * adds other's values to this
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.add = function(other) {

            this.x += other.x;
            this.y += other.y;
            this.z += other.z;

            return this;
        };

        /**
         * @method vadd
         * @memberof Odin.Vec3
         * adds a and b together saves it in this
         * @param Vec3 a
         * @param Vec3 b
         * @return this
         */
        Vec3.prototype.vadd = function(a, b) {

            this.x = a.x + b.x;
            this.y = a.y + b.y;
            this.z = a.z + b.z;

            return this;
        };

        /**
         * @method sadd
         * @memberof Odin.Vec3
         * adds scalar value to this
         * @param Number s
         * @return this
         */
        Vec3.prototype.sadd = function(s) {

            this.x += s;
            this.y += s;
            this.z += s;

            return this;
        };

        /**
         * @method sub
         * @memberof Odin.Vec3
         * subtracts other's values from this
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.sub = function(other) {

            this.x -= other.x;
            this.y -= other.y;
            this.z -= other.z;

            return this;
        };

        /**
         * @method vsub
         * @memberof Odin.Vec3
         * subtracts b from a saves it in this
         * @param Vec3 a
         * @param Vec3 b
         * @return this
         */
        Vec3.prototype.vsub = function(a, b) {

            this.x = a.x - b.x;
            this.y = a.y - b.y;
            this.z = a.z - b.z;

            return this;
        };

        /**
         * @method ssub
         * @memberof Odin.Vec3
         * subtracts this by a scalar value
         * @param Number s
         * @return this
         */
        Vec3.prototype.ssub = function(s) {

            this.x -= s;
            this.y -= s;
            this.z -= s;

            return this;
        };

        /**
         * @method mul
         * @memberof Odin.Vec3
         * muliples this's values by other's
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.mul = function(other) {

            this.x *= other.x;
            this.y *= other.y;
            this.z *= other.z;

            return this;
        };

        /**
         * @method vmul
         * @memberof Odin.Vec3
         * muliples a and b saves it in this
         * @param Vec3 a
         * @param Vec3 b
         * @return this
         */
        Vec3.prototype.vmul = function(a, b) {

            this.x = a.x * b.x;
            this.y = a.y * b.y;
            this.z = a.z * b.z;

            return this;
        };

        /**
         * @method smul
         * @memberof Odin.Vec3
         * muliples this by a scalar value
         * @param Number s
         * @return this
         */
        Vec3.prototype.smul = function(s) {

            this.x *= s;
            this.y *= s;
            this.z *= s;

            return this;
        };

        /**
         * @method div
         * @memberof Odin.Vec3
         * divides this's values by other's
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.div = function(other) {
            var x = other.x,
                y = other.y,
                z = other.z;

            this.x *= x !== 0 ? 1 / x : 0;
            this.y *= y !== 0 ? 1 / y : 0;
            this.z *= z !== 0 ? 1 / z : 0;

            return this;
        };

        /**
         * @method vdiv
         * @memberof Odin.Vec3
         * divides b from a saves it in this
         * @param Vec3 a
         * @param Vec3 b
         * @return this
         */
        Vec3.prototype.vdiv = function(a, b) {
            var x = b.x,
                y = b.y,
                z = b.z;

            this.x = x !== 0 ? a.x / x : 0;
            this.y = y !== 0 ? a.y / y : 0;
            this.z = z !== 0 ? a.z / z : 0;

            return this;
        };

        /**
         * @method sdiv
         * @memberof Odin.Vec3
         * divides this by scalar value
         * @param Number s
         * @return this
         */
        Vec3.prototype.sdiv = function(s) {
            s = s === 0 ? 0 : 1 / s;

            this.x *= s;
            this.y *= s;
            this.z *= s;

            return this;
        };

        /**
         * @method length
         * @memberof Odin.Vec3
         * returns the length of this
         * @return Number
         */
        Vec3.prototype.length = function() {
            var x = this.x,
                y = this.y,
                z = this.z,
                lsq = x * x + y * y + z * z;

            if (lsq === 1) return 1;

            return lsq === 0 ? 0 : sqrt(lsq);
        };

        /**
         * @method lengthSq
         * @memberof Odin.Vec3
         * returns the squared length of this
         * @return Number
         */
        Vec3.prototype.lengthSq = function() {
            var x = this.x,
                y = this.y,
                z = this.z;

            return x * x + y * y + z * z;
        };

        /**
         * @method setLength
         * @memberof Odin.Vec3
         * sets this so its magnitude is equal to length
         * @param Number length
         * @return Vec3
         */
        Vec3.prototype.setLength = function(length) {
            var x = this.x,
                y = this.y,
                z = this.z,
                l = x * x + y * y + z * z;

            if (l === 1) {
                this.x *= length;
                this.y *= length;
                this.z *= length;

                return this;
            }

            l = l > 0 ? 1 / sqrt(l) : 0;

            this.x *= l * length;
            this.y *= l * length;
            this.z *= l * length;

            return this;
        };

        /**
         * @method normalize
         * @memberof Odin.Vec3
         * returns this with a length of 1
         * @return this
         */
        Vec3.prototype.normalize = function() {
            var x = this.x,
                y = this.y,
                z = this.z,
                l = x * x + y * y + z * z;

            if (l === 1) return this;

            l = l > 0 ? 1 / sqrt(l) : 0;

            this.x *= l;
            this.y *= l;
            this.z *= l;

            return this;
        };

        /**
         * @method inverse
         * @memberof Odin.Vec3
         * returns the inverse of this
         * @return this
         */
        Vec3.prototype.inverse = function() {

            this.x *= -1;
            this.y *= -1;
            this.z *= -1;

            return this;
        };

        /**
         * @method inverseVec
         * @memberof Odin.Vec3
         * returns the inverse of other
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.inverseVec = function(other) {

            this.x = -other.x;
            this.y = -other.y;
            this.z = -other.z;

            return this;
        };

        /**
         * @method lerp
         * @memberof Odin.Vec3
         * linear interpolation between this and other by x
         * @param Vec3 other
         * @param Number x
         * @return Vec3
         */
        Vec3.prototype.lerp = function(other, x) {

            this.x += (other.x - this.x) * x;
            this.y += (other.y - this.y) * x;
            this.z += (other.z - this.z) * x;

            return this;
        };

        /**
         * @method vlerp
         * @memberof Odin.Vec3
         * linear interpolation between a and b by x
         * @param Vec3 a
         * @param Vec3 b
         * @param Number x
         * @return Vec3
         */
        Vec3.prototype.vlerp = function(a, b, x) {
            var ax = a.x,
                ay = a.y,
                az = a.z;

            this.x = ax + (b.x - ax) * x;
            this.y = ay + (b.y - ay) * x;
            this.z = az + (b.z - az) * x;

            return this;
        };

        /**
         * @method vdot
         * @memberof Odin.Vec3
         * dot product of two vectors, can be called as a static function Vec3.vdot( a, b )
         * @param Vec3 a
         * @param Vec3 b
         * @return Number
         */
        Vec3.vdot = Vec3.prototype.vdot = function(a, b) {

            return a.x * b.x + a.y * b.y + a.z * b.z;
        };

        /**
         * @method dot
         * @memberof Odin.Vec3
         * dot product of this and other vector
         * @param Vec3 other
         * @return Number
         */
        Vec3.prototype.dot = function(other) {

            return this.x * other.x + this.y * other.y + this.z * other.z;
        };

        /**
         * @method vcross
         * @memberof Odin.Vec3
         * cross product between a vector and b vector, can be called as a static function Vec3.vcross( a, b )
         * @param Vec3 a
         * @param Vec3 b
         * @return Number
         */
        Vec3.vcross = Vec3.prototype.vcross = function(a, b) {
            var ax = a.x,
                ay = a.y,
                az = a.z,
                bx = b.x,
                by = b.y,
                bz = b.z;

            this.x = ay * bz - az * by;
            this.y = az * bx - ax * bz;
            this.z = ax * by - ay * bx;

            return this;
        };

        /**
         * @method cross
         * @memberof Odin.Vec3
         * cross product between this vector and other
         * @param Vec3 other
         * @return Number
         */
        Vec3.prototype.cross = function(other) {
            var ax = this.x,
                ay = this.y,
                az = this.z,
                bx = other.x,
                by = other.y,
                bz = other.z;

            this.x = ay * bz - az * by;
            this.y = az * bx - ax * bz;
            this.z = ax * by - ay * bx;

            return this;
        };

        /**
         * @method min
         * @memberof Odin.Vec3
         * returns min values from this and other vector
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.min = function(other) {
            var ax = this.x,
                ay = this.y,
                az = this.z,
                bx = other.x,
                by = other.y,
                bz = other.z;

            this.x = bx < ax ? bx : ax;
            this.y = by < ay ? by : ay;
            this.z = bz < az ? bz : az;

            return this;
        };

        /**
         * @method max
         * @memberof Odin.Vec3
         * returns max values from this and other vector
         * @param Vec3 other
         * @return this
         */
        Vec3.prototype.max = function(other) {
            var ax = this.x,
                ay = this.y,
                az = this.z,
                bx = other.x,
                by = other.y,
                bz = other.z;

            this.x = bx > ax ? bx : ax;
            this.y = by > ay ? by : ay;
            this.z = bz > az ? bz : az;

            return this;
        };

        /**
         * @method clamp
         * @memberof Odin.Vec3
         * clamp values between min and max's values
         * @param Vec3 min
         * @param Vec3 max
         * @return this
         */
        Vec3.prototype.clamp = function(min, max) {
            var x = this.x,
                y = this.y,
                z = this.z,
                minx = min.x,
                miny = min.y,
                minz = min.z,
                maxx = max.x,
                maxy = max.y,
                maxz = max.z;

            this.x = x < minx ? minx : x > maxx ? maxx : x;
            this.y = y < miny ? miny : y > maxy ? maxy : y;
            this.z = z < minz ? minz : z > maxz ? maxz : z;

            return this;
        };

        /**
         * @method transformMat3
         * @memberof Odin.Vec3
         * transforms this with Mat3
         * @param Mat3 m
         * @return this
         */
        Vec3.prototype.transformMat3 = function(m) {
            var me = m.elements,
                x = this.x,
                y = this.y,
                z = this.z;

            this.x = x * me[0] + y * me[3] + z * me[6];
            this.y = x * me[1] + y * me[4] + z * me[7];
            this.z = x * me[2] + y * me[5] + z * me[8];

            return this;
        };

        /**
         * @method transformMat4
         * @memberof Odin.Vec3
         * transforms this with Mat4
         * @param Mat4 m
         * @return this
         */
        Vec3.prototype.transformMat4 = function(m) {
            var me = m.elements,
                x = this.x,
                y = this.y,
                z = this.z;

            this.x = x * me[0] + y * me[4] + z * me[8] + me[12];
            this.y = x * me[1] + y * me[5] + z * me[9] + me[13];
            this.z = x * me[2] + y * me[6] + z * me[10] + me[14];

            return this;
        };

        /**
         * @method transformProjection
         * @memberof Odin.Vec3
         * transforms this with Mat4 projection matrix
         * @param Mat4 m
         * @return this
         */
        Vec3.prototype.transformProjection = function(m) {
            var me = m.elements,
                x = this.x,
                y = this.y,
                z = this.z,
                d = 1 / (me[3] * x + me[7] * y + me[11] * z + me[15]);

            this.x = (me[0] * x + me[4] * y + me[8] * z + me[12]) * d;
            this.y = (me[1] * x + me[5] * y + me[9] * z + me[13]) * d;
            this.z = (me[2] * x + me[6] * y + me[10] * z + me[14]) * d;

            return this;
        };

        /**
         * @method transformQuat
         * @memberof Odin.Vec3
         * transforms this with Quat
         * @param Quat q
         * @return this
         */
        Vec3.prototype.transformQuat = function(q) {
            var x = this.x,
                y = this.y,
                z = this.z,
                qx = q.x,
                qy = q.y,
                qz = q.z,
                qw = q.w,

                ix = qw * x + qy * z - qz * y,
                iy = qw * y + qz * x - qx * z,
                iz = qw * z + qx * y - qy * x,
                iw = -qx * x - qy * y - qz * z;

            this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
            this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
            this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;

            return this;
        };

        /**
         * @method fromVec2
         * @memberof Odin.Vec3
         * sets values from Vec2
         * @param Vec2 v
         * @return this
         */
        Vec3.prototype.fromVec2 = function(v) {

            this.x = v.x;
            this.y = v.y;
            this.z = 0;

            return this;
        };

        /**
         * @method fromVec4
         * @memberof Odin.Vec3
         * sets position from Vec4
         * @param Vec4 v
         * @return this
         */
        Vec3.prototype.fromVec4 = function(v) {

            this.x = v.x;
            this.y = v.y;
            this.z = v.z;

            return this;
        };

        /**
         * @method positionFromMat4
         * @memberof Odin.Vec3
         * sets position from Mat4
         * @param Mat4 m
         * @return this
         */
        Vec3.prototype.positionFromMat4 = function(m) {
            var me = m.elements;

            this.x = me[12];
            this.y = me[13];
            this.z = me[14];

            return this;
        };

        /**
         * @method scaleFromMat3
         * @memberof Odin.Vec3
         * sets this from Mat3 scale
         * @param Mat3 m
         * @return this
         */
        Vec3.prototype.scaleFromMat3 = function(m) {
            var me = m.elements,
                x = this.set(me[0], me[3], me[6]).length(),
                y = this.set(me[1], me[4], me[7]).length(),
                z = this.set(me[2], me[5], me[8]).length();

            this.x = x;
            this.y = y;
            this.z = z;

            return this;
        };

        /**
         * @method scaleFromMat4
         * @memberof Odin.Vec3
         * sets this from Mat4 scale
         * @param Mat4 m
         * @return this
         */
        Vec3.prototype.scaleFromMat4 = function(m) {
            var me = m.elements,
                x = this.set(me[0], me[4], me[8]).length(),
                y = this.set(me[1], me[5], me[9]).length(),
                z = this.set(me[2], me[6], me[10]).length();

            this.x = x;
            this.y = y;
            this.z = z;

            return this;
        };

        /**
         * @memberof Odin.Vec3
         * @param Odin.Vec3 other
         * @return this
         */
        Vec3.prototype.equals = function(other) {

            return !(
                this.x !== other.x ||
                this.y !== other.y ||
                this.z !== other.z
            );
        };

        /**
         * @method fromJSON
         * @memberof Odin.Vec3
         * sets values from JSON object
         * @param Object json
         * @return this
         */
        Vec3.prototype.fromJSON = function(json) {

            this.x = json.x;
            this.y = json.y;
            this.z = json.z;

            return this;
        };

        /**
         * @method toJSON
         * @memberof Odin.Vec3
         * returns json object of this
         * @return Object
         */
        Vec3.prototype.toJSON = function(json) {
            json || (json = {});

            json._className = "Vec3";
            json.x = this.x;
            json.y = this.y;
            json.z = this.z;

            return json;
        };

        /**
         * @method fromArray
         * @memberof Odin.Vec3
         * sets values from Array object
         * @param Array array
         * @return this
         */
        Vec3.prototype.fromArray = function(array) {

            this.x = array[0];
            this.y = array[1];
            this.z = array[2];

            return this;
        };

        /**
         * @method toArray
         * @memberof Odin.Vec3
         * returns array object of this
         * @return Array
         */
        Vec3.prototype.toArray = function(array) {
            array || (array = []);

            array[0] = this.x;
            array[1] = this.y;
            array[2] = this.z;

            return array;
        };

        /**
         * @method toString
         * @memberof Odin.Vec3
         * returns string of this
         * @return String
         */
        Vec3.prototype.toString = function() {

            return "Vec3( " + this.x + ", " + this.y + ", " + this.z + " )";
        };


        return Vec3;
    }
);