@xeokit/xeokit-convert-xkt10
Version:
JavaScript utilities to create .XKT files
1,949 lines (1,759 loc) • 1.11 MB
JavaScript
/**
* @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] =