UNPKG

mjs

Version:

3D matrix and vector operations

1,958 lines (1,793 loc) 44.6 kB
"use strict"; /* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ /* * Copyright (c) 2010 Mozilla Corporation * Copyright (c) 2010 Vladimir Vukicevic * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * File: mjs * * Vector and Matrix math utilities for JavaScript, optimized for WebGL. */ module.exports = MJS; function MJS(MJS_FLOAT_ARRAY_TYPE) { var mJS = {}; if(!MJS_FLOAT_ARRAY_TYPE) { if(typeof Float32Array === "undefined") { MJS_FLOAT_ARRAY_TYPE = Array; } else if(typeof WebGLFloatArray === "undefined") { MJS_FLOAT_ARRAY_TYPE = Float32Array; } else { MJS_FLOAT_ARRAY_TYPE = WebGLFloatArray; } } // Some hacks for running in both the shell and browser, // and for supporting F32 and WebGLFloat arrays // try { WebGLFloatArray; } catch (x) { WebGLFloatArray = Float32Array; } /* * Constant: MJS_FLOAT_ARRAY_TYPE * * The base float array type. By default, WebGLFloatArray. * * mjs can work with any array-like elements, but if an array * creation is requested, it will create an array of the type * MJS_FLOAT_ARRAY_TYPE. Also, the builtin constants such as (M4x4.I) * will be of this type. */ /* * Class: V2 * * Methods for working with 2-element vectors. A vector is represented by a 2-element array. * Any valid JavaScript array type may be used, but if new * vectors are created they are created using the configured MJS_FLOAT_ARRAY_TYPE. */ var V2 = { }; mJS.V2 = V2; V2._temp1 = new MJS_FLOAT_ARRAY_TYPE(2); V2._temp2 = new MJS_FLOAT_ARRAY_TYPE(2); V2._temp3 = new MJS_FLOAT_ARRAY_TYPE(2); if (MJS_FLOAT_ARRAY_TYPE == Array) { V2.x = [1.0, 0.0]; V2.y = [0.0, 1.0]; V2.$ = function V2_$(x, y) { return [x, y]; }; V2.clone = function V2_clone(a) { return [a[0], a[1]]; }; } else { V2.x = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0]); V2.y = new MJS_FLOAT_ARRAY_TYPE([0.0, 1.0]); /* * Function: V2.$ * * Creates a new 2-element vector with the given values. * * Parameters: * * x,y - the 2 elements of the new vector. * * Returns: * * A new vector containing with the given argument values. */ V2.$ = function V2_$(x, y) { return new MJS_FLOAT_ARRAY_TYPE([x, y]); }; /* * Function: V2.clone * * Clone the given 2-element vector. * * Parameters: * * a - the 2-element vector to clone * * Returns: * * A new vector with the same values as the passed-in one. */ V2.clone = function V2_clone(a) { return new MJS_FLOAT_ARRAY_TYPE(a); }; } V2.u = V2.x; V2.v = V2.y; /* * Function: V2.add * * Perform r = a + b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.add = function V2_add(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; return r; }; /* * Function: V2.sub * * Perform * r = a - b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.sub = function V2_sub(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; return r; }; /* * Function: V2.neg * * Perform * r = - a. * * Parameters: * * a - the vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.neg = function V2_neg(a, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); r[0] = - a[0]; r[1] = - a[1]; return r; }; /* * Function: V2.direction * * Perform * r = (a - b) / |a - b|. The result is the normalized * direction from a to b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.direction = function V2_direction(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); return V2.normalize(V2.sub(a, b, r), r); }; /* * Function: V2.length * * Perform r = |a|. * * Parameters: * * a - the vector operand * * Returns: * * The length of the given vector. */ V2.length = function V2_length(a) { return Math.sqrt(a[0]*a[0] + a[1]*a[1]); }; /* * Function: V2.lengthSquard * * Perform r = |a|*|a|. * * Parameters: * * a - the vector operand * * Returns: * * The square of the length of the given vector. */ V2.lengthSquared = function V2_lengthSquared(a) { return a[0]*a[0] + a[1]*a[1]; }; /* * Function: V2.normalize * * Perform r = a / |a|. * * Parameters: * * a - the vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.normalize = function V2_normalize(a, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); var im = 1.0 / V2.length(a); r[0] = a[0] * im; r[1] = a[1] * im; return r; }; /* * Function: V2.scale * * Perform r = a * k. * * Parameters: * * a - the vector operand * k - a scalar value * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 2-element vector with the result. */ V2.scale = function V2_scale(a, k, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(2); r[0] = a[0] * k; r[1] = a[1] * k; return r; }; /* * Function: V2.dot * * Perform * r = dot(a, b). * * Parameters: * * a - the first vector operand * b - the second vector operand * * Returns: * * The dot product of a and b. */ V2.dot = function V2_dot(a, b) { return a[0] * b[0] + a[1] * b[1]; }; /* * Class: V3 * * Methods for working with 3-element vectors. A vector is represented by a 3-element array. * Any valid JavaScript array type may be used, but if new * vectors are created they are created using the configured MJS_FLOAT_ARRAY_TYPE. */ var V3 = { }; mJS.V3 = V3; V3._temp1 = new MJS_FLOAT_ARRAY_TYPE(3); V3._temp2 = new MJS_FLOAT_ARRAY_TYPE(3); V3._temp3 = new MJS_FLOAT_ARRAY_TYPE(3); if (MJS_FLOAT_ARRAY_TYPE == Array) { V3.x = [1.0, 0.0, 0.0]; V3.y = [0.0, 1.0, 0.0]; V3.z = [0.0, 0.0, 1.0]; V3.$ = function V3_$(x, y, z) { return [x, y, z]; }; V3.clone = function V3_clone(a) { return [a[0], a[1], a[2]]; }; } else { V3.x = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0, 0.0]); V3.y = new MJS_FLOAT_ARRAY_TYPE([0.0, 1.0, 0.0]); V3.z = new MJS_FLOAT_ARRAY_TYPE([0.0, 0.0, 1.0]); /* * Function: V3.$ * * Creates a new 3-element vector with the given values. * * Parameters: * * x,y,z - the 3 elements of the new vector. * * Returns: * * A new vector containing with the given argument values. */ V3.$ = function V3_$(x, y, z) { return new MJS_FLOAT_ARRAY_TYPE([x, y, z]); }; /* * Function: V3.clone * * Clone the given 3-element vector. * * Parameters: * * a - the 3-element vector to clone * * Returns: * * A new vector with the same values as the passed-in one. */ V3.clone = function V3_clone(a) { return new MJS_FLOAT_ARRAY_TYPE(a); }; } V3.u = V3.x; V3.v = V3.y; /* * Function: V3.add * * Perform r = a + b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.add = function V3_add(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; return r; }; /* * Function: V3.sub * * Perform * r = a - b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.sub = function V3_sub(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; r[2] = a[2] - b[2]; return r; }; /* * Function: V3.neg * * Perform * r = - a. * * Parameters: * * a - the vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.neg = function V3_neg(a, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); r[0] = - a[0]; r[1] = - a[1]; r[2] = - a[2]; return r; }; /* * Function: V3.direction * * Perform * r = (a - b) / |a - b|. The result is the normalized * direction from a to b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.direction = function V3_direction(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); return V3.normalize(V3.sub(a, b, r), r); }; /* * Function: V3.length * * Perform r = |a|. * * Parameters: * * a - the vector operand * * Returns: * * The length of the given vector. */ V3.length = function V3_length(a) { return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); }; /* * Function: V3.lengthSquard * * Perform r = |a|*|a|. * * Parameters: * * a - the vector operand * * Returns: * * The square of the length of the given vector. */ V3.lengthSquared = function V3_lengthSquared(a) { return a[0]*a[0] + a[1]*a[1] + a[2]*a[2]; }; /* * Function: V3.normalize * * Perform r = a / |a|. * * Parameters: * * a - the vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.normalize = function V3_normalize(a, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); var im = 1.0 / V3.length(a); r[0] = a[0] * im; r[1] = a[1] * im; r[2] = a[2] * im; return r; }; /* * Function: V3.scale * * Perform r = a * k. * * Parameters: * * a - the vector operand * k - a scalar value * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.scale = function V3_scale(a, k, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); r[0] = a[0] * k; r[1] = a[1] * k; r[2] = a[2] * k; return r; }; /* * Function: V3.dot * * Perform * r = dot(a, b). * * Parameters: * * a - the first vector operand * b - the second vector operand * * Returns: * * The dot product of a and b. */ V3.dot = function V3_dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; }; /* * Function: V3.cross * * Perform r = a x b. * * Parameters: * * a - the first vector operand * b - the second vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. */ V3.cross = function V3_cross(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); r[0] = a[1]*b[2] - a[2]*b[1]; r[1] = a[2]*b[0] - a[0]*b[2]; r[2] = a[0]*b[1] - a[1]*b[0]; return r; }; /* * Function: V3.mul4x4 * * Perform * r = m * v. * * Parameters: * * m - the 4x4 matrix operand * v - the 3-element vector operand * r - optional vector to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3-element vector with the result. * The 4-element result vector is divided by the w component * and returned as a 3-element vector. */ V3.mul4x4 = function V3_mul4x4(m, v, r) { var w; var tmp = V3._temp1; if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); tmp[0] = m[ 3]; tmp[1] = m[ 7]; tmp[2] = m[11]; w = V3.dot(v, tmp) + m[15]; tmp[0] = m[ 0]; tmp[1] = m[ 4]; tmp[2] = m[ 8]; r[0] = (V3.dot(v, tmp) + m[12])/w; tmp[0] = m[ 1]; tmp[1] = m[ 5]; tmp[2] = m[ 9]; r[1] = (V3.dot(v, tmp) + m[13])/w; tmp[0] = m[ 2]; tmp[1] = m[ 6]; tmp[2] = m[10]; r[2] = (V3.dot(v, tmp) + m[14])/w; return r; }; /* * Class: M4x4 * * Methods for working with 4x4 matrices. A matrix is represented by a 16-element array * in column-major order. Any valid JavaScript array type may be used, but if new * matrices are created they are created using the configured MJS_FLOAT_ARRAY_TYPE. */ var M4x4 = { }; mJS.M4x4 = M4x4; M4x4._temp1 = new MJS_FLOAT_ARRAY_TYPE(16); M4x4._temp2 = new MJS_FLOAT_ARRAY_TYPE(16); if (MJS_FLOAT_ARRAY_TYPE == Array) { M4x4.I = [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]; M4x4.$ = function M4x4_$(m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15) { return [m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15]; }; M4x4.clone = function M4x4_clone(m) { return [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]]; }; } else { M4x4.I = new MJS_FLOAT_ARRAY_TYPE([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: M4x4.$ * * Creates a new 4x4 matrix with the given values. * * Parameters: * * m00..m15 - the 16 elements of the new matrix. * * Returns: * * A new matrix filled with the given argument values. */ M4x4.$ = function M4x4_$(m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15) { return new MJS_FLOAT_ARRAY_TYPE([m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15]); }; /* * Function: M4x4.clone * * Clone the given 4x4 matrix. * * Parameters: * * m - the 4x4 matrix to clone * * Returns: * * A new matrix with the same values as the passed-in one. */ M4x4.clone = function M4x4_clone(m) { return new MJS_FLOAT_ARRAY_TYPE(m); }; } M4x4.identity = M4x4.I; /* * Function: M4x4.topLeft3x3 * * Return the top left 3x3 matrix from the given 4x4 matrix m. * * Parameters: * * m - the matrix * r - optional 3x3 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3x3 matrix with the result. */ M4x4.topLeft3x3 = function M4x4_topLeft3x3(m, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(9); r[0] = m[0]; r[1] = m[1]; r[2] = m[2]; r[3] = m[4]; r[4] = m[5]; r[5] = m[6]; r[6] = m[8]; r[7] = m[9]; r[8] = m[10]; return r; }; /* * Function: M4x4.inverseOrthonormal * * Computes the inverse of the given matrix m, assuming that * the matrix is orthonormal. * * Parameters: * * m - the matrix * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.inverseOrthonormal = function M4x4_inverseOrthonormal(m, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); M4x4.transpose(m, r); var t = [m[12], m[13], m[14]]; r[3] = r[7] = r[11] = 0; r[12] = -V3.dot([r[0], r[4], r[8]], t); r[13] = -V3.dot([r[1], r[5], r[9]], t); r[14] = -V3.dot([r[2], r[6], r[10]], t); return r; }; /* * Function: M4x4.inverseTo3x3 * * Computes the inverse of the given matrix m, but calculates * only the top left 3x3 values of the result. * * Parameters: * * m - the matrix * r - optional 3x3 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 3x3 matrix with the result. */ M4x4.inverseTo3x3 = function M4x4_inverseTo3x3(m, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(9); var a11 = m[10]*m[5]-m[6]*m[9], a21 = -m[10]*m[1]+m[2]*m[9], a31 = m[6]*m[1]-m[2]*m[5], a12 = -m[10]*m[4]+m[6]*m[8], a22 = m[10]*m[0]-m[2]*m[8], a32 = -m[6]*m[0]+m[2]*m[4], a13 = m[9]*m[4]-m[5]*m[8], a23 = -m[9]*m[0]+m[1]*m[8], a33 = m[5]*m[0]-m[1]*m[4]; var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13); if (det == 0) // no inverse throw "matrix not invertible"; var idet = 1.0 / det; r[0] = idet*a11; r[1] = idet*a21; r[2] = idet*a31; r[3] = idet*a12; r[4] = idet*a22; r[5] = idet*a32; r[6] = idet*a13; r[7] = idet*a23; r[8] = idet*a33; return r; }; /* * Function: M4x4.makeFrustum * * Creates a matrix for a projection frustum with the given parameters. * * Parameters: * * left - the left coordinate of the frustum * right- the right coordinate of the frustum * bottom - the bottom coordinate of the frustum * top - the top coordinate of the frustum * znear - the near z distance of the frustum * zfar - the far z distance of the frustum * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the projection matrix. * Otherwise, returns a new 4x4 matrix. */ M4x4.makeFrustum = function M4x4_makeFrustum(left, right, bottom, top, znear, zfar, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var X = 2*znear/(right-left); var Y = 2*znear/(top-bottom); var A = (right+left)/(right-left); var B = (top+bottom)/(top-bottom); var C = -(zfar+znear)/(zfar-znear); var D = -2*zfar*znear/(zfar-znear); r[0] = 2*znear/(right-left); r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = 2*znear/(top-bottom); r[6] = 0; r[7] = 0; r[8] = (right+left)/(right-left); r[9] = (top+bottom)/(top-bottom); r[10] = -(zfar+znear)/(zfar-znear); r[11] = -1; r[12] = 0; r[13] = 0; r[14] = -2*zfar*znear/(zfar-znear); r[15] = 0; return r; }; /* * Function: M4x4.makePerspective * * Creates a matrix for a perspective projection with the given parameters. * * Parameters: * * fovy - field of view in the y axis, in degrees * aspect - aspect ratio * znear - the near z distance of the projection * zfar - the far z distance of the projection * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the projection matrix. * Otherwise, returns a new 4x4 matrix. */ M4x4.makePerspective = function M4x4_makePerspective (fovy, aspect, znear, zfar, r) { var ymax = znear * Math.tan(fovy * Math.PI / 360.0); var ymin = -ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; return M4x4.makeFrustum(xmin, xmax, ymin, ymax, znear, zfar, r); }; /* * Function: M4x4.makeOrtho * * Creates a matrix for an orthogonal frustum projection with the given parameters. * * Parameters: * * left - the left coordinate of the frustum * right- the right coordinate of the frustum * bottom - the bottom coordinate of the frustum * top - the top coordinate of the frustum * znear - the near z distance of the frustum * zfar - the far z distance of the frustum * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the projection matrix. * Otherwise, returns a new 4x4 matrix. */ M4x4.makeOrtho = function M4x4_makeOrtho (left, right, bottom, top, znear, zfar, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var tX = -(right+left)/(right-left); var tY = -(top+bottom)/(top-bottom); var tZ = -(zfar+znear)/(zfar-znear); var X = 2 / (right-left); var Y = 2 / (top-bottom); var Z = -2 / (zfar-znear); r[0] = 2 / (right-left); r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = 2 / (top-bottom); r[6] = 0; r[7] = 0; r[8] = 0; r[9] = 0; r[10] = -2 / (zfar-znear); r[11] = 0; r[12] = -(right+left)/(right-left); r[13] = -(top+bottom)/(top-bottom); r[14] = -(zfar+znear)/(zfar-znear); r[15] = 1; return r; }; /* * Function: M4x4.makeOrtho * * Creates a matrix for a 2D orthogonal frustum projection with the given parameters. * znear and zfar are assumed to be -1 and 1, respectively. * * Parameters: * * left - the left coordinate of the frustum * right- the right coordinate of the frustum * bottom - the bottom coordinate of the frustum * top - the top coordinate of the frustum * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the projection matrix. * Otherwise, returns a new 4x4 matrix. */ M4x4.makeOrtho2D = function M4x4_makeOrtho2D (left, right, bottom, top, r) { return M4x4.makeOrtho(left, right, bottom, top, -1, 1, r); }; /* * Function: M4x4.mul * * Performs r = a * b. * * Parameters: * * a - the first matrix operand * b - the second matrix operand * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.mul = function M4x4_mul(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var a11 = a[0]; var a21 = a[1]; var a31 = a[2]; var a41 = a[3]; var a12 = a[4]; var a22 = a[5]; var a32 = a[6]; var a42 = a[7]; var a13 = a[8]; var a23 = a[9]; var a33 = a[10]; var a43 = a[11]; var a14 = a[12]; var a24 = a[13]; var a34 = a[14]; var a44 = a[15]; var b11 = b[0]; var b21 = b[1]; var b31 = b[2]; var b41 = b[3]; var b12 = b[4]; var b22 = b[5]; var b32 = b[6]; var b42 = b[7]; var b13 = b[8]; var b23 = b[9]; var b33 = b[10]; var b43 = b[11]; var b14 = b[12]; var b24 = b[13]; var b34 = b[14]; var b44 = b[15]; r[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; r[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; r[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; r[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; r[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; r[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; r[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; r[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; r[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; r[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; r[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; r[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; r[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return r; }; /* * Function: M4x4.mulOffset * * Performs r' = a * b, where r' is the 16 elements of r starting at element o. * * Parameters: * * a - the first matrix operand * b - the second matrix operand * r - array to store the result in * o - offset into r at which to start storing results * * Returns: * * r */ M4x4.mulOffset = function M4x4_mulOffset(a, b, r, o) { var a21 = a[1]; var a31 = a[2]; var a41 = a[3]; var a12 = a[4]; var a22 = a[5]; var a32 = a[6]; var a42 = a[7]; var a13 = a[8]; var a23 = a[9]; var a33 = a[10]; var a43 = a[11]; var a14 = a[12]; var a24 = a[13]; var a34 = a[14]; var a44 = a[15]; var b11 = b[0]; var b21 = b[1]; var b31 = b[2]; var b41 = b[3]; var b12 = b[4]; var b22 = b[5]; var b32 = b[6]; var b42 = b[7]; var b13 = b[8]; var b23 = b[9]; var b33 = b[10]; var b43 = b[11]; var b14 = b[12]; var b24 = b[13]; var b34 = b[14]; var b44 = b[15]; r[o+0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; r[o+1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; r[o+2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; r[o+3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; r[o+4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; r[o+5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; r[o+6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; r[o+7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; r[o+8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; r[o+9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; r[o+10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; r[o+11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; r[o+12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; r[o+13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; r[o+14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; r[o+15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return r; }; /* * Function: M4x4.mulAffine * * Performs r = a * b, assuming a and b are affine (elements 3,7,11,15 = 0,0,0,1) * * Parameters: * * a - the first matrix operand * b - the second matrix operand * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.mulAffine = function M4x4_mulAffine(a, b, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var a11 = a[0]; var a21 = a[1]; var a31 = a[2]; var a12 = a[4]; var a22 = a[5]; var a32 = a[6]; var a13 = a[8]; var a23 = a[9]; var a33 = a[10]; var a14 = a[12]; var a24 = a[13]; var a34 = a[14]; var b11 = b[0]; var b21 = b[1]; var b31 = b[2]; var b12 = b[4]; var b22 = b[5]; var b32 = b[6]; var b13 = b[8]; var b23 = b[9]; var b33 = b[10]; var b14 = b[12]; var b24 = b[13]; var b34 = b[14]; r[0] = a11 * b11 + a12 * b21 + a13 * b31; r[1] = a21 * b11 + a22 * b21 + a23 * b31; r[2] = a31 * b11 + a32 * b21 + a33 * b31; r[3] = 0; r[4] = a11 * b12 + a12 * b22 + a13 * b32; r[5] = a21 * b12 + a22 * b22 + a23 * b32; r[6] = a31 * b12 + a32 * b22 + a33 * b32; r[7] = 0; r[8] = a11 * b13 + a12 * b23 + a13 * b33; r[9] = a21 * b13 + a22 * b23 + a23 * b33; r[10] = a31 * b13 + a32 * b23 + a33 * b33; r[11] = 0; r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14; r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24; r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34; r[15] = 1; return r; }; /* * Function: M4x4.mulAffineOffset * * Performs r' = a * b, assuming a and b are affine (elements 3,7,11,15 = 0,0,0,1), where r' is the 16 elements of r starting at element o * * Parameters: * * a - the first matrix operand * b - the second matrix operand * r - array to store the result in * o - offset into r at which to start storing results * * Returns: * * r */ M4x4.mulAffine = function M4x4_mulAffine(a, b, r, o) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); o = o || 0; var a11 = a[0]; var a21 = a[1]; var a31 = a[2]; var a12 = a[4]; var a22 = a[5]; var a32 = a[6]; var a13 = a[8]; var a23 = a[9]; var a33 = a[10]; var a14 = a[12]; var a24 = a[13]; var a34 = a[14]; var b11 = b[0]; var b21 = b[1]; var b31 = b[2]; var b12 = b[4]; var b22 = b[5]; var b32 = b[6]; var b13 = b[8]; var b23 = b[9]; var b33 = b[10]; var b14 = b[12]; var b24 = b[13]; var b34 = b[14]; r[o+0] = a11 * b11 + a12 * b21 + a13 * b31; r[o+1] = a21 * b11 + a22 * b21 + a23 * b31; r[o+2] = a31 * b11 + a32 * b21 + a33 * b31; r[o+3] = 0; r[o+4] = a11 * b12 + a12 * b22 + a13 * b32; r[o+5] = a21 * b12 + a22 * b22 + a23 * b32; r[o+6] = a31 * b12 + a32 * b22 + a33 * b32; r[o+7] = 0; r[o+8] = a11 * b13 + a12 * b23 + a13 * b33; r[o+9] = a21 * b13 + a22 * b23 + a23 * b33; r[o+10] = a31 * b13 + a32 * b23 + a33 * b33; r[o+11] = 0; r[o+12] = a11 * b14 + a12 * b24 + a13 * b34 + a14; r[o+13] = a21 * b14 + a22 * b24 + a23 * b34 + a24; r[o+14] = a31 * b14 + a32 * b24 + a33 * b34 + a34; r[o+15] = 1; return r; }; /* * Function: M4x4.makeRotate * * Creates a transformation matrix for rotation by angle radians about the 3-element vector axis. * * Parameters: * * angle - the angle of rotation, in radians * axis - the axis around which the rotation is performed, a 3-element vector * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the matrix. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.makeRotate = function M4x4_makeRotate(angle, axis, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); axis = V3.normalize(axis, V3._temp1); var x = axis[0], y = axis[1], z = axis[2]; var c = Math.cos(angle); var c1 = 1-c; var s = Math.sin(angle); r[0] = x*x*c1+c; r[1] = y*x*c1+z*s; r[2] = z*x*c1-y*s; r[3] = 0; r[4] = x*y*c1-z*s; r[5] = y*y*c1+c; r[6] = y*z*c1+x*s; r[7] = 0; r[8] = x*z*c1+y*s; r[9] = y*z*c1-x*s; r[10] = z*z*c1+c; r[11] = 0; r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; return r; }; /* * Function: M4x4.rotate * * Concatenates a rotation of angle radians about the axis to the give matrix m. * * Parameters: * * angle - the angle of rotation, in radians * axis - the axis around which the rotation is performed, a 3-element vector * m - the matrix to concatenate the rotation to * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after performing the operation. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.rotate = function M4x4_rotate(angle, axis, m, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var a0=axis [0], a1=axis [1], a2=axis [2]; var l = Math.sqrt(a0*a0 + a1*a1 + a2*a2); var x = a0, y = a1, z = a2; if (l != 1.0) { var im = 1.0 / l; x *= im; y *= im; z *= im; } var c = Math.cos(angle); var c1 = 1-c; var s = Math.sin(angle); var xs = x*s; var ys = y*s; var zs = z*s; var xyc1 = x * y * c1; var xzc1 = x * z * c1; var yzc1 = y * z * c1; var m11 = m[0]; var m21 = m[1]; var m31 = m[2]; var m41 = m[3]; var m12 = m[4]; var m22 = m[5]; var m32 = m[6]; var m42 = m[7]; var m13 = m[8]; var m23 = m[9]; var m33 = m[10]; var m43 = m[11]; var t11 = x * x * c1 + c; var t21 = xyc1 + zs; var t31 = xzc1 - ys; var t12 = xyc1 - zs; var t22 = y * y * c1 + c; var t32 = yzc1 + xs; var t13 = xzc1 + ys; var t23 = yzc1 - xs; var t33 = z * z * c1 + c; r[0] = m11 * t11 + m12 * t21 + m13 * t31; r[1] = m21 * t11 + m22 * t21 + m23 * t31; r[2] = m31 * t11 + m32 * t21 + m33 * t31; r[3] = m41 * t11 + m42 * t21 + m43 * t31; r[4] = m11 * t12 + m12 * t22 + m13 * t32; r[5] = m21 * t12 + m22 * t22 + m23 * t32; r[6] = m31 * t12 + m32 * t22 + m33 * t32; r[7] = m41 * t12 + m42 * t22 + m43 * t32; r[8] = m11 * t13 + m12 * t23 + m13 * t33; r[9] = m21 * t13 + m22 * t23 + m23 * t33; r[10] = m31 * t13 + m32 * t23 + m33 * t33; r[11] = m41 * t13 + m42 * t23 + m43 * t33; if (r != m) { r[12] = m[12]; r[13] = m[13]; r[14] = m[14]; r[15] = m[15]; } return r; }; /* * Function: M4x4.makeScale3 * * Creates a transformation matrix for scaling by 3 scalar values, one for * each of the x, y, and z directions. * * Parameters: * * x - the scale for the x axis * y - the scale for the y axis * z - the scale for the z axis * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the matrix. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.makeScale3 = function M4x4_makeScale3(x, y, z, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = x; r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = y; r[6] = 0; r[7] = 0; r[8] = 0; r[9] = 0; r[10] = z; r[11] = 0; r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; return r; }; /* * Function: M4x4.makeScale1 * * Creates a transformation matrix for a uniform scale by a single scalar value. * * Parameters: * * k - the scale factor * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the matrix. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.makeScale1 = function M4x4_makeScale1(k, r) { return M4x4.makeScale3(k, k, k, r); }; /* * Function: M4x4.makeScale * * Creates a transformation matrix for scaling each of the x, y, and z axes by the amount * given in the corresponding element of the 3-element vector. * * Parameters: * * v - the 3-element vector containing the scale factors * r - optional 4x4 matrix to store the result in * * Returns: * * If r is specified, returns r after creating the matrix. * Otherwise, returns a new 4x4 matrix with the result. */ M4x4.makeScale = function M4x4_makeScale(v, r) { return M4x4.makeScale3(v[0], v[1], v[2], r); }; /* * Function: M4x4.scale3 */ M4x4.scale3 = function M4x4_scale3(x, y, z, m, r) { if (r == m) { m[0] *= x; m[1] *= x; m[2] *= x; m[3] *= x; m[4] *= y; m[5] *= y; m[6] *= y; m[7] *= y; m[8] *= z; m[9] *= z; m[10] *= z; m[11] *= z; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = m[0] * x; r[1] = m[1] * x; r[2] = m[2] * x; r[3] = m[3] * x; r[4] = m[4] * y; r[5] = m[5] * y; r[6] = m[6] * y; r[7] = m[7] * y; r[8] = m[8] * z; r[9] = m[9] * z; r[10] = m[10] * z; r[11] = m[11] * z; r[12] = m[12]; r[13] = m[13]; r[14] = m[14]; r[15] = m[15]; return r; }; /* * Function: M4x4.scale1 */ M4x4.scale1 = function M4x4_scale1(k, m, r) { if (r == m) { m[0] *= k; m[1] *= k; m[2] *= k; m[3] *= k; m[4] *= k; m[5] *= k; m[6] *= k; m[7] *= k; m[8] *= k; m[9] *= k; m[10] *= k; m[11] *= k; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = m[0] * k; r[1] = m[1] * k; r[2] = m[2] * k; r[3] = m[3] * k; r[4] = m[4] * k; r[5] = m[5] * k; r[6] = m[6] * k; r[7] = m[7] * k; r[8] = m[8] * k; r[9] = m[9] * k; r[10] = m[10] * k; r[11] = m[11] * k; r[12] = m[12]; r[13] = m[13]; r[14] = m[14]; r[15] = m[15]; return r; }; /* * Function: M4x4.scale1 */ M4x4.scale = function M4x4_scale(v, m, r) { var x = v[0], y = v[1], z = v[2]; if (r == m) { m[0] *= x; m[1] *= x; m[2] *= x; m[3] *= x; m[4] *= y; m[5] *= y; m[6] *= y; m[7] *= y; m[8] *= z; m[9] *= z; m[10] *= z; m[11] *= z; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = m[0] * x; r[1] = m[1] * x; r[2] = m[2] * x; r[3] = m[3] * x; r[4] = m[4] * y; r[5] = m[5] * y; r[6] = m[6] * y; r[7] = m[7] * y; r[8] = m[8] * z; r[9] = m[9] * z; r[10] = m[10] * z; r[11] = m[11] * z; r[12] = m[12]; r[13] = m[13]; r[14] = m[14]; r[15] = m[15]; return r; }; /* * Function: M4x4.makeTranslate3 */ M4x4.makeTranslate3 = function M4x4_makeTranslate3(x, y, z, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = 1; r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = 1; r[6] = 0; r[7] = 0; r[8] = 0; r[9] = 0; r[10] = 1; r[11] = 0; r[12] = x; r[13] = y; r[14] = z; r[15] = 1; return r; }; /* * Function: M4x4.makeTranslate1 */ M4x4.makeTranslate1 = function M4x4_makeTranslate1 (k, r) { return M4x4.makeTranslate3(k, k, k, r); }; /* * Function: M4x4.makeTranslate */ M4x4.makeTranslate = function M4x4_makeTranslate (v, r) { return M4x4.makeTranslate3(v[0], v[1], v[2], r); }; /* * Function: M4x4.translate3Self */ M4x4.translate3Self = function M4x4_translate3Self (x, y, z, m) { m[12] += m[0] * x + m[4] * y + m[8] * z; m[13] += m[1] * x + m[5] * y + m[9] * z; m[14] += m[2] * x + m[6] * y + m[10] * z; m[15] += m[3] * x + m[7] * y + m[11] * z; return m; }; /* * Function: M4x4.translate3 */ M4x4.translate3 = function M4x4_translate3 (x, y, z, m, r) { if (r == m) { m[12] += m[0] * x + m[4] * y + m[8] * z; m[13] += m[1] * x + m[5] * y + m[9] * z; m[14] += m[2] * x + m[6] * y + m[10] * z; m[15] += m[3] * x + m[7] * y + m[11] * z; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var m11 = m[0]; var m21 = m[1]; var m31 = m[2]; var m41 = m[3]; var m12 = m[4]; var m22 = m[5]; var m32 = m[6]; var m42 = m[7]; var m13 = m[8]; var m23 = m[9]; var m33 = m[10]; var m43 = m[11]; r[0] = m11; r[1] = m21; r[2] = m31; r[3] = m41; r[4] = m12; r[5] = m22; r[6] = m32; r[7] = m42; r[8] = m13; r[9] = m23; r[10] = m33; r[11] = m43; r[12] = m11 * x + m12 * y + m13 * z + m[12]; r[13] = m21 * x + m22 * y + m23 * z + m[13]; r[14] = m31 * x + m32 * y + m33 * z + m[14]; r[15] = m41 * x + m42 * y + m43 * z + m[15]; return r; }; /* * Function: M4x4.translate1 */ M4x4.translate1 = function M4x4_translate1 (k, m, r) { return M4x4.translate3(k, k, k, m, r); }; /* * Function: M4x4.translateSelf */ M4x4.translateSelf = function M4x4_translateSelf (v, m) { var x=v[0], y=v[1], z=v[2]; m[12] += m[0] * x + m[4] * y + m[8] * z; m[13] += m[1] * x + m[5] * y + m[9] * z; m[14] += m[2] * x + m[6] * y + m[10] * z; m[15] += m[3] * x + m[7] * y + m[11] * z; return m; }; /* * Function: M4x4.translate */ M4x4.translate = function M4x4_translate (v, m, r) { var x=v[0], y=v[1], z=v[2]; if (r == m) { m[12] += m[0] * x + m[4] * y + m[8] * z; m[13] += m[1] * x + m[5] * y + m[9] * z; m[14] += m[2] * x + m[6] * y + m[10] * z; m[15] += m[3] * x + m[7] * y + m[11] * z; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); var m11 = m[0]; var m21 = m[1]; var m31 = m[2]; var m41 = m[3]; var m12 = m[4]; var m22 = m[5]; var m32 = m[6]; var m42 = m[7]; var m13 = m[8]; var m23 = m[9]; var m33 = m[10]; var m43 = m[11]; r[0] = m11; r[1] = m21; r[2] = m31; r[3] = m41; r[4] = m12; r[5] = m22; r[6] = m32; r[7] = m42; r[8] = m13; r[9] = m23; r[10] = m33; r[11] = m43; r[12] = m11 * x + m12 * y + m13 * z + m[12]; r[13] = m21 * x + m22 * y + m23 * z + m[13]; r[14] = m31 * x + m32 * y + m33 * z + m[14]; r[15] = m41 * x + m42 * y + m43 * z + m[15]; return r; }; /* * Function: M4x4.makeLookAt */ M4x4.makeLookAt = function M4x4_makeLookAt (eye, center, up, r) { var z = V3.direction(eye, center, V3._temp1); var x = V3.normalize(V3.cross(up, z, V3._temp2), V3._temp2); var y = V3.normalize(V3.cross(z, x, V3._temp3), V3._temp3); var tm1 = M4x4._temp1; var tm2 = M4x4._temp2; tm1[0] = x[0]; tm1[1] = y[0]; tm1[2] = z[0]; tm1[3] = 0; tm1[4] = x[1]; tm1[5] = y[1]; tm1[6] = z[1]; tm1[7] = 0; tm1[8] = x[2]; tm1[9] = y[2]; tm1[10] = z[2]; tm1[11] = 0; tm1[12] = 0; tm1[13] = 0; tm1[14] = 0; tm1[15] = 1; tm2[0] = 1; tm2[1] = 0; tm2[2] = 0; tm2[3] = 0; tm2[4] = 0; tm2[5] = 1; tm2[6] = 0; tm2[7] = 0; tm2[8] = 0; tm2[9] = 0; tm2[10] = 1; tm2[11] = 0; tm2[12] = -eye[0]; tm2[13] = -eye[1]; tm2[14] = -eye[2]; tm2[15] = 1; if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); return M4x4.mul(tm1, tm2, r); }; /* * Function: M4x4.transposeSelf */ M4x4.transposeSelf = function M4x4_transposeSelf (m) { var tmp = m[1]; m[1] = m[4]; m[4] = tmp; tmp = m[2]; m[2] = m[8]; m[8] = tmp; tmp = m[3]; m[3] = m[12]; m[12] = tmp; tmp = m[6]; m[6] = m[9]; m[9] = tmp; tmp = m[7]; m[7] = m[13]; m[13] = tmp; tmp = m[11]; m[11] = m[14]; m[14] = tmp; return m; }; /* * Function: M4x4.transpose */ M4x4.transpose = function M4x4_transpose (m, r) { if (m == r) { var tmp = 0.0; tmp = m[1]; m[1] = m[4]; m[4] = tmp; tmp = m[2]; m[2] = m[8]; m[8] = tmp; tmp = m[3]; m[3] = m[12]; m[12] = tmp; tmp = m[6]; m[6] = m[9]; m[9] = tmp; tmp = m[7]; m[7] = m[13]; m[13] = tmp; tmp = m[11]; m[11] = m[14]; m[14] = tmp; return m; } if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(16); r[0] = m[0]; r[1] = m[4]; r[2] = m[8]; r[3] = m[12]; r[4] = m[1]; r[5] = m[5]; r[6] = m[9]; r[7] = m[13]; r[8] = m[2]; r[9] = m[6]; r[10] = m[10]; r[11] = m[14]; r[12] = m[3]; r[13] = m[7]; r[14] = m[11]; r[15] = m[15]; return r; }; /* * Function: M4x4.transformPoint */ M4x4.transformPoint = function M4x4_transformPoint (m, v, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); var v0 = v[0], v1 = v[1], v2 = v[2]; r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12]; r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13]; r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14]; var w = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15]; if (w != 1.0) { r[0] /= w; r[1] /= w; r[2] /= w; } return r; }; /* * Function: M4x4.transformLine */ M4x4.transformLine = function M4x4_transformLine(m, v, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); var v0 = v[0], v1 = v[1], v2 = v[2]; r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2; r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2; r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2; var w = m[3] * v0 + m[7] * v1 + m[11] * v2; if (w != 1.0) { r[0] /= w; r[1] /= w; r[2] /= w; } return r; }; /* * Function: M4x4.transformPointAffine */ M4x4.transformPointAffine = function M4x4_transformPointAffine (m, v, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); var v0 = v[0], v1 = v[1], v2 = v[2]; r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12]; r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13]; r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14]; return r; }; /* * Function: M4x4.transformLineAffine */ M4x4.transformLineAffine = function M4x4_transformLineAffine(m, v, r) { if (r == undefined) r = new MJS_FLOAT_ARRAY_TYPE(3); var v0 = v[0], v1 = v[1], v2 = v[2]; r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2; r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2; r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2; return r; }; return mJS; }