166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
366a37686207944273ced825e0e8b6b6375f8c3deJamie GennisRedistribution and use in source and binary forms, with or without modification,
466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisare permitted provided that the following conditions are met:
566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  * Redistributions of source code must retain the above copyright notice, this
766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    list of conditions and the following disclaimer.
866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  * Redistributions in binary form must reproduce the above copyright notice,
966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    this list of conditions and the following disclaimer in the documentation
1066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    and/or other materials provided with the distribution.
1166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
1266a37686207944273ced825e0e8b6b6375f8c3deJamie GennisTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1366a37686207944273ced825e0e8b6b6375f8c3deJamie GennisANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1466a37686207944273ced825e0e8b6b6375f8c3deJamie GennisWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1566a37686207944273ced825e0e8b6b6375f8c3deJamie GennisDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
1666a37686207944273ced825e0e8b6b6375f8c3deJamie GennisANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1866a37686207944273ced825e0e8b6b6375f8c3deJamie GennisLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1966a37686207944273ced825e0e8b6b6375f8c3deJamie GennisANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2166a37686207944273ced825e0e8b6b6375f8c3deJamie GennisSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
2266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
2466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @class 4x4 Matrix
2566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @name mat4
2666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
2766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisvar mat4 = {};
2866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
3066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Creates a new identity mat4
3166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
3266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} a new 4x4 matrix
3366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
3466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.create = function() {
3566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var out = new GLMAT_ARRAY_TYPE(16);
3666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = 1;
3766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = 0;
3866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = 0;
3966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
4066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = 0;
4166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = 1;
4266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = 0;
4366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
4466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = 0;
4566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = 0;
4666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = 1;
4766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
4866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = 0;
4966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = 0;
5066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = 0;
5166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
5266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
5366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
5466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
5566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
5666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Creates a new mat4 initialized with values from an existing matrix
5766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
5866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a matrix to clone
5966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} a new 4x4 matrix
6066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
6166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.clone = function(a) {
6266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var out = new GLMAT_ARRAY_TYPE(16);
6366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a[0];
6466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a[1];
6566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a[2];
6666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a[3];
6766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a[4];
6866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a[5];
6966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a[6];
7066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a[7];
7166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a[8];
7266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a[9];
7366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a[10];
7466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a[11];
7566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = a[12];
7666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = a[13];
7766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = a[14];
7866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = a[15];
7966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
8066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
8166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
8266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
8366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Copy the values from one mat4 to another
8466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
8566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
8666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the source matrix
8766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
8866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
8966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.copy = function(out, a) {
9066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a[0];
9166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a[1];
9266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a[2];
9366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a[3];
9466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a[4];
9566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a[5];
9666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a[6];
9766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a[7];
9866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a[8];
9966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a[9];
10066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a[10];
10166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a[11];
10266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = a[12];
10366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = a[13];
10466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = a[14];
10566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = a[15];
10666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
10766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
10866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
10966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
11066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Set a mat4 to the identity matrix
11166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
11266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
11366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
11466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
11566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.identity = function(out) {
11666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = 1;
11766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = 0;
11866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = 0;
11966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
12066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = 0;
12166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = 1;
12266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = 0;
12366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
12466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = 0;
12566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = 0;
12666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = 1;
12766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
12866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = 0;
12966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = 0;
13066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = 0;
13166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
13266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
13366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
13466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
13566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
13666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Transpose the values of a mat4
13766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
13866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
13966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the source matrix
14066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
14166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
14266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.transpose = function(out, a) {
14366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // If we are transposing ourselves we can skip a few steps but have to cache some values
14466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (out === a) {
14566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        var a01 = a[1], a02 = a[2], a03 = a[3],
14666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            a12 = a[6], a13 = a[7],
14766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            a23 = a[11];
14866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
14966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[1] = a[4];
15066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[2] = a[8];
15166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[3] = a[12];
15266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[4] = a01;
15366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[6] = a[9];
15466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[7] = a[13];
15566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[8] = a02;
15666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[9] = a12;
15766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[11] = a[14];
15866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a03;
15966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a13;
16066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a23;
16166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    } else {
16266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[0] = a[0];
16366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[1] = a[4];
16466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[2] = a[8];
16566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[3] = a[12];
16666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[4] = a[1];
16766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[5] = a[5];
16866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[6] = a[9];
16966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[7] = a[13];
17066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[8] = a[2];
17166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[9] = a[6];
17266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[10] = a[10];
17366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[11] = a[14];
17466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[3];
17566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[7];
17666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[11];
17766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[15];
17866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
17966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
18066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
18166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
18266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
18366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
18466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Inverts a mat4
18566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
18666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
18766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the source matrix
18866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
18966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
19066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.invert = function(out, a) {
19166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
19266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
19366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
19466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
19566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
19666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b00 = a00 * a11 - a01 * a10,
19766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b01 = a00 * a12 - a02 * a10,
19866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b02 = a00 * a13 - a03 * a10,
19966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b03 = a01 * a12 - a02 * a11,
20066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b04 = a01 * a13 - a03 * a11,
20166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b05 = a02 * a13 - a03 * a12,
20266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b06 = a20 * a31 - a21 * a30,
20366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b07 = a20 * a32 - a22 * a30,
20466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b08 = a20 * a33 - a23 * a30,
20566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b09 = a21 * a32 - a22 * a31,
20666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b10 = a21 * a33 - a23 * a31,
20766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b11 = a22 * a33 - a23 * a32,
20866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
20966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        // Calculate the determinant
21066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
21166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
21266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!det) {
21366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return null;
21466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
21566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    det = 1.0 / det;
21666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
21766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
21866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
21966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
22066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
22166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
22266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
22366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
22466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
22566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
22666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
22766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
22866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
22966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
23066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
23166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
23266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
23366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
23466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
23566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
23666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
23766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
23866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Calculates the adjugate of a mat4
23966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
24066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
24166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the source matrix
24266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
24366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
24466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.adjoint = function(out, a) {
24566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
24666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
24766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
24866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
24966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
25066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0]  =  (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
25166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1]  = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
25266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2]  =  (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
25366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3]  = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
25466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4]  = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
25566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5]  =  (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
25666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6]  = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
25766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7]  =  (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
25866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8]  =  (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
25966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9]  = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
26066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] =  (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
26166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
26266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
26366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] =  (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
26466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
26566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] =  (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
26666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
26766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
26866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
26966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
27066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Calculates the determinant of a mat4
27166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
27266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the source matrix
27366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {Number} determinant of a
27466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
27566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.determinant = function (a) {
27666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
27766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
27866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
27966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
28066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
28166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b00 = a00 * a11 - a01 * a10,
28266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b01 = a00 * a12 - a02 * a10,
28366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b02 = a00 * a13 - a03 * a10,
28466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b03 = a01 * a12 - a02 * a11,
28566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b04 = a01 * a13 - a03 * a11,
28666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b05 = a02 * a13 - a03 * a12,
28766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b06 = a20 * a31 - a21 * a30,
28866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b07 = a20 * a32 - a22 * a30,
28966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b08 = a20 * a33 - a23 * a30,
29066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b09 = a21 * a32 - a22 * a31,
29166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b10 = a21 * a33 - a23 * a31,
29266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b11 = a22 * a33 - a23 * a32;
29366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
29466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Calculate the determinant
29566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
29666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
29766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
29866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
29966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Multiplies two mat4's
30066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
30166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
30266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the first operand
30366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} b the second operand
30466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
30566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
30666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.multiply = function (out, a, b) {
30766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
30866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
30966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
31066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
31166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
31266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Cache only the current line of the second matrix
31366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var b0  = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
31466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
31566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
31666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
31766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
31866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
31966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
32066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
32166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
32266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
32366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
32466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
32566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
32666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
32766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
32866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
32966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
33066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
33166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
33266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
33366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
33466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
33566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
33666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
33766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
33866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
33966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
34066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Alias for {@link mat4.multiply}
34166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @function
34266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
34366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.mul = mat4.multiply;
34466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
34566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
34666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Translate a mat4 by the given vector
34766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
34866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
34966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to translate
35066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} v vector to translate by
35166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
35266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
35366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.translate = function (out, a, v) {
35466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x = v[0], y = v[1], z = v[2],
35566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a00, a01, a02, a03,
35666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10, a11, a12, a13,
35766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20, a21, a22, a23;
35866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
35966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (a === out) {
36066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
36166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
36266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
36366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
36466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    } else {
36566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
36666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
36766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
36866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
36966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
37066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
37166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
37266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
37366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a00 * x + a10 * y + a20 * z + a[12];
37466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a01 * x + a11 * y + a21 * z + a[13];
37566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a02 * x + a12 * y + a22 * z + a[14];
37666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a03 * x + a13 * y + a23 * z + a[15];
37766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
37866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
37966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
38066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
38166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
38266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
38366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Scales the mat4 by the dimensions in the given vec3
38466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
38566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
38666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to scale
38766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} v the vec3 to scale the matrix by
38866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
38966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis **/
39066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.scale = function(out, a, v) {
39166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x = v[0], y = v[1], z = v[2];
39266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
39366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a[0] * x;
39466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a[1] * x;
39566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a[2] * x;
39666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a[3] * x;
39766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a[4] * y;
39866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a[5] * y;
39966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a[6] * y;
40066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a[7] * y;
40166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a[8] * z;
40266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a[9] * z;
40366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a[10] * z;
40466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a[11] * z;
40566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = a[12];
40666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = a[13];
40766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = a[14];
40866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = a[15];
40966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
41066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
41166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
41266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
41366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Rotates a mat4 by the given angle
41466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
41566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
41666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to rotate
41766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} rad the angle to rotate the matrix by
41866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} axis the axis to rotate around
41966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
42066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
42166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.rotate = function (out, a, rad, axis) {
42266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x = axis[0], y = axis[1], z = axis[2],
42366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        len = Math.sqrt(x * x + y * y + z * z),
42466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        s, c, t,
42566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a00, a01, a02, a03,
42666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10, a11, a12, a13,
42766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20, a21, a22, a23,
42866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b00, b01, b02,
42966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b10, b11, b12,
43066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        b20, b21, b22;
43166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
43266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (Math.abs(len) < GLMAT_EPSILON) { return null; }
43366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
43466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    len = 1 / len;
43566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    x *= len;
43666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    y *= len;
43766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z *= len;
43866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
43966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    s = Math.sin(rad);
44066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    c = Math.cos(rad);
44166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    t = 1 - c;
44266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
44366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
44466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
44566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
44666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
44766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Construct the elements of the rotation matrix
44866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
44966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
45066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
45166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
45266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Perform rotation-specific matrix multiplication
45366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
45466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
45566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
45666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
45766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
45866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
45966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
46066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
46166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
46266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
46366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
46466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
46566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
46666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (a !== out) { // If the source and destination differ, copy the unchanged last row
46766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[12];
46866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[13];
46966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[14];
47066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[15];
47166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
47266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
47366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
47466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
47566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
47666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Rotates a matrix by the given angle around the X axis
47766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
47866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
47966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to rotate
48066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} rad the angle to rotate the matrix by
48166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
48266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
48366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.rotateX = function (out, a, rad) {
48466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var s = Math.sin(rad),
48566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        c = Math.cos(rad),
48666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4],
48766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a11 = a[5],
48866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a12 = a[6],
48966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a13 = a[7],
49066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8],
49166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a21 = a[9],
49266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a22 = a[10],
49366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a23 = a[11];
49466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
49566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (a !== out) { // If the source and destination differ, copy the unchanged rows
49666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[0]  = a[0];
49766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[1]  = a[1];
49866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[2]  = a[2];
49966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[3]  = a[3];
50066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[12];
50166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[13];
50266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[14];
50366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[15];
50466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
50566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
50666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Perform axis-specific matrix multiplication
50766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a10 * c + a20 * s;
50866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a11 * c + a21 * s;
50966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a12 * c + a22 * s;
51066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a13 * c + a23 * s;
51166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a20 * c - a10 * s;
51266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a21 * c - a11 * s;
51366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a22 * c - a12 * s;
51466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a23 * c - a13 * s;
51566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
51666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
51766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
51866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
51966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Rotates a matrix by the given angle around the Y axis
52066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
52166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
52266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to rotate
52366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} rad the angle to rotate the matrix by
52466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
52566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
52666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.rotateY = function (out, a, rad) {
52766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var s = Math.sin(rad),
52866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        c = Math.cos(rad),
52966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a00 = a[0],
53066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a01 = a[1],
53166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a02 = a[2],
53266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a03 = a[3],
53366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a20 = a[8],
53466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a21 = a[9],
53566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a22 = a[10],
53666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a23 = a[11];
53766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
53866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (a !== out) { // If the source and destination differ, copy the unchanged rows
53966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[4]  = a[4];
54066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[5]  = a[5];
54166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[6]  = a[6];
54266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[7]  = a[7];
54366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[12];
54466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[13];
54566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[14];
54666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[15];
54766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
54866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
54966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Perform axis-specific matrix multiplication
55066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a00 * c - a20 * s;
55166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a01 * c - a21 * s;
55266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a02 * c - a22 * s;
55366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a03 * c - a23 * s;
55466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = a00 * s + a20 * c;
55566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = a01 * s + a21 * c;
55666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = a02 * s + a22 * c;
55766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = a03 * s + a23 * c;
55866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
55966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
56066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
56166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
56266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Rotates a matrix by the given angle around the Z axis
56366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
56466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out the receiving matrix
56566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} a the matrix to rotate
56666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} rad the angle to rotate the matrix by
56766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
56866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
56966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.rotateZ = function (out, a, rad) {
57066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var s = Math.sin(rad),
57166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        c = Math.cos(rad),
57266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a00 = a[0],
57366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a01 = a[1],
57466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a02 = a[2],
57566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a03 = a[3],
57666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a10 = a[4],
57766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a11 = a[5],
57866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a12 = a[6],
57966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        a13 = a[7];
58066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
58166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (a !== out) { // If the source and destination differ, copy the unchanged last row
58266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[8]  = a[8];
58366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[9]  = a[9];
58466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[10] = a[10];
58566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[11] = a[11];
58666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[12] = a[12];
58766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[13] = a[13];
58866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[14] = a[14];
58966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        out[15] = a[15];
59066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
59166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
59266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Perform axis-specific matrix multiplication
59366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = a00 * c + a10 * s;
59466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = a01 * c + a11 * s;
59566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = a02 * c + a12 * s;
59666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = a03 * c + a13 * s;
59766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = a10 * c - a00 * s;
59866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = a11 * c - a01 * s;
59966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = a12 * c - a02 * s;
60066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = a13 * c - a03 * s;
60166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
60266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
60366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
60466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
60566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Creates a matrix from a quaternion rotation and vector translation
60666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * This is equivalent to (but much faster than):
60766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
60866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *     mat4.identity(dest);
60966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *     mat4.translate(dest, vec);
61066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *     var quatMat = mat4.create();
61166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *     quat4.toMat4(quat, quatMat);
61266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *     mat4.multiply(dest, quatMat);
61366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
61466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out mat4 receiving operation result
61566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {quat4} q Rotation quaternion
61666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} v Translation vector
61766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
61866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
61966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.fromRotationTranslation = function (out, q, v) {
62066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    // Quaternion math
62166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x = q[0], y = q[1], z = q[2], w = q[3],
62266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x2 = x + x,
62366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y2 = y + y,
62466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        z2 = z + z,
62566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
62666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xx = x * x2,
62766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xy = x * y2,
62866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xz = x * z2,
62966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        yy = y * y2,
63066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        yz = y * z2,
63166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        zz = z * z2,
63266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wx = w * x2,
63366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wy = w * y2,
63466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wz = w * z2;
63566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
63666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = 1 - (yy + zz);
63766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = xy + wz;
63866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = xz - wy;
63966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
64066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = xy - wz;
64166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = 1 - (xx + zz);
64266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = yz + wx;
64366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
64466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = xz + wy;
64566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = yz - wx;
64666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = 1 - (xx + yy);
64766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
64866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = v[0];
64966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = v[1];
65066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = v[2];
65166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
65266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
65366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
65466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
65566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
65666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
65766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis* Calculates a 4x4 matrix from the given quaternion
65866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis*
65966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis* @param {mat4} out mat4 receiving operation result
66066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis* @param {quat} q Quaternion to create matrix from
66166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis*
66266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis* @returns {mat4} out
66366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis*/
66466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.fromQuat = function (out, q) {
66566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x = q[0], y = q[1], z = q[2], w = q[3],
66666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x2 = x + x,
66766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y2 = y + y,
66866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        z2 = z + z,
66966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
67066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xx = x * x2,
67166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xy = x * y2,
67266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        xz = x * z2,
67366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        yy = y * y2,
67466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        yz = y * z2,
67566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        zz = z * z2,
67666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wx = w * x2,
67766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wy = w * y2,
67866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        wz = w * z2;
67966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
68066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = 1 - (yy + zz);
68166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = xy + wz;
68266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = xz - wy;
68366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
68466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
68566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = xy - wz;
68666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = 1 - (xx + zz);
68766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = yz + wx;
68866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
68966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
69066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = xz + wy;
69166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = yz - wx;
69266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = 1 - (xx + yy);
69366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
69466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
69566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = 0;
69666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = 0;
69766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = 0;
69866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
69966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
70066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
70166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
70266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
70366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
70466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Generates a frustum matrix with the given bounds
70566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
70666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out mat4 frustum matrix will be written into
70766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} left Left bound of the frustum
70866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} right Right bound of the frustum
70966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} bottom Bottom bound of the frustum
71066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} top Top bound of the frustum
71166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} near Near bound of the frustum
71266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {Number} far Far bound of the frustum
71366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
71466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
71566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.frustum = function (out, left, right, bottom, top, near, far) {
71666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var rl = 1 / (right - left),
71766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        tb = 1 / (top - bottom),
71866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        nf = 1 / (near - far);
71966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = (near * 2) * rl;
72066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = 0;
72166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = 0;
72266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
72366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = 0;
72466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = (near * 2) * tb;
72566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = 0;
72666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
72766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = (right + left) * rl;
72866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = (top + bottom) * tb;
72966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = (far + near) * nf;
73066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = -1;
73166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = 0;
73266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = 0;
73366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = (far * near * 2) * nf;
73466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 0;
73566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
73666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
73766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
73866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
73966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Generates a perspective projection matrix with the given bounds
74066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
74166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out mat4 frustum matrix will be written into
74266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} fovy Vertical field of view in radians
74366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} aspect Aspect ratio. typically viewport width/height
74466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} near Near bound of the frustum
74566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} far Far bound of the frustum
74666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
74766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
74866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.perspective = function (out, fovy, aspect, near, far) {
74966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var f = 1.0 / Math.tan(fovy / 2),
75066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        nf = 1 / (near - far);
75166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = f / aspect;
75266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = 0;
75366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = 0;
75466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
75566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = 0;
75666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = f;
75766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = 0;
75866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
75966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = 0;
76066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = 0;
76166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = (far + near) * nf;
76266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = -1;
76366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = 0;
76466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = 0;
76566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = (2 * far * near) * nf;
76666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 0;
76766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
76866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
76966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
77066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
77166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Generates a orthogonal projection matrix with the given bounds
77266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
77366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out mat4 frustum matrix will be written into
77466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} left Left bound of the frustum
77566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} right Right bound of the frustum
77666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} bottom Bottom bound of the frustum
77766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} top Top bound of the frustum
77866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} near Near bound of the frustum
77966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {number} far Far bound of the frustum
78066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
78166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
78266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.ortho = function (out, left, right, bottom, top, near, far) {
78366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var lr = 1 / (left - right),
78466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        bt = 1 / (bottom - top),
78566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        nf = 1 / (near - far);
78666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = -2 * lr;
78766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = 0;
78866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = 0;
78966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
79066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = 0;
79166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = -2 * bt;
79266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = 0;
79366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
79466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = 0;
79566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = 0;
79666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = 2 * nf;
79766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
79866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = (left + right) * lr;
79966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = (top + bottom) * bt;
80066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = (far + near) * nf;
80166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
80266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
80366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
80466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
80566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
80666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Generates a look-at matrix with the given eye position, focal point, and up axis
80766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
80866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} out mat4 frustum matrix will be written into
80966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} eye Position of the viewer
81066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} center Point the viewer is looking at
81166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {vec3} up vec3 pointing up
81266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {mat4} out
81366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
81466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.lookAt = function (out, eye, center, up) {
81566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
81666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        eyex = eye[0],
81766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        eyey = eye[1],
81866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        eyez = eye[2],
81966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        upx = up[0],
82066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        upy = up[1],
82166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        upz = up[2],
82266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        centerx = center[0],
82366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        centery = center[1],
82466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        centerz = center[2];
82566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
82666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
82766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        Math.abs(eyey - centery) < GLMAT_EPSILON &&
82866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        Math.abs(eyez - centerz) < GLMAT_EPSILON) {
82966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return mat4.identity(out);
83066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
83166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
83266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z0 = eyex - centerx;
83366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z1 = eyey - centery;
83466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z2 = eyez - centerz;
83566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
83666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
83766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z0 *= len;
83866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z1 *= len;
83966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    z2 *= len;
84066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
84166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    x0 = upy * z2 - upz * z1;
84266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    x1 = upz * z0 - upx * z2;
84366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    x2 = upx * z1 - upy * z0;
84466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
84566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!len) {
84666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x0 = 0;
84766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x1 = 0;
84866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x2 = 0;
84966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    } else {
85066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        len = 1 / len;
85166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x0 *= len;
85266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x1 *= len;
85366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        x2 *= len;
85466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
85566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
85666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    y0 = z1 * x2 - z2 * x1;
85766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    y1 = z2 * x0 - z0 * x2;
85866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    y2 = z0 * x1 - z1 * x0;
85966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
86066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
86166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!len) {
86266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y0 = 0;
86366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y1 = 0;
86466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y2 = 0;
86566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    } else {
86666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        len = 1 / len;
86766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y0 *= len;
86866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y1 *= len;
86966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        y2 *= len;
87066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
87166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
87266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[0] = x0;
87366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[1] = y0;
87466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[2] = z0;
87566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[3] = 0;
87666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[4] = x1;
87766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[5] = y1;
87866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[6] = z1;
87966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[7] = 0;
88066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[8] = x2;
88166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[9] = y2;
88266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[10] = z2;
88366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[11] = 0;
88466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
88566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
88666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
88766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    out[15] = 1;
88866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
88966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return out;
89066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
89166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
89266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis/**
89366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * Returns a string representation of a mat4
89466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis *
89566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @param {mat4} mat matrix to represent as a string
89666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis * @returns {String} string representation of the matrix
89766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis */
89866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennismat4.str = function (a) {
89966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
90066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
90166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
90266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
90366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis};
90466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
90566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisif(typeof(exports) !== 'undefined') {
90666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    exports.mat4 = mat4;
90766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis}
908