@rings-webgpu/core 1.0.25 → 1.0.27

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.
@@ -16792,6 +16792,10 @@ struct InstanceData {
16792
16792
  name;
16793
16793
  url;
16794
16794
  gpuTexture;
16795
+ _isDestroyed = false;
16796
+ get isDestroyed() {
16797
+ return this._isDestroyed;
16798
+ }
16795
16799
  pid;
16796
16800
  view;
16797
16801
  // Assigned later
@@ -17020,6 +17024,14 @@ struct InstanceData {
17020
17024
  this.textureDescriptor = null;
17021
17025
  this.gpuTexture.destroy();
17022
17026
  this.gpuTexture = null;
17027
+ this._isDestroyed = true;
17028
+ }
17029
+ if (this._sourceImageData && this._sourceImageData instanceof ImageBitmap) {
17030
+ try {
17031
+ this._sourceImageData.close();
17032
+ } catch (e) {
17033
+ }
17034
+ this._sourceImageData = null;
17023
17035
  }
17024
17036
  this._stateChangeRef.clear();
17025
17037
  }
@@ -20283,9 +20295,13 @@ struct InstanceData {
20283
20295
  * @param target reference parent
20284
20296
  */
20285
20297
  detached(ref, target) {
20298
+ if (!this.reference) return;
20286
20299
  let refMap = this.reference.get(ref);
20287
20300
  if (refMap) {
20288
20301
  refMap.delete(target);
20302
+ if (refMap.size === 0) {
20303
+ this.reference.delete(ref);
20304
+ }
20289
20305
  }
20290
20306
  }
20291
20307
  /**
@@ -22514,23 +22530,36 @@ struct InstanceData {
22514
22530
  }
22515
22531
  }
22516
22532
  beforeDestroy(force) {
22517
- Reference.getInstance().detached(this._geometry, this);
22518
- if (!Reference.getInstance().hasReference(this._geometry)) {
22519
- this._geometry.destroy(force);
22533
+ if (this._geometry) {
22534
+ Reference.getInstance().detached(this._geometry, this);
22535
+ if (!Reference.getInstance().hasReference(this._geometry)) {
22536
+ this._geometry.destroy(force);
22537
+ }
22520
22538
  }
22521
22539
  for (let i = 0; i < this._materials.length; i++) {
22522
22540
  const mat = this._materials[i];
22523
- Reference.getInstance().detached(mat, this);
22524
- if (!Reference.getInstance().hasReference(mat)) {
22525
- mat.destroy(force);
22541
+ if (mat) {
22542
+ Reference.getInstance().detached(mat, this);
22543
+ if (!Reference.getInstance().hasReference(mat)) {
22544
+ mat.destroy(force);
22545
+ }
22526
22546
  }
22527
22547
  }
22548
+ if (this._computes) {
22549
+ this._computes.length = 0;
22550
+ }
22551
+ this.detachSceneOctree();
22528
22552
  super.beforeDestroy(force);
22529
22553
  }
22530
22554
  destroy(force) {
22531
22555
  super.destroy(force);
22532
22556
  this._geometry = void 0;
22533
22557
  this._materials.length = 0;
22558
+ this._computes = null;
22559
+ if (this._passInit) {
22560
+ this._passInit.clear();
22561
+ this._passInit = null;
22562
+ }
22534
22563
  this._combineShaderRefection = void 0;
22535
22564
  }
22536
22565
  }
@@ -22550,6 +22579,7 @@ struct InstanceData {
22550
22579
  enable = true;
22551
22580
  _defaultSubShader;
22552
22581
  _shader;
22582
+ _isDestroyed = false;
22553
22583
  constructor() {
22554
22584
  this.instanceID = UUID();
22555
22585
  }
@@ -22664,10 +22694,17 @@ struct InstanceData {
22664
22694
  return newMat;
22665
22695
  }
22666
22696
  destroy(force) {
22697
+ if (this._isDestroyed) {
22698
+ return;
22699
+ }
22667
22700
  this.name = null;
22668
22701
  this.instanceID = null;
22669
- this._shader.destroy();
22670
- this._shader = null;
22702
+ if (this._shader) {
22703
+ this._shader.destroy(force);
22704
+ this._shader = null;
22705
+ }
22706
+ this._defaultSubShader = null;
22707
+ this._isDestroyed = true;
22671
22708
  }
22672
22709
  setDefine(define, value) {
22673
22710
  this.shader.setDefine(define, value);
@@ -23172,8 +23209,15 @@ struct InstanceData {
23172
23209
  }
23173
23210
  }
23174
23211
  }
23175
- destroy() {
23176
- this.getDefaultColorShader().destroy();
23212
+ destroy(force) {
23213
+ for (const pass of this.passShader) {
23214
+ for (const rd of pass[1]) {
23215
+ rd.destroy(force);
23216
+ }
23217
+ }
23218
+ this.passShader.clear();
23219
+ this.passShader = null;
23220
+ this.computes = null;
23177
23221
  }
23178
23222
  clone() {
23179
23223
  let newShader = new Shader();
@@ -23665,6 +23709,7 @@ struct InstanceData {
23665
23709
  _vertexBuffer;
23666
23710
  _onChange = true;
23667
23711
  _wireframeLines;
23712
+ _isDestroyed = false;
23668
23713
  constructor() {
23669
23714
  this.instanceID = UUID();
23670
23715
  this._attributeMap = /* @__PURE__ */ new Map();
@@ -23911,18 +23956,40 @@ struct InstanceData {
23911
23956
  return false;
23912
23957
  }
23913
23958
  destroy(force) {
23959
+ if (this._isDestroyed) {
23960
+ return;
23961
+ }
23914
23962
  this.instanceID = null;
23915
23963
  this.name = null;
23916
23964
  this.subGeometries = null;
23917
23965
  this.morphTargetDictionary = null;
23918
- this._bounds.destroy();
23919
- this._bounds = null;
23920
- this._attributeMap = null;
23966
+ this.skinNames = null;
23967
+ this.bindPose = null;
23968
+ this.blendShapeData = null;
23969
+ this._wireframeLines = null;
23970
+ if (this._bounds) {
23971
+ this._bounds.destroy();
23972
+ this._bounds = null;
23973
+ }
23974
+ if (this._attributeMap) {
23975
+ this._attributeMap.forEach((vertexInfo) => {
23976
+ if (vertexInfo && vertexInfo.data) {
23977
+ vertexInfo.data = null;
23978
+ }
23979
+ });
23980
+ this._attributeMap.clear();
23981
+ this._attributeMap = null;
23982
+ }
23921
23983
  this._attributes = null;
23922
- this._indicesBuffer.destroy();
23923
- this._vertexBuffer.destroy();
23924
- this._indicesBuffer = null;
23925
- this._vertexBuffer = null;
23984
+ if (this._indicesBuffer) {
23985
+ this._indicesBuffer.destroy();
23986
+ this._indicesBuffer = null;
23987
+ }
23988
+ if (this._vertexBuffer) {
23989
+ this._vertexBuffer.destroy();
23990
+ this._vertexBuffer = null;
23991
+ }
23992
+ this._isDestroyed = true;
23926
23993
  }
23927
23994
  }
23928
23995
 
@@ -25323,10 +25390,22 @@ struct InstanceData {
25323
25390
  c.destroy(force);
25324
25391
  });
25325
25392
  this.components.clear();
25326
- this.entityChildren.forEach((c) => {
25327
- c.destroy(force);
25328
- });
25329
- this.removeAllChild();
25393
+ this.components.clear();
25394
+ if (this.entityChildren) {
25395
+ this.entityChildren.forEach((c) => {
25396
+ c.destroy(force);
25397
+ });
25398
+ this.removeAllChild();
25399
+ this.entityChildren = [];
25400
+ }
25401
+ if (this._bound && this._bound.destroy) {
25402
+ this._bound.destroy();
25403
+ this._bound = null;
25404
+ }
25405
+ if (this._boundWorld && this._boundWorld.destroy) {
25406
+ this._boundWorld.destroy();
25407
+ this._boundWorld = null;
25408
+ }
25330
25409
  this.transform.parent = null;
25331
25410
  this._dispose = true;
25332
25411
  super.destroy();
@@ -25598,6 +25677,16 @@ struct InstanceData {
25598
25677
  this.onTransformLocalChange,
25599
25678
  this
25600
25679
  );
