UNPKG

@playcanvas/splat-transform

Version:

Library and CLI tool for 3D Gaussian splat format conversion and transformation

2,147 lines (2,127 loc) 5.69 MB
import { open, mkdir, stat, rename, lstat, readFile as readFile$2 } from 'node:fs/promises'; import { basename as basename$1, join as join$1, dirname as dirname$1, resolve as resolve$1 } from 'node:path'; import process$1, { exit } from 'node:process'; import { parseArgs } from 'node:util'; import { globals, create } from 'webgpu'; import { randomBytes } from 'crypto'; const TRACEID_GPU_TIMINGS = "GpuTimings"; const version$1 = "2.19.2"; const revision$1 = "3f52bb8"; function extend(target, ex) { for (const prop in ex) { const copy = ex[prop]; if (Array.isArray(copy)) { target[prop] = extend([], copy); } else if (copy && typeof copy === "object") { target[prop] = extend({}, copy); } else { target[prop] = copy; } } return target; } const guid = { create() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c === "x" ? r : r & 3 | 8; return v.toString(16); }); } }; const 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; } }; const 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; }; const ua = typeof navigator !== "undefined" ? navigator.userAgent : ""; const environment = typeof window !== "undefined" ? "browser" : typeof global !== "undefined" ? "node" : "worker"; const 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; detectPassiveEvents(); const platform = { name: platformName, browser: environment === "browser", worker: environment === "worker", desktop: ["windows", "osx", "linux", "cros"].includes(platformName), mobile: ["android", "ios"].includes(platformName), ios: platformName === "ios", android: platformName === "android"}; class EventHandle { 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; } } class EventHandler { _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; } } class Tags 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; } } const now$1 = typeof window !== "undefined" && window.performance && window.performance.now ? performance.now.bind(performance) : Date.now; const re = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; class URI { 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 s = ""; if (this.scheme) { s += `${this.scheme}:`; } if (this.authority) { s += `//${this.authority}`; } s += this.path; if (this.query) { s += `?${this.query}`; } if (this.fragment) { s += `#${this.fragment}`; } return s; } 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 q = ""; for (const key in params) { if (params.hasOwnProperty(key)) { if (q !== "") { q += "&"; } q += `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`; } } this.query = q; } } class Tracing { static _traceChannels = /* @__PURE__ */ new Set(); static stack = false; static set(channel, enabled = true) { } static get(channel) { return Tracing._traceChannels.has(channel); } } const 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(x) { return x !== 0 && !(x & x - 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, x) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * (3 - 2 * x); }, smootherstep(min, max, x) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * x * (x * (x * 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; } }; 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, offset = 0) { this.r = arr[offset] ?? this.r; this.g = arr[offset + 1] ?? this.g; this.b = arr[offset + 2] ?? this.b; this.a = arr[offset + 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 s = `#${((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) { s += `0${aa}`; } else { s += aa; } } return s; } toArray(arr = [], offset = 0, alpha = true) { arr[offset] = this.r; arr[offset + 1] = this.g; arr[offset + 2] = this.b; if (alpha) { arr[offset + 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)); } const floatView = new Float32Array(1); const int32View = new Int32Array(floatView.buffer); class FloatPacking { static float2Half(value) { floatView[0] = value; const x = int32View[0]; let bits = x >> 16 & 32768; let m = x >> 12 & 2047; const e = x >> 23 & 255; if (e < 103) { return bits; } if (e > 142) { bits |= 31744; bits |= (e === 255 ? 0 : 1) && x & 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, data) { floatView[0] = value; const intBits = int32View[0]; data.r = (intBits >> 24 & 255) / 255; data.g = (intBits >> 16 & 255) / 255; data.b = (intBits >> 8 & 255) / 255; data.a = (intBits & 255) / 255; } } class Vec3 { x; y; z; constructor(x = 0, y = 0, z = 0) { if (x.length === 3) { this.x = x[0]; this.y = x[1]; this.z = x[2]; } else { this.x = x; this.y = y; this.z = z; } } 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 x = this.x - rhs.x; const y = this.y - rhs.y; const z = this.z - rhs.z; return Math.sqrt(x * x + y * y + z * z); } 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 s = a_dot_b / b_dot_b; this.x = rhs.x * s; this.y = rhs.y * s; this.z = rhs.z * s; return this; } set(x, y, z) { this.x = x; this.y = y; this.z = z; 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, offset = 0) { this.x = arr[offset] ?? this.x; this.y = arr[offset + 1] ?? this.y; this.z = arr[offset + 2] ?? this.z; return this; } toString() { return `[${this.x}, ${this.y}, ${this.z}]`; } toArray(arr = [], offset = 0) { arr[offset] = this.x; arr[offset + 1] = this.y; arr[offset + 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)); } 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(x = new Vec3()) { return x.set(this.data[0], this.data[1], this.data[2]); } getY(y = new Vec3()) { return y.set(this.data[3], this.data[4], this.data[5]); } getZ(z = new Vec3()) { return z.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 s = src.data; const t = this.data; if (s === t) { let tmp; tmp = s[1]; t[1] = s[3]; t[3] = tmp; tmp = s[2]; t[2] = s[6]; t[6] = tmp; tmp = s[5]; t[5] = s[7]; t[7] = tmp; } else { t[0] = s[0]; t[1] = s[3]; t[2] = s[6]; t[3] = s[1]; t[4] = s[4]; t[5] = s[7]; t[6] = s[2]; t[7] = s[5]; t[8] = s[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 s = src.data; const a0 = s[0]; const a1 = s[1]; const a2 = s[2]; const a4 = s[4]; const a5 = s[5]; const a6 = s[6]; const a8 = s[8]; const a9 = s[9]; const a10 = s[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(vec, res = new Vec3()) { const m = this.data; const { x, y, z } = vec; res.x = x * m[0] + y * m[3] + z * m[6]; res.y = x * m[1] + y * m[4] + z * m[7]; res.z = x * m[2] + y * m[5] + z * m[8]; return res; } static IDENTITY = Object.freeze(new Mat3()); static ZERO = Object.freeze(new Mat3().set([0, 0, 0, 0, 0, 0, 0, 0, 0])); } class Vec2 { x; y; constructor(x = 0, y = 0) { if (x.length === 2) { this.x = x[0]; this.y = x[1]; } else { this.x = x; this.y = y; } } add(rhs) { this.x += rhs.x; this.y += rhs.y; return this; } add2(lhs, rhs) { this.x = lhs.x + rhs.x; this.y = lhs.y + rhs.y; return this; } addScalar(scalar) { this.x += scalar; this.y += scalar; return this; } addScaled(rhs, scalar) { this.x += rhs.x * scalar; this.y += rhs.y * scalar; return this; } clone() { const cstr = this.constructor; return new cstr(this.x, this.y); } copy(rhs) { this.x = rhs.x; this.y = rhs.y; return this; } cross(rhs) { return this.x * rhs.y - this.y * rhs.x; } distance(rhs) { const x = this.x - rhs.x; const y = this.y - rhs.y; return Math.sqrt(x * x + y * y); } div(rhs) { this.x /= rhs.x; this.y /= rhs.y; return this; } div2(lhs, rhs) { this.x = lhs.x / rhs.x; this.y = lhs.y / rhs.y; return this; } divScalar(scalar) { this.x /= scalar; this.y /= scalar; return this; } dot(rhs) { return this.x * rhs.x + this.y * rhs.y; } equals(rhs) { return this.x === rhs.x && this.y === rhs.y; } equalsApprox(rhs, epsilon = 1e-6) { return Math.abs(this.x - rhs.x) < epsilon && Math.abs(this.y - rhs.y) < epsilon; } length() { return Math.sqrt(this.x * this.x + this.y * this.y); } lengthSq() { return this.x * this.x + this.y * this.y; } lerp(lhs, rhs, alpha) { this.x = lhs.x + alpha * (rhs.x - lhs.x); this.y = lhs.y + alpha * (rhs.y - lhs.y); return this; } mul(rhs) { this.x *= rhs.x; this.y *= rhs.y; return this; } mul2(lhs, rhs) { this.x = lhs.x * rhs.x; this.y = lhs.y * rhs.y; return this; } mulScalar(scalar) { this.x *= scalar; this.y *= scalar; return this; } normalize(src = this) { const lengthSq = src.x * src.x + src.y * src.y; if (lengthSq > 0) { const invLength = 1 / Math.sqrt(lengthSq); this.x = src.x * invLength; this.y = src.y * invLength; } return this; } rotate(degrees) { const angle = Math.atan2(this.x, this.y) + degrees * math.DEG_TO_RAD; const len = Math.sqrt(this.x * this.x + this.y * this.y); this.x = Math.sin(angle) * len; this.y = Math.cos(angle) * len; return this; } angle() { return Math.atan2(this.x, this.y) * math.RAD_TO_DEG; } angleTo(rhs) { return Math.atan2(this.x * rhs.y + this.y * rhs.x, this.x * rhs.x + this.y * rhs.y) * math.RAD_TO_DEG; } floor(src = this) { this.x = Math.floor(src.x); this.y = Math.floor(src.y); return this; } ceil(src = this) { this.x = Math.ceil(src.x); this.y = Math.ceil(src.y); return this; } round(src = this) { this.x = Math.round(src.x); this.y = Math.round(src.y); return this; } min(rhs) { if (rhs.x < this.x) this.x = rhs.x; if (rhs.y < this.y) this.y = rhs.y; return this; } max(rhs) { if (rhs.x > this.x) this.x = rhs.x; if (rhs.y > this.y) this.y = rhs.y; return this; } set(x, y) { this.x = x; this.y = y; return this; } sub(rhs) { this.x -= rhs.x; this.y -= rhs.y; return this; } sub2(lhs, rhs) { this.x = lhs.x - rhs.x; this.y = lhs.y - rhs.y; return this; } subScalar(scalar) { this.x -= scalar; this.y -= scalar; return this; } fromArray(arr, offset = 0) { this.x = arr[offset] ?? this.x; this.y = arr[offset + 1] ?? this.y; return this; } toString() { return `[${this.x}, ${this.y}]`; } toArray(arr = [], offset = 0) { arr[offset] = this.x; arr[offset + 1] = this.y; return arr; } static angleRad(lhs, rhs) { return Math.atan2(lhs.x * rhs.y - lhs.y * rhs.x, lhs.x * rhs.x + lhs.y * rhs.y); } static ZERO = Object.freeze(new Vec2(0, 0)); static HALF = Object.freeze(new Vec2(0.5, 0.5)); static ONE = Object.freeze(new Vec2(1, 1)); static UP = Object.freeze(new Vec2(0, 1)); static DOWN = Object.freeze(new Vec2(0, -1)); static RIGHT = Object.freeze(new Vec2(1, 0)); static LEFT = Object.freeze(new Vec2(-1, 0)); } class Vec4 { x; y; z; w; constructor(x = 0, y = 0, z = 0, w = 0) { if (x.length === 4) { this.x = x[0]; this.y = x[1]; this.z = x[2]; this.w = x[3]; } else { this.x = x; this.y = y; this.z = z; this.w = w; } } add(rhs) { this.x += rhs.x; this.y += rhs.y; this.z += rhs.z; this.w += rhs.w; return this; } add2(lhs, rhs) { this.x = lhs.x + rhs.x; this.y = lhs.y + rhs.y; this.z = lhs.z + rhs.z; this.w = lhs.w + rhs.w; return this; } addScalar(scalar) { this.x += scalar; this.y += scalar; this.z += scalar; this.w += scalar; return this; } addScaled(rhs, scalar) { this.x += rhs.x * scalar; this.y += rhs.y * scalar; this.z += rhs.z * scalar; this.w += rhs.w * scalar; return this; } clone() { const cstr = this.constructor; return new cstr(this.x, this.y, this.z, this.w); } copy(rhs) { this.x = rhs.x; this.y = rhs.y; this.z = rhs.z; this.w = rhs.w; return this; } div(rhs) { this.x /= rhs.x; this.y /= rhs.y; this.z /= rhs.z; this.w /= rhs.w; return this; } div2(lhs, rhs) { this.x = lhs.x / rhs.x; this.y = lhs.y / rhs.y; this.z = lhs.z / rhs.z; this.w = lhs.w / rhs.w; return this; } divScalar(scalar) { this.x /= scalar; this.y /= scalar; this.z /= scalar; this.w /= scalar; return this; } dot(rhs) { return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z + this.w * rhs.w; } equals(rhs) { return this.x === rhs.x && this.y === rhs.y && this.z === rhs.z && this.w === rhs.w; } 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 && Math.abs(this.w - rhs.w) < epsilon; } length() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); } lengthSq() { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; } 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); this.w = lhs.w + alpha * (rhs.w - lhs.w); return this; } mul(rhs) { this.x *= rhs.x; this.y *= rhs.y; this.z *= rhs.z; this.w *= rhs.w; return this; } mul2(lhs, rhs) { this.x = lhs.x * rhs.x; this.y = lhs.y * rhs.y; this.z = lhs.z * rhs.z; this.w = lhs.w * rhs.w; return this; } mulScalar(scalar) { this.x *= scalar; this.y *= scalar; this.z *= scalar; this.w *= scalar; return this; } normalize(src = this) { const lengthSq = src.x * src.x + src.y * src.y + src.z * src.z + src.w * src.w; if (lengthSq > 0) { const invLength = 1 / Math.sqrt(lengthSq); this.x = src.x * invLength; this.y = src.y * invLength; this.z = src.z * invLength; this.w = src.w * invLength; } return this; } floor(src = this) { this.x = Math.floor(src.x); this.y = Math.floor(src.y); this.z = Math.floor(src.z); this.w = Math.floor(src.w); return this; } ceil(src = this) { this.x = Math.ceil(src.x); this.y = Math.ceil(src.y); this.z = Math.ceil(src.z); this.w = Math.ceil(src.w); return this; } round(src = this) { this.x = Math.round(src.x); this.y = Math.round(src.y); this.z = Math.round(src.z); this.w = Math.round(src.w); 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; if (rhs.w < this.w) this.w = rhs.w; 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; if (rhs.w > this.w) this.w = rhs.w; return this; } set(x, y, z, w) { this.x = x; this.y = y; this.z = z; this.w = w; return this; } sub(rhs) { this.x -= rhs.x; this.y -= rhs.y; this.z -= rhs.z; this.w -= rhs.w; return this; } sub2(lhs, rhs) { this.x = lhs.x - rhs.x; this.y = lhs.y - rhs.y; this.z = lhs.z - rhs.z; this.w = lhs.w - rhs.w; return this; } subScalar(scalar) { this.x -= scalar; this.y -= scalar; this.z -= scalar; this.w -= scalar; return this; } fromArray(arr, offset = 0) { this.x = arr[offset] ?? this.x; this.y = arr[offset + 1] ?? this.y; this.z = arr[offset + 2] ?? this.z; this.w = arr[offset + 3] ?? this.w; return this; } toString() { return `[${this.x}, ${this.y}, ${this.z}, ${this.w}]`; } toArray(arr = [], offset = 0) { arr[offset] = this.x; arr[offset + 1] = this.y; arr[offset + 2] = this.z; arr[offset + 3] = this.w; return arr; } static ZERO = Object.freeze(new Vec4(0, 0, 0, 0)); static HALF = Object.freeze(new Vec4(0.5, 0.5, 0.5, 0.5)); static ONE = Object.freeze(new Vec4(1, 1, 1, 1)); } const _halfSize$1 = new Vec2(); const x = new Vec3(); const y = new Vec3(); const z = new Vec3(); const scale = new Vec3(); class Mat4 { data = new Float32Array(16); constructor() { this.data[0] = this.data[5] = this.data[10] = this.data[15] = 1; } // Static function which evaluates perspective projection matrix half size at the near plane static _getPerspectiveHalfSize(halfSize, fov, aspect, znear, fovIsHorizontal) { if (fovIsHorizontal) { halfSize.x = znear * Math.tan(fov * Math.PI / 360); halfSize.y = halfSize.x / aspect; } else { halfSize.y = znear * Math.tan(fov * Math.PI / 360); halfSize.x = halfSize.y * aspect; } } add2(lhs, rhs) { const a = lhs.data, b = rhs.data, r = this.data; r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; r[3] = a[3] + b[3]; r[4] = a[4] + b[4]; r[5] = a[5] + b[5]; r[6] = a[6] + b[6]; r[7] = a[7] + b[7]; r[8] = a[8] + b[8]; r[9] = a[9] + b[9]; r[10] = a[10] + b[10]; r[11] = a[11] + b[11]; r[12] = a[12] + b[12]; r[13] = a[13] + b[13]; r[14] = a[14] + b[14]; r[15] = a[15] + b[15]; return this; } add(rhs) { return this.add2(this, rhs); } clone() { const cstr = this.constructor; return new cstr().copy(this); } copy(rhs) { const src = rhs.data, 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]; dst[9] = src[9]; dst[10] = src[10]; dst[11] = src[11]; dst[12] = src[12]; dst[13] = src[13]; dst[14] = src[14]; dst[15] = src[15]; return this; } equals(rhs) { const l = this.data, 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] && l[9] === r[9] && l[10] === r[10] && l[11] === r[11] && l[12] === r[12] && l[13] === r[13] && l[14] === r[14] && l[15] === r[15]; } isIdentity() { const m = this.data; return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 0 && m[4] === 0 && m[5] === 1 && m[6] === 0 && m[7] === 0 && m[8] === 0 && m[9] === 0 && m[10] === 1 && m[11] === 0 && m[12] === 0 && m[13] === 0 && m[14] === 0 && m[15] === 1; } mul2(lhs, rhs) { const a = lhs.data; const b = rhs.data; const r = this.data; const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; let b0, b1, b2, b3; b0 = b[0]; b1 = b[1]; b2 = b[2]; b3 = b[3]; r[0] = a00 * b0 + a10 * b1 + a20 * b2 + a30 * b3; r[1] = a01 * b0 + a11 * b1 + a21 * b2 + a31 * b3; r[2] = a02 * b0 + a12 * b1 + a22 * b2 + a32 * b3; r[3] = a03 * b0 + a13 * b1 + a23 * b2 + a33 * b3; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; r[4] = a00 * b0 + a10 * b1 + a20 * b2 + a30 * b3; r[5] = a01 * b0 + a11 * b1 + a21 * b2 + a31 * b3; r[6] = a02 * b0 + a12 * b1 + a22 * b2 + a32 * b3; r[7] = a03 * b0 + a13 * b1 + a23 * b2 + a33 * b3; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; r[8] = a00 * b0 + a10 * b1 + a20 * b2 + a30 * b3; r[9] = a01 * b0 + a11 * b1 + a21 * b2 + a31 * b3; r[10] = a02 * b0 + a12 * b1 + a22 * b2 + a32 * b3; r[11] = a03 * b0 + a13 * b1 + a23 * b2 + a33 * b3; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; r[12] = a00 * b0 + a10 * b1 + a20 * b2 + a30 * b3; r[13] = a01 * b0 + a11 * b1 + a21 * b2 + a31 * b3; r[14] = a02 * b0 + a12 * b1 + a22 * b2 + a32 * b3; r[15] = a03 * b0 + a13 * b1 + a23 * b2 + a33 * b3; return this; } mulAffine2(lhs, rhs) { const a = lhs.data; const b = rhs.data; const r = this.data; const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; let b0, b1, b2; b0 = b[0]; b1 = b[1]; b2 = b[2]; r[0] = a00 * b0 + a10 * b1 + a20 * b2; r[1] = a01 * b0 + a11 * b1 + a21 * b2; r[2] = a02 * b0 + a12 * b1 + a22 * b2; r[3] = 0; b0 = b[4]; b1 = b[5]; b2 = b[6]; r[4] = a00 * b0 + a10 * b1 + a20 * b2; r[5] = a01 * b0 + a11 * b1 + a21 * b2; r[6] = a02 * b0 + a12 * b1 + a22 * b2; r[7] = 0; b0 = b[8]; b1 = b[9]; b2 = b[10]; r[8] = a00 * b0 + a10 * b1 + a20 * b2; r[9] = a01 * b0 + a11 * b1 + a21 * b2; r[10] = a02 * b0 + a12 * b1 + a22 * b2; r[11] = 0; b0 = b[12]; b1 = b[13]; b2 = b[14]; r[12] = a00 * b0 + a10 * b1 + a20 * b2 + a30; r[13] = a01 * b0 + a11 * b1 + a21 * b2 + a31; r[14] = a02 * b0 + a12 * b1 + a22 * b2 + a32; r[15] = 1; return this; } mul(rhs) { return this.mul2(this, rhs); } transformPoint(vec, res = new Vec3()) { const m = this.data; const { x: x2, y: y2, z: z2 } = vec; res.x = x2 * m[0] + y2 * m[4] + z2 * m[8] + m[12]; res.y = x2 * m[1] + y2 * m[5] + z2 * m[9] + m[13]; res.z = x2 * m[2] + y2 * m[6] + z2 * m[10] + m[14]; return res; } transformVector(vec, res = new Vec3()) { const m = this.data; const { x: x2, y: y2, z: z2 } = vec; res.x = x2 * m[0] + y2 * m[4] + z2 * m[8]; res.y = x2 * m[1] + y2 * m[5] + z2 * m[9]; res.z = x2 * m[2] + y2 * m[6] + z2 * m[10]; return res; } transformVec4(vec, res = new Vec4()) { const m = this.data; const { x: x2, y: y2, z: z2, w } = vec; res.x = x2 * m[0] + y2 * m[4] + z2 * m[8] + w * m[12]; res.y = x2 * m[1] + y2 * m[5] + z2 * m[9] + w * m[13]; res.z = x2 * m[2] + y2 * m[6] + z2 * m[10] + w * m[14]; res.w = x2 * m[3] + y2 * m[7] + z2 * m[11] + w * m[15]; return res; } setLookAt(position, target, up) { z.sub2(position, target).normalize(); y.copy(up).normalize(); x.cross(y, z).normalize(); y.cross(z, x); const r = this.data; r[0] = x.x; r[1] = x.y; r[2] = x.z; r[3] = 0; r[4] = y.x; r[5] = y.y; r[6] = y.z; r[7] = 0; r[8] = z.x; r[9] = z.y; r[10] = z.z; r[11] = 0; r[12] = position.x; r[13] = position.y; r[14] = position.z; r[15] = 1; return this; } setFrustum(left, right, bottom, top, znear, zfar) { const temp1 = 2 * znear; const temp2 = right - left; const temp3 = top - bottom; const temp4 = zfar - znear; const r = this.data; r[0] = temp1 / temp2; r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = temp1 / temp3; r[6] = 0; r[7] = 0; r[8] = (right + left) / temp2; r[9] = (top + bottom) / temp3; r[10] = (-zfar - znear) / temp4; r[11] = -1; r[12] = 0; r[13] = 0; r[14] = -temp1 * zfar / temp4; r[15] = 0; return this; } setPerspective(fov, aspect, znear, zfar, fovIsHorizontal) { Mat4._getPerspectiveHalfSize(_halfSize$1, fov, aspect, znear, fovIsHorizontal); return this.setFrustum(-_halfSize$1.x, _halfSize$1.x, -_halfSize$1.y, _halfSize$1.y, znear, zfar); } setOrtho(left, right, bottom, top, near, far) { const r = this.data; r[0] = 2 / (right - left); r[1] = 0; r[2] = 0; r[3] = 0; r[4] = 0; r[5] = 2 / (top - bottom); r[6] = 0; r[7] = 0; r[8] = 0; r[9] = 0; r[10] = -2 / (far - near); r[11] = 0; r[12] = -(right + left) / (right - left); r[13] = -(top + bottom) / (top - bottom); r[14] = -(far + near) / (far - near); r[15] = 1; return this; } setFromAxisAngle(axis, angle) { angle *= math.DEG_TO_RAD; const { x: x2, y: y2, z: z2 } = axis; const c = Math.cos(angle); const s = Math.sin(angle); const t = 1 - c; const tx = t * x2; const ty = t * y2; const m = this.data; m[0] = tx * x2 + c; m[1] = tx * y2 + s * z2; m[2] = tx * z2 - s * y2; m[3] = 0; m[4] = tx * y2 - s * z2; m[5] = ty * y2 + c; m[6] = ty * z2 + s * x2; m[7] = 0; m[8] = tx * z2 + s * y2; m[9] = ty * z2 - x2 * s; m[10] = t * z2 * z2 + c; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return this; } setTranslate(x2, y2, z2) { const m = this.data; m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; m[12] = x2; m[13] = y2; m[14] = z2; m[15] = 1; return this; } setScale(x2, y2, z2) { const m = this.data; m[0] = x2; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = y2; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = z2; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return this; } setViewport(x2, y2, width, height) { const m = this.data; m[0] = width * 0.5; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = height * 0.5; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = 0.5; m[11] = 0; m[12] = x2 + width * 0.5; m[13] = y2 + height * 0.5; m[14] = 0.5; m[15] = 1; return this; } setReflection(normal, distance) { const a = normal.x; const b = normal.y; const c = normal.z; const data = this.data; data[0] = 1 - 2 * a * a; data[1] = -2 * a * b; data[2] = -2 * a * c; data[3] = 0; data[4] = -2 * a * b; data[5] = 1 - 2 * b * b; data[6] = -2 * b * c; data[7] = 0; data[8] = -2 * a * c; data[9] = -2 * b * c; data[10] = 1 - 2 * c * c; data[11] = 0; data[12] = -2 * a * distance; data[13] = -2 * b * distance; data[14] = -2 * c * distance; data[15] = 1; return this; } invert(src = this) { const s = src.data; const a00 = s[0]; const a01 = s[1]; const a02 = s[2]; const a03 = s[3]; const a10 = s[4]; const a11 = s[5]; const a12 = s[6]; const a13 = s[7]; const a20 = s[8]; const a21 = s[9]; const a22 = s[10]; const a23 = s[11]; const a30 = s[12]; const a31 = s[13]; const a32 = s[14]; const a33 = s[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; const b02 = a00 * a13 - a03 * a10; const b03 = a01 * a12 - a02 * a11; const b04 = a01 * a13 - a03 * a11; const b05 = a02 * a13 - a03 * a12; const b06 = a20 * a31 - a21 * a30; const b07 = a20 * a32 - a22 * a30; const b08 = a20 * a33 - a23 * a30; const b09 = a21 * a32 - a22 * a31; const b10 = a21 * a33 - a23 * a31; const b11 = a22 * a33 - a23 * a32; const det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (det === 0) { this.setIdentity(); } else { const invDet = 1 / det; const t = this.data; t[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; t[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; t[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; t[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; t[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; t[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; t[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; t[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; t[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; t[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; t[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; t[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; t[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; t[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; t[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; t[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; } 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]; dst[9] = src[9]; dst[10] = src[10]; dst[11] = src[11]; dst[12] = src[12]; dst[13] = src[13]; dst[14] = src[14]; dst[15] = src[15]; return this; } setIdentity() { const m = this.data; m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return this; } setTRS(t, r, s) { const qx = r.x; const qy = r.y; const qz = r.z; const qw = r.w; const sx = s.x; const sy = s.y; const sz = s.z; 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)) * sx; m[1] = (xy + wz) * sx; m[2] = (xz - wy) * sx; m[3] = 0; m[4] = (xy - wz) * sy; m[5] = (1 - (xx + zz)) * sy; m[6] = (yz + wx) * sy; m[7] = 0; m[8] = (xz + wy) * sz; m[9] = (yz - wx) * sz; m[10] = (1 - (xx + yy)) * sz; m[11] = 0; m[12] = t.x; m[13] = t.y; m[14] = t.z; m[15] = 1; return this; } transpose(src = this) { const s = src.data;