diff options
author | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-13 20:00:18 +0000 |
---|---|---|
committer | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-13 20:00:18 +0000 |
commit | ee9372cbbc0bbeb8c8f06473409f3749eb443dd2 (patch) | |
tree | 755b8a5792facb882afbf3c13d733613c09c9742 /o3d | |
parent | a0835ac1850ccabc846ebfcee537b0b0592b8519 (diff) | |
download | chromium_src-ee9372cbbc0bbeb8c8f06473409f3749eb443dd2.zip chromium_src-ee9372cbbc0bbeb8c8f06473409f3749eb443dd2.tar.gz chromium_src-ee9372cbbc0bbeb8c8f06473409f3749eb443dd2.tar.bz2 |
Replaces matrix math functions in o3d-webgl with a new library that uses 1-dimensional arrays to represent matrices instead of 2-dimensional arrays.
This is a duplicate of Daniel Horn's change http://codereview.chromium.org/3072008 for committal.
Review URL: http://codereview.chromium.org/3273004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59268 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
25 files changed, 5513 insertions, 2053 deletions
diff --git a/o3d/samples/o3d-webgl-samples/2d.html b/o3d/samples/o3d-webgl-samples/2d.html index 416c76c..2e7bd23 100644 --- a/o3d/samples/o3d-webgl-samples/2d.html +++ b/o3d/samples/o3d-webgl-samples/2d.html @@ -296,10 +296,10 @@ function initStep2(clientElements) { 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0,-1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1)); // Load all the textures. var loader = o3djs.loader.createLoader(initStep3); diff --git a/o3d/samples/o3d-webgl-samples/box2d-3d/demos/manager.js b/o3d/samples/o3d-webgl-samples/box2d-3d/demos/manager.js index b780460..c8bb604 100644 --- a/o3d/samples/o3d-webgl-samples/box2d-3d/demos/manager.js +++ b/o3d/samples/o3d-webgl-samples/box2d-3d/demos/manager.js @@ -24,10 +24,10 @@ O3DManager.prototype.createCylinder = function(radius) { shape = o3djs.primitives.createCylinder(g.pack, g.materials[0], radius, 40, 20, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1)); this.shapes[id] = shape; } return new O3DShape({shape: shape}); @@ -53,16 +53,16 @@ O3DManager.prototype.createCompoundCylinder = function(radius1, if (!shape) { shape = o3djs.primitives.createCylinder( g.pack, g.materials[0], radius1, 40, 20, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [offset1, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + offset1, 0, 0, 1)); shape2 = o3djs.primitives.createCylinder( g.pack, g.materials[0], radius2, 40, 20, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [offset2, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + offset2, 0, 0, 1)); shape2.elements[0].owner = shape; g.pack.removeObject(shape2); this.shapes[id] = shape; diff --git a/o3d/samples/o3d-webgl-samples/hellocube.html b/o3d/samples/o3d-webgl-samples/hellocube.html index 148183b..8655b62 100644 --- a/o3d/samples/o3d-webgl-samples/hellocube.html +++ b/o3d/samples/o3d-webgl-samples/hellocube.html @@ -207,8 +207,8 @@ function initStep2(clientElements) { // Set up our view transformation to look towards the world origin where the // cube is located. viewInfo.drawContext.view = g_math.matrix4.lookAt([0, 1, 5], // eye - [0, 0, 0], // target - [0, 1, 0]); // up + [0, 0, 0], // target + [0, 1, 0]); // up // Create an Effect object and initialize it using the shaders from the // text area. diff --git a/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html b/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html index 0464b30..9d7b967 100644 --- a/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html +++ b/o3d/samples/o3d-webgl-samples/hud-2d-overlay.html @@ -216,10 +216,10 @@ function initStep2(clientElements) { 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0,-1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1)); // Create a ground plane g_groundShape = o3djs.primitives.createPlane( @@ -235,10 +235,10 @@ function initStep2(clientElements) { g_pack, g_materials[1], 1, - [[0.9, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 0.9, 0], - [0, 0.5, 0, 1]]); + o3djs.math.makeMatrix4(0.9, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0.9, 0, + 0, 0.5, 0, 1)); // Load all the textures. var loader = o3djs.loader.createLoader(initStep3); diff --git a/o3d/samples/o3d-webgl-samples/pool.html b/o3d/samples/o3d-webgl-samples/pool.html index 14eca54..f9e983f0 100644 --- a/o3d/samples/o3d-webgl-samples/pool.html +++ b/o3d/samples/o3d-webgl-samples/pool.html @@ -396,7 +396,7 @@ pool.Physics = function() { [0, w / 2 - r, 0]]; var angles = [0, Math.PI/2, Math.PI, Math.PI, 3 * Math.PI / 2, 0]; - var translations = this.math.mulMatrixMatrix( + var translations = this.math.generalizedMulMatrixMatrix( [[-1, -1, 0], [0, -2, 0], [1, -1, 0], [1, 1, 0], [0, 2, 0], [-1, 1, 0]], [[w / 2, 0, 0], [0, w / 2, 0], [0, 0, 1]]); @@ -624,9 +624,10 @@ pool.Physics = function() { var b = r[1]; var c = r[2]; - return [[1 / m + (b * b + c * c) / I, (-a * b) / I, (-a * c) / I], - [(-a * b) / I, 1 / m + (a * a + c * c) / I, (-b * c) / I], - [(-a * c) / I, (-b * c) / I, 1 / m + (a * a + b * b) / I]]; + return o3djs.math + .makeMatrix3(1 / m + (b * b + c * c) / I, (-a * b) / I, (-a * c) / I, + (-a * b) / I, 1 / m + (a * a + c * c) / I, (-b * c) / I, + (-a * c) / I, (-b * c) / I, 1 / m + (a * a + b * b) / I); }; this.applyImpulse = function(i, impulse, r) { @@ -1269,11 +1270,11 @@ function initTable() { Math.PI, 15)).concat([[-scaledWoodBreadth - 1, 0]]); - var m = g_math.mulScalarMatrix(g_tableWidth / 2, g_math.identity(2)); - felt_polygon_A = g_math.mulMatrixMatrix(felt_polygon_A, m); - felt_polygon_B = g_math.mulMatrixMatrix(felt_polygon_B, m); - felt_polygon_C = g_math.mulMatrixMatrix(felt_polygon_C, m); - wood_polygon = g_math.mulMatrixMatrix(wood_polygon, m); + var m = [[g_tableWidth / 2, 0],[0,g_tableWidth / 2]]; + felt_polygon_A = g_math.generalizedMulMatrixMatrix(felt_polygon_A, m); + felt_polygon_B = g_math.generalizedMulMatrixMatrix(felt_polygon_B, m); + felt_polygon_C = g_math.generalizedMulMatrixMatrix(felt_polygon_C, m); + wood_polygon = g_math.generalizedMulMatrixMatrix(wood_polygon, m); var felt_polygons = []; var wood_polygons = []; @@ -1316,11 +1317,13 @@ function initTable() { var cushionSwoop = g_pocketRadius; var angles = [0, Math.PI/2, Math.PI, Math.PI, 3 * Math.PI / 2, 0]; - var translations = g_math.mulMatrixMatrix( + var translations = g_math.generalizedMulMatrixMatrix( [[-1, -1, 0], [0, -2, 0], [1, -1, 0], [1, 1, 0], [0, 2, 0], [-1, 1, 0]], [[g_tableWidth / 2, 0, 0], [0, g_tableWidth / 2, 0], [0, 0, 1]]); - var shortenings = g_math.mulScalarMatrix(g_pocketRadius, - [[1, root2], [root2, root2], [root2, 1]]) + var shortenings = + [[g_pocketRadius, g_pocketRadius*root2], + [g_pocketRadius*root2, g_pocketRadius*root2], + [g_pocketRadius*root2, g_pocketRadius]]; var billiardThickness = 0.1; var billiardBreadth = 1; @@ -1415,17 +1418,19 @@ function initHud() { var plane = o3djs.primitives.createPlane( g_pack, g_solidMaterial, 1, 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0,-1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1)); var backPlane = o3djs.primitives.createPlane( g_pack, g_solidMaterial, 1, 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0,-1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1)); barT2.addShape(plane); //backT2.addShape(backPlane); diff --git a/o3d/samples/o3d-webgl-samples/shadow-map.html b/o3d/samples/o3d-webgl-samples/shadow-map.html index 97defe2..77fca20 100644 --- a/o3d/samples/o3d-webgl-samples/shadow-map.html +++ b/o3d/samples/o3d-webgl-samples/shadow-map.html @@ -301,11 +301,6 @@ function updateLightMatrix() { 4, // Near plane. 20); // Far plane. - var adjustedProjection = - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 2, 0], [0, 0, -1, 1]]; - o3d.Transform.compose( - adjustedProjection, lightProjection, adjustedProjection); - // Make the light point toward the origin var lightView = g_math.matrix4.lookAt( g_lightWorldPos, // light @@ -384,17 +379,9 @@ function createShapes() { function createLightShape() { var inverseMatrix = g_math.matrix4.inverse(g_lightViewProjection); - // Scale and translate a cube of side length 2 to get a box - // that extends from [-1, -1, 0] to [1, 1, 1]. var shape = o3djs.lineprimitives.createLineCube( - g_pack, - o3djs.material.createConstantMaterial(g_pack, - g_colorViewInfo, - [1, 0, 0, 1]), - 2, - g_math.matrix4.compose( - g_math.matrix4.translation([0, 0, 0.5]), - g_math.matrix4.scaling([1, 1, 0.5]))); + g_pack, o3djs.material.createConstantMaterial(g_pack, g_colorViewInfo, + [1, 0, 0, 1]), 2); g_lightFrustumTransform = g_pack.createObject('Transform'); g_lightFrustumTransform.localMatrix = inverseMatrix; diff --git a/o3d/samples/o3d-webgl-samples/skinning.html b/o3d/samples/o3d-webgl-samples/skinning.html index f8450be..0b4e91e 100644 --- a/o3d/samples/o3d-webgl-samples/skinning.html +++ b/o3d/samples/o3d-webgl-samples/skinning.html @@ -122,10 +122,11 @@ function initStep2(clientElements) { // Create a cylinder. var vertexInfo = o3djs.primitives.createCylinderVertices( 40, 200, 120, 200, - [[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 100, 0, 1]]); + o3djs.math.makeMatrix4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 100, 0, 1)); var shape = vertexInfo.createShape(g_pack, material); // Create an ParamArray to hold matrices for skinning. diff --git a/o3d/samples/o3d-webgl/base.js b/o3d/samples/o3d-webgl/base.js index b484e484..3572a25 100644 --- a/o3d/samples/o3d-webgl/base.js +++ b/o3d/samples/o3d-webgl/base.js @@ -246,6 +246,7 @@ o3d.include('named_object_base'); o3d.include('named_object'); o3d.include('param_object'); o3d.include('param_array'); +o3d.include('transform'); o3d.include('param'); o3d.include('event'); o3d.include('raw_data'); @@ -266,7 +267,6 @@ o3d.include('state'); o3d.include('draw_context'); o3d.include('ray_intersection_info'); o3d.include('sampler'); -o3d.include('transform'); o3d.include('pack'); o3d.include('bounding_box'); o3d.include('draw_element'); diff --git a/o3d/samples/o3d-webgl/bounding_box.js b/o3d/samples/o3d-webgl/bounding_box.js index a3da9aa..8a88d78 100644 --- a/o3d/samples/o3d-webgl/bounding_box.js +++ b/o3d/samples/o3d-webgl/bounding_box.js @@ -129,7 +129,7 @@ o3d.BoundingBox.prototype.mul = var new_corners = []; for (var i = 0; i < corners.length; ++i) { - new_corners.push(o3d.Transform.transformPoint(matrix, corners[i])); + new_corners.push(o3d.Transform.transformPoint_(matrix, corners[i])); } return o3d.BoundingBox.fitBoxToPoints_(new_corners); @@ -283,7 +283,7 @@ o3d.BoundingBox.prototype.inFrustum = var bb_test = 0x3f; for (var i = 0; i < corners.length; ++i) { var corner = corners[i]; - var p = o3d.Transform.transformPoint(matrix, corner); + var p = o3d.Transform.transformPoint_(matrix, corner); bb_test &= (((p[0] > 1.0) << 0) | ((p[0] < -1.0) << 1) | ((p[1] > 1.0) << 2) | diff --git a/o3d/samples/o3d-webgl/draw_context.js b/o3d/samples/o3d-webgl/draw_context.js index 0b4967c..dde73e8 100644 --- a/o3d/samples/o3d-webgl/draw_context.js +++ b/o3d/samples/o3d-webgl/draw_context.js @@ -49,8 +49,7 @@ o3d.DrawContext = function(opt_view, opt_projection) { * take vertices from world space to view space. * @type {o3d.Matrix4} */ - this.view = opt_view || - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.view = opt_view || o3d.Transform.makeIdentityMatrix4_(); /** * The projection matrix represents the projection transformation, @@ -58,8 +57,7 @@ o3d.DrawContext = function(opt_view, opt_projection) { * matrix is usually an orthographic or perspective transformation. * @type {o3d.Matrix4} */ - this.projection = opt_projection || - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.projection = opt_projection || o3d.Transform.makeIdentityMatrix4_(); }; o3d.inherit('DrawContext', 'ParamObject'); diff --git a/o3d/samples/o3d-webgl/draw_list.js b/o3d/samples/o3d-webgl/draw_list.js index 68f635d..33cc7fd 100644 --- a/o3d/samples/o3d-webgl/draw_list.js +++ b/o3d/samples/o3d-webgl/draw_list.js @@ -83,10 +83,10 @@ o3d.DrawList.comparePriority_ = function(drawElementInfoA, drawElementInfoB) { * @param {!o3d.DrawElement} drawElementInfoB */ o3d.DrawList.compareZ_ = function(drawElementInfoA, drawElementInfoB) { - return o3d.Transform.transformPointZOnly( + return o3d.Transform.transformPointZOnly_( drawElementInfoB.worldViewProjection, drawElementInfoB.drawElement.owner.zSortPoint) - - o3d.Transform.transformPointZOnly( + o3d.Transform.transformPointZOnly_( drawElementInfoA.worldViewProjection, drawElementInfoA.drawElement.owner.zSortPoint); }; diff --git a/o3d/samples/o3d-webgl/param.js b/o3d/samples/o3d-webgl/param.js index 9ea8bd0..66fca29 100644 --- a/o3d/samples/o3d-webgl/param.js +++ b/o3d/samples/o3d-webgl/param.js @@ -39,50 +39,50 @@ * @constructor */ o3d.Param = function(param_type_name) { - o3d.Param.prototype.output_connections = []; + /** + * If true, this param will make sure its input param is up to date when + * using it as a source. Default = true. + * + * This is for helping with Param cycles. + * + * If paramA gets its value from paramB and paramB gets its value from + * paramA: + * If you go paramA.value, paramB will evaluate then copy to paramA. + * If you go paramB.value, paramA will evaluate then copy to paramB. + * If you set paramB.updateInput = false, then: + * If you go paramA.value, paramB will evaluate then copy to paramA. + * If you go paramB.value, paramB just copy paramA. paramA will NOT evaluate + * when paramB asks for its value. + */ + this.updateInput = true; + + /** + * @type {o3d.Param} + */ + this.inputConnection = null; + + /** + * @type {Array.<!o3d.Param>} + */ this.outputConnections = []; + + /** + * The ParamObject that has this param as a param. + * @type {o3d.ParamObject} + * @private + */ + o3d.Param.prototype.owner_ = null; + + /** + * Private variable to store the value of the param. + * @type {*} + * @private + */ + this.value_ = null; } o3d.inherit('Param', 'NamedObject'); -/** - * If true, this param will make sure its input param is up to date when - * using it as a source. Default = true. - * - * This is for helping with Param cycles. - * - * If paramA gets its value from paramB and paramB gets its value from - * paramA: - * If you go paramA.value, paramB will evaluate then copy to paramA. - * If you go paramB.value, paramA will evaluate then copy to paramB. - * If you set paramB.updateInput = false, then: - * If you go paramA.value, paramB will evaluate then copy to paramA. - * If you go paramB.value, paramB just copy paramA. paramA will NOT evaluate - * when paramB asks for its value. - */ -o3d.Param.prototype.update_input = true; - -/** - * @type {o3d.Param} - */ -o3d.Param.prototype.inputConnection = null; - -/** - * @type {Array.<!o3d.Param>} - */ -o3d.Param.prototype.outputConnections = []; - - -/** - * @type {o3d.ParamObject} - */ -o3d.Param.prototype.owner_ = null; - -/** - * @type {Object} The value of the parameter. - */ -o3d.Param.prototype.value_ = null; - o3d.Param.prototype.__defineSetter__('value', function(v) { if (this.inputConnection) { @@ -267,7 +267,7 @@ o3d.inherit('ParamFloat', 'Param'); */ o3d.ParamFloat2 = function() { o3d.Param.call(this); - this.value = [0.0, 0.0]; + this.value = o3d.Transform.makeVector2_(0.0, 0.0); }; o3d.inherit('ParamFloat2', 'Param'); @@ -277,7 +277,7 @@ o3d.inherit('ParamFloat2', 'Param'); */ o3d.ParamFloat3 = function() { o3d.Param.call(this); - this.value = [0.0, 0.0, 0.0]; + this.value = o3d.Transform.makeVector3_(0.0, 0.0, 0.0); }; o3d.inherit('ParamFloat3', 'Param'); @@ -287,7 +287,7 @@ o3d.inherit('ParamFloat3', 'Param'); */ o3d.ParamFloat4 = function() { o3d.Param.call(this); - this.value = [0.0, 0.0, 0.0, 0.0]; + this.value = o3d.Transform.makeVector4_(0.0, 0.0, 0.0, 0.0); }; o3d.inherit('ParamFloat4', 'Param'); @@ -327,17 +327,18 @@ o3d.inherit('ParamMaterial', 'Param'); */ o3d.ParamMatrix4 = function() { o3d.Param.call(this); - this.value = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.value = o3d.Transform.makeMatrix4_(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); }; o3d.inherit('ParamMatrix4', 'Param'); - /** * @constructor */ o3d.ParamParamArray = function() { o3d.Param.call(this); - this.value = null; }; o3d.inherit('ParamParamArray', 'Param'); @@ -483,8 +484,10 @@ o3d.CompositionParamMatrix4 = function() { o3d.ParamMatrix4.call(this); this.matrix_names_ = []; }; + o3d.inherit('CompositionParamMatrix4', 'ParamMatrix4'); + /** * The array of names of matrix params for the matrices that are to be * composed to get the value. @@ -508,15 +511,15 @@ o3d.CompositionParamMatrix4.prototype.transpose_ = false; o3d.CompositionParamMatrix4.prototype.__defineGetter__('value', // TODO(petersont): Cache the result if it hasn't changed. function() { - var product = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + var product = o3d.Transform.makeIdentityMatrix4_(); for (var i = 0; i < this.matrix_names_.length; ++i) { - o3d.Transform.compose(product, o3d.Param.SAS[this.matrix_names_[i]]); + o3d.Transform.compose_(product, o3d.Param.SAS[this.matrix_names_[i]]); } if (this.inverse_) { - o3d.Transform.inverse(product); + o3d.Transform.inverse_(product); } if (this.transpose_) { - o3d.Transform.transpose(product); + o3d.Transform.transpose_(product); } return product; } @@ -786,7 +789,6 @@ o3d.WorldViewProjectionTransposeParamMatrix4 = function() { o3d.inherit('WorldViewProjectionTransposeParamMatrix4', 'CompositionParamMatrix4'); - /** * @constructor */ @@ -862,7 +864,7 @@ o3d.ParamFloat4.prototype.applyToLocation = function(gl, location) { o3d.ParamMatrix4.prototype.applyToLocation = function(gl, location) { gl.uniformMatrix4fv(location, false, - o3d.Transform.flattenMatrix4(this.value)); + this.value); }; /** diff --git a/o3d/samples/o3d-webgl/param_operation.js b/o3d/samples/o3d-webgl/param_operation.js index 69ecea7..172f537 100644 --- a/o3d/samples/o3d-webgl/param_operation.js +++ b/o3d/samples/o3d-webgl/param_operation.js @@ -147,7 +147,7 @@ o3d.inherit('ParamOp2FloatsToFloat2', 'ParamObject'); /** * Called by o3d.Param*Output whenever its value gets read. - * @return {!Array.<number>} 2-element array equal to [input0,input1] + * @return {!Array.<number>} 2-element array equal to [input0, input1] */ o3d.ParamOp2FloatsToFloat2.prototype.updateOutputs = function() { this.last_output_value_[0] = this.getParam("input0").value; @@ -226,8 +226,7 @@ o3d.ParamOp4FloatsToFloat4.prototype.updateOutputs = function() { */ o3d.ParamOp16FloatsToMatrix4 = function() { o3d.ParamObject.call(this); - this.last_output_value_ = - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.last_output_value_ = o3d.Transform.makeIdentityMatrix4_(); }; o3d.inherit('ParamOp16FloatsToMatrix4', 'ParamObject'); @@ -242,12 +241,12 @@ o3d.inherit('ParamOp16FloatsToMatrix4', 'ParamObject'); /** * Called by o3d.Param*Output whenever its value gets read. - * @return {!Array.<!Array.<number>>} 4x4 array equal to - * [[i0,i1,i2,i3],[i4,i5,i6,i7],[i8,i9,i10,i11],[i12,i13,i14,i15]] + * @return {!Array<!Array<number>>} 4x4 array equal to + * [i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15] */ o3d.ParamOp16FloatsToMatrix4.prototype.updateOutputs = function() { for (var i = 0; i < 16; i++) { - this.last_output_value_[Math.floor(i/4)][i%4] = + this.last_output_value_[i] = this.getParam("input"+i).value; } return this.last_output_value_; @@ -282,8 +281,7 @@ o3d.TRSToMatrix4 = function() { this.scaleY = 1; this.scaleZ = 1; - this.last_output_value_ = - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.last_output_value_ = o3d.Transform.makeIdentityMatrix4_(); }; o3d.inherit('TRSToMatrix4', 'ParamObject'); @@ -320,22 +318,22 @@ o3d.TRSToMatrix4.prototype.updateOutputs = function () { var cosZSinY = cosZ * sinY; var sinZSinY = sinZ * sinY; - ret[0].splice(0, 4, cosZ * cosY * sX, - sinZ * cosY * sX, - -sinY * sX, - 0); - ret[1].splice(0, 4, (cosZSinY * sinX - sinZ * cosX) * sY, - (sinZSinY * sinX + cosZ * cosX) * sY, - cosY * sinX * sY, - 0); - ret[2].splice(0, 4, (cosZSinY * cosX + sinZ * sinX) * sZ, - (sinZSinY * cosX - cosZ * sinX) * sZ, - cosY * cosX * sZ, - 0); - ret[3].splice(0, 4, this.translateX, - this.translateY, - this.translateZ, - 1); + ret[0] = cosZ * cosY * sX; + ret[1] = sinZ * cosY * sX; + ret[2] = -sinY * sX; + ret[3] = 0; + ret[4] = (cosZSinY * sinX - sinZ * cosX) * sY; + ret[5] = (sinZSinY * sinX + cosZ * cosX) * sY; + ret[6] = cosY * sinX * sY, + ret[7] = 0; + ret[8] = (cosZSinY * cosX + sinZ * sinX) * sZ; + ret[9] = (sinZSinY * cosX - cosZ * sinX) * sZ; + ret[10] = cosY * cosX * sZ; + ret[11] = 0; + ret[12] = this.translateX; + ret[13] = this.translateY; + ret[14] = this.translateZ; + ret[15] = 1; return ret; }; @@ -347,8 +345,7 @@ o3d.TRSToMatrix4.prototype.updateOutputs = function () { */ o3d.Matrix4Composition = function() { o3d.ParamObject.call(this); - this.last_output_value_ = - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.last_output_value_ = o3d.Transform.makeIdentityMatrix4_(); }; o3d.inherit('Matrix4Composition', 'ParamObject'); @@ -363,13 +360,13 @@ o3d.ParamObject.setUpO3DParam_( /** * Called by o3d.Param*Output whenever its value gets read. - * @return {!Array.<!Array.<number>>} 4x4 array equal to - * inputMatrix * localMatrix + * @return {!Array<!Array<number>>} 4x4 array equal to + * inputMatrix * localMatrix. */ o3d.Matrix4Composition.prototype.updateOutputs = function() { var input = this.getParam("inputMatrix").value; var local = this.getParam("localMatrix").value; - o3d.Transform.compose(input, local, this.last_output_value_); + o3d.Transform.compose_(input, local, this.last_output_value_); return this.last_output_value_; }; @@ -408,7 +405,7 @@ o3d.Matrix4AxisRotation.prototype.updateOutputs = function() { var input = this.getParam("inputMatrix").value; var axis = this.getParam("axis").value; var angle = this.getParam("angle").value; - o3d.Transform.axisRotateMatrix(input, axis, angle, this.last_output_value_); + o3d.Transform.axisRotateMatrix_(input, axis, angle, this.last_output_value_); return this.last_output_value_; }; diff --git a/o3d/samples/o3d-webgl/shape.js b/o3d/samples/o3d-webgl/shape.js index a0ad16e..8823f83 100644 --- a/o3d/samples/o3d-webgl/shape.js +++ b/o3d/samples/o3d-webgl/shape.js @@ -155,10 +155,10 @@ o3d.Shape.prototype.writeToDrawLists = var view = context.view; var projection = context.projection; - var worldViewProjection = [[], [], [], []]; - var viewProjection = [[], [], [], []]; - o3d.Transform.compose(projection, view, viewProjection); - o3d.Transform.compose(viewProjection, world, worldViewProjection); + var worldViewProjection = o3d.Transform.makeIdentityMatrix4_(); + var viewProjection = o3d.Transform.makeIdentityMatrix4_(); + o3d.Transform.compose_(projection, view, viewProjection); + o3d.Transform.compose_(viewProjection, world, worldViewProjection); if (element.cull && element.boundingBox) { if (!element.boundingBox.inFrustum(worldViewProjection)) { diff --git a/o3d/samples/o3d-webgl/skin.js b/o3d/samples/o3d-webgl/skin.js index cbec71f..1e9455c 100644 --- a/o3d/samples/o3d-webgl/skin.js +++ b/o3d/samples/o3d-webgl/skin.js @@ -307,14 +307,14 @@ o3d.SkinEval = function() { * The base matrix to subtract from the matrices before skinning. * @type {!Array<!Array<number>>} */ - this.base = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.base = o3d.Transform.makeIdentityMatrix4_(); /** * Temporary storage for matrix ops. * @type {!Array<!Array<number>>} * @private */ - this.temp_matrix_ = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.temp_matrix_ = o3d.Transform.makeIdentityMatrix4_(); /** * Array of matrices representing each bone. @@ -325,7 +325,7 @@ o3d.SkinEval = function() { /** * Float32 array containing all matrices in 3x4 format. - * @type {Float32Array} + * @type {o3d.ParamArray} * @private */ this.bone_array_ = null; @@ -463,30 +463,9 @@ o3d.SkinEval.prototype.streamWasBound_ = function( * @private */ o3d.SkinEval.prototype.multiplyAdd_ = function(input, weight, output) { - var a0 = input[0]; - var a1 = input[1]; - var a2 = input[2]; - var a3 = input[3]; - var b0 = output[0]; - var b1 = output[1]; - var b2 = output[2]; - var b3 = output[3]; - b0[0] += a0[0] * weight; - b0[1] += a0[1] * weight; - b0[2] += a0[2] * weight; - b0[3] += a0[3] * weight; - b1[0] += a1[0] * weight; - b1[1] += a1[1] * weight; - b1[2] += a1[2] * weight; - b1[3] += a1[3] * weight; - b2[0] += a2[0] * weight; - b2[1] += a2[1] * weight; - b2[2] += a2[2] * weight; - b2[3] += a2[3] * weight; - b3[0] += a3[0] * weight; - b3[1] += a3[1] * weight; - b3[2] += a3[2] * weight; - b3[3] += a3[3] * weight; + for (var i = 0; i < 16; ++i) { + output[i] += input[i] * weight; + } }; /** @@ -637,11 +616,11 @@ o3d.SkinEval.prototype.doSkinning_ = function() { // combine the matrixes for this vertex. var accumulated_matrix = - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]; + o3d.Transform.makeNullMatrix4_(); this.multiplyAdd_(this.bones_[this_matrix_index], this_weight, accumulated_matrix); var num_influences = influences.length; - for (jj = 2; jj < num_influences; jj+=2) { + for (jj = 2; jj < num_influences; jj += 2) { var influence_matrix_index = influences[jj]; var influence_weight = influences[jj + 1]; this.multiplyAdd_(this.bones_[influence_matrix_index], @@ -707,7 +686,7 @@ o3d.SkinEval.prototype.updateBones_ = function() { // Get the inverse of our base to remove from the bones. var inverse_base = this.temp_matrix_; - o3d.Transform.inverse(this.base, inverse_base); + o3d.Transform.inverse_(this.base, inverse_base); for (var ii = 0; ii < param_array.length; ++ii) { var param = param_array.getParam(ii); // ParamMatrix4 @@ -718,10 +697,10 @@ o3d.SkinEval.prototype.updateBones_ = function() { + " is not a ParamMatrix4"); return; } - this.bones_[ii] = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; - o3d.Transform.compose(param.value, inverse_bind_pose_array[ii], + this.bones_[ii] = o3d.Transform.makeIdentityMatrix4_(); + o3d.Transform.compose_(param.value, inverse_bind_pose_array[ii], this.bones_[ii]); - o3d.Transform.compose(inverse_base, this.bones_[ii], this.bones_[ii]); + o3d.Transform.compose_(inverse_base, this.bones_[ii], this.bones_[ii]); } }; @@ -777,20 +756,20 @@ o3d.SkinEval.prototype.updateOutputs = function(param) { for (ii = 0; ii < this.bones_.length; ++ii) { var bone = this.bones_[ii]; row = boneArray.getParam(ii*3); - row.value[0] = bone[0][0]; - row.value[1] = bone[1][0]; - row.value[2] = bone[2][0]; - row.value[3] = bone[3][0]; + row.value[0] = bone[0]; + row.value[1] = bone[4]; + row.value[2] = bone[8]; + row.value[3] = bone[12]; row = boneArray.getParam(ii*3 + 1); - row.value[0] = bone[0][1]; - row.value[1] = bone[1][1]; - row.value[2] = bone[2][1]; - row.value[3] = bone[3][1]; + row.value[0] = bone[1]; + row.value[1] = bone[5]; + row.value[2] = bone[9]; + row.value[3] = bone[13]; row = boneArray.getParam(ii*3 + 2); - row.value[0] = bone[0][2]; - row.value[1] = bone[1][2]; - row.value[2] = bone[2][2]; - row.value[3] = bone[3][2]; + row.value[0] = bone[2]; + row.value[1] = bone[6]; + row.value[2] = bone[10]; + row.value[3] = bone[14]; } } return boneArray; @@ -884,7 +863,7 @@ o3d.SkinEval.StreamInfo.prototype.uninit = function() { o3d.SkinEval.StreamInfo.prototype.computeFloat3AsVector3 = function(matrix) { var ii = this.index_; var vec = [this.values_[ii], this.values_[ii + 1], this.values_[ii + 2], 0]; - this.result_ = o3d.Transform.multiplyVector(matrix, vec); + this.result_ = o3d.Transform.multiplyVector_(matrix, vec); this.index_ = ii + this.stride_; }; @@ -898,10 +877,10 @@ o3d.SkinEval.StreamInfo.prototype.computeFloat3AsVector3 = function(matrix) { o3d.SkinEval.StreamInfo.prototype.computeFloat3AsPoint3 = function(matrix) { var ii = this.index_; // TODO: The C++ code just dropped element 3 of the return Vector4, while - // o3d.Transform.transformPoint divides by the last value to make it 1. + // o3d.Transform.transformPoint_ divides by the last value to make it 1. // Which is the right one to use? var point = [this.values_[ii], this.values_[ii + 1], this.values_[ii + 2], 1]; - this.result_ = o3d.Transform.multiplyVector(matrix, point); + this.result_ = o3d.Transform.multiplyVector_(matrix, point); this.index_ = ii + this.stride_; }; @@ -916,7 +895,7 @@ o3d.SkinEval.StreamInfo.prototype.computeFloat4AsVector4 = function(matrix) { var ii = this.index_; var vec = [this.values_[ii], this.values_[ii + 1], this.values_[ii + 2], this.values_[ii + 3]]; - this.result_ = o3d.Transform.multiplyVector(matrix, vec); + this.result_ = o3d.Transform.multiplyVector_(matrix, vec); this.index_ = ii + this.stride_; }; diff --git a/o3d/samples/o3d-webgl/transform.js b/o3d/samples/o3d-webgl/transform.js index 677e36b..9d1a8f9 100644 --- a/o3d/samples/o3d-webgl/transform.js +++ b/o3d/samples/o3d-webgl/transform.js @@ -58,13 +58,13 @@ o3d.Transform = * Default = Identity. */ this.localMatrix = opt_localMatrix || - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + o3d.Transform.makeIdentityMatrix4_(); /** * World (model) matrix as it was last computed. */ this.worldMatrix = opt_worldMatrix || - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + o3d.Transform.makeIdentityMatrix4_(); /** * Sets the parent of the transform by re-parenting the transform under @@ -230,11 +230,11 @@ o3d.Transform.prototype.getUpdatedWorldMatrix = var parentWorldMatrix; if (!this.parent) { parentWorldMatrix = - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + o3d.Transform.makeIdentityMatrix4_(); } else { parentWorldMatrix = this.parent.getUpdatedWorldMatrix(); } - o3d.Transform.compose(parentWorldMatrix, this.localMatrix, this.worldMatrix); + o3d.Transform.compose_(parentWorldMatrix, this.localMatrix, this.worldMatrix); return this.worldMatrix; }; @@ -295,238 +295,12 @@ o3d.Transform.prototype.identity = function() { var m = this.localMatrix; for (var i = 0; i < 4; ++i) { for (var j = 0; j < 4; ++j) { - m[i][j] = i==j ? 1 : 0; + m[i * 4 + j] = i == j ? 1 : 0; } } }; -/* - * Utility function to copose a matrix with another matrix. - * Precomposes b with a, changing a, or if the target matrix if - * one is provided. - * - * @param {!Array.<!Array.<number>>} a - * @param {!Array.<!Array.<number>>} b - * @param {!Array.<!Array.<number>>} opt_target - */ -o3d.Transform.compose = function(a, b, opt_target) { - var t = opt_target || a; - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var a3 = a[3]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var b3 = b[3]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a03 = a0[3]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a13 = a1[3]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var a23 = a2[3]; - var a30 = a3[0]; - var a31 = a3[1]; - var a32 = a3[2]; - var a33 = a3[3]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b03 = b0[3]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b13 = b1[3]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - var b23 = b2[3]; - var b30 = b3[0]; - var b31 = b3[1]; - var b32 = b3[2]; - var b33 = b3[3]; - t[0].splice(0, 4, a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, - a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, - a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, - a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03); - t[1].splice(0, 4, a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, - a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, - a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, - a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13); - t[2].splice(0, 4, a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, - a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, - a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, - a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23); - t[3].splice(0, 4, a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, - a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, - a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, - a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33); -}; - - -/** - * Tests whether two matrices are either equal in the sense that they - * refer to the same memory, or equal in the sense that they have equal - * entries. - * - * @param {!Array.<!Array.<number>>} a A matrix. - * @param {!Array.<!Array.<number>>} b Another matrix. - * @return {boolean} Whether they are equal. - */ -o3d.Transform.matricesEqual = function(a, b) { - if (a==b) { - return true; - } - for (var i = 0; i < 4; ++i) { - for (var j = 0; j < 4; ++j) { - if (a[i][j] != b[i][j]) { - return false; - } - } - } - return true; -}; - - -/** - * Computes the transpose of the matrix a in place if no target is provided. - * Or if a target is provided, turns the target into the transpose of a. - * - * @param {!Array.<!Array.<number>>} m A matrix. - * @param {Array.<!Array.<number>>} opt_target - * The matrix to become the transpose of m. - */ -o3d.Transform.transpose = function(m, opt_target) { - var t = opt_target || m; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - t[0].splice(0, 4, m00, m10, m20, m30); - t[1].splice(0, 4, m01, m11, m21, m31); - t[2].splice(0, 4, m02, m12, m22, m32); - t[3].splice(0, 4, m03, m13, m23, m33); -}; - - -/** - * Computes the inverse of the matrix a in place if no target is provided. - * Or if a target is provided, turns the target into the transpose of a. - * - * @param {!Array.<!Array.<number>>} m A matrix. - * @param {Array.<!Array.<number>>} opt_target The matrix to become the - * inverse of a. - */ -o3d.Transform.inverse = function(m, opt_target) { - var t = opt_target || m; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - var tmp_0 = m22 * m33; - var tmp_1 = m32 * m23; - var tmp_2 = m12 * m33; - var tmp_3 = m32 * m13; - var tmp_4 = m12 * m23; - var tmp_5 = m22 * m13; - var tmp_6 = m02 * m33; - var tmp_7 = m32 * m03; - var tmp_8 = m02 * m23; - var tmp_9 = m22 * m03; - var tmp_10 = m02 * m13; - var tmp_11 = m12 * m03; - var tmp_12 = m20 * m31; - var tmp_13 = m30 * m21; - var tmp_14 = m10 * m31; - var tmp_15 = m30 * m11; - var tmp_16 = m10 * m21; - var tmp_17 = m20 * m11; - var tmp_18 = m00 * m31; - var tmp_19 = m30 * m01; - var tmp_20 = m00 * m21; - var tmp_21 = m20 * m01; - var tmp_22 = m00 * m11; - var tmp_23 = m10 * m01; - - var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - - (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); - var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - - (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); - var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - - (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); - var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - - (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); - - var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); - - t[0].splice(0, 4, d * t0, d * t1, d * t2, d * t3); - t[1].splice(0, 4, d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - - (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)), - d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - - (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)), - d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - - (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)), - d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - - (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20))); - t[2].splice(0, 4, d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - - (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)), - d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - - (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)), - d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - - (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)), - d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - - (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23))); - t[3].splice(0, 4, d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - - (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)), - d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - - (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)), - d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - - (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)), - d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - - (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02))); -}; - - /** * Pre-composes the local matrix of this Transform with a translation. For * example, if the local matrix is a rotation then new local matrix will @@ -545,31 +319,28 @@ o3d.Transform.prototype.translate = var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - m3.splice(0, 4, m00 * v0 + m10 * v1 + m20 * v2 + m30, - m01 * v0 + m11 * v1 + m21 * v2 + m31, - m02 * v0 + m12 * v1 + m22 * v2 + m32, - m03 * v0 + m13 * v1 + m23 * v2 + m33); + + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[12] = m00 * v0 + m10 * v1 + m20 * v2 + m30, + m[13] = m01 * v0 + m11 * v1 + m21 * v2 + m31, + m[14] = m02 * v0 + m12 * v1 + m22 * v2 + m32, + m[15] = m03 * v0 + m13 * v1 + m23 * v2 + m33; }; @@ -584,100 +355,26 @@ o3d.Transform.prototype.rotateX = function(angle) { var m = this.localMatrix; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var c = Math.cos(angle); var s = Math.sin(angle); - m1.splice(0, 4, c * m10 + s * m20, - c * m11 + s * m21, - c * m12 + s * m22, - c * m13 + s * m23); - m2.splice(0, 4, c * m20 - s * m10, - c * m21 - s * m11, - c * m22 - s * m12, - c * m23 - s * m13); -}; - - -/** - * Takes a 4-by-4 matrix and a vector with 3 entries, - * interprets the vector as a point, transforms that point by the matrix, and - * returns the result as a vector with 3 entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v The point. - * @return {!o3djs.math.Vector3} The transformed point. - */ -o3d.Transform.transformPoint = function(m, v) { - var v0 = v[0]; - var v1 = v[1]; - var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - var d = v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + m3[3]; - return [(v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + m3[0]) / d, - (v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + m3[1]) / d, - (v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + m3[2]) / d]; -}; - - -/** - * Takes a 4-by-4 matrix and a vector with 4 entries, - * interprets the vector as a point, transforms that point by the matrix, and - * returns the result as a vector with 4 entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector4} v The vector. - * @return {!o3djs.math.Vector4} The transformed vector. - */ -o3d.Transform.multiplyVector = function(m, v) { - var v0 = v[0]; - var v1 = v[1]; - var v2 = v[2]; - var v3 = v[3]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - return [(v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + v3 * m3[0]), - (v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + v3 * m3[1]), - (v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + v3 * m3[2]), - (v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + v3 * m3[3])]; -}; - - -/** - * Takes a 4-by-4 matrix and a vector with 3 entries, - * interprets the vector as a point, transforms that point by the matrix, - * returning the z-component of the result only. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v The point. - * @return {number} The z coordinate of the transformed point. - */ -o3d.Transform.transformPointZOnly = function(m, v) { - var v0 = v[0]; - var v1 = v[1]; - var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - return (v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + m3[2]) / - (v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + m3[3]); + m[4] = c * m10 + s * m20; + m[5] = c * m11 + s * m21; + m[6] = c * m12 + s * m22; + m[7] = c * m13 + s * m23; + m[8] = c * m20 - s * m10; + m[9] = c * m21 - s * m11; + m[10] = c * m22 - s * m12; + m[11] = c * m23 - s * m13; }; @@ -692,29 +389,25 @@ o3d.Transform.prototype.rotateY = function(angle) { var m = this.localMatrix; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; var c = Math.cos(angle); var s = Math.sin(angle); - m0.splice(0, 4, c * m00 - s * m20, - c * m01 - s * m21, - c * m02 - s * m22, - c * m03 - s * m23); - m2.splice(0, 4, c * m20 + s * m00, - c * m21 + s * m01, - c * m22 + s * m02, - c * m23 + s * m03); + m[0] = c * m00 - s * m20; + m[1] = c * m01 - s * m21; + m[2] = c * m02 - s * m22; + m[3] = c * m03 - s * m23; + m[8] = c * m20 + s * m00; + m[9] = c * m21 + s * m01; + m[10] = c * m22 + s * m02; + m[11] = c * m23 + s * m03; }; @@ -729,29 +422,25 @@ o3d.Transform.prototype.rotateZ = function(angle) { var m = this.localMatrix; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; var c = Math.cos(angle); var s = Math.sin(angle); - m0.splice(0, 4, c * m00 + s * m10, - c * m01 + s * m11, - c * m02 + s * m12, - c * m03 + s * m13); - m1.splice(0, 4, c * m10 - s * m00, - c * m11 - s * m01, - c * m12 - s * m02, - c * m13 - s * m03); + m[0] = c * m00 + s * m10; + m[1] = c * m01 + s * m11; + m[2] = c * m02 + s * m12; + m[3] = c * m03 + s * m13; + m[4] = c * m10 - s * m00; + m[5] = c * m11 - s * m01; + m[6] = c * m12 - s * m02; + m[7] = c * m13 - s * m03; }; @@ -788,45 +477,37 @@ o3d.Transform.prototype.rotateZYX = var r21 = sinZSinY * cosX - cosZ * sinX; var r22 = cosY * cosX; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - m0.splice(0, 4, - r00 * m00 + r01 * m10 + r02 * m20, - r00 * m01 + r01 * m11 + r02 * m21, - r00 * m02 + r01 * m12 + r02 * m22, - r00 * m03 + r01 * m13 + r02 * m23); - - m1.splice(0, 4, - r10 * m00 + r11 * m10 + r12 * m20, - r10 * m01 + r11 * m11 + r12 * m21, - r10 * m02 + r11 * m12 + r12 * m22, - r10 * m03 + r11 * m13 + r12 * m23); - - m2.splice(0, 4, - r20 * m00 + r21 * m10 + r22 * m20, - r20 * m01 + r21 * m11 + r22 * m21, - r20 * m02 + r21 * m12 + r22 * m22, - r20 * m03 + r21 * m13 + r22 * m23); + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[0] = r00 * m00 + r01 * m10 + r02 * m20; + m[1] = r00 * m01 + r01 * m11 + r02 * m21; + m[2] = r00 * m02 + r01 * m12 + r02 * m22; + m[3] = r00 * m03 + r01 * m13 + r02 * m23; + + m[4] = r10 * m00 + r11 * m10 + r12 * m20; + m[5] = r10 * m01 + r11 * m11 + r12 * m21; + m[6] = r10 * m02 + r11 * m12 + r12 * m22; + m[7] = r10 * m03 + r11 * m13 + r12 * m23; + + m[8] = r20 * m00 + r21 * m10 + r22 * m20; + m[9] = r20 * m01 + r21 * m11 + r22 * m21; + m[10] = r20 * m02 + r21 * m12 + r22 * m22; + m[11] = r20 * m03 + r21 * m13 + r22 * m23; }; @@ -871,47 +552,36 @@ o3d.Transform.axisRotateMatrix = var r21 = y * z * oneMinusCosine - x * s; var r22 = zz + (1 - zz) * c; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - opt_target[0].splice(0, 4, - r00 * m00 + r01 * m10 + r02 * m20, - r00 * m01 + r01 * m11 + r02 * m21, - r00 * m02 + r01 * m12 + r02 * m22, - r00 * m03 + r01 * m13 + r02 * m23); - - opt_target[1].splice(0, 4, - r10 * m00 + r11 * m10 + r12 * m20, - r10 * m01 + r11 * m11 + r12 * m21, - r10 * m02 + r11 * m12 + r12 * m22, - r10 * m03 + r11 * m13 + r12 * m23); - - opt_target[2].splice(0, 4, - r20 * m00 + r21 * m10 + r22 * m20, - r20 * m01 + r21 * m11 + r22 * m21, - r20 * m02 + r21 * m12 + r22 * m22, - r20 * m03 + r21 * m13 + r22 * m23); - - opt_target[3].splice(0, 4, m30, m31, m32, m33); + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[0] = r00 * m00 + r01 * m10 + r02 * m20; + m[1] = r00 * m01 + r01 * m11 + r02 * m21; + m[2] = r00 * m02 + r01 * m12 + r02 * m22; + m[3] = r00 * m03 + r01 * m13 + r02 * m23; + m[4] = r10 * m00 + r11 * m10 + r12 * m20; + m[5] = r10 * m01 + r11 * m11 + r12 * m21; + m[6] = r10 * m02 + r11 * m12 + r12 * m22; + m[7] = r10 * m03 + r11 * m13 + r12 * m23; + + m[8] = r20 * m00 + r21 * m10 + r22 * m20; + m[9] = r20 * m01 + r21 * m11 + r22 * m21; + m[10] = r20 * m02 + r21 * m12 + r22 * m22; + m[11] = r20 * m03 + r21 * m13 + r22 * m23; }; @@ -950,17 +620,17 @@ o3d.Transform.prototype.quaternionRotate = var d = qWqW + qXqX + qYqY + qZqZ; - o3d.Transform.compose(this.localMatrix, [ - [(qWqW + qXqX - qYqY - qZqZ) / d, + o3d.Transform.compose_(this.localMatrix, o3d.Transform.makeMatrix4_( + (qWqW + qXqX - qYqY - qZqZ) / d, 2 * (qWqZ + qXqY) / d, - 2 * (qXqZ - qWqY) / d, 0], - [2 * (qXqY - qWqZ) / d, + 2 * (qXqZ - qWqY) / d, 0, + 2 * (qXqY - qWqZ) / d, (qWqW - qXqX + qYqY - qZqZ) / d, - 2 * (qWqX + qYqZ) / d, 0], - [2 * (qWqY + qXqZ) / d, + 2 * (qWqX + qYqZ) / d, 0, + 2 * (qWqY + qXqZ) / d, 2 * (qYqZ - qWqX) / d, - (qWqW - qXqX - qYqY + qZqZ) / d, 0], - [0, 0, 0, 1]]); + (qWqW - qXqX - qYqY + qZqZ) / d, 0, + 0, 0, 0, 1)); }; @@ -984,32 +654,18 @@ o3d.Transform.prototype.scale = var v1 = v[1]; var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - m0.splice(0, 4, v0 * m0[0], v0 * m0[1], v0 * m0[2], v0 * m0[3]); - m1.splice(0, 4, v1 * m1[0], v1 * m1[1], v1 * m1[2], v1 * m1[3]); - m2.splice(0, 4, v2 * m2[0], v2 * m2[1], v2 * m2[2], v2 * m2[3]); -}; - - -/** - * Utility function to flatten an o3djs-style matrix - * (which is an array of arrays) into one array of entries. - * @param {Array.<Array.<number> >} m The o3djs-style matrix. - * @return {Array.<number>} The flattened matrix. - */ -o3d.Transform.flattenMatrix4 = function(m) { - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - return [m0[0], m0[1], m0[2], m0[3], - m1[0], m1[1], m1[2], m1[3], - m2[0], m2[1], m2[2], m2[3], - m3[0], m3[1], m3[2], m3[3]]; + m[0] = v0 * m[0]; + m[1] = v0 * m[1]; + m[2] = v0 * m[2]; + m[3] = v0 * m[3]; + m[4] = v1 * m[4]; + m[5] = v1 * m[5]; + m[6] = v1 * m[6]; + m[7] = v1 * m[7]; + m[8] = v2 * m[8]; + m[9] = v2 * m[9]; + m[10] = v2 * m[10]; + m[11] = v2 * m[11]; }; @@ -1027,10 +683,9 @@ o3d.Transform.prototype.traverse = return; } opt_parentWorldMatrix = - opt_parentWorldMatrix || - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + opt_parentWorldMatrix || o3d.Transform.makeIdentityMatrix4_(); - o3d.Transform.compose( + o3d.Transform.compose_( opt_parentWorldMatrix, this.localMatrix, this.worldMatrix); var remainingDrawListInfos = []; @@ -1040,10 +695,10 @@ o3d.Transform.prototype.traverse = for (var i = 0; i < drawListInfos.length; ++i) { var drawListInfo = drawListInfos[i]; - var worldViewProjection = [[], [], [], []]; - o3d.Transform.compose(drawListInfo.context.view, + var worldViewProjection = o3d.Transform.makeNullMatrix4_(); + o3d.Transform.compose_(drawListInfo.context.view, this.worldMatrix, worldViewProjection); - o3d.Transform.compose(drawListInfo.context.projection, + o3d.Transform.compose_(drawListInfo.context.projection, worldViewProjection, worldViewProjection); if (this.boundingBox.inFrustum(worldViewProjection)) { @@ -1073,3 +728,643 @@ o3d.Transform.prototype.traverse = }; +/** + * Tells the o3d-webgl subsection if it should use native javascript + * arrays or if it should switch to the newer Float32Array, which help the + * interpreter, once created, but can require a lot of gc work to allocate + * and deallocate. + * @type {boolean} + */ +o3d.Transform.useFloat32Array_ = false; + + +/** + * This defines the type of any given Matrix4 + * @type {!Array.<number>|!Float32Array} + */ +o3d.Transform.Matrix4 = goog.typedef; + + +/** + * This returns an identity 4x4 matrix with + * the diagonal as 1's and everything else 0 + * @return {!o3d.Transform.Matrix4} + * @private + */ +o3d.Transform.makeIdentityMatrix4_ = null; + + +/** + * This returns a 4x4 matrix with all values set to zero + * @return {!o3d.Transform.Matrix4} the vector made up of the elements + * @private + */ +o3d.Transform.makeNullMatrix4_ = null; + + +/** + * This returns a length 2 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ +o3d.Transform.makeVector2_ = null; + + +/** + * This returns a length 3 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ +o3d.Transform.makeVector3_ = null; + + +/** + * This returns a length 4 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @param {number} d the w element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ +o3d.Transform.makeVector4_ = null; + + +/** + * This returns a 4x4 matrix in row major order + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * @return {!o3d.Transform.Matrix4} + */ +o3d.Transform.makeMatrix4_ = null; + + +// If Float32Array isn't defined we might as well not bother including the +// Float32Array functions. +if (window.Float32Array != undefined) { + /** + * A namespace to hold Float32Array-specialized functions. + * @namespace + * @private + */ + o3d.Transform.Float32Array_ = {}; + + + /** + * This defines the type of any given Matrix4 in the Float32Array namespace + * @type {function} + * @private + */ + o3d.Transform.Float32Array_.Matrix4 = Float32Array; + + + /** + * This returns an identity 4x4 matrix with + * the diagonal as 1's and everything else 0 + * @return {!o3d.Transform.Matrix4} + * @private + */ + o3d.Transform.Float32Array_.makeIdentityMatrix4_ = function() { + var r = new Float32Array(16); + r[0] = 1; + r[5] = 1; + r[10] = 1; + r[15] = 1; + return r; + }; + + + /** + * This returns a 4x4 matrix with all values set to zero + * @return {!o3d.Transform.Matrix4} the vector made up of the elements + * @private + */ + o3d.Transform.Float32Array_.makeNullMatrix4_ = function() { + return new Float32Array(16); + }; + + + /** + * This returns a length 2 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ + o3d.Transform.Float32Array_.makeVector2_ = function(a, b) { + var f=new Float32Array(2); + f[0] = a; + f[1] = b; + return f; + }; + + + /** + * This returns a length 3 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ + o3d.Transform.Float32Array_.makeVector3_ = function(a, b, c) { + var f=new Float32Array(3); + f[0] = a; + f[1] = b; + f[2] = c; + return f; + }; + + + /** + * This returns a length 4 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @param {number} d the w element in the vector + * @return {!Float32Array} the vector made up of the elements + * @private + */ + o3d.Transform.Float32Array_.makeVector4_ = function(a, b, c, d) { + var f = new Float32Array(4); + f[0] = a; + f[1] = b; + f[2] = c; + f[3] = d; + return f; + }; + + + /** + * This returns a 4x4 matrix in row major order + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * @return {!o3d.Transform.Matrix4} + */ + o3d.Transform.Float32Array_.makeMatrix4_ = + function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + var m = new Float32Array(16); + m[0] = a; + m[1] = b; + m[2] = c; + m[3] = d; + m[4] = e; + m[5] = f; + m[6] = g; + m[7] = h; + m[8] = i; + m[9] = j; + m[10] = k; + m[11] = l; + m[12] = m; + m[13] = n; + m[14] = o; + m[15] = p; + return m; + }; +} else { + // If Float32Array doesn't exist, we cannot use that library. + o3d.Transform.useFloat32Array_ = false; +} + + +/** + * A namespace for Array specialized Transform functions that depend + * on what the matrix type of choice is + * @namespace + * @private + */ +o3d.Transform.Array_ = {}; + +/** + * This returns a length 3 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @return {!Array} the vector made up of the elements + * @private + */ +o3d.Transform.Array_.makeVector2_ = function(a, b) { + return [a,b]; +}; + +/** + * This returns a length 3 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @return {!Array} the vector made up of the elements + * @private + */ +o3d.Transform.Array_.makeVector3_ = function(a, b, c) { + return [a, b, c]; +}; + +/** + * This returns a length 4 vector with values set to the passed in arguments + * @param {number} a the x element in the vector + * @param {number} b the y element in the vector + * @param {number} c the z element in the vector + * @param {number} d the w element in the vector + * @return {!Array} the vector made up of the elements + * @private + */ +o3d.Transform.Array_.makeVector4_ = function(a, b, c, d) { + return [a, b, c, d]; +}; + +/** + * This returns a 4x4 matrix in row major order + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * @return {!o3d.Transform.Matrix4} + * @private + */ +o3d.Transform.Array_.makeMatrix4_ = + function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + return [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]; +}; + +o3d.Transform.Array_.Matrix4_ = Array; + +/** + * This returns an identity 4x4 matrix with + * the diagonal as 1's and everything else 0 + * @return {!o3d.Transform.Matrix4} + */ +o3d.Transform.Array_.makeIdentityMatrix4_ = function() { + return [1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1]; +}; + + +/** + * This returns an identity 4x4 matrix with all values as 0 + * @return {!o3d.Transform.Matrix4} + */ +o3d.Transform.Array_.makeNullMatrix4_ = function() { + return [0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0]; +}; + + +if (o3d.Transform.useFloat32Array_) { + for (var i in o3d.Transform.Float32Array_) { + o3d.Transform[i] = o3d.Transform.Float32Array_[i]; + } +} else { + for (var i in o3d.Transform.Array_) { + o3d.Transform[i] = o3d.Transform.Array_[i]; + } +} + + +/* + * Utility function to copose a matrix with another matrix. + * Precomposes b with a, changing a, or if the target matrix if + * one is provided. + * + * @param {!Array.<!Array.<number>>} a + * @param {!Array.<!Array.<number>>} b + * @param {!Array.<!Array.<number>>} opt_target + * @private + */ +o3d.Transform.compose_ = function(a, b, opt_target) { + var t = opt_target || a; + + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + var a30 = a[12]; + var a31 = a[13]; + var a32 = a[14]; + var a33 = a[15]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b03 = b[3]; + var b10 = b[4]; + var b11 = b[5]; + var b12 = b[6]; + var b13 = b[7]; + var b20 = b[8]; + var b21 = b[9]; + var b22 = b[10]; + var b23 = b[11]; + var b30 = b[12]; + var b31 = b[13]; + var b32 = b[14]; + var b33 = b[15]; + t[0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; + t[1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; + t[2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; + t[3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; + t[4] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; + t[5] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; + t[6] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; + t[7] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; + t[8] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; + t[9] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; + t[10] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; + t[11] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; + t[12] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + t[13] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + t[14] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + t[15] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; +}; + + +/** + * Tests whether two matrices are either equal in the sense that they + * refer to the same memory, or equal in the sense that they have equal + * entries. + * + * @param {!Array.<!Array.<number>>} a A matrix. + * @param {!Array.<!Array.<number>>} b Another matrix. + * @return {boolean} Whether they are equal. + * @private + */ +o3d.Transform.matricesEqual_ = function(a, b) { + if (a==b) { + return true; + } + for (var i = 0; i < 16; ++i) { + if (a[i] != b[i]) { + return false; + } + } + + return true; +}; + + +/** + * Computes the transpose of the matrix a in place if no target is provided. + * Or if a target is provided, turns the target into the transpose of a. + * + * @param {!Array.<!Array.<number>>} m A matrix. + * @param {Array.<!Array.<number>>} opt_target + * The matrix to become the transpose of m. + * @private + */ +o3d.Transform.transpose_ = function(m, opt_target) { + var t = opt_target || m; + + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + t[0] = m00; + t[1] = m10; + t[2] = m20; + t[3] = m30; + + t[4] = m01; + t[5] = m11; + t[6] = m21; + t[7] = m31; + + t[8] = m02; + t[9] = m12; + t[10] = m22; + t[11] = m32; + + t[12] = m03; + t[13] = m13; + t[14] = m23; + t[15] = m33; +}; + + +/** + * Computes the inverse of the matrix a in place if no target is provided. + * Or if a target is provided, turns the target into the transpose of a. + * + * @param {!Array.<!Array.<number>>} m A matrix. + * @param {Array.<!Array.<number>>} opt_target The matrix to become the + * inverse of a. + */ +o3d.Transform.inverse_ = function(m, opt_target) { + var t = opt_target || m; + + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + var tmp_0 = m22 * m33; + var tmp_1 = m32 * m23; + var tmp_2 = m12 * m33; + var tmp_3 = m32 * m13; + var tmp_4 = m12 * m23; + var tmp_5 = m22 * m13; + var tmp_6 = m02 * m33; + var tmp_7 = m32 * m03; + var tmp_8 = m02 * m23; + var tmp_9 = m22 * m03; + var tmp_10 = m02 * m13; + var tmp_11 = m12 * m03; + var tmp_12 = m20 * m31; + var tmp_13 = m30 * m21; + var tmp_14 = m10 * m31; + var tmp_15 = m30 * m11; + var tmp_16 = m10 * m21; + var tmp_17 = m20 * m11; + var tmp_18 = m00 * m31; + var tmp_19 = m30 * m01; + var tmp_20 = m00 * m21; + var tmp_21 = m20 * m01; + var tmp_22 = m00 * m11; + var tmp_23 = m10 * m01; + + var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - + (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); + var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - + (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); + var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - + (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); + var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - + (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); + + var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); + + t[0] = d * t0; + t[1] = d * t1; + t[2] = d * t2; + t[3] = d * t3; + t[4] = d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - + (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)); + t[5] = d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - + (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)); + t[6] = d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - + (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)); + t[7] = d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - + (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)); + t[8] = d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - + (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)); + t[9] = d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - + (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)); + t[10] = d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - + (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)); + t[11] = d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - + (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)); + t[12] = d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - + (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)); + t[13] = d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - + (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)); + t[14] = d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - + (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)); + t[15] = d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - + (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02)); +}; + + +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, + * interprets the vector as a point, transforms that point by the matrix, and + * returns the result as a vector with 3 entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v The point. + * @return {!o3djs.math.Vector3} The transformed point. + * @private + */ +o3d.Transform.transformPoint_ = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + + var d = v0 * m[3] + v1 * m[7] + v2 * m[11] + m[15]; + return o3d.Transform.makeVector3_( + (v0 * m[0] + v1 * m[4] + v2 * m[8] + m[12]) / d, + (v0 * m[1] + v1 * m[5] + v2 * m[9] + m[13]) / d, + (v0 * m[2] + v1 * m[6] + v2 * m[10] + m[14]) / d); +}; + + +/** + * Takes a 4-by-4 matrix and a vector with 4 entries, + * interprets the vector as a point, transforms that point by the matrix, and + * returns the result as a vector with 4 entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector4} v The vector. + * @return {!o3djs.math.Vector4} The transformed vector. + * @private + */ +o3d.Transform.multiplyVector_ = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var v3 = v[3]; + + return o3d.Transform.makeVector4_( + (v0 * m[0] + v1 * m[4] + v2 * m[8] + v3 * m[12]), + (v0 * m[1] + v1 * m[5] + v2 * m[9] + v3 * m[13]), + (v0 * m[2] + v1 * m[6] + v2 * m[10] + v3 * m[14]), + (v0 * m[3] + v1 * m[7] + v2 * m[11] + v3 * m[15])); +}; + + +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, + * interprets the vector as a point, transforms that point by the matrix, + * returning the z-component of the result only. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v The point. + * @return {number} The z coordinate of the transformed point. + * @private + */ +o3d.Transform.transformPointZOnly_ = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + + return (v0 * m[2] + v1 * m[6] + v2 * m[10] + m[14]) / + (v0 * m[3] + v1 * m[7] + v2 * m[11] + m[15]); +}; diff --git a/o3d/samples/o3djs/canvas.js b/o3d/samples/o3djs/canvas.js index 2d83718..fce83b4 100644 --- a/o3d/samples/o3djs/canvas.js +++ b/o3d/samples/o3djs/canvas.js @@ -241,10 +241,10 @@ o3djs.canvas.CanvasInfo = function(pack, root, viewInfo) { 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0 ,0, + 0, 0, 0, 1)); /** * A shape for opaque quads. @@ -257,10 +257,10 @@ o3djs.canvas.CanvasInfo = function(pack, root, viewInfo) { 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [0, 0, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0 ,0, + 0, 0, 0, 1)); }; /** * The CanvasQuad object encapsulates a Transform, a rectangle Shape, diff --git a/o3d/samples/o3djs/debug.js b/o3d/samples/o3djs/debug.js index b1730ab..f646d90 100644 --- a/o3d/samples/o3djs/debug.js +++ b/o3d/samples/o3djs/debug.js @@ -258,10 +258,10 @@ o3djs.debug.DebugLine.prototype.update_ = function() { perp2 = math.cross(perp1, direction); } this.transform_.localMatrix = - [perp2.concat(0), - direction.concat(0), - perp1.concat(0), - this.start_.concat(1)]; + o3djs.math.makeMatrix4(perp2[0], perp2[1], perp2[2], 0, + direction[0], direction[1], direction[2], 0, + perp1[0], perp1[1], perp1[2], 0, + this.start_[0], this.start_[1], this.start_[2], 1); this.transform_.scale(1, math.length(vector), 1); }; @@ -517,16 +517,18 @@ o3djs.debug.DebugHelper = function(pack, viewInfo) { // Create the axis shape. for (var ii = 0; ii < O3D_DEBUG_AXIS_INFO_.length; ++ii) { var info = O3D_DEBUG_AXIS_INFO_[ii]; - var cubeShape = o3djs.primitives.createCube(pack, - material, - 1, - [[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [info.offset[0] * 0.5, - info.offset[1] * 0.5, - info.offset[2] * 0.5, - 1]]); + var cubeShape = o3djs.primitives.createCube( + pack, + material, + 1, + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + info.offset[0] * 0.5, + info.offset[1] * 0.5, + info.offset[2] * 0.5, + 1)); + var cube = cubeShape.elements[0]; cube.owner = this.axisShape_; pack.removeObject(cubeShape); diff --git a/o3d/samples/o3djs/fps.js b/o3d/samples/o3djs/fps.js index c8e7888..51c233d 100644 --- a/o3d/samples/o3djs/fps.js +++ b/o3d/samples/o3djs/fps.js @@ -251,10 +251,10 @@ o3djs.fps.FPSManager = function(pack, clientWidth, clientHeight, opt_parent) { 1, 1, 1, - [[1, 0, 0, 0], - [0, 0, 1, 0], - [0, -1, 0, 0], - [0.5, 0.5, 0, 1]]); + o3djs.math.makeMatrix4(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0.5, 0.5, 0, 1)); var barXOffset = 10; var barYOffset = 2; diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js index 8dc7278..4aa300f 100644 --- a/o3d/samples/o3djs/manipulators.js +++ b/o3d/samples/o3djs/manipulators.js @@ -244,8 +244,10 @@ o3djs.manipulators.Line_.prototype.closestPointToRay = function(startPoint, // value of u' is less than zero. var rayDirection = o3djs.math.subVector(endPoint, startPoint); var ddrd = o3djs.math.dot(this.direction_, rayDirection); - var A = [[-o3djs.math.lengthSquared(this.direction_), ddrd], - [ddrd, -o3djs.math.lengthSquared(rayDirection)]]; + var A = o3djs.math.makeMatrix2(-o3djs.math.lengthSquared(this.direction_), + ddrd, + ddrd, + -o3djs.math.lengthSquared(rayDirection)); var det = o3djs.math.det2(A); if (Math.abs(det) < o3djs.manipulators.EPSILON) { return null; diff --git a/o3d/samples/o3djs/math.js b/o3d/samples/o3djs/math.js index e840f23..c37ccb2 100644 --- a/o3d/samples/o3djs/math.js +++ b/o3d/samples/o3djs/math.js @@ -35,21 +35,20 @@ * It adds them to the "math" module on the o3djs object. * * o3djs.math supports a row-major and a column-major mode. In both - * modes, vectors are stored as arrays of numbers, and matrices are stored as - * arrays of arrays of numbers. + * modes, vectors are stored as arrays of numbers, and matrices are also. * * In row-major mode: * - * - Rows of a matrix are sub-arrays. - * - Individual entries of a matrix M get accessed in M[row][column] fashion. - * - Tuples of coordinates are interpreted as row-vectors. + * - Rows of a matrix are neighboring <dimension> elements in the array. + * - Entries of a matrix M get accessed in M[row*dimension+column] fashion. + * - Tuples of coordinates adjacent are interpreted as row-vectors. * - A vector v gets transformed by a matrix M by multiplying in the order v*M. * * In column-major mode: * - * - Columns of a matrix are sub-arrays. - * - Individual entries of a matrix M get accessed in M[column][row] fashion. - * - Tuples of coordinates are interpreted as column-vectors. + * - Columns of a matrix are neighboring <dimension> elements in the array. + * - Entries of a matrix M get accessed in M[column*dimension+row] fashion. + * - Tuples of coordinates adjacent are interpreted as column-vectors. * - A matrix M transforms a vector v by multiplying in the order M*v. * * When a function in o3djs.math requires separate row-major and @@ -96,123 +95,483 @@ * mean all sample code will work even if a line is added which switches major * modes, but it does mean that calls to o3djs still do what they are supposed * to. - * */ -o3djs.provide('o3djs.math'); + +var use_plugin_math = false; + +if ((typeof o3d != 'undefined') && o3d && o3d.Transform && + o3d.Transform.makeIdentityMatrix4_) { + o3djs.provide('o3djs.math'); +} else { + use_plugin_math = true; + o3djs.require('o3djs.plugin_math'); +} + +o3djs.provide("o3djs.flat_math"); /** - * A module for math for o3djs.math. + * A module for math functions where a matrix is represented as a flat + * (1-dimensional) array. * @namespace */ -o3djs.math = o3djs.math || {}; +o3djs.flat_math = o3djs.flat_math || {}; /** * A random seed for the pseudoRandom function. * @private * @type {number} */ -o3djs.math.randomSeed_ = 0; +o3djs.flat_math.randomSeed_ = 0; /** * A constant for the pseudoRandom function * @private * @type {number} */ -o3djs.math.RANDOM_RANGE_ = Math.pow(2, 32); +o3djs.flat_math.RANDOM_RANGE_ = Math.pow(2, 32); /** * Functions which deal with 4-by-4 transformation matrices are kept in their * own namespsace. * @namespace */ -o3djs.math.matrix4 = o3djs.math.matrix4 || {}; +o3djs.flat_math.matrix4 = o3djs.flat_math.matrix4 || {}; /** * Functions that are specifically row major are kept in their own namespace. * @namespace */ -o3djs.math.rowMajor = o3djs.math.rowMajor || {}; +o3djs.flat_math.rowMajor = o3djs.flat_math.rowMajor || {}; /** * Functions that are specifically column major are kept in their own namespace. * @namespace */ -o3djs.math.columnMajor = o3djs.math.columnMajor || {}; +o3djs.flat_math.columnMajor = o3djs.flat_math.columnMajor || {}; /** * Functions that do error checking are stored in their own namespace. * @namespace */ -o3djs.math.errorCheck = o3djs.math.errorCheck || {}; +o3djs.flat_math.errorCheck = o3djs.flat_math.errorCheck || {}; /** * Functions that do no error checking and have a separate version that does in - * o3djs.math.errorCheck are stored in their own namespace. + * o3djs.flat_math.errorCheck are stored in their own namespace. * @namespace */ -o3djs.math.errorCheckFree = o3djs.math.errorCheckFree || {}; +o3djs.flat_math.errorCheckFree = o3djs.flat_math.errorCheckFree || {}; /** - * An Array of 2 floats - * @type {(!Array.<number>|!o3d.Float2)} + * An Float32Array of 2 floats + * @type {(!Float32Array.<number>|!o3d.Float2)} */ -o3djs.math.Vector2 = goog.typedef; +o3djs.flat_math.Vector2 = goog.typedef; /** - * An Array of 3 floats - * @type {(!Array.<number>|!o3d.Float3)} + * An Float32Array of 3 floats + * @type {(!Float32Array.<number>|!o3d.Float3)} */ -o3djs.math.Vector3 = goog.typedef; +o3djs.flat_math.Vector3 = goog.typedef; /** - * An Array of 4 floats - * @type {(!Array.<number>|!o3d.Float4)} + * An Float32Array of 4 floats + * @type {(!Float32Array.<number>|!o3d.Float4)} */ -o3djs.math.Vector4 = goog.typedef; +o3djs.flat_math.Vector4 = goog.typedef; -/** - * An Array of floats. - * @type {!Array.<number>} - */ -o3djs.math.Vector = goog.typedef; /** * A 1x1 Matrix of floats - * @type {!Array.<!Array.<number>>} + * @type {!Array.<number>} */ -o3djs.math.Matrix1 = goog.typedef; +o3djs.flat_math.Matrix1 = goog.typedef; /** * A 2x2 Matrix of floats - * @type {!Array.<!Array.<number>>} + * @type {!Array.<number>} */ -o3djs.math.Matrix2 = goog.typedef; +o3djs.flat_math.Matrix2 = goog.typedef; /** * A 3x3 Matrix of floats - * @type {!Array.<!Array.<number>>} + * @type {!Array.<number>} */ -o3djs.math.Matrix3 = goog.typedef; +o3djs.flat_math.Matrix3 = goog.typedef; /** * A 4x4 Matrix of floats - * @type {(!Array.<!Array.<number>>|!o3d.Matrix4)} + * @type {(!Array.<number>|!o3d.Matrix4)} + */ +o3djs.flat_math.Matrix4 = goog.typedef; + +o3djs.flat_math.useFloat32Array_ = false; + +/** + * A arbitrary size Matrix of floats + * @type {(!Array.<number>|!o3d.Matrix4)} */ -o3djs.math.Matrix4 = goog.typedef; +o3djs.flat_math.Matrix = goog.typedef; + +/** + * A arbitrary size Matrix of floats + * @type {(!Array.<number>)} + */ +o3djs.flat_math.Vector = goog.typedef; + + +/** + * Namespace for Float32Array specific math functions + */ +o3djs.flat_math.Float32Array = {}; + +/** + * A arbitrary size Matrix of floats + * @type {(!Array.<number>|!o3d.Matrix4)} + */ +o3djs.flat_math.Float32Array.Matrix = + (use_plugin_math ? goog.typedef : Float32Array); +/** + * An Float32Array of floats. + * @type {!Array.<number>} + */ +o3djs.flat_math.Float32Array.Vector = + (use_plugin_math ? goog.typedef : Float32Array); + +/** + * If 16 arguments, this returns a 4x4 matrix + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * + * If 9 arguments returns a 3x3 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [1][0] element + * @param {number} e [1][1] element + * @param {number} f [1][2] element + * @param {number} g [2][0] element + * @param {number} h [2][1] element + * @param {number} i [2][2] element + + * If 4 arguments returns a 2x2 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [1][0] element + * @param {number} d [1][1] element + * @returns {!o3djs.flat_math.Matrix} + */ +o3djs.flat_math.Float32Array.makeMatrix = function( + a, b, c, d, + e, f, g, h, + i, j, k, l, + m, n, o, p) { + if (p === undefined) { + if (i === undefined) { + var retval = new Float32Array(4); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + return retval; + } + var retval = new Float32Array(9); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + retval[4] = e; + retval[5] = f; + retval[6] = g; + retval[7] = h; + retval[8] = i; + return retval; + } + var retval = new Float32Array(16); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + retval[4] = e; + retval[5] = f; + retval[6] = g; + retval[7] = h; + retval[8] = i; + retval[9] = j; + retval[10] = k; + retval[11] = l; + retval[12] = m; + retval[13] = n; + retval[14] = o; + retval[15] = p; + return retval; +}; + +/** + * returns a 2x2 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [1][0] element + * @param {number} d [1][1] element + * @returns {!o3djs.flat_math.Matrix} + */ +o3djs.flat_math.Float32Array.makeMatrix2 = function(a,b, + c,d) { + var retval = new Float32Array(4); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + return retval; +}; + +/** + * If returns a 3x3 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [1][0] element + * @param {number} e [1][1] element + * @param {number} f [1][2] element + * @param {number} g [2][0] element + * @param {number} h [2][1] element + * @param {number} i [2][2] element + * @return {!o3djs.flat_math.Matrix} the matrix of the above elements + */ +o3djs.flat_math.Float32Array.makeMatrix3 = function( + a, b, c, + d, e, f, + g, h, i) { + var retval = new Float32Array(9); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + retval[4] = e; + retval[5] = f; + retval[6] = g; + retval[7] = h; + retval[8] = i; + return retval; +}; + +/** + * returns a 4x4 matrix + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * @returns {o3djs.flat_math.Matrix} comprised of the above elements + */ +o3djs.flat_math.Float32Array.makeMatrix4 = function( + a, b, c, d, + e, f, g, h, + i, j, k, l, + m, n, o, p) { + var retval = new Float32Array(16); + retval[0] = a; + retval[1] = b; + retval[2] = c; + retval[3] = d; + retval[4] = e; + retval[5] = f; + retval[6] = g; + retval[7] = h; + retval[8] = i; + retval[9] = j; + retval[10] = k; + retval[11] = l; + retval[12] = m; + retval[13] = n; + retval[14] = o; + retval[15] = p; + return retval; +}; + +/** + * Namespace for Array specific math functions + */ +o3djs.flat_math.Array={}; /** * A arbitrary size Matrix of floats * @type {(!Array.<!Array.<number>>|!o3d.Matrix4)} */ -o3djs.math.Matrix = goog.typedef; +o3djs.flat_math.Array.Matrix = (use_plugin_math ? goog.typedef: Array); + +/** + * An Float32Array of floats. + * @type {!Float32Array.<number>} + */ +o3djs.flat_math.Array.Vector = (use_plugin_math ? goog.typedef: Array); + +/** + * If 16 arguments, this returns a 4x4 matrix + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * + * If 9 arguments returns a 3x3 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [1][0] element + * @param {number} e [1][1] element + * @param {number} f [1][2] element + * @param {number} g [2][0] element + * @param {number} h [2][1] element + * @param {number} i [2][2] element + + * If 4 arguments returns a 2x2 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [1][0] element + * @param {number} d [1][1] element + * @returns {!o3djs.flat_math.Matrix} + */ +o3djs.flat_math.Array.makeMatrix = function( + a, b, c, d, + e, f, g, h, + i, j, k, l, + m, n, o, p) { + if (p === undefined) { + if (i === undefined) { + return [a,b,c,d]; + } + return [a, b, c, d, e, f, g, h, i]; + } + return [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]; +}; + +/** + * returns a 2x2 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [1][0] element + * @param {number} d [1][1] element + * @returns {!o3djs.flat_math.Matrix} + */ +o3djs.flat_math.Array.makeMatrix2 = function(a, b, c, d) { + return [a, b, c, d]; +}; + +/** + * If returns a 3x3 matrix + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [1][0] element + * @param {number} e [1][1] element + * @param {number} f [1][2] element + * @param {number} g [2][0] element + * @param {number} h [2][1] element + * @param {number} i [2][2] element + * @return {!o3djs.flat_math.Matrix} the matrix of the above elements + */ +o3djs.flat_math.Array.makeMatrix3 = function( + a, b, c, + d, e, f, + g, h, i) { + return [a, b, c, d, e, f, g, h, i]; +}; + +/** + * returns a 4x4 matrix + * with values set to the passed in arguments + * @param {number} a [0][0] element + * @param {number} b [0][1] element + * @param {number} c [0][2] element + * @param {number} d [0][3] element + * @param {number} e [1][0] element + * @param {number} f [1][1] element + * @param {number} g [1][2] element + * @param {number} h [1][3] element + * @param {number} i [2][0] element + * @param {number} j [2][1] element + * @param {number} k [2][2] element + * @param {number} l [2][3] element + * @param {number} m [3][0] element + * @param {number} n [3][1] element + * @param {number} o [3][2] element + * @param {number} p [3][3] element + * @returns {o3djs.flat_math.Matrix} comprised of the above elements + */ +o3djs.flat_math.Array.makeMatrix4 = function( + a, b, c, d, + e, f, g, h, + i, j, k, l, + m, n, o, p) { + return [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]; +}; + +if (o3djs.flat_math.useFloat32Array_) { + o3djs.flat_math.Matrix = o3djs.flat_math.Float32Array.Matrix; + o3djs.flat_math.Vector = o3djs.flat_math.Float32Array.Vector; + for (var i in o3djs.flat_math.Float32Array) { + if (o3djs.flat_math.Float32Array[i].call) + o3djs.flat_math[i]=o3djs.flat_math.Float32Array[i]; + } +} else { + o3djs.flat_math.Matrix = o3djs.flat_math.Array.Matrix; + o3djs.flat_math.Vector = o3djs.flat_math.Array.Vector; + for (var i in o3djs.flat_math.Array) { + if (o3djs.flat_math.Array[i].call) + o3djs.flat_math[i]=o3djs.flat_math.Array[i]; + } +} + + + /** * Returns a deterministic pseudorandom number between 0 and 1 * @return {number} a random number between 0 and 1 */ -o3djs.math.pseudoRandom = function() { - var math = o3djs.math; +o3djs.flat_math.pseudoRandom = function() { + var math = o3djs.flat_math; return (math.randomSeed_ = (134775813 * math.randomSeed_ + 1) % math.RANDOM_RANGE_) / math.RANDOM_RANGE_; @@ -221,8 +580,8 @@ o3djs.math.pseudoRandom = function() { /** * Resets the pseudoRandom function sequence. */ -o3djs.math.resetPseudoRandom = function() { - o3djs.math.randomSeed_ = 0; +o3djs.flat_math.resetPseudoRandom = function() { + o3djs.flat_math.randomSeed_ = 0; }; /** @@ -230,7 +589,7 @@ o3djs.math.resetPseudoRandom = function() { * @param {number} degrees A value in degrees. * @return {number} the value in radians. */ -o3djs.math.degToRad = function(degrees) { +o3djs.flat_math.degToRad = function(degrees) { return degrees * Math.PI / 180; }; @@ -239,7 +598,7 @@ o3djs.math.degToRad = function(degrees) { * @param {number} radians A value in radians. * @return {number} the value in degrees. */ -o3djs.math.radToDeg = function(radians) { +o3djs.flat_math.radToDeg = function(radians) { return radians * 180 / Math.PI; }; @@ -252,19 +611,19 @@ o3djs.math.radToDeg = function(radians) { * @param {number} t Interpolation coefficient. * @return {number} The weighted sum of a and b. */ -o3djs.math.lerpScalar = function(a, b, t) { +o3djs.flat_math.lerpScalar = function(a, b, t) { return (1 - t) * a + t * b; }; /** * Adds two vectors; assumes a and b have the same dimension. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. - * @return {!o3djs.math.Vector} The sum of a and b. + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. + * @return {!o3djs.flat_math.Vector} The sum of a and b. */ -o3djs.math.addVector = function(a, b) { - var r = []; +o3djs.flat_math.addVector = function(a, b) { var aLength = a.length; + var r = new o3djs.flat_math.Vector(aLength); for (var i = 0; i < aLength; ++i) r[i] = a[i] + b[i]; return r; @@ -272,30 +631,43 @@ o3djs.math.addVector = function(a, b) { /** * Subtracts two vectors. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. - * @return {!o3djs.math.Vector} The difference of a and b. + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. + * @return {!o3djs.flat_math.Vector} The difference of a and b. */ -o3djs.math.subVector = function(a, b) { - var r = []; +o3djs.flat_math.subVector = function(a, b) { var aLength = a.length; + var r = new o3djs.flat_math.Vector(aLength); for (var i = 0; i < aLength; ++i) r[i] = a[i] - b[i]; return r; }; /** + * Subtracts two 3d vectors. + * @param {!o3djs.flat_math.Vector3} a Operand vector. + * @param {!o3djs.flat_math.Vector3} b Operand vector. + * @return {!o3djs.flat_math.Vector3} The difference of a and b. + */ +o3djs.flat_math.subVector3 = function(a, b) { + var r = new o3djs.flat_math.Vector(3); + for (var i = 0; i < 3; ++i) + r[i] = a[i] - b[i]; + return r; +}; + +/** * Performs linear interpolation on two vectors. * Given vectors a and b and interpolation coefficient t, returns * (1 - t) * a + t * b. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. * @param {number} t Interpolation coefficient. - * @return {!o3djs.math.Vector} The weighted sum of a and b. + * @return {!o3djs.flat_math.Vector} The weighted sum of a and b. */ -o3djs.math.lerpVector = function(a, b, t) { - var r = []; +o3djs.flat_math.lerpVector = function(a, b, t) { var aLength = a.length; + var r = new o3djs.flat_math.Vector(aLength); for (var i = 0; i < aLength; ++i) r[i] = (1 - t) * a[i] + t * b[i]; return r; @@ -308,7 +680,7 @@ o3djs.math.lerpVector = function(a, b, t) { * @param {number} opt_rangeStart start of range. Default = 0. * @return {number} Clamp modded value. */ -o3djs.math.modClamp = function(v, range, opt_rangeStart) { +o3djs.flat_math.modClamp = function(v, range, opt_rangeStart) { var start = opt_rangeStart || 0; if (range < 0.00001) { return start; @@ -332,9 +704,9 @@ o3djs.math.modClamp = function(v, range, opt_rangeStart) { * @param {number} range Range of circle. * @return {number} lerped result. */ -o3djs.math.lerpCircular = function(a, b, t, range) { - a = o3djs.math.modClamp(a, range); - b = o3djs.math.modClamp(b, range); +o3djs.flat_math.lerpCircular = function(a, b, t, range) { + a = o3djs.flat_math.modClamp(a, range); + b = o3djs.flat_math.modClamp(b, range); var delta = b - a; if (Math.abs(delta) > range * 0.5) { if (delta > 0) { @@ -343,7 +715,7 @@ o3djs.math.lerpCircular = function(a, b, t, range) { b += range; } } - return o3djs.math.modClamp(o3djs.math.lerpScalar(a, b, t), range); + return o3djs.flat_math.modClamp(o3djs.flat_math.lerpScalar(a, b, t), range); }; /** @@ -353,17 +725,17 @@ o3djs.math.lerpCircular = function(a, b, t, range) { * @param {number} t Amount to lerp (0 to 1). * @return {number} lerped result. */ -o3djs.math.lerpRadian = function(a, b, t) { - return o3djs.math.lerpCircular(a, b, t, Math.PI * 2); +o3djs.flat_math.lerpRadian = function(a, b, t) { + return o3djs.flat_math.lerpCircular(a, b, t, Math.PI * 2); }; /** * Divides a vector by a scalar. - * @param {!o3djs.math.Vector} v The vector. + * @param {!o3djs.flat_math.Vector} v The vector. * @param {number} k The scalar. - * @return {!o3djs.math.Vector} v The vector v divided by k. + * @return {!o3djs.flat_math.Vector} v The vector v divided by k. */ -o3djs.math.divVectorScalar = function(v, k) { +o3djs.flat_math.divVectorScalar = function(v, k) { var r = []; var vLength = v.length; for (var i = 0; i < vLength; ++i) @@ -374,11 +746,11 @@ o3djs.math.divVectorScalar = function(v, k) { /** * Computes the dot product of two vectors; assumes that a and b have * the same dimension. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. * @return {number} The dot product of a and b. */ -o3djs.math.dot = function(a, b) { +o3djs.flat_math.dot = function(a, b) { var r = 0.0; var aLength = a.length; for (var i = 0; i < aLength; ++i) @@ -389,23 +761,25 @@ o3djs.math.dot = function(a, b) { /** * Computes the cross product of two vectors; assumes both vectors have * three entries. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. - * @return {!o3djs.math.Vector} The vector a cross b. - */ -o3djs.math.cross = function(a, b) { - return [a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0]]; + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. + * @return {!o3djs.flat_math.Vector} The vector a cross b. + */ +o3djs.flat_math.cross = function(a, b) { + var r = new o3djs.flat_math.Vector(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; }; /** * Computes the Euclidean length of a vector, i.e. the square root of the * sum of the squares of the entries. - * @param {!o3djs.math.Vector} a The vector. + * @param {!o3djs.flat_math.Vector} a The vector. * @return {number} The length of a. */ -o3djs.math.length = function(a) { +o3djs.flat_math.length = function(a) { var r = 0.0; var aLength = a.length; for (var i = 0; i < aLength; ++i) @@ -416,10 +790,10 @@ o3djs.math.length = function(a) { /** * Computes the square of the Euclidean length of a vector, i.e. the sum * of the squares of the entries. - * @param {!o3djs.math.Vector} a The vector. + * @param {!o3djs.flat_math.Vector} a The vector. * @return {number} The square of the length of a. */ -o3djs.math.lengthSquared = function(a) { +o3djs.flat_math.lengthSquared = function(a) { var r = 0.0; var aLength = a.length; for (var i = 0; i < aLength; ++i) @@ -429,11 +803,11 @@ o3djs.math.lengthSquared = function(a) { /** * Computes the Euclidean distance between two vectors. - * @param {!o3djs.math.Vector} a A vector. - * @param {!o3djs.math.Vector} b A vector. + * @param {!o3djs.flat_math.Vector} a A vector. + * @param {!o3djs.flat_math.Vector} b A vector. * @return {number} The distance between a and b. */ -o3djs.math.distance = function(a, b) { +o3djs.flat_math.distance = function(a, b) { var r = 0.0; var aLength = a.length; for (var i = 0; i < aLength; ++i) { @@ -445,11 +819,11 @@ o3djs.math.distance = function(a, b) { /** * Computes the square of the Euclidean distance between two vectors. - * @param {!o3djs.math.Vector} a A vector. - * @param {!o3djs.math.Vector} b A vector. + * @param {!o3djs.flat_math.Vector} a A vector. + * @param {!o3djs.flat_math.Vector} b A vector. * @return {number} The distance between a and b. */ -o3djs.math.distanceSquared = function(a, b) { +o3djs.flat_math.distanceSquared = function(a, b) { var r = 0.0; var aLength = a.length; for (var i = 0; i < aLength; ++i) { @@ -461,59 +835,48 @@ o3djs.math.distanceSquared = function(a, b) { /** * Divides a vector by its Euclidean length and returns the quotient. - * @param {!o3djs.math.Vector} a The vector. - * @return {!o3djs.math.Vector} The normalized vector. + * @param {!o3djs.flat_math.Vector} a The vector. + * @return {!o3djs.flat_math.Vector} The normalized vector. */ -o3djs.math.normalize = function(a) { - var r = []; - var n = 0.0; +o3djs.flat_math.normalize = function(a) { var aLength = a.length; - for (var i = 0; i < aLength; ++i) + var r = new o3djs.flat_math.Vector(aLength); + var n = 0.0; + var i; + for (i = 0; i < aLength; ++i) n += a[i] * a[i]; n = Math.sqrt(n); - for (var i = 0; i < aLength; ++i) + for (i = 0; i < aLength; ++i) r[i] = a[i] / n; return r; }; /** * Adds two matrices; assumes a and b are the same size. - * @param {!o3djs.math.Matrix} a Operand matrix. - * @param {!o3djs.math.Matrix} b Operand matrix. - * @return {!o3djs.math.Matrix} The sum of a and b. + * @param {!o3djs.flat_math.Matrix} a Operand matrix. + * @param {!o3djs.flat_math.Matrix} b Operand matrix. + * @return {!o3djs.flat_math.Matrix} The sum of a and b. */ -o3djs.math.addMatrix = function(a, b) { - var r = []; +o3djs.flat_math.addMatrix = function(a, b) { var aLength = a.length; - var a0Length = a[0].length; + var r = new o3djs.flat_math.Matrix(aLength); for (var i = 0; i < aLength; ++i) { - var row = []; - var ai = a[i]; - var bi = b[i]; - for (var j = 0; j < a0Length; ++j) - row[j] = ai[j] + bi[j]; - r[i] = row; + r[i] = a[i] + b[i]; } return r; }; /** * Subtracts two matrices; assumes a and b are the same size. - * @param {!o3djs.math.Matrix} a Operand matrix. - * @param {!o3djs.math.Matrix} b Operand matrix. - * @return {!o3djs.math.Matrix} The sum of a and b. + * @param {!o3djs.flat_math.Matrix} a Operand matrix. + * @param {!o3djs.flat_math.Matrix} b Operand matrix. + * @return {!o3djs.flat_math.Matrix} The sum of a and b. */ -o3djs.math.subMatrix = function(a, b) { - var r = []; +o3djs.flat_math.subMatrix = function(a, b) { var aLength = a.length; - var a0Length = a[0].length; + var r = new o3djs.flat_math.Matrix(aLength); for (var i = 0; i < aLength; ++i) { - var row = []; - var ai = a[i]; - var bi = b[i]; - for (var j = 0; j < a0Length; ++j) - row[j] = ai[j] - bi[j]; - r[i] = row; + r[i] = a[i] - b[i]; } return r; }; @@ -522,40 +885,31 @@ o3djs.math.subMatrix = function(a, b) { * Performs linear interpolation on two matrices. * Given matrices a and b and interpolation coefficient t, returns * (1 - t) * a + t * b. - * @param {!o3djs.math.Matrix} a Operand matrix. - * @param {!o3djs.math.Matrix} b Operand matrix. + * @param {!o3djs.flat_math.Matrix} a Operand matrix. + * @param {!o3djs.flat_math.Matrix} b Operand matrix. * @param {number} t Interpolation coefficient. - * @return {!o3djs.math.Matrix} The weighted of a and b. + * @return {!o3djs.flat_math.Matrix} Interpolated a and b. */ -o3djs.math.lerpMatrix = function(a, b, t) { - var r = []; +o3djs.flat_math.lerpMatrix = function(a, b, t) { var aLength = a.length; - var a0Length = a[0].length; + var r = new o3djs.flat_math.Matrix(aLength); for (var i = 0; i < aLength; ++i) { - var row = []; - var ai = a[i]; - var bi = b[i]; - for (var j = 0; j < a0Length; ++j) - row[j] = (1 - t) * ai[j] + t * bi[j]; - r[i] = row; + r[i] = (1 - t) * a[i] + t * b[i]; } return r; }; /** - * Divides a matrix by a scalar. - * @param {!o3djs.math.Matrix} m The matrix. - * @param {number} k The scalar. - * @return {!o3djs.math.Matrix} The matrix m divided by k. + * Divides a matrix by a scalar; assumes a and b are the same size. + * @param {!o3djs.flat_math.Matrix} a Operand matrix. + * @param {number} b scalar + * @return {!o3djs.flat_math.Matrix} The division of a by b. */ -o3djs.math.divMatrixScalar = function(m, k) { - var r = []; - var mLength = m.length; - var m0Length = m[0].length; - for (var i = 0; i < mLength; ++i) { - r[i] = []; - for (var j = 0; j < m0Length; ++j) - r[i][j] = m[i][j] / k; +o3djs.flat_math.divMatrixScalar = function(a, b) { + var aLength = a.length; + var r = new o3djs.flat_math.Matrix(aLength); + for (var i = 0; i < aLength; ++i) { + r[i] = a[i] / b; } return r; }; @@ -565,18 +919,18 @@ o3djs.math.divMatrixScalar = function(m, k) { * @param {number} a The scalar. * @return {number} -a. */ -o3djs.math.negativeScalar = function(a) { +o3djs.flat_math.negativeScalar = function(a) { return -a; }; /** * Negates a vector. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} -v. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} -v. */ -o3djs.math.negativeVector = function(v) { - var r = []; +o3djs.flat_math.negativeVector = function(v) { var vLength = v.length; + var r = new o3djs.flat_math.Vector(vLength); for (var i = 0; i < vLength; ++i) { r[i] = -v[i]; } @@ -585,17 +939,14 @@ o3djs.math.negativeVector = function(v) { /** * Negates a matrix. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} -m. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} -m. */ -o3djs.math.negativeMatrix = function(m) { - var r = []; +o3djs.flat_math.negativeMatrix = function(m) { var mLength = m.length; - var m0Length = m[0].length; + var r = new o3djs.flat_math.Matrix(mLength); for (var i = 0; i < mLength; ++i) { - r[i] = []; - for (var j = 0; j < m0Length; ++j) - r[i][j] = -m[i][j]; + r[i] = -m[i]; } return r; }; @@ -605,57 +956,56 @@ o3djs.math.negativeMatrix = function(m) { * @param {number} a The scalar. * @return {number} a. */ -o3djs.math.copyScalar = function(a) { +o3djs.flat_math.copyScalar = function(a) { return a; }; /** * Copies a vector. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} A copy of v. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} A copy of v. */ -o3djs.math.copyVector = function(v) { - var r = []; - for (var i = 0; i < v.length; i++) +o3djs.flat_math.copyVector = function(v) { + var vLength = v.length; + var r = new o3djs.flat_math.Vector(vLength); + for (var i = 0; i < vLength; i++) r[i] = v[i]; return r; }; /** - * Copies a matrix. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} A copy of m. + * Copies a vector. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Vector} r Set to a copy of v. */ -o3djs.math.copyMatrix = function(m) { - var r = []; - var mLength = m.length; - for (var i = 0; i < mLength; ++i) { - r[i] = []; - for (var j = 0; j < m[i].length; j++) { - r[i][j] = m[i][j]; - } - } - return r; +o3djs.flat_math.copyVectorTo = function(v, r) { + var vLength = v.length; + for (var i = 0; i < vLength; i++) + r[i] = v[i]; }; /** - * Returns the elements of a matrix as a one-dimensional array. The + * Copies a matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} A copy of m. + */ +o3djs.flat_math.copyMatrix = o3djs.flat_math.copyVector; + +/** + * Copies a matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} A copy of m. + */ +o3djs.flat_math.copyMatrixTo = o3djs.flat_math.copyVectorTo; + +/** + * Returns the elements of a matrix as a copied one-dimensional array. The * rows or columns (depending on whether the matrix is row-major or * column-major) are concatenated. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @return {!Array.<number>} The matrix's elements as a one-dimensional array. */ -o3djs.math.getMatrixElements = function(m) { - var r = []; - var mLength = m.length; - var k = 0; - for (var i = 0; i < mLength; i++) { - for (var j = 0; j < m[i].length; j++) { - r[k++] = m[i][j]; - } - } - return r; -}; +o3djs.flat_math.getMatrixElements = o3djs.flat_math.copyMatrix; /** * Multiplies two scalars. @@ -663,19 +1013,19 @@ o3djs.math.getMatrixElements = function(m) { * @param {number} b Operand scalar. * @return {number} The product of a and b. */ -o3djs.math.mulScalarScalar = function(a, b) { +o3djs.flat_math.mulScalarScalar = function(a, b) { return a * b; }; /** * Multiplies a scalar by a vector. * @param {number} k The scalar. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} The product of k and v. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} The product of k and v. */ -o3djs.math.mulScalarVector = function(k, v) { - var r = []; +o3djs.flat_math.mulScalarVector = function(k, v) { var vLength = v.length; + var r = new o3djs.flat_math.Vector(vLength); for (var i = 0; i < vLength; ++i) { r[i] = k * v[i]; } @@ -684,53 +1034,41 @@ o3djs.math.mulScalarVector = function(k, v) { /** * Multiplies a vector by a scalar. - * @param {!o3djs.math.Vector} v The vector. + * @param {!o3djs.flat_math.Vector} v The vector. * @param {number} k The scalar. - * @return {!o3djs.math.Vector} The product of k and v. + * @return {!o3djs.flat_math.Vector} The product of k and v. */ -o3djs.math.mulVectorScalar = function(v, k) { - return o3djs.math.mulScalarVector(k, v); +o3djs.flat_math.mulVectorScalar = function(v, k) { + return o3djs.flat_math.mulScalarVector(k, v); }; /** * Multiplies a scalar by a matrix. * @param {number} k The scalar. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} The product of m and k. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} The product of m and k. */ -o3djs.math.mulScalarMatrix = function(k, m) { - var r = []; - var mLength = m.length; - var m0Length = m[0].length; - for (var i = 0; i < mLength; ++i) { - r[i] = []; - for (var j = 0; j < m0Length; ++j) - r[i][j] = k * m[i][j]; - } - return r; -}; +o3djs.flat_math.mulScalarMatrix = o3djs.flat_math.mulScalarVector; /** * Multiplies a matrix by a scalar. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} k The scalar. - * @return {!o3djs.math.Matrix} The product of m and k. + * @return {!o3djs.flat_math.Matrix} The product of m and k. */ -o3djs.math.mulMatrixScalar = function(m, k) { - return o3djs.math.mulScalarMatrix(k, m); -}; +o3djs.flat_math.mulMatrixScalar = o3djs.flat_math.mulVectorScalar; /** * Multiplies a vector by another vector (component-wise); assumes a and * b have the same length. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. - * @return {!o3djs.math.Vector} The vector of products of entries of a and + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. + * @return {!o3djs.flat_math.Vector} The vector of products of entries of a and * b. */ -o3djs.math.mulVectorVector = function(a, b) { - var r = []; +o3djs.flat_math.mulVectorVector = function(a, b) { var aLength = a.length; + var r = new o3djs.flat_math.Vector(aLength); for (var i = 0; i < aLength; ++i) r[i] = a[i] * b[i]; return r; @@ -739,14 +1077,14 @@ o3djs.math.mulVectorVector = function(a, b) { /** * Divides a vector by another vector (component-wise); assumes a and * b have the same length. - * @param {!o3djs.math.Vector} a Operand vector. - * @param {!o3djs.math.Vector} b Operand vector. - * @return {!o3djs.math.Vector} The vector of quotients of entries of a and + * @param {!o3djs.flat_math.Vector} a Operand vector. + * @param {!o3djs.flat_math.Vector} b Operand vector. + * @return {!o3djs.flat_math.Vector} The vector of quotients of entries of a and * b. */ -o3djs.math.divVectorVector = function(a, b) { - var r = []; +o3djs.flat_math.divVectorVector = function(a, b) { var aLength = a.length; + var r = new o3djs.flat_math.Vector(aLength); for (var i = 0; i < aLength; ++i) r[i] = a[i] / b[i]; return r; @@ -754,398 +1092,490 @@ o3djs.math.divVectorVector = function(a, b) { /** * Multiplies a vector by a matrix; treats the vector as a row vector; assumes - * matrix entries are accessed in [row][column] fashion. - * @param {!o3djs.math.Vector} v The vector. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Vector} The product of v and m as a row vector. + * matrix entries are accessed in [row*4+column] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Vector} The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulVectorMatrix4 = function(v, m) { + var r = new o3djs.flat_math.Vector(16); + for (var i = 0; i < 4; ++i) { + r[i] = 0.0; + for (var j = 0; j < 4; ++j) + r[i] += v[j] * m[j * 4 + i]; + } + return r; +}; + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [row*2+column] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @returns {!o3djs.flat_math.Vector} The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulVectorMatrix2 = function(v, m) { + var r = new o3djs.flat_math.Vector(4); + for (var i = 0; i < 2; ++i) { + r[i] = 0.0; + for (var j = 0; j < 2; ++j) + r[i] += v[j] * m[j * 2 + i]; + } + return r; +}; + + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [row*3+column] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @returns {!o3djs.flat_math.Vector} The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulVectorMatrix3 = function(v, m) { + var r = new o3djs.flat_math.Vector(9); + for (var i = 0; i < 3; ++i) { + r[i] = 0.0; + for (var j = 0; j < 3; ++j) + r[i] += v[j] * m[j * 3 + i]; + } + return r; +}; + + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [row*dimension+column] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Vector} The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulVectorMatrix = function(v, m) { + switch(m.length) { + case 4: + return o3djs.flat_math.rowMajor.mulVectorMatrix2(v, m); + case 9: + return o3djs.flat_math.rowMajor.mulVectorMatrix3(v, m); + case 16: + return o3djs.flat_math.rowMajor.mulVectorMatrix4(v, m); + default: + throw "Cannot handle matrices of size other than 3x3 or 4x4"; + } +}; + + + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [column*4+row] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} r The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulMatrixVector4 = function(m, v) { + var r = new o3djs.flat_math.Vector(4); + var vLength = v.length; + for (var i = 0; i < 4; ++i) { + r[i] = 0.0; + for (var j = 0; j < 4; ++j) + r[i] += v[j] * m[i * 4 + j]; + } + return r; +}; + + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [column*3+row] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} r The product of v and m as a row vector. */ -o3djs.math.rowMajor.mulVectorMatrix = function(v, m) { - var r = []; - var m0Length = m[0].length; +o3djs.flat_math.rowMajor.mulMatrixVector3 = function(m, v) { + var r = new o3djs.flat_math.Vector(3); var vLength = v.length; - for (var i = 0; i < m0Length; ++i) { + for (var i = 0; i < 3; ++i) { r[i] = 0.0; - for (var j = 0; j < vLength; ++j) - r[i] += v[j] * m[j][i]; + for (var j = 0; j < 3; ++j) + r[i] += v[j] * m[i * 3 + j]; } return r; }; /** * Multiplies a vector by a matrix; treats the vector as a row vector; assumes - * matrix entries are accessed in [column][row] fashion. - * @param {!o3djs.math.Vector} v The vector. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Vector} The product of v and m as a row vector. + * matrix entries are accessed in [column*2+row] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} r The product of v and m as a row vector. */ -o3djs.math.columnMajor.mulVectorMatrix = function(v, m) { - var r = []; - var mLength = m.length; +o3djs.flat_math.rowMajor.mulMatrixVector2 = function(m, v) { + var r = new o3djs.flat_math.Vector(2); + var vLength = v.length; - for (var i = 0; i < mLength; ++i) { + for (var i = 0; i < 2; ++i) { r[i] = 0.0; - var column = m[i]; - for (var j = 0; j < vLength; ++j) - r[i] += v[j] * column[j]; + for (var j = 0; j < 2; ++j) + r[i] += v[j] * m[i * 2 + j]; } return r; }; + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [column*dimension+row] fashion. + * @param {!o3djs.flat_math.Vector} v The vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Vector} The product of v and m as a row vector. + */ +o3djs.flat_math.rowMajor.mulMatrixVector = function(m, v) { + switch(m.length) { + case 4: + return o3djs.flat_math.rowMajor.mulMatrixVector2(m, v); + case 9: + return o3djs.flat_math.rowMajor.mulMatrixVector3(m, v); + case 16: + return o3djs.flat_math.rowMajor.mulMatrixVector4(m, v); + default: + throw "Cannot handle matrices of size other than 3x3 or 4x4"; + } +}; + /** * Multiplies a vector by a matrix; treats the vector as a row vector. - * @param {!o3djs.math.Matrix} m The matrix. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} The product of m and v as a row vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} The product of m and v as a row vector. */ -o3djs.math.mulVectorMatrix = null; +o3djs.flat_math.mulVectorMatrix = null; /** * Multiplies a matrix by a vector; treats the vector as a column vector. * assumes matrix entries are accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix} m The matrix. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} The product of m and v as a column vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} The product of m and v as a column vector. */ -o3djs.math.rowMajor.mulMatrixVector = function(m, v) { - var r = []; - var mLength = m.length; - var m0Length = m[0].length; - for (var i = 0; i < mLength; ++i) { - r[i] = 0.0; - var row = m[i]; - for (var j = 0; j < m0Length; ++j) - r[i] += row[j] * v[j]; - } - return r; +o3djs.flat_math.columnMajor.mulVectorMatrix = function (v, m) { + return o3djs.flat_math.rowMajor.mulMatrixVector(m, v); }; /** * Multiplies a matrix by a vector; treats the vector as a column vector; * assumes matrix entries are accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix} m The matrix. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} The product of m and v as a column vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} The product of m and v as a column vector. */ -o3djs.math.columnMajor.mulMatrixVector = function(m, v) { - var r = []; - var m0Length = m[0].length; - var vLength = v.length; - for (var i = 0; i < m0Length; ++i) { - r[i] = 0.0; - for (var j = 0; j < vLength; ++j) - r[i] += v[j] * m[j][i]; - } - return r; +o3djs.flat_math.columnMajor.mulMatrixVector = function(m, v) { + return o3djs.flat_math.rowMajor.mulVectorMatrix(v, m); }; /** * Multiplies a matrix by a vector; treats the vector as a column vector. - * @param {!o3djs.math.Matrix} m The matrix. - * @param {!o3djs.math.Vector} v The vector. - * @return {!o3djs.math.Vector} The product of m and v as a column vector. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Vector} v The vector. + * @return {!o3djs.flat_math.Vector} The product of m and v as a column vector. */ -o3djs.math.mulMatrixVector = null; +o3djs.flat_math.mulMatrixVector = null; /** * Multiplies two 2-by-2 matrices; assumes that the given matrices are 2-by-2; * assumes matrix entries are accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix2} a The matrix on the left. - * @param {!o3djs.math.Matrix2} b The matrix on the right. - * @return {!o3djs.math.Matrix2} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix2} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix2} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix2} The matrix product of a and b. */ -o3djs.math.rowMajor.mulMatrixMatrix2 = function(a, b) { +o3djs.flat_math.rowMajor.mulMatrixMatrix2 = function(a, b) { var a0 = a[0]; var a1 = a[1]; var b0 = b[0]; var b1 = b[1]; - var a00 = a0[0]; - var a01 = a0[1]; - var a10 = a1[0]; - var a11 = a1[1]; - var b00 = b0[0]; - var b01 = b0[1]; - var b10 = b1[0]; - var b11 = b1[1]; - return [[a00 * b00 + a01 * b10, a00 * b01 + a01 * b11], - [a10 * b00 + a11 * b10, a10 * b01 + a11 * b11]]; + var a00 = a[0]; + var a01 = a[1]; + var a10 = a[2]; + var a11 = a[3]; + var b00 = b[0]; + var b01 = b[1]; + var b10 = b[2]; + var b11 = b[3]; + return o3djs.flat_math.makeMatrix2(a00 * b00 + a01 * b10, a00 * b01 + a01 * b11, + a10 * b00 + a11 * b10, a10 * b01 + a11 * b11); }; /** * Multiplies two 2-by-2 matrices; assumes that the given matrices are 2-by-2; * assumes matrix entries are accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix2} a The matrix on the left. - * @param {!o3djs.math.Matrix2} b The matrix on the right. - * @return {!o3djs.math.Matrix2} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix2} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix2} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix2} The matrix product of a and b. */ -o3djs.math.columnMajor.mulMatrixMatrix2 = function(a, b) { +o3djs.flat_math.columnMajor.mulMatrixMatrix2 = function(a, b) { var a0 = a[0]; var a1 = a[1]; var b0 = b[0]; var b1 = b[1]; - var a00 = a0[0]; - var a01 = a0[1]; - var a10 = a1[0]; - var a11 = a1[1]; - var b00 = b0[0]; - var b01 = b0[1]; - var b10 = b1[0]; - var b11 = b1[1]; - return [[a00 * b00 + a10 * b01, a01 * b00 + a11 * b01], - [a00 * b10 + a10 * b11, a01 * b10 + a11 * b11]]; + var a00 = a[0]; + var a01 = a[1]; + var a10 = a[2]; + var a11 = a[3]; + var b00 = b[0]; + var b01 = b[1]; + var b10 = b[2]; + var b11 = b[3]; + return o3djs.flat_math.makeMatrix2(a00 * b00 + a10 * b01, a01 * b00 + a11 * b01, + a00 * b10 + a10 * b11, a01 * b10 + a11 * b11); }; /** * Multiplies two 2-by-2 matrices. - * @param {!o3djs.math.Matrix2} a The matrix on the left. - * @param {!o3djs.math.Matrix2} b The matrix on the right. - * @return {!o3djs.math.Matrix2} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix2} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix2} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix2} The matrix product of a and b. */ -o3djs.math.mulMatrixMatrix2 = null; +o3djs.flat_math.mulMatrixMatrix2 = null; /** * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3; * assumes matrix entries are accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix3} a The matrix on the left. - * @param {!o3djs.math.Matrix3} b The matrix on the right. - * @return {!o3djs.math.Matrix3} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix3} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix3} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix3} The matrix product of a and b. */ -o3djs.math.rowMajor.mulMatrixMatrix3 = function(a, b) { +o3djs.flat_math.rowMajor.mulMatrixMatrix3 = function(a, b) { var a0 = a[0]; var a1 = a[1]; var a2 = a[2]; var b0 = b[0]; var b1 = b[1]; var b2 = b[2]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - return [[a00 * b00 + a01 * b10 + a02 * b20, + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a10 = a[3]; + var a11 = a[4]; + var a12 = a[5]; + var a20 = a[6]; + var a21 = a[7]; + var a22 = a[8]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b10 = b[3]; + var b11 = b[4]; + var b12 = b[5]; + var b20 = b[6]; + var b21 = b[7]; + var b22 = b[8]; + return o3djs.flat_math.makeMatrix3(a00 * b00 + a01 * b10 + a02 * b20, a00 * b01 + a01 * b11 + a02 * b21, - a00 * b02 + a01 * b12 + a02 * b22], - [a10 * b00 + a11 * b10 + a12 * b20, + a00 * b02 + a01 * b12 + a02 * b22, + a10 * b00 + a11 * b10 + a12 * b20, a10 * b01 + a11 * b11 + a12 * b21, - a10 * b02 + a11 * b12 + a12 * b22], - [a20 * b00 + a21 * b10 + a22 * b20, + a10 * b02 + a11 * b12 + a12 * b22, + a20 * b00 + a21 * b10 + a22 * b20, a20 * b01 + a21 * b11 + a22 * b21, - a20 * b02 + a21 * b12 + a22 * b22]]; + a20 * b02 + a21 * b12 + a22 * b22); }; /** * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3; * assumes matrix entries are accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix3} a The matrix on the left. - * @param {!o3djs.math.Matrix3} b The matrix on the right. - * @return {!o3djs.math.Matrix3} The matrix product of a and b. - */ -o3djs.math.columnMajor.mulMatrixMatrix3 = function(a, b) { - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - return [[a00 * b00 + a10 * b01 + a20 * b02, + * @param {!o3djs.flat_math.Matrix3} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix3} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix3} The matrix product of a and b. + */ +o3djs.flat_math.columnMajor.mulMatrixMatrix3 = function(a, b) { + + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a10 = a[3]; + var a11 = a[4]; + var a12 = a[5]; + var a20 = a[6]; + var a21 = a[7]; + var a22 = a[8]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b10 = b[3]; + var b11 = b[4]; + var b12 = b[5]; + var b20 = b[6]; + var b21 = b[7]; + var b22 = b[8]; + + return o3djs.flat_math.makeMatrix4(a00 * b00 + a10 * b01 + a20 * b02, a01 * b00 + a11 * b01 + a21 * b02, - a02 * b00 + a12 * b01 + a22 * b02], - [a00 * b10 + a10 * b11 + a20 * b12, + a02 * b00 + a12 * b01 + a22 * b02, + a00 * b10 + a10 * b11 + a20 * b12, a01 * b10 + a11 * b11 + a21 * b12, - a02 * b10 + a12 * b11 + a22 * b12], - [a00 * b20 + a10 * b21 + a20 * b22, + a02 * b10 + a12 * b11 + a22 * b12, + a00 * b20 + a10 * b21 + a20 * b22, a01 * b20 + a11 * b21 + a21 * b22, - a02 * b20 + a12 * b21 + a22 * b22]]; + a02 * b20 + a12 * b21 + a22 * b22); }; /** * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3. - * @param {!o3djs.math.Matrix3} a The matrix on the left. - * @param {!o3djs.math.Matrix3} b The matrix on the right. - * @return {!o3djs.math.Matrix3} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix3} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix3} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix3} The matrix product of a and b. */ -o3djs.math.mulMatrixMatrix3 = null; +o3djs.flat_math.mulMatrixMatrix3 = null; /** * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4; * assumes matrix entries are accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix4} a The matrix on the left. - * @param {!o3djs.math.Matrix4} b The matrix on the right. - * @return {!o3djs.math.Matrix4} The matrix product of a and b. - */ -o3djs.math.rowMajor.mulMatrixMatrix4 = function(a, b) { - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var a3 = a[3]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var b3 = b[3]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a03 = a0[3]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a13 = a1[3]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var a23 = a2[3]; - var a30 = a3[0]; - var a31 = a3[1]; - var a32 = a3[2]; - var a33 = a3[3]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b03 = b0[3]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b13 = b1[3]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - var b23 = b2[3]; - var b30 = b3[0]; - var b31 = b3[1]; - var b32 = b3[2]; - var b33 = b3[3]; - return [[a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30, + * @param {!o3djs.flat_math.Matrix4} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix4} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix4} The matrix product of a and b. + */ +o3djs.flat_math.rowMajor.mulMatrixMatrix4 = function(a, b) { + + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + var a30 = a[12]; + var a31 = a[13]; + var a32 = a[14]; + var a33 = a[15]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b03 = b[3]; + var b10 = b[4]; + var b11 = b[5]; + var b12 = b[6]; + var b13 = b[7]; + var b20 = b[8]; + var b21 = b[9]; + var b22 = b[10]; + var b23 = b[11]; + var b30 = b[12]; + var b31 = b[13]; + var b32 = b[14]; + var b33 = b[15]; + return o3djs.flat_math.makeMatrix4(a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30, a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31, a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32, - a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33], - [a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30, + a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33, + a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30, a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31, a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32, - a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33], - [a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30, + a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33, + a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30, a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31, a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32, - a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33], - [a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30, + a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33, + a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30, a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31, a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32, - a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33]]; + a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33); }; /** * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4; * assumes matrix entries are accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix4} a The matrix on the left. - * @param {!o3djs.math.Matrix4} b The matrix on the right. - * @return {!o3djs.math.Matrix4} The matrix product of a and b. - */ -o3djs.math.columnMajor.mulMatrixMatrix4 = function(a, b) { - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var a3 = a[3]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var b3 = b[3]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a03 = a0[3]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a13 = a1[3]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var a23 = a2[3]; - var a30 = a3[0]; - var a31 = a3[1]; - var a32 = a3[2]; - var a33 = a3[3]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b03 = b0[3]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b13 = b1[3]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - var b23 = b2[3]; - var b30 = b3[0]; - var b31 = b3[1]; - var b32 = b3[2]; - var b33 = b3[3]; - return [[a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, - a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, - a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, - a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03], - [a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, - a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, - a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, - a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13], - [a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, - a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, - a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, - a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23], - [a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, - a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, - a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, - a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33]]; + * @param {!o3djs.flat_math.Matrix4} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix4} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix4} The matrix product of a and b. + */ +o3djs.flat_math.columnMajor.mulMatrixMatrix4 = function(a, b) { + + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + var a30 = a[12]; + var a31 = a[13]; + var a32 = a[14]; + var a33 = a[15]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b03 = b[3]; + var b10 = b[4]; + var b11 = b[5]; + var b12 = b[6]; + var b13 = b[7]; + var b20 = b[8]; + var b21 = b[9]; + var b22 = b[10]; + var b23 = b[11]; + var b30 = b[12]; + var b31 = b[13]; + var b32 = b[14]; + var b33 = b[15]; + return o3djs.flat_math.makeMatrix4( + a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, + a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, + a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, + a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03, + a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, + a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, + a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, + a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13, + a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, + a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, + a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, + a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23, + a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, + a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, + a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, + a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33); }; /** * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4. - * @param {!o3djs.math.Matrix4} a The matrix on the left. - * @param {!o3djs.math.Matrix4} b The matrix on the right. - * @return {!o3djs.math.Matrix4} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix4} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix4} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix4} The matrix product of a and b. */ -o3djs.math.mulMatrixMatrix4 = null; +o3djs.flat_math.mulMatrixMatrix4 = null; /** * Multiplies two matrices; assumes that the sizes of the matrices are * appropriately compatible; assumes matrix entries are accessed in * [row][column] fashion. - * @param {!o3djs.math.Matrix} a The matrix on the left. - * @param {!o3djs.math.Matrix} b The matrix on the right. - * @return {!o3djs.math.Matrix} The matrix product of a and b. - */ -o3djs.math.rowMajor.mulMatrixMatrix = function(a, b) { + * @param {!o3djs.flat_math.Matrix} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix} The matrix product of a and b. + */ +o3djs.flat_math.rowMajor.mulMatrixMatrix = function(a, b) { + switch(a.length) { + case 4: + return o3djs.flat_math.rowMajor.mulMatrixMatrix2(a,b); + case 9: + return o3djs.flat_math.rowMajor.mulMatrixMatrix3(a,b); + case 16: + return o3djs.flat_math.rowMajor.mulMatrixMatrix4(a,b); + default: + throw "Unable to handle irregular matrices or matrices of dim > 4 or < 2"; + } + }; + +o3djs.flat_math.rowMajor.generalizedMulMatrixMatrix= function(a, b) { var r = []; var aRows = a.length; var bColumns = b[0].length; @@ -1167,49 +1597,56 @@ o3djs.math.rowMajor.mulMatrixMatrix = function(a, b) { * Multiplies two matrices; assumes that the sizes of the matrices are * appropriately compatible; assumes matrix entries are accessed in * [row][column] fashion. - * @param {!o3djs.math.Matrix} a The matrix on the left. - * @param {!o3djs.math.Matrix} b The matrix on the right. - * @return {!o3djs.math.Matrix} The matrix product of a and b. - */ -o3djs.math.columnMajor.mulMatrixMatrix = function(a, b) { - var r = []; - var bColumns = b.length; - var aRows = a[0].length; - var aColumns = a.length; - for (var i = 0; i < bColumns; ++i) { - var v = []; // v becomes a column of the answer. - var bi = b[i]; // ith column of b. - for (var j = 0; j < aRows; ++j) { - v[j] = 0.0; - for (var k = 0; k < aColumns; ++k) - v[j] += bi[k] * a[k][j]; // kth column, jth row. - } - r[i] = v; + * @param {!o3djs.flat_math.Matrix} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix} The matrix product of a and b. + */ +o3djs.flat_math.columnMajor.mulMatrixMatrix = function(a, b) { + switch(a.length) { + case 4: + return o3djs.flat_math.columnMajor.mulMatrixMatrix2(a,b); + case 9: + return o3djs.flat_math.columnMajor.mulMatrixMatrix3(a,b); + case 16: + return o3djs.flat_math.columnMajor.mulMatrixMatrix4(a,b); + default: + throw "Unable to handle irregular matrices or matrices of dim > 4 or < 2"; } - return r; }; /** * Multiplies two matrices; assumes that the sizes of the matrices are * appropriately compatible. - * @param {!o3djs.math.Matrix} a The matrix on the left. - * @param {!o3djs.math.Matrix} b The matrix on the right. - * @return {!o3djs.math.Matrix} The matrix product of a and b. + * @param {!o3djs.flat_math.Matrix} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix} The matrix product of a and b. */ -o3djs.math.mulMatrixMatrix = null; +o3djs.flat_math.mulMatrixMatrix = null; /** * Gets the jth column of the given matrix m; assumes matrix entries are - * accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix} m The matrix. + * accessed in [row*dimension+column] fashion. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} j The index of the desired column. - * @return {!o3djs.math.Vector} The jth column of m as a vector. + * @return {!o3djs.flat_math.Vector} The jth column of m as a vector. */ -o3djs.math.rowMajor.column = function(m, j) { - var r = []; +o3djs.flat_math.rowMajor.column = function(m, j) { var mLength = m.length; - for (var i = 0; i < mLength; ++i) { - r[i] = m[i][j]; + var dimension; + switch (mLength){ + case 4: + dimension = 2; + break; + case 9: + dimension = 3; + break; + case 16: + dimension = 4; + break; + } + var r = new o3djs.flat_math.Vector(dimension); + for (var i = 0; i < dimension; ++i) { + r[i] = m[i * dimension + j]; } return r; }; @@ -1217,85 +1654,110 @@ o3djs.math.rowMajor.column = function(m, j) { /** * Gets the jth column of the given matrix m; assumes matrix entries are * accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} j The index of the desired column. - * @return {!o3djs.math.Vector} The jth column of m as a vector. + * @return {!o3djs.flat_math.Vector} The jth column of m as a vector. */ -o3djs.math.columnMajor.column = function(m, j) { - return m[j].slice(); +o3djs.flat_math.columnMajor.column = function(m, j) { + var dimension; + var mLength = m.length; + switch (mLength){ + case 4: + dimension = 2; + break; + case 9: + dimension = 3; + break; + case 16: + dimension = 4; + break; + default: + dimension = Math.sqrt(dimension); + if (Math.round(dimension) * Math.round(dimension) != mLength) { + throw "Calling column on nonsquare matrix"; + } + } + return m.slice(j * dimension, j * dimension + dimension); }; /** * Gets the jth column of the given matrix m. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} j The index of the desired column. - * @return {!o3djs.math.Vector} The jth column of m as a vector. + * @return {!o3djs.flat_math.Vector} The jth column of m as a vector. */ -o3djs.math.column = null; +o3djs.flat_math.column = null; /** * Gets the ith row of the given matrix m; assumes matrix entries are * accessed in [row][column] fashion. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} i The index of the desired row. - * @return {!o3djs.math.Vector} The ith row of m. + * @return {!o3djs.flat_math.Vector} The ith row of m. */ -o3djs.math.rowMajor.row = function(m, i) { - return m[i].slice(); -}; +o3djs.flat_math.rowMajor.row = o3djs.flat_math.columnMajor.column; /** * Gets the ith row of the given matrix m; assumes matrix entries are * accessed in [column][row] fashion. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} i The index of the desired row. - * @return {!o3djs.math.Vector} The ith row of m. + * @return {!o3djs.flat_math.Vector} The ith row of m. */ -o3djs.math.columnMajor.row = function(m, i) { - var r = []; - var mLength = m.length; - for (var j = 0; j < mLength; ++j) { - r[j] = m[j][i]; - } - return r; -}; +o3djs.flat_math.columnMajor.row = o3djs.flat_math.rowMajor.column; /** * Gets the ith row of the given matrix m. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @param {number} i The index of the desired row. - * @return {!o3djs.math.Vector} The ith row of m. + * @return {!o3djs.flat_math.Vector} The ith row of m. */ -o3djs.math.row = null; +o3djs.flat_math.row = null; /** * Creates an n-by-n identity matrix. * @param {number} n The dimension of the identity matrix required. - * @return {!o3djs.math.Matrix} An n-by-n identity matrix. + * @return {!o3djs.flat_math.Matrix} An n-by-n identity matrix. */ -o3djs.math.identity = function(n) { - var r = []; +o3djs.flat_math.identity = function(n) { + var r = new o3djs.flat_math.Matrix(n*n); + for (var j = 0; j < n; ++j) { - r[j] = []; for (var i = 0; i < n; ++i) - r[j][i] = (i == j) ? 1 : 0; + r[j * n + i] = (i == j) ? 1 : 0; } return r; }; /** * Takes the transpose of a matrix. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} The transpose of m. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} The transpose of m. */ -o3djs.math.transpose = function(m) { - var r = []; - var m0Length = m[0].length; +o3djs.flat_math.transpose = function(m) { var mLength = m.length; - for (var j = 0; j < m0Length; ++j) { - r[j] = []; - for (var i = 0; i < mLength; ++i) - r[j][i] = m[i][j]; + var r = new o3djs.flat_math.Matrix(mLength); + var dimension; + switch (mLength){ + case 4: + dimension = 2; + break; + case 9: + dimension = 3; + break; + case 16: + dimension = 4; + break; + default: + dimension = Math.sqrt(dimension); + if (Math.round(dimension) * Math.round(dimension) != mLength) { + throw "Calling transpose on nonsquare matrix"; + } + } + + for (var j = 0; j < dimension; ++j) { + for (var i = 0; i < dimension; ++i) + r[j * dimension + i] = m[i * dimension + j]; } return r; }; @@ -1303,218 +1765,259 @@ o3djs.math.transpose = function(m) { /** * Computes the trace (sum of the diagonal entries) of a square matrix; * assumes m is square. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @return {number} The trace of m. */ -o3djs.math.trace = function(m) { +o3djs.flat_math.trace = function(m) { var r = 0.0; - var mLength = m.length; + var dimension; + switch (mLength){ + case 4: + dimension = 2; + break; + case 9: + dimension = 3; + break; + case 16: + dimension = 4; + break; + } + var mLength = dimension; for (var i = 0; i < mLength; ++i) - r += m[i][i]; + r += m[i * dimension + i]; return r; }; /** * Computes the determinant of a 1-by-1 matrix. - * @param {!o3djs.math.Matrix1} m The matrix. + * @param {!o3djs.flat_math.Matrix1} m The matrix. * @return {number} The determinant of m. */ -o3djs.math.det1 = function(m) { - return m[0][0]; +o3djs.flat_math.det1 = function(m) { + return m[0]; }; /** * Computes the determinant of a 2-by-2 matrix. - * @param {!o3djs.math.Matrix2} m The matrix. + * @param {!o3djs.flat_math.Matrix2} m The matrix. * @return {number} The determinant of m. */ -o3djs.math.det2 = function(m) { - return m[0][0] * m[1][1] - m[0][1] * m[1][0]; +o3djs.flat_math.det2 = function(m) { + return m[0] * m[3] - m[1] * m[2]; }; /** * Computes the determinant of a 3-by-3 matrix. - * @param {!o3djs.math.Matrix3} m The matrix. + * @param {!o3djs.flat_math.Matrix3} m The matrix. * @return {number} The determinant of m. */ -o3djs.math.det3 = function(m) { - return m[2][2] * (m[0][0] * m[1][1] - m[0][1] * m[1][0]) - - m[2][1] * (m[0][0] * m[1][2] - m[0][2] * m[1][0]) + - m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]); +o3djs.flat_math.det3 = function(m) { + return m[8] * (m[0 * 3] * m[4] - m[1] * m[1 * 3]) - + m[7] * (m[0 * 3] * m[5] - m[2] * m[1 * 3]) + + m[2 * 3] * (m[1] * m[5] - m[2] * m[4]); }; /** * Computes the determinant of a 4-by-4 matrix. - * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Matrix4} m The matrix. * @return {number} The determinant of m. */ -o3djs.math.det4 = function(m) { - var t01 = m[0][0] * m[1][1] - m[0][1] * m[1][0]; - var t02 = m[0][0] * m[1][2] - m[0][2] * m[1][0]; - var t03 = m[0][0] * m[1][3] - m[0][3] * m[1][0]; - var t12 = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - var t13 = m[0][1] * m[1][3] - m[0][3] * m[1][1]; - var t23 = m[0][2] * m[1][3] - m[0][3] * m[1][2]; - return m[3][3] * (m[2][2] * t01 - m[2][1] * t02 + m[2][0] * t12) - - m[3][2] * (m[2][3] * t01 - m[2][1] * t03 + m[2][0] * t13) + - m[3][1] * (m[2][3] * t02 - m[2][2] * t03 + m[2][0] * t23) - - m[3][0] * (m[2][3] * t12 - m[2][2] * t13 + m[2][1] * t23); +o3djs.flat_math.det4 = function(m) { + var t01 = m[0] * m[5] - m[1] * m[4]; + var t02 = m[0] * m[6] - m[2] * m[4]; + var t03 = m[0] * m[7] - m[3] * m[4]; + var t12 = m[1] * m[6] - m[2] * m[5]; + var t13 = m[1] * m[7] - m[3] * m[5]; + var t23 = m[2] * m[7] - m[3] * m[6]; + return m[15] * (m[10] * t01 - m[9] * t02 + m[8] * t12) - + m[14] * (m[11] * t01 - m[9] * t03 + m[8] * t13) + + m[13] * (m[11] * t02 - m[10] * t03 + m[8] * t23) - + m[12] * (m[11] * t12 - m[10] * t13 + m[9] * t23); }; /** * Computes the inverse of a 1-by-1 matrix. - * @param {!o3djs.math.Matrix1} m The matrix. - * @return {!o3djs.math.Matrix1} The inverse of m. + * @param {!o3djs.flat_math.Matrix1} m The matrix. + * @return {!o3djs.flat_math.Matrix1} The inverse of m. */ -o3djs.math.inverse1 = function(m) { - return [[1.0 / m[0][0]]]; +o3djs.flat_math.inverse1 = function(m) { + var retval = new o3djs.flat_math.Matrix(1); + retval[0] = 1.0 / m[0]; + return retval; }; /** * Computes the inverse of a 2-by-2 matrix. - * @param {!o3djs.math.Matrix2} m The matrix. - * @return {!o3djs.math.Matrix2} The inverse of m. + * @param {!o3djs.flat_math.Matrix2} m The matrix. + * @return {!o3djs.flat_math.Matrix2} The inverse of m. */ -o3djs.math.inverse2 = function(m) { - var d = 1.0 / (m[0][0] * m[1][1] - m[0][1] * m[1][0]); - return [[d * m[1][1], -d * m[0][1]], [-d * m[1][0], d * m[0][0]]]; +o3djs.flat_math.inverse2 = function(m) { + var d = 1.0 / (m[0] * m[3] - m[1] * m[2]); + return o3djs.flat_math.makeMatrix2(d * m[3], -d * m[1], + -d * m[2], d * m[0]); }; /** * Computes the inverse of a 3-by-3 matrix. - * @param {!o3djs.math.Matrix3} m The matrix. - * @return {!o3djs.math.Matrix3} The inverse of m. + * @param {!o3djs.flat_math.Matrix3} m The matrix. + * @return {!o3djs.flat_math.Matrix3} The inverse of m. */ -o3djs.math.inverse3 = function(m) { - var t00 = m[1][1] * m[2][2] - m[1][2] * m[2][1]; - var t10 = m[0][1] * m[2][2] - m[0][2] * m[2][1]; - var t20 = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - var d = 1.0 / (m[0][0] * t00 - m[1][0] * t10 + m[2][0] * t20); - return [[d * t00, -d * t10, d * t20], - [-d * (m[1][0] * m[2][2] - m[1][2] * m[2][0]), - d * (m[0][0] * m[2][2] - m[0][2] * m[2][0]), - -d * (m[0][0] * m[1][2] - m[0][2] * m[1][0])], - [d * (m[1][0] * m[2][1] - m[1][1] * m[2][0]), - -d * (m[0][0] * m[2][1] - m[0][1] * m[2][0]), - d * (m[0][0] * m[1][1] - m[0][1] * m[1][0])]]; +o3djs.flat_math.inverse3 = function(m) { + var t00 = m[4] * m[8] - m[5] * m[7]; + var t10 = m[1] * m[8] - m[2] * m[7]; + var t20 = m[1] * m[5] - m[2] * m[4]; + var d = 1.0 / (m[0] * t00 - m[3] * t10 + m[6] * t20); + return o3djs.flat_math.makeMatrix3(d * t00, -d * t10, d * t20, + -d * (m[3] * m[8] - m[5] * m[6]), + d * (m[0] * m[8] - m[2] * m[6]), + -d * (m[0] * m[5] - m[2] * m[3]), + d * (m[3] * m[7] - m[4] * m[6]), + -d * (m[0] * m[7] - m[1] * m[6]), + d * (m[0] * m[4] - m[1] * m[3])); }; /** * Computes the inverse of a 4-by-4 matrix. - * @param {!o3djs.math.Matrix4} m The matrix. - * @return {!o3djs.math.Matrix4} The inverse of m. - */ -o3djs.math.inverse4 = function(m) { - var tmp_0 = m[2][2] * m[3][3]; - var tmp_1 = m[3][2] * m[2][3]; - var tmp_2 = m[1][2] * m[3][3]; - var tmp_3 = m[3][2] * m[1][3]; - var tmp_4 = m[1][2] * m[2][3]; - var tmp_5 = m[2][2] * m[1][3]; - var tmp_6 = m[0][2] * m[3][3]; - var tmp_7 = m[3][2] * m[0][3]; - var tmp_8 = m[0][2] * m[2][3]; - var tmp_9 = m[2][2] * m[0][3]; - var tmp_10 = m[0][2] * m[1][3]; - var tmp_11 = m[1][2] * m[0][3]; - var tmp_12 = m[2][0] * m[3][1]; - var tmp_13 = m[3][0] * m[2][1]; - var tmp_14 = m[1][0] * m[3][1]; - var tmp_15 = m[3][0] * m[1][1]; - var tmp_16 = m[1][0] * m[2][1]; - var tmp_17 = m[2][0] * m[1][1]; - var tmp_18 = m[0][0] * m[3][1]; - var tmp_19 = m[3][0] * m[0][1]; - var tmp_20 = m[0][0] * m[2][1]; - var tmp_21 = m[2][0] * m[0][1]; - var tmp_22 = m[0][0] * m[1][1]; - var tmp_23 = m[1][0] * m[0][1]; - - var t0 = (tmp_0 * m[1][1] + tmp_3 * m[2][1] + tmp_4 * m[3][1]) - - (tmp_1 * m[1][1] + tmp_2 * m[2][1] + tmp_5 * m[3][1]); - var t1 = (tmp_1 * m[0][1] + tmp_6 * m[2][1] + tmp_9 * m[3][1]) - - (tmp_0 * m[0][1] + tmp_7 * m[2][1] + tmp_8 * m[3][1]); - var t2 = (tmp_2 * m[0][1] + tmp_7 * m[1][1] + tmp_10 * m[3][1]) - - (tmp_3 * m[0][1] + tmp_6 * m[1][1] + tmp_11 * m[3][1]); - var t3 = (tmp_5 * m[0][1] + tmp_8 * m[1][1] + tmp_11 * m[2][1]) - - (tmp_4 * m[0][1] + tmp_9 * m[1][1] + tmp_10 * m[2][1]); - - var d = 1.0 / (m[0][0] * t0 + m[1][0] * t1 + m[2][0] * t2 + m[3][0] * t3); - - var row0 = [d * t0, d * t1, d * t2, d * t3]; - var row1 = [d * ((tmp_1 * m[1][0] + tmp_2 * m[2][0] + tmp_5 * m[3][0]) - - (tmp_0 * m[1][0] + tmp_3 * m[2][0] + tmp_4 * m[3][0])), - d * ((tmp_0 * m[0][0] + tmp_7 * m[2][0] + tmp_8 * m[3][0]) - - (tmp_1 * m[0][0] + tmp_6 * m[2][0] + tmp_9 * m[3][0])), - d * ((tmp_3 * m[0][0] + tmp_6 * m[1][0] + tmp_11 * m[3][0]) - - (tmp_2 * m[0][0] + tmp_7 * m[1][0] + tmp_10 * m[3][0])), - d * ((tmp_4 * m[0][0] + tmp_9 * m[1][0] + tmp_10 * m[2][0]) - - (tmp_5 * m[0][0] + tmp_8 * m[1][0] + tmp_11 * m[2][0]))]; - var row2 =[d * ((tmp_12 * m[1][3] + tmp_15 * m[2][3] + tmp_16 * m[3][3]) - - (tmp_13 * m[1][3] + tmp_14 * m[2][3] + tmp_17 * m[3][3])), - d * ((tmp_13 * m[0][3] + tmp_18 * m[2][3] + tmp_21 * m[3][3]) - - (tmp_12 * m[0][3] + tmp_19 * m[2][3] + tmp_20 * m[3][3])), - d * ((tmp_14 * m[0][3] + tmp_19 * m[1][3] + tmp_22 * m[3][3]) - - (tmp_15 * m[0][3] + tmp_18 * m[1][3] + tmp_23 * m[3][3])), - d * ((tmp_17 * m[0][3] + tmp_20 * m[1][3] + tmp_23 * m[2][3]) - - (tmp_16 * m[0][3] + tmp_21 * m[1][3] + tmp_22 * m[2][3]))]; - var row3 = [d * ((tmp_14 * m[2][2] + tmp_17 * m[3][2] + tmp_13 * m[1][2]) - - (tmp_16 * m[3][2] + tmp_12 * m[1][2] + tmp_15 * m[2][2])), - d * ((tmp_20 * m[3][2] + tmp_12 * m[0][2] + tmp_19 * m[2][2]) - - (tmp_18 * m[2][2] + tmp_21 * m[3][2] + tmp_13 * m[0][2])), - d * ((tmp_18 * m[1][2] + tmp_23 * m[3][2] + tmp_15 * m[0][2]) - - (tmp_22 * m[3][2] + tmp_14 * m[0][2] + tmp_19 * m[1][2])), - d * ((tmp_22 * m[2][2] + tmp_16 * m[0][2] + tmp_21 * m[1][2]) - - (tmp_20 * m[1][2] + tmp_23 * m[2][2] + tmp_17 * m[0][2]))]; - return [row0, row1, row2, row3]; + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @return {!o3djs.flat_math.Matrix4} The inverse of m. + */ +o3djs.flat_math.inverse4 = function(m) { + var tmp_0 = m[10] * m[15]; + var tmp_1 = m[14] * m[11]; + var tmp_2 = m[6] * m[15]; + var tmp_3 = m[14] * m[7]; + var tmp_4 = m[6] * m[11]; + var tmp_5 = m[10] * m[7]; + var tmp_6 = m[2] * m[15]; + var tmp_7 = m[14] * m[3]; + var tmp_8 = m[2] * m[11]; + var tmp_9 = m[10] * m[3]; + var tmp_10 = m[2] * m[7]; + var tmp_11 = m[6] * m[3]; + var tmp_12 = m[8] * m[13]; + var tmp_13 = m[12] * m[9]; + var tmp_14 = m[4] * m[13]; + var tmp_15 = m[12] * m[5]; + var tmp_16 = m[4] * m[9]; + var tmp_17 = m[8] * m[5]; + var tmp_18 = m[0] * m[13]; + var tmp_19 = m[12] * m[1]; + var tmp_20 = m[0] * m[9]; + var tmp_21 = m[8] * m[1]; + var tmp_22 = m[0] * m[5]; + var tmp_23 = m[4] * m[1]; + + var t0 = tmp_0 * m[5] + tmp_3 * m[9] + tmp_4 * m[13] - + (tmp_1 * m[5] + tmp_2 * m[9] + tmp_5 * m[13]); + var t1 = tmp_1 * m[1] + tmp_6 * m[9] + tmp_9 * m[13] - + (tmp_0 * m[1] + tmp_7 * m[9] + tmp_8 * m[13]); + var t2 = tmp_2 * m[1] + tmp_7 * m[5] + tmp_10 * m[13] - + (tmp_3 * m[1] + tmp_6 * m[5] + tmp_11 * m[13]); + var t3 = (tmp_5 * m[1] + tmp_8 * m[5] + tmp_11 * m[9]) - + (tmp_4 * m[1] + tmp_9 * m[5] + tmp_10 * m[9]); + + var d = 1.0 / (m[0] * t0 + m[1 * 4] * t1 + m[8] * t2 + m[12] * t3); + + return o3djs.flat_math.makeMatrix4(d * t0, d * t1, d * t2, d * t3, + d * ((tmp_1 * m[1 * 4] + tmp_2 * m[8] + tmp_5 * m[12]) - + (tmp_0 * m[1 * 4] + tmp_3 * m[8] + tmp_4 * m[12])), + d * ((tmp_0 * m[0 * 4] + tmp_7 * m[8] + tmp_8 * m[12]) - + (tmp_1 * m[0 * 4] + tmp_6 * m[8] + tmp_9 * m[12])), + d * ((tmp_3 * m[0 * 4] + tmp_6 * m[1 * 4] + tmp_11 * m[12]) - + (tmp_2 * m[0 * 4] + tmp_7 * m[1 * 4] + tmp_10 * m[12])), + d * ((tmp_4 * m[0 * 4] + tmp_9 * m[1 * 4] + tmp_10 * m[8]) - + (tmp_5 * m[0 * 4] + tmp_8 * m[1 * 4] + tmp_11 * m[8])), + d * ((tmp_12 * m[4 + 3] + tmp_15 * m[11] + tmp_16 * m[15]) - + (tmp_13 * m[4 + 3] + tmp_14 * m[11] + tmp_17 * m[15])), + d * ((tmp_13 * m[3] + tmp_18 * m[11] + tmp_21 * m[15]) - + (tmp_12 * m[3] + tmp_19 * m[11] + tmp_20 * m[15])), + d * ((tmp_14 * m[3] + tmp_19 * m[7] + tmp_22 * m[15]) - + (tmp_15 * m[3] + tmp_18 * m[7] + tmp_23 * m[15])), + d * ((tmp_17 * m[3] + tmp_20 * m[7] + tmp_23 * m[11]) - + (tmp_16 * m[3] + tmp_21 * m[7] + tmp_22 * m[11])), + d * ((tmp_14 * m[10] + tmp_17 * m[14] + tmp_13 * m[4 + 2]) - + (tmp_16 * m[14] + tmp_12 * m[4 + 2] + tmp_15 * m[10])), + d * ((tmp_20 * m[14] + tmp_12 * m[2] + tmp_19 * m[10]) - + (tmp_18 * m[10] + tmp_21 * m[14] + tmp_13 * m[2])), + d * ((tmp_18 * m[6] + tmp_23 * m[14] + tmp_15 * m[2]) - + (tmp_22 * m[14] + tmp_14 * m[2] + tmp_19 * m[6])), + d * ((tmp_22 * m[10] + tmp_16 * m[2] + tmp_21 * m[6]) - + (tmp_20 * m[6] + tmp_23 * m[10] + tmp_17 * m[2]))); }; /** * Computes the determinant of the cofactor matrix obtained by removal * of a specified row and column. This is a helper function for the general * determinant and matrix inversion functions. - * @param {!o3djs.math.Matrix} a The original matrix. + * @param {!o3djs.flat_math.Matrix} a The original matrix. * @param {number} x The row to be removed. * @param {number} y The column to be removed. * @return {number} The determinant of the matrix obtained by removing * row x and column y from a. */ -o3djs.math.codet = function(a, x, y) { - var size = a.length; - var b = []; +o3djs.flat_math.codet = function(a, x, y) { + var aLength = a.length; + var size; + switch (aLength) { + case 4: + size = 2; + break; + case 9: + size = 3; + break; + case 16: + size = 4; + break; + default: + size=Math.sqrt(aLength); + if (Math.round(size) * Math.round(size) != aLength) { + throw "Calling codet on nonsquare matrix"; + } + } + var b = new o3djs.flat_math.Matrix(aLength); var ai = 0; for (var bi = 0; bi < size - 1; ++bi) { if (ai == x) ai++; - b[bi] = []; var aj = 0; for (var bj = 0; bj < size - 1; ++bj) { if (aj == y) aj++; - b[bi][bj] = a[ai][aj]; + b[bi*size+bj] = a[ai*size+aj]; aj++; } ai++; } - return o3djs.math.det(b); + return o3djs.flat_math.det(b); }; /** * Computes the determinant of an arbitrary square matrix. - * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.flat_math.Matrix} m The matrix. * @return {number} the determinant of m. */ -o3djs.math.det = function(m) { +o3djs.flat_math.det = function(m) { var d = m.length; - if (d <= 4) { - return o3djs.math['det' + d](m); + switch (d) { + case 4: + return o3djs.flat_math.det2(m); + case 9: + return o3djs.flat_math.det3(m); + case 16: + return o3djs.flat_math.det4(m); + default: + d = Math.sqrt(d); + if (Math.round(d) * Math.round(d) != m.length) { + throw "Calling det on nonsquare matrix"; + } + break; } var r = 0.0; var sign = 1; - var row = m[0]; + var row = m; var mLength = m.length; for (var y = 0; y < mLength; y++) { - r += sign * row[y] * o3djs.math.codet(m, 0, y); + r += sign * m[0] * o3djs.flat_math.codet(m, 0, y); sign *= -1; } return r; @@ -1522,22 +2025,34 @@ o3djs.math.det = function(m) { /** * Computes the inverse of an arbitrary square matrix. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} The inverse of m. + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} The inverse of m. */ -o3djs.math.inverse = function(m) { +o3djs.flat_math.inverse = function(m) { var d = m.length; - if (d <= 4) { - return o3djs.math['inverse' + d](m); + switch (d) { + case 4: + return o3djs.flat_math.inverse2(m); + case 9: + return o3djs.flat_math.inverse3(m); + case 16: + return o3djs.flat_math.inverse4(m); + default: + d = Math.sqrt(d); + if (Math.round(d) * Math.round(d) != m.length) { + throw "Calling inverse on nonsquare matrix"; + } + break; } - var r = []; + var r = new o3djs.flat_math.Matrix(m.length); var size = m.length; + var det = o3djs.flat_math.det(m); for (var j = 0; j < size; ++j) { - r[j] = []; for (var i = 0; i < size; ++i) - r[j][i] = ((i + j) % 2 ? -1 : 1) * o3djs.math.codet(m, i, j); + r[j * d + i] = + ((i + j) % 2 ? -1 : 1) * o3djs.flat_math.codet(m, i, j) / det; } - return o3djs.math.divMatrixScalar(r, o3djs.math.det(m)); + return r; }; /** @@ -1546,80 +2061,99 @@ o3djs.math.inverse = function(m) { * multiplying many orthogonal matrices together, errors can accumulate causing * the product to fail to be orthogonal. This function can be used to correct * that. - * @param {!o3djs.math.Matrix} m The matrix. - * @return {!o3djs.math.Matrix} A matrix whose rows are obtained from the + * @param {!o3djs.flat_math.Matrix} m The matrix. + * @return {!o3djs.flat_math.Matrix} A matrix whose rows are obtained from the * rows of m by the Graham-Schmidt process. */ -o3djs.math.orthonormalize = function(m) { - var r = []; - var mLength = m.length; - for (var i = 0; i < mLength; ++i) { - var v = m[i]; +o3djs.flat_math.orthonormalize = function(m) { + var d = m.length; + var r = new o3djs.flat_math.Matrix(d); + switch (d) { + case 4: + d = 2; break; + case 9: + d = 3; break; + case 16: + d = 4; break; + default: + d = Math.sqrt(d); + if (Math.round(d) * Math.round(d) != m.length) { + throw "Calling orthonormalize on nonsquare matrix"; + } + break; + } + for (var i = 0; i < d; ++i) { + var v = m.slice(i*d,i*d+d); for (var j = 0; j < i; ++j) { - v = o3djs.math.subVector(v, o3djs.math.mulScalarVector( - o3djs.math.dot(r[j], m[i]), r[j])); + v = o3djs.flat_math.subVector(v, o3djs.flat_math.mulScalarVector( + o3djs.flat_math.dot(r[j], v), r[j])); + } + var ri = o3djs.flat_math.normalize(v); + for (var k = 0; k < d; ++ k) { + r[i * d +k ] = ri[k]; } - r[i] = o3djs.math.normalize(v); } return r; }; /** * Computes the inverse of a 4-by-4 matrix. - * Note: It is faster to call this than o3djs.math.inverse. - * @param {!o3djs.math.Matrix4} m The matrix. - * @return {!o3djs.math.Matrix4} The inverse of m. + * Note: It is faster to call this than o3djs.flat_math.inverse. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @return {!o3djs.flat_math.Matrix4} The inverse of m. */ -o3djs.math.matrix4.inverse = function(m) { - return o3djs.math.inverse4(m); +o3djs.flat_math.matrix4.inverse = function(m) { + return o3djs.flat_math.inverse4(m); }; /** * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4. - * Note: It is faster to call this than o3djs.math.mul. - * @param {!o3djs.math.Matrix4} a The matrix on the left. - * @param {!o3djs.math.Matrix4} b The matrix on the right. - * @return {!o3djs.math.Matrix4} The matrix product of a and b. + * Note: It is faster to call this than o3djs.flat_math.mul. + * @param {!o3djs.flat_math.Matrix4} a The matrix on the left. + * @param {!o3djs.flat_math.Matrix4} b The matrix on the right. + * @return {!o3djs.flat_math.Matrix4} The matrix product of a and b. */ -o3djs.math.matrix4.mul = function(a, b) { - return o3djs.math.mulMatrixMatrix4(a, b); +o3djs.flat_math.matrix4.mul = function(a, b) { + return o3djs.flat_math.mulMatrixMatrix4(a, b); }; /** * Computes the determinant of a 4-by-4 matrix. - * Note: It is faster to call this than o3djs.math.det. - * @param {!o3djs.math.Matrix4} m The matrix. + * Note: It is faster to call this than o3djs.flat_math.det. + * @param {!o3djs.flat_math.Matrix4} m The matrix. * @return {number} The determinant of m. */ -o3djs.math.matrix4.det = function(m) { - return o3djs.math.det4(m); +o3djs.flat_math.matrix4.det = function(m) { + return o3djs.flat_math.det4(m); }; /** * Copies a Matrix4. - * Note: It is faster to call this than o3djs.math.copy. - * @param {!o3djs.math.Matrix4} m The matrix. - * @return {!o3djs.math.Matrix4} A copy of m. + * Note: It is faster to call this than o3djs.flat_math.copy. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @return {!o3djs.flat_math.Matrix4} A copy of m. */ -o3djs.math.matrix4.copy = function(m) { - return o3djs.math.copyMatrix(m); +o3djs.flat_math.matrix4.copy = function(m) { + return o3djs.flat_math.copyMatrix(m); }; /** * Sets the upper 3-by-3 block of matrix a to the upper 3-by-3 block of matrix * b; assumes that a and b are big enough to contain an upper 3-by-3 block. - * @param {!o3djs.math.Matrix4} a A matrix. - * @param {!o3djs.math.Matrix3} b A 3-by-3 matrix. - * @return {!o3djs.math.Matrix4} a once modified. - */ -o3djs.math.matrix4.setUpper3x3 = function(a, b) { - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - - a[0].splice(0, 3, b0[0], b0[1], b0[2]); - a[1].splice(0, 3, b1[0], b1[1], b1[2]); - a[2].splice(0, 3, b2[0], b2[1], b2[2]); + * @param {!o3djs.flat_math.Matrix4} a A matrix. + * @param {!o3djs.flat_math.Matrix3} b A 3-by-3 matrix. + * @return {!o3djs.flat_math.Matrix4} a once modified. + */ +o3djs.flat_math.matrix4.setUpper3x3 = function(a, b) { + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[4] = b[4]; + a[5] = b[5]; + a[6] = b[6]; + a[8] = b[8]; + a[9] = b[9]; + a[10] = b[10]; return a; }; @@ -1627,80 +2161,107 @@ o3djs.math.matrix4.setUpper3x3 = function(a, b) { /** * Returns a 3-by-3 matrix mimicking the upper 3-by-3 block of m; assumes m * is big enough to contain an upper 3-by-3 block. - * @param {!o3djs.math.Matrix4} m The matrix. - * @return {!o3djs.math.Matrix3} The upper 3-by-3 block of m. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @return {!o3djs.flat_math.Matrix3} The upper 3-by-3 block of m. */ -o3djs.math.matrix4.getUpper3x3 = function(m) { - return [m[0].slice(0, 3), m[1].slice(0, 3), m[2].slice(0, 3)]; +o3djs.flat_math.matrix4.getUpper3x3 = function(m) { + return o3djs.flat_math.makeMatrix3( + m[0], m[1], m[2], + m[4], m[5], m[6], + m[8], m[9], m[10]); }; /** * Sets the translation component of a 4-by-4 matrix to the given * vector. - * @param {!o3djs.math.Matrix4} a The matrix. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector. - * @return {!o3djs.math.Matrix4} a once modified. - */ -o3djs.math.matrix4.setTranslation = function(a, v) { - a[3].splice(0, 4, v[0], v[1], v[2], 1); + * @param {!o3djs.flat_math.Matrix4} a The matrix. + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} v The vector. + * @return {!o3djs.flat_math.Matrix4} a once modified. + */ +o3djs.flat_math.matrix4.setTranslation = function(a, v) { + a[12] = v[0]; + a[13] = v[1]; + a[14] = v[2]; return a; }; /** * Returns the translation component of a 4-by-4 matrix as a vector with 3 * entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @return {!o3djs.math.Vector3} The translation component of m. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @return {!o3djs.flat_math.Vector3} The translation component of m. */ -o3djs.math.matrix4.getTranslation = function(m) { - return m[3].slice(0, 3); +o3djs.flat_math.matrix4.getTranslation = function(m) { + var retval =new o3djs.flat_math.Vector(3); + retval[0] = m[12]; + retval[1] = m[13]; + retval[2] = m[14]; + return retval; }; /** * Takes a 4-by-4 matrix and a vector with 3 entries, * interprets the vector as a point, transforms that point by the matrix, and * returns the result as a vector with 3 entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v The point. - * @return {!o3djs.math.Vector3} The transformed point. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Vector3} v The point. + * @return {!o3djs.flat_math.Vector3} The transformed point. */ -o3djs.math.matrix4.transformPoint = function(m, v) { +o3djs.flat_math.matrix4.transformPoint = function(m, v) { var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var d = v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + m3[3]; - return [(v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + m3[0]) / d, - (v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + m3[1]) / d, - (v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + m3[2]) / d]; + var d = v0 * m[3] + + v1 * m[7] + + v2 * m[11] + + m[15]; + var retval = new o3djs.flat_math.Vector(3); + retval[0] = (v0 * m[0] + + v1 * m[4] + + v2 * m[8] + + m[12]) / d; + retval[1] = (v0 * m[1] + + v1 * m[5] + + v2 * m[9] + + m[13]) / d; + retval[2] = (v0 * m[2] + + v1 * m[6] + + v2 * m[10] + + m[14]) / d; + return retval; }; /** * Takes a 4-by-4 matrix and a vector with 4 entries, transforms that vector by * the matrix, and returns the result as a vector with 4 entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector4} v The point in homogenous coordinates. - * @return {!o3djs.math.Vector4} The transformed point in homogenous + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Vector4} v The point in homogenous coordinates. + * @return {!o3djs.flat_math.Vector4} The transformed point in homogenous * coordinates. */ -o3djs.math.matrix4.transformVector4 = function(m, v) { +o3djs.flat_math.matrix4.transformVector4 = function(m, v) { var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; var v3 = v[3]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - return [v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + v3 * m3[0], - v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + v3 * m3[1], - v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + v3 * m3[2], - v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + v3 * m3[3]]; + return [v0 * m[0] + + v1 * m[4] + + v2 * m[8] + + v3 * m[12], + v0 * m[1] + + v1 * m[5] + + v2 * m[9] + + v3 * m[13], + v0 * m[2] + + v1 * m[6] + + v2 * m[10] + + v3 * m[14], + v0 * m[3] + + v1 * m[7] + + v2 * m[11] + + v3 * m[15]]; }; /** @@ -1710,22 +2271,24 @@ o3djs.math.matrix4.transformVector4 = function(m, v) { * is parallel-preserving, i.e. any combination of rotation, scaling and * translation, but not a perspective distortion. Returns a vector with 3 * entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v The direction. - * @return {!o3djs.math.Vector3} The transformed direction. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Vector3} v The direction. + * @return {!o3djs.flat_math.Vector3} The transformed direction. */ -o3djs.math.matrix4.transformDirection = function(m, v) { +o3djs.flat_math.matrix4.transformDirection = function(m, v) { var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - return [v0 * m0[0] + v1 * m1[0] + v2 * m2[0], - v0 * m0[1] + v1 * m1[1] + v2 * m2[1], - v0 * m0[2] + v1 * m1[2] + v2 * m2[2]]; + return [v0 * m[0] + + v1 * m[4] + + v2 * m[8], + v0 * m[1] + + v1 * m[5] + + v2 * m[9], + v0 * m[2] + + v1 * m[6] + + v2 * m[10]]; }; /** @@ -1737,50 +2300,49 @@ o3djs.math.matrix4.transformDirection = function(m, v) { * matrix is parallel-preserving, i.e. any combination of rotation, scaling and * translation, but not a perspective distortion. Returns a vector with 3 * entries. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v The normal. - * @return {!o3djs.math.Vector3} The transformed normal. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Vector3} v The normal. + * @return {!o3djs.flat_math.Vector3} The transformed normal. */ -o3djs.math.matrix4.transformNormal = function(m, v) { - var mInverse = o3djs.math.inverse4(m); +o3djs.flat_math.matrix4.transformNormal = function(m, v) { + var mInverse = o3djs.flat_math.inverse4(m); var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; - var mi0 = mInverse[0]; - var mi1 = mInverse[1]; - var mi2 = mInverse[2]; - var mi3 = mInverse[3]; - return [v0 * mi0[0] + v1 * mi0[1] + v2 * mi0[2], - v0 * mi1[0] + v1 * mi1[1] + v2 * mi1[2], - v0 * mi2[0] + v1 * mi2[1] + v2 * mi2[2]]; + return [v0 * mInverse[0] + v1 * mInverse[1] + v2 * mInverse[2], + v0 * mInverse[4] + + v1 * mInverse[5] + + v2 * mInverse[6], + v0 * mInverse[8] + + v1 * mInverse[9] + + v2 * mInverse[10]]; }; /** * Creates a 4-by-4 identity matrix. - * @return {!o3djs.math.Matrix4} The 4-by-4 identity. + * @return {!o3djs.flat_math.Matrix4} The 4-by-4 identity. */ -o3djs.math.matrix4.identity = function() { - return [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1] - ]; +o3djs.flat_math.matrix4.identity = function() { + return o3djs.flat_math.makeMatrix4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); }; /** * Sets the given 4-by-4 matrix to the identity matrix. - * @param {!o3djs.math.Matrix4} m The matrix to set to identity. - * @return {!o3djs.math.Matrix4} m once modified. + * @param {!o3djs.flat_math.Matrix4} m The matrix to set to identity. + * @return {!o3djs.flat_math.Matrix4} m once modified. */ -o3djs.math.matrix4.setIdentity = function(m) { +o3djs.flat_math.matrix4.setIdentity = function(m) { for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { if (i == j) { - m[i][j] = 1; + m[i * 4 + j] = 1; } else { - m[i][j] = 0; + m[i * 4 + j] = 0; } } } @@ -1804,18 +2366,18 @@ o3djs.math.matrix4.setIdentity = function(m) { * of the near clipping plane. * @param {number} far The depth (negative z coordinate) * of the far clipping plane. - * @return {!o3djs.math.Matrix4} The perspective matrix. + * @return {!o3djs.flat_math.Matrix4} The perspective matrix. */ -o3djs.math.matrix4.perspective = function(angle, aspect, near, far) { +o3djs.flat_math.matrix4.perspective = function(angle, aspect, near, far) { var f = Math.tan(0.5 * (Math.PI - angle)); var range = near - far; - return [ - [f / aspect, 0, 0, 0], - [0, f, 0, 0], - [0, 0, far / range, -1], - [0, 0, near * far / range, 0] - ]; + return o3djs.flat_math.makeMatrix4 ( + f / aspect, 0, 0, 0, + 0, f, 0, 0, + 0, 0, 2 * far / range + 1, -1, + 0, 0, 2 * near * far / range, 0 + ); }; /** @@ -1832,18 +2394,17 @@ o3djs.math.matrix4.perspective = function(angle, aspect, near, far) { * @param {number} top The y coordinate of the right plane of the box. * @param {number} near The negative z coordinate of the near plane of the box. * @param {number} far The negative z coordinate of the far plane of the box. - * @return {!o3djs.math.Matrix4} The orthographic projection matrix. + * @return {!o3djs.flat_math.Matrix4} The orthographic projection matrix. */ -o3djs.math.matrix4.orthographic = +o3djs.flat_math.matrix4.orthographic = function(left, right, bottom, top, near, far) { - return [ - [2 / (right - left), 0, 0, 0], - [0, 2 / (top - bottom), 0, 0], - [0, 0, 1 / (near - far), 0], - [(left + right) / (left - right), - (bottom + top) / (bottom - top), - near / (near - far), 1] - ]; + return o3djs.flat_math.makeMatrix4 ( + 2 / (right - left), 0, 0, 0, + 0, 2 / (top - bottom), 0, 0, + 0, 0, 2 / (near - far), 0, + (left + right) / (left - right), + (bottom + top) / (bottom - top), + (near + far) / (near - far), 1); }; /** @@ -1861,17 +2422,17 @@ o3djs.math.matrix4.orthographic = * @param {number} top The y coordinate of the right plane of the box. * @param {number} near The negative z coordinate of the near plane of the box. * @param {number} far The negative z coordinate of the far plane of the box. - * @return {!o3djs.math.Matrix4} The perspective projection matrix. + * @return {!o3djs.flat_math.Matrix4} The perspective projection matrix. */ -o3djs.math.matrix4.frustum = function(left, right, bottom, top, near, far) { +o3djs.flat_math.matrix4.frustum = function(left, right, bottom, top, near, far) { var dx = (right - left); var dy = (top - bottom); var dz = (near - far); - return [ - [2 * near / dx, 0, 0, 0], - [0, 2 * near / dy, 0, 0], - [(left + right) / dx, (top + bottom) / dy, far / dz, -1], - [0, 0, near * far / dz, 0]]; + return o3djs.flat_math.makeMatrix4( + 2 * near / dx, 0, 0, 0, + 0, 2 * near / dy, 0, 0, + (left + right) / dx, (top + bottom) / dy, far / dz, -1, + 0, 0, near * far / dz, 0); }; /** @@ -1881,22 +2442,25 @@ o3djs.math.matrix4.frustum = function(left, right, bottom, top, near, far) { * vector pointing from the eye to the target to a vector pointing in the * negative z direction, and also sends the up vector into the upper half of * the yz plane. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} eye The position + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} eye The position * of the eye. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} target The + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} target The * position meant to be viewed. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} up A vector + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} up A vector * pointing up. - * @return {!o3djs.math.Matrix4} The look-at matrix. + * @return {!o3djs.flat_math.Matrix4} The look-at matrix. */ -o3djs.math.matrix4.lookAt = function(eye, target, up) { - var vz = o3djs.math.normalize( - o3djs.math.subVector(eye, target).slice(0, 3)).concat(0); - var vx = o3djs.math.normalize( - o3djs.math.cross(up, vz)).concat(0); - var vy = o3djs.math.cross(vz, vx).concat(0); - - return o3djs.math.inverse([vx, vy, vz, eye.concat(1)]); +o3djs.flat_math.matrix4.lookAt = function(eye, target, up) { + var vz = o3djs.flat_math.normalize( + o3djs.flat_math.subVector(eye, target).slice(0, 3)); + var vx = o3djs.flat_math.normalize( + o3djs.flat_math.cross(up, vz)); + var vy = o3djs.flat_math.cross(vz, vx); + return o3djs.flat_math.inverse4(o3djs.flat_math.makeMatrix4( + vx[0], vx[1], vx[2], 0, + vy[0], vy[1], vy[2], 0, + vz[0], vz[1], vz[2], 0, + eye[0], eye[1], eye[2], 1)); }; /** @@ -1905,67 +2469,60 @@ o3djs.math.matrix4.lookAt = function(eye, target, up) { * transform by b first and then a. Note this is subtly different from just * multiplying the matrices together. For given a and b, this function returns * the same object in both row-major and column-major mode. - * @param {!o3djs.math.Matrix4} a A 4-by-4 matrix. - * @param {!o3djs.math.Matrix4} b A 4-by-4 matrix. - * @return {!o3djs.math.Matrix4} the composition of a and b, b first then a. - */ -o3djs.math.matrix4.composition = function(a, b) { - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var a3 = a[3]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var b3 = b[3]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a03 = a0[3]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a13 = a1[3]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var a23 = a2[3]; - var a30 = a3[0]; - var a31 = a3[1]; - var a32 = a3[2]; - var a33 = a3[3]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b03 = b0[3]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b13 = b1[3]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - var b23 = b2[3]; - var b30 = b3[0]; - var b31 = b3[1]; - var b32 = b3[2]; - var b33 = b3[3]; - return [[a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, - a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, - a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, - a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03], - [a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, - a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, - a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, - a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13], - [a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, - a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, - a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, - a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23], - [a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, - a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, - a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, - a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33]]; + * @param {!o3djs.flat_math.Matrix4} a A 4-by-4 matrix. + * @param {!o3djs.flat_math.Matrix4} b A 4-by-4 matrix. + * @return {!o3djs.flat_math.Matrix4} the composition of a and b, b first then a. + */ +o3djs.flat_math.matrix4.composition = function(a, b) { + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + var a30 = a[12]; + var a31 = a[13]; + var a32 = a[14]; + var a33 = a[15]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b03 = b[3]; + var b10 = b[4]; + var b11 = b[5]; + var b12 = b[6]; + var b13 = b[7]; + var b20 = b[8]; + var b21 = b[9]; + var b22 = b[10]; + var b23 = b[11]; + var b30 = b[12]; + var b31 = b[13]; + var b32 = b[14]; + var b33 = b[15]; + return o3djs.flat_math.makeMatrix( + a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, + a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, + a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, + a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03, + a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, + a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, + a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, + a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13, + a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, + a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, + a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, + a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23, + a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, + a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, + a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, + a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33); }; /** @@ -1974,121 +2531,105 @@ o3djs.math.matrix4.composition = function(a, b) { * transform by b first and then a. Note this is subtly different from just * multiplying the matrices together. For given a and b, a, upon modification, * will be the same object in both row-major and column-major mode. - * @param {!o3djs.math.Matrix4} a A 4-by-4 matrix. - * @param {!o3djs.math.Matrix4} b A 4-by-4 matrix. - * @return {!o3djs.math.Matrix4} a once modified. - */ -o3djs.math.matrix4.compose = function(a, b) { - var a0 = a[0]; - var a1 = a[1]; - var a2 = a[2]; - var a3 = a[3]; - var b0 = b[0]; - var b1 = b[1]; - var b2 = b[2]; - var b3 = b[3]; - var a00 = a0[0]; - var a01 = a0[1]; - var a02 = a0[2]; - var a03 = a0[3]; - var a10 = a1[0]; - var a11 = a1[1]; - var a12 = a1[2]; - var a13 = a1[3]; - var a20 = a2[0]; - var a21 = a2[1]; - var a22 = a2[2]; - var a23 = a2[3]; - var a30 = a3[0]; - var a31 = a3[1]; - var a32 = a3[2]; - var a33 = a3[3]; - var b00 = b0[0]; - var b01 = b0[1]; - var b02 = b0[2]; - var b03 = b0[3]; - var b10 = b1[0]; - var b11 = b1[1]; - var b12 = b1[2]; - var b13 = b1[3]; - var b20 = b2[0]; - var b21 = b2[1]; - var b22 = b2[2]; - var b23 = b2[3]; - var b30 = b3[0]; - var b31 = b3[1]; - var b32 = b3[2]; - var b33 = b3[3]; - a[0].splice(0, 4, a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, - a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, - a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, - a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03); - a[1].splice(0, 4, a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, - a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, - a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, - a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13); - a[2].splice(0, 4, a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, - a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, - a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, - a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23), - a[3].splice(0, 4, a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, - a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, - a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, - a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33); + * @param {!o3djs.flat_math.Matrix4} a A 4-by-4 matrix. + * @param {!o3djs.flat_math.Matrix4} b A 4-by-4 matrix. + * @return {!o3djs.flat_math.Matrix4} a once modified. + */ +o3djs.flat_math.matrix4.compose = function(a, b) { + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + var a30 = a[12]; + var a31 = a[13]; + var a32 = a[14]; + var a33 = a[15]; + var b00 = b[0]; + var b01 = b[1]; + var b02 = b[2]; + var b03 = b[3]; + var b10 = b[4]; + var b11 = b[5]; + var b12 = b[6]; + var b13 = b[7]; + var b20 = b[8]; + var b21 = b[9]; + var b22 = b[10]; + var b23 = b[11]; + var b30 = b[12]; + var b31 = b[13]; + var b32 = b[14]; + var b33 = b[15]; + a[0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; + a[1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; + a[2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; + a[3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; + a[4] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; + a[5] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; + a[6] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; + a[7] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; + a[8] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; + a[9] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; + a[10] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; + a[11] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; + a[12] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; + a[13] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; + a[14] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; + a[15] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; return a; }; /** * Creates a 4-by-4 matrix which translates by the given vector v. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector by + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} v The vector by * which to translate. - * @return {!o3djs.math.Matrix4} The translation matrix. + * @return {!o3djs.flat_math.Matrix4} The translation matrix. */ -o3djs.math.matrix4.translation = function(v) { - return [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [v[0], v[1], v[2], 1] - ]; +o3djs.flat_math.matrix4.translation = function(v) { + return o3djs.flat_math.makeMatrix4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + v[0], v[1], v[2], 1); }; /** * Modifies the given 4-by-4 matrix by translation by the given vector v. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector by + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} v The vector by * which to translate. - * @return {!o3djs.math.Matrix4} m once modified. - */ -o3djs.math.matrix4.translate = function(m, v) { - var v0 = v[0]; - var v1 = v[1]; - var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - m3.splice(0, 4, m00 * v0 + m10 * v1 + m20 * v2 + m30, - m01 * v0 + m11 * v1 + m21 * v2 + m31, - m02 * v0 + m12 * v1 + m22 * v2 + m32, - m03 * v0 + m13 * v1 + m23 * v2 + m33); + * @return {!o3djs.flat_math.Matrix4} m once modified. + */ +o3djs.flat_math.matrix4.translate = function(m, v) { + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[12] = m00 * v0 + m10 * v1 + m20 * v2 + m30; + m[13] = m01 * v0 + m11 * v1 + m21 * v2 + m31; + m[14] = m02 * v0 + m12 * v1 + m22 * v2 + m32; + m[15] = m03 * v0 + m13 * v1 + m23 * v2 + m33; return m; }; @@ -2097,41 +2638,38 @@ o3djs.math.matrix4.translate = function(m, v) { * Creates a 4-by-4 matrix which scales in each dimension by an amount given by * the corresponding entry in the given vector; assumes the vector has three * entries. - * @param {!o3djs.math.Vector3} v A vector of + * @param {!o3djs.flat_math.Vector3} v A vector of * three entries specifying the factor by which to scale in each dimension. - * @return {!o3djs.math.Matrix4} The scaling matrix. + * @return {!o3djs.flat_math.Matrix4} The scaling matrix. */ -o3djs.math.matrix4.scaling = function(v) { - return [ - [v[0], 0, 0, 0], - [0, v[1], 0, 0], - [0, 0, v[2], 0], - [0, 0, 0, 1] - ]; +o3djs.flat_math.matrix4.scaling = function(v) { + return o3djs.flat_math.makeMatrix( + v[0], 0, 0, 0, + 0, v[1], 0, 0, + 0, 0, v[2], 0, + 0, 0, 0, 1 + ); }; /** * Modifies the given 4-by-4 matrix, scaling in each dimension by an amount * given by the corresponding entry in the given vector; assumes the vector has * three entries. - * @param {!o3djs.math.Matrix4} m The matrix to be modified. - * @param {!o3djs.math.Vector3} v A vector of three entries specifying the + * @param {!o3djs.flat_math.Matrix4} m The matrix to be modified. + * @param {!o3djs.flat_math.Vector3} v A vector of three entries specifying the * factor by which to scale in each dimension. - * @return {!o3djs.math.Matrix4} m once modified. + * @return {!o3djs.flat_math.Matrix4} m once modified. */ -o3djs.math.matrix4.scale = function(m, v) { +o3djs.flat_math.matrix4.scale = function(m, v) { var v0 = v[0]; var v1 = v[1]; var v2 = v[2]; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - m0.splice(0, 4, v0 * m0[0], v0 * m0[1], v0 * m0[2], v0 * m0[3]); - m1.splice(0, 4, v1 * m1[0], v1 * m1[1], v1 * m1[2], v1 * m1[3]); - m2.splice(0, 4, v2 * m2[0], v2 * m2[1], v2 * m2[2], v2 * m2[3]); + for (var i = 0; i < 4; ++i) { + m[i] *= v0; + m[4 + i] *= v1; + m[8 + i] *= v2; + } return m; }; @@ -2139,51 +2677,46 @@ o3djs.math.matrix4.scale = function(m, v) { /** * Creates a 4-by-4 matrix which rotates around the x-axis by the given angle. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} The rotation matrix. + * @return {!o3djs.flat_math.Matrix4} The rotation matrix. */ -o3djs.math.matrix4.rotationX = function(angle) { +o3djs.flat_math.matrix4.rotationX = function(angle) { var c = Math.cos(angle); var s = Math.sin(angle); - return [ - [1, 0, 0, 0], - [0, c, s, 0], - [0, -s, c, 0], - [0, 0, 0, 1] - ]; + return o3djs.flat_math.makeMatrix( + 1, 0, 0, 0, + 0, c, s, 0, + 0, -s, c, 0, + 0, 0, 0, 1); }; /** * Modifies the given 4-by-4 matrix by a rotation around the x-axis by the given * angle. - * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Matrix4} m The matrix. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} m once modified. - */ -o3djs.math.matrix4.rotateX = function(m, angle) { - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; + * @return {!o3djs.flat_math.Matrix4} m once modified. + */ +o3djs.flat_math.matrix4.rotateX = function(m, angle) { + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; var c = Math.cos(angle); var s = Math.sin(angle); - m1.splice(0, 4, c * m10 + s * m20, - c * m11 + s * m21, - c * m12 + s * m22, - c * m13 + s * m23); - m2.splice(0, 4, c * m20 - s * m10, - c * m21 - s * m11, - c * m22 - s * m12, - c * m23 - s * m13); + m[4] = c * m10 + s * m20; + m[5] = c * m11 + s * m21; + m[6] = c * m12 + s * m22; + m[7] = c * m13 + s * m23; + m[8] = c * m20 - s * m10; + m[9] = c * m21 - s * m11; + m[10] = c * m22 - s * m12; + m[11] = c * m23 - s * m13; return m; }; @@ -2191,51 +2724,46 @@ o3djs.math.matrix4.rotateX = function(m, angle) { /** * Creates a 4-by-4 matrix which rotates around the y-axis by the given angle. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} The rotation matrix. + * @return {!o3djs.flat_math.Matrix4} The rotation matrix. */ -o3djs.math.matrix4.rotationY = function(angle) { +o3djs.flat_math.matrix4.rotationY = function(angle) { var c = Math.cos(angle); var s = Math.sin(angle); - return [ - [c, 0, -s, 0], - [0, 1, 0, 0], - [s, 0, c, 0], - [0, 0, 0, 1] - ]; + return o3djs.flat_math.makeMatrix( + c, 0, -s, 0, + 0, 1, 0, 0, + s, 0, c, 0, + 0, 0, 0, 1); }; /** * Modifies the given 4-by-4 matrix by a rotation around the y-axis by the given * angle. - * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Matrix4} m The matrix. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} m once modified. - */ -o3djs.math.matrix4.rotateY = function(m, angle) { - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; + * @return {!o3djs.flat_math.Matrix4} m once modified. + */ +o3djs.flat_math.matrix4.rotateY = function(m, angle) { + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; var c = Math.cos(angle); var s = Math.sin(angle); - m0.splice(0, 4, c * m00 - s * m20, - c * m01 - s * m21, - c * m02 - s * m22, - c * m03 - s * m23); - m2.splice(0, 4, c * m20 + s * m00, - c * m21 + s * m01, - c * m22 + s * m02, - c * m23 + s * m03); + m[0] = c * m00 - s * m20; + m[1] = c * m01 - s * m21; + m[2] = c * m02 - s * m22; + m[3] = c * m03 - s * m23; + m[8] = c * m20 + s * m00; + m[9] = c * m21 + s * m01; + m[10] = c * m22 + s * m02; + m[11] = c * m23 + s * m03; return m; }; @@ -2243,51 +2771,46 @@ o3djs.math.matrix4.rotateY = function(m, angle) { /** * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} The rotation matrix. + * @return {!o3djs.flat_math.Matrix4} The rotation matrix. */ -o3djs.math.matrix4.rotationZ = function(angle) { +o3djs.flat_math.matrix4.rotationZ = function(angle) { var c = Math.cos(angle); var s = Math.sin(angle); - return [ - [c, s, 0, 0], - [-s, c, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1] - ]; + return o3djs.flat_math.makeMatrix( + c, s, 0, 0, + -s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); }; /** * Modifies the given 4-by-4 matrix by a rotation around the z-axis by the given * angle. - * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Matrix4} m The matrix. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} m once modified. - */ -o3djs.math.matrix4.rotateZ = function(m, angle) { - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; + * @return {!o3djs.flat_math.Matrix4} m once modified. + */ +o3djs.flat_math.matrix4.rotateZ = function(m, angle) { + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; var c = Math.cos(angle); var s = Math.sin(angle); - m0.splice(0, 4, c * m00 + s * m10, - c * m01 + s * m11, - c * m02 + s * m12, - c * m03 + s * m13); - m1.splice(0, 4, c * m10 - s * m00, - c * m11 - s * m01, - c * m12 - s * m02, - c * m13 - s * m03); + m[0] = c * m00 + s * m10; + m[1] = c * m01 + s * m11; + m[2] = c * m02 + s * m12; + m[3] = c * m03 + s * m13; + m[4] = c * m10 - s * m00; + m[5] = c * m11 - s * m01; + m[6] = c * m12 - s * m02; + m[7] = c * m13 - s * m03; return m; }; @@ -2297,10 +2820,10 @@ o3djs.math.matrix4.rotateZ = function(m, angle) { * vector as angles by which to rotate around the x, y and z axes, returns a * a matrix which rotates around the x-axis first, then the y-axis, then the * z-axis. - * @param {!o3djs.math.Vector3} v A vector of angles (in radians). - * @return {!o3djs.math.Matrix4} The rotation matrix. + * @param {!o3djs.flat_math.Vector3} v A vector of angles (in radians). + * @return {!o3djs.flat_math.Matrix4} The rotation matrix. */ -o3djs.math.matrix4.rotationZYX = function(v) { +o3djs.flat_math.matrix4.rotationZYX = function(v) { var sinx = Math.sin(v[0]); var cosx = Math.cos(v[0]); var siny = Math.sin(v[1]); @@ -2311,29 +2834,22 @@ o3djs.math.matrix4.rotationZYX = function(v) { var coszsiny = cosz * siny; var sinzsiny = sinz * siny; - return [ - [cosz * cosy, sinz * cosy, -siny, 0], - [coszsiny * sinx - sinz * cosx, - sinzsiny * sinx + cosz * cosx, - cosy * sinx, - 0], - [coszsiny * cosx + sinz * sinx, - sinzsiny * cosx - cosz * sinx, - cosy * cosx, - 0], - [0, 0, 0, 1] - ]; + return o3djs.flat_math.makeMatrix( + cosz * cosy, sinz * cosy, -siny, 0, coszsiny * sinx - sinz * cosx, + sinzsiny * sinx + cosz * cosx, cosy * sinx, 0, + coszsiny * cosx + sinz * sinx, sinzsiny * cosx - cosz * sinx, cosy * cosx, + 0, 0, 0, 0, 1); }; /** * Modifies a 4-by-4 matrix by a rotation. Interprets the coordinates of the * given vector as angles by which to rotate around the x, y and z axes, rotates * around the x-axis first, then the y-axis, then the z-axis. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {!o3djs.math.Vector3} v A vector of angles (in radians). - * @return {!o3djs.math.Matrix4} m once modified. + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {!o3djs.flat_math.Vector3} v A vector of angles (in radians). + * @return {!o3djs.flat_math.Matrix4} m once modified. */ -o3djs.math.matrix4.rotateZYX = function(m, v) { +o3djs.flat_math.matrix4.rotateZYX = function(m, v) { var sinX = Math.sin(v[0]); var cosX = Math.cos(v[0]); var sinY = Math.sin(v[1]); @@ -2354,45 +2870,37 @@ o3djs.math.matrix4.rotateZYX = function(m, v) { var r21 = sinZSinY * cosX - cosZ * sinX; var r22 = cosY * cosX; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - m0.splice(0, 4, - r00 * m00 + r01 * m10 + r02 * m20, - r00 * m01 + r01 * m11 + r02 * m21, - r00 * m02 + r01 * m12 + r02 * m22, - r00 * m03 + r01 * m13 + r02 * m23); - - m1.splice(0, 4, - r10 * m00 + r11 * m10 + r12 * m20, - r10 * m01 + r11 * m11 + r12 * m21, - r10 * m02 + r11 * m12 + r12 * m22, - r10 * m03 + r11 * m13 + r12 * m23); - - m2.splice(0, 4, - r20 * m00 + r21 * m10 + r22 * m20, - r20 * m01 + r21 * m11 + r22 * m21, - r20 * m02 + r21 * m12 + r22 * m22, - r20 * m03 + r21 * m13 + r22 * m23); + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[0] = r00 * m00 + r01 * m10 + r02 * m20; + m[1] = r00 * m01 + r01 * m11 + r02 * m21; + m[2] = r00 * m02 + r01 * m12 + r02 * m22; + m[3] = r00 * m03 + r01 * m13 + r02 * m23; + + m[4] = r10 * m00 + r11 * m10 + r12 * m20; + m[5] = r10 * m01 + r11 * m11 + r12 * m21; + m[6] = r10 * m02 + r11 * m12 + r12 * m22; + m[7] = r10 * m03 + r11 * m13 + r12 * m23; + + m[8] = r20 * m00 + r21 * m10 + r22 * m20; + m[9] = r20 * m01 + r21 * m11 + r22 * m21; + m[10] = r20 * m02 + r21 * m12 + r22 * m22; + m[11] = r20 * m03 + r21 * m13 + r22 * m23; return m; }; @@ -2400,13 +2908,13 @@ o3djs.math.matrix4.rotateZYX = function(m, v) { /** * Creates a 4-by-4 matrix which rotates around the given axis by the given * angle. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} axis The axis + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} axis The axis * about which to rotate. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} A matrix which rotates angle radians + * @return {!o3djs.flat_math.Matrix4} A matrix which rotates angle radians * around the axis. */ -o3djs.math.matrix4.axisRotation = function(axis, angle) { +o3djs.flat_math.matrix4.axisRotation = function(axis, angle) { var x = axis[0]; var y = axis[1]; var z = axis[2]; @@ -2421,33 +2929,33 @@ o3djs.math.matrix4.axisRotation = function(axis, angle) { var s = Math.sin(angle); var oneMinusCosine = 1 - c; - return [ - [xx + (1 - xx) * c, + return o3djs.flat_math.makeMatrix( + xx + (1 - xx) * c, x * y * oneMinusCosine + z * s, x * z * oneMinusCosine - y * s, - 0], - [x * y * oneMinusCosine - z * s, + 0, + x * y * oneMinusCosine - z * s, yy + (1 - yy) * c, y * z * oneMinusCosine + x * s, - 0], - [x * z * oneMinusCosine + y * s, + 0, + x * z * oneMinusCosine + y * s, y * z * oneMinusCosine - x * s, zz + (1 - zz) * c, - 0], - [0, 0, 0, 1] - ]; + 0, + 0, 0, 0, 1 + ); }; /** * Modifies the given 4-by-4 matrix by rotation around the given axis by the * given angle. - * @param {!o3djs.math.Matrix4} m The matrix. - * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} axis The axis + * @param {!o3djs.flat_math.Matrix4} m The matrix. + * @param {(!o3djs.flat_math.Vector3|!o3djs.flat_math.Vector4)} axis The axis * about which to rotate. * @param {number} angle The angle by which to rotate (in radians). - * @return {!o3djs.math.Matrix4} m once modified. + * @return {!o3djs.flat_math.Matrix4} m once modified. */ -o3djs.math.matrix4.axisRotate = function(m, axis, angle) { +o3djs.flat_math.matrix4.axisRotate = function(m, axis, angle) { var x = axis[0]; var y = axis[1]; var z = axis[2]; @@ -2472,97 +2980,105 @@ o3djs.math.matrix4.axisRotate = function(m, axis, angle) { var r21 = y * z * oneMinusCosine - x * s; var r22 = zz + (1 - zz) * c; - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; - var m3 = m[3]; - - var m00 = m0[0]; - var m01 = m0[1]; - var m02 = m0[2]; - var m03 = m0[3]; - var m10 = m1[0]; - var m11 = m1[1]; - var m12 = m1[2]; - var m13 = m1[3]; - var m20 = m2[0]; - var m21 = m2[1]; - var m22 = m2[2]; - var m23 = m2[3]; - var m30 = m3[0]; - var m31 = m3[1]; - var m32 = m3[2]; - var m33 = m3[3]; - - m0.splice(0, 4, - r00 * m00 + r01 * m10 + r02 * m20, - r00 * m01 + r01 * m11 + r02 * m21, - r00 * m02 + r01 * m12 + r02 * m22, - r00 * m03 + r01 * m13 + r02 * m23); - - m1.splice(0, 4, - r10 * m00 + r11 * m10 + r12 * m20, - r10 * m01 + r11 * m11 + r12 * m21, - r10 * m02 + r11 * m12 + r12 * m22, - r10 * m03 + r11 * m13 + r12 * m23); - - m2.splice(0, 4, - r20 * m00 + r21 * m10 + r22 * m20, - r20 * m01 + r21 * m11 + r22 * m21, - r20 * m02 + r21 * m12 + r22 * m22, - r20 * m03 + r21 * m13 + r22 * m23); + var m00 = m[0]; + var m01 = m[1]; + var m02 = m[2]; + var m03 = m[3]; + var m10 = m[4]; + var m11 = m[5]; + var m12 = m[6]; + var m13 = m[7]; + var m20 = m[8]; + var m21 = m[9]; + var m22 = m[10]; + var m23 = m[11]; + var m30 = m[12]; + var m31 = m[13]; + var m32 = m[14]; + var m33 = m[15]; + + m[0] = r00 * m00 + r01 * m10 + r02 * m20; + m[1] = r00 * m01 + r01 * m11 + r02 * m21; + m[2] = r00 * m02 + r01 * m12 + r02 * m22; + m[3] = r00 * m03 + r01 * m13 + r02 * m23; + + m[4] = r10 * m00 + r11 * m10 + r12 * m20; + m[5] = r10 * m01 + r11 * m11 + r12 * m21; + m[6] = r10 * m02 + r11 * m12 + r12 * m22; + m[7] = r10 * m03 + r11 * m13 + r12 * m23; + + m[8] = r20 * m00 + r21 * m10 + r22 * m20; + m[9] = r20 * m01 + r21 * m11 + r22 * m21; + m[10] = r20 * m02 + r21 * m12 + r22 * m22; + m[11] = r20 * m03 + r21 * m13 + r22 * m23; return m; }; /** - * Sets each function in the namespace o3djs.math to the row major - * version in o3djs.math.rowMajor (provided such a function exists in - * o3djs.math.rowMajor). Call this function to establish the row major + * Sets each function in the namespace o3djs.flat_math to the row major + * version in o3djs.flat_math.rowMajor (provided such a function exists in + * o3djs.flat_math.rowMajor). Call this function to establish the row major * convention. */ -o3djs.math.installRowMajorFunctions = function() { - for (var f in o3djs.math.rowMajor) { - o3djs.math[f] = o3djs.math.rowMajor[f]; +o3djs.flat_math.installRowMajorFunctions = function() { + for (var f in o3djs.flat_math.rowMajor) { + o3djs.flat_math[f] = o3djs.flat_math.rowMajor[f]; } }; /** - * Sets each function in the namespace o3djs.math to the column major - * version in o3djs.math.columnMajor (provided such a function exists in - * o3djs.math.columnMajor). Call this function to establish the column + * Sets each function in the namespace o3djs.flat_math to the column major + * version in o3djs.flat_math.columnMajor (provided such a function exists in + * o3djs.flat_math.columnMajor). Call this function to establish the column * major convention. */ -o3djs.math.installColumnMajorFunctions = function() { - for (var f in o3djs.math.columnMajor) { - o3djs.math[f] = o3djs.math.columnMajor[f]; +o3djs.flat_math.installColumnMajorFunctions = function() { + for (var f in o3djs.flat_math.columnMajor) { + o3djs.flat_math[f] = o3djs.flat_math.columnMajor[f]; } }; /** - * Sets each function in the namespace o3djs.math to the error checking - * version in o3djs.math.errorCheck (provided such a function exists in - * o3djs.math.errorCheck). + * Sets each function in the namespace o3djs.flat_math to the error checking + * version in o3djs.flat_math.errorCheck (provided such a function exists in + * o3djs.flat_math.errorCheck). */ -o3djs.math.installErrorCheckFunctions = function() { - for (var f in o3djs.math.errorCheck) { - o3djs.math[f] = o3djs.math.errorCheck[f]; +o3djs.flat_math.installErrorCheckFunctions = function() { + for (var f in o3djs.flat_math.errorCheck) { + o3djs.flat_math[f] = o3djs.flat_math.errorCheck[f]; } }; /** - * Sets each function in the namespace o3djs.math to the error checking free - * version in o3djs.math.errorCheckFree (provided such a function exists in - * o3djs.math.errorCheckFree). + * Sets each function in the namespace o3djs.flat_math to the error checking free + * version in o3djs.flat_math.errorCheckFree (provided such a function exists in + * o3djs.flat_math.errorCheckFree). */ -o3djs.math.installErrorCheckFreeFunctions = function() { - for (var f in o3djs.math.errorCheckFree) { - o3djs.math[f] = o3djs.math.errorCheckFree[f]; +o3djs.flat_math.installErrorCheckFreeFunctions = function() { + for (var f in o3djs.flat_math.errorCheckFree) { + o3djs.flat_math[f] = o3djs.flat_math.errorCheckFree[f]; } -} +}; // By default, install the row-major functions. -o3djs.math.installRowMajorFunctions(); +o3djs.flat_math.installRowMajorFunctions(); // By default, install prechecking. -o3djs.math.installErrorCheckFunctions(); +o3djs.flat_math.installErrorCheckFunctions(); + +if (!use_plugin_math) { + for (var i in o3djs.flat_math) { + o3djs.math[i] = o3djs.flat_math[i]; + } +} + + +/** + * True if we are using the plugin math library in which matrices are + * represented by 2-dimensional arrays. + * @type {boolean} + * @private + */ +o3djs.math.usePluginMath_ = true; + diff --git a/o3d/samples/o3djs/plugin_math.js b/o3d/samples/o3djs/plugin_math.js new file mode 100644 index 0000000..799ce78 --- /dev/null +++ b/o3d/samples/o3djs/plugin_math.js @@ -0,0 +1,2621 @@ +/* + * Copyright 2009, Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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. + */ + + +/** + * @fileoverview This file contains matrix/vector math functions. + * It adds them to the "math" module on the o3djs object. + * + * o3djs.math supports a row-major and a column-major mode. In both + * modes, vectors are stored as arrays of numbers, and matrices are stored as + * arrays of arrays of numbers. + * + * In row-major mode: + * + * - Rows of a matrix are sub-arrays. + * - Individual entries of a matrix M get accessed in M[row][column] fashion. + * - Tuples of coordinates are interpreted as row-vectors. + * - A vector v gets transformed by a matrix M by multiplying in the order v*M. + * + * In column-major mode: + * + * - Columns of a matrix are sub-arrays. + * - Individual entries of a matrix M get accessed in M[column][row] fashion. + * - Tuples of coordinates are interpreted as column-vectors. + * - A matrix M transforms a vector v by multiplying in the order M*v. + * + * When a function in o3djs.math requires separate row-major and + * column-major versions, a function with the same name gets added to each of + * the namespaces o3djs.math.rowMajor and o3djs.math.columnMajor. The + * function installRowMajorFunctions() or the function + * installColumnMajorFunctions() should get called during initialization to + * establish the mode. installRowMajorFunctions() works by iterating through + * the o3djs.math.rowMajor namespace and for each function foo, setting + * o3djs.math.foo equal to o3djs.math.rowMajor.foo. + * installRowMajorFunctions() works the same way, iterating over the columnMajor + * namespace. At the end of this file, we call installRowMajorFunctions(). + * + * Switching modes changes two things. It changes how a matrix is encoded as an + * array, and it changes how the entries of a matrix get interpreted. Because + * those two things change together, the matrix representing a given + * transformation of space is the same JavaScript object in either mode. + * One consequence of this is that very few functions require separate row-major + * and column-major versions. Typically, a function requires separate versions + * only if it makes matrix multiplication order explicit, like + * mulMatrixMatrix(), mulMatrixVector(), or mulVectorMatrix(). Functions which + * create a new matrix, like scaling(), rotationZYX(), and translation() return + * the same JavaScript object in either mode, and functions which implicitly + * multiply like scale(), rotateZYX() and translate() modify the matrix in the + * same way in either mode. + * + * The convention choice made for math functions in this library is independent + * of the convention choice for how matrices get loaded into shaders. That + * convention is determined on a per-shader basis. + * + * Other utilities in o3djs should avoid making calls to functions that make + * multiplication order explicit. Instead they should appeal to functions like: + * + * o3djs.math.matrix4.transformPoint + * o3djs.math.matrix4.transformDirection + * o3djs.math.matrix4.transformNormal + * o3djs.math.matrix4.transformVector4 + * o3djs.math.matrix4.composition + * o3djs.math.matrix4.compose + * + * These functions multiply matrices implicitly and internally choose the + * multiplication order to get the right result. That way, utilities which use + * o3djs.math work in either major mode. Note that this does not necessarily + * mean all sample code will work even if a line is added which switches major + * modes, but it does mean that calls to o3djs still do what they are supposed + * to. + * + */ + +o3djs.provide('o3djs.math'); + +/** + * A module for math for o3djs.math. + * @namespace + */ +o3djs.math = o3djs.math || {}; + +/** + * A random seed for the pseudoRandom function. + * @private + * @type {number} + */ +o3djs.math.randomSeed_ = 0; + +/** + * A constant for the pseudoRandom function + * @private + * @type {number} + */ +o3djs.math.RANDOM_RANGE_ = Math.pow(2, 32); + +/** + * Functions which deal with 4-by-4 transformation matrices are kept in their + * own namespsace. + * @namespace + */ +o3djs.math.matrix4 = o3djs.math.matrix4 || {}; + +/** + * Functions that are specifically row major are kept in their own namespace. + * @namespace + */ +o3djs.math.rowMajor = o3djs.math.rowMajor || {}; + +/** + * Functions that are specifically column major are kept in their own namespace. + * @namespace + */ +o3djs.math.columnMajor = o3djs.math.columnMajor || {}; + +/** + * Functions that do error checking are stored in their own namespace. + * @namespace + */ +o3djs.math.errorCheck = o3djs.math.errorCheck || {}; + +/** + * Functions that do no error checking and have a separate version that does in + * o3djs.math.errorCheck are stored in their own namespace. + * @namespace + */ +o3djs.math.errorCheckFree = o3djs.math.errorCheckFree || {}; + +/** + * An Array of 2 floats + * @type {(!Array.<number>|!o3d.Float2)} + */ +o3djs.math.Vector2 = goog.typedef; + +/** + * An Array of 3 floats + * @type {(!Array.<number>|!o3d.Float3)} + */ +o3djs.math.Vector3 = goog.typedef; + +/** + * An Array of 4 floats + * @type {(!Array.<number>|!o3d.Float4)} + */ +o3djs.math.Vector4 = goog.typedef; + +/** + * An Array of floats. + * @type {!Array.<number>} + */ +o3djs.math.Vector = goog.typedef; + +/** + * A 1x1 Matrix of floats + * @type {!Array.<!Array.<number>>} + */ +o3djs.math.Matrix1 = goog.typedef; + +/** + * A 2x2 Matrix of floats + * @type {!Array.<!Array.<number>>} + */ +o3djs.math.Matrix2 = goog.typedef; + +/** + * A 3x3 Matrix of floats + * @type {!Array.<!Array.<number>>} + */ +o3djs.math.Matrix3 = goog.typedef; + +/** + * A 4x4 Matrix of floats + * @type {(!Array.<!Array.<number>>|!o3d.Matrix4)} + */ +o3djs.math.Matrix4 = goog.typedef; + +/** + * A arbitrary size Matrix of floats + * @type {(!Array.<!Array.<number>>|!o3d.Matrix4)} + */ +o3djs.math.Matrix = goog.typedef; + + +o3djs.math.makeMatrix = function(a,b,c,d, + e,f,g,h, + i,j,k,l, + m,n,o,p) { + if (p===undefined) { + if (i===undefined) { + return [[a,b], + [c,d]]; + } + return [[a,b,c], + [d,e,f], + [g,h,i]]; + } + return [[a,b,c,d], + [e,f,g,h], + [i,j,k,l], + [m,n,o,p]]; +}; + +o3djs.math.makeMatrix2 = function(a,b, + c,d) { + return [[a,b], + [c,d]]; +}; +o3djs.math.makeMatrix3 = function(a,b,c, + d,e,f, + g,h,i) { + return [[a,b,c], + [d,e,f], + [g,h,i]]; +}; +o3djs.math.makeMatrix4 = function(a,b,c,d, + e,f,g,h, + i,j,k,l, + m,n,o,p) { + return [[a,b,c,d], + [e,f,g,h], + [i,j,k,l], + [m,n,o,p]]; +}; + + + +/** + * Returns a deterministic pseudorandom number between 0 and 1 + * @return {number} a random number between 0 and 1 + */ +o3djs.math.pseudoRandom = function() { + var math = o3djs.math; + return (math.randomSeed_ = + (134775813 * math.randomSeed_ + 1) % + math.RANDOM_RANGE_) / math.RANDOM_RANGE_; +}; + +/** + * Resets the pseudoRandom function sequence. + */ +o3djs.math.resetPseudoRandom = function() { + o3djs.math.randomSeed_ = 0; +}; + +/** + * Converts degrees to radians. + * @param {number} degrees A value in degrees. + * @return {number} the value in radians. + */ +o3djs.math.degToRad = function(degrees) { + return degrees * Math.PI / 180; +}; + +/** + * Converts radians to degrees. + * @param {number} radians A value in radians. + * @return {number} the value in degrees. + */ +o3djs.math.radToDeg = function(radians) { + return radians * 180 / Math.PI; +}; + +/** + * Performs linear interpolation on two scalars. + * Given scalars a and b and interpolation coefficient t, returns + * (1 - t) * a + t * b. + * @param {number} a Operand scalar. + * @param {number} b Operand scalar. + * @param {number} t Interpolation coefficient. + * @return {number} The weighted sum of a and b. + */ +o3djs.math.lerpScalar = function(a, b, t) { + return (1 - t) * a + t * b; +}; + +/** + * Adds two vectors; assumes a and b have the same dimension. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {!o3djs.math.Vector} The sum of a and b. + */ +o3djs.math.addVector = function(a, b) { + var r = []; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r[i] = a[i] + b[i]; + return r; +}; + +/** + * Subtracts two vectors. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {!o3djs.math.Vector} The difference of a and b. + */ +o3djs.math.subVector = function(a, b) { + var r = []; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r[i] = a[i] - b[i]; + return r; +}; + +/** + * Performs linear interpolation on two vectors. + * Given vectors a and b and interpolation coefficient t, returns + * (1 - t) * a + t * b. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @param {number} t Interpolation coefficient. + * @return {!o3djs.math.Vector} The weighted sum of a and b. + */ +o3djs.math.lerpVector = function(a, b, t) { + var r = []; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r[i] = (1 - t) * a[i] + t * b[i]; + return r; +}; + +/** + * Clamps a value between 0 and range using a modulo. + * @param {number} v Value to clamp mod. + * @param {number} range Range to clamp to. + * @param {number} opt_rangeStart start of range. Default = 0. + * @return {number} Clamp modded value. + */ +o3djs.math.modClamp = function(v, range, opt_rangeStart) { + var start = opt_rangeStart || 0; + if (range < 0.00001) { + return start; + } + v -= start; + if (v < 0) { + v -= Math.floor(v / range) * range; + } else { + v = v % range; + } + return v + start; +}; + +/** + * Lerps in a circle. + * Does a lerp between a and b but inside range so for example if + * range is 100, a is 95 and b is 5 lerping will go in the positive direction. + * @param {number} a Start value. + * @param {number} b Target value. + * @param {number} t Amount to lerp (0 to 1). + * @param {number} range Range of circle. + * @return {number} lerped result. + */ +o3djs.math.lerpCircular = function(a, b, t, range) { + a = o3djs.math.modClamp(a, range); + b = o3djs.math.modClamp(b, range); + var delta = b - a; + if (Math.abs(delta) > range * 0.5) { + if (delta > 0) { + b -= range; + } else { + b += range; + } + } + return o3djs.math.modClamp(o3djs.math.lerpScalar(a, b, t), range); +}; + +/** + * Lerps radians. + * @param {number} a Start value. + * @param {number} b Target value. + * @param {number} t Amount to lerp (0 to 1). + * @return {number} lerped result. + */ +o3djs.math.lerpRadian = function(a, b, t) { + return o3djs.math.lerpCircular(a, b, t, Math.PI * 2); +}; + +/** + * Divides a vector by a scalar. + * @param {!o3djs.math.Vector} v The vector. + * @param {number} k The scalar. + * @return {!o3djs.math.Vector} v The vector v divided by k. + */ +o3djs.math.divVectorScalar = function(v, k) { + var r = []; + var vLength = v.length; + for (var i = 0; i < vLength; ++i) + r[i] = v[i] / k; + return r; +}; + +/** + * Computes the dot product of two vectors; assumes that a and b have + * the same dimension. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {number} The dot product of a and b. + */ +o3djs.math.dot = function(a, b) { + var r = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r += a[i] * b[i]; + return r; +}; + +/** + * Computes the cross product of two vectors; assumes both vectors have + * three entries. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {!o3djs.math.Vector} The vector a cross b. + */ +o3djs.math.cross = function(a, b) { + return [a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0]]; +}; + +/** + * Computes the Euclidean length of a vector, i.e. the square root of the + * sum of the squares of the entries. + * @param {!o3djs.math.Vector} a The vector. + * @return {number} The length of a. + */ +o3djs.math.length = function(a) { + var r = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r += a[i] * a[i]; + return Math.sqrt(r); +}; + +/** + * Computes the square of the Euclidean length of a vector, i.e. the sum + * of the squares of the entries. + * @param {!o3djs.math.Vector} a The vector. + * @return {number} The square of the length of a. + */ +o3djs.math.lengthSquared = function(a) { + var r = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r += a[i] * a[i]; + return r; +}; + +/** + * Computes the Euclidean distance between two vectors. + * @param {!o3djs.math.Vector} a A vector. + * @param {!o3djs.math.Vector} b A vector. + * @return {number} The distance between a and b. + */ +o3djs.math.distance = function(a, b) { + var r = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) { + var t = a[i] - b[i]; + r += t * t; + } + return Math.sqrt(r); +}; + +/** + * Computes the square of the Euclidean distance between two vectors. + * @param {!o3djs.math.Vector} a A vector. + * @param {!o3djs.math.Vector} b A vector. + * @return {number} The distance between a and b. + */ +o3djs.math.distanceSquared = function(a, b) { + var r = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) { + var t = a[i] - b[i]; + r += t * t; + } + return r; +}; + +/** + * Divides a vector by its Euclidean length and returns the quotient. + * @param {!o3djs.math.Vector} a The vector. + * @return {!o3djs.math.Vector} The normalized vector. + */ +o3djs.math.normalize = function(a) { + var r = []; + var n = 0.0; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + n += a[i] * a[i]; + n = Math.sqrt(n); + for (var i = 0; i < aLength; ++i) + r[i] = a[i] / n; + return r; +}; + +/** + * Adds two matrices; assumes a and b are the same size. + * @param {!o3djs.math.Matrix} a Operand matrix. + * @param {!o3djs.math.Matrix} b Operand matrix. + * @return {!o3djs.math.Matrix} The sum of a and b. + */ +o3djs.math.addMatrix = function(a, b) { + var r = []; + var aLength = a.length; + var a0Length = a[0].length; + for (var i = 0; i < aLength; ++i) { + var row = []; + var ai = a[i]; + var bi = b[i]; + for (var j = 0; j < a0Length; ++j) + row[j] = ai[j] + bi[j]; + r[i] = row; + } + return r; +}; + +/** + * Subtracts two matrices; assumes a and b are the same size. + * @param {!o3djs.math.Matrix} a Operand matrix. + * @param {!o3djs.math.Matrix} b Operand matrix. + * @return {!o3djs.math.Matrix} The sum of a and b. + */ +o3djs.math.subMatrix = function(a, b) { + var r = []; + var aLength = a.length; + var a0Length = a[0].length; + for (var i = 0; i < aLength; ++i) { + var row = []; + var ai = a[i]; + var bi = b[i]; + for (var j = 0; j < a0Length; ++j) + row[j] = ai[j] - bi[j]; + r[i] = row; + } + return r; +}; + +/** + * Performs linear interpolation on two matrices. + * Given matrices a and b and interpolation coefficient t, returns + * (1 - t) * a + t * b. + * @param {!o3djs.math.Matrix} a Operand matrix. + * @param {!o3djs.math.Matrix} b Operand matrix. + * @param {number} t Interpolation coefficient. + * @return {!o3djs.math.Matrix} The weighted of a and b. + */ +o3djs.math.lerpMatrix = function(a, b, t) { + var r = []; + var aLength = a.length; + var a0Length = a[0].length; + for (var i = 0; i < aLength; ++i) { + var row = []; + var ai = a[i]; + var bi = b[i]; + for (var j = 0; j < a0Length; ++j) + row[j] = (1 - t) * ai[j] + t * bi[j]; + r[i] = row; + } + return r; +}; + +/** + * Divides a matrix by a scalar. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} k The scalar. + * @return {!o3djs.math.Matrix} The matrix m divided by k. + */ +o3djs.math.divMatrixScalar = function(m, k) { + var r = []; + var mLength = m.length; + var m0Length = m[0].length; + for (var i = 0; i < mLength; ++i) { + r[i] = []; + for (var j = 0; j < m0Length; ++j) + r[i][j] = m[i][j] / k; + } + return r; +}; + +/** + * Negates a scalar. + * @param {number} a The scalar. + * @return {number} -a. + */ +o3djs.math.negativeScalar = function(a) { + return -a; +}; + +/** + * Negates a vector. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} -v. + */ +o3djs.math.negativeVector = function(v) { + var r = []; + var vLength = v.length; + for (var i = 0; i < vLength; ++i) { + r[i] = -v[i]; + } + return r; +}; + +/** + * Negates a matrix. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} -m. + */ +o3djs.math.negativeMatrix = function(m) { + var r = []; + var mLength = m.length; + var m0Length = m[0].length; + for (var i = 0; i < mLength; ++i) { + r[i] = []; + for (var j = 0; j < m0Length; ++j) + r[i][j] = -m[i][j]; + } + return r; +}; + +/** + * Copies a scalar. + * @param {number} a The scalar. + * @return {number} a. + */ +o3djs.math.copyScalar = function(a) { + return a; +}; + +/** + * Copies a vector. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} A copy of v. + */ +o3djs.math.copyVector = function(v) { + var r = []; + for (var i = 0; i < v.length; i++) + r[i] = v[i]; + return r; +}; + +/** + * Copies a matrix. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} A copy of m. + */ +o3djs.math.copyMatrix = function(m) { + var r = []; + var mLength = m.length; + for (var i = 0; i < mLength; ++i) { + r[i] = []; + for (var j = 0; j < m[i].length; j++) { + r[i][j] = m[i][j]; + } + } + return r; +}; + +/** + * Returns the elements of a matrix as a one-dimensional array. The + * rows or columns (depending on whether the matrix is row-major or + * column-major) are concatenated. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!Array.<number>} The matrix's elements as a one-dimensional array. + */ +o3djs.math.getMatrixElements = function(m) { + var r = []; + var mLength = m.length; + var k = 0; + for (var i = 0; i < mLength; i++) { + for (var j = 0; j < m[i].length; j++) { + r[k++] = m[i][j]; + } + } + return r; +}; + +/** + * Multiplies two scalars. + * @param {number} a Operand scalar. + * @param {number} b Operand scalar. + * @return {number} The product of a and b. + */ +o3djs.math.mulScalarScalar = function(a, b) { + return a * b; +}; + +/** + * Multiplies a scalar by a vector. + * @param {number} k The scalar. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} The product of k and v. + */ +o3djs.math.mulScalarVector = function(k, v) { + var r = []; + var vLength = v.length; + for (var i = 0; i < vLength; ++i) { + r[i] = k * v[i]; + } + return r; +}; + +/** + * Multiplies a vector by a scalar. + * @param {!o3djs.math.Vector} v The vector. + * @param {number} k The scalar. + * @return {!o3djs.math.Vector} The product of k and v. + */ +o3djs.math.mulVectorScalar = function(v, k) { + return o3djs.math.mulScalarVector(k, v); +}; + +/** + * Multiplies a scalar by a matrix. + * @param {number} k The scalar. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} The product of m and k. + */ +o3djs.math.mulScalarMatrix = function(k, m) { + var r = []; + var mLength = m.length; + var m0Length = m[0].length; + for (var i = 0; i < mLength; ++i) { + r[i] = []; + for (var j = 0; j < m0Length; ++j) + r[i][j] = k * m[i][j]; + } + return r; +}; + +/** + * Multiplies a matrix by a scalar. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} k The scalar. + * @return {!o3djs.math.Matrix} The product of m and k. + */ +o3djs.math.mulMatrixScalar = function(m, k) { + return o3djs.math.mulScalarMatrix(k, m); +}; + +/** + * Multiplies a vector by another vector (component-wise); assumes a and + * b have the same length. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {!o3djs.math.Vector} The vector of products of entries of a and + * b. + */ +o3djs.math.mulVectorVector = function(a, b) { + var r = []; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r[i] = a[i] * b[i]; + return r; +}; + +/** + * Divides a vector by another vector (component-wise); assumes a and + * b have the same length. + * @param {!o3djs.math.Vector} a Operand vector. + * @param {!o3djs.math.Vector} b Operand vector. + * @return {!o3djs.math.Vector} The vector of quotients of entries of a and + * b. + */ +o3djs.math.divVectorVector = function(a, b) { + var r = []; + var aLength = a.length; + for (var i = 0; i < aLength; ++i) + r[i] = a[i] / b[i]; + return r; +}; + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [row][column] fashion. + * @param {!o3djs.math.Vector} v The vector. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Vector} The product of v and m as a row vector. + */ +o3djs.math.rowMajor.mulVectorMatrix = function(v, m) { + var r = []; + var m0Length = m[0].length; + var vLength = v.length; + for (var i = 0; i < m0Length; ++i) { + r[i] = 0.0; + for (var j = 0; j < vLength; ++j) + r[i] += v[j] * m[j][i]; + } + return r; +}; + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector; assumes + * matrix entries are accessed in [column][row] fashion. + * @param {!o3djs.math.Vector} v The vector. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Vector} The product of v and m as a row vector. + */ +o3djs.math.columnMajor.mulVectorMatrix = function(v, m) { + var r = []; + var mLength = m.length; + var vLength = v.length; + for (var i = 0; i < mLength; ++i) { + r[i] = 0.0; + var column = m[i]; + for (var j = 0; j < vLength; ++j) + r[i] += v[j] * column[j]; + } + return r; +}; + +/** + * Multiplies a vector by a matrix; treats the vector as a row vector. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} The product of m and v as a row vector. + */ +o3djs.math.mulVectorMatrix = null; + +/** + * Multiplies a matrix by a vector; treats the vector as a column vector. + * assumes matrix entries are accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} The product of m and v as a column vector. + */ +o3djs.math.rowMajor.mulMatrixVector = function(m, v) { + var r = []; + var mLength = m.length; + var m0Length = m[0].length; + for (var i = 0; i < mLength; ++i) { + r[i] = 0.0; + var row = m[i]; + for (var j = 0; j < m0Length; ++j) + r[i] += row[j] * v[j]; + } + return r; +}; + +/** + * Multiplies a matrix by a vector; treats the vector as a column vector; + * assumes matrix entries are accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} The product of m and v as a column vector. + */ +o3djs.math.columnMajor.mulMatrixVector = function(m, v) { + var r = []; + var m0Length = m[0].length; + var vLength = v.length; + for (var i = 0; i < m0Length; ++i) { + r[i] = 0.0; + for (var j = 0; j < vLength; ++j) + r[i] += v[j] * m[j][i]; + } + return r; +}; + +/** + * Multiplies a matrix by a vector; treats the vector as a column vector. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {!o3djs.math.Vector} v The vector. + * @return {!o3djs.math.Vector} The product of m and v as a column vector. + */ +o3djs.math.mulMatrixVector = null; + +/** + * Multiplies two 2-by-2 matrices; assumes that the given matrices are 2-by-2; + * assumes matrix entries are accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix2} a The matrix on the left. + * @param {!o3djs.math.Matrix2} b The matrix on the right. + * @return {!o3djs.math.Matrix2} The matrix product of a and b. + */ +o3djs.math.rowMajor.mulMatrixMatrix2 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var b0 = b[0]; + var b1 = b[1]; + var a00 = a0[0]; + var a01 = a0[1]; + var a10 = a1[0]; + var a11 = a1[1]; + var b00 = b0[0]; + var b01 = b0[1]; + var b10 = b1[0]; + var b11 = b1[1]; + return [[a00 * b00 + a01 * b10, a00 * b01 + a01 * b11], + [a10 * b00 + a11 * b10, a10 * b01 + a11 * b11]]; +}; + +/** + * Multiplies two 2-by-2 matrices; assumes that the given matrices are 2-by-2; + * assumes matrix entries are accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix2} a The matrix on the left. + * @param {!o3djs.math.Matrix2} b The matrix on the right. + * @return {!o3djs.math.Matrix2} The matrix product of a and b. + */ +o3djs.math.columnMajor.mulMatrixMatrix2 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var b0 = b[0]; + var b1 = b[1]; + var a00 = a0[0]; + var a01 = a0[1]; + var a10 = a1[0]; + var a11 = a1[1]; + var b00 = b0[0]; + var b01 = b0[1]; + var b10 = b1[0]; + var b11 = b1[1]; + return [[a00 * b00 + a10 * b01, a01 * b00 + a11 * b01], + [a00 * b10 + a10 * b11, a01 * b10 + a11 * b11]]; +}; + +/** + * Multiplies two 2-by-2 matrices. + * @param {!o3djs.math.Matrix2} a The matrix on the left. + * @param {!o3djs.math.Matrix2} b The matrix on the right. + * @return {!o3djs.math.Matrix2} The matrix product of a and b. + */ +o3djs.math.mulMatrixMatrix2 = null; + + +/** + * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3; + * assumes matrix entries are accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix3} a The matrix on the left. + * @param {!o3djs.math.Matrix3} b The matrix on the right. + * @return {!o3djs.math.Matrix3} The matrix product of a and b. + */ +o3djs.math.rowMajor.mulMatrixMatrix3 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + return [[a00 * b00 + a01 * b10 + a02 * b20, + a00 * b01 + a01 * b11 + a02 * b21, + a00 * b02 + a01 * b12 + a02 * b22], + [a10 * b00 + a11 * b10 + a12 * b20, + a10 * b01 + a11 * b11 + a12 * b21, + a10 * b02 + a11 * b12 + a12 * b22], + [a20 * b00 + a21 * b10 + a22 * b20, + a20 * b01 + a21 * b11 + a22 * b21, + a20 * b02 + a21 * b12 + a22 * b22]]; +}; + +/** + * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3; + * assumes matrix entries are accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix3} a The matrix on the left. + * @param {!o3djs.math.Matrix3} b The matrix on the right. + * @return {!o3djs.math.Matrix3} The matrix product of a and b. + */ +o3djs.math.columnMajor.mulMatrixMatrix3 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + return [[a00 * b00 + a10 * b01 + a20 * b02, + a01 * b00 + a11 * b01 + a21 * b02, + a02 * b00 + a12 * b01 + a22 * b02], + [a00 * b10 + a10 * b11 + a20 * b12, + a01 * b10 + a11 * b11 + a21 * b12, + a02 * b10 + a12 * b11 + a22 * b12], + [a00 * b20 + a10 * b21 + a20 * b22, + a01 * b20 + a11 * b21 + a21 * b22, + a02 * b20 + a12 * b21 + a22 * b22]]; +}; + +/** + * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3. + * @param {!o3djs.math.Matrix3} a The matrix on the left. + * @param {!o3djs.math.Matrix3} b The matrix on the right. + * @return {!o3djs.math.Matrix3} The matrix product of a and b. + */ +o3djs.math.mulMatrixMatrix3 = null; + +/** + * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4; + * assumes matrix entries are accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix4} a The matrix on the left. + * @param {!o3djs.math.Matrix4} b The matrix on the right. + * @return {!o3djs.math.Matrix4} The matrix product of a and b. + */ +o3djs.math.rowMajor.mulMatrixMatrix4 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var a3 = a[3]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a03 = a0[3]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a13 = a1[3]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var a23 = a2[3]; + var a30 = a3[0]; + var a31 = a3[1]; + var a32 = a3[2]; + var a33 = a3[3]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b03 = b0[3]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b13 = b1[3]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + var b23 = b2[3]; + var b30 = b3[0]; + var b31 = b3[1]; + var b32 = b3[2]; + var b33 = b3[3]; + return [[a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30, + a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31, + a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32, + a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33], + [a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30, + a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31, + a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32, + a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33], + [a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30, + a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31, + a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32, + a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33], + [a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30, + a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31, + a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32, + a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33]]; +}; + +/** + * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4; + * assumes matrix entries are accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix4} a The matrix on the left. + * @param {!o3djs.math.Matrix4} b The matrix on the right. + * @return {!o3djs.math.Matrix4} The matrix product of a and b. + */ +o3djs.math.columnMajor.mulMatrixMatrix4 = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var a3 = a[3]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a03 = a0[3]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a13 = a1[3]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var a23 = a2[3]; + var a30 = a3[0]; + var a31 = a3[1]; + var a32 = a3[2]; + var a33 = a3[3]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b03 = b0[3]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b13 = b1[3]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + var b23 = b2[3]; + var b30 = b3[0]; + var b31 = b3[1]; + var b32 = b3[2]; + var b33 = b3[3]; + return [[a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, + a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, + a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, + a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03], + [a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, + a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, + a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, + a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13], + [a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, + a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, + a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, + a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23], + [a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, + a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, + a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, + a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33]]; +}; + +/** + * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4. + * @param {!o3djs.math.Matrix4} a The matrix on the left. + * @param {!o3djs.math.Matrix4} b The matrix on the right. + * @return {!o3djs.math.Matrix4} The matrix product of a and b. + */ +o3djs.math.mulMatrixMatrix4 = null; + +/** + * Multiplies two matrices; assumes that the sizes of the matrices are + * appropriately compatible; assumes matrix entries are accessed in + * [row][column] fashion. + * @param {!o3djs.math.Matrix} a The matrix on the left. + * @param {!o3djs.math.Matrix} b The matrix on the right. + * @return {!o3djs.math.Matrix} The matrix product of a and b. + */ +o3djs.math.rowMajor.mulMatrixMatrix = function(a, b) { + var r = []; + var aRows = a.length; + var bColumns = b[0].length; + var bRows = b.length; + for (var i = 0; i < aRows; ++i) { + var v = []; // v becomes a row of the answer. + var ai = a[i]; // ith row of a. + for (var j = 0; j < bColumns; ++j) { + v[j] = 0.0; + for (var k = 0; k < bRows; ++k) + v[j] += ai[k] * b[k][j]; // kth row, jth column. + } + r[i] = v; + } + return r; +}; + +/** + * Multiplies two matrices; assumes that the sizes of the matrices are + * appropriately compatible; assumes matrix entries are accessed in + * [row][column] fashion. + * @param {!o3djs.math.Matrix} a The matrix on the left. + * @param {!o3djs.math.Matrix} b The matrix on the right. + * @return {!o3djs.math.Matrix} The matrix product of a and b. + */ +o3djs.math.columnMajor.mulMatrixMatrix = function(a, b) { + var r = []; + var bColumns = b.length; + var aRows = a[0].length; + var aColumns = a.length; + for (var i = 0; i < bColumns; ++i) { + var v = []; // v becomes a column of the answer. + var bi = b[i]; // ith column of b. + for (var j = 0; j < aRows; ++j) { + v[j] = 0.0; + for (var k = 0; k < aColumns; ++k) + v[j] += bi[k] * a[k][j]; // kth column, jth row. + } + r[i] = v; + } + return r; +}; + +/** + * Multiplies two matrices; assumes that the sizes of the matrices are + * appropriately compatible. + * @param {!o3djs.math.Matrix} a The matrix on the left. + * @param {!o3djs.math.Matrix} b The matrix on the right. + * @return {!o3djs.math.Matrix} The matrix product of a and b. + */ +o3djs.math.mulMatrixMatrix = null; + +/** + * Gets the jth column of the given matrix m; assumes matrix entries are + * accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} j The index of the desired column. + * @return {!o3djs.math.Vector} The jth column of m as a vector. + */ +o3djs.math.rowMajor.column = function(m, j) { + var r = []; + var mLength = m.length; + for (var i = 0; i < mLength; ++i) { + r[i] = m[i][j]; + } + return r; +}; + +/** + * Gets the jth column of the given matrix m; assumes matrix entries are + * accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} j The index of the desired column. + * @return {!o3djs.math.Vector} The jth column of m as a vector. + */ +o3djs.math.columnMajor.column = function(m, j) { + return m[j].slice(); +}; + +/** + * Gets the jth column of the given matrix m. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} j The index of the desired column. + * @return {!o3djs.math.Vector} The jth column of m as a vector. + */ +o3djs.math.column = null; + +/** + * Gets the ith row of the given matrix m; assumes matrix entries are + * accessed in [row][column] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} i The index of the desired row. + * @return {!o3djs.math.Vector} The ith row of m. + */ +o3djs.math.rowMajor.row = function(m, i) { + return m[i].slice(); +}; + +/** + * Gets the ith row of the given matrix m; assumes matrix entries are + * accessed in [column][row] fashion. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} i The index of the desired row. + * @return {!o3djs.math.Vector} The ith row of m. + */ +o3djs.math.columnMajor.row = function(m, i) { + var r = []; + var mLength = m.length; + for (var j = 0; j < mLength; ++j) { + r[j] = m[j][i]; + } + return r; +}; + +/** + * Gets the ith row of the given matrix m. + * @param {!o3djs.math.Matrix} m The matrix. + * @param {number} i The index of the desired row. + * @return {!o3djs.math.Vector} The ith row of m. + */ +o3djs.math.row = null; + +/** + * Creates an n-by-n identity matrix. + * @param {number} n The dimension of the identity matrix required. + * @return {!o3djs.math.Matrix} An n-by-n identity matrix. + */ +o3djs.math.identity = function(n) { + var r = []; + for (var j = 0; j < n; ++j) { + r[j] = []; + for (var i = 0; i < n; ++i) + r[j][i] = (i == j) ? 1 : 0; + } + return r; +}; + +/** + * Takes the transpose of a matrix. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} The transpose of m. + */ +o3djs.math.transpose = function(m) { + var r = []; + var m0Length = m[0].length; + var mLength = m.length; + for (var j = 0; j < m0Length; ++j) { + r[j] = []; + for (var i = 0; i < mLength; ++i) + r[j][i] = m[i][j]; + } + return r; +}; + +/** + * Computes the trace (sum of the diagonal entries) of a square matrix; + * assumes m is square. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {number} The trace of m. + */ +o3djs.math.trace = function(m) { + var r = 0.0; + var mLength = m.length; + for (var i = 0; i < mLength; ++i) + r += m[i][i]; + return r; +}; + +/** + * Computes the determinant of a 1-by-1 matrix. + * @param {!o3djs.math.Matrix1} m The matrix. + * @return {number} The determinant of m. + */ +o3djs.math.det1 = function(m) { + return m[0][0]; +}; + +/** + * Computes the determinant of a 2-by-2 matrix. + * @param {!o3djs.math.Matrix2} m The matrix. + * @return {number} The determinant of m. + */ +o3djs.math.det2 = function(m) { + return m[0][0] * m[1][1] - m[0][1] * m[1][0]; +}; + +/** + * Computes the determinant of a 3-by-3 matrix. + * @param {!o3djs.math.Matrix3} m The matrix. + * @return {number} The determinant of m. + */ +o3djs.math.det3 = function(m) { + return m[2][2] * (m[0][0] * m[1][1] - m[0][1] * m[1][0]) - + m[2][1] * (m[0][0] * m[1][2] - m[0][2] * m[1][0]) + + m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]); +}; + +/** + * Computes the determinant of a 4-by-4 matrix. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {number} The determinant of m. + */ +o3djs.math.det4 = function(m) { + var t01 = m[0][0] * m[1][1] - m[0][1] * m[1][0]; + var t02 = m[0][0] * m[1][2] - m[0][2] * m[1][0]; + var t03 = m[0][0] * m[1][3] - m[0][3] * m[1][0]; + var t12 = m[0][1] * m[1][2] - m[0][2] * m[1][1]; + var t13 = m[0][1] * m[1][3] - m[0][3] * m[1][1]; + var t23 = m[0][2] * m[1][3] - m[0][3] * m[1][2]; + return m[3][3] * (m[2][2] * t01 - m[2][1] * t02 + m[2][0] * t12) - + m[3][2] * (m[2][3] * t01 - m[2][1] * t03 + m[2][0] * t13) + + m[3][1] * (m[2][3] * t02 - m[2][2] * t03 + m[2][0] * t23) - + m[3][0] * (m[2][3] * t12 - m[2][2] * t13 + m[2][1] * t23); +}; + +/** + * Computes the inverse of a 1-by-1 matrix. + * @param {!o3djs.math.Matrix1} m The matrix. + * @return {!o3djs.math.Matrix1} The inverse of m. + */ +o3djs.math.inverse1 = function(m) { + return [[1.0 / m[0][0]]]; +}; + +/** + * Computes the inverse of a 2-by-2 matrix. + * @param {!o3djs.math.Matrix2} m The matrix. + * @return {!o3djs.math.Matrix2} The inverse of m. + */ +o3djs.math.inverse2 = function(m) { + var d = 1.0 / (m[0][0] * m[1][1] - m[0][1] * m[1][0]); + return [[d * m[1][1], -d * m[0][1]], [-d * m[1][0], d * m[0][0]]]; +}; + +/** + * Computes the inverse of a 3-by-3 matrix. + * @param {!o3djs.math.Matrix3} m The matrix. + * @return {!o3djs.math.Matrix3} The inverse of m. + */ +o3djs.math.inverse3 = function(m) { + var t00 = m[1][1] * m[2][2] - m[1][2] * m[2][1]; + var t10 = m[0][1] * m[2][2] - m[0][2] * m[2][1]; + var t20 = m[0][1] * m[1][2] - m[0][2] * m[1][1]; + var d = 1.0 / (m[0][0] * t00 - m[1][0] * t10 + m[2][0] * t20); + return [[d * t00, -d * t10, d * t20], + [-d * (m[1][0] * m[2][2] - m[1][2] * m[2][0]), + d * (m[0][0] * m[2][2] - m[0][2] * m[2][0]), + -d * (m[0][0] * m[1][2] - m[0][2] * m[1][0])], + [d * (m[1][0] * m[2][1] - m[1][1] * m[2][0]), + -d * (m[0][0] * m[2][1] - m[0][1] * m[2][0]), + d * (m[0][0] * m[1][1] - m[0][1] * m[1][0])]]; +}; + +/** + * Computes the inverse of a 4-by-4 matrix. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {!o3djs.math.Matrix4} The inverse of m. + */ +o3djs.math.inverse4 = function(m) { + var tmp_0 = m[2][2] * m[3][3]; + var tmp_1 = m[3][2] * m[2][3]; + var tmp_2 = m[1][2] * m[3][3]; + var tmp_3 = m[3][2] * m[1][3]; + var tmp_4 = m[1][2] * m[2][3]; + var tmp_5 = m[2][2] * m[1][3]; + var tmp_6 = m[0][2] * m[3][3]; + var tmp_7 = m[3][2] * m[0][3]; + var tmp_8 = m[0][2] * m[2][3]; + var tmp_9 = m[2][2] * m[0][3]; + var tmp_10 = m[0][2] * m[1][3]; + var tmp_11 = m[1][2] * m[0][3]; + var tmp_12 = m[2][0] * m[3][1]; + var tmp_13 = m[3][0] * m[2][1]; + var tmp_14 = m[1][0] * m[3][1]; + var tmp_15 = m[3][0] * m[1][1]; + var tmp_16 = m[1][0] * m[2][1]; + var tmp_17 = m[2][0] * m[1][1]; + var tmp_18 = m[0][0] * m[3][1]; + var tmp_19 = m[3][0] * m[0][1]; + var tmp_20 = m[0][0] * m[2][1]; + var tmp_21 = m[2][0] * m[0][1]; + var tmp_22 = m[0][0] * m[1][1]; + var tmp_23 = m[1][0] * m[0][1]; + + var t0 = (tmp_0 * m[1][1] + tmp_3 * m[2][1] + tmp_4 * m[3][1]) - + (tmp_1 * m[1][1] + tmp_2 * m[2][1] + tmp_5 * m[3][1]); + var t1 = (tmp_1 * m[0][1] + tmp_6 * m[2][1] + tmp_9 * m[3][1]) - + (tmp_0 * m[0][1] + tmp_7 * m[2][1] + tmp_8 * m[3][1]); + var t2 = (tmp_2 * m[0][1] + tmp_7 * m[1][1] + tmp_10 * m[3][1]) - + (tmp_3 * m[0][1] + tmp_6 * m[1][1] + tmp_11 * m[3][1]); + var t3 = (tmp_5 * m[0][1] + tmp_8 * m[1][1] + tmp_11 * m[2][1]) - + (tmp_4 * m[0][1] + tmp_9 * m[1][1] + tmp_10 * m[2][1]); + + var d = 1.0 / (m[0][0] * t0 + m[1][0] * t1 + m[2][0] * t2 + m[3][0] * t3); + + var row0 = [d * t0, d * t1, d * t2, d * t3]; + var row1 = [d * ((tmp_1 * m[1][0] + tmp_2 * m[2][0] + tmp_5 * m[3][0]) - + (tmp_0 * m[1][0] + tmp_3 * m[2][0] + tmp_4 * m[3][0])), + d * ((tmp_0 * m[0][0] + tmp_7 * m[2][0] + tmp_8 * m[3][0]) - + (tmp_1 * m[0][0] + tmp_6 * m[2][0] + tmp_9 * m[3][0])), + d * ((tmp_3 * m[0][0] + tmp_6 * m[1][0] + tmp_11 * m[3][0]) - + (tmp_2 * m[0][0] + tmp_7 * m[1][0] + tmp_10 * m[3][0])), + d * ((tmp_4 * m[0][0] + tmp_9 * m[1][0] + tmp_10 * m[2][0]) - + (tmp_5 * m[0][0] + tmp_8 * m[1][0] + tmp_11 * m[2][0]))]; + var row2 =[d * ((tmp_12 * m[1][3] + tmp_15 * m[2][3] + tmp_16 * m[3][3]) - + (tmp_13 * m[1][3] + tmp_14 * m[2][3] + tmp_17 * m[3][3])), + d * ((tmp_13 * m[0][3] + tmp_18 * m[2][3] + tmp_21 * m[3][3]) - + (tmp_12 * m[0][3] + tmp_19 * m[2][3] + tmp_20 * m[3][3])), + d * ((tmp_14 * m[0][3] + tmp_19 * m[1][3] + tmp_22 * m[3][3]) - + (tmp_15 * m[0][3] + tmp_18 * m[1][3] + tmp_23 * m[3][3])), + d * ((tmp_17 * m[0][3] + tmp_20 * m[1][3] + tmp_23 * m[2][3]) - + (tmp_16 * m[0][3] + tmp_21 * m[1][3] + tmp_22 * m[2][3]))]; + var row3 = [d * ((tmp_14 * m[2][2] + tmp_17 * m[3][2] + tmp_13 * m[1][2]) - + (tmp_16 * m[3][2] + tmp_12 * m[1][2] + tmp_15 * m[2][2])), + d * ((tmp_20 * m[3][2] + tmp_12 * m[0][2] + tmp_19 * m[2][2]) - + (tmp_18 * m[2][2] + tmp_21 * m[3][2] + tmp_13 * m[0][2])), + d * ((tmp_18 * m[1][2] + tmp_23 * m[3][2] + tmp_15 * m[0][2]) - + (tmp_22 * m[3][2] + tmp_14 * m[0][2] + tmp_19 * m[1][2])), + d * ((tmp_22 * m[2][2] + tmp_16 * m[0][2] + tmp_21 * m[1][2]) - + (tmp_20 * m[1][2] + tmp_23 * m[2][2] + tmp_17 * m[0][2]))]; + return [row0, row1, row2, row3]; +}; + +/** + * Computes the determinant of the cofactor matrix obtained by removal + * of a specified row and column. This is a helper function for the general + * determinant and matrix inversion functions. + * @param {!o3djs.math.Matrix} a The original matrix. + * @param {number} x The row to be removed. + * @param {number} y The column to be removed. + * @return {number} The determinant of the matrix obtained by removing + * row x and column y from a. + */ +o3djs.math.codet = function(a, x, y) { + var size = a.length; + var b = []; + var ai = 0; + for (var bi = 0; bi < size - 1; ++bi) { + if (ai == x) + ai++; + b[bi] = []; + var aj = 0; + for (var bj = 0; bj < size - 1; ++bj) { + if (aj == y) + aj++; + b[bi][bj] = a[ai][aj]; + aj++; + } + ai++; + } + return o3djs.math.det(b); +}; + +/** + * Computes the determinant of an arbitrary square matrix. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {number} the determinant of m. + */ +o3djs.math.det = function(m) { + var d = m.length; + if (d <= 4) { + return o3djs.math['det' + d](m); + } + var r = 0.0; + var sign = 1; + var row = m[0]; + var mLength = m.length; + for (var y = 0; y < mLength; y++) { + r += sign * row[y] * o3djs.math.codet(m, 0, y); + sign *= -1; + } + return r; +}; + +/** + * Computes the inverse of an arbitrary square matrix. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} The inverse of m. + */ +o3djs.math.inverse = function(m) { + var d = m.length; + if (d <= 4) { + return o3djs.math['inverse' + d](m); + } + var r = []; + var size = m.length; + for (var j = 0; j < size; ++j) { + r[j] = []; + for (var i = 0; i < size; ++i) + r[j][i] = ((i + j) % 2 ? -1 : 1) * o3djs.math.codet(m, i, j); + } + return o3djs.math.divMatrixScalar(r, o3djs.math.det(m)); +}; + +/** + * Performs Graham-Schmidt orthogonalization on the vectors which make up the + * given matrix and returns the result in the rows of a new matrix. When + * multiplying many orthogonal matrices together, errors can accumulate causing + * the product to fail to be orthogonal. This function can be used to correct + * that. + * @param {!o3djs.math.Matrix} m The matrix. + * @return {!o3djs.math.Matrix} A matrix whose rows are obtained from the + * rows of m by the Graham-Schmidt process. + */ +o3djs.math.orthonormalize = function(m) { + var r = []; + var mLength = m.length; + for (var i = 0; i < mLength; ++i) { + var v = m[i]; + for (var j = 0; j < i; ++j) { + v = o3djs.math.subVector(v, o3djs.math.mulScalarVector( + o3djs.math.dot(r[j], m[i]), r[j])); + } + r[i] = o3djs.math.normalize(v); + } + return r; +}; + +/** + * Computes the inverse of a 4-by-4 matrix. + * Note: It is faster to call this than o3djs.math.inverse. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {!o3djs.math.Matrix4} The inverse of m. + */ +o3djs.math.matrix4.inverse = function(m) { + return o3djs.math.inverse4(m); +}; + +/** + * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4. + * Note: It is faster to call this than o3djs.math.mul. + * @param {!o3djs.math.Matrix4} a The matrix on the left. + * @param {!o3djs.math.Matrix4} b The matrix on the right. + * @return {!o3djs.math.Matrix4} The matrix product of a and b. + */ +o3djs.math.matrix4.mul = function(a, b) { + return o3djs.math.mulMatrixMatrix4(a, b); +}; + +/** + * Computes the determinant of a 4-by-4 matrix. + * Note: It is faster to call this than o3djs.math.det. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {number} The determinant of m. + */ +o3djs.math.matrix4.det = function(m) { + return o3djs.math.det4(m); +}; + +/** + * Copies a Matrix4. + * Note: It is faster to call this than o3djs.math.copy. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {!o3djs.math.Matrix4} A copy of m. + */ +o3djs.math.matrix4.copy = function(m) { + return o3djs.math.copyMatrix(m); +}; + +/** + * Sets the upper 3-by-3 block of matrix a to the upper 3-by-3 block of matrix + * b; assumes that a and b are big enough to contain an upper 3-by-3 block. + * @param {!o3djs.math.Matrix4} a A matrix. + * @param {!o3djs.math.Matrix3} b A 3-by-3 matrix. + * @return {!o3djs.math.Matrix4} a once modified. + */ +o3djs.math.matrix4.setUpper3x3 = function(a, b) { + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + + a[0].splice(0, 3, b0[0], b0[1], b0[2]); + a[1].splice(0, 3, b1[0], b1[1], b1[2]); + a[2].splice(0, 3, b2[0], b2[1], b2[2]); + + return a; +}; + +/** + * Returns a 3-by-3 matrix mimicking the upper 3-by-3 block of m; assumes m + * is big enough to contain an upper 3-by-3 block. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {!o3djs.math.Matrix3} The upper 3-by-3 block of m. + */ +o3djs.math.matrix4.getUpper3x3 = function(m) { + return [m[0].slice(0, 3), m[1].slice(0, 3), m[2].slice(0, 3)]; +}; + +/** + * Sets the translation component of a 4-by-4 matrix to the given + * vector. + * @param {!o3djs.math.Matrix4} a The matrix. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector. + * @return {!o3djs.math.Matrix4} a once modified. + */ +o3djs.math.matrix4.setTranslation = function(a, v) { + a[3].splice(0, 4, v[0], v[1], v[2], 1); + return a; +}; + +/** + * Returns the translation component of a 4-by-4 matrix as a vector with 3 + * entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @return {!o3djs.math.Vector3} The translation component of m. + */ +o3djs.math.matrix4.getTranslation = function(m) { + return m[3].slice(0, 3); +}; + +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, + * interprets the vector as a point, transforms that point by the matrix, and + * returns the result as a vector with 3 entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v The point. + * @return {!o3djs.math.Vector3} The transformed point. + */ +o3djs.math.matrix4.transformPoint = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + var d = v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + m3[3]; + return [(v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + m3[0]) / d, + (v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + m3[1]) / d, + (v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + m3[2]) / d]; +}; + +/** + * Takes a 4-by-4 matrix and a vector with 4 entries, transforms that vector by + * the matrix, and returns the result as a vector with 4 entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector4} v The point in homogenous coordinates. + * @return {!o3djs.math.Vector4} The transformed point in homogenous + * coordinates. + */ +o3djs.math.matrix4.transformVector4 = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var v3 = v[3]; + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + return [v0 * m0[0] + v1 * m1[0] + v2 * m2[0] + v3 * m3[0], + v0 * m0[1] + v1 * m1[1] + v2 * m2[1] + v3 * m3[1], + v0 * m0[2] + v1 * m1[2] + v2 * m2[2] + v3 * m3[2], + v0 * m0[3] + v1 * m1[3] + v2 * m2[3] + v3 * m3[3]]; +}; + +/** + * Takes a 4-by-4 matrix and a vector with 3 entries, interprets the vector as a + * direction, transforms that direction by the matrix, and returns the result; + * assumes the transformation of 3-dimensional space represented by the matrix + * is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v The direction. + * @return {!o3djs.math.Vector3} The transformed direction. + */ +o3djs.math.matrix4.transformDirection = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + return [v0 * m0[0] + v1 * m1[0] + v2 * m2[0], + v0 * m0[1] + v1 * m1[1] + v2 * m2[1], + v0 * m0[2] + v1 * m1[2] + v2 * m2[2]]; +}; + +/** + * Takes a 4-by-4 matrix m and a vector v with 3 entries, interprets the vector + * as a normal to a surface, and computes a vector which is normal upon + * transforming that surface by the matrix. The effect of this function is the + * same as transforming v (as a direction) by the inverse-transpose of m. This + * function assumes the transformation of 3-dimensional space represented by the + * matrix is parallel-preserving, i.e. any combination of rotation, scaling and + * translation, but not a perspective distortion. Returns a vector with 3 + * entries. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v The normal. + * @return {!o3djs.math.Vector3} The transformed normal. + */ +o3djs.math.matrix4.transformNormal = function(m, v) { + var mInverse = o3djs.math.inverse4(m); + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var mi0 = mInverse[0]; + var mi1 = mInverse[1]; + var mi2 = mInverse[2]; + var mi3 = mInverse[3]; + + return [v0 * mi0[0] + v1 * mi0[1] + v2 * mi0[2], + v0 * mi1[0] + v1 * mi1[1] + v2 * mi1[2], + v0 * mi2[0] + v1 * mi2[1] + v2 * mi2[2]]; +}; + +/** + * Creates a 4-by-4 identity matrix. + * @return {!o3djs.math.Matrix4} The 4-by-4 identity. + */ +o3djs.math.matrix4.identity = function() { + return [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Sets the given 4-by-4 matrix to the identity matrix. + * @param {!o3djs.math.Matrix4} m The matrix to set to identity. + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.setIdentity = function(m) { + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + if (i == j) { + m[i][j] = 1; + } else { + m[i][j] = 0; + } + } + } + return m; +}; + +/** + * Computes a 4-by-4 perspective transformation matrix given the angular height + * of the frustum, the aspect ratio, and the near and far clipping planes. The + * arguments define a frustum extending in the negative z direction. The given + * angle is the vertical angle of the frustum, and the horizontal angle is + * determined to produce the given aspect ratio. The arguments near and far are + * the distances to the near and far clipping planes. Note that near and far + * are not z coordinates, but rather they are distances along the negative + * z-axis. The matrix generated sends the viewing frustum to the unit box. + * We assume a unit box extending from -1 to 1 in the x and y dimensions and + * from 0 to 1 in the z dimension. + * @param {number} angle The camera angle from top to bottom (in radians). + * @param {number} aspect The aspect ratio width / height. + * @param {number} near The depth (negative z coordinate) + * of the near clipping plane. + * @param {number} far The depth (negative z coordinate) + * of the far clipping plane. + * @return {!o3djs.math.Matrix4} The perspective matrix. + */ +o3djs.math.matrix4.perspective = function(angle, aspect, near, far) { + var f = Math.tan(0.5 * (Math.PI - angle)); + var range = near - far; + + return [ + [f / aspect, 0, 0, 0], + [0, f, 0, 0], + [0, 0, far / range, -1], + [0, 0, near * far / range, 0] + ]; +}; + +/** + * Computes a 4-by-4 orthographic projection matrix given the coordinates of the + * planes defining the axis-aligned, box-shaped viewing volume. The matrix + * generated sends that box to the unit box. Note that although left and right + * are x coordinates and bottom and top are y coordinates, near and far + * are not z coordinates, but rather they are distances along the negative + * z-axis. We assume a unit box extending from -1 to 1 in the x and y + * dimensions and from 0 to 1 in the z dimension. + * @param {number} left The x coordinate of the left plane of the box. + * @param {number} right The x coordinate of the right plane of the box. + * @param {number} bottom The y coordinate of the bottom plane of the box. + * @param {number} top The y coordinate of the right plane of the box. + * @param {number} near The negative z coordinate of the near plane of the box. + * @param {number} far The negative z coordinate of the far plane of the box. + * @return {!o3djs.math.Matrix4} The orthographic projection matrix. + */ +o3djs.math.matrix4.orthographic = + function(left, right, bottom, top, near, far) { + return [ + [2 / (right - left), 0, 0, 0], + [0, 2 / (top - bottom), 0, 0], + [0, 0, 1 / (near - far), 0], + [(left + right) / (left - right), + (bottom + top) / (bottom - top), + near / (near - far), 1] + ]; +}; + +/** + * Computes a 4-by-4 perspective transformation matrix given the left, right, + * top, bottom, near and far clipping planes. The arguments define a frustum + * extending in the negative z direction. The arguments near and far are the + * distances to the near and far clipping planes. Note that near and far are not + * z coordinates, but rather they are distances along the negative z-axis. The + * matrix generated sends the viewing frustum to the unit box. We assume a unit + * box extending from -1 to 1 in the x and y dimensions and from 0 to 1 in the z + * dimension. + * @param {number} left The x coordinate of the left plane of the box. + * @param {number} right The x coordinate of the right plane of the box. + * @param {number} bottom The y coordinate of the bottom plane of the box. + * @param {number} top The y coordinate of the right plane of the box. + * @param {number} near The negative z coordinate of the near plane of the box. + * @param {number} far The negative z coordinate of the far plane of the box. + * @return {!o3djs.math.Matrix4} The perspective projection matrix. + */ +o3djs.math.matrix4.frustum = function(left, right, bottom, top, near, far) { + var dx = (right - left); + var dy = (top - bottom); + var dz = (near - far); + return [ + [2 * near / dx, 0, 0, 0], + [0, 2 * near / dy, 0, 0], + [(left + right) / dx, (top + bottom) / dy, far / dz, -1], + [0, 0, near * far / dz, 0]]; +}; + +/** + * Computes a 4-by-4 look-at transformation. The transformation generated is + * an orthogonal rotation matrix with translation component. The translation + * component sends the eye to the origin. The rotation component sends the + * vector pointing from the eye to the target to a vector pointing in the + * negative z direction, and also sends the up vector into the upper half of + * the yz plane. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} eye The position + * of the eye. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} target The + * position meant to be viewed. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} up A vector + * pointing up. + * @return {!o3djs.math.Matrix4} The look-at matrix. + */ +o3djs.math.matrix4.lookAt = function(eye, target, up) { + var vz = o3djs.math.normalize( + o3djs.math.subVector(eye, target).slice(0, 3)).concat(0); + var vx = o3djs.math.normalize( + o3djs.math.cross(up, vz)).concat(0); + var vy = o3djs.math.cross(vz, vx).concat(0); + + return o3djs.math.inverse([vx, vy, vz, eye.concat(1)]); +}; + +/** + * Takes two 4-by-4 matrices, a and b, and computes the product in the order + * that pre-composes b with a. In other words, the matrix returned will + * transform by b first and then a. Note this is subtly different from just + * multiplying the matrices together. For given a and b, this function returns + * the same object in both row-major and column-major mode. + * @param {!o3djs.math.Matrix4} a A 4-by-4 matrix. + * @param {!o3djs.math.Matrix4} b A 4-by-4 matrix. + * @return {!o3djs.math.Matrix4} the composition of a and b, b first then a. + */ +o3djs.math.matrix4.composition = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var a3 = a[3]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a03 = a0[3]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a13 = a1[3]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var a23 = a2[3]; + var a30 = a3[0]; + var a31 = a3[1]; + var a32 = a3[2]; + var a33 = a3[3]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b03 = b0[3]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b13 = b1[3]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + var b23 = b2[3]; + var b30 = b3[0]; + var b31 = b3[1]; + var b32 = b3[2]; + var b33 = b3[3]; + return [[a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, + a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, + a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, + a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03], + [a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, + a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, + a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, + a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13], + [a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, + a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, + a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, + a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23], + [a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, + a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, + a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, + a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33]]; +}; + +/** + * Takes two 4-by-4 matrices, a and b, and modifies a to be the product in the + * order that pre-composes b with a. The matrix a, upon modification will + * transform by b first and then a. Note this is subtly different from just + * multiplying the matrices together. For given a and b, a, upon modification, + * will be the same object in both row-major and column-major mode. + * @param {!o3djs.math.Matrix4} a A 4-by-4 matrix. + * @param {!o3djs.math.Matrix4} b A 4-by-4 matrix. + * @return {!o3djs.math.Matrix4} a once modified. + */ +o3djs.math.matrix4.compose = function(a, b) { + var a0 = a[0]; + var a1 = a[1]; + var a2 = a[2]; + var a3 = a[3]; + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + var b3 = b[3]; + var a00 = a0[0]; + var a01 = a0[1]; + var a02 = a0[2]; + var a03 = a0[3]; + var a10 = a1[0]; + var a11 = a1[1]; + var a12 = a1[2]; + var a13 = a1[3]; + var a20 = a2[0]; + var a21 = a2[1]; + var a22 = a2[2]; + var a23 = a2[3]; + var a30 = a3[0]; + var a31 = a3[1]; + var a32 = a3[2]; + var a33 = a3[3]; + var b00 = b0[0]; + var b01 = b0[1]; + var b02 = b0[2]; + var b03 = b0[3]; + var b10 = b1[0]; + var b11 = b1[1]; + var b12 = b1[2]; + var b13 = b1[3]; + var b20 = b2[0]; + var b21 = b2[1]; + var b22 = b2[2]; + var b23 = b2[3]; + var b30 = b3[0]; + var b31 = b3[1]; + var b32 = b3[2]; + var b33 = b3[3]; + a[0].splice(0, 4, a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03, + a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03, + a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03, + a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03); + a[1].splice(0, 4, a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13, + a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13, + a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13, + a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13); + a[2].splice(0, 4, a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23, + a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23, + a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23, + a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23), + a[3].splice(0, 4, a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33, + a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33, + a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33, + a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33); + return a; +}; + +/** + * Creates a 4-by-4 matrix which translates by the given vector v. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector by + * which to translate. + * @return {!o3djs.math.Matrix4} The translation matrix. + */ +o3djs.math.matrix4.translation = function(v) { + return [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [v[0], v[1], v[2], 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix by translation by the given vector v. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} v The vector by + * which to translate. + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.translate = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + var m00 = m0[0]; + var m01 = m0[1]; + var m02 = m0[2]; + var m03 = m0[3]; + var m10 = m1[0]; + var m11 = m1[1]; + var m12 = m1[2]; + var m13 = m1[3]; + var m20 = m2[0]; + var m21 = m2[1]; + var m22 = m2[2]; + var m23 = m2[3]; + var m30 = m3[0]; + var m31 = m3[1]; + var m32 = m3[2]; + var m33 = m3[3]; + + m3.splice(0, 4, m00 * v0 + m10 * v1 + m20 * v2 + m30, + m01 * v0 + m11 * v1 + m21 * v2 + m31, + m02 * v0 + m12 * v1 + m22 * v2 + m32, + m03 * v0 + m13 * v1 + m23 * v2 + m33); + + return m; +}; + +/** + * Creates a 4-by-4 matrix which scales in each dimension by an amount given by + * the corresponding entry in the given vector; assumes the vector has three + * entries. + * @param {!o3djs.math.Vector3} v A vector of + * three entries specifying the factor by which to scale in each dimension. + * @return {!o3djs.math.Matrix4} The scaling matrix. + */ +o3djs.math.matrix4.scaling = function(v) { + return [ + [v[0], 0, 0, 0], + [0, v[1], 0, 0], + [0, 0, v[2], 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix, scaling in each dimension by an amount + * given by the corresponding entry in the given vector; assumes the vector has + * three entries. + * @param {!o3djs.math.Matrix4} m The matrix to be modified. + * @param {!o3djs.math.Vector3} v A vector of three entries specifying the + * factor by which to scale in each dimension. + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.scale = function(m, v) { + var v0 = v[0]; + var v1 = v[1]; + var v2 = v[2]; + + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + m0.splice(0, 4, v0 * m0[0], v0 * m0[1], v0 * m0[2], v0 * m0[3]); + m1.splice(0, 4, v1 * m1[0], v1 * m1[1], v1 * m1[2], v1 * m1[3]); + m2.splice(0, 4, v2 * m2[0], v2 * m2[1], v2 * m2[2], v2 * m2[3]); + + return m; +}; + +/** + * Creates a 4-by-4 matrix which rotates around the x-axis by the given angle. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} The rotation matrix. + */ +o3djs.math.matrix4.rotationX = function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + + return [ + [1, 0, 0, 0], + [0, c, s, 0], + [0, -s, c, 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix by a rotation around the x-axis by the given + * angle. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.rotateX = function(m, angle) { + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + var m10 = m1[0]; + var m11 = m1[1]; + var m12 = m1[2]; + var m13 = m1[3]; + var m20 = m2[0]; + var m21 = m2[1]; + var m22 = m2[2]; + var m23 = m2[3]; + var c = Math.cos(angle); + var s = Math.sin(angle); + + m1.splice(0, 4, c * m10 + s * m20, + c * m11 + s * m21, + c * m12 + s * m22, + c * m13 + s * m23); + m2.splice(0, 4, c * m20 - s * m10, + c * m21 - s * m11, + c * m22 - s * m12, + c * m23 - s * m13); + + return m; +}; + +/** + * Creates a 4-by-4 matrix which rotates around the y-axis by the given angle. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} The rotation matrix. + */ +o3djs.math.matrix4.rotationY = function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + + return [ + [c, 0, -s, 0], + [0, 1, 0, 0], + [s, 0, c, 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix by a rotation around the y-axis by the given + * angle. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.rotateY = function(m, angle) { + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + var m00 = m0[0]; + var m01 = m0[1]; + var m02 = m0[2]; + var m03 = m0[3]; + var m20 = m2[0]; + var m21 = m2[1]; + var m22 = m2[2]; + var m23 = m2[3]; + var c = Math.cos(angle); + var s = Math.sin(angle); + + m0.splice(0, 4, c * m00 - s * m20, + c * m01 - s * m21, + c * m02 - s * m22, + c * m03 - s * m23); + m2.splice(0, 4, c * m20 + s * m00, + c * m21 + s * m01, + c * m22 + s * m02, + c * m23 + s * m03); + + return m; +}; + +/** + * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} The rotation matrix. + */ +o3djs.math.matrix4.rotationZ = function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + + return [ + [c, s, 0, 0], + [-s, c, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix by a rotation around the z-axis by the given + * angle. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.rotateZ = function(m, angle) { + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + var m00 = m0[0]; + var m01 = m0[1]; + var m02 = m0[2]; + var m03 = m0[3]; + var m10 = m1[0]; + var m11 = m1[1]; + var m12 = m1[2]; + var m13 = m1[3]; + var c = Math.cos(angle); + var s = Math.sin(angle); + + m0.splice(0, 4, c * m00 + s * m10, + c * m01 + s * m11, + c * m02 + s * m12, + c * m03 + s * m13); + m1.splice(0, 4, c * m10 - s * m00, + c * m11 - s * m01, + c * m12 - s * m02, + c * m13 - s * m03); + + return m; +}; + +/** + * Creates a 4-by-4 rotation matrix. Interprets the entries of the given + * vector as angles by which to rotate around the x, y and z axes, returns a + * a matrix which rotates around the x-axis first, then the y-axis, then the + * z-axis. + * @param {!o3djs.math.Vector3} v A vector of angles (in radians). + * @return {!o3djs.math.Matrix4} The rotation matrix. + */ +o3djs.math.matrix4.rotationZYX = function(v) { + var sinx = Math.sin(v[0]); + var cosx = Math.cos(v[0]); + var siny = Math.sin(v[1]); + var cosy = Math.cos(v[1]); + var sinz = Math.sin(v[2]); + var cosz = Math.cos(v[2]); + + var coszsiny = cosz * siny; + var sinzsiny = sinz * siny; + + return [ + [cosz * cosy, sinz * cosy, -siny, 0], + [coszsiny * sinx - sinz * cosx, + sinzsiny * sinx + cosz * cosx, + cosy * sinx, + 0], + [coszsiny * cosx + sinz * sinx, + sinzsiny * cosx - cosz * sinx, + cosy * cosx, + 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies a 4-by-4 matrix by a rotation. Interprets the coordinates of the + * given vector as angles by which to rotate around the x, y and z axes, rotates + * around the x-axis first, then the y-axis, then the z-axis. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {!o3djs.math.Vector3} v A vector of angles (in radians). + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.rotateZYX = function(m, v) { + var sinX = Math.sin(v[0]); + var cosX = Math.cos(v[0]); + var sinY = Math.sin(v[1]); + var cosY = Math.cos(v[1]); + var sinZ = Math.sin(v[2]); + var cosZ = Math.cos(v[2]); + + var cosZSinY = cosZ * sinY; + var sinZSinY = sinZ * sinY; + + var r00 = cosZ * cosY; + var r01 = sinZ * cosY; + var r02 = -sinY; + var r10 = cosZSinY * sinX - sinZ * cosX; + var r11 = sinZSinY * sinX + cosZ * cosX; + var r12 = cosY * sinX; + var r20 = cosZSinY * cosX + sinZ * sinX; + var r21 = sinZSinY * cosX - cosZ * sinX; + var r22 = cosY * cosX; + + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + var m00 = m0[0]; + var m01 = m0[1]; + var m02 = m0[2]; + var m03 = m0[3]; + var m10 = m1[0]; + var m11 = m1[1]; + var m12 = m1[2]; + var m13 = m1[3]; + var m20 = m2[0]; + var m21 = m2[1]; + var m22 = m2[2]; + var m23 = m2[3]; + var m30 = m3[0]; + var m31 = m3[1]; + var m32 = m3[2]; + var m33 = m3[3]; + + m0.splice(0, 4, + r00 * m00 + r01 * m10 + r02 * m20, + r00 * m01 + r01 * m11 + r02 * m21, + r00 * m02 + r01 * m12 + r02 * m22, + r00 * m03 + r01 * m13 + r02 * m23); + + m1.splice(0, 4, + r10 * m00 + r11 * m10 + r12 * m20, + r10 * m01 + r11 * m11 + r12 * m21, + r10 * m02 + r11 * m12 + r12 * m22, + r10 * m03 + r11 * m13 + r12 * m23); + + m2.splice(0, 4, + r20 * m00 + r21 * m10 + r22 * m20, + r20 * m01 + r21 * m11 + r22 * m21, + r20 * m02 + r21 * m12 + r22 * m22, + r20 * m03 + r21 * m13 + r22 * m23); + + return m; +}; + +/** + * Creates a 4-by-4 matrix which rotates around the given axis by the given + * angle. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} axis The axis + * about which to rotate. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} A matrix which rotates angle radians + * around the axis. + */ +o3djs.math.matrix4.axisRotation = function(axis, angle) { + var x = axis[0]; + var y = axis[1]; + var z = axis[2]; + var n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + var xx = x * x; + var yy = y * y; + var zz = z * z; + var c = Math.cos(angle); + var s = Math.sin(angle); + var oneMinusCosine = 1 - c; + + return [ + [xx + (1 - xx) * c, + x * y * oneMinusCosine + z * s, + x * z * oneMinusCosine - y * s, + 0], + [x * y * oneMinusCosine - z * s, + yy + (1 - yy) * c, + y * z * oneMinusCosine + x * s, + 0], + [x * z * oneMinusCosine + y * s, + y * z * oneMinusCosine - x * s, + zz + (1 - zz) * c, + 0], + [0, 0, 0, 1] + ]; +}; + +/** + * Modifies the given 4-by-4 matrix by rotation around the given axis by the + * given angle. + * @param {!o3djs.math.Matrix4} m The matrix. + * @param {(!o3djs.math.Vector3|!o3djs.math.Vector4)} axis The axis + * about which to rotate. + * @param {number} angle The angle by which to rotate (in radians). + * @return {!o3djs.math.Matrix4} m once modified. + */ +o3djs.math.matrix4.axisRotate = function(m, axis, angle) { + var x = axis[0]; + var y = axis[1]; + var z = axis[2]; + var n = Math.sqrt(x * x + y * y + z * z); + x /= n; + y /= n; + z /= n; + var xx = x * x; + var yy = y * y; + var zz = z * z; + var c = Math.cos(angle); + var s = Math.sin(angle); + var oneMinusCosine = 1 - c; + + var r00 = xx + (1 - xx) * c; + var r01 = x * y * oneMinusCosine + z * s; + var r02 = x * z * oneMinusCosine - y * s; + var r10 = x * y * oneMinusCosine - z * s; + var r11 = yy + (1 - yy) * c; + var r12 = y * z * oneMinusCosine + x * s; + var r20 = x * z * oneMinusCosine + y * s; + var r21 = y * z * oneMinusCosine - x * s; + var r22 = zz + (1 - zz) * c; + + var m0 = m[0]; + var m1 = m[1]; + var m2 = m[2]; + var m3 = m[3]; + + var m00 = m0[0]; + var m01 = m0[1]; + var m02 = m0[2]; + var m03 = m0[3]; + var m10 = m1[0]; + var m11 = m1[1]; + var m12 = m1[2]; + var m13 = m1[3]; + var m20 = m2[0]; + var m21 = m2[1]; + var m22 = m2[2]; + var m23 = m2[3]; + var m30 = m3[0]; + var m31 = m3[1]; + var m32 = m3[2]; + var m33 = m3[3]; + + m0.splice(0, 4, + r00 * m00 + r01 * m10 + r02 * m20, + r00 * m01 + r01 * m11 + r02 * m21, + r00 * m02 + r01 * m12 + r02 * m22, + r00 * m03 + r01 * m13 + r02 * m23); + + m1.splice(0, 4, + r10 * m00 + r11 * m10 + r12 * m20, + r10 * m01 + r11 * m11 + r12 * m21, + r10 * m02 + r11 * m12 + r12 * m22, + r10 * m03 + r11 * m13 + r12 * m23); + + m2.splice(0, 4, + r20 * m00 + r21 * m10 + r22 * m20, + r20 * m01 + r21 * m11 + r22 * m21, + r20 * m02 + r21 * m12 + r22 * m22, + r20 * m03 + r21 * m13 + r22 * m23); + + return m; +}; + +/** + * Sets each function in the namespace o3djs.math to the row major + * version in o3djs.math.rowMajor (provided such a function exists in + * o3djs.math.rowMajor). Call this function to establish the row major + * convention. + */ +o3djs.math.installRowMajorFunctions = function() { + for (var f in o3djs.math.rowMajor) { + o3djs.math[f] = o3djs.math.rowMajor[f]; + } +}; + +/** + * Sets each function in the namespace o3djs.math to the column major + * version in o3djs.math.columnMajor (provided such a function exists in + * o3djs.math.columnMajor). Call this function to establish the column + * major convention. + */ +o3djs.math.installColumnMajorFunctions = function() { + for (var f in o3djs.math.columnMajor) { + o3djs.math[f] = o3djs.math.columnMajor[f]; + } +}; + +/** + * Sets each function in the namespace o3djs.math to the error checking + * version in o3djs.math.errorCheck (provided such a function exists in + * o3djs.math.errorCheck). + */ +o3djs.math.installErrorCheckFunctions = function() { + for (var f in o3djs.math.errorCheck) { + o3djs.math[f] = o3djs.math.errorCheck[f]; + } +}; + +/** + * Sets each function in the namespace o3djs.math to the error checking free + * version in o3djs.math.errorCheckFree (provided such a function exists in + * o3djs.math.errorCheckFree). + */ +o3djs.math.installErrorCheckFreeFunctions = function() { + for (var f in o3djs.math.errorCheckFree) { + o3djs.math[f] = o3djs.math.errorCheckFree[f]; + } +} + +// By default, install the row-major functions. +o3djs.math.installRowMajorFunctions(); + +// By default, install prechecking. +o3djs.math.installErrorCheckFunctions(); + + +/** + * True if we are using the plugin math library in which matrices are + * represented by 2-dimensional arrays. + * @type {boolean} + * @private + */ +o3djs.math.usePluginMath_ = true; diff --git a/o3d/samples/o3djs/primitives.js b/o3d/samples/o3djs/primitives.js index f736305..34d058d 100644 --- a/o3d/samples/o3djs/primitives.js +++ b/o3d/samples/o3djs/primitives.js @@ -707,7 +707,8 @@ o3djs.primitives.VertexInfo.prototype.addTangentStreams = if (!frame) { frame = [[0, 0, 0], [0, 0, 0]]; } - frame = math.addMatrix(frame, [tangent, binormal]); + math.addVector3To(frame[0], tangent, frame[0]); + math.addVector3To(frame[1], binormal, frame[1]); tangentFrames[key] = frame; } @@ -1054,10 +1055,10 @@ o3djs.primitives.createBox = function(pack, depth, opt_matrix) { var vertexInfo = o3djs.primitives.createCubeVertices(1); - vertexInfo.reorient([[width, 0, 0, 0], - [0, height, 0, 0], - [0, 0, depth, 0], - [0, 0, 0, 1]]); + vertexInfo.reorient(o3djs.math.makeMatrix4(width, 0, 0, 0, + 0, height, 0, 0, + 0, 0, depth, 0, + 0, 0, 0, 1)); if (opt_matrix) { vertexInfo.reorient(opt_matrix); diff --git a/o3d/samples/o3djs/quaternions.js b/o3d/samples/o3djs/quaternions.js index fe9c406..24d9d65 100644 --- a/o3d/samples/o3djs/quaternions.js +++ b/o3d/samples/o3djs/quaternions.js @@ -426,17 +426,17 @@ o3djs.quaternions.quaternionToRotation = function(q) { var d = qWqW + qXqX + qYqY + qZqZ; - return [ - [(qWqW + qXqX - qYqY - qZqZ) / d, + return o3djs.math.makeMatrix4( + (qWqW + qXqX - qYqY - qZqZ) / d, 2 * (qWqZ + qXqY) / d, - 2 * (qXqZ - qWqY) / d, 0], - [2 * (qXqY - qWqZ) / d, + 2 * (qXqZ - qWqY) / d, 0, + 2 * (qXqY - qWqZ) / d, (qWqW - qXqX + qYqY - qZqZ) / d, - 2 * (qWqX + qYqZ) / d, 0], - [2 * (qWqY + qXqZ) / d, + 2 * (qWqX + qYqZ) / d, 0, + 2 * (qWqY + qXqZ) / d, 2 * (qYqZ - qWqX) / d, - (qWqW - qXqX - qYqY + qZqZ) / d, 0], - [0, 0, 0, 1]]; + (qWqW - qXqX - qYqY + qZqZ) / d, 0, + 0, 0, 0, 1); }; /** @@ -453,10 +453,16 @@ o3djs.quaternions.rotationToQuaternion = function(m) { var w; var q = []; - - var m0 = m[0]; - var m1 = m[1]; - var m2 = m[2]; + var m0,m1,m2; + if (m.length==9) { + m0 = [m[0], m[1], m[2]]; + m1 = [m[3], m[4], m[5]]; + m2 = [m[6], m[7], m[8]]; + }else { + m0 = [m[0], m[1], m[2]]; + m1 = [m[4], m[5], m[6]]; + m2 = [m[8], m[9], m[10]]; + } var m00 = m0[0]; var m11 = m1[1]; diff --git a/o3d/samples/o3djs/serialization.js b/o3d/samples/o3djs/serialization.js index c300023..9a5ed29 100644 --- a/o3d/samples/o3djs/serialization.js +++ b/o3d/samples/o3djs/serialization.js @@ -38,6 +38,7 @@ o3djs.provide('o3djs.serialization'); +o3djs.require('o3djs.math'); o3djs.require('o3djs.error'); o3djs.require('o3djs.texture'); @@ -447,7 +448,10 @@ o3djs.serialization.Deserializer.prototype.deserializeValue = function( for (var i = 0; i != valueAsObject.length; ++i) { valueAsObject[i] = this.deserializeValue(valueAsObject[i]); } - return valueAsObject; + if (o3djs.math.usePluginMath_) { + return valueAsObject; + } + return o3djs.serialization.fixMatrices(valueAsObject); } var refId = valueAsObject['ref']; @@ -746,6 +750,50 @@ o3djs.serialization.deserialize = function(pack, json) { }; /** + * This function looks at a given data type, determines if it is an old style + * matrix that is a 2d doubly nested array. If so, it flattens the matrix in + * place so that it may be handled by the code. + * @param {object} parsed a potential array that will be repaired + */ +o3djs.serialization.fixMatrices = function(parsed) { + function isMatrix(m) { + var len = m && m.length; + if (len && len <= 4) { + for (var i = 0; i < len; ++i) { + var mi = m[i]; + var mlen = mi.length; + if (mlen != len) { + return false; + } + for(var j = 0; j < len; ++j) { + if (Number(mi[j]) == NaN){ + return false; + } + } + } + return true; + } else { + return false; + } + } + + function flatten(m) { + var len = m.length; + var retval = new o3djs.math.makeMatrix4(len * len); + for (var i = 0; i < len; ++i) { + for (var j = 0; j < len; ++j) { + retval[i * len + j] = m[i][j]; + } + } + return retval; + } + if (isMatrix(parsed)) { + return flatten(parsed); + } + return parsed; +}; + +/** * Deserializes a single json object named 'scene.json' from a loaded * o3djs.io.ArchiveInfo. * @param {!o3djs.io.ArchiveInfo} archiveInfo Archive to load from. |