Mercurial > hg > Members > e085711
view webGL/dandy/resources/CanvasMatrix.js @ 3:10344afb38a6
upload dandy
author | NOBUYASU Oshiro |
---|---|
date | Mon, 07 Jun 2010 17:58:31 +0900 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* CanvasMatrix4 class This class implements a 4x4 matrix. It has functions which duplicate the functionality of the OpenGL matrix stack and glut functions. IDL: [ Constructor(in CanvasMatrix4 matrix), // copy passed matrix into new CanvasMatrix4 Constructor(in sequence<float> array) // create new CanvasMatrix4 with 16 floats (row major) Constructor() // create new CanvasMatrix4 with identity matrix ] interface CanvasMatrix4 { attribute float m11; attribute float m12; attribute float m13; attribute float m14; attribute float m21; attribute float m22; attribute float m23; attribute float m24; attribute float m31; attribute float m32; attribute float m33; attribute float m34; attribute float m41; attribute float m42; attribute float m43; attribute float m44; void load(in CanvasMatrix4 matrix); // copy the values from the passed matrix void load(in sequence<float> array); // copy 16 floats into the matrix sequence<float> getAsArray(); // return the matrix as an array of 16 floats WebGLFloatArray getAsCanvasFloatArray(); // return the matrix as a WebGLFloatArray with 16 values void makeIdentity(); // replace the matrix with identity void transpose(); // replace the matrix with its transpose void invert(); // replace the matrix with its inverse void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right void rotate(in float angle, // multiply the matrix by passed rotation values on the right in float x, in float y, in float z); // (angle is in degrees) void multRight(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right void multLeft(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the left void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right in float bottom, in float top, in float near, in float far); void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right in float bottom, in float top, in float near, in float far); void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right in float zNear, in float zFar); void lookat(in float eyex, in float eyey, in float eyez, // multiply the matrix by the passed lookat in float ctrx, in float ctry, in float ctrz, // values on the right in float upx, in float upy, in float upz); } */ CanvasMatrix4 = function(m) { if (typeof m == 'object') { if ("length" in m && m.length >= 16) { 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]); return; } else if (m instanceof CanvasMatrix4) { this.load(m); return; } } this.makeIdentity(); } CanvasMatrix4.prototype.load = function() { if (arguments.length == 1 && typeof arguments[0] == 'object') { var matrix = arguments[0]; if ("length" in matrix && matrix.length == 16) { this.m11 = matrix[0]; this.m12 = matrix[1]; this.m13 = matrix[2]; this.m14 = matrix[3]; this.m21 = matrix[4]; this.m22 = matrix[5]; this.m23 = matrix[6]; this.m24 = matrix[7]; this.m31 = matrix[8]; this.m32 = matrix[9]; this.m33 = matrix[10]; this.m34 = matrix[11]; this.m41 = matrix[12]; this.m42 = matrix[13]; this.m43 = matrix[14]; this.m44 = matrix[15]; return; } if (arguments[0] instanceof CanvasMatrix4) { this.m11 = matrix.m11; this.m12 = matrix.m12; this.m13 = matrix.m13; this.m14 = matrix.m14; this.m21 = matrix.m21; this.m22 = matrix.m22; this.m23 = matrix.m23; this.m24 = matrix.m24; this.m31 = matrix.m31; this.m32 = matrix.m32; this.m33 = matrix.m33; this.m34 = matrix.m34; this.m41 = matrix.m41; this.m42 = matrix.m42; this.m43 = matrix.m43; this.m44 = matrix.m44; return; } } this.makeIdentity(); } CanvasMatrix4.prototype.getAsArray = function() { return [ this.m11, this.m12, this.m13, this.m14, this.m21, this.m22, this.m23, this.m24, this.m31, this.m32, this.m33, this.m34, this.m41, this.m42, this.m43, this.m44 ]; } CanvasMatrix4.prototype.getAsWebGLFloatArray = function() { return new WebGLFloatArray(this.getAsArray()); } CanvasMatrix4.prototype.makeIdentity = function() { this.m11 = 1; this.m12 = 0; this.m13 = 0; this.m14 = 0; this.m21 = 0; this.m22 = 1; this.m23 = 0; this.m24 = 0; this.m31 = 0; this.m32 = 0; this.m33 = 1; this.m34 = 0; this.m41 = 0; this.m42 = 0; this.m43 = 0; this.m44 = 1; } CanvasMatrix4.prototype.transpose = function() { var tmp = this.m12; this.m12 = this.m21; this.m21 = tmp; tmp = this.m13; this.m13 = this.m31; this.m31 = tmp; tmp = this.m14; this.m14 = this.m41; this.m41 = tmp; tmp = this.m23; this.m23 = this.m32; this.m32 = tmp; tmp = this.m24; this.m24 = this.m42; this.m42 = tmp; tmp = this.m34; this.m34 = this.m43; this.m43 = tmp; } CanvasMatrix4.prototype.invert = function() { // Calculate the 4x4 determinant // If the determinant is zero, // then the inverse matrix is not unique. var det = this._determinant4x4(); if (Math.abs(det) < 1e-8) return null; this._makeAdjoint(); // Scale the adjoint matrix to get the inverse this.m11 /= det; this.m12 /= det; this.m13 /= det; this.m14 /= det; this.m21 /= det; this.m22 /= det; this.m23 /= det; this.m24 /= det; this.m31 /= det; this.m32 /= det; this.m33 /= det; this.m34 /= det; this.m41 /= det; this.m42 /= det; this.m43 /= det; this.m44 /= det; } CanvasMatrix4.prototype.translate = function(x,y,z) { if (x == undefined) x = 0; if (y == undefined) y = 0; if (z == undefined) z = 0; var matrix = new CanvasMatrix4(); matrix.m41 = x; matrix.m42 = y; matrix.m43 = z; this.multRight(matrix); } CanvasMatrix4.prototype.scale = function(x,y,z) { if (x == undefined) x = 1; if (z == undefined) { if (y == undefined) { y = x; z = x; } else z = 1; } else if (y == undefined) y = x; var matrix = new CanvasMatrix4(); matrix.m11 = x; matrix.m22 = y; matrix.m33 = z; this.multRight(matrix); } CanvasMatrix4.prototype.rotate = function(angle,x,y,z) { // angles are in degrees. Switch to radians angle = angle / 180 * Math.PI; angle /= 2; var sinA = Math.sin(angle); var cosA = Math.cos(angle); var sinA2 = sinA * sinA; // normalize var length = Math.sqrt(x * x + y * y + z * z); if (length == 0) { // bad vector, just use something reasonable x = 0; y = 0; z = 1; } else if (length != 1) { x /= length; y /= length; z /= length; } var mat = new CanvasMatrix4(); // optimize case where axis is along major axis if (x == 1 && y == 0 && z == 0) { mat.m11 = 1; mat.m12 = 0; mat.m13 = 0; mat.m21 = 0; mat.m22 = 1 - 2 * sinA2; mat.m23 = 2 * sinA * cosA; mat.m31 = 0; mat.m32 = -2 * sinA * cosA; mat.m33 = 1 - 2 * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else if (x == 0 && y == 1 && z == 0) { mat.m11 = 1 - 2 * sinA2; mat.m12 = 0; mat.m13 = -2 * sinA * cosA; mat.m21 = 0; mat.m22 = 1; mat.m23 = 0; mat.m31 = 2 * sinA * cosA; mat.m32 = 0; mat.m33 = 1 - 2 * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else if (x == 0 && y == 0 && z == 1) { mat.m11 = 1 - 2 * sinA2; mat.m12 = 2 * sinA * cosA; mat.m13 = 0; mat.m21 = -2 * sinA * cosA; mat.m22 = 1 - 2 * sinA2; mat.m23 = 0; mat.m31 = 0; mat.m32 = 0; mat.m33 = 1; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else { var x2 = x*x; var y2 = y*y; var z2 = z*z; mat.m11 = 1 - 2 * (y2 + z2) * sinA2; mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA); mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA); mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA); mat.m22 = 1 - 2 * (z2 + x2) * sinA2; mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA); mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA); mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA); mat.m33 = 1 - 2 * (x2 + y2) * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } this.multRight(mat); } CanvasMatrix4.prototype.multRight = function(mat) { var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21 + this.m13 * mat.m31 + this.m14 * mat.m41); var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22 + this.m13 * mat.m32 + this.m14 * mat.m42); var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23 + this.m13 * mat.m33 + this.m14 * mat.m43); var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24 + this.m13 * mat.m34 + this.m14 * mat.m44); var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21 + this.m23 * mat.m31 + this.m24 * mat.m41); var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22 + this.m23 * mat.m32 + this.m24 * mat.m42); var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23 + this.m23 * mat.m33 + this.m24 * mat.m43); var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24 + this.m23 * mat.m34 + this.m24 * mat.m44); var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21 + this.m33 * mat.m31 + this.m34 * mat.m41); var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22 + this.m33 * mat.m32 + this.m34 * mat.m42); var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23 + this.m33 * mat.m33 + this.m34 * mat.m43); var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24 + this.m33 * mat.m34 + this.m34 * mat.m44); var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21 + this.m43 * mat.m31 + this.m44 * mat.m41); var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22 + this.m43 * mat.m32 + this.m44 * mat.m42); var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23 + this.m43 * mat.m33 + this.m44 * mat.m43); var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24 + this.m43 * mat.m34 + this.m44 * mat.m44); this.m11 = m11; this.m12 = m12; this.m13 = m13; this.m14 = m14; this.m21 = m21; this.m22 = m22; this.m23 = m23; this.m24 = m24; this.m31 = m31; this.m32 = m32; this.m33 = m33; this.m34 = m34; this.m41 = m41; this.m42 = m42; this.m43 = m43; this.m44 = m44; } CanvasMatrix4.prototype.multLeft = function(mat) { var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21 + mat.m13 * this.m31 + mat.m14 * this.m41); var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22 + mat.m13 * this.m32 + mat.m14 * this.m42); var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23 + mat.m13 * this.m33 + mat.m14 * this.m43); var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24 + mat.m13 * this.m34 + mat.m14 * this.m44); var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21 + mat.m23 * this.m31 + mat.m24 * this.m41); var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22 + mat.m23 * this.m32 + mat.m24 * this.m42); var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23 + mat.m23 * this.m33 + mat.m24 * this.m43); var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24 + mat.m23 * this.m34 + mat.m24 * this.m44); var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21 + mat.m33 * this.m31 + mat.m34 * this.m41); var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22 + mat.m33 * this.m32 + mat.m34 * this.m42); var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23 + mat.m33 * this.m33 + mat.m34 * this.m43); var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24 + mat.m33 * this.m34 + mat.m34 * this.m44); var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21 + mat.m43 * this.m31 + mat.m44 * this.m41); var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22 + mat.m43 * this.m32 + mat.m44 * this.m42); var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23 + mat.m43 * this.m33 + mat.m44 * this.m43); var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24 + mat.m43 * this.m34 + mat.m44 * this.m44); this.m11 = m11; this.m12 = m12; this.m13 = m13; this.m14 = m14; this.m21 = m21; this.m22 = m22; this.m23 = m23; this.m24 = m24; this.m31 = m31; this.m32 = m32; this.m33 = m33; this.m34 = m34; this.m41 = m41; this.m42 = m42; this.m43 = m43; this.m44 = m44; } CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far) { var tx = (left + right) / (left - right); var ty = (top + bottom) / (top - bottom); var tz = (far + near) / (far - near); var matrix = new CanvasMatrix4(); matrix.m11 = 2 / (left - right); matrix.m12 = 0; matrix.m13 = 0; matrix.m14 = 0; matrix.m21 = 0; matrix.m22 = 2 / (top - bottom); matrix.m23 = 0; matrix.m24 = 0; matrix.m31 = 0; matrix.m32 = 0; matrix.m33 = -2 / (far - near); matrix.m34 = 0; matrix.m41 = tx; matrix.m42 = ty; matrix.m43 = tz; matrix.m44 = 1; this.multRight(matrix); } CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far) { var matrix = new CanvasMatrix4(); var A = (right + left) / (right - left); var B = (top + bottom) / (top - bottom); var C = -(far + near) / (far - near); var D = -(2 * far * near) / (far - near); matrix.m11 = (2 * near) / (right - left); matrix.m12 = 0; matrix.m13 = 0; matrix.m14 = 0; matrix.m21 = 0; matrix.m22 = 2 * near / (top - bottom); matrix.m23 = 0; matrix.m24 = 0; matrix.m31 = A; matrix.m32 = B; matrix.m33 = C; matrix.m34 = -1; matrix.m41 = 0; matrix.m42 = 0; matrix.m43 = D; matrix.m44 = 0; this.multRight(matrix); } CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar) { var top = Math.tan(fovy * Math.PI / 360) * zNear; var bottom = -top; var left = aspect * bottom; var right = aspect * top; this.frustum(left, right, bottom, top, zNear, zFar); } CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz) { var matrix = new CanvasMatrix4(); // Make rotation matrix // Z vector var zx = eyex - centerx; var zy = eyey - centery; var zz = eyez - centerz; var mag = Math.sqrt(zx * zx + zy * zy + zz * zz); if (mag) { zx /= mag; zy /= mag; zz /= mag; } // Y vector var yx = upx; var yy = upy; var yz = upz; // X vector = Y cross Z xx = yy * zz - yz * zy; xy = -yx * zz + yz * zx; xz = yx * zy - yy * zx; // Recompute Y = Z cross X yx = zy * xz - zz * xy; yy = -zx * xz + zz * xx; yx = zx * xy - zy * xx; // cross product gives area of parallelogram, which is < 1.0 for // non-perpendicular unit-length vectors; so normalize x, y here mag = Math.sqrt(xx * xx + xy * xy + xz * xz); if (mag) { xx /= mag; xy /= mag; xz /= mag; } mag = Math.sqrt(yx * yx + yy * yy + yz * yz); if (mag) { yx /= mag; yy /= mag; yz /= mag; } matrix.m11 = xx; matrix.m12 = xy; matrix.m13 = xz; matrix.m14 = 0; matrix.m21 = yx; matrix.m22 = yy; matrix.m23 = yz; matrix.m24 = 0; matrix.m31 = zx; matrix.m32 = zy; matrix.m33 = zz; matrix.m34 = 0; matrix.m41 = 0; matrix.m42 = 0; matrix.m43 = 0; matrix.m44 = 1; matrix.translate(-eyex, -eyey, -eyez); this.multRight(matrix); } // Support functions CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d) { return a * d - b * c; } CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3) { return a1 * this._determinant2x2(b2, b3, c2, c3) - b1 * this._determinant2x2(a2, a3, c2, c3) + c1 * this._determinant2x2(a2, a3, b2, b3); } CanvasMatrix4.prototype._determinant4x4 = function() { var a1 = this.m11; var b1 = this.m12; var c1 = this.m13; var d1 = this.m14; var a2 = this.m21; var b2 = this.m22; var c2 = this.m23; var d2 = this.m24; var a3 = this.m31; var b3 = this.m32; var c3 = this.m33; var d3 = this.m34; var a4 = this.m41; var b4 = this.m42; var c4 = this.m43; var d4 = this.m44; return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); } CanvasMatrix4.prototype._makeAdjoint = function() { var a1 = this.m11; var b1 = this.m12; var c1 = this.m13; var d1 = this.m14; var a2 = this.m21; var b2 = this.m22; var c2 = this.m23; var d2 = this.m24; var a3 = this.m31; var b3 = this.m32; var c3 = this.m33; var d3 = this.m34; var a4 = this.m41; var b4 = this.m42; var c4 = this.m43; var d4 = this.m44; // Row column labeling reversed since we transpose rows & columns this.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); this.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); this.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); this.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); this.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); this.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); this.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); this.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); this.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); this.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); this.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); this.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); this.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); this.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); this.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); this.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); }