1/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE. */
20
21var glMatrix = require("./common.js");
22
23/**
24 * @class 4x4 Matrix
25 * @name mat4
26 */
27var mat4 = {};
28
29/**
30 * Creates a new identity mat4
31 *
32 * @returns {mat4} a new 4x4 matrix
33 */
34mat4.create = function() {
35    var out = new glMatrix.ARRAY_TYPE(16);
36    out[0] = 1;
37    out[1] = 0;
38    out[2] = 0;
39    out[3] = 0;
40    out[4] = 0;
41    out[5] = 1;
42    out[6] = 0;
43    out[7] = 0;
44    out[8] = 0;
45    out[9] = 0;
46    out[10] = 1;
47    out[11] = 0;
48    out[12] = 0;
49    out[13] = 0;
50    out[14] = 0;
51    out[15] = 1;
52    return out;
53};
54
55/**
56 * Creates a new mat4 initialized with values from an existing matrix
57 *
58 * @param {mat4} a matrix to clone
59 * @returns {mat4} a new 4x4 matrix
60 */
61mat4.clone = function(a) {
62    var out = new glMatrix.ARRAY_TYPE(16);
63    out[0] = a[0];
64    out[1] = a[1];
65    out[2] = a[2];
66    out[3] = a[3];
67    out[4] = a[4];
68    out[5] = a[5];
69    out[6] = a[6];
70    out[7] = a[7];
71    out[8] = a[8];
72    out[9] = a[9];
73    out[10] = a[10];
74    out[11] = a[11];
75    out[12] = a[12];
76    out[13] = a[13];
77    out[14] = a[14];
78    out[15] = a[15];
79    return out;
80};
81
82/**
83 * Copy the values from one mat4 to another
84 *
85 * @param {mat4} out the receiving matrix
86 * @param {mat4} a the source matrix
87 * @returns {mat4} out
88 */
89mat4.copy = function(out, a) {
90    out[0] = a[0];
91    out[1] = a[1];
92    out[2] = a[2];
93    out[3] = a[3];
94    out[4] = a[4];
95    out[5] = a[5];
96    out[6] = a[6];
97    out[7] = a[7];
98    out[8] = a[8];
99    out[9] = a[9];
100    out[10] = a[10];
101    out[11] = a[11];
102    out[12] = a[12];
103    out[13] = a[13];
104    out[14] = a[14];
105    out[15] = a[15];
106    return out;
107};
108
109/**
110 * Set a mat4 to the identity matrix
111 *
112 * @param {mat4} out the receiving matrix
113 * @returns {mat4} out
114 */
115mat4.identity = function(out) {
116    out[0] = 1;
117    out[1] = 0;
118    out[2] = 0;
119    out[3] = 0;
120    out[4] = 0;
121    out[5] = 1;
122    out[6] = 0;
123    out[7] = 0;
124    out[8] = 0;
125    out[9] = 0;
126    out[10] = 1;
127    out[11] = 0;
128    out[12] = 0;
129    out[13] = 0;
130    out[14] = 0;
131    out[15] = 1;
132    return out;
133};
134
135/**
136 * Transpose the values of a mat4
137 *
138 * @param {mat4} out the receiving matrix
139 * @param {mat4} a the source matrix
140 * @returns {mat4} out
141 */
142mat4.transpose = function(out, a) {
143    // If we are transposing ourselves we can skip a few steps but have to cache some values
144    if (out === a) {
145        var a01 = a[1], a02 = a[2], a03 = a[3],
146            a12 = a[6], a13 = a[7],
147            a23 = a[11];
148
149        out[1] = a[4];
150        out[2] = a[8];
151        out[3] = a[12];
152        out[4] = a01;
153        out[6] = a[9];
154        out[7] = a[13];
155        out[8] = a02;
156        out[9] = a12;
157        out[11] = a[14];
158        out[12] = a03;
159        out[13] = a13;
160        out[14] = a23;
161    } else {
162        out[0] = a[0];
163        out[1] = a[4];
164        out[2] = a[8];
165        out[3] = a[12];
166        out[4] = a[1];
167        out[5] = a[5];
168        out[6] = a[9];
169        out[7] = a[13];
170        out[8] = a[2];
171        out[9] = a[6];
172        out[10] = a[10];
173        out[11] = a[14];
174        out[12] = a[3];
175        out[13] = a[7];
176        out[14] = a[11];
177        out[15] = a[15];
178    }
179
180    return out;
181};
182
183/**
184 * Inverts a mat4
185 *
186 * @param {mat4} out the receiving matrix
187 * @param {mat4} a the source matrix
188 * @returns {mat4} out
189 */
190mat4.invert = function(out, a) {
191    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
192        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
193        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
194        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
195
196        b00 = a00 * a11 - a01 * a10,
197        b01 = a00 * a12 - a02 * a10,
198        b02 = a00 * a13 - a03 * a10,
199        b03 = a01 * a12 - a02 * a11,
200        b04 = a01 * a13 - a03 * a11,
201        b05 = a02 * a13 - a03 * a12,
202        b06 = a20 * a31 - a21 * a30,
203        b07 = a20 * a32 - a22 * a30,
204        b08 = a20 * a33 - a23 * a30,
205        b09 = a21 * a32 - a22 * a31,
206        b10 = a21 * a33 - a23 * a31,
207        b11 = a22 * a33 - a23 * a32,
208
209        // Calculate the determinant
210        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
211
212    if (!det) {
213        return null;
214    }
215    det = 1.0 / det;
216
217    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
218    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
219    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
220    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
221    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
222    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
223    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
224    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
225    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
226    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
227    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
228    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
229    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
230    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
231    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
232    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
233
234    return out;
235};
236
237/**
238 * Calculates the adjugate of a mat4
239 *
240 * @param {mat4} out the receiving matrix
241 * @param {mat4} a the source matrix
242 * @returns {mat4} out
243 */
244mat4.adjoint = function(out, a) {
245    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
246        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
247        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
248        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
249
250    out[0]  =  (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
251    out[1]  = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
252    out[2]  =  (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
253    out[3]  = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
254    out[4]  = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
255    out[5]  =  (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
256    out[6]  = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
257    out[7]  =  (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
258    out[8]  =  (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
259    out[9]  = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
260    out[10] =  (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
261    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
262    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
263    out[13] =  (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
264    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
265    out[15] =  (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
266    return out;
267};
268
269/**
270 * Calculates the determinant of a mat4
271 *
272 * @param {mat4} a the source matrix
273 * @returns {Number} determinant of a
274 */
275mat4.determinant = function (a) {
276    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
277        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
278        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
279        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
280
281        b00 = a00 * a11 - a01 * a10,
282        b01 = a00 * a12 - a02 * a10,
283        b02 = a00 * a13 - a03 * a10,
284        b03 = a01 * a12 - a02 * a11,
285        b04 = a01 * a13 - a03 * a11,
286        b05 = a02 * a13 - a03 * a12,
287        b06 = a20 * a31 - a21 * a30,
288        b07 = a20 * a32 - a22 * a30,
289        b08 = a20 * a33 - a23 * a30,
290        b09 = a21 * a32 - a22 * a31,
291        b10 = a21 * a33 - a23 * a31,
292        b11 = a22 * a33 - a23 * a32;
293
294    // Calculate the determinant
295    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
296};
297
298/**
299 * Multiplies two mat4's
300 *
301 * @param {mat4} out the receiving matrix
302 * @param {mat4} a the first operand
303 * @param {mat4} b the second operand
304 * @returns {mat4} out
305 */
306mat4.multiply = function (out, a, b) {
307    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
308        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
309        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
310        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
311
312    // Cache only the current line of the second matrix
313    var b0  = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
314    out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
315    out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
316    out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
317    out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
318
319    b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
320    out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
321    out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
322    out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
323    out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
324
325    b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
326    out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
327    out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
328    out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
329    out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
330
331    b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
332    out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
333    out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
334    out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
335    out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
336    return out;
337};
338
339/**
340 * Alias for {@link mat4.multiply}
341 * @function
342 */
343mat4.mul = mat4.multiply;
344
345/**
346 * Translate a mat4 by the given vector
347 *
348 * @param {mat4} out the receiving matrix
349 * @param {mat4} a the matrix to translate
350 * @param {vec3} v vector to translate by
351 * @returns {mat4} out
352 */
353mat4.translate = function (out, a, v) {
354    var x = v[0], y = v[1], z = v[2],
355        a00, a01, a02, a03,
356        a10, a11, a12, a13,
357        a20, a21, a22, a23;
358
359    if (a === out) {
360        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
361        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
362        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
363        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
364    } else {
365        a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
366        a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
367        a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
368
369        out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
370        out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
371        out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
372
373        out[12] = a00 * x + a10 * y + a20 * z + a[12];
374        out[13] = a01 * x + a11 * y + a21 * z + a[13];
375        out[14] = a02 * x + a12 * y + a22 * z + a[14];
376        out[15] = a03 * x + a13 * y + a23 * z + a[15];
377    }
378
379    return out;
380};
381
382/**
383 * Scales the mat4 by the dimensions in the given vec3
384 *
385 * @param {mat4} out the receiving matrix
386 * @param {mat4} a the matrix to scale
387 * @param {vec3} v the vec3 to scale the matrix by
388 * @returns {mat4} out
389 **/
390mat4.scale = function(out, a, v) {
391    var x = v[0], y = v[1], z = v[2];
392
393    out[0] = a[0] * x;
394    out[1] = a[1] * x;
395    out[2] = a[2] * x;
396    out[3] = a[3] * x;
397    out[4] = a[4] * y;
398    out[5] = a[5] * y;
399    out[6] = a[6] * y;
400    out[7] = a[7] * y;
401    out[8] = a[8] * z;
402    out[9] = a[9] * z;
403    out[10] = a[10] * z;
404    out[11] = a[11] * z;
405    out[12] = a[12];
406    out[13] = a[13];
407    out[14] = a[14];
408    out[15] = a[15];
409    return out;
410};
411
412/**
413 * Rotates a mat4 by the given angle around the given axis
414 *
415 * @param {mat4} out the receiving matrix
416 * @param {mat4} a the matrix to rotate
417 * @param {Number} rad the angle to rotate the matrix by
418 * @param {vec3} axis the axis to rotate around
419 * @returns {mat4} out
420 */
421mat4.rotate = function (out, a, rad, axis) {
422    var x = axis[0], y = axis[1], z = axis[2],
423        len = Math.sqrt(x * x + y * y + z * z),
424        s, c, t,
425        a00, a01, a02, a03,
426        a10, a11, a12, a13,
427        a20, a21, a22, a23,
428        b00, b01, b02,
429        b10, b11, b12,
430        b20, b21, b22;
431
432    if (Math.abs(len) < glMatrix.EPSILON) { return null; }
433
434    len = 1 / len;
435    x *= len;
436    y *= len;
437    z *= len;
438
439    s = Math.sin(rad);
440    c = Math.cos(rad);
441    t = 1 - c;
442
443    a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
444    a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
445    a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
446
447    // Construct the elements of the rotation matrix
448    b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
449    b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
450    b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
451
452    // Perform rotation-specific matrix multiplication
453    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
454    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
455    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
456    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
457    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
458    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
459    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
460    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
461    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
462    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
463    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
464    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
465
466    if (a !== out) { // If the source and destination differ, copy the unchanged last row
467        out[12] = a[12];
468        out[13] = a[13];
469        out[14] = a[14];
470        out[15] = a[15];
471    }
472    return out;
473};
474
475/**
476 * Rotates a matrix by the given angle around the X axis
477 *
478 * @param {mat4} out the receiving matrix
479 * @param {mat4} a the matrix to rotate
480 * @param {Number} rad the angle to rotate the matrix by
481 * @returns {mat4} out
482 */
483mat4.rotateX = function (out, a, rad) {
484    var s = Math.sin(rad),
485        c = Math.cos(rad),
486        a10 = a[4],
487        a11 = a[5],
488        a12 = a[6],
489        a13 = a[7],
490        a20 = a[8],
491        a21 = a[9],
492        a22 = a[10],
493        a23 = a[11];
494
495    if (a !== out) { // If the source and destination differ, copy the unchanged rows
496        out[0]  = a[0];
497        out[1]  = a[1];
498        out[2]  = a[2];
499        out[3]  = a[3];
500        out[12] = a[12];
501        out[13] = a[13];
502        out[14] = a[14];
503        out[15] = a[15];
504    }
505
506    // Perform axis-specific matrix multiplication
507    out[4] = a10 * c + a20 * s;
508    out[5] = a11 * c + a21 * s;
509    out[6] = a12 * c + a22 * s;
510    out[7] = a13 * c + a23 * s;
511    out[8] = a20 * c - a10 * s;
512    out[9] = a21 * c - a11 * s;
513    out[10] = a22 * c - a12 * s;
514    out[11] = a23 * c - a13 * s;
515    return out;
516};
517
518/**
519 * Rotates a matrix by the given angle around the Y axis
520 *
521 * @param {mat4} out the receiving matrix
522 * @param {mat4} a the matrix to rotate
523 * @param {Number} rad the angle to rotate the matrix by
524 * @returns {mat4} out
525 */
526mat4.rotateY = function (out, a, rad) {
527    var s = Math.sin(rad),
528        c = Math.cos(rad),
529        a00 = a[0],
530        a01 = a[1],
531        a02 = a[2],
532        a03 = a[3],
533        a20 = a[8],
534        a21 = a[9],
535        a22 = a[10],
536        a23 = a[11];
537
538    if (a !== out) { // If the source and destination differ, copy the unchanged rows
539        out[4]  = a[4];
540        out[5]  = a[5];
541        out[6]  = a[6];
542        out[7]  = a[7];
543        out[12] = a[12];
544        out[13] = a[13];
545        out[14] = a[14];
546        out[15] = a[15];
547    }
548
549    // Perform axis-specific matrix multiplication
550    out[0] = a00 * c - a20 * s;
551    out[1] = a01 * c - a21 * s;
552    out[2] = a02 * c - a22 * s;
553    out[3] = a03 * c - a23 * s;
554    out[8] = a00 * s + a20 * c;
555    out[9] = a01 * s + a21 * c;
556    out[10] = a02 * s + a22 * c;
557    out[11] = a03 * s + a23 * c;
558    return out;
559};
560
561/**
562 * Rotates a matrix by the given angle around the Z axis
563 *
564 * @param {mat4} out the receiving matrix
565 * @param {mat4} a the matrix to rotate
566 * @param {Number} rad the angle to rotate the matrix by
567 * @returns {mat4} out
568 */
569mat4.rotateZ = function (out, a, rad) {
570    var s = Math.sin(rad),
571        c = Math.cos(rad),
572        a00 = a[0],
573        a01 = a[1],
574        a02 = a[2],
575        a03 = a[3],
576        a10 = a[4],
577        a11 = a[5],
578        a12 = a[6],
579        a13 = a[7];
580
581    if (a !== out) { // If the source and destination differ, copy the unchanged last row
582        out[8]  = a[8];
583        out[9]  = a[9];
584        out[10] = a[10];
585        out[11] = a[11];
586        out[12] = a[12];
587        out[13] = a[13];
588        out[14] = a[14];
589        out[15] = a[15];
590    }
591
592    // Perform axis-specific matrix multiplication
593    out[0] = a00 * c + a10 * s;
594    out[1] = a01 * c + a11 * s;
595    out[2] = a02 * c + a12 * s;
596    out[3] = a03 * c + a13 * s;
597    out[4] = a10 * c - a00 * s;
598    out[5] = a11 * c - a01 * s;
599    out[6] = a12 * c - a02 * s;
600    out[7] = a13 * c - a03 * s;
601    return out;
602};
603
604/**
605 * Creates a matrix from a vector translation
606 * This is equivalent to (but much faster than):
607 *
608 *     mat4.identity(dest);
609 *     mat4.translate(dest, dest, vec);
610 *
611 * @param {mat4} out mat4 receiving operation result
612 * @param {vec3} v Translation vector
613 * @returns {mat4} out
614 */
615mat4.fromTranslation = function(out, v) {
616    out[0] = 1;
617    out[1] = 0;
618    out[2] = 0;
619    out[3] = 0;
620    out[4] = 0;
621    out[5] = 1;
622    out[6] = 0;
623    out[7] = 0;
624    out[8] = 0;
625    out[9] = 0;
626    out[10] = 1;
627    out[11] = 0;
628    out[12] = v[0];
629    out[13] = v[1];
630    out[14] = v[2];
631    out[15] = 1;
632    return out;
633}
634
635/**
636 * Creates a matrix from a vector scaling
637 * This is equivalent to (but much faster than):
638 *
639 *     mat4.identity(dest);
640 *     mat4.scale(dest, dest, vec);
641 *
642 * @param {mat4} out mat4 receiving operation result
643 * @param {vec3} v Scaling vector
644 * @returns {mat4} out
645 */
646mat4.fromScaling = function(out, v) {
647    out[0] = v[0];
648    out[1] = 0;
649    out[2] = 0;
650    out[3] = 0;
651    out[4] = 0;
652    out[5] = v[1];
653    out[6] = 0;
654    out[7] = 0;
655    out[8] = 0;
656    out[9] = 0;
657    out[10] = v[2];
658    out[11] = 0;
659    out[12] = 0;
660    out[13] = 0;
661    out[14] = 0;
662    out[15] = 1;
663    return out;
664}
665
666/**
667 * Creates a matrix from a given angle around a given axis
668 * This is equivalent to (but much faster than):
669 *
670 *     mat4.identity(dest);
671 *     mat4.rotate(dest, dest, rad, axis);
672 *
673 * @param {mat4} out mat4 receiving operation result
674 * @param {Number} rad the angle to rotate the matrix by
675 * @param {vec3} axis the axis to rotate around
676 * @returns {mat4} out
677 */
678mat4.fromRotation = function(out, rad, axis) {
679    var x = axis[0], y = axis[1], z = axis[2],
680        len = Math.sqrt(x * x + y * y + z * z),
681        s, c, t;
682
683    if (Math.abs(len) < glMatrix.EPSILON) { return null; }
684
685    len = 1 / len;
686    x *= len;
687    y *= len;
688    z *= len;
689
690    s = Math.sin(rad);
691    c = Math.cos(rad);
692    t = 1 - c;
693
694    // Perform rotation-specific matrix multiplication
695    out[0] = x * x * t + c;
696    out[1] = y * x * t + z * s;
697    out[2] = z * x * t - y * s;
698    out[3] = 0;
699    out[4] = x * y * t - z * s;
700    out[5] = y * y * t + c;
701    out[6] = z * y * t + x * s;
702    out[7] = 0;
703    out[8] = x * z * t + y * s;
704    out[9] = y * z * t - x * s;
705    out[10] = z * z * t + c;
706    out[11] = 0;
707    out[12] = 0;
708    out[13] = 0;
709    out[14] = 0;
710    out[15] = 1;
711    return out;
712}
713
714/**
715 * Creates a matrix from the given angle around the X axis
716 * This is equivalent to (but much faster than):
717 *
718 *     mat4.identity(dest);
719 *     mat4.rotateX(dest, dest, rad);
720 *
721 * @param {mat4} out mat4 receiving operation result
722 * @param {Number} rad the angle to rotate the matrix by
723 * @returns {mat4} out
724 */
725mat4.fromXRotation = function(out, rad) {
726    var s = Math.sin(rad),
727        c = Math.cos(rad);
728
729    // Perform axis-specific matrix multiplication
730    out[0]  = 1;
731    out[1]  = 0;
732    out[2]  = 0;
733    out[3]  = 0;
734    out[4] = 0;
735    out[5] = c;
736    out[6] = s;
737    out[7] = 0;
738    out[8] = 0;
739    out[9] = -s;
740    out[10] = c;
741    out[11] = 0;
742    out[12] = 0;
743    out[13] = 0;
744    out[14] = 0;
745    out[15] = 1;
746    return out;
747}
748
749/**
750 * Creates a matrix from the given angle around the Y axis
751 * This is equivalent to (but much faster than):
752 *
753 *     mat4.identity(dest);
754 *     mat4.rotateY(dest, dest, rad);
755 *
756 * @param {mat4} out mat4 receiving operation result
757 * @param {Number} rad the angle to rotate the matrix by
758 * @returns {mat4} out
759 */
760mat4.fromYRotation = function(out, rad) {
761    var s = Math.sin(rad),
762        c = Math.cos(rad);
763
764    // Perform axis-specific matrix multiplication
765    out[0]  = c;
766    out[1]  = 0;
767    out[2]  = -s;
768    out[3]  = 0;
769    out[4] = 0;
770    out[5] = 1;
771    out[6] = 0;
772    out[7] = 0;
773    out[8] = s;
774    out[9] = 0;
775    out[10] = c;
776    out[11] = 0;
777    out[12] = 0;
778    out[13] = 0;
779    out[14] = 0;
780    out[15] = 1;
781    return out;
782}
783
784/**
785 * Creates a matrix from the given angle around the Z axis
786 * This is equivalent to (but much faster than):
787 *
788 *     mat4.identity(dest);
789 *     mat4.rotateZ(dest, dest, rad);
790 *
791 * @param {mat4} out mat4 receiving operation result
792 * @param {Number} rad the angle to rotate the matrix by
793 * @returns {mat4} out
794 */
795mat4.fromZRotation = function(out, rad) {
796    var s = Math.sin(rad),
797        c = Math.cos(rad);
798
799    // Perform axis-specific matrix multiplication
800    out[0]  = c;
801    out[1]  = s;
802    out[2]  = 0;
803    out[3]  = 0;
804    out[4] = -s;
805    out[5] = c;
806    out[6] = 0;
807    out[7] = 0;
808    out[8] = 0;
809    out[9] = 0;
810    out[10] = 1;
811    out[11] = 0;
812    out[12] = 0;
813    out[13] = 0;
814    out[14] = 0;
815    out[15] = 1;
816    return out;
817}
818
819/**
820 * Creates a matrix from a quaternion rotation and vector translation
821 * This is equivalent to (but much faster than):
822 *
823 *     mat4.identity(dest);
824 *     mat4.translate(dest, vec);
825 *     var quatMat = mat4.create();
826 *     quat4.toMat4(quat, quatMat);
827 *     mat4.multiply(dest, quatMat);
828 *
829 * @param {mat4} out mat4 receiving operation result
830 * @param {quat4} q Rotation quaternion
831 * @param {vec3} v Translation vector
832 * @returns {mat4} out
833 */
834mat4.fromRotationTranslation = function (out, q, v) {
835    // Quaternion math
836    var x = q[0], y = q[1], z = q[2], w = q[3],
837        x2 = x + x,
838        y2 = y + y,
839        z2 = z + z,
840
841        xx = x * x2,
842        xy = x * y2,
843        xz = x * z2,
844        yy = y * y2,
845        yz = y * z2,
846        zz = z * z2,
847        wx = w * x2,
848        wy = w * y2,
849        wz = w * z2;
850
851    out[0] = 1 - (yy + zz);
852    out[1] = xy + wz;
853    out[2] = xz - wy;
854    out[3] = 0;
855    out[4] = xy - wz;
856    out[5] = 1 - (xx + zz);
857    out[6] = yz + wx;
858    out[7] = 0;
859    out[8] = xz + wy;
860    out[9] = yz - wx;
861    out[10] = 1 - (xx + yy);
862    out[11] = 0;
863    out[12] = v[0];
864    out[13] = v[1];
865    out[14] = v[2];
866    out[15] = 1;
867
868    return out;
869};
870
871/**
872 * Creates a matrix from a quaternion rotation, vector translation and vector scale
873 * This is equivalent to (but much faster than):
874 *
875 *     mat4.identity(dest);
876 *     mat4.translate(dest, vec);
877 *     var quatMat = mat4.create();
878 *     quat4.toMat4(quat, quatMat);
879 *     mat4.multiply(dest, quatMat);
880 *     mat4.scale(dest, scale)
881 *
882 * @param {mat4} out mat4 receiving operation result
883 * @param {quat4} q Rotation quaternion
884 * @param {vec3} v Translation vector
885 * @param {vec3} s Scaling vector
886 * @returns {mat4} out
887 */
888mat4.fromRotationTranslationScale = function (out, q, v, s) {
889    // Quaternion math
890    var x = q[0], y = q[1], z = q[2], w = q[3],
891        x2 = x + x,
892        y2 = y + y,
893        z2 = z + z,
894
895        xx = x * x2,
896        xy = x * y2,
897        xz = x * z2,
898        yy = y * y2,
899        yz = y * z2,
900        zz = z * z2,
901        wx = w * x2,
902        wy = w * y2,
903        wz = w * z2,
904        sx = s[0],
905        sy = s[1],
906        sz = s[2];
907
908    out[0] = (1 - (yy + zz)) * sx;
909    out[1] = (xy + wz) * sx;
910    out[2] = (xz - wy) * sx;
911    out[3] = 0;
912    out[4] = (xy - wz) * sy;
913    out[5] = (1 - (xx + zz)) * sy;
914    out[6] = (yz + wx) * sy;
915    out[7] = 0;
916    out[8] = (xz + wy) * sz;
917    out[9] = (yz - wx) * sz;
918    out[10] = (1 - (xx + yy)) * sz;
919    out[11] = 0;
920    out[12] = v[0];
921    out[13] = v[1];
922    out[14] = v[2];
923    out[15] = 1;
924
925    return out;
926};
927
928/**
929 * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
930 * This is equivalent to (but much faster than):
931 *
932 *     mat4.identity(dest);
933 *     mat4.translate(dest, vec);
934 *     mat4.translate(dest, origin);
935 *     var quatMat = mat4.create();
936 *     quat4.toMat4(quat, quatMat);
937 *     mat4.multiply(dest, quatMat);
938 *     mat4.scale(dest, scale)
939 *     mat4.translate(dest, negativeOrigin);
940 *
941 * @param {mat4} out mat4 receiving operation result
942 * @param {quat4} q Rotation quaternion
943 * @param {vec3} v Translation vector
944 * @param {vec3} s Scaling vector
945 * @param {vec3} o The origin vector around which to scale and rotate
946 * @returns {mat4} out
947 */
948mat4.fromRotationTranslationScaleOrigin = function (out, q, v, s, o) {
949  // Quaternion math
950  var x = q[0], y = q[1], z = q[2], w = q[3],
951      x2 = x + x,
952      y2 = y + y,
953      z2 = z + z,
954
955      xx = x * x2,
956      xy = x * y2,
957      xz = x * z2,
958      yy = y * y2,
959      yz = y * z2,
960      zz = z * z2,
961      wx = w * x2,
962      wy = w * y2,
963      wz = w * z2,
964
965      sx = s[0],
966      sy = s[1],
967      sz = s[2],
968
969      ox = o[0],
970      oy = o[1],
971      oz = o[2];
972
973  out[0] = (1 - (yy + zz)) * sx;
974  out[1] = (xy + wz) * sx;
975  out[2] = (xz - wy) * sx;
976  out[3] = 0;
977  out[4] = (xy - wz) * sy;
978  out[5] = (1 - (xx + zz)) * sy;
979  out[6] = (yz + wx) * sy;
980  out[7] = 0;
981  out[8] = (xz + wy) * sz;
982  out[9] = (yz - wx) * sz;
983  out[10] = (1 - (xx + yy)) * sz;
984  out[11] = 0;
985  out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz);
986  out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz);
987  out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz);
988  out[15] = 1;
989
990  return out;
991};
992
993mat4.fromQuat = function (out, q) {
994    var x = q[0], y = q[1], z = q[2], w = q[3],
995        x2 = x + x,
996        y2 = y + y,
997        z2 = z + z,
998
999        xx = x * x2,
1000        yx = y * x2,
1001        yy = y * y2,
1002        zx = z * x2,
1003        zy = z * y2,
1004        zz = z * z2,
1005        wx = w * x2,
1006        wy = w * y2,
1007        wz = w * z2;
1008
1009    out[0] = 1 - yy - zz;
1010    out[1] = yx + wz;
1011    out[2] = zx - wy;
1012    out[3] = 0;
1013
1014    out[4] = yx - wz;
1015    out[5] = 1 - xx - zz;
1016    out[6] = zy + wx;
1017    out[7] = 0;
1018
1019    out[8] = zx + wy;
1020    out[9] = zy - wx;
1021    out[10] = 1 - xx - yy;
1022    out[11] = 0;
1023
1024    out[12] = 0;
1025    out[13] = 0;
1026    out[14] = 0;
1027    out[15] = 1;
1028
1029    return out;
1030};
1031
1032/**
1033 * Generates a frustum matrix with the given bounds
1034 *
1035 * @param {mat4} out mat4 frustum matrix will be written into
1036 * @param {Number} left Left bound of the frustum
1037 * @param {Number} right Right bound of the frustum
1038 * @param {Number} bottom Bottom bound of the frustum
1039 * @param {Number} top Top bound of the frustum
1040 * @param {Number} near Near bound of the frustum
1041 * @param {Number} far Far bound of the frustum
1042 * @returns {mat4} out
1043 */
1044mat4.frustum = function (out, left, right, bottom, top, near, far) {
1045    var rl = 1 / (right - left),
1046        tb = 1 / (top - bottom),
1047        nf = 1 / (near - far);
1048    out[0] = (near * 2) * rl;
1049    out[1] = 0;
1050    out[2] = 0;
1051    out[3] = 0;
1052    out[4] = 0;
1053    out[5] = (near * 2) * tb;
1054    out[6] = 0;
1055    out[7] = 0;
1056    out[8] = (right + left) * rl;
1057    out[9] = (top + bottom) * tb;
1058    out[10] = (far + near) * nf;
1059    out[11] = -1;
1060    out[12] = 0;
1061    out[13] = 0;
1062    out[14] = (far * near * 2) * nf;
1063    out[15] = 0;
1064    return out;
1065};
1066
1067/**
1068 * Generates a perspective projection matrix with the given bounds
1069 *
1070 * @param {mat4} out mat4 frustum matrix will be written into
1071 * @param {number} fovy Vertical field of view in radians
1072 * @param {number} aspect Aspect ratio. typically viewport width/height
1073 * @param {number} near Near bound of the frustum
1074 * @param {number} far Far bound of the frustum
1075 * @returns {mat4} out
1076 */
1077mat4.perspective = function (out, fovy, aspect, near, far) {
1078    var f = 1.0 / Math.tan(fovy / 2),
1079        nf = 1 / (near - far);
1080    out[0] = f / aspect;
1081    out[1] = 0;
1082    out[2] = 0;
1083    out[3] = 0;
1084    out[4] = 0;
1085    out[5] = f;
1086    out[6] = 0;
1087    out[7] = 0;
1088    out[8] = 0;
1089    out[9] = 0;
1090    out[10] = (far + near) * nf;
1091    out[11] = -1;
1092    out[12] = 0;
1093    out[13] = 0;
1094    out[14] = (2 * far * near) * nf;
1095    out[15] = 0;
1096    return out;
1097};
1098
1099/**
1100 * Generates a perspective projection matrix with the given field of view.
1101 * This is primarily useful for generating projection matrices to be used
1102 * with the still experiemental WebVR API.
1103 *
1104 * @param {mat4} out mat4 frustum matrix will be written into
1105 * @param {number} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
1106 * @param {number} near Near bound of the frustum
1107 * @param {number} far Far bound of the frustum
1108 * @returns {mat4} out
1109 */
1110mat4.perspectiveFromFieldOfView = function (out, fov, near, far) {
1111    var upTan = Math.tan(fov.upDegrees * Math.PI/180.0),
1112        downTan = Math.tan(fov.downDegrees * Math.PI/180.0),
1113        leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0),
1114        rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0),
1115        xScale = 2.0 / (leftTan + rightTan),
1116        yScale = 2.0 / (upTan + downTan);
1117
1118    out[0] = xScale;
1119    out[1] = 0.0;
1120    out[2] = 0.0;
1121    out[3] = 0.0;
1122    out[4] = 0.0;
1123    out[5] = yScale;
1124    out[6] = 0.0;
1125    out[7] = 0.0;
1126    out[8] = -((leftTan - rightTan) * xScale * 0.5);
1127    out[9] = ((upTan - downTan) * yScale * 0.5);
1128    out[10] = far / (near - far);
1129    out[11] = -1.0;
1130    out[12] = 0.0;
1131    out[13] = 0.0;
1132    out[14] = (far * near) / (near - far);
1133    out[15] = 0.0;
1134    return out;
1135}
1136
1137/**
1138 * Generates a orthogonal projection matrix with the given bounds
1139 *
1140 * @param {mat4} out mat4 frustum matrix will be written into
1141 * @param {number} left Left bound of the frustum
1142 * @param {number} right Right bound of the frustum
1143 * @param {number} bottom Bottom bound of the frustum
1144 * @param {number} top Top bound of the frustum
1145 * @param {number} near Near bound of the frustum
1146 * @param {number} far Far bound of the frustum
1147 * @returns {mat4} out
1148 */
1149mat4.ortho = function (out, left, right, bottom, top, near, far) {
1150    var lr = 1 / (left - right),
1151        bt = 1 / (bottom - top),
1152        nf = 1 / (near - far);
1153    out[0] = -2 * lr;
1154    out[1] = 0;
1155    out[2] = 0;
1156    out[3] = 0;
1157    out[4] = 0;
1158    out[5] = -2 * bt;
1159    out[6] = 0;
1160    out[7] = 0;
1161    out[8] = 0;
1162    out[9] = 0;
1163    out[10] = 2 * nf;
1164    out[11] = 0;
1165    out[12] = (left + right) * lr;
1166    out[13] = (top + bottom) * bt;
1167    out[14] = (far + near) * nf;
1168    out[15] = 1;
1169    return out;
1170};
1171
1172/**
1173 * Generates a look-at matrix with the given eye position, focal point, and up axis
1174 *
1175 * @param {mat4} out mat4 frustum matrix will be written into
1176 * @param {vec3} eye Position of the viewer
1177 * @param {vec3} center Point the viewer is looking at
1178 * @param {vec3} up vec3 pointing up
1179 * @returns {mat4} out
1180 */
1181mat4.lookAt = function (out, eye, center, up) {
1182    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
1183        eyex = eye[0],
1184        eyey = eye[1],
1185        eyez = eye[2],
1186        upx = up[0],
1187        upy = up[1],
1188        upz = up[2],
1189        centerx = center[0],
1190        centery = center[1],
1191        centerz = center[2];
1192
1193    if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&
1194        Math.abs(eyey - centery) < glMatrix.EPSILON &&
1195        Math.abs(eyez - centerz) < glMatrix.EPSILON) {
1196        return mat4.identity(out);
1197    }
1198
1199    z0 = eyex - centerx;
1200    z1 = eyey - centery;
1201    z2 = eyez - centerz;
1202
1203    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
1204    z0 *= len;
1205    z1 *= len;
1206    z2 *= len;
1207
1208    x0 = upy * z2 - upz * z1;
1209    x1 = upz * z0 - upx * z2;
1210    x2 = upx * z1 - upy * z0;
1211    len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
1212    if (!len) {
1213        x0 = 0;
1214        x1 = 0;
1215        x2 = 0;
1216    } else {
1217        len = 1 / len;
1218        x0 *= len;
1219        x1 *= len;
1220        x2 *= len;
1221    }
1222
1223    y0 = z1 * x2 - z2 * x1;
1224    y1 = z2 * x0 - z0 * x2;
1225    y2 = z0 * x1 - z1 * x0;
1226
1227    len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
1228    if (!len) {
1229        y0 = 0;
1230        y1 = 0;
1231        y2 = 0;
1232    } else {
1233        len = 1 / len;
1234        y0 *= len;
1235        y1 *= len;
1236        y2 *= len;
1237    }
1238
1239    out[0] = x0;
1240    out[1] = y0;
1241    out[2] = z0;
1242    out[3] = 0;
1243    out[4] = x1;
1244    out[5] = y1;
1245    out[6] = z1;
1246    out[7] = 0;
1247    out[8] = x2;
1248    out[9] = y2;
1249    out[10] = z2;
1250    out[11] = 0;
1251    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
1252    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
1253    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
1254    out[15] = 1;
1255
1256    return out;
1257};
1258
1259/**
1260 * Returns a string representation of a mat4
1261 *
1262 * @param {mat4} mat matrix to represent as a string
1263 * @returns {String} string representation of the matrix
1264 */
1265mat4.str = function (a) {
1266    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
1267                    a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
1268                    a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
1269                    a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
1270};
1271
1272/**
1273 * Returns Frobenius norm of a mat4
1274 *
1275 * @param {mat4} a the matrix to calculate Frobenius norm of
1276 * @returns {Number} Frobenius norm
1277 */
1278mat4.frob = function (a) {
1279    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))
1280};
1281
1282
1283module.exports = mat4;
1284