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