25680
+ const batchTable = this.batchTable;
25681
+ if (batchTable && typeof batchTable.destroy === "function") {
25682
+ batchTable.destroy();
25683
+ this.batchTable = null;
25684
+ }
25685
+ const featureTable = this.featureTable;
25686
+ if (featureTable && typeof featureTable.destroy === "function") {
25687
+ featureTable.destroy();
25688
+ this.featureTable = null;
25689
+ }
25601
25690
  super.destroy(force);
25602
25691
  }
25603
25692
  };
@@ -32912,6 +33001,12 @@ fn CsMain( @builtin(workgroup_id) workgroup_id : vec3<u32> , @builtin(global_inv
32912
33001
  return this._source;
32913
33002
  }
32914
33003
  set source(value) {
33004
+ if (this._source && this._source instanceof ImageBitmap) {
33005
+ try {
33006
+ this._source.close();
33007
+ } catch (e) {
33008
+ }
33009
+ }
32915
33010
  this._source = value;
32916
33011
  if (this._source instanceof HTMLImageElement) {
32917
33012
  this._source.decode().then(async () => {
@@ -32979,17 +33074,32 @@ fn CsMain( @builtin(workgroup_id) workgroup_id : vec3<u32> , @builtin(global_inv
32979
33074
  if (imageBitmap.width < 32 || imageBitmap.height < 32) {
32980
33075
  let width = Math.max(imageBitmap.width, 32);
32981
33076
  let height = Math.max(imageBitmap.height, 32);
33077
+ const oldImageBitmap = imageBitmap;
32982
33078
  imageBitmap = await createImageBitmap(imageBitmap, {
32983
33079
  resizeWidth: width,
32984
33080
  resizeHeight: height,
32985
33081
  imageOrientation: this.flipY ? "flipY" : "from-image",
32986
33082
  premultiplyAlpha: "none"
32987
33083
  });
33084
+ try {
33085
+ oldImageBitmap.close();
33086
+ } catch (e) {
33087
+ }
32988
33088
  }
32989
33089
  this.format = GPUTextureFormat.rgba8unorm;
32990
33090
  this.generate(imageBitmap);
32991
33091
  return true;
32992
33092
  }
33093
+ destroy(force) {
33094
+ if (this._source && this._source instanceof ImageBitmap) {
33095
+ try {
33096
+ this._source.close();
33097
+ } catch (e) {
33098
+ }
33099
+ this._source = null;
33100
+ }
33101
+ super.destroy(force);
33102
+ }
32993
33103
  }
32994
33104
 
32995
33105
  class LoaderBase {
@@ -36237,6 +36347,7 @@ else if (typeof exports === 'object')
36237
36347
  this._gltf,
36238
36348
  this._gltf.scene
36239
36349
  );
36350
+ subParser.destroy();
36240
36351
  if (nodes) {
36241
36352
  this.data = nodes.rootNode;
36242
36353
  return nodes.rootNode;
@@ -36274,6 +36385,7 @@ else if (typeof exports === 'object')
36274
36385
  this._gltf,
36275
36386
  this._gltf.scene
36276
36387
  );
36388
+ subParser.destroy();
36277
36389
  if (nodes) {
36278
36390
  this.data = nodes.rootNode;
36279
36391
  return nodes.rootNode;
@@ -39074,6 +39186,12 @@ else if (typeof exports === 'object')
39074
39186
  return data;
39075
39187
  }
39076
39188
  }
39189
+ destroy() {
39190
+ this.buffer = null;
39191
+ this.header = null;
39192
+ this.binOffset = null;
39193
+ this.binLength = null;
39194
+ }
39077
39195
  }
39078
39196
  class BatchTable extends FeatureTable {
39079
39197
  batchSize;
@@ -40999,6 +41117,25 @@ else if (typeof exports === 'object')
40999
41117
  this._texturePool.set(url, texture);
41000
41118
  return texture;
41001
41119
  }
41120
+ destroyTexture(url) {
41121
+ const texture = this._texturePool.get(url);
41122
+ if (texture) {
41123
+ if (!Reference.getInstance().hasReference(texture)) {
41124
+ if (!texture.isDestroyed) {
41125
+ texture.destroy();
41126
+ }
41127
+ this._texturePool.delete(url);
41128
+ return true;
41129
+ }
41130
+ return false;
41131
+ }
41132
+ return false;
41133
+ }
41134
+ destroyTextureAllUnUsed() {
41135
+ for (const [url, texture] of this._texturePool.entries()) {
41136
+ this.destroyTexture(url);
41137
+ }
41138
+ }
41002
41139
  async loadTextureCount(urls, count, loaderFunctions, flipY) {
41003
41140
  return new Promise(async (suc, fail) => {
41004
41141
  let total = 0;
@@ -41295,7 +41432,7 @@ else if (typeof exports === 'object')
41295
41432
  }
41296
41433
  }
41297
41434
 
41298
- const version = "1.0.24";
41435
+ const version = "1.0.26";
41299
41436
 
41300
41437
  class Engine3D {
41301
41438
  /**
@@ -59007,6 +59144,15 @@ fn frag(){
59007
59144
  return "unknown" /* UNKNOWN */;
59008
59145
  }
59009
59146
 
59147
+ var PlyMode = /* @__PURE__ */ ((PlyMode2) => {
59148
+ PlyMode2[PlyMode2["Splat"] = 0] = "Splat";
59149
+ PlyMode2[PlyMode2["PointCloud"] = 1] = "PointCloud";
59150
+ PlyMode2[PlyMode2["Mesh"] = 2] = "Mesh";
59151
+ return PlyMode2;
59152
+ })(PlyMode || {});
59153
+ const splatProperties = ["x", "y", "z", "scale_0", "scale_1", "scale_2", "opacity", "rot_0", "rot_1", "rot_2", "rot_3"];
59154
+ const splatColorProperties = ["red", "green", "blue", "f_dc_0", "f_dc_1", "f_dc_2"];
59155
+
59010
59156
  function byteSizeOfType(t) {
59011
59157
  switch (t) {
59012
59158
  case "char":
@@ -59082,34 +59228,85 @@ fn frag(){
59082
59228
  const lines = headerText.split(/\r?\n/);
59083
59229
  let format = "";
59084
59230
  let vertexCount = 0;
59231
+ let faceCount = 0;
59085
59232
  const properties = [];
59233
+ const faceProperties = [];
59234
+ const textureFiles = [];
59086
59235
  let inVertexElement = false;
59236
+ let inFaceElement = false;
59087
59237
  for (const line of lines) {
59088
59238
  if (line.startsWith("format ")) {
59089
59239
  format = line.split(/\s+/)[1];
59240
+ } else if (line.startsWith("comment TextureFile ")) {
59241
+ const texturePath = line.substring("comment TextureFile ".length).trim();
59242
+ if (texturePath) {
59243
+ textureFiles.push(texturePath);
59244
+ }
59090
59245
  } else if (line.startsWith("element ")) {
59091
59246
  const toks = line.split(/\s+/);
59092
59247
  inVertexElement = toks[1] === "vertex";
59093
- if (inVertexElement) vertexCount = parseInt(toks[2]);
59248
+ inFaceElement = toks[1] === "face";
59249
+ if (inVertexElement) {
59250
+ vertexCount = parseInt(toks[2]);
59251
+ inFaceElement = false;
59252
+ }
59253
+ if (inFaceElement) {
59254
+ faceCount = parseInt(toks[2]);
59255
+ inVertexElement = false;
59256
+ }
59094
59257
  } else if (inVertexElement && line.startsWith("property ")) {
59095
59258
  const toks = line.split(/\s+/);
59096
59259
  const type = toks[1];
59097
59260
  const name = toks[2];
59098
59261
  properties.push({ name, type });
59262
+ } else if (inFaceElement && line.startsWith("property ")) {
59263
+ const toks = line.split(/\s+/);
59264
+ if (toks[1] === "list") {
59265
+ const countType = toks[2];
59266
+ const itemType = toks[3];
59267
+ const name = toks[4];
59268
+ faceProperties.push({ name, type: `list ${countType} ${itemType}` });
59269
+ } else {
59270
+ const type = toks[1];
59271
+ const name = toks[2];
59272
+ faceProperties.push({ name, type });
59273
+ }
59099
59274
  }
59100
59275
  }
59101
- if (format !== "binary_little_endian") {
59102
- throw new Error("PLY: Only binary_little_endian PLY is supported");
59276
+ if (format !== "binary_little_endian" && format !== "ascii") {
59277
+ throw new Error(`PLY: Unsupported format: ${format}. Only binary_little_endian and ascii are supported.`);
59278
+ }
59279
+ let splatPropertyCount = 0;
59280
+ let splatPropertyColorCount = 0;
59281
+ for (const property of properties) {
59282
+ if (splatProperties.includes(property.name)) {
59283
+ splatPropertyCount++;
59284
+ }
59285
+ if (splatColorProperties.includes(property.name)) {
59286
+ splatPropertyColorCount++;
59287
+ }
59103
59288
  }
59104
59289
  return {
59105
59290
  format,
59106
59291
  vertexCount,
59292
+ faceCount,
59107
59293
  properties,
59108
- headerByteLength: headerText.length
59294
+ faceProperties: faceProperties.length > 0 ? faceProperties : void 0,
59295
+ textureFiles,
59296
+ headerByteLength: headerText.length,
59297
+ mode: faceCount ? PlyMode.Mesh : splatPropertyCount === splatProperties.length && splatPropertyColorCount === 3 ? PlyMode.Splat : PlyMode.PointCloud
59109
59298
  };
59110
59299
  }
59111
59300
  function parsePlyGaussianSplat(buffer) {
59112
59301
  const header = parsePlyHeader(buffer);
59302
+ const { format } = header;
59303
+ if (format === "ascii") {
59304
+ return parsePlyGaussianSplatASCII(buffer, header);
59305
+ } else {
59306
+ return parsePlyGaussianSplatBinary(buffer, header);
59307
+ }
59308
+ }
59309
+ function parsePlyGaussianSplatBinary(buffer, header) {
59113
59310
  const { vertexCount, properties, headerByteLength } = header;
59114
59311
  const payload = new DataView(buffer, headerByteLength);
59115
59312
  const has = (n) => properties.find((p) => p.name === n) != null;
@@ -59231,6 +59428,743 @@ fn frag(){
59231
59428
  sh: hasSH && shCoeffs ? { order: shOrder, coeffs: shCoeffs } : void 0
59232
59429
  };
59233
59430
  }
59431
+ function parsePlyGaussianSplatASCII(buffer, header) {
59432
+ const { vertexCount, properties } = header;
59433
+ const text = new TextDecoder("utf-8").decode(buffer);
59434
+ const headerEnd = text.indexOf("end_header");
59435
+ if (headerEnd < 0) {
59436
+ throw new Error("PLY: Invalid PLY header");
59437
+ }
59438
+ let bodyStart = headerEnd + "end_header".length;
59439
+ while (bodyStart < text.length && (text[bodyStart] === " " || text[bodyStart] === "\n" || text[bodyStart] === "\r")) {
59440
+ bodyStart++;
59441
+ }
59442
+ const bodyText = text.substring(bodyStart);
59443
+ const tokens = bodyText.split(/\s+/).filter((token) => token.length > 0);
59444
+ let tokenIndex = 0;
59445
+ const has = (n) => properties.find((p) => p.name === n) != null;
59446
+ const propIndex = (n) => properties.findIndex((p) => p.name === n);
59447
+ const parseASCIINumber = (type) => {
59448
+ if (tokenIndex >= tokens.length) {
59449
+ throw new Error("PLY: Unexpected end of file");
59450
+ }
59451
+ const value = tokens[tokenIndex++];
59452
+ switch (type) {
59453
+ case "char":
59454
+ case "uchar":
59455
+ case "short":
59456
+ case "ushort":
59457
+ case "int":
59458
+ case "uint":
59459
+ case "int8":
59460
+ case "uint8":
59461
+ case "int16":
59462
+ case "uint16":
59463
+ case "int32":
59464
+ case "uint32":
59465
+ return parseInt(value);
59466
+ case "float":
59467
+ case "double":
59468
+ case "float32":
59469
+ case "float64":
59470
+ return parseFloat(value);
59471
+ default:
59472
+ return parseFloat(value);
59473
+ }
59474
+ };
59475
+ const position = new Float32Array(vertexCount * 3);
59476
+ const scale = has("scale_0") ? new Float32Array(vertexCount * 3) : void 0;
59477
+ const rotation = has("rot_0") ? new Float32Array(vertexCount * 4) : void 0;
59478
+ const opacity = has("opacity") ? new Float32Array(vertexCount) : void 0;
59479
+ const dcIdx = [propIndex("f_dc_0"), propIndex("f_dc_1"), propIndex("f_dc_2")];
59480
+ const restIndices = [];
59481
+ for (let i = 0; i < properties.length; i++) {
59482
+ if (properties[i].name.startsWith("f_rest_")) restIndices.push(i);
59483
+ }
59484
+ const hasSH = dcIdx[0] >= 0 && dcIdx[1] >= 0 && dcIdx[2] >= 0;
59485
+ let shCoeffs = void 0;
59486
+ let shOrder = 0;
59487
+ if (hasSH) {
59488
+ const coeffsPerColor = 1 + restIndices.length / 3;
59489
+ shOrder = inferSHOrder(coeffsPerColor);
59490
+ shCoeffs = new Float32Array(vertexCount * coeffsPerColor * 3);
59491
+ }
59492
+ const ix = propIndex("x");
59493
+ const iy = propIndex("y");
59494
+ const iz = propIndex("z");
59495
+ if (ix < 0 || iy < 0 || iz < 0) {
59496
+ throw new Error("PLY: Missing x/y/z for vertex");
59497
+ }
59498
+ const s0 = scale ? propIndex("scale_0") : -1;
59499
+ const s1 = scale ? propIndex("scale_1") : -1;
59500
+ const s2 = scale ? propIndex("scale_2") : -1;
59501
+ const r0 = rotation ? propIndex("rot_0") : -1;
59502
+ const r1 = rotation ? propIndex("rot_1") : -1;
59503
+ const r2 = rotation ? propIndex("rot_2") : -1;
59504
+ const r3 = rotation ? propIndex("rot_3") : -1;
59505
+ const oi = opacity ? propIndex("opacity") : -1;
59506
+ for (let v = 0; v < vertexCount; v++) {
59507
+ for (let pIdx = 0; pIdx < properties.length; pIdx++) {
59508
+ const prop = properties[pIdx];
59509
+ const value = parseASCIINumber(prop.type);
59510
+ if (pIdx === ix) {
59511
+ position[v * 3 + 0] = value;
59512
+ } else if (pIdx === iy) {
59513
+ position[v * 3 + 1] = value;
59514
+ } else if (pIdx === iz) {
59515
+ position[v * 3 + 2] = value;
59516
+ }
59517
+ if (scale && pIdx === s0) {
59518
+ scale[v * 3 + 0] = value;
59519
+ } else if (scale && pIdx === s1) {
59520
+ scale[v * 3 + 1] = value;
59521
+ } else if (scale && pIdx === s2) {
59522
+ scale[v * 3 + 2] = value;
59523
+ }
59524
+ if (rotation && pIdx === r0) {
59525
+ rotation[v * 4 + 3] = value;
59526
+ } else if (rotation && pIdx === r1) {
59527
+ rotation[v * 4 + 0] = value;
59528
+ } else if (rotation && pIdx === r2) {
59529
+ rotation[v * 4 + 1] = value;
59530
+ } else if (rotation && pIdx === r3) {
59531
+ rotation[v * 4 + 2] = value;
59532
+ }
59533
+ if (opacity && pIdx === oi) {
59534
+ opacity[v] = value;
59535
+ }
59536
+ if (hasSH && shCoeffs) {
59537
+ const coeffsPerColor = 1 + restIndices.length / 3;
59538
+ const baseIndex = v * coeffsPerColor * 3;
59539
+ if (pIdx === dcIdx[0]) {
59540
+ shCoeffs[baseIndex + 0] = value;
59541
+ } else if (pIdx === dcIdx[1]) {
59542
+ shCoeffs[baseIndex + coeffsPerColor + 0] = value;
59543
+ } else if (pIdx === dcIdx[2]) {
59544
+ shCoeffs[baseIndex + 2 * coeffsPerColor + 0] = value;
59545
+ }
59546
+ for (let i = 0; i < restIndices.length; i += 3) {
59547
+ const ri = restIndices[i + 0];
59548
+ const gi = restIndices[i + 1];
59549
+ const bi = restIndices[i + 2];
59550
+ if (pIdx === ri) {
59551
+ shCoeffs[baseIndex + (i / 3 + 1)] = value;
59552
+ } else if (pIdx === gi) {
59553
+ shCoeffs[baseIndex + coeffsPerColor + (i / 3 + 1)] = value;
59554
+ } else if (pIdx === bi) {
59555
+ shCoeffs[baseIndex + 2 * coeffsPerColor + (i / 3 + 1)] = value;
59556
+ }
59557
+ }
59558
+ }
59559
+ }
59560
+ }
59561
+ return {
59562
+ vertexCount,
59563
+ position,
59564
+ scale,
59565
+ rotation,
59566
+ opacity,
59567
+ sh: hasSH && shCoeffs ? { order: shOrder, coeffs: shCoeffs } : void 0
59568
+ };
59569
+ }
59570
+ function parsePlyMesh(buffer) {
59571
+ const header = parsePlyHeader(buffer);
59572
+ const { format, vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
59573
+ if (format === "ascii") {
59574
+ return parsePlyMeshASCII(buffer, header);
59575
+ } else {
59576
+ return parsePlyMeshBinary(buffer, header);
59577
+ }
59578
+ }
59579
+ function parsePlyMeshBinary(buffer, header) {
59580
+ const { vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
59581
+ const payload = new DataView(buffer, headerByteLength);
59582
+ const has = (n) => properties.find((p) => p.name === n) != null;
59583
+ const propIndex = (n) => properties.findIndex((p) => p.name === n);
59584
+ const hasTexcoord = faceProperties?.some((p) => p.name === "texcoord") || false;
59585
+ const hasTexnumber = faceProperties?.some((p) => p.name === "texnumber") || false;
59586
+ faceProperties?.find((p) => p.name === "texcoord");
59587
+ faceProperties?.find((p) => p.name === "texnumber");
59588
+ const position = new Float32Array(vertexCount * 3);
59589
+ const hasNormalData = has("nx") && has("ny") && has("nz");
59590
+ const normal = hasNormalData ? new Float32Array(vertexCount * 3) : new Float32Array(vertexCount * 3);
59591
+ const color = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b")) ? new Float32Array(vertexCount * 3) : void 0;
59592
+ const hasVertexUV = (has("u") || has("s")) && (has("v") || has("t"));
59593
+ const uv = hasVertexUV || hasTexcoord ? new Float32Array(vertexCount * 2) : void 0;
59594
+ const faceTexcoords = /* @__PURE__ */ new Map();
59595
+ const faceTexnumbers = hasTexnumber ? new Array(faceCount) : [];
59596
+ const propOffsets = [];
59597
+ let stride = 0;
59598
+ for (const p of properties) {
59599
+ propOffsets.push(stride);
59600
+ stride += byteSizeOfType(p.type);
59601
+ }
59602
+ let base = 0;
59603
+ for (let v = 0; v < vertexCount; v++) {
59604
+ const vOffset = base;
59605
+ const ix = propIndex("x");
59606
+ const iy = propIndex("y");
59607
+ const iz = propIndex("z");
59608
+ if (ix < 0 || iy < 0 || iz < 0) {
59609
+ throw new Error("PLY: Missing x/y/z for vertex");
59610
+ }
59611
+ position[v * 3 + 0] = readByType(payload, vOffset + propOffsets[ix], properties[ix].type);
59612
+ position[v * 3 + 1] = readByType(payload, vOffset + propOffsets[iy], properties[iy].type);
59613
+ position[v * 3 + 2] = readByType(payload, vOffset + propOffsets[iz], properties[iz].type);
59614
+ if (hasNormalData) {
59615
+ const nx = propIndex("nx");
59616
+ const ny = propIndex("ny");
59617
+ const nz = propIndex("nz");
59618
+ normal[v * 3 + 0] = readByType(payload, vOffset + propOffsets[nx], properties[nx].type);
59619
+ normal[v * 3 + 1] = readByType(payload, vOffset + propOffsets[ny], properties[ny].type);
59620
+ normal[v * 3 + 2] = readByType(payload, vOffset + propOffsets[nz], properties[nz].type);
59621
+ }
59622
+ if (color) {
59623
+ const rIdx = propIndex("red") >= 0 ? propIndex("red") : propIndex("r");
59624
+ const gIdx = propIndex("green") >= 0 ? propIndex("green") : propIndex("g");
59625
+ const bIdx = propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b");
59626
+ if (rIdx >= 0 && gIdx >= 0 && bIdx >= 0) {
59627
+ let r = readByType(payload, vOffset + propOffsets[rIdx], properties[rIdx].type);
59628
+ let g = readByType(payload, vOffset + propOffsets[gIdx], properties[gIdx].type);
59629
+ let b = readByType(payload, vOffset + propOffsets[bIdx], properties[bIdx].type);
59630
+ if (properties[rIdx].type === "uchar" || properties[rIdx].type === "uint8") {
59631
+ r /= 255;
59632
+ g /= 255;
59633
+ b /= 255;
59634
+ }
59635
+ color[v * 3 + 0] = r;
59636
+ color[v * 3 + 1] = g;
59637
+ color[v * 3 + 2] = b;
59638
+ }
59639
+ }
59640
+ if (uv) {
59641
+ const uIdx = propIndex("u") >= 0 ? propIndex("u") : propIndex("s");
59642
+ const vIdx = propIndex("v") >= 0 ? propIndex("v") : propIndex("t");
59643
+ if (uIdx >= 0 && vIdx >= 0) {
59644
+ uv[v * 2 + 0] = readByType(payload, vOffset + propOffsets[uIdx], properties[uIdx].type);
59645
+ uv[v * 2 + 1] = readByType(payload, vOffset + propOffsets[vIdx], properties[vIdx].type);
59646
+ }
59647
+ }
59648
+ base += stride;
59649
+ }
59650
+ const indices = [];
59651
+ const triangleTexnumbers = [];
59652
+ const faceVertexUvs = [];
59653
+ let faceBase = base;
59654
+ uv && !hasVertexUV && !hasTexcoord ? new Array(vertexCount).fill(false) : null;
59655
+ for (let f = 0; f < faceCount; f++) {
59656
+ let currentOffset = faceBase;
59657
+ let faceIndices = [];
59658
+ let faceTexcoordArray = void 0;
59659
+ let faceTexnum = 0;
59660
+ let vertexCountInFace = 0;
59661
+ if (!faceProperties || faceProperties.length === 0) {
59662
+ throw new Error("PLY: Face element must have properties");
59663
+ }
59664
+ for (const prop of faceProperties) {
59665
+ if (prop.name === "vertex_indices") {
59666
+ const parts = prop.type.split(" ");
59667
+ if (parts.length !== 3 || parts[0] !== "list") {
59668
+ throw new Error(`PLY: Invalid vertex_indices property type: ${prop.type}`);
59669
+ }
59670
+ const countType = parts[1];
59671
+ const itemType = parts[2];
59672
+ vertexCountInFace = readByType(payload, currentOffset, countType);
59673
+ currentOffset += byteSizeOfType(countType);
59674
+ if (vertexCountInFace < 3) {
59675
+ throw new Error(`PLY: Face ${f} has less than 3 vertices`);
59676
+ }
59677
+ const indexSize = byteSizeOfType(itemType);
59678
+ faceIndices = [];
59679
+ for (let i = 0; i < vertexCountInFace; i++) {
59680
+ const idx = readByType(payload, currentOffset, itemType);
59681
+ faceIndices.push(idx);
59682
+ currentOffset += indexSize;
59683
+ }
59684
+ } else if (prop.name === "texcoord") {
59685
+ const parts = prop.type.split(" ");
59686
+ if (parts.length !== 3 || parts[0] !== "list") {
59687
+ throw new Error(`PLY: Invalid texcoord property type: ${prop.type}`);
59688
+ }
59689
+ const countType = parts[1];
59690
+ const itemType = parts[2];
59691
+ const texcoordCount = readByType(payload, currentOffset, countType);
59692
+ currentOffset += byteSizeOfType(countType);
59693
+ const itemSize = byteSizeOfType(itemType);
59694
+ faceTexcoordArray = new Float32Array(texcoordCount);
59695
+ for (let i = 0; i < texcoordCount; i++) {
59696
+ faceTexcoordArray[i] = readByType(payload, currentOffset, itemType);
59697
+ currentOffset += itemSize;
59698
+ }
59699
+ faceTexcoords.set(f, faceTexcoordArray);
59700
+ } else if (prop.name === "texnumber") {
59701
+ faceTexnum = readByType(payload, currentOffset, prop.type);
59702
+ currentOffset += byteSizeOfType(prop.type);
59703
+ faceTexnumbers[f] = faceTexnum;
59704
+ } else {
59705
+ if (prop.type.startsWith("list ")) {
59706
+ const parts = prop.type.split(" ");
59707
+ if (parts.length === 3) {
59708
+ const countType = parts[1];
59709
+ const itemType = parts[2];
59710
+ const count = readByType(payload, currentOffset, countType);
59711
+ currentOffset += byteSizeOfType(countType);
59712
+ const itemSize = byteSizeOfType(itemType);
59713
+ currentOffset += count * itemSize;
59714
+ }
59715
+ } else {
59716
+ currentOffset += byteSizeOfType(prop.type);
59717
+ }
59718
+ }
59719
+ }
59720
+ faceBase = currentOffset;
59721
+ const texnum = hasTexnumber ? faceTexnumbers[f] ?? 0 : 0;
59722
+ if (vertexCountInFace === 3) {
59723
+ indices.push(faceIndices[0], faceIndices[1], faceIndices[2]);
59724
+ if (hasTexnumber) {
59725
+ triangleTexnumbers.push(texnum);
59726
+ }
59727
+ if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= 6) {
59728
+ faceVertexUvs.push(
59729
+ faceTexcoordArray[0],
59730
+ 1 - faceTexcoordArray[1],
59731
+ // vertex 0
59732
+ faceTexcoordArray[2],
59733
+ 1 - faceTexcoordArray[3],
59734
+ // vertex 1
59735
+ faceTexcoordArray[4],
59736
+ 1 - faceTexcoordArray[5]
59737
+ // vertex 2
59738
+ );
59739
+ }
59740
+ } else {
59741
+ for (let i = 1; i < vertexCountInFace - 1; i++) {
59742
+ indices.push(faceIndices[0], faceIndices[i], faceIndices[i + 1]);
59743
+ if (hasTexnumber) {
59744
+ triangleTexnumbers.push(texnum);
59745
+ }
59746
+ if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= vertexCountInFace * 2) {
59747
+ faceVertexUvs.push(
59748
+ faceTexcoordArray[0],
59749
+ 1 - faceTexcoordArray[1],
59750
+ // vertex 0 (center of fan)
59751
+ faceTexcoordArray[i * 2 + 0],
59752
+ 1 - faceTexcoordArray[i * 2 + 1],
59753
+ // vertex i
59754
+ faceTexcoordArray[(i + 1) * 2 + 0],
59755
+ 1 - faceTexcoordArray[(i + 1) * 2 + 1]
59756
+ // vertex i+1
59757
+ );
59758
+ }
59759
+ }
59760
+ }
59761
+ }
59762
+ if (!hasNormalData) {
59763
+ for (let i = 0; i < vertexCount * 3; i++) {
59764
+ normal[i] = 0;
59765
+ }
59766
+ for (let i = 0; i < indices.length; i += 3) {
59767
+ const i0 = indices[i];
59768
+ const i1 = indices[i + 1];
59769
+ const i2 = indices[i + 2];
59770
+ const v0x = position[i0 * 3 + 0];
59771
+ const v0y = position[i0 * 3 + 1];
59772
+ const v0z = position[i0 * 3 + 2];
59773
+ const v1x = position[i1 * 3 + 0];
59774
+ const v1y = position[i1 * 3 + 1];
59775
+ const v1z = position[i1 * 3 + 2];
59776
+ const v2x = position[i2 * 3 + 0];
59777
+ const v2y = position[i2 * 3 + 1];
59778
+ const v2z = position[i2 * 3 + 2];
59779
+ const edge1x = v1x - v0x;
59780
+ const edge1y = v1y - v0y;
59781
+ const edge1z = v1z - v0z;
59782
+ const edge2x = v2x - v0x;
59783
+ const edge2y = v2y - v0y;
59784
+ const edge2z = v2z - v0z;
59785
+ const nx = edge1y * edge2z - edge1z * edge2y;
59786
+ const ny = edge1z * edge2x - edge1x * edge2z;
59787
+ const nz = edge1x * edge2y - edge1y * edge2x;
59788
+ normal[i0 * 3 + 0] += nx;
59789
+ normal[i0 * 3 + 1] += ny;
59790
+ normal[i0 * 3 + 2] += nz;
59791
+ normal[i1 * 3 + 0] += nx;
59792
+ normal[i1 * 3 + 1] += ny;
59793
+ normal[i1 * 3 + 2] += nz;
59794
+ normal[i2 * 3 + 0] += nx;
59795
+ normal[i2 * 3 + 1] += ny;
59796
+ normal[i2 * 3 + 2] += nz;
59797
+ }
59798
+ for (let v = 0; v < vertexCount; v++) {
59799
+ const nx = normal[v * 3 + 0];
59800
+ const ny = normal[v * 3 + 1];
59801
+ const nz = normal[v * 3 + 2];
59802
+ const length = Math.sqrt(nx * nx + ny * ny + nz * nz);
59803
+ if (length > 1e-5) {
59804
+ normal[v * 3 + 0] = nx / length;
59805
+ normal[v * 3 + 1] = ny / length;
59806
+ normal[v * 3 + 2] = nz / length;
59807
+ } else {
59808
+ normal[v * 3 + 0] = 0;
59809
+ normal[v * 3 + 1] = 1;
59810
+ normal[v * 3 + 2] = 0;
59811
+ }
59812
+ }
59813
+ }
59814
+ let finalPosition = position;
59815
+ let finalNormal = normal;
59816
+ let finalColor = color;
59817
+ let finalUv = void 0;
59818
+ let finalIndices = void 0;
59819
+ if (hasTexcoord && faceVertexUvs.length > 0) {
59820
+ const triangleCount = indices.length / 3;
59821
+ const expandedPosition = new Float32Array(triangleCount * 3 * 3);
59822
+ const expandedNormal = new Float32Array(triangleCount * 3 * 3);
59823
+ const expandedColor = color ? new Float32Array(triangleCount * 3 * 3) : void 0;
59824
+ finalUv = new Float32Array(faceVertexUvs);
59825
+ for (let i = 0; i < triangleCount; i++) {
59826
+ const baseIdx = i * 3;
59827
+ const i0 = indices[baseIdx + 0];
59828
+ const i1 = indices[baseIdx + 1];
59829
+ const i2 = indices[baseIdx + 2];
59830
+ expandedPosition[i * 9 + 0] = position[i0 * 3 + 0];
59831
+ expandedPosition[i * 9 + 1] = position[i0 * 3 + 1];
59832
+ expandedPosition[i * 9 + 2] = position[i0 * 3 + 2];
59833
+ expandedPosition[i * 9 + 3] = position[i1 * 3 + 0];
59834
+ expandedPosition[i * 9 + 4] = position[i1 * 3 + 1];
59835
+ expandedPosition[i * 9 + 5] = position[i1 * 3 + 2];
59836
+ expandedPosition[i * 9 + 6] = position[i2 * 3 + 0];
59837
+ expandedPosition[i * 9 + 7] = position[i2 * 3 + 1];
59838
+ expandedPosition[i * 9 + 8] = position[i2 * 3 + 2];
59839
+ expandedNormal[i * 9 + 0] = normal[i0 * 3 + 0];
59840
+ expandedNormal[i * 9 + 1] = normal[i0 * 3 + 1];
59841
+ expandedNormal[i * 9 + 2] = normal[i0 * 3 + 2];
59842
+ expandedNormal[i * 9 + 3] = normal[i1 * 3 + 0];
59843
+ expandedNormal[i * 9 + 4] = normal[i1 * 3 + 1];
59844
+ expandedNormal[i * 9 + 5] = normal[i1 * 3 + 2];
59845
+ expandedNormal[i * 9 + 6] = normal[i2 * 3 + 0];
59846
+ expandedNormal[i * 9 + 7] = normal[i2 * 3 + 1];
59847
+ expandedNormal[i * 9 + 8] = normal[i2 * 3 + 2];
59848
+ if (expandedColor && color) {
59849
+ expandedColor[i * 9 + 0] = color[i0 * 3 + 0];
59850
+ expandedColor[i * 9 + 1] = color[i0 * 3 + 1];
59851
+ expandedColor[i * 9 + 2] = color[i0 * 3 + 2];
59852
+ expandedColor[i * 9 + 3] = color[i1 * 3 + 0];
59853
+ expandedColor[i * 9 + 4] = color[i1 * 3 + 1];
59854
+ expandedColor[i * 9 + 5] = color[i1 * 3 + 2];
59855
+ expandedColor[i * 9 + 6] = color[i2 * 3 + 0];
59856
+ expandedColor[i * 9 + 7] = color[i2 * 3 + 1];
59857
+ expandedColor[i * 9 + 8] = color[i2 * 3 + 2];
59858
+ }
59859
+ }
59860
+ finalPosition = expandedPosition;
59861
+ finalNormal = expandedNormal;
59862
+ finalColor = expandedColor;
59863
+ const sequentialIndices = new Uint32Array(triangleCount * 3);
59864
+ for (let i = 0; i < triangleCount * 3; i++) {
59865
+ sequentialIndices[i] = i;
59866
+ }
59867
+ finalIndices = sequentialIndices;
59868
+ } else {
59869
+ finalIndices = new Uint32Array(indices);
59870
+ finalUv = uv;
59871
+ }
59872
+ return {
59873
+ vertexCount: hasTexcoord && faceVertexUvs.length > 0 ? finalPosition.length / 3 : vertexCount,
59874
+ faceCount,
59875
+ position: finalPosition,
59876
+ normal: finalNormal,
59877
+ color: finalColor,
59878
+ uv: finalUv,
59879
+ indices: finalIndices,
59880
+ textureFiles: textureFiles.length > 0 ? textureFiles : void 0,
59881
+ triangleTexnumbers: triangleTexnumbers.length > 0 ? triangleTexnumbers : void 0
59882
+ };
59883
+ }
59884
+ function parsePlyMeshASCII(buffer, header) {
59885
+ const { vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
59886
+ const text = new TextDecoder("utf-8").decode(buffer);
59887
+ const headerEnd = text.indexOf("end_header");
59888
+ if (headerEnd < 0) {
59889
+ throw new Error("PLY: Invalid PLY header");
59890
+ }
59891
+ let bodyStart = headerEnd + "end_header".length;
59892
+ while (bodyStart < text.length && (text[bodyStart] === " " || text[bodyStart] === "\n" || text[bodyStart] === "\r")) {
59893
+ bodyStart++;
59894
+ }
59895
+ const bodyText = text.substring(bodyStart);
59896
+ const tokens = bodyText.split(/\s+/).filter((token) => token.length > 0);
59897
+ let tokenIndex = 0;
59898
+ const has = (n) => properties.find((p) => p.name === n) != null;
59899
+ const parseASCIINumber = (type) => {
59900
+ if (tokenIndex >= tokens.length) {
59901
+ throw new Error("PLY: Unexpected end of file");
59902
+ }
59903
+ const value = tokens[tokenIndex++];
59904
+ switch (type) {
59905
+ case "char":
59906
+ case "uchar":
59907
+ case "short":
59908
+ case "ushort":
59909
+ case "int":
59910
+ case "uint":
59911
+ case "int8":
59912
+ case "uint8":
59913
+ case "int16":
59914
+ case "uint16":
59915
+ case "int32":
59916
+ case "uint32":
59917
+ return parseInt(value);
59918
+ case "float":
59919
+ case "double":
59920
+ case "float32":
59921
+ case "float64":
59922
+ return parseFloat(value);
59923
+ default:
59924
+ return parseFloat(value);
59925
+ }
59926
+ };
59927
+ const position = new Float32Array(vertexCount * 3);
59928
+ const hasNormalData = has("nx") && has("ny") && has("nz");
59929
+ const normal = hasNormalData ? new Float32Array(vertexCount * 3) : new Float32Array(vertexCount * 3);
59930
+ const color = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b")) ? new Float32Array(vertexCount * 3) : void 0;
59931
+ const hasVertexUV = (has("u") || has("s")) && (has("v") || has("t"));
59932
+ const hasTexcoord = faceProperties?.some((p) => p.name === "texcoord") || false;
59933
+ const uv = hasVertexUV || hasTexcoord ? new Float32Array(vertexCount * 2) : void 0;
59934
+ const faceTexcoords = /* @__PURE__ */ new Map();
59935
+ const hasTexnumber = faceProperties?.some((p) => p.name === "texnumber") || false;
59936
+ const faceTexnumbers = hasTexnumber ? new Array(faceCount) : [];
59937
+ const indices = [];
59938
+ const triangleTexnumbers = [];
59939
+ const faceVertexUvs = [];
59940
+ const propIndex = (n) => properties.findIndex((p) => p.name === n);
59941
+ const xIdx = propIndex("x");
59942
+ const yIdx = propIndex("y");
59943
+ const zIdx = propIndex("z");
59944
+ const nxIdx = hasNormalData ? propIndex("nx") : -1;
59945
+ const nyIdx = hasNormalData ? propIndex("ny") : -1;
59946
+ const nzIdx = hasNormalData ? propIndex("nz") : -1;
59947
+ const rIdx = color ? propIndex("red") >= 0 ? propIndex("red") : propIndex("r") : -1;
59948
+ const gIdx = color ? propIndex("green") >= 0 ? propIndex("green") : propIndex("g") : -1;
59949
+ const bIdx = color ? propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b") : -1;
59950
+ const uIdx = uv && hasVertexUV ? propIndex("u") >= 0 ? propIndex("u") : propIndex("s") : -1;
59951
+ const vIdx = uv && hasVertexUV ? propIndex("v") >= 0 ? propIndex("v") : propIndex("t") : -1;
59952
+ for (let v = 0; v < vertexCount; v++) {
59953
+ for (let pIdx = 0; pIdx < properties.length; pIdx++) {
59954
+ const prop = properties[pIdx];
59955
+ const value = parseASCIINumber(prop.type);
59956
+ if (pIdx === xIdx) {
59957
+ position[v * 3 + 0] = value;
59958
+ } else if (pIdx === yIdx) {
59959
+ position[v * 3 + 1] = value;
59960
+ } else if (pIdx === zIdx) {
59961
+ position[v * 3 + 2] = value;
59962
+ } else if (pIdx === nxIdx) {
59963
+ normal[v * 3 + 0] = value;
59964
+ } else if (pIdx === nyIdx) {
59965
+ normal[v * 3 + 1] = value;
59966
+ } else if (pIdx === nzIdx) {
59967
+ normal[v * 3 + 2] = value;
59968
+ } else if (pIdx === rIdx && color) {
59969
+ color[v * 3 + 0] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
59970
+ } else if (pIdx === gIdx && color) {
59971
+ color[v * 3 + 1] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
59972
+ } else if (pIdx === bIdx && color) {
59973
+ color[v * 3 + 2] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
59974
+ } else if (pIdx === uIdx && uv) {
59975
+ uv[v * 2 + 0] = value;
59976
+ } else if (pIdx === vIdx && uv) {
59977
+ uv[v * 2 + 1] = value;
59978
+ }
59979
+ }
59980
+ }
59981
+ for (let f = 0; f < faceCount; f++) {
59982
+ let faceIndices = [];
59983
+ let faceTexcoordArray = void 0;
59984
+ let faceTexnum = 0;
59985
+ for (const prop of faceProperties || []) {
59986
+ if (prop.name === "vertex_indices") {
59987
+ const parts = prop.type.split(" ");
59988
+ const countType = parts[1];
59989
+ const itemType = parts[2];
59990
+ const vertexCountInFace2 = parseASCIINumber(countType);
59991
+ faceIndices = [];
59992
+ for (let i = 0; i < vertexCountInFace2; i++) {
59993
+ faceIndices.push(parseASCIINumber(itemType));
59994
+ }
59995
+ } else if (prop.name === "texcoord") {
59996
+ const parts = prop.type.split(" ");
59997
+ const countType = parts[1];
59998
+ const itemType = parts[2];
59999
+ const texcoordCount = parseASCIINumber(countType);
60000
+ faceTexcoordArray = new Float32Array(texcoordCount);
60001
+ for (let i = 0; i < texcoordCount; i++) {
60002
+ faceTexcoordArray[i] = parseASCIINumber(itemType);
60003
+ }
60004
+ faceTexcoords.set(f, faceTexcoordArray);
60005
+ } else if (prop.name === "texnumber") {
60006
+ faceTexnum = parseASCIINumber(prop.type);
60007
+ faceTexnumbers[f] = faceTexnum;
60008
+ }
60009
+ }
60010
+ const vertexCountInFace = faceIndices.length;
60011
+ const texnum = hasTexnumber ? faceTexnumbers[f] ?? 0 : 0;
60012
+ if (vertexCountInFace === 3) {
60013
+ indices.push(faceIndices[0], faceIndices[1], faceIndices[2]);
60014
+ if (hasTexnumber) {
60015
+ triangleTexnumbers.push(texnum);
60016
+ }
60017
+ if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= 6) {
60018
+ faceVertexUvs.push(
60019
+ faceTexcoordArray[0],
60020
+ 1 - faceTexcoordArray[1],
60021
+ faceTexcoordArray[2],
60022
+ 1 - faceTexcoordArray[3],
60023
+ faceTexcoordArray[4],
60024
+ 1 - faceTexcoordArray[5]
60025
+ );
60026
+ }
60027
+ } else {
60028
+ for (let i = 1; i < vertexCountInFace - 1; i++) {
60029
+ indices.push(faceIndices[0], faceIndices[i], faceIndices[i + 1]);
60030
+ if (hasTexnumber) {
60031
+ triangleTexnumbers.push(texnum);
60032
+ }
60033
+ if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= vertexCountInFace * 2) {
60034
+ faceVertexUvs.push(
60035
+ faceTexcoordArray[0],
60036
+ 1 - faceTexcoordArray[1],
60037
+ faceTexcoordArray[i * 2 + 0],
60038
+ 1 - faceTexcoordArray[i * 2 + 1],
60039
+ faceTexcoordArray[(i + 1) * 2 + 0],
60040
+ 1 - faceTexcoordArray[(i + 1) * 2 + 1]
60041
+ );
60042
+ }
60043
+ }
60044
+ }
60045
+ }
60046
+ if (!hasNormalData) {
60047
+ for (let i = 0; i < vertexCount * 3; i++) {
60048
+ normal[i] = 0;
60049
+ }
60050
+ for (let i = 0; i < indices.length; i += 3) {
60051
+ const i0 = indices[i];
60052
+ const i1 = indices[i + 1];
60053
+ const i2 = indices[i + 2];
60054
+ const v0x = position[i0 * 3 + 0];
60055
+ const v0y = position[i0 * 3 + 1];
60056
+ const v0z = position[i0 * 3 + 2];
60057
+ const v1x = position[i1 * 3 + 0];
60058
+ const v1y = position[i1 * 3 + 1];
60059
+ const v1z = position[i1 * 3 + 2];
60060
+ const v2x = position[i2 * 3 + 0];
60061
+ const v2y = position[i2 * 3 + 1];
60062
+ const v2z = position[i2 * 3 + 2];
60063
+ const edge1x = v1x - v0x;
60064
+ const edge1y = v1y - v0y;
60065
+ const edge1z = v1z - v0z;
60066
+ const edge2x = v2x - v0x;
60067
+ const edge2y = v2y - v0y;
60068
+ const edge2z = v2z - v0z;
60069
+ const nx = edge1y * edge2z - edge1z * edge2y;
60070
+ const ny = edge1z * edge2x - edge1x * edge2z;
60071
+ const nz = edge1x * edge2y - edge1y * edge2x;
60072
+ normal[i0 * 3 + 0] += nx;
60073
+ normal[i0 * 3 + 1] += ny;
60074
+ normal[i0 * 3 + 2] += nz;
60075
+ normal[i1 * 3 + 0] += nx;
60076
+ normal[i1 * 3 + 1] += ny;
60077
+ normal[i1 * 3 + 2] += nz;
60078
+ normal[i2 * 3 + 0] += nx;
60079
+ normal[i2 * 3 + 1] += ny;
60080
+ normal[i2 * 3 + 2] += nz;
60081
+ }
60082
+ for (let v = 0; v < vertexCount; v++) {
60083
+ const nx = normal[v * 3 + 0];
60084
+ const ny = normal[v * 3 + 1];
60085
+ const nz = normal[v * 3 + 2];
60086
+ const length = Math.sqrt(nx * nx + ny * ny + nz * nz);
60087
+ if (length > 1e-5) {
60088
+ normal[v * 3 + 0] = nx / length;
60089
+ normal[v * 3 + 1] = ny / length;
60090
+ normal[v * 3 + 2] = nz / length;
60091
+ } else {
60092
+ normal[v * 3 + 0] = 0;
60093
+ normal[v * 3 + 1] = 1;
60094
+ normal[v * 3 + 2] = 0;
60095
+ }
60096
+ }
60097
+ }
60098
+ let finalPosition = position;
60099
+ let finalNormal = normal;
60100
+ let finalColor = color;
60101
+ let finalUv = void 0;
60102
+ let finalIndices = void 0;
60103
+ if (hasTexcoord && faceVertexUvs.length > 0) {
60104
+ const triangleCount = indices.length / 3;
60105
+ const expandedPosition = new Float32Array(triangleCount * 3 * 3);
60106
+ const expandedNormal = new Float32Array(triangleCount * 3 * 3);
60107
+ const expandedColor = color ? new Float32Array(triangleCount * 3 * 3) : void 0;
60108
+ finalUv = new Float32Array(faceVertexUvs);
60109
+ for (let i = 0; i < triangleCount; i++) {
60110
+ const baseIdx = i * 3;
60111
+ const i0 = indices[baseIdx + 0];
60112
+ const i1 = indices[baseIdx + 1];
60113
+ const i2 = indices[baseIdx + 2];
60114
+ expandedPosition[i * 9 + 0] = position[i0 * 3 + 0];
60115
+ expandedPosition[i * 9 + 1] = position[i0 * 3 + 1];
60116
+ expandedPosition[i * 9 + 2] = position[i0 * 3 + 2];
60117
+ expandedPosition[i * 9 + 3] = position[i1 * 3 + 0];
60118
+ expandedPosition[i * 9 + 4] = position[i1 * 3 + 1];
60119
+ expandedPosition[i * 9 + 5] = position[i1 * 3 + 2];
60120
+ expandedPosition[i * 9 + 6] = position[i2 * 3 + 0];
60121
+ expandedPosition[i * 9 + 7] = position[i2 * 3 + 1];
60122
+ expandedPosition[i * 9 + 8] = position[i2 * 3 + 2];
60123
+ expandedNormal[i * 9 + 0] = normal[i0 * 3 + 0];
60124
+ expandedNormal[i * 9 + 1] = normal[i0 * 3 + 1];
60125
+ expandedNormal[i * 9 + 2] = normal[i0 * 3 + 2];
60126
+ expandedNormal[i * 9 + 3] = normal[i1 * 3 + 0];
60127
+ expandedNormal[i * 9 + 4] = normal[i1 * 3 + 1];
60128
+ expandedNormal[i * 9 + 5] = normal[i1 * 3 + 2];
60129
+ expandedNormal[i * 9 + 6] = normal[i2 * 3 + 0];
60130
+ expandedNormal[i * 9 + 7] = normal[i2 * 3 + 1];
60131
+ expandedNormal[i * 9 + 8] = normal[i2 * 3 + 2];
60132
+ if (expandedColor && color) {
60133
+ expandedColor[i * 9 + 0] = color[i0 * 3 + 0];
60134
+ expandedColor[i * 9 + 1] = color[i0 * 3 + 1];
60135
+ expandedColor[i * 9 + 2] = color[i0 * 3 + 2];
60136
+ expandedColor[i * 9 + 3] = color[i1 * 3 + 0];
60137
+ expandedColor[i * 9 + 4] = color[i1 * 3 + 1];
60138
+ expandedColor[i * 9 + 5] = color[i1 * 3 + 2];
60139
+ expandedColor[i * 9 + 6] = color[i2 * 3 + 0];
60140
+ expandedColor[i * 9 + 7] = color[i2 * 3 + 1];
60141
+ expandedColor[i * 9 + 8] = color[i2 * 3 + 2];
60142
+ }
60143
+ }
60144
+ finalPosition = expandedPosition;
60145
+ finalNormal = expandedNormal;
60146
+ finalColor = expandedColor;
60147
+ const sequentialIndices = new Uint32Array(triangleCount * 3);
60148
+ for (let i = 0; i < triangleCount * 3; i++) {
60149
+ sequentialIndices[i] = i;
60150
+ }
60151
+ finalIndices = sequentialIndices;
60152
+ } else {
60153
+ finalIndices = new Uint32Array(indices);
60154
+ finalUv = uv;
60155
+ }
60156
+ return {
60157
+ vertexCount: hasTexcoord && faceVertexUvs.length > 0 ? finalPosition.length / 3 : vertexCount,
60158
+ faceCount,
60159
+ position: finalPosition,
60160
+ normal: finalNormal,
60161
+ color: finalColor,
60162
+ uv: finalUv,
60163
+ indices: finalIndices,
60164
+ textureFiles: textureFiles.length > 0 ? textureFiles : void 0,
60165
+ triangleTexnumbers: triangleTexnumbers.length > 0 ? triangleTexnumbers : void 0
60166
+ };
60167
+ }
59234
60168
 
59235
60169
  class GaussianSplatParser extends ParserBase {
59236
60170
  static format = ParserFormat.BIN;
@@ -59339,6 +60273,133 @@ fn frag(){
59339
60273
  class KHR_materials_ior {
59340
60274
  }
59341
60275
 
60276
+ class PlyParser extends ParserBase {
60277
+ static format = ParserFormat.BIN;
60278
+ async parseBuffer(buffer) {
60279
+ const header = parsePlyHeader(buffer);
60280
+ switch (header.mode) {
60281
+ case PlyMode.Splat: {
60282
+ const plyData = parsePlyGaussianSplat(buffer);
60283
+ const asset = {
60284
+ count: plyData.vertexCount,
60285
+ position: plyData.position,
60286
+ rotation: plyData.rotation,
60287
+ scale: plyData.scale,
60288
+ opacity: plyData.opacity,
60289
+ sh: plyData.sh
60290
+ };
60291
+ asset.bbox = computeAABBFromPositions(plyData.position);
60292
+ const gsplatObj = new exports.Object3D();
60293
+ gsplatObj.name = "GaussianSplat";
60294
+ const renderer = gsplatObj.addComponent(exports.GSplatRenderer);
60295
+ renderer.initAsset(asset);
60296
+ this.data = gsplatObj;
60297
+ break;
60298
+ }
60299
+ case PlyMode.PointCloud: {
60300
+ break;
60301
+ }
60302
+ case PlyMode.Mesh: {
60303
+ const plyData = parsePlyMesh(buffer);
60304
+ const rootObj = new exports.Object3D();
60305
+ rootObj.name = "PLYMesh";
60306
+ const textureGroups = /* @__PURE__ */ new Map();
60307
+ if (plyData.triangleTexnumbers && plyData.triangleTexnumbers.length > 0) {
60308
+ for (let i = 0; i < plyData.triangleTexnumbers.length; i++) {
60309
+ const texnum = plyData.triangleTexnumbers[i];
60310
+ if (!textureGroups.has(texnum)) {
60311
+ textureGroups.set(texnum, []);
60312
+ }
60313
+ textureGroups.get(texnum).push(i);
60314
+ }
60315
+ } else {
60316
+ const triangleCount = plyData.indices.length / 3;
60317
+ const allTriangles = [];
60318
+ for (let i = 0; i < triangleCount; i++) {
60319
+ allTriangles.push(i);
60320
+ }
60321
+ textureGroups.set(0, allTriangles);
60322
+ }
60323
+ const materials = /* @__PURE__ */ new Map();
60324
+ if (plyData.textureFiles && plyData.textureFiles.length > 0) {
60325
+ const promiseList = [];
60326
+ for (let texnum = 0; texnum < plyData.textureFiles.length; texnum++) {
60327
+ const material = new LitMaterial();
60328
+ const texturePath = StringUtil.normalizePath(
60329
+ this.baseUrl + plyData.textureFiles[texnum]
60330
+ );
60331
+ promiseList.push(Engine3D.res.loadTexture(texturePath).then((texture) => {
60332
+ material.baseMap = texture;
60333
+ materials.set(texnum, material);
60334
+ }));
60335
+ }
60336
+ await Promise.all(promiseList);
60337
+ }
60338
+ if (materials.size === 0) {
60339
+ materials.set(0, new LitMaterial());
60340
+ }
60341
+ for (const [texnum, triangleIndices] of textureGroups) {
60342
+ const groupIndices = [];
60343
+ for (const triIdx of triangleIndices) {
60344
+ const baseIdx = triIdx * 3;
60345
+ groupIndices.push(
60346
+ plyData.indices[baseIdx + 0],
60347
+ plyData.indices[baseIdx + 1],
60348
+ plyData.indices[baseIdx + 2]
60349
+ );
60350
+ }
60351
+ const geometry = new GeometryBase();
60352
+ geometry.setAttribute(
60353
+ VertexAttributeName.position,
60354
+ plyData.position
60355
+ );
60356
+ geometry.setAttribute(
60357
+ VertexAttributeName.normal,
60358
+ plyData.normal
60359
+ );
60360
+ if (plyData.uv) {
60361
+ geometry.setAttribute(
60362
+ VertexAttributeName.uv,
60363
+ plyData.uv
60364
+ );
60365
+ }
60366
+ if (plyData.color) {
60367
+ geometry.setAttribute(
60368
+ VertexAttributeName.color,
60369
+ plyData.color
60370
+ );
60371
+ }
60372
+ geometry.setIndices(new Uint32Array(groupIndices));
60373
+ geometry.addSubGeometry({
60374
+ indexStart: 0,
60375
+ indexCount: groupIndices.length,
60376
+ vertexStart: 0,
60377
+ vertexCount: 0,
60378
+ firstStart: 0,
60379
+ index: 0,
60380
+ topology: 0
60381
+ });
60382
+ let material = materials.get(texnum);
60383
+ if (!material) {
60384
+ material = materials.values().next().value || new LitMaterial();
60385
+ }
60386
+ const meshObj = new exports.Object3D();
60387
+ meshObj.name = `PLYMesh_Texture_${texnum}`;
60388
+ const renderer = meshObj.addComponent(exports.MeshRenderer);
60389
+ renderer.geometry = geometry;
60390
+ renderer.material = material;
60391
+ rootObj.addChild(meshObj);
60392
+ }
60393
+ this.data = rootObj;
60394
+ break;
60395
+ }
60396
+ }
60397
+ }
60398
+ verification() {
60399
+ return !!this.data;
60400
+ }
60401
+ }
60402
+
59342
60403
  class PrefabBoneData {
59343
60404
  boneName;
59344
60405
  bonePath;
@@ -62527,7 +63588,7 @@ fn frag(){
62527
63588
  if (sceneObj.parent) {
62528
63589
  sceneObj.parent.object3D.removeChild(sceneObj);
62529
63590
  }
62530
- sceneObj.destroy();
63591
+ sceneObj.destroy(true);
62531
63592
  tileItem.cached.scene = null;
62532
63593
  }
62533
63594
  tileItem.loadingState = UNLOADED;
@@ -62841,7 +63902,7 @@ fn frag(){
62841
63902
  /**
62842
63903
  * Clean up resources
62843
63904
  */
62844
- dispose() {
63905
+ dispose(force) {
62845
63906
  const plugins = [...this.plugins];
62846
63907
  plugins.forEach((plugin) => this.unregisterPlugin(plugin));
62847
63908
  this.lruCache.clear();
@@ -62853,7 +63914,7 @@ fn frag(){
62853
63914
  this.frameCount = 0;
62854
63915
  this.isLoading = false;
62855
63916
  this.resetCacheStats();
62856
- this.group.destroy();
63917
+ this.group.destroy(force);
62857
63918
  }
62858
63919
  /**
62859
63920
  * Rings-specific: Add camera
@@ -69322,6 +70383,8 @@ fn frag(){
69322
70383
  exports.Plane3D = Plane3D;
69323
70384
  exports.PlaneClassification = PlaneClassification;
69324
70385
  exports.PlaneGeometry = PlaneGeometry;
70386
+ exports.PlyMode = PlyMode;
70387
+ exports.PlyParser = PlyParser;
69325
70388
  exports.PointClassification = PointClassification;
69326
70389
  exports.PointLightShadowRenderer = PointLightShadowRenderer;
69327
70390
  exports.PointShadowCubeCamera = PointShadowCubeCamera;
@@ -69662,6 +70725,7 @@ fn frag(){
69662
70725
  exports.outlinePostManager = outlinePostManager;
69663
70726
  exports.parsePlyGaussianSplat = parsePlyGaussianSplat;
69664
70727
  exports.parsePlyHeader = parsePlyHeader;
70728
+ exports.parsePlyMesh = parsePlyMesh;
69665
70729
  exports.perm = perm;
69666
70730
  exports.post = post;
69667
70731
  exports.priorityCallback = priorityCallback;
@@ -69697,6 +70761,8 @@ fn frag(){
69697
70761
  exports.snoise2 = snoise2;
69698
70762
  exports.snoise3 = snoise3;
69699
70763
  exports.snoise4 = snoise4;
70764
+ exports.splatColorProperties = splatColorProperties;
70765
+ exports.splatProperties = splatProperties;
69700
70766
  exports.sqrMagnitude = sqrMagnitude;
69701
70767
  exports.sqrtImpl = sqrtImpl;
69702
70768
  exports.stencilStateFace = stencilStateFace;