Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 "use strict";
8 const {Cu} = require("chrome");
10 let TiltUtils = require("devtools/tilt/tilt-utils");
12 /**
13 * Module containing high performance matrix and vector operations for WebGL.
14 * Inspired by glMatrix, version 0.9.6, (c) 2011 Brandon Jones.
15 */
17 let EPSILON = 0.01;
18 exports.EPSILON = EPSILON;
20 const PI_OVER_180 = Math.PI / 180;
21 const INV_PI_OVER_180 = 180 / Math.PI;
22 const FIFTEEN_OVER_225 = 15 / 225;
23 const ONE_OVER_255 = 1 / 255;
25 /**
26 * vec3 - 3 Dimensional Vector.
27 */
28 let vec3 = {
30 /**
31 * Creates a new instance of a vec3 using the Float32Array type.
32 * Any array containing at least 3 numeric elements can serve as a vec3.
33 *
34 * @param {Array} aVec
35 * optional, vec3 containing values to initialize with
36 *
37 * @return {Array} a new instance of a vec3
38 */
39 create: function V3_create(aVec)
40 {
41 let dest = new Float32Array(3);
43 if (aVec) {
44 vec3.set(aVec, dest);
45 } else {
46 vec3.zero(dest);
47 }
48 return dest;
49 },
51 /**
52 * Copies the values of one vec3 to another.
53 *
54 * @param {Array} aVec
55 * vec3 containing values to copy
56 * @param {Array} aDest
57 * vec3 receiving copied values
58 *
59 * @return {Array} the destination vec3 receiving copied values
60 */
61 set: function V3_set(aVec, aDest)
62 {
63 aDest[0] = aVec[0];
64 aDest[1] = aVec[1];
65 aDest[2] = aVec[2] || 0;
66 return aDest;
67 },
69 /**
70 * Sets a vec3 to an zero vector.
71 *
72 * @param {Array} aDest
73 * vec3 to set
74 *
75 * @return {Array} the same vector
76 */
77 zero: function V3_zero(aDest)
78 {
79 aDest[0] = 0;
80 aDest[1] = 0;
81 aDest[2] = 0;
82 return aDest;
83 },
85 /**
86 * Performs a vector addition.
87 *
88 * @param {Array} aVec
89 * vec3, first operand
90 * @param {Array} aVec2
91 * vec3, second operand
92 * @param {Array} aDest
93 * optional, vec3 receiving operation result
94 * if not specified result is written to the first operand
95 *
96 * @return {Array} the destination vec3 if specified, first operand otherwise
97 */
98 add: function V3_add(aVec, aVec2, aDest)
99 {
100 if (!aDest) {
101 aDest = aVec;
102 }
104 aDest[0] = aVec[0] + aVec2[0];
105 aDest[1] = aVec[1] + aVec2[1];
106 aDest[2] = aVec[2] + aVec2[2];
107 return aDest;
108 },
110 /**
111 * Performs a vector subtraction.
112 *
113 * @param {Array} aVec
114 * vec3, first operand
115 * @param {Array} aVec2
116 * vec3, second operand
117 * @param {Array} aDest
118 * optional, vec3 receiving operation result
119 * if not specified result is written to the first operand
120 *
121 * @return {Array} the destination vec3 if specified, first operand otherwise
122 */
123 subtract: function V3_subtract(aVec, aVec2, aDest)
124 {
125 if (!aDest) {
126 aDest = aVec;
127 }
129 aDest[0] = aVec[0] - aVec2[0];
130 aDest[1] = aVec[1] - aVec2[1];
131 aDest[2] = aVec[2] - aVec2[2];
132 return aDest;
133 },
135 /**
136 * Negates the components of a vec3.
137 *
138 * @param {Array} aVec
139 * vec3 to negate
140 * @param {Array} aDest
141 * optional, vec3 receiving operation result
142 * if not specified result is written to the first operand
143 *
144 * @return {Array} the destination vec3 if specified, first operand otherwise
145 */
146 negate: function V3_negate(aVec, aDest)
147 {
148 if (!aDest) {
149 aDest = aVec;
150 }
152 aDest[0] = -aVec[0];
153 aDest[1] = -aVec[1];
154 aDest[2] = -aVec[2];
155 return aDest;
156 },
158 /**
159 * Multiplies the components of a vec3 by a scalar value.
160 *
161 * @param {Array} aVec
162 * vec3 to scale
163 * @param {Number} aVal
164 * numeric value to scale by
165 * @param {Array} aDest
166 * optional, vec3 receiving operation result
167 * if not specified result is written to the first operand
168 *
169 * @return {Array} the destination vec3 if specified, first operand otherwise
170 */
171 scale: function V3_scale(aVec, aVal, aDest)
172 {
173 if (!aDest) {
174 aDest = aVec;
175 }
177 aDest[0] = aVec[0] * aVal;
178 aDest[1] = aVec[1] * aVal;
179 aDest[2] = aVec[2] * aVal;
180 return aDest;
181 },
183 /**
184 * Generates a unit vector of the same direction as the provided vec3.
185 * If vector length is 0, returns [0, 0, 0].
186 *
187 * @param {Array} aVec
188 * vec3 to normalize
189 * @param {Array} aDest
190 * optional, vec3 receiving operation result
191 * if not specified result is written to the first operand
192 *
193 * @return {Array} the destination vec3 if specified, first operand otherwise
194 */
195 normalize: function V3_normalize(aVec, aDest)
196 {
197 if (!aDest) {
198 aDest = aVec;
199 }
201 let x = aVec[0];
202 let y = aVec[1];
203 let z = aVec[2];
204 let len = Math.sqrt(x * x + y * y + z * z);
206 if (Math.abs(len) < EPSILON) {
207 aDest[0] = 0;
208 aDest[1] = 0;
209 aDest[2] = 0;
210 return aDest;
211 }
213 len = 1 / len;
214 aDest[0] = x * len;
215 aDest[1] = y * len;
216 aDest[2] = z * len;
217 return aDest;
218 },
220 /**
221 * Generates the cross product of two vectors.
222 *
223 * @param {Array} aVec
224 * vec3, first operand
225 * @param {Array} aVec2
226 * vec3, second operand
227 * @param {Array} aDest
228 * optional, vec3 receiving operation result
229 * if not specified result is written to the first operand
230 *
231 * @return {Array} the destination vec3 if specified, first operand otherwise
232 */
233 cross: function V3_cross(aVec, aVec2, aDest)
234 {
235 if (!aDest) {
236 aDest = aVec;
237 }
239 let x = aVec[0];
240 let y = aVec[1];
241 let z = aVec[2];
242 let x2 = aVec2[0];
243 let y2 = aVec2[1];
244 let z2 = aVec2[2];
246 aDest[0] = y * z2 - z * y2;
247 aDest[1] = z * x2 - x * z2;
248 aDest[2] = x * y2 - y * x2;
249 return aDest;
250 },
252 /**
253 * Caclulate the dot product of two vectors.
254 *
255 * @param {Array} aVec
256 * vec3, first operand
257 * @param {Array} aVec2
258 * vec3, second operand
259 *
260 * @return {Array} dot product of the first and second operand
261 */
262 dot: function V3_dot(aVec, aVec2)
263 {
264 return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2];
265 },
267 /**
268 * Caclulate the length of a vec3.
269 *
270 * @param {Array} aVec
271 * vec3 to calculate length of
272 *
273 * @return {Array} length of the vec3
274 */
275 length: function V3_length(aVec)
276 {
277 let x = aVec[0];
278 let y = aVec[1];
279 let z = aVec[2];
281 return Math.sqrt(x * x + y * y + z * z);
282 },
284 /**
285 * Generates a unit vector pointing from one vector to another.
286 *
287 * @param {Array} aVec
288 * origin vec3
289 * @param {Array} aVec2
290 * vec3 to point to
291 * @param {Array} aDest
292 * optional, vec3 receiving operation result
293 * if not specified result is written to the first operand
294 *
295 * @return {Array} the destination vec3 if specified, first operand otherwise
296 */
297 direction: function V3_direction(aVec, aVec2, aDest)
298 {
299 if (!aDest) {
300 aDest = aVec;
301 }
303 let x = aVec[0] - aVec2[0];
304 let y = aVec[1] - aVec2[1];
305 let z = aVec[2] - aVec2[2];
306 let len = Math.sqrt(x * x + y * y + z * z);
308 if (Math.abs(len) < EPSILON) {
309 aDest[0] = 0;
310 aDest[1] = 0;
311 aDest[2] = 0;
312 return aDest;
313 }
315 len = 1 / len;
316 aDest[0] = x * len;
317 aDest[1] = y * len;
318 aDest[2] = z * len;
319 return aDest;
320 },
322 /**
323 * Performs a linear interpolation between two vec3.
324 *
325 * @param {Array} aVec
326 * first vector
327 * @param {Array} aVec2
328 * second vector
329 * @param {Number} aLerp
330 * interpolation amount between the two inputs
331 * @param {Array} aDest
332 * optional, vec3 receiving operation result
333 * if not specified result is written to the first operand
334 *
335 * @return {Array} the destination vec3 if specified, first operand otherwise
336 */
337 lerp: function V3_lerp(aVec, aVec2, aLerp, aDest)
338 {
339 if (!aDest) {
340 aDest = aVec;
341 }
343 aDest[0] = aVec[0] + aLerp * (aVec2[0] - aVec[0]);
344 aDest[1] = aVec[1] + aLerp * (aVec2[1] - aVec[1]);
345 aDest[2] = aVec[2] + aLerp * (aVec2[2] - aVec[2]);
346 return aDest;
347 },
349 /**
350 * Projects a 3D point on a 2D screen plane.
351 *
352 * @param {Array} aP
353 * the [x, y, z] coordinates of the point to project
354 * @param {Array} aViewport
355 * the viewport [x, y, width, height] coordinates
356 * @param {Array} aMvMatrix
357 * the model view matrix
358 * @param {Array} aProjMatrix
359 * the projection matrix
360 * @param {Array} aDest
361 * optional parameter, the array to write the values to
362 *
363 * @return {Array} the projected coordinates
364 */
365 project: function V3_project(aP, aViewport, aMvMatrix, aProjMatrix, aDest)
366 {
367 /*jshint undef: false */
369 let mvpMatrix = new Float32Array(16);
370 let coordinates = new Float32Array(4);
372 // compute the perspective * model view matrix
373 mat4.multiply(aProjMatrix, aMvMatrix, mvpMatrix);
375 // now transform that vector into homogenous coordinates
376 coordinates[0] = aP[0];
377 coordinates[1] = aP[1];
378 coordinates[2] = aP[2];
379 coordinates[3] = 1;
380 mat4.multiplyVec4(mvpMatrix, coordinates);
382 // transform the homogenous coordinates into screen space
383 coordinates[0] /= coordinates[3];
384 coordinates[0] *= aViewport[2] * 0.5;
385 coordinates[0] += aViewport[2] * 0.5;
386 coordinates[1] /= coordinates[3];
387 coordinates[1] *= -aViewport[3] * 0.5;
388 coordinates[1] += aViewport[3] * 0.5;
389 coordinates[2] = 0;
391 if (!aDest) {
392 vec3.set(coordinates, aP);
393 } else {
394 vec3.set(coordinates, aDest);
395 }
396 return coordinates;
397 },
399 /**
400 * Unprojects a 2D point to 3D space.
401 *
402 * @param {Array} aP
403 * the [x, y, z] coordinates of the point to unproject;
404 * the z value should range between 0 and 1, as clipping plane
405 * @param {Array} aViewport
406 * the viewport [x, y, width, height] coordinates
407 * @param {Array} aMvMatrix
408 * the model view matrix
409 * @param {Array} aProjMatrix
410 * the projection matrix
411 * @param {Array} aDest
412 * optional parameter, the array to write the values to
413 *
414 * @return {Array} the unprojected coordinates
415 */
416 unproject: function V3_unproject(
417 aP, aViewport, aMvMatrix, aProjMatrix, aDest)
418 {
419 /*jshint undef: false */
421 let mvpMatrix = new Float32Array(16);
422 let coordinates = new Float32Array(4);
424 // compute the inverse of the perspective * model view matrix
425 mat4.multiply(aProjMatrix, aMvMatrix, mvpMatrix);
426 mat4.inverse(mvpMatrix);
428 // transformation of normalized coordinates (-1 to 1)
429 coordinates[0] = +((aP[0] - aViewport[0]) / aViewport[2] * 2 - 1);
430 coordinates[1] = -((aP[1] - aViewport[1]) / aViewport[3] * 2 - 1);
431 coordinates[2] = 2 * aP[2] - 1;
432 coordinates[3] = 1;
434 // now transform that vector into space coordinates
435 mat4.multiplyVec4(mvpMatrix, coordinates);
437 // invert to normalize x, y, and z values
438 coordinates[3] = 1 / coordinates[3];
439 coordinates[0] *= coordinates[3];
440 coordinates[1] *= coordinates[3];
441 coordinates[2] *= coordinates[3];
443 if (!aDest) {
444 vec3.set(coordinates, aP);
445 } else {
446 vec3.set(coordinates, aDest);
447 }
448 return coordinates;
449 },
451 /**
452 * Create a ray between two points using the current model view & projection
453 * matrices. This is useful when creating a ray destined for 3D picking.
454 *
455 * @param {Array} aP0
456 * the [x, y, z] coordinates of the first point
457 * @param {Array} aP1
458 * the [x, y, z] coordinates of the second point
459 * @param {Array} aViewport
460 * the viewport [x, y, width, height] coordinates
461 * @param {Array} aMvMatrix
462 * the model view matrix
463 * @param {Array} aProjMatrix
464 * the projection matrix
465 *
466 * @return {Object} a ray object containing the direction vector between
467 * the two unprojected points, the position and the lookAt
468 */
469 createRay: function V3_createRay(aP0, aP1, aViewport, aMvMatrix, aProjMatrix)
470 {
471 // unproject the two points
472 vec3.unproject(aP0, aViewport, aMvMatrix, aProjMatrix, aP0);
473 vec3.unproject(aP1, aViewport, aMvMatrix, aProjMatrix, aP1);
475 return {
476 origin: aP0,
477 direction: vec3.normalize(vec3.subtract(aP1, aP0))
478 };
479 },
481 /**
482 * Returns a string representation of a vector.
483 *
484 * @param {Array} aVec
485 * vec3 to represent as a string
486 *
487 * @return {String} representation of the vector
488 */
489 str: function V3_str(aVec)
490 {
491 return '[' + aVec[0] + ", " + aVec[1] + ", " + aVec[2] + ']';
492 }
493 };
495 exports.vec3 = vec3;
497 /**
498 * mat3 - 3x3 Matrix.
499 */
500 let mat3 = {
502 /**
503 * Creates a new instance of a mat3 using the Float32Array array type.
504 * Any array containing at least 9 numeric elements can serve as a mat3.
505 *
506 * @param {Array} aMat
507 * optional, mat3 containing values to initialize with
508 *
509 * @return {Array} a new instance of a mat3
510 */
511 create: function M3_create(aMat)
512 {
513 let dest = new Float32Array(9);
515 if (aMat) {
516 mat3.set(aMat, dest);
517 } else {
518 mat3.identity(dest);
519 }
520 return dest;
521 },
523 /**
524 * Copies the values of one mat3 to another.
525 *
526 * @param {Array} aMat
527 * mat3 containing values to copy
528 * @param {Array} aDest
529 * mat3 receiving copied values
530 *
531 * @return {Array} the destination mat3 receiving copied values
532 */
533 set: function M3_set(aMat, aDest)
534 {
535 aDest[0] = aMat[0];
536 aDest[1] = aMat[1];
537 aDest[2] = aMat[2];
538 aDest[3] = aMat[3];
539 aDest[4] = aMat[4];
540 aDest[5] = aMat[5];
541 aDest[6] = aMat[6];
542 aDest[7] = aMat[7];
543 aDest[8] = aMat[8];
544 return aDest;
545 },
547 /**
548 * Sets a mat3 to an identity matrix.
549 *
550 * @param {Array} aDest
551 * mat3 to set
552 *
553 * @return {Array} the same matrix
554 */
555 identity: function M3_identity(aDest)
556 {
557 aDest[0] = 1;
558 aDest[1] = 0;
559 aDest[2] = 0;
560 aDest[3] = 0;
561 aDest[4] = 1;
562 aDest[5] = 0;
563 aDest[6] = 0;
564 aDest[7] = 0;
565 aDest[8] = 1;
566 return aDest;
567 },
569 /**
570 * Transposes a mat3 (flips the values over the diagonal).
571 *
572 * @param {Array} aMat
573 * mat3 to transpose
574 * @param {Array} aDest
575 * optional, mat3 receiving operation result
576 * if not specified result is written to the first operand
577 *
578 * @return {Array} the destination mat3 if specified, first operand otherwise
579 */
580 transpose: function M3_transpose(aMat, aDest)
581 {
582 if (!aDest || aMat === aDest) {
583 let a01 = aMat[1];
584 let a02 = aMat[2];
585 let a12 = aMat[5];
587 aMat[1] = aMat[3];
588 aMat[2] = aMat[6];
589 aMat[3] = a01;
590 aMat[5] = aMat[7];
591 aMat[6] = a02;
592 aMat[7] = a12;
593 return aMat;
594 }
596 aDest[0] = aMat[0];
597 aDest[1] = aMat[3];
598 aDest[2] = aMat[6];
599 aDest[3] = aMat[1];
600 aDest[4] = aMat[4];
601 aDest[5] = aMat[7];
602 aDest[6] = aMat[2];
603 aDest[7] = aMat[5];
604 aDest[8] = aMat[8];
605 return aDest;
606 },
608 /**
609 * Copies the elements of a mat3 into the upper 3x3 elements of a mat4.
610 *
611 * @param {Array} aMat
612 * mat3 containing values to copy
613 * @param {Array} aDest
614 * optional, mat4 receiving operation result
615 * if not specified result is written to the first operand
616 *
617 * @return {Array} the destination mat3 if specified, first operand otherwise
618 */
619 toMat4: function M3_toMat4(aMat, aDest)
620 {
621 if (!aDest) {
622 aDest = new Float32Array(16);
623 }
625 aDest[0] = aMat[0];
626 aDest[1] = aMat[1];
627 aDest[2] = aMat[2];
628 aDest[3] = 0;
629 aDest[4] = aMat[3];
630 aDest[5] = aMat[4];
631 aDest[6] = aMat[5];
632 aDest[7] = 0;
633 aDest[8] = aMat[6];
634 aDest[9] = aMat[7];
635 aDest[10] = aMat[8];
636 aDest[11] = 0;
637 aDest[12] = 0;
638 aDest[13] = 0;
639 aDest[14] = 0;
640 aDest[15] = 1;
641 return aDest;
642 },
644 /**
645 * Returns a string representation of a 3x3 matrix.
646 *
647 * @param {Array} aMat
648 * mat3 to represent as a string
649 *
650 * @return {String} representation of the matrix
651 */
652 str: function M3_str(aMat)
653 {
654 return "[" + aMat[0] + ", " + aMat[1] + ", " + aMat[2] +
655 ", " + aMat[3] + ", " + aMat[4] + ", " + aMat[5] +
656 ", " + aMat[6] + ", " + aMat[7] + ", " + aMat[8] + "]";
657 }
658 };
660 exports.mat3 = mat3;
662 /**
663 * mat4 - 4x4 Matrix.
664 */
665 let mat4 = {
667 /**
668 * Creates a new instance of a mat4 using the default Float32Array type.
669 * Any array containing at least 16 numeric elements can serve as a mat4.
670 *
671 * @param {Array} aMat
672 * optional, mat4 containing values to initialize with
673 *
674 * @return {Array} a new instance of a mat4
675 */
676 create: function M4_create(aMat)
677 {
678 let dest = new Float32Array(16);
680 if (aMat) {
681 mat4.set(aMat, dest);
682 } else {
683 mat4.identity(dest);
684 }
685 return dest;
686 },
688 /**
689 * Copies the values of one mat4 to another
690 *
691 * @param {Array} aMat
692 * mat4 containing values to copy
693 * @param {Array} aDest
694 * mat4 receiving copied values
695 *
696 * @return {Array} the destination mat4 receiving copied values
697 */
698 set: function M4_set(aMat, aDest)
699 {
700 aDest[0] = aMat[0];
701 aDest[1] = aMat[1];
702 aDest[2] = aMat[2];
703 aDest[3] = aMat[3];
704 aDest[4] = aMat[4];
705 aDest[5] = aMat[5];
706 aDest[6] = aMat[6];
707 aDest[7] = aMat[7];
708 aDest[8] = aMat[8];
709 aDest[9] = aMat[9];
710 aDest[10] = aMat[10];
711 aDest[11] = aMat[11];
712 aDest[12] = aMat[12];
713 aDest[13] = aMat[13];
714 aDest[14] = aMat[14];
715 aDest[15] = aMat[15];
716 return aDest;
717 },
719 /**
720 * Sets a mat4 to an identity matrix.
721 *
722 * @param {Array} aDest
723 * mat4 to set
724 *
725 * @return {Array} the same matrix
726 */
727 identity: function M4_identity(aDest)
728 {
729 aDest[0] = 1;
730 aDest[1] = 0;
731 aDest[2] = 0;
732 aDest[3] = 0;
733 aDest[4] = 0;
734 aDest[5] = 1;
735 aDest[6] = 0;
736 aDest[7] = 0;
737 aDest[8] = 0;
738 aDest[9] = 0;
739 aDest[10] = 1;
740 aDest[11] = 0;
741 aDest[12] = 0;
742 aDest[13] = 0;
743 aDest[14] = 0;
744 aDest[15] = 1;
745 return aDest;
746 },
748 /**
749 * Transposes a mat4 (flips the values over the diagonal).
750 *
751 * @param {Array} aMat
752 * mat4 to transpose
753 * @param {Array} aDest
754 * optional, mat4 receiving operation result
755 * if not specified result is written to the first operand
756 *
757 * @return {Array} the destination mat4 if specified, first operand otherwise
758 */
759 transpose: function M4_transpose(aMat, aDest)
760 {
761 if (!aDest || aMat === aDest) {
762 let a01 = aMat[1];
763 let a02 = aMat[2];
764 let a03 = aMat[3];
765 let a12 = aMat[6];
766 let a13 = aMat[7];
767 let a23 = aMat[11];
769 aMat[1] = aMat[4];
770 aMat[2] = aMat[8];
771 aMat[3] = aMat[12];
772 aMat[4] = a01;
773 aMat[6] = aMat[9];
774 aMat[7] = aMat[13];
775 aMat[8] = a02;
776 aMat[9] = a12;
777 aMat[11] = aMat[14];
778 aMat[12] = a03;
779 aMat[13] = a13;
780 aMat[14] = a23;
781 return aMat;
782 }
784 aDest[0] = aMat[0];
785 aDest[1] = aMat[4];
786 aDest[2] = aMat[8];
787 aDest[3] = aMat[12];
788 aDest[4] = aMat[1];
789 aDest[5] = aMat[5];
790 aDest[6] = aMat[9];
791 aDest[7] = aMat[13];
792 aDest[8] = aMat[2];
793 aDest[9] = aMat[6];
794 aDest[10] = aMat[10];
795 aDest[11] = aMat[14];
796 aDest[12] = aMat[3];
797 aDest[13] = aMat[7];
798 aDest[14] = aMat[11];
799 aDest[15] = aMat[15];
800 return aDest;
801 },
803 /**
804 * Calculate the determinant of a mat4.
805 *
806 * @param {Array} aMat
807 * mat4 to calculate determinant of
808 *
809 * @return {Number} determinant of the matrix
810 */
811 determinant: function M4_determinant(mat)
812 {
813 let a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
814 let a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
815 let a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
816 let a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
818 return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 -
819 a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 +
820 a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 -
821 a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 +
822 a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 -
823 a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 +
824 a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 -
825 a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 +
826 a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 -
827 a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 +
828 a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 -
829 a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33;
830 },
832 /**
833 * Calculate the inverse of a mat4.
834 *
835 * @param {Array} aMat
836 * mat4 to calculate inverse of
837 * @param {Array} aDest
838 * optional, mat4 receiving operation result
839 * if not specified result is written to the first operand
840 *
841 * @return {Array} the destination mat4 if specified, first operand otherwise
842 */
843 inverse: function M4_inverse(aMat, aDest)
844 {
845 if (!aDest) {
846 aDest = aMat;
847 }
849 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
850 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
851 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
852 let a30 = aMat[12], a31 = aMat[13], a32 = aMat[14], a33 = aMat[15];
854 let b00 = a00 * a11 - a01 * a10;
855 let b01 = a00 * a12 - a02 * a10;
856 let b02 = a00 * a13 - a03 * a10;
857 let b03 = a01 * a12 - a02 * a11;
858 let b04 = a01 * a13 - a03 * a11;
859 let b05 = a02 * a13 - a03 * a12;
860 let b06 = a20 * a31 - a21 * a30;
861 let b07 = a20 * a32 - a22 * a30;
862 let b08 = a20 * a33 - a23 * a30;
863 let b09 = a21 * a32 - a22 * a31;
864 let b10 = a21 * a33 - a23 * a31;
865 let b11 = a22 * a33 - a23 * a32;
866 let id = 1 / ((b00 * b11 - b01 * b10 + b02 * b09 +
867 b03 * b08 - b04 * b07 + b05 * b06) || EPSILON);
869 aDest[0] = ( a11 * b11 - a12 * b10 + a13 * b09) * id;
870 aDest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * id;
871 aDest[2] = ( a31 * b05 - a32 * b04 + a33 * b03) * id;
872 aDest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * id;
873 aDest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * id;
874 aDest[5] = ( a00 * b11 - a02 * b08 + a03 * b07) * id;
875 aDest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * id;
876 aDest[7] = ( a20 * b05 - a22 * b02 + a23 * b01) * id;
877 aDest[8] = ( a10 * b10 - a11 * b08 + a13 * b06) * id;
878 aDest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * id;
879 aDest[10] = ( a30 * b04 - a31 * b02 + a33 * b00) * id;
880 aDest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * id;
881 aDest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * id;
882 aDest[13] = ( a00 * b09 - a01 * b07 + a02 * b06) * id;
883 aDest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * id;
884 aDest[15] = ( a20 * b03 - a21 * b01 + a22 * b00) * id;
885 return aDest;
886 },
888 /**
889 * Copies the upper 3x3 elements of a mat4 into another mat4.
890 *
891 * @param {Array} aMat
892 * mat4 containing values to copy
893 * @param {Array} aDest
894 * optional, mat4 receiving operation result
895 * if not specified result is written to the first operand
896 *
897 * @return {Array} the destination mat4 if specified, first operand otherwise
898 */
899 toRotationMat: function M4_toRotationMat(aMat, aDest)
900 {
901 if (!aDest) {
902 aDest = new Float32Array(16);
903 }
905 aDest[0] = aMat[0];
906 aDest[1] = aMat[1];
907 aDest[2] = aMat[2];
908 aDest[3] = aMat[3];
909 aDest[4] = aMat[4];
910 aDest[5] = aMat[5];
911 aDest[6] = aMat[6];
912 aDest[7] = aMat[7];
913 aDest[8] = aMat[8];
914 aDest[9] = aMat[9];
915 aDest[10] = aMat[10];
916 aDest[11] = aMat[11];
917 aDest[12] = 0;
918 aDest[13] = 0;
919 aDest[14] = 0;
920 aDest[15] = 1;
921 return aDest;
922 },
924 /**
925 * Copies the upper 3x3 elements of a mat4 into a mat3.
926 *
927 * @param {Array} aMat
928 * mat4 containing values to copy
929 * @param {Array} aDest
930 * optional, mat3 receiving operation result
931 * if not specified result is written to the first operand
932 *
933 * @return {Array} the destination mat3 if specified, first operand otherwise
934 */
935 toMat3: function M4_toMat3(aMat, aDest)
936 {
937 if (!aDest) {
938 aDest = new Float32Array(9);
939 }
941 aDest[0] = aMat[0];
942 aDest[1] = aMat[1];
943 aDest[2] = aMat[2];
944 aDest[3] = aMat[4];
945 aDest[4] = aMat[5];
946 aDest[5] = aMat[6];
947 aDest[6] = aMat[8];
948 aDest[7] = aMat[9];
949 aDest[8] = aMat[10];
950 return aDest;
951 },
953 /**
954 * Calculate the inverse of the upper 3x3 elements of a mat4 and copies
955 * the result into a mat3. The resulting matrix is useful for calculating
956 * transformed normals.
957 *
958 * @param {Array} aMat
959 * mat4 containing values to invert and copy
960 * @param {Array} aDest
961 * optional, mat3 receiving operation result
962 * if not specified result is written to the first operand
963 *
964 * @return {Array} the destination mat3 if specified, first operand otherwise
965 */
966 toInverseMat3: function M4_toInverseMat3(aMat, aDest)
967 {
968 if (!aDest) {
969 aDest = new Float32Array(9);
970 }
972 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2];
973 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6];
974 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10];
976 let b01 = a22 * a11 - a12 * a21;
977 let b11 = -a22 * a10 + a12 * a20;
978 let b21 = a21 * a10 - a11 * a20;
979 let id = 1 / ((a00 * b01 + a01 * b11 + a02 * b21) || EPSILON);
981 aDest[0] = b01 * id;
982 aDest[1] = (-a22 * a01 + a02 * a21) * id;
983 aDest[2] = ( a12 * a01 - a02 * a11) * id;
984 aDest[3] = b11 * id;
985 aDest[4] = ( a22 * a00 - a02 * a20) * id;
986 aDest[5] = (-a12 * a00 + a02 * a10) * id;
987 aDest[6] = b21 * id;
988 aDest[7] = (-a21 * a00 + a01 * a20) * id;
989 aDest[8] = ( a11 * a00 - a01 * a10) * id;
990 return aDest;
991 },
993 /**
994 * Performs a matrix multiplication.
995 *
996 * @param {Array} aMat
997 * first operand
998 * @param {Array} aMat2
999 * second operand
1000 * @param {Array} aDest
1001 * optional, mat4 receiving operation result
1002 * if not specified result is written to the first operand
1003 *
1004 * @return {Array} the destination mat4 if specified, first operand otherwise
1005 */
1006 multiply: function M4_multiply(aMat, aMat2, aDest)
1007 {
1008 if (!aDest) {
1009 aDest = aMat;
1010 }
1012 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
1013 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
1014 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
1015 let a30 = aMat[12], a31 = aMat[13], a32 = aMat[14], a33 = aMat[15];
1017 let b00 = aMat2[0], b01 = aMat2[1], b02 = aMat2[2], b03 = aMat2[3];
1018 let b10 = aMat2[4], b11 = aMat2[5], b12 = aMat2[6], b13 = aMat2[7];
1019 let b20 = aMat2[8], b21 = aMat2[9], b22 = aMat2[10], b23 = aMat2[11];
1020 let b30 = aMat2[12], b31 = aMat2[13], b32 = aMat2[14], b33 = aMat2[15];
1022 aDest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
1023 aDest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
1024 aDest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
1025 aDest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
1026 aDest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
1027 aDest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
1028 aDest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
1029 aDest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
1030 aDest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
1031 aDest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
1032 aDest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
1033 aDest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
1034 aDest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
1035 aDest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
1036 aDest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
1037 aDest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
1038 return aDest;
1039 },
1041 /**
1042 * Transforms a vec3 with the given matrix.
1043 * 4th vector component is implicitly 1.
1044 *
1045 * @param {Array} aMat
1046 * mat4 to transform the vector with
1047 * @param {Array} aVec
1048 * vec3 to transform
1049 * @param {Array} aDest
1050 * optional, vec3 receiving operation result
1051 * if not specified result is written to the first operand
1052 *
1053 * @return {Array} the destination vec3 if specified, aVec operand otherwise
1054 */
1055 multiplyVec3: function M4_multiplyVec3(aMat, aVec, aDest)
1056 {
1057 if (!aDest) {
1058 aDest = aVec;
1059 }
1061 let x = aVec[0];
1062 let y = aVec[1];
1063 let z = aVec[2];
1065 aDest[0] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12];
1066 aDest[1] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13];
1067 aDest[2] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14];
1068 return aDest;
1069 },
1071 /**
1072 * Transforms a vec4 with the given matrix.
1073 *
1074 * @param {Array} aMat
1075 * mat4 to transform the vector with
1076 * @param {Array} aVec
1077 * vec4 to transform
1078 * @param {Array} aDest
1079 * optional, vec4 receiving operation result
1080 * if not specified result is written to the first operand
1081 *
1082 * @return {Array} the destination vec4 if specified, vec4 operand otherwise
1083 */
1084 multiplyVec4: function M4_multiplyVec4(aMat, aVec, aDest)
1085 {
1086 if (!aDest) {
1087 aDest = aVec;
1088 }
1090 let x = aVec[0];
1091 let y = aVec[1];
1092 let z = aVec[2];
1093 let w = aVec[3];
1095 aDest[0] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12] * w;
1096 aDest[1] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13] * w;
1097 aDest[2] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14] * w;
1098 aDest[3] = aMat[3] * x + aMat[7] * y + aMat[11] * z + aMat[15] * w;
1099 return aDest;
1100 },
1102 /**
1103 * Translates a matrix by the given vector.
1104 *
1105 * @param {Array} aMat
1106 * mat4 to translate
1107 * @param {Array} aVec
1108 * vec3 specifying the translation
1109 * @param {Array} aDest
1110 * optional, mat4 receiving operation result
1111 * if not specified result is written to the first operand
1112 *
1113 * @return {Array} the destination mat4 if specified, first operand otherwise
1114 */
1115 translate: function M4_translate(aMat, aVec, aDest)
1116 {
1117 let x = aVec[0];
1118 let y = aVec[1];
1119 let z = aVec[2];
1121 if (!aDest || aMat === aDest) {
1122 aMat[12] = aMat[0] * x + aMat[4] * y + aMat[8] * z + aMat[12];
1123 aMat[13] = aMat[1] * x + aMat[5] * y + aMat[9] * z + aMat[13];
1124 aMat[14] = aMat[2] * x + aMat[6] * y + aMat[10] * z + aMat[14];
1125 aMat[15] = aMat[3] * x + aMat[7] * y + aMat[11] * z + aMat[15];
1126 return aMat;
1127 }
1129 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
1130 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
1131 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
1133 aDest[0] = a00;
1134 aDest[1] = a01;
1135 aDest[2] = a02;
1136 aDest[3] = a03;
1137 aDest[4] = a10;
1138 aDest[5] = a11;
1139 aDest[6] = a12;
1140 aDest[7] = a13;
1141 aDest[8] = a20;
1142 aDest[9] = a21;
1143 aDest[10] = a22;
1144 aDest[11] = a23;
1145 aDest[12] = a00 * x + a10 * y + a20 * z + aMat[12];
1146 aDest[13] = a01 * x + a11 * y + a21 * z + aMat[13];
1147 aDest[14] = a02 * x + a12 * y + a22 * z + aMat[14];
1148 aDest[15] = a03 * x + a13 * y + a23 * z + aMat[15];
1149 return aDest;
1150 },
1152 /**
1153 * Scales a matrix by the given vector.
1154 *
1155 * @param {Array} aMat
1156 * mat4 to translate
1157 * @param {Array} aVec
1158 * vec3 specifying the scale on each axis
1159 * @param {Array} aDest
1160 * optional, mat4 receiving operation result
1161 * if not specified result is written to the first operand
1162 *
1163 * @return {Array} the destination mat4 if specified, first operand otherwise
1164 */
1165 scale: function M4_scale(aMat, aVec, aDest)
1166 {
1167 let x = aVec[0];
1168 let y = aVec[1];
1169 let z = aVec[2];
1171 if (!aDest || aMat === aDest) {
1172 aMat[0] *= x;
1173 aMat[1] *= x;
1174 aMat[2] *= x;
1175 aMat[3] *= x;
1176 aMat[4] *= y;
1177 aMat[5] *= y;
1178 aMat[6] *= y;
1179 aMat[7] *= y;
1180 aMat[8] *= z;
1181 aMat[9] *= z;
1182 aMat[10] *= z;
1183 aMat[11] *= z;
1184 return aMat;
1185 }
1187 aDest[0] = aMat[0] * x;
1188 aDest[1] = aMat[1] * x;
1189 aDest[2] = aMat[2] * x;
1190 aDest[3] = aMat[3] * x;
1191 aDest[4] = aMat[4] * y;
1192 aDest[5] = aMat[5] * y;
1193 aDest[6] = aMat[6] * y;
1194 aDest[7] = aMat[7] * y;
1195 aDest[8] = aMat[8] * z;
1196 aDest[9] = aMat[9] * z;
1197 aDest[10] = aMat[10] * z;
1198 aDest[11] = aMat[11] * z;
1199 aDest[12] = aMat[12];
1200 aDest[13] = aMat[13];
1201 aDest[14] = aMat[14];
1202 aDest[15] = aMat[15];
1203 return aDest;
1204 },
1206 /**
1207 * Rotates a matrix by the given angle around the specified axis.
1208 * If rotating around a primary axis (x, y, z) one of the specialized
1209 * rotation functions should be used instead for performance,
1210 *
1211 * @param {Array} aMat
1212 * mat4 to rotate
1213 * @param {Number} aAngle
1214 * the angle (in radians) to rotate
1215 * @param {Array} aAxis
1216 * vec3 representing the axis to rotate around
1217 * @param {Array} aDest
1218 * optional, mat4 receiving operation result
1219 * if not specified result is written to the first operand
1220 *
1221 * @return {Array} the destination mat4 if specified, first operand otherwise
1222 */
1223 rotate: function M4_rotate(aMat, aAngle, aAxis, aDest)
1224 {
1225 let x = aAxis[0];
1226 let y = aAxis[1];
1227 let z = aAxis[2];
1228 let len = 1 / (Math.sqrt(x * x + y * y + z * z) || EPSILON);
1230 x *= len;
1231 y *= len;
1232 z *= len;
1234 let s = Math.sin(aAngle);
1235 let c = Math.cos(aAngle);
1236 let t = 1 - c;
1238 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
1239 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
1240 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
1242 let b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s;
1243 let b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s;
1244 let b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c;
1246 if (!aDest) {
1247 aDest = aMat;
1248 } else if (aMat !== aDest) {
1249 aDest[12] = aMat[12];
1250 aDest[13] = aMat[13];
1251 aDest[14] = aMat[14];
1252 aDest[15] = aMat[15];
1253 }
1255 aDest[0] = a00 * b00 + a10 * b01 + a20 * b02;
1256 aDest[1] = a01 * b00 + a11 * b01 + a21 * b02;
1257 aDest[2] = a02 * b00 + a12 * b01 + a22 * b02;
1258 aDest[3] = a03 * b00 + a13 * b01 + a23 * b02;
1259 aDest[4] = a00 * b10 + a10 * b11 + a20 * b12;
1260 aDest[5] = a01 * b10 + a11 * b11 + a21 * b12;
1261 aDest[6] = a02 * b10 + a12 * b11 + a22 * b12;
1262 aDest[7] = a03 * b10 + a13 * b11 + a23 * b12;
1263 aDest[8] = a00 * b20 + a10 * b21 + a20 * b22;
1264 aDest[9] = a01 * b20 + a11 * b21 + a21 * b22;
1265 aDest[10] = a02 * b20 + a12 * b21 + a22 * b22;
1266 aDest[11] = a03 * b20 + a13 * b21 + a23 * b22;
1267 return aDest;
1268 },
1270 /**
1271 * Rotates a matrix by the given angle around the X axis.
1272 *
1273 * @param {Array} aMat
1274 * mat4 to rotate
1275 * @param {Number} aAngle
1276 * the angle (in radians) to rotate
1277 * @param {Array} aDest
1278 * optional, mat4 receiving operation result
1279 * if not specified result is written to the first operand
1280 *
1281 * @return {Array} the destination mat4 if specified, first operand otherwise
1282 */
1283 rotateX: function M4_rotateX(aMat, aAngle, aDest)
1284 {
1285 let s = Math.sin(aAngle);
1286 let c = Math.cos(aAngle);
1288 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
1289 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
1291 if (!aDest) {
1292 aDest = aMat;
1293 } else if (aMat !== aDest) {
1294 aDest[0] = aMat[0];
1295 aDest[1] = aMat[1];
1296 aDest[2] = aMat[2];
1297 aDest[3] = aMat[3];
1298 aDest[12] = aMat[12];
1299 aDest[13] = aMat[13];
1300 aDest[14] = aMat[14];
1301 aDest[15] = aMat[15];
1302 }
1304 aDest[4] = a10 * c + a20 * s;
1305 aDest[5] = a11 * c + a21 * s;
1306 aDest[6] = a12 * c + a22 * s;
1307 aDest[7] = a13 * c + a23 * s;
1308 aDest[8] = a10 * -s + a20 * c;
1309 aDest[9] = a11 * -s + a21 * c;
1310 aDest[10] = a12 * -s + a22 * c;
1311 aDest[11] = a13 * -s + a23 * c;
1312 return aDest;
1313 },
1315 /**
1316 * Rotates a matrix by the given angle around the Y axix.
1317 *
1318 * @param {Array} aMat
1319 * mat4 to rotate
1320 * @param {Number} aAngle
1321 * the angle (in radians) to rotate
1322 * @param {Array} aDest
1323 * optional, mat4 receiving operation result
1324 * if not specified result is written to the first operand
1325 *
1326 * @return {Array} the destination mat4 if specified, first operand otherwise
1327 */
1328 rotateY: function M4_rotateY(aMat, aAngle, aDest)
1329 {
1330 let s = Math.sin(aAngle);
1331 let c = Math.cos(aAngle);
1333 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
1334 let a20 = aMat[8], a21 = aMat[9], a22 = aMat[10], a23 = aMat[11];
1336 if (!aDest) {
1337 aDest = aMat;
1338 } else if (aMat !== aDest) {
1339 aDest[4] = aMat[4];
1340 aDest[5] = aMat[5];
1341 aDest[6] = aMat[6];
1342 aDest[7] = aMat[7];
1343 aDest[12] = aMat[12];
1344 aDest[13] = aMat[13];
1345 aDest[14] = aMat[14];
1346 aDest[15] = aMat[15];
1347 }
1349 aDest[0] = a00 * c + a20 * -s;
1350 aDest[1] = a01 * c + a21 * -s;
1351 aDest[2] = a02 * c + a22 * -s;
1352 aDest[3] = a03 * c + a23 * -s;
1353 aDest[8] = a00 * s + a20 * c;
1354 aDest[9] = a01 * s + a21 * c;
1355 aDest[10] = a02 * s + a22 * c;
1356 aDest[11] = a03 * s + a23 * c;
1357 return aDest;
1358 },
1360 /**
1361 * Rotates a matrix by the given angle around the Z axix.
1362 *
1363 * @param {Array} aMat
1364 * mat4 to rotate
1365 * @param {Number} aAngle
1366 * the angle (in radians) to rotate
1367 * @param {Array} aDest
1368 * optional, mat4 receiving operation result
1369 * if not specified result is written to the first operand
1370 *
1371 * @return {Array} the destination mat4 if specified, first operand otherwise
1372 */
1373 rotateZ: function M4_rotateZ(aMat, aAngle, aDest)
1374 {
1375 let s = Math.sin(aAngle);
1376 let c = Math.cos(aAngle);
1378 let a00 = aMat[0], a01 = aMat[1], a02 = aMat[2], a03 = aMat[3];
1379 let a10 = aMat[4], a11 = aMat[5], a12 = aMat[6], a13 = aMat[7];
1381 if (!aDest) {
1382 aDest = aMat;
1383 } else if (aMat !== aDest) {
1384 aDest[8] = aMat[8];
1385 aDest[9] = aMat[9];
1386 aDest[10] = aMat[10];
1387 aDest[11] = aMat[11];
1388 aDest[12] = aMat[12];
1389 aDest[13] = aMat[13];
1390 aDest[14] = aMat[14];
1391 aDest[15] = aMat[15];
1392 }
1394 aDest[0] = a00 * c + a10 * s;
1395 aDest[1] = a01 * c + a11 * s;
1396 aDest[2] = a02 * c + a12 * s;
1397 aDest[3] = a03 * c + a13 * s;
1398 aDest[4] = a00 * -s + a10 * c;
1399 aDest[5] = a01 * -s + a11 * c;
1400 aDest[6] = a02 * -s + a12 * c;
1401 aDest[7] = a03 * -s + a13 * c;
1402 return aDest;
1403 },
1405 /**
1406 * Generates a frustum matrix with the given bounds.
1407 *
1408 * @param {Number} aLeft
1409 * scalar, left bound of the frustum
1410 * @param {Number} aRight
1411 * scalar, right bound of the frustum
1412 * @param {Number} aBottom
1413 * scalar, bottom bound of the frustum
1414 * @param {Number} aTop
1415 * scalar, top bound of the frustum
1416 * @param {Number} aNear
1417 * scalar, near bound of the frustum
1418 * @param {Number} aFar
1419 * scalar, far bound of the frustum
1420 * @param {Array} aDest
1421 * optional, mat4 frustum matrix will be written into
1422 * if not specified result is written to a new mat4
1423 *
1424 * @return {Array} the destination mat4 if specified, a new mat4 otherwise
1425 */
1426 frustum: function M4_frustum(
1427 aLeft, aRight, aBottom, aTop, aNear, aFar, aDest)
1428 {
1429 if (!aDest) {
1430 aDest = new Float32Array(16);
1431 }
1433 let rl = (aRight - aLeft);
1434 let tb = (aTop - aBottom);
1435 let fn = (aFar - aNear);
1437 aDest[0] = (aNear * 2) / rl;
1438 aDest[1] = 0;
1439 aDest[2] = 0;
1440 aDest[3] = 0;
1441 aDest[4] = 0;
1442 aDest[5] = (aNear * 2) / tb;
1443 aDest[6] = 0;
1444 aDest[7] = 0;
1445 aDest[8] = (aRight + aLeft) / rl;
1446 aDest[9] = (aTop + aBottom) / tb;
1447 aDest[10] = -(aFar + aNear) / fn;
1448 aDest[11] = -1;
1449 aDest[12] = 0;
1450 aDest[13] = 0;
1451 aDest[14] = -(aFar * aNear * 2) / fn;
1452 aDest[15] = 0;
1453 return aDest;
1454 },
1456 /**
1457 * Generates a perspective projection matrix with the given bounds.
1458 *
1459 * @param {Number} aFovy
1460 * scalar, vertical field of view (degrees)
1461 * @param {Number} aAspect
1462 * scalar, aspect ratio (typically viewport width/height)
1463 * @param {Number} aNear
1464 * scalar, near bound of the frustum
1465 * @param {Number} aFar
1466 * scalar, far bound of the frustum
1467 * @param {Array} aDest
1468 * optional, mat4 frustum matrix will be written into
1469 * if not specified result is written to a new mat4
1470 *
1471 * @return {Array} the destination mat4 if specified, a new mat4 otherwise
1472 */
1473 perspective: function M4_perspective(
1474 aFovy, aAspect, aNear, aFar, aDest, aFlip)
1475 {
1476 let upper = aNear * Math.tan(aFovy * 0.00872664626); // PI * 180 / 2
1477 let right = upper * aAspect;
1478 let top = upper * (aFlip || 1);
1480 return mat4.frustum(-right, right, -top, top, aNear, aFar, aDest);
1481 },
1483 /**
1484 * Generates a orthogonal projection matrix with the given bounds.
1485 *
1486 * @param {Number} aLeft
1487 * scalar, left bound of the frustum
1488 * @param {Number} aRight
1489 * scalar, right bound of the frustum
1490 * @param {Number} aBottom
1491 * scalar, bottom bound of the frustum
1492 * @param {Number} aTop
1493 * scalar, top bound of the frustum
1494 * @param {Number} aNear
1495 * scalar, near bound of the frustum
1496 * @param {Number} aFar
1497 * scalar, far bound of the frustum
1498 * @param {Array} aDest
1499 * optional, mat4 frustum matrix will be written into
1500 * if not specified result is written to a new mat4
1501 *
1502 * @return {Array} the destination mat4 if specified, a new mat4 otherwise
1503 */
1504 ortho: function M4_ortho(aLeft, aRight, aBottom, aTop, aNear, aFar, aDest)
1505 {
1506 if (!aDest) {
1507 aDest = new Float32Array(16);
1508 }
1510 let rl = (aRight - aLeft);
1511 let tb = (aTop - aBottom);
1512 let fn = (aFar - aNear);
1514 aDest[0] = 2 / rl;
1515 aDest[1] = 0;
1516 aDest[2] = 0;
1517 aDest[3] = 0;
1518 aDest[4] = 0;
1519 aDest[5] = 2 / tb;
1520 aDest[6] = 0;
1521 aDest[7] = 0;
1522 aDest[8] = 0;
1523 aDest[9] = 0;
1524 aDest[10] = -2 / fn;
1525 aDest[11] = 0;
1526 aDest[12] = -(aLeft + aRight) / rl;
1527 aDest[13] = -(aTop + aBottom) / tb;
1528 aDest[14] = -(aFar + aNear) / fn;
1529 aDest[15] = 1;
1530 return aDest;
1531 },
1533 /**
1534 * Generates a look-at matrix with the given eye position, focal point, and
1535 * up axis.
1536 *
1537 * @param {Array} aEye
1538 * vec3, position of the viewer
1539 * @param {Array} aCenter
1540 * vec3, point the viewer is looking at
1541 * @param {Array} aUp
1542 * vec3 pointing up
1543 * @param {Array} aDest
1544 * optional, mat4 frustum matrix will be written into
1545 * if not specified result is written to a new mat4
1546 *
1547 * @return {Array} the destination mat4 if specified, a new mat4 otherwise
1548 */
1549 lookAt: function M4_lookAt(aEye, aCenter, aUp, aDest)
1550 {
1551 if (!aDest) {
1552 aDest = new Float32Array(16);
1553 }
1555 let eyex = aEye[0];
1556 let eyey = aEye[1];
1557 let eyez = aEye[2];
1558 let upx = aUp[0];
1559 let upy = aUp[1];
1560 let upz = aUp[2];
1561 let centerx = aCenter[0];
1562 let centery = aCenter[1];
1563 let centerz = aCenter[2];
1565 let z0 = eyex - aCenter[0];
1566 let z1 = eyey - aCenter[1];
1567 let z2 = eyez - aCenter[2];
1568 let len = 1 / (Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2) || EPSILON);
1570 z0 *= len;
1571 z1 *= len;
1572 z2 *= len;
1574 let x0 = upy * z2 - upz * z1;
1575 let x1 = upz * z0 - upx * z2;
1576 let x2 = upx * z1 - upy * z0;
1577 len = 1 / (Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2) || EPSILON);
1579 x0 *= len;
1580 x1 *= len;
1581 x2 *= len;
1583 let y0 = z1 * x2 - z2 * x1;
1584 let y1 = z2 * x0 - z0 * x2;
1585 let y2 = z0 * x1 - z1 * x0;
1586 len = 1 / (Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2) || EPSILON);
1588 y0 *= len;
1589 y1 *= len;
1590 y2 *= len;
1592 aDest[0] = x0;
1593 aDest[1] = y0;
1594 aDest[2] = z0;
1595 aDest[3] = 0;
1596 aDest[4] = x1;
1597 aDest[5] = y1;
1598 aDest[6] = z1;
1599 aDest[7] = 0;
1600 aDest[8] = x2;
1601 aDest[9] = y2;
1602 aDest[10] = z2;
1603 aDest[11] = 0;
1604 aDest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
1605 aDest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
1606 aDest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
1607 aDest[15] = 1;
1609 return aDest;
1610 },
1612 /**
1613 * Returns a string representation of a 4x4 matrix.
1614 *
1615 * @param {Array} aMat
1616 * mat4 to represent as a string
1617 *
1618 * @return {String} representation of the matrix
1619 */
1620 str: function M4_str(mat)
1621 {
1622 return "[" + mat[0] + ", " + mat[1] + ", " + mat[2] + ", " + mat[3] +
1623 ", "+ mat[4] + ", " + mat[5] + ", " + mat[6] + ", " + mat[7] +
1624 ", "+ mat[8] + ", " + mat[9] + ", " + mat[10] + ", " + mat[11] +
1625 ", "+ mat[12] + ", " + mat[13] + ", " + mat[14] + ", " + mat[15] +
1626 "]";
1627 }
1628 };
1630 exports.mat4 = mat4;
1632 /**
1633 * quat4 - Quaternion.
1634 */
1635 let quat4 = {
1637 /**
1638 * Creates a new instance of a quat4 using the default Float32Array type.
1639 * Any array containing at least 4 numeric elements can serve as a quat4.
1640 *
1641 * @param {Array} aQuat
1642 * optional, quat4 containing values to initialize with
1643 *
1644 * @return {Array} a new instance of a quat4
1645 */
1646 create: function Q4_create(aQuat)
1647 {
1648 let dest = new Float32Array(4);
1650 if (aQuat) {
1651 quat4.set(aQuat, dest);
1652 } else {
1653 quat4.identity(dest);
1654 }
1655 return dest;
1656 },
1658 /**
1659 * Copies the values of one quat4 to another.
1660 *
1661 * @param {Array} aQuat
1662 * quat4 containing values to copy
1663 * @param {Array} aDest
1664 * quat4 receiving copied values
1665 *
1666 * @return {Array} the destination quat4 receiving copied values
1667 */
1668 set: function Q4_set(aQuat, aDest)
1669 {
1670 aDest[0] = aQuat[0];
1671 aDest[1] = aQuat[1];
1672 aDest[2] = aQuat[2];
1673 aDest[3] = aQuat[3];
1674 return aDest;
1675 },
1677 /**
1678 * Sets a quat4 to an identity quaternion.
1679 *
1680 * @param {Array} aDest
1681 * quat4 to set
1682 *
1683 * @return {Array} the same quaternion
1684 */
1685 identity: function Q4_identity(aDest)
1686 {
1687 aDest[0] = 0;
1688 aDest[1] = 0;
1689 aDest[2] = 0;
1690 aDest[3] = 1;
1691 return aDest;
1692 },
1694 /**
1695 * Calculate the W component of a quat4 from the X, Y, and Z components.
1696 * Assumes that quaternion is 1 unit in length.
1697 * Any existing W component will be ignored.
1698 *
1699 * @param {Array} aQuat
1700 * quat4 to calculate W component of
1701 * @param {Array} aDest
1702 * optional, quat4 receiving calculated values
1703 * if not specified result is written to the first operand
1704 *
1705 * @return {Array} the destination quat if specified, first operand otherwise
1706 */
1707 calculateW: function Q4_calculateW(aQuat, aDest)
1708 {
1709 if (!aDest) {
1710 aDest = aQuat;
1711 }
1713 let x = aQuat[0];
1714 let y = aQuat[1];
1715 let z = aQuat[2];
1717 aDest[0] = x;
1718 aDest[1] = y;
1719 aDest[2] = z;
1720 aDest[3] = -Math.sqrt(Math.abs(1 - x * x - y * y - z * z));
1721 return aDest;
1722 },
1724 /**
1725 * Calculate the inverse of a quat4.
1726 *
1727 * @param {Array} aQuat
1728 * quat4 to calculate the inverse of
1729 * @param {Array} aDest
1730 * optional, quat4 receiving the inverse values
1731 * if not specified result is written to the first operand
1732 *
1733 * @return {Array} the destination quat if specified, first operand otherwise
1734 */
1735 inverse: function Q4_inverse(aQuat, aDest)
1736 {
1737 if (!aDest) {
1738 aDest = aQuat;
1739 }
1741 aQuat[0] = -aQuat[0];
1742 aQuat[1] = -aQuat[1];
1743 aQuat[2] = -aQuat[2];
1744 return aQuat;
1745 },
1747 /**
1748 * Generates a unit quaternion of the same direction as the provided quat4.
1749 * If quaternion length is 0, returns [0, 0, 0, 0].
1750 *
1751 * @param {Array} aQuat
1752 * quat4 to normalize
1753 * @param {Array} aDest
1754 * optional, quat4 receiving the operation result
1755 * if not specified result is written to the first operand
1756 *
1757 * @return {Array} the destination quat if specified, first operand otherwise
1758 */
1759 normalize: function Q4_normalize(aQuat, aDest)
1760 {
1761 if (!aDest) {
1762 aDest = aQuat;
1763 }
1765 let x = aQuat[0];
1766 let y = aQuat[1];
1767 let z = aQuat[2];
1768 let w = aQuat[3];
1769 let len = Math.sqrt(x * x + y * y + z * z + w * w);
1771 if (Math.abs(len) < EPSILON) {
1772 aDest[0] = 0;
1773 aDest[1] = 0;
1774 aDest[2] = 0;
1775 aDest[3] = 0;
1776 return aDest;
1777 }
1779 len = 1 / len;
1780 aDest[0] = x * len;
1781 aDest[1] = y * len;
1782 aDest[2] = z * len;
1783 aDest[3] = w * len;
1784 return aDest;
1785 },
1787 /**
1788 * Calculate the length of a quat4.
1789 *
1790 * @param {Array} aQuat
1791 * quat4 to calculate the length of
1792 *
1793 * @return {Number} length of the quaternion
1794 */
1795 length: function Q4_length(aQuat)
1796 {
1797 let x = aQuat[0];
1798 let y = aQuat[1];
1799 let z = aQuat[2];
1800 let w = aQuat[3];
1802 return Math.sqrt(x * x + y * y + z * z + w * w);
1803 },
1805 /**
1806 * Performs a quaternion multiplication.
1807 *
1808 * @param {Array} aQuat
1809 * first operand
1810 * @param {Array} aQuat2
1811 * second operand
1812 * @param {Array} aDest
1813 * optional, quat4 receiving the operation result
1814 * if not specified result is written to the first operand
1815 *
1816 * @return {Array} the destination quat if specified, first operand otherwise
1817 */
1818 multiply: function Q4_multiply(aQuat, aQuat2, aDest)
1819 {
1820 if (!aDest) {
1821 aDest = aQuat;
1822 }
1824 let qax = aQuat[0];
1825 let qay = aQuat[1];
1826 let qaz = aQuat[2];
1827 let qaw = aQuat[3];
1828 let qbx = aQuat2[0];
1829 let qby = aQuat2[1];
1830 let qbz = aQuat2[2];
1831 let qbw = aQuat2[3];
1833 aDest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
1834 aDest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
1835 aDest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
1836 aDest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
1837 return aDest;
1838 },
1840 /**
1841 * Transforms a vec3 with the given quaternion.
1842 *
1843 * @param {Array} aQuat
1844 * quat4 to transform the vector with
1845 * @param {Array} aVec
1846 * vec3 to transform
1847 * @param {Array} aDest
1848 * optional, vec3 receiving the operation result
1849 * if not specified result is written to the first operand
1850 *
1851 * @return {Array} the destination vec3 if specified, aVec operand otherwise
1852 */
1853 multiplyVec3: function Q4_multiplyVec3(aQuat, aVec, aDest)
1854 {
1855 if (!aDest) {
1856 aDest = aVec;
1857 }
1859 let x = aVec[0];
1860 let y = aVec[1];
1861 let z = aVec[2];
1863 let qx = aQuat[0];
1864 let qy = aQuat[1];
1865 let qz = aQuat[2];
1866 let qw = aQuat[3];
1868 let ix = qw * x + qy * z - qz * y;
1869 let iy = qw * y + qz * x - qx * z;
1870 let iz = qw * z + qx * y - qy * x;
1871 let iw = -qx * x - qy * y - qz * z;
1873 aDest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
1874 aDest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
1875 aDest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
1876 return aDest;
1877 },
1879 /**
1880 * Performs a spherical linear interpolation between two quat4.
1881 *
1882 * @param {Array} aQuat
1883 * first quaternion
1884 * @param {Array} aQuat2
1885 * second quaternion
1886 * @param {Number} aSlerp
1887 * interpolation amount between the two inputs
1888 * @param {Array} aDest
1889 * optional, quat4 receiving the operation result
1890 * if not specified result is written to the first operand
1891 *
1892 * @return {Array} the destination quat if specified, first operand otherwise
1893 */
1894 slerp: function Q4_slerp(aQuat, aQuat2, aSlerp, aDest)
1895 {
1896 if (!aDest) {
1897 aDest = aQuat;
1898 }
1900 let cosHalfTheta = aQuat[0] * aQuat2[0] +
1901 aQuat[1] * aQuat2[1] +
1902 aQuat[2] * aQuat2[2] +
1903 aQuat[3] * aQuat2[3];
1905 if (Math.abs(cosHalfTheta) >= 1) {
1906 aDest[0] = aQuat[0];
1907 aDest[1] = aQuat[1];
1908 aDest[2] = aQuat[2];
1909 aDest[3] = aQuat[3];
1910 return aDest;
1911 }
1913 let halfTheta = Math.acos(cosHalfTheta);
1914 let sinHalfTheta = Math.sqrt(1 - cosHalfTheta * cosHalfTheta);
1916 if (Math.abs(sinHalfTheta) < EPSILON) {
1917 aDest[0] = (aQuat[0] * 0.5 + aQuat2[0] * 0.5);
1918 aDest[1] = (aQuat[1] * 0.5 + aQuat2[1] * 0.5);
1919 aDest[2] = (aQuat[2] * 0.5 + aQuat2[2] * 0.5);
1920 aDest[3] = (aQuat[3] * 0.5 + aQuat2[3] * 0.5);
1921 return aDest;
1922 }
1924 let ratioA = Math.sin((1 - aSlerp) * halfTheta) / sinHalfTheta;
1925 let ratioB = Math.sin(aSlerp * halfTheta) / sinHalfTheta;
1927 aDest[0] = (aQuat[0] * ratioA + aQuat2[0] * ratioB);
1928 aDest[1] = (aQuat[1] * ratioA + aQuat2[1] * ratioB);
1929 aDest[2] = (aQuat[2] * ratioA + aQuat2[2] * ratioB);
1930 aDest[3] = (aQuat[3] * ratioA + aQuat2[3] * ratioB);
1931 return aDest;
1932 },
1934 /**
1935 * Calculates a 3x3 matrix from the given quat4.
1936 *
1937 * @param {Array} aQuat
1938 * quat4 to create matrix from
1939 * @param {Array} aDest
1940 * optional, mat3 receiving the initialization result
1941 * if not specified, a new matrix is created
1942 *
1943 * @return {Array} the destination mat3 if specified, first operand otherwise
1944 */
1945 toMat3: function Q4_toMat3(aQuat, aDest)
1946 {
1947 if (!aDest) {
1948 aDest = new Float32Array(9);
1949 }
1951 let x = aQuat[0];
1952 let y = aQuat[1];
1953 let z = aQuat[2];
1954 let w = aQuat[3];
1956 let x2 = x + x;
1957 let y2 = y + y;
1958 let z2 = z + z;
1959 let xx = x * x2;
1960 let xy = x * y2;
1961 let xz = x * z2;
1962 let yy = y * y2;
1963 let yz = y * z2;
1964 let zz = z * z2;
1965 let wx = w * x2;
1966 let wy = w * y2;
1967 let wz = w * z2;
1969 aDest[0] = 1 - (yy + zz);
1970 aDest[1] = xy - wz;
1971 aDest[2] = xz + wy;
1972 aDest[3] = xy + wz;
1973 aDest[4] = 1 - (xx + zz);
1974 aDest[5] = yz - wx;
1975 aDest[6] = xz - wy;
1976 aDest[7] = yz + wx;
1977 aDest[8] = 1 - (xx + yy);
1978 return aDest;
1979 },
1981 /**
1982 * Calculates a 4x4 matrix from the given quat4.
1983 *
1984 * @param {Array} aQuat
1985 * quat4 to create matrix from
1986 * @param {Array} aDest
1987 * optional, mat4 receiving the initialization result
1988 * if not specified, a new matrix is created
1989 *
1990 * @return {Array} the destination mat4 if specified, first operand otherwise
1991 */
1992 toMat4: function Q4_toMat4(aQuat, aDest)
1993 {
1994 if (!aDest) {
1995 aDest = new Float32Array(16);
1996 }
1998 let x = aQuat[0];
1999 let y = aQuat[1];
2000 let z = aQuat[2];
2001 let w = aQuat[3];
2003 let x2 = x + x;
2004 let y2 = y + y;
2005 let z2 = z + z;
2006 let xx = x * x2;
2007 let xy = x * y2;
2008 let xz = x * z2;
2009 let yy = y * y2;
2010 let yz = y * z2;
2011 let zz = z * z2;
2012 let wx = w * x2;
2013 let wy = w * y2;
2014 let wz = w * z2;
2016 aDest[0] = 1 - (yy + zz);
2017 aDest[1] = xy - wz;
2018 aDest[2] = xz + wy;
2019 aDest[3] = 0;
2020 aDest[4] = xy + wz;
2021 aDest[5] = 1 - (xx + zz);
2022 aDest[6] = yz - wx;
2023 aDest[7] = 0;
2024 aDest[8] = xz - wy;
2025 aDest[9] = yz + wx;
2026 aDest[10] = 1 - (xx + yy);
2027 aDest[11] = 0;
2028 aDest[12] = 0;
2029 aDest[13] = 0;
2030 aDest[14] = 0;
2031 aDest[15] = 1;
2032 return aDest;
2033 },
2035 /**
2036 * Creates a rotation quaternion from axis-angle.
2037 * This function expects that the axis is a normalized vector.
2038 *
2039 * @param {Array} aAxis
2040 * an array of elements representing the [x, y, z] axis
2041 * @param {Number} aAngle
2042 * the angle of rotation
2043 * @param {Array} aDest
2044 * optional, quat4 receiving the initialization result
2045 * if not specified, a new quaternion is created
2046 *
2047 * @return {Array} the quaternion as [x, y, z, w]
2048 */
2049 fromAxis: function Q4_fromAxis(aAxis, aAngle, aDest)
2050 {
2051 if (!aDest) {
2052 aDest = new Float32Array(4);
2053 }
2055 let ang = aAngle * 0.5;
2056 let sin = Math.sin(ang);
2057 let cos = Math.cos(ang);
2059 aDest[0] = aAxis[0] * sin;
2060 aDest[1] = aAxis[1] * sin;
2061 aDest[2] = aAxis[2] * sin;
2062 aDest[3] = cos;
2063 return aDest;
2064 },
2066 /**
2067 * Creates a rotation quaternion from Euler angles.
2068 *
2069 * @param {Number} aYaw
2070 * the yaw angle of rotation
2071 * @param {Number} aPitch
2072 * the pitch angle of rotation
2073 * @param {Number} aRoll
2074 * the roll angle of rotation
2075 * @param {Array} aDest
2076 * optional, quat4 receiving the initialization result
2077 * if not specified, a new quaternion is created
2078 *
2079 * @return {Array} the quaternion as [x, y, z, w]
2080 */
2081 fromEuler: function Q4_fromEuler(aYaw, aPitch, aRoll, aDest)
2082 {
2083 if (!aDest) {
2084 aDest = new Float32Array(4);
2085 }
2087 let x = aPitch * 0.5;
2088 let y = aYaw * 0.5;
2089 let z = aRoll * 0.5;
2091 let sinr = Math.sin(x);
2092 let sinp = Math.sin(y);
2093 let siny = Math.sin(z);
2094 let cosr = Math.cos(x);
2095 let cosp = Math.cos(y);
2096 let cosy = Math.cos(z);
2098 aDest[0] = sinr * cosp * cosy - cosr * sinp * siny;
2099 aDest[1] = cosr * sinp * cosy + sinr * cosp * siny;
2100 aDest[2] = cosr * cosp * siny - sinr * sinp * cosy;
2101 aDest[3] = cosr * cosp * cosy + sinr * sinp * siny;
2102 return aDest;
2103 },
2105 /**
2106 * Returns a string representation of a quaternion.
2107 *
2108 * @param {Array} aQuat
2109 * quat4 to represent as a string
2110 *
2111 * @return {String} representation of the quaternion
2112 */
2113 str: function Q4_str(aQuat) {
2114 return "[" + aQuat[0] + ", " +
2115 aQuat[1] + ", " +
2116 aQuat[2] + ", " +
2117 aQuat[3] + "]";
2118 }
2119 };
2121 exports.quat4 = quat4;
2123 /**
2124 * Various algebraic math functions required by the engine.
2125 */
2126 let TiltMath = {
2128 /**
2129 * Helper function, converts degrees to radians.
2130 *
2131 * @param {Number} aDegrees
2132 * the degrees to be converted to radians
2133 *
2134 * @return {Number} the degrees converted to radians
2135 */
2136 radians: function TM_radians(aDegrees)
2137 {
2138 return aDegrees * PI_OVER_180;
2139 },
2141 /**
2142 * Helper function, converts radians to degrees.
2143 *
2144 * @param {Number} aRadians
2145 * the radians to be converted to degrees
2146 *
2147 * @return {Number} the radians converted to degrees
2148 */
2149 degrees: function TM_degrees(aRadians)
2150 {
2151 return aRadians * INV_PI_OVER_180;
2152 },
2154 /**
2155 * Re-maps a number from one range to another.
2156 *
2157 * @param {Number} aValue
2158 * the number to map
2159 * @param {Number} aLow1
2160 * the normal lower bound of the number
2161 * @param {Number} aHigh1
2162 * the normal upper bound of the number
2163 * @param {Number} aLow2
2164 * the new lower bound of the number
2165 * @param {Number} aHigh2
2166 * the new upper bound of the number
2167 *
2168 * @return {Number} the remapped number
2169 */
2170 map: function TM_map(aValue, aLow1, aHigh1, aLow2, aHigh2)
2171 {
2172 return aLow2 + (aHigh2 - aLow2) * ((aValue - aLow1) / (aHigh1 - aLow1));
2173 },
2175 /**
2176 * Returns if number is power of two.
2177 *
2178 * @param {Number} aNumber
2179 * the number to be verified
2180 *
2181 * @return {Boolean} true if x is power of two
2182 */
2183 isPowerOfTwo: function TM_isPowerOfTwo(aNumber)
2184 {
2185 return !(aNumber & (aNumber - 1));
2186 },
2188 /**
2189 * Returns the next closest power of two greater than a number.
2190 *
2191 * @param {Number} aNumber
2192 * the number to be converted
2193 *
2194 * @return {Number} the next closest power of two for x
2195 */
2196 nextPowerOfTwo: function TM_nextPowerOfTwo(aNumber)
2197 {
2198 --aNumber;
2200 for (let i = 1; i < 32; i <<= 1) {
2201 aNumber = aNumber | aNumber >> i;
2202 }
2203 return aNumber + 1;
2204 },
2206 /**
2207 * A convenient way of limiting values to a set boundary.
2208 *
2209 * @param {Number} aValue
2210 * the number to be limited
2211 * @param {Number} aMin
2212 * the minimum allowed value for the number
2213 * @param {Number} aMax
2214 * the maximum allowed value for the number
2215 */
2216 clamp: function TM_clamp(aValue, aMin, aMax)
2217 {
2218 return Math.max(aMin, Math.min(aMax, aValue));
2219 },
2221 /**
2222 * Convenient way to clamp a value to 0..1
2223 *
2224 * @param {Number} aValue
2225 * the number to be limited
2226 */
2227 saturate: function TM_saturate(aValue)
2228 {
2229 return Math.max(0, Math.min(1, aValue));
2230 },
2232 /**
2233 * Converts a hex color to rgba.
2234 * If the passed param is invalid, it will be converted to [0, 0, 0, 1];
2235 *
2236 * @param {String} aColor
2237 * color expressed in hex, or using rgb() or rgba()
2238 *
2239 * @return {Array} with 4 color 0..1 components: [red, green, blue, alpha]
2240 */
2241 hex2rgba: (function()
2242 {
2243 let cache = {};
2245 return function TM_hex2rgba(aColor) {
2246 let hex = aColor.charAt(0) === "#" ? aColor.substring(1) : aColor;
2248 // check the cache to see if this color wasn't converted already
2249 if (cache[hex] !== undefined) {
2250 return cache[hex];
2251 }
2253 // e.g. "f00"
2254 if (hex.length === 3) {
2255 let r = parseInt(hex.substring(0, 1), 16) * FIFTEEN_OVER_225;
2256 let g = parseInt(hex.substring(1, 2), 16) * FIFTEEN_OVER_225;
2257 let b = parseInt(hex.substring(2, 3), 16) * FIFTEEN_OVER_225;
2259 return (cache[hex] = [r, g, b, 1]);
2260 }
2261 // e.g. "f008"
2262 if (hex.length === 4) {
2263 let r = parseInt(hex.substring(0, 1), 16) * FIFTEEN_OVER_225;
2264 let g = parseInt(hex.substring(1, 2), 16) * FIFTEEN_OVER_225;
2265 let b = parseInt(hex.substring(2, 3), 16) * FIFTEEN_OVER_225;
2266 let a = parseInt(hex.substring(3, 4), 16) * FIFTEEN_OVER_225;
2268 return (cache[hex] = [r, g, b, a]);
2269 }
2270 // e.g. "ff0000"
2271 if (hex.length === 6) {
2272 let r = parseInt(hex.substring(0, 2), 16) * ONE_OVER_255;
2273 let g = parseInt(hex.substring(2, 4), 16) * ONE_OVER_255;
2274 let b = parseInt(hex.substring(4, 6), 16) * ONE_OVER_255;
2275 let a = 1;
2277 return (cache[hex] = [r, g, b, a]);
2278 }
2279 // e.g "ff0000aa"
2280 if (hex.length === 8) {
2281 let r = parseInt(hex.substring(0, 2), 16) * ONE_OVER_255;
2282 let g = parseInt(hex.substring(2, 4), 16) * ONE_OVER_255;
2283 let b = parseInt(hex.substring(4, 6), 16) * ONE_OVER_255;
2284 let a = parseInt(hex.substring(6, 8), 16) * ONE_OVER_255;
2286 return (cache[hex] = [r, g, b, a]);
2287 }
2288 // e.g. "rgba(255, 0, 0, 0.5)"
2289 if (hex.match("^rgba")) {
2290 let rgba = hex.substring(5, hex.length - 1).split(",");
2291 rgba[0] *= ONE_OVER_255;
2292 rgba[1] *= ONE_OVER_255;
2293 rgba[2] *= ONE_OVER_255;
2294 // in CSS, the alpha component of rgba() is already in the range 0..1
2296 return (cache[hex] = rgba);
2297 }
2298 // e.g. "rgb(255, 0, 0)"
2299 if (hex.match("^rgb")) {
2300 let rgba = hex.substring(4, hex.length - 1).split(",");
2301 rgba[0] *= ONE_OVER_255;
2302 rgba[1] *= ONE_OVER_255;
2303 rgba[2] *= ONE_OVER_255;
2304 rgba[3] = 1;
2306 return (cache[hex] = rgba);
2307 }
2309 // your argument is invalid
2310 return (cache[hex] = [0, 0, 0, 1]);
2311 };
2312 }())
2313 };
2315 exports.TiltMath = TiltMath;
2317 // bind the owner object to the necessary functions
2318 TiltUtils.bindObjectFunc(vec3);
2319 TiltUtils.bindObjectFunc(mat3);
2320 TiltUtils.bindObjectFunc(mat4);
2321 TiltUtils.bindObjectFunc(quat4);
2322 TiltUtils.bindObjectFunc(TiltMath);