minidraco 0.1.0 → 0.2.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
@@ -200,6 +200,14 @@ var DecoderBuffer = class {
200
200
  this._pos += size;
201
201
  return result;
202
202
  }
203
+ // Zero-copy variant of decodeBytes: a view into the stream, only valid until
204
+ // the caller's next chance to mutate the buffer — copy out before keeping it.
205
+ decodeBytesView(size) {
206
+ if (this._pos + size > this._dataSize) return void 0;
207
+ const result = this._data.subarray(this._pos, this._pos + size);
208
+ this._pos += size;
209
+ return result;
210
+ }
203
211
  startBitDecoding(decodeSize) {
204
212
  let outSize = 0;
205
213
  if (decodeSize) {
@@ -257,6 +265,48 @@ var DecoderBuffer = class {
257
265
  }
258
266
  };
259
267
 
268
+ // src/decoder/core/ScratchArena.ts
269
+ var freeInt32 = [];
270
+ var freeUint8 = [];
271
+ var borrowedInt32 = [];
272
+ var borrowedUint8 = [];
273
+ var acquire = (free, borrowed, size) => {
274
+ for (let i = free.length - 1; i >= 0; --i) {
275
+ const buffer = free[i];
276
+ if (buffer.length >= size) {
277
+ free[i] = free[free.length - 1];
278
+ free.pop();
279
+ borrowed.push(buffer);
280
+ return buffer;
281
+ }
282
+ }
283
+ return null;
284
+ };
285
+ var scratchInt32 = (size) => {
286
+ const pooled = acquire(freeInt32, borrowedInt32, size);
287
+ if (pooled !== null) return pooled.subarray(0, size);
288
+ const fresh = new Int32Array(size);
289
+ borrowedInt32.push(fresh);
290
+ return fresh;
291
+ };
292
+ var scratchUint8Zeroed = (size) => {
293
+ const pooled = acquire(freeUint8, borrowedUint8, size);
294
+ if (pooled !== null) {
295
+ const view = pooled.subarray(0, size);
296
+ view.fill(0);
297
+ return view;
298
+ }
299
+ const fresh = new Uint8Array(size);
300
+ borrowedUint8.push(fresh);
301
+ return fresh;
302
+ };
303
+ var releaseScratch = () => {
304
+ for (const buffer of borrowedInt32) freeInt32.push(buffer);
305
+ for (const buffer of borrowedUint8) freeUint8.push(buffer);
306
+ borrowedInt32.length = 0;
307
+ borrowedUint8.length = 0;
308
+ };
309
+
260
310
  // src/decoder/point_cloud/PointCloud.ts
261
311
  var NAMED_ATTRIBUTES_COUNT = 8;
262
312
  var PointCloud = class {
@@ -356,25 +406,17 @@ var Mesh = class extends PointCloud {
356
406
  this.numFaces_ = 0;
357
407
  this.attribute_data_ = [];
358
408
  }
359
- _ensureFaceCapacity(numFaces) {
360
- if (this.faces_.length >= numFaces * 3) {
361
- return;
362
- }
363
- const grown = new Int32Array(numFaces * 3);
364
- grown.set(this.faces_);
365
- this.faces_ = grown;
366
- }
367
- addFace(face) {
368
- const f = this.numFaces_;
369
- this._ensureFaceCapacity(f + 1);
370
- const o = f * 3;
371
- this.faces_[o] = face[0];
372
- this.faces_[o + 1] = face[1];
373
- this.faces_[o + 2] = face[2];
374
- this.numFaces_ = f + 1;
375
- }
409
+ // Sizes faces_ to hold numFaces faces. Called once per decode, before any
410
+ // face index is written (edgebreaker: _assignPointsToCorners; sequential:
411
+ // decodeConnectivity), so the buffer is allocated exactly here — the
412
+ // decoders fill faces_ directly rather than appending face-by-face.
376
413
  setNumFaces(numFaces) {
377
- this._ensureFaceCapacity(numFaces);
414
+ const needed = numFaces * 3;
415
+ if (this.faces_.length < needed) {
416
+ const grown = new Int32Array(needed);
417
+ grown.set(this.faces_);
418
+ this.faces_ = grown;
419
+ }
378
420
  this.numFaces_ = numFaces;
379
421
  }
380
422
  numFaces() {
@@ -1044,15 +1086,6 @@ var MeshAttributeCornerTable = class {
1044
1086
  leftMostCorner(v) {
1045
1087
  return this.vertex_to_left_most_corner_map_[v];
1046
1088
  }
1047
- face(corner) {
1048
- return this.corner_table_.face(corner);
1049
- }
1050
- firstCorner(faceIndex) {
1051
- return this.corner_table_.firstCorner(faceIndex);
1052
- }
1053
- allCorners(faceIndex) {
1054
- return this.corner_table_.allCorners(faceIndex);
1055
- }
1056
1089
  // --- Flat-array accessors: let DepthFirstTraverser avoid per-corner dispatch. ---
1057
1090
  cornerToVertexArray() {
1058
1091
  return this.corner_to_vertex_map_;
@@ -1067,7 +1100,8 @@ var MeshAttributeCornerTable = class {
1067
1100
  if (seamCorners.length === 0) {
1068
1101
  this._effectiveOpposite = base;
1069
1102
  } else {
1070
- const eff = base.slice(0, nc);
1103
+ const eff = scratchInt32(nc);
1104
+ eff.set(base.length === nc ? base : base.subarray(0, nc));
1071
1105
  for (let i = 0, l = seamCorners.length; i < l; ++i) {
1072
1106
  eff[seamCorners[i]] = kInvalidCornerIndex;
1073
1107
  }
@@ -1101,9 +1135,6 @@ var MeshAttributeCornerTable = class {
1101
1135
  this._effectiveOpposite = other._effectiveOpposite;
1102
1136
  this._seamCorners = other._seamCorners;
1103
1137
  }
1104
- isDegenerated(faceIndex) {
1105
- return this.corner_table_.isDegenerated(faceIndex);
1106
- }
1107
1138
  };
1108
1139
 
1109
1140
  // src/decoder/core/DracoTypes.ts
@@ -1851,15 +1882,12 @@ var SequentialAttributeDecoder = class {
1851
1882
  decodeValues(pointIds, buffer) {
1852
1883
  const numValues = pointIds.length;
1853
1884
  const entrySize = this._attribute.byteStride;
1854
- let outBytePos = 0;
1855
- for (let i = 0; i < numValues; i++) {
1856
- const valueData = buffer.decodeBytes(entrySize);
1857
- if (valueData === void 0) {
1858
- return false;
1859
- }
1860
- this._attribute.buffer.write(outBytePos, valueData, entrySize);
1861
- outBytePos += entrySize;
1885
+ const totalSize = numValues * entrySize;
1886
+ const valueData = buffer.decodeBytesView(totalSize);
1887
+ if (valueData === void 0) {
1888
+ return false;
1862
1889
  }
1890
+ this._attribute.buffer.write(0, valueData, totalSize);
1863
1891
  return true;
1864
1892
  }
1865
1893
  setPortableAttribute(att) {
@@ -1997,6 +2025,9 @@ var RAnsDecoder = class {
1997
2025
  this.bufOffset = offset - 3;
1998
2026
  this.state = memGetLe24(buf, offset - 3) & 4194303;
1999
2027
  } else if (x === 3) {
2028
+ if (offset - base < 4) {
2029
+ return 1;
2030
+ }
2000
2031
  this.bufOffset = offset - 4;
2001
2032
  this.state = memGetLe32(buf, offset - 4) & 1073741823;
2002
2033
  } else {
@@ -2041,12 +2072,69 @@ var RAnsDecoder = class {
2041
2072
  }
2042
2073
  // Batch ransRead() into out[0..count): all fields hoisted to locals, state
2043
2074
  // written back once. Removes per-symbol property reads and call indirection.
2075
+ // lutTable's element type varies per decoder (Uint8/16/32 by symbol count),
2076
+ // which would make the hot lutTable[rem] access site polymorphic — dispatch
2077
+ // once here so each loop body stays monomorphic on its concrete type. The
2078
+ // three bodies are intentionally identical copies.
2044
2079
  decodeSymbols(out, count) {
2080
+ const lutTable = this.lutTable;
2081
+ if (lutTable instanceof Uint8Array) {
2082
+ this._decodeSymbolsU8(out, count, lutTable);
2083
+ } else if (lutTable instanceof Uint16Array) {
2084
+ this._decodeSymbolsU16(out, count, lutTable);
2085
+ } else {
2086
+ this._decodeSymbolsU32(out, count, lutTable);
2087
+ }
2088
+ }
2089
+ _decodeSymbolsU8(out, count, lutTable) {
2090
+ const buf = this.buf;
2091
+ const lRansBase = this.lRansBase;
2092
+ const ransPrecisionBits = this.ransPrecisionBits;
2093
+ const ransPrecisionMask = this.ransPrecisionMask;
2094
+ const probTable = this.probTable;
2095
+ const cumProbTable = this.cumProbTable;
2096
+ let state = this.state;
2097
+ let bufOffset = this.bufOffset;
2098
+ const bufStart = this.bufStart;
2099
+ for (let i = 0; i < count; ++i) {
2100
+ while (state < lRansBase && bufOffset > bufStart) {
2101
+ state = state << 8 | buf[--bufOffset];
2102
+ }
2103
+ const rem = state & ransPrecisionMask;
2104
+ const symbol = lutTable[rem];
2105
+ out[i] = symbol;
2106
+ state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
2107
+ }
2108
+ this.state = state;
2109
+ this.bufOffset = bufOffset;
2110
+ }
2111
+ _decodeSymbolsU16(out, count, lutTable) {
2112
+ const buf = this.buf;
2113
+ const lRansBase = this.lRansBase;
2114
+ const ransPrecisionBits = this.ransPrecisionBits;
2115
+ const ransPrecisionMask = this.ransPrecisionMask;
2116
+ const probTable = this.probTable;
2117
+ const cumProbTable = this.cumProbTable;
2118
+ let state = this.state;
2119
+ let bufOffset = this.bufOffset;
2120
+ const bufStart = this.bufStart;
2121
+ for (let i = 0; i < count; ++i) {
2122
+ while (state < lRansBase && bufOffset > bufStart) {
2123
+ state = state << 8 | buf[--bufOffset];
2124
+ }
2125
+ const rem = state & ransPrecisionMask;
2126
+ const symbol = lutTable[rem];
2127
+ out[i] = symbol;
2128
+ state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
2129
+ }
2130
+ this.state = state;
2131
+ this.bufOffset = bufOffset;
2132
+ }
2133
+ _decodeSymbolsU32(out, count, lutTable) {
2045
2134
  const buf = this.buf;
2046
2135
  const lRansBase = this.lRansBase;
2047
2136
  const ransPrecisionBits = this.ransPrecisionBits;
2048
2137
  const ransPrecisionMask = this.ransPrecisionMask;
2049
- const lutTable = this.lutTable;
2050
2138
  const probTable = this.probTable;
2051
2139
  const cumProbTable = this.cumProbTable;
2052
2140
  let state = this.state;
@@ -2107,16 +2195,12 @@ function computeRAnsPrecisionFromUniqueSymbolsBitLength(symbolsBitLength) {
2107
2195
  return unclamped;
2108
2196
  }
2109
2197
  var RAnsSymbolDecoder = class {
2110
- uniqueSymbolsBitLength_;
2111
2198
  ransPrecisionBits_;
2112
- ransPrecision_;
2113
2199
  probabilityTable_;
2114
2200
  numSymbols_;
2115
2201
  ans_;
2116
2202
  constructor(uniqueSymbolsBitLength) {
2117
- this.uniqueSymbolsBitLength_ = uniqueSymbolsBitLength;
2118
2203
  this.ransPrecisionBits_ = computeRAnsPrecisionFromUniqueSymbolsBitLength(uniqueSymbolsBitLength);
2119
- this.ransPrecision_ = 1 << this.ransPrecisionBits_;
2120
2204
  this.probabilityTable_ = null;
2121
2205
  this.numSymbols_ = 0;
2122
2206
  this.ans_ = new RAnsDecoder(this.ransPrecisionBits_);
@@ -3528,8 +3612,7 @@ var MeshPredictionSchemeTexCoordsPortablePredictor = class {
3528
3612
  }
3529
3613
  const xUV0 = nUV0 * pnNorm2Squared + cnDotPn * pnUV0;
3530
3614
  const xUV1 = nUV1 * pnNorm2Squared + cnDotPn * pnUV1;
3531
- const pnAbsMax = Math.max(Math.abs(pn0), Math.abs(pn1), Math.abs(pn2));
3532
- if (pnAbsMax > 0 && Math.abs(cnDotPn) > INT64_MAX / pnAbsMax) {
3615
+ if (pnAbsMaxG > 0 && cnDotPnAbs > INT64_MAX / pnAbsMaxG) {
3533
3616
  return false;
3534
3617
  }
3535
3618
  const xPos0 = next0 + Math.trunc(cnDotPn * pn0 / pnNorm2Squared);
@@ -4574,15 +4657,6 @@ var AttributeQuantizationTransform = class _AttributeQuantizationTransform exten
4574
4657
  }
4575
4658
  return true;
4576
4659
  }
4577
- get quantizationBits() {
4578
- return this._quantizationBits;
4579
- }
4580
- get range() {
4581
- return this._range;
4582
- }
4583
- minValue(axis) {
4584
- return this._minValues[axis];
4585
- }
4586
4660
  static _isQuantizationValid(quantizationBits) {
4587
4661
  return quantizationBits >= 1 && quantizationBits <= 30;
4588
4662
  }
@@ -4661,7 +4735,7 @@ var SequentialAttributeDecodersController = class extends AttributesDecoder {
4661
4735
  if (!this._sequencer) {
4662
4736
  return false;
4663
4737
  }
4664
- if (!this._sequencer.generateSequence(this._pointIds)) {
4738
+ if (!this._sequencer.generateSequence()) {
4665
4739
  return false;
4666
4740
  }
4667
4741
  this._pointIds = this._sequencer.getOutputPointIds();
@@ -4785,19 +4859,29 @@ var DepthFirstTraverser = class {
4785
4859
  init(cornerTable, observer) {
4786
4860
  this._cornerTable = cornerTable;
4787
4861
  this._observer = observer;
4788
- this._isFaceVisited = new Uint8Array(cornerTable.numFaces());
4789
- this._isVertexVisited = new Uint8Array(cornerTable.numVertices());
4862
+ this._isFaceVisited = null;
4863
+ this._isVertexVisited = null;
4790
4864
  this._numVisitedFaces = 0;
4791
4865
  this._cornerToVertex = cornerTable.cornerToVertexArray();
4792
4866
  this._oppositeCorners = cornerTable.oppositeCornerArray();
4793
4867
  this._vertexLeftmost = cornerTable.vertexLeftmostCornerArray();
4794
4868
  this._numCorners = cornerTable.numCorners();
4795
- this._cornerTraversalStack = new Int32Array(this._numCorners);
4796
4869
  }
4797
4870
  cornerTable() {
4798
4871
  return this._cornerTable;
4799
4872
  }
4873
+ // Scratch buffers are set up here rather than in init() so a shared-traversal
4874
+ // -cache hit — where generateSequence returns before any traversal — skips
4875
+ // this entirely, including the visited-flag zero-fill (worth ~0.5% on the
4876
+ // 488-primitive manablade-static bundle, which shares attribute corner tables across
4877
+ // primitives). Uint8Array (0/1) instead of Array(bool): these flags are read
4878
+ // and written on every corner of the hottest decode loop (traverseFromCorner).
4879
+ // Decode-scoped scratch: released in bulk at the end of the decode.
4800
4880
  onTraversalStart() {
4881
+ const cornerTable = this._cornerTable;
4882
+ this._isFaceVisited = scratchUint8Zeroed(cornerTable.numFaces());
4883
+ this._isVertexVisited = scratchUint8Zeroed(cornerTable.numVertices());
4884
+ this._cornerTraversalStack = scratchInt32(this._numCorners);
4801
4885
  }
4802
4886
  onTraversalEnd() {
4803
4887
  }
@@ -4813,6 +4897,14 @@ var DepthFirstTraverser = class {
4813
4897
  const vertexLeftmost = this._vertexLeftmost;
4814
4898
  const stack = this._cornerTraversalStack;
4815
4899
  let numVisitedFaces = this._numVisitedFaces;
4900
+ const sequencer = observer._sequencer;
4901
+ const encodingData = observer._encodingData;
4902
+ const obsFaces = observer._faces;
4903
+ const encodedToCornerMap = observer._encodedToCornerMap;
4904
+ const vertexToEncodedMap = observer._vertexToEncodedMap;
4905
+ const outPointIds = sequencer._outPointIds;
4906
+ let numOutPoints = sequencer._numOutPoints;
4907
+ let numValues = encodingData.numValues;
4816
4908
  let stackSize = 0;
4817
4909
  stack[stackSize++] = cornerId;
4818
4910
  const nextCorner = cornerId % 3 === 2 ? cornerId - 2 : cornerId + 1;
@@ -4824,11 +4916,15 @@ var DepthFirstTraverser = class {
4824
4916
  }
4825
4917
  if (!isVertexVisited[nextVert]) {
4826
4918
  isVertexVisited[nextVert] = 1;
4827
- observer.onNewVertexVisited(nextVert, nextCorner);
4919
+ outPointIds[numOutPoints++] = obsFaces[nextCorner];
4920
+ encodedToCornerMap[numValues] = nextCorner;
4921
+ vertexToEncodedMap[nextVert] = numValues++;
4828
4922
  }
4829
4923
  if (!isVertexVisited[prevVert]) {
4830
4924
  isVertexVisited[prevVert] = 1;
4831
- observer.onNewVertexVisited(prevVert, prevCorner);
4925
+ outPointIds[numOutPoints++] = obsFaces[prevCorner];
4926
+ encodedToCornerMap[numValues] = prevCorner;
4927
+ vertexToEncodedMap[prevVert] = numValues++;
4832
4928
  }
4833
4929
  while (stackSize > 0) {
4834
4930
  cornerId = stack[stackSize - 1];
@@ -4842,6 +4938,8 @@ var DepthFirstTraverser = class {
4842
4938
  numVisitedFaces++;
4843
4939
  const vertId = cornerToVertex[cornerId];
4844
4940
  if (vertId === kInvalidVertexIndex2) {
4941
+ sequencer._numOutPoints = numOutPoints;
4942
+ encodingData.numValues = numValues;
4845
4943
  return false;
4846
4944
  }
4847
4945
  if (!isVertexVisited[vertId]) {
@@ -4852,7 +4950,9 @@ var DepthFirstTraverser = class {
4852
4950
  onBoundary = oppositeCorners[nextLc] < 0;
4853
4951
  }
4854
4952
  isVertexVisited[vertId] = 1;
4855
- observer.onNewVertexVisited(vertId, cornerId);
4953
+ outPointIds[numOutPoints++] = obsFaces[cornerId];
4954
+ encodedToCornerMap[numValues] = cornerId;
4955
+ vertexToEncodedMap[vertId] = numValues++;
4856
4956
  if (!onBoundary) {
4857
4957
  const nextCornerId2 = cornerId % 3 === 2 ? cornerId - 2 : cornerId + 1;
4858
4958
  cornerId = oppositeCorners[nextCornerId2];
@@ -4889,6 +4989,8 @@ var DepthFirstTraverser = class {
4889
4989
  }
4890
4990
  }
4891
4991
  this._numVisitedFaces = numVisitedFaces;
4992
+ sequencer._numOutPoints = numOutPoints;
4993
+ encodingData.numValues = numValues;
4892
4994
  return true;
4893
4995
  }
4894
4996
  };
@@ -5101,7 +5203,7 @@ var MeshTraversalSequencer = class {
5101
5203
  setTraverser(traverser) {
5102
5204
  this._traverser = traverser;
5103
5205
  }
5104
- generateSequence(_outPointIds) {
5206
+ generateSequence() {
5105
5207
  const cornerTable = this._traverser.cornerTable();
5106
5208
  const methodId = this._traverser._traversalMethodId;
5107
5209
  const cacheKey = cornerTable.cornerToVertexArray();
@@ -5439,7 +5541,7 @@ var MeshEdgebreakerDecoderImpl = class {
5439
5541
  return true;
5440
5542
  }
5441
5543
  _decodeConnectivity(numSymbols) {
5442
- const activeCornerStack = new Int32Array(numSymbols + this._topologySplitData.length + 16);
5544
+ const activeCornerStack = scratchInt32(numSymbols + this._topologySplitData.length + 16);
5443
5545
  let activeCornerStackSize = 0;
5444
5546
  const topologySplitActiveCorners = /* @__PURE__ */ new Map();
5445
5547
  const invalidVertices = [];
@@ -6303,7 +6405,7 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
6303
6405
  this._activeContext = -1;
6304
6406
  this._minValence = 2;
6305
6407
  this._maxValence = 7;
6306
- this._vertexValences = [];
6408
+ this._vertexValences = new Int32Array(0);
6307
6409
  this._contextSymbols = [];
6308
6410
  this._contextCounters = [];
6309
6411
  }
@@ -6327,7 +6429,7 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
6327
6429
  if (this._numVertices < 0) {
6328
6430
  return false;
6329
6431
  }
6330
- this._vertexValences = new Array(this._numVertices).fill(0);
6432
+ this._vertexValences = new Int32Array(this._numVertices);
6331
6433
  const numUniqueValences = this._maxValence - this._minValence + 1;
6332
6434
  this._contextSymbols = new Array(numUniqueValences);
6333
6435
  this._contextCounters = new Array(numUniqueValences);
@@ -6369,34 +6471,37 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
6369
6471
  return this._lastSymbol;
6370
6472
  }
6371
6473
  newActiveCornerReached(corner) {
6372
- const ct = this._cornerTable;
6373
- const next = ct.next(corner);
6374
- const prev = ct.previous(corner);
6474
+ const cornerToVertex = this._cornerTable._cornerToVertex;
6475
+ const valences = this._vertexValences;
6476
+ const next = corner % 3 === 2 ? corner - 2 : corner + 1;
6477
+ const prev = corner % 3 === 0 ? corner + 2 : corner - 1;
6478
+ const vertNext = cornerToVertex[next];
6479
+ const vertPrev = cornerToVertex[prev];
6375
6480
  switch (this._lastSymbol) {
6376
6481
  case TOPOLOGY_C:
6377
6482
  case TOPOLOGY_S:
6378
- this._vertexValences[ct.vertex(next)] += 1;
6379
- this._vertexValences[ct.vertex(prev)] += 1;
6483
+ valences[vertNext] += 1;
6484
+ valences[vertPrev] += 1;
6380
6485
  break;
6381
6486
  case TOPOLOGY_R:
6382
- this._vertexValences[ct.vertex(corner)] += 1;
6383
- this._vertexValences[ct.vertex(next)] += 1;
6384
- this._vertexValences[ct.vertex(prev)] += 2;
6487
+ valences[cornerToVertex[corner]] += 1;
6488
+ valences[vertNext] += 1;
6489
+ valences[vertPrev] += 2;
6385
6490
  break;
6386
6491
  case TOPOLOGY_L:
6387
- this._vertexValences[ct.vertex(corner)] += 1;
6388
- this._vertexValences[ct.vertex(next)] += 2;
6389
- this._vertexValences[ct.vertex(prev)] += 1;
6492
+ valences[cornerToVertex[corner]] += 1;
6493
+ valences[vertNext] += 2;
6494
+ valences[vertPrev] += 1;
6390
6495
  break;
6391
6496
  case TOPOLOGY_E:
6392
- this._vertexValences[ct.vertex(corner)] += 2;
6393
- this._vertexValences[ct.vertex(next)] += 2;
6394
- this._vertexValences[ct.vertex(prev)] += 2;
6497
+ valences[cornerToVertex[corner]] += 2;
6498
+ valences[vertNext] += 2;
6499
+ valences[vertPrev] += 2;
6395
6500
  break;
6396
6501
  default:
6397
6502
  break;
6398
6503
  }
6399
- const activeValence = this._vertexValences[ct.vertex(next)];
6504
+ const activeValence = valences[vertNext];
6400
6505
  let clampedValence;
6401
6506
  if (activeValence < this._minValence) {
6402
6507
  clampedValence = this._minValence;
@@ -6515,45 +6620,30 @@ var MeshSequentialDecoder = class extends MeshDecoder {
6515
6620
  return false;
6516
6621
  }
6517
6622
  } else {
6623
+ const mesh = this.mesh();
6624
+ mesh.setNumFaces(numFaces);
6625
+ const faces = mesh.faces_;
6626
+ const numIndices = numFaces * 3;
6627
+ const buffer = this.buffer();
6518
6628
  if (numPoints < 256) {
6519
- for (let i = 0; i < numFaces; ++i) {
6520
- const face = [0, 0, 0];
6521
- for (let j = 0; j < 3; ++j) {
6522
- const val = this.buffer().decodeUint8();
6523
- if (val === void 0) return false;
6524
- face[j] = val;
6525
- }
6526
- this.mesh().addFace(face);
6527
- }
6629
+ const src = buffer.decodeBytesView(numIndices);
6630
+ if (src === void 0) return false;
6631
+ for (let i = 0; i < numIndices; ++i) faces[i] = src[i];
6528
6632
  } else if (numPoints < 1 << 16) {
6529
- for (let i = 0; i < numFaces; ++i) {
6530
- const face = [0, 0, 0];
6531
- for (let j = 0; j < 3; ++j) {
6532
- const val = this.buffer().decodeUint16();
6533
- if (val === void 0) return false;
6534
- face[j] = val;
6535
- }
6536
- this.mesh().addFace(face);
6537
- }
6633
+ const src = buffer.decodeBytesView(numIndices * 2);
6634
+ if (src === void 0) return false;
6635
+ for (let i = 0; i < numIndices; ++i) faces[i] = src[i * 2] | src[i * 2 + 1] << 8;
6538
6636
  } else if (numPoints < 1 << 21) {
6539
- for (let i = 0; i < numFaces; ++i) {
6540
- const face = [0, 0, 0];
6541
- for (let j = 0; j < 3; ++j) {
6542
- const val = decodeVarint(this.buffer());
6543
- if (val === void 0) return false;
6544
- face[j] = val;
6545
- }
6546
- this.mesh().addFace(face);
6637
+ for (let i = 0; i < numIndices; ++i) {
6638
+ const val = decodeVarint(buffer);
6639
+ if (val === void 0) return false;
6640
+ faces[i] = val;
6547
6641
  }
6548
6642
  } else {
6549
- for (let i = 0; i < numFaces; ++i) {
6550
- const face = [0, 0, 0];
6551
- for (let j = 0; j < 3; ++j) {
6552
- const val = this.buffer().decodeUint32();
6553
- if (val === void 0) return false;
6554
- face[j] = val;
6555
- }
6556
- this.mesh().addFace(face);
6643
+ const src = buffer.decodeBytesView(numIndices * 4);
6644
+ if (src === void 0) return false;
6645
+ for (let i = 0; i < numIndices; ++i) {
6646
+ faces[i] = src[i * 4] | src[i * 4 + 1] << 8 | src[i * 4 + 2] << 16 | src[i * 4 + 3] << 24;
6557
6647
  }
6558
6648
  }
6559
6649
  }
@@ -6567,32 +6657,31 @@ var MeshSequentialDecoder = class extends MeshDecoder {
6567
6657
  );
6568
6658
  }
6569
6659
  _decodeAndDecompressIndices(numFaces) {
6570
- const indicesBuffer = new Uint32Array(numFaces * 3);
6571
- if (!decodeSymbols(numFaces * 3, 1, this.buffer(), indicesBuffer)) {
6660
+ const numIndices = numFaces * 3;
6661
+ const indicesBuffer = new Uint32Array(numIndices);
6662
+ if (!decodeSymbols(numIndices, 1, this.buffer(), indicesBuffer)) {
6572
6663
  return false;
6573
6664
  }
6665
+ const mesh = this.mesh();
6666
+ mesh.setNumFaces(numFaces);
6667
+ const faces = mesh.faces_;
6574
6668
  let lastIndexValue = 0;
6575
- let vertexIndex = 0;
6576
- for (let i = 0; i < numFaces; ++i) {
6577
- const face = [0, 0, 0];
6578
- for (let j = 0; j < 3; ++j) {
6579
- const encodedVal = indicesBuffer[vertexIndex++];
6580
- let indexDiff = encodedVal >>> 1;
6581
- if (encodedVal & 1) {
6582
- if (indexDiff > lastIndexValue) {
6583
- return false;
6584
- }
6585
- indexDiff = -indexDiff;
6586
- } else {
6587
- if (indexDiff > 2147483647 - lastIndexValue) {
6588
- return false;
6589
- }
6669
+ for (let i = 0; i < numIndices; ++i) {
6670
+ const encodedVal = indicesBuffer[i];
6671
+ let indexDiff = encodedVal >>> 1;
6672
+ if (encodedVal & 1) {
6673
+ if (indexDiff > lastIndexValue) {
6674
+ return false;
6675
+ }
6676
+ indexDiff = -indexDiff;
6677
+ } else {
6678
+ if (indexDiff > 2147483647 - lastIndexValue) {
6679
+ return false;
6590
6680
  }
6591
- const indexValue = indexDiff + lastIndexValue | 0;
6592
- face[j] = indexValue;
6593
- lastIndexValue = indexValue;
6594
6681
  }
6595
- this.mesh().addFace(face);
6682
+ const indexValue = indexDiff + lastIndexValue | 0;
6683
+ faces[i] = indexValue;
6684
+ lastIndexValue = indexValue;
6596
6685
  }
6597
6686
  return true;
6598
6687
  }
@@ -6650,9 +6739,15 @@ var Decoder = class {
6650
6739
  if (result.header.encoderType !== EncodedGeometryType.TRIANGULAR_MESH) {
6651
6740
  return { ok: false, message: "Input is not a mesh." };
6652
6741
  }
6653
- const decoder = createMeshDecoder(result.header.encoderMethod);
6654
- const status = decoder.decodeMesh(this.options_, inBuffer, outGeometry);
6655
- return { ok: status.ok(), message: status.errorMsg };
6742
+ try {
6743
+ const decoder = createMeshDecoder(result.header.encoderMethod);
6744
+ const status = decoder.decodeMesh(this.options_, inBuffer, outGeometry);
6745
+ return { ok: status.ok(), message: status.errorMsg };
6746
+ } catch (error) {
6747
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
6748
+ } finally {
6749
+ releaseScratch();
6750
+ }
6656
6751
  }
6657
6752
  options() {
6658
6753
  return this.options_;
package/dist/three.d.ts CHANGED
@@ -113,8 +113,6 @@ declare class Mesh extends PointCloud {
113
113
  elementType: number;
114
114
  }[];
115
115
  constructor();
116
- _ensureFaceCapacity(numFaces: number): void;
117
- addFace(face: ArrayLike<number>): void;
118
116
  setNumFaces(numFaces: number): void;
119
117
  numFaces(): number;
120
118
  face(faceId: number): number[];
@@ -123,6 +121,12 @@ declare class Mesh extends PointCloud {
123
121
 
124
122
  type AttributeIDs = Record<string, number | string>;
125
123
  type AttributeTypes = Record<string, string>;
124
+ interface MiniDRACOLoaderOptions {
125
+ manager?: LoadingManager;
126
+ workers?: boolean;
127
+ workerLimit?: number;
128
+ syncByteThreshold?: number;
129
+ }
126
130
  interface TaskConfig {
127
131
  attributeIDs: AttributeIDs;
128
132
  attributeTypes: AttributeTypes;
@@ -142,10 +146,18 @@ interface WorkerEntry {
142
146
  worker: Worker;
143
147
  pending: number;
144
148
  }
149
+ interface QueuedTask {
150
+ id: number;
151
+ buffer: ArrayBuffer;
152
+ taskConfig: TaskConfig;
153
+ resolve: (raw: RawGeometry) => void;
154
+ reject: (error: unknown) => void;
155
+ }
145
156
  declare class MiniDRACOLoader extends Loader<BufferGeometry> {
146
157
  defaultAttributeIDs: AttributeIDs;
147
158
  defaultAttributeTypes: AttributeTypes;
148
159
  workerLimit: number;
160
+ syncByteThreshold: number;
149
161
  _workers: WorkerEntry[];
150
162
  _taskId: number;
151
163
  _tasks: Map<number, {
@@ -153,11 +165,17 @@ declare class MiniDRACOLoader extends Loader<BufferGeometry> {
153
165
  reject: (error: unknown) => void;
154
166
  entry: WorkerEntry;
155
167
  }>;
168
+ _batch: QueuedTask[];
169
+ _batchScheduled: boolean;
156
170
  _workersBroken: boolean;
157
- constructor(manager?: LoadingManager);
158
- setDecoderPath(_path?: string): this;
159
- setDecoderConfig(_config?: object): this;
171
+ _workerUrl: string | URL | null;
172
+ _workerBlobUrl: string | null;
173
+ constructor(managerOrOptions?: LoadingManager | MiniDRACOLoaderOptions);
174
+ setWorkerUrl(url: string | URL | null): this;
175
+ setDecoderPath(_path?: unknown): this;
176
+ setDecoderConfig(_config?: unknown): this;
160
177
  setWorkerLimit(limit: number): this;
178
+ setWorkers(enabled: boolean): this;
161
179
  preload(): this;
162
180
  dispose(): this;
163
181
  load(url: string, onLoad: (geometry: BufferGeometry) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): void;
@@ -166,12 +184,13 @@ declare class MiniDRACOLoader extends Loader<BufferGeometry> {
166
184
  decodeGeometry(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<BufferGeometry>;
167
185
  _runTask(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<BufferGeometry>;
168
186
  _workersAvailable(): boolean;
169
- _getWorker(): WorkerEntry;
187
+ _getWorker(): WorkerEntry | null;
170
188
  _decodeInWorker(buffer: ArrayBuffer, taskConfig: TaskConfig): Promise<RawGeometry>;
189
+ _flushBatch(): void;
171
190
  _buildGeometryFromRaw(raw: RawGeometry, taskConfig: TaskConfig): BufferGeometry;
172
191
  _decodeBuffer(buffer: ArrayBuffer, taskConfig: TaskConfig): BufferGeometry;
173
192
  _buildGeometry(dracoGeometry: Mesh, taskConfig: TaskConfig): BufferGeometry;
174
193
  _assignVertexColorSpace(attribute: BufferAttribute, inputColorSpace: string): void;
175
194
  }
176
195
 
177
- export { type AttributeIDs, type AttributeTypes, MiniDRACOLoader as DRACOLoader, MiniDRACOLoader };
196
+ export { type AttributeIDs, type AttributeTypes, MiniDRACOLoader as DRACOLoader, MiniDRACOLoader, type MiniDRACOLoaderOptions };