UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

2,036 lines (2,010 loc) 3.61 MB
/** * @license * PlayCanvas Engine v2.19.1 revision 9069deb (PROFILE) * Copyright 2011-2026 PlayCanvas Ltd. All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x2, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x2)(function(x2) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x2 + '" is not supported'); }); var TRACEID_RENDER_FRAME = "RenderFrame"; var TRACEID_RENDER_FRAME_TIME = "RenderFrameTime"; var TRACEID_RENDER_PASS = "RenderPass"; var TRACEID_RENDER_PASS_DETAIL = "RenderPassDetail"; var TRACEID_RENDER_ACTION = "RenderAction"; var TRACEID_RENDER_TARGET_ALLOC = "RenderTargetAlloc"; var TRACEID_TEXTURE_ALLOC = "TextureAlloc"; var TRACEID_SHADER_ALLOC = "ShaderAlloc"; var TRACEID_SHADER_COMPILE = "ShaderCompile"; var TRACEID_VRAM_TEXTURE = "VRAM.Texture"; var TRACEID_VRAM_VB = "VRAM.Vb"; var TRACEID_VRAM_IB = "VRAM.Ib"; var TRACEID_VRAM_SB = "VRAM.Sb"; var TRACEID_BINDGROUP_ALLOC = "BindGroupAlloc"; var TRACEID_BINDGROUPFORMAT_ALLOC = "BindGroupFormatAlloc"; var TRACEID_RENDERPIPELINE_ALLOC = "RenderPipelineAlloc"; var TRACEID_COMPUTEPIPELINE_ALLOC = "ComputePipelineAlloc"; var TRACEID_PIPELINELAYOUT_ALLOC = "PipelineLayoutAlloc"; var TRACEID_ELEMENT = "Element"; var TRACEID_TEXTURES = "Textures"; var TRACEID_BUFFERS = "Buffers"; var TRACEID_ASSETS = "Assets"; var TRACEID_RENDER_QUEUE = "RenderQueue"; var TRACEID_OCTREE_RESOURCES = "OctreeResources"; var TRACEID_GPU_TIMINGS = "GpuTimings"; var version = "2.19.1"; var revision = "9069deb"; function extend(target2, ex) { for (const prop in ex) { const copy = ex[prop]; if (Array.isArray(copy)) { target2[prop] = extend([], copy); } else if (copy && typeof copy === "object") { target2[prop] = extend({}, copy); } else { target2[prop] = copy; } } return target2; } var guid = { create() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c2) => { const r = Math.random() * 16 | 0; const v6 = c2 === "x" ? r : r & 3 | 8; return v6.toString(16); }); } }; var path = { delimiter: "/", join(...sections) { let result = sections[0]; for (let i = 0; i < sections.length - 1; i++) { const one = sections[i]; const two = sections[i + 1]; if (two[0] === path.delimiter) { result = two; continue; } if (one && two && one[one.length - 1] !== path.delimiter && two[0] !== path.delimiter) { result += path.delimiter + two; } else { result += two; } } return result; }, normalize(pathname) { const lead = pathname.startsWith(path.delimiter); const trail = pathname.endsWith(path.delimiter); const parts = pathname.split("/"); let result = ""; let cleaned = []; for (let i = 0; i < parts.length; i++) { if (parts[i] === "") continue; if (parts[i] === ".") continue; if (parts[i] === ".." && cleaned.length > 0) { cleaned = cleaned.slice(0, cleaned.length - 2); continue; } if (i > 0) cleaned.push(path.delimiter); cleaned.push(parts[i]); } result = cleaned.join(""); if (!lead && result[0] === path.delimiter) { result = result.slice(1); } if (trail && result[result.length - 1] !== path.delimiter) { result += path.delimiter; } return result; }, split(pathname) { const lastDelimiterIndex = pathname.lastIndexOf(path.delimiter); if (lastDelimiterIndex !== -1) { return [pathname.substring(0, lastDelimiterIndex), pathname.substring(lastDelimiterIndex + 1)]; } return ["", pathname]; }, getBasename(pathname) { return path.split(pathname)[1]; }, getDirectory(pathname) { return path.split(pathname)[0]; }, getExtension(pathname) { const ext = pathname.split("?")[0].split(".").pop(); if (ext !== pathname) { return `.${ext}`; } return ""; }, isRelativePath(pathname) { return pathname.charAt(0) !== "/" && pathname.match(/:\/\//) === null; }, extractPath(pathname) { let result = ""; const parts = pathname.split("/"); let i = 0; if (parts.length > 1) { if (path.isRelativePath(pathname)) { if (parts[0] === ".") { for (i = 0; i < parts.length - 1; ++i) { result += i === 0 ? parts[i] : `/${parts[i]}`; } } else if (parts[0] === "..") { for (i = 0; i < parts.length - 1; ++i) { result += i === 0 ? parts[i] : `/${parts[i]}`; } } else { result = "."; for (i = 0; i < parts.length - 1; ++i) { result += `/${parts[i]}`; } } } else { for (i = 0; i < parts.length - 1; ++i) { result += i === 0 ? parts[i] : `/${parts[i]}`; } } } return result; } }; var detectPassiveEvents = () => { let result = false; try { const opts = Object.defineProperty({}, "passive", { get: function() { result = true; return false; } }); window.addEventListener("testpassive", null, opts); window.removeEventListener("testpassive", null, opts); } catch (e) { } return result; }; var ua = typeof navigator !== "undefined" ? navigator.userAgent : ""; var environment = typeof window !== "undefined" ? "browser" : typeof global !== "undefined" ? "node" : "worker"; var platformName = /android/i.test(ua) ? "android" : /ip(?:[ao]d|hone)/i.test(ua) ? "ios" : /windows/i.test(ua) ? "windows" : /mac os/i.test(ua) ? "osx" : /linux/i.test(ua) ? "linux" : /cros/i.test(ua) ? "cros" : null; var browserName = environment !== "browser" ? null : /Chrome\/|Chromium\/|Edg.*\//.test(ua) ? "chrome" : ( // chrome, chromium, edge /Safari\//.test(ua) ? "safari" : ( // safari, ios chrome/firefox /Firefox\//.test(ua) ? "firefox" : "other" ) ); var xbox = /xbox/i.test(ua); var visionos = /Macintosh/i.test(ua) && typeof navigator !== "undefined" && navigator.maxTouchPoints > 0 && !/iPhone|iPad|iPod/i.test(ua); var touch = environment === "browser" && ("ontouchstart" in window || "maxTouchPoints" in navigator && navigator.maxTouchPoints > 0); var gamepads = environment === "browser" && (!!navigator.getGamepads || !!navigator.webkitGetGamepads); var workers = typeof Worker !== "undefined"; var passiveEvents = detectPassiveEvents(); var platform = { name: platformName, environment, global: (typeof globalThis !== "undefined" && globalThis) ?? (environment === "browser" && window) ?? (environment === "node" && global) ?? (environment === "worker" && self), browser: environment === "browser", worker: environment === "worker", desktop: ["windows", "osx", "linux", "cros"].includes(platformName), mobile: ["android", "ios"].includes(platformName), ios: platformName === "ios", android: platformName === "android", visionos, xbox, gamepads, touch, workers, passiveEvents, browserName }; var ASCII_LOWERCASE = "abcdefghijklmnopqrstuvwxyz"; var ASCII_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var ASCII_LETTERS = ASCII_LOWERCASE + ASCII_UPPERCASE; var HIGH_SURROGATE_BEGIN = 55296; var HIGH_SURROGATE_END = 56319; var LOW_SURROGATE_BEGIN = 56320; var LOW_SURROGATE_END = 57343; var ZERO_WIDTH_JOINER = 8205; var REGIONAL_INDICATOR_BEGIN = 127462; var REGIONAL_INDICATOR_END = 127487; var FITZPATRICK_MODIFIER_BEGIN = 127995; var FITZPATRICK_MODIFIER_END = 127999; var DIACRITICAL_MARKS_BEGIN = 8400; var DIACRITICAL_MARKS_END = 8447; var VARIATION_MODIFIER_BEGIN = 65024; var VARIATION_MODIFIER_END = 65039; function getCodePointData(string2, i = 0) { const size = string2.length; if (i < 0 || i >= size) { return null; } const first = string2.charCodeAt(i); if (size > 1 && first >= HIGH_SURROGATE_BEGIN && first <= HIGH_SURROGATE_END) { const second = string2.charCodeAt(i + 1); if (second >= LOW_SURROGATE_BEGIN && second <= LOW_SURROGATE_END) { return { code: (first - HIGH_SURROGATE_BEGIN) * 1024 + second - LOW_SURROGATE_BEGIN + 65536, long: true }; } } return { code: first, long: false }; } function isCodeBetween(string2, begin, end) { if (!string2) { return false; } const codeData = getCodePointData(string2); if (codeData) { const code = codeData.code; return code >= begin && code <= end; } return false; } function numCharsToTakeForNextSymbol(string2, index) { if (index === string2.length - 1) { return 1; } if (isCodeBetween(string2[index], HIGH_SURROGATE_BEGIN, HIGH_SURROGATE_END)) { const first = string2.substring(index, index + 2); const second = string2.substring(index + 2, index + 4); if (isCodeBetween(second, FITZPATRICK_MODIFIER_BEGIN, FITZPATRICK_MODIFIER_END) || isCodeBetween(first, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END) && isCodeBetween(second, REGIONAL_INDICATOR_BEGIN, REGIONAL_INDICATOR_END)) { return 4; } if (isCodeBetween(second, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 3; } return 2; } if (isCodeBetween(string2[index + 1], VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { return 2; } return 1; } var string = { ASCII_LOWERCASE, ASCII_UPPERCASE, ASCII_LETTERS, format(s2, ...args) { for (let i = 0; i < args.length; i++) { s2 = s2.replace(`{${i}}`, args[i]); } return s2; }, getCodePoint(string2, i) { const codePointData = getCodePointData(string2, i); return codePointData && codePointData.code; }, getCodePoints(string2) { if (typeof string2 !== "string") { throw new TypeError("Not a string"); } let i = 0; const arr = []; let codePoint; while (!!(codePoint = getCodePointData(string2, i))) { arr.push(codePoint.code); i += codePoint.long ? 2 : 1; } return arr; }, getSymbols(string2) { if (typeof string2 !== "string") { throw new TypeError("Not a string"); } let index = 0; const length = string2.length; const output = []; let take = 0; let ch; while (index < length) { take += numCharsToTakeForNextSymbol(string2, index + take); ch = string2[index + take]; if (isCodeBetween(ch, DIACRITICAL_MARKS_BEGIN, DIACRITICAL_MARKS_END)) { ch = string2[index + take++]; } if (isCodeBetween(ch, VARIATION_MODIFIER_BEGIN, VARIATION_MODIFIER_END)) { ch = string2[index + take++]; } if (ch && ch.charCodeAt(0) === ZERO_WIDTH_JOINER) { ch = string2[index + take++]; continue; } const char = string2.substring(index, index + take); output.push(char); index += take; take = 0; } return output; }, fromCodePoint(...args) { return args.map((codePoint) => { if (codePoint > 65535) { codePoint -= 65536; return String.fromCharCode( (codePoint >> 10) + 55296, codePoint % 1024 + 56320 ); } return String.fromCharCode(codePoint); }).join(""); } }; var Tracing = class _Tracing { static _traceChannels = /* @__PURE__ */ new Set(); static stack = false; static set(channel, enabled = true) { } static get(channel) { return _Tracing._traceChannels.has(channel); } }; var EventHandle = class { handler; name; callback; scope; _once; _removed = false; constructor(handler, name, callback, scope, once = false) { this.handler = handler; this.name = name; this.callback = callback; this.scope = scope; this._once = once; } off() { if (this._removed) return; this.handler.offByHandle(this); } on(name, callback, scope = this) { return this.handler._addCallback(name, callback, scope, false); } once(name, callback, scope = this) { return this.handler._addCallback(name, callback, scope, true); } set removed(value) { if (!value) return; this._removed = true; } get removed() { return this._removed; } // don't stringify EventHandle to JSON by JSON.stringify toJSON(key) { return void 0; } }; var EventHandler = class { _callbacks = /* @__PURE__ */ new Map(); _callbackActive = /* @__PURE__ */ new Map(); initEventHandler() { this._callbacks = /* @__PURE__ */ new Map(); this._callbackActive = /* @__PURE__ */ new Map(); } _addCallback(name, callback, scope, once) { if (!this._callbacks.has(name)) { this._callbacks.set(name, []); } if (this._callbackActive.has(name)) { const callbackActive = this._callbackActive.get(name); if (callbackActive && callbackActive === this._callbacks.get(name)) { this._callbackActive.set(name, callbackActive.slice()); } } const evt = new EventHandle(this, name, callback, scope, once); this._callbacks.get(name).push(evt); return evt; } on(name, callback, scope = this) { return this._addCallback(name, callback, scope, false); } once(name, callback, scope = this) { return this._addCallback(name, callback, scope, true); } off(name, callback, scope) { if (name) { if (this._callbackActive.has(name) && this._callbackActive.get(name) === this._callbacks.get(name)) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } } else { for (const [key, callbacks] of this._callbackActive) { if (!this._callbacks.has(key)) { continue; } if (this._callbacks.get(key) !== callbacks) { continue; } this._callbackActive.set(key, callbacks.slice()); } } if (!name) { for (const callbacks of this._callbacks.values()) { for (let i = 0; i < callbacks.length; i++) { callbacks[i].removed = true; } } this._callbacks.clear(); } else if (!callback) { const callbacks = this._callbacks.get(name); if (callbacks) { for (let i = 0; i < callbacks.length; i++) { callbacks[i].removed = true; } this._callbacks.delete(name); } } else { const callbacks = this._callbacks.get(name); if (!callbacks) { return this; } for (let i = 0; i < callbacks.length; i++) { if (callbacks[i].callback !== callback) { continue; } if (scope && callbacks[i].scope !== scope) { continue; } callbacks[i].removed = true; callbacks.splice(i, 1); i--; } if (callbacks.length === 0) { this._callbacks.delete(name); } } return this; } offByHandle(handle) { const name = handle.name; handle.removed = true; if (this._callbackActive.has(name) && this._callbackActive.get(name) === this._callbacks.get(name)) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } const callbacks = this._callbacks.get(name); if (!callbacks) { return this; } const ind = callbacks.indexOf(handle); if (ind !== -1) { callbacks.splice(ind, 1); if (callbacks.length === 0) { this._callbacks.delete(name); } } return this; } fire(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) { if (!name) { return this; } const callbacksInitial = this._callbacks.get(name); if (!callbacksInitial) { return this; } let callbacks; if (!this._callbackActive.has(name)) { this._callbackActive.set(name, callbacksInitial); } else if (this._callbackActive.get(name) !== callbacksInitial) { callbacks = callbacksInitial.slice(); } for (let i = 0; (callbacks || this._callbackActive.get(name)) && i < (callbacks || this._callbackActive.get(name)).length; i++) { const evt = (callbacks || this._callbackActive.get(name))[i]; if (!evt.callback) continue; evt.callback.call(evt.scope, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); if (evt._once) { const existingCallback = this._callbacks.get(name); const ind = existingCallback ? existingCallback.indexOf(evt) : -1; if (ind !== -1) { if (this._callbackActive.get(name) === existingCallback) { this._callbackActive.set(name, this._callbackActive.get(name).slice()); } const callbacks2 = this._callbacks.get(name); if (!callbacks2) continue; callbacks2[ind].removed = true; callbacks2.splice(ind, 1); if (callbacks2.length === 0) { this._callbacks.delete(name); } } } } if (!callbacks) { this._callbackActive.delete(name); } return this; } hasEvent(name) { return !!this._callbacks.get(name)?.length; } }; var IndexedList = class { _list = []; _index = {}; push(key, item) { if (this._index[key]) { throw Error(`Key already in index ${key}`); } const location = this._list.push(item) - 1; this._index[key] = location; } has(key) { return this._index[key] !== void 0; } get(key) { const location = this._index[key]; if (location !== void 0) { return this._list[location]; } return null; } remove(key) { const location = this._index[key]; if (location !== void 0) { this._list.splice(location, 1); delete this._index[key]; for (key in this._index) { const idx = this._index[key]; if (idx > location) { this._index[key] = idx - 1; } } return true; } return false; } list() { return this._list; } clear() { this._list.length = 0; for (const prop in this._index) { delete this._index[prop]; } } }; var cachedResult = (func) => { const uninitToken = {}; let result = uninitToken; return () => { if (result === uninitToken) { result = func(); } return result; }; }; var Impl = class _Impl { static modules = {}; // returns true if the running host supports wasm modules (all browsers except IE) static wasmSupported = cachedResult(() => { try { if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { const module = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0)); if (module instanceof WebAssembly.Module) { return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; } } } catch (e) { } return false; }); // load a script static loadScript(url, callback) { const s2 = document.createElement("script"); s2.setAttribute("src", url); s2.onload = () => { callback(null); }; s2.onerror = () => { callback(`Failed to load script='${url}'`); }; document.body.appendChild(s2); } // load a wasm module static loadWasm(moduleName, config, callback) { const loadUrl = _Impl.wasmSupported() && config.glueUrl && config.wasmUrl ? config.glueUrl : config.fallbackUrl; if (loadUrl) { _Impl.loadScript(loadUrl, (err2) => { if (err2) { callback(err2, null); } else { const module = window[moduleName]; window[moduleName] = void 0; module({ locateFile: () => config.wasmUrl, onAbort: () => { callback("wasm module aborted."); } }).then((instance) => { callback(null, instance); }); } }); } else { callback("No supported wasm modules found.", null); } } // get state object for the named module static getModule(name) { if (!_Impl.modules.hasOwnProperty(name)) { _Impl.modules[name] = { config: null, initializing: false, instance: null, callbacks: [] }; } return _Impl.modules[name]; } static initialize(moduleName, module) { if (module.initializing) { return; } const config = module.config; if (config.glueUrl || config.wasmUrl || config.fallbackUrl) { module.initializing = true; _Impl.loadWasm(moduleName, config, (err2, instance) => { if (err2) { if (config.errorHandler) { config.errorHandler(err2); } else { console.error(`failed to initialize module=${moduleName} error=${err2}`); } } else { module.instance = instance; module.callbacks.forEach((callback) => { callback(instance); }); } }); } } }; var WasmModule = class { static setConfig(moduleName, config) { const module = Impl.getModule(moduleName); module.config = config; if (module.callbacks.length > 0) { Impl.initialize(moduleName, module); } } static getConfig(moduleName) { return Impl.modules?.[moduleName]?.config; } static getInstance(moduleName, callback) { const module = Impl.getModule(moduleName); if (module.instance) { callback(module.instance); } else { module.callbacks.push(callback); if (module.config) { Impl.initialize(moduleName, module); } } } }; var ReadStream = class { arraybuffer; dataView; offset = 0; constructor(arraybuffer) { this.arraybuffer = arraybuffer; this.dataView = new DataView(arraybuffer); } get remainingBytes() { return this.dataView.byteLength - this.offset; } reset(offset3 = 0) { this.offset = offset3; } skip(bytes) { this.offset += bytes; } align(bytes) { this.offset = this.offset + bytes - 1 & ~(bytes - 1); } _inc(amount) { this.offset += amount; return this.offset - amount; } readChar() { return String.fromCharCode(this.dataView.getUint8(this.offset++)); } readChars(numChars) { let result = ""; for (let i = 0; i < numChars; ++i) { result += this.readChar(); } return result; } readU8() { return this.dataView.getUint8(this.offset++); } readU16() { return this.dataView.getUint16(this._inc(2), true); } readU32() { return this.dataView.getUint32(this._inc(4), true); } readU64() { return this.readU32() + 2 ** 32 * this.readU32(); } readU32be() { return this.dataView.getUint32(this._inc(4), false); } readArray(result) { for (let i = 0; i < result.length; ++i) { result[i] = this.readU8(); } } readLine() { const view = this.dataView; let result = ""; while (true) { if (this.offset >= view.byteLength) { break; } const c2 = String.fromCharCode(this.readU8()); if (c2 === "\n") { break; } result += c2; } return result; } }; var SortedLoopArray = class { items = []; length = 0; loopIndex = -1; _sortBy; _sortHandler; constructor(args) { this._sortBy = args.sortBy; this._sortHandler = this._doSort.bind(this); } _binarySearch(item) { let left = 0; let right2 = this.items.length - 1; const search = item[this._sortBy]; let middle; let current; while (left <= right2) { middle = Math.floor((left + right2) / 2); current = this.items[middle][this._sortBy]; if (current <= search) { left = middle + 1; } else if (current > search) { right2 = middle - 1; } } return left; } _doSort(a, b) { const sortBy = this._sortBy; return a[sortBy] - b[sortBy]; } insert(item) { const index = this._binarySearch(item); this.items.splice(index, 0, item); this.length++; if (this.loopIndex >= index) { this.loopIndex++; } } append(item) { this.items.push(item); this.length++; } remove(item) { const idx = this.items.indexOf(item); if (idx < 0) return; this.items.splice(idx, 1); this.length--; if (this.loopIndex >= idx) { this.loopIndex--; } } sort() { const current = this.loopIndex >= 0 ? this.items[this.loopIndex] : null; this.items.sort(this._sortHandler); if (current !== null) { this.loopIndex = this.items.indexOf(current); } } }; var Tags = class extends EventHandler { static EVENT_ADD = "add"; static EVENT_REMOVE = "remove"; static EVENT_CHANGE = "change"; _index = {}; _list = []; _parent; constructor(parent) { super(); this._parent = parent; } add(...args) { let changed = false; const tags = this._processArguments(args, true); if (!tags.length) { return changed; } for (let i = 0; i < tags.length; i++) { if (this._index[tags[i]]) { continue; } changed = true; this._index[tags[i]] = true; this._list.push(tags[i]); this.fire("add", tags[i], this._parent); } if (changed) { this.fire("change", this._parent); } return changed; } remove(...args) { let changed = false; if (!this._list.length) { return changed; } const tags = this._processArguments(args, true); if (!tags.length) { return changed; } for (let i = 0; i < tags.length; i++) { if (!this._index[tags[i]]) { continue; } changed = true; delete this._index[tags[i]]; this._list.splice(this._list.indexOf(tags[i]), 1); this.fire("remove", tags[i], this._parent); } if (changed) { this.fire("change", this._parent); } return changed; } clear() { if (!this._list.length) { return; } const tags = this._list.slice(0); this._list = []; this._index = {}; for (let i = 0; i < tags.length; i++) { this.fire("remove", tags[i], this._parent); } this.fire("change", this._parent); } has(...query) { if (!this._list.length) { return false; } return this._has(this._processArguments(query)); } _has(tags) { if (!this._list.length || !tags.length) { return false; } for (let i = 0; i < tags.length; i++) { if (tags[i].length === 1) { if (this._index[tags[i][0]]) { return true; } } else { let multiple = true; for (let t = 0; t < tags[i].length; t++) { if (this._index[tags[i][t]]) { continue; } multiple = false; break; } if (multiple) { return true; } } } return false; } list() { return this._list.slice(0); } _processArguments(args, flat) { const tags = []; let tmp = []; if (!args || !args.length) { return tags; } for (let i = 0; i < args.length; i++) { if (args[i] instanceof Array) { if (!flat) { tmp = []; } for (let t = 0; t < args[i].length; t++) { if (typeof args[i][t] !== "string") { continue; } if (flat) { tags.push(args[i][t]); } else { tmp.push(args[i][t]); } } if (!flat && tmp.length) { tags.push(tmp); } } else if (typeof args[i] === "string") { if (flat) { tags.push(args[i]); } else { tags.push([args[i]]); } } } return tags; } get size() { return this._list.length; } }; var now = typeof window !== "undefined" && window.performance && window.performance.now ? performance.now.bind(performance) : Date.now; function createURI(options2) { let s2 = ""; if ((options2.authority || options2.scheme) && (options2.host || options2.hostpath)) { throw new Error("Can't have 'scheme' or 'authority' and 'host' or 'hostpath' option"); } if (options2.host && options2.hostpath) { throw new Error("Can't have 'host' and 'hostpath' option"); } if (options2.path && options2.hostpath) { throw new Error("Can't have 'path' and 'hostpath' option"); } if (options2.scheme) { s2 += `${options2.scheme}:`; } if (options2.authority) { s2 += `//${options2.authority}`; } if (options2.host) { s2 += options2.host; } if (options2.path) { s2 += options2.path; } if (options2.hostpath) { s2 += options2.hostpath; } if (options2.query) { s2 += `?${options2.query}`; } if (options2.fragment) { s2 += `#${options2.fragment}`; } return s2; } var re = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; var URI = class { scheme; authority; path; query; fragment; constructor(uri) { const result = uri.match(re); this.scheme = result[2]; this.authority = result[4]; this.path = result[5]; this.query = result[7]; this.fragment = result[9]; } toString() { let s2 = ""; if (this.scheme) { s2 += `${this.scheme}:`; } if (this.authority) { s2 += `//${this.authority}`; } s2 += this.path; if (this.query) { s2 += `?${this.query}`; } if (this.fragment) { s2 += `#${this.fragment}`; } return s2; } getQuery() { const result = {}; if (this.query) { const queryParams = decodeURIComponent(this.query).split("&"); for (const queryParam of queryParams) { const pair = queryParam.split("="); result[pair[0]] = pair[1]; } } return result; } setQuery(params) { let q5 = ""; for (const key in params) { if (params.hasOwnProperty(key)) { if (q5 !== "") { q5 += "&"; } q5 += `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`; } } this.query = q5; } }; var CURVE_LINEAR = 0; var CURVE_SMOOTHSTEP = 1; var CURVE_SPLINE = 4; var CURVE_STEP = 5; var math = { DEG_TO_RAD: Math.PI / 180, RAD_TO_DEG: 180 / Math.PI, clamp(value, min, max) { if (value >= max) return max; if (value <= min) return min; return value; }, intToBytes24(i) { const r = i >> 16 & 255; const g = i >> 8 & 255; const b = i & 255; return [r, g, b]; }, intToBytes32(i) { const r = i >> 24 & 255; const g = i >> 16 & 255; const b = i >> 8 & 255; const a = i & 255; return [r, g, b, a]; }, bytesToInt24(r, g, b) { if (r.length) { b = r[2]; g = r[1]; r = r[0]; } return r << 16 | g << 8 | b; }, bytesToInt32(r, g, b, a) { if (r.length) { a = r[3]; b = r[2]; g = r[1]; r = r[0]; } return (r << 24 | g << 16 | b << 8 | a) >>> 0; }, lerp(a, b, alpha) { return a + (b - a) * math.clamp(alpha, 0, 1); }, lerpAngle(a, b, alpha) { if (b - a > 180) { b -= 360; } if (b - a < -180) { b += 360; } return math.lerp(a, b, math.clamp(alpha, 0, 1)); }, powerOfTwo(x2) { return x2 !== 0 && !(x2 & x2 - 1); }, nextPowerOfTwo(val) { val--; val |= val >> 1; val |= val >> 2; val |= val >> 4; val |= val >> 8; val |= val >> 16; val++; return val; }, nearestPowerOfTwo(val) { return Math.pow(2, Math.round(Math.log2(val))); }, random(min, max) { const diff = max - min; return Math.random() * diff + min; }, smoothstep(min, max, x2) { if (x2 <= min) return 0; if (x2 >= max) return 1; x2 = (x2 - min) / (max - min); return x2 * x2 * (3 - 2 * x2); }, smootherstep(min, max, x2) { if (x2 <= min) return 0; if (x2 >= max) return 1; x2 = (x2 - min) / (max - min); return x2 * x2 * x2 * (x2 * (x2 * 6 - 15) + 10); }, roundUp(numToRound, multiple) { if (multiple === 0) { return numToRound; } return Math.ceil(numToRound / multiple) * multiple; }, between(num, a, b, inclusive) { const min = Math.min(a, b); const max = Math.max(a, b); return inclusive ? num >= min && num <= max : num > min && num < max; } }; var Color = class _Color { r; g; b; a; constructor(r = 0, g = 0, b = 0, a = 1) { const length = r.length; if (length === 3 || length === 4) { this.r = r[0]; this.g = r[1]; this.b = r[2]; this.a = r[3] ?? 1; } else { this.r = r; this.g = g; this.b = b; this.a = a; } } clone() { const cstr = this.constructor; return new cstr(this.r, this.g, this.b, this.a); } copy(rhs) { this.r = rhs.r; this.g = rhs.g; this.b = rhs.b; this.a = rhs.a; return this; } equals(rhs) { return this.r === rhs.r && this.g === rhs.g && this.b === rhs.b && this.a === rhs.a; } set(r, g, b, a = 1) { this.r = r; this.g = g; this.b = b; this.a = a; return this; } lerp(lhs, rhs, alpha) { this.r = lhs.r + alpha * (rhs.r - lhs.r); this.g = lhs.g + alpha * (rhs.g - lhs.g); this.b = lhs.b + alpha * (rhs.b - lhs.b); this.a = lhs.a + alpha * (rhs.a - lhs.a); return this; } linear(src = this) { this.r = Math.pow(src.r, 2.2); this.g = Math.pow(src.g, 2.2); this.b = Math.pow(src.b, 2.2); this.a = src.a; return this; } gamma(src = this) { this.r = Math.pow(src.r, 1 / 2.2); this.g = Math.pow(src.g, 1 / 2.2); this.b = Math.pow(src.b, 1 / 2.2); this.a = src.a; return this; } mulScalar(scalar) { this.r *= scalar; this.g *= scalar; this.b *= scalar; return this; } fromString(hex) { const i = parseInt(hex.replace("#", "0x"), 16); let bytes; if (hex.length > 7) { bytes = math.intToBytes32(i); } else { bytes = math.intToBytes24(i); bytes[3] = 255; } this.set(bytes[0] / 255, bytes[1] / 255, bytes[2] / 255, bytes[3] / 255); return this; } fromArray(arr, offset3 = 0) { this.r = arr[offset3] ?? this.r; this.g = arr[offset3 + 1] ?? this.g; this.b = arr[offset3 + 2] ?? this.b; this.a = arr[offset3 + 3] ?? this.a; return this; } toString(alpha, asArray) { const { r, g, b, a } = this; if (asArray || r > 1 || g > 1 || b > 1) { return `${r.toFixed(3)}, ${g.toFixed(3)}, ${b.toFixed(3)}, ${a.toFixed(3)}`; } let s2 = `#${((1 << 24) + (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255)).toString(16).slice(1)}`; if (alpha === true) { const aa = Math.round(a * 255).toString(16); if (this.a < 16 / 255) { s2 += `0${aa}`; } else { s2 += aa; } } return s2; } toArray(arr = [], offset3 = 0, alpha = true) { arr[offset3] = this.r; arr[offset3 + 1] = this.g; arr[offset3 + 2] = this.b; if (alpha) { arr[offset3 + 3] = this.a; } return arr; } static BLACK = Object.freeze(new _Color(0, 0, 0, 1)); static BLUE = Object.freeze(new _Color(0, 0, 1, 1)); static CYAN = Object.freeze(new _Color(0, 1, 1, 1)); static GRAY = Object.freeze(new _Color(0.5, 0.5, 0.5, 1)); static GREEN = Object.freeze(new _Color(0, 1, 0, 1)); static MAGENTA = Object.freeze(new _Color(1, 0, 1, 1)); static RED = Object.freeze(new _Color(1, 0, 0, 1)); static WHITE = Object.freeze(new _Color(1, 1, 1, 1)); static YELLOW = Object.freeze(new _Color(1, 1, 0, 1)); }; var CurveEvaluator = class { _curve; _left = -Infinity; _right = Infinity; _recip = 0; _p0 = 0; _p1 = 0; _m0 = 0; _m1 = 0; constructor(curve, time = 0) { this._curve = curve; this._reset(time); } evaluate(time, forceReset = false) { if (forceReset || time < this._left || time >= this._right) { this._reset(time); } let result; const type = this._curve.type; if (type === CURVE_STEP) { result = this._p0; } else { const t = this._recip === 0 ? 0 : (time - this._left) * this._recip; if (type === CURVE_LINEAR) { result = math.lerp(this._p0, this._p1, t); } else if (type === CURVE_SMOOTHSTEP) { result = math.lerp(this._p0, this._p1, t * t * (3 - 2 * t)); } else { result = this._evaluateHermite(this._p0, this._p1, this._m0, this._m1, t); } } return result; } _reset(time) { const keys = this._curve.keys; const len = keys.length; if (!len) { this._left = -Infinity; this._right = Infinity; this._recip = 0; this._p0 = this._p1 = this._m0 = this._m1 = 0; } else { if (time < keys[0][0]) { this._left = -Infinity; this._right = keys[0][0]; this._recip = 0; this._p0 = this._p1 = keys[0][1]; this._m0 = this._m1 = 0; } else if (time >= keys[len - 1][0]) { this._left = keys[len - 1][0]; this._right = Infinity; this._recip = 0; this._p0 = this._p1 = keys[len - 1][1]; this._m0 = this._m1 = 0; } else { let index = 0; while (time >= keys[index + 1][0]) { index++; } this._left = keys[index][0]; this._right = keys[index + 1][0]; const diff = 1 / (this._right - this._left); this._recip = isFinite(diff) ? diff : 0; this._p0 = keys[index][1]; this._p1 = keys[index + 1][1]; if (this._curve.type === CURVE_SPLINE) { this._calcTangents(keys, index); } } } } _calcTangents(keys, index) { let a; const b = keys[index]; const c2 = keys[index + 1]; let d; if (index === 0) { a = [ keys[0][0] + (keys[0][0] - keys[1][0]), keys[0][1] + (keys[0][1] - keys[1][1]) ]; } else { a = keys[index - 1]; } if (index === keys.length - 2) { d = [ keys[index + 1][0] + (keys[index + 1][0] - keys[index][0]), keys[index + 1][1] + (keys[index + 1][1] - keys[index][1]) ]; } else { d = keys[index + 2]; } if (this._curve.type === CURVE_SPLINE) { const s1_ = 2 * (c2[0] - b[0]) / (c2[0] - a[0]); const s2_ = 2 * (c2[0] - b[0]) / (d[0] - b[0]); this._m0 = this._curve.tension * (isFinite(s1_) ? s1_ : 0) * (c2[1] - a[1]); this._m1 = this._curve.tension * (isFinite(s2_) ? s2_ : 0) * (d[1] - b[1]); } else { const s1 = (c2[0] - b[0]) / (b[0] - a[0]); const s2 = (c2[0] - b[0]) / (d[0] - c2[0]); const a_ = b[1] + (a[1] - b[1]) * (isFinite(s1) ? s1 : 0); const d_ = c2[1] + (d[1] - c2[1]) * (isFinite(s2) ? s2 : 0); const tension = this._curve.tension; this._m0 = tension * (c2[1] - a_); this._m1 = tension * (d_ - b[1]); } } _evaluateHermite(p0, p12, m0, m12, t) { const t2 = t * t; const twot = t + t; const omt = 1 - t; const omt2 = omt * omt; return p0 * ((1 + twot) * omt2) + m0 * (t * omt2) + p12 * (t2 * (3 - twot)) + m12 * (t2 * (t - 1)); } }; var Curve = class { keys = []; type = CURVE_SMOOTHSTEP; tension = 0.5; _eval = new CurveEvaluator(this); constructor(data2) { if (data2) { for (let i = 0; i < data2.length - 1; i += 2) { this.keys.push([data2[i], data2[i + 1]]); } } this.sort(); } get length() { return this.keys.length; } add(time, value) { const keys = this.keys; const len = keys.length; let i = 0; for (; i < len; i++) { if (keys[i][0] > time) { break; } } const key = [time, value]; this.keys.splice(i, 0, key); return key; } get(index) { return this.keys[index]; } sort() { this.keys.sort((a, b) => a[0] - b[0]); } value(time) { return this._eval.evaluate(time, true); } closest(time) { const keys = this.keys; const length = keys.length; let min = 2; let result = null; for (let i = 0; i < length; i++) { const diff = Math.abs(time - keys[i][0]); if (min >= diff) { min = diff; result = keys[i]; } else { break; } } return result; } clone() { const result = new this.constructor(); result.keys = this.keys.map((key) => [...key]); result.type = this.type; result.tension = this.tension; return result; } quantize(precision) { precision = Math.max(precision, 2); const values = new Float32Array(precision); const step = 1 / (precision - 1); values[0] = this._eval.evaluate(0, true); for (let i = 1; i < precision; i++) { values[i] = this._eval.evaluate(step * i); } return values; } quantizeClamped(precision, min, max) { const result = this.quantize(precision); for (let i = 0; i < result.length; ++i) { result[i] = Math.min(max, Math.max(min, result[i])); } return result; } }; var CurveSet = class { curves = []; _type = CURVE_SMOOTHSTEP; constructor(...args) { if (args.length > 1) { for (let i = 0; i < args.length; i++) { this.curves.push(new Curve(args[i])); } } else if (args.length === 0) { this.curves.push(new Curve()); } else { const arg = args[0]; if (typeof arg === "number") { for (let i = 0; i < arg; i++) { this.curves.push(new Curve()); } } else { for (let i = 0; i < arg.length; i++) { this.curves.push(new Curve(arg[i])); } } } } get length() { return this.curves.length; } set type(value) { this._type = value; for (let i = 0; i < this.curves.length; i++) { this.curves[i].type = value; } } get type() { return this._type; } get(index) { return this.curves[index]; } value(time, result = []) { const length = this.curves.length; result.length = length; for (let i = 0; i < length; i++) { result[i] = this.curves[i].value(time); } return result; } clone() { const result = new this.constructor(); result.curves = []; for (let i = 0; i < this.curves.length; i++) { result.curves.push(this.curves[i].clone()); } result._type = this._type; return result; } quantize(precision) { precision = Math.max(precision, 2); const numCurves = this.curves.length; const values = new Float32Array(precision * numCurves); const step = 1 / (precision - 1); for (let c2 = 0; c2 < numCurves; c2++) { const ev = new CurveEvaluator(this.curves[c2]); for (let i = 0; i < precision; i++) { values[i * numCurves + c2] = ev.evaluate(step * i); } } return values; } quantizeClamped(precision, min, max) { const result = this.quantize(precision); for (let i = 0; i < result.length; ++i) { result[i] = Math.min(max, Math.max(min, result[i])); } return result; } }; var floatView = new Float32Array(1); var int32View = new Int32Array(floatView.buffer); var FloatPacking = class { static float2Half(value) { floatView[0] = value; const x2 = int32View[0]; let bits = x2 >> 16 & 32768; let m = x2 >> 12 & 2047; const e = x2 >> 23 & 255; if (e < 103) { return bits; } if (e > 142) { bits |= 31744; bits |= (e === 255 ? 0 : 1) && x2 & 8388607; return bits; } if (e < 113) { m |= 2048; bits |= (m >> 114 - e) + (m >> 113 - e & 1); return bits; } bits |= e - 112 << 10 | m >> 1; bits += m & 1; return bits; } static float2RGBA8(value, data2) { floatView[0] = value; const intBits = int32View[0]; data2.r = (intBits >> 24 & 255) / 255; data2.g = (intBits >> 16 & 255) / 255; data2.b = (intBits >> 8 & 255) / 255; data2.a = (intBits & 255) / 255; } }; var Kernel = class { static concentric(numRings, numPoints) { const kernel = []; kernel.push(0, 0); const spacing = 2 * Math.PI / numRings / numPoints; for (let ring = 1; ring <= numRings; ring++) { const radius = ring / numRings; const circumference = 2 * Math.PI * radius; const pointsPerRing = Math.max(1, Math.floor(circumference / spacing)); const angleStep = 2 * Math.PI / pointsPerRing; for (let point5 = 0; point5 < pointsPerRing; point5++) { const angle = point5 * angleStep; const x2 = radius * Math.cos(angle); const y2 = radius * Math.sin(angle); kernel.push(x2, y2); } } return kernel; } }; var Vec3 = class _Vec3 { x; y; z; constructor(x2 = 0, y2 = 0, z2 = 0) { if (x2.length === 3) { this.x = x2[0]; this.y = x2[1]; this.z = x2[2]; } else { this.x = x2; this.y = y2; this.z = z2; } } add(rhs) { this.x += rhs.x; this.y += rhs.y; this.z += rhs.z; return this; } add2(lhs, rhs) { this.x = lhs.x + rhs.x; this.y = lhs.y + rhs.y; this.z = lhs.z + rhs.z; return this; } addScalar(scalar) { this.x += scalar; this.y += scalar; this.z += scalar; return this; } addScaled(rhs, scalar) { this.x += rhs.x * scalar; this.y += rhs.y * scalar; this.z += rhs.z * scalar; return this; } clone() { const cstr = this.constructor; return new cstr(this.x, this.y, this.z); } copy(rhs) { this.x = rhs.x; this.y = rhs.y; this.z = rhs.z; return this; } cross(lhs, rhs) { const lx = lhs.x; const ly = lhs.y; const lz = lhs.z; const rx = rhs.x; const ry = rhs.y; const rz = rhs.z; this.x = ly * rz - ry * lz; this.y = lz * rx - rz * lx; this.z = lx * ry - rx * ly; return this; } distance(rhs) { const x2 = this.x - rhs.x; const y2 = this.y - rhs.y; const z2 = this.z - rhs.z; return Math.sqrt(x2 * x2 + y2 * y2 + z2 * z2); } div(rhs) { this.x /= rhs.x; this.y /= rhs.y; this.z /= rhs.z; return this; } div2(lhs, rhs) { this.x = lhs.x / rhs.x; this.y = lhs.y / rhs.y; this.z = lhs.z / rhs.z; return this; } divScalar(scalar) { this.x /= scalar; this.y /= scalar; this.z /= scalar; return this; } dot(rhs) { return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z; } equals(rhs) { return this.x === rhs.x && this.y === rhs.y && this.z === rhs.z; } equalsApprox(rhs, epsilon = 1e-6) { return Math.abs(this.x - rhs.x) < epsilon && Math.abs(this.y - rhs.y) < epsilon && Math.abs(this.z - rhs.z) < epsilon; } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); } lengthSq() { return this.x * this.x + this.y * this.y + this.z * this.z; } lerp(lhs, rhs, alpha) { this.x = lhs.x + alpha * (rhs.x - lhs.x); this.y = lhs.y + alpha * (rhs.y - lhs.y); this.z = lhs.z + alpha * (rhs.z - lhs.z); return this; } mul(rhs) { this.x *= rhs.x; this.y *= rhs.y; this.z *= rhs.z; return this; } mul2(lhs, rhs) { this.x = lhs.x * rhs.x; this.y = lhs.y * rhs.y; this.z = lhs.z * rhs.z; return this; } mulScalar(scalar) { this.x *= scalar; this.y *= scalar; this.z *= scalar; return this; } normalize(src = this) { const lengthSq = src.x * src.x + src.y * src.y + src.z * src.z; if (lengthSq > 0) { const invLength = 1 / Math.sqrt(lengthSq); this.x = src.x * invLength; this.y = src.y * invLength; this.z = src.z * invLength; } return this; } floor(src = this) { this.x = Math.floor(src.x); this.y = Math.floor(src.y); this.z = Math.floor(src.z); return this; } ceil(src = this) { this.x = Math.ceil(src.x); this.y = Math.ceil(src.y); this.z = Math.ceil(src.z); return this; } round(src = this) { this.x = Math.round(src.x); this.y = Math.round(src.y); this.z = Math.round(src.z); return this; } min(rhs) { if (rhs.x < this.x) this.x = rhs.x; if (rhs.y < this.y) this.y = rhs.y; if (rhs.z < this.z) this.z = rhs.z; return this; } max(rhs) { if (rhs.x > this.x) this.x = rhs.x; if (rhs.y > this.y) this.y = rhs.y; if (rhs.z > this.z) this.z = rhs.z; return this; } project(rhs) { const a_dot_b = this.x * rhs.x + this.y * rhs.y + this.z * rhs.z; const b_dot_b = rhs.x * rhs.x + rhs.y * rhs.y + rhs.z * rhs.z; const s2 = a_dot_b / b_dot_b; this.x = rhs.x * s2; this.y = rhs.y * s2; this.z = rhs.z * s2; return this; } set(x2, y2, z2) { this.x = x2; this.y = y2; this.z = z2; return this; } sub(rhs) { this.x -= rhs.x; this.y -= rhs.y; this.z -= rhs.z; return this; } sub2(lhs, rhs) { this.x = lhs.x - rhs.x; this.y = lhs.y - rhs.y; this.z = lhs.z - rhs.z; return this; } subScalar(scalar) { this.x -= scalar; this.y -= scalar; this.z -= scalar; return this; } fromArray(arr, offset3 = 0) { this.x = arr[offset3] ?? this.x; this.y = arr[offset3 + 1] ?? this.y; this.z = arr[offset3 + 2] ?? this.z; return this; } toString() { return `[${this.x}, ${this.y}, ${this.z}]`; } toArray(arr = [], offset3 = 0) { arr[offset3] = this.x; arr[offset3 + 1] = this.y; arr[offset3 + 2] = this.z; return arr; } static ZERO = Object.freeze(new _Vec3(0, 0, 0)); static HALF = Object.freeze(new _Vec3(0.5, 0.5, 0.5)); static ONE = Object.freeze(new _Vec3(1, 1, 1)); static UP = Object.freeze(new _Vec3(0, 1, 0)); static DOWN = Object.freeze(new _Vec3(0, -1, 0)); static RIGHT = Object.freeze(new _Vec3(1, 0, 0)); static LEFT = Object.freeze(new _Vec3(-1, 0, 0)); static FORWARD = Object.freeze(new _Vec3(0, 0, -1)); static BACK = Object.freeze(new _Vec3(0, 0, 1)); }; var Mat3 = class _Mat3 { data = new Float32Array(9); constructor() { this.data[0] = this.data[4] = this.data[8] = 1; } clone() { const cstr = this.constructor; return new cstr().copy(this); } copy(rhs) { const src = rhs.data; const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; dst[8] = src[8]; return this; } set(src) { const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; dst[8] = src[8]; return this; } getX(x2 = new Vec3()) { return x2.set(this.data[0], this.data[1], this.data[2]); } getY(y2 = new Vec3()) { return y2.set(this.data[3], this.data[4], this.data[5]); } getZ(z2 = new Vec3()) { return z2.set(this.data[6], this.data[7], this.data[8]); } equals(rhs) { const l = this.data; const r = rhs.data; return l[0] === r[0] && l[1] === r[1] && l[2] === r[2] && l[3] === r[3] && l[4] === r[4] && l[5] === r[5] && l[6] === r[6] && l[7] === r[7] && l[8] === r[8]; } isIdentity() { const m = this.data; return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 0 && m[4] === 1 && m[5] === 0 && m[6] === 0 && m[7] === 0 && m[8] === 1; } setIdentity() { const m = this.data; m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 1; m[5] = 0; m[6] = 0; m[7] = 0; m[8] = 1; return this; } toString() { return `[${this.data.join(", ")}]`; } transpose(src = this) { const s2 = src.data; const t = this.data; if (s2 === t) { let tmp; tmp = s2[1]; t[1] = s2[3]; t[3] = tmp; tmp = s2[2]; t[2] = s2[6]; t[6] = tmp; tmp = s2[5]; t[5] = s2[7]; t[7] = tmp; } else { t[0] = s2[0]; t[1] = s2[3]; t[2] = s2[6]; t[3] = s2[1]; t[4] = s2[4]; t[5] = s2[7]; t[6] = s2[2]; t[7] = s2[5]; t[8] = s2[8]; } return this; } setFromMat4(m) { const src = m.data; const dst = this.data; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6]; dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10]; return this; } setFromQuat(r) { const qx = r.x; const qy = r.y; const qz = r.z; const qw = r.w; const x2 = qx + qx; const y2 = qy + qy; const z2 = qz + qz; const xx = qx * x2; const xy = qx * y2; const xz = qx * z2; const yy = qy * y2; const yz = qy * z2; const zz = qz * z2; const wx = qw * x2; const wy = qw * y2; const wz = qw * z2; const m = this.data; m[0] = 1 - (yy + zz); m[1] = xy + wz; m[2] = xz - wy; m[3] = xy - wz; m[4] = 1 - (xx + zz); m[5] = yz + wx; m[6] = xz + wy; m[7] = yz - wx; m[8] = 1 - (xx + yy); return this; } invertMat4(src) { const s2 = src.data; const a0 = s2[0]; const a1 = s2[1]; const a2 = s2[2]; const a4 = s2[4]; const a5 = s2[5]; const a6 = s2[6]; const a8 = s2[8]; const a9 = s2[9]; const a10 = s2[10]; const b11 = a10 * a5 - a6 * a9; const b21 = -a10 * a1 + a2 * a9; const b31 = a6 * a1 - a2 * a5; const b12 = -a10 * a4 + a6 * a8; const b22 = a10 * a0 - a2 * a8; const b32 = -a6 * a0 + a2 * a4; const b13 = a9 * a4 - a5 * a8; const b23 = -a9 * a0 + a1 * a8; const b33 = a5 * a0 - a1 * a4; const det = a0 * b11 + a1 * b12 + a2 * b13; if (det === 0) { this.setIdentity(); } else { const invDet = 1 / det; const t = this.data; t[0] = b11 * invDet; t[1] = b21 * invDet; t[2] = b31 * invDet; t[3] = b12 * invDet; t[4] = b22 * invDet; t[5] = b32 * invDet; t[6] = b13 * invDet; t[7] = b23 * invDet; t[8] = b33 * invDet; } return this; } transformVector(vec2, res = new Vec3()) { const m = this.data; const { x: x2, y: y2, z: z2 } = vec2; res.x = x2 * m[0] + y2 * m[3] + z2 * m[6]; res.y = x2 * m[1] + y2 * m[4] + z2 * m[7]; res.z = x2 * m[2] + y2 * m[5] + z2 * m[8]; return res; } static IDENTITY = Object.freeze(new _Mat3()); static ZERO = Object.freeze(new _Mat3().set([0, 0, 0, 0, 0, 0, 0