UNPKG

manifold-3d

Version:

Geometry library for topological robustness

1,371 lines (1,369 loc) 1.72 MB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // node_modules/property-graph/dist/index.mjs var EventDispatcher, GraphEdge, Graph, RefList, RefSet, RefMap, $attributes, $immutableKeys, GraphNode; var init_dist = __esm({ "node_modules/property-graph/dist/index.mjs"() { EventDispatcher = class { _listeners = {}; addEventListener(type, listener) { const listeners = this._listeners; if (listeners[type] === void 0) listeners[type] = []; if (listeners[type].indexOf(listener) === -1) listeners[type].push(listener); return this; } removeEventListener(type, listener) { const listenerArray = this._listeners[type]; if (listenerArray !== void 0) { const index = listenerArray.indexOf(listener); if (index !== -1) listenerArray.splice(index, 1); } return this; } dispatchEvent(event) { const listenerArray = this._listeners[event.type]; if (listenerArray !== void 0) { const array = listenerArray.slice(0); for (let i = 0, l = array.length; i < l; i++) array[i].call(this, event); } return this; } dispose() { for (const key in this._listeners) delete this._listeners[key]; } }; GraphEdge = class { _disposed = false; _name; _parent; _child; _attributes; constructor(_name, _parent, _child, _attributes = {}) { this._name = _name; this._parent = _parent; this._child = _child; this._attributes = _attributes; if (!_parent.isOnGraph(_child)) throw new Error("Cannot connect disconnected graphs."); } /** Name (attribute name from parent {@link GraphNode}). */ getName() { return this._name; } /** Owner node. */ getParent() { return this._parent; } /** Resource node. */ getChild() { return this._child; } /** * Sets the child node. * * @internal Only {@link Graph} implementations may safely call this method directly. Use * {@link Property.swap} or {@link Graph.swapChild} instead. */ setChild(child) { this._child = child; return this; } /** Attributes of the graph node relationship. */ getAttributes() { return this._attributes; } /** Destroys a (currently intact) edge, updating both the graph and the owner. */ dispose() { if (this._disposed) return; this._parent._destroyRef(this); this._disposed = true; } /** Whether this link has been destroyed. */ isDisposed() { return this._disposed; } }; Graph = class extends EventDispatcher { _emptySet = /* @__PURE__ */ new Set(); _edges = /* @__PURE__ */ new Set(); _parentEdges = /* @__PURE__ */ new Map(); _childEdges = /* @__PURE__ */ new Map(); /** Returns a list of all parent->child edges on this graph. */ listEdges() { return Array.from(this._edges); } /** Returns a list of all edges on the graph having the given node as their child. */ listParentEdges(node) { return Array.from(this._childEdges.get(node) || this._emptySet); } /** Returns a list of parent nodes for the given child node. */ listParents(node) { const parentSet = /* @__PURE__ */ new Set(); for (const edge of this.listParentEdges(node)) parentSet.add(edge.getParent()); return Array.from(parentSet); } /** Returns a list of all edges on the graph having the given node as their parent. */ listChildEdges(node) { return Array.from(this._parentEdges.get(node) || this._emptySet); } /** Returns a list of child nodes for the given parent node. */ listChildren(node) { const childSet = /* @__PURE__ */ new Set(); for (const edge of this.listChildEdges(node)) childSet.add(edge.getChild()); return Array.from(childSet); } disconnectParents(node, filter) { for (const edge of this.listParentEdges(node)) if (!filter || filter(edge.getParent())) edge.dispose(); return this; } /********************************************************************************************** * Internal. */ /** * Creates a {@link GraphEdge} connecting two {@link GraphNode} instances. Edge is returned * for the caller to store. * @param a Owner * @param b Resource * @hidden * @internal */ _createEdge(name, a, b, attributes) { const edge = new GraphEdge(name, a, b, attributes); this._edges.add(edge); const parent = edge.getParent(); if (!this._parentEdges.has(parent)) this._parentEdges.set(parent, /* @__PURE__ */ new Set()); this._parentEdges.get(parent).add(edge); const child = edge.getChild(); if (!this._childEdges.has(child)) this._childEdges.set(child, /* @__PURE__ */ new Set()); this._childEdges.get(child).add(edge); return edge; } /** * Detaches a {@link GraphEdge} from the {@link Graph}. Before calling this * method, ensure that the GraphEdge has first been detached from any * associated {@link GraphNode} attributes. * @hidden * @internal */ _destroyEdge(edge) { this._edges.delete(edge); this._parentEdges.get(edge.getParent()).delete(edge); this._childEdges.get(edge.getChild()).delete(edge); return this; } }; RefList = class { list = []; constructor(refs) { if (refs) for (const ref of refs) this.list.push(ref); } add(ref) { this.list.push(ref); } remove(ref) { const index = this.list.indexOf(ref); if (index >= 0) this.list.splice(index, 1); } removeChild(child) { const refs = []; for (const ref of this.list) if (ref.getChild() === child) refs.push(ref); for (const ref of refs) this.remove(ref); return refs; } listRefsByChild(child) { const refs = []; for (const ref of this.list) if (ref.getChild() === child) refs.push(ref); return refs; } values() { return this.list; } }; RefSet = class { set = /* @__PURE__ */ new Set(); map = /* @__PURE__ */ new Map(); constructor(refs) { if (refs) for (const ref of refs) this.add(ref); } add(ref) { const child = ref.getChild(); this.removeChild(child); this.set.add(ref); this.map.set(child, ref); } remove(ref) { this.set.delete(ref); this.map.delete(ref.getChild()); } removeChild(child) { const ref = this.map.get(child) || null; if (ref) this.remove(ref); return ref; } getRefByChild(child) { return this.map.get(child) || null; } values() { return Array.from(this.set); } }; RefMap = class { map = {}; constructor(map) { if (map) Object.assign(this.map, map); } set(key, child) { this.map[key] = child; } delete(key) { delete this.map[key]; } get(key) { return this.map[key] || null; } keys() { return Object.keys(this.map); } values() { return Object.values(this.map); } }; $attributes = /* @__PURE__ */ Symbol("attributes"); $immutableKeys = /* @__PURE__ */ Symbol("immutableKeys"); GraphNode = class GraphNode2 extends EventDispatcher { _disposed = false; /** * Internal graph used to search and maintain references. * @hidden */ graph; /** * Attributes (literal values and GraphNode references) associated with this instance. For each * GraphNode reference, the attributes stores a {@link GraphEdge}. List and Map references are * stored as arrays and dictionaries of edges. * @internal */ [$attributes]; /** * Attributes included with `getDefaultAttributes` are considered immutable, and cannot be * modifed by `.setRef()`, `.copy()`, or other GraphNode methods. Both the edges and the * properties will be disposed with the parent GraphNode. * * Currently, only single-edge references (getRef/setRef) are supported as immutables. * * @internal */ [$immutableKeys]; constructor(graph) { super(); this.graph = graph; this[$immutableKeys] = /* @__PURE__ */ new Set(); this[$attributes] = this._createAttributes(); } /** * Returns default attributes for the graph node. Subclasses having any attributes (either * literal values or references to other graph nodes) must override this method. Literal * attributes should be given their default values, if any. References should generally be * initialized as empty (Ref → null, RefList → [], RefMap → {}) and then modified by setters. * * Any single-edge references (setRef) returned by this method will be considered immutable, * to be owned by and disposed with the parent node. Multi-edge references (addRef, removeRef, * setRefMap) cannot be returned as default attributes. */ getDefaults() { return {}; } /** * Constructs and returns an object used to store a graph nodes attributes. Compared to the * default Attributes interface, this has two distinctions: * * 1. Slots for GraphNode<T> objects are replaced with slots for GraphEdge<this, GraphNode<T>> * 2. GraphNode<T> objects provided as defaults are considered immutable * * @internal */ _createAttributes() { const defaultAttributes = this.getDefaults(); const attributes = {}; for (const key in defaultAttributes) { const value2 = defaultAttributes[key]; if (value2 instanceof GraphNode2) { const ref = this.graph._createEdge(key, this, value2); this[$immutableKeys].add(key); attributes[key] = ref; } else attributes[key] = value2; } return attributes; } /** @internal Returns true if two nodes are on the same {@link Graph}. */ isOnGraph(other) { return this.graph === other.graph; } /** Returns true if the node has been permanently removed from the graph. */ isDisposed() { return this._disposed; } /** * Removes both inbound references to and outbound references from this object. At the end * of the process the object holds no references, and nothing holds references to it. A * disposed object is not reusable. */ dispose() { if (this._disposed) return; this.graph.listChildEdges(this).forEach((edge) => edge.dispose()); this.graph.disconnectParents(this); this._disposed = true; this.dispatchEvent({ type: "dispose" }); } /** * Removes all inbound references to this object. At the end of the process the object is * considered 'detached': it may hold references to child resources, but nothing holds * references to it. A detached object may be re-attached. */ detach() { this.graph.disconnectParents(this); return this; } /** * Transfers this object's references from the old node to the new one. The old node is fully * detached from this parent at the end of the process. * * @hidden */ swap(prevValue, nextValue) { for (const attribute in this[$attributes]) { const value2 = this[$attributes][attribute]; if (value2 instanceof GraphEdge) { const ref = value2; if (ref.getChild() === prevValue) this.setRef(attribute, nextValue, ref.getAttributes()); } else if (value2 instanceof RefList) for (const ref of value2.listRefsByChild(prevValue)) { const refAttributes = ref.getAttributes(); this.removeRef(attribute, prevValue); this.addRef(attribute, nextValue, refAttributes); } else if (value2 instanceof RefSet) { const ref = value2.getRefByChild(prevValue); if (ref) { const refAttributes = ref.getAttributes(); this.removeRef(attribute, prevValue); this.addRef(attribute, nextValue, refAttributes); } } else if (value2 instanceof RefMap) for (const key of value2.keys()) { const ref = value2.get(key); if (ref.getChild() === prevValue) this.setRefMap(attribute, key, nextValue, ref.getAttributes()); } } return this; } /********************************************************************************************** * Literal attributes. */ /** @hidden */ get(attribute) { return this[$attributes][attribute]; } /** @hidden */ set(attribute, value2) { this[$attributes][attribute] = value2; return this.dispatchEvent({ type: "change", attribute }); } /********************************************************************************************** * Ref: 1:1 graph node references. */ /** @hidden */ getRef(attribute) { const ref = this[$attributes][attribute]; return ref ? ref.getChild() : null; } /** @hidden */ setRef(attribute, value2, attributes) { if (this[$immutableKeys].has(attribute)) throw new Error(`Cannot overwrite immutable attribute, "${attribute}".`); const prevRef = this[$attributes][attribute]; if (prevRef) prevRef.dispose(); if (!value2) return this; const ref = this.graph._createEdge(attribute, this, value2, attributes); this[$attributes][attribute] = ref; return this.dispatchEvent({ type: "change", attribute }); } /********************************************************************************************** * RefList: 1:many graph node references. */ /** @hidden */ listRefs(attribute) { return this.assertRefList(attribute).values().map((ref) => ref.getChild()); } /** @hidden */ addRef(attribute, value2, attributes) { const ref = this.graph._createEdge(attribute, this, value2, attributes); this.assertRefList(attribute).add(ref); return this.dispatchEvent({ type: "change", attribute }); } /** @hidden */ removeRef(attribute, value2) { const refs = this.assertRefList(attribute); if (refs instanceof RefList) for (const ref of refs.listRefsByChild(value2)) ref.dispose(); else { const ref = refs.getRefByChild(value2); if (ref) ref.dispose(); } return this; } /** @hidden */ assertRefList(attribute) { const refs = this[$attributes][attribute]; if (refs instanceof RefList || refs instanceof RefSet) return refs; throw new Error(`Expected RefList or RefSet for attribute "${attribute}"`); } /********************************************************************************************** * RefMap: Named 1:many (map) graph node references. */ /** @hidden */ listRefMapKeys(attribute) { return this.assertRefMap(attribute).keys(); } /** @hidden */ listRefMapValues(attribute) { return this.assertRefMap(attribute).values().map((ref) => ref.getChild()); } /** @hidden */ getRefMap(attribute, key) { const ref = this.assertRefMap(attribute).get(key); return ref ? ref.getChild() : null; } /** @hidden */ setRefMap(attribute, key, value2, metadata) { const refMap = this.assertRefMap(attribute); const prevRef = refMap.get(key); if (prevRef) prevRef.dispose(); if (!value2) return this; metadata = Object.assign(metadata || {}, { key }); const ref = this.graph._createEdge(attribute, this, value2, { ...metadata, key }); refMap.set(key, ref); return this.dispatchEvent({ type: "change", attribute, key }); } /** @hidden */ assertRefMap(attribute) { const map = this[$attributes][attribute]; if (map instanceof RefMap) return map; throw new Error(`Expected RefMap for attribute "${attribute}"`); } /********************************************************************************************** * Events. */ /** * Dispatches an event on the GraphNode, and on the associated * Graph. Event types on the graph are prefixed, `"node:[type]"`. */ dispatchEvent(event) { super.dispatchEvent({ ...event, target: this }); this.graph.dispatchEvent({ ...event, target: this, type: `node:${event.type}` }); return this; } /********************************************************************************************** * Internal. */ /** @hidden */ _destroyRef(ref) { const attribute = ref.getName(); if (this[$attributes][attribute] === ref) { this[$attributes][attribute] = null; if (this[$immutableKeys].has(attribute)) ref.getChild().dispose(); } else if (this[$attributes][attribute] instanceof RefList) this[$attributes][attribute].remove(ref); else if (this[$attributes][attribute] instanceof RefSet) this[$attributes][attribute].remove(ref); else if (this[$attributes][attribute] instanceof RefMap) { const refMap = this[$attributes][attribute]; for (const key of refMap.keys()) if (refMap.get(key) === ref) refMap.delete(key); } else return; this.graph._destroyEdge(ref); this.dispatchEvent({ type: "change", attribute }); } }; } }); // node_modules/@gltf-transform/core/dist/index.modern.js function validateJPEGBuffer(view, i) { if (i > view.byteLength) { throw new TypeError("Corrupt JPG, exceeded buffer limits"); } if (view.getUint8(i) !== 255) { throw new TypeError("Invalid JPG, marker table corrupted"); } return view; } function create() { var out = new ARRAY_TYPE(3); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } return out; } function length(a) { var x = a[0]; var y = a[1]; var z = a[2]; return Math.sqrt(x * x + y * y + z * z); } function transformMat4(out, a, m) { var x = a[0], y = a[1], z = a[2]; var w = m[3] * x + m[7] * y + m[11] * z + m[15]; w = w || 1; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; return out; } function getBounds(node) { const resultBounds = createBounds(); const parents = node.propertyType === PropertyType.NODE ? [node] : node.listChildren(); for (const parent of parents) { parent.traverse((node2) => { const mesh = node2.getMesh(); if (!mesh) return; const meshBounds = getMeshBounds(mesh, node2.getWorldMatrix()); if (meshBounds.min.every(isFinite) && meshBounds.max.every(isFinite)) { expandBounds(meshBounds.min, resultBounds); expandBounds(meshBounds.max, resultBounds); } }); } return resultBounds; } function getMeshBounds(mesh, worldMatrix) { const meshBounds = createBounds(); for (const prim of mesh.listPrimitives()) { const position = prim.getAttribute("POSITION"); const indices = prim.getIndices(); if (!position) continue; let localPos = [0, 0, 0]; let worldPos = [0, 0, 0]; for (let i = 0, il = indices ? indices.getCount() : position.getCount(); i < il; i++) { const index = indices ? indices.getScalar(i) : i; localPos = position.getElement(index, localPos); worldPos = transformMat4(worldPos, localPos, worldMatrix); expandBounds(worldPos, meshBounds); } } return meshBounds; } function expandBounds(point, target) { for (let i = 0; i < 3; i++) { target.min[i] = Math.min(point[i], target.min[i]); target.max[i] = Math.max(point[i], target.max[i]); } } function createBounds() { return { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] }; } function isObject(o) { return Object.prototype.toString.call(o) === "[object Object]"; } function isPlainObject(o) { if (isObject(o) === false) return false; const ctor = o.constructor; if (ctor === void 0) return true; const prot = ctor.prototype; if (isObject(prot) === false) return false; if (Object.hasOwn(prot, "isPrototypeOf") === false) { return false; } return true; } function determinant(a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b0 = a00 * a11 - a01 * a10; var b1 = a00 * a12 - a02 * a10; var b22 = a01 * a12 - a02 * a11; var b3 = a20 * a31 - a21 * a30; var b42 = a20 * a32 - a22 * a30; var b5 = a21 * a32 - a22 * a31; var b6 = a00 * b5 - a01 * b42 + a02 * b3; var b7 = a10 * b5 - a11 * b42 + a12 * b3; var b82 = a20 * b22 - a21 * b1 + a22 * b0; var b9 = a30 * b22 - a31 * b1 + a32 * b0; return a13 * b6 - a03 * b7 + a33 * b82 - a23 * b9; } function multiply(out, a, b) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b0 = b[0], b1 = b[1], b22 = b[2], b3 = b[3]; out[0] = b0 * a00 + b1 * a10 + b22 * a20 + b3 * a30; out[1] = b0 * a01 + b1 * a11 + b22 * a21 + b3 * a31; out[2] = b0 * a02 + b1 * a12 + b22 * a22 + b3 * a32; out[3] = b0 * a03 + b1 * a13 + b22 * a23 + b3 * a33; b0 = b[4]; b1 = b[5]; b22 = b[6]; b3 = b[7]; out[4] = b0 * a00 + b1 * a10 + b22 * a20 + b3 * a30; out[5] = b0 * a01 + b1 * a11 + b22 * a21 + b3 * a31; out[6] = b0 * a02 + b1 * a12 + b22 * a22 + b3 * a32; out[7] = b0 * a03 + b1 * a13 + b22 * a23 + b3 * a33; b0 = b[8]; b1 = b[9]; b22 = b[10]; b3 = b[11]; out[8] = b0 * a00 + b1 * a10 + b22 * a20 + b3 * a30; out[9] = b0 * a01 + b1 * a11 + b22 * a21 + b3 * a31; out[10] = b0 * a02 + b1 * a12 + b22 * a22 + b3 * a32; out[11] = b0 * a03 + b1 * a13 + b22 * a23 + b3 * a33; b0 = b[12]; b1 = b[13]; b22 = b[14]; b3 = b[15]; out[12] = b0 * a00 + b1 * a10 + b22 * a20 + b3 * a30; out[13] = b0 * a01 + b1 * a11 + b22 * a21 + b3 * a31; out[14] = b0 * a02 + b1 * a12 + b22 * a22 + b3 * a32; out[15] = b0 * a03 + b1 * a13 + b22 * a23 + b3 * a33; return out; } function getScaling(out, mat) { var m11 = mat[0]; var m12 = mat[1]; var m13 = mat[2]; var m21 = mat[4]; var m22 = mat[5]; var m23 = mat[6]; var m31 = mat[8]; var m32 = mat[9]; var m33 = mat[10]; out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13); out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23); out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33); return out; } function getRotation(out, mat) { var scaling = new ARRAY_TYPE(3); getScaling(scaling, mat); var is1 = 1 / scaling[0]; var is2 = 1 / scaling[1]; var is3 = 1 / scaling[2]; var sm11 = mat[0] * is1; var sm12 = mat[1] * is2; var sm13 = mat[2] * is3; var sm21 = mat[4] * is1; var sm22 = mat[5] * is2; var sm23 = mat[6] * is3; var sm31 = mat[8] * is1; var sm32 = mat[9] * is2; var sm33 = mat[10] * is3; var trace = sm11 + sm22 + sm33; var S = 0; if (trace > 0) { S = Math.sqrt(trace + 1) * 2; out[3] = 0.25 * S; out[0] = (sm23 - sm32) / S; out[1] = (sm31 - sm13) / S; out[2] = (sm12 - sm21) / S; } else if (sm11 > sm22 && sm11 > sm33) { S = Math.sqrt(1 + sm11 - sm22 - sm33) * 2; out[3] = (sm23 - sm32) / S; out[0] = 0.25 * S; out[1] = (sm12 + sm21) / S; out[2] = (sm31 + sm13) / S; } else if (sm22 > sm33) { S = Math.sqrt(1 + sm22 - sm11 - sm33) * 2; out[3] = (sm31 - sm13) / S; out[0] = (sm12 + sm21) / S; out[1] = 0.25 * S; out[2] = (sm23 + sm32) / S; } else { S = Math.sqrt(1 + sm33 - sm11 - sm22) * 2; out[3] = (sm12 - sm21) / S; out[0] = (sm31 + sm13) / S; out[1] = (sm23 + sm32) / S; out[2] = 0.25 * S; } return out; } function equalsRef(refA, refB) { if (!!refA !== !!refB) return false; const a = refA.getChild(); const b = refB.getChild(); return a === b || a.equals(b); } function equalsRefSet(refSetA, refSetB) { if (!!refSetA !== !!refSetB) return false; const refValuesA = refSetA.values(); const refValuesB = refSetB.values(); if (refValuesA.length !== refValuesB.length) return false; for (let i = 0; i < refValuesA.length; i++) { const a = refValuesA[i]; const b = refValuesB[i]; if (a.getChild() === b.getChild()) continue; if (!a.getChild().equals(b.getChild())) return false; } return true; } function equalsRefMap(refMapA, refMapB) { if (!!refMapA !== !!refMapB) return false; const keysA = refMapA.keys(); const keysB = refMapB.keys(); if (keysA.length !== keysB.length) return false; for (const key of keysA) { const refA = refMapA.get(key); const refB = refMapB.get(key); if (!!refA !== !!refB) return false; const a = refA.getChild(); const b = refB.getChild(); if (a === b) continue; if (!a.equals(b)) return false; } return true; } function equalsArray(a, b) { if (a === b) return true; if (!!a !== !!b || !a || !b) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } function equalsObject(_a2, _b2) { if (_a2 === _b2) return true; if (!!_a2 !== !!_b2) return false; if (!isPlainObject(_a2) || !isPlainObject(_b2)) { return _a2 === _b2; } const a = _a2; const b = _b2; let numKeysA = 0; let numKeysB = 0; let key; for (key in a) numKeysA++; for (key in b) numKeysB++; if (numKeysA !== numKeysB) return false; for (key in a) { const valueA = a[key]; const valueB = b[key]; if (isArray(valueA) && isArray(valueB)) { if (!equalsArray(valueA, valueB)) return false; } else if (isPlainObject(valueA) && isPlainObject(valueB)) { if (!equalsObject(valueA, valueB)) return false; } else { if (valueA !== valueB) return false; } } return true; } function isArray(value2) { return Array.isArray(value2) || ArrayBuffer.isView(value2); } function arrayToComponentType(array) { switch (array.constructor) { case Float32Array: return Accessor.ComponentType.FLOAT; case Uint32Array: return Accessor.ComponentType.UNSIGNED_INT; case Uint16Array: return Accessor.ComponentType.UNSIGNED_SHORT; case Uint8Array: return Accessor.ComponentType.UNSIGNED_BYTE; case Int16Array: return Accessor.ComponentType.SHORT; case Int8Array: return Accessor.ComponentType.BYTE; default: throw new Error("Unknown accessor componentType."); } } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function(n2) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n2[r] = t[r]); } return n2; }, _extends.apply(null, arguments); } function getInterleavedArray(accessorDef, context) { const jsonDoc = context.jsonDoc; const bufferView = context.bufferViews[accessorDef.bufferView]; const bufferViewDef = jsonDoc.json.bufferViews[accessorDef.bufferView]; const TypedArray = ComponentTypeToTypedArray[accessorDef.componentType]; const elementSize = Accessor.getElementSize(accessorDef.type); const componentSize = TypedArray.BYTES_PER_ELEMENT; const accessorByteOffset = accessorDef.byteOffset || 0; const array = new TypedArray(accessorDef.count * elementSize); const view = new DataView(bufferView.buffer, bufferView.byteOffset, bufferView.byteLength); const byteStride = bufferViewDef.byteStride; for (let i = 0; i < accessorDef.count; i++) { for (let j = 0; j < elementSize; j++) { const byteOffset = accessorByteOffset + i * byteStride + j * componentSize; let value2; switch (accessorDef.componentType) { case Accessor.ComponentType.FLOAT: value2 = view.getFloat32(byteOffset, true); break; case Accessor.ComponentType.UNSIGNED_INT: value2 = view.getUint32(byteOffset, true); break; case Accessor.ComponentType.UNSIGNED_SHORT: value2 = view.getUint16(byteOffset, true); break; case Accessor.ComponentType.UNSIGNED_BYTE: value2 = view.getUint8(byteOffset); break; case Accessor.ComponentType.SHORT: value2 = view.getInt16(byteOffset, true); break; case Accessor.ComponentType.BYTE: value2 = view.getInt8(byteOffset); break; default: throw new Error(`Unexpected componentType "${accessorDef.componentType}".`); } array[i * elementSize + j] = value2; } } return array; } function getAccessorArray(accessorDef, context) { const jsonDoc = context.jsonDoc; const bufferView = context.bufferViews[accessorDef.bufferView]; const bufferViewDef = jsonDoc.json.bufferViews[accessorDef.bufferView]; const TypedArray = ComponentTypeToTypedArray[accessorDef.componentType]; const elementSize = Accessor.getElementSize(accessorDef.type); const componentSize = TypedArray.BYTES_PER_ELEMENT; const elementStride = elementSize * componentSize; if (bufferViewDef.byteStride !== void 0 && bufferViewDef.byteStride !== elementStride) { return getInterleavedArray(accessorDef, context); } const byteOffset = bufferView.byteOffset + (accessorDef.byteOffset || 0); const byteLength = accessorDef.count * elementSize * componentSize; return new TypedArray(bufferView.buffer.slice(byteOffset, byteOffset + byteLength)); } function getSparseArray(accessorDef, context) { const TypedArray = ComponentTypeToTypedArray[accessorDef.componentType]; const elementSize = Accessor.getElementSize(accessorDef.type); let array; if (accessorDef.bufferView !== void 0) { array = getAccessorArray(accessorDef, context); } else { array = new TypedArray(accessorDef.count * elementSize); } const sparseDef = accessorDef.sparse; if (!sparseDef) return array; const count = sparseDef.count; const indicesDef = _extends({}, accessorDef, sparseDef.indices, { count, type: "SCALAR" }); const valuesDef = _extends({}, accessorDef, sparseDef.values, { count }); const indices = getAccessorArray(indicesDef, context); const values = getAccessorArray(valuesDef, context); for (let i = 0; i < indicesDef.count; i++) { for (let j = 0; j < elementSize; j++) { array[indices[i] * elementSize + j] = values[i * elementSize + j]; } } return array; } function getSlot(document, texture) { const edge = document.getGraph().listParentEdges(texture).find((edge2) => edge2.getParent() !== document.getRoot()); return edge ? edge.getName().replace(/texture$/i, "") : ""; } function clean(object) { const unused = []; for (const key in object) { const value2 = object[key]; if (Array.isArray(value2) && value2.length === 0) { unused.push(key); } else if (value2 === null || value2 === "") { unused.push(key); } else if (value2 && typeof value2 === "object" && Object.keys(value2).length === 0) { unused.push(key); } } for (const key of unused) { delete object[key]; } } function isExternalBuffer(jsonDocument, bufferDef) { return bufferDef.uri !== void 0 && !(bufferDef.uri in jsonDocument.resources); } function isExternalImage(jsonDocument, imageDef) { return imageDef.uri !== void 0 && !(imageDef.uri in jsonDocument.resources) && imageDef.bufferView === void 0; } function isGLB(view) { if (view.byteLength < 3 * Uint32Array.BYTES_PER_ELEMENT) return false; const header = new Uint32Array(view.buffer, view.byteOffset, 3); return header[0] === 1179937895 && header[1] === 2; } var VERSION, GLB_BUFFER, PropertyType, VertexLayout, BufferViewUsage$1, TextureChannel, Format, ComponentTypeToTypedArray, BufferUtils, JPEGImageUtils, PNGImageUtils, ImageUtils, FileUtils, ARRAY_TYPE, NULL_DOMAIN, HTTPUtils, _Logger, Verbosity, Logger, MathUtils, ALPHABET, UNIQUE_RETRIES, ID_LENGTH, previousIDs, generateOne, uuid, COPY_IDENTITY, EMPTY_SET, Property, ExtensibleProperty, Accessor, Animation, AnimationChannel, AnimationSampler, Buffer$1, Camera, ExtensionProperty, TextureInfo, R, G, B, A, Material, Mesh, Node, Primitive, PrimitiveTarget, Scene, Skin, Texture, Root, Document, Extension, ReaderContext, DEFAULT_OPTIONS, SUPPORTED_PREREAD_TYPES, GLTFReader, BufferViewTarget, WriterContext, UniqueURIGenerator, BufferViewUsage, UNSIGNED_INT, UNSIGNED_SHORT, UNSIGNED_BYTE, SUPPORTED_PREWRITE_TYPES, GLTFWriter, ChunkType, PlatformIO, WebIO; var init_index_modern = __esm({ "node_modules/@gltf-transform/core/dist/index.modern.js"() { init_dist(); init_dist(); VERSION = `v${"4.3.0"}`; GLB_BUFFER = "@glb.bin"; (function(PropertyType2) { PropertyType2["ACCESSOR"] = "Accessor"; PropertyType2["ANIMATION"] = "Animation"; PropertyType2["ANIMATION_CHANNEL"] = "AnimationChannel"; PropertyType2["ANIMATION_SAMPLER"] = "AnimationSampler"; PropertyType2["BUFFER"] = "Buffer"; PropertyType2["CAMERA"] = "Camera"; PropertyType2["MATERIAL"] = "Material"; PropertyType2["MESH"] = "Mesh"; PropertyType2["PRIMITIVE"] = "Primitive"; PropertyType2["PRIMITIVE_TARGET"] = "PrimitiveTarget"; PropertyType2["NODE"] = "Node"; PropertyType2["ROOT"] = "Root"; PropertyType2["SCENE"] = "Scene"; PropertyType2["SKIN"] = "Skin"; PropertyType2["TEXTURE"] = "Texture"; PropertyType2["TEXTURE_INFO"] = "TextureInfo"; })(PropertyType || (PropertyType = {})); (function(VertexLayout2) { VertexLayout2["INTERLEAVED"] = "interleaved"; VertexLayout2["SEPARATE"] = "separate"; })(VertexLayout || (VertexLayout = {})); (function(BufferViewUsage2) { BufferViewUsage2["ARRAY_BUFFER"] = "ARRAY_BUFFER"; BufferViewUsage2["ELEMENT_ARRAY_BUFFER"] = "ELEMENT_ARRAY_BUFFER"; BufferViewUsage2["INVERSE_BIND_MATRICES"] = "INVERSE_BIND_MATRICES"; BufferViewUsage2["OTHER"] = "OTHER"; BufferViewUsage2["SPARSE"] = "SPARSE"; })(BufferViewUsage$1 || (BufferViewUsage$1 = {})); (function(TextureChannel2) { TextureChannel2[TextureChannel2["R"] = 4096] = "R"; TextureChannel2[TextureChannel2["G"] = 256] = "G"; TextureChannel2[TextureChannel2["B"] = 16] = "B"; TextureChannel2[TextureChannel2["A"] = 1] = "A"; })(TextureChannel || (TextureChannel = {})); (function(Format2) { Format2["GLTF"] = "GLTF"; Format2["GLB"] = "GLB"; })(Format || (Format = {})); ComponentTypeToTypedArray = { "5120": Int8Array, "5121": Uint8Array, "5122": Int16Array, "5123": Uint16Array, "5125": Uint32Array, "5126": Float32Array }; BufferUtils = class { /** Creates a byte array from a Data URI. */ static createBufferFromDataURI(dataURI) { if (typeof Buffer === "undefined") { const byteString = atob(dataURI.split(",")[1]); const ia = new Uint8Array(byteString.length); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return ia; } else { const data = dataURI.split(",")[1]; const isBase64 = dataURI.indexOf("base64") >= 0; return Buffer.from(data, isBase64 ? "base64" : "utf8"); } } /** Encodes text to a byte array. */ static encodeText(text) { return new TextEncoder().encode(text); } /** Decodes a byte array to text. */ static decodeText(array) { return new TextDecoder().decode(array); } /** * Concatenates N byte arrays. */ static concat(arrays) { let totalByteLength = 0; for (const array of arrays) { totalByteLength += array.byteLength; } const result = new Uint8Array(totalByteLength); let byteOffset = 0; for (const array of arrays) { result.set(array, byteOffset); byteOffset += array.byteLength; } return result; } /** * Pads a Uint8Array to the next 4-byte boundary. * * Reference: [glTF → Data Alignment](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment) */ static pad(srcArray, paddingByte = 0) { const paddedLength = this.padNumber(srcArray.byteLength); if (paddedLength === srcArray.byteLength) return srcArray; const dstArray = new Uint8Array(paddedLength); dstArray.set(srcArray); if (paddingByte !== 0) { for (let i = srcArray.byteLength; i < paddedLength; i++) { dstArray[i] = paddingByte; } } return dstArray; } /** Pads a number to 4-byte boundaries. */ static padNumber(v) { return Math.ceil(v / 4) * 4; } /** Returns true if given byte array instances are equal. */ static equals(a, b) { if (a === b) return true; if (a.byteLength !== b.byteLength) return false; let i = a.byteLength; while (i--) { if (a[i] !== b[i]) return false; } return true; } /** * Returns a Uint8Array view of a typed array, with the same underlying ArrayBuffer. * * A shorthand for: * * ```js * const buffer = new Uint8Array( * array.buffer, * array.byteOffset + byteOffset, * Math.min(array.byteLength, byteLength) * ); * ``` * */ static toView(a, byteOffset = 0, byteLength = Infinity) { return new Uint8Array(a.buffer, a.byteOffset + byteOffset, Math.min(a.byteLength, byteLength)); } static assertView(view) { if (view && !ArrayBuffer.isView(view)) { throw new Error(`Method requires Uint8Array parameter; received "${typeof view}".`); } return view; } }; JPEGImageUtils = class { match(array) { return array.length >= 3 && array[0] === 255 && array[1] === 216 && array[2] === 255; } getSize(array) { let view = new DataView(array.buffer, array.byteOffset + 4); let i, next; while (view.byteLength) { i = view.getUint16(0, false); validateJPEGBuffer(view, i); next = view.getUint8(i + 1); if (next === 192 || next === 193 || next === 194) { return [view.getUint16(i + 7, false), view.getUint16(i + 5, false)]; } view = new DataView(array.buffer, view.byteOffset + i + 2); } throw new TypeError("Invalid JPG, no size found"); } getChannels(_buffer) { return 3; } }; PNGImageUtils = class _PNGImageUtils { match(array) { return array.length >= 8 && array[0] === 137 && array[1] === 80 && array[2] === 78 && array[3] === 71 && array[4] === 13 && array[5] === 10 && array[6] === 26 && array[7] === 10; } getSize(array) { const view = new DataView(array.buffer, array.byteOffset); const magic = BufferUtils.decodeText(array.slice(12, 16)); if (magic === _PNGImageUtils.PNG_FRIED_CHUNK_NAME) { return [view.getUint32(32, false), view.getUint32(36, false)]; } return [view.getUint32(16, false), view.getUint32(20, false)]; } getChannels(_buffer) { return 4; } }; PNGImageUtils.PNG_FRIED_CHUNK_NAME = "CgBI"; ImageUtils = class { /** Registers support for a new image format; useful for certain extensions. */ static registerFormat(mimeType, impl) { this.impls[mimeType] = impl; } /** * Returns detected MIME type of the given image buffer. Note that for image * formats with support provided by extensions, the extension must be * registered with an I/O class before it can be detected by ImageUtils. */ static getMimeType(buffer) { for (const mimeType in this.impls) { if (this.impls[mimeType].match(buffer)) { return mimeType; } } return null; } /** Returns the dimensions of the image. */ static getSize(buffer, mimeType) { if (!this.impls[mimeType]) return null; return this.impls[mimeType].getSize(buffer); } /** * Returns a conservative estimate of the number of channels in the image. For some image * formats, the method may return 4 indicating the possibility of an alpha channel, without * the ability to guarantee that an alpha channel is present. */ static getChannels(buffer, mimeType) { if (!this.impls[mimeType]) return null; return this.impls[mimeType].getChannels(buffer); } /** Returns a conservative estimate of the GPU memory required by this image. */ static getVRAMByteLength(buffer, mimeType) { if (!this.impls[mimeType]) return null; if (this.impls[mimeType].getVRAMByteLength) { return this.impls[mimeType].getVRAMByteLength(buffer); } let uncompressedBytes = 0; const channels = 4; const resolution = this.getSize(buffer, mimeType); if (!resolution) return null; while (resolution[0] > 1 || resolution[1] > 1) { uncompressedBytes += resolution[0] * resolution[1] * channels; resolution[0] = Math.max(Math.floor(resolution[0] / 2), 1); resolution[1] = Math.max(Math.floor(resolution[1] / 2), 1); } uncompressedBytes += 1 * 1 * channels; return uncompressedBytes; } /** Returns the preferred file extension for the given MIME type. */ static mimeTypeToExtension(mimeType) { if (mimeType === "image/jpeg") return "jpg"; return mimeType.split("/").pop(); } /** Returns the MIME type for the given file extension. */ static extensionToMimeType(extension) { if (extension === "jpg") return "image/jpeg"; if (!extension) return ""; return `image/${extension}`; } }; ImageUtils.impls = { "image/jpeg": new JPEGImageUtils(), "image/png": new PNGImageUtils() }; FileUtils = class { /** * Extracts the basename from a file path, e.g. "folder/model.glb" -> "model". * See: {@link HTTPUtils.basename} */ static basename(uri) { const fileName = uri.split(/[\\/]/).pop(); return fileName.substring(0, fileName.lastIndexOf(".")); } /** * Extracts the extension from a file path, e.g. "folder/model.glb" -> "glb". * See: {@link HTTPUtils.extension} */ static extension(uri) { if (uri.startsWith("data:image/")) { const mimeType = uri.match(/data:(image\/\w+)/)[1]; return ImageUtils.mimeTypeToExtension(mimeType); } else if (uri.startsWith("data:model/gltf+json")) { return "gltf"; } else if (uri.startsWith("data:model/gltf-binary")) { return "glb"; } else if (uri.startsWith("data:application/")) { return "bin"; } return uri.split(/[\\/]/).pop().split(/[.]/).pop(); } }; ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array; (function() { var vec = create(); return function(a, stride, offset, count, fn, arg) { var i, l; if (!stride) { stride = 3; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; vec[2] = a[i + 2]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; a[i + 2] = vec[2]; } return a; }; })(); NULL_DOMAIN = "https://null.example"; HTTPUtils = class { static dirname(path) { const index = path.lastIndexOf("/"); if (index === -1) return "./"; return path.substring(0, index + 1); } /** * Extracts the basename from a URL, e.g. "folder/model.glb" -> "model". * See: {@link FileUtils.basename} */ static basename(uri) { return FileUtils.basename(new URL(uri, NULL_DOMAIN).pathname); } /** * Extracts the extension from a URL, e.g. "folder/model.glb" -> "glb". * See: {@link FileUtils.extension} */ static extension(uri) { return FileUtils.extension(new URL(uri, NULL_DOMAIN).pathname); } static resolve(base, path) { if (!this.isRelativePath(path)) return path; const stack = base.split("/"); const parts = path.split("/"); stack.pop(); for (let i = 0; i < parts.length; i++) { if (parts[i] === ".") continue; if (parts[i] === "..") { stack.pop(); } else { stack.push(parts[i]); } } return stack.join("/"); } /** * Returns true for URLs containing a protocol, and false for both * absolute and relative paths. */ static isAbsoluteURL(path) { return this.PROTOCOL_REGEXP.test(path); } /** * Returns true for paths that are declared relative to some unknown base * path. For example, "foo/bar/" is relative both "/foo/bar/" is not. */ static isRelativePath(path) { return !/^(?:[a-zA-Z]+:)?\//.test(path); } }; HTTPUtils.DEFAULT_INIT = {}; HTTPUtils.PROTOCOL_REGEXP = /^[a-zA-Z]+:\/\//; (function(Verbosity2) { Verbosity2[Verbosity2["SILENT"] = 4] = "SILENT"; Verbosity2[Verbosity2["ERROR"] = 3] = "ERROR"; Verbosity2[Verbosity2["WARN"] = 2] = "WARN"; Verbosity2[Verbosity2["INFO"] = 1] = "INFO"; Verbosity2[Verbosity2["DEBUG"] = 0] = "DEBUG"; })(Verbosity || (Verbosity = {})); Logger = class _Logger2 { /** Constructs a new Logger instance. */ constructor(verbosity) { this.verbosity = void 0; this.verbosity = verbosity; } /** Logs an event at level {@link Logger.Verbosity.DEBUG}. */ debug(text) { if (this.verbosity <= _Logger2.Verbosity.DEBUG) { console.debug(text); } } /** Logs an event at level {@link Logger.Verbosity.INFO}. */ info(text) { if (this.verbosity <= _Logger2.Verbosity.INFO) { console.info(text); } } /** Logs an event at level {@link Logger.Verbosity.WARN}. */ warn(text) { if (this.verbosity <= _Logger2.Verbosity.WARN) { console.warn(text); } } /** Logs an event at level {@link Logger.Verbosity.ERROR}. */ error(text) { if (this.verbosity <= _Logger2.Verbosity.ERROR) { console.error(text); } } }; _Logger = Logger; Logger.Verbosity = Verbosity; Logger.DEFAULT_INSTANCE = new _Logger(_Logger.Verbosity.INFO); MathUtils = class _MathUtils { static identity(v) { return v; } static eq(a, b, tolerance = 1e-5) { if (a.length !== b.length) return false; for (let