@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
1,429 lines • 1.15 MB
JavaScript
globalThis.GLTF_PROGRESSIVE_VERSION = "";
console.debug("[gltf-progressive] version -");
const Ra = "182", Ih = 0, Xo = 1, Sh = 2, Ws = 1, vh = 2, as = 3, Dn = 0, Gt = 1, An = 2, Rn = 0, Mi = 1, Yo = 2, Ko = 3, jo = 4, Mh = 5, ri = 100, yh = 101, Bh = 102, wh = 103, Th = 104, Rh = 200, Dh = 201, Lh = 202, Fh = 203, $r = 204, ea = 205, Uh = 206, Ph = 207, Nh = 208, Qh = 209, Oh = 210, kh = 211, Gh = 212, Hh = 213, Vh = 214, ta = 0, na = 1, ia = 2, Ri = 3, sa = 4, ra = 5, aa = 6, oa = 7, pc = 0, zh = 1, Wh = 2, En = 0, gc = 1, mc = 2, _c = 3, bc = 4, Ec = 5, xc = 6, Cc = 7, Jo = "attached", qh = "detached", Ic = 300, Wn = 301, Di = 302, ca = 303, la = 304, dr = 306, Li = 1e3, sn = 1001, js = 1002, _t = 1003, Da = 1004, os = 1005, ft = 1006, qs = 1007, rn = 1008, Re = 1009, Sc = 1010, vc = 1011, ds = 1012, La = 1013, Sn = 1014, Tt = 1015, Dt = 1016, Fa = 1017, Ua = 1018, fs = 1020, fr = 35902, Ar = 35899, Mc = 1021, As = 1022, St = 1023, Ln = 1026, ai = 1027, Vn = 1028, Pa = 1029, an = 1030, Na = 1031, Qa = 1033, yi = 33776, hi = 33777, Bi = 33778, cs = 33779, Js = 35840, ha = 35841, Fi = 35842, ps = 35843, Zs = 36196, gs = 37492, ms = 37496, $s = 37488, er = 37489, tr = 37490, nr = 37491, ui = 37808, ua = 37809, da = 37810, fa = 37811, wi = 37812, Aa = 37813, pa = 37814, ga = 37815, ma = 37816, _a = 37817, ba = 37818, Ea = 37819, xa = 37820, Ca = 37821, Ui = 36492, Ia = 36494, ir = 36495, sr = 36283, rr = 36284, ar = 36285, or = 36286, _s = 2300, bs = 2301, jr = 2302, Zo = 2400, $o = 2401, ec = 2402, Xh = 2500, Yh = 0, yc = 1, Sa = 2, Kh = 3200, Bc = 0, jh = 1, pn = "", At = "srgb", Rt = "srgb-linear", cr = "linear", Je = "srgb", Ii = 7680, tc = 519, Jh = 512, Zh = 513, $h = 514, Oa = 515, eu = 516, tu = 517, ka = 518, nu = 519, va = 35044, nc = "300 es", mn = 2e3, lr = 2001;
function iu(s) {
for (let e = s.length - 1; e >= 0; --e)
if (s[e] >= 65535) return !0;
return !1;
}
function Wd(s) {
return ArrayBuffer.isView(s) && !(s instanceof DataView);
}
function hr(s) {
return document.createElementNS("http://www.w3.org/1999/xhtml", s);
}
function su() {
const s = hr("canvas");
return s.style.display = "block", s;
}
const al = {};
function ur(...s) {
const e = "THREE." + s.shift();
console.log(e, ...s);
}
function Se(...s) {
const e = "THREE." + s.shift();
console.warn(e, ...s);
}
function Be(...s) {
const e = "THREE." + s.shift();
console.error(e, ...s);
}
function Es(...s) {
const e = s.join(" ");
e in al || (al[e] = !0, Se(...s));
}
function qd(s, e, t) {
return new Promise(function(n, i) {
function r() {
switch (s.clientWaitSync(e, s.SYNC_FLUSH_COMMANDS_BIT, 0)) {
case s.WAIT_FAILED:
i();
break;
case s.TIMEOUT_EXPIRED:
setTimeout(r, t);
break;
default:
n();
}
}
setTimeout(r, t);
});
}
class Oi {
/**
* Adds the given event listener to the given event type.
*
* @param {string} type - The type of event to listen to.
* @param {Function} listener - The function that gets called when the event is fired.
*/
addEventListener(e, t) {
this._listeners === void 0 && (this._listeners = {});
const n = this._listeners;
n[e] === void 0 && (n[e] = []), n[e].indexOf(t) === -1 && n[e].push(t);
}
/**
* Returns `true` if the given event listener has been added to the given event type.
*
* @param {string} type - The type of event.
* @param {Function} listener - The listener to check.
* @return {boolean} Whether the given event listener has been added to the given event type.
*/
hasEventListener(e, t) {
const n = this._listeners;
return n === void 0 ? !1 : n[e] !== void 0 && n[e].indexOf(t) !== -1;
}
/**
* Removes the given event listener from the given event type.
*
* @param {string} type - The type of event.
* @param {Function} listener - The listener to remove.
*/
removeEventListener(e, t) {
const n = this._listeners;
if (n === void 0) return;
const i = n[e];
if (i !== void 0) {
const r = i.indexOf(t);
r !== -1 && i.splice(r, 1);
}
}
/**
* Dispatches an event object.
*
* @param {Object} event - The event that gets fired.
*/
dispatchEvent(e) {
const t = this._listeners;
if (t === void 0) return;
const n = t[e.type];
if (n !== void 0) {
e.target = this;
const i = n.slice(0);
for (let r = 0, a = i.length; r < a; r++)
i[r].call(this, e);
e.target = null;
}
}
}
const Lt = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"];
let ol = 1234567;
const Xs = Math.PI / 180, xs = 180 / Math.PI;
function xn() {
const s = Math.random() * 4294967295 | 0, e = Math.random() * 4294967295 | 0, t = Math.random() * 4294967295 | 0, n = Math.random() * 4294967295 | 0;
return (Lt[s & 255] + Lt[s >> 8 & 255] + Lt[s >> 16 & 255] + Lt[s >> 24 & 255] + "-" + Lt[e & 255] + Lt[e >> 8 & 255] + "-" + Lt[e >> 16 & 15 | 64] + Lt[e >> 24 & 255] + "-" + Lt[t & 63 | 128] + Lt[t >> 8 & 255] + "-" + Lt[t >> 16 & 255] + Lt[t >> 24 & 255] + Lt[n & 255] + Lt[n >> 8 & 255] + Lt[n >> 16 & 255] + Lt[n >> 24 & 255]).toLowerCase();
}
function Ve(s, e, t) {
return Math.max(e, Math.min(t, s));
}
function wc(s, e) {
return (s % e + e) % e;
}
function Xd(s, e, t, n, i) {
return n + (s - e) * (i - n) / (t - e);
}
function Yd(s, e, t) {
return s !== e ? (t - s) / (e - s) : 0;
}
function Ys(s, e, t) {
return (1 - t) * s + t * e;
}
function Kd(s, e, t, n) {
return Ys(s, e, 1 - Math.exp(-t * n));
}
function jd(s, e = 1) {
return e - Math.abs(wc(s, e * 2) - e);
}
function Jd(s, e, t) {
return s <= e ? 0 : s >= t ? 1 : (s = (s - e) / (t - e), s * s * (3 - 2 * s));
}
function Zd(s, e, t) {
return s <= e ? 0 : s >= t ? 1 : (s = (s - e) / (t - e), s * s * s * (s * (s * 6 - 15) + 10));
}
function $d(s, e) {
return s + Math.floor(Math.random() * (e - s + 1));
}
function ef(s, e) {
return s + Math.random() * (e - s);
}
function tf(s) {
return s * (0.5 - Math.random());
}
function nf(s) {
s !== void 0 && (ol = s);
let e = ol += 1831565813;
return e = Math.imul(e ^ e >>> 15, e | 1), e ^= e + Math.imul(e ^ e >>> 7, e | 61), ((e ^ e >>> 14) >>> 0) / 4294967296;
}
function sf(s) {
return s * Xs;
}
function rf(s) {
return s * xs;
}
function af(s) {
return (s & s - 1) === 0 && s !== 0;
}
function of(s) {
return Math.pow(2, Math.ceil(Math.log(s) / Math.LN2));
}
function cf(s) {
return Math.pow(2, Math.floor(Math.log(s) / Math.LN2));
}
function lf(s, e, t, n, i) {
const r = Math.cos, a = Math.sin, o = r(t / 2), c = a(t / 2), l = r((e + n) / 2), h = a((e + n) / 2), u = r((e - n) / 2), d = a((e - n) / 2), A = r((n - e) / 2), g = a((n - e) / 2);
switch (i) {
case "XYX":
s.set(o * h, c * u, c * d, o * l);
break;
case "YZY":
s.set(c * d, o * h, c * u, o * l);
break;
case "ZXZ":
s.set(c * u, c * d, o * h, o * l);
break;
case "XZX":
s.set(o * h, c * g, c * A, o * l);
break;
case "YXY":
s.set(c * A, o * h, c * g, o * l);
break;
case "ZYZ":
s.set(c * g, c * A, o * h, o * l);
break;
default:
Se("MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: " + i);
}
}
function gn(s, e) {
switch (e.constructor) {
case Float32Array:
return s;
case Uint32Array:
return s / 4294967295;
case Uint16Array:
return s / 65535;
case Uint8Array:
return s / 255;
case Int32Array:
return Math.max(s / 2147483647, -1);
case Int16Array:
return Math.max(s / 32767, -1);
case Int8Array:
return Math.max(s / 127, -1);
default:
throw new Error("Invalid component type.");
}
}
function it(s, e) {
switch (e.constructor) {
case Float32Array:
return s;
case Uint32Array:
return Math.round(s * 4294967295);
case Uint16Array:
return Math.round(s * 65535);
case Uint8Array:
return Math.round(s * 255);
case Int32Array:
return Math.round(s * 2147483647);
case Int16Array:
return Math.round(s * 32767);
case Int8Array:
return Math.round(s * 127);
default:
throw new Error("Invalid component type.");
}
}
const ru = {
DEG2RAD: Xs,
RAD2DEG: xs,
/**
* Generate a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier)
* (universally unique identifier).
*
* @static
* @method
* @return {string} The UUID.
*/
generateUUID: xn,
/**
* Clamps the given value between min and max.
*
* @static
* @method
* @param {number} value - The value to clamp.
* @param {number} min - The min value.
* @param {number} max - The max value.
* @return {number} The clamped value.
*/
clamp: Ve,
/**
* Computes the Euclidean modulo of the given parameters that
* is `( ( n % m ) + m ) % m`.
*
* @static
* @method
* @param {number} n - The first parameter.
* @param {number} m - The second parameter.
* @return {number} The Euclidean modulo.
*/
euclideanModulo: wc,
/**
* Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>`
* for the given value.
*
* @static
* @method
* @param {number} x - The value to be mapped.
* @param {number} a1 - Minimum value for range A.
* @param {number} a2 - Maximum value for range A.
* @param {number} b1 - Minimum value for range B.
* @param {number} b2 - Maximum value for range B.
* @return {number} The mapped value.
*/
mapLinear: Xd,
/**
* Returns the percentage in the closed interval `[0, 1]` of the given value
* between the start and end point.
*
* @static
* @method
* @param {number} x - The start point
* @param {number} y - The end point.
* @param {number} value - A value between start and end.
* @return {number} The interpolation factor.
*/
inverseLerp: Yd,
/**
* Returns a value linearly interpolated from two known points based on the given interval -
* `t = 0` will return `x` and `t = 1` will return `y`.
*
* @static
* @method
* @param {number} x - The start point
* @param {number} y - The end point.
* @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
* @return {number} The interpolated value.
*/
lerp: Ys,
/**
* Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta
* time to maintain frame rate independent movement. For details, see
* [Frame rate independent damping using lerp](http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/).
*
* @static
* @method
* @param {number} x - The current point.
* @param {number} y - The target point.
* @param {number} lambda - A higher lambda value will make the movement more sudden,
* and a lower value will make the movement more gradual.
* @param {number} dt - Delta time in seconds.
* @return {number} The interpolated value.
*/
damp: Kd,
/**
* Returns a value that alternates between `0` and the given `length` parameter.
*
* @static
* @method
* @param {number} x - The value to pingpong.
* @param {number} [length=1] - The positive value the function will pingpong to.
* @return {number} The alternated value.
*/
pingpong: jd,
/**
* Returns a value in the range `[0,1]` that represents the percentage that `x` has
* moved between `min` and `max`, but smoothed or slowed down the closer `x` is to
* the `min` and `max`.
*
* See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details.
*
* @static
* @method
* @param {number} x - The value to evaluate based on its position between min and max.
* @param {number} min - The min value. Any x value below min will be `0`.
* @param {number} max - The max value. Any x value above max will be `1`.
* @return {number} The alternated value.
*/
smoothstep: Jd,
/**
* A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations)
* that has zero 1st and 2nd order derivatives at x=0 and x=1.
*
* @static
* @method
* @param {number} x - The value to evaluate based on its position between min and max.
* @param {number} min - The min value. Any x value below min will be `0`.
* @param {number} max - The max value. Any x value above max will be `1`.
* @return {number} The alternated value.
*/
smootherstep: Zd,
/**
* Returns a random integer from `<low, high>` interval.
*
* @static
* @method
* @param {number} low - The lower value boundary.
* @param {number} high - The upper value boundary
* @return {number} A random integer.
*/
randInt: $d,
/**
* Returns a random float from `<low, high>` interval.
*
* @static
* @method
* @param {number} low - The lower value boundary.
* @param {number} high - The upper value boundary
* @return {number} A random float.
*/
randFloat: ef,
/**
* Returns a random integer from `<-range/2, range/2>` interval.
*
* @static
* @method
* @param {number} range - Defines the value range.
* @return {number} A random float.
*/
randFloatSpread: tf,
/**
* Returns a deterministic pseudo-random float in the interval `[0, 1]`.
*
* @static
* @method
* @param {number} [s] - The integer seed.
* @return {number} A random float.
*/
seededRandom: nf,
/**
* Converts degrees to radians.
*
* @static
* @method
* @param {number} degrees - A value in degrees.
* @return {number} The converted value in radians.
*/
degToRad: sf,
/**
* Converts radians to degrees.
*
* @static
* @method
* @param {number} radians - A value in radians.
* @return {number} The converted value in degrees.
*/
radToDeg: rf,
/**
* Returns `true` if the given number is a power of two.
*
* @static
* @method
* @param {number} value - The value to check.
* @return {boolean} Whether the given number is a power of two or not.
*/
isPowerOfTwo: af,
/**
* Returns the smallest power of two that is greater than or equal to the given number.
*
* @static
* @method
* @param {number} value - The value to find a POT for.
* @return {number} The smallest power of two that is greater than or equal to the given number.
*/
ceilPowerOfTwo: of,
/**
* Returns the largest power of two that is less than or equal to the given number.
*
* @static
* @method
* @param {number} value - The value to find a POT for.
* @return {number} The largest power of two that is less than or equal to the given number.
*/
floorPowerOfTwo: cf,
/**
* Sets the given quaternion from the [Intrinsic Proper Euler Angles](https://en.wikipedia.org/wiki/Euler_angles)
* defined by the given angles and order.
*
* Rotations are applied to the axes in the order specified by order:
* rotation by angle `a` is applied first, then by angle `b`, then by angle `c`.
*
* @static
* @method
* @param {Quaternion} q - The quaternion to set.
* @param {number} a - The rotation applied to the first axis, in radians.
* @param {number} b - The rotation applied to the second axis, in radians.
* @param {number} c - The rotation applied to the third axis, in radians.
* @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order.
*/
setQuaternionFromProperEuler: lf,
/**
* Normalizes the given value according to the given typed array.
*
* @static
* @method
* @param {number} value - The float value in the range `[0,1]` to normalize.
* @param {TypedArray} array - The typed array that defines the data type of the value.
* @return {number} The normalize value.
*/
normalize: it,
/**
* Denormalizes the given value according to the given typed array.
*
* @static
* @method
* @param {number} value - The value to denormalize.
* @param {TypedArray} array - The typed array that defines the data type of the value.
* @return {number} The denormalize (float) value in the range `[0,1]`.
*/
denormalize: gn
};
class We {
/**
* Constructs a new 2D vector.
*
* @param {number} [x=0] - The x value of this vector.
* @param {number} [y=0] - The y value of this vector.
*/
constructor(e = 0, t = 0) {
We.prototype.isVector2 = !0, this.x = e, this.y = t;
}
/**
* Alias for {@link Vector2#x}.
*
* @type {number}
*/
get width() {
return this.x;
}
set width(e) {
this.x = e;
}
/**
* Alias for {@link Vector2#y}.
*
* @type {number}
*/
get height() {
return this.y;
}
set height(e) {
this.y = e;
}
/**
* Sets the vector components.
*
* @param {number} x - The value of the x component.
* @param {number} y - The value of the y component.
* @return {Vector2} A reference to this vector.
*/
set(e, t) {
return this.x = e, this.y = t, this;
}
/**
* Sets the vector components to the same value.
*
* @param {number} scalar - The value to set for all vector components.
* @return {Vector2} A reference to this vector.
*/
setScalar(e) {
return this.x = e, this.y = e, this;
}
/**
* Sets the vector's x component to the given value
*
* @param {number} x - The value to set.
* @return {Vector2} A reference to this vector.
*/
setX(e) {
return this.x = e, this;
}
/**
* Sets the vector's y component to the given value
*
* @param {number} y - The value to set.
* @return {Vector2} A reference to this vector.
*/
setY(e) {
return this.y = e, this;
}
/**
* Allows to set a vector component with an index.
*
* @param {number} index - The component index. `0` equals to x, `1` equals to y.
* @param {number} value - The value to set.
* @return {Vector2} A reference to this vector.
*/
setComponent(e, t) {
switch (e) {
case 0:
this.x = t;
break;
case 1:
this.y = t;
break;
default:
throw new Error("index is out of range: " + e);
}
return this;
}
/**
* Returns the value of the vector component which matches the given index.
*
* @param {number} index - The component index. `0` equals to x, `1` equals to y.
* @return {number} A vector component value.
*/
getComponent(e) {
switch (e) {
case 0:
return this.x;
case 1:
return this.y;
default:
throw new Error("index is out of range: " + e);
}
}
/**
* Returns a new vector with copied values from this instance.
*
* @return {Vector2} A clone of this instance.
*/
clone() {
return new this.constructor(this.x, this.y);
}
/**
* Copies the values of the given vector to this instance.
*
* @param {Vector2} v - The vector to copy.
* @return {Vector2} A reference to this vector.
*/
copy(e) {
return this.x = e.x, this.y = e.y, this;
}
/**
* Adds the given vector to this instance.
*
* @param {Vector2} v - The vector to add.
* @return {Vector2} A reference to this vector.
*/
add(e) {
return this.x += e.x, this.y += e.y, this;
}
/**
* Adds the given scalar value to all components of this instance.
*
* @param {number} s - The scalar to add.
* @return {Vector2} A reference to this vector.
*/
addScalar(e) {
return this.x += e, this.y += e, this;
}
/**
* Adds the given vectors and stores the result in this instance.
*
* @param {Vector2} a - The first vector.
* @param {Vector2} b - The second vector.
* @return {Vector2} A reference to this vector.
*/
addVectors(e, t) {
return this.x = e.x + t.x, this.y = e.y + t.y, this;
}
/**
* Adds the given vector scaled by the given factor to this instance.
*
* @param {Vector2} v - The vector.
* @param {number} s - The factor that scales `v`.
* @return {Vector2} A reference to this vector.
*/
addScaledVector(e, t) {
return this.x += e.x * t, this.y += e.y * t, this;
}
/**
* Subtracts the given vector from this instance.
*
* @param {Vector2} v - The vector to subtract.
* @return {Vector2} A reference to this vector.
*/
sub(e) {
return this.x -= e.x, this.y -= e.y, this;
}
/**
* Subtracts the given scalar value from all components of this instance.
*
* @param {number} s - The scalar to subtract.
* @return {Vector2} A reference to this vector.
*/
subScalar(e) {
return this.x -= e, this.y -= e, this;
}
/**
* Subtracts the given vectors and stores the result in this instance.
*
* @param {Vector2} a - The first vector.
* @param {Vector2} b - The second vector.
* @return {Vector2} A reference to this vector.
*/
subVectors(e, t) {
return this.x = e.x - t.x, this.y = e.y - t.y, this;
}
/**
* Multiplies the given vector with this instance.
*
* @param {Vector2} v - The vector to multiply.
* @return {Vector2} A reference to this vector.
*/
multiply(e) {
return this.x *= e.x, this.y *= e.y, this;
}
/**
* Multiplies the given scalar value with all components of this instance.
*
* @param {number} scalar - The scalar to multiply.
* @return {Vector2} A reference to this vector.
*/
multiplyScalar(e) {
return this.x *= e, this.y *= e, this;
}
/**
* Divides this instance by the given vector.
*
* @param {Vector2} v - The vector to divide.
* @return {Vector2} A reference to this vector.
*/
divide(e) {
return this.x /= e.x, this.y /= e.y, this;
}
/**
* Divides this vector by the given scalar.
*
* @param {number} scalar - The scalar to divide.
* @return {Vector2} A reference to this vector.
*/
divideScalar(e) {
return this.multiplyScalar(1 / e);
}
/**
* Multiplies this vector (with an implicit 1 as the 3rd component) by
* the given 3x3 matrix.
*
* @param {Matrix3} m - The matrix to apply.
* @return {Vector2} A reference to this vector.
*/
applyMatrix3(e) {
const t = this.x, n = this.y, i = e.elements;
return this.x = i[0] * t + i[3] * n + i[6], this.y = i[1] * t + i[4] * n + i[7], this;
}
/**
* If this vector's x or y value is greater than the given vector's x or y
* value, replace that value with the corresponding min value.
*
* @param {Vector2} v - The vector.
* @return {Vector2} A reference to this vector.
*/
min(e) {
return this.x = Math.min(this.x, e.x), this.y = Math.min(this.y, e.y), this;
}
/**
* If this vector's x or y value is less than the given vector's x or y
* value, replace that value with the corresponding max value.
*
* @param {Vector2} v - The vector.
* @return {Vector2} A reference to this vector.
*/
max(e) {
return this.x = Math.max(this.x, e.x), this.y = Math.max(this.y, e.y), this;
}
/**
* If this vector's x or y value is greater than the max vector's x or y
* value, it is replaced by the corresponding value.
* If this vector's x or y value is less than the min vector's x or y value,
* it is replaced by the corresponding value.
*
* @param {Vector2} min - The minimum x and y values.
* @param {Vector2} max - The maximum x and y values in the desired range.
* @return {Vector2} A reference to this vector.
*/
clamp(e, t) {
return this.x = Ve(this.x, e.x, t.x), this.y = Ve(this.y, e.y, t.y), this;
}
/**
* If this vector's x or y values are greater than the max value, they are
* replaced by the max value.
* If this vector's x or y values are less than the min value, they are
* replaced by the min value.
*
* @param {number} minVal - The minimum value the components will be clamped to.
* @param {number} maxVal - The maximum value the components will be clamped to.
* @return {Vector2} A reference to this vector.
*/
clampScalar(e, t) {
return this.x = Ve(this.x, e, t), this.y = Ve(this.y, e, t), this;
}
/**
* If this vector's length is greater than the max value, it is replaced by
* the max value.
* If this vector's length is less than the min value, it is replaced by the
* min value.
*
* @param {number} min - The minimum value the vector length will be clamped to.
* @param {number} max - The maximum value the vector length will be clamped to.
* @return {Vector2} A reference to this vector.
*/
clampLength(e, t) {
const n = this.length();
return this.divideScalar(n || 1).multiplyScalar(Ve(n, e, t));
}
/**
* The components of this vector are rounded down to the nearest integer value.
*
* @return {Vector2} A reference to this vector.
*/
floor() {
return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this;
}
/**
* The components of this vector are rounded up to the nearest integer value.
*
* @return {Vector2} A reference to this vector.
*/
ceil() {
return this.x = Math.ceil(this.x), this.y = Math.ceil(this.y), this;
}
/**
* The components of this vector are rounded to the nearest integer value
*
* @return {Vector2} A reference to this vector.
*/
round() {
return this.x = Math.round(this.x), this.y = Math.round(this.y), this;
}
/**
* The components of this vector are rounded towards zero (up if negative,
* down if positive) to an integer value.
*
* @return {Vector2} A reference to this vector.
*/
roundToZero() {
return this.x = Math.trunc(this.x), this.y = Math.trunc(this.y), this;
}
/**
* Inverts this vector - i.e. sets x = -x and y = -y.
*
* @return {Vector2} A reference to this vector.
*/
negate() {
return this.x = -this.x, this.y = -this.y, this;
}
/**
* Calculates the dot product of the given vector with this instance.
*
* @param {Vector2} v - The vector to compute the dot product with.
* @return {number} The result of the dot product.
*/
dot(e) {
return this.x * e.x + this.y * e.y;
}
/**
* Calculates the cross product of the given vector with this instance.
*
* @param {Vector2} v - The vector to compute the cross product with.
* @return {number} The result of the cross product.
*/
cross(e) {
return this.x * e.y - this.y * e.x;
}
/**
* Computes the square of the Euclidean length (straight-line length) from
* (0, 0) to (x, y). If you are comparing the lengths of vectors, you should
* compare the length squared instead as it is slightly more efficient to calculate.
*
* @return {number} The square length of this vector.
*/
lengthSq() {
return this.x * this.x + this.y * this.y;
}
/**
* Computes the Euclidean length (straight-line length) from (0, 0) to (x, y).
*
* @return {number} The length of this vector.
*/
length() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
/**
* Computes the Manhattan length of this vector.
*
* @return {number} The length of this vector.
*/
manhattanLength() {
return Math.abs(this.x) + Math.abs(this.y);
}
/**
* Converts this vector to a unit vector - that is, sets it equal to a vector
* with the same direction as this one, but with a vector length of `1`.
*
* @return {Vector2} A reference to this vector.
*/
normalize() {
return this.divideScalar(this.length() || 1);
}
/**
* Computes the angle in radians of this vector with respect to the positive x-axis.
*
* @return {number} The angle in radians.
*/
angle() {
return Math.atan2(-this.y, -this.x) + Math.PI;
}
/**
* Returns the angle between the given vector and this instance in radians.
*
* @param {Vector2} v - The vector to compute the angle with.
* @return {number} The angle in radians.
*/
angleTo(e) {
const t = Math.sqrt(this.lengthSq() * e.lengthSq());
if (t === 0) return Math.PI / 2;
const n = this.dot(e) / t;
return Math.acos(Ve(n, -1, 1));
}
/**
* Computes the distance from the given vector to this instance.
*
* @param {Vector2} v - The vector to compute the distance to.
* @return {number} The distance.
*/
distanceTo(e) {
return Math.sqrt(this.distanceToSquared(e));
}
/**
* Computes the squared distance from the given vector to this instance.
* If you are just comparing the distance with another distance, you should compare
* the distance squared instead as it is slightly more efficient to calculate.
*
* @param {Vector2} v - The vector to compute the squared distance to.
* @return {number} The squared distance.
*/
distanceToSquared(e) {
const t = this.x - e.x, n = this.y - e.y;
return t * t + n * n;
}
/**
* Computes the Manhattan distance from the given vector to this instance.
*
* @param {Vector2} v - The vector to compute the Manhattan distance to.
* @return {number} The Manhattan distance.
*/
manhattanDistanceTo(e) {
return Math.abs(this.x - e.x) + Math.abs(this.y - e.y);
}
/**
* Sets this vector to a vector with the same direction as this one, but
* with the specified length.
*
* @param {number} length - The new length of this vector.
* @return {Vector2} A reference to this vector.
*/
setLength(e) {
return this.normalize().multiplyScalar(e);
}
/**
* Linearly interpolates between the given vector and this instance, where
* alpha is the percent distance along the line - alpha = 0 will be this
* vector, and alpha = 1 will be the given one.
*
* @param {Vector2} v - The vector to interpolate towards.
* @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
* @return {Vector2} A reference to this vector.
*/
lerp(e, t) {
return this.x += (e.x - this.x) * t, this.y += (e.y - this.y) * t, this;
}
/**
* Linearly interpolates between the given vectors, where alpha is the percent
* distance along the line - alpha = 0 will be first vector, and alpha = 1 will
* be the second one. The result is stored in this instance.
*
* @param {Vector2} v1 - The first vector.
* @param {Vector2} v2 - The second vector.
* @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`.
* @return {Vector2} A reference to this vector.
*/
lerpVectors(e, t, n) {
return this.x = e.x + (t.x - e.x) * n, this.y = e.y + (t.y - e.y) * n, this;
}
/**
* Returns `true` if this vector is equal with the given one.
*
* @param {Vector2} v - The vector to test for equality.
* @return {boolean} Whether this vector is equal with the given one.
*/
equals(e) {
return e.x === this.x && e.y === this.y;
}
/**
* Sets this vector's x value to be `array[ offset ]` and y
* value to be `array[ offset + 1 ]`.
*
* @param {Array<number>} array - An array holding the vector component values.
* @param {number} [offset=0] - The offset into the array.
* @return {Vector2} A reference to this vector.
*/
fromArray(e, t = 0) {
return this.x = e[t], this.y = e[t + 1], this;
}
/**
* Writes the components of this vector to the given array. If no array is provided,
* the method returns a new instance.
*
* @param {Array<number>} [array=[]] - The target array holding the vector components.
* @param {number} [offset=0] - Index of the first element in the array.
* @return {Array<number>} The vector components.
*/
toArray(e = [], t = 0) {
return e[t] = this.x, e[t + 1] = this.y, e;
}
/**
* Sets the components of this vector from the given buffer attribute.
*
* @param {BufferAttribute} attribute - The buffer attribute holding vector data.
* @param {number} index - The index into the attribute.
* @return {Vector2} A reference to this vector.
*/
fromBufferAttribute(e, t) {
return this.x = e.getX(t), this.y = e.getY(t), this;
}
/**
* Rotates this vector around the given center by the given angle.
*
* @param {Vector2} center - The point around which to rotate.
* @param {number} angle - The angle to rotate, in radians.
* @return {Vector2} A reference to this vector.
*/
rotateAround(e, t) {
const n = Math.cos(t), i = Math.sin(t), r = this.x - e.x, a = this.y - e.y;
return this.x = r * n - a * i + e.x, this.y = r * i + a * n + e.y, this;
}
/**
* Sets each component of this vector to a pseudo-random value between `0` and
* `1`, excluding `1`.
*
* @return {Vector2} A reference to this vector.
*/
random() {
return this.x = Math.random(), this.y = Math.random(), this;
}
*[Symbol.iterator]() {
yield this.x, yield this.y;
}
}
class qn {
/**
* Constructs a new quaternion.
*
* @param {number} [x=0] - The x value of this quaternion.
* @param {number} [y=0] - The y value of this quaternion.
* @param {number} [z=0] - The z value of this quaternion.
* @param {number} [w=1] - The w value of this quaternion.
*/
constructor(e = 0, t = 0, n = 0, i = 1) {
this.isQuaternion = !0, this._x = e, this._y = t, this._z = n, this._w = i;
}
/**
* Interpolates between two quaternions via SLERP. This implementation assumes the
* quaternion data are managed in flat arrays.
*
* @param {Array<number>} dst - The destination array.
* @param {number} dstOffset - An offset into the destination array.
* @param {Array<number>} src0 - The source array of the first quaternion.
* @param {number} srcOffset0 - An offset into the first source array.
* @param {Array<number>} src1 - The source array of the second quaternion.
* @param {number} srcOffset1 - An offset into the second source array.
* @param {number} t - The interpolation factor in the range `[0,1]`.
* @see {@link Quaternion#slerp}
*/
static slerpFlat(e, t, n, i, r, a, o) {
let c = n[i + 0], l = n[i + 1], h = n[i + 2], u = n[i + 3], d = r[a + 0], A = r[a + 1], g = r[a + 2], m = r[a + 3];
if (o <= 0) {
e[t + 0] = c, e[t + 1] = l, e[t + 2] = h, e[t + 3] = u;
return;
}
if (o >= 1) {
e[t + 0] = d, e[t + 1] = A, e[t + 2] = g, e[t + 3] = m;
return;
}
if (u !== m || c !== d || l !== A || h !== g) {
let p = c * d + l * A + h * g + u * m;
p < 0 && (d = -d, A = -A, g = -g, m = -m, p = -p);
let f = 1 - o;
if (p < 0.9995) {
const E = Math.acos(p), I = Math.sin(E);
f = Math.sin(f * E) / I, o = Math.sin(o * E) / I, c = c * f + d * o, l = l * f + A * o, h = h * f + g * o, u = u * f + m * o;
} else {
c = c * f + d * o, l = l * f + A * o, h = h * f + g * o, u = u * f + m * o;
const E = 1 / Math.sqrt(c * c + l * l + h * h + u * u);
c *= E, l *= E, h *= E, u *= E;
}
}
e[t] = c, e[t + 1] = l, e[t + 2] = h, e[t + 3] = u;
}
/**
* Multiplies two quaternions. This implementation assumes the quaternion data are managed
* in flat arrays.
*
* @param {Array<number>} dst - The destination array.
* @param {number} dstOffset - An offset into the destination array.
* @param {Array<number>} src0 - The source array of the first quaternion.
* @param {number} srcOffset0 - An offset into the first source array.
* @param {Array<number>} src1 - The source array of the second quaternion.
* @param {number} srcOffset1 - An offset into the second source array.
* @return {Array<number>} The destination array.
* @see {@link Quaternion#multiplyQuaternions}.
*/
static multiplyQuaternionsFlat(e, t, n, i, r, a) {
const o = n[i], c = n[i + 1], l = n[i + 2], h = n[i + 3], u = r[a], d = r[a + 1], A = r[a + 2], g = r[a + 3];
return e[t] = o * g + h * u + c * A - l * d, e[t + 1] = c * g + h * d + l * u - o * A, e[t + 2] = l * g + h * A + o * d - c * u, e[t + 3] = h * g - o * u - c * d - l * A, e;
}
/**
* The x value of this quaternion.
*
* @type {number}
* @default 0
*/
get x() {
return this._x;
}
set x(e) {
this._x = e, this._onChangeCallback();
}
/**
* The y value of this quaternion.
*
* @type {number}
* @default 0
*/
get y() {
return this._y;
}
set y(e) {
this._y = e, this._onChangeCallback();
}
/**
* The z value of this quaternion.
*
* @type {number}
* @default 0
*/
get z() {
return this._z;
}
set z(e) {
this._z = e, this._onChangeCallback();
}
/**
* The w value of this quaternion.
*
* @type {number}
* @default 1
*/
get w() {
return this._w;
}
set w(e) {
this._w = e, this._onChangeCallback();
}
/**
* Sets the quaternion components.
*
* @param {number} x - The x value of this quaternion.
* @param {number} y - The y value of this quaternion.
* @param {number} z - The z value of this quaternion.
* @param {number} w - The w value of this quaternion.
* @return {Quaternion} A reference to this quaternion.
*/
set(e, t, n, i) {
return this._x = e, this._y = t, this._z = n, this._w = i, this._onChangeCallback(), this;
}
/**
* Returns a new quaternion with copied values from this instance.
*
* @return {Quaternion} A clone of this instance.
*/
clone() {
return new this.constructor(this._x, this._y, this._z, this._w);
}
/**
* Copies the values of the given quaternion to this instance.
*
* @param {Quaternion} quaternion - The quaternion to copy.
* @return {Quaternion} A reference to this quaternion.
*/
copy(e) {
return this._x = e.x, this._y = e.y, this._z = e.z, this._w = e.w, this._onChangeCallback(), this;
}
/**
* Sets this quaternion from the rotation specified by the given
* Euler angles.
*
* @param {Euler} euler - The Euler angles.
* @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not.
* @return {Quaternion} A reference to this quaternion.
*/
setFromEuler(e, t = !0) {
const n = e._x, i = e._y, r = e._z, a = e._order, o = Math.cos, c = Math.sin, l = o(n / 2), h = o(i / 2), u = o(r / 2), d = c(n / 2), A = c(i / 2), g = c(r / 2);
switch (a) {
case "XYZ":
this._x = d * h * u + l * A * g, this._y = l * A * u - d * h * g, this._z = l * h * g + d * A * u, this._w = l * h * u - d * A * g;
break;
case "YXZ":
this._x = d * h * u + l * A * g, this._y = l * A * u - d * h * g, this._z = l * h * g - d * A * u, this._w = l * h * u + d * A * g;
break;
case "ZXY":
this._x = d * h * u - l * A * g, this._y = l * A * u + d * h * g, this._z = l * h * g + d * A * u, this._w = l * h * u - d * A * g;
break;
case "ZYX":
this._x = d * h * u - l * A * g, this._y = l * A * u + d * h * g, this._z = l * h * g - d * A * u, this._w = l * h * u + d * A * g;
break;
case "YZX":
this._x = d * h * u + l * A * g, this._y = l * A * u + d * h * g, this._z = l * h * g - d * A * u, this._w = l * h * u - d * A * g;
break;
case "XZY":
this._x = d * h * u - l * A * g, this._y = l * A * u - d * h * g, this._z = l * h * g + d * A * u, this._w = l * h * u + d * A * g;
break;
default:
Se("Quaternion: .setFromEuler() encountered an unknown order: " + a);
}
return t === !0 && this._onChangeCallback(), this;
}
/**
* Sets this quaternion from the given axis and angle.
*
* @param {Vector3} axis - The normalized axis.
* @param {number} angle - The angle in radians.
* @return {Quaternion} A reference to this quaternion.
*/
setFromAxisAngle(e, t) {
const n = t / 2, i = Math.sin(n);
return this._x = e.x * i, this._y = e.y * i, this._z = e.z * i, this._w = Math.cos(n), this._onChangeCallback(), this;
}
/**
* Sets this quaternion from the given rotation matrix.
*
* @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled).
* @return {Quaternion} A reference to this quaternion.
*/
setFromRotationMatrix(e) {
const t = e.elements, n = t[0], i = t[4], r = t[8], a = t[1], o = t[5], c = t[9], l = t[2], h = t[6], u = t[10], d = n + o + u;
if (d > 0) {
const A = 0.5 / Math.sqrt(d + 1);
this._w = 0.25 / A, this._x = (h - c) * A, this._y = (r - l) * A, this._z = (a - i) * A;
} else if (n > o && n > u) {
const A = 2 * Math.sqrt(1 + n - o - u);
this._w = (h - c) / A, this._x = 0.25 * A, this._y = (i + a) / A, this._z = (r + l) / A;
} else if (o > u) {
const A = 2 * Math.sqrt(1 + o - n - u);
this._w = (r - l) / A, this._x = (i + a) / A, this._y = 0.25 * A, this._z = (c + h) / A;
} else {
const A = 2 * Math.sqrt(1 + u - n - o);
this._w = (a - i) / A, this._x = (r + l) / A, this._y = (c + h) / A, this._z = 0.25 * A;
}
return this._onChangeCallback(), this;
}
/**
* Sets this quaternion to the rotation required to rotate the direction vector
* `vFrom` to the direction vector `vTo`.
*
* @param {Vector3} vFrom - The first (normalized) direction vector.
* @param {Vector3} vTo - The second (normalized) direction vector.
* @return {Quaternion} A reference to this quaternion.
*/
setFromUnitVectors(e, t) {
let n = e.dot(t) + 1;
return n < 1e-8 ? (n = 0, Math.abs(e.x) > Math.abs(e.z) ? (this._x = -e.y, this._y = e.x, this._z = 0, this._w = n) : (this._x = 0, this._y = -e.z, this._z = e.y, this._w = n)) : (this._x = e.y * t.z - e.z * t.y, this._y = e.z * t.x - e.x * t.z, this._z = e.x * t.y - e.y * t.x, this._w = n), this.normalize();
}
/**
* Returns the angle between this quaternion and the given one in radians.
*
* @param {Quaternion} q - The quaternion to compute the angle with.
* @return {number} The angle in radians.
*/
angleTo(e) {
return 2 * Math.acos(Math.abs(Ve(this.dot(e), -1, 1)));
}
/**
* Rotates this quaternion by a given angular step to the given quaternion.
* The method ensures that the final quaternion will not overshoot `q`.
*
* @param {Quaternion} q - The target quaternion.
* @param {number} step - The angular step in radians.
* @return {Quaternion} A reference to this quaternion.
*/
rotateTowards(e, t) {
const n = this.angleTo(e);
if (n === 0) return this;
const i = Math.min(1, t / n);
return this.slerp(e, i), this;
}
/**
* Sets this quaternion to the identity quaternion; that is, to the
* quaternion that represents "no rotation".
*
* @return {Quaternion} A reference to this quaternion.
*/
identity() {
return this.set(0, 0, 0, 1);
}
/**
* Inverts this quaternion via {@link Quaternion#conjugate}. The
* quaternion is assumed to have unit length.
*
* @return {Quaternion} A reference to this quaternion.
*/
invert() {
return this.conjugate();
}
/**
* Returns the rotational conjugate of this quaternion. The conjugate of a
* quaternion represents the same rotation in the opposite direction about
* the rotational axis.
*
* @return {Quaternion} A reference to this quaternion.
*/
conjugate() {
return this._x *= -1, this._y *= -1, this._z *= -1, this._onChangeCallback(), this;
}
/**
* Calculates the dot product of this quaternion and the given one.
*
* @param {Quaternion} v - The quaternion to compute the dot product with.
* @return {number} The result of the dot product.
*/
dot(e) {
return this._x * e._x + this._y * e._y + this._z * e._z + this._w * e._w;
}
/**
* Computes the squared Euclidean length (straight-line length) of this quaternion,
* considered as a 4 dimensional vector. This can be useful if you are comparing the
* lengths of two quaternions, as this is a slightly more efficient calculation than
* {@link Quaternion#length}.
*
* @return {number} The squared Euclidean length.
*/
lengthSq() {
return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
}
/**
* Computes the Euclidean length (straight-line length) of this quaternion,
* considered as a 4 dimensional vector.
*
* @return {number} The Euclidean length.
*/
length() {
return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
}
/**
* Normalizes this quaternion - that is, calculated the quaternion that performs
* the same rotation as this one, but has a length equal to `1`.
*
* @return {Quaternion} A reference to this quaternion.
*/
normalize() {
let e = this.length();
return e === 0 ? (this._x = 0, this._y = 0, this._z = 0, this._w = 1) : (e = 1 / e, this._x = this._x * e, this._y = this._y * e, this._z = this._z * e, this._w = this._w * e), this._onChangeCallback(), this;
}
/**
* Multiplies this quaternion by the given one.
*
* @param {Quaternion} q - The quaternion.
* @return {Quaternion} A reference to this quaternion.
*/
multiply(e) {
return this.multiplyQuaternions(this, e);
}
/**
* Pre-multiplies this quaternion by the given one.
*
* @param {Quaternion} q - The quaternion.
* @return {Quaternion} A reference to this quaternion.
*/
premultiply(e) {
return this.multiplyQuaternions(e, this);
}
/**
* Multiplies the given quaternions and stores the result in this instance.
*
* @param {Quaternion} a - The first quaternion.
* @param {Quaternion} b - The second quaternion.
* @return {Quaternion} A reference to this quaternion.
*/
multiplyQuaternions(e, t) {
const n = e._x, i = e._y, r = e._z, a = e._w, o = t._x, c = t._y, l = t._z, h = t._w;
return this._x = n * h + a * o + i * l - r * c, this._y = i * h + a * c + r * o - n * l, this._z = r * h + a * l + n * c - i * o, this._w = a * h - n * o - i * c - r * l, this._onChangeCallback(), this;
}
/**
* Performs a spherical linear interpolation between quaternions.
*
* @param {Quaternion} qb - The target quaternion.
* @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
* @return {Quaternion} A reference to this quaternion.
*/
slerp(e, t) {
if (t <= 0) return this;
if (t >= 1) return this.copy(e);
let n = e._x, i = e._y, r = e._z, a = e._w, o = this.dot(e);
o < 0 && (n = -n, i = -i, r = -r, a = -a, o = -o);
let c = 1 - t;
if (o < 0.9995) {
const l = Math.acos(o), h = Math.sin(l);
c = Math.sin(c * l) / h, t = Math.sin(t * l) / h, this._x = this._x * c + n * t, this._y = this._y * c + i * t, this._z = this._z * c + r * t, this._w = this._w * c + a * t, this._onChangeCallback();
} else
this._x = this._x * c + n * t, this._y = this._y * c + i * t, this._z = this._z * c + r * t, this._w = this._w * c + a * t, this.normalize();
return this;
}
/**
* Performs a spherical linear interpolation between the given quaternions
* and stores the result in this quaternion.
*
* @param {Quaternion} qa - The source quaternion.
* @param {Quaternion} qb - The target quaternion.
* @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
* @return {Quaternion} A reference to this quaternion.
*/
slerpQuaternions(e, t, n) {
return this.copy(e).slerp(t, n);
}
/**
* Sets this quaternion to a uniformly random, normalized quaternion.
*
* @return {Quaternion} A reference to this quaternion.
*/
random() {
const e = 2 * Math.PI * Math.random(), t = 2 * Math.PI * Math.random(), n = Math.random(), i = Math.sqrt(1 - n), r = Math.sqrt(n);
return this.set(
i * Math.sin(e),
i * Math.cos(e),
r * Math.sin(t),
r * Math.cos(t)
);
}
/**
* Returns `true` if this quaternion is equal with the given one.
*
* @param {Quaternion} quaternion - The quaternion to test for equality.
* @return {boolean} Whether this quaternion is equal with the given one.
*/
equals(e) {
return e._x === this._x && e._y === this._y && e._z === this._z && e._w === this._w;
}
/**
* Sets this quaternion's components from the given array.
*
* @param {Array<number>} array - An array holding the quaternion component values.
* @param {number} [offset=0] - The offset into the array.
* @return {Quaternion} A reference to this quaternion.
*/
fromArray(e, t = 0) {
return this._x = e[t], this._y = e[t + 1], this._z = e[t + 2], this._w = e[t + 3], this._onChangeCallback(), this;
}
/**
* Writes the components of this quaternion to the gi