scripts/CanvasMatrix.js
author Eugen Sawin <sawine@me73.com>
Wed, 27 Apr 2011 14:41:04 +0200
changeset 31 744b427d1379
parent 1 92e65293655d
permissions -rwxr-xr-x
Switched to per-fragment lighting.
     1 /*
     2     CanvasMatrix4 class
     3     
     4     This class implements a 4x4 matrix. It has functions which
     5     duplicate the functionality of the OpenGL matrix stack and
     6     glut functions.
     7     
     8     IDL:
     9     
    10     [
    11         Constructor(in CanvasMatrix4 matrix),           // copy passed matrix into new CanvasMatrix4
    12         Constructor(in sequence<float> array)           // create new CanvasMatrix4 with 16 floats (row major)
    13         Constructor()                                   // create new CanvasMatrix4 with identity matrix
    14     ]
    15     interface CanvasMatrix4 {
    16         attribute float m11;
    17         attribute float m12;
    18         attribute float m13;
    19         attribute float m14;
    20         attribute float m21;
    21         attribute float m22;
    22         attribute float m23;
    23         attribute float m24;
    24         attribute float m31;
    25         attribute float m32;
    26         attribute float m33;
    27         attribute float m34;
    28         attribute float m41;
    29         attribute float m42;
    30         attribute float m43;
    31         attribute float m44;
    32 
    33         void load(in CanvasMatrix4 matrix);                 // copy the values from the passed matrix
    34         void load(in sequence<float> array);                // copy 16 floats into the matrix
    35         sequence<float> getAsArray();                       // return the matrix as an array of 16 floats
    36         WebGLFloatArray getAsCanvasFloatArray();           // return the matrix as a WebGLFloatArray with 16 values
    37         void makeIdentity();                                // replace the matrix with identity
    38         void transpose();                                   // replace the matrix with its transpose
    39         void invert();                                      // replace the matrix with its inverse
    40         
    41         void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right
    42         void scale(in float x, in float y, in float z);     // multiply the matrix by passed scale values on the right
    43         void rotate(in float angle,                         // multiply the matrix by passed rotation values on the right
    44                     in float x, in float y, in float z);    // (angle is in degrees)
    45         void multRight(in CanvasMatrix matrix);             // multiply the matrix by the passed matrix on the right
    46         void multLeft(in CanvasMatrix matrix);              // multiply the matrix by the passed matrix on the left
    47         void ortho(in float left, in float right,           // multiply the matrix by the passed ortho values on the right
    48                    in float bottom, in float top, 
    49                    in float near, in float far);
    50         void frustum(in float left, in float right,         // multiply the matrix by the passed frustum values on the right
    51                      in float bottom, in float top, 
    52                      in float near, in float far);
    53         void perspective(in float fovy, in float aspect,    // multiply the matrix by the passed perspective values on the right
    54                          in float zNear, in float zFar);
    55         void lookat(in float eyex, in float eyey, in float eyez,    // multiply the matrix by the passed lookat 
    56                     in float ctrx, in float ctry, in float ctrz,    // values on the right
    57                     in float upx, in float upy, in float upz);
    58     }
    59 */
    60 
    61 CanvasMatrix4 = function(m)
    62 {
    63     if (typeof m == 'object') {
    64         if ("length" in m && m.length >= 16) {
    65             this.load(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]);
    66             return;
    67         }
    68         else if (m instanceof CanvasMatrix4) {
    69             this.load(m);
    70             return;
    71         }
    72     }
    73     this.makeIdentity();
    74 }
    75 
    76 CanvasMatrix4.prototype.load = function()
    77 {
    78     if (arguments.length == 1 && typeof arguments[0] == 'object') {
    79         var matrix = arguments[0];
    80         
    81         if ("length" in matrix && matrix.length == 16) {
    82             this.m11 = matrix[0];
    83             this.m12 = matrix[1];
    84             this.m13 = matrix[2];
    85             this.m14 = matrix[3];
    86 
    87             this.m21 = matrix[4];
    88             this.m22 = matrix[5];
    89             this.m23 = matrix[6];
    90             this.m24 = matrix[7];
    91 
    92             this.m31 = matrix[8];
    93             this.m32 = matrix[9];
    94             this.m33 = matrix[10];
    95             this.m34 = matrix[11];
    96 
    97             this.m41 = matrix[12];
    98             this.m42 = matrix[13];
    99             this.m43 = matrix[14];
   100             this.m44 = matrix[15];
   101             return;
   102         }
   103             
   104         if (arguments[0] instanceof CanvasMatrix4) {
   105         
   106             this.m11 = matrix.m11;
   107             this.m12 = matrix.m12;
   108             this.m13 = matrix.m13;
   109             this.m14 = matrix.m14;
   110 
   111             this.m21 = matrix.m21;
   112             this.m22 = matrix.m22;
   113             this.m23 = matrix.m23;
   114             this.m24 = matrix.m24;
   115 
   116             this.m31 = matrix.m31;
   117             this.m32 = matrix.m32;
   118             this.m33 = matrix.m33;
   119             this.m34 = matrix.m34;
   120 
   121             this.m41 = matrix.m41;
   122             this.m42 = matrix.m42;
   123             this.m43 = matrix.m43;
   124             this.m44 = matrix.m44;
   125             return;
   126         }
   127     }
   128     
   129     this.makeIdentity();
   130 }
   131 
   132 CanvasMatrix4.prototype.getAsArray = function()
   133 {
   134     return [
   135         this.m11, this.m12, this.m13, this.m14, 
   136         this.m21, this.m22, this.m23, this.m24, 
   137         this.m31, this.m32, this.m33, this.m34, 
   138         this.m41, this.m42, this.m43, this.m44
   139     ];
   140 }
   141 
   142 CanvasMatrix4.prototype.getAsCanvasFloatArray = function()
   143 {
   144     return new WebGLFloatArray(this.getAsArray());
   145 }
   146 
   147 CanvasMatrix4.prototype.makeIdentity = function()
   148 {
   149     this.m11 = 1;
   150     this.m12 = 0;
   151     this.m13 = 0;
   152     this.m14 = 0;
   153     
   154     this.m21 = 0;
   155     this.m22 = 1;
   156     this.m23 = 0;
   157     this.m24 = 0;
   158     
   159     this.m31 = 0;
   160     this.m32 = 0;
   161     this.m33 = 1;
   162     this.m34 = 0;
   163     
   164     this.m41 = 0;
   165     this.m42 = 0;
   166     this.m43 = 0;
   167     this.m44 = 1;
   168 }
   169 
   170 CanvasMatrix4.prototype.transpose = function()
   171 {
   172     var tmp = this.m12;
   173     this.m12 = this.m21;
   174     this.m21 = tmp;
   175     
   176     tmp = this.m13;
   177     this.m13 = this.m31;
   178     this.m31 = tmp;
   179     
   180     tmp = this.m14;
   181     this.m14 = this.m41;
   182     this.m41 = tmp;
   183     
   184     tmp = this.m23;
   185     this.m23 = this.m32;
   186     this.m32 = tmp;
   187     
   188     tmp = this.m24;
   189     this.m24 = this.m42;
   190     this.m42 = tmp;
   191     
   192     tmp = this.m34;
   193     this.m34 = this.m43;
   194     this.m43 = tmp;
   195 }
   196 
   197 CanvasMatrix4.prototype.invert = function()
   198 {
   199     // Calculate the 4x4 determinant
   200     // If the determinant is zero, 
   201     // then the inverse matrix is not unique.
   202     var det = this._determinant4x4();
   203 
   204     if (Math.abs(det) < 1e-8)
   205         return null;
   206 
   207     this._makeAdjoint();
   208 
   209     // Scale the adjoint matrix to get the inverse
   210     this.m11 /= det;
   211     this.m12 /= det;
   212     this.m13 /= det;
   213     this.m14 /= det;
   214     
   215     this.m21 /= det;
   216     this.m22 /= det;
   217     this.m23 /= det;
   218     this.m24 /= det;
   219     
   220     this.m31 /= det;
   221     this.m32 /= det;
   222     this.m33 /= det;
   223     this.m34 /= det;
   224     
   225     this.m41 /= det;
   226     this.m42 /= det;
   227     this.m43 /= det;
   228     this.m44 /= det;
   229 }
   230 
   231 CanvasMatrix4.prototype.translate = function(x,y,z)
   232 {
   233     if (x == undefined)
   234         x = 0;
   235         if (y == undefined)
   236             y = 0;
   237     if (z == undefined)
   238         z = 0;
   239     
   240     var matrix = new CanvasMatrix4();
   241     matrix.m41 = x;
   242     matrix.m42 = y;
   243     matrix.m43 = z;
   244 
   245     this.multRight(matrix);
   246 }
   247 
   248 CanvasMatrix4.prototype.scale = function(x,y,z)
   249 {
   250     if (x == undefined)
   251         x = 1;
   252     if (z == undefined) {
   253         if (y == undefined) {
   254             y = x;
   255             z = x;
   256         }
   257         else
   258             z = 1;
   259     }
   260     else if (y == undefined)
   261         y = x;
   262     
   263     var matrix = new CanvasMatrix4();
   264     matrix.m11 = x;
   265     matrix.m22 = y;
   266     matrix.m33 = z;
   267     
   268     this.multRight(matrix);
   269 }
   270 
   271 CanvasMatrix4.prototype.rotate = function(angle,x,y,z)
   272 {
   273     // angles are in degrees. Switch to radians
   274     angle = angle / 180 * Math.PI;
   275     
   276     angle /= 2;
   277     var sinA = Math.sin(angle);
   278     var cosA = Math.cos(angle);
   279     var sinA2 = sinA * sinA;
   280     
   281     // normalize
   282     var length = Math.sqrt(x * x + y * y + z * z);
   283     if (length == 0) {
   284         // bad vector, just use something reasonable
   285         x = 0;
   286         y = 0;
   287         z = 1;
   288     } else if (length != 1) {
   289         x /= length;
   290         y /= length;
   291         z /= length;
   292     }
   293     
   294     var mat = new CanvasMatrix4();
   295 
   296     // optimize case where axis is along major axis
   297     if (x == 1 && y == 0 && z == 0) {
   298         mat.m11 = 1;
   299         mat.m12 = 0;
   300         mat.m13 = 0;
   301         mat.m21 = 0;
   302         mat.m22 = 1 - 2 * sinA2;
   303         mat.m23 = 2 * sinA * cosA;
   304         mat.m31 = 0;
   305         mat.m32 = -2 * sinA * cosA;
   306         mat.m33 = 1 - 2 * sinA2;
   307         mat.m14 = mat.m24 = mat.m34 = 0;
   308         mat.m41 = mat.m42 = mat.m43 = 0;
   309         mat.m44 = 1;
   310     } else if (x == 0 && y == 1 && z == 0) {
   311         mat.m11 = 1 - 2 * sinA2;
   312         mat.m12 = 0;
   313         mat.m13 = -2 * sinA * cosA;
   314         mat.m21 = 0;
   315         mat.m22 = 1;
   316         mat.m23 = 0;
   317         mat.m31 = 2 * sinA * cosA;
   318         mat.m32 = 0;
   319         mat.m33 = 1 - 2 * sinA2;
   320         mat.m14 = mat.m24 = mat.m34 = 0;
   321         mat.m41 = mat.m42 = mat.m43 = 0;
   322         mat.m44 = 1;
   323     } else if (x == 0 && y == 0 && z == 1) {
   324         mat.m11 = 1 - 2 * sinA2;
   325         mat.m12 = 2 * sinA * cosA;
   326         mat.m13 = 0;
   327         mat.m21 = -2 * sinA * cosA;
   328         mat.m22 = 1 - 2 * sinA2;
   329         mat.m23 = 0;
   330         mat.m31 = 0;
   331         mat.m32 = 0;
   332         mat.m33 = 1;
   333         mat.m14 = mat.m24 = mat.m34 = 0;
   334         mat.m41 = mat.m42 = mat.m43 = 0;
   335         mat.m44 = 1;
   336     } else {
   337         var x2 = x*x;
   338         var y2 = y*y;
   339         var z2 = z*z;
   340     
   341         mat.m11 = 1 - 2 * (y2 + z2) * sinA2;
   342         mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA);
   343         mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA);
   344         mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA);
   345         mat.m22 = 1 - 2 * (z2 + x2) * sinA2;
   346         mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA);
   347         mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA);
   348         mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA);
   349         mat.m33 = 1 - 2 * (x2 + y2) * sinA2;
   350         mat.m14 = mat.m24 = mat.m34 = 0;
   351         mat.m41 = mat.m42 = mat.m43 = 0;
   352         mat.m44 = 1;
   353     }
   354     this.multRight(mat);
   355 }
   356 
   357 CanvasMatrix4.prototype.multRight = function(mat)
   358 {
   359     var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21
   360                + this.m13 * mat.m31 + this.m14 * mat.m41);
   361     var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22
   362                + this.m13 * mat.m32 + this.m14 * mat.m42);
   363     var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23
   364                + this.m13 * mat.m33 + this.m14 * mat.m43);
   365     var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24
   366                + this.m13 * mat.m34 + this.m14 * mat.m44);
   367 
   368     var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21
   369                + this.m23 * mat.m31 + this.m24 * mat.m41);
   370     var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22
   371                + this.m23 * mat.m32 + this.m24 * mat.m42);
   372     var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23
   373                + this.m23 * mat.m33 + this.m24 * mat.m43);
   374     var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24
   375                + this.m23 * mat.m34 + this.m24 * mat.m44);
   376 
   377     var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21
   378                + this.m33 * mat.m31 + this.m34 * mat.m41);
   379     var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22
   380                + this.m33 * mat.m32 + this.m34 * mat.m42);
   381     var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23
   382                + this.m33 * mat.m33 + this.m34 * mat.m43);
   383     var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24
   384                + this.m33 * mat.m34 + this.m34 * mat.m44);
   385 
   386     var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21
   387                + this.m43 * mat.m31 + this.m44 * mat.m41);
   388     var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22
   389                + this.m43 * mat.m32 + this.m44 * mat.m42);
   390     var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23
   391                + this.m43 * mat.m33 + this.m44 * mat.m43);
   392     var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24
   393                + this.m43 * mat.m34 + this.m44 * mat.m44);
   394     
   395     this.m11 = m11;
   396     this.m12 = m12;
   397     this.m13 = m13;
   398     this.m14 = m14;
   399     
   400     this.m21 = m21;
   401     this.m22 = m22;
   402     this.m23 = m23;
   403     this.m24 = m24;
   404     
   405     this.m31 = m31;
   406     this.m32 = m32;
   407     this.m33 = m33;
   408     this.m34 = m34;
   409     
   410     this.m41 = m41;
   411     this.m42 = m42;
   412     this.m43 = m43;
   413     this.m44 = m44;
   414 }
   415 
   416 CanvasMatrix4.prototype.multLeft = function(mat)
   417 {
   418     var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21
   419                + mat.m13 * this.m31 + mat.m14 * this.m41);
   420     var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22
   421                + mat.m13 * this.m32 + mat.m14 * this.m42);
   422     var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23
   423                + mat.m13 * this.m33 + mat.m14 * this.m43);
   424     var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24
   425                + mat.m13 * this.m34 + mat.m14 * this.m44);
   426 
   427     var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21
   428                + mat.m23 * this.m31 + mat.m24 * this.m41);
   429     var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22
   430                + mat.m23 * this.m32 + mat.m24 * this.m42);
   431     var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23
   432                + mat.m23 * this.m33 + mat.m24 * this.m43);
   433     var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24
   434                + mat.m23 * this.m34 + mat.m24 * this.m44);
   435 
   436     var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21
   437                + mat.m33 * this.m31 + mat.m34 * this.m41);
   438     var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22
   439                + mat.m33 * this.m32 + mat.m34 * this.m42);
   440     var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23
   441                + mat.m33 * this.m33 + mat.m34 * this.m43);
   442     var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24
   443                + mat.m33 * this.m34 + mat.m34 * this.m44);
   444 
   445     var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21
   446                + mat.m43 * this.m31 + mat.m44 * this.m41);
   447     var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22
   448                + mat.m43 * this.m32 + mat.m44 * this.m42);
   449     var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23
   450                + mat.m43 * this.m33 + mat.m44 * this.m43);
   451     var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24
   452                + mat.m43 * this.m34 + mat.m44 * this.m44);
   453     
   454     this.m11 = m11;
   455     this.m12 = m12;
   456     this.m13 = m13;
   457     this.m14 = m14;
   458 
   459     this.m21 = m21;
   460     this.m22 = m22;
   461     this.m23 = m23;
   462     this.m24 = m24;
   463 
   464     this.m31 = m31;
   465     this.m32 = m32;
   466     this.m33 = m33;
   467     this.m34 = m34;
   468 
   469     this.m41 = m41;
   470     this.m42 = m42;
   471     this.m43 = m43;
   472     this.m44 = m44;
   473 }
   474 
   475 CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far)
   476 {
   477     var tx = (left + right) / (left - right);
   478     var ty = (top + bottom) / (top - bottom);
   479     var tz = (far + near) / (far - near);
   480     
   481     var matrix = new CanvasMatrix4();
   482     matrix.m11 = 2 / (left - right);
   483     matrix.m12 = 0;
   484     matrix.m13 = 0;
   485     matrix.m14 = 0;
   486     matrix.m21 = 0;
   487     matrix.m22 = 2 / (top - bottom);
   488     matrix.m23 = 0;
   489     matrix.m24 = 0;
   490     matrix.m31 = 0;
   491     matrix.m32 = 0;
   492     matrix.m33 = -2 / (far - near);
   493     matrix.m34 = 0;
   494     matrix.m41 = tx;
   495     matrix.m42 = ty;
   496     matrix.m43 = tz;
   497     matrix.m44 = 1;
   498     
   499     this.multRight(matrix);
   500 }
   501 
   502 CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far)
   503 {
   504     var matrix = new CanvasMatrix4();
   505     var A = (right + left) / (right - left);
   506     var B = (top + bottom) / (top - bottom);
   507     var C = -(far + near) / (far - near);
   508     var D = -(2 * far * near) / (far - near);
   509     
   510     matrix.m11 = (2 * near) / (right - left);
   511     matrix.m12 = 0;
   512     matrix.m13 = 0;
   513     matrix.m14 = 0;
   514     
   515     matrix.m21 = 0;
   516     matrix.m22 = 2 * near / (top - bottom);
   517     matrix.m23 = 0;
   518     matrix.m24 = 0;
   519     
   520     matrix.m31 = A;
   521     matrix.m32 = B;
   522     matrix.m33 = C;
   523     matrix.m34 = -1;
   524     
   525     matrix.m41 = 0;
   526     matrix.m42 = 0;
   527     matrix.m43 = D;
   528     matrix.m44 = 0;
   529     
   530     this.multRight(matrix);
   531 }
   532 
   533 CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
   534 {
   535     var top = Math.tan(fovy * Math.PI / 360) * zNear;
   536     var bottom = -top;
   537     var left = aspect * bottom;
   538     var right = aspect * top;
   539     this.frustum(left, right, bottom, top, zNear, zFar);
   540 }
   541 
   542 CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
   543 {
   544     var matrix = new CanvasMatrix4();
   545     
   546     // Make rotation matrix
   547 
   548     // Z vector
   549     var zx = eyex - centerx;
   550     var zy = eyey - centery;
   551     var zz = eyez - centerz;
   552     var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
   553     if (mag) {
   554         zx /= mag;
   555         zy /= mag;
   556         zz /= mag;
   557     }
   558 
   559     // Y vector
   560     var yx = upx;
   561     var yy = upy;
   562     var yz = upz;
   563 
   564     // X vector = Y cross Z
   565     xx =  yy * zz - yz * zy;
   566     xy = -yx * zz + yz * zx;
   567     xz =  yx * zy - yy * zx;
   568 
   569     // Recompute Y = Z cross X
   570     yx = zy * xz - zz * xy;
   571     yy = -zx * xz + zz * xx;
   572     yx = zx * xy - zy * xx;
   573 
   574     // cross product gives area of parallelogram, which is < 1.0 for
   575     // non-perpendicular unit-length vectors; so normalize x, y here
   576 
   577     mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
   578     if (mag) {
   579         xx /= mag;
   580         xy /= mag;
   581         xz /= mag;
   582     }
   583 
   584     mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
   585     if (mag) {
   586         yx /= mag;
   587         yy /= mag;
   588         yz /= mag;
   589     }
   590 
   591     matrix.m11 = xx;
   592     matrix.m12 = xy;
   593     matrix.m13 = xz;
   594     matrix.m14 = 0;
   595     
   596     matrix.m21 = yx;
   597     matrix.m22 = yy;
   598     matrix.m23 = yz;
   599     matrix.m24 = 0;
   600     
   601     matrix.m31 = zx;
   602     matrix.m32 = zy;
   603     matrix.m33 = zz;
   604     matrix.m34 = 0;
   605     
   606     matrix.m41 = 0;
   607     matrix.m42 = 0;
   608     matrix.m43 = 0;
   609     matrix.m44 = 1;
   610     matrix.translate(-eyex, -eyey, -eyez);
   611     
   612     this.multRight(matrix);
   613 }
   614 
   615 // Support functions
   616 CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d)
   617 {
   618     return a * d - b * c;
   619 }
   620 
   621 CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
   622 {
   623     return a1 * this._determinant2x2(b2, b3, c2, c3)
   624          - b1 * this._determinant2x2(a2, a3, c2, c3)
   625          + c1 * this._determinant2x2(a2, a3, b2, b3);
   626 }
   627 
   628 CanvasMatrix4.prototype._determinant4x4 = function()
   629 {
   630     var a1 = this.m11;
   631     var b1 = this.m12; 
   632     var c1 = this.m13;
   633     var d1 = this.m14;
   634 
   635     var a2 = this.m21;
   636     var b2 = this.m22; 
   637     var c2 = this.m23;
   638     var d2 = this.m24;
   639 
   640     var a3 = this.m31;
   641     var b3 = this.m32; 
   642     var c3 = this.m33;
   643     var d3 = this.m34;
   644 
   645     var a4 = this.m41;
   646     var b4 = this.m42; 
   647     var c4 = this.m43;
   648     var d4 = this.m44;
   649 
   650     return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
   651          - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
   652          + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
   653          - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
   654 }
   655 
   656 CanvasMatrix4.prototype._makeAdjoint = function()
   657 {
   658     var a1 = this.m11;
   659     var b1 = this.m12; 
   660     var c1 = this.m13;
   661     var d1 = this.m14;
   662 
   663     var a2 = this.m21;
   664     var b2 = this.m22; 
   665     var c2 = this.m23;
   666     var d2 = this.m24;
   667 
   668     var a3 = this.m31;
   669     var b3 = this.m32; 
   670     var c3 = this.m33;
   671     var d3 = this.m34;
   672 
   673     var a4 = this.m41;
   674     var b4 = this.m42; 
   675     var c4 = this.m43;
   676     var d4 = this.m44;
   677 
   678     // Row column labeling reversed since we transpose rows & columns
   679     this.m11  =   this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
   680     this.m21  = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
   681     this.m31  =   this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
   682     this.m41  = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
   683         
   684     this.m12  = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
   685     this.m22  =   this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
   686     this.m32  = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
   687     this.m42  =   this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
   688         
   689     this.m13  =   this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
   690     this.m23  = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
   691     this.m33  =   this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
   692     this.m43  = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
   693         
   694     this.m14  = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
   695     this.m24  =   this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
   696     this.m34  = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
   697     this.m44  =   this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
   698 }