function Matrix() { this.m = new Array(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); } function degreesToRadians(degrees) { return degrees * Math.PI / 180.0; } function radiansToDegrees(radians) { return radians * 180.0 / Math.PI; } Matrix.prototype.loadIdentity = function() { this.m[0] = 1.0; this.m[1] = 0.0; this.m[2] = 0.0; this.m[3] = 0.0; this.m[4] = 0.0; this.m[5] = 1.0; this.m[6] = 0.0; this.m[7] = 0.0; this.m[8] = 0.0; this.m[9] = 0.0; this.m[10] = 1.0; this.m[11] = 0.0; this.m[12] = 0.0; this.m[13] = 0.0; this.m[14] = 0.0; this.m[15] = 1.0; } Matrix.prototype.copy = function() { return Matrix.withValues(this.m[0], this.m[4], this.m[8], this.m[12], this.m[1], this.m[5], this.m[9], this.m[13], this.m[2], this.m[6], this.m[10], this.m[14], this.m[3], this.m[7], this.m[11], this.m[15]); } Matrix.withValues = function(m0, m4, m8, m12, m1, m5, m9, m13, m2, m6, m10, m14, m3, m7, m11, m15) { var matrix = new Matrix(); matrix.m[0] = m0; matrix.m[1] = m1; matrix.m[2] = m2; matrix.m[3] = m3; matrix.m[4] = m4; matrix.m[5] = m5; matrix.m[6] = m6; matrix.m[7] = m7; matrix.m[8] = m8; matrix.m[9] = m9; matrix.m[10] = m10; matrix.m[11] = m11; matrix.m[12] = m12; matrix.m[13] = m13; matrix.m[14] = m14; matrix.m[15] = m15; return matrix; } Matrix.fromDirectionVectors = function(right, up, front) { var matrix = new Matrix(); matrix.loadIdentity(); matrix.m[0] = right.x; matrix.m[1] = right.y; matrix.m[2] = right.z; matrix.m[4] = up.x; matrix.m[5] = up.y; matrix.m[6] = up.z; matrix.m[8] = front.x; matrix.m[9] = front.y; matrix.m[10] = front.z; return matrix; } Matrix.prototype.multiply = function(matrix) { var result = new Array(); result[0] = this.m[0] * matrix.m[0] + this.m[4] * matrix.m[1] + this.m[8] * matrix.m[2] + this.m[12] * matrix.m[3]; result[1] = this.m[1] * matrix.m[0] + this.m[5] * matrix.m[1] + this.m[9] * matrix.m[2] + this.m[13] * matrix.m[3]; result[2] = this.m[2] * matrix.m[0] + this.m[6] * matrix.m[1] + this.m[10] * matrix.m[2] + this.m[14] * matrix.m[3]; result[3] = this.m[3] * matrix.m[0] + this.m[7] * matrix.m[1] + this.m[11] * matrix.m[2] + this.m[15] * matrix.m[3]; result[4] = this.m[0] * matrix.m[4] + this.m[4] * matrix.m[5] + this.m[8] * matrix.m[6] + this.m[12] * matrix.m[7]; result[5] = this.m[1] * matrix.m[4] + this.m[5] * matrix.m[5] + this.m[9] * matrix.m[6] + this.m[13] * matrix.m[7]; result[6] = this.m[2] * matrix.m[4] + this.m[6] * matrix.m[5] + this.m[10] * matrix.m[6] + this.m[14] * matrix.m[7]; result[7] = this.m[3] * matrix.m[4] + this.m[7] * matrix.m[5] + this.m[11] * matrix.m[6] + this.m[15] * matrix.m[7]; result[8] = this.m[0] * matrix.m[8] + this.m[4] * matrix.m[9] + this.m[8] * matrix.m[10] + this.m[12] * matrix.m[11]; result[9] = this.m[1] * matrix.m[8] + this.m[5] * matrix.m[9] + this.m[9] * matrix.m[10] + this.m[13] * matrix.m[11]; result[10] = this.m[2] * matrix.m[8] + this.m[6] * matrix.m[9] + this.m[10] * matrix.m[10] + this.m[14] * matrix.m[11]; result[11] = this.m[3] * matrix.m[8] + this.m[7] * matrix.m[9] + this.m[11] * matrix.m[10] + this.m[15] * matrix.m[11]; result[12] = this.m[0] * matrix.m[12] + this.m[4] * matrix.m[13] + this.m[8] * matrix.m[14] + this.m[12] * matrix.m[15]; result[13] = this.m[1] * matrix.m[12] + this.m[5] * matrix.m[13] + this.m[9] * matrix.m[14] + this.m[13] * matrix.m[15]; result[14] = this.m[2] * matrix.m[12] + this.m[6] * matrix.m[13] + this.m[10] * matrix.m[14] + this.m[14] * matrix.m[15]; result[15] = this.m[3] * matrix.m[12] + this.m[7] * matrix.m[13] + this.m[11] * matrix.m[14] + this.m[15] * matrix.m[15]; this.m = result; } Matrix.prototype.multiplied = function(matrix) { var result = this.copy(); result.multiply(matrix); return result; } Matrix.prototype.translate = function(x, y, z) { var translationMatrix = new Matrix(); translationMatrix.loadIdentity(); translationMatrix.m[12] = x; translationMatrix.m[13] = y; translationMatrix.m[14] = z; this.multiply(translationMatrix); } Matrix.prototype.translated = function(x, y, z) { var result = this.copy(); result.translate(x, y, z); return result; } Matrix.prototype.scale = function(x, y, z) { var scalingMatrix = new Matrix(); scalingMatrix.loadIdentity(); scalingMatrix.m[0] = x; scalingMatrix.m[5] = y; scalingMatrix.m[10] = z; this.multiply(scalingMatrix); } Matrix.prototype.scaled = function(x, y, z) { var result = this.copy(); result.scale(x, y, z); return result; } Matrix.prototype.rotate = function(axis, angle) { var rotationMatrix = new Matrix(); var quaternion; quaternion = Quaternion.fromAxisAngle(axis, angle); rotationMatrix = quaternion.toMatrix(); this.multiply(rotationMatrix); } Matrix.prototype.rotated = function(axis, angle) { var result = this.copy(); result.rotate(axis, angle); return result; } Matrix.prototype.shearX = function(y, z) { var shearingMatrix = new Matrix(); shearingMatrix.loadIdentity(); shearingMatrix.m[1] = y; shearingMatrix.m[2] = z; this.multiply(shearingMatrix); } Matrix.prototype.shearedX = function(y, z) { var result = this.copy(); result.shearX(y, z); return result; } Matrix.prototype.shearY = function(x, z) { var shearingMatrix = new Matrix(); shearingMatrix.loadIdentity(); shearingMatrix.m[4] = x; shearingMatrix.m[6] = z; this.multiply(shearingMatrix); } Matrix.prototype.shearedY = function(x, z) { var result = this.copy(); result.shearY(x, z); return result; } Matrix.prototype.shearZ = function(x, y) { var shearingMatrix = new Matrix(); shearingMatrix.loadIdentity(); shearingMatrix.m[8] = x; shearingMatrix.m[9] = y; this.multiply(shearingMatrix); } Matrix.prototype.shearedZ = function(x, y) { var result = this.copy(); result.shearZ(x, y); return result; } Matrix.prototype.applyPerspective = function(fovY, aspect, zNear, zFar) { var perspectiveMatrix = new Matrix(); var sine, cotangent, deltaZ; fovY = degreesToRadians(fovY) / 2.0; deltaZ = zFar - zNear; sine = Math.sin(fovY); if (deltaZ == 0.0 || sine == 0.0 || aspect == 0.0) { return; } cotangent = Math.cos(fovY) / sine; perspectiveMatrix.loadIdentity(); perspectiveMatrix.m[0] = cotangent / aspect; perspectiveMatrix.m[5] = cotangent; perspectiveMatrix.m[10] = -(zFar + zNear) / deltaZ; perspectiveMatrix.m[11] = -1.0; perspectiveMatrix.m[14] = -2.0 * zNear * zFar / deltaZ; perspectiveMatrix.m[15] = 0.0; this.multiply(perspectiveMatrix); } Matrix.prototype.perspective = function(fovY, aspect, zNear, zFar) { var result = this.copy(); result.applyPerspective(fovY, aspect, zNear, zFar); return result; } Matrix.prototype.transpose = function() { this.m = Matrix.withValues(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5], this.m[6], this.m[7], this.m[8], this.m[9], this.m[10], this.m[11], this.m[12], this.m[13], this.m[14], this.m[15]).m; } Matrix.prototype.transposed = function() { var result = this.copy(); result.transpose(); return result; } Matrix.prototype.subdeterminant = function(excludeIndex) { var index4x4, index3x3; var matrix3x3 = new Array(); index3x3 = 0; for (index4x4 = 0; index4x4 < 16; index4x4++) { if (index4x4 / 4 == excludeIndex / 4 || index4x4 % 4 == excludeIndex % 4) { continue; } matrix3x3[index3x3++] = this.m[index4x4]; } return matrix3x3[0] * (matrix3x3[4] * matrix3x3[8] - matrix3x3[5] * matrix3x3[7]) - matrix3x3[3] * (matrix3x3[1] * matrix3x3[8] - matrix3x3[2] * matrix3x3[7]) + matrix3x3[6] * (matrix3x3[1] * matrix3x3[5] - matrix3x3[2] * matrix3x3[4]); } Matrix.prototype.determinant = function() { var subdeterminant0, subdeterminant1, subdeterminant2, subdeterminant3; subdeterminant0 = this.subdeterminant(0); subdeterminant1 = this.subdeterminant(4); subdeterminant2 = this.subdeterminant(8); subdeterminant3 = this.subdeterminant(12); return this.m[0] * subdeterminant0 + this.m[4] * -subdeterminant1 + this.m[8] * subdeterminant2 + this.m[12] * -subdeterminant3; } Matrix.prototype.invert = function() { var determinant; var result = new Matrix(); var index, indexTransposed; var sign; determinant = this.determinant(); for (index = 0; index < 16; index++) { sign = 1 - (((index % 4) + (index / 4)) % 2) * 2; indexTransposed = (index % 4) * 4 + index / 4; result.m[indexTransposed] = this.subdeterminant(index) * sign / determinant; } this.m = result.concat(); } Matrix.prototype.inverted = function() { var result = this.copy(); result.invert(); return result; } Matrix.prototype.multiplyVector2 = function(vector) { var result = new Vector2(); result.x = ((this.m[0] * vector.x) + (this.m[4] * vector.y) + this.m[12]); result.y = ((this.m[1] * vector.x) + (this.m[5] * vector.y) + this.m[13]); return result; } Matrix.prototype.multiplyVector3 = function(vector) { var result = new Vector3(); result.x = ((this.m[0] * vector.x) + (this.m[4] * vector.y) + (this.m[8] * vector.z) + this.m[12]); result.y = ((this.m[1] * vector.x) + (this.m[5] * vector.y) + (this.m[9] * vector.z) + this.m[13]); result.z = ((this.m[2] * vector.x) + (this.m[6] * vector.y) + (this.m[10] * vector.z) + this.m[14]); return result; } Matrix.prototype.multiplyVector4 = function(vector) { var result = new Vector4(); result.x = ((this.m[0] * vector.x) + (this.m[4] * vector.y) + (this.m[8] * vector.z) + (this.m[12] * vector.w)); result.y = ((this.m[1] * vector.x) + (this.m[5] * vector.y) + (this.m[9] * vector.z) + (this.m[13] * vector.w)); result.z = ((this.m[2] * vector.x) + (this.m[6] * vector.y) + (this.m[10] * vector.z) + (this.m[14] * vector.w)); result.w = ((this.m[3] * vector.x) + (this.m[7] * vector.y) + (this.m[11] * vector.z) + (this.m[15] * vector.w)); return result; } Matrix.prototype.multiplyVector3_rotationOnly = function(vector) { var result = new Vector3(); result.x = (this.m[0] * vector.x) + (this.m[4] * vector.y) + (this.m[8] * vector.z); result.y = (this.m[1] * vector.x) + (this.m[5] * vector.y) + (this.m[9] * vector.z); result.z = (this.m[2] * vector.x) + (this.m[6] * vector.y) + (this.m[10] * vector.z); return result; }