@giszhc/three-model-viewer 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,10 +5,14 @@ import { CSS2DObject as r, CSS2DRenderer as i } from "three/addons/renderers/CSS
5
5
  import * as a from "@tweenjs/tween.js";
6
6
  import { OBJLoader as o } from "three/addons/loaders/OBJLoader.js";
7
7
  import { MTLLoader as s } from "three/addons/loaders/MTLLoader.js";
8
- import { acceleratedRaycast as c, computeBoundsTree as l, disposeBoundsTree as u } from "three-mesh-bvh";
9
- import d from "jszip";
8
+ import { GLTFLoader as c } from "three/addons/loaders/GLTFLoader.js";
9
+ import { DRACOLoader as l } from "three/addons/loaders/DRACOLoader.js";
10
+ import { KTX2Loader as u } from "three/addons/loaders/KTX2Loader.js";
11
+ import { MeshoptDecoder as d } from "three/addons/libs/meshopt_decoder.module.js";
12
+ import { acceleratedRaycast as f, computeBoundsTree as p, disposeBoundsTree as m } from "three-mesh-bvh";
13
+ import h from "jszip";
10
14
  //#region src/core/SceneManager.ts
11
- var f = class {
15
+ var g = class {
12
16
  container;
13
17
  scene;
14
18
  camera;
@@ -73,7 +77,7 @@ var f = class {
73
77
  destroy() {
74
78
  this.isDestroyed = !0, this.animationFrameId !== null && cancelAnimationFrame(this.animationFrameId), this.resizeObserver && this.resizeObserver.disconnect(), this.controls.dispose(), this.renderer.dispose(), this.renderer.domElement.parentElement && this.renderer.domElement.parentElement.removeChild(this.renderer.domElement), this.labelRenderer.domElement.parentElement && this.labelRenderer.domElement.parentElement.removeChild(this.labelRenderer.domElement);
75
79
  }
76
- }, p = class {
80
+ }, _ = class {
77
81
  events;
78
82
  constructor() {
79
83
  this.events = /* @__PURE__ */ new Map();
@@ -100,52 +104,69 @@ var f = class {
100
104
  removeAllListeners(e) {
101
105
  return e ? this.events.delete(e) : this.events.clear(), this;
102
106
  }
103
- }, m = class {
107
+ }, v = class {
104
108
  static async extract(t, n) {
105
109
  let r;
106
- if (n?.(5, "正在读取文件字节流..."), typeof t == "string") {
110
+ if (n?.(5, "正在读取压缩包文件流..."), typeof t == "string") {
107
111
  let e = await fetch(t);
108
112
  if (!e.ok) throw Error(`Failed to fetch zip file: ${e.statusText}`);
109
113
  r = await e.arrayBuffer();
110
114
  } else r = t instanceof Blob || t instanceof File ? await t.arrayBuffer() : t;
111
115
  n?.(15, "正在解压 ZIP 文件包...");
112
- let i = await d.loadAsync(r), a = /* @__PURE__ */ new Map(), o = null, s = null, c = [
116
+ let i = await h.loadAsync(r), a = /* @__PURE__ */ new Map(), o = null, s = null, c = null, l = null, u = [
113
117
  ".png",
114
118
  ".jpg",
115
119
  ".jpeg",
116
120
  ".webp",
117
121
  ".bmp",
118
122
  ".tga",
119
- ".dds"
120
- ], l = Object.keys(i.files), u = l.length || 1;
121
- for (let e = 0; e < l.length; e++) {
122
- let t = l[e], r = i.files[t];
123
+ ".dds",
124
+ ".hdr",
125
+ ".svg",
126
+ ".ktx2"
127
+ ], d = Object.keys(i.files), f = d.length || 1;
128
+ for (let e = 0; e < d.length; e++) {
129
+ let t = d[e], r = i.files[t];
123
130
  if (r.dir || t.includes("__MACOSX") || t.split("/").pop()?.startsWith("._")) continue;
124
- let d = t.toLowerCase(), f = Math.round(20 + e / u * 35);
125
- if (d.endsWith(".obj") && !o ? (o = r, n?.(f, `找到模型文件: ${t.split("/").pop()}`)) : d.endsWith(".mtl") && !s && (s = r, n?.(f, `找到材质定义: ${t.split("/").pop()}`)), c.some((e) => d.endsWith(e))) {
126
- let e = t.split("/").pop() || t;
127
- n?.(f, `加载贴图: ${e}`);
128
- let i = await r.async("blob"), o = URL.createObjectURL(i);
129
- a.set(t, o), a.set(e, o), a.set(e.toLowerCase(), o);
131
+ let p = t.toLowerCase(), m = t.split("/").pop() || t, h = Math.round(20 + e / f * 35);
132
+ if (p.endsWith(".glb") && !o ? (o = r, n?.(h, `找到 GLB 二进制模型: ${m}`)) : p.endsWith(".gltf") && !s ? (s = r, n?.(h, `找到 GLTF 场景定义: ${m}`)) : p.endsWith(".obj") && !c ? (c = r, n?.(h, `找到 OBJ 网格模型: ${m}`)) : p.endsWith(".mtl") && !l && (l = r, n?.(h, `找到 MTL 材质定义: ${m}`)), p.endsWith(".bin")) {
133
+ n?.(h, `加载二进制缓冲区: ${m}`);
134
+ let e = await r.async("blob"), i = URL.createObjectURL(e);
135
+ a.set(t, i), a.set(m, i), a.set(m.toLowerCase(), i);
136
+ }
137
+ if (u.some((e) => p.endsWith(e))) {
138
+ n?.(h, `加载贴图资源: ${m}`);
139
+ let e = await r.async("blob"), i = URL.createObjectURL(e);
140
+ a.set(t, i), a.set(m, i), a.set(m.toLowerCase(), i);
130
141
  }
131
142
  }
132
- if (n?.(60, "提取完成,准备解析三维几何网格..."), !o) throw a.forEach((e) => URL.revokeObjectURL(e)), Error("No .obj file found in the zip archive.");
133
- let f = await o.async("string"), p = o.name, m = null, h = null;
134
- s && (m = await s.async("string"), h = s.name);
135
- let g = new e.LoadingManager();
136
- return g.setURLModifier((e) => {
137
- let t = decodeURIComponent(e), n = t.split("/").pop()?.split("\\").pop() || t;
143
+ n?.(60, "ZIP 资源索引提取完毕,准备解析三维模型网格...");
144
+ let p;
145
+ if (o) p = "glb";
146
+ else if (s) p = "gltf";
147
+ else if (c) p = "obj";
148
+ else throw a.forEach((e) => URL.revokeObjectURL(e)), Error("ZIP 压缩包中未检测到支持的 3D 模型文件(需要包含 .glb, .gltf 或 .obj 文件)");
149
+ let m, g, _ = null, v = null, y, b;
150
+ p === "glb" ? (y = await o.async("arraybuffer"), b = o.name) : p === "gltf" ? (y = await s.async("string"), b = s.name) : (m = await c.async("string"), g = c.name, l && (_ = await l.async("string"), v = l.name));
151
+ let x = new e.LoadingManager();
152
+ return x.setURLModifier((e) => {
153
+ let t = decodeURIComponent(e).replace(/^\.\//, ""), n = t.split("/").pop()?.split("\\").pop() || t;
154
+ if (a.has(e)) return a.get(e);
138
155
  if (a.has(t)) return a.get(t);
139
156
  if (a.has(n)) return a.get(n);
140
- for (let [e, t] of a.entries()) if (e.toLowerCase() === n.toLowerCase()) return t;
157
+ let r = n.toLowerCase();
158
+ for (let [e, t] of a.entries()) if (e.toLowerCase() === r || e.toLowerCase().endsWith("/" + r)) return t;
141
159
  return e;
142
160
  }), {
143
- objContent: f,
144
- objFileName: p,
145
- mtlContent: m,
146
- mtlFileName: h,
161
+ format: p,
162
+ objContent: m,
163
+ objFileName: g,
164
+ mtlContent: _,
165
+ mtlFileName: v,
166
+ gltfContent: y,
167
+ gltfFileName: b,
147
168
  blobUrls: a,
148
- loadingManager: g,
169
+ loadingManager: x,
149
170
  dispose: () => {
150
171
  a.forEach((e) => {
151
172
  try {
@@ -156,18 +177,63 @@ var f = class {
156
177
  };
157
178
  }
158
179
  };
159
- e.BufferGeometry.prototype.computeBoundsTree = l, e.BufferGeometry.prototype.disposeBoundsTree = u, e.Mesh.prototype.raycast = c;
160
- var h = class {
180
+ e.BufferGeometry.prototype.computeBoundsTree = p, e.BufferGeometry.prototype.disposeBoundsTree = m, e.Mesh.prototype.raycast = f;
181
+ var y = class {
161
182
  currentZipContent = null;
183
+ customBlobUrls = [];
162
184
  managedMaterials = [];
163
185
  isTextureEnabled = !0;
164
186
  displayStyle = "solid";
165
187
  plainColor = 5016790;
166
188
  currentClippingPlanes = [];
189
+ dracoDecoderPath = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/";
190
+ dracoLoader = null;
191
+ ktx2TranscoderPath = "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/libs/basis/";
192
+ ktx2Loader = null;
193
+ renderer = null;
194
+ constructor(e, t) {
195
+ typeof e == "string" ? (this.dracoDecoderPath = e, t && (this.renderer = t)) : typeof e == "object" && e && (e.dracoDecoderPath && (this.dracoDecoderPath = e.dracoDecoderPath), e.ktx2TranscoderPath && (this.ktx2TranscoderPath = e.ktx2TranscoderPath), this.renderer = e.renderer || t || null);
196
+ }
197
+ setRenderer(e) {
198
+ this.renderer = e, this.ktx2Loader && this.ktx2Loader.detectSupport(e);
199
+ }
200
+ setDracoDecoderPath(e) {
201
+ this.dracoDecoderPath = e, this.dracoLoader && this.dracoLoader.setDecoderPath(e);
202
+ }
203
+ setKTX2TranscoderPath(e) {
204
+ this.ktx2TranscoderPath = e, this.ktx2Loader && this.ktx2Loader.setTranscoderPath(e);
205
+ }
206
+ getDracoLoader() {
207
+ return this.dracoLoader || (this.dracoLoader = new l(), this.dracoLoader.setDecoderPath(this.dracoDecoderPath)), this.dracoLoader;
208
+ }
209
+ getKTX2Loader() {
210
+ if (!this.ktx2Loader) {
211
+ if (this.ktx2Loader = new u(), this.ktx2Loader.setTranscoderPath(this.ktx2TranscoderPath), this.renderer) this.ktx2Loader.detectSupport(this.renderer);
212
+ else if (typeof document < "u") try {
213
+ let t = document.createElement("canvas"), n = new e.WebGLRenderer({ canvas: t });
214
+ this.ktx2Loader.detectSupport(n), n.dispose();
215
+ } catch (e) {
216
+ console.warn("KTX2Loader: Failed to auto-detect WebGL compressed texture support", e);
217
+ }
218
+ }
219
+ return this.ktx2Loader;
220
+ }
221
+ createGLTFLoader(e) {
222
+ let t = new c(e);
223
+ return t.setDRACOLoader(this.getDracoLoader()), t.setKTX2Loader(this.getKTX2Loader()), t.setMeshoptDecoder(d), t;
224
+ }
167
225
  async loadZip(e, t) {
168
226
  this.cleanup();
169
- let n = await m.extract(e, t);
170
- this.currentZipContent = n;
227
+ let n = await v.extract(e, t);
228
+ if (this.currentZipContent = n, n.format === "glb" || n.format === "gltf") {
229
+ t?.(70, "正在解析 GLTF/GLB 网格结构与材质贴图...");
230
+ let e = this.createGLTFLoader(n.loadingManager), r = n.gltfContent, i = await new Promise((t, n) => {
231
+ e.parse(r, "", (e) => t(e), (e) => n(e));
232
+ });
233
+ t?.(88, "正在建立空间 BVH 加速结构与几何居中...");
234
+ let a = this.postProcessModel(i.scene, i.animations, n.format);
235
+ return t?.(100, "加载完成"), a;
236
+ }
171
237
  let { objContent: r, mtlContent: i, loadingManager: a } = n;
172
238
  t?.(65, "正在解析材质与贴图数据...");
173
239
  let c = null;
@@ -176,48 +242,121 @@ var h = class {
176
242
  c && l.setMaterials(c);
177
243
  let u = typeof r == "string" ? r : new TextDecoder().decode(r), d = l.parse(u);
178
244
  t?.(88, "正在建立空间 BVH 加速结构与几何居中...");
179
- let f = this.postProcessModel(d);
245
+ let f = this.postProcessModel(d, [], "obj");
180
246
  return t?.(100, "加载完成"), f;
181
247
  }
182
- async loadOBJ(e, t, n) {
183
- this.cleanup(), n?.(20, "正在加载材质定义...");
184
- let r = null;
185
- t && (r = await new s().loadAsync(t), r.preload()), n?.(50, "正在加载 OBJ 模型几何数据...");
186
- let i = new o();
187
- r && i.setMaterials(r);
188
- let a = await i.loadAsync(e, (e) => {
248
+ async loadGLTF(e, t, n) {
249
+ this.cleanup();
250
+ let r = this.createGLTFLoader(t), i, a = typeof e == "string" && /\.glb(\?.*)?$/i.test(e);
251
+ typeof e == "string" ? (n?.(30, "正在请求 GLTF/GLB 模型数据..."), i = await r.loadAsync(e, (e) => {
189
252
  if (e.lengthComputable && e.total > 0) {
190
- let t = Math.round(50 + e.loaded / e.total * 35);
253
+ let t = Math.round(30 + e.loaded / e.total * 50);
191
254
  n?.(t, `正在传输模型数据 (${Math.round(e.loaded / e.total * 100)}%)...`);
192
255
  }
256
+ })) : (n?.(60, "正在解析 GLTF/GLB 二进制数据流..."), i = await new Promise((t, n) => {
257
+ r.parse(e, "", (e) => t(e), (e) => n(e));
258
+ })), n?.(88, "正在建立空间 BVH 加速结构与几何居中...");
259
+ let o = this.postProcessModel(i.scene, i.animations, a ? "glb" : "gltf");
260
+ return n?.(100, "加载完成"), o;
261
+ }
262
+ async loadGLB(e, t) {
263
+ if (e instanceof Blob || e instanceof File) {
264
+ let n = await e.arrayBuffer();
265
+ return this.loadGLTF(n, void 0, t);
266
+ }
267
+ return this.loadGLTF(e, void 0, t);
268
+ }
269
+ async loadOBJ(e, t, n, r) {
270
+ this.cleanup(), r?.(20, "正在加载材质定义...");
271
+ let i = null;
272
+ t && (i = await new s(n).loadAsync(t), i.preload()), r?.(50, "正在加载 OBJ 模型几何数据...");
273
+ let a = new o(n);
274
+ i && a.setMaterials(i);
275
+ let c = await a.loadAsync(e, (e) => {
276
+ if (e.lengthComputable && e.total > 0) {
277
+ let t = Math.round(50 + e.loaded / e.total * 35);
278
+ r?.(t, `正在传输模型数据 (${Math.round(e.loaded / e.total * 100)}%)...`);
279
+ }
193
280
  });
194
- n?.(88, "正在建立空间 BVH 加速结构与几何居中...");
195
- let c = this.postProcessModel(a);
196
- return n?.(100, "加载完成"), c;
281
+ r?.(88, "正在建立空间 BVH 加速结构与几何居中...");
282
+ let l = this.postProcessModel(c, [], "obj");
283
+ return r?.(100, "加载完成"), l;
284
+ }
285
+ async loadFiles(t, n) {
286
+ let r = Array.from(t);
287
+ if (r.length === 0) throw Error("未选择任何文件");
288
+ let i = r.find((e) => e.name.toLowerCase().endsWith(".zip"));
289
+ if (i) return this.loadZip(i, n);
290
+ let a = r.find((e) => e.name.toLowerCase().endsWith(".glb"));
291
+ if (a) return this.loadGLB(a, n);
292
+ let o = r.find((e) => e.name.toLowerCase().endsWith(".gltf"));
293
+ if (o) {
294
+ n?.(15, "正在建立 GLTF 关联资源映射表...");
295
+ let t = /* @__PURE__ */ new Map();
296
+ for (let e of r) {
297
+ let n = URL.createObjectURL(e);
298
+ this.customBlobUrls.push(n), t.set(e.name, n), t.set(e.name.toLowerCase(), n);
299
+ }
300
+ let i = new e.LoadingManager();
301
+ i.setURLModifier((e) => {
302
+ let n = decodeURIComponent(e).replace(/^\.\//, ""), r = n.split("/").pop()?.split("\\").pop() || n;
303
+ if (t.has(e)) return t.get(e);
304
+ if (t.has(n)) return t.get(n);
305
+ if (t.has(r)) return t.get(r);
306
+ let i = r.toLowerCase();
307
+ for (let [e, n] of t.entries()) if (e.toLowerCase() === i || e.toLowerCase().endsWith("/" + i)) return n;
308
+ return e;
309
+ });
310
+ let a = await o.text();
311
+ return this.loadGLTF(a, i, n);
312
+ }
313
+ let s = r.find((e) => e.name.toLowerCase().endsWith(".obj"));
314
+ if (s) {
315
+ let t = r.find((e) => e.name.toLowerCase().endsWith(".mtl")), i = /* @__PURE__ */ new Map();
316
+ for (let e of r) {
317
+ let t = URL.createObjectURL(e);
318
+ this.customBlobUrls.push(t), i.set(e.name, t), i.set(e.name.toLowerCase(), t);
319
+ }
320
+ let a = new e.LoadingManager();
321
+ a.setURLModifier((e) => {
322
+ let t = decodeURIComponent(e).replace(/^\.\//, ""), n = t.split("/").pop()?.split("\\").pop() || t;
323
+ if (i.has(e)) return i.get(e);
324
+ if (i.has(t)) return i.get(t);
325
+ if (i.has(n)) return i.get(n);
326
+ let r = n.toLowerCase();
327
+ for (let [e, t] of i.entries()) if (e.toLowerCase() === r || e.toLowerCase().endsWith("/" + r)) return t;
328
+ return e;
329
+ });
330
+ let o = i.get(s.name), c = t ? i.get(t.name) : void 0;
331
+ return this.loadOBJ(o, c, a, n);
332
+ }
333
+ throw Error("未识别到支持的 3D 模型文件(请提供 .glb, .gltf, .obj 或 .zip 格式)");
197
334
  }
198
- postProcessModel(t) {
199
- let n = 0, r = 0;
335
+ postProcessModel(t, n, r = "obj") {
336
+ let i = 0, a = 0;
200
337
  this.managedMaterials = [];
201
- let i = (t) => {
202
- t && (t.anisotropy = 16, t.generateMipmaps = !0, t.minFilter = e.LinearMipmapLinearFilter, t.magFilter = e.LinearFilter, t.colorSpace = e.SRGBColorSpace, t.needsUpdate = !0);
203
- }, a = (t) => {
338
+ let o = (t, n = !0) => {
339
+ t && (t.anisotropy = 16, t.generateMipmaps = !0, t.minFilter = e.LinearMipmapLinearFilter, t.magFilter = e.LinearFilter, n && !t.colorSpace && (t.colorSpace = e.SRGBColorSpace), t.needsUpdate = !0);
340
+ }, s = (t) => {
204
341
  if (t.side = e.DoubleSide, t.needsUpdate = !0, "color" in t) {
205
342
  let e = t;
206
- i(e.map), "normalMap" in e && i(e.normalMap), "bumpMap" in e && i(e.bumpMap), !e.map && e.color && e.color.getHex() < 2236962 && e.color.setHex(11581636);
343
+ o(e.map, !0), "emissiveMap" in e && o(e.emissiveMap, !0), "normalMap" in e && o(e.normalMap, !1), "bumpMap" in e && o(e.bumpMap, !1), "roughnessMap" in e && o(e.roughnessMap, !1), "metalnessMap" in e && o(e.metalnessMap, !1), "aoMap" in e && o(e.aoMap, !1), r === "obj" && !e.map && e.color && e.color.getHex() < 2236962 && e.color.setHex(11581636);
207
344
  }
208
- }, o = new e.Box3().setFromObject(t), s = new e.Vector3(), c = new e.Vector3();
209
- return o.getCenter(s), o.getSize(c), t.traverse((t) => {
345
+ };
346
+ t.updateMatrixWorld(!0);
347
+ let c = new e.Box3().setFromObject(t), l = new e.Vector3(), u = new e.Vector3();
348
+ c.getCenter(l), c.getSize(u), t.traverse((t) => {
210
349
  if (t.isMesh) {
211
- let i = t;
212
- i.castShadow = !0, i.receiveShadow = !0, i.material ? Array.isArray(i.material) ? i.material.forEach(a) : a(i.material) : i.material = new e.MeshStandardMaterial({
350
+ let n = t;
351
+ n.castShadow = !0, n.receiveShadow = !0, n.material ? Array.isArray(n.material) ? n.material.forEach(s) : s(n.material) : n.material = new e.MeshStandardMaterial({
213
352
  color: this.plainColor,
214
353
  roughness: .45,
215
354
  metalness: .12,
216
355
  side: e.DoubleSide
217
356
  });
218
- let o = i.geometry;
219
- if (o) {
220
- o.translate(-s.x, -s.y, -s.z), o.attributes.normal || o.computeVertexNormals(), o.computeBoundsTree && o.computeBoundsTree(), o.attributes.position && (n += o.attributes.position.count), o.index ? r += o.index.count / 3 : o.attributes.position && (r += o.attributes.position.count / 3);
357
+ let r = n.geometry;
358
+ if (r) {
359
+ r.attributes.normal || r.computeVertexNormals(), r.computeBoundsTree && r.computeBoundsTree(), r.attributes.position && (i += r.attributes.position.count), r.index ? a += r.index.count / 3 : r.attributes.position && (a += r.attributes.position.count / 3);
221
360
  let t = new e.MeshStandardMaterial({
222
361
  color: this.plainColor,
223
362
  roughness: .45,
@@ -225,21 +364,25 @@ var h = class {
225
364
  side: e.DoubleSide,
226
365
  clippingPlanes: this.currentClippingPlanes.length > 0 ? this.currentClippingPlanes : null,
227
366
  clipShadows: !0
228
- }), a = {
229
- mesh: i,
230
- originalMaterial: i.material,
367
+ }), o = {
368
+ mesh: n,
369
+ originalMaterial: n.material,
231
370
  plainMaterial: t
232
371
  };
233
- this.applyStyleToItem(a), this.managedMaterials.push(a);
372
+ this.applyStyleToItem(o), this.managedMaterials.push(o);
234
373
  }
235
374
  }
236
- }), t.position.set(0, 0, 0), t.rotation.set(0, 0, 0), t.scale.set(1, 1, 1), t.updateMatrixWorld(!0), {
237
- model: t,
238
- box: new e.Box3().setFromObject(t),
239
- size: c,
240
- center: s,
241
- vertexCount: n,
242
- faceCount: Math.round(r)
375
+ });
376
+ let d = new e.Group();
377
+ return d.name = "gmv-model-root", t.position.set(-l.x, -l.y, -l.z), d.add(t), d.updateMatrixWorld(!0), {
378
+ model: d,
379
+ box: new e.Box3().setFromObject(d),
380
+ size: u,
381
+ center: l,
382
+ vertexCount: i,
383
+ faceCount: Math.round(a),
384
+ animations: n || [],
385
+ format: r
243
386
  };
244
387
  }
245
388
  applyStyleToItem(e) {
@@ -303,14 +446,21 @@ var h = class {
303
446
  }
304
447
  }
305
448
  cleanup() {
306
- this.currentZipContent &&= (this.currentZipContent.dispose(), null);
449
+ this.currentZipContent &&= (this.currentZipContent.dispose(), null), this.customBlobUrls.length > 0 && (this.customBlobUrls.forEach((e) => {
450
+ try {
451
+ URL.revokeObjectURL(e);
452
+ } catch {}
453
+ }), this.customBlobUrls = []);
307
454
  for (let e of this.managedMaterials) e.plainMaterial && e.plainMaterial.dispose(), e.mesh.geometry && e.mesh.geometry.disposeBoundsTree && e.mesh.geometry.disposeBoundsTree();
308
455
  this.managedMaterials = [];
309
456
  }
457
+ destroy() {
458
+ this.cleanup(), this.dracoLoader &&= (this.dracoLoader.dispose(), null), this.ktx2Loader &&= (this.ktx2Loader.dispose(), null);
459
+ }
310
460
  };
311
461
  //#endregion
312
462
  //#region src/utils/math.ts
313
- function g(t) {
463
+ function b(t) {
314
464
  let n = t.geometry;
315
465
  if (!n) return 0;
316
466
  let r = n.attributes.position;
@@ -322,15 +472,15 @@ function g(t) {
322
472
  let e = n.index;
323
473
  for (let t = 0; t < e.count; t += 3) {
324
474
  let n = e.getX(t), l = e.getX(t + 1), u = e.getX(t + 2);
325
- a.fromBufferAttribute(r, n).applyMatrix4(c), o.fromBufferAttribute(r, l).applyMatrix4(c), s.fromBufferAttribute(r, u).applyMatrix4(c), i += v(a, o, s);
475
+ a.fromBufferAttribute(r, n).applyMatrix4(c), o.fromBufferAttribute(r, l).applyMatrix4(c), s.fromBufferAttribute(r, u).applyMatrix4(c), i += S(a, o, s);
326
476
  }
327
- } else for (let e = 0; e < r.count; e += 3) a.fromBufferAttribute(r, e).applyMatrix4(c), o.fromBufferAttribute(r, e + 1).applyMatrix4(c), s.fromBufferAttribute(r, e + 2).applyMatrix4(c), i += v(a, o, s);
477
+ } else for (let e = 0; e < r.count; e += 3) a.fromBufferAttribute(r, e).applyMatrix4(c), o.fromBufferAttribute(r, e + 1).applyMatrix4(c), s.fromBufferAttribute(r, e + 2).applyMatrix4(c), i += S(a, o, s);
328
478
  return Math.abs(i);
329
479
  }
330
- function _(t) {
480
+ function x(t) {
331
481
  let n = 0;
332
482
  t.traverse((e) => {
333
- e.isMesh && (n += g(e));
483
+ e.isMesh && (n += b(e));
334
484
  });
335
485
  let r = new e.Box3().setFromObject(t), i = new e.Vector3();
336
486
  r.getSize(i);
@@ -340,10 +490,10 @@ function _(t) {
340
490
  bboxVolume: a
341
491
  };
342
492
  }
343
- function v(e, t, n) {
493
+ function S(e, t, n) {
344
494
  return e.dot(t.clone().cross(n)) / 6;
345
495
  }
346
- function y(t) {
496
+ function C(t) {
347
497
  let n = t.length;
348
498
  if (n < 3) return 0;
349
499
  let r = new e.Vector3(0, 0, 0);
@@ -353,12 +503,12 @@ function y(t) {
353
503
  }
354
504
  return r.length() * .5;
355
505
  }
356
- function b(e, t = "m", n = 2) {
506
+ function w(e, t = "m", n = 2) {
357
507
  return Math.abs(e) < .001 ? `0.00 ${t}` : `${e.toFixed(n)} ${t}`;
358
508
  }
359
509
  //#endregion
360
510
  //#region src/tools/BoundingBoxTool.ts
361
- var x = class {
511
+ var T = class {
362
512
  scene;
363
513
  boxGroup;
364
514
  wireframeBox = null;
@@ -388,25 +538,28 @@ var x = class {
388
538
  }
389
539
  attachToModel(t, n) {
390
540
  this.detach(), this.currentModel = t, this.unit = n?.unit || "m", t.updateMatrixWorld(!0);
391
- let i = new e.Box3();
541
+ let i = new e.Box3(), a = t.matrixWorld.clone().invert();
392
542
  t.traverse((e) => {
393
543
  if (e.isMesh) {
394
544
  let t = e;
395
- t.geometry && (t.geometry.boundingBox || t.geometry.computeBoundingBox(), t.geometry.boundingBox && i.union(t.geometry.boundingBox));
545
+ if (t.geometry && (t.geometry.boundingBox || t.geometry.computeBoundingBox(), t.geometry.boundingBox)) {
546
+ let e = t.matrixWorld.clone().premultiply(a), n = t.geometry.boundingBox.clone().applyMatrix4(e);
547
+ i.union(n);
548
+ }
396
549
  }
397
550
  }), i.isEmpty() && i.setFromObject(t);
398
- let a = i.min, o = i.max;
551
+ let o = i.min, s = i.max;
399
552
  i.getSize(this.modelSize), this.localVertices = [
400
- new e.Vector3(a.x, a.y, a.z),
401
- new e.Vector3(o.x, a.y, a.z),
402
- new e.Vector3(a.x, o.y, a.z),
403
- new e.Vector3(o.x, o.y, a.z),
404
- new e.Vector3(a.x, a.y, o.z),
405
- new e.Vector3(o.x, a.y, o.z),
406
- new e.Vector3(a.x, o.y, o.z),
407
- new e.Vector3(o.x, o.y, o.z)
553
+ new e.Vector3(o.x, o.y, o.z),
554
+ new e.Vector3(s.x, o.y, o.z),
555
+ new e.Vector3(o.x, s.y, o.z),
556
+ new e.Vector3(s.x, s.y, o.z),
557
+ new e.Vector3(o.x, o.y, s.z),
558
+ new e.Vector3(s.x, o.y, s.z),
559
+ new e.Vector3(o.x, s.y, s.z),
560
+ new e.Vector3(s.x, s.y, s.z)
408
561
  ];
409
- let s = [
562
+ let c = [
410
563
  0,
411
564
  1,
412
565
  2,
@@ -431,22 +584,22 @@ var x = class {
431
584
  6,
432
585
  3,
433
586
  7
434
- ], c = new e.BufferGeometry(), l = new Float32Array(s.length * 3);
435
- c.setAttribute("position", new e.BufferAttribute(l, 3));
436
- let u = new e.LineBasicMaterial({
587
+ ], l = new e.BufferGeometry(), u = new Float32Array(c.length * 3);
588
+ l.setAttribute("position", new e.BufferAttribute(u, 3));
589
+ let d = new e.LineBasicMaterial({
437
590
  color: n?.color ? new e.Color(n.color) : 54015,
438
591
  linewidth: 1,
439
592
  transparent: !0,
440
593
  opacity: .6,
441
594
  depthTest: !0
442
595
  });
443
- this.wireframeBox = new e.LineSegments(c, u), this.boxGroup.add(this.wireframeBox), this.lineX = this.createDynamicLine(15680580), this.lineY = this.createDynamicLine(1096065), this.lineZ = this.createDynamicLine(3900150);
444
- let d = document.createElement("div");
445
- d.className = "gmv-dimension-badge dim-x", d.innerHTML = `<span>长 (X):</span> <strong>${b(this.modelSize.x, this.unit)}</strong>`, this.labelX = new r(d), this.boxGroup.add(this.labelX);
596
+ this.wireframeBox = new e.LineSegments(l, d), this.boxGroup.add(this.wireframeBox), this.lineX = this.createDynamicLine(15680580), this.lineY = this.createDynamicLine(1096065), this.lineZ = this.createDynamicLine(3900150);
446
597
  let f = document.createElement("div");
447
- f.className = "gmv-dimension-badge dim-y", f.innerHTML = `<span>高 (Y):</span> <strong>${b(this.modelSize.y, this.unit)}</strong>`, this.labelY = new r(f), this.boxGroup.add(this.labelY);
598
+ f.className = "gmv-dimension-badge dim-x", f.innerHTML = `<span>长 (X):</span> <strong>${w(this.modelSize.x, this.unit)}</strong>`, this.labelX = new r(f), this.boxGroup.add(this.labelX);
448
599
  let p = document.createElement("div");
449
- p.className = "gmv-dimension-badge dim-z", p.innerHTML = `<span>宽 (Z):</span> <strong>${b(this.modelSize.z, this.unit)}</strong>`, this.labelZ = new r(p), this.boxGroup.add(this.labelZ), this.setVisible(n?.visible ?? !1);
600
+ p.className = "gmv-dimension-badge dim-y", p.innerHTML = `<span>高 (Y):</span> <strong>${w(this.modelSize.y, this.unit)}</strong>`, this.labelY = new r(p), this.boxGroup.add(this.labelY);
601
+ let m = document.createElement("div");
602
+ m.className = "gmv-dimension-badge dim-z", m.innerHTML = `<span>宽 (Z):</span> <strong>${w(this.modelSize.z, this.unit)}</strong>`, this.labelZ = new r(m), this.boxGroup.add(this.labelZ), this.setVisible(n?.visible ?? !1);
450
603
  }
451
604
  createDynamicLine(t) {
452
605
  let n = new e.BufferGeometry().setFromPoints([new e.Vector3(), new e.Vector3()]), r = new e.LineBasicMaterial({
@@ -525,7 +678,7 @@ var x = class {
525
678
  destroy() {
526
679
  this.detach(), this.scene.remove(this.boxGroup);
527
680
  }
528
- }, S = class {
681
+ }, E = class {
529
682
  camera;
530
683
  controls;
531
684
  tweenGroup;
@@ -657,7 +810,7 @@ var x = class {
657
810
  };
658
811
  //#endregion
659
812
  //#region src/utils/snapping.ts
660
- function C(t, n, r, i = 15, a = 800, o = 600) {
813
+ function D(t, n, r, i = 15, a = 800, o = 600) {
661
814
  if (!r || r.length === 0) return {
662
815
  hit: !1,
663
816
  point: null,
@@ -709,7 +862,7 @@ function C(t, n, r, i = 15, a = 800, o = 600) {
709
862
  }
710
863
  //#endregion
711
864
  //#region src/tools/ClippingTool.ts
712
- var w = class {
865
+ var O = class {
713
866
  scene;
714
867
  camera;
715
868
  container;
@@ -1156,7 +1309,7 @@ var w = class {
1156
1309
  return this.customPlane !== null;
1157
1310
  }
1158
1311
  handleCustomPointPick(t) {
1159
- let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1312
+ let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1160
1313
  r.hit && r.point && this.addCustomPoint(r.point);
1161
1314
  }
1162
1315
  addCustomPoint(t) {
@@ -1223,7 +1376,7 @@ var w = class {
1223
1376
  destroy() {
1224
1377
  this.cancelCustomClip(), this.resetAll(), this.clearPlaneWidgets(), this.scene.remove(this.planesGroup), this.scene.remove(this.customMarkersGroup), this.container.removeEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.removeEventListener("pointermove", this.onPointerMoveBound), this.container.removeEventListener("dblclick", this.onDoubleClickBound, { capture: !0 }), window.removeEventListener("pointermove", this.onPointerMoveDragBound, { capture: !0 }), window.removeEventListener("pointerup", this.onPointerUpDragBound, { capture: !0 });
1225
1378
  }
1226
- }, T = class {
1379
+ }, k = class {
1227
1380
  scene;
1228
1381
  camera;
1229
1382
  container;
@@ -1275,12 +1428,12 @@ var w = class {
1275
1428
  }
1276
1429
  handlePointerMove(t) {
1277
1430
  if (this.currentMode === "none") return;
1278
- let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1431
+ let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1279
1432
  !r.hit || !r.point ? (this.container.style.cursor = "not-allowed", this.snapCursorMesh.visible = !1) : (this.container.style.cursor = "crosshair", this.snapCursorMesh.visible = !0, this.snapCursorMesh.position.copy(r.point), r.isVertexSnapped ? (this.snapCursorMesh.material.color.setHex(16007006), this.snapCursorMesh.userData.fixedScreenRadius = 7.5) : (this.snapCursorMesh.material.color.setHex(3718648), this.snapCursorMesh.userData.fixedScreenRadius = 5.5), this.updateSingleMeshScale(this.snapCursorMesh), this.activePoints.length > 0 && this.updateDynamicPreview(r.point));
1280
1433
  }
1281
1434
  handlePointerDown(t) {
1282
1435
  if (this.currentMode === "none" || t.button !== 0) return;
1283
- let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1436
+ let n = this.container.getBoundingClientRect(), r = D(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
1284
1437
  if (!r.hit || !r.point) return;
1285
1438
  let i = r.point.clone();
1286
1439
  this.activePoints.push(i), this.addActiveMarker(i), this.emitter.emit("measure:change", [...this.activePoints]), this.currentMode === "distance" && this.activePoints.length === 2 ? this.finishDistanceMeasurement() : this.currentMode === "height" && this.activePoints.length === 2 ? this.finishHeightMeasurement() : this.currentMode === "angle" && this.activePoints.length === 3 && this.finishAngleMeasurement();
@@ -1315,14 +1468,14 @@ var w = class {
1315
1468
  }), l = new e.Line(s, c);
1316
1469
  o.add(l), this.addEndSphere(o, t, 3900150), this.addEndSphere(o, n, 3900150);
1317
1470
  let u = document.createElement("div");
1318
- u.className = "gmv-measure-badge distance", u.innerHTML = `<span>距离:</span> <strong>${b(i, this.unit)}</strong>`;
1471
+ u.className = "gmv-measure-badge distance", u.innerHTML = `<span>距离:</span> <strong>${w(i, this.unit)}</strong>`;
1319
1472
  let d = new r(u);
1320
1473
  d.position.copy(a), o.add(d), this.measurementGroup.add(o);
1321
1474
  let f = {
1322
1475
  id: `dist_${Date.now()}`,
1323
1476
  type: "distance",
1324
1477
  value: i,
1325
- formattedValue: b(i, this.unit),
1478
+ formattedValue: w(i, this.unit),
1326
1479
  unit: this.unit,
1327
1480
  points: [t, n]
1328
1481
  };
@@ -1349,16 +1502,16 @@ var w = class {
1349
1502
  s.add(_), this.addEndSphere(s, t, 1096065), this.addEndSphere(s, n, 15680580), this.addEndSphere(s, d, 16436245, 4);
1350
1503
  let v = new e.Vector3().addVectors(d, n).multiplyScalar(.5), y = document.createElement("div");
1351
1504
  y.className = "gmv-measure-badge height", y.innerHTML = `
1352
- <div><span>高差 (ΔH):</span> <strong>${b(i, this.unit)}</strong></div>
1353
- <div style="font-size:10px;opacity:0.85;">水平: ${b(a, this.unit)} · 直线: ${b(o, this.unit)}</div>
1505
+ <div><span>高差 (ΔH):</span> <strong>${w(i, this.unit)}</strong></div>
1506
+ <div style="font-size:10px;opacity:0.85;">水平: ${w(a, this.unit)} · 直线: ${w(o, this.unit)}</div>
1354
1507
  `;
1355
- let x = new r(y);
1356
- x.position.copy(v), s.add(x), this.measurementGroup.add(s);
1357
- let S = {
1508
+ let b = new r(y);
1509
+ b.position.copy(v), s.add(b), this.measurementGroup.add(s);
1510
+ let x = {
1358
1511
  id: `height_${Date.now()}`,
1359
1512
  type: "height",
1360
1513
  value: i,
1361
- formattedValue: b(i, this.unit),
1514
+ formattedValue: w(i, this.unit),
1362
1515
  unit: this.unit,
1363
1516
  points: [t, n],
1364
1517
  extra: {
@@ -1366,11 +1519,11 @@ var w = class {
1366
1519
  horizontalDistance: a
1367
1520
  }
1368
1521
  };
1369
- this.results.push(S), this.emitter.emit("measure:complete", S), this.cancelActive(), this.setMode("none");
1522
+ this.results.push(x), this.emitter.emit("measure:complete", x), this.cancelActive(), this.setMode("none");
1370
1523
  }
1371
1524
  finishAreaMeasurement() {
1372
1525
  if (this.activePoints.length < 3) return;
1373
- let t = [...this.activePoints], n = y(t), i = new e.Group(), a = [...t, t[0]], o = new e.BufferGeometry().setFromPoints(a), s = new e.LineBasicMaterial({
1526
+ let t = [...this.activePoints], n = C(t), i = new e.Group(), a = [...t, t[0]], o = new e.BufferGeometry().setFromPoints(a), s = new e.LineBasicMaterial({
1374
1527
  color: 9133302,
1375
1528
  linewidth: 2,
1376
1529
  depthTest: !1
@@ -1379,14 +1532,14 @@ var w = class {
1379
1532
  let l = new e.Vector3();
1380
1533
  t.forEach((e) => l.add(e)), l.divideScalar(t.length);
1381
1534
  let u = document.createElement("div");
1382
- u.className = "gmv-measure-badge area", u.innerHTML = `<span>面积:</span> <strong>${b(n, `${this.unit}²`)}</strong>`;
1535
+ u.className = "gmv-measure-badge area", u.innerHTML = `<span>面积:</span> <strong>${w(n, `${this.unit}²`)}</strong>`;
1383
1536
  let d = new r(u);
1384
1537
  d.position.copy(l), i.add(d), this.measurementGroup.add(i);
1385
1538
  let f = {
1386
1539
  id: `area_${Date.now()}`,
1387
1540
  type: "area",
1388
1541
  value: n,
1389
- formattedValue: b(n, `${this.unit}²`),
1542
+ formattedValue: w(n, `${this.unit}²`),
1390
1543
  unit: `${this.unit}²`,
1391
1544
  points: t,
1392
1545
  extra: { area: n }
@@ -1507,7 +1660,7 @@ var w = class {
1507
1660
  destroy() {
1508
1661
  this.removeListeners(), this.clearAll(), this.scene.remove(this.measurementGroup), this.scene.remove(this.activePreviewGroup), this.scene.remove(this.snapCursorMesh);
1509
1662
  }
1510
- }, E = class {
1663
+ }, A = class {
1511
1664
  renderer;
1512
1665
  scene;
1513
1666
  camera;
@@ -1593,7 +1746,7 @@ var w = class {
1593
1746
  }), this.renderer.render(this.scene, this.camera);
1594
1747
  }
1595
1748
  }
1596
- }, D = class extends p {
1749
+ }, j = class extends _ {
1597
1750
  sceneManager;
1598
1751
  modelLoader;
1599
1752
  boundingBoxTool;
@@ -1605,8 +1758,22 @@ var w = class {
1605
1758
  currentModelInfo = null;
1606
1759
  unit = "m";
1607
1760
  defaultShowBoundingBox = !1;
1761
+ animationMixer = null;
1762
+ animationClips = [];
1763
+ activeAction = null;
1764
+ currentAnimationName = null;
1765
+ animationClock = new e.Clock();
1766
+ isAnimationActive = !1;
1608
1767
  constructor(e) {
1609
- super(), this.unit = e.unit || "m", this.defaultShowBoundingBox = e.showBoundingBox ?? !1, this.sceneManager = new f(e), this.modelLoader = new h(), this.boundingBoxTool = new x(this.sceneManager.scene), this.cameraTool = new S(this.sceneManager.camera, this.sceneManager.controls, this.sceneManager.tweenGroup), this.clippingTool = new w(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this.sceneManager.controls, this), this.measurementTool = new T(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this, this.sceneManager.controls), this.measurementTool.setUnit(this.unit), this.screenshotTool = new E(this.sceneManager.renderer, this.sceneManager.scene, this.sceneManager.camera, () => this.currentModel), this.measurementTool.setUnit(this.unit), this.sceneManager.onBeforeRender = () => {
1768
+ super(), this.unit = e.unit || "m", this.defaultShowBoundingBox = e.showBoundingBox ?? !1, this.sceneManager = new g(e), this.modelLoader = new y({
1769
+ dracoDecoderPath: e.dracoDecoderPath,
1770
+ ktx2TranscoderPath: e.ktx2TranscoderPath,
1771
+ renderer: this.sceneManager.renderer
1772
+ }), this.boundingBoxTool = new T(this.sceneManager.scene), this.cameraTool = new E(this.sceneManager.camera, this.sceneManager.controls, this.sceneManager.tweenGroup), this.clippingTool = new O(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this.sceneManager.controls, this), this.measurementTool = new k(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this, this.sceneManager.controls), this.measurementTool.setUnit(this.unit), this.screenshotTool = new A(this.sceneManager.renderer, this.sceneManager.scene, this.sceneManager.camera, () => this.currentModel), this.measurementTool.setUnit(this.unit), this.sceneManager.onBeforeRender = () => {
1773
+ if (this.animationMixer && this.isAnimationActive) {
1774
+ let e = this.animationClock.getDelta();
1775
+ this.animationMixer.update(e);
1776
+ }
1610
1777
  this.boundingBoxTool.update(this.sceneManager.camera), this.cameraTool.updatePerFrame(), this.measurementTool.updatePerFrame(), this.clippingTool.updatePerFrame();
1611
1778
  };
1612
1779
  }
@@ -1625,7 +1792,7 @@ var w = class {
1625
1792
  async loadOBJ(e, t) {
1626
1793
  try {
1627
1794
  this.emit("load:start", e), this.clearModel();
1628
- let n = await this.modelLoader.loadOBJ(e, t, (e, t) => {
1795
+ let n = await this.modelLoader.loadOBJ(e, t, void 0, (e, t) => {
1629
1796
  this.emit("load:progress", e, t);
1630
1797
  });
1631
1798
  return this.setupLoadedModel(n), this.emit("load:success", n), n;
@@ -1634,6 +1801,60 @@ var w = class {
1634
1801
  throw this.emit("load:error", t), t;
1635
1802
  }
1636
1803
  }
1804
+ async loadGLTF(e) {
1805
+ try {
1806
+ this.emit("load:start", typeof e == "string" ? e : "GLTF Data"), this.clearModel();
1807
+ let t = await this.modelLoader.loadGLTF(e, void 0, (e, t) => {
1808
+ this.emit("load:progress", e, t);
1809
+ });
1810
+ return this.setupLoadedModel(t), this.emit("load:success", t), t;
1811
+ } catch (e) {
1812
+ let t = e instanceof Error ? e : Error(String(e));
1813
+ throw this.emit("load:error", t), t;
1814
+ }
1815
+ }
1816
+ async loadGLB(e) {
1817
+ try {
1818
+ let t = typeof e == "string" ? e : e instanceof File ? e.name : "GLB Model";
1819
+ this.emit("load:start", t), this.clearModel();
1820
+ let n = await this.modelLoader.loadGLB(e, (e, t) => {
1821
+ this.emit("load:progress", e, t);
1822
+ });
1823
+ return this.setupLoadedModel(n), this.emit("load:success", n), n;
1824
+ } catch (e) {
1825
+ let t = e instanceof Error ? e : Error(String(e));
1826
+ throw this.emit("load:error", t), t;
1827
+ }
1828
+ }
1829
+ async loadFiles(e) {
1830
+ try {
1831
+ let t = Array.from(e)[0]?.name || "Files";
1832
+ this.emit("load:start", t), this.clearModel();
1833
+ let n = await this.modelLoader.loadFiles(e, (e, t) => {
1834
+ this.emit("load:progress", e, t);
1835
+ });
1836
+ return this.setupLoadedModel(n), this.emit("load:success", n), n;
1837
+ } catch (e) {
1838
+ let t = e instanceof Error ? e : Error(String(e));
1839
+ throw this.emit("load:error", t), t;
1840
+ }
1841
+ }
1842
+ async loadFromUrl(e) {
1843
+ let t = e.split("?")[0].toLowerCase();
1844
+ if (t.endsWith(".glb")) return this.loadGLB(e);
1845
+ if (t.endsWith(".gltf")) return this.loadGLTF(e);
1846
+ if (t.endsWith(".zip")) return this.loadZip(e);
1847
+ if (t.endsWith(".obj")) return this.loadOBJ(e);
1848
+ try {
1849
+ return await this.loadGLB(e);
1850
+ } catch {
1851
+ try {
1852
+ return await this.loadZip(e);
1853
+ } catch {
1854
+ return await this.loadOBJ(e);
1855
+ }
1856
+ }
1857
+ }
1637
1858
  loadSampleGeometry(t = "mechanical") {
1638
1859
  this.clearModel();
1639
1860
  let n = new e.Group();
@@ -1678,14 +1899,14 @@ var w = class {
1678
1899
  let r = this.modelLoader.postProcessModel(n);
1679
1900
  return this.setupLoadedModel(r), this.emit("load:success", r), r;
1680
1901
  }
1681
- setupLoadedModel(e) {
1682
- this.currentModel = e.model, this.currentModel.name = "gmv-current-model", this.currentModelInfo = e, this.sceneManager.scene.add(this.currentModel), this.boundingBoxTool.attachToModel(this.currentModel, {
1902
+ setupLoadedModel(t) {
1903
+ this.currentModel = t.model, this.currentModel.name = "gmv-current-model", this.currentModelInfo = t, this.sceneManager.scene.add(this.currentModel), t.animations && t.animations.length > 0 ? (this.animationClips = t.animations, this.animationMixer = new e.AnimationMixer(this.currentModel), this.playAnimation(0)) : (this.animationClips = [], this.animationMixer = null, this.activeAction = null, this.currentAnimationName = null, this.isAnimationActive = !1), this.boundingBoxTool.attachToModel(this.currentModel, {
1683
1904
  visible: this.defaultShowBoundingBox,
1684
1905
  unit: this.unit
1685
- }), this.clippingTool.setModelBounds(e.box), this.cameraTool.setView("front", this.currentModel, 0);
1906
+ }), this.clippingTool.setModelBounds(t.box), this.cameraTool.setView("front", this.currentModel, 0);
1686
1907
  }
1687
1908
  clearModel() {
1688
- this.measurementTool.clearAll(), this.clippingTool.resetAll(), this.boundingBoxTool.detach(), this.currentModel &&= (this.sceneManager.scene.remove(this.currentModel), null), this.currentModelInfo = null, this.modelLoader.cleanup();
1909
+ this.animationMixer &&= (this.animationMixer.stopAllAction(), this.currentModel && this.animationMixer.uncacheRoot(this.currentModel), null), this.animationClips = [], this.activeAction = null, this.currentAnimationName = null, this.isAnimationActive = !1, this.measurementTool.clearAll(), this.clippingTool.resetAll(), this.boundingBoxTool.detach(), this.currentModel &&= (this.sceneManager.scene.remove(this.currentModel), null), this.currentModelInfo = null, this.modelLoader.cleanup();
1689
1910
  }
1690
1911
  setBackground(e, t) {
1691
1912
  this.sceneManager.setBackground(e, t);
@@ -1865,11 +2086,39 @@ var w = class {
1865
2086
  off(e, t) {
1866
2087
  return super.off(e, t);
1867
2088
  }
2089
+ getAnimations() {
2090
+ return this.animationClips.map((e, t) => e.name || `Animation ${t + 1}`);
2091
+ }
2092
+ getCurrentAnimation() {
2093
+ return this.currentAnimationName;
2094
+ }
2095
+ playAnimation(e = 0) {
2096
+ if (!this.animationMixer || this.animationClips.length === 0) return;
2097
+ let t;
2098
+ if (t = typeof e == "number" ? this.animationClips[e] : this.animationClips.find((t, n) => t.name === e || `Animation ${n + 1}` === e), t ||= this.animationClips[0], !t) return;
2099
+ let n = this.animationMixer.clipAction(t);
2100
+ this.activeAction && this.activeAction !== n ? (this.activeAction.fadeOut(.3), n.reset().fadeIn(.3).play()) : n.play(), this.activeAction = n, this.currentAnimationName = t.name || "Animation 1", this.isAnimationActive = !0, this.animationClock.getDelta(), this.emit("animation:play", this.currentAnimationName);
2101
+ }
2102
+ pauseAnimation() {
2103
+ this.isAnimationActive = !1, this.emit("animation:pause");
2104
+ }
2105
+ resumeAnimation() {
2106
+ this.animationMixer && this.activeAction && (this.isAnimationActive = !0, this.animationClock.getDelta(), this.emit("animation:play", this.currentAnimationName || ""));
2107
+ }
2108
+ stopAnimation() {
2109
+ this.isAnimationActive = !1, this.activeAction && this.activeAction.stop(), this.emit("animation:stop");
2110
+ }
2111
+ isAnimationPlaying() {
2112
+ return this.isAnimationActive;
2113
+ }
2114
+ setAnimationSpeed(e) {
2115
+ this.animationMixer && (this.animationMixer.timeScale = Math.max(0, e), this.emit("animation:speed", e));
2116
+ }
1868
2117
  destroy() {
1869
- this.clearModel(), this.measurementTool.destroy(), this.clippingTool.destroy(), this.sceneManager.destroy(), this.removeAllListeners();
2118
+ this.clearModel(), this.modelLoader.destroy(), this.measurementTool.destroy(), this.clippingTool.destroy(), this.sceneManager.destroy(), this.removeAllListeners();
1870
2119
  }
1871
2120
  };
1872
2121
  //#endregion
1873
- export { x as BoundingBoxTool, S as CameraTool, w as ClippingTool, p as EventEmitter, T as MeasurementTool, h as ModelLoader, f as SceneManager, E as ScreenshotTool, D as Viewer, m as ZipExtractor, y as compute3DPolygonArea, _ as computeGroupVolume, g as computeMeshVolume, C as findSnapPoint, b as formatUnit };
2122
+ export { T as BoundingBoxTool, E as CameraTool, O as ClippingTool, _ as EventEmitter, k as MeasurementTool, y as ModelLoader, g as SceneManager, A as ScreenshotTool, j as Viewer, v as ZipExtractor, C as compute3DPolygonArea, x as computeGroupVolume, b as computeMeshVolume, D as findSnapPoint, w as formatUnit };
1874
2123
 
1875
2124
  //# sourceMappingURL=index.js.map