if (typeof(define) !== "function") {
var define = require("amdefine")(module);
}
define([
"odin/math/mathf",
"odin/math/vec3"
],
function(Mathf, Vec3) {
"use strict";
var abs = Math.abs,
sqrt = Math.sqrt,
acos = Math.acos,
sin = Math.sin,
cos = Math.cos,
EPSILON = Mathf.EPSILON;
/**
* @class Quat
* quaterian
* @param Number x
* @param Number y
* @param Number z
* @param Number w
*/
function Quat(x, y, z, w) {
/**
* @property Number x
* @memberof Odin.Quat
*/
this.x = x || 0;
/**
* @property Number y
* @memberof Odin.Quat
*/
this.y = y || 0;
/**
* @property Number z
* @memberof Odin.Quat
*/
this.z = z || 0;
/**
* @property Number w
* @memberof Odin.Quat
*/
this.w = w !== undefined ? w : 1;
}
Mathf._classes["Quat"] = Quat;
/**
* @method clone
* @memberof Odin.Quat
* returns new instance of this
* @return Quat
*/
Quat.prototype.clone = function() {
return new Quat(this.x, this.y, this.z, this.w);
};
/**
* @method copy
* @memberof Odin.Quat
* copies other
* @param Quat other
* @return this
*/
Quat.prototype.copy = function(other) {
this.x = other.x;
this.y = other.y;
this.z = other.z;
this.w = other.w;
return this;
};
/**
* @method set
* @memberof Odin.Quat
* sets values of this
* @param Number x
* @param Number y
* @param Number z
* @param Number w
* @return this
*/
Quat.prototype.set = function(x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
};
/**
* @method mul
* @memberof Odin.Quat
* muliples this's values by other's
* @param Quat other
* @return this
*/
Quat.prototype.mul = function(other) {
var ax = this.x,
ay = this.y,
az = this.z,
aw = this.w,
bx = other.x,
by = other.y,
bz = other.z,
bw = other.w;
this.x = ax * bw + aw * bx + ay * bz - az * by;
this.y = ay * bw + aw * by + az * bx - ax * bz;
this.z = az * bw + aw * bz + ax * by - ay * bx;
this.w = aw * bw - ax * bx - ay * by - az * bz;
return this;
};
/**
* @method qmul
* @memberof Odin.Quat
* muliples a and b saves it in this
* @param Quat a
* @param Quat b
* @return this
*/
Quat.prototype.qmul = function(a, b) {
var ax = a.x,
ay = a.y,
az = a.z,
aw = a.w,
bx = b.x,
by = b.y,
bz = b.z,
bw = b.w;
this.x = ax * bw + aw * bx + ay * bz - az * by;
this.y = ay * bw + aw * by + az * bx - ax * bz;
this.z = az * bw + aw * bz + ax * by - ay * bx;
this.w = aw * bw - ax * bx - ay * by - az * bz;
return this;
};
/**
* @method div
* @memberof Odin.Quat
* divides this's values by other's
* @param Quat other
* @return this
*/
Quat.prototype.div = function(other) {
var ax = this.x,
ay = this.y,
az = this.z,
aw = this.w,
bx = -other.x,
by = -other.y,
bz = -other.z,
bw = other.w;
this.x = ax * bw + aw * bx + ay * bz - az * by;
this.y = ay * bw + aw * by + az * bx - ax * bz;
this.z = az * bw + aw * bz + ax * by - ay * bx;
this.w = aw * bw - ax * bx - ay * by - az * bz;
return this;
};
/**
* @method qdiv
* @memberof Odin.Quat
* divides b from a saves it in this
* @param Quat a
* @param Quat b
* @return this
*/
Quat.prototype.qdiv = function(a, b) {
var ax = a.x,
ay = a.y,
az = a.z,
aw = a.w,
bx = -b.x,
by = -b.y,
bz = -b.z,
bw = b.w;
this.x = ax * bw + aw * bx + ay * bz - az * by;
this.y = ay * bw + aw * by + az * bx - ax * bz;
this.z = az * bw + aw * bz + ax * by - ay * bx;
this.w = aw * bw - ax * bx - ay * by - az * bz;
return this;
};
/**
* @method length
* @memberof Odin.Quat
* returns the length of this
* @return Number
*/
Quat.prototype.length = function() {
var x = this.x,
y = this.y,
z = this.z,
w = this.w,
lsq = x * x + y * y + z * z + w * w;
return lsq > 0 ? sqrt(lsq) : 0;
};
/**
* @method lengthSq
* @memberof Odin.Quat
* returns the squared length of this
* @return Number
*/
Quat.prototype.lengthSq = function() {
var x = this.x,
y = this.y,
z = this.z,
w = this.w;
return x * x + y * y + z * z + w * w;
};
/**
* @method normalize
* @memberof Odin.Quat
* returns this with a length of 1
* @return this
*/
Quat.prototype.normalize = function() {
var x = this.x,
y = this.y,
z = this.z,
w = this.w,
l = x * x + y * y + z * z + w * w;
l = l > 0 ? 1 / sqrt(l) : 0;
this.x *= l;
this.y *= l;
this.z *= l;
this.w *= l;
return this;
};
/**
* @method inverse
* @memberof Odin.Quat
* returns the inverse of this
* @return this
*/
Quat.prototype.inverse = function() {
var x = this.x,
y = this.y,
z = this.z,
w = this.w,
d = x * x + y * y + z * z + w * w,
invD = d > 0 ? 1 / d : 0;
this.x *= -invD;
this.y *= -invD;
this.z *= -invD;
this.w *= invD;
return this;
};
/**
* @method inverseQuat
* @memberof Odin.Quat
* returns the inverse of other
* @param Quat other
* @return this
*/
Quat.prototype.inverseQuat = function(other) {
var x = other.x,
y = other.y,
z = other.z,
w = other.w,
d = x * x + y * y + z * z + w * w,
invD = d > 0 ? 1 / d : 0;
this.x = -x * invD;
this.y = -y * invD;
this.z = -z * invD;
this.w = w * invD;
return this;
};
/**
* @method conjugate
* @memberof Odin.Quat
* this faster than inverse, if quat is normalized and produces the same result
* @return this
*/
Quat.prototype.conjugate = function() {
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
return this;
};
/**
* @method calculateW
* @memberof Odin.Quat
* calculates w component of quat
* @return this
*/
Quat.prototype.calculateW = function() {
var x = this.x,
y = this.y,
z = this.z;
this.w = -sqrt(abs(1 - x * x - y * y - z * z));
return this;
};
/**
* @method lerp
* @memberof Odin.Quat
* linear interpolation between this and other by x
* @param Quat other
* @param Number x
* @return this
*/
Quat.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;
this.w += (other.w - this.w) * x;
return this;
};
/**
* @method qlerp
* @memberof Odin.Quat
* linear interpolation between a and b by x
* @param Quat a
* @param Quat b
* @param Number x
* @return this
*/
Quat.prototype.qlerp = function(a, b, x) {
var ax = a.x,
ay = a.y,
az = a.z,
aw = a.w;
this.x = ax + (b.x - ax) * x;
this.y = ay + (b.y - ay) * x;
this.z = az + (b.z - az) * x;
this.w = aw + (b.w - aw) * x;
return this;
};
/**
* @method nlerp
* @memberof Odin.Quat
* faster but less accurate than slerp
* @param Quat other
* @param Number x
* @return this
*/
Quat.prototype.nlerp = function(other, x) {
this.x += (other.x - this.x) * x;
this.y += (other.y - this.y) * x;
this.z += (other.z - this.z) * x;
this.w += (other.w - this.w) * x;
return this.normalize();
};
/**
* @method qnlerp
* @memberof Odin.Quat
* faster but less accurate than qslerp
* @param Quat a
* @param Quat b
* @param Number x
* @return this
*/
Quat.prototype.qnlerp = function(a, b, x) {
var ax = a.x,
ay = a.y,
az = a.z,
aw = a.w;
this.x = ax + (b.x - ax) * x;
this.y = ay + (b.y - ay) * x;
this.z = az + (b.z - az) * x;
this.w = aw + (b.w - aw) * x;
return this.normalize();
};
/**
* @method slerp
* @memberof Odin.Quat
* spherical linear Interpolation of this and other by x
* @param Quat other
* @param Number x
* @return this
*/
Quat.prototype.slerp = function(other, x) {
var ax = this.x,
ay = this.y,
az = this.z,
aw = this.w,
bx = other.x,
by = other.y,
bz = other.z,
bw = other.w,
omega, sinom, scale0, scale1,
cosom = ax * bx + ay * by + az * bz + aw * bw;
if (cosom < 0) {
cosom *= -1;
bx *= -1;
by *= -1;
bz *= -1;
bw *= -1;
}
if (1 - cosom > EPSILON) {
omega = acos(cosom);
sinom = 1 / sin(omega);
scale0 = sin((1 - x) * omega) * sinom;
scale1 = sin(x * omega) * sinom;
} else {
scale0 = 1 - x;
scale1 = x;
}
this.x = scale0 * ax + scale1 * bx;
this.y = scale0 * ay + scale1 * by;
this.z = scale0 * az + scale1 * bz;
this.w = scale0 * aw + scale1 * bw;
return this;
};
/**
* @method qslerp
* @memberof Odin.Quat
* spherical linear Interpolation between a and b by x
* @param Quat a
* @param Quat b
* @param Number x
* @return this
*/
Quat.prototype.qslerp = function(a, b, x) {
var ax = a.x,
ay = a.y,
az = a.z,
aw = a.w,
bx = b.x,
by = b.y,
bz = b.z,
bw = b.w,
omega, sinom, scale0, scale1,
cosom = ax * bx + ay * by + az * bz + aw * bw;
if (cosom < 0) {
cosom *= -1;
bx *= -1;
by *= -1;
bz *= -1;
bw *= -1;
}
if (1 - cosom > EPSILON) {
omega = acos(cosom);
sinom = 1 / sin(omega);
scale0 = sin((1 - x) * omega) * sinom;
scale1 = sin(x * omega) * sinom;
} else {
scale0 = 1 - x;
scale1 = x;
}
this.x = scale0 * ax + scale1 * bx;
this.y = scale0 * ay + scale1 * by;
this.z = scale0 * az + scale1 * bz;
this.w = scale0 * aw + scale1 * bw;
return this;
};
/**
* @method qdot
* @memberof Odin.Quat
* dot product of two quats, can be called as a static function Quat.qdot( a, b )
* @param Quat a
* @param Quat b
* @return Number
*/
Quat.qdot = Quat.prototype.qdot = function(a, b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
};
/**
* @method dot
* @memberof Odin.Quat
* dot product of this and other
* @param Quat other
* @return Number
*/
Quat.prototype.dot = function(other) {
return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w;
};
/**
* @method rotateX
* @memberof Odin.Quat
* sets quat's x rotation
* @param Number angle
* @return this
*/
Quat.prototype.rotateX = function(angle) {
var halfAngle = angle * 0.5,
x = this.x,
y = this.y,
z = this.z,
w = this.w,
s = sin(halfAngle),
c = cos(halfAngle);
this.x = x * c + w * s;
this.y = y * c + z * s;
this.z = z * c - y * s;
this.w = w * c - x * s;
return this;
};
/**
* @method rotateY
* @memberof Odin.Quat
* sets quat's y rotation
* @param Number angle
* @return this
*/
Quat.prototype.rotateY = function(angle) {
var halfAngle = angle * 0.5,
x = this.x,
y = this.y,
z = this.z,
w = this.w,
s = sin(halfAngle),
c = cos(halfAngle);
this.x = x * c - z * s;
this.y = y * c + w * s;
this.z = z * c + x * s;
this.w = w * c - y * s;
return this;
};
/**
* @method rotateZ
* @memberof Odin.Quat
* sets quat's z rotation
* @param Number angle
* @return this
*/
Quat.prototype.rotateZ = function(angle) {
var halfAngle = angle * 0.5,
x = this.x,
y = this.y,
z = this.z,
w = this.w,
s = sin(halfAngle),
c = cos(halfAngle);
this.x = x * c + y * s;
this.y = y * c - x * s;
this.z = z * c + w * s;
this.w = w * c - z * s;
return this;
};
/**
* @method rotate
* @memberof Odin.Quat
* rotates quat by z then x then y in that order
* @param Number x
* @param Number y
* @param Number z
* @return this
*/
Quat.prototype.rotate = function(x, y, z) {
this.rotateZ(z);
this.rotateX(x);
this.rotateY(y);
return this;
};
/**
* @method lookRotation
* @memberof Odin.Quat
* creates a rotation with the specified forward and upwards directions
* @param Vec3 forward
* @param Vec3 up
* @return this
*/
Quat.prototype.lookRotation = function(forward, up) {
var fx = forward.x,
fy = forward.y,
fz = forward.z,
ux = up.x,
uy = up.y,
uz = up.z,
ax = uy * fz - uz * fy,
ay = uz * fx - ux * fz,
az = ux * fy - uy * fx,
d = (1 + ux * fx + uy * fy + uz * fz) * 2,
dsq = d * d,
s = 1 / dsq;
this.x = ax * s;
this.y = ay * s;
this.z = az * s;
this.w = dsq * 0.5;
return this;
};
/**
* @method fromAxisAngle
* @memberof Odin.Quat
* sets quat from axis and angle
* @param Vec3 axis
* @param Number angle
* @return this
*/
Quat.prototype.fromAxisAngle = function(axis, angle) {
var halfAngle = angle * 0.5,
s = sin(halfAngle);
this.x = axis.x * s;
this.y = axis.y * s;
this.z = axis.z * s;
this.w = cos(halfAngle);
return this;
};
/**
* @method fromVec3s
* @memberof Odin.Quat
* sets quat from two vectors
* @param Vec3 u
* @param Vec3 v
* @return this
*/
Quat.prototype.fromVec3s = function() {
var a = new Vec3;
return function(u, v) {
a.vcross(u, v);
this.x = a.x;
this.y = a.y;
this.z = a.z;
this.w = sqrt(u.lengthSq() * v.lengthSq()) + u.dot(v);
return this.normalize();
};
}();
/**
* @method fromMat3
* @memberof Odin.Quat
* sets values from Mat3
* @param Mat3 m
* @return this
*/
Quat.prototype.fromMat3 = function(m) {
var te = m.elements,
m11 = te[0],
m12 = te[3],
m13 = te[6],
m21 = te[1],
m22 = te[4],
m23 = te[7],
m31 = te[2],
m32 = te[5],
m33 = te[8],
trace = m11 + m22 + m33,
s, invS;
if (trace > 0) {
s = 0.5 / sqrt(trace + 1);
this.w = 0.25 / s;
this.x = (m32 - m23) * s;
this.y = (m13 - m31) * s;
this.z = (m21 - m12) * s;
} else if (m11 > m22 && m11 > m33) {
s = 2 * sqrt(1 + m11 - m22 - m33);
invS = 1 / s;
this.w = (m32 - m23) * invS;
this.x = 0.25 * s;
this.y = (m12 + m21) * invS;
this.z = (m13 + m31) * invS;
} else if (m22 > m33) {
s = 2 * sqrt(1 + m22 - m11 - m33);
invS = 1 / s;
this.w = (m13 - m31) * invS;
this.x = (m12 + m21) * invS;
this.y = 0.25 * s;
this.z = (m23 + m32) * invS;
} else {
s = 2 * sqrt(1 + m33 - m11 - m22);
invS = 1 / s;
this.w = (m21 - m12) * invS;
this.x = (m13 + m31) * invS;
this.y = (m23 + m32) * invS;
this.z = 0.25 * s;
}
return this;
};
/**
* @method fromMat4
* @memberof Odin.Quat
* sets values from Mat4
* @param Mat4 m
* @return this
*/
Quat.prototype.fromMat4 = function(m) {
var te = m.elements,
m11 = te[0],
m12 = te[4],
m13 = te[8],
m21 = te[1],
m22 = te[5],
m23 = te[9],
m31 = te[2],
m32 = te[6],
m33 = te[10],
trace = m11 + m22 + m33,
s, invS;
if (trace > 0) {
s = 0.5 / sqrt(trace + 1);
this.w = 0.25 / s;
this.x = (m32 - m23) * s;
this.y = (m13 - m31) * s;
this.z = (m21 - m12) * s;
} else if (m11 > m22 && m11 > m33) {
s = 2 * sqrt(1 + m11 - m22 - m33);
invS = 1 / s;
this.w = (m32 - m23) * invS;
this.x = 0.25 * s;
this.y = (m12 + m21) * invS;
this.z = (m13 + m31) * invS;
} else if (m22 > m33) {
s = 2 * sqrt(1 + m22 - m11 - m33);
invS = 1 / s;
this.w = (m13 - m31) * invS;
this.x = (m12 + m21) * invS;
this.y = 0.25 * s;
this.z = (m23 + m32) * invS;
} else {
s = 2 * sqrt(1 + m33 - m11 - m22);
invS = 1 / s;
this.w = (m21 - m12) * invS;
this.x = (m13 + m31) * invS;
this.y = (m23 + m32) * invS;
this.z = 0.25 * s;
}
return this;
};
/**
* @method fromArray
* @memberof Odin.Quat
* sets values from array
* @param Array array
* @return this
*/
Quat.prototype.fromArray = function(array) {
this.x = array[0];
this.y = array[1];
this.z = array[2];
this.w = array[3];
return this;
};
/**
* @memberof Odin.Quat
* @param Odin.Quat other
* @return this
*/
Quat.prototype.equals = function(other) {
return !(
this.x !== other.x ||
this.y !== other.y ||
this.z !== other.z ||
this.w !== other.w
);
};
/**
* @method fromJSON
* @memberof Odin.Quat
* sets values from JSON object
* @param Object json
* @return this
*/
Quat.prototype.fromJSON = function(json) {
this.x = json.x;
this.y = json.y;
this.z = json.z;
this.w = json.w;
return this;
};
/**
* @method toArray
* @memberof Odin.Quat
* returns array of this
* @return Object
*/
Quat.prototype.toArray = function(array) {
array || (array = []);
array[0] = this.x;
array[1] = this.y;
array[2] = this.z;
array[3] = this.w;
return array;
};
/**
* @method toJSON
* @memberof Odin.Quat
* returns json object of this
* @return Object
*/
Quat.prototype.toJSON = function(json) {
json || (json = {});
json._className = "Quat";
json.x = this.x;
json.y = this.y;
json.z = this.z;
json.w = this.w;
return json;
};
/**
* @method toString
* @memberof Odin.Quat
* returns string of this
* @return String
*/
Quat.prototype.toString = function() {
return "Quat( " + this.x + ", " + this.y + ", " + this.z + ", " + this.w + " )";
};
return Quat;
}
);