minidraco 0.3.0 → 0.5.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 +12 -12
- package/dist/index.d.ts +10 -1
- package/dist/index.js +1729 -645
- package/dist/three.d.ts +10 -1
- package/dist/three.js +1727 -643
- package/dist/worker.js +1729 -645
- package/package.json +1 -1
package/dist/three.js
CHANGED
|
@@ -271,6 +271,90 @@ var Mesh = class extends PointCloud {
|
|
|
271
271
|
}
|
|
272
272
|
};
|
|
273
273
|
|
|
274
|
+
// src/decoder/core/ScratchArena.ts
|
|
275
|
+
var MAX_CLASS = 28;
|
|
276
|
+
var freeInt32 = [];
|
|
277
|
+
var freeUint32 = [];
|
|
278
|
+
var freeUint8 = [];
|
|
279
|
+
for (let i = 0; i <= MAX_CLASS; ++i) {
|
|
280
|
+
freeInt32.push([]);
|
|
281
|
+
freeUint32.push([]);
|
|
282
|
+
freeUint8.push([]);
|
|
283
|
+
}
|
|
284
|
+
var borrowedInt32 = [];
|
|
285
|
+
var borrowedUint32 = [];
|
|
286
|
+
var borrowedUint8 = [];
|
|
287
|
+
var sizeClass = (size) => size <= 1 ? 0 : 32 - Math.clz32(size - 1);
|
|
288
|
+
var takeInt32 = (size) => {
|
|
289
|
+
const k = sizeClass(size);
|
|
290
|
+
if (k > MAX_CLASS) return new Int32Array(size);
|
|
291
|
+
const bucket = freeInt32[k];
|
|
292
|
+
let pooled = bucket.length > 0 ? bucket.pop() : new Int32Array(size);
|
|
293
|
+
if (pooled.length < size) pooled = new Int32Array(1 << k);
|
|
294
|
+
borrowedInt32.push(pooled);
|
|
295
|
+
return pooled.length === size ? pooled : pooled.subarray(0, size);
|
|
296
|
+
};
|
|
297
|
+
var takeUint32 = (size) => {
|
|
298
|
+
const k = sizeClass(size);
|
|
299
|
+
if (k > MAX_CLASS) return new Uint32Array(size);
|
|
300
|
+
const bucket = freeUint32[k];
|
|
301
|
+
let pooled = bucket.length > 0 ? bucket.pop() : new Uint32Array(size);
|
|
302
|
+
if (pooled.length < size) pooled = new Uint32Array(1 << k);
|
|
303
|
+
borrowedUint32.push(pooled);
|
|
304
|
+
return pooled.length === size ? pooled : pooled.subarray(0, size);
|
|
305
|
+
};
|
|
306
|
+
var byteCapacity = (size) => size < 8 ? 8 : size + 7 & ~7;
|
|
307
|
+
var takeUint8 = (size) => {
|
|
308
|
+
const capacity = byteCapacity(size);
|
|
309
|
+
const k = sizeClass(capacity);
|
|
310
|
+
if (k > MAX_CLASS) return new Uint8Array(capacity);
|
|
311
|
+
const bucket = freeUint8[k];
|
|
312
|
+
let pooled = bucket.length > 0 ? bucket.pop() : new Uint8Array(capacity);
|
|
313
|
+
if (pooled.length < size) pooled = new Uint8Array(1 << k);
|
|
314
|
+
borrowedUint8.push(pooled);
|
|
315
|
+
return pooled.length === size ? pooled : pooled.subarray(0, size);
|
|
316
|
+
};
|
|
317
|
+
var scratchInt32 = (size) => takeInt32(size);
|
|
318
|
+
var scratchInt32Filled = (size, value) => {
|
|
319
|
+
const view = takeInt32(size);
|
|
320
|
+
view.fill(value);
|
|
321
|
+
return view;
|
|
322
|
+
};
|
|
323
|
+
var scratchUint32 = (size) => takeUint32(size);
|
|
324
|
+
var scratchUint32Zeroed = (size) => {
|
|
325
|
+
const view = takeUint32(size);
|
|
326
|
+
view.fill(0);
|
|
327
|
+
return view;
|
|
328
|
+
};
|
|
329
|
+
var scratchUint8 = (size) => takeUint8(size);
|
|
330
|
+
var scratchUint8Zeroed = (size) => {
|
|
331
|
+
const view = takeUint8(size);
|
|
332
|
+
view.fill(0);
|
|
333
|
+
return view;
|
|
334
|
+
};
|
|
335
|
+
var scratchUint8Filled = (size, value) => {
|
|
336
|
+
const view = takeUint8(size);
|
|
337
|
+
view.fill(value);
|
|
338
|
+
return view;
|
|
339
|
+
};
|
|
340
|
+
var releaseScratch = () => {
|
|
341
|
+
for (let i = 0; i < borrowedInt32.length; ++i) {
|
|
342
|
+
const buffer = borrowedInt32[i];
|
|
343
|
+
freeInt32[sizeClass(buffer.length)].push(buffer);
|
|
344
|
+
}
|
|
345
|
+
for (let i = 0; i < borrowedUint32.length; ++i) {
|
|
346
|
+
const buffer = borrowedUint32[i];
|
|
347
|
+
freeUint32[sizeClass(buffer.length)].push(buffer);
|
|
348
|
+
}
|
|
349
|
+
for (let i = 0; i < borrowedUint8.length; ++i) {
|
|
350
|
+
const buffer = borrowedUint8[i];
|
|
351
|
+
freeUint8[sizeClass(buffer.length)].push(buffer);
|
|
352
|
+
}
|
|
353
|
+
borrowedInt32.length = 0;
|
|
354
|
+
borrowedUint32.length = 0;
|
|
355
|
+
borrowedUint8.length = 0;
|
|
356
|
+
};
|
|
357
|
+
|
|
274
358
|
// src/decoder/core/DataBuffer.ts
|
|
275
359
|
var DataBuffer = class {
|
|
276
360
|
_data;
|
|
@@ -295,6 +379,15 @@ var DataBuffer = class {
|
|
|
295
379
|
resize(newSize) {
|
|
296
380
|
this._resize(newSize);
|
|
297
381
|
}
|
|
382
|
+
// Replaces the contents with a decode-scoped scratch buffer of exactly
|
|
383
|
+
// `size` bytes; the previous contents are dropped and the new ones are
|
|
384
|
+
// arbitrary, so every byte must be written before it is read. Only for
|
|
385
|
+
// buffers that never outlive the decode (see ScratchArena) — the portable
|
|
386
|
+
// attributes the integer decoders build and discard per attribute are the
|
|
387
|
+
// one caller, and their per-primitive allocation showed up in profiles.
|
|
388
|
+
adoptScratch(size) {
|
|
389
|
+
this._data = scratchUint8(size);
|
|
390
|
+
}
|
|
298
391
|
write(bytePos, inArray, dataSize) {
|
|
299
392
|
if (inArray instanceof Uint8Array) {
|
|
300
393
|
this._data.set(inArray.length === dataSize ? inArray : inArray.subarray(0, dataSize), bytePos);
|
|
@@ -384,6 +477,19 @@ var PointAttribute = class extends GeometryAttribute {
|
|
|
384
477
|
this._numUniqueEntries = numAttributeValues;
|
|
385
478
|
return true;
|
|
386
479
|
}
|
|
480
|
+
// Like reset(), but backs the attribute with decode-scoped scratch memory.
|
|
481
|
+
// Only valid for attributes that never escape the decode and whose every
|
|
482
|
+
// byte is written before it is read (see DataBuffer.adoptScratch).
|
|
483
|
+
resetScratch(numAttributeValues) {
|
|
484
|
+
if (this._attributeBuffer === null) {
|
|
485
|
+
this._attributeBuffer = new DataBuffer();
|
|
486
|
+
}
|
|
487
|
+
const entrySize = dataTypeLength(this.dataType) * this.numComponents;
|
|
488
|
+
this._attributeBuffer.adoptScratch(numAttributeValues * entrySize);
|
|
489
|
+
this.resetBuffer(this._attributeBuffer, entrySize, 0);
|
|
490
|
+
this._numUniqueEntries = numAttributeValues;
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
387
493
|
get size() {
|
|
388
494
|
return this._numUniqueEntries;
|
|
389
495
|
}
|
|
@@ -426,6 +532,20 @@ var PointAttribute = class extends GeometryAttribute {
|
|
|
426
532
|
this._identityMapping = false;
|
|
427
533
|
this._indicesMap = new Uint32Array(numPoints);
|
|
428
534
|
}
|
|
535
|
+
// Adopts an already-computed map, shared with other attributes of the same
|
|
536
|
+
// mesh. The map must be treated as read-only from here on (reads go through
|
|
537
|
+
// mappedIndex/extractTo; copyFrom slices).
|
|
538
|
+
setExplicitMappingShared(map) {
|
|
539
|
+
this._identityMapping = false;
|
|
540
|
+
this._indicesMap = map;
|
|
541
|
+
}
|
|
542
|
+
// Like setExplicitMappingUnfilled, but from decode-scoped scratch. Only for
|
|
543
|
+
// attributes that never escape the decode (see ScratchArena) -- the portable
|
|
544
|
+
// attributes the sequential decoders build and discard.
|
|
545
|
+
setExplicitMappingScratch(numPoints) {
|
|
546
|
+
this._identityMapping = false;
|
|
547
|
+
this._indicesMap = scratchUint32(numPoints);
|
|
548
|
+
}
|
|
429
549
|
setAttributeTransformData(transformData) {
|
|
430
550
|
this._attributeTransformData = transformData;
|
|
431
551
|
}
|
|
@@ -921,48 +1041,6 @@ var DecoderBuffer = class {
|
|
|
921
1041
|
}
|
|
922
1042
|
};
|
|
923
1043
|
|
|
924
|
-
// src/decoder/core/ScratchArena.ts
|
|
925
|
-
var freeInt32 = [];
|
|
926
|
-
var freeUint8 = [];
|
|
927
|
-
var borrowedInt32 = [];
|
|
928
|
-
var borrowedUint8 = [];
|
|
929
|
-
var acquire = (free, borrowed, size) => {
|
|
930
|
-
for (let i = free.length - 1; i >= 0; --i) {
|
|
931
|
-
const buffer = free[i];
|
|
932
|
-
if (buffer.length >= size) {
|
|
933
|
-
free[i] = free[free.length - 1];
|
|
934
|
-
free.pop();
|
|
935
|
-
borrowed.push(buffer);
|
|
936
|
-
return buffer;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
return null;
|
|
940
|
-
};
|
|
941
|
-
var scratchInt32 = (size) => {
|
|
942
|
-
const pooled = acquire(freeInt32, borrowedInt32, size);
|
|
943
|
-
if (pooled !== null) return pooled.subarray(0, size);
|
|
944
|
-
const fresh = new Int32Array(size);
|
|
945
|
-
borrowedInt32.push(fresh);
|
|
946
|
-
return fresh;
|
|
947
|
-
};
|
|
948
|
-
var scratchUint8Zeroed = (size) => {
|
|
949
|
-
const pooled = acquire(freeUint8, borrowedUint8, size);
|
|
950
|
-
if (pooled !== null) {
|
|
951
|
-
const view = pooled.subarray(0, size);
|
|
952
|
-
view.fill(0);
|
|
953
|
-
return view;
|
|
954
|
-
}
|
|
955
|
-
const fresh = new Uint8Array(size);
|
|
956
|
-
borrowedUint8.push(fresh);
|
|
957
|
-
return fresh;
|
|
958
|
-
};
|
|
959
|
-
var releaseScratch = () => {
|
|
960
|
-
for (const buffer of borrowedInt32) freeInt32.push(buffer);
|
|
961
|
-
for (const buffer of borrowedUint8) freeUint8.push(buffer);
|
|
962
|
-
borrowedInt32.length = 0;
|
|
963
|
-
borrowedUint8.length = 0;
|
|
964
|
-
};
|
|
965
|
-
|
|
966
1044
|
// src/decoder/compression/config/CompressionShared.ts
|
|
967
1045
|
var kDracoPointCloudBitstreamVersionMajor = 2;
|
|
968
1046
|
var kDracoPointCloudBitstreamVersionMinor = 3;
|
|
@@ -1194,82 +1272,705 @@ var MetadataDecoder = class {
|
|
|
1194
1272
|
}
|
|
1195
1273
|
};
|
|
1196
1274
|
|
|
1197
|
-
// src/decoder/compression/
|
|
1198
|
-
var
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1275
|
+
// src/decoder/compression/entropy/ANSCoding.ts
|
|
1276
|
+
var ANS_P8_PRECISION = 256;
|
|
1277
|
+
var ANS_L_BASE = 4096;
|
|
1278
|
+
var ANS_IO_BASE = 256;
|
|
1279
|
+
var COARSE_STREAM_FACTOR = 8;
|
|
1280
|
+
var COARSE_BUCKET_BITS = 8;
|
|
1281
|
+
function memGetLe16(buf, offset) {
|
|
1282
|
+
return buf[offset] | buf[offset + 1] << 8;
|
|
1283
|
+
}
|
|
1284
|
+
function memGetLe24(buf, offset) {
|
|
1285
|
+
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16;
|
|
1286
|
+
}
|
|
1287
|
+
function memGetLe32(buf, offset) {
|
|
1288
|
+
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16 | buf[offset + 3] << 24 >>> 0;
|
|
1289
|
+
}
|
|
1290
|
+
var AnsDecoder = class {
|
|
1291
|
+
buf;
|
|
1292
|
+
bufOffset;
|
|
1293
|
+
// First valid byte of this decoder's slice within buf: init is passed
|
|
1294
|
+
// absolute offsets into the source buffer to avoid a subarray allocation.
|
|
1295
|
+
bufStart;
|
|
1296
|
+
state;
|
|
1206
1297
|
constructor() {
|
|
1207
|
-
this.
|
|
1208
|
-
this.
|
|
1209
|
-
this.
|
|
1210
|
-
this.
|
|
1211
|
-
this._options = null;
|
|
1212
|
-
this._attributesDecoders = [];
|
|
1213
|
-
this._attributeToDecoderMap = [];
|
|
1298
|
+
this.buf = null;
|
|
1299
|
+
this.bufOffset = 0;
|
|
1300
|
+
this.bufStart = 0;
|
|
1301
|
+
this.state = 0;
|
|
1214
1302
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1303
|
+
};
|
|
1304
|
+
function ansReadInit(ans, buf, offset, base = 0) {
|
|
1305
|
+
if (offset - base < 1) {
|
|
1306
|
+
return 1;
|
|
1217
1307
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1308
|
+
ans.buf = buf;
|
|
1309
|
+
ans.bufStart = base;
|
|
1310
|
+
const x = buf[offset - 1] >> 6;
|
|
1311
|
+
if (x === 0) {
|
|
1312
|
+
ans.bufOffset = offset - 1;
|
|
1313
|
+
ans.state = buf[offset - 1] & 63;
|
|
1314
|
+
} else if (x === 1) {
|
|
1315
|
+
if (offset - base < 2) {
|
|
1316
|
+
return 1;
|
|
1224
1317
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1318
|
+
ans.bufOffset = offset - 2;
|
|
1319
|
+
ans.state = memGetLe16(buf, offset - 2) & 16383;
|
|
1320
|
+
} else if (x === 2) {
|
|
1321
|
+
if (offset - base < 3) {
|
|
1322
|
+
return 1;
|
|
1227
1323
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1324
|
+
ans.bufOffset = offset - 3;
|
|
1325
|
+
ans.state = memGetLe24(buf, offset - 3) & 4194303;
|
|
1326
|
+
} else {
|
|
1327
|
+
return 1;
|
|
1328
|
+
}
|
|
1329
|
+
ans.state += ANS_L_BASE;
|
|
1330
|
+
if (ans.state >= ANS_L_BASE * ANS_IO_BASE) {
|
|
1331
|
+
return 1;
|
|
1332
|
+
}
|
|
1333
|
+
return 0;
|
|
1334
|
+
}
|
|
1335
|
+
function ansReadEnd(ans) {
|
|
1336
|
+
return ans.state === ANS_L_BASE;
|
|
1337
|
+
}
|
|
1338
|
+
var tablePool = [];
|
|
1339
|
+
var acquirePooled = (Ctor, size) => {
|
|
1340
|
+
for (let i = tablePool.length - 1; i >= 0; --i) {
|
|
1341
|
+
const buf = tablePool[i];
|
|
1342
|
+
if (buf.constructor === Ctor && buf.length >= size) {
|
|
1343
|
+
tablePool[i] = tablePool[tablePool.length - 1];
|
|
1344
|
+
tablePool.pop();
|
|
1345
|
+
return buf;
|
|
1231
1346
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1347
|
+
}
|
|
1348
|
+
return new Ctor(size);
|
|
1349
|
+
};
|
|
1350
|
+
var RAnsDecoder = class {
|
|
1351
|
+
ransPrecisionBits;
|
|
1352
|
+
ransPrecision;
|
|
1353
|
+
ransPrecisionMask;
|
|
1354
|
+
lRansBase;
|
|
1355
|
+
lutTable;
|
|
1356
|
+
probTable;
|
|
1357
|
+
cumProbTable;
|
|
1358
|
+
// Short-stream mode (see ransBuildLookUpTable): no full-precision lut; a
|
|
1359
|
+
// 256-entry bucket table narrows each lookup to a symbol range that a short
|
|
1360
|
+
// cumProb scan finishes. cumProbTable then carries one extra trailing entry
|
|
1361
|
+
// (== ransPrecision) so the scan needs no bounds check.
|
|
1362
|
+
coarse;
|
|
1363
|
+
bucketShift;
|
|
1364
|
+
bucketTable;
|
|
1365
|
+
buf;
|
|
1366
|
+
bufOffset;
|
|
1367
|
+
// First valid byte of this decoder's slice within buf (absolute offsets,
|
|
1368
|
+
// see AnsDecoder.bufStart).
|
|
1369
|
+
bufStart;
|
|
1370
|
+
state;
|
|
1371
|
+
constructor(ransPrecisionBits) {
|
|
1372
|
+
this.ransPrecisionBits = ransPrecisionBits;
|
|
1373
|
+
this.ransPrecision = 1 << ransPrecisionBits;
|
|
1374
|
+
this.ransPrecisionMask = this.ransPrecision - 1;
|
|
1375
|
+
this.lRansBase = this.ransPrecision * 4;
|
|
1376
|
+
this.lutTable = null;
|
|
1377
|
+
this.probTable = null;
|
|
1378
|
+
this.cumProbTable = null;
|
|
1379
|
+
this.coarse = false;
|
|
1380
|
+
this.bucketShift = 0;
|
|
1381
|
+
this.bucketTable = null;
|
|
1382
|
+
this.buf = null;
|
|
1383
|
+
this.bufOffset = 0;
|
|
1384
|
+
this.bufStart = 0;
|
|
1385
|
+
this.state = 0;
|
|
1386
|
+
}
|
|
1387
|
+
// offset is the absolute end of the encoded bytes within buf and base the
|
|
1388
|
+
// absolute start (offset - base = encoded length). Passing the source
|
|
1389
|
+
// buffer with absolute offsets avoids a subarray allocation per init.
|
|
1390
|
+
// Returns 0 on success, non-zero on error.
|
|
1391
|
+
readInit(buf, offset, base = 0) {
|
|
1392
|
+
if (offset - base < 1) {
|
|
1393
|
+
return 1;
|
|
1235
1394
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1395
|
+
this.buf = buf;
|
|
1396
|
+
this.bufStart = base;
|
|
1397
|
+
const x = buf[offset - 1] >> 6;
|
|
1398
|
+
if (x === 0) {
|
|
1399
|
+
this.bufOffset = offset - 1;
|
|
1400
|
+
this.state = buf[offset - 1] & 63;
|
|
1401
|
+
} else if (x === 1) {
|
|
1402
|
+
if (offset - base < 2) {
|
|
1403
|
+
return 1;
|
|
1404
|
+
}
|
|
1405
|
+
this.bufOffset = offset - 2;
|
|
1406
|
+
this.state = memGetLe16(buf, offset - 2) & 16383;
|
|
1407
|
+
} else if (x === 2) {
|
|
1408
|
+
if (offset - base < 3) {
|
|
1409
|
+
return 1;
|
|
1410
|
+
}
|
|
1411
|
+
this.bufOffset = offset - 3;
|
|
1412
|
+
this.state = memGetLe24(buf, offset - 3) & 4194303;
|
|
1413
|
+
} else if (x === 3) {
|
|
1414
|
+
if (offset - base < 4) {
|
|
1415
|
+
return 1;
|
|
1416
|
+
}
|
|
1417
|
+
this.bufOffset = offset - 4;
|
|
1418
|
+
this.state = memGetLe32(buf, offset - 4) & 1073741823;
|
|
1419
|
+
} else {
|
|
1420
|
+
return 1;
|
|
1240
1421
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1422
|
+
this.state += this.lRansBase;
|
|
1423
|
+
if (this.state >= this.lRansBase * ANS_IO_BASE) {
|
|
1424
|
+
return 1;
|
|
1245
1425
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1426
|
+
return 0;
|
|
1427
|
+
}
|
|
1428
|
+
readEnd() {
|
|
1429
|
+
if (this.lutTable !== null) {
|
|
1430
|
+
tablePool.push(this.lutTable);
|
|
1431
|
+
this.lutTable = null;
|
|
1250
1432
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1433
|
+
if (this.probTable !== null) {
|
|
1434
|
+
tablePool.push(this.probTable);
|
|
1435
|
+
this.probTable = null;
|
|
1255
1436
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
// Main entry point for point cloud decoding.
|
|
1260
|
-
decode(options, inBuffer, outPointCloud) {
|
|
1261
|
-
this._options = options;
|
|
1262
|
-
this._buffer = inBuffer;
|
|
1263
|
-
this._pointCloud = outPointCloud;
|
|
1264
|
-
const header = new DracoHeader();
|
|
1265
|
-
const headerStatus = _PointCloudDecoder.decodeHeader(this._buffer, header);
|
|
1266
|
-
if (!headerStatus.ok()) {
|
|
1267
|
-
return headerStatus;
|
|
1437
|
+
if (this.cumProbTable !== null) {
|
|
1438
|
+
tablePool.push(this.cumProbTable);
|
|
1439
|
+
this.cumProbTable = null;
|
|
1268
1440
|
}
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1441
|
+
if (this.bucketTable !== null) {
|
|
1442
|
+
tablePool.push(this.bucketTable);
|
|
1443
|
+
this.bucketTable = null;
|
|
1271
1444
|
}
|
|
1272
|
-
this.
|
|
1445
|
+
return this.state === this.lRansBase;
|
|
1446
|
+
}
|
|
1447
|
+
ransRead() {
|
|
1448
|
+
const buf = this.buf;
|
|
1449
|
+
const lRansBase = this.lRansBase;
|
|
1450
|
+
let state = this.state;
|
|
1451
|
+
let bufOffset = this.bufOffset;
|
|
1452
|
+
const bufStart = this.bufStart;
|
|
1453
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
1454
|
+
state = state << 8 | buf[--bufOffset];
|
|
1455
|
+
}
|
|
1456
|
+
const quo = state >>> this.ransPrecisionBits;
|
|
1457
|
+
const rem = state & this.ransPrecisionMask;
|
|
1458
|
+
let symbol;
|
|
1459
|
+
if (this.coarse) {
|
|
1460
|
+
const cumProbTable = this.cumProbTable;
|
|
1461
|
+
symbol = this.bucketTable[rem >> this.bucketShift];
|
|
1462
|
+
while (cumProbTable[symbol + 1] <= rem) symbol++;
|
|
1463
|
+
} else {
|
|
1464
|
+
symbol = this.lutTable[rem];
|
|
1465
|
+
}
|
|
1466
|
+
this.state = quo * this.probTable[symbol] + rem - this.cumProbTable[symbol];
|
|
1467
|
+
this.bufOffset = bufOffset;
|
|
1468
|
+
return symbol;
|
|
1469
|
+
}
|
|
1470
|
+
// Batch ransRead() into out[0..count): all fields hoisted to locals, state
|
|
1471
|
+
// written back once. Removes per-symbol property reads and call indirection.
|
|
1472
|
+
// lutTable's element type varies per decoder (Uint8/16/32 by symbol count),
|
|
1473
|
+
// which would make the hot lutTable[rem] access site polymorphic — dispatch
|
|
1474
|
+
// once here so each loop body stays monomorphic on its concrete type. The
|
|
1475
|
+
// three bodies are intentionally identical copies.
|
|
1476
|
+
decodeSymbols(out, count) {
|
|
1477
|
+
if (this.coarse) {
|
|
1478
|
+
this._decodeSymbolsCoarse(out, count);
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
const lutTable = this.lutTable;
|
|
1482
|
+
if (lutTable instanceof Uint8Array) {
|
|
1483
|
+
this._decodeSymbolsU8(out, count, lutTable);
|
|
1484
|
+
} else if (lutTable instanceof Uint16Array) {
|
|
1485
|
+
this._decodeSymbolsU16(out, count, lutTable);
|
|
1486
|
+
} else {
|
|
1487
|
+
this._decodeSymbolsU32(out, count, lutTable);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
_decodeSymbolsU8(out, count, lutTable) {
|
|
1491
|
+
const buf = this.buf;
|
|
1492
|
+
const lRansBase = this.lRansBase;
|
|
1493
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
1494
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
1495
|
+
const probTable = this.probTable;
|
|
1496
|
+
const cumProbTable = this.cumProbTable;
|
|
1497
|
+
let state = this.state;
|
|
1498
|
+
let bufOffset = this.bufOffset;
|
|
1499
|
+
const bufStart = this.bufStart;
|
|
1500
|
+
for (let i = 0; i < count; ++i) {
|
|
1501
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
1502
|
+
state = state << 8 | buf[--bufOffset];
|
|
1503
|
+
}
|
|
1504
|
+
const rem = state & ransPrecisionMask;
|
|
1505
|
+
const symbol = lutTable[rem];
|
|
1506
|
+
out[i] = symbol;
|
|
1507
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
1508
|
+
}
|
|
1509
|
+
this.state = state;
|
|
1510
|
+
this.bufOffset = bufOffset;
|
|
1511
|
+
}
|
|
1512
|
+
_decodeSymbolsU16(out, count, lutTable) {
|
|
1513
|
+
const buf = this.buf;
|
|
1514
|
+
const lRansBase = this.lRansBase;
|
|
1515
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
1516
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
1517
|
+
const probTable = this.probTable;
|
|
1518
|
+
const cumProbTable = this.cumProbTable;
|
|
1519
|
+
let state = this.state;
|
|
1520
|
+
let bufOffset = this.bufOffset;
|
|
1521
|
+
const bufStart = this.bufStart;
|
|
1522
|
+
for (let i = 0; i < count; ++i) {
|
|
1523
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
1524
|
+
state = state << 8 | buf[--bufOffset];
|
|
1525
|
+
}
|
|
1526
|
+
const rem = state & ransPrecisionMask;
|
|
1527
|
+
const symbol = lutTable[rem];
|
|
1528
|
+
out[i] = symbol;
|
|
1529
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
1530
|
+
}
|
|
1531
|
+
this.state = state;
|
|
1532
|
+
this.bufOffset = bufOffset;
|
|
1533
|
+
}
|
|
1534
|
+
// Short-stream loop: bucket table + cumProb scan instead of the full lut.
|
|
1535
|
+
// Same state arithmetic as the lut loops, so the output is identical.
|
|
1536
|
+
_decodeSymbolsCoarse(out, count) {
|
|
1537
|
+
const buf = this.buf;
|
|
1538
|
+
const lRansBase = this.lRansBase;
|
|
1539
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
1540
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
1541
|
+
const probTable = this.probTable;
|
|
1542
|
+
const cumProbTable = this.cumProbTable;
|
|
1543
|
+
const bucketTable = this.bucketTable;
|
|
1544
|
+
const bucketShift = this.bucketShift;
|
|
1545
|
+
let state = this.state;
|
|
1546
|
+
let bufOffset = this.bufOffset;
|
|
1547
|
+
const bufStart = this.bufStart;
|
|
1548
|
+
for (let i = 0; i < count; ++i) {
|
|
1549
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
1550
|
+
state = state << 8 | buf[--bufOffset];
|
|
1551
|
+
}
|
|
1552
|
+
const rem = state & ransPrecisionMask;
|
|
1553
|
+
let symbol = bucketTable[rem >> bucketShift];
|
|
1554
|
+
while (cumProbTable[symbol + 1] <= rem) symbol++;
|
|
1555
|
+
out[i] = symbol;
|
|
1556
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
1557
|
+
}
|
|
1558
|
+
this.state = state;
|
|
1559
|
+
this.bufOffset = bufOffset;
|
|
1560
|
+
}
|
|
1561
|
+
_decodeSymbolsU32(out, count, lutTable) {
|
|
1562
|
+
const buf = this.buf;
|
|
1563
|
+
const lRansBase = this.lRansBase;
|
|
1564
|
+
const ransPrecisionBits = this.ransPrecisionBits;
|
|
1565
|
+
const ransPrecisionMask = this.ransPrecisionMask;
|
|
1566
|
+
const probTable = this.probTable;
|
|
1567
|
+
const cumProbTable = this.cumProbTable;
|
|
1568
|
+
let state = this.state;
|
|
1569
|
+
let bufOffset = this.bufOffset;
|
|
1570
|
+
const bufStart = this.bufStart;
|
|
1571
|
+
for (let i = 0; i < count; ++i) {
|
|
1572
|
+
while (state < lRansBase && bufOffset > bufStart) {
|
|
1573
|
+
state = state << 8 | buf[--bufOffset];
|
|
1574
|
+
}
|
|
1575
|
+
const rem = state & ransPrecisionMask;
|
|
1576
|
+
const symbol = lutTable[rem];
|
|
1577
|
+
out[i] = symbol;
|
|
1578
|
+
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
1579
|
+
}
|
|
1580
|
+
this.state = state;
|
|
1581
|
+
this.bufOffset = bufOffset;
|
|
1582
|
+
}
|
|
1583
|
+
// Builds the decoding tables. Returns false on bad input data.
|
|
1584
|
+
//
|
|
1585
|
+
// expectedCount is how many symbols the caller will decode from this stream.
|
|
1586
|
+
// The full lut has ransPrecision (>= 4096) entries, and a primitive-heavy
|
|
1587
|
+
// file builds thousands of them to decode a few dozen symbols each -- on such
|
|
1588
|
+
// files the table builds cost more than the decodes. Short streams therefore
|
|
1589
|
+
// get a coarse 256-entry bucket table (symbol at the start of each
|
|
1590
|
+
// precision/256-wide bucket) and finish each lookup with a scan of the
|
|
1591
|
+
// cumulative probabilities; long streams keep the exact lut, whose per-symbol
|
|
1592
|
+
// cost is lower.
|
|
1593
|
+
ransBuildLookUpTable(tokenProbs, numSymbols, expectedCount = 2147483647) {
|
|
1594
|
+
const ransPrecision = this.ransPrecision;
|
|
1595
|
+
const coarse = numSymbols <= 65535 && expectedCount * COARSE_STREAM_FACTOR < ransPrecision;
|
|
1596
|
+
this.coarse = coarse;
|
|
1597
|
+
const probTable = acquirePooled(Uint32Array, numSymbols);
|
|
1598
|
+
const cumProbTable = acquirePooled(Uint32Array, numSymbols + 1);
|
|
1599
|
+
this.probTable = probTable;
|
|
1600
|
+
this.cumProbTable = cumProbTable;
|
|
1601
|
+
let cumProb = 0;
|
|
1602
|
+
if (coarse) {
|
|
1603
|
+
this.lutTable = null;
|
|
1604
|
+
for (let i = 0; i < numSymbols; ++i) {
|
|
1605
|
+
const prob = tokenProbs[i];
|
|
1606
|
+
probTable[i] = prob;
|
|
1607
|
+
cumProbTable[i] = cumProb;
|
|
1608
|
+
cumProb += prob;
|
|
1609
|
+
if (cumProb > ransPrecision) {
|
|
1610
|
+
return false;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
if (cumProb !== ransPrecision) {
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
cumProbTable[numSymbols] = ransPrecision;
|
|
1617
|
+
const bucketShift = this.ransPrecisionBits - COARSE_BUCKET_BITS;
|
|
1618
|
+
const bucketTable = acquirePooled(Uint16Array, 1 << COARSE_BUCKET_BITS);
|
|
1619
|
+
this.bucketShift = bucketShift;
|
|
1620
|
+
this.bucketTable = bucketTable;
|
|
1621
|
+
let symbol = 0;
|
|
1622
|
+
for (let b = 0; b < 1 << COARSE_BUCKET_BITS; ++b) {
|
|
1623
|
+
const rem = b << bucketShift;
|
|
1624
|
+
while (cumProbTable[symbol + 1] <= rem) symbol++;
|
|
1625
|
+
bucketTable[b] = symbol;
|
|
1626
|
+
}
|
|
1627
|
+
return true;
|
|
1628
|
+
}
|
|
1629
|
+
const LutArray = numSymbols <= 256 ? Uint8Array : numSymbols <= 65536 ? Uint16Array : Uint32Array;
|
|
1630
|
+
const lutTable = acquirePooled(LutArray, ransPrecision);
|
|
1631
|
+
this.lutTable = lutTable;
|
|
1632
|
+
let actProb = 0;
|
|
1633
|
+
for (let i = 0; i < numSymbols; ++i) {
|
|
1634
|
+
const prob = tokenProbs[i];
|
|
1635
|
+
probTable[i] = prob;
|
|
1636
|
+
cumProbTable[i] = cumProb;
|
|
1637
|
+
cumProb += prob;
|
|
1638
|
+
if (cumProb > ransPrecision) {
|
|
1639
|
+
return false;
|
|
1640
|
+
}
|
|
1641
|
+
if (prob < 32) {
|
|
1642
|
+
for (let j = actProb; j < cumProb; ++j) {
|
|
1643
|
+
lutTable[j] = i;
|
|
1644
|
+
}
|
|
1645
|
+
} else {
|
|
1646
|
+
lutTable.fill(i, actProb, cumProb);
|
|
1647
|
+
}
|
|
1648
|
+
actProb = cumProb;
|
|
1649
|
+
}
|
|
1650
|
+
if (cumProb !== ransPrecision) {
|
|
1651
|
+
return false;
|
|
1652
|
+
}
|
|
1653
|
+
cumProbTable[numSymbols] = ransPrecision;
|
|
1654
|
+
return true;
|
|
1655
|
+
}
|
|
1656
|
+
};
|
|
1657
|
+
function ransDecodeSymbolsPairU8(a, outA, countA, b, outB, countB) {
|
|
1658
|
+
const lutA = a.lutTable;
|
|
1659
|
+
const lutB = b.lutTable;
|
|
1660
|
+
const bufA = a.buf;
|
|
1661
|
+
const bufB = b.buf;
|
|
1662
|
+
const probA = a.probTable;
|
|
1663
|
+
const probB = b.probTable;
|
|
1664
|
+
const cumA = a.cumProbTable;
|
|
1665
|
+
const cumB = b.cumProbTable;
|
|
1666
|
+
const lBaseA = a.lRansBase;
|
|
1667
|
+
const lBaseB = b.lRansBase;
|
|
1668
|
+
const bitsA = a.ransPrecisionBits;
|
|
1669
|
+
const bitsB = b.ransPrecisionBits;
|
|
1670
|
+
const maskA = a.ransPrecisionMask;
|
|
1671
|
+
const maskB = b.ransPrecisionMask;
|
|
1672
|
+
const startA = a.bufStart;
|
|
1673
|
+
const startB = b.bufStart;
|
|
1674
|
+
let stateA = a.state;
|
|
1675
|
+
let stateB = b.state;
|
|
1676
|
+
let offA = a.bufOffset;
|
|
1677
|
+
let offB = b.bufOffset;
|
|
1678
|
+
const shared = countA < countB ? countA : countB;
|
|
1679
|
+
for (let i = 0; i < shared; ++i) {
|
|
1680
|
+
while (stateA < lBaseA && offA > startA) {
|
|
1681
|
+
stateA = stateA << 8 | bufA[--offA];
|
|
1682
|
+
}
|
|
1683
|
+
while (stateB < lBaseB && offB > startB) {
|
|
1684
|
+
stateB = stateB << 8 | bufB[--offB];
|
|
1685
|
+
}
|
|
1686
|
+
const remA = stateA & maskA;
|
|
1687
|
+
const remB = stateB & maskB;
|
|
1688
|
+
const symA = lutA[remA];
|
|
1689
|
+
const symB = lutB[remB];
|
|
1690
|
+
outA[i] = symA;
|
|
1691
|
+
outB[i] = symB;
|
|
1692
|
+
stateA = (stateA >>> bitsA) * probA[symA] + remA - cumA[symA];
|
|
1693
|
+
stateB = (stateB >>> bitsB) * probB[symB] + remB - cumB[symB];
|
|
1694
|
+
}
|
|
1695
|
+
a.state = stateA;
|
|
1696
|
+
a.bufOffset = offA;
|
|
1697
|
+
b.state = stateB;
|
|
1698
|
+
b.bufOffset = offB;
|
|
1699
|
+
if (shared < countA) {
|
|
1700
|
+
a.decodeSymbols(outA.subarray(shared), countA - shared);
|
|
1701
|
+
}
|
|
1702
|
+
if (shared < countB) {
|
|
1703
|
+
b.decodeSymbols(outB.subarray(shared), countB - shared);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
function ransDecodeSymbolsPair(a, outA, countA, b, outB, countB) {
|
|
1707
|
+
const lutA = a.lutTable;
|
|
1708
|
+
const lutB = b.lutTable;
|
|
1709
|
+
if (lutA instanceof Uint8Array && lutB instanceof Uint8Array) {
|
|
1710
|
+
ransDecodeSymbolsPairU8(a, outA, countA, b, outB, countB);
|
|
1711
|
+
} else if (lutA instanceof Uint16Array && lutB instanceof Uint16Array) {
|
|
1712
|
+
ransDecodeSymbolsPairU16(a, outA, countA, b, outB, countB);
|
|
1713
|
+
} else if (lutA instanceof Uint8Array && lutB instanceof Uint16Array) {
|
|
1714
|
+
ransDecodeSymbolsPairU8U16(a, outA, countA, b, outB, countB);
|
|
1715
|
+
} else if (lutA instanceof Uint16Array && lutB instanceof Uint8Array) {
|
|
1716
|
+
ransDecodeSymbolsPairU8U16(b, outB, countB, a, outA, countA);
|
|
1717
|
+
} else {
|
|
1718
|
+
a.decodeSymbols(outA, countA);
|
|
1719
|
+
b.decodeSymbols(outB, countB);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
function ransDecodeSymbolsPairU16(a, outA, countA, b, outB, countB) {
|
|
1723
|
+
const lutA = a.lutTable;
|
|
1724
|
+
const lutB = b.lutTable;
|
|
1725
|
+
const bufA = a.buf;
|
|
1726
|
+
const bufB = b.buf;
|
|
1727
|
+
const probA = a.probTable;
|
|
1728
|
+
const probB = b.probTable;
|
|
1729
|
+
const cumA = a.cumProbTable;
|
|
1730
|
+
const cumB = b.cumProbTable;
|
|
1731
|
+
const lBaseA = a.lRansBase;
|
|
1732
|
+
const lBaseB = b.lRansBase;
|
|
1733
|
+
const bitsA = a.ransPrecisionBits;
|
|
1734
|
+
const bitsB = b.ransPrecisionBits;
|
|
1735
|
+
const maskA = a.ransPrecisionMask;
|
|
1736
|
+
const maskB = b.ransPrecisionMask;
|
|
1737
|
+
const startA = a.bufStart;
|
|
1738
|
+
const startB = b.bufStart;
|
|
1739
|
+
let stateA = a.state;
|
|
1740
|
+
let stateB = b.state;
|
|
1741
|
+
let offA = a.bufOffset;
|
|
1742
|
+
let offB = b.bufOffset;
|
|
1743
|
+
const shared = countA < countB ? countA : countB;
|
|
1744
|
+
for (let i = 0; i < shared; ++i) {
|
|
1745
|
+
while (stateA < lBaseA && offA > startA) {
|
|
1746
|
+
stateA = stateA << 8 | bufA[--offA];
|
|
1747
|
+
}
|
|
1748
|
+
while (stateB < lBaseB && offB > startB) {
|
|
1749
|
+
stateB = stateB << 8 | bufB[--offB];
|
|
1750
|
+
}
|
|
1751
|
+
const remA = stateA & maskA;
|
|
1752
|
+
const remB = stateB & maskB;
|
|
1753
|
+
const symA = lutA[remA];
|
|
1754
|
+
const symB = lutB[remB];
|
|
1755
|
+
outA[i] = symA;
|
|
1756
|
+
outB[i] = symB;
|
|
1757
|
+
stateA = (stateA >>> bitsA) * probA[symA] + remA - cumA[symA];
|
|
1758
|
+
stateB = (stateB >>> bitsB) * probB[symB] + remB - cumB[symB];
|
|
1759
|
+
}
|
|
1760
|
+
a.state = stateA;
|
|
1761
|
+
a.bufOffset = offA;
|
|
1762
|
+
b.state = stateB;
|
|
1763
|
+
b.bufOffset = offB;
|
|
1764
|
+
if (shared < countA) {
|
|
1765
|
+
a.decodeSymbols(outA.subarray(shared), countA - shared);
|
|
1766
|
+
}
|
|
1767
|
+
if (shared < countB) {
|
|
1768
|
+
b.decodeSymbols(outB.subarray(shared), countB - shared);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function ransDecodeSymbolsPairU8U16(a, outA, countA, b, outB, countB) {
|
|
1772
|
+
const lutA = a.lutTable;
|
|
1773
|
+
const lutB = b.lutTable;
|
|
1774
|
+
const bufA = a.buf;
|
|
1775
|
+
const bufB = b.buf;
|
|
1776
|
+
const probA = a.probTable;
|
|
1777
|
+
const probB = b.probTable;
|
|
1778
|
+
const cumA = a.cumProbTable;
|
|
1779
|
+
const cumB = b.cumProbTable;
|
|
1780
|
+
const lBaseA = a.lRansBase;
|
|
1781
|
+
const lBaseB = b.lRansBase;
|
|
1782
|
+
const bitsA = a.ransPrecisionBits;
|
|
1783
|
+
const bitsB = b.ransPrecisionBits;
|
|
1784
|
+
const maskA = a.ransPrecisionMask;
|
|
1785
|
+
const maskB = b.ransPrecisionMask;
|
|
1786
|
+
const startA = a.bufStart;
|
|
1787
|
+
const startB = b.bufStart;
|
|
1788
|
+
let stateA = a.state;
|
|
1789
|
+
let stateB = b.state;
|
|
1790
|
+
let offA = a.bufOffset;
|
|
1791
|
+
let offB = b.bufOffset;
|
|
1792
|
+
const shared = countA < countB ? countA : countB;
|
|
1793
|
+
for (let i = 0; i < shared; ++i) {
|
|
1794
|
+
while (stateA < lBaseA && offA > startA) {
|
|
1795
|
+
stateA = stateA << 8 | bufA[--offA];
|
|
1796
|
+
}
|
|
1797
|
+
while (stateB < lBaseB && offB > startB) {
|
|
1798
|
+
stateB = stateB << 8 | bufB[--offB];
|
|
1799
|
+
}
|
|
1800
|
+
const remA = stateA & maskA;
|
|
1801
|
+
const remB = stateB & maskB;
|
|
1802
|
+
const symA = lutA[remA];
|
|
1803
|
+
const symB = lutB[remB];
|
|
1804
|
+
outA[i] = symA;
|
|
1805
|
+
outB[i] = symB;
|
|
1806
|
+
stateA = (stateA >>> bitsA) * probA[symA] + remA - cumA[symA];
|
|
1807
|
+
stateB = (stateB >>> bitsB) * probB[symB] + remB - cumB[symB];
|
|
1808
|
+
}
|
|
1809
|
+
a.state = stateA;
|
|
1810
|
+
a.bufOffset = offA;
|
|
1811
|
+
b.state = stateB;
|
|
1812
|
+
b.bufOffset = offB;
|
|
1813
|
+
if (shared < countA) {
|
|
1814
|
+
a.decodeSymbols(outA.subarray(shared), countA - shared);
|
|
1815
|
+
}
|
|
1816
|
+
if (shared < countB) {
|
|
1817
|
+
b.decodeSymbols(outB.subarray(shared), countB - shared);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
function ransDecodeSymbolsTrioU8(a, outA, countA, b, outB, countB, c, outC, countC) {
|
|
1821
|
+
const lutA = a.lutTable;
|
|
1822
|
+
const lutB = b.lutTable;
|
|
1823
|
+
const lutC = c.lutTable;
|
|
1824
|
+
const bufA = a.buf;
|
|
1825
|
+
const bufB = b.buf;
|
|
1826
|
+
const bufC = c.buf;
|
|
1827
|
+
const probA = a.probTable;
|
|
1828
|
+
const probB = b.probTable;
|
|
1829
|
+
const probC = c.probTable;
|
|
1830
|
+
const cumA = a.cumProbTable;
|
|
1831
|
+
const cumB = b.cumProbTable;
|
|
1832
|
+
const cumC = c.cumProbTable;
|
|
1833
|
+
const lBaseA = a.lRansBase;
|
|
1834
|
+
const lBaseB = b.lRansBase;
|
|
1835
|
+
const lBaseC = c.lRansBase;
|
|
1836
|
+
const bitsA = a.ransPrecisionBits;
|
|
1837
|
+
const bitsB = b.ransPrecisionBits;
|
|
1838
|
+
const bitsC = c.ransPrecisionBits;
|
|
1839
|
+
const maskA = a.ransPrecisionMask;
|
|
1840
|
+
const maskB = b.ransPrecisionMask;
|
|
1841
|
+
const maskC = c.ransPrecisionMask;
|
|
1842
|
+
const startA = a.bufStart;
|
|
1843
|
+
const startB = b.bufStart;
|
|
1844
|
+
const startC = c.bufStart;
|
|
1845
|
+
let stateA = a.state;
|
|
1846
|
+
let stateB = b.state;
|
|
1847
|
+
let stateC = c.state;
|
|
1848
|
+
let offA = a.bufOffset;
|
|
1849
|
+
let offB = b.bufOffset;
|
|
1850
|
+
let offC = c.bufOffset;
|
|
1851
|
+
let shared = countA < countB ? countA : countB;
|
|
1852
|
+
if (countC < shared) shared = countC;
|
|
1853
|
+
for (let i = 0; i < shared; ++i) {
|
|
1854
|
+
while (stateA < lBaseA && offA > startA) {
|
|
1855
|
+
stateA = stateA << 8 | bufA[--offA];
|
|
1856
|
+
}
|
|
1857
|
+
while (stateB < lBaseB && offB > startB) {
|
|
1858
|
+
stateB = stateB << 8 | bufB[--offB];
|
|
1859
|
+
}
|
|
1860
|
+
while (stateC < lBaseC && offC > startC) {
|
|
1861
|
+
stateC = stateC << 8 | bufC[--offC];
|
|
1862
|
+
}
|
|
1863
|
+
const remA = stateA & maskA;
|
|
1864
|
+
const remB = stateB & maskB;
|
|
1865
|
+
const remC = stateC & maskC;
|
|
1866
|
+
const symA = lutA[remA];
|
|
1867
|
+
const symB = lutB[remB];
|
|
1868
|
+
const symC = lutC[remC];
|
|
1869
|
+
outA[i] = symA;
|
|
1870
|
+
outB[i] = symB;
|
|
1871
|
+
outC[i] = symC;
|
|
1872
|
+
stateA = (stateA >>> bitsA) * probA[symA] + remA - cumA[symA];
|
|
1873
|
+
stateB = (stateB >>> bitsB) * probB[symB] + remB - cumB[symB];
|
|
1874
|
+
stateC = (stateC >>> bitsC) * probC[symC] + remC - cumC[symC];
|
|
1875
|
+
}
|
|
1876
|
+
a.state = stateA;
|
|
1877
|
+
a.bufOffset = offA;
|
|
1878
|
+
b.state = stateB;
|
|
1879
|
+
b.bufOffset = offB;
|
|
1880
|
+
c.state = stateC;
|
|
1881
|
+
c.bufOffset = offC;
|
|
1882
|
+
const restA = countA - shared;
|
|
1883
|
+
const restB = countB - shared;
|
|
1884
|
+
const restC = countC - shared;
|
|
1885
|
+
const tails = [];
|
|
1886
|
+
if (restA > 0) tails.push([a, outA.subarray(shared), restA]);
|
|
1887
|
+
if (restB > 0) tails.push([b, outB.subarray(shared), restB]);
|
|
1888
|
+
if (restC > 0) tails.push([c, outC.subarray(shared), restC]);
|
|
1889
|
+
if (tails.length === 2) {
|
|
1890
|
+
ransDecodeSymbolsPairU8(tails[0][0], tails[0][1], tails[0][2], tails[1][0], tails[1][1], tails[1][2]);
|
|
1891
|
+
} else {
|
|
1892
|
+
for (const [decoder, out, count] of tails) {
|
|
1893
|
+
decoder.decodeSymbols(out, count);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// src/decoder/compression/point_cloud/PointCloudDecoder.ts
|
|
1899
|
+
var PointCloudDecoder = class _PointCloudDecoder {
|
|
1900
|
+
_pointCloud;
|
|
1901
|
+
_buffer;
|
|
1902
|
+
_versionMajor;
|
|
1903
|
+
_versionMinor;
|
|
1904
|
+
_options;
|
|
1905
|
+
_attributesDecoders;
|
|
1906
|
+
_attributeToDecoderMap;
|
|
1907
|
+
constructor() {
|
|
1908
|
+
this._pointCloud = null;
|
|
1909
|
+
this._buffer = null;
|
|
1910
|
+
this._versionMajor = 0;
|
|
1911
|
+
this._versionMinor = 0;
|
|
1912
|
+
this._options = null;
|
|
1913
|
+
this._attributesDecoders = [];
|
|
1914
|
+
this._attributeToDecoderMap = [];
|
|
1915
|
+
}
|
|
1916
|
+
getGeometryType() {
|
|
1917
|
+
return EncodedGeometryType.POINT_CLOUD;
|
|
1918
|
+
}
|
|
1919
|
+
// Returns a Status; on success outHeader is populated.
|
|
1920
|
+
static decodeHeader(buffer, outHeader) {
|
|
1921
|
+
const kIoErrorMsg = "Failed to parse Draco header.";
|
|
1922
|
+
const bytes = buffer.decodeBytes(5);
|
|
1923
|
+
if (bytes === void 0) {
|
|
1924
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1925
|
+
}
|
|
1926
|
+
for (let i = 0; i < 5; i++) {
|
|
1927
|
+
outHeader.dracoString[i] = bytes[i];
|
|
1928
|
+
}
|
|
1929
|
+
const magic = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]);
|
|
1930
|
+
if (magic !== "DRACO") {
|
|
1931
|
+
return new Status(StatusCode.DRACO_ERROR, "Not a Draco file.");
|
|
1932
|
+
}
|
|
1933
|
+
const versionMajor = buffer.decodeUint8();
|
|
1934
|
+
if (versionMajor === void 0) {
|
|
1935
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1936
|
+
}
|
|
1937
|
+
outHeader.versionMajor = versionMajor;
|
|
1938
|
+
const versionMinor = buffer.decodeUint8();
|
|
1939
|
+
if (versionMinor === void 0) {
|
|
1940
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1941
|
+
}
|
|
1942
|
+
outHeader.versionMinor = versionMinor;
|
|
1943
|
+
const encoderType = buffer.decodeUint8();
|
|
1944
|
+
if (encoderType === void 0) {
|
|
1945
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1946
|
+
}
|
|
1947
|
+
outHeader.encoderType = encoderType;
|
|
1948
|
+
const encoderMethod = buffer.decodeUint8();
|
|
1949
|
+
if (encoderMethod === void 0) {
|
|
1950
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1951
|
+
}
|
|
1952
|
+
outHeader.encoderMethod = encoderMethod;
|
|
1953
|
+
const flags = buffer.decodeUint16();
|
|
1954
|
+
if (flags === void 0) {
|
|
1955
|
+
return new Status(StatusCode.IO_ERROR, kIoErrorMsg);
|
|
1956
|
+
}
|
|
1957
|
+
outHeader.flags = flags;
|
|
1958
|
+
return okStatus();
|
|
1959
|
+
}
|
|
1960
|
+
// Main entry point for point cloud decoding.
|
|
1961
|
+
decode(options, inBuffer, outPointCloud) {
|
|
1962
|
+
this._options = options;
|
|
1963
|
+
this._buffer = inBuffer;
|
|
1964
|
+
this._pointCloud = outPointCloud;
|
|
1965
|
+
const header = new DracoHeader();
|
|
1966
|
+
const headerStatus = _PointCloudDecoder.decodeHeader(this._buffer, header);
|
|
1967
|
+
if (!headerStatus.ok()) {
|
|
1968
|
+
return headerStatus;
|
|
1969
|
+
}
|
|
1970
|
+
if (header.encoderType !== this.getGeometryType()) {
|
|
1971
|
+
return new Status(StatusCode.DRACO_ERROR, "Using incompatible decoder for the input geometry.");
|
|
1972
|
+
}
|
|
1973
|
+
this._versionMajor = header.versionMajor;
|
|
1273
1974
|
this._versionMinor = header.versionMinor;
|
|
1274
1975
|
const maxSupportedMajorVersion = header.encoderType === EncodedGeometryType.POINT_CLOUD ? kDracoPointCloudBitstreamVersionMajor : kDracoMeshBitstreamVersionMajor;
|
|
1275
1976
|
const maxSupportedMinorVersion = header.encoderType === EncodedGeometryType.POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor : kDracoMeshBitstreamVersionMinor;
|
|
@@ -1388,17 +2089,40 @@ var PointCloudDecoder = class _PointCloudDecoder {
|
|
|
1388
2089
|
return true;
|
|
1389
2090
|
}
|
|
1390
2091
|
decodeAllAttributes() {
|
|
1391
|
-
|
|
1392
|
-
|
|
2092
|
+
const decoders = this._attributesDecoders;
|
|
2093
|
+
for (let i2 = 0; i2 < decoders.length; i2++) {
|
|
2094
|
+
if (!decoders[i2].decodeAttributesParse(this._buffer)) {
|
|
1393
2095
|
return false;
|
|
1394
2096
|
}
|
|
1395
2097
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
2098
|
+
const pending = [];
|
|
2099
|
+
for (let i2 = 0; i2 < decoders.length; i2++) {
|
|
2100
|
+
decoders[i2].collectPendingSymbolStreams(pending);
|
|
2101
|
+
}
|
|
2102
|
+
const paired = pending.filter((stream) => !stream.ans.coarse);
|
|
2103
|
+
let i = 0;
|
|
2104
|
+
for (; i + 1 < paired.length; i += 2) {
|
|
2105
|
+
const a = paired[i];
|
|
2106
|
+
const b = paired[i + 1];
|
|
2107
|
+
ransDecodeSymbolsPair(a.ans, a.out, a.count, b.ans, b.out, b.count);
|
|
2108
|
+
}
|
|
2109
|
+
if (i < paired.length) {
|
|
2110
|
+
paired[i].ans.decodeSymbols(paired[i].out, paired[i].count);
|
|
2111
|
+
}
|
|
2112
|
+
for (const stream of pending) {
|
|
2113
|
+
if (stream.ans.coarse) stream.ans.decodeSymbols(stream.out, stream.count);
|
|
2114
|
+
}
|
|
2115
|
+
for (let k = 0; k < decoders.length; k++) {
|
|
2116
|
+
if (!decoders[k].decodeAttributesFinish()) {
|
|
2117
|
+
return false;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
return true;
|
|
2121
|
+
}
|
|
2122
|
+
onAttributesDecoded() {
|
|
2123
|
+
return true;
|
|
2124
|
+
}
|
|
2125
|
+
_decodeMetadata() {
|
|
1402
2126
|
const metadataDecoder = new MetadataDecoder();
|
|
1403
2127
|
if (!metadataDecoder.skipGeometryMetadata(this._buffer)) {
|
|
1404
2128
|
return new Status(StatusCode.DRACO_ERROR, "Failed to decode metadata.");
|
|
@@ -1457,46 +2181,62 @@ var MeshAttributeCornerTable = class {
|
|
|
1457
2181
|
no_interior_seams_;
|
|
1458
2182
|
corner_to_vertex_map_;
|
|
1459
2183
|
vertex_to_left_most_corner_map_;
|
|
1460
|
-
|
|
2184
|
+
// Attribute-vertex count. C++ keeps a vertex -> attribute-entry map here, but
|
|
2185
|
+
// the decoder only ever reads its size, so track the count directly instead
|
|
2186
|
+
// of allocating an Int32Array per attribute corner table.
|
|
2187
|
+
num_attribute_vertices_;
|
|
1461
2188
|
corner_table_;
|
|
1462
2189
|
// Lazily built; see oppositeCornerArray.
|
|
1463
2190
|
_effectiveOpposite;
|
|
1464
2191
|
// Every corner passed to addSeamEdge (may contain duplicates); lets
|
|
1465
2192
|
// oppositeCornerArray patch seams without scanning every corner's flag.
|
|
2193
|
+
// Preallocated to its exact upper bound (2 per seam edge) by the caller via
|
|
2194
|
+
// reserveSeamEdges -- a plain array grown by push() was measurable on
|
|
2195
|
+
// seam-heavy files.
|
|
1466
2196
|
_seamCorners;
|
|
2197
|
+
_numSeamCorners;
|
|
1467
2198
|
constructor() {
|
|
1468
2199
|
this.is_edge_on_seam_ = [];
|
|
1469
2200
|
this.is_vertex_on_seam_ = [];
|
|
1470
2201
|
this.no_interior_seams_ = true;
|
|
1471
2202
|
this.corner_to_vertex_map_ = [];
|
|
1472
2203
|
this.vertex_to_left_most_corner_map_ = [];
|
|
1473
|
-
this.
|
|
2204
|
+
this.num_attribute_vertices_ = 0;
|
|
1474
2205
|
this.corner_table_ = null;
|
|
1475
2206
|
this._effectiveOpposite = null;
|
|
1476
2207
|
this._seamCorners = [];
|
|
2208
|
+
this._numSeamCorners = 0;
|
|
1477
2209
|
}
|
|
1478
2210
|
initEmpty(table) {
|
|
1479
2211
|
if (table === null) {
|
|
1480
2212
|
return false;
|
|
1481
2213
|
}
|
|
1482
|
-
this.is_edge_on_seam_ =
|
|
1483
|
-
this.is_vertex_on_seam_ =
|
|
1484
|
-
this.corner_to_vertex_map_ =
|
|
1485
|
-
this.
|
|
2214
|
+
this.is_edge_on_seam_ = scratchUint8Zeroed(table.numCorners());
|
|
2215
|
+
this.is_vertex_on_seam_ = scratchUint8Zeroed(table.numVertices());
|
|
2216
|
+
this.corner_to_vertex_map_ = scratchInt32Filled(table.numCorners(), kInvalidVertexIndex);
|
|
2217
|
+
this.num_attribute_vertices_ = 0;
|
|
1486
2218
|
this.vertex_to_left_most_corner_map_ = [];
|
|
1487
2219
|
this._effectiveOpposite = null;
|
|
1488
2220
|
this._seamCorners = [];
|
|
2221
|
+
this._numSeamCorners = 0;
|
|
1489
2222
|
this.corner_table_ = table;
|
|
1490
2223
|
this.no_interior_seams_ = true;
|
|
1491
2224
|
return true;
|
|
1492
2225
|
}
|
|
2226
|
+
// Sizes the seam-corner list for numSeamEdges upcoming addSeamEdge calls
|
|
2227
|
+
// (each adds at most two corners). Decode-scoped scratch.
|
|
2228
|
+
reserveSeamEdges(numSeamEdges) {
|
|
2229
|
+
this._seamCorners = scratchInt32(numSeamEdges * 2);
|
|
2230
|
+
this._numSeamCorners = 0;
|
|
2231
|
+
}
|
|
1493
2232
|
addSeamEdge(c) {
|
|
1494
2233
|
const cornerToVertex = this.corner_table_.cornerToVertexArray();
|
|
1495
2234
|
const oppositeCorners = this.corner_table_.oppositeCornerArray();
|
|
1496
2235
|
const isEdge = this.is_edge_on_seam_;
|
|
1497
2236
|
const isVert = this.is_vertex_on_seam_;
|
|
2237
|
+
const seamCorners = this._seamCorners;
|
|
1498
2238
|
isEdge[c] = 1;
|
|
1499
|
-
this.
|
|
2239
|
+
seamCorners[this._numSeamCorners++] = c;
|
|
1500
2240
|
let rem = c - (c / 3 | 0) * 3;
|
|
1501
2241
|
isVert[cornerToVertex[rem === 2 ? c - 2 : c + 1]] = 1;
|
|
1502
2242
|
isVert[cornerToVertex[rem === 0 ? c + 2 : c - 1]] = 1;
|
|
@@ -1504,7 +2244,7 @@ var MeshAttributeCornerTable = class {
|
|
|
1504
2244
|
if (oppCorner !== kInvalidCornerIndex) {
|
|
1505
2245
|
this.no_interior_seams_ = false;
|
|
1506
2246
|
isEdge[oppCorner] = 1;
|
|
1507
|
-
this.
|
|
2247
|
+
seamCorners[this._numSeamCorners++] = oppCorner;
|
|
1508
2248
|
rem = oppCorner - (oppCorner / 3 | 0) * 3;
|
|
1509
2249
|
isVert[cornerToVertex[rem === 2 ? oppCorner - 2 : oppCorner + 1]] = 1;
|
|
1510
2250
|
isVert[cornerToVertex[rem === 0 ? oppCorner + 2 : oppCorner - 1]] = 1;
|
|
@@ -1519,12 +2259,12 @@ var MeshAttributeCornerTable = class {
|
|
|
1519
2259
|
const ct = this.corner_table_;
|
|
1520
2260
|
const numCorners = ct.numCorners();
|
|
1521
2261
|
const numBaseVertices = ct.numVertices();
|
|
1522
|
-
const leftMostMap =
|
|
2262
|
+
const leftMostMap = scratchInt32(numCorners);
|
|
1523
2263
|
const cornerToVertex = this.corner_to_vertex_map_;
|
|
1524
2264
|
const isVertexOnSeam = this.is_vertex_on_seam_;
|
|
1525
2265
|
const isEdgeOnSeam = this.is_edge_on_seam_;
|
|
1526
2266
|
const seamOpp = this.oppositeCornerArray();
|
|
1527
|
-
const
|
|
2267
|
+
const swingRight = ct.swingRightArray();
|
|
1528
2268
|
const vertexLeftmost = ct.vertexLeftmostCornerArray();
|
|
1529
2269
|
let numNewVertices = 0;
|
|
1530
2270
|
for (let v = 0; v < numBaseVertices; ++v) {
|
|
@@ -1534,14 +2274,10 @@ var MeshAttributeCornerTable = class {
|
|
|
1534
2274
|
const firstVertId = numNewVertices++;
|
|
1535
2275
|
leftMostMap[firstVertId] = c;
|
|
1536
2276
|
cornerToVertex[c] = firstVertId;
|
|
1537
|
-
let
|
|
1538
|
-
let bopp = baseOpp[pv];
|
|
1539
|
-
let actC = bopp < 0 ? kInvalidCornerIndex : bopp % 3 === 0 ? bopp + 2 : bopp - 1;
|
|
2277
|
+
let actC = swingRight[c];
|
|
1540
2278
|
while (actC !== kInvalidCornerIndex && actC !== c) {
|
|
1541
2279
|
cornerToVertex[actC] = firstVertId;
|
|
1542
|
-
|
|
1543
|
-
bopp = baseOpp[pv];
|
|
1544
|
-
actC = bopp < 0 ? kInvalidCornerIndex : bopp % 3 === 0 ? bopp + 2 : bopp - 1;
|
|
2280
|
+
actC = swingRight[actC];
|
|
1545
2281
|
}
|
|
1546
2282
|
} else {
|
|
1547
2283
|
let firstVertId = numNewVertices++;
|
|
@@ -1559,9 +2295,7 @@ var MeshAttributeCornerTable = class {
|
|
|
1559
2295
|
}
|
|
1560
2296
|
cornerToVertex[firstC] = firstVertId;
|
|
1561
2297
|
leftMostMap[firstVertId] = firstC;
|
|
1562
|
-
|
|
1563
|
-
let bopp = baseOpp[pv];
|
|
1564
|
-
actC = bopp < 0 ? kInvalidCornerIndex : bopp % 3 === 0 ? bopp + 2 : bopp - 1;
|
|
2298
|
+
actC = swingRight[firstC];
|
|
1565
2299
|
while (actC !== kInvalidCornerIndex && actC !== firstC) {
|
|
1566
2300
|
const nAct = actC % 3 === 2 ? actC - 2 : actC + 1;
|
|
1567
2301
|
if (isEdgeOnSeam[nAct]) {
|
|
@@ -1569,13 +2303,11 @@ var MeshAttributeCornerTable = class {
|
|
|
1569
2303
|
leftMostMap[firstVertId] = actC;
|
|
1570
2304
|
}
|
|
1571
2305
|
cornerToVertex[actC] = firstVertId;
|
|
1572
|
-
|
|
1573
|
-
bopp = baseOpp[pv];
|
|
1574
|
-
actC = bopp < 0 ? kInvalidCornerIndex : bopp % 3 === 0 ? bopp + 2 : bopp - 1;
|
|
2306
|
+
actC = swingRight[actC];
|
|
1575
2307
|
}
|
|
1576
2308
|
}
|
|
1577
2309
|
}
|
|
1578
|
-
this.
|
|
2310
|
+
this.num_attribute_vertices_ = numNewVertices;
|
|
1579
2311
|
this.vertex_to_left_most_corner_map_ = leftMostMap.subarray(0, numNewVertices);
|
|
1580
2312
|
return true;
|
|
1581
2313
|
}
|
|
@@ -1601,7 +2333,7 @@ var MeshAttributeCornerTable = class {
|
|
|
1601
2333
|
return this.next(this.opposite(this.next(corner)));
|
|
1602
2334
|
}
|
|
1603
2335
|
numVertices() {
|
|
1604
|
-
return this.
|
|
2336
|
+
return this.num_attribute_vertices_;
|
|
1605
2337
|
}
|
|
1606
2338
|
numFaces() {
|
|
1607
2339
|
return this.corner_table_.numFaces();
|
|
@@ -1629,12 +2361,13 @@ var MeshAttributeCornerTable = class {
|
|
|
1629
2361
|
const nc = this.corner_table_.numCorners();
|
|
1630
2362
|
const base = this.corner_table_.oppositeCornerArray();
|
|
1631
2363
|
const seamCorners = this._seamCorners;
|
|
1632
|
-
|
|
2364
|
+
const numSeamCorners = this._numSeamCorners;
|
|
2365
|
+
if (numSeamCorners === 0) {
|
|
1633
2366
|
this._effectiveOpposite = base;
|
|
1634
2367
|
} else {
|
|
1635
2368
|
const eff = scratchInt32(nc);
|
|
1636
2369
|
eff.set(base.length === nc ? base : base.subarray(0, nc));
|
|
1637
|
-
for (let i = 0
|
|
2370
|
+
for (let i = 0; i < numSeamCorners; ++i) {
|
|
1638
2371
|
eff[seamCorners[i]] = kInvalidCornerIndex;
|
|
1639
2372
|
}
|
|
1640
2373
|
this._effectiveOpposite = eff;
|
|
@@ -1649,23 +2382,20 @@ var MeshAttributeCornerTable = class {
|
|
|
1649
2382
|
vertexOnSeamArray() {
|
|
1650
2383
|
return this.is_vertex_on_seam_;
|
|
1651
2384
|
}
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
}
|
|
1660
|
-
return true;
|
|
1661
|
-
}
|
|
1662
|
-
adoptVertexRecompute(other) {
|
|
2385
|
+
// Takes over another table's state wholesale. Only valid when both tables
|
|
2386
|
+
// were built from the same corner table and the same seam edges, in which
|
|
2387
|
+
// case every one of these is identical and read-only from here on.
|
|
2388
|
+
adoptFrom(other) {
|
|
2389
|
+
this.corner_table_ = other.corner_table_;
|
|
2390
|
+
this.is_edge_on_seam_ = other.is_edge_on_seam_;
|
|
2391
|
+
this.is_vertex_on_seam_ = other.is_vertex_on_seam_;
|
|
1663
2392
|
this.corner_to_vertex_map_ = other.corner_to_vertex_map_;
|
|
1664
|
-
this.
|
|
2393
|
+
this.num_attribute_vertices_ = other.num_attribute_vertices_;
|
|
1665
2394
|
this.vertex_to_left_most_corner_map_ = other.vertex_to_left_most_corner_map_;
|
|
1666
2395
|
this.no_interior_seams_ = other.no_interior_seams_;
|
|
1667
2396
|
this._effectiveOpposite = other._effectiveOpposite;
|
|
1668
2397
|
this._seamCorners = other._seamCorners;
|
|
2398
|
+
this._numSeamCorners = other._numSeamCorners;
|
|
1669
2399
|
}
|
|
1670
2400
|
};
|
|
1671
2401
|
|
|
@@ -1679,6 +2409,21 @@ var AttributesDecoderInterface = class {
|
|
|
1679
2409
|
decodeAttributesDecoderData(_buffer) {
|
|
1680
2410
|
return false;
|
|
1681
2411
|
}
|
|
2412
|
+
// --- Optional two-phase decode across attributes decoders ---
|
|
2413
|
+
// PointCloudDecoder parses every decoder first (all buffer reads are
|
|
2414
|
+
// size-driven, so parsing runs ahead of the deferred rANS symbol decodes),
|
|
2415
|
+
// then decodes the collected streams two at a time, then finishes each
|
|
2416
|
+
// decoder in order (so parent attributes complete before dependents).
|
|
2417
|
+
// Defaults keep the original single-phase behavior for decoders that do not
|
|
2418
|
+
// split.
|
|
2419
|
+
decodeAttributesParse(buffer) {
|
|
2420
|
+
return this.decodeAttributes(buffer);
|
|
2421
|
+
}
|
|
2422
|
+
collectPendingSymbolStreams(_out) {
|
|
2423
|
+
}
|
|
2424
|
+
decodeAttributesFinish() {
|
|
2425
|
+
return true;
|
|
2426
|
+
}
|
|
1682
2427
|
decodeAttributes(_buffer) {
|
|
1683
2428
|
return false;
|
|
1684
2429
|
}
|
|
@@ -1825,6 +2570,22 @@ var SequentialAttributeDecoder = class {
|
|
|
1825
2570
|
this._attributeId = attributeId;
|
|
1826
2571
|
return true;
|
|
1827
2572
|
}
|
|
2573
|
+
// --- Optional two-phase decode ---
|
|
2574
|
+
// The controller calls Parse for every attribute first (headers, schemes,
|
|
2575
|
+
// prediction data -- all size-driven cursor movement), collects the pending
|
|
2576
|
+
// rANS symbol streams, decodes them in pairs (see ransDecodeSymbolsPair),
|
|
2577
|
+
// then calls Finish per attribute in order. Decoders without a deferrable
|
|
2578
|
+
// stream simply do the whole decode in Parse. Defaults preserve the
|
|
2579
|
+
// original single-phase behavior.
|
|
2580
|
+
decodePortableAttributeParse(pointIds, buffer) {
|
|
2581
|
+
return this.decodePortableAttribute(pointIds, buffer);
|
|
2582
|
+
}
|
|
2583
|
+
pendingSymbolStream() {
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
decodePortableAttributeFinish() {
|
|
2587
|
+
return true;
|
|
2588
|
+
}
|
|
1828
2589
|
decodePortableAttribute(pointIds, buffer) {
|
|
1829
2590
|
if (this._attribute.numComponents <= 0) {
|
|
1830
2591
|
return false;
|
|
@@ -1845,7 +2606,7 @@ var SequentialAttributeDecoder = class {
|
|
|
1845
2606
|
getPortableAttribute() {
|
|
1846
2607
|
if (!this._attribute.isMappingIdentity && this._portableAttribute && this._portableAttribute.isMappingIdentity) {
|
|
1847
2608
|
const size = this._attribute.indicesMapSize;
|
|
1848
|
-
this._portableAttribute.
|
|
2609
|
+
this._portableAttribute.setExplicitMappingScratch(size);
|
|
1849
2610
|
const src = this._attribute.indicesMap;
|
|
1850
2611
|
const dst = this._portableAttribute.indicesMap;
|
|
1851
2612
|
if (src.length === size) {
|
|
@@ -1890,300 +2651,11 @@ var SequentialAttributeDecoder = class {
|
|
|
1890
2651
|
this._attribute.buffer.write(0, valueData, totalSize);
|
|
1891
2652
|
return true;
|
|
1892
2653
|
}
|
|
1893
|
-
setPortableAttribute(att) {
|
|
1894
|
-
this._portableAttribute = att;
|
|
1895
|
-
}
|
|
1896
|
-
get portableAttribute() {
|
|
1897
|
-
return this._portableAttribute;
|
|
1898
|
-
}
|
|
1899
|
-
};
|
|
1900
|
-
|
|
1901
|
-
// src/decoder/compression/entropy/ANSCoding.ts
|
|
1902
|
-
var ANS_P8_PRECISION = 256;
|
|
1903
|
-
var ANS_L_BASE = 4096;
|
|
1904
|
-
var ANS_IO_BASE = 256;
|
|
1905
|
-
function memGetLe16(buf, offset) {
|
|
1906
|
-
return buf[offset] | buf[offset + 1] << 8;
|
|
1907
|
-
}
|
|
1908
|
-
function memGetLe24(buf, offset) {
|
|
1909
|
-
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16;
|
|
1910
|
-
}
|
|
1911
|
-
function memGetLe32(buf, offset) {
|
|
1912
|
-
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16 | buf[offset + 3] << 24 >>> 0;
|
|
1913
|
-
}
|
|
1914
|
-
var AnsDecoder = class {
|
|
1915
|
-
buf;
|
|
1916
|
-
bufOffset;
|
|
1917
|
-
// First valid byte of this decoder's slice within buf: init is passed
|
|
1918
|
-
// absolute offsets into the source buffer to avoid a subarray allocation.
|
|
1919
|
-
bufStart;
|
|
1920
|
-
state;
|
|
1921
|
-
constructor() {
|
|
1922
|
-
this.buf = null;
|
|
1923
|
-
this.bufOffset = 0;
|
|
1924
|
-
this.bufStart = 0;
|
|
1925
|
-
this.state = 0;
|
|
1926
|
-
}
|
|
1927
|
-
};
|
|
1928
|
-
function ansReadInit(ans, buf, offset, base = 0) {
|
|
1929
|
-
if (offset - base < 1) {
|
|
1930
|
-
return 1;
|
|
1931
|
-
}
|
|
1932
|
-
ans.buf = buf;
|
|
1933
|
-
ans.bufStart = base;
|
|
1934
|
-
const x = buf[offset - 1] >> 6;
|
|
1935
|
-
if (x === 0) {
|
|
1936
|
-
ans.bufOffset = offset - 1;
|
|
1937
|
-
ans.state = buf[offset - 1] & 63;
|
|
1938
|
-
} else if (x === 1) {
|
|
1939
|
-
if (offset - base < 2) {
|
|
1940
|
-
return 1;
|
|
1941
|
-
}
|
|
1942
|
-
ans.bufOffset = offset - 2;
|
|
1943
|
-
ans.state = memGetLe16(buf, offset - 2) & 16383;
|
|
1944
|
-
} else if (x === 2) {
|
|
1945
|
-
if (offset - base < 3) {
|
|
1946
|
-
return 1;
|
|
1947
|
-
}
|
|
1948
|
-
ans.bufOffset = offset - 3;
|
|
1949
|
-
ans.state = memGetLe24(buf, offset - 3) & 4194303;
|
|
1950
|
-
} else {
|
|
1951
|
-
return 1;
|
|
1952
|
-
}
|
|
1953
|
-
ans.state += ANS_L_BASE;
|
|
1954
|
-
if (ans.state >= ANS_L_BASE * ANS_IO_BASE) {
|
|
1955
|
-
return 1;
|
|
1956
|
-
}
|
|
1957
|
-
return 0;
|
|
1958
|
-
}
|
|
1959
|
-
function ansReadEnd(ans) {
|
|
1960
|
-
return ans.state === ANS_L_BASE;
|
|
1961
|
-
}
|
|
1962
|
-
var tablePool = [];
|
|
1963
|
-
var acquirePooled = (Ctor, size) => {
|
|
1964
|
-
for (let i = tablePool.length - 1; i >= 0; --i) {
|
|
1965
|
-
const buf = tablePool[i];
|
|
1966
|
-
if (buf.constructor === Ctor && buf.length >= size) {
|
|
1967
|
-
tablePool[i] = tablePool[tablePool.length - 1];
|
|
1968
|
-
tablePool.pop();
|
|
1969
|
-
return buf;
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
return new Ctor(size);
|
|
1973
|
-
};
|
|
1974
|
-
var RAnsDecoder = class {
|
|
1975
|
-
ransPrecisionBits;
|
|
1976
|
-
ransPrecision;
|
|
1977
|
-
ransPrecisionMask;
|
|
1978
|
-
lRansBase;
|
|
1979
|
-
lutTable;
|
|
1980
|
-
probTable;
|
|
1981
|
-
cumProbTable;
|
|
1982
|
-
buf;
|
|
1983
|
-
bufOffset;
|
|
1984
|
-
// First valid byte of this decoder's slice within buf (absolute offsets,
|
|
1985
|
-
// see AnsDecoder.bufStart).
|
|
1986
|
-
bufStart;
|
|
1987
|
-
state;
|
|
1988
|
-
constructor(ransPrecisionBits) {
|
|
1989
|
-
this.ransPrecisionBits = ransPrecisionBits;
|
|
1990
|
-
this.ransPrecision = 1 << ransPrecisionBits;
|
|
1991
|
-
this.ransPrecisionMask = this.ransPrecision - 1;
|
|
1992
|
-
this.lRansBase = this.ransPrecision * 4;
|
|
1993
|
-
this.lutTable = null;
|
|
1994
|
-
this.probTable = null;
|
|
1995
|
-
this.cumProbTable = null;
|
|
1996
|
-
this.buf = null;
|
|
1997
|
-
this.bufOffset = 0;
|
|
1998
|
-
this.bufStart = 0;
|
|
1999
|
-
this.state = 0;
|
|
2000
|
-
}
|
|
2001
|
-
// offset is the absolute end of the encoded bytes within buf and base the
|
|
2002
|
-
// absolute start (offset - base = encoded length). Passing the source
|
|
2003
|
-
// buffer with absolute offsets avoids a subarray allocation per init.
|
|
2004
|
-
// Returns 0 on success, non-zero on error.
|
|
2005
|
-
readInit(buf, offset, base = 0) {
|
|
2006
|
-
if (offset - base < 1) {
|
|
2007
|
-
return 1;
|
|
2008
|
-
}
|
|
2009
|
-
this.buf = buf;
|
|
2010
|
-
this.bufStart = base;
|
|
2011
|
-
const x = buf[offset - 1] >> 6;
|
|
2012
|
-
if (x === 0) {
|
|
2013
|
-
this.bufOffset = offset - 1;
|
|
2014
|
-
this.state = buf[offset - 1] & 63;
|
|
2015
|
-
} else if (x === 1) {
|
|
2016
|
-
if (offset - base < 2) {
|
|
2017
|
-
return 1;
|
|
2018
|
-
}
|
|
2019
|
-
this.bufOffset = offset - 2;
|
|
2020
|
-
this.state = memGetLe16(buf, offset - 2) & 16383;
|
|
2021
|
-
} else if (x === 2) {
|
|
2022
|
-
if (offset - base < 3) {
|
|
2023
|
-
return 1;
|
|
2024
|
-
}
|
|
2025
|
-
this.bufOffset = offset - 3;
|
|
2026
|
-
this.state = memGetLe24(buf, offset - 3) & 4194303;
|
|
2027
|
-
} else if (x === 3) {
|
|
2028
|
-
if (offset - base < 4) {
|
|
2029
|
-
return 1;
|
|
2030
|
-
}
|
|
2031
|
-
this.bufOffset = offset - 4;
|
|
2032
|
-
this.state = memGetLe32(buf, offset - 4) & 1073741823;
|
|
2033
|
-
} else {
|
|
2034
|
-
return 1;
|
|
2035
|
-
}
|
|
2036
|
-
this.state += this.lRansBase;
|
|
2037
|
-
if (this.state >= this.lRansBase * ANS_IO_BASE) {
|
|
2038
|
-
return 1;
|
|
2039
|
-
}
|
|
2040
|
-
return 0;
|
|
2041
|
-
}
|
|
2042
|
-
readEnd() {
|
|
2043
|
-
if (this.lutTable !== null) {
|
|
2044
|
-
tablePool.push(this.lutTable);
|
|
2045
|
-
this.lutTable = null;
|
|
2046
|
-
}
|
|
2047
|
-
if (this.probTable !== null) {
|
|
2048
|
-
tablePool.push(this.probTable);
|
|
2049
|
-
this.probTable = null;
|
|
2050
|
-
}
|
|
2051
|
-
if (this.cumProbTable !== null) {
|
|
2052
|
-
tablePool.push(this.cumProbTable);
|
|
2053
|
-
this.cumProbTable = null;
|
|
2054
|
-
}
|
|
2055
|
-
return this.state === this.lRansBase;
|
|
2056
|
-
}
|
|
2057
|
-
ransRead() {
|
|
2058
|
-
const buf = this.buf;
|
|
2059
|
-
const lRansBase = this.lRansBase;
|
|
2060
|
-
let state = this.state;
|
|
2061
|
-
let bufOffset = this.bufOffset;
|
|
2062
|
-
const bufStart = this.bufStart;
|
|
2063
|
-
while (state < lRansBase && bufOffset > bufStart) {
|
|
2064
|
-
state = state << 8 | buf[--bufOffset];
|
|
2065
|
-
}
|
|
2066
|
-
const quo = state >>> this.ransPrecisionBits;
|
|
2067
|
-
const rem = state & this.ransPrecisionMask;
|
|
2068
|
-
const symbol = this.lutTable[rem];
|
|
2069
|
-
this.state = quo * this.probTable[symbol] + rem - this.cumProbTable[symbol];
|
|
2070
|
-
this.bufOffset = bufOffset;
|
|
2071
|
-
return symbol;
|
|
2072
|
-
}
|
|
2073
|
-
// Batch ransRead() into out[0..count): all fields hoisted to locals, state
|
|
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.
|
|
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) {
|
|
2134
|
-
const buf = this.buf;
|
|
2135
|
-
const lRansBase = this.lRansBase;
|
|
2136
|
-
const ransPrecisionBits = this.ransPrecisionBits;
|
|
2137
|
-
const ransPrecisionMask = this.ransPrecisionMask;
|
|
2138
|
-
const probTable = this.probTable;
|
|
2139
|
-
const cumProbTable = this.cumProbTable;
|
|
2140
|
-
let state = this.state;
|
|
2141
|
-
let bufOffset = this.bufOffset;
|
|
2142
|
-
const bufStart = this.bufStart;
|
|
2143
|
-
for (let i = 0; i < count; ++i) {
|
|
2144
|
-
while (state < lRansBase && bufOffset > bufStart) {
|
|
2145
|
-
state = state << 8 | buf[--bufOffset];
|
|
2146
|
-
}
|
|
2147
|
-
const rem = state & ransPrecisionMask;
|
|
2148
|
-
const symbol = lutTable[rem];
|
|
2149
|
-
out[i] = symbol;
|
|
2150
|
-
state = (state >>> ransPrecisionBits) * probTable[symbol] + rem - cumProbTable[symbol];
|
|
2151
|
-
}
|
|
2152
|
-
this.state = state;
|
|
2153
|
-
this.bufOffset = bufOffset;
|
|
2154
|
-
}
|
|
2155
|
-
// Builds the ransPrecision-entry lookup table. Returns false on bad input data.
|
|
2156
|
-
ransBuildLookUpTable(tokenProbs, numSymbols) {
|
|
2157
|
-
const LutArray = numSymbols <= 256 ? Uint8Array : numSymbols <= 65536 ? Uint16Array : Uint32Array;
|
|
2158
|
-
const lutTable = acquirePooled(LutArray, this.ransPrecision);
|
|
2159
|
-
const probTable = acquirePooled(Uint32Array, numSymbols);
|
|
2160
|
-
const cumProbTable = acquirePooled(Uint32Array, numSymbols);
|
|
2161
|
-
this.lutTable = lutTable;
|
|
2162
|
-
this.probTable = probTable;
|
|
2163
|
-
this.cumProbTable = cumProbTable;
|
|
2164
|
-
let cumProb = 0;
|
|
2165
|
-
let actProb = 0;
|
|
2166
|
-
for (let i = 0; i < numSymbols; ++i) {
|
|
2167
|
-
const prob = tokenProbs[i];
|
|
2168
|
-
probTable[i] = prob;
|
|
2169
|
-
cumProbTable[i] = cumProb;
|
|
2170
|
-
cumProb += prob;
|
|
2171
|
-
if (cumProb > this.ransPrecision) {
|
|
2172
|
-
return false;
|
|
2173
|
-
}
|
|
2174
|
-
if (prob < 32) {
|
|
2175
|
-
for (let j = actProb; j < cumProb; ++j) {
|
|
2176
|
-
lutTable[j] = i;
|
|
2177
|
-
}
|
|
2178
|
-
} else {
|
|
2179
|
-
lutTable.fill(i, actProb, cumProb);
|
|
2180
|
-
}
|
|
2181
|
-
actProb = cumProb;
|
|
2182
|
-
}
|
|
2183
|
-
if (cumProb !== this.ransPrecision) {
|
|
2184
|
-
return false;
|
|
2185
|
-
}
|
|
2186
|
-
return true;
|
|
2654
|
+
setPortableAttribute(att) {
|
|
2655
|
+
this._portableAttribute = att;
|
|
2656
|
+
}
|
|
2657
|
+
get portableAttribute() {
|
|
2658
|
+
return this._portableAttribute;
|
|
2187
2659
|
}
|
|
2188
2660
|
};
|
|
2189
2661
|
|
|
@@ -2208,8 +2680,10 @@ var RAnsSymbolDecoder = class {
|
|
|
2208
2680
|
get numSymbols() {
|
|
2209
2681
|
return this.numSymbols_;
|
|
2210
2682
|
}
|
|
2211
|
-
// Initialize the decoder and decode the probability table.
|
|
2212
|
-
|
|
2683
|
+
// Initialize the decoder and decode the probability table. expectedCount is
|
|
2684
|
+
// the number of symbols the caller will decode (lets short streams skip the
|
|
2685
|
+
// full lookup table; see RAnsDecoder.ransBuildLookUpTable).
|
|
2686
|
+
create(buffer, expectedCount = 2147483647) {
|
|
2213
2687
|
if (buffer.bitstreamVersion === 0) {
|
|
2214
2688
|
return false;
|
|
2215
2689
|
}
|
|
@@ -2220,7 +2694,7 @@ var RAnsSymbolDecoder = class {
|
|
|
2220
2694
|
return false;
|
|
2221
2695
|
}
|
|
2222
2696
|
const numSymbols = this.numSymbols_;
|
|
2223
|
-
const probabilityTable =
|
|
2697
|
+
const probabilityTable = scratchUint32Zeroed(numSymbols);
|
|
2224
2698
|
this.probabilityTable_ = probabilityTable;
|
|
2225
2699
|
if (numSymbols === 0) {
|
|
2226
2700
|
return true;
|
|
@@ -2250,7 +2724,7 @@ var RAnsSymbolDecoder = class {
|
|
|
2250
2724
|
}
|
|
2251
2725
|
}
|
|
2252
2726
|
buffer.advance(pos - startPos);
|
|
2253
|
-
if (!this.ans_.ransBuildLookUpTable(this.probabilityTable_, this.numSymbols_)) {
|
|
2727
|
+
if (!this.ans_.ransBuildLookUpTable(this.probabilityTable_, this.numSymbols_, expectedCount)) {
|
|
2254
2728
|
return false;
|
|
2255
2729
|
}
|
|
2256
2730
|
return true;
|
|
@@ -2292,7 +2766,7 @@ function decodeSymbols(numValues, numComponents, srcBuffer, outValues) {
|
|
|
2292
2766
|
}
|
|
2293
2767
|
function decodeTaggedSymbols(numValues, numComponents, srcBuffer, outValues) {
|
|
2294
2768
|
const tagDecoder = new RAnsSymbolDecoder(5);
|
|
2295
|
-
if (!tagDecoder.create(srcBuffer)) {
|
|
2769
|
+
if (!tagDecoder.create(srcBuffer, Math.ceil(numValues / numComponents))) {
|
|
2296
2770
|
return false;
|
|
2297
2771
|
}
|
|
2298
2772
|
if (!tagDecoder.startDecoding(srcBuffer)) {
|
|
@@ -2301,27 +2775,76 @@ function decodeTaggedSymbols(numValues, numComponents, srcBuffer, outValues) {
|
|
|
2301
2775
|
if (numValues > 0 && tagDecoder.numSymbols === 0) {
|
|
2302
2776
|
return false;
|
|
2303
2777
|
}
|
|
2778
|
+
const tagAns = tagDecoder.ans_;
|
|
2304
2779
|
srcBuffer.startBitDecoding(false);
|
|
2305
2780
|
const bd = srcBuffer._bitDecoder;
|
|
2306
|
-
const
|
|
2781
|
+
const buf = bd._bitBuffer;
|
|
2782
|
+
const byteLength = bd._byteLength;
|
|
2783
|
+
let bitOffset = bd._bitOffset;
|
|
2307
2784
|
let valueId = 0;
|
|
2308
2785
|
for (let i = 0; i < numValues; i += numComponents) {
|
|
2309
2786
|
const bitLength = tagAns.ransRead();
|
|
2310
|
-
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2313
|
-
|
|
2787
|
+
if (bitLength < 32) {
|
|
2788
|
+
const mask = (1 << bitLength) - 1;
|
|
2789
|
+
let j = 0;
|
|
2790
|
+
for (; j < numComponents; ++j) {
|
|
2791
|
+
const byteOffset = bitOffset >> 3;
|
|
2792
|
+
if (byteOffset + 4 >= byteLength) break;
|
|
2793
|
+
const bitShift = bitOffset & 7;
|
|
2794
|
+
let value = (buf[byteOffset] | buf[byteOffset + 1] << 8 | buf[byteOffset + 2] << 16 | buf[byteOffset + 3] << 24) >>> bitShift;
|
|
2795
|
+
if (bitLength > 32 - bitShift) {
|
|
2796
|
+
value = (value | buf[byteOffset + 4] << 32 - bitShift) >>> 0;
|
|
2797
|
+
}
|
|
2798
|
+
bitOffset += bitLength;
|
|
2799
|
+
outValues[valueId++] = value & mask;
|
|
2800
|
+
}
|
|
2801
|
+
if (j === numComponents) continue;
|
|
2802
|
+
bd._bitOffset = bitOffset;
|
|
2803
|
+
for (; j < numComponents; ++j) {
|
|
2804
|
+
const val = bd.getBits(bitLength);
|
|
2805
|
+
if (val === void 0) {
|
|
2806
|
+
return false;
|
|
2807
|
+
}
|
|
2808
|
+
outValues[valueId++] = val;
|
|
2809
|
+
}
|
|
2810
|
+
bitOffset = bd._bitOffset;
|
|
2811
|
+
} else {
|
|
2812
|
+
bd._bitOffset = bitOffset;
|
|
2813
|
+
for (let j = 0; j < numComponents; ++j) {
|
|
2814
|
+
const val = bd.getBits(bitLength);
|
|
2815
|
+
if (val === void 0) {
|
|
2816
|
+
return false;
|
|
2817
|
+
}
|
|
2818
|
+
outValues[valueId++] = val;
|
|
2314
2819
|
}
|
|
2315
|
-
|
|
2820
|
+
bitOffset = bd._bitOffset;
|
|
2316
2821
|
}
|
|
2317
2822
|
}
|
|
2823
|
+
bd._bitOffset = bitOffset;
|
|
2318
2824
|
tagDecoder.endDecoding();
|
|
2319
2825
|
srcBuffer.endBitDecoding();
|
|
2320
2826
|
return true;
|
|
2321
2827
|
}
|
|
2828
|
+
function parseRawSymbolStream(numValues, srcBuffer) {
|
|
2829
|
+
const maxBitLength = srcBuffer.decodeUint8();
|
|
2830
|
+
if (maxBitLength === void 0 || maxBitLength < 1 || maxBitLength > 18) {
|
|
2831
|
+
return null;
|
|
2832
|
+
}
|
|
2833
|
+
const decoder = new RAnsSymbolDecoder(maxBitLength);
|
|
2834
|
+
if (!decoder.create(srcBuffer, numValues)) {
|
|
2835
|
+
return null;
|
|
2836
|
+
}
|
|
2837
|
+
if (numValues > 0 && decoder.numSymbols === 0) {
|
|
2838
|
+
return null;
|
|
2839
|
+
}
|
|
2840
|
+
if (!decoder.startDecoding(srcBuffer)) {
|
|
2841
|
+
return null;
|
|
2842
|
+
}
|
|
2843
|
+
return decoder;
|
|
2844
|
+
}
|
|
2322
2845
|
function decodeRawSymbolsInternal(uniqueSymbolsBitLength, numValues, srcBuffer, outValues) {
|
|
2323
2846
|
const decoder = new RAnsSymbolDecoder(uniqueSymbolsBitLength);
|
|
2324
|
-
if (!decoder.create(srcBuffer)) {
|
|
2847
|
+
if (!decoder.create(srcBuffer, numValues)) {
|
|
2325
2848
|
return false;
|
|
2326
2849
|
}
|
|
2327
2850
|
if (numValues > 0 && decoder.numSymbols === 0) {
|
|
@@ -2421,6 +2944,16 @@ var PredictionSchemeDecoderInterface = class {
|
|
|
2421
2944
|
decodePredictionData(_buffer) {
|
|
2422
2945
|
return true;
|
|
2423
2946
|
}
|
|
2947
|
+
/**
|
|
2948
|
+
* Like computeOriginalValues, but inCorr still holds unsigned zigzag-coded
|
|
2949
|
+
* corrections; the implementation unpacks each one inline, replacing the
|
|
2950
|
+
* standalone convertSymbolsToSignedInts pass. Returns undefined when the
|
|
2951
|
+
* scheme/transform combination cannot fuse (the caller then falls back to
|
|
2952
|
+
* the two-pass path). Base implementation: never fusable.
|
|
2953
|
+
*/
|
|
2954
|
+
computeOriginalValuesZigzag(_inCorr, _outData, _size, _numComponents, _entryToPointIdMap) {
|
|
2955
|
+
return void 0;
|
|
2956
|
+
}
|
|
2424
2957
|
/** Reverts the prediction applied during encoding, writing original values to outData. */
|
|
2425
2958
|
computeOriginalValues(_inCorr, _outData, _size, _numComponents, _entryToPointIdMap) {
|
|
2426
2959
|
return false;
|
|
@@ -2756,7 +3289,7 @@ var OctahedronToolBox = class {
|
|
|
2756
3289
|
// src/decoder/compression/attributes/prediction_schemes/MeshPredictionSchemeGeometricNormalPredictorArea.ts
|
|
2757
3290
|
var UPPER_BOUND = 1 << 29;
|
|
2758
3291
|
function buildInt32PositionCache(att, map, numEntries, tempPos) {
|
|
2759
|
-
const cache =
|
|
3292
|
+
const cache = scratchInt32(numEntries * 3);
|
|
2760
3293
|
const bufData = att.buffer && att.buffer.data;
|
|
2761
3294
|
if (att.dataType === DataType.INT32 && att.numComponents === 3 && bufData) {
|
|
2762
3295
|
const src = new Int32Array(bufData.buffer);
|
|
@@ -2837,7 +3370,7 @@ var MeshPredictionSchemeGeometricNormalPredictorArea = class {
|
|
|
2837
3370
|
const cornerToVertex = this._cornerToVertex;
|
|
2838
3371
|
const vertexToDataMap = this._meshData.vertexToDataMap;
|
|
2839
3372
|
const nc = cornerToVertex.length;
|
|
2840
|
-
const c2o =
|
|
3373
|
+
const c2o = scratchInt32(nc);
|
|
2841
3374
|
for (let c = 0; c < nc; ++c) {
|
|
2842
3375
|
const v = cornerToVertex[c];
|
|
2843
3376
|
c2o[c] = v < 0 ? -1 : vertexToDataMap[v] * 3;
|
|
@@ -3088,10 +3621,21 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3088
3621
|
isInitialized() {
|
|
3089
3622
|
return this._meshData.isInitialized();
|
|
3090
3623
|
}
|
|
3624
|
+
// Zigzag-fused variant: decodes corrections that are still in their unsigned
|
|
3625
|
+
// zigzag form, unpacking each one inline. Only offered for the wrap
|
|
3626
|
+
// transform (whose corrections are the only zigzag-coded ones this scheme
|
|
3627
|
+
// sees); callers fall back to the standalone conversion pass otherwise.
|
|
3628
|
+
computeOriginalValuesZigzag(inCorr, outData, _size, numComponents, _entryToPointIdMap) {
|
|
3629
|
+
this._transform.init(numComponents);
|
|
3630
|
+
if (!this._transform.getType || this._transform.getType() !== PredictionSchemeTransformType.PREDICTION_TRANSFORM_WRAP) {
|
|
3631
|
+
return void 0;
|
|
3632
|
+
}
|
|
3633
|
+
return this._computeOriginalValuesWrap(inCorr, outData, numComponents, true);
|
|
3634
|
+
}
|
|
3091
3635
|
computeOriginalValues(inCorr, outData, size, numComponents, entryToPointIdMap) {
|
|
3092
3636
|
this._transform.init(numComponents);
|
|
3093
3637
|
if (this._transform.getType && this._transform.getType() === PredictionSchemeTransformType.PREDICTION_TRANSFORM_WRAP) {
|
|
3094
|
-
return this._computeOriginalValuesWrap(inCorr, outData, numComponents);
|
|
3638
|
+
return this._computeOriginalValuesWrap(inCorr, outData, numComponents, false);
|
|
3095
3639
|
}
|
|
3096
3640
|
const table = this._meshData.cornerTable;
|
|
3097
3641
|
const vertexToDataMap = this._meshData.vertexToDataMap;
|
|
@@ -3132,12 +3676,18 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3132
3676
|
}
|
|
3133
3677
|
return true;
|
|
3134
3678
|
}
|
|
3135
|
-
|
|
3679
|
+
// The wrap transform's corrections are zigzag-coded; with `zigzag` set the
|
|
3680
|
+
// decode folds the (val >>> 1) ^ -(val & 1) unpacking into each correction
|
|
3681
|
+
// read, replacing the standalone convertSymbolsToSignedInts pass over the
|
|
3682
|
+
// whole array (see computeOriginalValuesZigzag). Every correction is read
|
|
3683
|
+
// exactly once before its slot is overwritten, so the in-place aliasing of
|
|
3684
|
+
// inCorr and outData is preserved.
|
|
3685
|
+
_computeOriginalValuesWrap(inCorr, outData, numComponents, zigzag) {
|
|
3136
3686
|
if (numComponents === 2) {
|
|
3137
|
-
return this._computeOriginalValuesWrap2(inCorr, outData);
|
|
3687
|
+
return this._computeOriginalValuesWrap2(inCorr, outData, zigzag);
|
|
3138
3688
|
}
|
|
3139
3689
|
if (numComponents === 3) {
|
|
3140
|
-
return this._computeOriginalValuesWrap3(inCorr, outData);
|
|
3690
|
+
return this._computeOriginalValuesWrap3(inCorr, outData, zigzag);
|
|
3141
3691
|
}
|
|
3142
3692
|
const table = this._meshData.cornerTable;
|
|
3143
3693
|
const vertexToDataMap = this._meshData.vertexToDataMap;
|
|
@@ -3155,7 +3705,8 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3155
3705
|
} else if (pred < minValue) {
|
|
3156
3706
|
pred = minValue;
|
|
3157
3707
|
}
|
|
3158
|
-
|
|
3708
|
+
const raw = inCorr[c];
|
|
3709
|
+
let orig = pred + (zigzag ? raw >>> 1 ^ -(raw & 1) : raw) | 0;
|
|
3159
3710
|
if (orig > maxValue) {
|
|
3160
3711
|
orig -= maxDif;
|
|
3161
3712
|
} else if (orig < minValue) {
|
|
@@ -3194,7 +3745,8 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3194
3745
|
} else if (pred < minValue) {
|
|
3195
3746
|
pred = minValue;
|
|
3196
3747
|
}
|
|
3197
|
-
|
|
3748
|
+
const raw = inCorr[dstOffset + c];
|
|
3749
|
+
let orig = pred + (zigzag ? raw >>> 1 ^ -(raw & 1) : raw) | 0;
|
|
3198
3750
|
if (orig > maxValue) {
|
|
3199
3751
|
orig -= maxDif;
|
|
3200
3752
|
} else if (orig < minValue) {
|
|
@@ -3211,7 +3763,8 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3211
3763
|
} else if (pred < minValue) {
|
|
3212
3764
|
pred = minValue;
|
|
3213
3765
|
}
|
|
3214
|
-
|
|
3766
|
+
const raw = inCorr[dstOffset + c];
|
|
3767
|
+
let orig = pred + (zigzag ? raw >>> 1 ^ -(raw & 1) : raw) | 0;
|
|
3215
3768
|
if (orig > maxValue) {
|
|
3216
3769
|
orig -= maxDif;
|
|
3217
3770
|
} else if (orig < minValue) {
|
|
@@ -3223,7 +3776,7 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3223
3776
|
}
|
|
3224
3777
|
return true;
|
|
3225
3778
|
}
|
|
3226
|
-
_computeOriginalValuesWrap2(inCorr, outData) {
|
|
3779
|
+
_computeOriginalValuesWrap2(inCorr, outData, zigzag) {
|
|
3227
3780
|
const table = this._meshData.cornerTable;
|
|
3228
3781
|
const vertexToDataMap = this._meshData.vertexToDataMap;
|
|
3229
3782
|
const oppositeCorners = table.oppositeCornerArray();
|
|
@@ -3245,8 +3798,10 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3245
3798
|
} else if (pred1 < minValue) {
|
|
3246
3799
|
pred1 = minValue;
|
|
3247
3800
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
3801
|
+
const raw0 = inCorr[0];
|
|
3802
|
+
const raw1 = inCorr[1];
|
|
3803
|
+
let orig0 = pred0 + (zigzag ? raw0 >>> 1 ^ -(raw0 & 1) : raw0) | 0;
|
|
3804
|
+
let orig1 = pred1 + (zigzag ? raw1 >>> 1 ^ -(raw1 & 1) : raw1) | 0;
|
|
3250
3805
|
if (orig0 > maxValue) {
|
|
3251
3806
|
orig0 -= maxDif;
|
|
3252
3807
|
} else if (orig0 < minValue) {
|
|
@@ -3300,8 +3855,10 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3300
3855
|
} else if (pred1 < minValue) {
|
|
3301
3856
|
pred1 = minValue;
|
|
3302
3857
|
}
|
|
3303
|
-
|
|
3304
|
-
|
|
3858
|
+
const rawA = inCorr[dstOffset];
|
|
3859
|
+
const rawB = inCorr[dstOffset + 1];
|
|
3860
|
+
orig0 = pred0 + (zigzag ? rawA >>> 1 ^ -(rawA & 1) : rawA) | 0;
|
|
3861
|
+
orig1 = pred1 + (zigzag ? rawB >>> 1 ^ -(rawB & 1) : rawB) | 0;
|
|
3305
3862
|
if (orig0 > maxValue) {
|
|
3306
3863
|
orig0 -= maxDif;
|
|
3307
3864
|
} else if (orig0 < minValue) {
|
|
@@ -3317,7 +3874,7 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3317
3874
|
}
|
|
3318
3875
|
return true;
|
|
3319
3876
|
}
|
|
3320
|
-
_computeOriginalValuesWrap3(inCorr, outData) {
|
|
3877
|
+
_computeOriginalValuesWrap3(inCorr, outData, zigzag) {
|
|
3321
3878
|
const table = this._meshData.cornerTable;
|
|
3322
3879
|
const vertexToDataMap = this._meshData.vertexToDataMap;
|
|
3323
3880
|
const oppositeCorners = table.oppositeCornerArray();
|
|
@@ -3345,9 +3902,12 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3345
3902
|
} else if (pred2 < minValue) {
|
|
3346
3903
|
pred2 = minValue;
|
|
3347
3904
|
}
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3905
|
+
const raw0 = inCorr[0];
|
|
3906
|
+
const raw1 = inCorr[1];
|
|
3907
|
+
const raw2 = inCorr[2];
|
|
3908
|
+
let orig0 = pred0 + (zigzag ? raw0 >>> 1 ^ -(raw0 & 1) : raw0) | 0;
|
|
3909
|
+
let orig1 = pred1 + (zigzag ? raw1 >>> 1 ^ -(raw1 & 1) : raw1) | 0;
|
|
3910
|
+
let orig2 = pred2 + (zigzag ? raw2 >>> 1 ^ -(raw2 & 1) : raw2) | 0;
|
|
3351
3911
|
if (orig0 > maxValue) {
|
|
3352
3912
|
orig0 -= maxDif;
|
|
3353
3913
|
} else if (orig0 < minValue) {
|
|
@@ -3414,9 +3974,12 @@ var MeshPredictionSchemeParallelogramDecoder = class extends MeshPredictionSchem
|
|
|
3414
3974
|
} else if (pred2 < minValue) {
|
|
3415
3975
|
pred2 = minValue;
|
|
3416
3976
|
}
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3977
|
+
const rawA = inCorr[dstOffset];
|
|
3978
|
+
const rawB = inCorr[dstOffset + 1];
|
|
3979
|
+
const rawC = inCorr[dstOffset + 2];
|
|
3980
|
+
orig0 = pred0 + (zigzag ? rawA >>> 1 ^ -(rawA & 1) : rawA) | 0;
|
|
3981
|
+
orig1 = pred1 + (zigzag ? rawB >>> 1 ^ -(rawB & 1) : rawB) | 0;
|
|
3982
|
+
orig2 = pred2 + (zigzag ? rawC >>> 1 ^ -(rawC & 1) : rawC) | 0;
|
|
3420
3983
|
if (orig0 > maxValue) {
|
|
3421
3984
|
orig0 -= maxDif;
|
|
3422
3985
|
} else if (orig0 < minValue) {
|
|
@@ -3783,11 +4346,16 @@ var PredictionSchemeDeltaDecoder = class extends PredictionSchemeDecoder {
|
|
|
3783
4346
|
return true;
|
|
3784
4347
|
}
|
|
3785
4348
|
computeOriginalValues(inCorr, outData, size, numComponents, entryToPointIdMap) {
|
|
3786
|
-
this._transform
|
|
4349
|
+
const transform = this._transform;
|
|
4350
|
+
transform.init(numComponents);
|
|
4351
|
+
if (transform.computeOriginalValuesDelta) {
|
|
4352
|
+
transform.computeOriginalValuesDelta(inCorr, outData, size, numComponents);
|
|
4353
|
+
return true;
|
|
4354
|
+
}
|
|
3787
4355
|
const zeroVals = new Int32Array(numComponents);
|
|
3788
|
-
|
|
4356
|
+
transform.computeOriginalValue(zeroVals, 0, inCorr, 0, outData, 0);
|
|
3789
4357
|
for (let i = numComponents; i < size; i += numComponents) {
|
|
3790
|
-
|
|
4358
|
+
transform.computeOriginalValue(outData, i - numComponents, inCorr, i, outData, i);
|
|
3791
4359
|
}
|
|
3792
4360
|
return true;
|
|
3793
4361
|
}
|
|
@@ -3923,14 +4491,49 @@ var PredictionSchemeWrapDecodingTransform = class {
|
|
|
3923
4491
|
// src/decoder/compression/attributes/SequentialIntegerAttributeDecoder.ts
|
|
3924
4492
|
var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder {
|
|
3925
4493
|
_predictionScheme;
|
|
4494
|
+
// Two-phase decode state (see SequentialAttributeDecoder): the parse phase
|
|
4495
|
+
// stashes the primed raw-symbol stream here so the controller can batch and
|
|
4496
|
+
// pair several attributes' decodes; the finish phase consumes it.
|
|
4497
|
+
_pendingSymbolDecoder;
|
|
4498
|
+
_pendingNumValues;
|
|
4499
|
+
_finishPointIds;
|
|
3926
4500
|
constructor() {
|
|
3927
4501
|
super();
|
|
3928
4502
|
this._predictionScheme = null;
|
|
4503
|
+
this._pendingSymbolDecoder = null;
|
|
4504
|
+
this._pendingNumValues = 0;
|
|
4505
|
+
this._finishPointIds = null;
|
|
3929
4506
|
}
|
|
3930
|
-
|
|
3931
|
-
|
|
4507
|
+
// --- Two-phase decode (parse headers / batch symbol decode / finish) ---
|
|
4508
|
+
decodePortableAttributeParse(pointIds, buffer) {
|
|
4509
|
+
if (this.attribute.numComponents <= 0) {
|
|
4510
|
+
return false;
|
|
4511
|
+
}
|
|
4512
|
+
if (!this.attribute.reset(pointIds.length)) {
|
|
4513
|
+
return false;
|
|
4514
|
+
}
|
|
4515
|
+
this._finishPointIds = pointIds;
|
|
4516
|
+
return this._decodeValuesParse(pointIds, buffer);
|
|
3932
4517
|
}
|
|
3933
|
-
|
|
4518
|
+
pendingSymbolStream() {
|
|
4519
|
+
if (this._pendingSymbolDecoder === null) {
|
|
4520
|
+
return null;
|
|
4521
|
+
}
|
|
4522
|
+
const portableAttributeData = this.getPortableAttributeData();
|
|
4523
|
+
return {
|
|
4524
|
+
ans: this._pendingSymbolDecoder.ans_,
|
|
4525
|
+
out: new Uint32Array(portableAttributeData.buffer, portableAttributeData.byteOffset, this._pendingNumValues),
|
|
4526
|
+
count: this._pendingNumValues
|
|
4527
|
+
};
|
|
4528
|
+
}
|
|
4529
|
+
decodePortableAttributeFinish() {
|
|
4530
|
+
if (this._pendingSymbolDecoder !== null) {
|
|
4531
|
+
this._pendingSymbolDecoder.endDecoding();
|
|
4532
|
+
this._pendingSymbolDecoder = null;
|
|
4533
|
+
}
|
|
4534
|
+
return this._finishIntegerValues(this._finishPointIds);
|
|
4535
|
+
}
|
|
4536
|
+
_decodeValuesParse(pointIds, buffer) {
|
|
3934
4537
|
const predictionSchemeMethod = buffer.decodeInt8();
|
|
3935
4538
|
if (predictionSchemeMethod === void 0) return false;
|
|
3936
4539
|
if (predictionSchemeMethod < PredictionSchemeMethod.PREDICTION_NONE || predictionSchemeMethod >= PredictionSchemeMethod.NUM_PREDICTION_SCHEMES) {
|
|
@@ -3949,12 +4552,6 @@ var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder
|
|
|
3949
4552
|
return false;
|
|
3950
4553
|
}
|
|
3951
4554
|
}
|
|
3952
|
-
if (!this.decodeIntegerValues(pointIds, buffer)) {
|
|
3953
|
-
return false;
|
|
3954
|
-
}
|
|
3955
|
-
return true;
|
|
3956
|
-
}
|
|
3957
|
-
decodeIntegerValues(pointIds, buffer) {
|
|
3958
4555
|
const numComponents = this.getNumValueComponents();
|
|
3959
4556
|
if (numComponents <= 0) {
|
|
3960
4557
|
return false;
|
|
@@ -3969,9 +4566,23 @@ var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder
|
|
|
3969
4566
|
const compressed = buffer.decodeUint8();
|
|
3970
4567
|
if (compressed === void 0) return false;
|
|
3971
4568
|
if (compressed > 0) {
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
4569
|
+
if (numValues > 0) {
|
|
4570
|
+
const scheme = buffer.decodeUint8();
|
|
4571
|
+
if (scheme === SymbolCodingMethod.SYMBOL_CODING_RAW) {
|
|
4572
|
+
const decoder = parseRawSymbolStream(numValues, buffer);
|
|
4573
|
+
if (decoder === null) {
|
|
4574
|
+
return false;
|
|
4575
|
+
}
|
|
4576
|
+
this._pendingSymbolDecoder = decoder;
|
|
4577
|
+
this._pendingNumValues = numValues;
|
|
4578
|
+
} else if (scheme === SymbolCodingMethod.SYMBOL_CODING_TAGGED) {
|
|
4579
|
+
const outUint32 = new Uint32Array(portableAttributeData.buffer, portableAttributeData.byteOffset, numValues);
|
|
4580
|
+
if (!decodeTaggedSymbols(numValues, numComponents, buffer, outUint32)) {
|
|
4581
|
+
return false;
|
|
4582
|
+
}
|
|
4583
|
+
} else {
|
|
4584
|
+
return false;
|
|
4585
|
+
}
|
|
3975
4586
|
}
|
|
3976
4587
|
} else {
|
|
3977
4588
|
const numBytes = buffer.decodeUint8();
|
|
@@ -4002,15 +4613,40 @@ var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder
|
|
|
4002
4613
|
}
|
|
4003
4614
|
}
|
|
4004
4615
|
}
|
|
4005
|
-
if (numValues > 0 && (this._predictionScheme === null || !this._predictionScheme.areCorrectionsPositive())) {
|
|
4006
|
-
const asUint32 = new Uint32Array(portableAttributeData.buffer, portableAttributeData.byteOffset, numValues);
|
|
4007
|
-
convertSymbolsToSignedInts(asUint32, numValues, portableAttributeData);
|
|
4008
|
-
}
|
|
4009
4616
|
if (this._predictionScheme) {
|
|
4010
4617
|
if (!this._predictionScheme.decodePredictionData(buffer)) {
|
|
4011
4618
|
return false;
|
|
4012
4619
|
}
|
|
4620
|
+
}
|
|
4621
|
+
return true;
|
|
4622
|
+
}
|
|
4623
|
+
// The post-symbol tail of the decode: zigzag unpacking and prediction.
|
|
4624
|
+
_finishIntegerValues(pointIds) {
|
|
4625
|
+
const numComponents = this.getNumValueComponents();
|
|
4626
|
+
const numValues = pointIds.length * numComponents;
|
|
4627
|
+
const portableAttributeData = this.getPortableAttributeData();
|
|
4628
|
+
if (portableAttributeData === null) {
|
|
4629
|
+
return false;
|
|
4630
|
+
}
|
|
4631
|
+
const needsZigzag = numValues > 0 && (this._predictionScheme === null || !this._predictionScheme.areCorrectionsPositive());
|
|
4632
|
+
if (this._predictionScheme) {
|
|
4013
4633
|
if (numValues > 0) {
|
|
4634
|
+
if (needsZigzag) {
|
|
4635
|
+
const fused = this._predictionScheme.computeOriginalValuesZigzag(
|
|
4636
|
+
portableAttributeData,
|
|
4637
|
+
portableAttributeData,
|
|
4638
|
+
numValues,
|
|
4639
|
+
numComponents,
|
|
4640
|
+
pointIds
|
|
4641
|
+
);
|
|
4642
|
+
if (fused !== void 0) {
|
|
4643
|
+
return fused;
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
if (needsZigzag) {
|
|
4647
|
+
const asUint32 = new Uint32Array(portableAttributeData.buffer, portableAttributeData.byteOffset, numValues);
|
|
4648
|
+
convertSymbolsToSignedInts(asUint32, numValues, portableAttributeData);
|
|
4649
|
+
}
|
|
4014
4650
|
if (!this._predictionScheme.computeOriginalValues(
|
|
4015
4651
|
portableAttributeData,
|
|
4016
4652
|
portableAttributeData,
|
|
@@ -4021,9 +4657,34 @@ var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder
|
|
|
4021
4657
|
return false;
|
|
4022
4658
|
}
|
|
4023
4659
|
}
|
|
4660
|
+
} else if (needsZigzag) {
|
|
4661
|
+
const asUint32 = new Uint32Array(portableAttributeData.buffer, portableAttributeData.byteOffset, numValues);
|
|
4662
|
+
convertSymbolsToSignedInts(asUint32, numValues, portableAttributeData);
|
|
4024
4663
|
}
|
|
4025
4664
|
return true;
|
|
4026
4665
|
}
|
|
4666
|
+
transformAttributeToOriginalFormat(pointIds) {
|
|
4667
|
+
return this._storeValues(pointIds.length);
|
|
4668
|
+
}
|
|
4669
|
+
// Single-phase entry (base-class decodePortableAttribute path): parse,
|
|
4670
|
+
// decode any deferred symbol stream immediately, finish.
|
|
4671
|
+
decodeValues(pointIds, buffer) {
|
|
4672
|
+
this._finishPointIds = pointIds;
|
|
4673
|
+
if (!this._decodeValuesParse(pointIds, buffer)) {
|
|
4674
|
+
return false;
|
|
4675
|
+
}
|
|
4676
|
+
const pending = this._pendingSymbolDecoder;
|
|
4677
|
+
if (pending !== null) {
|
|
4678
|
+
const portableAttributeData = this.getPortableAttributeData();
|
|
4679
|
+
const outUint32 = new Uint32Array(
|
|
4680
|
+
portableAttributeData.buffer,
|
|
4681
|
+
portableAttributeData.byteOffset,
|
|
4682
|
+
this._pendingNumValues
|
|
4683
|
+
);
|
|
4684
|
+
pending.ans_.decodeSymbols(outUint32, this._pendingNumValues);
|
|
4685
|
+
}
|
|
4686
|
+
return this.decodePortableAttributeFinish();
|
|
4687
|
+
}
|
|
4027
4688
|
// Prediction scheme for decoding integer values; subclasses override for others.
|
|
4028
4689
|
createIntPredictionScheme(method, transformType) {
|
|
4029
4690
|
if (transformType !== PredictionSchemeTransformType.PREDICTION_TRANSFORM_WRAP) {
|
|
@@ -4086,7 +4747,7 @@ var SequentialIntegerAttributeDecoder = class extends SequentialAttributeDecoder
|
|
|
4086
4747
|
);
|
|
4087
4748
|
const portAtt = new PointAttribute(ga);
|
|
4088
4749
|
portAtt.setIdentityMapping();
|
|
4089
|
-
portAtt.
|
|
4750
|
+
portAtt.resetScratch(numEntries);
|
|
4090
4751
|
portAtt.uniqueId = this.attribute.uniqueId;
|
|
4091
4752
|
this.setPortableAttribute(portAtt);
|
|
4092
4753
|
}
|
|
@@ -4112,12 +4773,22 @@ var AttributeTransformType = {
|
|
|
4112
4773
|
};
|
|
4113
4774
|
|
|
4114
4775
|
// src/decoder/attributes/AttributeTransformData.ts
|
|
4776
|
+
var INITIAL_CAPACITY = 32;
|
|
4115
4777
|
var AttributeTransformData = class {
|
|
4116
4778
|
_transformType;
|
|
4117
|
-
|
|
4779
|
+
// Parameter bytes, little-endian, appended in transform-defined order.
|
|
4780
|
+
// Capacity grows geometrically and the DataView is cached alongside it: the
|
|
4781
|
+
// previous DataBuffer-backed version reallocated the buffer and built a
|
|
4782
|
+
// fresh DataView on *every* appended value, which on primitive-heavy files
|
|
4783
|
+
// cost more than the dequantization it describes.
|
|
4784
|
+
_bytes;
|
|
4785
|
+
_view;
|
|
4786
|
+
_size;
|
|
4118
4787
|
constructor() {
|
|
4119
4788
|
this._transformType = AttributeTransformType.INVALID;
|
|
4120
|
-
this.
|
|
4789
|
+
this._bytes = new Uint8Array(INITIAL_CAPACITY);
|
|
4790
|
+
this._view = new DataView(this._bytes.buffer);
|
|
4791
|
+
this._size = 0;
|
|
4121
4792
|
}
|
|
4122
4793
|
get transformType() {
|
|
4123
4794
|
return this._transformType;
|
|
@@ -4125,13 +4796,29 @@ var AttributeTransformData = class {
|
|
|
4125
4796
|
set transformType(type) {
|
|
4126
4797
|
this._transformType = type;
|
|
4127
4798
|
}
|
|
4799
|
+
// Number of parameter bytes written so far (the next append offset).
|
|
4800
|
+
get dataSize() {
|
|
4801
|
+
return this._size;
|
|
4802
|
+
}
|
|
4803
|
+
get data() {
|
|
4804
|
+
return this._bytes.subarray(0, this._size);
|
|
4805
|
+
}
|
|
4806
|
+
_reserve(sizeNeeded) {
|
|
4807
|
+
if (sizeNeeded <= this._bytes.length) return;
|
|
4808
|
+
let capacity = this._bytes.length * 2;
|
|
4809
|
+
if (capacity < sizeNeeded) capacity = sizeNeeded;
|
|
4810
|
+
const grown = new Uint8Array(capacity);
|
|
4811
|
+
grown.set(this._bytes);
|
|
4812
|
+
this._bytes = grown;
|
|
4813
|
+
this._view = new DataView(grown.buffer);
|
|
4814
|
+
}
|
|
4128
4815
|
setParameterValue(byteOffset, value, type) {
|
|
4129
4816
|
const sizeNeeded = byteOffset + this._typeSize(type);
|
|
4130
|
-
|
|
4131
|
-
|
|
4817
|
+
this._reserve(sizeNeeded);
|
|
4818
|
+
if (sizeNeeded > this._size) {
|
|
4819
|
+
this._size = sizeNeeded;
|
|
4132
4820
|
}
|
|
4133
|
-
const
|
|
4134
|
-
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
4821
|
+
const view = this._view;
|
|
4135
4822
|
switch (type) {
|
|
4136
4823
|
case "int32":
|
|
4137
4824
|
view.setInt32(byteOffset, value, true);
|
|
@@ -4163,7 +4850,7 @@ var AttributeTransformData = class {
|
|
|
4163
4850
|
}
|
|
4164
4851
|
}
|
|
4165
4852
|
appendParameterValue(value, type) {
|
|
4166
|
-
this.setParameterValue(this.
|
|
4853
|
+
this.setParameterValue(this._size, value, type);
|
|
4167
4854
|
}
|
|
4168
4855
|
_typeSize(type) {
|
|
4169
4856
|
switch (type) {
|
|
@@ -4209,7 +4896,6 @@ var AttributeTransform = class {
|
|
|
4209
4896
|
// src/decoder/attributes/AttributeOctahedronTransform.ts
|
|
4210
4897
|
var AttributeOctahedronTransform = class extends AttributeTransform {
|
|
4211
4898
|
_quantizationBits;
|
|
4212
|
-
_tmpVec;
|
|
4213
4899
|
constructor() {
|
|
4214
4900
|
super();
|
|
4215
4901
|
this._quantizationBits = -1;
|
|
@@ -4241,15 +4927,30 @@ var AttributeOctahedronTransform = class extends AttributeTransform {
|
|
|
4241
4927
|
const srcI32 = new Int32Array(srcAddr.buffer, srcAddr.byteOffset, numPoints * 2);
|
|
4242
4928
|
const dstAddr = targetAttribute.getAddress(0);
|
|
4243
4929
|
const dstF32 = new Float32Array(dstAddr.buffer, dstAddr.byteOffset, numPoints * 3);
|
|
4244
|
-
const
|
|
4930
|
+
const fround = Math.fround;
|
|
4931
|
+
const scale = toolBox._dequantizationScale;
|
|
4245
4932
|
let si = 0;
|
|
4246
4933
|
let di = 0;
|
|
4247
4934
|
for (let i = 0; i < numPoints; i++) {
|
|
4248
|
-
|
|
4935
|
+
let y = fround(fround(fround(srcI32[si]) * scale) - 1);
|
|
4936
|
+
let z = fround(fround(fround(srcI32[si + 1]) * scale) - 1);
|
|
4249
4937
|
si += 2;
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4938
|
+
const x = fround(fround(1 - Math.abs(y)) - Math.abs(z));
|
|
4939
|
+
let xOffset = -x;
|
|
4940
|
+
if (xOffset < 0) xOffset = 0;
|
|
4941
|
+
y = fround(y + (y < 0 ? xOffset : -xOffset));
|
|
4942
|
+
z = fround(z + (z < 0 ? xOffset : -xOffset));
|
|
4943
|
+
const normSquared = fround(fround(fround(x * x) + fround(y * y)) + fround(z * z));
|
|
4944
|
+
if (normSquared < 1e-6) {
|
|
4945
|
+
dstF32[di] = 0;
|
|
4946
|
+
dstF32[di + 1] = 0;
|
|
4947
|
+
dstF32[di + 2] = 0;
|
|
4948
|
+
} else {
|
|
4949
|
+
const d = fround(1 / fround(Math.sqrt(normSquared)));
|
|
4950
|
+
dstF32[di] = fround(x * d);
|
|
4951
|
+
dstF32[di + 1] = fround(y * d);
|
|
4952
|
+
dstF32[di + 2] = fround(z * d);
|
|
4953
|
+
}
|
|
4253
4954
|
di += 3;
|
|
4254
4955
|
}
|
|
4255
4956
|
return true;
|
|
@@ -4419,6 +5120,140 @@ var PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform = class exten
|
|
|
4419
5120
|
outOrigVals[outOffset] = origS + center;
|
|
4420
5121
|
outOrigVals[outOffset + 1] = origT + center;
|
|
4421
5122
|
}
|
|
5123
|
+
// Fused delta loop for PredictionSchemeDeltaDecoder: the whole
|
|
5124
|
+
// value[i] = original(value[i-1], corr[i]) chain in one call, with the
|
|
5125
|
+
// toolbox fields hoisted to locals and the previous output carried in
|
|
5126
|
+
// locals. This is the hot path for PREDICTION_DIFFERENCE normals (one call
|
|
5127
|
+
// per value through the interface was ~8% of decode time on the bundles).
|
|
5128
|
+
// The arithmetic is computeOriginalValue above verbatim -- keep them in
|
|
5129
|
+
// sync; only the plumbing differs.
|
|
5130
|
+
computeOriginalValuesDelta(inCorr, outData, size, numComponents) {
|
|
5131
|
+
const toolBox = this._octahedronToolBox;
|
|
5132
|
+
const center = toolBox._centerValue;
|
|
5133
|
+
const maxQuantizedValue = toolBox._maxQuantizedValue;
|
|
5134
|
+
let prevS = 0;
|
|
5135
|
+
let prevT = 0;
|
|
5136
|
+
for (let i = 0; i < size; i += numComponents) {
|
|
5137
|
+
const corrS = inCorr[i];
|
|
5138
|
+
const corrT = inCorr[i + 1];
|
|
5139
|
+
let predS = prevS - center;
|
|
5140
|
+
let predT = prevT - center;
|
|
5141
|
+
const predIsInDiamond = Math.abs(predS) + Math.abs(predT) <= center;
|
|
5142
|
+
if (!predIsInDiamond) {
|
|
5143
|
+
let signS = 0;
|
|
5144
|
+
let signT = 0;
|
|
5145
|
+
if (predS >= 0 && predT >= 0) {
|
|
5146
|
+
signS = 1;
|
|
5147
|
+
signT = 1;
|
|
5148
|
+
} else if (predS <= 0 && predT <= 0) {
|
|
5149
|
+
signS = -1;
|
|
5150
|
+
signT = -1;
|
|
5151
|
+
} else {
|
|
5152
|
+
signS = predS > 0 ? 1 : -1;
|
|
5153
|
+
signT = predT > 0 ? 1 : -1;
|
|
5154
|
+
}
|
|
5155
|
+
const cornerPointS = signS * center;
|
|
5156
|
+
const cornerPointT = signT * center;
|
|
5157
|
+
let us = predS * 2 - cornerPointS | 0;
|
|
5158
|
+
let ut = predT * 2 - cornerPointT | 0;
|
|
5159
|
+
if (signS * signT >= 0) {
|
|
5160
|
+
const temp = us;
|
|
5161
|
+
us = -ut;
|
|
5162
|
+
ut = -temp;
|
|
5163
|
+
} else {
|
|
5164
|
+
const temp = us;
|
|
5165
|
+
us = ut;
|
|
5166
|
+
ut = temp;
|
|
5167
|
+
}
|
|
5168
|
+
predS = (us + cornerPointS) / 2 | 0;
|
|
5169
|
+
predT = (ut + cornerPointT) / 2 | 0;
|
|
5170
|
+
}
|
|
5171
|
+
const predIsInBottomLeft = predS === 0 && predT === 0 || predS < 0 && predT <= 0;
|
|
5172
|
+
let rotationCount = 0;
|
|
5173
|
+
if (predS === 0) {
|
|
5174
|
+
if (predT > 0) rotationCount = 3;
|
|
5175
|
+
else if (predT < 0) rotationCount = 1;
|
|
5176
|
+
} else if (predS > 0) {
|
|
5177
|
+
if (predT >= 0) rotationCount = 2;
|
|
5178
|
+
else rotationCount = 1;
|
|
5179
|
+
} else {
|
|
5180
|
+
if (predT > 0) rotationCount = 3;
|
|
5181
|
+
}
|
|
5182
|
+
if (!predIsInBottomLeft) {
|
|
5183
|
+
const s = predS, t = predT;
|
|
5184
|
+
switch (rotationCount) {
|
|
5185
|
+
case 1:
|
|
5186
|
+
predS = t;
|
|
5187
|
+
predT = -s | 0;
|
|
5188
|
+
break;
|
|
5189
|
+
case 2:
|
|
5190
|
+
predS = -s | 0;
|
|
5191
|
+
predT = -t | 0;
|
|
5192
|
+
break;
|
|
5193
|
+
case 3:
|
|
5194
|
+
predS = -t | 0;
|
|
5195
|
+
predT = s;
|
|
5196
|
+
break;
|
|
5197
|
+
}
|
|
5198
|
+
}
|
|
5199
|
+
let origS = predS + corrS | 0;
|
|
5200
|
+
if (origS > center) origS -= maxQuantizedValue;
|
|
5201
|
+
else if (origS < -center) origS += maxQuantizedValue;
|
|
5202
|
+
let origT = predT + corrT | 0;
|
|
5203
|
+
if (origT > center) origT -= maxQuantizedValue;
|
|
5204
|
+
else if (origT < -center) origT += maxQuantizedValue;
|
|
5205
|
+
if (!predIsInBottomLeft) {
|
|
5206
|
+
const s = origS, t = origT;
|
|
5207
|
+
switch (4 - rotationCount & 3) {
|
|
5208
|
+
case 1:
|
|
5209
|
+
origS = t;
|
|
5210
|
+
origT = -s | 0;
|
|
5211
|
+
break;
|
|
5212
|
+
case 2:
|
|
5213
|
+
origS = -s | 0;
|
|
5214
|
+
origT = -t | 0;
|
|
5215
|
+
break;
|
|
5216
|
+
case 3:
|
|
5217
|
+
origS = -t | 0;
|
|
5218
|
+
origT = s;
|
|
5219
|
+
break;
|
|
5220
|
+
}
|
|
5221
|
+
}
|
|
5222
|
+
if (!predIsInDiamond) {
|
|
5223
|
+
let signS = 0;
|
|
5224
|
+
let signT = 0;
|
|
5225
|
+
if (origS >= 0 && origT >= 0) {
|
|
5226
|
+
signS = 1;
|
|
5227
|
+
signT = 1;
|
|
5228
|
+
} else if (origS <= 0 && origT <= 0) {
|
|
5229
|
+
signS = -1;
|
|
5230
|
+
signT = -1;
|
|
5231
|
+
} else {
|
|
5232
|
+
signS = origS > 0 ? 1 : -1;
|
|
5233
|
+
signT = origT > 0 ? 1 : -1;
|
|
5234
|
+
}
|
|
5235
|
+
const cornerPointS = signS * center;
|
|
5236
|
+
const cornerPointT = signT * center;
|
|
5237
|
+
let us = origS * 2 - cornerPointS | 0;
|
|
5238
|
+
let ut = origT * 2 - cornerPointT | 0;
|
|
5239
|
+
if (signS * signT >= 0) {
|
|
5240
|
+
const temp = us;
|
|
5241
|
+
us = -ut;
|
|
5242
|
+
ut = -temp;
|
|
5243
|
+
} else {
|
|
5244
|
+
const temp = us;
|
|
5245
|
+
us = ut;
|
|
5246
|
+
ut = temp;
|
|
5247
|
+
}
|
|
5248
|
+
origS = (us + cornerPointS) / 2 | 0;
|
|
5249
|
+
origT = (ut + cornerPointT) / 2 | 0;
|
|
5250
|
+
}
|
|
5251
|
+
prevS = origS + center | 0;
|
|
5252
|
+
prevT = origT + center | 0;
|
|
5253
|
+
outData[i] = prevS;
|
|
5254
|
+
outData[i + 1] = prevT;
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
4422
5257
|
};
|
|
4423
5258
|
|
|
4424
5259
|
// src/decoder/compression/attributes/prediction_schemes/PredictionSchemeNormalOctahedronDecodingTransform.ts
|
|
@@ -4733,6 +5568,12 @@ var SequentialAttributeDecodersController = class extends AttributesDecoder {
|
|
|
4733
5568
|
return true;
|
|
4734
5569
|
}
|
|
4735
5570
|
decodeAttributes(buffer) {
|
|
5571
|
+
if (!this._prepareSequence()) {
|
|
5572
|
+
return false;
|
|
5573
|
+
}
|
|
5574
|
+
return super.decodeAttributes(buffer);
|
|
5575
|
+
}
|
|
5576
|
+
_prepareSequence() {
|
|
4736
5577
|
if (!this._sequencer) {
|
|
4737
5578
|
return false;
|
|
4738
5579
|
}
|
|
@@ -4747,7 +5588,44 @@ var SequentialAttributeDecodersController = class extends AttributesDecoder {
|
|
|
4747
5588
|
return false;
|
|
4748
5589
|
}
|
|
4749
5590
|
}
|
|
4750
|
-
return
|
|
5591
|
+
return true;
|
|
5592
|
+
}
|
|
5593
|
+
// Two-phase decode (see AttributesDecoder): parse everything that reads the
|
|
5594
|
+
// buffer -- sequence, portable headers (deferring raw rANS symbol decodes),
|
|
5595
|
+
// and the transform parameters -- so the deferred streams of ALL attributes
|
|
5596
|
+
// decoders can then be paired, and finish (zigzag, prediction, inverse
|
|
5597
|
+
// transform) runs per decoder in the original order afterwards. None of the
|
|
5598
|
+
// finish work reads the buffer, and dependents only read parent portable
|
|
5599
|
+
// VALUES in finish, so ordering and output stay identical.
|
|
5600
|
+
decodeAttributesParse(buffer) {
|
|
5601
|
+
if (!this._prepareSequence()) {
|
|
5602
|
+
return false;
|
|
5603
|
+
}
|
|
5604
|
+
const numAttributes = this.getNumAttributes();
|
|
5605
|
+
for (let i = 0; i < numAttributes; i++) {
|
|
5606
|
+
if (!this._sequentialDecoders[i].decodePortableAttributeParse(this._pointIds, buffer)) {
|
|
5607
|
+
return false;
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
return this.decodeDataNeededByPortableTransforms(buffer);
|
|
5611
|
+
}
|
|
5612
|
+
collectPendingSymbolStreams(out) {
|
|
5613
|
+
const numAttributes = this.getNumAttributes();
|
|
5614
|
+
for (let i = 0; i < numAttributes; i++) {
|
|
5615
|
+
const pending = this._sequentialDecoders[i].pendingSymbolStream();
|
|
5616
|
+
if (pending !== null) {
|
|
5617
|
+
out.push(pending);
|
|
5618
|
+
}
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
decodeAttributesFinish() {
|
|
5622
|
+
const numAttributes = this.getNumAttributes();
|
|
5623
|
+
for (let i = 0; i < numAttributes; i++) {
|
|
5624
|
+
if (!this._sequentialDecoders[i].decodePortableAttributeFinish()) {
|
|
5625
|
+
return false;
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
return this.transformAttributesToOriginalFormat();
|
|
4751
5629
|
}
|
|
4752
5630
|
getPortableAttribute(pointAttributeId) {
|
|
4753
5631
|
const locId = this.getLocalIdForPointAttribute(pointAttributeId);
|
|
@@ -4874,14 +5752,13 @@ var DepthFirstTraverser = class {
|
|
|
4874
5752
|
// Scratch buffers are set up here rather than in init() so a shared-traversal
|
|
4875
5753
|
// -cache hit — where generateSequence returns before any traversal — skips
|
|
4876
5754
|
// this entirely, including the visited-flag zero-fill (worth ~0.5% on the
|
|
4877
|
-
//
|
|
5755
|
+
// ~500-primitive manablade bundle, which shares attribute corner tables across
|
|
4878
5756
|
// primitives). Uint8Array (0/1) instead of Array(bool): these flags are read
|
|
4879
5757
|
// and written on every corner of the hottest decode loop (traverseFromCorner).
|
|
4880
5758
|
// Decode-scoped scratch: released in bulk at the end of the decode.
|
|
4881
5759
|
onTraversalStart() {
|
|
4882
5760
|
const cornerTable = this._cornerTable;
|
|
4883
5761
|
this._isFaceVisited = scratchUint8Zeroed(cornerTable.numFaces());
|
|
4884
|
-
this._isVertexVisited = scratchUint8Zeroed(cornerTable.numVertices());
|
|
4885
5762
|
this._cornerTraversalStack = scratchInt32(this._numCorners);
|
|
4886
5763
|
}
|
|
4887
5764
|
onTraversalEnd() {
|
|
@@ -4891,7 +5768,6 @@ var DepthFirstTraverser = class {
|
|
|
4891
5768
|
return true;
|
|
4892
5769
|
}
|
|
4893
5770
|
const isFaceVisited = this._isFaceVisited;
|
|
4894
|
-
const isVertexVisited = this._isVertexVisited;
|
|
4895
5771
|
const observer = this._observer;
|
|
4896
5772
|
const cornerToVertex = this._cornerToVertex;
|
|
4897
5773
|
const oppositeCorners = this._oppositeCorners;
|
|
@@ -4915,14 +5791,12 @@ var DepthFirstTraverser = class {
|
|
|
4915
5791
|
if (nextVert === kInvalidVertexIndex2 || prevVert === kInvalidVertexIndex2) {
|
|
4916
5792
|
return false;
|
|
4917
5793
|
}
|
|
4918
|
-
if (
|
|
4919
|
-
isVertexVisited[nextVert] = 1;
|
|
5794
|
+
if (vertexToEncodedMap[nextVert] < 0) {
|
|
4920
5795
|
outPointIds[numOutPoints++] = obsFaces[nextCorner];
|
|
4921
5796
|
encodedToCornerMap[numValues] = nextCorner;
|
|
4922
5797
|
vertexToEncodedMap[nextVert] = numValues++;
|
|
4923
5798
|
}
|
|
4924
|
-
if (
|
|
4925
|
-
isVertexVisited[prevVert] = 1;
|
|
5799
|
+
if (vertexToEncodedMap[prevVert] < 0) {
|
|
4926
5800
|
outPointIds[numOutPoints++] = obsFaces[prevCorner];
|
|
4927
5801
|
encodedToCornerMap[numValues] = prevCorner;
|
|
4928
5802
|
vertexToEncodedMap[prevVert] = numValues++;
|
|
@@ -4943,27 +5817,26 @@ var DepthFirstTraverser = class {
|
|
|
4943
5817
|
encodingData.numValues = numValues;
|
|
4944
5818
|
return false;
|
|
4945
5819
|
}
|
|
4946
|
-
|
|
5820
|
+
const faceBase = faceId * 3;
|
|
5821
|
+
const nextCornerId = cornerId === faceBase + 2 ? faceBase : cornerId + 1;
|
|
5822
|
+
if (vertexToEncodedMap[vertId] < 0) {
|
|
4947
5823
|
const lc = vertexLeftmost[vertId];
|
|
4948
5824
|
let onBoundary = true;
|
|
4949
|
-
if (lc
|
|
5825
|
+
if (lc >= 0) {
|
|
4950
5826
|
const nextLc = lc % 3 === 2 ? lc - 2 : lc + 1;
|
|
4951
5827
|
onBoundary = oppositeCorners[nextLc] < 0;
|
|
4952
5828
|
}
|
|
4953
|
-
isVertexVisited[vertId] = 1;
|
|
4954
5829
|
outPointIds[numOutPoints++] = obsFaces[cornerId];
|
|
4955
5830
|
encodedToCornerMap[numValues] = cornerId;
|
|
4956
5831
|
vertexToEncodedMap[vertId] = numValues++;
|
|
4957
5832
|
if (!onBoundary) {
|
|
4958
|
-
|
|
4959
|
-
cornerId = oppositeCorners[nextCornerId2];
|
|
5833
|
+
cornerId = oppositeCorners[nextCornerId];
|
|
4960
5834
|
faceId = cornerId / 3 | 0;
|
|
4961
5835
|
continue;
|
|
4962
5836
|
}
|
|
4963
5837
|
}
|
|
4964
|
-
const nextCornerId = cornerId % 3 === 2 ? cornerId - 2 : cornerId + 1;
|
|
4965
5838
|
const rightCornerId = oppositeCorners[nextCornerId];
|
|
4966
|
-
const prevCornerId = cornerId
|
|
5839
|
+
const prevCornerId = cornerId === faceBase ? faceBase + 2 : cornerId - 1;
|
|
4967
5840
|
const leftCornerId = oppositeCorners[prevCornerId];
|
|
4968
5841
|
const rightFaceId = rightCornerId === kInvalidCornerIndex4 ? kInvalidFaceIndex : rightCornerId / 3 | 0;
|
|
4969
5842
|
const leftFaceId = leftCornerId === kInvalidCornerIndex4 ? kInvalidFaceIndex : leftCornerId / 3 | 0;
|
|
@@ -5193,6 +6066,9 @@ var MeshTraversalSequencer = class {
|
|
|
5193
6066
|
_outPointIds;
|
|
5194
6067
|
_numOutPoints;
|
|
5195
6068
|
_traversalCache;
|
|
6069
|
+
// The cache entry the last generateSequence resolved to (hit or store);
|
|
6070
|
+
// carries the shared indicesMap.
|
|
6071
|
+
_cacheEntry;
|
|
5196
6072
|
constructor(mesh, encodingData, traversalCache = null) {
|
|
5197
6073
|
this._mesh = mesh;
|
|
5198
6074
|
this._encodingData = encodingData;
|
|
@@ -5200,6 +6076,7 @@ var MeshTraversalSequencer = class {
|
|
|
5200
6076
|
this._outPointIds = new Int32Array(0);
|
|
5201
6077
|
this._numOutPoints = 0;
|
|
5202
6078
|
this._traversalCache = traversalCache;
|
|
6079
|
+
this._cacheEntry = null;
|
|
5203
6080
|
}
|
|
5204
6081
|
setTraverser(traverser) {
|
|
5205
6082
|
this._traverser = traverser;
|
|
@@ -5214,6 +6091,7 @@ var MeshTraversalSequencer = class {
|
|
|
5214
6091
|
if (cached !== void 0) {
|
|
5215
6092
|
this._outPointIds = cached.pointIds;
|
|
5216
6093
|
this._encodingData.adoptTraversalResult(cached.vertexMap, cached.cornerMap, cached.numValues);
|
|
6094
|
+
this._cacheEntry = cached;
|
|
5217
6095
|
return true;
|
|
5218
6096
|
}
|
|
5219
6097
|
}
|
|
@@ -5229,12 +6107,15 @@ var MeshTraversalSequencer = class {
|
|
|
5229
6107
|
byMethod = /* @__PURE__ */ new Map();
|
|
5230
6108
|
this._traversalCache.set(cacheKey, byMethod);
|
|
5231
6109
|
}
|
|
5232
|
-
|
|
6110
|
+
const entry = {
|
|
5233
6111
|
pointIds: this._outPointIds,
|
|
5234
6112
|
vertexMap: this._encodingData.vertexToEncodedAttributeValueIndexMap,
|
|
5235
6113
|
cornerMap: this._encodingData.encodedAttributeValueIndexToCornerMap,
|
|
5236
|
-
numValues: this._encodingData.numValues
|
|
5237
|
-
|
|
6114
|
+
numValues: this._encodingData.numValues,
|
|
6115
|
+
indicesMap: null
|
|
6116
|
+
};
|
|
6117
|
+
byMethod.set(methodId, entry);
|
|
6118
|
+
this._cacheEntry = entry;
|
|
5238
6119
|
}
|
|
5239
6120
|
return true;
|
|
5240
6121
|
}
|
|
@@ -5245,6 +6126,11 @@ var MeshTraversalSequencer = class {
|
|
|
5245
6126
|
this._outPointIds[this._numOutPoints++] = pointId;
|
|
5246
6127
|
}
|
|
5247
6128
|
updatePointToAttributeIndexMapping(attribute) {
|
|
6129
|
+
const entry = this._cacheEntry;
|
|
6130
|
+
if (entry !== null && entry.indicesMap !== null) {
|
|
6131
|
+
attribute.setExplicitMappingShared(entry.indicesMap);
|
|
6132
|
+
return true;
|
|
6133
|
+
}
|
|
5248
6134
|
const cornerTable = this._traverser.cornerTable();
|
|
5249
6135
|
const numFaces = this._mesh.numFaces();
|
|
5250
6136
|
const numPoints = this._mesh.numPoints();
|
|
@@ -5266,11 +6152,14 @@ var MeshTraversalSequencer = class {
|
|
|
5266
6152
|
}
|
|
5267
6153
|
indicesMap[pointId] = attEntryId;
|
|
5268
6154
|
}
|
|
6155
|
+
if (entry !== null) {
|
|
6156
|
+
entry.indicesMap = attribute.indicesMap;
|
|
6157
|
+
}
|
|
5269
6158
|
return true;
|
|
5270
6159
|
}
|
|
5271
6160
|
_generateSequenceInternal() {
|
|
5272
6161
|
this._numOutPoints = 0;
|
|
5273
|
-
this._outPointIds =
|
|
6162
|
+
this._outPointIds = scratchInt32(this._mesh.numPoints());
|
|
5274
6163
|
this._traverser.onTraversalStart();
|
|
5275
6164
|
const numFaces = this._traverser.cornerTable().numFaces();
|
|
5276
6165
|
for (let i = 0; i < numFaces && this._traverser._numVisitedFaces < numFaces; ++i) {
|
|
@@ -5461,14 +6350,14 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5461
6350
|
this._attributeData = [];
|
|
5462
6351
|
for (let i = 0; i < numAttributeData; ++i) {
|
|
5463
6352
|
const ad = new AttributeData();
|
|
5464
|
-
ad.attributeSeamCorners =
|
|
6353
|
+
ad.attributeSeamCorners = scratchInt32(numFaces * 3);
|
|
5465
6354
|
ad.numSeamCorners = 0;
|
|
5466
6355
|
this._attributeData.push(ad);
|
|
5467
6356
|
}
|
|
5468
6357
|
if (!this._cornerTable.reset(numFaces, this._numEncodedVertices + numEncodedSplitSymbols)) {
|
|
5469
6358
|
return false;
|
|
5470
6359
|
}
|
|
5471
|
-
this._isVertHole =
|
|
6360
|
+
this._isVertHole = scratchUint8Filled(this._numEncodedVertices + numEncodedSplitSymbols, 1);
|
|
5472
6361
|
if (this._decodeHoleAndTopologySplitEvents(this._decoder.buffer()) === -1) {
|
|
5473
6362
|
return false;
|
|
5474
6363
|
}
|
|
@@ -5493,20 +6382,37 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5493
6382
|
}
|
|
5494
6383
|
this._traversalDecoder.done();
|
|
5495
6384
|
let previousConnectivityData = null;
|
|
6385
|
+
let previousSeamCorners = null;
|
|
6386
|
+
let previousSeamCount = 0;
|
|
5496
6387
|
for (let i = 0; i < this._attributeData.length; ++i) {
|
|
5497
6388
|
const connectivityData = this._attributeData[i].connectivityData;
|
|
5498
|
-
connectivityData.initEmpty(this._cornerTable);
|
|
5499
6389
|
const seamCorners = this._attributeData[i].attributeSeamCorners;
|
|
5500
6390
|
const seamCount = this._attributeData[i].numSeamCorners;
|
|
5501
|
-
|
|
5502
|
-
|
|
6391
|
+
let sameAsPrevious = previousConnectivityData !== null && seamCount === previousSeamCount;
|
|
6392
|
+
if (sameAsPrevious) {
|
|
6393
|
+
const previous = previousSeamCorners;
|
|
6394
|
+
for (let s = 0; s < seamCount; ++s) {
|
|
6395
|
+
if (seamCorners[s] !== previous[s]) {
|
|
6396
|
+
sameAsPrevious = false;
|
|
6397
|
+
break;
|
|
6398
|
+
}
|
|
6399
|
+
}
|
|
5503
6400
|
}
|
|
5504
|
-
if (
|
|
5505
|
-
connectivityData.
|
|
5506
|
-
} else
|
|
5507
|
-
|
|
6401
|
+
if (sameAsPrevious) {
|
|
6402
|
+
connectivityData.adoptFrom(previousConnectivityData);
|
|
6403
|
+
} else {
|
|
6404
|
+
connectivityData.initEmpty(this._cornerTable);
|
|
6405
|
+
connectivityData.reserveSeamEdges(seamCount);
|
|
6406
|
+
for (let s = 0; s < seamCount; ++s) {
|
|
6407
|
+
connectivityData.addSeamEdge(seamCorners[s]);
|
|
6408
|
+
}
|
|
6409
|
+
if (!connectivityData.recomputeVertices(null, null)) {
|
|
6410
|
+
return false;
|
|
6411
|
+
}
|
|
5508
6412
|
}
|
|
5509
6413
|
previousConnectivityData = connectivityData;
|
|
6414
|
+
previousSeamCorners = seamCorners;
|
|
6415
|
+
previousSeamCount = seamCount;
|
|
5510
6416
|
}
|
|
5511
6417
|
this._posEncodingData.init(this._cornerTable.numVertices());
|
|
5512
6418
|
for (let i = 0; i < this._attributeData.length; ++i) {
|
|
@@ -5545,39 +6451,27 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5545
6451
|
const activeCornerStack = scratchInt32(numSymbols + this._topologySplitData.length + 16);
|
|
5546
6452
|
let activeCornerStackSize = 0;
|
|
5547
6453
|
const topologySplitActiveCorners = /* @__PURE__ */ new Map();
|
|
6454
|
+
const splitResult = { faceEdge: 0, encoderSplitSymbolId: 0 };
|
|
5548
6455
|
const invalidVertices = [];
|
|
5549
6456
|
const removeInvalidVertices = this._attributeData.length === 0;
|
|
5550
6457
|
let maxNumVertices = this._isVertHole.length;
|
|
5551
6458
|
let numFacesDecoded = 0;
|
|
5552
6459
|
const cornerToVertex = this._cornerTable._cornerToVertex;
|
|
5553
6460
|
const oppositeCorners = this._cornerTable._oppositeCorners;
|
|
5554
|
-
const numCorners = this._cornerTable.numCorners();
|
|
5555
|
-
const next = (c) => c < 0 ? -1 : c % 3 === 2 ? c - 2 : c + 1;
|
|
5556
|
-
const prev = (c) => c < 0 ? -1 : c % 3 === 0 ? c + 2 : c - 1;
|
|
5557
|
-
const vertex = (c) => c < 0 || c >= numCorners ? -1 : cornerToVertex[c];
|
|
5558
|
-
const opposite = (c) => c < 0 || c >= numCorners ? -1 : oppositeCorners[c];
|
|
5559
|
-
const leftMostCorner = (v) => v < 0 || v >= this._cornerTable._vertexCorners.length ? -1 : this._cornerTable._vertexCorners[v];
|
|
5560
|
-
const swingLeft = (c) => {
|
|
5561
|
-
const n = next(c);
|
|
5562
|
-
const o = opposite(n);
|
|
5563
|
-
return o < 0 ? -1 : next(o);
|
|
5564
|
-
};
|
|
5565
|
-
const swingRight = (c) => {
|
|
5566
|
-
const p = prev(c);
|
|
5567
|
-
const o = opposite(p);
|
|
5568
|
-
return o < 0 ? -1 : prev(o);
|
|
5569
|
-
};
|
|
5570
6461
|
const vc = this._cornerTable;
|
|
6462
|
+
let vertexCorners = vc._vertexCorners;
|
|
6463
|
+
const isVertHole = this._isVertHole;
|
|
6464
|
+
const traversalDecoder = this._traversalDecoder;
|
|
5571
6465
|
for (let symbolId = 0; symbolId < numSymbols; ++symbolId) {
|
|
5572
6466
|
const faceIndex = numFacesDecoded++;
|
|
5573
6467
|
let checkTopologySplit = false;
|
|
5574
|
-
const symbol =
|
|
6468
|
+
const symbol = traversalDecoder.decodeSymbol();
|
|
5575
6469
|
if (symbol === TOPOLOGY_C) {
|
|
5576
6470
|
if (activeCornerStackSize === 0) return -1;
|
|
5577
6471
|
const cornerA = activeCornerStack[activeCornerStackSize - 1];
|
|
5578
6472
|
const nA = cornerA % 3 === 2 ? cornerA - 2 : cornerA + 1;
|
|
5579
6473
|
const vertexX = cornerToVertex[nA];
|
|
5580
|
-
const lmcX =
|
|
6474
|
+
const lmcX = vertexCorners[vertexX];
|
|
5581
6475
|
const cornerB = lmcX % 3 === 2 ? lmcX - 2 : lmcX + 1;
|
|
5582
6476
|
if (cornerA === cornerB) return -1;
|
|
5583
6477
|
if (oppositeCorners[cornerA] !== kInvalidCornerIndex6 || oppositeCorners[cornerB] !== kInvalidCornerIndex6) {
|
|
@@ -5596,8 +6490,8 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5596
6490
|
cornerToVertex[corner] = vertexX;
|
|
5597
6491
|
cornerToVertex[corner + 1] = vertBNext;
|
|
5598
6492
|
cornerToVertex[corner + 2] = vertAPrev;
|
|
5599
|
-
|
|
5600
|
-
|
|
6493
|
+
vertexCorners[vertAPrev] = corner + 2;
|
|
6494
|
+
isVertHole[vertexX] = 0;
|
|
5601
6495
|
activeCornerStack[activeCornerStackSize - 1] = corner;
|
|
5602
6496
|
} else if (symbol === TOPOLOGY_R || symbol === TOPOLOGY_L) {
|
|
5603
6497
|
if (activeCornerStackSize === 0) return -1;
|
|
@@ -5618,14 +6512,20 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5618
6512
|
}
|
|
5619
6513
|
oppositeCorners[oppCorner] = cornerA;
|
|
5620
6514
|
oppositeCorners[cornerA] = oppCorner;
|
|
5621
|
-
|
|
5622
|
-
if (
|
|
6515
|
+
let newVertIndex;
|
|
6516
|
+
if (vc._numVertices < vertexCorners.length) {
|
|
6517
|
+
newVertIndex = vc._numVertices++;
|
|
6518
|
+
} else {
|
|
6519
|
+
newVertIndex = vc.addNewVertex();
|
|
6520
|
+
vertexCorners = vc._vertexCorners;
|
|
6521
|
+
}
|
|
6522
|
+
if (vc._numVertices > maxNumVertices) return -1;
|
|
5623
6523
|
cornerToVertex[oppCorner] = newVertIndex;
|
|
5624
|
-
|
|
6524
|
+
vertexCorners[newVertIndex] = oppCorner;
|
|
5625
6525
|
const pA = cornerA % 3 === 0 ? cornerA + 2 : cornerA - 1;
|
|
5626
6526
|
const vertexR = cornerToVertex[pA];
|
|
5627
6527
|
cornerToVertex[cornerR] = vertexR;
|
|
5628
|
-
|
|
6528
|
+
vertexCorners[vertexR] = cornerR;
|
|
5629
6529
|
const nA = cornerA % 3 === 2 ? cornerA - 2 : cornerA + 1;
|
|
5630
6530
|
cornerToVertex[cornerL] = cornerToVertex[nA];
|
|
5631
6531
|
activeCornerStack[activeCornerStackSize - 1] = corner;
|
|
@@ -5657,11 +6557,11 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5657
6557
|
const pB = cornerB % 3 === 0 ? cornerB + 2 : cornerB - 1;
|
|
5658
6558
|
const vertBPrev = cornerToVertex[pB];
|
|
5659
6559
|
cornerToVertex[corner + 2] = vertBPrev;
|
|
5660
|
-
|
|
6560
|
+
vertexCorners[vertBPrev] = corner + 2;
|
|
5661
6561
|
let cornerN = cornerB % 3 === 2 ? cornerB - 2 : cornerB + 1;
|
|
5662
6562
|
const vertexN = cornerToVertex[cornerN];
|
|
5663
|
-
|
|
5664
|
-
|
|
6563
|
+
traversalDecoder.mergeVertices(vertexP, vertexN);
|
|
6564
|
+
vertexCorners[vertexP] = vertexCorners[vertexN];
|
|
5665
6565
|
const firstCorner = cornerN;
|
|
5666
6566
|
while (cornerN !== kInvalidCornerIndex6) {
|
|
5667
6567
|
cornerToVertex[cornerN] = vertexP;
|
|
@@ -5672,32 +6572,38 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5672
6572
|
return -1;
|
|
5673
6573
|
}
|
|
5674
6574
|
}
|
|
5675
|
-
|
|
6575
|
+
vertexCorners[vertexN] = -1;
|
|
5676
6576
|
if (removeInvalidVertices) {
|
|
5677
6577
|
invalidVertices.push(vertexN);
|
|
5678
6578
|
}
|
|
5679
6579
|
activeCornerStack[activeCornerStackSize - 1] = corner;
|
|
5680
6580
|
} else if (symbol === TOPOLOGY_E) {
|
|
5681
6581
|
const corner = 3 * faceIndex;
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
6582
|
+
let firstVertIndex;
|
|
6583
|
+
if (vc._numVertices + 3 <= vertexCorners.length) {
|
|
6584
|
+
firstVertIndex = vc._numVertices;
|
|
6585
|
+
vc._numVertices += 3;
|
|
6586
|
+
} else {
|
|
6587
|
+
firstVertIndex = vc.addNewVertex();
|
|
6588
|
+
vc.addNewVertex();
|
|
6589
|
+
vc.addNewVertex();
|
|
6590
|
+
vertexCorners = vc._vertexCorners;
|
|
6591
|
+
}
|
|
6592
|
+
if (vc._numVertices > maxNumVertices) return -1;
|
|
5686
6593
|
cornerToVertex[corner] = firstVertIndex;
|
|
5687
6594
|
cornerToVertex[corner + 1] = firstVertIndex + 1;
|
|
5688
6595
|
cornerToVertex[corner + 2] = firstVertIndex + 2;
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
6596
|
+
vertexCorners[firstVertIndex] = corner;
|
|
6597
|
+
vertexCorners[firstVertIndex + 1] = corner + 1;
|
|
6598
|
+
vertexCorners[firstVertIndex + 2] = corner + 2;
|
|
5692
6599
|
activeCornerStack[activeCornerStackSize++] = corner;
|
|
5693
6600
|
checkTopologySplit = true;
|
|
5694
6601
|
} else {
|
|
5695
6602
|
return -1;
|
|
5696
6603
|
}
|
|
5697
|
-
|
|
5698
|
-
if (checkTopologySplit) {
|
|
6604
|
+
traversalDecoder.newActiveCornerReached(activeCornerStack[activeCornerStackSize - 1]);
|
|
6605
|
+
if (checkTopologySplit && this._topologySplitData.length > 0) {
|
|
5699
6606
|
const encoderSymbolId = numSymbols - symbolId - 1;
|
|
5700
|
-
const splitResult = { faceEdge: 0, encoderSplitSymbolId: 0 };
|
|
5701
6607
|
while (this._isTopologySplit(encoderSymbolId, splitResult)) {
|
|
5702
6608
|
if (splitResult.encoderSplitSymbolId < 0) return -1;
|
|
5703
6609
|
const actTopCorner = activeCornerStack[activeCornerStackSize - 1];
|
|
@@ -5712,15 +6618,39 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5712
6618
|
}
|
|
5713
6619
|
}
|
|
5714
6620
|
}
|
|
5715
|
-
if (
|
|
6621
|
+
if (vc._numVertices > maxNumVertices) {
|
|
6622
|
+
return -1;
|
|
6623
|
+
}
|
|
6624
|
+
numFacesDecoded = this._decodeStartFaces(activeCornerStack, activeCornerStackSize, numFacesDecoded);
|
|
6625
|
+
if (numFacesDecoded === -1) {
|
|
6626
|
+
return -1;
|
|
6627
|
+
}
|
|
6628
|
+
if (numFacesDecoded !== this._cornerTable.numFaces()) {
|
|
5716
6629
|
return -1;
|
|
5717
6630
|
}
|
|
6631
|
+
return this._removeInvalidVertices(invalidVertices);
|
|
6632
|
+
}
|
|
6633
|
+
// Connects the remaining active-stack corners to newly decoded start faces.
|
|
6634
|
+
// Returns the updated decoded-face count, or -1 on malformed input.
|
|
6635
|
+
_decodeStartFaces(activeCornerStack, activeCornerStackSize, numFacesDecoded) {
|
|
6636
|
+
const ct = this._cornerTable;
|
|
6637
|
+
const cornerToVertex = ct._cornerToVertex;
|
|
6638
|
+
const oppositeCorners = ct._oppositeCorners;
|
|
6639
|
+
const vertexCorners = ct._vertexCorners;
|
|
6640
|
+
const isVertHole = this._isVertHole;
|
|
6641
|
+
const traversalDecoder = this._traversalDecoder;
|
|
6642
|
+
const numCorners = ct.numCorners();
|
|
6643
|
+
const numFaces = ct.numFaces();
|
|
6644
|
+
const next = (c) => c < 0 ? -1 : c % 3 === 2 ? c - 2 : c + 1;
|
|
6645
|
+
const vertex = (c) => c < 0 || c >= numCorners ? -1 : cornerToVertex[c];
|
|
6646
|
+
const opposite = (c) => c < 0 || c >= numCorners ? -1 : oppositeCorners[c];
|
|
6647
|
+
const leftMostCorner = (v) => v < 0 || v >= vertexCorners.length ? -1 : vertexCorners[v];
|
|
5718
6648
|
while (activeCornerStackSize > 0) {
|
|
5719
6649
|
const corner = activeCornerStack[activeCornerStackSize - 1];
|
|
5720
6650
|
activeCornerStackSize--;
|
|
5721
|
-
const interiorFace =
|
|
6651
|
+
const interiorFace = traversalDecoder.decodeStartFaceConfiguration();
|
|
5722
6652
|
if (interiorFace) {
|
|
5723
|
-
if (numFacesDecoded >=
|
|
6653
|
+
if (numFacesDecoded >= numFaces) {
|
|
5724
6654
|
return -1;
|
|
5725
6655
|
}
|
|
5726
6656
|
const cornerA = corner;
|
|
@@ -5746,9 +6676,9 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5746
6676
|
cornerToVertex[newCorner] = vertX;
|
|
5747
6677
|
cornerToVertex[newCorner + 1] = vertP;
|
|
5748
6678
|
cornerToVertex[newCorner + 2] = vertN;
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
6679
|
+
isVertHole[vertX] = 0;
|
|
6680
|
+
isVertHole[vertP] = 0;
|
|
6681
|
+
isVertHole[vertN] = 0;
|
|
5752
6682
|
this._initFaceConfigurations.push(true);
|
|
5753
6683
|
this._initCorners.push(newCorner);
|
|
5754
6684
|
} else {
|
|
@@ -5756,10 +6686,34 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5756
6686
|
this._initCorners.push(corner);
|
|
5757
6687
|
}
|
|
5758
6688
|
}
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
6689
|
+
return numFacesDecoded;
|
|
6690
|
+
}
|
|
6691
|
+
// Removes invalid (isolated) vertices by swapping them with the last valid
|
|
6692
|
+
// vertex in the table, matching C++ mesh_edgebreaker_decoder_impl.cc (the
|
|
6693
|
+
// forward iteration order matters). Returns the final vertex count, or -1.
|
|
6694
|
+
_removeInvalidVertices(invalidVertices) {
|
|
6695
|
+
const ct = this._cornerTable;
|
|
6696
|
+
const cornerToVertex = ct._cornerToVertex;
|
|
6697
|
+
const oppositeCorners = ct._oppositeCorners;
|
|
6698
|
+
const vertexCorners = ct._vertexCorners;
|
|
6699
|
+
const isVertHole = this._isVertHole;
|
|
6700
|
+
const numCorners = ct.numCorners();
|
|
6701
|
+
const next = (c) => c < 0 ? -1 : c % 3 === 2 ? c - 2 : c + 1;
|
|
6702
|
+
const prev = (c) => c < 0 ? -1 : c % 3 === 0 ? c + 2 : c - 1;
|
|
6703
|
+
const vertex = (c) => c < 0 || c >= numCorners ? -1 : cornerToVertex[c];
|
|
6704
|
+
const opposite = (c) => c < 0 || c >= numCorners ? -1 : oppositeCorners[c];
|
|
6705
|
+
const leftMostCorner = (v) => v < 0 || v >= vertexCorners.length ? -1 : vertexCorners[v];
|
|
6706
|
+
const swingLeft = (c) => {
|
|
6707
|
+
const n = next(c);
|
|
6708
|
+
const o = opposite(n);
|
|
6709
|
+
return o < 0 ? -1 : next(o);
|
|
6710
|
+
};
|
|
6711
|
+
const swingRight = (c) => {
|
|
6712
|
+
const p = prev(c);
|
|
6713
|
+
const o = opposite(p);
|
|
6714
|
+
return o < 0 ? -1 : prev(o);
|
|
6715
|
+
};
|
|
6716
|
+
let numVertices = ct.numVertices();
|
|
5763
6717
|
for (let ivIdx = 0; ivIdx < invalidVertices.length; ++ivIdx) {
|
|
5764
6718
|
const invalidVert = invalidVertices[ivIdx];
|
|
5765
6719
|
let srcVert = numVertices - 1;
|
|
@@ -5789,10 +6743,10 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5789
6743
|
cid = swingRight(cid);
|
|
5790
6744
|
}
|
|
5791
6745
|
}
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
6746
|
+
vertexCorners[invalidVert] = leftMostCorner(srcVert);
|
|
6747
|
+
vertexCorners[srcVert] = -1;
|
|
6748
|
+
isVertHole[invalidVert] = isVertHole[srcVert];
|
|
6749
|
+
isVertHole[srcVert] = 0;
|
|
5796
6750
|
numVertices--;
|
|
5797
6751
|
}
|
|
5798
6752
|
return numVertices;
|
|
@@ -5835,14 +6789,55 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5835
6789
|
// per-corner decodeNextBit work. Within each face the three corners are
|
|
5836
6790
|
// visited in encoder edge order [base, next, prev] = [c, c+1, c+2] (the
|
|
5837
6791
|
// caller always starts a face at its base corner, so next/prev need no wrap).
|
|
6792
|
+
//
|
|
6793
|
+
// The face comparison the C++ makes -- floor(oppCorner/3) >= floor(cc/3) for
|
|
6794
|
+
// the face's base corner -- is just `oppCorner >= faceBaseCorner`, since the
|
|
6795
|
+
// base corner is a multiple of 3. That removes the per-corner division; the
|
|
6796
|
+
// invalid-corner case (-1) is still handled by the branch above it.
|
|
5838
6797
|
_decodeAttributeConnectivities() {
|
|
5839
6798
|
const oppositeCorners = this._cornerTable.oppositeCornerArray();
|
|
5840
6799
|
const attributeData = this._attributeData;
|
|
5841
6800
|
const numAttrData = attributeData.length;
|
|
5842
6801
|
const connectivityDecoders = this._traversalDecoder._attributeConnectivityDecoders;
|
|
5843
6802
|
const numCorners = this._cornerTable.numCorners();
|
|
6803
|
+
if (numAttrData === 1) {
|
|
6804
|
+
const ad = attributeData[0];
|
|
6805
|
+
const seamCorners = ad.attributeSeamCorners;
|
|
6806
|
+
let numSeamCorners = ad.numSeamCorners;
|
|
6807
|
+
const decoder = connectivityDecoders[0];
|
|
6808
|
+
const ans = decoder.ansDecoder_;
|
|
6809
|
+
const p = decoder.p_;
|
|
6810
|
+
const buf = ans.buf;
|
|
6811
|
+
const bufStart = ans.bufStart;
|
|
6812
|
+
let state = ans.state;
|
|
6813
|
+
let bufOffset = ans.bufOffset;
|
|
6814
|
+
for (let corner = 0; corner < numCorners; corner += 3) {
|
|
6815
|
+
for (let k = 0; k < 3; ++k) {
|
|
6816
|
+
const cc = corner + k;
|
|
6817
|
+
const oppCorner = oppositeCorners[cc];
|
|
6818
|
+
if (oppCorner === kInvalidCornerIndex6) {
|
|
6819
|
+
seamCorners[numSeamCorners++] = cc;
|
|
6820
|
+
} else if (oppCorner >= corner) {
|
|
6821
|
+
if (state < ANS_L_BASE && bufOffset > bufStart) {
|
|
6822
|
+
state = state << 8 | buf[--bufOffset];
|
|
6823
|
+
}
|
|
6824
|
+
const rem = state & 255;
|
|
6825
|
+
const xn = (state >>> 8) * p;
|
|
6826
|
+
if (rem < p) {
|
|
6827
|
+
state = xn + rem;
|
|
6828
|
+
seamCorners[numSeamCorners++] = cc;
|
|
6829
|
+
} else {
|
|
6830
|
+
state = state - xn - p;
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
ans.state = state;
|
|
6836
|
+
ans.bufOffset = bufOffset;
|
|
6837
|
+
ad.numSeamCorners = numSeamCorners;
|
|
6838
|
+
return;
|
|
6839
|
+
}
|
|
5844
6840
|
for (let corner = 0; corner < numCorners; corner += 3) {
|
|
5845
|
-
const srcFaceId = corner / 3 | 0;
|
|
5846
6841
|
for (let k = 0; k < 3; ++k) {
|
|
5847
6842
|
const cc = corner + k;
|
|
5848
6843
|
const oppCorner = oppositeCorners[cc];
|
|
@@ -5851,7 +6846,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5851
6846
|
const ad = attributeData[i];
|
|
5852
6847
|
ad.attributeSeamCorners[ad.numSeamCorners++] = cc;
|
|
5853
6848
|
}
|
|
5854
|
-
} else if (
|
|
6849
|
+
} else if (oppCorner >= corner) {
|
|
5855
6850
|
for (let i = 0; i < numAttrData; ++i) {
|
|
5856
6851
|
if (connectivityDecoders[i].decodeNextBit()) {
|
|
5857
6852
|
const ad = attributeData[i];
|
|
@@ -5882,10 +6877,10 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5882
6877
|
const attributeData = this._attributeData;
|
|
5883
6878
|
const numAttrData = attributeData.length;
|
|
5884
6879
|
let numPoints = 0;
|
|
5885
|
-
const cornerToPointMap =
|
|
6880
|
+
const cornerToPointMap = scratchInt32(ct.numCorners());
|
|
5886
6881
|
const numVertices = ct.numVertices();
|
|
5887
6882
|
const vertexLeftmost = ct.vertexLeftmostCornerArray();
|
|
5888
|
-
const
|
|
6883
|
+
const swingRight = ct.swingRightArray();
|
|
5889
6884
|
const _baseCornerToVertex = ct.cornerToVertexArray();
|
|
5890
6885
|
const isVertHole = this._isVertHole;
|
|
5891
6886
|
const attCornerToVertex = new Array(numAttrData);
|
|
@@ -5899,7 +6894,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5899
6894
|
if (numAttrData === 1) {
|
|
5900
6895
|
anyAttVertexOnSeam = attVertexOnSeam[0];
|
|
5901
6896
|
} else {
|
|
5902
|
-
anyAttVertexOnSeam =
|
|
6897
|
+
anyAttVertexOnSeam = scratchUint8Zeroed(numVertices);
|
|
5903
6898
|
for (let i = 0; i < numAttrData; ++i) {
|
|
5904
6899
|
const attSeam = attVertexOnSeam[i];
|
|
5905
6900
|
for (let v = 0; v < numVertices; ++v) {
|
|
@@ -5917,37 +6912,24 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5917
6912
|
const initialC = c;
|
|
5918
6913
|
const pointId = numPoints++;
|
|
5919
6914
|
cornerToPointMap[initialC] = pointId;
|
|
5920
|
-
|
|
5921
|
-
let pv = rem === 0 ? initialC + 2 : initialC - 1;
|
|
5922
|
-
let opp = baseOpp[pv];
|
|
5923
|
-
c = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6915
|
+
c = swingRight[initialC];
|
|
5924
6916
|
while (c !== kInvalidCornerIndex6 && c !== initialC) {
|
|
5925
6917
|
cornerToPointMap[c] = pointId;
|
|
5926
|
-
|
|
5927
|
-
pv = rem === 0 ? c + 2 : c - 1;
|
|
5928
|
-
opp = baseOpp[pv];
|
|
5929
|
-
c = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6918
|
+
c = swingRight[c];
|
|
5930
6919
|
}
|
|
5931
6920
|
} else {
|
|
5932
6921
|
let deduplicationFirstCorner = c;
|
|
5933
|
-
let rem, pv, opp;
|
|
5934
6922
|
if (!isVertHole[v]) {
|
|
5935
6923
|
if (numAttrData === 1) {
|
|
5936
6924
|
const vertId = singleAttC2V[c];
|
|
5937
|
-
|
|
5938
|
-
pv = rem === 0 ? c + 2 : c - 1;
|
|
5939
|
-
opp = baseOpp[pv];
|
|
5940
|
-
let actC = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6925
|
+
let actC = swingRight[c];
|
|
5941
6926
|
while (actC !== c) {
|
|
5942
6927
|
if (actC === kInvalidCornerIndex6) return false;
|
|
5943
6928
|
if (singleAttC2V[actC] !== vertId) {
|
|
5944
6929
|
deduplicationFirstCorner = actC;
|
|
5945
6930
|
break;
|
|
5946
6931
|
}
|
|
5947
|
-
|
|
5948
|
-
pv = rem === 0 ? actC + 2 : actC - 1;
|
|
5949
|
-
opp = baseOpp[pv];
|
|
5950
|
-
actC = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6932
|
+
actC = swingRight[actC];
|
|
5951
6933
|
}
|
|
5952
6934
|
} else {
|
|
5953
6935
|
for (let i = 0; i < numAttrData; ++i) {
|
|
@@ -5956,10 +6938,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5956
6938
|
}
|
|
5957
6939
|
const attC2V = attCornerToVertex[i];
|
|
5958
6940
|
const vertId = attC2V[c];
|
|
5959
|
-
|
|
5960
|
-
pv = rem === 0 ? c + 2 : c - 1;
|
|
5961
|
-
opp = baseOpp[pv];
|
|
5962
|
-
let actC = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6941
|
+
let actC = swingRight[c];
|
|
5963
6942
|
let seamFound = false;
|
|
5964
6943
|
while (actC !== c) {
|
|
5965
6944
|
if (actC === kInvalidCornerIndex6) return false;
|
|
@@ -5968,10 +6947,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5968
6947
|
seamFound = true;
|
|
5969
6948
|
break;
|
|
5970
6949
|
}
|
|
5971
|
-
|
|
5972
|
-
pv = rem === 0 ? actC + 2 : actC - 1;
|
|
5973
|
-
opp = baseOpp[pv];
|
|
5974
|
-
actC = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6950
|
+
actC = swingRight[actC];
|
|
5975
6951
|
}
|
|
5976
6952
|
if (seamFound) break;
|
|
5977
6953
|
}
|
|
@@ -5980,10 +6956,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
5980
6956
|
c = deduplicationFirstCorner;
|
|
5981
6957
|
cornerToPointMap[c] = numPoints++;
|
|
5982
6958
|
let prevC = c;
|
|
5983
|
-
|
|
5984
|
-
pv = rem === 0 ? c + 2 : c - 1;
|
|
5985
|
-
opp = baseOpp[pv];
|
|
5986
|
-
c = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6959
|
+
c = swingRight[c];
|
|
5987
6960
|
while (c !== kInvalidCornerIndex6 && c !== deduplicationFirstCorner) {
|
|
5988
6961
|
let attributeSeam;
|
|
5989
6962
|
if (numAttrData === 1) {
|
|
@@ -6004,10 +6977,7 @@ var MeshEdgebreakerDecoderImpl = class {
|
|
|
6004
6977
|
cornerToPointMap[c] = cornerToPointMap[prevC];
|
|
6005
6978
|
}
|
|
6006
6979
|
prevC = c;
|
|
6007
|
-
|
|
6008
|
-
pv = rem === 0 ? c + 2 : c - 1;
|
|
6009
|
-
opp = baseOpp[pv];
|
|
6010
|
-
c = opp < 0 ? kInvalidCornerIndex6 : opp % 3 === 0 ? opp + 2 : opp - 1;
|
|
6980
|
+
c = swingRight[c];
|
|
6011
6981
|
}
|
|
6012
6982
|
}
|
|
6013
6983
|
}
|
|
@@ -6033,8 +7003,8 @@ var MeshAttributeIndicesEncodingData = class {
|
|
|
6033
7003
|
this._numValues = 0;
|
|
6034
7004
|
}
|
|
6035
7005
|
init(numVertices) {
|
|
6036
|
-
this._vertexToEncodedAttributeValueIndexMap =
|
|
6037
|
-
this._encodedAttributeValueIndexToCornerMap =
|
|
7006
|
+
this._vertexToEncodedAttributeValueIndexMap = scratchInt32Filled(numVertices, -1);
|
|
7007
|
+
this._encodedAttributeValueIndexToCornerMap = scratchInt32(numVertices);
|
|
6038
7008
|
this._numValues = 0;
|
|
6039
7009
|
}
|
|
6040
7010
|
// Adopts a traversal result from an identical corner table, avoiding a
|
|
@@ -6084,6 +7054,8 @@ var CornerTable = class {
|
|
|
6084
7054
|
// corner -> opposite corner
|
|
6085
7055
|
_vertexCorners;
|
|
6086
7056
|
// vertex -> left-most corner
|
|
7057
|
+
_swingRight;
|
|
7058
|
+
// corner -> next corner around its vertex, CW
|
|
6087
7059
|
constructor() {
|
|
6088
7060
|
this._numFaces = 0;
|
|
6089
7061
|
this._numCorners = 0;
|
|
@@ -6091,16 +7063,42 @@ var CornerTable = class {
|
|
|
6091
7063
|
this._cornerToVertex = null;
|
|
6092
7064
|
this._oppositeCorners = null;
|
|
6093
7065
|
this._vertexCorners = null;
|
|
7066
|
+
this._swingRight = null;
|
|
6094
7067
|
}
|
|
6095
7068
|
reset(numFaces, numVertices) {
|
|
6096
7069
|
this._numFaces = numFaces;
|
|
6097
7070
|
this._numCorners = numFaces * 3;
|
|
6098
7071
|
this._numVertices = 0;
|
|
6099
|
-
this._cornerToVertex =
|
|
6100
|
-
this._oppositeCorners =
|
|
6101
|
-
this._vertexCorners =
|
|
7072
|
+
this._cornerToVertex = scratchInt32Filled(this._numCorners, -1);
|
|
7073
|
+
this._oppositeCorners = scratchInt32Filled(this._numCorners, -1);
|
|
7074
|
+
this._vertexCorners = scratchInt32Filled(numVertices, -1);
|
|
7075
|
+
this._swingRight = null;
|
|
6102
7076
|
return true;
|
|
6103
7077
|
}
|
|
7078
|
+
// swingRight(c) = previous(opposite(previous(c))) for every corner. Walking
|
|
7079
|
+
// the corner ring of a vertex is the inner loop of both the attribute-vertex
|
|
7080
|
+
// recompute and the point assignment, and each of those passes otherwise
|
|
7081
|
+
// pays two modulus-by-3 chains per step on top of the opposite lookup. Built
|
|
7082
|
+
// lazily -- callers only reach it once connectivity is final -- from
|
|
7083
|
+
// decode-scoped scratch, and dropped by reset().
|
|
7084
|
+
swingRightArray() {
|
|
7085
|
+
let table = this._swingRight;
|
|
7086
|
+
if (table === null) {
|
|
7087
|
+
const numCorners = this._numCorners;
|
|
7088
|
+
const opposite = this._oppositeCorners;
|
|
7089
|
+
table = scratchInt32(numCorners);
|
|
7090
|
+
for (let c = 0; c < numCorners; c += 3) {
|
|
7091
|
+
let o = opposite[c + 2];
|
|
7092
|
+
table[c] = o < 0 ? kInvalidCornerIndex6 : o % 3 === 0 ? o + 2 : o - 1;
|
|
7093
|
+
o = opposite[c];
|
|
7094
|
+
table[c + 1] = o < 0 ? kInvalidCornerIndex6 : o % 3 === 0 ? o + 2 : o - 1;
|
|
7095
|
+
o = opposite[c + 1];
|
|
7096
|
+
table[c + 2] = o < 0 ? kInvalidCornerIndex6 : o % 3 === 0 ? o + 2 : o - 1;
|
|
7097
|
+
}
|
|
7098
|
+
this._swingRight = table;
|
|
7099
|
+
}
|
|
7100
|
+
return table;
|
|
7101
|
+
}
|
|
6104
7102
|
numFaces() {
|
|
6105
7103
|
return this._numFaces;
|
|
6106
7104
|
}
|
|
@@ -6144,8 +7142,7 @@ var CornerTable = class {
|
|
|
6144
7142
|
this._numVertices++;
|
|
6145
7143
|
if (newVertex >= this._vertexCorners.length) {
|
|
6146
7144
|
const newCapacity = Math.max(newVertex + 1, this._vertexCorners.length * 2, 64);
|
|
6147
|
-
const newArr =
|
|
6148
|
-
newArr.fill(-1);
|
|
7145
|
+
const newArr = scratchInt32Filled(newCapacity, -1);
|
|
6149
7146
|
newArr.set(this._vertexCorners);
|
|
6150
7147
|
this._vertexCorners = newArr;
|
|
6151
7148
|
}
|
|
@@ -6176,6 +7173,10 @@ var MeshEdgebreakerTraversalDecoder = class {
|
|
|
6176
7173
|
_attributeConnectivityDecoders;
|
|
6177
7174
|
_numAttributeData;
|
|
6178
7175
|
_decoderImpl;
|
|
7176
|
+
// _symbolBuffer's bit cursor, captured once bit decoding starts: decodeSymbol
|
|
7177
|
+
// runs per decoded face and would otherwise reach it through two property
|
|
7178
|
+
// loads and a method call per read.
|
|
7179
|
+
_symbolBits;
|
|
6179
7180
|
constructor() {
|
|
6180
7181
|
this._buffer = new DecoderBuffer();
|
|
6181
7182
|
this._symbolBuffer = new DecoderBuffer();
|
|
@@ -6183,6 +7184,7 @@ var MeshEdgebreakerTraversalDecoder = class {
|
|
|
6183
7184
|
this._attributeConnectivityDecoders = null;
|
|
6184
7185
|
this._numAttributeData = 0;
|
|
6185
7186
|
this._decoderImpl = null;
|
|
7187
|
+
this._symbolBits = null;
|
|
6186
7188
|
}
|
|
6187
7189
|
init(decoder) {
|
|
6188
7190
|
this._decoderImpl = decoder;
|
|
@@ -6217,6 +7219,21 @@ var MeshEdgebreakerTraversalDecoder = class {
|
|
|
6217
7219
|
return this._startFaceDecoder.decodeNextBit() ? true : false;
|
|
6218
7220
|
}
|
|
6219
7221
|
decodeSymbol() {
|
|
7222
|
+
const bd = this._symbolBits;
|
|
7223
|
+
if (bd !== null) {
|
|
7224
|
+
const buf = bd._bitBuffer;
|
|
7225
|
+
const off = bd._bitOffset;
|
|
7226
|
+
const byteOffset = off >> 3;
|
|
7227
|
+
if (byteOffset + 4 < bd._byteLength) {
|
|
7228
|
+
const bits = (buf[byteOffset] | buf[byteOffset + 1] << 8 | buf[byteOffset + 2] << 16 | buf[byteOffset + 3] << 24) >>> (off & 7) & 7;
|
|
7229
|
+
if ((bits & 1) === TOPOLOGY_C) {
|
|
7230
|
+
bd._bitOffset = off + 1;
|
|
7231
|
+
return TOPOLOGY_C;
|
|
7232
|
+
}
|
|
7233
|
+
bd._bitOffset = off + 3;
|
|
7234
|
+
return bits;
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
6220
7237
|
let symbol = this._symbolBuffer.decodeLeastSignificantBits32(1);
|
|
6221
7238
|
if (symbol === TOPOLOGY_C) {
|
|
6222
7239
|
return symbol;
|
|
@@ -6246,6 +7263,7 @@ var MeshEdgebreakerTraversalDecoder = class {
|
|
|
6246
7263
|
if (traversalSize === void 0) {
|
|
6247
7264
|
return false;
|
|
6248
7265
|
}
|
|
7266
|
+
this._symbolBits = this._symbolBuffer._bitDecoder;
|
|
6249
7267
|
this._buffer.init(
|
|
6250
7268
|
this._symbolBuffer.dataHead,
|
|
6251
7269
|
this._symbolBuffer.remainingSize,
|
|
@@ -6398,7 +7416,13 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6398
7416
|
_maxValence;
|
|
6399
7417
|
_vertexValences;
|
|
6400
7418
|
_contextSymbols;
|
|
7419
|
+
// Int32Array, not number[]: read and written once per decoded symbol.
|
|
6401
7420
|
_contextCounters;
|
|
7421
|
+
// corner -> vertex of _cornerTable, cached at init(); the array is created
|
|
7422
|
+
// once by CornerTable.reset() before the traversal decoder is initialized and
|
|
7423
|
+
// never replaced, so the per-symbol hot path can read it without two property
|
|
7424
|
+
// loads.
|
|
7425
|
+
_cornerToVertex;
|
|
6402
7426
|
constructor() {
|
|
6403
7427
|
super();
|
|
6404
7428
|
this._cornerTable = null;
|
|
@@ -6409,11 +7433,13 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6409
7433
|
this._maxValence = 7;
|
|
6410
7434
|
this._vertexValences = new Int32Array(0);
|
|
6411
7435
|
this._contextSymbols = [];
|
|
6412
|
-
this._contextCounters =
|
|
7436
|
+
this._contextCounters = new Int32Array(0);
|
|
7437
|
+
this._cornerToVertex = new Int32Array(0);
|
|
6413
7438
|
}
|
|
6414
7439
|
init(decoder) {
|
|
6415
7440
|
super.init(decoder);
|
|
6416
7441
|
this._cornerTable = decoder.getCornerTable();
|
|
7442
|
+
this._cornerToVertex = this._cornerTable._cornerToVertex;
|
|
6417
7443
|
}
|
|
6418
7444
|
setNumEncodedVertices(numVertices) {
|
|
6419
7445
|
this._numVertices = numVertices;
|
|
@@ -6431,10 +7457,11 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6431
7457
|
if (this._numVertices < 0) {
|
|
6432
7458
|
return false;
|
|
6433
7459
|
}
|
|
6434
|
-
this._vertexValences =
|
|
7460
|
+
this._vertexValences = scratchInt32Filled(this._numVertices, 0);
|
|
6435
7461
|
const numUniqueValences = this._maxValence - this._minValence + 1;
|
|
6436
7462
|
this._contextSymbols = new Array(numUniqueValences);
|
|
6437
|
-
this._contextCounters = new
|
|
7463
|
+
this._contextCounters = new Int32Array(numUniqueValences);
|
|
7464
|
+
const pending = [];
|
|
6438
7465
|
for (let i = 0; i < numUniqueValences; ++i) {
|
|
6439
7466
|
const numSymbols = decodeVarint(outBuffer);
|
|
6440
7467
|
if (numSymbols === void 0) {
|
|
@@ -6444,16 +7471,73 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6444
7471
|
return false;
|
|
6445
7472
|
}
|
|
6446
7473
|
if (numSymbols > 0) {
|
|
6447
|
-
this._contextSymbols[i] =
|
|
6448
|
-
|
|
7474
|
+
this._contextSymbols[i] = scratchUint32(numSymbols);
|
|
7475
|
+
const scheme = outBuffer.decodeUint8();
|
|
7476
|
+
if (scheme === SymbolCodingMethod.SYMBOL_CODING_TAGGED) {
|
|
7477
|
+
if (!decodeTaggedSymbols(numSymbols, 1, outBuffer, this._contextSymbols[i])) {
|
|
7478
|
+
return false;
|
|
7479
|
+
}
|
|
7480
|
+
this._contextCounters[i] = numSymbols;
|
|
7481
|
+
continue;
|
|
7482
|
+
}
|
|
7483
|
+
if (scheme !== SymbolCodingMethod.SYMBOL_CODING_RAW) {
|
|
6449
7484
|
return false;
|
|
6450
7485
|
}
|
|
7486
|
+
const maxBitLength = outBuffer.decodeUint8();
|
|
7487
|
+
if (maxBitLength === void 0 || maxBitLength < 1 || maxBitLength > 18) {
|
|
7488
|
+
return false;
|
|
7489
|
+
}
|
|
7490
|
+
const decoder = new RAnsSymbolDecoder(maxBitLength);
|
|
7491
|
+
if (!decoder.create(outBuffer, numSymbols)) {
|
|
7492
|
+
return false;
|
|
7493
|
+
}
|
|
7494
|
+
if (decoder.numSymbols === 0) {
|
|
7495
|
+
return false;
|
|
7496
|
+
}
|
|
7497
|
+
if (!decoder.startDecoding(outBuffer)) {
|
|
7498
|
+
return false;
|
|
7499
|
+
}
|
|
7500
|
+
pending.push({ decoder, out: this._contextSymbols[i], count: numSymbols });
|
|
6451
7501
|
this._contextCounters[i] = numSymbols;
|
|
6452
7502
|
} else {
|
|
6453
7503
|
this._contextSymbols[i] = new Uint32Array(0);
|
|
6454
7504
|
this._contextCounters[i] = 0;
|
|
6455
7505
|
}
|
|
6456
7506
|
}
|
|
7507
|
+
const lockstep = pending.filter((entry) => entry.decoder.ans_.lutTable instanceof Uint8Array);
|
|
7508
|
+
let p = 0;
|
|
7509
|
+
while (lockstep.length - p >= 3) {
|
|
7510
|
+
const a = lockstep[p];
|
|
7511
|
+
const b = lockstep[p + 1];
|
|
7512
|
+
const c = lockstep[p + 2];
|
|
7513
|
+
ransDecodeSymbolsTrioU8(
|
|
7514
|
+
a.decoder.ans_,
|
|
7515
|
+
a.out,
|
|
7516
|
+
a.count,
|
|
7517
|
+
b.decoder.ans_,
|
|
7518
|
+
b.out,
|
|
7519
|
+
b.count,
|
|
7520
|
+
c.decoder.ans_,
|
|
7521
|
+
c.out,
|
|
7522
|
+
c.count
|
|
7523
|
+
);
|
|
7524
|
+
p += 3;
|
|
7525
|
+
}
|
|
7526
|
+
if (lockstep.length - p === 2) {
|
|
7527
|
+
const a = lockstep[p];
|
|
7528
|
+
const b = lockstep[p + 1];
|
|
7529
|
+
ransDecodeSymbolsPairU8(a.decoder.ans_, a.out, a.count, b.decoder.ans_, b.out, b.count);
|
|
7530
|
+
p += 2;
|
|
7531
|
+
}
|
|
7532
|
+
for (; p < lockstep.length; ++p) {
|
|
7533
|
+
lockstep[p].decoder.ans_.decodeSymbols(lockstep[p].out, lockstep[p].count);
|
|
7534
|
+
}
|
|
7535
|
+
for (const entry of pending) {
|
|
7536
|
+
if (!(entry.decoder.ans_.lutTable instanceof Uint8Array)) {
|
|
7537
|
+
entry.decoder.ans_.decodeSymbols(entry.out, entry.count);
|
|
7538
|
+
}
|
|
7539
|
+
entry.decoder.endDecoding();
|
|
7540
|
+
}
|
|
6457
7541
|
return true;
|
|
6458
7542
|
}
|
|
6459
7543
|
decodeSymbol() {
|
|
@@ -6473,7 +7557,7 @@ var MeshEdgebreakerTraversalValenceDecoder = class extends MeshEdgebreakerTraver
|
|
|
6473
7557
|
return this._lastSymbol;
|
|
6474
7558
|
}
|
|
6475
7559
|
newActiveCornerReached(corner) {
|
|
6476
|
-
const cornerToVertex = this.
|
|
7560
|
+
const cornerToVertex = this._cornerToVertex;
|
|
6477
7561
|
const valences = this._vertexValences;
|
|
6478
7562
|
const next = corner % 3 === 2 ? corner - 2 : corner + 1;
|
|
6479
7563
|
const prev = corner % 3 === 0 ? corner + 2 : corner - 1;
|