UNPKG

@valeera/mathx

Version:

A math library written in TS.

1,790 lines (1,773 loc) 159 kB
const ArraybufferDataType = { COLOR_CMYK: "col_cmyk", COLOR_GPU: "col", COLOR_HSL: "col_hsl", COLOR_HSLA: "col_hsla", COLOR_HSV: "col_hsv", COLOR_HSVA: "col_hsva", COLOR_RGB: "col_rgb", COLOR_RGBA: "col_rgba", COLOR_RYB: "col_ryb", COLOR_RYBA: "col_ryba", COLOR_XYZ: "col_xyz", EULER: "euler", MATRIX2: "mat2", MATRIX3: "mat3", MATRIX4: "mat4", POLAR: "polar", QUATERNION: "qua", SPHERICAL: "spherical", VECTOR2: "vec2", VECTOR3: "vec3", VECTOR4: "vec4", }; const DEG_TO_RAD = Math.PI / 180; const DEG_360_RAD = Math.PI * 2; const DEG_90_RAD = Math.PI * 0.5; const DEG_60_RAD = Math.PI / 3; const DEG_45_RAD = Math.PI * 0.25; const DEG_30_RAD = Math.PI / 6; const EPSILON = Math.pow(2, -52); const RAD_TO_DEG = 180 / Math.PI; const WEIGHT_GRAY_RED = 0.299; const WEIGHT_GRAY_GREEN = 0.587; const WEIGHT_GRAY_BLUE = 0.114; var constants = /*#__PURE__*/Object.freeze({ __proto__: null, DEG_30_RAD: DEG_30_RAD, DEG_360_RAD: DEG_360_RAD, DEG_45_RAD: DEG_45_RAD, DEG_60_RAD: DEG_60_RAD, DEG_90_RAD: DEG_90_RAD, DEG_TO_RAD: DEG_TO_RAD, EPSILON: EPSILON, RAD_TO_DEG: RAD_TO_DEG, WEIGHT_GRAY_BLUE: WEIGHT_GRAY_BLUE, WEIGHT_GRAY_GREEN: WEIGHT_GRAY_GREEN, WEIGHT_GRAY_RED: WEIGHT_GRAY_RED }); const COLOR_HEX_MAP = { aliceblue: 0xf0f8ff, antiquewhite: 0xfaebd7, aqua: 0x00ffff, aquamarine: 0x7fffd4, azure: 0xf0ffff, beige: 0xf5f5dc, bisque: 0xffe4c4, black: 0x000000, blanchedalmond: 0xffebcd, blue: 0x0000ff, blueviolet: 0x8a2be2, brown: 0xa52a2a, burlywood: 0xdeb887, cadetblue: 0x5f9ea0, chartreuse: 0x7fff00, chocolate: 0xd2691e, coral: 0xff7f50, cornflowerblue: 0x6495ed, cornsilk: 0xfff8dc, crimson: 0xdc143c, cyan: 0x00ffff, darkblue: 0x00008b, darkcyan: 0x008b8b, darkgoldenrod: 0xb8860b, darkgray: 0xa9a9a9, darkgreen: 0x006400, darkgrey: 0xa9a9a9, darkkhaki: 0xbdb76b, darkmagenta: 0x8b008b, darkolivegreen: 0x556b2f, darkorange: 0xff8c00, darkorchid: 0x9932cc, darkred: 0x8b0000, darksalmon: 0xe9967a, darkseagreen: 0x8fbc8f, darkslateblue: 0x483d8b, darkslategray: 0x2f4f4f, darkslategrey: 0x2f4f4f, darkturquoise: 0x00ced1, darkviolet: 0x9400d3, deeppink: 0xff1493, deepskyblue: 0x00bfff, dimgray: 0x696969, dimgrey: 0x696969, dodgerblue: 0x1e90ff, firebrick: 0xb22222, floralwhite: 0xfffaf0, forestgreen: 0x228b22, fuchsia: 0xff00ff, gainsboro: 0xdcdcdc, ghostwhite: 0xf8f8ff, gold: 0xffd700, goldenrod: 0xdaa520, gray: 0x808080, green: 0x008000, greenyellow: 0xadff2f, grey: 0x808080, honeydew: 0xf0fff0, hotpink: 0xff69b4, indianred: 0xcd5c5c, indigo: 0x4b0082, ivory: 0xfffff0, khaki: 0xf0e68c, lavender: 0xe6e6fa, lavenderblush: 0xfff0f5, lawngreen: 0x7cfc00, lemonchiffon: 0xfffacd, lightblue: 0xadd8e6, lightcoral: 0xf08080, lightcyan: 0xe0ffff, lightgoldenrodyellow: 0xfafad2, lightgray: 0xd3d3d3, lightgreen: 0x90ee90, lightgrey: 0xd3d3d3, lightpink: 0xffb6c1, lightsalmon: 0xffa07a, lightseagreen: 0x20b2aa, lightskyblue: 0x87cefa, lightslategray: 0x778899, lightslategrey: 0x778899, lightsteelblue: 0xb0c4de, lightyellow: 0xffffe0, lime: 0x00ff00, limegreen: 0x32cd32, linen: 0xfaf0e6, magenta: 0xff00ff, maroon: 0x800000, mediumaquamarine: 0x66cdaa, mediumblue: 0x0000cd, mediumorchid: 0xba55d3, mediumpurple: 0x9370db, mediumseagreen: 0x3cb371, mediumslateblue: 0x7b68ee, mediumspringgreen: 0x00fa9a, mediumturquoise: 0x48d1cc, mediumvioletred: 0xc71585, midnightblue: 0x191970, mintcream: 0xf5fffa, mistyrose: 0xffe4e1, moccasin: 0xffe4b5, navajowhite: 0xffdead, navy: 0x000080, oldlace: 0xfdf5e6, olive: 0x808000, olivedrab: 0x6b8e23, orange: 0xffa500, orangered: 0xff4500, orchid: 0xda70d6, palegoldenrod: 0xeee8aa, palegreen: 0x98fb98, paleturquoise: 0xafeeee, palevioletred: 0xdb7093, papayawhip: 0xffefd5, peachpuff: 0xffdab9, peru: 0xcd853f, pink: 0xffc0cb, plum: 0xdda0dd, powderblue: 0xb0e0e6, purple: 0x800080, rebeccapurple: 0x663399, red: 0xff0000, rosybrown: 0xbc8f8f, royalblue: 0x4169e1, saddlebrown: 0x8b4513, salmon: 0xfa8072, sandybrown: 0xf4a460, seagreen: 0x2e8b57, seashell: 0xfff5ee, sienna: 0xa0522d, silver: 0xc0c0c0, skyblue: 0x87ceeb, slateblue: 0x6a5acd, slategray: 0x708090, slategrey: 0x708090, snow: 0xfffafa, springgreen: 0x00ff7f, steelblue: 0x4682b4, tan: 0xd2b48c, teal: 0x008080, thistle: 0xd8bfd8, tomato: 0xff6347, turquoise: 0x40e0d0, violet: 0xee82ee, wheat: 0xf5deb3, white: 0xffffff, whitesmoke: 0xf5f5f5, yellow: 0xffff00, yellowgreen: 0x9acd32, }; let max$2 = 0; class ColorCMYK extends Float32Array { dataType = ArraybufferDataType.COLOR_CMYK; static fromRGBUnsignedNormal(r, g, b, out = new ColorCMYK()) { max$2 = Math.max(r, g, b); out[0] = 1 - r / max$2; out[1] = 1 - g / max$2; out[2] = 1 - b / max$2; out[3] = 1 - max$2; return out; } constructor(c = 0, m = 0, y = 0, k = 0) { super(4); this[0] = c; this[1] = m; this[2] = y; this[3] = k; } get c() { return this[0]; } set c(val) { this[0] = val; } get m() { return this[1]; } set m(val) { this[1] = val; } get y() { return this[2]; } set y(val) { this[2] = val; } get k() { return this[3]; } set k(val) { this[3] = val; } } const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; const linearToSrgb = (c) => { if (c <= 0) { return 0; } else if (c >= 1) { return 1; } else if (c < 0.0031308) { return c * 12.92; } else { return Math.pow(c, 1 / 2.4) * 1.055 - 0.055; } }; const srgbToLinear = (x) => { if (x <= 0) { return 0; } else if (x >= 1) { return 1; } else if (x < 0.04045) { return x / 12.92; } else { return Math.pow((x + 0.055) / 1.055, 2.4); } }; /** * @function clamp * @desc 将目标值限定在指定区间内。假定min小于等于max才能得到正确的结果。 * @see clampSafe * @param {number} val 目标值 * @param {number} min 最小值,必须小于等于max * @param {number} max 最大值,必须大于等于min * @returns {number} 限制之后的值 * @example Mathx.clamp(1, 0, 2); // 1; * Mathx.clamp(-1, 0, 2); // 0; * Mathx.clamp(3, 0, 2); // 2; */ const clamp = (val, min, max) => { return Math.max(min, Math.min(max, val)); }; /** * @function clampSafe * @desc 与clamp函数功能一样,将目标值限定在指定区间内。但此函数是安全的,不要求第二个参数必须小于第三个参数 * @see clamp * @param {number} val 目标值 * @param {number} a 区间中一个最值 * @param {number} b 区间中另一个最值 * @returns {number} 限制之后的值 * @example Mathx.clamp(1, 0, 2); // 1; * Mathx.clamp(1, 2, 0); // 1; * Mathx.clamp(-1, 0, 2); // 0; * Mathx.clamp(-1, 2, 0); // 0; * Mathx.clamp(3, 0, 2); // 2; * Mathx.clamp(3, 2, 0); // 2; */ const clampSafe = (val, a, b) => { if (a > b) { return Math.max(b, Math.min(a, val)); } else if (b > a) { return Math.max(a, Math.min(b, val)); } return a; }; /** * @function closeTo * @desc 判断一个数是否在另一个数的邻域内,通常用于检验浮点计算是否精度在EPSILON以内 * @param {number} val 需要判断的数值 * @param {number} target 目标数值 * @param {number} [epsilon = Number.EPSILON] 邻域半径 * @example Mathx.closeTo(0.1 + 0.2, 0.3); // true; * Mathx.clamp(2, 3, 1); // true; * Mathx.clamp(2, 3, 0.5); // false; */ const closeTo = (val, target, epsilon = EPSILON) => { return Math.abs(val - target) <= epsilon; }; /** * @function floorToZero * @desc 以0为中心取整 * @param {number} num 数值 * @return {number} 取整之后的结果 * @example Mathx.roundToZero(0.8 ); // 0; * Mathx.roundToZero(-0.8); // 0; * Mathx.roundToZero(-1.1); // -1; */ const floorToZero = (num) => { return num < 0 ? Math.ceil(num) : Math.floor(num); }; let x$4 = 0; let y$4 = 0; let c$1 = 0; let s$4 = 0; class Vector2 extends Float32Array { static VECTOR2_ZERO = new Vector2(0, 0); static VECTOR2_TOP = new Vector2(0, 1); static VECTOR2_BOTTOM = new Vector2(0, -1); static VECTOR2_LEFT = new Vector2(-1, 0); static VECTOR2_RIGHT = new Vector2(1, 0); static VECTOR2_ONE = new Vector2(1, 1); static add = (a, b, out = new Vector2()) => { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; return out; }; static addScalar = (a, b, out = new Vector2()) => { out[0] = a[0] + b; out[1] = a[1] + b; return out; }; static angle = (a) => { return Math.atan2(a[1], a[0]); }; static area = (a) => { return a[0] * a[1]; }; static ceil = (a, out = new Vector2()) => { out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); return out; }; static clamp = (a, min, max, out = new Vector2()) => { out[0] = clamp(a[0], min[0], max[0]); out[1] = clamp(a[1], min[1], max[1]); return out; }; static clampSafe = (a, min, max, out = new Vector2()) => { out[0] = clampSafe(a[0], min[0], max[0]); out[1] = clampSafe(a[1], min[1], max[1]); return out; }; static clampLength = (a, min, max, out = new Vector2()) => { out[0] = clampSafe(a[0], min[0], max[0]); out[1] = clampSafe(a[1], min[1], max[1]); return out; }; static clampScalar = (a, min, max, out = new Vector2()) => { out[0] = clamp(a[0], min, max); out[1] = clamp(a[1], min, max); return out; }; static closeTo = (a, b, epsilon = EPSILON) => { return Vector2.distanceTo(a, b) <= epsilon; }; static closeToRect = (a, b, epsilon = EPSILON) => { return closeTo(a[0], b[0], epsilon) && closeTo(a[1], b[1], epsilon); }; static closeToManhattan = (a, b, epsilon = EPSILON) => { return Vector2.distanceToManhattan(a, b) <= epsilon; }; static clone = (a, out = new Vector2()) => { out[0] = a[0]; out[1] = a[1]; return out; }; static cross = (a, b) => { return a[0] * b[1] - a[1] * b[0]; }; static create = (x = 0, y = 0) => { const out = new Vector2(); out[0] = x; out[1] = y; return out; }; static distanceTo = (a, b) => { x$4 = b[0] - a[0]; y$4 = b[1] - a[1]; return Math.hypot(x$4, y$4); }; static distanceToManhattan = (a, b) => { return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); }; static distanceToSquared = (a, b) => { x$4 = a[0] - b[0]; y$4 = a[1] - b[1]; return x$4 * x$4 + y$4 * y$4; }; static divide = (a, b, out = new Vector2()) => { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; return out; }; static divideScalar = (a, scalar, out = new Vector2()) => { return Vector2.multiplyScalar(a, 1 / scalar, out); }; static dot = (a, b) => { return a[0] * b[0] + a[1] * b[1]; }; static equals = (a, b) => { return a[0] === b[0] && a[1] === b[1]; }; static floor = (a, out = new Vector2()) => { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); return out; }; static floorToZero = (a, out = new Vector2()) => { out[0] = floorToZero(a[0]); out[1] = floorToZero(a[1]); return out; }; static fromArray = (arr, index = 0, out = new Vector2()) => { out[0] = arr[index]; out[1] = arr[index + 1]; return out; }; static fromJson = (j, out = new Vector2()) => { out[0] = j.x; out[1] = j.y; return out; }; static fromPolar = (p, out = new Vector2()) => { out[0] = Math.cos(p.a) * p.r; out[1] = Math.sin(p.a) * p.r; return out; }; static fromPointerEvent = (e, out = new Vector2()) => { if (e.target) { out[0] = (e.clientX / e.target.offsetWidth) * 2 - 1; out[1] = 1 - (e.clientY / e.target.offsetHeight) * 2; } return out; }; static fromScalar = (value = 0, out = new Vector2()) => { out[0] = out[1] = value; return out; }; static fromXY = (x, y, out = new Vector2()) => { out[0] = x; out[1] = y; return out; }; static inverse = (a, out = new Vector2()) => { out[0] = 1 / a[0] || 0; out[1] = 1 / a[1] || 0; return out; }; static norm = (a) => { return Math.sqrt(a[0] * a[0] + a[1] * a[1]); }; static lengthManhattan = (a) => { return Math.abs(a[0]) + Math.abs(a[1]); }; static lengthSquared = (a) => { return a[0] * a[0] + a[1] * a[1]; }; static lerp = (a, b, alpha, out = new Vector2()) => { out[0] = (b[0] - a[0]) * alpha + a[0]; out[1] = (b[1] - a[1]) * alpha + a[1]; return out; }; static max = (a, b, out = new Vector2()) => { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); return out; }; static min = (a, b, out = new Vector2()) => { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); return out; }; static minus = (a, b, out = new Vector2()) => { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; return out; }; static minusScalar = (a, num, out = new Vector2()) => { out[0] = a[0] - num; out[1] = a[1] - num; return out; }; static multiply = (a, b, out = new Vector2()) => { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; }; static multiplyScalar = (a, scalar, out = new Vector2()) => { out[0] = a[0] * scalar; out[1] = a[1] * scalar; return out; }; static negate = (a, out = new Vector2()) => { out[0] = -a[0]; out[1] = -a[1]; return out; }; static normalize = (a, out = new Vector2()) => { return Vector2.divideScalar(a, Vector2.norm(a) || 1, out); }; static opposite = (a, center, out = new Vector2()) => { x$4 = center[0]; y$4 = center[1]; out[0] = x$4 + x$4 - a[0]; out[1] = y$4 + y$4 - a[1]; return out; }; static random = (norm = 1, out = new Vector2()) => { x$4 = Math.random() * DEG_360_RAD; out[0] = Math.cos(x$4) * norm; out[1] = Math.sin(x$4) * norm; return out; }; static reflect = (origin, normal, out = new Vector2()) => { Vector2.multiplyScalar(normal, 2 * Vector2.dot(origin, normal), out); return Vector2.minus(origin, out, out); }; static rotate = (a, angle, center = Vector2.VECTOR2_ZERO, out = new Vector2()) => { c$1 = Math.cos(angle); s$4 = Math.sin(angle); x$4 = a[0] - center[0]; y$4 = a[1] - center[1]; out[0] = x$4 * c$1 - y$4 * s$4 + center[0]; out[1] = x$4 * s$4 + y$4 * c$1 + center[1]; return out; }; static round = (a, out = new Vector2()) => { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); return out; }; static setNorm = (a, norm, out = new Vector2(2)) => { Vector2.normalize(a, out); return Vector2.multiplyScalar(out, norm, out); }; static toArray = (a, arr = []) => { arr[0] = a[0]; arr[1] = a[1]; return arr; }; static toPalorJson = (a, p = { a: 0, r: 0 }) => { p.r = Vector2.norm(a); p.a = Vector2.angle(a); return p; }; static toString = (a) => { return `(${a[0]}, ${a[1]})`; }; static transformDirection = (a, m, out = new Vector2()) => { x$4 = a[0]; y$4 = a[1]; out[0] = m[0] * x$4 + m[3] * y$4; out[1] = m[1] * x$4 + m[4] * y$4; return Vector2.normalize(out, out); }; static transformMatrix3 = (a, m, out = new Vector2()) => { x$4 = a[0]; y$4 = a[1]; out[0] = m[0] * x$4 + m[3] * y$4 + m[6]; out[1] = m[1] * x$4 + m[4] * y$4 + m[7]; return out; }; dataType = ArraybufferDataType.VECTOR2; constructor(x = 0, y = 0) { super(2); this[0] = x; this[1] = y; } get x() { return this[0]; } set x(value) { this[0] = value; } get y() { return this[1]; } set y(value) { this[1] = value; } } let ax$1; let ay$1; let az$1; let bx$1; let by$1; let bz$1; let ag; let s$3; class Vector3 extends Float32Array { static VECTOR3_ZERO = new Vector3(0, 0, 0); static VECTOR3_ONE = new Vector3(1, 1, 1); static VECTOR3_TOP = new Vector3(0, 1, 0); static VECTOR3_BOTTOM = new Vector3(0, -1, 0); static VECTOR3_LEFT = new Vector3(-1, 0, 0); static VECTOR3_RIGHT = new Vector3(1, 0, 0); static VECTOR3_FRONT = new Vector3(0, 0, -1); static VECTOR3_BACK = new Vector3(0, 0, 1); static add = (a, b, out = new Vector3()) => { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; return out; }; static addScalar = (a, b, out = new Vector3()) => { out[0] = a[0] + b; out[1] = a[1] + b; out[2] = a[2] + b; return out; }; static angle = (a, b) => { ax$1 = a[0]; ay$1 = a[1]; az$1 = a[2]; bx$1 = b[0]; by$1 = b[1]; bz$1 = b[2]; const mag1 = Math.sqrt(ax$1 * ax$1 + ay$1 * ay$1 + az$1 * az$1); const mag2 = Math.sqrt(bx$1 * bx$1 + by$1 * by$1 + bz$1 * bz$1); const mag = mag1 * mag2; const cosine = mag && Vector3.dot(a, b) / mag; return Math.acos(clamp(cosine, -1, 1)); }; static clamp = (a, min, max, out = new Vector3()) => { out[0] = clamp(a[0], min[0], max[0]); out[1] = clamp(a[1], min[1], max[1]); out[2] = clamp(a[2], min[2], max[2]); return out; }; static clampSafe = (a, min, max, out = new Vector3()) => { out[0] = clampSafe(a[0], min[0], max[0]); out[1] = clampSafe(a[1], min[1], max[1]); out[1] = clampSafe(a[2], min[2], max[2]); return out; }; static clampScalar = (a, min, max, out = new Vector3()) => { out[0] = clamp(a[0], min, max); out[1] = clamp(a[1], min, max); out[2] = clamp(a[2], min, max); return out; }; static clone = (a, out = new Vector3()) => { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; }; static closeTo = (a, b, epsilon = EPSILON) => { return Vector3.distanceTo(a, b) <= epsilon; }; static closeToRect = (a, b, epsilon = EPSILON) => { return closeTo(a[0], b[0], epsilon) && closeTo(a[1], b[1], epsilon) && closeTo(a[2], b[2], epsilon); }; static create = (x = 0, y = 0, z = 0) => { const out = new Vector3(); out[0] = x; out[1] = y; out[2] = z; return out; }; static cross = (a, b, out = new Vector3()) => { ax$1 = a[0]; ay$1 = a[1]; az$1 = a[2]; bx$1 = b[0]; by$1 = b[1]; bz$1 = b[2]; out[0] = ay$1 * bz$1 - az$1 * by$1; out[1] = az$1 * bx$1 - ax$1 * bz$1; out[2] = ax$1 * by$1 - ay$1 * bx$1; return out; }; static distanceTo = (a, b) => { ax$1 = b[0] - a[0]; ay$1 = b[1] - a[1]; az$1 = b[2] - a[2]; return Math.hypot(ax$1, ay$1, az$1); }; static distanceToManhattan = (a, b) => { return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2]); }; static distanceToSquared = (a, b) => { ax$1 = a[0] - b[0]; ay$1 = a[1] - b[1]; az$1 = a[2] - b[2]; return ax$1 * ax$1 + ay$1 * ay$1 + az$1 * az$1; }; static divide = (a, b, out = new Vector3()) => { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; out[2] = a[2] / b[2]; return out; }; static divideScalar = (a, b, out = new Vector3()) => { out[0] = a[0] / b; out[1] = a[1] / b; out[2] = a[2] / b; return out; }; static dot = (a, b) => { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; }; static equals = (a, b) => { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; }; static floor = (a, out = new Vector3()) => { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); out[2] = Math.floor(a[2]); return out; }; static fromArray = (a, offset = 0, out = new Vector3()) => { out[0] = a[offset]; out[1] = a[offset + 1]; out[2] = a[offset + 2]; return out; }; static fromScalar = (num, out = new Vector3()) => { out[0] = out[1] = out[2] = num; return out; }; static fromXYZ = (x, y, z, out = new Vector3()) => { out[0] = x; out[1] = y; out[2] = z; return out; }; static fromMatrix4Scale = (mat, out = new Vector3()) => { out[0] = mat[0]; out[1] = mat[5]; out[2] = mat[10]; return out; }; static fromMatrix4Translate = (mat, out = new Vector3()) => { out[0] = mat[12]; out[1] = mat[13]; out[2] = mat[14]; return out; }; static hermite = (a, b, c, d, t, out = new Vector3()) => { ag = t * t; const factor1 = ag * (2 * t - 3) + 1; const factor2 = ag * (t - 2) + t; const factor3 = ag * (t - 1); const factor4 = ag * (3 - 2 * t); out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; return out; }; static inverse = (a, out = new Vector3()) => { out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; out[2] = 1.0 / a[2]; return out; }; static norm = (a) => { return Math.sqrt(Vector3.lengthSquared(a)); }; static lengthManhattan = (a) => { return Math.abs(a[0]) + Math.abs(a[1]) + Math.abs(a[2]); }; static lengthSquared = (a) => { return a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; }; static lerp = (a, b, alpha, out = new Vector3()) => { out[0] = (b[0] - a[0]) * alpha + a[0]; out[1] = (b[1] - a[1]) * alpha + a[1]; out[2] = (b[2] - a[2]) * alpha + a[2]; return out; }; static max = (a, b, out = new Vector3()) => { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); out[2] = Math.max(a[2], b[2]); return out; }; static min = (a, b, out = new Vector3()) => { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); out[2] = Math.min(a[2], b[2]); return out; }; static minus = (a, b, out = new Vector3()) => { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; return out; }; static minusScalar = (a, b, out = new Vector3()) => { out[0] = a[0] - b; out[1] = a[1] - b; out[2] = a[2] - b; return out; }; static multiply = (a, b, out = new Vector3()) => { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; out[2] = a[2] * b[2]; return out; }; static multiplyScalar = (a, scalar, out = new Vector3()) => { out[0] = a[0] * scalar; out[1] = a[1] * scalar; out[2] = a[2] * scalar; return out; }; static negate = (a, out = new Vector3()) => { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; return out; }; static normalize = (a, out = new Vector3()) => { return Vector3.divideScalar(a, Vector3.norm(a) || 1, out); }; static opposite = (a, center, out = new Vector3()) => { ax$1 = center[0]; ay$1 = center[1]; az$1 = center[2]; out[0] = ax$1 + ax$1 - a[0]; out[1] = ay$1 + ay$1 - a[1]; out[2] = az$1 + az$1 - a[2]; return out; }; static reflect = (origin, normal, out = new Vector3()) => { Vector3.multiplyScalar(normal, 2 * Vector3.dot(origin, normal), out); return Vector3.minus(origin, out, out); }; static rotateX = (a, b, rad, out = new Vector3()) => { ax$1 = a[0] - b[0]; ay$1 = a[1] - b[1]; az$1 = a[2] - b[2]; bx$1 = ax$1; by$1 = ay$1 * Math.cos(rad) - az$1 * Math.sin(rad); bz$1 = ay$1 * Math.sin(rad) + az$1 * Math.cos(rad); out[0] = bx$1 + b[0]; out[1] = by$1 + b[1]; out[2] = bz$1 + b[2]; return out; }; static rotateY = (a, b, rad, out = new Vector3()) => { ax$1 = a[0] - b[0]; ay$1 = a[1] - b[1]; az$1 = a[2] - b[2]; bx$1 = az$1 * Math.sin(rad) + ax$1 * Math.cos(rad); by$1 = ay$1; bz$1 = az$1 * Math.cos(rad) - ax$1 * Math.sin(rad); out[0] = bx$1 + b[0]; out[1] = by$1 + b[1]; out[2] = bz$1 + b[2]; return out; }; static rotateZ = (a, b, rad, out = new Vector3()) => { ax$1 = a[0] - b[0]; ay$1 = a[1] - b[1]; az$1 = a[2] - b[2]; bx$1 = ax$1 * Math.cos(rad) - ay$1 * Math.sin(rad); by$1 = ax$1 * Math.sin(rad) + ay$1 * Math.cos(rad); bz$1 = az$1; out[0] = bx$1 + b[0]; out[1] = by$1 + b[1]; out[2] = bz$1 + b[2]; return out; }; static round = (a, out = new Vector3()) => { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); out[2] = Math.round(a[2]); return out; }; static setNorm = (a, norm, out = new Vector3()) => { return Vector3.multiplyScalar(Vector3.normalize(a, out), norm, out); }; static slerp = (a, b, t, out = new Vector3()) => { ag = Math.acos(Math.min(Math.max(Vector3.dot(a, b), -1), 1)); s$3 = Math.sin(ag); ax$1 = Math.sin((1 - t) * ag) / s$3; bx$1 = Math.sin(t * ag) / s$3; out[0] = ax$1 * a[0] + bx$1 * b[0]; out[1] = ax$1 * a[1] + bx$1 * b[1]; out[2] = ax$1 * a[2] + bx$1 * b[2]; return out; }; static toString = (a) => { return `(${a[0]}, ${a[1]}, ${a[2]})`; }; static transformMatrix3 = (a, m, out = new Vector3()) => { ax$1 = a[0]; ay$1 = a[1]; az$1 = a[2]; out[0] = ax$1 * m[0] + ay$1 * m[3] + az$1 * m[6]; out[1] = ax$1 * m[1] + ay$1 * m[4] + az$1 * m[7]; out[2] = ax$1 * m[2] + ay$1 * m[5] + az$1 * m[8]; return out; }; static transformDirection = (a, m, out = new Vector3()) => { ax$1 = a[0]; ay$1 = a[1]; az$1 = a[2]; out[0] = m[0] * ax$1 + m[4] * ay$1 + m[8] * az$1; out[1] = m[1] * ax$1 + m[5] * ay$1 + m[9] * az$1; out[2] = m[2] * ax$1 + m[6] * ay$1 + m[10] * az$1; return Vector3.normalize(out, out); }; static transformMatrix4 = (a, m, out = new Vector3()) => { ax$1 = a[0]; ay$1 = a[1]; az$1 = a[2]; ag = m[3] * ax$1 + m[7] * ay$1 + m[11] * az$1 + m[15]; ag = ag ? 1 / ag : 1.0; out[0] = (m[0] * ax$1 + m[4] * ay$1 + m[8] * az$1 + m[12]) * ag; out[1] = (m[1] * ax$1 + m[5] * ay$1 + m[9] * az$1 + m[13]) * ag; out[2] = (m[2] * ax$1 + m[6] * ay$1 + m[10] * az$1 + m[14]) * ag; return out; }; static transformQuat = (a, q, out = new Vector3()) => { const qx = q[0]; const qy = q[1]; const qz = q[2]; const qw = q[3]; const x = a[0]; const y = a[1]; const z = a[2]; // var qvec = [qx, qy, qz]; // var uv = vec3.cross([], qvec, a); let uvx = qy * z - qz * y; let uvy = qz * x - qx * z; let uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv); let uuvx = qy * uvz - qz * uvy; let uuvy = qz * uvx - qx * uvz; let uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w); const w2 = qw * 2; uvx *= w2; uvy *= w2; uvz *= w2; // vec3.scale(uuv, uuv, 2); uuvx *= 2; uuvy *= 2; uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv)); out[0] = x + uvx + uuvx; out[1] = y + uvy + uuvy; out[2] = z + uvz + uuvz; return out; }; static volume = (a) => { return a[0] * a[1] * a[2]; }; dataType = ArraybufferDataType.VECTOR3; constructor(x = 0, y = 0, z = 0) { super(3); this[0] = x; this[1] = y; this[2] = z; } get x() { return this[0]; } set x(value) { this[0] = value; } get y() { return this[1]; } set y(value) { this[1] = value; } get z() { return this[2]; } set z(value) { this[2] = value; } } let ax; let ay; let az; let aw; let bx; let by; let bz; let len$2; let ix; let iy; let iz; let iw; let A; let B; let C; let D; let E; let F; let G; let H; let I; let J; class Vector4 extends Float32Array { static VECTOR4_ZERO = new Vector4(0, 0, 0, 0); static VECTOR4_ONE = new Vector4(1, 1, 1, 1); static add = (a, b, out = new Vector4()) => { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; return out; }; static ceil = (a, out = new Vector4()) => { out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); out[2] = Math.ceil(a[2]); out[3] = Math.ceil(a[3]); return out; }; static closeTo = (a, b, epsilon = EPSILON) => { return Vector4.distanceTo(a, b) <= epsilon; }; static closeToRect = (a, b, epsilon = EPSILON) => { return closeTo(a[0], b[0], epsilon) && closeTo(a[1], b[1], epsilon) && closeTo(a[2], b[2], epsilon) && closeTo(a[3], b[3], epsilon); }; static create = (x = 0, y = 0, z = 0, w = 0) => { const out = new Vector4(); out[0] = x; out[1] = y; out[2] = z; out[3] = w; return out; }; static cross = (u, v, w, out = new Vector4(4)) => { A = v[0] * w[1] - v[1] * w[0]; B = v[0] * w[2] - v[2] * w[0]; C = v[0] * w[3] - v[3] * w[0]; D = v[1] * w[2] - v[2] * w[1]; E = v[1] * w[3] - v[3] * w[1]; F = v[2] * w[3] - v[3] * w[2]; G = u[0]; H = u[1]; I = u[2]; J = u[3]; out[0] = H * F - I * E + J * D; out[1] = -(G * F) + I * C - J * B; out[2] = G * E - H * C + J * A; out[3] = -(G * D) + H * B - I * A; return out; }; static distanceTo = (a, b) => { ax = b[0] - a[0]; ay = b[1] - a[1]; az = b[2] - a[2]; aw = b[3] - a[3]; return Math.hypot(ax, ay, az, aw); }; static distanceToSquared = (a, b) => { ax = b[0] - a[0]; ay = b[1] - a[1]; az = b[2] - a[2]; aw = b[3] - a[3]; return ax * ax + ay * ay + az * az + aw * aw; }; static divide = (a, b, out = new Vector4()) => { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; out[2] = a[2] / b[2]; out[3] = a[3] / b[3]; return out; }; static dot = (a, b) => { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; }; static equals = (a, b) => { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; }; static floor = (a, out = new Vector4()) => { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); out[2] = Math.floor(a[2]); out[3] = Math.floor(a[3]); return out; }; static fromArray = (a, offset = 0, out = new Vector4()) => { out[0] = a[offset]; out[1] = a[offset + 1]; out[2] = a[offset + 2]; out[3] = a[offset + 3]; return out; }; static fromScalar = (num, out = new Vector4()) => { out[0] = out[1] = out[2] = out[3] = num; return out; }; static fromXYZW = (x, y, z, w, out = new Vector4()) => { out[0] = x; out[1] = y; out[2] = z; out[3] = w; return out; }; static inverse = (a, out = new Vector4()) => { out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; out[2] = 1.0 / a[2]; out[3] = 1.0 / a[3]; return out; }; static norm = (a) => { return Math.hypot(a[0], a[1], a[2], a[3]); }; static lengthSquared = (a) => { ax = a[0]; ay = a[1]; az = a[2]; aw = a[3]; return ax * ax + ay * ay + az * az + aw * aw; }; static lerp = (a, b, t, out = new Vector4()) => { ax = a[0]; ay = a[1]; az = a[2]; aw = a[3]; out[0] = ax + t * (b[0] - ax); out[1] = ay + t * (b[1] - ay); out[2] = az + t * (b[2] - az); out[3] = aw + t * (b[3] - aw); return out; }; static max = (a, b, out = new Vector4()) => { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); out[2] = Math.max(a[2], b[2]); out[3] = Math.max(a[3], b[3]); return out; }; static min = (a, b, out = new Vector4()) => { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); out[2] = Math.min(a[2], b[2]); out[3] = Math.min(a[3], b[3]); return out; }; static minus = (a, b, out = new Vector4()) => { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; return out; }; static multiply = (a, b, out = new Vector4()) => { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; out[2] = a[2] * b[2]; out[3] = a[3] * b[3]; return out; }; static multiplyScalar = (a, b, out = new Vector4()) => { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; return out; }; static negate = (a, out = new Vector4()) => { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; out[3] = -a[3]; return out; }; static normalize = (a, out = new Vector4()) => { ax = a[0]; ay = a[1]; az = a[2]; aw = a[3]; len$2 = ax * ax + ay * ay + az * az + aw * aw; if (len$2 > 0) { len$2 = 1 / Math.sqrt(len$2); } out[0] = ax * len$2; out[1] = ay * len$2; out[2] = az * len$2; out[3] = aw * len$2; return out; }; static round = (a, out = new Vector4()) => { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); out[2] = Math.round(a[2]); out[3] = Math.round(a[3]); return out; }; static setNorm = (a, length, out = new Vector4(2)) => { Vector4.normalize(a, out); Vector4.multiplyScalar(out, length, out); return out; }; static toString = (a) => { return `(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]})`; }; static transformMatrix4 = (a, m, out = new Vector4()) => { ax = a[0]; ay = a[1]; az = a[2]; aw = a[3]; out[0] = m[0] * ax + m[4] * ay + m[8] * az + m[12] * aw; out[1] = m[1] * ax + m[5] * ay + m[9] * az + m[13] * aw; out[2] = m[2] * ax + m[6] * ay + m[10] * az + m[14] * aw; out[3] = m[3] * ax + m[7] * ay + m[11] * az + m[15] * aw; return out; }; static transformQuat = (a, q, out = new Vector4()) => { bx = a[0]; by = a[1]; bz = a[2]; ax = q[0]; ay = q[1]; az = q[2]; aw = q[3]; ix = aw * bx + ay * bz - az * by; iy = aw * by + az * bx - ax * bz; iz = aw * bz + ax * by - ay * bx; iw = -ax * bx - ay * by - az * bz; out[0] = ix * aw + iw * -ax + iy * -az - iz * -ay; out[1] = iy * aw + iw * -ay + iz * -ax - ix * -az; out[2] = iz * aw + iw * -az + ix * -ay - iy * -ax; out[3] = a[3]; return out; }; dataType = ArraybufferDataType.VECTOR4; constructor(x = 0, y = 0, z = 0, w = 0) { super(4); this[0] = x; this[1] = y; this[2] = z; this[3] = w; } get x() { return this[0]; } set x(value) { this[0] = value; } get y() { return this[1]; } set y(value) { this[1] = value; } get z() { return this[2]; } set z(value) { this[2] = value; } get w() { return this[3]; } set w(value) { this[3] = value; } } const MATRIX_XYZ2RGB = new Float32Array([ 3.2404542, -0.969266, 0.0556434, -1.5371385, 1.8760108, -0.2040259, -0.4985314, 0.041556, 1.0572252, ]); const MATRIX_RGB2XYZ = new Float32Array([ 0.4124564, 0.2126729, 0.0193339, 0.3575761, 0.7151522, 0.119192, 0.1804375, 0.072175, 0.9503041, ]); const tmpVec3 = new Float32Array(3); class ColorXYZ extends Float32Array { static clone = (color) => { return new ColorXYZ(color[0], color[1], color[2]); }; static create = (r = 0, g = 0, b = 0) => { return new ColorXYZ(r, g, b); }; static equals = (a, b) => { return (a.x ?? a[0]) === (b.x ?? b[0]) && (a.y ?? a[1]) === (b.y ?? b[1]) && (a.z ?? a[2]) === (b.z ?? b[2]); }; static fromArray = (arr, out = new ColorXYZ()) => { out[0] = arr[0]; out[1] = arr[1]; out[2] = arr[2]; return out; }; static fromColorGPU = (color, out = new ColorXYZ()) => { return Vector3.transformMatrix3(color, MATRIX_RGB2XYZ, out); }; static fromJson = (json, out = new ColorXYZ()) => { out[0] = json.x; out[1] = json.y; out[2] = json.z; return out; }; static fromRGBUnsignedNormal = (r, g, b, out = new ColorXYZ()) => { tmpVec3[0] = r; tmpVec3[1] = g; tmpVec3[2] = b; return ColorXYZ.fromColorGPU(tmpVec3, out); }; static fromScalar = (scalar, out = new ColorXYZ()) => { out[0] = scalar; out[1] = scalar; out[2] = scalar; return out; }; dataType = ArraybufferDataType.COLOR_RGB; constructor(r = 0, y = 0, b = 0) { super(3); this[0] = r; this[1] = y; this[2] = b; } get x() { return this[0]; } set x(val) { this[0] = val; } get y() { return this[1]; } set y(val) { this[1] = val; } get z() { return this[2]; } set z(val) { this[2] = val; } } let max$1 = 0; let min$1 = 0; let h$1 = 0; let s$2 = 0; let l = 0; class ColorHSL extends Float32Array { dataType = ArraybufferDataType.COLOR_HSL; static fromRGBUnsignedNormal(r, g, b, out = new ColorHSL()) { max$1 = Math.max(r, g, b); min$1 = Math.min(r, g, b); l = (max$1 + min$1) / 2; if (max$1 === min$1) { h$1 = s$2 = 0; } else { let d = max$1 - min$1; s$2 = l > 0.5 ? d / (2 - max$1 - min$1) : d / (max$1 + min$1); switch (max$1) { case r: h$1 = (g - b) / d + (g < b ? 6 : 0); break; case g: h$1 = (b - r) / d + 2; break; case b: h$1 = (r - g) / d + 4; break; } h$1 /= 6; } out[0] = h$1; out[1] = s$2; out[2] = l; return out; } constructor(h = 0, s = 0, l = 0) { super(3); this[0] = h; this[1] = s; this[2] = l; } get h() { return this[0]; } set h(val) { this[0] = val; } get s() { return this[1]; } set s(val) { this[1] = val; } get l() { return this[2]; } set l(val) { this[2] = val; } } let max = 0; let min = 0; let h = 0; let s$1 = 0; let v$2 = 0; class ColorHSV extends Float32Array { dataType = ArraybufferDataType.COLOR_HSV; static fromRGBUnsignedNormal(r, g, b, out = new ColorHSV()) { max = Math.max(r, g, b); min = Math.min(r, g, b); v$2 = max; if (max === min) { h = 0; } else { let d = max - min; s$1 = v$2 > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } if (max) { s$1 = 1 - min / max; } else { s$1 = 0; } out[0] = h; out[1] = s$1; out[2] = v$2; return out; } constructor(h = 0, s = 0, v = 0) { super(3); this[0] = h; this[1] = s; this[2] = v; } get h() { return this[0]; } set h(val) { this[0] = val; } get s() { return this[1]; } set s(val) { this[1] = val; } get v() { return this[2]; } set v(val) { this[2] = val; } } class ColorRGB extends Uint8Array { static average = (color) => { return (color[0] + color[1] + color[2]) / 3; }; static averageWeighted = (color, wr = WEIGHT_GRAY_RED, wg = WEIGHT_GRAY_GREEN, wb = WEIGHT_GRAY_BLUE) => { return color[0] * wr + color[1] * wg + color[2] * wb; }; static clone = (color) => { return new ColorRGB(color[0], color[1], color[2]); }; static create = (r = 0, g = 0, b = 0) => { return new ColorRGB(r, g, b); }; static equals = (a, b) => { return (a.r ?? a[0]) === (b.r ?? b[0]) && (a.g ?? a[1]) === (b.g ?? b[1]) && (a.b ?? a[2]) === (b.b ?? b[2]); }; static fromArray = (arr, out = new ColorRGB()) => { out[0] = arr[0]; out[1] = arr[1]; out[2] = arr[2]; return out; }; static fromColorRYB(color, out = new ColorRGB()) { let r = color[0]; let y = color[1]; let b = color[2]; // Remove the whiteness from the color. let w = Math.min(r, y, b); r -= w; y -= w; b -= w; let my = Math.max(r, y, b); // Get the green out of the yellow and blue let g = Math.min(y, b); y -= g; b -= g; if (b && g) { b *= 2.0; g *= 2.0; } // Redistribute the remaining yellow. r += y; g += y; // Normalize to values. let mg = Math.max(r, g, b); if (mg) { let n = my / mg; r *= n; g *= n; b *= n; } // Add the white back in. r += w; g += w; b += w; out[0] = r; out[1] = g; out[2] = b; return out; } static fromHex = (hex, out = new ColorRGB()) => { out[0] = hex >> 16; out[1] = (hex >> 8) & 255; out[2] = hex & 255; return out; }; static fromHSL = (h, s, l, out = new ColorRGB()) => { let r; let g; let b; if (s === 0) { r = g = b = l; // achromatic } else { let q = l < 0.5 ? l * (1 + s) : l + s - l * s; let p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } out[0] = Math.round(r * 255); out[1] = Math.round(g * 255); out[2] = Math.round(b * 255); return out; }; static fromJson = (json, out = new ColorRGB()) => { out[0] = json.r; out[1] = json.g; out[2] = json.b; return out; }; static fromScalar = (scalar, out = new ColorRGB()) => { out[0] = scalar; out[1] = scalar; out[2] = scalar; return out; }; static fromString = (str, out = new ColorRGB()) => { if (str in COLOR_HEX_MAP) { return ColorRGB.fromHex(COLOR_HEX_MAP[str], out); } else if (str.startsWith("#")) { str = str.substring(1); return ColorRGB.fromScalar(parseInt(str, 16), out); } else if (str.startsWith("rgb(")) { str = str.substring(4, str.length - 1); const arr = str.split(","); out[0] = parseInt(arr[0], 10); out[1] = parseInt(arr[1], 10); out[2] = parseInt(arr[2], 10); } return out; }; static grayscale = (color, wr = WEIGHT_GRAY_RED, wg = WEIGHT_GRAY_GREEN, wb = WEIGHT_GRAY_BLUE, out = new ColorRGB()) => { const gray = ColorRGB.averageWeighted(color, wr, wg, wb); ColorRGB.fromScalar(gray, out); return out; }; dataType = ArraybufferDataType.COLOR_RGB; constructor(r = 0, g = 0, b = 0) { super(3); this[0] = r; this[1] = g; this[2] = b; } get r() { return this[0]; } set r(val) { this[0] = val; } get g() { return this[1]; } set g(val) { this[1] = val; } get b() { return this[2]; } set b(val) { this[2] = val; } } class ColorRGBA extends Uint8Array { static average = (color) => { return (color[0] + color[1] + color[2]) / 3; }; static averageWeighted = (color, wr = WEIGHT_GRAY_RED, wg = WEIGHT_GRAY_GREEN, wb = WEIGHT_GRAY_BLUE) => { return color[0] * wr + color[1] * wg + color[2] * wb; }; static clone = (color) => { return new ColorRGBA(color[0], color[1], color[2], color[3]); }; static create = (r = 0, g = 0, b = 0, a = 1) => { return new ColorRGBA(r, g, b, a); }; static equals = (a, b) => { return ((a.r ?? a[0]) === (b.r ?? b[0]) && (a.g ?? a[1]) === (b.g ?? b[1]) && (a.b ?? a[2]) === (b.b ?? b[2]) && (a.a ?? a[3]) === (b.a ?? b[3])); }; static fromArray = (arr, out = new ColorRGBA()) => { out[0] = arr[0]; out[1] = arr[1]; out[2] = arr[2]; out[3] = arr[3]; return out; }; static fromColorRYB = (color, out = new ColorRGBA()) => { let r = color[0]; let y = color[1]; let b = color[2]; // Remove the whiteness from the color. let w = Math.min(r, y, b); r -= w; y -= w; b -= w; let my = Math.max(r, y, b); // Get the green out of the yellow and blue let g = Math.min(y, b); y -= g; b -= g; if (b && g) { b *= 2.0; g *= 2.0; } // Redistribute the remaining yellow. r += y; g += y; // Normalize to values. let mg = Math.max(r, g, b); if (mg) { let n = my / mg; r *= n; g *= n; b *= n; } // Add the white back in. r += w; g += w; b += w; out[0] = r; out[1] = g; out[2] = b; out[3] = 1; return out; }; static fromHex = (hex, alpha = 255, out = new ColorRGBA()) => { out[0] = hex >> 16; out[1] = (hex >> 8) & 255; out[2] = hex & 255; out[3] = alpha; return out; }; static fromHSL = (h, s, l, out = new ColorRGBA()) => { let r; let g; let b; if (s === 0) { r = g = b = l; // achromatic } else { let q = l < 0.5 ? l * (1 + s) : l + s - l * s; let p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } out[0] = Math.round(r * 255); out[1] = Math.round(g * 255); out[2] = Math.round(b * 255); out[3] = 255; return out; }; static fromJson = (json, out = new ColorRGBA()) => { out[0] = json.r; out[1] = json.g; out[2] = json.b; out[3] = json.a; return out; }; static fromScalar = (scalar, alpha = 255, out = new ColorRGBA()) => { out[0] = scalar; out[1] = scalar; out[2] = scalar; out[3] = alpha; return out; }; static fromString = (str, out = new ColorRGBA()) => { if (str in COLOR_HEX_MAP) { return ColorRGBA.fromHex(COLOR_HEX_MAP[str], 255, out); } else if (str.startsWith("#")) { str = str.substring(1); return ColorRGBA.fromScalar(parseInt(str, 16), 255, out); } else if (str.startsWith("rgba(")) { str = str.substring(4, str.length - 1); const arr = str.split(","); out[0] = parseInt(arr[0], 10); out[1] = parseInt(arr[1], 10); out[2] = parseInt(arr[2], 10); out[3] = parseInt(arr[3], 10); } return out; }; static grayscale = (color, wr =