1/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
2
3Redistribution and use in source and binary forms, with or without modification,
4are permitted provided that the following conditions are met:
5
6  * Redistributions of source code must retain the above copyright notice, this
7    list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright notice,
9    this list of conditions and the following disclaimer in the documentation
10    and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23/**
24 * @class Quaternion
25 * @name quat
26 */
27var quat = {};
28
29/**
30 * Creates a new identity quat
31 *
32 * @returns {quat} a new quaternion
33 */
34quat.create = function() {
35    var out = new GLMAT_ARRAY_TYPE(4);
36    out[0] = 0;
37    out[1] = 0;
38    out[2] = 0;
39    out[3] = 1;
40    return out;
41};
42
43/**
44 * Creates a new quat initialized with values from an existing quaternion
45 *
46 * @param {quat} a quaternion to clone
47 * @returns {quat} a new quaternion
48 * @function
49 */
50quat.clone = vec4.clone;
51
52/**
53 * Creates a new quat initialized with the given values
54 *
55 * @param {Number} x X component
56 * @param {Number} y Y component
57 * @param {Number} z Z component
58 * @param {Number} w W component
59 * @returns {quat} a new quaternion
60 * @function
61 */
62quat.fromValues = vec4.fromValues;
63
64/**
65 * Copy the values from one quat to another
66 *
67 * @param {quat} out the receiving quaternion
68 * @param {quat} a the source quaternion
69 * @returns {quat} out
70 * @function
71 */
72quat.copy = vec4.copy;
73
74/**
75 * Set the components of a quat to the given values
76 *
77 * @param {quat} out the receiving quaternion
78 * @param {Number} x X component
79 * @param {Number} y Y component
80 * @param {Number} z Z component
81 * @param {Number} w W component
82 * @returns {quat} out
83 * @function
84 */
85quat.set = vec4.set;
86
87/**
88 * Set a quat to the identity quaternion
89 *
90 * @param {quat} out the receiving quaternion
91 * @returns {quat} out
92 */
93quat.identity = function(out) {
94    out[0] = 0;
95    out[1] = 0;
96    out[2] = 0;
97    out[3] = 1;
98    return out;
99};
100
101/**
102 * Sets a quat from the given angle and rotation axis,
103 * then returns it.
104 *
105 * @param {quat} out the receiving quaternion
106 * @param {vec3} axis the axis around which to rotate
107 * @param {Number} rad the angle in radians
108 * @returns {quat} out
109 **/
110quat.setAxisAngle = function(out, axis, rad) {
111    rad = rad * 0.5;
112    var s = Math.sin(rad);
113    out[0] = s * axis[0];
114    out[1] = s * axis[1];
115    out[2] = s * axis[2];
116    out[3] = Math.cos(rad);
117    return out;
118};
119
120/**
121 * Adds two quat's
122 *
123 * @param {quat} out the receiving quaternion
124 * @param {quat} a the first operand
125 * @param {quat} b the second operand
126 * @returns {quat} out
127 * @function
128 */
129quat.add = vec4.add;
130
131/**
132 * Multiplies two quat's
133 *
134 * @param {quat} out the receiving quaternion
135 * @param {quat} a the first operand
136 * @param {quat} b the second operand
137 * @returns {quat} out
138 */
139quat.multiply = function(out, a, b) {
140    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
141        bx = b[0], by = b[1], bz = b[2], bw = b[3];
142
143    out[0] = ax * bw + aw * bx + ay * bz - az * by;
144    out[1] = ay * bw + aw * by + az * bx - ax * bz;
145    out[2] = az * bw + aw * bz + ax * by - ay * bx;
146    out[3] = aw * bw - ax * bx - ay * by - az * bz;
147    return out;
148};
149
150/**
151 * Alias for {@link quat.multiply}
152 * @function
153 */
154quat.mul = quat.multiply;
155
156/**
157 * Scales a quat by a scalar number
158 *
159 * @param {quat} out the receiving vector
160 * @param {quat} a the vector to scale
161 * @param {Number} b amount to scale the vector by
162 * @returns {quat} out
163 * @function
164 */
165quat.scale = vec4.scale;
166
167/**
168 * Rotates a quaternion by the given angle around the X axis
169 *
170 * @param {quat} out quat receiving operation result
171 * @param {quat} a quat to rotate
172 * @param {number} rad angle (in radians) to rotate
173 * @returns {quat} out
174 */
175quat.rotateX = function (out, a, rad) {
176    rad *= 0.5;
177
178    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
179        bx = Math.sin(rad), bw = Math.cos(rad);
180
181    out[0] = ax * bw + aw * bx;
182    out[1] = ay * bw + az * bx;
183    out[2] = az * bw - ay * bx;
184    out[3] = aw * bw - ax * bx;
185    return out;
186};
187
188/**
189 * Rotates a quaternion by the given angle around the Y axis
190 *
191 * @param {quat} out quat receiving operation result
192 * @param {quat} a quat to rotate
193 * @param {number} rad angle (in radians) to rotate
194 * @returns {quat} out
195 */
196quat.rotateY = function (out, a, rad) {
197    rad *= 0.5;
198
199    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
200        by = Math.sin(rad), bw = Math.cos(rad);
201
202    out[0] = ax * bw - az * by;
203    out[1] = ay * bw + aw * by;
204    out[2] = az * bw + ax * by;
205    out[3] = aw * bw - ay * by;
206    return out;
207};
208
209/**
210 * Rotates a quaternion by the given angle around the Z axis
211 *
212 * @param {quat} out quat receiving operation result
213 * @param {quat} a quat to rotate
214 * @param {number} rad angle (in radians) to rotate
215 * @returns {quat} out
216 */
217quat.rotateZ = function (out, a, rad) {
218    rad *= 0.5;
219
220    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
221        bz = Math.sin(rad), bw = Math.cos(rad);
222
223    out[0] = ax * bw + ay * bz;
224    out[1] = ay * bw - ax * bz;
225    out[2] = az * bw + aw * bz;
226    out[3] = aw * bw - az * bz;
227    return out;
228};
229
230/**
231 * Calculates the W component of a quat from the X, Y, and Z components.
232 * Assumes that quaternion is 1 unit in length.
233 * Any existing W component will be ignored.
234 *
235 * @param {quat} out the receiving quaternion
236 * @param {quat} a quat to calculate W component of
237 * @returns {quat} out
238 */
239quat.calculateW = function (out, a) {
240    var x = a[0], y = a[1], z = a[2];
241
242    out[0] = x;
243    out[1] = y;
244    out[2] = z;
245    out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
246    return out;
247};
248
249/**
250 * Calculates the dot product of two quat's
251 *
252 * @param {quat} a the first operand
253 * @param {quat} b the second operand
254 * @returns {Number} dot product of a and b
255 * @function
256 */
257quat.dot = vec4.dot;
258
259/**
260 * Performs a linear interpolation between two quat's
261 *
262 * @param {quat} out the receiving quaternion
263 * @param {quat} a the first operand
264 * @param {quat} b the second operand
265 * @param {Number} t interpolation amount between the two inputs
266 * @returns {quat} out
267 * @function
268 */
269quat.lerp = vec4.lerp;
270
271/**
272 * Performs a spherical linear interpolation between two quat
273 *
274 * @param {quat} out the receiving quaternion
275 * @param {quat} a the first operand
276 * @param {quat} b the second operand
277 * @param {Number} t interpolation amount between the two inputs
278 * @returns {quat} out
279 */
280quat.slerp = function (out, a, b, t) {
281    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
282        bx = b[0], by = b[1], bz = b[2], bw = b[3];
283
284    var cosHalfTheta = ax * bx + ay * by + az * bz + aw * bw,
285        halfTheta,
286        sinHalfTheta,
287        ratioA,
288        ratioB;
289
290    if (Math.abs(cosHalfTheta) >= 1.0) {
291        if (out !== a) {
292            out[0] = ax;
293            out[1] = ay;
294            out[2] = az;
295            out[3] = aw;
296        }
297        return out;
298    }
299
300    halfTheta = Math.acos(cosHalfTheta);
301    sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
302
303    if (Math.abs(sinHalfTheta) < 0.001) {
304        out[0] = (ax * 0.5 + bx * 0.5);
305        out[1] = (ay * 0.5 + by * 0.5);
306        out[2] = (az * 0.5 + bz * 0.5);
307        out[3] = (aw * 0.5 + bw * 0.5);
308        return out;
309    }
310
311    ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta;
312    ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
313
314    out[0] = (ax * ratioA + bx * ratioB);
315    out[1] = (ay * ratioA + by * ratioB);
316    out[2] = (az * ratioA + bz * ratioB);
317    out[3] = (aw * ratioA + bw * ratioB);
318
319    return out;
320};
321
322/**
323 * Calculates the inverse of a quat
324 *
325 * @param {quat} out the receiving quaternion
326 * @param {quat} a quat to calculate inverse of
327 * @returns {quat} out
328 */
329quat.invert = function(out, a) {
330    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
331        dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
332        invDot = dot ? 1.0/dot : 0;
333
334    // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
335
336    out[0] = -a0*invDot;
337    out[1] = -a1*invDot;
338    out[2] = -a2*invDot;
339    out[3] = a3*invDot;
340    return out;
341};
342
343/**
344 * Calculates the conjugate of a quat
345 * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
346 *
347 * @param {quat} out the receiving quaternion
348 * @param {quat} a quat to calculate conjugate of
349 * @returns {quat} out
350 */
351quat.conjugate = function (out, a) {
352    out[0] = -a[0];
353    out[1] = -a[1];
354    out[2] = -a[2];
355    out[3] = a[3];
356    return out;
357};
358
359/**
360 * Calculates the length of a quat
361 *
362 * @param {quat} a vector to calculate length of
363 * @returns {Number} length of a
364 * @function
365 */
366quat.length = vec4.length;
367
368/**
369 * Alias for {@link quat.length}
370 * @function
371 */
372quat.len = quat.length;
373
374/**
375 * Calculates the squared length of a quat
376 *
377 * @param {quat} a vector to calculate squared length of
378 * @returns {Number} squared length of a
379 * @function
380 */
381quat.squaredLength = vec4.squaredLength;
382
383/**
384 * Alias for {@link quat.squaredLength}
385 * @function
386 */
387quat.sqrLen = quat.squaredLength;
388
389/**
390 * Normalize a quat
391 *
392 * @param {quat} out the receiving quaternion
393 * @param {quat} a quaternion to normalize
394 * @returns {quat} out
395 * @function
396 */
397quat.normalize = vec4.normalize;
398
399/**
400 * Creates a quaternion from the given 3x3 rotation matrix.
401 *
402 * @param {quat} out the receiving quaternion
403 * @param {mat3} m rotation matrix
404 * @returns {quat} out
405 * @function
406 */
407quat.fromMat3 = (function() {
408    var s_iNext = [1,2,0];
409    return function(out, m) {
410        // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
411        // article "Quaternion Calculus and Fast Animation".
412        var fTrace = m[0] + m[4] + m[8];
413        var fRoot;
414
415        if ( fTrace > 0.0 ) {
416            // |w| > 1/2, may as well choose w > 1/2
417            fRoot = Math.sqrt(fTrace + 1.0);  // 2w
418            out[3] = 0.5 * fRoot;
419            fRoot = 0.5/fRoot;  // 1/(4w)
420            out[0] = (m[7]-m[5])*fRoot;
421            out[1] = (m[2]-m[6])*fRoot;
422            out[2] = (m[3]-m[1])*fRoot;
423        } else {
424            // |w| <= 1/2
425            var i = 0;
426            if ( m[4] > m[0] )
427              i = 1;
428            if ( m[8] > m[i*3+i] )
429              i = 2;
430            var j = s_iNext[i];
431            var k = s_iNext[j];
432
433            fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
434            out[i] = 0.5 * fRoot;
435            fRoot = 0.5 / fRoot;
436            out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
437            out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
438            out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
439        }
440
441        return out;
442    };
443})();
444
445/**
446 * Returns a string representation of a quatenion
447 *
448 * @param {quat} vec vector to represent as a string
449 * @returns {String} string representation of the vector
450 */
451quat.str = function (a) {
452    return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
453};
454
455if(typeof(exports) !== 'undefined') {
456    exports.quat = quat;
457}
458