UNPKG

@xeokit/xeokit-convert-xkt10

Version:

JavaScript utilities to create .XKT files

1,949 lines (1,759 loc) 1.11 MB
/** * @desc Provides info on the XKT generated by xeokit-convert. */ const XKT_INFO = { /** * The XKT version generated by xeokit-convert. * * This is the XKT version that's modeled by {@link XKTModel}, serialized * by {@link writeXKTModelToArrayBuffer}, and written by {@link convert2xkt}. * * * Current XKT version: **9** * * [XKT format specs](https://github.com/xeokit/xeokit-convert/blob/main/specs/index.md) * * @property xktVersion * @type {number} */ xktVersion: 10 }; // Some temporary vars to help avoid garbage collection const FloatArrayType = Float64Array ; const tempMat1 = new FloatArrayType(16); const tempMat2 = new FloatArrayType(16); const tempVec4 = new FloatArrayType(4); /** * @private */ const math = { MIN_DOUBLE: -Number.MAX_SAFE_INTEGER, MAX_DOUBLE: Number.MAX_SAFE_INTEGER, /** * The number of radiians in a degree (0.0174532925). * @property DEGTORAD * @type {Number} */ DEGTORAD: 0.0174532925, /** * The number of degrees in a radian. * @property RADTODEG * @type {Number} */ RADTODEG: 57.295779513, /** * Returns a new, uninitialized two-element vector. * @method vec2 * @param [values] Initial values. * @static * @returns {Number[]} */ vec2(values) { return new FloatArrayType(values || 2); }, /** * Returns a new, uninitialized three-element vector. * @method vec3 * @param [values] Initial values. * @static * @returns {Number[]} */ vec3(values) { return new FloatArrayType(values || 3); }, /** * Returns a new, uninitialized four-element vector. * @method vec4 * @param [values] Initial values. * @static * @returns {Number[]} */ vec4(values) { return new FloatArrayType(values || 4); }, /** * Returns a new, uninitialized 3x3 matrix. * @method mat3 * @param [values] Initial values. * @static * @returns {Number[]} */ mat3(values) { return new FloatArrayType(values || 9); }, /** * Converts a 3x3 matrix to 4x4 * @method mat3ToMat4 * @param mat3 3x3 matrix. * @param mat4 4x4 matrix * @static * @returns {Number[]} */ mat3ToMat4(mat3, mat4 = new FloatArrayType(16)) { mat4[0] = mat3[0]; mat4[1] = mat3[1]; mat4[2] = mat3[2]; mat4[3] = 0; mat4[4] = mat3[3]; mat4[5] = mat3[4]; mat4[6] = mat3[5]; mat4[7] = 0; mat4[8] = mat3[6]; mat4[9] = mat3[7]; mat4[10] = mat3[8]; mat4[11] = 0; mat4[12] = 0; mat4[13] = 0; mat4[14] = 0; mat4[15] = 1; return mat4; }, /** * Returns a new, uninitialized 4x4 matrix. * @method mat4 * @param [values] Initial values. * @static * @returns {Number[]} */ mat4(values) { return new FloatArrayType(values || 16); }, /** * Converts a 4x4 matrix to 3x3 * @method mat4ToMat3 * @param mat4 4x4 matrix. * @param mat3 3x3 matrix * @static * @returns {Number[]} */ mat4ToMat3(mat4, mat3) { // TODO //return new FloatArrayType(values || 9); }, /** * Returns a new UUID. * @method createUUID * @static * @return string The new UUID */ createUUID: ((() => { const lut = []; for (let i = 0; i < 256; i++) { lut[i] = (i < 16 ? '0' : '') + (i).toString(16); } return () => { const d0 = Math.random() * 0xffffffff | 0; const d1 = Math.random() * 0xffffffff | 0; const d2 = Math.random() * 0xffffffff | 0; const d3 = Math.random() * 0xffffffff | 0; return `${lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff]}-${lut[d1 & 0xff]}${lut[d1 >> 8 & 0xff]}-${lut[d1 >> 16 & 0x0f | 0x40]}${lut[d1 >> 24 & 0xff]}-${lut[d2 & 0x3f | 0x80]}${lut[d2 >> 8 & 0xff]}-${lut[d2 >> 16 & 0xff]}${lut[d2 >> 24 & 0xff]}${lut[d3 & 0xff]}${lut[d3 >> 8 & 0xff]}${lut[d3 >> 16 & 0xff]}${lut[d3 >> 24 & 0xff]}`; }; }))(), /** * Clamps a value to the given range. * @param {Number} value Value to clamp. * @param {Number} min Lower bound. * @param {Number} max Upper bound. * @returns {Number} Clamped result. */ clamp(value, min, max) { return Math.max(min, Math.min(max, value)); }, /** * Floating-point modulus * @method fmod * @static * @param {Number} a * @param {Number} b * @returns {*} */ fmod(a, b) { if (a < b) { console.error("math.fmod : Attempting to find modulus within negative range - would be infinite loop - ignoring"); return a; } while (b <= a) { a -= b; } return a; }, /** * Negates a four-element vector. * @method negateVec4 * @static * @param {Array(Number)} v Vector to negate * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ negateVec4(v, dest) { if (!dest) { dest = v; } dest[0] = -v[0]; dest[1] = -v[1]; dest[2] = -v[2]; dest[3] = -v[3]; return dest; }, /** * Adds one four-element vector to another. * @method addVec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ addVec4(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] + v[0]; dest[1] = u[1] + v[1]; dest[2] = u[2] + v[2]; dest[3] = u[3] + v[3]; return dest; }, /** * Adds a scalar value to each element of a four-element vector. * @method addVec4Scalar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ addVec4Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; dest[3] = v[3] + s; return dest; }, /** * Adds one three-element vector to another. * @method addVec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ addVec3(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] + v[0]; dest[1] = u[1] + v[1]; dest[2] = u[2] + v[2]; return dest; }, /** * Adds a scalar value to each element of a three-element vector. * @method addVec4Scalar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ addVec3Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; return dest; }, /** * Subtracts one four-element vector from another. * @method subVec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Vector to subtract * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ subVec4(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] - v[0]; dest[1] = u[1] - v[1]; dest[2] = u[2] - v[2]; dest[3] = u[3] - v[3]; return dest; }, /** * Subtracts one three-element vector from another. * @method subVec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Vector to subtract * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ subVec3(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] - v[0]; dest[1] = u[1] - v[1]; dest[2] = u[2] - v[2]; return dest; }, /** * Subtracts one two-element vector from another. * @method subVec2 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Vector to subtract * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ subVec2(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] - v[0]; dest[1] = u[1] - v[1]; return dest; }, /** * Subtracts a scalar value from each element of a four-element vector. * @method subVec4Scalar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ subVec4Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] - s; dest[1] = v[1] - s; dest[2] = v[2] - s; dest[3] = v[3] - s; return dest; }, /** * Sets each element of a 4-element vector to a scalar value minus the value of that element. * @method subScalarVec4 * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ subScalarVec4(v, s, dest) { if (!dest) { dest = v; } dest[0] = s - v[0]; dest[1] = s - v[1]; dest[2] = s - v[2]; dest[3] = s - v[3]; return dest; }, /** * Multiplies one three-element vector by another. * @method mulVec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ mulVec4(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] * v[0]; dest[1] = u[1] * v[1]; dest[2] = u[2] * v[2]; dest[3] = u[3] * v[3]; return dest; }, /** * Multiplies each element of a four-element vector by a scalar. * @method mulVec34calar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ mulVec4Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; dest[3] = v[3] * s; return dest; }, /** * Multiplies each element of a three-element vector by a scalar. * @method mulVec3Scalar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ mulVec3Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; return dest; }, /** * Multiplies each element of a two-element vector by a scalar. * @method mulVec2Scalar * @static * @param {Array(Number)} v The vector * @param {Number} s The scalar * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, v otherwise */ mulVec2Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] * s; dest[1] = v[1] * s; return dest; }, /** * Divides one three-element vector by another. * @method divVec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ divVec3(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] / v[0]; dest[1] = u[1] / v[1]; dest[2] = u[2] / v[2]; return dest; }, /** * Divides one four-element vector by another. * @method divVec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @param {Array(Number)} [dest] Destination vector * @return {Array(Number)} dest if specified, u otherwise */ divVec4(u, v, dest) { if (!dest) { dest = u; } dest[0] = u[0] / v[0]; dest[1] = u[1] / v[1]; dest[2] = u[2] / v[2]; dest[3] = u[3] / v[3]; return dest; }, /** * Divides a scalar by a three-element vector, returning a new vector. * @method divScalarVec3 * @static * @param v vec3 * @param s scalar * @param dest vec3 - optional destination * @return [] dest if specified, v otherwise */ divScalarVec3(s, v, dest) { if (!dest) { dest = v; } dest[0] = s / v[0]; dest[1] = s / v[1]; dest[2] = s / v[2]; return dest; }, /** * Divides a three-element vector by a scalar. * @method divVec3Scalar * @static * @param v vec3 * @param s scalar * @param dest vec3 - optional destination * @return [] dest if specified, v otherwise */ divVec3Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] / s; dest[1] = v[1] / s; dest[2] = v[2] / s; return dest; }, /** * Divides a four-element vector by a scalar. * @method divVec4Scalar * @static * @param v vec4 * @param s scalar * @param dest vec4 - optional destination * @return [] dest if specified, v otherwise */ divVec4Scalar(v, s, dest) { if (!dest) { dest = v; } dest[0] = v[0] / s; dest[1] = v[1] / s; dest[2] = v[2] / s; dest[3] = v[3] / s; return dest; }, /** * Divides a scalar by a four-element vector, returning a new vector. * @method divScalarVec4 * @static * @param s scalar * @param v vec4 * @param dest vec4 - optional destination * @return [] dest if specified, v otherwise */ divScalarVec4(s, v, dest) { if (!dest) { dest = v; } dest[0] = s / v[0]; dest[1] = s / v[1]; dest[2] = s / v[2]; dest[3] = s / v[3]; return dest; }, /** * Returns the dot product of two four-element vectors. * @method dotVec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @return The dot product */ dotVec4(u, v) { return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]); }, /** * Returns the cross product of two four-element vectors. * @method cross3Vec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @return The cross product */ cross3Vec4(u, v) { const u0 = u[0]; const u1 = u[1]; const u2 = u[2]; const v0 = v[0]; const v1 = v[1]; const v2 = v[2]; return [ u1 * v2 - u2 * v1, u2 * v0 - u0 * v2, u0 * v1 - u1 * v0, 0.0]; }, /** * Returns the cross product of two three-element vectors. * @method cross3Vec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @return The cross product */ cross3Vec3(u, v, dest) { if (!dest) { dest = u; } const x = u[0]; const y = u[1]; const z = u[2]; const x2 = v[0]; const y2 = v[1]; const z2 = v[2]; dest[0] = y * z2 - z * y2; dest[1] = z * x2 - x * z2; dest[2] = x * y2 - y * x2; return dest; }, sqLenVec4(v) { // TODO return math.dotVec4(v, v); }, /** * Returns the length of a four-element vector. * @method lenVec4 * @static * @param {Array(Number)} v The vector * @return The length */ lenVec4(v) { return Math.sqrt(math.sqLenVec4(v)); }, /** * Returns the dot product of two three-element vectors. * @method dotVec3 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @return The dot product */ dotVec3(u, v) { return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]); }, /** * Returns the dot product of two two-element vectors. * @method dotVec4 * @static * @param {Array(Number)} u First vector * @param {Array(Number)} v Second vector * @return The dot product */ dotVec2(u, v) { return (u[0] * v[0] + u[1] * v[1]); }, sqLenVec3(v) { return math.dotVec3(v, v); }, sqLenVec2(v) { return math.dotVec2(v, v); }, /** * Returns the length of a three-element vector. * @method lenVec3 * @static * @param {Array(Number)} v The vector * @return The length */ lenVec3(v) { return Math.sqrt(math.sqLenVec3(v)); }, distVec3: ((() => { const vec = new FloatArrayType(3); return (v, w) => math.lenVec3(math.subVec3(v, w, vec)); }))(), /** * Returns the length of a two-element vector. * @method lenVec2 * @static * @param {Array(Number)} v The vector * @return The length */ lenVec2(v) { return Math.sqrt(math.sqLenVec2(v)); }, distVec2: ((() => { const vec = new FloatArrayType(2); return (v, w) => math.lenVec2(math.subVec2(v, w, vec)); }))(), /** * @method rcpVec3 * @static * @param v vec3 * @param dest vec3 - optional destination * @return [] dest if specified, v otherwise * */ rcpVec3(v, dest) { return math.divScalarVec3(1.0, v, dest); }, /** * Normalizes a four-element vector * @method normalizeVec4 * @static * @param v vec4 * @param dest vec4 - optional destination * @return [] dest if specified, v otherwise * */ normalizeVec4(v, dest) { const f = 1.0 / math.lenVec4(v); return math.mulVec4Scalar(v, f, dest); }, /** * Normalizes a three-element vector * @method normalizeVec4 * @static */ normalizeVec3(v, dest) { const f = 1.0 / math.lenVec3(v); return math.mulVec3Scalar(v, f, dest); }, /** * Normalizes a two-element vector * @method normalizeVec2 * @static */ normalizeVec2(v, dest) { const f = 1.0 / math.lenVec2(v); return math.mulVec2Scalar(v, f, dest); }, /** * Gets the angle between two vectors * @method angleVec3 * @param v * @param w * @returns {number} */ angleVec3(v, w) { let theta = math.dotVec3(v, w) / (Math.sqrt(math.sqLenVec3(v) * math.sqLenVec3(w))); theta = theta < -1 ? -1 : (theta > 1 ? 1 : theta); // Clamp to handle numerical problems return Math.acos(theta); }, /** * Creates a three-element vector from the rotation part of a sixteen-element matrix. * @param m * @param dest */ vec3FromMat4Scale: ((() => { const tempVec3 = new FloatArrayType(3); return (m, dest) => { tempVec3[0] = m[0]; tempVec3[1] = m[1]; tempVec3[2] = m[2]; dest[0] = math.lenVec3(tempVec3); tempVec3[0] = m[4]; tempVec3[1] = m[5]; tempVec3[2] = m[6]; dest[1] = math.lenVec3(tempVec3); tempVec3[0] = m[8]; tempVec3[1] = m[9]; tempVec3[2] = m[10]; dest[2] = math.lenVec3(tempVec3); return dest; }; }))(), /** * Converts an n-element vector to a JSON-serializable * array with values rounded to two decimal places. */ vecToArray: ((() => { function trunc(v) { return Math.round(v * 100000) / 100000 } return v => { v = Array.prototype.slice.call(v); for (let i = 0, len = v.length; i < len; i++) { v[i] = trunc(v[i]); } return v; }; }))(), /** * Converts a 3-element vector from an array to an object of the form ````{x:999, y:999, z:999}````. * @param arr * @returns {{x: *, y: *, z: *}} */ xyzArrayToObject(arr) { return {"x": arr[0], "y": arr[1], "z": arr[2]}; }, /** * Converts a 3-element vector object of the form ````{x:999, y:999, z:999}```` to an array. * @param xyz * @param [arry] * @returns {*[]} */ xyzObjectToArray(xyz, arry) { arry = arry || new FloatArrayType(3); arry[0] = xyz.x; arry[1] = xyz.y; arry[2] = xyz.z; return arry; }, /** * Duplicates a 4x4 identity matrix. * @method dupMat4 * @static */ dupMat4(m) { return m.slice(0, 16); }, /** * Extracts a 3x3 matrix from a 4x4 matrix. * @method mat4To3 * @static */ mat4To3(m) { return [ m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10] ]; }, /** * Returns a 4x4 matrix with each element set to the given scalar value. * @method m4s * @static */ m4s(s) { return [ s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s ]; }, /** * Returns a 4x4 matrix with each element set to zero. * @method setMat4ToZeroes * @static */ setMat4ToZeroes() { return math.m4s(0.0); }, /** * Returns a 4x4 matrix with each element set to 1.0. * @method setMat4ToOnes * @static */ setMat4ToOnes() { return math.m4s(1.0); }, /** * Returns a 4x4 matrix with each element set to 1.0. * @method setMat4ToOnes * @static */ diagonalMat4v(v) { return new FloatArrayType([ v[0], 0.0, 0.0, 0.0, 0.0, v[1], 0.0, 0.0, 0.0, 0.0, v[2], 0.0, 0.0, 0.0, 0.0, v[3] ]); }, /** * Returns a 4x4 matrix with diagonal elements set to the given vector. * @method diagonalMat4c * @static */ diagonalMat4c(x, y, z, w) { return math.diagonalMat4v([x, y, z, w]); }, /** * Returns a 4x4 matrix with diagonal elements set to the given scalar. * @method diagonalMat4s * @static */ diagonalMat4s(s) { return math.diagonalMat4c(s, s, s, s); }, /** * Returns a 4x4 identity matrix. * @method identityMat4 * @static */ identityMat4(mat = new FloatArrayType(16)) { mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = 0.0; mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = 0.0; mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; return mat; }, /** * Returns a 3x3 identity matrix. * @method identityMat3 * @static */ identityMat3(mat = new FloatArrayType(9)) { mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; mat[4] = 1.0; mat[5] = 0.0; mat[6] = 0.0; mat[7] = 0.0; mat[8] = 1.0; return mat; }, /** * Tests if the given 4x4 matrix is the identity matrix. * @method isIdentityMat4 * @static */ isIdentityMat4(m) { if (m[0] !== 1.0 || m[1] !== 0.0 || m[2] !== 0.0 || m[3] !== 0.0 || m[4] !== 0.0 || m[5] !== 1.0 || m[6] !== 0.0 || m[7] !== 0.0 || m[8] !== 0.0 || m[9] !== 0.0 || m[10] !== 1.0 || m[11] !== 0.0 || m[12] !== 0.0 || m[13] !== 0.0 || m[14] !== 0.0 || m[15] !== 1.0) { return false; } return true; }, /** * Negates the given 4x4 matrix. * @method negateMat4 * @static */ negateMat4(m, dest) { if (!dest) { dest = m; } dest[0] = -m[0]; dest[1] = -m[1]; dest[2] = -m[2]; dest[3] = -m[3]; dest[4] = -m[4]; dest[5] = -m[5]; dest[6] = -m[6]; dest[7] = -m[7]; dest[8] = -m[8]; dest[9] = -m[9]; dest[10] = -m[10]; dest[11] = -m[11]; dest[12] = -m[12]; dest[13] = -m[13]; dest[14] = -m[14]; dest[15] = -m[15]; return dest; }, /** * Adds the given 4x4 matrices together. * @method addMat4 * @static */ addMat4(a, b, dest) { if (!dest) { dest = a; } dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; dest[3] = a[3] + b[3]; dest[4] = a[4] + b[4]; dest[5] = a[5] + b[5]; dest[6] = a[6] + b[6]; dest[7] = a[7] + b[7]; dest[8] = a[8] + b[8]; dest[9] = a[9] + b[9]; dest[10] = a[10] + b[10]; dest[11] = a[11] + b[11]; dest[12] = a[12] + b[12]; dest[13] = a[13] + b[13]; dest[14] = a[14] + b[14]; dest[15] = a[15] + b[15]; return dest; }, /** * Adds the given scalar to each element of the given 4x4 matrix. * @method addMat4Scalar * @static */ addMat4Scalar(m, s, dest) { if (!dest) { dest = m; } dest[0] = m[0] + s; dest[1] = m[1] + s; dest[2] = m[2] + s; dest[3] = m[3] + s; dest[4] = m[4] + s; dest[5] = m[5] + s; dest[6] = m[6] + s; dest[7] = m[7] + s; dest[8] = m[8] + s; dest[9] = m[9] + s; dest[10] = m[10] + s; dest[11] = m[11] + s; dest[12] = m[12] + s; dest[13] = m[13] + s; dest[14] = m[14] + s; dest[15] = m[15] + s; return dest; }, /** * Adds the given scalar to each element of the given 4x4 matrix. * @method addScalarMat4 * @static */ addScalarMat4(s, m, dest) { return math.addMat4Scalar(m, s, dest); }, /** * Subtracts the second 4x4 matrix from the first. * @method subMat4 * @static */ subMat4(a, b, dest) { if (!dest) { dest = a; } dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; dest[3] = a[3] - b[3]; dest[4] = a[4] - b[4]; dest[5] = a[5] - b[5]; dest[6] = a[6] - b[6]; dest[7] = a[7] - b[7]; dest[8] = a[8] - b[8]; dest[9] = a[9] - b[9]; dest[10] = a[10] - b[10]; dest[11] = a[11] - b[11]; dest[12] = a[12] - b[12]; dest[13] = a[13] - b[13]; dest[14] = a[14] - b[14]; dest[15] = a[15] - b[15]; return dest; }, /** * Subtracts the given scalar from each element of the given 4x4 matrix. * @method subMat4Scalar * @static */ subMat4Scalar(m, s, dest) { if (!dest) { dest = m; } dest[0] = m[0] - s; dest[1] = m[1] - s; dest[2] = m[2] - s; dest[3] = m[3] - s; dest[4] = m[4] - s; dest[5] = m[5] - s; dest[6] = m[6] - s; dest[7] = m[7] - s; dest[8] = m[8] - s; dest[9] = m[9] - s; dest[10] = m[10] - s; dest[11] = m[11] - s; dest[12] = m[12] - s; dest[13] = m[13] - s; dest[14] = m[14] - s; dest[15] = m[15] - s; return dest; }, /** * Subtracts the given scalar from each element of the given 4x4 matrix. * @method subScalarMat4 * @static */ subScalarMat4(s, m, dest) { if (!dest) { dest = m; } dest[0] = s - m[0]; dest[1] = s - m[1]; dest[2] = s - m[2]; dest[3] = s - m[3]; dest[4] = s - m[4]; dest[5] = s - m[5]; dest[6] = s - m[6]; dest[7] = s - m[7]; dest[8] = s - m[8]; dest[9] = s - m[9]; dest[10] = s - m[10]; dest[11] = s - m[11]; dest[12] = s - m[12]; dest[13] = s - m[13]; dest[14] = s - m[14]; dest[15] = s - m[15]; return dest; }, /** * Multiplies the two given 4x4 matrix by each other. * @method mulMat4 * @static */ mulMat4(a, b, dest) { if (!dest) { dest = a; } // Cache the matrix values (makes for huge speed increases!) const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; const b00 = b[0]; const b01 = b[1]; const b02 = b[2]; const b03 = b[3]; const b10 = b[4]; const b11 = b[5]; const b12 = b[6]; const b13 = b[7]; const b20 = b[8]; const b21 = b[9]; const b22 = b[10]; const b23 = b[11]; const b30 = b[12]; const b31 = b[13]; const b32 = b[14]; const b33 = b[15]; dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; return dest; }, /** * Multiplies the two given 3x3 matrices by each other. * @method mulMat4 * @static */ mulMat3(a, b, dest) { if (!dest) { dest = new FloatArrayType(9); } const a11 = a[0]; const a12 = a[3]; const a13 = a[6]; const a21 = a[1]; const a22 = a[4]; const a23 = a[7]; const a31 = a[2]; const a32 = a[5]; const a33 = a[8]; const b11 = b[0]; const b12 = b[3]; const b13 = b[6]; const b21 = b[1]; const b22 = b[4]; const b23 = b[7]; const b31 = b[2]; const b32 = b[5]; const b33 = b[8]; dest[0] = a11 * b11 + a12 * b21 + a13 * b31; dest[3] = a11 * b12 + a12 * b22 + a13 * b32; dest[6] = a11 * b13 + a12 * b23 + a13 * b33; dest[1] = a21 * b11 + a22 * b21 + a23 * b31; dest[4] = a21 * b12 + a22 * b22 + a23 * b32; dest[7] = a21 * b13 + a22 * b23 + a23 * b33; dest[2] = a31 * b11 + a32 * b21 + a33 * b31; dest[5] = a31 * b12 + a32 * b22 + a33 * b32; dest[8] = a31 * b13 + a32 * b23 + a33 * b33; return dest; }, /** * Multiplies each element of the given 4x4 matrix by the given scalar. * @method mulMat4Scalar * @static */ mulMat4Scalar(m, s, dest) { if (!dest) { dest = m; } dest[0] = m[0] * s; dest[1] = m[1] * s; dest[2] = m[2] * s; dest[3] = m[3] * s; dest[4] = m[4] * s; dest[5] = m[5] * s; dest[6] = m[6] * s; dest[7] = m[7] * s; dest[8] = m[8] * s; dest[9] = m[9] * s; dest[10] = m[10] * s; dest[11] = m[11] * s; dest[12] = m[12] * s; dest[13] = m[13] * s; dest[14] = m[14] * s; dest[15] = m[15] * s; return dest; }, /** * Multiplies the given 4x4 matrix by the given four-element vector. * @method mulMat4v4 * @static */ mulMat4v4(m, v, dest = math.vec4()) { const v0 = v[0]; const v1 = v[1]; const v2 = v[2]; const v3 = v[3]; dest[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3; dest[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3; dest[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3; dest[3] = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3; return dest; }, /** * Transposes the given 4x4 matrix. * @method transposeMat4 * @static */ transposeMat4(mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values const m4 = mat[4]; const m14 = mat[14]; const m8 = mat[8]; const m13 = mat[13]; const m12 = mat[12]; const m9 = mat[9]; if (!dest || mat === dest) { const a01 = mat[1]; const a02 = mat[2]; const a03 = mat[3]; const a12 = mat[6]; const a13 = mat[7]; const a23 = mat[11]; mat[1] = m4; mat[2] = m8; mat[3] = m12; mat[4] = a01; mat[6] = m9; mat[7] = m13; mat[8] = a02; mat[9] = a12; mat[11] = m14; mat[12] = a03; mat[13] = a13; mat[14] = a23; return mat; } dest[0] = mat[0]; dest[1] = m4; dest[2] = m8; dest[3] = m12; dest[4] = mat[1]; dest[5] = mat[5]; dest[6] = m9; dest[7] = m13; dest[8] = mat[2]; dest[9] = mat[6]; dest[10] = mat[10]; dest[11] = m14; dest[12] = mat[3]; dest[13] = mat[7]; dest[14] = mat[11]; dest[15] = mat[15]; return dest; }, /** * Transposes the given 3x3 matrix. * * @method transposeMat3 * @static */ transposeMat3(mat, dest) { if (dest === mat) { const a01 = mat[1]; const a02 = mat[2]; const a12 = mat[5]; dest[1] = mat[3]; dest[2] = mat[6]; dest[3] = a01; dest[5] = mat[7]; dest[6] = a02; dest[7] = a12; } else { dest[0] = mat[0]; dest[1] = mat[3]; dest[2] = mat[6]; dest[3] = mat[1]; dest[4] = mat[4]; dest[5] = mat[7]; dest[6] = mat[2]; dest[7] = mat[5]; dest[8] = mat[8]; } return dest; }, /** * Returns the determinant of the given 4x4 matrix. * @method determinantMat4 * @static */ determinantMat4(mat) { // Cache the matrix values (makes for huge speed increases!) const a00 = mat[0]; const a01 = mat[1]; const a02 = mat[2]; const a03 = mat[3]; const a10 = mat[4]; const a11 = mat[5]; const a12 = mat[6]; const a13 = mat[7]; const a20 = mat[8]; const a21 = mat[9]; const a22 = mat[10]; const a23 = mat[11]; const a30 = mat[12]; const a31 = mat[13]; const a32 = mat[14]; const a33 = mat[15]; return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33; }, /** * Returns the inverse of the given 4x4 matrix. * @method inverseMat4 * @static */ inverseMat4(mat, dest) { if (!dest) { dest = mat; } // Cache the matrix values (makes for huge speed increases!) const a00 = mat[0]; const a01 = mat[1]; const a02 = mat[2]; const a03 = mat[3]; const a10 = mat[4]; const a11 = mat[5]; const a12 = mat[6]; const a13 = mat[7]; const a20 = mat[8]; const a21 = mat[9]; const a22 = mat[10]; const a23 = mat[11]; const a30 = mat[12]; const a31 = mat[13]; const a32 = mat[14]; const a33 = mat[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; const b02 = a00 * a13 - a03 * a10; const b03 = a01 * a12 - a02 * a11; const b04 = a01 * a13 - a03 * a11; const b05 = a02 * a13 - a03 * a12; const b06 = a20 * a31 - a21 * a30; const b07 = a20 * a32 - a22 * a30; const b08 = a20 * a33 - a23 * a30; const b09 = a21 * a32 - a22 * a31; const b10 = a21 * a33 - a23 * a31; const b11 = a22 * a33 - a23 * a32; // Calculate the determinant (inlined to avoid double-caching) const invDet = 1 / (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06); dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; return dest; }, /** * Returns the trace of the given 4x4 matrix. * @method traceMat4 * @static */ traceMat4(m) { return (m[0] + m[5] + m[10] + m[15]); }, /** * Returns 4x4 translation matrix. * @method translationMat4 * @static */ translationMat4v(v, dest) { const m = dest || math.identityMat4(); m[12] = v[0]; m[13] = v[1]; m[14] = v[2]; return m; }, /** * Returns 3x3 translation matrix. * @method translationMat3 * @static */ translationMat3v(v, dest) { const m = dest || math.identityMat3(); m[6] = v[0]; m[7] = v[1]; return m; }, /** * Returns 4x4 translation matrix. * @method translationMat4c * @static */ translationMat4c: ((() => { const xyz = new FloatArrayType(3); return (x, y, z, dest) => { xyz[0] = x; xyz[1] = y; xyz[2] = z; return math.translationMat4v(xyz, dest); }; }))(), /** * Returns 4x4 translation matrix. * @method translationMat4s * @static */ translationMat4s(s, dest) { return math.translationMat4c(s, s, s, dest); }, /** * Efficiently post-concatenates a translation to the given matrix. * @param v * @param m */ translateMat4v(xyz, m) { return math.translateMat4c(xyz[0], xyz[1], xyz[2], m); }, /** * Efficiently post-concatenates a translation to the given matrix. * @param x * @param y * @param z * @param m */ OLDtranslateMat4c(x, y, z, m) { const m12 = m[12]; m[0] += m12 * x; m[4] += m12 * y; m[8] += m12 * z; const m13 = m[13]; m[1] += m13 * x; m[5] += m13 * y; m[9] += m13 * z; const m14 = m[14]; m[2] += m14 * x; m[6] += m14 * y; m[10] += m14 * z; const m15 = m[15]; m[3] += m15 * x; m[7] += m15 * y; m[11] += m15 * z; return m; }, translateMat4c(x, y, z, m) { const m3 = m[3]; m[0] += m3 * x; m[1] += m3 * y; m[2] += m3 * z; const m7 = m[7]; m[4] += m7 * x; m[5] += m7 * y; m[6] += m7 * z; const m11 = m[11]; m[8] += m11 * x; m[9] += m11 * y; m[10] += m11 * z; const m15 = m[15]; m[12] += m15 * x; m[13] += m15 * y; m[14] += m15 * z; return m; }, /** * Returns 4x4 rotation matrix. * @method rotationMat4v * @static */ rotationMat4v(anglerad, axis, m) { const ax = math.normalizeVec4([axis[0], axis[1], axis[2], 0.0], []); const s = Math.sin(anglerad); const c = Math.cos(anglerad); const q = 1.0 - c; const x = ax[0]; const y = ax[1]; const z = ax[2]; let xy; let yz; let zx; let xs; let ys; let zs; //xx = x * x; used once //yy = y * y; used once //zz = z * z; used once xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; m = m || math.mat4(); m[0] = (q * x * x) + c; m[1] = (q * xy) + zs; m[2] = (q * zx) - ys; m[3] = 0.0; m[4] = (q * xy) - zs; m[5] = (q * y * y) + c; m[6] = (q * yz) + xs; m[7] = 0.0; m[8] = (q * zx) + ys; m[9] = (q * yz) - xs; m[10] = (q * z * z) + c; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; return m; }, /** * Returns 4x4 rotation matrix. * @method rotationMat4c * @static */ rotationMat4c(anglerad, x, y, z, mat) { return math.rotationMat4v(anglerad, [x, y, z], mat); }, /** * Returns 4x4 scale matrix. * @method scalingMat4v * @static */ scalingMat4v(v, m = math.identityMat4()) { m[0] = v[0]; m[5] = v[1]; m[10] = v[2]; return m; }, /** * Returns 3x3 scale matrix. * @method scalingMat3v * @static */ scalingMat3v(v, m = math.identityMat3()) { m[0] = v[0]; m[4] = v[1]; return m; }, /** * Returns 4x4 scale matrix. * @method scalingMat4c * @static */ scalingMat4c: ((() => { const xyz = new FloatArrayType(3); return (x, y, z, dest) => { xyz[0] = x; xyz[1] = y; xyz[2] = z; return math.scalingMat4v(xyz, dest); }; }))(), /** * Efficiently post-concatenates a scaling to the given matrix. * @method scaleMat4c * @param x * @param y * @param z * @param m */ scaleMat4c(x, y, z, m) { m[0] *= x; m[4] *= y; m[8] *= z; m[1] *= x; m[5] *= y; m[9] *= z; m[2] *= x; m[6] *= y; m[10] *= z; m[3] *= x; m[7] *= y; m[11] *= z; return m; }, /** * Efficiently post-concatenates a scaling to the given matrix. * @method scaleMat4c * @param xyz * @param m */ scaleMat4v(xyz, m) { const x = xyz[0]; const y = xyz[1]; const z = xyz[2]; m[0] *= x; m[4] *= y; m[8] *= z; m[1] *= x; m[5] *= y; m[9] *= z; m[2] *= x; m[6] *= y; m[10] *= z; m[3] *= x; m[7] *= y; m[11] *= z; return m; }, /** * Returns 4x4 scale matrix. * @method scalingMat4s * @static */ scalingMat4s(s) { return math.scalingMat4c(s, s, s); }, /** * Creates a matrix from a quaternion rotation and vector translation * * @param {Number[]} q Rotation quaternion * @param {Number[]} v Translation vector * @param {Number[]} dest Destination matrix * @returns {Number[]} dest */ rotationTranslationMat4(q, v, dest = math.mat4()) { const x = q[0]; const y = q[1]; const z = q[2]; const w = q[3]; const x2 = x + x; const y2 = y + y; const z2 = z + z; const xx = x * x2; const xy = x * y2; const xz = x * z2; const yy = y * y2; const yz = y * z2; const zz = z * z2; const wx = w * x2; const wy = w * y2; const wz = w * z2; dest[0] = 1 - (yy + zz); dest[1] = xy + wz; dest[2] = xz - wy; dest[3] = 0; dest[4] = xy - wz; dest[5] = 1 - (xx + zz); dest[6] = yz + wx; dest[7] = 0; dest[8] = xz + wy; dest[9] = yz - wx; dest[10] = 1 - (xx + yy); dest[11] = 0; dest[12] = v[0]; dest[13] = v[1]; dest[14] = v[2]; dest[15] = 1; return dest; }, /** * Gets Euler angles from a 4x4 matrix. * * @param {Number[]} mat The 4x4 matrix. * @param {String} order Desired Euler angle order: "XYZ", "YXZ", "ZXY" etc. * @param {Number[]} [dest] Destination Euler angles, created by default. * @returns {Number[]} The Euler angles. */ mat4ToEuler(mat, order, dest = math.vec4()) { const clamp = math.clamp; // Assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) const m11 = mat[0]; const m12 = mat[4]; const m13 = mat[8]; const m21 = mat[1]; const m22 = mat[5]; const m23 = mat[9]; const m31 = mat[2]; const m32 = mat[6]; const m33 = mat[10]; if (order === 'XYZ') { dest[1] = Math.asin(clamp(m13, -1, 1)); if (Math.abs(m13) < 0.99999) { dest[0] = Math.atan2(-m23, m33); dest[2] = Math.atan2(-m12, m11); } else { dest[0] = Math.atan2(m32, m22); dest[2] = 0; } } else if (order === 'YXZ') { dest[0] = Math.asin(-clamp(m23, -1, 1)); if (Math.abs(m23) < 0.99999) { dest[1] = Math.atan2(m13, m33); dest[2] = Math.atan2(m21, m22); } else { dest[1] = Math.atan2(-m31, m11); dest[2] = 0; } } else if (order === 'ZXY') { dest[0] = Math.asin(clamp(m32, -1, 1)); if (Math.abs(m32) < 0.99999) { dest[1] = Math.atan2(-m31, m33); dest[2] = Math.atan2(-m12, m22); } else { dest[1] = 0; dest[2] = Math.atan2(m21, m11); } } else if (order === 'ZYX') { dest[1] = Math.asin(-clamp(m31, -1, 1)); if (Math.abs(m31) < 0.99999) { dest[0] = Math.atan2(m32, m33); dest[2] = Math.atan2(m21, m11); } else { dest[0] = 0; dest[2] = Math.atan2(-m12, m22); } } else if (order === 'YZX') { dest[2] = Math.asin(clamp(m21, -1, 1)); if (Math.abs(m21) < 0.99999) { dest[0] = Math.atan2(-m23, m22); dest[1] = Math.atan2(-m31, m11); } else { dest[0] = 0; dest[1] = Math.atan2(m13, m33); } } else if (order === 'XZY') { dest[2] = Math.asin(-clamp(m12, -1, 1)); if (Math.abs(m12) < 0.99999) { dest[0] =