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/README.md +50 -20
- package/dist/index.d.ts +1 -2
- package/dist/index.js +234 -139
- package/dist/three.d.ts +26 -7
- package/dist/three.js +381 -176
- package/dist/worker.js +287 -169
- package/package.json +6 -1
package/dist/three.js
CHANGED
|
@@ -212,6 +212,14 @@ var DecoderBuffer = class {
|
|
|
212
212
|
this._pos += size;
|
|
213
213
|
return result;
|
|
214
214
|
}
|
|
215
|
+
// Zero-copy variant of decodeBytes: a view into the stream, only valid until
|
|
216
|
+
// the caller's next chance to mutate the buffer — copy out before keeping it.
|
|
217
|
+
decodeBytesView(size) {
|
|
218
|
+
if (this._pos + size > this._dataSize) return void 0;
|
|
219
|
+
const result = this._data.subarray(this._pos, this._pos + size);
|
|
220
|
+
this._pos += size;
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
215
223
|
startBitDecoding(decodeSize) {
|
|
216
224
|
let outSize = 0;
|
|
217
225
|
if (decodeSize) {
|
|
@@ -269,6 +277,48 @@ var DecoderBuffer = class {
|
|
|
269
277
|
}
|
|
270
278
|
};
|
|
271
279
|
|
|
280
|
+
// src/decoder/core/ScratchArena.ts
|
|
281
|
+
var freeInt32 = [];
|
|
282
|
+
var freeUint8 = [];
|
|
283
|
+
var borrowedInt32 = [];
|
|
284
|
+
var borrowedUint8 = [];
|
|
285
|
+
var acquire = (free, borrowed, size) => {
|
|
286
|
+
for (let i = free.length - 1; i >= 0; --i) {
|
|
287
|
+
const buffer = free[i];
|
|
288
|
+
if (buffer.length >= size) {
|
|
289
|
+
free[i] = free[free.length - 1];
|
|
290
|
+
free.pop();
|
|
291
|
+
borrowed.push(buffer);
|
|
292
|
+
return buffer;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
};
|
|
297
|
+
var scratchInt32 = (size) => {
|
|
298
|
+
const pooled = acquire(freeInt32, borrowedInt32, size);
|
|
299
|
+
if (pooled !== null) return pooled.subarray(0, size);
|
|
300
|
+
const fresh = new Int32Array(size);
|
|
301
|
+
borrowedInt32.push(fresh);
|
|
302
|
+
return fresh;
|
|
303
|
+
};
|
|
304
|
+
var scratchUint8Zeroed = (size) => {
|
|
305
|
+
const pooled = acquire(freeUint8, borrowedUint8, size);
|
|
306
|
+
if (pooled !== null) {
|
|
307
|
+
const view = pooled.subarray(0, size);
|
|
308
|
+
view.fill(0);
|
|
309
|
+
return view;
|
|
310
|
+
}
|
|
311
|
+
const fresh = new Uint8Array(size);
|
|
312
|
+
borrowedUint8.push(fresh);
|
|
313
|
+
return fresh;
|
|
314
|
+
};
|
|
315
|
+
var releaseScratch = () => {
|
|
316
|
+
for (const buffer of borrowedInt32) freeInt32.push(buffer);
|
|
317
|
+
for (const buffer of borrowedUint8) freeUint8.push(buffer);
|
|
318
|
+
borrowedInt32.length = 0;
|
|
319
|
+
borrowedUint8.length = 0;
|
|
320
|
+
};
|
|
321
|
+
|
|
272
322
|
// src/decoder/point_cloud/PointCloud.ts
|
|
273
323
|
var NAMED_ATTRIBUTES_COUNT = 8;
|
|
274
324
|
var PointCloud = class {
|
|
@@ -368,25 +418,17 @@ var Mesh = class extends PointCloud {
|
|
|
368
418
|
this.numFaces_ = 0;
|
|
369
419
|
this.attribute_data_ = [];
|
|
370
420
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const grown = new Int32Array(numFaces * 3);
|
|
376
|
-
grown.set(this.faces_);
|
|
377
|
-
this.faces_ = grown;
|
|
378
|
-
}
|
|
379
|
-
addFace(face) {
|
|
380
|
-
const f = this.numFaces_;
|
|
381
|
-
this._ensureFaceCapacity(f + 1);
|
|
382
|
-
const o = f * 3;
|
|
383
|
-
this.faces_[o] = face[0];
|
|
384
|
-
this.faces_[o + 1] = face[1];
|
|
385
|
-
this.faces_[o + 2] = face[2];
|
|
386
|
-
this.numFaces_ = f + 1;
|
|
387
|
-
}
|
|
421
|
+
// Sizes faces_ to hold numFaces faces. Called once per decode, before any
|
|
422
|
+
// face index is written (edgebreaker: _assignPointsToCorners; sequential:
|
|
423
|
+
// decodeConnectivity), so the buffer is allocated exactly here — the
|
|
424
|
+
// decoders fill faces_ directly rather than appending face-by-face.
|
|
388
425
|
setNumFaces(numFaces) {
|
|
389
|
-
|
|
426
|
+
const needed = numFaces * 3;
|
|
427
|
+
if (this.faces_.length < needed) {
|
|
428
|
+
const grown = new Int32Array(needed);
|
|
429
|
+
grown.set(this.faces_);
|
|
430
|
+
this.faces_ = grown;
|
|
431
|
+
}
|
|
390
432
|
this.numFaces_ = numFaces;
|
|
391
433
|
}
|
|
392
434
|
numFaces() {
|
|
@@ -1056,15 +1098,6 @@ var MeshAttributeCornerTable = class {
|
|
|
1056
1098
|
leftMostCorner(v) {
|
|
1057
1099
|
return this.vertex_to_left_most_corner_map_[v];
|
|
1058
1100
|
}
|
|
1059
|
-
face(corner) {
|
|
1060
|
-
return this.corner_table_.face(corner);
|
|
1061
|
-
}
|
|
1062
|
-
firstCorner(faceIndex) {
|
|
1063
|
-
return this.corner_table_.firstCorner(faceIndex);
|
|
1064
|
-
}
|
|
1065
|
-
allCorners(faceIndex) {
|
|
1066
|
-
return this.corner_table_.allCorners(faceIndex);
|
|
1067
|
-
}
|
|
1068
1101
|
// --- Flat-array accessors: let DepthFirstTraverser avoid per-corner dispatch. ---
|
|
1069
1102
|
cornerToVertexArray() {
|
|
1070
1103
|
return this.corner_to_vertex_map_;
|
|
@@ -1079,7 +1112,8 @@ var MeshAttributeCornerTable = class {
|
|
|
1079
1112
|
if (seamCorners.length === 0) {
|
|
1080
1113
|
this._effectiveOpposite = base;
|
|
1081
1114
|
} else {
|
|
1082
|
-
const eff =
|
|
1115
|
+
const eff = scratchInt32(nc);
|
|
1116
|
+
eff.set(base.length === nc ? base : base.subarray(0, nc));
|
|
1083
1117
|
for (let i = 0, l = seamCorners.length; i < l; ++i) {
|
|
1084
1118
|
eff[seamCorners[i]] = kInvalidCornerIndex;
|
|
1085
1119
|
}
|
|
@@ -1113,9 +1147,6 @@ var MeshAttributeCornerTable = class {
|
|
|
1113
1147
|
this._effectiveOpposite = other._effectiveOpposite;
|
|
1114
1148
|
this._seamCorners = other._seamCorners;
|
|
1115
1149
|
}
|
|
1116
|
-
isDegenerated(faceIndex) {
|
|
1117
|
-
return this.corner_table_.isDegenerated(faceIndex);
|
|
1118
|
-
}
|
|
1119
1150
|
};
|
|
1120
1151
|
|
|
1121
1152
|
// src/decoder/core/DracoTypes.ts
|
|
@@ -1863,15 +1894,12 @@ var SequentialAttributeDecoder = class {
|
|
|
1863
1894
|
decodeValues(pointIds, buffer) {
|
|
1864
1895
|
const numValues = pointIds.length;
|
|
1865
1896
|
const entrySize = this._attribute.byteStride;
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
return false;
|
|
1871
|
-
}
|
|
1872
|
-
this._attribute.buffer.write(outBytePos, valueData, entrySize);
|
|
1873
|
-
outBytePos += entrySize;
|
|
1897
|
+
const totalSize = numValues * entrySize;
|
|
1898
|
+
const valueData = buffer.decodeBytesView(totalSize);
|
|
1899
|
+
if (valueData === void 0) {
|
|
1900
|
+
return false;
|
|
1874
1901
|
}
|
|
1902
|
+
this._attribute.buffer.write(0, valueData, totalSize);
|
|
1875
1903
|
return true;
|
|
1876
1904
|
}
|
|
1877
1905
|
setPortableAttribute(att) {
|
|
@@ -2009,6 +2037,9 @@ var RAnsDecoder = class {
|
|
|
2009
2037
|
this.bufOffset = offset - 3;
|
|
2010
2038
|
this.state = memGetLe24(buf, offset - 3) & 4194303;
|
|
2011
2039
|
} else if (x === 3) {
|
|
2040
|
+
if (offset - base < 4) {
|
|
2041
|
+
return 1;
|
|
2042
|
+
}
|
|
2012
2043
|
this.bufOffset = offset - 4;
|
|
2013
2044
|
this.state = memGetLe32(buf, offset - 4) & 1073741823;
|
|
2014
2045
|
} else {
|
|
@@ -2053,12 +2084,69 @@ var RAnsDecoder = class {
|
|
|
2053
2084
|
}
|
|
2054
2085
|
// Batch ransRead() into out[0..count): all fields hoisted to locals, state
|
|
2055
2086
|
// written back once. Removes per-symbol property reads and call indirection.
|
|
2087
|
+
// lutTable's element type varies per decoder (Uint8/16/32 by symbol count),
|
|
2088
|
+
// which would make the hot lutTable[rem] access site polymorphic — dispatch
|
|
2089
|
+
// once here so each loop body stays monomorphic on its concrete type. The
|
|
2090
|
+
// three bodies are intentionally identical copies.
|
|
2056
2091
|
decodeSymbols(out, count) {
|
|
2092
|
+
const lutTable = this.lutTable;
|
|
2093
|
+
if (lutTable instanceof Uint8Array) {
|
|
2094
|
+
this._decodeSymbolsU8(out, count, lutTable);
|
|
2095
|
+
} else if (lutTable instanceof Uint16Array) {
|
|
2096
|
+
this._decodeSymbolsU16(out, count, lutTable);
|
|
2097
|
+
} else {
|
|
2098
|
+
this._decodeSymbolsU32(out, count, lutTable);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
_decodeSymbolsU8(out, count, lutTable) {
|
|
2102
|
+
const buf = this.buf;
|
|
2103
|
+
const lRansBase = this.lRansBase;
|
|
2104
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
2105
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
2106
|
+
const probTable = this.probTable;
|
|
2107
|
+
const cumProbTable = this.cumProbTable;
|
|
2108
|
+
let state = this.state;
|
|
2109
|
+
let bufOffset = this.bufOffset;
|
|
2110
|
+
const bufStart = this.bufStart;
|
|
2111
|
+
for (let i = 0; i < count; ++i) {
|
|
2112
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
2113
|
+
state = state << 8 | buf[--bufOffset];
|
|
2114
|
+
}
|
|
2115
|
+
const rem = state & ransPrecisionMask;
|
|
2116
|
+
const symbol = lutTable[rem];
|
|
2117
|
+
out[i] = symbol;
|
|
2118
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
2119
|
+
}
|
|
2120
|
+
this.state = state;
|
|
2121
|
+
this.bufOffset = bufOffset;
|
|
2122
|
+
}
|
|
2123
|
+
_decodeSymbolsU16(out, count, lutTable) {
|
|
2124
|
+
const buf = this.buf;
|
|
2125
|
+
const lRansBase = this.lRansBase;
|
|
2126
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
2127
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
2128
|
+
const probTable = this.probTable;
|
|
2129
|
+
const cumProbTable = this.cumProbTable;
|
|
2130
|
+
let state = this.state;
|
|
2131
|
+
let bufOffset = this.bufOffset;
|
|
2132
|
+
const bufStart = this.bufStart;
|
|
2133
|
+
for (let i = 0; i < count; ++i) {
|
|
2134
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
2135
|
+
state = state << 8 | buf[--bufOffset];
|
|
2136
|
+
}
|
|
2137
|
+
const rem = state & ransPrecisionMask;
|
|
2138
|
+
const symbol = lutTable[rem];
|
|
2139
|
+
out[i] = symbol;
|
|
2140
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
2141
|
+
}
|
|
2142
|
+
this.state = state;
|
|
2143
|
+
this.bufOffset = bufOffset;
|
|
2144
|
+
}
|
|
2145
|
+
_decodeSymbolsU32(out, count, lutTable) {
|
|
2057
2146
|
const buf = this.buf;
|
|
2058
2147
|
const lRansBase = this.lRansBase;
|
|
2059
2148
|
const ransPrecisionBits = this.ransPrecisionBits;
|
|
2060
2149
|
const ransPrecisionMask = this.ransPrecisionMask;
|
|
2061
|
-
const lutTable = this.lutTable;
|
|
2062
2150
|
const probTable = this.probTable;
|
|
2063
2151
|
const cumProbTable = this.cumProbTable;
|
|
2064
2152
|
let state = this.state;
|
|
@@ -2119,16 +2207,12 @@ function computeRAnsPrecisionFromUniqueSymbolsBitLength(symbolsBitLength) {
|
|
|
2119
2207
|
return unclamped;
|
|
2120
2208
|
}
|
|
2121
2209
|
var RAnsSymbolDecoder = class {
|
|
2122
|
-
uniqueSymbolsBitLength_;
|
|
2123
2210
|
ransPrecisionBits_;
|
|
2124
|
-
ransPrecision_;
|
|
2125
2211
|
probabilityTable_;
|
|
2126
2212
|
numSymbols_;
|
|
2127
2213
|
ans_;
|
|
2128
2214
|
constructor(uniqueSymbolsBitLength) {
|
|
2129
|
-
this.uniqueSymbolsBitLength_ = uniqueSymbolsBitLength;
|
|
2130
2215
|
this.ransPrecisionBits_ = computeRAnsPrecisionFromUniqueSymbolsBitLength(uniqueSymbolsBitLength);
|
|
2131
|
-
this.ransPrecision_ = 1 << this.ransPrecisionBits_;
|
|
2132
2216
|
this.probabilityTable_ = null;
|
|
2133
2217
|
this.numSymbols_ = 0;
|
|
2134
2218
|
this.ans_ = new RAnsDecoder(this.ransPrecisionBits_);
|
|
@@ -3540,8 +3624,7 @@ var MeshPredictionSchemeTexCoordsPortablePredictor = class {
|
|
|
3540
3624
|
}
|
|
3541
3625
|
const xUV0 = nUV0 * pnNorm2Squared + cnDotPn * pnUV0;
|
|
3542
3626
|
const xUV1 = nUV1 * pnNorm2Squared + cnDotPn * pnUV1;
|
|
3543
|
-
|
|
3544
|
-
if (pnAbsMax > 0 && Math.abs(cnDotPn) > INT64_MAX / pnAbsMax) {
|
|
3627
|
+
if (pnAbsMaxG > 0 && cnDotPnAbs > INT64_MAX / pnAbsMaxG) {
|
|
3545
3628
|
return false;
|
|
3546
3629
|
}
|
|
3547
3630
|
const xPos0 = next0 + Math.trunc(cnDotPn * pn0 / pnNorm2Squared);
|
|
@@ -4586,15 +4669,6 @@ var AttributeQuantizationTransform = class _AttributeQuantizationTransform exten
|
|
|
4586
4669
|
}
|
|
4587
4670
|
return true;
|
|
4588
4671
|
}
|
|
4589
|
-
get quantizationBits() {
|
|
4590
|
-
return this._quantizationBits;
|
|
4591
|
-
}
|
|
4592
|
-
get range() {
|
|
4593
|
-
return this._range;
|
|
4594
|
-
}
|
|
4595
|
-
minValue(axis) {
|
|
4596
|
-
return this._minValues[axis];
|
|
4597
|
-
}
|
|
4598
4672
|
static _isQuantizationValid(quantizationBits) {
|
|
4599
4673
|
return quantizationBits >= 1 && quantizationBits <= 30;
|
|
4600
4674
|
}
|
|
@@ -4673,7 +4747,7 @@ var SequentialAttributeDecodersController = class extends AttributesDecoder {
|
|
|
4673
4747
|
if (!this._sequencer) {
|
|
4674
4748
|
return false;
|
|
4675
4749
|
}
|
|
4676
|
-
if (!this._sequencer.generateSequence(
|
|
4750
|
+
if (!this._sequencer.generateSequence()) {
|
|
4677
4751
|
return false;
|
|
4678
4752
|
}
|
|
4679
4753
|
this._pointIds = this._sequencer.getOutputPointIds();
|
|
@@ -4797,19 +4871,29 @@ var DepthFirstTraverser = class {
|
|
|
4797
4871
|
init(cornerTable, observer) {
|
|
4798
4872
|
this._cornerTable = cornerTable;
|
|
4799
4873
|
this._observer = observer;
|
|
4800
|
-
this._isFaceVisited =
|
|
4801
|
-
this._isVertexVisited =
|
|
4874
|
+
this._isFaceVisited = null;
|
|
4875
|
+
this._isVertexVisited = null;
|
|
4802
4876
|
this._numVisitedFaces = 0;
|
|
4803
4877
|
this._cornerToVertex = cornerTable.cornerToVertexArray();
|
|
4804
4878
|
this._oppositeCorners = cornerTable.oppositeCornerArray();
|
|
4805
4879
|
this._vertexLeftmost = cornerTable.vertexLeftmostCornerArray();
|
|
4806
4880
|
this._numCorners = cornerTable.numCorners();
|
|
4807
|
-
this._cornerTraversalStack = new Int32Array(this._numCorners);
|
|
4808
4881
|
}
|
|
4809
4882
|
cornerTable() {
|
|
4810
4883
|
return this._cornerTable;
|
|
4811
4884
|
}
|
|
4885
|
+
// Scratch buffers are set up here rather than in init() so a shared-traversal
|
|
4886
|
+
// -cache hit — where generateSequence returns before any traversal — skips
|
|
4887
|
+
// this entirely, including the visited-flag zero-fill (worth ~0.5% on the
|
|
4888
|
+
// 488-primitive manablade-static bundle, which shares attribute corner tables across
|
|
4889
|
+
// primitives). Uint8Array (0/1) instead of Array(bool): these flags are read
|
|
4890
|
+
// and written on every corner of the hottest decode loop (traverseFromCorner).
|
|
4891
|
+
// Decode-scoped scratch: released in bulk at the end of the decode.
|
|
4812
4892
|
onTraversalStart() {
|
|
4893
|
+
const cornerTable = this._cornerTable;
|
|
4894
|
+
this._isFaceVisited = scratchUint8Zeroed(cornerTable.numFaces());
|
|
4895
|
+
this._isVertexVisited = scratchUint8Zeroed(cornerTable.numVertices());
|
|
4896
|
+
this._cornerTraversalStack = scratchInt32(this._numCorners);
|
|
4813
4897
|
}
|
|
4814
4898
|
onTraversalEnd() {
|
|
4815
4899
|
}
|
|
@@ -4825,6 +4909,14 @@ var DepthFirstTraverser = class {
|
|
|
4825
4909
|
const vertexLeftmost = this._vertexLeftmost;
|
|
4826
4910
|
const stack = this._cornerTraversalStack;
|
|
4827
4911
|
let numVisitedFaces = this._numVisitedFaces;
|
|
4912
|
+
const sequencer = observer._sequencer;
|
|
4913
|
+
const encodingData = observer._encodingData;
|
|
4914
|
+
const obsFaces = observer._faces;
|
|
4915
|
+
const encodedToCornerMap = observer._encodedToCornerMap;
|
|
4916
|
+
const vertexToEncodedMap = observer._vertexToEncodedMap;
|
|
4917
|
+
const outPointIds = sequencer._outPointIds;
|
|
4918
|
+
let numOutPoints = sequencer._numOutPoints;
|
|
4919
|
+
let numValues = encodingData.numValues;
|
|
4828
4920
|
let stackSize = 0;
|
|
4829
4921
|
stack[stackSize++] = cornerId;
|
|
4830
4922
|
const nextCorner = cornerId % 3 === 2 ? cornerId - 2 : cornerId + 1;
|
|
@@ -4836,11 +4928,15 @@ var DepthFirstTraverser = class {
|
|
|
4836
4928
|
}
|
|
4837
4929
|
if (!isVertexVisited[nextVert]) {
|
|
4838
4930
|
isVertexVisited[nextVert] = 1;
|
|
4839
|
-
|
|
4931
|
+
outPointIds[numOutPoints++] = obsFaces[nextCorner];
|
|
4932
|
+
encodedToCornerMap[numValues] = nextCorner;
|
|
4933
|
+
vertexToEncodedMap[nextVert] = numValues++;
|
|
4840
4934
|
}
|
|
4841
4935
|
if (!isVertexVisited[prevVert]) {
|
|
4842
4936
|
isVertexVisited[prevVert] = 1;
|
|
4843
|
-
|
|
4937
|
+
outPointIds[numOutPoints++] = obsFaces[prevCorner];
|
|
4938
|
+
encodedToCornerMap[numValues] = prevCorner;
|
|
4939
|
+
vertexToEncodedMap[prevVert] = numValues++;
|
|
4844
4940
|
}
|
|
4845
4941
|
while (stackSize > 0) {
|
|
4846
4942
|
cornerId = stack[stackSize - 1];
|
|
@@ -4854,6 +4950,8 @@ var DepthFirstTraverser = class {
|
|
|
4854
4950
|
numVisitedFaces++;
|
|
4855
4951
|
const vertId = cornerToVertex[cornerId];
|
|
4856
4952
|
if (vertId === kInvalidVertexIndex2) {
|
|
4953
|
+
sequencer._numOutPoints = numOutPoints;
|
|
4954
|
+
encodingData.numValues = numValues;
|
|
4857
4955
|
return false;
|
|
4858
4956
|
}
|
|
4859
4957
|
if (!isVertexVisited[vertId]) {
|
|
@@ -4864,7 +4962,9 @@ var DepthFirstTraverser = class {
|
|
|
4864
4962
|
onBoundary = oppositeCorners[nextLc] < 0;
|
|
4865
4963
|
}
|
|
4866
4964
|
isVertexVisited[vertId] = 1;
|
|
4867
|
-
|
|
4965
|
+
outPointIds[numOutPoints++] = obsFaces[cornerId];
|
|
4966
|
+
encodedToCornerMap[numValues] = cornerId;
|
|
4967
|
+
vertexToEncodedMap[vertId] = numValues++;
|
|
4868
4968
|
if (!onBoundary) {
|
|
4869
4969
|
const nextCornerId2 = cornerId % 3 === 2 ? cornerId - 2 : cornerId + 1;
|
|
4870
4970
|
cornerId = oppositeCorners[nextCornerId2];
|
|
@@ -4901,6 +5001,8 @@ var DepthFirstTraverser = class {
|
|
|
4901
5001
|
}
|
|
4902
5002
|
}
|
|
4903
5003
|
this._numVisitedFaces = numVisitedFaces;
|
|
5004
|
+
sequencer._numOutPoints = numOutPoints;
|
|
5005
|
+
encodingData.numValues = numValues;
|
|
4904
5006
|
return true;
|
|
4905
5007
|
}
|
|
4906
5008
|
};
|
|
@@ -5113,7 +5215,7 @@ var MeshTraversalSequencer = class {
|
|
|
5113
5215
|
setTraverser(traverser) {
|
|
5114
5216
|
this._traverser = traverser;
|
|
5115
5217
|
}
|
|
5116
|
-
generateSequence(
|
|
5218
|
+
generateSequence() {
|
|
5117
5219
|
const cornerTable = this._traverser.cornerTable();
|
|
5118
5220
|
const methodId = this._traverser._traversalMethodId;
|
|
5119
5221
|
const cacheKey = cornerTable.cornerToVertexArray();
|
|
@@ -5451,7 +5553,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5451
5553
|
return true;
|
|
5452
5554
|
}
|
|
5453
5555
|
_decodeConnectivity(numSymbols) {
|
|
5454
|
-
const activeCornerStack =
|
|
5556
|
+
const activeCornerStack = scratchInt32(numSymbols + this._topologySplitData.length + 16);
|
|
5455
5557
|
let activeCornerStackSize = 0;
|
|
5456
5558
|
const topologySplitActiveCorners = /* @__PURE__ */ new Map();
|
|
5457
5559
|
const invalidVertices = [];
|
|
@@ -6315,7 +6417,7 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6315
6417
|
this._activeContext = -1;
|
|
6316
6418
|
this._minValence = 2;
|
|
6317
6419
|
this._maxValence = 7;
|
|
6318
|
-
this._vertexValences =
|
|
6420
|
+
this._vertexValences = new Int32Array(0);
|
|
6319
6421
|
this._contextSymbols = [];
|
|
6320
6422
|
this._contextCounters = [];
|
|
6321
6423
|
}
|
|
@@ -6339,7 +6441,7 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6339
6441
|
if (this._numVertices < 0) {
|
|
6340
6442
|
return false;
|
|
6341
6443
|
}
|
|
6342
|
-
this._vertexValences = new
|
|
6444
|
+
this._vertexValences = new Int32Array(this._numVertices);
|
|
6343
6445
|
const numUniqueValences = this._maxValence - this._minValence + 1;
|
|
6344
6446
|
this._contextSymbols = new Array(numUniqueValences);
|
|
6345
6447
|
this._contextCounters = new Array(numUniqueValences);
|
|
@@ -6381,34 +6483,37 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6381
6483
|
return this._lastSymbol;
|
|
6382
6484
|
}
|
|
6383
6485
|
newActiveCornerReached(corner) {
|
|
6384
|
-
const
|
|
6385
|
-
const
|
|
6386
|
-
const
|
|
6486
|
+
const cornerToVertex = this._cornerTable._cornerToVertex;
|
|
6487
|
+
const valences = this._vertexValences;
|
|
6488
|
+
const next = corner % 3 === 2 ? corner - 2 : corner + 1;
|
|
6489
|
+
const prev = corner % 3 === 0 ? corner + 2 : corner - 1;
|
|
6490
|
+
const vertNext = cornerToVertex[next];
|
|
6491
|
+
const vertPrev = cornerToVertex[prev];
|
|
6387
6492
|
switch (this._lastSymbol) {
|
|
6388
6493
|
case TOPOLOGY_C:
|
|
6389
6494
|
case TOPOLOGY_S:
|
|
6390
|
-
|
|
6391
|
-
|
|
6495
|
+
valences[vertNext] += 1;
|
|
6496
|
+
valences[vertPrev] += 1;
|
|
6392
6497
|
break;
|
|
6393
6498
|
case TOPOLOGY_R:
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6499
|
+
valences[cornerToVertex[corner]] += 1;
|
|
6500
|
+
valences[vertNext] += 1;
|
|
6501
|
+
valences[vertPrev] += 2;
|
|
6397
6502
|
break;
|
|
6398
6503
|
case TOPOLOGY_L:
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6504
|
+
valences[cornerToVertex[corner]] += 1;
|
|
6505
|
+
valences[vertNext] += 2;
|
|
6506
|
+
valences[vertPrev] += 1;
|
|
6402
6507
|
break;
|
|
6403
6508
|
case TOPOLOGY_E:
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6509
|
+
valences[cornerToVertex[corner]] += 2;
|
|
6510
|
+
valences[vertNext] += 2;
|
|
6511
|
+
valences[vertPrev] += 2;
|
|
6407
6512
|
break;
|
|
6408
6513
|
default:
|
|
6409
6514
|
break;
|
|
6410
6515
|
}
|
|
6411
|
-
const activeValence =
|
|
6516
|
+
const activeValence = valences[vertNext];
|
|
6412
6517
|
let clampedValence;
|
|
6413
6518
|
if (activeValence < this._minValence) {
|
|
6414
6519
|
clampedValence = this._minValence;
|
|
@@ -6527,45 +6632,30 @@ var MeshSequentialDecoder = class extends MeshDecoder {
|
|
|
6527
6632
|
return false;
|
|
6528
6633
|
}
|
|
6529
6634
|
} else {
|
|
6635
|
+
const mesh = this.mesh();
|
|
6636
|
+
mesh.setNumFaces(numFaces);
|
|
6637
|
+
const faces = mesh.faces_;
|
|
6638
|
+
const numIndices = numFaces * 3;
|
|
6639
|
+
const buffer = this.buffer();
|
|
6530
6640
|
if (numPoints < 256) {
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
const val = this.buffer().decodeUint8();
|
|
6535
|
-
if (val === void 0) return false;
|
|
6536
|
-
face[j] = val;
|
|
6537
|
-
}
|
|
6538
|
-
this.mesh().addFace(face);
|
|
6539
|
-
}
|
|
6641
|
+
const src = buffer.decodeBytesView(numIndices);
|
|
6642
|
+
if (src === void 0) return false;
|
|
6643
|
+
for (let i = 0; i < numIndices; ++i) faces[i] = src[i];
|
|
6540
6644
|
} else if (numPoints < 1 << 16) {
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
const val = this.buffer().decodeUint16();
|
|
6545
|
-
if (val === void 0) return false;
|
|
6546
|
-
face[j] = val;
|
|
6547
|
-
}
|
|
6548
|
-
this.mesh().addFace(face);
|
|
6549
|
-
}
|
|
6645
|
+
const src = buffer.decodeBytesView(numIndices * 2);
|
|
6646
|
+
if (src === void 0) return false;
|
|
6647
|
+
for (let i = 0; i < numIndices; ++i) faces[i] = src[i * 2] | src[i * 2 + 1] << 8;
|
|
6550
6648
|
} else if (numPoints < 1 << 21) {
|
|
6551
|
-
for (let i = 0; i <
|
|
6552
|
-
const
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
if (val === void 0) return false;
|
|
6556
|
-
face[j] = val;
|
|
6557
|
-
}
|
|
6558
|
-
this.mesh().addFace(face);
|
|
6649
|
+
for (let i = 0; i < numIndices; ++i) {
|
|
6650
|
+
const val = decodeVarint(buffer);
|
|
6651
|
+
if (val === void 0) return false;
|
|
6652
|
+
faces[i] = val;
|
|
6559
6653
|
}
|
|
6560
6654
|
} else {
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
if (val === void 0) return false;
|
|
6566
|
-
face[j] = val;
|
|
6567
|
-
}
|
|
6568
|
-
this.mesh().addFace(face);
|
|
6655
|
+
const src = buffer.decodeBytesView(numIndices * 4);
|
|
6656
|
+
if (src === void 0) return false;
|
|
6657
|
+
for (let i = 0; i < numIndices; ++i) {
|
|
6658
|
+
faces[i] = src[i * 4] | src[i * 4 + 1] << 8 | src[i * 4 + 2] << 16 | src[i * 4 + 3] << 24;
|
|
6569
6659
|
}
|
|
6570
6660
|
}
|
|
6571
6661
|
}
|
|
@@ -6579,32 +6669,31 @@ var MeshSequentialDecoder = class extends MeshDecoder {
|
|
|
6579
6669
|
);
|
|
6580
6670
|
}
|
|
6581
6671
|
_decodeAndDecompressIndices(numFaces) {
|
|
6582
|
-
const
|
|
6583
|
-
|
|
6672
|
+
const numIndices = numFaces * 3;
|
|
6673
|
+
const indicesBuffer = new Uint32Array(numIndices);
|
|
6674
|
+
if (!decodeSymbols(numIndices, 1, this.buffer(), indicesBuffer)) {
|
|
6584
6675
|
return false;
|
|
6585
6676
|
}
|
|
6677
|
+
const mesh = this.mesh();
|
|
6678
|
+
mesh.setNumFaces(numFaces);
|
|
6679
|
+
const faces = mesh.faces_;
|
|
6586
6680
|
let lastIndexValue = 0;
|
|
6587
|
-
let
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
} else {
|
|
6599
|
-
if (indexDiff > 2147483647 - lastIndexValue) {
|
|
6600
|
-
return false;
|
|
6601
|
-
}
|
|
6681
|
+
for (let i = 0; i < numIndices; ++i) {
|
|
6682
|
+
const encodedVal = indicesBuffer[i];
|
|
6683
|
+
let indexDiff = encodedVal >>> 1;
|
|
6684
|
+
if (encodedVal & 1) {
|
|
6685
|
+
if (indexDiff > lastIndexValue) {
|
|
6686
|
+
return false;
|
|
6687
|
+
}
|
|
6688
|
+
indexDiff = -indexDiff;
|
|
6689
|
+
} else {
|
|
6690
|
+
if (indexDiff > 2147483647 - lastIndexValue) {
|
|
6691
|
+
return false;
|
|
6602
6692
|
}
|
|
6603
|
-
const indexValue = indexDiff + lastIndexValue | 0;
|
|
6604
|
-
face[j] = indexValue;
|
|
6605
|
-
lastIndexValue = indexValue;
|
|
6606
6693
|
}
|
|
6607
|
-
|
|
6694
|
+
const indexValue = indexDiff + lastIndexValue | 0;
|
|
6695
|
+
faces[i] = indexValue;
|
|
6696
|
+
lastIndexValue = indexValue;
|
|
6608
6697
|
}
|
|
6609
6698
|
return true;
|
|
6610
6699
|
}
|
|
@@ -6662,9 +6751,15 @@ var Decoder = class {
|
|
|
6662
6751
|
if (result.header.encoderType !== EncodedGeometryType.TRIANGULAR_MESH) {
|
|
6663
6752
|
return { ok: false, message: "Input is not a mesh." };
|
|
6664
6753
|
}
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6754
|
+
try {
|
|
6755
|
+
const decoder = createMeshDecoder(result.header.encoderMethod);
|
|
6756
|
+
const status = decoder.decodeMesh(this.options_, inBuffer, outGeometry);
|
|
6757
|
+
return { ok: status.ok(), message: status.errorMsg };
|
|
6758
|
+
} catch (error) {
|
|
6759
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
6760
|
+
} finally {
|
|
6761
|
+
releaseScratch();
|
|
6762
|
+
}
|
|
6668
6763
|
}
|
|
6669
6764
|
options() {
|
|
6670
6765
|
return this.options_;
|
|
@@ -6687,6 +6782,7 @@ var decodeDracoMesh = (data) => {
|
|
|
6687
6782
|
};
|
|
6688
6783
|
|
|
6689
6784
|
// src/three/index.ts
|
|
6785
|
+
var isLoadingManager = (value) => typeof value?.itemStart === "function";
|
|
6690
6786
|
var _taskCache = /* @__PURE__ */ new WeakMap();
|
|
6691
6787
|
var _attributeTypeMap = {
|
|
6692
6788
|
POSITION: Type.POSITION,
|
|
@@ -6708,14 +6804,31 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6708
6804
|
defaultAttributeIDs;
|
|
6709
6805
|
defaultAttributeTypes;
|
|
6710
6806
|
workerLimit;
|
|
6807
|
+
// Opt-in (0 = disabled): buffers at or below this size decode synchronously
|
|
6808
|
+
// on the main thread instead of paying the ~0.5 ms worker message roundtrip.
|
|
6809
|
+
// Worth enabling (e.g. 4096) when the main thread is otherwise idle during
|
|
6810
|
+
// loads — in a full GLTFLoader parse the main thread is already busy
|
|
6811
|
+
// building geometries, and measurements show the pool wins there even for
|
|
6812
|
+
// tiny primitives.
|
|
6813
|
+
syncByteThreshold;
|
|
6711
6814
|
_workers;
|
|
6712
6815
|
_taskId;
|
|
6713
6816
|
_tasks;
|
|
6817
|
+
// Tasks queued during the current microtask; flushed as one batched message
|
|
6818
|
+
// per worker (a 488-primitive scene costs 4 postMessages, not 488).
|
|
6819
|
+
_batch;
|
|
6820
|
+
_batchScheduled;
|
|
6714
6821
|
// Set when spawning a worker fails (bundler without module-worker support,
|
|
6715
6822
|
// file:// pages, …): decoding transparently falls back to the main thread.
|
|
6716
6823
|
_workersBroken;
|
|
6717
|
-
|
|
6718
|
-
|
|
6824
|
+
_workerUrl;
|
|
6825
|
+
// Same-origin blob bootstrap used when the worker asset lives on a CDN
|
|
6826
|
+
// origin (created lazily, revoked on dispose).
|
|
6827
|
+
_workerBlobUrl;
|
|
6828
|
+
// Accepts either a LoadingManager (three-compatible form) or an options bag.
|
|
6829
|
+
constructor(managerOrOptions) {
|
|
6830
|
+
const options = isLoadingManager(managerOrOptions) ? { manager: managerOrOptions } : managerOrOptions ?? {};
|
|
6831
|
+
super(options.manager);
|
|
6719
6832
|
this.defaultAttributeIDs = {
|
|
6720
6833
|
position: "POSITION",
|
|
6721
6834
|
normal: "NORMAL",
|
|
@@ -6728,14 +6841,31 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6728
6841
|
color: "Float32Array",
|
|
6729
6842
|
uv: "Float32Array"
|
|
6730
6843
|
};
|
|
6731
|
-
this.workerLimit = 4;
|
|
6844
|
+
this.workerLimit = options.workers === false ? 0 : options.workerLimit ?? 4;
|
|
6845
|
+
this.syncByteThreshold = options.syncByteThreshold ?? 0;
|
|
6732
6846
|
this._workers = [];
|
|
6733
6847
|
this._taskId = 0;
|
|
6734
6848
|
this._tasks = /* @__PURE__ */ new Map();
|
|
6849
|
+
this._batch = [];
|
|
6850
|
+
this._batchScheduled = false;
|
|
6735
6851
|
this._workersBroken = false;
|
|
6852
|
+
this._workerUrl = null;
|
|
6853
|
+
this._workerBlobUrl = null;
|
|
6854
|
+
}
|
|
6855
|
+
// Overrides where the decode worker is loaded from. Normally unnecessary:
|
|
6856
|
+
// the worker resolves through `new URL('./worker.js', import.meta.url)`
|
|
6857
|
+
// (bundlers emit it as a hashed asset), and CDN origins are handled by the
|
|
6858
|
+
// blob bootstrap in _getWorker.
|
|
6859
|
+
setWorkerUrl(url) {
|
|
6860
|
+
this._workerUrl = url;
|
|
6861
|
+
return this;
|
|
6736
6862
|
}
|
|
6737
|
-
//
|
|
6738
|
-
// external decoder files to configure.
|
|
6863
|
+
// No-ops kept for API compatibility with THREE.DRACOLoader — minidraco has
|
|
6864
|
+
// no external decoder files to configure. The params are `unknown` (not
|
|
6865
|
+
// `string`/`object`) so the signatures stay assignable to THREE.DRACOLoader
|
|
6866
|
+
// across three versions, whose setDecoderPath has grown to accept a
|
|
6867
|
+
// `string | DecoderPaths` — letting `new MiniDRACOLoader()` be passed to
|
|
6868
|
+
// GLTFLoader.setDRACOLoader() with no cast.
|
|
6739
6869
|
setDecoderPath(_path) {
|
|
6740
6870
|
return this;
|
|
6741
6871
|
}
|
|
@@ -6746,14 +6876,35 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6746
6876
|
this.workerLimit = limit;
|
|
6747
6877
|
return this;
|
|
6748
6878
|
}
|
|
6879
|
+
// Toggle the worker pool on/off. false decodes synchronously on the main
|
|
6880
|
+
// thread; true enables the pool, keeping the current size or falling back to
|
|
6881
|
+
// the default 4 if it was disabled. For a specific pool size use
|
|
6882
|
+
// setWorkerLimit(n).
|
|
6883
|
+
setWorkers(enabled) {
|
|
6884
|
+
this.workerLimit = enabled ? this.workerLimit || 4 : 0;
|
|
6885
|
+
return this;
|
|
6886
|
+
}
|
|
6749
6887
|
preload() {
|
|
6750
|
-
if (this._workersAvailable())
|
|
6888
|
+
if (this._workersAvailable()) {
|
|
6889
|
+
while (this._workers.length < this.workerLimit && this._getWorker() !== null) {
|
|
6890
|
+
}
|
|
6891
|
+
}
|
|
6751
6892
|
return this;
|
|
6752
6893
|
}
|
|
6753
6894
|
dispose() {
|
|
6754
6895
|
for (const entry of this._workers) entry.worker.terminate();
|
|
6755
6896
|
this._workers = [];
|
|
6897
|
+
const disposedError = new Error("MiniDRACOLoader: disposed while decoding");
|
|
6898
|
+
disposedError.isDecodeError = true;
|
|
6899
|
+
for (const task of this._batch) task.reject(disposedError);
|
|
6900
|
+
this._batch = [];
|
|
6901
|
+
this._batchScheduled = false;
|
|
6902
|
+
for (const [, task] of this._tasks) task.reject(disposedError);
|
|
6756
6903
|
this._tasks.clear();
|
|
6904
|
+
if (this._workerBlobUrl !== null) {
|
|
6905
|
+
URL.revokeObjectURL(this._workerBlobUrl);
|
|
6906
|
+
this._workerBlobUrl = null;
|
|
6907
|
+
}
|
|
6757
6908
|
return this;
|
|
6758
6909
|
}
|
|
6759
6910
|
load(url, onLoad, onProgress, onError) {
|
|
@@ -6791,10 +6942,6 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6791
6942
|
const cachedTask = _taskCache.get(buffer);
|
|
6792
6943
|
if (cachedTask.key === taskKey) {
|
|
6793
6944
|
return cachedTask.promise;
|
|
6794
|
-
} else if (buffer.byteLength === 0) {
|
|
6795
|
-
throw new Error(
|
|
6796
|
-
"MiniDRACOLoader: Unable to re-decode a buffer with different settings. Buffer has already been transferred."
|
|
6797
|
-
);
|
|
6798
6945
|
}
|
|
6799
6946
|
}
|
|
6800
6947
|
const geometryPending = this._runTask(buffer, taskConfig);
|
|
@@ -6803,12 +6950,16 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6803
6950
|
}
|
|
6804
6951
|
async _runTask(buffer, taskConfig) {
|
|
6805
6952
|
if (this._workersAvailable()) {
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6953
|
+
if (buffer.byteLength > this.syncByteThreshold) {
|
|
6954
|
+
try {
|
|
6955
|
+
const raw = await this._decodeInWorker(buffer, taskConfig);
|
|
6956
|
+
return this._buildGeometryFromRaw(raw, taskConfig);
|
|
6957
|
+
} catch (error) {
|
|
6958
|
+
if (error?.isDecodeError) throw error;
|
|
6959
|
+
this._workersBroken = true;
|
|
6960
|
+
}
|
|
6961
|
+
} else {
|
|
6962
|
+
await Promise.resolve();
|
|
6812
6963
|
}
|
|
6813
6964
|
}
|
|
6814
6965
|
return this._decodeBuffer(buffer, taskConfig);
|
|
@@ -6817,21 +6968,38 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6817
6968
|
return this.workerLimit > 0 && typeof Worker !== "undefined" && !this._workersBroken;
|
|
6818
6969
|
}
|
|
6819
6970
|
_getWorker() {
|
|
6971
|
+
if (this._workersBroken) return null;
|
|
6820
6972
|
if (this._workers.length < this.workerLimit) {
|
|
6821
|
-
const
|
|
6973
|
+
const workerUrl = this._workerUrl ?? new URL("./worker.js", import.meta.url);
|
|
6974
|
+
let worker;
|
|
6975
|
+
try {
|
|
6976
|
+
worker = new Worker(workerUrl, { type: "module" });
|
|
6977
|
+
} catch {
|
|
6978
|
+
try {
|
|
6979
|
+
if (this._workerBlobUrl === null) {
|
|
6980
|
+
const bootstrap = `import ${JSON.stringify(String(workerUrl))};`;
|
|
6981
|
+
this._workerBlobUrl = URL.createObjectURL(new Blob([bootstrap], { type: "text/javascript" }));
|
|
6982
|
+
}
|
|
6983
|
+
worker = new Worker(this._workerBlobUrl, { type: "module" });
|
|
6984
|
+
} catch {
|
|
6985
|
+
this._workersBroken = true;
|
|
6986
|
+
return null;
|
|
6987
|
+
}
|
|
6988
|
+
}
|
|
6822
6989
|
const entry = { worker, pending: 0 };
|
|
6823
6990
|
worker.onmessage = (event) => {
|
|
6824
|
-
const { id, ok, indices, attributes, error }
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6991
|
+
for (const { id, ok, indices, attributes, error } of event.data.results) {
|
|
6992
|
+
const task = this._tasks.get(id);
|
|
6993
|
+
if (!task) continue;
|
|
6994
|
+
this._tasks.delete(id);
|
|
6995
|
+
task.entry.pending--;
|
|
6996
|
+
if (ok) {
|
|
6997
|
+
task.resolve({ indices, attributes });
|
|
6998
|
+
} else {
|
|
6999
|
+
const decodeError = new Error(error);
|
|
7000
|
+
decodeError.isDecodeError = true;
|
|
7001
|
+
task.reject(decodeError);
|
|
7002
|
+
}
|
|
6835
7003
|
}
|
|
6836
7004
|
};
|
|
6837
7005
|
worker.onerror = (event) => {
|
|
@@ -6851,19 +7019,56 @@ var MiniDRACOLoader = class extends Loader {
|
|
|
6851
7019
|
return best;
|
|
6852
7020
|
}
|
|
6853
7021
|
_decodeInWorker(buffer, taskConfig) {
|
|
6854
|
-
const entry = this._getWorker();
|
|
6855
7022
|
const id = this._taskId++;
|
|
6856
7023
|
return new Promise((resolve, reject) => {
|
|
6857
|
-
this.
|
|
6858
|
-
|
|
7024
|
+
this._batch.push({ id, buffer, taskConfig, resolve, reject });
|
|
7025
|
+
if (!this._batchScheduled) {
|
|
7026
|
+
this._batchScheduled = true;
|
|
7027
|
+
queueMicrotask(() => this._flushBatch());
|
|
7028
|
+
}
|
|
7029
|
+
});
|
|
7030
|
+
}
|
|
7031
|
+
_flushBatch() {
|
|
7032
|
+
this._batchScheduled = false;
|
|
7033
|
+
const batch = this._batch;
|
|
7034
|
+
if (batch.length === 0) return;
|
|
7035
|
+
this._batch = [];
|
|
7036
|
+
while (this._workers.length < Math.min(this.workerLimit, batch.length) && this._getWorker() !== null) {
|
|
7037
|
+
}
|
|
7038
|
+
if (this._workersBroken || this._workers.length === 0) {
|
|
7039
|
+
const error = new Error("MiniDRACOLoader: worker unavailable");
|
|
7040
|
+
for (const task of batch) task.reject(error);
|
|
7041
|
+
return;
|
|
7042
|
+
}
|
|
7043
|
+
batch.sort((a, b) => b.buffer.byteLength - a.buffer.byteLength);
|
|
7044
|
+
let totalBytes = 0;
|
|
7045
|
+
for (const task of batch) totalBytes += task.buffer.byteLength;
|
|
7046
|
+
const averageBytes = totalBytes / batch.length;
|
|
7047
|
+
const buckets = this._workers.map((entry) => ({
|
|
7048
|
+
entry,
|
|
7049
|
+
tasks: [],
|
|
7050
|
+
bytes: entry.pending * averageBytes
|
|
7051
|
+
}));
|
|
7052
|
+
for (const task of batch) {
|
|
7053
|
+
let best = buckets[0];
|
|
7054
|
+
for (const bucket of buckets) if (bucket.bytes < best.bytes) best = bucket;
|
|
7055
|
+
best.tasks.push(task);
|
|
7056
|
+
best.bytes += task.buffer.byteLength;
|
|
7057
|
+
}
|
|
7058
|
+
for (const { entry, tasks } of buckets) {
|
|
7059
|
+
if (tasks.length === 0) continue;
|
|
7060
|
+
entry.pending += tasks.length;
|
|
7061
|
+
for (const task of tasks) this._tasks.set(task.id, { resolve: task.resolve, reject: task.reject, entry });
|
|
6859
7062
|
entry.worker.postMessage({
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
7063
|
+
tasks: tasks.map((task) => ({
|
|
7064
|
+
id: task.id,
|
|
7065
|
+
buffer: task.buffer,
|
|
7066
|
+
attributeIDs: task.taskConfig.attributeIDs,
|
|
7067
|
+
attributeTypes: task.taskConfig.attributeTypes,
|
|
7068
|
+
useUniqueIDs: task.taskConfig.useUniqueIDs
|
|
7069
|
+
}))
|
|
6865
7070
|
});
|
|
6866
|
-
}
|
|
7071
|
+
}
|
|
6867
7072
|
}
|
|
6868
7073
|
_buildGeometryFromRaw(raw, taskConfig) {
|
|
6869
7074
|
const geometry = new BufferGeometry();
|