diff options
Diffstat (limited to 'o3d/samples/o3d-webgl/transform.js')
-rw-r--r-- | o3d/samples/o3d-webgl/transform.js | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/o3d/samples/o3d-webgl/transform.js b/o3d/samples/o3d-webgl/transform.js new file mode 100644 index 0000000..2ef5d21 --- /dev/null +++ b/o3d/samples/o3d-webgl/transform.js @@ -0,0 +1,942 @@ +/* + * Copyright 2010, 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. + */ + + +/** + * The Transform defines parent child relationship and a localMatrix.. + * A Transform can have one or no parents and + * an arbitrary number of children. + * + * @param {o3d.math.Matrix4} opt_localMatrix The local matrix for this + * transform. + * @param {o3d.math.Matrix4} opt_worldMatrix ParamMatrix4 The world matrix of + * this transform. + * @param {boolean} opt_visible Whether or not this transform and all its + * children are visible. + * @param {o3d.BoundingBox} opt_boundingBox ParamBoundingBox The bounding box + * for this transform and all its children. + * @param {boolean} opt_cull ParamBoolean Whether or not to attempt to + * cull this transform and all its children based on whether or not its + * bounding box is in the view frustum. + * @constructor + */ +o3d.Transform = + function(opt_localMatrix, opt_worldMatrix, opt_visible, opt_boundingBox, + opt_cull) { + this.localMatrix = opt_localMatrix || + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.worldMatrix = opt_worldMatrix || + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + this.visible = opt_visible || true; + this.boundingBox = opt_boundingBox || + new o3d.BoundingBox([-1, -1, -1], [1, 1, 1]); + this.cull = opt_cull || false; + + this.children = []; + this.shapes = []; +}; +o3d.inherit('Transform', 'ParamObject'); + + +/** + * The Visibility for this transform. + * Default = true. + */ +o3d.Transform.prototype.visible = true; + + + +/** + * Sets the parent of the transform by re-parenting the transform under + * parent. Setting parent to null removes the transform and the + * entire subtree below it from the transform graph. + * If the operation would create a cycle it fails. + */ +o3d.Transform.prototype.parent = null; + +o3d.Transform.prototype.__defineSetter__('parent', + function(p) { + this.parent_ = p; + p.addChild(this); + } +); + +o3d.Transform.prototype.__defineGetter__('parent', + function(p) { + return this.parent_; + } +); + + +/** + * The immediate children of this Transform. + * + * Each access to this field gets the entire list, so it is best to get it + * just once. For example: + * + * var children = transform.children; + * for (var i = 0; i < children.length; i++) { + * var child = children[i]; + * } + * + * Note that modifications to this array [e.g. additions to it] will not affect + * the underlying Transform, while modifications to the members of the array + * will affect them. + */ +o3d.Transform.prototype.children = []; + + +/** + * Adds a child transform. + * @param {o3d.Transform} The new child. + */ +o3d.Transform.prototype.addChild = function(child) { + this.children.push(child); +}; + + +/** + * Returns all the transforms under this transform including this one. + * + * Note that modifications to this array [e.g. additions to it] will not affect + * the underlying Transform, while modifications to the members of the array + * will affect them. + * + * An array containing the transforms of the subtree. + */ +o3d.Transform.prototype.getTransformsInTree = + function() { + +}; + + + +/** + * Searches for transforms that match the given name in the hierarchy under and + * including this transform. Since there can be more than one transform with a + * given name, results are returned in an array. + * + * Note that modifications to this array [e.g. additions to it] will not affect + * the underlying Transform, while modifications to the members of the array + * will affect them. + * + * @param {string} name Transform name to look for. + * @returns {Array.<o3d.Transform>} An array containing the transforms of the + * under and including this transform matching the given name. + */ +o3d.Transform.prototype.getTransformsByNameInTree = + function(name) { + +}; + + +/** + * Evaluates and returns the current world matrix. + * + * The updated world matrix. + */ +o3d.Transform.prototype.getUpdatedWorldMatrix = + function() { + +}; + + +/** + * Adds a shape do this transform. + * @param {o3d.Shape} shape Shape to add. + */ +o3d.Transform.prototype.addShape = + function(shape) { + this.shapes.push(shape); +}; + + +/** + * Removes a shape from this transform. + * @param {o3d.Shape} shape Shape to remove. + * @returns {boolean} true if successful, false if shape was not in + * this transform. + */ +o3d.Transform.prototype.removeShape = + function(shape) { + +}; + + +/** + * Gets the shapes owned by this transform. + * + * Each access to this field gets the entire list so it is best to get it + * just once. For example: + * + * var shapes = transform.shapes; + * for (var i = 0; i < shapes.length; i++) { + * var shape = shapes[i]; + * } + * + * + * Note that modifications to this array [e.g. additions to it] will not affect + * the underlying Transform, while modifications to the members of the array + * will affect them. + */ +o3d.Transform.prototype.shapes = []; + + + +/** + * Walks the tree of transforms starting with this transform and creates + * draw elements. If an Element already has a DrawElement that uses material a + * new DrawElement will not be created. + * @param {o3d.Pack} pack Pack used to manage created elements. + * @param {o3d.Material} material Material to use for each element. If you + * pass null, it will use the material on the element to which a draw + * element is being added. In other words, a DrawElement will use the + * material of the corresponding Element if material is null. This allows + * you to easily setup the default (just draw as is) by passing null or + * setup a shadow pass by passing in a shadow material. + */ +o3d.Transform.prototype.createDrawElements = + function(pack, material) { + o3d.notImplemented(); +}; + + +/** + * World (model) matrix as it was last computed. + */ +o3d.Transform.prototype.worldMatrix = []; + + + +/** + * Local transformation matrix. + * Default = Identity. + */ +o3d.Transform.prototype.local_matrix = []; + + + +/** + * The cull setting for this transform. If true this Transform will be culled + * by having its bounding box compared to the view frustum of any draw context + * it is used with. + * Default = false. + */ +o3d.Transform.prototype.cull_ = false; + + + +/** + * The BoundingBox for this Transform. If culling is on this bounding box will + * be tested against the view frustum of any draw context used to with this + * Transform. + */ +o3d.Transform.prototype.boundingBox = null; + + + +/** + * Sets the local matrix of this transform to the identity matrix. + */ +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; + } + } +}; + + +/* + * 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. + * @returns {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 || a; + 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 + * translate by the given vector and then rotated. + */ +o3d.Transform.prototype.translate = + function() { + var v; + if (arguments.length == 3) { + v = arguments; + } else { + v = arguments[0]; + } + var m = this.localMatrix; + + 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation about the + * x-axis. For example, if the local matrix is a tranlsation, the new local + * matrix will rotate around the x-axis and then translate. + * + * @param {number} radians The number of radians to rotate around x-axis. + */ +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 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation about the + * y-axis. For example, if the local matrix is a translation, the new local + * matrix will rotate around the y-axis and then translate. + * + * @param {number} radians The number of radians to rotate around y-axis. + */ +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 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation about the + * z-axis. For example, if the local matrix is a translation, the new local + * matrix will rotate around the z-axis and then translate. + * + * @param {number} radians The number of radians to rotate around z-axis. + */ +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 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation. + * Interprets the three entries 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 {!o3d.math.Vector3} v A vector of angles (in radians) by which + * to rotate around the x, y and z axes. + */ +o3d.Transform.prototype.rotateZYX = + function(v) { + var m = this.localMatrix; + + 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation around the + * given axis. For example, if the local matrix is a translation, the new + * local matrix will rotate around the given axis and then translate. + * + * @param {number} angle The number of radians to rotate. + * @param {!o3d.math.Vector3} axis a non-zero vector representing the axis + * around which to rotate. + */ +o3d.Transform.prototype.axisRotate = + function(axis, angle) { + var m = this.localMatrix; + + 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); +}; + + +/** + * Pre-composes the local matrix of this Transform with a rotation defined by + * the given quaternion. + * + * @param {o3d.math.Quat} q A non-zero quaternion to be interpreted as a + * rotation. + */ +o3d.Transform.prototype.quaternionRotate = + function(q) { + var m = this.localMatrix; + + var qX = q[0]; + var qY = q[1]; + var qZ = q[2]; + var qW = q[3]; + + var qWqW = qW * qW; + var qWqX = qW * qX; + var qWqY = qW * qY; + var qWqZ = qW * qZ; + var qXqW = qX * qW; + var qXqX = qX * qX; + var qXqY = qX * qY; + var qXqZ = qX * qZ; + var qYqW = qY * qW; + var qYqX = qY * qX; + var qYqY = qY * qY; + var qYqZ = qY * qZ; + var qZqW = qZ * qW; + var qZqX = qZ * qX; + var qZqY = qZ * qY; + var qZqZ = qZ * qZ; + + var d = qWqW + qXqX + qYqY + qZqZ; + + o3d.Transform.compose(this.localMatrix, [ + [(qWqW + qXqX - qYqY - qZqZ) / d, + 2 * (qWqZ + qXqY) / 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 * (qYqZ - qWqX) / d, + (qWqW - qXqX - qYqY + qZqZ) / d, 0], + [0, 0, 0, 1]]); +}; + + +/** + * Pre-composes the local matrix of this transform by a scaling transformation. + * For example, if the local matrix is a rotation, the new local matrix will + * scale and then rotate. + */ +o3d.Transform.prototype.scale = + function() { + var v; + if (arguments.length == 3) { + v = arguments; + } else { + v = arguments[0]; + } + + var m = this.localMatrix; + + 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]); +}; + + +/** + * 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. + * @returns {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]]; +}; + + +/** + * Traverses the transform tree starting at this node and adds DrawElements + * for each shape to DrawList. + * @param {Array.<Object>} drawListInfos A list of objects containing a draw + * list and matrix information. + * @param {o3d.math.Matrix4} opt_parentWorldMatrix + */ +o3d.Transform.prototype.traverse = + function(drawListInfos, opt_parentWorldMatrix) { + opt_parentWorldMatrix = + opt_parentWorldMatrix || + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + + o3d.Transform.compose( + opt_parentWorldMatrix, this.localMatrix, this.worldMatrix); + + var children = this.children; + var shapes = this.shapes; + + for (var i = 0; i < shapes.length; ++i) { + shapes[i].writeToDrawLists(drawListInfos, this.worldMatrix, this); + } + + for (var i = 0; i < children.length; ++i) { + children[i].traverse(drawListInfos, this.worldMatrix); + } +}; + + |