@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
JavaScript
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;