sawine@2: /* sawine@2: CanvasMatrix4 class sawine@2: sawine@2: This class implements a 4x4 matrix. It has functions which sawine@2: duplicate the functionality of the OpenGL matrix stack and sawine@2: glut functions. sawine@2: sawine@2: IDL: sawine@2: sawine@2: [ sawine@2: Constructor(in CanvasMatrix4 matrix), // copy passed matrix into new CanvasMatrix4 sawine@2: Constructor(in sequence array) // create new CanvasMatrix4 with 16 floats (row major) sawine@2: Constructor() // create new CanvasMatrix4 with identity matrix sawine@2: ] sawine@2: interface CanvasMatrix4 { sawine@2: attribute float m11; sawine@2: attribute float m12; sawine@2: attribute float m13; sawine@2: attribute float m14; sawine@2: attribute float m21; sawine@2: attribute float m22; sawine@2: attribute float m23; sawine@2: attribute float m24; sawine@2: attribute float m31; sawine@2: attribute float m32; sawine@2: attribute float m33; sawine@2: attribute float m34; sawine@2: attribute float m41; sawine@2: attribute float m42; sawine@2: attribute float m43; sawine@2: attribute float m44; sawine@2: sawine@2: void load(in CanvasMatrix4 matrix); // copy the values from the passed matrix sawine@2: void load(in sequence array); // copy 16 floats into the matrix sawine@2: sequence getAsArray(); // return the matrix as an array of 16 floats sawine@2: WebGLFloatArray getAsCanvasFloatArray(); // return the matrix as a WebGLFloatArray with 16 values sawine@2: void makeIdentity(); // replace the matrix with identity sawine@2: void transpose(); // replace the matrix with its transpose sawine@2: void invert(); // replace the matrix with its inverse sawine@2: sawine@2: void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right sawine@2: void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right sawine@2: void rotate(in float angle, // multiply the matrix by passed rotation values on the right sawine@2: in float x, in float y, in float z); // (angle is in degrees) sawine@2: void multRight(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right sawine@2: void multLeft(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the left sawine@2: void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right sawine@2: in float bottom, in float top, sawine@2: in float near, in float far); sawine@2: void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right sawine@2: in float bottom, in float top, sawine@2: in float near, in float far); sawine@2: void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right sawine@2: in float zNear, in float zFar); sawine@2: void lookat(in float eyex, in float eyey, in float eyez, // multiply the matrix by the passed lookat sawine@2: in float ctrx, in float ctry, in float ctrz, // values on the right sawine@2: in float upx, in float upy, in float upz); sawine@2: } sawine@2: */ sawine@2: sawine@2: CanvasMatrix4 = function(m) sawine@2: { sawine@2: if (typeof m == 'object') { sawine@2: if ("length" in m && m.length >= 16) { sawine@2: 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: return; sawine@2: } sawine@2: else if (m instanceof CanvasMatrix4) { sawine@2: this.load(m); sawine@2: return; sawine@2: } sawine@2: } sawine@2: this.makeIdentity(); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.load = function() sawine@2: { sawine@2: if (arguments.length == 1 && typeof arguments[0] == 'object') { sawine@2: var matrix = arguments[0]; sawine@2: sawine@2: if ("length" in matrix && matrix.length == 16) { sawine@2: this.m11 = matrix[0]; sawine@2: this.m12 = matrix[1]; sawine@2: this.m13 = matrix[2]; sawine@2: this.m14 = matrix[3]; sawine@2: sawine@2: this.m21 = matrix[4]; sawine@2: this.m22 = matrix[5]; sawine@2: this.m23 = matrix[6]; sawine@2: this.m24 = matrix[7]; sawine@2: sawine@2: this.m31 = matrix[8]; sawine@2: this.m32 = matrix[9]; sawine@2: this.m33 = matrix[10]; sawine@2: this.m34 = matrix[11]; sawine@2: sawine@2: this.m41 = matrix[12]; sawine@2: this.m42 = matrix[13]; sawine@2: this.m43 = matrix[14]; sawine@2: this.m44 = matrix[15]; sawine@2: return; sawine@2: } sawine@2: sawine@2: if (arguments[0] instanceof CanvasMatrix4) { sawine@2: sawine@2: this.m11 = matrix.m11; sawine@2: this.m12 = matrix.m12; sawine@2: this.m13 = matrix.m13; sawine@2: this.m14 = matrix.m14; sawine@2: sawine@2: this.m21 = matrix.m21; sawine@2: this.m22 = matrix.m22; sawine@2: this.m23 = matrix.m23; sawine@2: this.m24 = matrix.m24; sawine@2: sawine@2: this.m31 = matrix.m31; sawine@2: this.m32 = matrix.m32; sawine@2: this.m33 = matrix.m33; sawine@2: this.m34 = matrix.m34; sawine@2: sawine@2: this.m41 = matrix.m41; sawine@2: this.m42 = matrix.m42; sawine@2: this.m43 = matrix.m43; sawine@2: this.m44 = matrix.m44; sawine@2: return; sawine@2: } sawine@2: } sawine@2: sawine@2: this.makeIdentity(); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.getAsArray = function() sawine@2: { sawine@2: return [ sawine@2: this.m11, this.m12, this.m13, this.m14, sawine@2: this.m21, this.m22, this.m23, this.m24, sawine@2: this.m31, this.m32, this.m33, this.m34, sawine@2: this.m41, this.m42, this.m43, this.m44 sawine@2: ]; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.getAsCanvasFloatArray = function() sawine@2: { sawine@2: return new WebGLFloatArray(this.getAsArray()); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.makeIdentity = function() sawine@2: { sawine@2: this.m11 = 1; sawine@2: this.m12 = 0; sawine@2: this.m13 = 0; sawine@2: this.m14 = 0; sawine@2: sawine@2: this.m21 = 0; sawine@2: this.m22 = 1; sawine@2: this.m23 = 0; sawine@2: this.m24 = 0; sawine@2: sawine@2: this.m31 = 0; sawine@2: this.m32 = 0; sawine@2: this.m33 = 1; sawine@2: this.m34 = 0; sawine@2: sawine@2: this.m41 = 0; sawine@2: this.m42 = 0; sawine@2: this.m43 = 0; sawine@2: this.m44 = 1; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.transpose = function() sawine@2: { sawine@2: var tmp = this.m12; sawine@2: this.m12 = this.m21; sawine@2: this.m21 = tmp; sawine@2: sawine@2: tmp = this.m13; sawine@2: this.m13 = this.m31; sawine@2: this.m31 = tmp; sawine@2: sawine@2: tmp = this.m14; sawine@2: this.m14 = this.m41; sawine@2: this.m41 = tmp; sawine@2: sawine@2: tmp = this.m23; sawine@2: this.m23 = this.m32; sawine@2: this.m32 = tmp; sawine@2: sawine@2: tmp = this.m24; sawine@2: this.m24 = this.m42; sawine@2: this.m42 = tmp; sawine@2: sawine@2: tmp = this.m34; sawine@2: this.m34 = this.m43; sawine@2: this.m43 = tmp; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.invert = function() sawine@2: { sawine@2: // Calculate the 4x4 determinant sawine@2: // If the determinant is zero, sawine@2: // then the inverse matrix is not unique. sawine@2: var det = this._determinant4x4(); sawine@2: sawine@2: if (Math.abs(det) < 1e-8) sawine@2: return null; sawine@2: sawine@2: this._makeAdjoint(); sawine@2: sawine@2: // Scale the adjoint matrix to get the inverse sawine@2: this.m11 /= det; sawine@2: this.m12 /= det; sawine@2: this.m13 /= det; sawine@2: this.m14 /= det; sawine@2: sawine@2: this.m21 /= det; sawine@2: this.m22 /= det; sawine@2: this.m23 /= det; sawine@2: this.m24 /= det; sawine@2: sawine@2: this.m31 /= det; sawine@2: this.m32 /= det; sawine@2: this.m33 /= det; sawine@2: this.m34 /= det; sawine@2: sawine@2: this.m41 /= det; sawine@2: this.m42 /= det; sawine@2: this.m43 /= det; sawine@2: this.m44 /= det; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.translate = function(x,y,z) sawine@2: { sawine@2: if (x == undefined) sawine@2: x = 0; sawine@2: if (y == undefined) sawine@2: y = 0; sawine@2: if (z == undefined) sawine@2: z = 0; sawine@2: sawine@2: var matrix = new CanvasMatrix4(); sawine@2: matrix.m41 = x; sawine@2: matrix.m42 = y; sawine@2: matrix.m43 = z; sawine@2: sawine@2: this.multRight(matrix); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.scale = function(x,y,z) sawine@2: { sawine@2: if (x == undefined) sawine@2: x = 1; sawine@2: if (z == undefined) { sawine@2: if (y == undefined) { sawine@2: y = x; sawine@2: z = x; sawine@2: } sawine@2: else sawine@2: z = 1; sawine@2: } sawine@2: else if (y == undefined) sawine@2: y = x; sawine@2: sawine@2: var matrix = new CanvasMatrix4(); sawine@2: matrix.m11 = x; sawine@2: matrix.m22 = y; sawine@2: matrix.m33 = z; sawine@2: sawine@2: this.multRight(matrix); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.rotate = function(angle,x,y,z) sawine@2: { sawine@2: // angles are in degrees. Switch to radians sawine@2: angle = angle / 180 * Math.PI; sawine@2: sawine@2: angle /= 2; sawine@2: var sinA = Math.sin(angle); sawine@2: var cosA = Math.cos(angle); sawine@2: var sinA2 = sinA * sinA; sawine@2: sawine@2: // normalize sawine@2: var length = Math.sqrt(x * x + y * y + z * z); sawine@2: if (length == 0) { sawine@2: // bad vector, just use something reasonable sawine@2: x = 0; sawine@2: y = 0; sawine@2: z = 1; sawine@2: } else if (length != 1) { sawine@2: x /= length; sawine@2: y /= length; sawine@2: z /= length; sawine@2: } sawine@2: sawine@2: var mat = new CanvasMatrix4(); sawine@2: sawine@2: // optimize case where axis is along major axis sawine@2: if (x == 1 && y == 0 && z == 0) { sawine@2: mat.m11 = 1; sawine@2: mat.m12 = 0; sawine@2: mat.m13 = 0; sawine@2: mat.m21 = 0; sawine@2: mat.m22 = 1 - 2 * sinA2; sawine@2: mat.m23 = 2 * sinA * cosA; sawine@2: mat.m31 = 0; sawine@2: mat.m32 = -2 * sinA * cosA; sawine@2: mat.m33 = 1 - 2 * sinA2; sawine@2: mat.m14 = mat.m24 = mat.m34 = 0; sawine@2: mat.m41 = mat.m42 = mat.m43 = 0; sawine@2: mat.m44 = 1; sawine@2: } else if (x == 0 && y == 1 && z == 0) { sawine@2: mat.m11 = 1 - 2 * sinA2; sawine@2: mat.m12 = 0; sawine@2: mat.m13 = -2 * sinA * cosA; sawine@2: mat.m21 = 0; sawine@2: mat.m22 = 1; sawine@2: mat.m23 = 0; sawine@2: mat.m31 = 2 * sinA * cosA; sawine@2: mat.m32 = 0; sawine@2: mat.m33 = 1 - 2 * sinA2; sawine@2: mat.m14 = mat.m24 = mat.m34 = 0; sawine@2: mat.m41 = mat.m42 = mat.m43 = 0; sawine@2: mat.m44 = 1; sawine@2: } else if (x == 0 && y == 0 && z == 1) { sawine@2: mat.m11 = 1 - 2 * sinA2; sawine@2: mat.m12 = 2 * sinA * cosA; sawine@2: mat.m13 = 0; sawine@2: mat.m21 = -2 * sinA * cosA; sawine@2: mat.m22 = 1 - 2 * sinA2; sawine@2: mat.m23 = 0; sawine@2: mat.m31 = 0; sawine@2: mat.m32 = 0; sawine@2: mat.m33 = 1; sawine@2: mat.m14 = mat.m24 = mat.m34 = 0; sawine@2: mat.m41 = mat.m42 = mat.m43 = 0; sawine@2: mat.m44 = 1; sawine@2: } else { sawine@2: var x2 = x*x; sawine@2: var y2 = y*y; sawine@2: var z2 = z*z; sawine@2: sawine@2: mat.m11 = 1 - 2 * (y2 + z2) * sinA2; sawine@2: mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA); sawine@2: mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA); sawine@2: mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA); sawine@2: mat.m22 = 1 - 2 * (z2 + x2) * sinA2; sawine@2: mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA); sawine@2: mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA); sawine@2: mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA); sawine@2: mat.m33 = 1 - 2 * (x2 + y2) * sinA2; sawine@2: mat.m14 = mat.m24 = mat.m34 = 0; sawine@2: mat.m41 = mat.m42 = mat.m43 = 0; sawine@2: mat.m44 = 1; sawine@2: } sawine@2: this.multRight(mat); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.multRight = function(mat) sawine@2: { sawine@2: var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21 sawine@2: + this.m13 * mat.m31 + this.m14 * mat.m41); sawine@2: var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22 sawine@2: + this.m13 * mat.m32 + this.m14 * mat.m42); sawine@2: var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23 sawine@2: + this.m13 * mat.m33 + this.m14 * mat.m43); sawine@2: var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24 sawine@2: + this.m13 * mat.m34 + this.m14 * mat.m44); sawine@2: sawine@2: var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21 sawine@2: + this.m23 * mat.m31 + this.m24 * mat.m41); sawine@2: var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22 sawine@2: + this.m23 * mat.m32 + this.m24 * mat.m42); sawine@2: var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23 sawine@2: + this.m23 * mat.m33 + this.m24 * mat.m43); sawine@2: var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24 sawine@2: + this.m23 * mat.m34 + this.m24 * mat.m44); sawine@2: sawine@2: var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21 sawine@2: + this.m33 * mat.m31 + this.m34 * mat.m41); sawine@2: var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22 sawine@2: + this.m33 * mat.m32 + this.m34 * mat.m42); sawine@2: var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23 sawine@2: + this.m33 * mat.m33 + this.m34 * mat.m43); sawine@2: var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24 sawine@2: + this.m33 * mat.m34 + this.m34 * mat.m44); sawine@2: sawine@2: var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21 sawine@2: + this.m43 * mat.m31 + this.m44 * mat.m41); sawine@2: var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22 sawine@2: + this.m43 * mat.m32 + this.m44 * mat.m42); sawine@2: var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23 sawine@2: + this.m43 * mat.m33 + this.m44 * mat.m43); sawine@2: var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24 sawine@2: + this.m43 * mat.m34 + this.m44 * mat.m44); sawine@2: sawine@2: this.m11 = m11; sawine@2: this.m12 = m12; sawine@2: this.m13 = m13; sawine@2: this.m14 = m14; sawine@2: sawine@2: this.m21 = m21; sawine@2: this.m22 = m22; sawine@2: this.m23 = m23; sawine@2: this.m24 = m24; sawine@2: sawine@2: this.m31 = m31; sawine@2: this.m32 = m32; sawine@2: this.m33 = m33; sawine@2: this.m34 = m34; sawine@2: sawine@2: this.m41 = m41; sawine@2: this.m42 = m42; sawine@2: this.m43 = m43; sawine@2: this.m44 = m44; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.multLeft = function(mat) sawine@2: { sawine@2: var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21 sawine@2: + mat.m13 * this.m31 + mat.m14 * this.m41); sawine@2: var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22 sawine@2: + mat.m13 * this.m32 + mat.m14 * this.m42); sawine@2: var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23 sawine@2: + mat.m13 * this.m33 + mat.m14 * this.m43); sawine@2: var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24 sawine@2: + mat.m13 * this.m34 + mat.m14 * this.m44); sawine@2: sawine@2: var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21 sawine@2: + mat.m23 * this.m31 + mat.m24 * this.m41); sawine@2: var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22 sawine@2: + mat.m23 * this.m32 + mat.m24 * this.m42); sawine@2: var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23 sawine@2: + mat.m23 * this.m33 + mat.m24 * this.m43); sawine@2: var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24 sawine@2: + mat.m23 * this.m34 + mat.m24 * this.m44); sawine@2: sawine@2: var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21 sawine@2: + mat.m33 * this.m31 + mat.m34 * this.m41); sawine@2: var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22 sawine@2: + mat.m33 * this.m32 + mat.m34 * this.m42); sawine@2: var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23 sawine@2: + mat.m33 * this.m33 + mat.m34 * this.m43); sawine@2: var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24 sawine@2: + mat.m33 * this.m34 + mat.m34 * this.m44); sawine@2: sawine@2: var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21 sawine@2: + mat.m43 * this.m31 + mat.m44 * this.m41); sawine@2: var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22 sawine@2: + mat.m43 * this.m32 + mat.m44 * this.m42); sawine@2: var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23 sawine@2: + mat.m43 * this.m33 + mat.m44 * this.m43); sawine@2: var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24 sawine@2: + mat.m43 * this.m34 + mat.m44 * this.m44); sawine@2: sawine@2: this.m11 = m11; sawine@2: this.m12 = m12; sawine@2: this.m13 = m13; sawine@2: this.m14 = m14; sawine@2: sawine@2: this.m21 = m21; sawine@2: this.m22 = m22; sawine@2: this.m23 = m23; sawine@2: this.m24 = m24; sawine@2: sawine@2: this.m31 = m31; sawine@2: this.m32 = m32; sawine@2: this.m33 = m33; sawine@2: this.m34 = m34; sawine@2: sawine@2: this.m41 = m41; sawine@2: this.m42 = m42; sawine@2: this.m43 = m43; sawine@2: this.m44 = m44; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far) sawine@2: { sawine@2: var tx = (left + right) / (left - right); sawine@2: var ty = (top + bottom) / (top - bottom); sawine@2: var tz = (far + near) / (far - near); sawine@2: sawine@2: var matrix = new CanvasMatrix4(); sawine@2: matrix.m11 = 2 / (left - right); sawine@2: matrix.m12 = 0; sawine@2: matrix.m13 = 0; sawine@2: matrix.m14 = 0; sawine@2: matrix.m21 = 0; sawine@2: matrix.m22 = 2 / (top - bottom); sawine@2: matrix.m23 = 0; sawine@2: matrix.m24 = 0; sawine@2: matrix.m31 = 0; sawine@2: matrix.m32 = 0; sawine@2: matrix.m33 = -2 / (far - near); sawine@2: matrix.m34 = 0; sawine@2: matrix.m41 = tx; sawine@2: matrix.m42 = ty; sawine@2: matrix.m43 = tz; sawine@2: matrix.m44 = 1; sawine@2: sawine@2: this.multRight(matrix); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far) sawine@2: { sawine@2: var matrix = new CanvasMatrix4(); sawine@2: var A = (right + left) / (right - left); sawine@2: var B = (top + bottom) / (top - bottom); sawine@2: var C = -(far + near) / (far - near); sawine@2: var D = -(2 * far * near) / (far - near); sawine@2: sawine@2: matrix.m11 = (2 * near) / (right - left); sawine@2: matrix.m12 = 0; sawine@2: matrix.m13 = 0; sawine@2: matrix.m14 = 0; sawine@2: sawine@2: matrix.m21 = 0; sawine@2: matrix.m22 = 2 * near / (top - bottom); sawine@2: matrix.m23 = 0; sawine@2: matrix.m24 = 0; sawine@2: sawine@2: matrix.m31 = A; sawine@2: matrix.m32 = B; sawine@2: matrix.m33 = C; sawine@2: matrix.m34 = -1; sawine@2: sawine@2: matrix.m41 = 0; sawine@2: matrix.m42 = 0; sawine@2: matrix.m43 = D; sawine@2: matrix.m44 = 0; sawine@2: sawine@2: this.multRight(matrix); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar) sawine@2: { sawine@2: var top = Math.tan(fovy * Math.PI / 360) * zNear; sawine@2: var bottom = -top; sawine@2: var left = aspect * bottom; sawine@2: var right = aspect * top; sawine@2: this.frustum(left, right, bottom, top, zNear, zFar); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz) sawine@2: { sawine@2: var matrix = new CanvasMatrix4(); sawine@2: sawine@2: // Make rotation matrix sawine@2: sawine@2: // Z vector sawine@2: var zx = eyex - centerx; sawine@2: var zy = eyey - centery; sawine@2: var zz = eyez - centerz; sawine@2: var mag = Math.sqrt(zx * zx + zy * zy + zz * zz); sawine@2: if (mag) { sawine@2: zx /= mag; sawine@2: zy /= mag; sawine@2: zz /= mag; sawine@2: } sawine@2: sawine@2: // Y vector sawine@2: var yx = upx; sawine@2: var yy = upy; sawine@2: var yz = upz; sawine@2: sawine@2: // X vector = Y cross Z sawine@2: xx = yy * zz - yz * zy; sawine@2: xy = -yx * zz + yz * zx; sawine@2: xz = yx * zy - yy * zx; sawine@2: sawine@2: // Recompute Y = Z cross X sawine@2: yx = zy * xz - zz * xy; sawine@2: yy = -zx * xz + zz * xx; sawine@2: yx = zx * xy - zy * xx; sawine@2: sawine@2: // cross product gives area of parallelogram, which is < 1.0 for sawine@2: // non-perpendicular unit-length vectors; so normalize x, y here sawine@2: sawine@2: mag = Math.sqrt(xx * xx + xy * xy + xz * xz); sawine@2: if (mag) { sawine@2: xx /= mag; sawine@2: xy /= mag; sawine@2: xz /= mag; sawine@2: } sawine@2: sawine@2: mag = Math.sqrt(yx * yx + yy * yy + yz * yz); sawine@2: if (mag) { sawine@2: yx /= mag; sawine@2: yy /= mag; sawine@2: yz /= mag; sawine@2: } sawine@2: sawine@2: matrix.m11 = xx; sawine@2: matrix.m12 = xy; sawine@2: matrix.m13 = xz; sawine@2: matrix.m14 = 0; sawine@2: sawine@2: matrix.m21 = yx; sawine@2: matrix.m22 = yy; sawine@2: matrix.m23 = yz; sawine@2: matrix.m24 = 0; sawine@2: sawine@2: matrix.m31 = zx; sawine@2: matrix.m32 = zy; sawine@2: matrix.m33 = zz; sawine@2: matrix.m34 = 0; sawine@2: sawine@2: matrix.m41 = 0; sawine@2: matrix.m42 = 0; sawine@2: matrix.m43 = 0; sawine@2: matrix.m44 = 1; sawine@2: matrix.translate(-eyex, -eyey, -eyez); sawine@2: sawine@2: this.multRight(matrix); sawine@2: } sawine@2: sawine@2: // Support functions sawine@2: CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d) sawine@2: { sawine@2: return a * d - b * c; sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3) sawine@2: { sawine@2: return a1 * this._determinant2x2(b2, b3, c2, c3) sawine@2: - b1 * this._determinant2x2(a2, a3, c2, c3) sawine@2: + c1 * this._determinant2x2(a2, a3, b2, b3); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype._determinant4x4 = function() sawine@2: { sawine@2: var a1 = this.m11; sawine@2: var b1 = this.m12; sawine@2: var c1 = this.m13; sawine@2: var d1 = this.m14; sawine@2: sawine@2: var a2 = this.m21; sawine@2: var b2 = this.m22; sawine@2: var c2 = this.m23; sawine@2: var d2 = this.m24; sawine@2: sawine@2: var a3 = this.m31; sawine@2: var b3 = this.m32; sawine@2: var c3 = this.m33; sawine@2: var d3 = this.m34; sawine@2: sawine@2: var a4 = this.m41; sawine@2: var b4 = this.m42; sawine@2: var c4 = this.m43; sawine@2: var d4 = this.m44; sawine@2: sawine@2: return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) sawine@2: - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) sawine@2: + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) sawine@2: - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); sawine@2: } sawine@2: sawine@2: CanvasMatrix4.prototype._makeAdjoint = function() sawine@2: { sawine@2: var a1 = this.m11; sawine@2: var b1 = this.m12; sawine@2: var c1 = this.m13; sawine@2: var d1 = this.m14; sawine@2: sawine@2: var a2 = this.m21; sawine@2: var b2 = this.m22; sawine@2: var c2 = this.m23; sawine@2: var d2 = this.m24; sawine@2: sawine@2: var a3 = this.m31; sawine@2: var b3 = this.m32; sawine@2: var c3 = this.m33; sawine@2: var d3 = this.m34; sawine@2: sawine@2: var a4 = this.m41; sawine@2: var b4 = this.m42; sawine@2: var c4 = this.m43; sawine@2: var d4 = this.m44; sawine@2: sawine@2: // Row column labeling reversed since we transpose rows & columns sawine@2: this.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); sawine@2: this.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); sawine@2: this.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); sawine@2: this.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); sawine@2: sawine@2: this.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); sawine@2: this.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); sawine@2: this.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); sawine@2: this.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); sawine@2: sawine@2: this.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); sawine@2: this.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); sawine@2: this.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); sawine@2: this.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); sawine@2: sawine@2: this.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); sawine@2: this.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); sawine@2: this.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); sawine@2: this.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); sawine@2: }