browser/devtools/tilt/tilt-math.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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
  1004    * @return {Array} the destination mat4 if specified, first operand otherwise
  1005    */
  1006   multiply: function M4_multiply(aMat, aMat2, aDest)
  1008     if (!aDest) {
  1009       aDest = aMat;
  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.
  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
  1053    * @return {Array} the destination vec3 if specified, aVec operand otherwise
  1054    */
  1055   multiplyVec3: function M4_multiplyVec3(aMat, aVec, aDest)
  1057     if (!aDest) {
  1058       aDest = aVec;
  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.
  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
  1082    * @return {Array} the destination vec4 if specified, vec4 operand otherwise
  1083    */
  1084   multiplyVec4: function M4_multiplyVec4(aMat, aVec, aDest)
  1086     if (!aDest) {
  1087       aDest = aVec;
  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.
  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
  1113    * @return {Array} the destination mat4 if specified, first operand otherwise
  1114    */
  1115   translate: function M4_translate(aMat, aVec, aDest)
  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;
  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.
  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
  1163    * @return {Array} the destination mat4 if specified, first operand otherwise
  1164    */
  1165   scale: function M4_scale(aMat, aVec, aDest)
  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;
  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,
  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
  1221    * @return {Array} the destination mat4 if specified, first operand otherwise
  1222    */
  1223   rotate: function M4_rotate(aMat, aAngle, aAxis, aDest)
  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];
  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.
  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
  1281    * @return {Array} the destination mat4 if specified, first operand otherwise
  1282    */
  1283   rotateX: function M4_rotateX(aMat, aAngle, aDest)
  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];
  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.
  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
  1326    * @return {Array} the destination mat4 if specified, first operand otherwise
  1327    */
  1328   rotateY: function M4_rotateY(aMat, aAngle, aDest)
  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];
  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.
  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
  1371    * @return {Array} the destination mat4 if specified, first operand otherwise
  1372    */
  1373   rotateZ: function M4_rotateZ(aMat, aAngle, aDest)
  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];
  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.
  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
  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)
  1429     if (!aDest) {
  1430       aDest = new Float32Array(16);
  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.
  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
  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)
  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.
  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
  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)
  1506     if (!aDest) {
  1507       aDest = new Float32Array(16);
  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.
  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
  1547    * @return {Array} the destination mat4 if specified, a new mat4 otherwise
  1548    */
  1549   lookAt: function M4_lookAt(aEye, aCenter, aUp, aDest)
  1551     if (!aDest) {
  1552       aDest = new Float32Array(16);
  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.
  1615    * @param {Array} aMat
  1616    *                mat4 to represent as a string
  1618    * @return {String} representation of the matrix
  1619    */
  1620   str: function M4_str(mat)
  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            "]";
  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.
  1641    * @param {Array} aQuat
  1642    *                optional, quat4 containing values to initialize with
  1644    * @return {Array} a new instance of a quat4
  1645    */
  1646   create: function Q4_create(aQuat)
  1648     let dest = new Float32Array(4);
  1650     if (aQuat) {
  1651       quat4.set(aQuat, dest);
  1652     } else {
  1653       quat4.identity(dest);
  1655     return dest;
  1656   },
  1658   /**
  1659    * Copies the values of one quat4 to another.
  1661    * @param {Array} aQuat
  1662    *                quat4 containing values to copy
  1663    * @param {Array} aDest
  1664    *                quat4 receiving copied values
  1666    * @return {Array} the destination quat4 receiving copied values
  1667    */
  1668   set: function Q4_set(aQuat, aDest)
  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.
  1680    * @param {Array} aDest
  1681    *                quat4 to set
  1683    * @return {Array} the same quaternion
  1684    */
  1685   identity: function Q4_identity(aDest)
  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.
  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
  1705    * @return {Array} the destination quat if specified, first operand otherwise
  1706    */
  1707   calculateW: function Q4_calculateW(aQuat, aDest)
  1709     if (!aDest) {
  1710       aDest = aQuat;
  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.
  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
  1733    * @return {Array} the destination quat if specified, first operand otherwise
  1734    */
  1735   inverse: function Q4_inverse(aQuat, aDest)
  1737     if (!aDest) {
  1738       aDest = aQuat;
  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].
  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
  1757    * @return {Array} the destination quat if specified, first operand otherwise
  1758    */
  1759   normalize: function Q4_normalize(aQuat, aDest)
  1761     if (!aDest) {
  1762       aDest = aQuat;
  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;
  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.
  1790    * @param {Array} aQuat
  1791    *                quat4 to calculate the length of
  1793    * @return {Number} length of the quaternion
  1794    */
  1795   length: function Q4_length(aQuat)
  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.
  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
  1816    * @return {Array} the destination quat if specified, first operand otherwise
  1817    */
  1818   multiply: function Q4_multiply(aQuat, aQuat2, aDest)
  1820     if (!aDest) {
  1821       aDest = aQuat;
  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.
  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
  1851    * @return {Array} the destination vec3 if specified, aVec operand otherwise
  1852    */
  1853   multiplyVec3: function Q4_multiplyVec3(aQuat, aVec, aDest)
  1855     if (!aDest) {
  1856       aDest = aVec;
  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.
  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
  1892    * @return {Array} the destination quat if specified, first operand otherwise
  1893    */
  1894   slerp: function Q4_slerp(aQuat, aQuat2, aSlerp, aDest)
  1896     if (!aDest) {
  1897       aDest = aQuat;
  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;
  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;
  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.
  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
  1943    * @return {Array} the destination mat3 if specified, first operand otherwise
  1944    */
  1945   toMat3: function Q4_toMat3(aQuat, aDest)
  1947     if (!aDest) {
  1948       aDest = new Float32Array(9);
  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.
  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
  1990    * @return {Array} the destination mat4 if specified, first operand otherwise
  1991    */
  1992   toMat4: function Q4_toMat4(aQuat, aDest)
  1994     if (!aDest) {
  1995       aDest = new Float32Array(16);
  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.
  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
  2047    * @return {Array} the quaternion as [x, y, z, w]
  2048    */
  2049   fromAxis: function Q4_fromAxis(aAxis, aAngle, aDest)
  2051     if (!aDest) {
  2052       aDest = new Float32Array(4);
  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.
  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
  2079    * @return {Array} the quaternion as [x, y, z, w]
  2080    */
  2081   fromEuler: function Q4_fromEuler(aYaw, aPitch, aRoll, aDest)
  2083     if (!aDest) {
  2084       aDest = new Float32Array(4);
  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.
  2108    * @param {Array} aQuat
  2109    *                quat4 to represent as a string
  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] + "]";
  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.
  2131    * @param {Number} aDegrees
  2132    *                 the degrees to be converted to radians
  2134    * @return {Number} the degrees converted to radians
  2135    */
  2136   radians: function TM_radians(aDegrees)
  2138     return aDegrees * PI_OVER_180;
  2139   },
  2141   /**
  2142    * Helper function, converts radians to degrees.
  2144    * @param {Number} aRadians
  2145    *                 the radians to be converted to degrees
  2147    * @return {Number} the radians converted to degrees
  2148    */
  2149   degrees: function TM_degrees(aRadians)
  2151     return aRadians * INV_PI_OVER_180;
  2152   },
  2154   /**
  2155    * Re-maps a number from one range to another.
  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
  2168    * @return {Number} the remapped number
  2169    */
  2170   map: function TM_map(aValue, aLow1, aHigh1, aLow2, aHigh2)
  2172     return aLow2 + (aHigh2 - aLow2) * ((aValue - aLow1) / (aHigh1 - aLow1));
  2173   },
  2175   /**
  2176    * Returns if number is power of two.
  2178    * @param {Number} aNumber
  2179    *                 the number to be verified
  2181    * @return {Boolean} true if x is power of two
  2182    */
  2183   isPowerOfTwo: function TM_isPowerOfTwo(aNumber)
  2185     return !(aNumber & (aNumber - 1));
  2186   },
  2188   /**
  2189    * Returns the next closest power of two greater than a number.
  2191    * @param {Number} aNumber
  2192    *                 the number to be converted
  2194    * @return {Number} the next closest power of two for x
  2195    */
  2196   nextPowerOfTwo: function TM_nextPowerOfTwo(aNumber)
  2198     --aNumber;
  2200     for (let i = 1; i < 32; i <<= 1) {
  2201       aNumber = aNumber | aNumber >> i;
  2203     return aNumber + 1;
  2204   },
  2206   /**
  2207    * A convenient way of limiting values to a set boundary.
  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)
  2218     return Math.max(aMin, Math.min(aMax, aValue));
  2219   },
  2221   /**
  2222    * Convenient way to clamp a value to 0..1
  2224    * @param {Number} aValue
  2225    *                 the number to be limited
  2226    */
  2227   saturate: function TM_saturate(aValue)
  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];
  2236    * @param {String} aColor
  2237    *                 color expressed in hex, or using rgb() or rgba()
  2239    * @return {Array} with 4 color 0..1 components: [red, green, blue, alpha]
  2240    */
  2241   hex2rgba: (function()
  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];
  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]);
  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]);
  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]);
  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]);
  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);
  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);
  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);

mercurial