1/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
2
3Redistribution and use in source and binary forms, with or without modification,
4are permitted provided that the following conditions are met:
5
6  * Redistributions of source code must retain the above copyright notice, this
7    list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright notice,
9    this list of conditions and the following disclaimer in the documentation
10    and/or other materials provided with the distribution.
11
12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22
23/**
24 * @class 3x3 Matrix
25 * @name mat3
26 */
27var mat3 = {};
28
29/**
30 * Creates a new identity mat3
31 *
32 * @returns {mat3} a new 3x3 matrix
33 */
34mat3.create = function() {
35    var out = new GLMAT_ARRAY_TYPE(9);
36    out[0] = 1;
37    out[1] = 0;
38    out[2] = 0;
39    out[3] = 0;
40    out[4] = 1;
41    out[5] = 0;
42    out[6] = 0;
43    out[7] = 0;
44    out[8] = 1;
45    return out;
46};
47
48/**
49 * Copies the upper-left 3x3 values into the given mat3.
50 *
51 * @param {mat3} out the receiving 3x3 matrix
52 * @param {mat4} a   the source 4x4 matrix
53 * @returns {mat3} out
54 */
55mat3.fromMat4 = function(out, a) {
56    out[0] = a[0];
57    out[1] = a[1];
58    out[2] = a[2];
59    out[3] = a[4];
60    out[4] = a[5];
61    out[5] = a[6];
62    out[6] = a[8];
63    out[7] = a[9];
64    out[8] = a[10];
65    return out;
66};
67
68/**
69 * Creates a new mat3 initialized with values from an existing matrix
70 *
71 * @param {mat3} a matrix to clone
72 * @returns {mat3} a new 3x3 matrix
73 */
74mat3.clone = function(a) {
75    var out = new GLMAT_ARRAY_TYPE(9);
76    out[0] = a[0];
77    out[1] = a[1];
78    out[2] = a[2];
79    out[3] = a[3];
80    out[4] = a[4];
81    out[5] = a[5];
82    out[6] = a[6];
83    out[7] = a[7];
84    out[8] = a[8];
85    return out;
86};
87
88/**
89 * Copy the values from one mat3 to another
90 *
91 * @param {mat3} out the receiving matrix
92 * @param {mat3} a the source matrix
93 * @returns {mat3} out
94 */
95mat3.copy = function(out, a) {
96    out[0] = a[0];
97    out[1] = a[1];
98    out[2] = a[2];
99    out[3] = a[3];
100    out[4] = a[4];
101    out[5] = a[5];
102    out[6] = a[6];
103    out[7] = a[7];
104    out[8] = a[8];
105    return out;
106};
107
108/**
109 * Set a mat3 to the identity matrix
110 *
111 * @param {mat3} out the receiving matrix
112 * @returns {mat3} out
113 */
114mat3.identity = function(out) {
115    out[0] = 1;
116    out[1] = 0;
117    out[2] = 0;
118    out[3] = 0;
119    out[4] = 1;
120    out[5] = 0;
121    out[6] = 0;
122    out[7] = 0;
123    out[8] = 1;
124    return out;
125};
126
127/**
128 * Transpose the values of a mat3
129 *
130 * @param {mat3} out the receiving matrix
131 * @param {mat3} a the source matrix
132 * @returns {mat3} out
133 */
134mat3.transpose = function(out, a) {
135    // If we are transposing ourselves we can skip a few steps but have to cache some values
136    if (out === a) {
137        var a01 = a[1], a02 = a[2], a12 = a[5];
138        out[1] = a[3];
139        out[2] = a[6];
140        out[3] = a01;
141        out[5] = a[7];
142        out[6] = a02;
143        out[7] = a12;
144    } else {
145        out[0] = a[0];
146        out[1] = a[3];
147        out[2] = a[6];
148        out[3] = a[1];
149        out[4] = a[4];
150        out[5] = a[7];
151        out[6] = a[2];
152        out[7] = a[5];
153        out[8] = a[8];
154    }
155
156    return out;
157};
158
159/**
160 * Inverts a mat3
161 *
162 * @param {mat3} out the receiving matrix
163 * @param {mat3} a the source matrix
164 * @returns {mat3} out
165 */
166mat3.invert = function(out, a) {
167    var a00 = a[0], a01 = a[1], a02 = a[2],
168        a10 = a[3], a11 = a[4], a12 = a[5],
169        a20 = a[6], a21 = a[7], a22 = a[8],
170
171        b01 = a22 * a11 - a12 * a21,
172        b11 = -a22 * a10 + a12 * a20,
173        b21 = a21 * a10 - a11 * a20,
174
175        // Calculate the determinant
176        det = a00 * b01 + a01 * b11 + a02 * b21;
177
178    if (!det) {
179        return null;
180    }
181    det = 1.0 / det;
182
183    out[0] = b01 * det;
184    out[1] = (-a22 * a01 + a02 * a21) * det;
185    out[2] = (a12 * a01 - a02 * a11) * det;
186    out[3] = b11 * det;
187    out[4] = (a22 * a00 - a02 * a20) * det;
188    out[5] = (-a12 * a00 + a02 * a10) * det;
189    out[6] = b21 * det;
190    out[7] = (-a21 * a00 + a01 * a20) * det;
191    out[8] = (a11 * a00 - a01 * a10) * det;
192    return out;
193};
194
195/**
196 * Calculates the adjugate of a mat3
197 *
198 * @param {mat3} out the receiving matrix
199 * @param {mat3} a the source matrix
200 * @returns {mat3} out
201 */
202mat3.adjoint = function(out, a) {
203    var a00 = a[0], a01 = a[1], a02 = a[2],
204        a10 = a[3], a11 = a[4], a12 = a[5],
205        a20 = a[6], a21 = a[7], a22 = a[8];
206
207    out[0] = (a11 * a22 - a12 * a21);
208    out[1] = (a02 * a21 - a01 * a22);
209    out[2] = (a01 * a12 - a02 * a11);
210    out[3] = (a12 * a20 - a10 * a22);
211    out[4] = (a00 * a22 - a02 * a20);
212    out[5] = (a02 * a10 - a00 * a12);
213    out[6] = (a10 * a21 - a11 * a20);
214    out[7] = (a01 * a20 - a00 * a21);
215    out[8] = (a00 * a11 - a01 * a10);
216    return out;
217};
218
219/**
220 * Calculates the determinant of a mat3
221 *
222 * @param {mat3} a the source matrix
223 * @returns {Number} determinant of a
224 */
225mat3.determinant = function (a) {
226    var a00 = a[0], a01 = a[1], a02 = a[2],
227        a10 = a[3], a11 = a[4], a12 = a[5],
228        a20 = a[6], a21 = a[7], a22 = a[8];
229
230    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
231};
232
233/**
234 * Multiplies two mat3's
235 *
236 * @param {mat3} out the receiving matrix
237 * @param {mat3} a the first operand
238 * @param {mat3} b the second operand
239 * @returns {mat3} out
240 */
241mat3.multiply = function (out, a, b) {
242    var a00 = a[0], a01 = a[1], a02 = a[2],
243        a10 = a[3], a11 = a[4], a12 = a[5],
244        a20 = a[6], a21 = a[7], a22 = a[8],
245
246        b00 = b[0], b01 = b[1], b02 = b[2],
247        b10 = b[3], b11 = b[4], b12 = b[5],
248        b20 = b[6], b21 = b[7], b22 = b[8];
249
250    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
251    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
252    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
253
254    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
255    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
256    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
257
258    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
259    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
260    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
261    return out;
262};
263
264/**
265 * Alias for {@link mat3.multiply}
266 * @function
267 */
268mat3.mul = mat3.multiply;
269
270/**
271 * Translate a mat3 by the given vector
272 *
273 * @param {mat3} out the receiving matrix
274 * @param {mat3} a the matrix to translate
275 * @param {vec2} v vector to translate by
276 * @returns {mat3} out
277 */
278mat3.translate = function(out, a, v) {
279    var a00 = a[0], a01 = a[1], a02 = a[2],
280        a10 = a[3], a11 = a[4], a12 = a[5],
281        a20 = a[6], a21 = a[7], a22 = a[8],
282        x = v[0], y = v[1];
283
284    out[0] = a00;
285    out[1] = a01;
286    out[2] = a02;
287
288    out[3] = a10;
289    out[4] = a11;
290    out[5] = a12;
291
292    out[6] = x * a00 + y * a10 + a20;
293    out[7] = x * a01 + y * a11 + a21;
294    out[8] = x * a02 + y * a12 + a22;
295    return out;
296};
297
298/**
299 * Rotates a mat3 by the given angle
300 *
301 * @param {mat3} out the receiving matrix
302 * @param {mat3} a the matrix to rotate
303 * @param {Number} rad the angle to rotate the matrix by
304 * @returns {mat3} out
305 */
306mat3.rotate = function (out, a, rad) {
307    var a00 = a[0], a01 = a[1], a02 = a[2],
308        a10 = a[3], a11 = a[4], a12 = a[5],
309        a20 = a[6], a21 = a[7], a22 = a[8],
310
311        s = Math.sin(rad),
312        c = Math.cos(rad);
313
314    out[0] = c * a00 + s * a10;
315    out[1] = c * a01 + s * a11;
316    out[2] = c * a02 + s * a12;
317
318    out[3] = c * a10 - s * a00;
319    out[4] = c * a11 - s * a01;
320    out[5] = c * a12 - s * a02;
321
322    out[6] = a20;
323    out[7] = a21;
324    out[8] = a22;
325    return out;
326};
327
328/**
329 * Scales the mat3 by the dimensions in the given vec2
330 *
331 * @param {mat3} out the receiving matrix
332 * @param {mat3} a the matrix to rotate
333 * @param {vec2} v the vec2 to scale the matrix by
334 * @returns {mat3} out
335 **/
336mat3.scale = function(out, a, v) {
337    var x = v[0], y = v[2];
338
339    out[0] = x * a[0];
340    out[1] = x * a[1];
341    out[2] = x * a[2];
342
343    out[3] = y * a[3];
344    out[4] = y * a[4];
345    out[5] = y * a[5];
346
347    out[6] = a[6];
348    out[7] = a[7];
349    out[8] = a[8];
350    return out;
351};
352
353/**
354 * Copies the values from a mat2d into a mat3
355 *
356 * @param {mat3} out the receiving matrix
357 * @param {mat3} a the matrix to rotate
358 * @param {vec2} v the vec2 to scale the matrix by
359 * @returns {mat3} out
360 **/
361mat3.fromMat2d = function(out, a) {
362    out[0] = a[0];
363    out[1] = a[1];
364    out[2] = 0;
365
366    out[3] = a[2];
367    out[4] = a[3];
368    out[5] = 0;
369
370    out[6] = a[4];
371    out[7] = a[5];
372    out[8] = 1;
373    return out;
374};
375
376/**
377* Calculates a 3x3 matrix from the given quaternion
378*
379* @param {mat3} out mat3 receiving operation result
380* @param {quat} q Quaternion to create matrix from
381*
382* @returns {mat3} out
383*/
384mat3.fromQuat = function (out, q) {
385    var x = q[0], y = q[1], z = q[2], w = q[3],
386        x2 = x + x,
387        y2 = y + y,
388        z2 = z + z,
389
390        xx = x * x2,
391        xy = x * y2,
392        xz = x * z2,
393        yy = y * y2,
394        yz = y * z2,
395        zz = z * z2,
396        wx = w * x2,
397        wy = w * y2,
398        wz = w * z2;
399
400    out[0] = 1 - (yy + zz);
401    out[1] = xy + wz;
402    out[2] = xz - wy;
403
404    out[3] = xy - wz;
405    out[4] = 1 - (xx + zz);
406    out[5] = yz + wx;
407
408    out[6] = xz + wy;
409    out[7] = yz - wx;
410    out[8] = 1 - (xx + yy);
411
412    return out;
413};
414
415/**
416 * Returns a string representation of a mat3
417 *
418 * @param {mat3} mat matrix to represent as a string
419 * @returns {String} string representation of the matrix
420 */
421mat3.str = function (a) {
422    return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
423                    a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
424                    a[6] + ', ' + a[7] + ', ' + a[8] + ')';
425};
426
427if(typeof(exports) !== 'undefined') {
428    exports.mat3 = mat3;
429}
430