@playcanvas/splat-transform 1.9.0 → 1.9.2
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 +1 -1
- package/dist/cli.mjs +1547 -110
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +1523 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1523 -100
- package/dist/index.mjs.map +1 -1
- package/dist/lib/index.d.cts +2 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/spatial/kd-tree.d.ts +1 -0
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/utils/logger.d.ts +6 -0
- package/dist/lib/voxel/collision-glb.d.ts +12 -0
- package/dist/lib/voxel/index.d.ts +2 -0
- package/dist/lib/voxel/marching-cubes.d.ts +25 -0
- package/dist/lib/writers/write-voxel.d.ts +7 -1
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -11854,6 +11854,16 @@ class Progress {
|
|
|
11854
11854
|
if (!quiet)
|
|
11855
11855
|
impl.onProgress(this.currentNode);
|
|
11856
11856
|
}
|
|
11857
|
+
/**
|
|
11858
|
+
* Cancel the current progress node, popping it from the stack without
|
|
11859
|
+
* completing remaining steps. Use this before early exits (e.g. break)
|
|
11860
|
+
* to keep the progress stack balanced.
|
|
11861
|
+
*/
|
|
11862
|
+
cancel() {
|
|
11863
|
+
if (!this.currentNode)
|
|
11864
|
+
return;
|
|
11865
|
+
this.currentNode = this.currentNode.parent;
|
|
11866
|
+
}
|
|
11857
11867
|
/**
|
|
11858
11868
|
* Advance to the next step. Auto-increments the step counter.
|
|
11859
11869
|
* Auto-ends when all steps are complete.
|
|
@@ -12041,33 +12051,74 @@ const sortMortonOrder = (dataTable, indices) => {
|
|
|
12041
12051
|
generate(indices);
|
|
12042
12052
|
};
|
|
12043
12053
|
|
|
12054
|
+
const nthElement = (arr, lo, hi, k, values) => {
|
|
12055
|
+
while (lo < hi) {
|
|
12056
|
+
const mid = (lo + hi) >> 1;
|
|
12057
|
+
const va = values[arr[lo]], vb = values[arr[mid]], vc = values[arr[hi]];
|
|
12058
|
+
let pivotIdx;
|
|
12059
|
+
if ((vb - va) * (vc - vb) >= 0)
|
|
12060
|
+
pivotIdx = mid;
|
|
12061
|
+
else if ((va - vb) * (vc - va) >= 0)
|
|
12062
|
+
pivotIdx = lo;
|
|
12063
|
+
else
|
|
12064
|
+
pivotIdx = hi;
|
|
12065
|
+
const pivotVal = values[arr[pivotIdx]];
|
|
12066
|
+
let tmp = arr[pivotIdx];
|
|
12067
|
+
arr[pivotIdx] = arr[hi];
|
|
12068
|
+
arr[hi] = tmp;
|
|
12069
|
+
let store = lo;
|
|
12070
|
+
for (let i = lo; i < hi; i++) {
|
|
12071
|
+
if (values[arr[i]] < pivotVal) {
|
|
12072
|
+
tmp = arr[i];
|
|
12073
|
+
arr[i] = arr[store];
|
|
12074
|
+
arr[store] = tmp;
|
|
12075
|
+
store++;
|
|
12076
|
+
}
|
|
12077
|
+
}
|
|
12078
|
+
tmp = arr[store];
|
|
12079
|
+
arr[store] = arr[hi];
|
|
12080
|
+
arr[hi] = tmp;
|
|
12081
|
+
if (store === k)
|
|
12082
|
+
return;
|
|
12083
|
+
else if (store < k)
|
|
12084
|
+
lo = store + 1;
|
|
12085
|
+
else
|
|
12086
|
+
hi = store - 1;
|
|
12087
|
+
}
|
|
12088
|
+
};
|
|
12044
12089
|
class KdTree {
|
|
12045
12090
|
centroids;
|
|
12046
12091
|
root;
|
|
12092
|
+
colData;
|
|
12047
12093
|
constructor(centroids) {
|
|
12048
|
-
const
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12094
|
+
const numCols = centroids.numColumns;
|
|
12095
|
+
const colData = centroids.columns.map(c => c.data);
|
|
12096
|
+
const indices = new Uint32Array(centroids.numRows);
|
|
12097
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
12098
|
+
indices[i] = i;
|
|
12099
|
+
}
|
|
12100
|
+
const build = (lo, hi, depth) => {
|
|
12101
|
+
const count = hi - lo + 1;
|
|
12102
|
+
if (count === 1) {
|
|
12103
|
+
return { index: indices[lo], count: 1 };
|
|
12057
12104
|
}
|
|
12058
|
-
|
|
12105
|
+
const values = colData[depth % numCols];
|
|
12106
|
+
if (count === 2) {
|
|
12107
|
+
if (values[indices[lo]] > values[indices[hi]]) {
|
|
12108
|
+
const tmp = indices[lo];
|
|
12109
|
+
indices[lo] = indices[hi];
|
|
12110
|
+
indices[hi] = tmp;
|
|
12111
|
+
}
|
|
12059
12112
|
return {
|
|
12060
|
-
index: indices[
|
|
12113
|
+
index: indices[lo],
|
|
12061
12114
|
count: 2,
|
|
12062
|
-
right: {
|
|
12063
|
-
index: indices[1],
|
|
12064
|
-
count: 1
|
|
12065
|
-
}
|
|
12115
|
+
right: { index: indices[hi], count: 1 }
|
|
12066
12116
|
};
|
|
12067
12117
|
}
|
|
12068
|
-
const mid =
|
|
12069
|
-
|
|
12070
|
-
const
|
|
12118
|
+
const mid = lo + (count >> 1);
|
|
12119
|
+
nthElement(indices, lo, hi, mid, values);
|
|
12120
|
+
const left = build(lo, mid - 1, depth + 1);
|
|
12121
|
+
const right = build(mid + 1, hi, depth + 1);
|
|
12071
12122
|
return {
|
|
12072
12123
|
index: indices[mid],
|
|
12073
12124
|
count: 1 + left.count + right.count,
|
|
@@ -12075,48 +12126,39 @@ class KdTree {
|
|
|
12075
12126
|
right
|
|
12076
12127
|
};
|
|
12077
12128
|
};
|
|
12078
|
-
const indices = new Uint32Array(centroids.numRows);
|
|
12079
|
-
for (let i = 0; i < indices.length; ++i) {
|
|
12080
|
-
indices[i] = i;
|
|
12081
|
-
}
|
|
12082
12129
|
this.centroids = centroids;
|
|
12083
|
-
this.
|
|
12130
|
+
this.colData = colData;
|
|
12131
|
+
this.root = build(0, indices.length - 1, 0);
|
|
12084
12132
|
}
|
|
12085
12133
|
findNearest(point, filterFunc) {
|
|
12086
|
-
const
|
|
12087
|
-
const
|
|
12088
|
-
const calcDistance = (index) => {
|
|
12089
|
-
let l = 0;
|
|
12090
|
-
for (let i = 0; i < numColumns; ++i) {
|
|
12091
|
-
const v = centroids.columns[i].data[index] - point[i];
|
|
12092
|
-
l += v * v;
|
|
12093
|
-
}
|
|
12094
|
-
return l;
|
|
12095
|
-
};
|
|
12134
|
+
const colData = this.colData;
|
|
12135
|
+
const numCols = colData.length;
|
|
12096
12136
|
let mind = Infinity;
|
|
12097
12137
|
let mini = -1;
|
|
12098
12138
|
let cnt = 0;
|
|
12099
|
-
const recurse = (node,
|
|
12100
|
-
const
|
|
12101
|
-
const distance = point[axis] - centroids.columns[axis].data[node.index];
|
|
12139
|
+
const recurse = (node, axis) => {
|
|
12140
|
+
const distance = point[axis] - colData[axis][node.index];
|
|
12102
12141
|
const next = (distance > 0) ? node.right : node.left;
|
|
12142
|
+
const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
|
|
12103
12143
|
cnt++;
|
|
12104
12144
|
if (next) {
|
|
12105
|
-
recurse(next,
|
|
12145
|
+
recurse(next, nextAxis);
|
|
12106
12146
|
}
|
|
12107
|
-
// check index
|
|
12108
12147
|
if (!filterFunc || filterFunc(node.index)) {
|
|
12109
|
-
|
|
12148
|
+
let thisd = 0;
|
|
12149
|
+
for (let c = 0; c < numCols; c++) {
|
|
12150
|
+
const v = colData[c][node.index] - point[c];
|
|
12151
|
+
thisd += v * v;
|
|
12152
|
+
}
|
|
12110
12153
|
if (thisd < mind) {
|
|
12111
12154
|
mind = thisd;
|
|
12112
12155
|
mini = node.index;
|
|
12113
12156
|
}
|
|
12114
12157
|
}
|
|
12115
|
-
// check the other side
|
|
12116
12158
|
if (distance * distance < mind) {
|
|
12117
12159
|
const other = next === node.right ? node.left : node.right;
|
|
12118
12160
|
if (other) {
|
|
12119
|
-
recurse(other,
|
|
12161
|
+
recurse(other, nextAxis);
|
|
12120
12162
|
}
|
|
12121
12163
|
}
|
|
12122
12164
|
};
|
|
@@ -12128,16 +12170,8 @@ class KdTree {
|
|
|
12128
12170
|
return { indices: new Int32Array(0), distances: new Float32Array(0) };
|
|
12129
12171
|
}
|
|
12130
12172
|
k = Math.min(k, this.centroids.numRows);
|
|
12131
|
-
const
|
|
12132
|
-
const
|
|
12133
|
-
const calcDistance = (index) => {
|
|
12134
|
-
let l = 0;
|
|
12135
|
-
for (let i = 0; i < numColumns; ++i) {
|
|
12136
|
-
const v = centroids.columns[i].data[index] - point[i];
|
|
12137
|
-
l += v * v;
|
|
12138
|
-
}
|
|
12139
|
-
return l;
|
|
12140
|
-
};
|
|
12173
|
+
const colData = this.colData;
|
|
12174
|
+
const numCols = colData.length;
|
|
12141
12175
|
// Bounded max-heap: stores (distance, index) pairs sorted so the
|
|
12142
12176
|
// farthest element is at position 0, enabling O(1) pruning bound.
|
|
12143
12177
|
const heapDist = new Float32Array(k).fill(Infinity);
|
|
@@ -12145,14 +12179,12 @@ class KdTree {
|
|
|
12145
12179
|
let heapSize = 0;
|
|
12146
12180
|
const heapPush = (dist, idx) => {
|
|
12147
12181
|
if (heapSize < k) {
|
|
12148
|
-
// Heap not full yet -- insert via sift-up
|
|
12149
12182
|
let pos = heapSize++;
|
|
12150
12183
|
heapDist[pos] = dist;
|
|
12151
12184
|
heapIdx[pos] = idx;
|
|
12152
12185
|
while (pos > 0) {
|
|
12153
12186
|
const parent = (pos - 1) >> 1;
|
|
12154
12187
|
if (heapDist[parent] < heapDist[pos]) {
|
|
12155
|
-
// swap
|
|
12156
12188
|
const td = heapDist[parent];
|
|
12157
12189
|
heapDist[parent] = heapDist[pos];
|
|
12158
12190
|
heapDist[pos] = td;
|
|
@@ -12167,7 +12199,6 @@ class KdTree {
|
|
|
12167
12199
|
}
|
|
12168
12200
|
}
|
|
12169
12201
|
else if (dist < heapDist[0]) {
|
|
12170
|
-
// Replace root (farthest) and sift-down
|
|
12171
12202
|
heapDist[0] = dist;
|
|
12172
12203
|
heapIdx[0] = idx;
|
|
12173
12204
|
let pos = 0;
|
|
@@ -12191,22 +12222,26 @@ class KdTree {
|
|
|
12191
12222
|
}
|
|
12192
12223
|
}
|
|
12193
12224
|
};
|
|
12194
|
-
const recurse = (node,
|
|
12195
|
-
const
|
|
12196
|
-
const distance = point[axis] - centroids.columns[axis].data[node.index];
|
|
12225
|
+
const recurse = (node, axis) => {
|
|
12226
|
+
const distance = point[axis] - colData[axis][node.index];
|
|
12197
12227
|
const next = (distance > 0) ? node.right : node.left;
|
|
12228
|
+
const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
|
|
12198
12229
|
if (next) {
|
|
12199
|
-
recurse(next,
|
|
12230
|
+
recurse(next, nextAxis);
|
|
12200
12231
|
}
|
|
12201
12232
|
if (!filterFunc || filterFunc(node.index)) {
|
|
12202
|
-
|
|
12233
|
+
let thisd = 0;
|
|
12234
|
+
for (let c = 0; c < numCols; c++) {
|
|
12235
|
+
const v = colData[c][node.index] - point[c];
|
|
12236
|
+
thisd += v * v;
|
|
12237
|
+
}
|
|
12203
12238
|
heapPush(thisd, node.index);
|
|
12204
12239
|
}
|
|
12205
12240
|
const bound = heapSize < k ? Infinity : heapDist[0];
|
|
12206
12241
|
if (distance * distance < bound) {
|
|
12207
12242
|
const other = next === node.right ? node.left : node.right;
|
|
12208
12243
|
if (other) {
|
|
12209
|
-
recurse(other,
|
|
12244
|
+
recurse(other, nextAxis);
|
|
12210
12245
|
}
|
|
12211
12246
|
}
|
|
12212
12247
|
};
|
|
@@ -12241,6 +12276,54 @@ const OPACITY_PRUNE_THRESHOLD = 0.1;
|
|
|
12241
12276
|
const KNN_K = 16;
|
|
12242
12277
|
const MC_SAMPLES = 1;
|
|
12243
12278
|
const EPS_COV = 1e-8;
|
|
12279
|
+
const PROGRESS_TICKS = 100;
|
|
12280
|
+
// Radix sort edge indices by their Float32 costs.
|
|
12281
|
+
// Converts floats to sortable uint32 keys (preserving order), then does
|
|
12282
|
+
// 4-pass LSD radix sort with 8-bit radix. Returns the number of valid
|
|
12283
|
+
// (finite-cost) edges written to `out`.
|
|
12284
|
+
const radixSortIndicesByFloat = (out, count, keys) => {
|
|
12285
|
+
const keyBits = new Uint32Array(keys.buffer, keys.byteOffset, keys.length);
|
|
12286
|
+
const sortKeys = new Uint32Array(count);
|
|
12287
|
+
let validCount = 0;
|
|
12288
|
+
for (let i = 0; i < count; i++) {
|
|
12289
|
+
const bits = keyBits[i];
|
|
12290
|
+
if ((bits & 0x7F800000) === 0x7F800000)
|
|
12291
|
+
continue;
|
|
12292
|
+
sortKeys[validCount] = (bits & 0x80000000) ? ~bits >>> 0 : (bits | 0x80000000) >>> 0;
|
|
12293
|
+
out[validCount] = i;
|
|
12294
|
+
validCount++;
|
|
12295
|
+
}
|
|
12296
|
+
if (validCount <= 1)
|
|
12297
|
+
return validCount;
|
|
12298
|
+
const n = validCount;
|
|
12299
|
+
const temp = new Uint32Array(n);
|
|
12300
|
+
const tempKeys = new Uint32Array(n);
|
|
12301
|
+
const counts = new Uint32Array(256);
|
|
12302
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
12303
|
+
const shift = pass << 3;
|
|
12304
|
+
const srcIdx = (pass & 1) ? temp : out;
|
|
12305
|
+
const dstIdx = (pass & 1) ? out : temp;
|
|
12306
|
+
const srcK = (pass & 1) ? tempKeys : sortKeys;
|
|
12307
|
+
const dstK = (pass & 1) ? sortKeys : tempKeys;
|
|
12308
|
+
counts.fill(0);
|
|
12309
|
+
for (let i = 0; i < n; i++) {
|
|
12310
|
+
counts[(srcK[i] >>> shift) & 0xFF]++;
|
|
12311
|
+
}
|
|
12312
|
+
let sum = 0;
|
|
12313
|
+
for (let b = 0; b < 256; b++) {
|
|
12314
|
+
const c = counts[b];
|
|
12315
|
+
counts[b] = sum;
|
|
12316
|
+
sum += c;
|
|
12317
|
+
}
|
|
12318
|
+
for (let i = 0; i < n; i++) {
|
|
12319
|
+
const bucket = (srcK[i] >>> shift) & 0xFF;
|
|
12320
|
+
const pos = counts[bucket]++;
|
|
12321
|
+
dstIdx[pos] = srcIdx[i];
|
|
12322
|
+
dstK[pos] = srcK[i];
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
return validCount;
|
|
12326
|
+
};
|
|
12244
12327
|
// ---------- sigmoid / logit ----------
|
|
12245
12328
|
const sigmoid$1 = (x) => 1 / (1 + Math.exp(-x));
|
|
12246
12329
|
const logit = (p) => {
|
|
@@ -12728,7 +12811,6 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12728
12811
|
let current;
|
|
12729
12812
|
if (keptIndices.length < N && keptIndices.length > targetCount) {
|
|
12730
12813
|
current = dataTable.permuteRows(keptIndices);
|
|
12731
|
-
logger.debug(`opacity pruning: ${N} -> ${current.numRows} splats (threshold=${pruneThreshold.toFixed(4)})`);
|
|
12732
12814
|
}
|
|
12733
12815
|
else {
|
|
12734
12816
|
current = dataTable;
|
|
@@ -12739,7 +12821,8 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12739
12821
|
while (current.numRows > targetCount) {
|
|
12740
12822
|
const n = current.numRows;
|
|
12741
12823
|
const kEff = Math.min(Math.max(1, KNN_K), Math.max(1, n - 1));
|
|
12742
|
-
logger.
|
|
12824
|
+
logger.progress.begin(5);
|
|
12825
|
+
logger.progress.step('Building KD-tree');
|
|
12743
12826
|
const cx = current.getColumnByName('x').data;
|
|
12744
12827
|
const cy = current.getColumnByName('y').data;
|
|
12745
12828
|
const cz = current.getColumnByName('z').data;
|
|
@@ -12752,16 +12835,21 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12752
12835
|
const cr2 = current.getColumnByName('rot_2').data;
|
|
12753
12836
|
const cr3 = current.getColumnByName('rot_3').data;
|
|
12754
12837
|
const cache = buildPerSplatCache(n, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3);
|
|
12755
|
-
// Build KNN graph
|
|
12756
12838
|
const posTable = new DataTable([
|
|
12757
12839
|
new Column('x', cx instanceof Float32Array ? cx : new Float32Array(cx)),
|
|
12758
12840
|
new Column('y', cy instanceof Float32Array ? cy : new Float32Array(cy)),
|
|
12759
12841
|
new Column('z', cz instanceof Float32Array ? cz : new Float32Array(cz))
|
|
12760
12842
|
]);
|
|
12761
12843
|
const kdTree = new KdTree(posTable);
|
|
12762
|
-
|
|
12763
|
-
|
|
12844
|
+
logger.progress.step('Finding nearest neighbors');
|
|
12845
|
+
let edgeCapacity = Math.ceil(n * kEff / 2);
|
|
12846
|
+
let edgeU = new Uint32Array(edgeCapacity);
|
|
12847
|
+
let edgeV = new Uint32Array(edgeCapacity);
|
|
12848
|
+
let edgeCount = 0;
|
|
12764
12849
|
const queryPoint = new Float32Array(3);
|
|
12850
|
+
const knnInterval = Math.max(1, Math.ceil(n / PROGRESS_TICKS));
|
|
12851
|
+
const knnTicks = Math.ceil(n / knnInterval);
|
|
12852
|
+
logger.progress.begin(knnTicks);
|
|
12765
12853
|
for (let i = 0; i < n; i++) {
|
|
12766
12854
|
queryPoint[0] = cx[i];
|
|
12767
12855
|
queryPoint[1] = cy[i];
|
|
@@ -12769,46 +12857,58 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12769
12857
|
const knn = kdTree.findKNearest(queryPoint, kEff + 1);
|
|
12770
12858
|
for (let ki = 0; ki < knn.indices.length; ki++) {
|
|
12771
12859
|
const j = knn.indices[ki];
|
|
12772
|
-
if (j
|
|
12860
|
+
if (j <= i)
|
|
12773
12861
|
continue;
|
|
12774
|
-
|
|
12775
|
-
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12862
|
+
if (edgeCount === edgeCapacity) {
|
|
12863
|
+
edgeCapacity *= 2;
|
|
12864
|
+
const newU = new Uint32Array(edgeCapacity);
|
|
12865
|
+
const newV = new Uint32Array(edgeCapacity);
|
|
12866
|
+
newU.set(edgeU);
|
|
12867
|
+
newV.set(edgeV);
|
|
12868
|
+
edgeU = newU;
|
|
12869
|
+
edgeV = newV;
|
|
12780
12870
|
}
|
|
12871
|
+
edgeU[edgeCount] = i;
|
|
12872
|
+
edgeV[edgeCount] = j;
|
|
12873
|
+
edgeCount++;
|
|
12781
12874
|
}
|
|
12875
|
+
if ((i + 1) % knnInterval === 0)
|
|
12876
|
+
logger.progress.step();
|
|
12782
12877
|
}
|
|
12783
|
-
if (
|
|
12878
|
+
if (n % knnInterval !== 0)
|
|
12879
|
+
logger.progress.step();
|
|
12880
|
+
if (edgeCount === 0) {
|
|
12881
|
+
logger.progress.cancel();
|
|
12784
12882
|
break;
|
|
12785
|
-
|
|
12883
|
+
}
|
|
12884
|
+
logger.progress.step('Computing edge costs');
|
|
12786
12885
|
const appData = [];
|
|
12787
12886
|
for (let ai = 0; ai < allAppearanceCols.length; ai++) {
|
|
12788
12887
|
const col = current.getColumnByName(allAppearanceCols[ai]);
|
|
12789
12888
|
if (col)
|
|
12790
12889
|
appData.push(col.data);
|
|
12791
12890
|
}
|
|
12792
|
-
const costs = new Float32Array(edges.length);
|
|
12793
|
-
for (let e = 0; e < edges.length; e++) {
|
|
12794
|
-
costs[e] = computeEdgeCost(edges[e][0], edges[e][1], cx, cy, cz, cache, Z, appData, appData.length);
|
|
12795
|
-
}
|
|
12796
|
-
// Greedy disjoint pair selection
|
|
12797
|
-
const valid = [];
|
|
12798
|
-
for (let i = 0; i < edges.length; i++) {
|
|
12799
|
-
if (Number.isFinite(costs[i]))
|
|
12800
|
-
valid.push(i);
|
|
12801
|
-
}
|
|
12802
|
-
valid.sort((a, b) => {
|
|
12803
|
-
const d = costs[a] - costs[b];
|
|
12804
|
-
return d !== 0 ? d : a - b;
|
|
12805
|
-
});
|
|
12806
12891
|
const mergesNeeded = n - targetCount;
|
|
12892
|
+
const costs = new Float32Array(edgeCount);
|
|
12893
|
+
const costInterval = Math.max(1, Math.ceil(edgeCount / PROGRESS_TICKS));
|
|
12894
|
+
const costTicks = Math.ceil(edgeCount / costInterval);
|
|
12895
|
+
logger.progress.begin(costTicks);
|
|
12896
|
+
for (let e = 0; e < edgeCount; e++) {
|
|
12897
|
+
costs[e] = computeEdgeCost(edgeU[e], edgeV[e], cx, cy, cz, cache, Z, appData, appData.length);
|
|
12898
|
+
if ((e + 1) % costInterval === 0)
|
|
12899
|
+
logger.progress.step();
|
|
12900
|
+
}
|
|
12901
|
+
if (edgeCount % costInterval !== 0)
|
|
12902
|
+
logger.progress.step();
|
|
12903
|
+
logger.progress.step('Merging splats');
|
|
12904
|
+
// Sort and greedy disjoint pair selection
|
|
12905
|
+
const sorted = new Uint32Array(edgeCount);
|
|
12906
|
+
const validCount = radixSortIndicesByFloat(sorted, edgeCount, costs);
|
|
12807
12907
|
const used = new Uint8Array(n);
|
|
12808
12908
|
const pairs = [];
|
|
12809
|
-
for (let t = 0; t <
|
|
12810
|
-
const e =
|
|
12811
|
-
const u =
|
|
12909
|
+
for (let t = 0; t < validCount; t++) {
|
|
12910
|
+
const e = sorted[t];
|
|
12911
|
+
const u = edgeU[e], v = edgeV[e];
|
|
12812
12912
|
if (used[u] || used[v])
|
|
12813
12913
|
continue;
|
|
12814
12914
|
used[u] = 1;
|
|
@@ -12817,9 +12917,10 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12817
12917
|
if (pairs.length >= mergesNeeded)
|
|
12818
12918
|
break;
|
|
12819
12919
|
}
|
|
12820
|
-
if (pairs.length === 0)
|
|
12920
|
+
if (pairs.length === 0) {
|
|
12921
|
+
logger.progress.cancel();
|
|
12821
12922
|
break;
|
|
12822
|
-
|
|
12923
|
+
}
|
|
12823
12924
|
// Mark which indices are consumed by merging
|
|
12824
12925
|
const usedSet = new Uint8Array(n);
|
|
12825
12926
|
for (let p = 0; p < pairs.length; p++) {
|
|
@@ -12847,7 +12948,7 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12847
12948
|
newTable.columns[c].data[dst] = cols[c].data[src];
|
|
12848
12949
|
}
|
|
12849
12950
|
}
|
|
12850
|
-
// Merge pairs
|
|
12951
|
+
// Merge pairs
|
|
12851
12952
|
const mergeOut = {
|
|
12852
12953
|
mu: new Float64Array(3),
|
|
12853
12954
|
sc: new Float64Array(3),
|
|
@@ -12875,6 +12976,9 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12875
12976
|
.filter(col => !handledCols.has(col.name))
|
|
12876
12977
|
.map(col => ({ src: col, dst: newTable.getColumnByName(col.name) }))
|
|
12877
12978
|
.filter(pair => pair.dst);
|
|
12979
|
+
const mergeInterval = Math.max(1, Math.ceil(pairs.length / PROGRESS_TICKS));
|
|
12980
|
+
const mergeTicks = Math.ceil(pairs.length / mergeInterval);
|
|
12981
|
+
logger.progress.begin(mergeTicks);
|
|
12878
12982
|
for (let p = 0; p < pairs.length; p++, dst++) {
|
|
12879
12983
|
const pi = pairs[p][0], pj = pairs[p][1];
|
|
12880
12984
|
momentMatch(pi, pj, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3, mergeOut, appData, appData.length);
|
|
@@ -12897,7 +13001,12 @@ const simplifyGaussians = (dataTable, targetCount) => {
|
|
|
12897
13001
|
for (let u = 0; u < unhandledColPairs.length; u++) {
|
|
12898
13002
|
unhandledColPairs[u].dst.data[dst] = unhandledColPairs[u].src.data[dominant];
|
|
12899
13003
|
}
|
|
13004
|
+
if ((p + 1) % mergeInterval === 0)
|
|
13005
|
+
logger.progress.step();
|
|
12900
13006
|
}
|
|
13007
|
+
if (pairs.length % mergeInterval !== 0)
|
|
13008
|
+
logger.progress.step();
|
|
13009
|
+
logger.progress.step('Finalizing');
|
|
12901
13010
|
current = newTable;
|
|
12902
13011
|
}
|
|
12903
13012
|
return current;
|
|
@@ -16330,7 +16439,7 @@ class CompressedChunk {
|
|
|
16330
16439
|
}
|
|
16331
16440
|
}
|
|
16332
16441
|
|
|
16333
|
-
var version = "1.9.
|
|
16442
|
+
var version = "1.9.2";
|
|
16334
16443
|
|
|
16335
16444
|
const generatedByString = `Generated by splat-transform ${version}`;
|
|
16336
16445
|
const chunkProps = [
|
|
@@ -18377,6 +18486,746 @@ const writePly = async (options, fs) => {
|
|
|
18377
18486
|
await writer.close();
|
|
18378
18487
|
};
|
|
18379
18488
|
|
|
18489
|
+
// This file is part of meshoptimizer library and is distributed under the terms of MIT License.
|
|
18490
|
+
// Copyright (C) 2016-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
|
18491
|
+
var MeshoptSimplifier = (function () {
|
|
18492
|
+
// Built with clang version 19.1.5-wasi-sdk
|
|
18493
|
+
// Built from meshoptimizer 1.0
|
|
18494
|
+
var wasm =
|
|
18495
|
+
'b9H79Tebbbe:6eO9Geueu9Geub9Gbb9Gsuuuuuuuuuuuu99uueu9Gvuuuuub9Gruuuuuuub9Gouuuuuue999Gvuuuuueu9Gzuuuuuuuuuuu99uuuub9Gquuuuuuu99uueu9GPuuuuuuuuuuu99uueu9Gquuuuuuuu99ueu9Gruuuuuu99eu9Gwuuuuuu99ueu9Giuuue999Gluuuueu9Gluuuub9GiuuueuiLQdilvorlwDiqkxmPszbHHbelve9Weiiviebeoweuec:G:Pdkr:Bdxo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bbz9TW79O9V9Wt9F79P9T9W29P9M95bw8E9TW79O9V9Wt9F79P9T9W29P9M959x9Pt9OcttV9P9I91tW7bD8A9TW79O9V9Wt9F79P9T9W29P9M959x9Pt9O9v9W9K9HtWbqQ9TW79O9V9Wt9F79P9T9W29P9M959t29V9W9W95bkX9TW79O9V9Wt9F79P9T9W29P9M959qV919UWbxQ9TW79O9V9Wt9F79P9T9W29P9M959q9V9P9Ut7bmX9TW79O9V9Wt9F79P9T9W29P9M959t9J9H2WbPa9TW79O9V9Wt9F9V9Wt9P9T9P96W9wWVtW94SWt9J9O9sW9T9H9Wbs59TW79O9V9Wt9F9NW9UWV9HtW9q9V79Pt9P9V9U9sW9T9H9Wbzl79IV9RbHDwebcekdCXqM;YeQdbk;A1er3ue99euE99Que9:r998Jjjjjbcj;sb9Rgs8Kjjjjbcbhzasc:Cefcbc;Kbz:tjjjb8AdnabaeSmbabaeadcdtzMjjjb8AkdnamcdGTmbalcrfci4cbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egecdtfaHBdbasaecefBd;8ecbhlcbhednadTmbabheadhOinaHaeydbci4fcb86bbaeclfheaOcufgOmbkcbhlabheadhOinaHaeydbgAci4fgCaCRbbgCceaAcrGgAtV86bbaCcu7aA4ceGalfhlaeclfheaOcufgOmbkcualcdtalcFFFFi0Ehekaecbyd1:jjjbHjjjjbbhzasc:Cefasyd;8egecdtfazBdbasaecefBd;8ealcd4alfhOcehHinaHgecethHaeaO6mbkcbhXcuaecdtgOaecFFFFi0Ecbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egAcdtfaHBdbasaAcefBd;8eaHcFeaOz:tjjjbhQdnadTmbaecufhLcbhKindndnaQabaXcdtfgYydbgAc:v;t;h;Ev2aLGgOcdtfgCydbgHcuSmbceheinazaHcdtfydbaASmdaOaefhHaecefheaQaHaLGgOcdtfgCydbgHcu9hmbkkazaKcdtfaABdbaCaKBdbaKhHaKcefhKkaYaHBdbaXcefgXad9hmbkkaQcbyd:m:jjjbH:bjjjbbasasyd;8ecufBd;8ekcbh8AcualcefgecdtaecFFFFi0Ecbyd1:jjjbHjjjjbbhXasc:Cefasyd;8egecdtfaXBdbasaXBdNeasaecefBd;8ecuadcitadcFFFFe0Ecbyd1:jjjbHjjjjbbhEasc:Cefasyd;8egecdtfaEBdbasaEBd:yeasaecefBd;8eascNefabadalcbz:cjjjbcualcdtgealcFFFFi0Eg3cbyd1:jjjbHjjjjbbhAasc:Cefasyd;8egHcdtfaABdbasaHcefBd;8ea3cbyd1:jjjbHjjjjbbhKasc:Cefasyd;8egHcdtfaKBdbasaHcefBd;8eaAaKaialavazasc:Cefz:djjjbalcbyd1:jjjbHjjjjbbh5asc:Cefasyd;8egHcdtfa5BdbasaHcefBd;8ea3cbyd1:jjjbHjjjjbbhHasc:Cefasyd;8egOcdtfaHBdbasaOcefBd;8ea3cbyd1:jjjbHjjjjbbhOasc:Cefasyd;8egCcdtfaOBdbasaCcefBd;8eaHcFeaez:tjjjbh8EaOcFeaez:tjjjbh8FdnalTmbaEcwfhaindnaXa8AgOcefg8AcdtfydbgCaXaOcdtgefydbgHSmbaCaH9RhhaEaHcitfhga8Faefh8Ja8Eaefh8KcbhQindndnagaQcitfydbgLaO9hmba8KaOBdba8JaOBdbxekdnaXaLcdtg8LfgeclfydbgHaeydbgeSmbaEaecitgCfydbaOSmeaHae9Rh8Maecu7aHfhYaaaCfhHcbheinaYaeSmeaecefheaHydbhCaHcwfhHaCaO9hmbkaea8M6meka8Fa8LfgeaOaLaeydbcuSEBdba8KaLaOa8KydbcuSEBdbkaQcefgQah9hmbkka8Aal9hmbkaAhHaKhOa8FhCa8EhQcbheindndnaeaHydbgL9hmbdnaeaOydbgL9hmbaQydbhLdnaCydbgYcu9hmbaLcu9hmba5aefcb86bbxikdnaYcuSmbaLcuSmbaeaYSmbaAaYcdtfydbaAaLcdtfydb9hmba5aefcd86bbxika5aefh8KdnaeaYSmbaeaLSmba8Kce86bbxika8Kcl86bbxdkdnaeaKaLcdtgYfydb9hmbdnaCydbg8KcuSmbaea8KSmbaQydbghcuSmbaeahSmba8FaYfydbggcuSmbagaLSmba8EaYfydbgYcuSmbaYaLSmbdnaAa8KcdtfydbgLaAaYcdtfydb9hmbaLaAahcdtfydbgYSmbaYaAagcdtfydb9hmba5aefcd86bbxlka5aefcl86bbxika5aefcl86bbxdka5aefcl86bbxeka5aefa5aLfRbb86bbkaHclfhHaOclfhOaCclfhCaQclfhQalaecefge9hmbkdnamcaGTmbaEcwfh8Jcbh8Nindndna5a8NfgyRbbg8Pc9:fPibebekdndndnaAa8Ncdtfydbgea8N9hmbdnaqmbcbhgxdkdnazTmbcbhga8NheinagaqazaecdtgefydbfRbbcdGce4VhgaKaefydbgea8N9hmbxikkcbhga8NheinagaqaefRbbcdGce4VhgaKaecdtfydbgea8N9hmbxdkka5aefRbbhexeka8NheindnaXaecdtgafgeclfydbgHaeydbgeSmbaHae9Rh8AaEaecitfh8MaAaafh8Lcbh8Kina8Ma8KcitfydbgYhednindnaXaecdtgLfgeclfydbgHaeydbgeSmbdnaAaEaecitgOfydbcdtfydba8LydbgQ9hmbcehexikaHae9Rhhaecu7aHfhCa8JaOfhHcbheinaCaeSmeaecefheaHydbhOaHcwfhHaAaOcdtfydbaQ9hmbkaeah6hexdkaKaLfydbgeaY9hmbkcbhekagaece7Vhga8Kcefg8Ka8A9hmbkkaKaafydbgea8N9hmbka8PciagceGEhekayae86bbka8Ncefg8Nal9hmbkkdnaqTmbdndnazTmbazheaAhHalhOindnaqaeydbfRbbceGTmba5aHydbfcl86bbkaeclfheaHclfhHaOcufgOmbxdkkaqheaAhHalhOindnaeRbbceGTmba5aHydbfcl86bbkaecefheaHclfhHaOcufgOmbkkaAhealhOa5hHindna5aeydbfRbbcl9hmbaHcl86bbkaeclfheaHcefhHaOcufgOmbkkamceGTmba5healhHindnaeRbbce9hmbaecl86bbkaecefheaHcufgHmbkkcbhIcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbhaasc:Cefasyd;8egecdtfaaBdbasaecefBd;8easc:qefcbBdbas9cb83i1eaaaialavazasc1efz:ejjjbh8RdndnaDmbcbhycbhCxekcbhCawhecbhHindnaeIdbJbbbb9ETmbasaCcdtfaHBdbaCcefhCkaeclfheaDaHcefgH9hmbkcuaCal2gecdtaecFFFFi0Ecbyd1:jjjbHjjjjbbhyasc:Cefasyd;8egecdtfayBdbasaecefBd;8ealTmbdnaCmbcbhCxekarcd4h8KdnazTmbaCcdthhcbhXayhYinaoazaXcdtfydba8K2cdtfhLasheaYhHaChOinaHaLaeydbcdtgQfIdbawaQfIdbNUdbaeclfheaHclfhHaOcufgOmbkaYahfhYaXcefgXal9hmbxdkkaCcdthhcbhXayhYinaoaXa8K2cdtfhLasheaYhHaChOinaHaLaeydbcdtgQfIdbawaQfIdbNUdbaeclfheaHclfhHaOcufgOmbkaYahfhYaXcefgXal9hmbkkcualc8S2gHalc;D;O;f8U0EgQcbyd1:jjjbHjjjjbbheasc:Cefasyd;8egOcdtfaeBdbasaOcefBd;8eaecbaHz:tjjjbh8ScbhDcbh8KdnaCTmbcbhIaQcbyd1:jjjbHjjjjbbh8Kasc:Cefasyd;8egecdtfa8KBdbasaecefBd;8ea8KcbaHz:tjjjb8AcuaCal2gecltgHaecFFFFb0Ecbyd1:jjjbHjjjjbbhDasc:Cefasyd;8egecdtfaDBdbasaecefBd;8eaDcbaHz:tjjjb8AamcjjjjdGTmbcualcltgealcFFFFb0Ecbyd1:jjjbHjjjjbbhIasc:Cefasyd;8egHcdtfaIBdbasaHcefBd;8eaIcbaez:tjjjb8AkdnadTmbcbhLabhHinaaaHclfydbgXcx2fgeIdbaaaHydbgYcx2fgOIdbgR:tg8UaaaHcwfydbghcx2fgQIdlaOIdlg8V:tg8WNaQIdbaR:tg8XaeIdla8V:tg8YN:tg8Zh80aeIdwaOIdwg81:tgBa8XNaQIdwa81:tg83a8UN:tgUh8Xa8Ya83Na8WaBN:tg8Yh8Udna8Za8ZNa8Ya8YNaUaUNMM:rgBJbbbb9EgOTmba8ZaB:vh80aUaB:vh8Xa8YaB:vh8Uka8SaAaYcdtfydbgQc8S2fgea8UaB:rg8Wa8UNNg85aeIdbMUdbaea8Xa8Wa8XNg86Ng87aeIdlMUdlaea80a8Wa80Ng83Ng88aeIdwMUdwaea86a8UNg86aeIdxMUdxaea83a8UNg89aeIdzMUdzaea83a8XNg8:aeIdCMUdCaea8Ua8Wa80a81Na8UaRNa8Va8XNMM:mgZNg83Ng8UaeIdKMUdKaea8Xa83Ng8XaeId3MUd3aea80a83Ng80aeIdaMUdaaea83aZNg83aeId8KMUd8Kaea8WaeIdyMUdya8SaAaXcdtfydbgXc8S2fgea85aeIdbMUdbaea87aeIdlMUdlaea88aeIdwMUdwaea86aeIdxMUdxaea89aeIdzMUdzaea8:aeIdCMUdCaea8UaeIdKMUdKaea8XaeId3MUd3aea80aeIdaMUdaaea83aeId8KMUd8Kaea8WaeIdyMUdya8SaAahcdtfydbgYc8S2fgea85aeIdbMUdbaea87aeIdlMUdlaea88aeIdwMUdwaea86aeIdxMUdxaea89aeIdzMUdzaea8:aeIdCMUdCaea8UaeIdKMUdKaea8XaeId3MUd3aea80aeIdaMUdaaea83aeId8KMUd8Kaea8WaeIdyMUdydnaITmbdnaOTmba8ZaB:vh8ZaUaB:vhUa8YaB:vh8YkaIaQcltfgeaBJbbbZNg8UaUNg8WaeIdlMUdlaea8Ua8ZNg8XaeIdwMUdwaea8Ua8YNg80aeIdbMUdbaea8UaR:ma8YNaUa8VN:ta81a8ZN:tNg8UaeIdxMUdxaIaXcltfgea8WaeIdlMUdlaea8XaeIdwMUdwaea80aeIdbMUdbaea8UaeIdxMUdxaIaYcltfgea8WaeIdlMUdlaea8XaeIdwMUdwaea80aeIdbMUdbaea8UaeIdxMUdxkaHcxfhHaLcifgLad6mbkkdnalTmbJ;n;m;m89J:v:;;w8ZamczGEh8YcbhOaAhQaahHa8SheindnaOaQydb9hmbaecxfgLaLIdbJbbbbMUdbaeczfgLaLIdbJbbbbMUdbaecCfgLaLIdbJbbbbMUdbaea8YaecyfgLIdbg8ZNg8UaeIdbMUdbaeclfgXa8UaXIdbMUdbaecwfgXa8UaXIdbMUdbaecKfgXaXIdbaHIdbg8Xa8UN:tUdbaHcwfIdbh8Waec3fgXaXIdba8UaHclfIdbg80N:tUdbaecafgXaXIdba8Ua8WN:tUdbaec8KfgXIdbhUaLa8Za8UMUdbaXaUa8Ua8Wa8WNa8Xa8XNa80a80NMMNMUdbkaQclfhQaHcxfhHaec8SfhealaOcefgO9hmbkkdnadTmbcbhhabhYinabahcdtfhXcbhHina5aXaHc:G1jjbfydbcdtfydbgOfRbbhedndna5aYaHfydbgQfRbbgLc99fcFeGcpe0mbaec99fcFeGc;:e6mekdnaLcufcFeGce0mba8EaQcdtfydbaO9hmekdnaecufcFeGce0mba8FaOcdtfydbaQ9hmekJbbacJbbacJbbbZaecFeGceSEaLcFeGceSEh88aaaOcx2fgeIdwaaaQcx2fgLIdwgB:tg80:mh86aeIdlaLIdlg83:tg8Z:mh89aeIdbaLIdbgR:tgU:mh8:dnaaaXaHc:K1jjbfydbcdtfydbcx2fgeIdwaB:tg8Va80a80NaUaUNa8Za8ZNMMg8YNa8Va80NaeIdbaR:tg81aUNa8ZaeIdla83:tg85NMMg8Wa80N:tg8Xa8XNa81a8YNa8WaUN:tg8Ua8UNa85a8YNa8Wa8ZN:tg8Wa8WNMM:rg87Jbbbb9ETmba8Xa87:vh8Xa8Wa87:vh8Wa8Ua87:vh8Uka88a8Y:rNg8Ya8XaBNa8UaRNa83a8WNMM:mgZNg87aZNhZa8Xa87Nhna8Wa87Nhca8Ua87Nh9ca8Ya8XNg87a8WNhJa87a8UNh9ea8Ya8WNgTa8UNhSa8Xa87Nh87a8WaTNhTa8Ua8Ya8UNNh9hdnaUa85Na81a89NMg8Xa8XNa8Za8VNa85a86NMg8Ua8UNa80a81Na8Va8:NMg8Wa8WNMM:rg80Jbbbb9ETmba8Xa80:vh8Xa8Wa80:vh8Wa8Ua80:vh8Uka8SaAaQcdtfydbc8S2fgeaeIdba9ha8Ua88a80:rNg80a8UNNMgUMUdbaeaTa8Wa80a8WNg8VNMg81aeIdlMUdlaea87a8Xa80a8XNg8ZNMg85aeIdwMUdwaeaSa8Va8UNMg8VaeIdxMUdxaea9ea8Za8UNMg87aeIdzMUdzaeaJa8Za8WNMg8ZaeIdCMUdCaea9ca8Ua80a8XaBNa8UaRNa83a8WNMMgB:mNg80NMg8UaeIdKMUdKaeaca8Wa80NMg8WaeId3MUd3aeana8Xa80NMg8XaeIdaMUdaaeaZaBa80N:tg80aeId8KMUd8Kaea8YJbbbbMg8YaeIdyMUdya8SaAaOcdtfydbc8S2fgeaUaeIdbMUdbaea81aeIdlMUdlaea85aeIdwMUdwaea8VaeIdxMUdxaea87aeIdzMUdzaea8ZaeIdCMUdCaea8UaeIdKMUdKaea8WaeId3MUd3aea8XaeIdaMUdaaea80aeId8KMUd8Kaea8YaeIdyMUdykaHclfgHcx9hmbkaYcxfhYahcifghad6mbkaCTmbcbhYinJbbbbh8YaaabaYcdtfgeclfydbghcx2fgHIdwaaaeydbggcx2fgOIdwg81:tg8Wa8WNaHIdbaOIdbg85:tg8Xa8XNaHIdlaOIdlg87:tg80a80NMMgRaaaecwfydbgEcx2fgeIdwa81:tg8ZNa8Wa8Wa8ZNa8XaeIdba85:tgUNa80aeIdla87:tgBNMMg8UN:tJbbbbJbbjZaRa8Za8ZNaUaUNaBaBNMMg8VNa8Ua8UN:tg83:va83Jbbbb9BEg83Nh89a8Va8WNa8Za8UN:ta83Nh8:aRaBNa80a8UN:ta83NhZa8Va80NaBa8UN:ta83NhnaRaUNa8Xa8UN:ta83Nhca8Va8XNaUa8UN:ta83Nh9ca8XaBNaUa80N:tg8Ua8UNa80a8ZNaBa8WN:tg8Ua8UNa8WaUNa8Za8XN:tg8Ua8UNMM:rJbbbZNh8UayagaC2g8LcdtfhHayaEaC2g8JcdtfhOayahaC2g8AcdtfhQa81:mhJa87:mh9ea85:mhTcbhLaChXJbbbbhBJbbbbh83JbbbbhRJbbbbh8VJbbbbh81Jbbbbh85Jbbbbh87Jbbbbh88Jbbbbh86inascjdfaLfgecwfa8Ua8:aQIdbaHIdbg8Z:tg80Na89aOIdba8Z:tgUNMg8WNUdbaeclfa8Uana80NaZaUNMg8XNUdbaea8Ua9ca80NacaUNMg80NUdbaecxfa8UaJa8WNa9ea8XNa8ZaTa80NMMMg8ZNUdba8Ua8Wa8XNNa8VMh8Va8Ua8Wa80NNa81Mh81a8Ua8Xa80NNa85Mh85a8Ua8Za8ZNNa8YMh8Ya8Ua8Wa8ZNNaBMhBa8Ua8Xa8ZNNa83Mh83a8Ua80a8ZNNaRMhRa8Ua8Wa8WNNa87Mh87a8Ua8Xa8XNNa88Mh88a8Ua80a80NNa86Mh86aHclfhHaQclfhQaOclfhOaLczfhLaXcufgXmbka8Kagc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdya8Kahc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdya8KaEc8S2fgea86aeIdbMUdbaea88aeIdlMUdlaea87aeIdwMUdwaea85aeIdxMUdxaea81aeIdzMUdzaea8VaeIdCMUdCaeaRaeIdKMUdKaea83aeId3MUd3aeaBaeIdaMUdaaea8YaeId8KMUd8Kaea8UaeIdyMUdyaDa8LcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaDa8AcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaDa8JcltfhXcbhHaChQinaXaHfgeascjdfaHfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaYcifgYad6mbkkcbhOdndnamcwGg9imbJbbbbhRcbh6cbh9kcbh0xekcbh6a3cbyd1:jjjbHjjjjbbh0asc:Cefasyd;8egecdtfa0BdbasaecefBd;8ecua0alabadaAz:fjjjbgQcltaQcjjjjiGEcbyd1:jjjbHjjjjbbh9kasc:Cefasyd;8egecdtfa9kBdbasaecefBd;8ea9kaQa0aaalz:gjjjbJFFuuhRaQTmba9kheaQhHinaeIdbg8UaRaRa8U9EEhRaeclfheaHcufgHmbkaQh6kasydNeh9mdnalTmba9mclfhea9mydbhQa5hHalhLcbhOincbaeydbgXaQ9RaHRbbcpeGEaOfhOaHcefhHaeclfheaXhQaLcufgLmbkaOce4hOkcuadaO9Rcifg9ncx2a9nc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbh9oasc:Cefasyd;8egecdtfa9oBdbasaecefBd;8ecua9ncdta9ncFFFFi0Ecbyd1:jjjbHjjjjbbh9pasc:Cefasyd;8egecdtfa9pBdbasaecefBd;8ea3cbyd1:jjjbHjjjjbbh8Pasc:Cefasyd;8egecdtfa8PBdbasaecefBd;8ealcbyd1:jjjbHjjjjbbh9qasc:Cefasyd;8egecdtfa9qBdbasaecefBd;8eaxaxNa8RJbbjZamclGEgnanN:vh88Jbbbbh86dnadak9nmbdna9nci6mbasyd:yeh9raCclth9sa9ocwfh9tJbbbbh87Jbbbbh86inascNefabadalaAz:cjjjbabhgcbh8Ncbh3inaba3cdtfh8LcbheindnaAagaefydbgOcdtghfydbgQaAa8Laec:W1jjbfydbcdtfydbgHcdtgEfydbgLSmba5aHfRbbgYcv2a5aOfRbbgXfc;a1jjbfRbbg8AaXcv2aYfg8Jc;a1jjbfRbbg8MVcFeGTmbdnaLaQ9nmba8Jc;G1jjbfRbbcFeGmekdnaXcufcFeGce0mbaYTmba8EahfydbaH9hmekdnaXTmbaYcufcFeGce0mba8FaEfydbaO9hmeka9oa8Ncx2fgQaHaOa8McFeGgLEBdlaQaOaHaLEBdbaQaLa8AGcb9hBdwa8Ncefh8Nkaeclfgecx9hmbkdna3cifg3ad9pmbagcxfhga8Ncifa9n9nmekka8NTmdcbh8Jina8SaAa9oa8Jcx2fghydbgLcdtgQfydbggc8S2fgeIdwaaahydlgXcx2fgHIdwg8XNaeIdzaHIdbg80NaeIdaMg8Ua8UMMa8XNaeIdlaHIdlg8ZNaeIdCa8XNaeId3Mg8Ua8UMMa8ZNaeIdba80NaeIdxa8ZNaeIdKMg8Ua8UMMa80NaeId8KMMM:lh8UJbbbbJbbjZaeIdyg8W:va8WJbbbb9BEh8Wdndnahydwg8LmbJFFuuh83xekJbbbbJbbjZa8SaAaXcdtfydbc8S2fgeIdygU:vaUJbbbb9BEaeIdwaaaLcx2fgHIdwgUNaeIdzaHIdbg8YNaeIdaMgBaBMMaUNaeIdlaHIdlgBNaeIdCaUNaeId3MgUaUMMaBNaeIdba8YNaeIdxaBNaeIdKMgUaUMMa8YNaeId8KMMM:lNh83ka8Wa8UNhBdnaCTmba8KaLc8S2fgOIdwa8XNaOIdza80NaOIdaMg8Ua8UMMa8XNaOIdla8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaXaC2gYcdtfhHaDaLaC2gEcltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkdndna8LmbJbbbbh8Wxeka8KaXc8S2fgOIdwaaaLcx2fgeIdwg80NaOIdzaeIdbg8ZNaOIdaMg8Wa8WMMa80NaOIdlaeIdlgUNaOIdCa80NaOId3Mg8Wa8WMMaUNaOIdba8ZNaOIdxaUNaOIdKMg8Wa8WMMa8ZNaOId8KMMMh8WayaEcdtfhHaDaYcltfheaOIdyh8YaChOinaHIdbg8Xa8Xa8YNaecxfIdba80aecwfIdbNa8ZaeIdbNaUaeclfIdbNMMMg8Xa8XM:tNa8WMh8WaHclfhHaeczfheaOcufgOmbka8W:lh8WkaBa8U:lMhBa83a8WMh83dndndna5aLfRbbc9:fPddbekaKaQfydbgQaLSmbaAaXcdtfydbhEindndna8EaQcdtgYfydbgecuSmbaAaecdtfydbaESmekdna8FaYfydbgecuSmbaAaecdtfydbaESmekaXheka8KaQc8S2fgOIdwaaaecx2fgHIdwg8XNaOIdzaHIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaHIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaeaC2cdtfhHaDaQaC2cltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkaBa8U:lMhBaKaYfydbgQaL9hmbkka5aXfRbbci9hmea8LTmeaKaXcdtfydbgQaXSmeindndna8EaQcdtgYfydbgecuSmbaAaecdtfydbagSmekdna8FaYfydbgecuSmbaAaecdtfydbagSmekaLheka8KaQc8S2fgOIdwaaaecx2fgHIdwg8XNaOIdzaHIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaHIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaeaC2cdtfhHaDaQaC2cltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbka83a8U:lMh83aKaYfydbgQaX9hmbxdkkdna8Fa8Ea8EaQfydbaXSEaKaQfydbgYcdtfydbgQcu9hmbaKaXcdtfydbhQka8KaYc8S2fgOIdwaaaQcx2fgeIdwg8XNaOIdzaeIdbg80NaOIdaMg8Ua8UMMa8XNaOIdlaeIdlg8ZNaOIdCa8XNaOId3Mg8Ua8UMMa8ZNaOIdba80NaOIdxa8ZNaOIdKMg8Ua8UMMa80NaOId8KMMMh8UayaQaC2ggcdtfhHaDaYaC2gEcltfheaOIdyhUaChOinaHIdbg8Wa8WaUNaecxfIdba8XaecwfIdbNa80aeIdbNa8ZaeclfIdbNMMMg8Wa8WM:tNa8UMh8UaHclfhHaeczfheaOcufgOmbkdndna8LmbJbbbbh8Wxeka8KaQc8S2fgOIdwaaaYcx2fgeIdwg80NaOIdzaeIdbg8ZNaOIdaMg8Wa8WMMa80NaOIdlaeIdlgUNaOIdCa80NaOId3Mg8Wa8WMMaUNaOIdba8ZNaOIdxaUNaOIdKMg8Wa8WMMa8ZNaOId8KMMMh8WayaEcdtfhHaDagcltfheaOIdyh8YaChOinaHIdbg8Xa8Xa8YNaecxfIdba80aecwfIdbNa8ZaeIdbNaUaeclfIdbNMMMg8Xa8XM:tNa8WMh8WaHclfhHaeczfheaOcufgOmbka8W:lh8WkaBa8U:lMhBa83a8WMh83kaha83aBa83aB9DgeEUdwahaLaXaea8Lcb9hGgeEBdlahaXaLaeEBdba8Jcefg8Ja8N9hmbkascjdfcbcj;qbz:tjjjb8Aa9thea8NhHinascjdfaeydbcA4cF8FGgOcFAaOcFA6EcdtfgOaOydbcefBdbaecxfheaHcufgHmbkcbhecbhHinascjdfaefgOydbhQaOaHBdbaQaHfhHaeclfgecj;qb9hmbkcbhea9thHinascjdfaHydbcA4cF8FGgOcFAaOcFA6EcdtfgOaOydbgOcefBdba9paOcdtfaeBdbaHcxfhHa8Naecefge9hmbkadak9RgOci9Uh9udnalTmbcbhea8PhHinaHaeBdbaHclfhHalaecefge9hmbkkcbh9va9qcbalz:tjjjbh9waOcO9Uh9xa9uce4h9ycbh3cbh8Adnina9oa9pa8Acdtfydbcx2fg8JIdwg8Ua889Emea3a9u9pmeJFFuuh8Wdna9ya8N9pmba9oa9pa9ycdtfydbcx2fIdwJbb;aZNh8Wkdna8Ua8W9ETmba8Ua869ETmba3a9x0mdkdna9waAa8Jydlg8Mcdtg9zfgEydbgQfg9ARbba9waAa8Jydbggcdtg9Bfydbgefg9CRbbVmba5agfRbbh9Ddna9maecdtfgHclfydbgOaHydbgHSmbaOaH9RhLaaaQcx2fhYaaaecx2fhha9raHcitfhecbhHceh8Ldnindna8PaeydbcdtfydbgOaQSmba8PaeclfydbcdtfydbgXaQSmbaOaXSmbaaaXcx2fgXIdbaaaOcx2fgOIdbg8X:tg8UahIdlaOIdlg80:tg8YNahIdba8X:tgBaXIdla80:tg8WN:tg8Za8UaYIdla80:tg83NaYIdba8X:tg8Va8WN:tg80Na8WahIdwaOIdwgU:tg81Na8YaXIdwaU:tg8XN:tg8Ya8WaYIdwaU:tg85Na83a8XN:tg8WNa8XaBNa81a8UN:tgUa8Xa8VNa85a8UN:tg8UNMMa8Za8ZNa8Ya8YNaUaUNMMa80a80Na8Wa8WNa8Ua8UNMMN:rJbbj8:N9FmdkaecwfheaHcefgHaL6h8LaLaH9hmbkka8LceGTmba9ycefh9yxekdndndndna9Dc9:fPdebdkagheinaEydbhOdndna8EaecdtgHfydbgecuSmbaAaecdtfydbaOSmekdna8FaHfydbgecuSmbaAaecdtfydbaOSmeka8Mheka8PaHfaeBdbaKaHfydbgeag9hmbxikkdna8Fa8Ea8Ea9Bfydba8MSEaKa9Bfydbggcdtfydbgecu9hmbaKa9zfydbheka8Pa9Bfa8MBdbaeh8Mka8Pagcdtfa8MBdbka9Cce86bba9Ace86bba8JIdwg8Ua86a86a8U9DEh86a9vcefh9vcecda9DceSEa3fh3ka8Acefg8Aa8N9hmbkka9vTmddnalTmbcbhXcbhhindna8PahcdtgefydbgOahSmbaAaOcdtfydbhgdnahaAaefydb9hgEmba8Sagc8S2fgea8Sahc8S2fgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxaeaHIdzaeIdzMUdzaeaHIdCaeIdCMUdCaeaHIdKaeIdKMUdKaeaHId3aeId3MUd3aeaHIdaaeIdaMUdaaeaHId8KaeId8KMUd8KaeaHIdyaeIdyMUdyaITmbaIagcltfgeaIahcltfgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxkaCTmba8KaOc8S2fgea8Kahc8S2g8LfgHIdbaeIdbMUdbaeaHIdlaeIdlMUdlaeaHIdwaeIdwMUdwaeaHIdxaeIdxMUdxaeaHIdzaeIdzMUdzaeaHIdCaeIdCMUdCaeaHIdKaeIdKMUdKaeaHId3aeId3MUd3aeaHIdaaeIdaMUdaaeaHId8KaeId8KMUd8KaeaHIdyaeIdyMUdya9saO2hYaDhHaChQinaHaYfgeaHaXfgOIdbaeIdbMUdbaeclfgLaOclfIdbaLIdbMUdbaecwfgLaOcwfIdbaLIdbMUdbaecxfgeaOcxfIdbaeIdbMUdbaHczfhHaQcufgQmbkaEmbJbbbbJbbjZa8Sa8LfgeIdyg8U:va8UJbbbb9BEaeIdwaaagcx2fgHIdwg8UNaeIdzaHIdbg8WNaeIdaMg8Xa8XMMa8UNaeIdlaHIdlg8XNaeIdCa8UNaeId3Mg8Ua8UMMa8XNaeIdba8WNaeIdxa8XNaeIdKMg8Ua8UMMa8WNaeId8KMMM:lNg8Ua87a87a8U9DEh87kaXa9sfhXahcefghal9hmbkcbhHa8EheindnaeydbgOcuSmbdnaHa8PaOcdtgQfydbgO9hmbcuhOa8EaQfydbgQcuSmba8PaQcdtfydbhOkaeaOBdbkaeclfhealaHcefgH9hmbkcbhHa8FheindnaeydbgOcuSmbdnaHa8PaOcdtgQfydbgO9hmbcuhOa8FaQfydbgQcuSmba8PaQcdtfydbhOkaeaOBdbkaeclfhealaHcefgH9hmbkka87a86aCEh87cbhHabhecbhOindnaAa8PaeydbcdtfydbgXcdtfydbgQaAa8PaeclfydbcdtfydbgYcdtfydbgLSmbaQaAa8PaecwfydbcdtfydbggcdtfydbghSmbaLahSmbabaHcdtfgQaXBdbaQcwfagBdbaQclfaYBdbaHcifhHkaecxfheaOcifgOad6mbkdndna9imbaHhdxekdnaHak0mbaHhdxekdnaRa879FmbaHhdxekJFFuuhRcbhdabhecbhOindna9ka0aeydbgQcdtfydbcdtfIdbg8Ua879ETmbaeclf8Pdbh9EabadcdtfgLaQBdbaLclfa9E83dba8UaRaRa8U9EEhRadcifhdkaecxfheaOcifgOaH6mbkkadak0mbxdkkascNefabadalaAz:cjjjbkdndnadak0mbadhhxekdna9imbadhhxekdnaRa889FmbadhhxekcehLinaRJbb;aZNg8Ua88a8Ua889DEh8XJbbbbh8Udna6Tmba9khea6hHinaeIdbg8Wa8Ua8Wa8X9FEa8Ua8Wa8U9EEh8UaeclfheaHcufgHmbkkJFFuuhRcbhhabhecbhHindna9ka0aeydbgOcdtfydbcdtfIdbg8Wa8X9ETmbaeclf8Pdbh9EabahcdtfgQaOBdbaQclfa9E83dba8WaRaRa8W9EEhRahcifhhkaecxfheaHcifgHad6mbkdnaLahad9hVceGmbadhhxdka8Ua86a86a8U9DEh86ahak9nmecbhLahhdaRa889FmbkkdnamcjjjjdGTmba9qcbalz:tjjjbh8LdnahTmbabheahhHina8LaeydbgOfce86bba8LaAaOcdtfydbfce86bbaeclfheaHcufgHmbkkascNefabahalaAz:cjjjbdndndnalTmbcbhQasyd:yehEindna8LaQfRbbTmbdna5aQfRbbgecl0mbceaetcQGmekdnaAaQcdtgXfydbgeaQSmbaaaQcx2fgHaaaecx2fge8Pdb83dbaHcwfaecwfydbBdbxeka8SaQc8S2fgLIdyg9ca9cJL:3;rUNg8UMh88aLIdwg9ha8UMhRaLIdlgxa8UMh8VaLIdbg9Fa8UMhUaLIdag9Ga8UaaaQcx2fggIdwg89N:th81aLId3g9Ha8UagIdlg8:N:th85aLIdKg9IagIdbgZa8UN:th8YJbbbbhcaLIdCg9JJbbbbMh87aLIdzg9KJbbbbMhBaLIdxgWJbbbbMh83dndnaCTmbaQhOinJbbbba88a8KaOc8S2fgHIdyg8U:va8UJbbbb9BEh8UaDaOaC2cltfheaHIdaa88Na81Mh81aHId3a88Na85Mh85aHIdKa88Na8YMh8YaHIdCa88Na87Mh87aHIdza88NaBMhBaHIdxa88Na83Mh83aHIdwa88NaRMhRaHIdla88Na8VMh8VaHIdba88NaUMhUaChHina81aecxfIdbg8ZaecwfIdbg8WNa8UN:th81a85a8ZaeclfIdbg8XNa8UN:th85a87a8Wa8XNa8UN:th87aUaeIdbg80a80Na8UN:thUa8Ya8Za80Na8UN:th8YaBa8Wa80Na8UN:thBa83a8Xa80Na8UN:th83aRa8Wa8WNa8UN:thRa8Va8Xa8XNa8UN:th8VaeczfheaHcufgHmbkaKaOcdtfydbgOaQ9hmbkaITmbaIaQcltfgeIdxhSaeIdwhJaeIdlh9eaeIdbh8UxekJbbbbhSJbbbbhJJbbbbh9eJbbbbh8UkaBaU:vg8Xa8YNa81:ta87aBa83aU:vg8WN:tg81a8Va83a8WN:tg8Z:vg80a8Wa8YNa85:tg8VN:th85aJa8Ua8XN:ta9ea8Ua8WN:tg83a80N:tg87aRaBa8XN:ta81a80N:tgB:vgR:mh81a83a8Z:vgJ:mh9ednJbbbba8Ua8UaU:vgTN:ta83aJN:ta87aRN:tg83:la88J:983:g81Ng8U9ETmba81a85Na9ea8VNaTa8YNaS:tMMa83:vhckaU:la8U9ETmba8Z:la8U9ETmbaB:la8U9ETmbaT:macNa8X:ma81acNa85aB:vMgBNa8W:ma9eacNa80:maBNa8Va8Z:vMMg87Na8Y:maU:vMMMh88a9maXfgeclfydbgHaeydbge9RhYaEaecitfhXJbbbbh8UdnaHaeSg8JmbJbbbbh8UaXheaYhOinaaaeclfydbcx2fgHIdwa89:tg8Wa8WNaHIdbaZ:tg8Wa8WNaHIdla8::tg8Wa8WNMMg8Waaaeydbcx2fgHIdwa89:tg8Xa8XNaHIdbaZ:tg8Xa8XNaHIdla8::tg8Xa8XNMMg8Xa8Ua8Ua8X9DEg8Ua8Ua8W9DEh8UaecwfheaOcufgOmbkkaBa89:tg8Wa8WNa88aZ:tg8Wa8WNa87a8::tg8Wa8WNMMa8U:rg8Ua8UN9EmbaLId8Khcdna8JmbcbhOcehLdninaaaXclfydbcx2fgeIdbaaaXydbcx2fgHIdbg8X:tg8Ua8:aHIdlg80:tg8YNaZa8X:tg83aeIdla80:tg8WN:tg8Za8Ua87a80:tgRNa88a8X:tg8Va8WN:tg80Na8Wa89aHIdwgU:tg81Na8YaeIdwaU:tg8XN:tg8Ya8WaBaU:tg85NaRa8XN:tg8WNa8Xa83Na81a8UN:tgUa8Xa8VNa85a8UN:tg8UNMMa8Za8ZNa8Ya8YNaUaUNMMa80a80Na8Wa8WNa8Ua8UNMMN:rJbbj8:N9FmeaXcwfhXaOcefgOaY6hLaYaO9hmbkkaLceGmekJbbbbJbbjZa9c:va9cJbbbb9BEg8Ua9haBNa9Ka88Na9GMg8Wa8WMMaBNaxa87Na9JaBNa9HMg8Wa8WMMa87Na9Fa88NaWa87Na9IMg8Wa8WMMa88NacMMM:lNa8Ua9ha89Na9KaZNa9GMg8Wa8WMMa89Naxa8:Na9Ja89Na9HMg8Wa8WMMa8:Na9FaZNaWa8:Na9IMg8Wa8WMMaZNacMMM:lNJbb;aZNJ:983:g81M9EmbagaBUdwaga87Udlaga88UdbkaQcefgQal9hmbkaCTmecbhLindna8LaLfRbbTmbaAaLcdtgefydbaL9hmba5aLfhEaaaLcx2fhOaKaefh8JayaLaC2cdtfh8AcbhgincuhQdnaERbbci9hmbaLhQa8JydbgeaLSmbayagcdtgHfhXa8AaHfIdbh8UaLhQinaQhHcuhQdnaXaeaC2cdtfIdba8U9CmbaHcuSmbaHhQa8Kaec8S2fIdya8KaHc8S2fIdy9ETmbaehQkaKaecdtfydbgeaL9hmbkkayagcdtfhXaDagcltfhYaLheinaXaeaC2cdtfJbbbbJbbjZa8KaeaQaQcuSEgHc8S2fIdyg8U:va8UJbbbb9BEaYaHaC2cltfgHIdwaOIdwNaHIdbaOIdbNaHIdlaOIdlNMMaHIdxMNUdbaKaecdtfydbgeaL9hmbkagcefggaC9hmbkkaLcefgLalSmixbkkaCmekcbhCkaiavaoarawaCalaaayazasa8Rasc1efa5a8Laqz:hjjjbkdnamcjjjjlGTmbazmbahTmbcbhQabheina5aeydbgAfRbbc3thLaecwfgKydbhHdndna8EaAcdtgYfydbaeclfgXydbgOSmbcbhCa8FaOcdtfydbaA9hmekcjjjj94hCkaeaLaCVaAVBdba5aOfRbbc3thLdndna8EaOcdtfydbaHSmbcbhCa8FaHcdtfydbaO9hmekcjjjj94hCkaXaLaCVaOVBdba5aHfRbbc3thCdndna8EaHcdtfydbaASmbcbhOa8FaYfydbaH9hmekcjjjj94hOkaKaCaOVaHVBdbaecxfheaQcifgQah6mbkkdnazTmbahTmbahheinabazabydbcdtfydbBdbabclfhbaecufgembkkdnaPTmbaPana86:rNUdbkasyd;8egecdtasc:Ceffc98fhHdninaeTmeaHydbcbyd:m:jjjbH:bjjjbbaHc98fhHaecufhexbkkascj;sbf8Kjjjjbahk;Yieouabydlhvabydbclfcbaicdtz:tjjjbhoadci9UhrdnadTmbdnalTmbaehwadhDinaoalawydbcdtfydbcdtfgqaqydbcefBdbawclfhwaDcufgDmbxdkkaehwadhDinaoawydbcdtfgqaqydbcefBdbawclfhwaDcufgDmbkkdnaiTmbcbhDaohwinawydbhqawaDBdbawclfhwaqaDfhDaicufgimbkkdnadci6mbinaecwfydbhwaeclfydbhDaeydbhidnalTmbalawcdtfydbhwalaDcdtfydbhDalaicdtfydbhikavaoaicdtfgqydbcitfaDBdbavaqydbcitfawBdlaqaqydbcefBdbavaoaDcdtfgqydbcitfawBdbavaqydbcitfaiBdlaqaqydbcefBdbavaoawcdtfgwydbcitfaiBdbavawydbcitfaDBdlawawydbcefBdbaecxfhearcufgrmbkkabydbcbBdbk:todDue99aicd4aifhrcehwinawgDcethwaDar6mbkcuaDcdtgraDcFFFFi0Ecbyd1:jjjbHjjjjbbhwaoaoyd9GgqcefBd9GaoaqcdtfawBdbawcFearz:tjjjbhkdnaiTmbalcd4hlaDcufhxcbhminamhDdnavTmbavamcdtfydbhDkcbadaDal2cdtfgDydlgwawcjjjj94SEgwcH4aw7c:F:b:DD2cbaDydbgwawcjjjj94SEgwcH4aw7c;D;O:B8J27cbaDydwgDaDcjjjj94SEgDcH4aD7c:3F;N8N27axGhwamcdthPdndndnavTmbakawcdtfgrydbgDcuSmeadavaPfydbal2cdtfgsIdbhzcehqinaqhrdnadavaDcdtfydbal2cdtfgqIdbaz9CmbaqIdlasIdl9CmbaqIdwasIdw9BmlkarcefhqakawarfaxGgwcdtfgrydbgDcu9hmbxdkkakawcdtfgrydbgDcuSmbadamal2cdtfgsIdbhzcehqinaqhrdnadaDal2cdtfgqIdbaz9CmbaqIdlasIdl9CmbaqIdwasIdw9BmikarcefhqakawarfaxGgwcdtfgrydbgDcu9hmbkkaramBdbamhDkabaPfaDBdbamcefgmai9hmbkkakcbyd:m:jjjbH:bjjjbbaoaoyd9GcufBd9GdnaeTmbaiTmbcbhDaehwinawaDBdbawclfhwaiaDcefgD9hmbkcbhDaehwindnaDabydbgrSmbawaearcdtfgrydbBdbaraDBdbkawclfhwabclfhbaiaDcefgD9hmbkkk:hrdvuv998Jjjjjbca9Rgoczfcwfcbyd11jjbBdbaocb8Pdj1jjb83izaocwfcbydN1jjbBdbaocb8Pd:m1jjb83ibdnadTmbaicd4hrdnabmbdnalTmbcbhwinaealawcdtfydbar2cdtfhDcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkawcefgwad9hmbxikkarcdthwcbhDincbhiinaoczfaifgqaeaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkaeawfheaDcefgDad9hmbxdkkdnalTmbcbhwinabawcx2fgiaealawcdtfydbar2cdtfgDIdbUdbaiaDIdlUdlaiaDIdwUdwcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkawcefgwad9hmbxdkkarcdthlcbhwaehDinabawcx2fgiaeawar2cdtfgqIdbUdbaiaqIdlUdlaiaqIdwUdwcbhiinaoczfaifgqaDaifIdbgkaqIdbgxaxak9EEUdbaoaifgqakaqIdbgxaxak9DEUdbaiclfgicx9hmbkaDalfhDawcefgwad9hmbkkJbbbbaoIdbaoIdzgx:tgkakJbbbb9DEgkaoIdlaoIdCgm:tgPaPak9DEgkaoIdwaoIdKgP:tgsasak9DEhsdnabTmbadTmbJbbbbJbbjZas:vasJbbbb9BEhkinabakabIdbax:tNUdbabclfgoakaoIdbam:tNUdbabcwfgoakaoIdbaP:tNUdbabcxfhbadcufgdmbkkdnavTmbavaPUdwavamUdlavaxUdbkask:ZlewudnaeTmbcbhvabhoinaoavBdbaoclfhoaeavcefgv9hmbkkdnaiTmbcbhrinadarcdtfhwcbhDinalawaDcdtgvc:G1jjbfydbcdtfydbcdtfydbhodnabalawavfydbcdtfydbgqcdtfgkydbgvaqSmbinakabavgqcdtfgxydbgvBdbaxhkaqav9hmbkkdnabaocdtfgkydbgvaoSmbinakabavgocdtfgxydbgvBdbaxhkaoav9hmbkkdnaqaoSmbabaqaoaqao0Ecdtfaqaoaqao6EBdbkaDcefgDci9hmbkarcifgrai6mbkkdnaembcbskcbhxindnalaxcdtgvfydbax9hmbaxhodnabavfgDydbgvaxSmbaDhqinaqabavgocdtfgkydbgvBdbakhqaoav9hmbkkaDaoBdbkaxcefgxae9hmbkcbhvabhocbhkindndnavalydbgq9hmbdnavaoydbgq9hmbaoakBdbakcefhkxdkaoabaqcdtfydbBdbxekaoabaqcdtfydbBdbkaoclfhoalclfhlaeavcefgv9hmbkakk;Jiilud99duabcbaecltz:tjjjbhvdnalTmbadhoaihralhwinarcwfIdbhDarclfIdbhqavaoydbcltfgkarIdbakIdbMUdbakclfgxaqaxIdbMUdbakcwfgxaDaxIdbMUdbakcxfgkakIdbJbbjZMUdbaoclfhoarcxfhrawcufgwmbkkdnaeTmbavhraehkinarcxfgoIdbhDaocbBdbararIdbJbbbbJbbjZaD:vaDJbbbb9BEgDNUdbarclfgoaDaoIdbNUdbarcwfgoaDaoIdbNUdbarczfhrakcufgkmbkkdnalTmbinavadydbcltfgrcxfgkaicwfIdbarcwfIdb:tgDaDNaiIdbarIdb:tgDaDNaiclfIdbarclfIdb:tgDaDNMMgDakIdbgqaqaD9DEUdbadclfhdaicxfhialcufglmbkkdnaeTmbavcxfhrinabarIdbUdbarczfhrabclfhbaecufgembkkk:moerudnaoTmbaecd4hzdnavTmbaicd4hHavcdthOcbhAindnaPaAfRbbTmbaAhednaDTmbaDaAcdtfydbhekdnasTmbasaefRbbceGmekdnamaAfRbbclSmbabaeaz2cdtfgiaraAcx2fgCIdbakNaxIdbMUdbaiaCIdlakNaxIdlMUdlaiaCIdwakNaxIdwMUdwkadaeaH2cdtfhXaqheawhiavhCinaXaeydbcdtgQfaiIdbalaQfIdb:vUdbaeclfheaiclfhiaCcufgCmbkkawaOfhwaAcefgAao9hmbxdkkdnasmbcbheaDhiindnaPaefRbbTmbaehCdnaDTmbaiydbhCkamaefRbbclSmbabaCaz2cdtfgCarIdbakNaxIdbMUdbaCarclfIdbakNaxIdlMUdlaCarcwfIdbakNaxIdwMUdwkaiclfhiarcxfhraoaecefge9hmbxdkkdnaDTmbindnaPRbbTmbasaDydbgefRbbceGmbamRbbclSmbabaeaz2cdtfgearIdbakNaxIdbMUdbaearclfIdbakNaxIdlMUdlaearcwfIdbakNaxIdwMUdwkaPcefhPaDclfhDamcefhmarcxfhraocufgombxdkkazcdthicbheindnaPaefRbbTmbasaefRbbceGmbamaefRbbclSmbabarIdbakNaxIdbMUdbabclfarclfIdbakNaxIdlMUdbabcwfarcwfIdbakNaxIdwMUdbkarcxfhrabaifhbaoaecefge9hmbkkk8MbabaeadaialavcbcbcbcbcbaoarawaDz:bjjjbk8MbabaeadaialavaoarawaDaqakaxamaPz:bjjjbkRbababaeadaialavaoarawaDaqakaxcjjjjdVamz:bjjjbk:d8Koque99due99duq998Jjjjjbc;Wb9Rgq8Kjjjjbcbhkaqcxfcbc;Kbz:tjjjb8Aaqcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbgxBdxaqceBd2axaialavcbcbz:ejjjb8AaqcualcdtalcFFFFi0Egmcbyd1:jjjbHjjjjbbgiBdzaqcdBd2dndnJFF959eJbbjZawJbbjZawJbbjZ9DE:vawJ9VO:d869DEgw:lJbbb9p9DTmbaw:OhPxekcjjjj94hPkadci9Uhsarco9UhzdndnaombaPcd9imekdnalTmbaPcuf:YhwdnaoTmbcbhvaihHaxhOindndnaoavfRbbceGTmbavcjjjjlVhAxekdndnaOclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcqthAdndnaOcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXVhAdndnaOIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXcCtVhAkaHaABdbaHclfhHaOcxfhOalavcefgv9hmbxdkkaxhvaihOalhHindndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcCthAdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqtaAVhAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaOaAaXVBdbavcxfhvaOclfhOaHcufgHmbkkadTmbcbhkaehvcbhOinakaiavclfydbcdtfydbgHaiavcwfydbcdtfydbgA9haiavydbcdtfydbgXaH9haXaA9hGGfhkavcxfhvaOcifgOad6mbkkarci9UhQdndnaz:Z:rJbbbZMgw:lJbbb9p9DTmbaw:Ohvxekcjjjj94hvkaQ:ZhLcbhKc:bwhzdninakaQ9pmeazaP9Rcd9imeavazcufavaz9iEaPcefavaP9kEhYdnalTmbaYcuf:YhwdnaoTmbcbhOaihHaxhvindndnaoaOfRbbceGTmbaOcjjjjlVhAxekdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcqthAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXVhAdndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaAaXcCtVhAkaHaABdbaHclfhHavcxfhvalaOcefgO9hmbxdkkaxhvaihOalhHindndnavIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhAxekcjjjj94hAkaAcCthAdndnavclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqtaAVhAdndnavcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaOaAaXVBdbavcxfhvaOclfhOaHcufgHmbkkcbhOdnadTmbaehvcbhHinaOaiavclfydbcdtfydbgAaiavcwfydbcdtfydbgX9haiavydbcdtfydbgraA9haraX9hGGfhOavcxfhvaHcifgHad6mbkkJbbbbh8Adnas:ZgCaL:taY:Ygwaz:Y:tgENak:Zg3aO:Zg5:tNa3aL:tawaP:Y:tg8ENa5aC:tNMg8FJbbbb9BmbaCa3:ta8EaEa5aL:tNNNa8F:vh8AkdndnaOaQ0mbaOhkaYhPxekaOhsaYhzkdndnaKcl0mbdna8AawMJbbbZMgw:lJbbb9p9DTmbaw:Ohvxdkcjjjj94hvxekaPazfcd9ThvkaKcefgKcs9hmbkkdndndnakmbJbbjZhwcbhicdhvaDmexdkalcd4alfhHcehOinaOgvcethOavaH6mbkcbhOaqcuavcdtgYavcFFFFi0Ecbyd1:jjjbHjjjjbbgKBdCaqciBd2aqamcbyd1:jjjbHjjjjbbgzBdKaqclBd2dndndndnalTmbaPcuf:YhwaoTmecbhOaihAaxhHindndnaoaOfRbbceGTmbaOcjjjjlVhXxekdndnaHclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcqthXdndnaHcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaXarVhXdndnaHIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaXarcCtVhXkaAaXBdbaAclfhAaHcxfhHalaOcefgO9hmbxikkaKcFeaYz:tjjjb8AcbhPcbhvxdkaxhOaihHalhAindndnaOIdbawNJbbbZMgC:lJbbb9p9DTmbaC:OhXxekcjjjj94hXkaXcCthXdndnaOclfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkarcqtaXVhXdndnaOcwfIdbawNJbbbZMgC:lJbbb9p9DTmbaC:Ohrxekcjjjj94hrkaHaXarVBdbaOcxfhOaHclfhHaAcufgAmbkkaKcFeaYz:tjjjbhravcufhocbhPcbhYindndndnaraiaYcdtgKfydbgAcm4aA7c:v;t;h;Ev2gvcs4av7aoGgHcdtfgXydbgOcuSmbcehvinaiaOcdtgOfydbaASmdaHavfhOavcefhvaraOaoGgHcdtfgXydbgOcu9hmbkkaXaYBdbaPhvaPcefhPxekazaOfydbhvkazaKfavBdbaYcefgYal9hmbkcuaPc8S2gOaPc;D;O;f8U0Ehvkcbhraqavcbyd1:jjjbHjjjjbbgvBd3aqcvBd2avcbaOz:tjjjbhOdnadTmbaehiinJbbnnJbbjZazaiydbgAcdtfydbgvazaiclfydbgHcdtfydbgYSavazaicwfydbgXcdtfydbgKSGgoEh8EdnaxaHcx2fgHIdbaxaAcx2fgAIdbg5:tgCaxaXcx2fgXIdlaAIdlg8A:tgwNaXIdba5:tg3aHIdla8A:tg8FN:tgLaLNa8FaXIdwaAIdwgE:tgaNawaHIdwaE:tg8FN:tgwawNa8Fa3NaaaCN:tgCaCNMM:rg3Jbbbb9ETmbaLa3:vhLaCa3:vhCawa3:vhwkaOavc8S2fgvavIdbawa8Ea3:rNg3awNNg8FMUdbavaCa3aCNgaNghavIdlMUdlavaLa3aLNg8ENggavIdwMUdwavaaawNgaavIdxMUdxava8EawNg8JavIdzMUdzava8EaCNg8EavIdCMUdCavawa3aLaENawa5Na8AaCNMM:mg8ANg5NgwavIdKMUdKavaCa5NgCavId3MUd3avaLa5NgLavIdaMUdaava5a8ANg5avId8KMUd8Kava3avIdyMUdydnaombaOaYc8S2fgva8FavIdbMUdbavahavIdlMUdlavagavIdwMUdwavaaavIdxMUdxava8JavIdzMUdzava8EavIdCMUdCavawavIdKMUdKavaCavId3MUd3avaLavIdaMUdaava5avId8KMUd8Kava3avIdyMUdyaOaKc8S2fgva8FavIdbMUdbavahavIdlMUdlavagavIdwMUdwavaaavIdxMUdxava8JavIdzMUdzava8EavIdCMUdCavawavIdKMUdKavaCavId3MUd3avaLavIdaMUdaava5avId8KMUd8Kava3avIdyMUdykaicxfhiarcifgrad6mbkkcbhAaqcuaPcdtgvaPcFFFFi0Egicbyd1:jjjbHjjjjbbgHBdaaqcoBd2aqaicbyd1:jjjbHjjjjbbgiBd8KaqcrBd2aHcFeavz:tjjjbhYdnalTmbazhHinJbbbbJbbjZaOaHydbgXc8S2fgvIdygw:vawJbbbb9BEavIdwaxcwfIdbgwNavIdzaxIdbgCNavIdaMgLaLMMawNavIdlaxclfIdbgLNavIdCawNavId3MgwawMMaLNavIdbaCNavIdxaLNavIdKMgwawMMaCNavId8KMMM:lNhwdndnaYaXcdtgvfgXydbcuSmbaiavfIdbaw9ETmekaXaABdbaiavfawUdbkaHclfhHaxcxfhxalaAcefgA9hmbkkJbbbbhwdnaPTmbinaiIdbgCawawaC9DEhwaiclfhiaPcufgPmbkkakcd4akfhOcehiinaigvcethiavaO6mbkcbhiaqcuavcdtgOavcFFFFi0Ecbyd1:jjjbHjjjjbbgHBdyaHcFeaOz:tjjjbhXdnadTmbavcufhrcbhPcbhxindnazaeaxcdtfgvydbcdtfydbgiazavclfydbcdtfydbgOSmbaiazavcwfydbcdtfydbgvSmbaOavSmbaYavcdtfydbhAdndnaYaOcdtfydbgvaYaicdtfydbgi9pmbavaA9pmbaAhlaihoavhAxekdnaAai9pmbaAav9pmbaihlavhoxekavhlaAhoaihAkabaPcx2fgvaABdbavcwfaoBdbavclfalBdbdnaXaoc:3F;N8N2alc:F:b:DD27aAc;D;O:B8J27arGgOcdtfgvydbgicuSmbcehHinaHhvdnabaicx2fgiydbaA9hmbaiydlal9hmbaiydwaoSmikavcefhHaXaOavfarGgOcdtfgvydbgicu9hmbkkavaPBdbaPcefhPkaxcifgxad6mbkaPci2hikdnaDmbcwhvxdkaw:rhwcwhvkaDawUdbkavcdthvdninavTmeavc98fgvaqcxffydbcbyd:m:jjjbH:bjjjbbxbkkaqc;Wbf8Kjjjjbaik:2ldwue9:8Jjjjjbc;Wb9Rgr8Kjjjjbcbhwarcxfcbc;Kbz:tjjjb8AdnabaeSmbabaeadcdtzMjjjb8AkarcualcdtalcFFFFi0EgDcbyd1:jjjbHjjjjbbgqBdxarceBd2aqcbaialavcbarcxfz:djjjbcualcx2alc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbhkarcxfaryd2gxcdtgmfakBdbaraxcefgPBd2akaialavcbcbz:ejjjb8AarcxfaPcdtfaDcbyd1:jjjbHjjjjbbgvBdbaraxcdfgiBd2arcxfaicdtfcuavalaeadaqz:fjjjbgecltaecjjjjiGEcbyd1:jjjbHjjjjbbgiBdbaiaeavakalz:gjjjbdnadTmbaoaoNhocbhwabhlcbhkindnaiavalydbgecdtfydbcdtfIdbao9ETmbalclf8PdbhsabawcdtfgqaeBdbaqclfas83dbawcifhwkalcxfhlakcifgkad6mbkkaxcifhlamarcxffcwfhkdninalTmeakydbcbyd:m:jjjbH:bjjjbbakc98fhkalcufhlxbkkarc;Wbf8Kjjjjbawk:XCoDud99vue99vuo998Jjjjjbc;Wb9Rgw8KjjjjbdndnarmbcbhDxekawcxfcbc;Kbz:tjjjb8Aawcuadcx2adc;v:Q;v:Qe0Ecbyd1:jjjbHjjjjbbgqBdxawceBd2aqaeadaicbcbz:ejjjb8AawcuadcdtadcFFFFi0Egkcbyd1:jjjbHjjjjbbgxBdzawcdBd2adcd4adfhmceheinaegicetheaiam6mbkcbhPawcuaicdtgsaicFFFFi0Ecbyd1:jjjbHjjjjbbgzBdCawciBd2dndnar:ZgH:rJbbbZMgO:lJbbb9p9DTmbaO:Ohexekcjjjj94hekaicufhAc:bwhDcbhCadhXcbhQinaeaDcufaeaD9iEaPcefaeaP9kEhLdndnadTmbaLcuf:YhOaqhiaxheadhmindndnaiIdbaONJbbbZMgK:lJbbb9p9DTmbaK:OhYxekcjjjj94hYkaYcCthYdndnaiclfIdbaONJbbbZMgK:lJbbb9p9DTmbaK:Oh8Axekcjjjj94h8Aka8AcqtaYVhYdndnaicwfIdbaONJbbbZMgK:lJbbb9p9DTmbaK:Oh8Axekcjjjj94h8AkaeaYa8AVBdbaicxfhiaeclfheamcufgmmbkazcFeasz:tjjjbhEcbh3cbh5indnaEaxa5cdtfydbgYcm4aY7c:v;t;h;Ev2gics4ai7aAGgmcdtfg8AydbgecuSmbaeaYSmbcehiinaEamaifaAGgmcdtfg8AydbgecuSmeaicefhiaeaY9hmbkka8AaYBdba3aecuSfh3a5cefg5ad9hmbxdkkazcFeasz:tjjjb8Acbh3kJbbbbh8EdnaX:ZgKaH:taL:YgOaD:Y:tg8FNaC:Zgaa3:Zgh:tNaaaH:taOaP:Y:tggNahaK:tNMg8JJbbbb9BmbaKaa:taga8FahaH:tNNNa8J:vh8EkaPaLa3ar0giEhPaCa3aiEhCdna3arSmbaLaDaiEgDaP9Rcd9imbdndnaQcl0mbdna8EaOMJbbbZMgO:lJbbb9p9DTmbaO:Ohexdkcjjjj94hexekaPaDfcd9Theka3aXaiEhXaQcefgQcs9hmekkdndnaCmbcihicbhDxekcbhiawakcbyd1:jjjbHjjjjbbg5BdKawclBd2aPcuf:YhKdndnadTmbaqhiaxheadhmindndnaiIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:OhYxekcjjjj94hYkaYcCthYdndnaiclfIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:Oh8Axekcjjjj94h8Aka8AcqtaYVhYdndnaicwfIdbaKNJbbbZMgO:lJbbb9p9DTmbaO:Oh8Axekcjjjj94h8AkaeaYa8AVBdbaicxfhiaeclfheamcufgmmbkazcFeasz:tjjjbhEcbhDcbh3indndndnaEaxa3cdtgLfydbgYcm4aY7c:v;t;h;Ev2gics4ai7aAGgmcdtfg8AydbgecuSmbcehiinaxaecdtgefydbaYSmdamaifheaicefhiaEaeaAGgmcdtfg8Aydbgecu9hmbkka8Aa3BdbaDhiaDcefhDxeka5aefydbhika5aLfaiBdba3cefg3ad9hmbkcuaDc32giaDc;j:KM;jb0EhexekazcFeasz:tjjjb8AcbhDcbhekawaecbyd1:jjjbHjjjjbbgeBd3awcvBd2aecbaiz:tjjjbh8Aavcd4hxdnadTmbdnalTmbaxcdthEa5hYaqhealhmadhAina8AaYydbc32fgiaeIdbaiIdbMUdbaiaeclfIdbaiIdlMUdlaiaecwfIdbaiIdwMUdwaiamIdbaiIdxMUdxaiamclfIdbaiIdzMUdzaiamcwfIdbaiIdCMUdCaiaiIdKJbbjZMUdKaYclfhYaecxfheamaEfhmaAcufgAmbxdkka5hmaqheadhYina8Aamydbc32fgiaeIdbaiIdbMUdbaiaeclfIdbaiIdlMUdlaiaecwfIdbaiIdwMUdwaiaiIdxJbbbbMUdxaiaiIdzJbbbbMUdzaiaiIdCJbbbbMUdCaiaiIdKJbbjZMUdKamclfhmaecxfheaYcufgYmbkkdnaDTmba8AhiaDheinaiaiIdbJbbbbJbbjZaicKfIdbgO:vaOJbbbb9BEgONUdbaiclfgmaOamIdbNUdbaicwfgmaOamIdbNUdbaicxfgmaOamIdbNUdbaiczfgmaOamIdbNUdbaicCfgmaOamIdbNUdbaic3fhiaecufgembkkcbhYawcuaDcdtgLaDcFFFFi0Egicbyd1:jjjbHjjjjbbgeBdaawcoBd2awaicbyd1:jjjbHjjjjbbgEBd8KaecFeaLz:tjjjbh3dnadTmbJbbjZJbbjZaK:vaPceSEaoNgOaONhKaxcdthxalheinaKaec;81jjbalEgmIdwa8Aa5ydbgAc32fgiIdC:tgOaONamIdbaiIdx:tgOaONamIdlaiIdz:tgOaONMMNaqcwfIdbaiIdw:tgOaONaqIdbaiIdb:tgOaONaqclfIdbaiIdl:tgOaONMMMhOdndna3aAcdtgifgmydbcuSmbaEaifIdbaO9ETmekamaYBdbaEaifaOUdbka5clfh5aqcxfhqaeaxfheadaYcefgY9hmbkkaba3aLzMjjjb8AcrhikaicdthiinaiTmeaic98fgiawcxffydbcbyd:m:jjjbH:bjjjbbxbkkawc;Wbf8KjjjjbaDk:Ydidui99ducbhi8Jjjjjbca9Rglczfcwfcbyd11jjbBdbalcb8Pdj1jjb83izalcwfcbydN1jjbBdbalcb8Pd:m1jjb83ibdndnaembJbbjFhvJbbjFhoJbbjFhrxekadcd4cdthwincbhdinalczfadfgDabadfIdbgvaDIdbgoaoav9EEUdbaladfgDavaDIdbgoaoav9DEUdbadclfgdcx9hmbkabawfhbaicefgiae9hmbkalIdwalIdK:thralIdlalIdC:thoalIdbalIdz:thvkJbbbbavavJbbbb9DEgvaoaoav9DEgvararav9DEk9DeeuabcFeaicdtz:tjjjbhlcbhbdnadTmbindnalaeydbcdtfgiydbcu9hmbaiabBdbabcefhbkaeclfheadcufgdmbkkabk;7idqui998Jjjjjbc;Wb9Rgl8Kjjjjbalcxfcbc;Kbz:tjjjb8Aadcd4adfhvcehoinaogrcethoarav6mbkalcuarcdtgoarcFFFFi0Ecbyd1:jjjbHjjjjbbgvBdxavcFeaoz:tjjjbhwdnadTmbaicd4hDarcufhqcbhkindndnawcbaeakaD2cdtfgrydlgiaicjjjj94SEgocH4ao7c:F:b:DD2cbarydbgxaxcjjjj94SEgocH4ao7c;D;O:B8J27cbarydwgmamcjjjj94SEgrcH4ar7c:3F;N8N27aqGgvcdtfgrydbgocuSmbam::hPai::hsax::hzcehiinaihrdnaeaoaD2cdtfgiIdbaz9CmbaiIdlas9CmbaiIdwaP9BmikarcefhiawavarfaqGgvcdtfgrydbgocu9hmbkkarakBdbakhokabakcdtfaoBdbakcefgkad9hmbkkcbhrdninarc98Smealcxfarfydbcbyd:m:jjjbH:bjjjbbarc98fhrxbkkalc;Wbf8Kjjjjbk9teiucbcbyd:q:jjjbgeabcifc98GfgbBd:q:jjjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;teeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiaeydlBdlaiaeydwBdwaiaeydxBdxaeczfheaiczfhiadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk:3eedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdxaialBdwaialBdlaialBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabk9teiucbcbyd:q:jjjbgeabcrfc94GfgbBd:q:jjjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikTeeucbabcbyd:q:jjjbge9Rcifc98GaefgbBd:q:jjjbdnabZbcztge9nmbabae9RcFFifcz4nb8Akkk:Iedbcjwk1eFFuuFFuuFFuuFFuFFFuFFFuFbbbbbbbbebbbdbbbbbbbebbbebbbdbbbbbbbbbbbeeeeebebbebbebebbbeebbbbbbbbbbbbeeeeeebebbeeebeebbbbebebbbbbbbbbbbbbbbbbbc1Dkxebbbdbbb:GNbb'; // embed! wasm
|
|
18496
|
+
|
|
18497
|
+
var wasmpack = new Uint8Array([
|
|
18498
|
+
32, 0, 65, 2, 1, 106, 34, 33, 3, 128, 11, 4, 13, 64, 6, 253, 10, 7, 15, 116, 127, 5, 8, 12, 40, 16, 19, 54, 20, 9, 27, 255, 113, 17, 42, 67,
|
|
18499
|
+
24, 23, 146, 148, 18, 14, 22, 45, 70, 69, 56, 114, 101, 21, 25, 63, 75, 136, 108, 28, 118, 29, 73, 115,
|
|
18500
|
+
]);
|
|
18501
|
+
|
|
18502
|
+
if (typeof WebAssembly !== 'object') {
|
|
18503
|
+
return {
|
|
18504
|
+
supported: false,
|
|
18505
|
+
};
|
|
18506
|
+
}
|
|
18507
|
+
|
|
18508
|
+
var instance;
|
|
18509
|
+
|
|
18510
|
+
var ready = WebAssembly.instantiate(unpack(wasm), {}).then(function (result) {
|
|
18511
|
+
instance = result.instance;
|
|
18512
|
+
instance.exports.__wasm_call_ctors();
|
|
18513
|
+
});
|
|
18514
|
+
|
|
18515
|
+
function unpack(data) {
|
|
18516
|
+
var result = new Uint8Array(data.length);
|
|
18517
|
+
for (var i = 0; i < data.length; ++i) {
|
|
18518
|
+
var ch = data.charCodeAt(i);
|
|
18519
|
+
result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4;
|
|
18520
|
+
}
|
|
18521
|
+
var write = 0;
|
|
18522
|
+
for (var i = 0; i < data.length; ++i) {
|
|
18523
|
+
result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i];
|
|
18524
|
+
}
|
|
18525
|
+
return result.buffer.slice(0, write);
|
|
18526
|
+
}
|
|
18527
|
+
|
|
18528
|
+
function assert(cond) {
|
|
18529
|
+
if (!cond) {
|
|
18530
|
+
throw new Error('Assertion failed');
|
|
18531
|
+
}
|
|
18532
|
+
}
|
|
18533
|
+
|
|
18534
|
+
function bytes(view) {
|
|
18535
|
+
return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
|
18536
|
+
}
|
|
18537
|
+
|
|
18538
|
+
function genremap(fun, positions, vertices, stride) {
|
|
18539
|
+
var sbrk = instance.exports.sbrk;
|
|
18540
|
+
var rp = sbrk(vertices * 4);
|
|
18541
|
+
var sp = sbrk(vertices * stride * 4);
|
|
18542
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18543
|
+
heap.set(bytes(positions), sp);
|
|
18544
|
+
fun(rp, sp, vertices, stride * 4);
|
|
18545
|
+
// heap may have grown
|
|
18546
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18547
|
+
var remap = new Uint32Array(vertices);
|
|
18548
|
+
new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
|
|
18549
|
+
sbrk(rp - sbrk(0));
|
|
18550
|
+
return remap;
|
|
18551
|
+
}
|
|
18552
|
+
|
|
18553
|
+
function reorder(fun, indices, vertices) {
|
|
18554
|
+
var sbrk = instance.exports.sbrk;
|
|
18555
|
+
var ip = sbrk(indices.length * 4);
|
|
18556
|
+
var rp = sbrk(vertices * 4);
|
|
18557
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18558
|
+
var indices8 = bytes(indices);
|
|
18559
|
+
heap.set(indices8, ip);
|
|
18560
|
+
var unique = fun(rp, ip, indices.length, vertices);
|
|
18561
|
+
// heap may have grown
|
|
18562
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18563
|
+
var remap = new Uint32Array(vertices);
|
|
18564
|
+
new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
|
|
18565
|
+
indices8.set(heap.subarray(ip, ip + indices.length * 4));
|
|
18566
|
+
sbrk(ip - sbrk(0));
|
|
18567
|
+
|
|
18568
|
+
for (var i = 0; i < indices.length; ++i) indices[i] = remap[indices[i]];
|
|
18569
|
+
|
|
18570
|
+
return [remap, unique];
|
|
18571
|
+
}
|
|
18572
|
+
|
|
18573
|
+
function maxindex(source) {
|
|
18574
|
+
var result = 0;
|
|
18575
|
+
for (var i = 0; i < source.length; ++i) {
|
|
18576
|
+
var index = source[i];
|
|
18577
|
+
result = result < index ? index : result;
|
|
18578
|
+
}
|
|
18579
|
+
return result;
|
|
18580
|
+
}
|
|
18581
|
+
|
|
18582
|
+
function simplify(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, options) {
|
|
18583
|
+
var sbrk = instance.exports.sbrk;
|
|
18584
|
+
var te = sbrk(4);
|
|
18585
|
+
var ti = sbrk(index_count * 4);
|
|
18586
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18587
|
+
var si = sbrk(index_count * 4);
|
|
18588
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18589
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18590
|
+
heap.set(bytes(indices), si);
|
|
18591
|
+
var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_index_count, target_error, options, te);
|
|
18592
|
+
// heap may have grown
|
|
18593
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18594
|
+
var target = new Uint32Array(result);
|
|
18595
|
+
bytes(target).set(heap.subarray(ti, ti + result * 4));
|
|
18596
|
+
var error = new Float32Array(1);
|
|
18597
|
+
bytes(error).set(heap.subarray(te, te + 4));
|
|
18598
|
+
sbrk(te - sbrk(0));
|
|
18599
|
+
return [target, error[0]];
|
|
18600
|
+
}
|
|
18601
|
+
|
|
18602
|
+
function simplifyAttr(
|
|
18603
|
+
fun,
|
|
18604
|
+
indices,
|
|
18605
|
+
index_count,
|
|
18606
|
+
vertex_positions,
|
|
18607
|
+
vertex_count,
|
|
18608
|
+
vertex_positions_stride,
|
|
18609
|
+
vertex_attributes,
|
|
18610
|
+
vertex_attributes_stride,
|
|
18611
|
+
attribute_weights,
|
|
18612
|
+
vertex_lock,
|
|
18613
|
+
target_index_count,
|
|
18614
|
+
target_error,
|
|
18615
|
+
options
|
|
18616
|
+
) {
|
|
18617
|
+
var sbrk = instance.exports.sbrk;
|
|
18618
|
+
var te = sbrk(4);
|
|
18619
|
+
var ti = sbrk(index_count * 4);
|
|
18620
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18621
|
+
var sa = sbrk(vertex_count * vertex_attributes_stride);
|
|
18622
|
+
var sw = sbrk(attribute_weights.length * 4);
|
|
18623
|
+
var si = sbrk(index_count * 4);
|
|
18624
|
+
var vl = vertex_lock ? sbrk(vertex_count) : 0;
|
|
18625
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18626
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18627
|
+
heap.set(bytes(vertex_attributes), sa);
|
|
18628
|
+
heap.set(bytes(attribute_weights), sw);
|
|
18629
|
+
heap.set(bytes(indices), si);
|
|
18630
|
+
if (vertex_lock) {
|
|
18631
|
+
heap.set(bytes(vertex_lock), vl);
|
|
18632
|
+
}
|
|
18633
|
+
var result = fun(
|
|
18634
|
+
ti,
|
|
18635
|
+
si,
|
|
18636
|
+
index_count,
|
|
18637
|
+
sp,
|
|
18638
|
+
vertex_count,
|
|
18639
|
+
vertex_positions_stride,
|
|
18640
|
+
sa,
|
|
18641
|
+
vertex_attributes_stride,
|
|
18642
|
+
sw,
|
|
18643
|
+
attribute_weights.length,
|
|
18644
|
+
vl,
|
|
18645
|
+
target_index_count,
|
|
18646
|
+
target_error,
|
|
18647
|
+
options,
|
|
18648
|
+
te
|
|
18649
|
+
);
|
|
18650
|
+
// heap may have grown
|
|
18651
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18652
|
+
var target = new Uint32Array(result);
|
|
18653
|
+
bytes(target).set(heap.subarray(ti, ti + result * 4));
|
|
18654
|
+
var error = new Float32Array(1);
|
|
18655
|
+
bytes(error).set(heap.subarray(te, te + 4));
|
|
18656
|
+
sbrk(te - sbrk(0));
|
|
18657
|
+
return [target, error[0]];
|
|
18658
|
+
}
|
|
18659
|
+
|
|
18660
|
+
function simplifyUpdate(
|
|
18661
|
+
fun,
|
|
18662
|
+
indices,
|
|
18663
|
+
index_count,
|
|
18664
|
+
vertex_positions,
|
|
18665
|
+
vertex_count,
|
|
18666
|
+
vertex_positions_stride,
|
|
18667
|
+
vertex_attributes,
|
|
18668
|
+
vertex_attributes_stride,
|
|
18669
|
+
attribute_weights,
|
|
18670
|
+
vertex_lock,
|
|
18671
|
+
target_index_count,
|
|
18672
|
+
target_error,
|
|
18673
|
+
options
|
|
18674
|
+
) {
|
|
18675
|
+
var sbrk = instance.exports.sbrk;
|
|
18676
|
+
var te = sbrk(4);
|
|
18677
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18678
|
+
var sa = sbrk(vertex_count * vertex_attributes_stride);
|
|
18679
|
+
var sw = sbrk(attribute_weights.length * 4);
|
|
18680
|
+
var si = sbrk(index_count * 4);
|
|
18681
|
+
var vl = vertex_lock ? sbrk(vertex_count) : 0;
|
|
18682
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18683
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18684
|
+
heap.set(bytes(vertex_attributes), sa);
|
|
18685
|
+
heap.set(bytes(attribute_weights), sw);
|
|
18686
|
+
heap.set(bytes(indices), si);
|
|
18687
|
+
if (vertex_lock) {
|
|
18688
|
+
heap.set(bytes(vertex_lock), vl);
|
|
18689
|
+
}
|
|
18690
|
+
var result = fun(
|
|
18691
|
+
si,
|
|
18692
|
+
index_count,
|
|
18693
|
+
sp,
|
|
18694
|
+
vertex_count,
|
|
18695
|
+
vertex_positions_stride,
|
|
18696
|
+
sa,
|
|
18697
|
+
vertex_attributes_stride,
|
|
18698
|
+
sw,
|
|
18699
|
+
attribute_weights.length,
|
|
18700
|
+
vl,
|
|
18701
|
+
target_index_count,
|
|
18702
|
+
target_error,
|
|
18703
|
+
options,
|
|
18704
|
+
te
|
|
18705
|
+
);
|
|
18706
|
+
// heap may have grown
|
|
18707
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18708
|
+
bytes(indices).set(heap.subarray(si, si + result * 4));
|
|
18709
|
+
bytes(vertex_positions).set(heap.subarray(sp, sp + vertex_count * vertex_positions_stride));
|
|
18710
|
+
bytes(vertex_attributes).set(heap.subarray(sa, sa + vertex_count * vertex_attributes_stride));
|
|
18711
|
+
var error = new Float32Array(1);
|
|
18712
|
+
bytes(error).set(heap.subarray(te, te + 4));
|
|
18713
|
+
sbrk(te - sbrk(0));
|
|
18714
|
+
return [result, error[0]];
|
|
18715
|
+
}
|
|
18716
|
+
|
|
18717
|
+
function simplifyScale(fun, vertex_positions, vertex_count, vertex_positions_stride) {
|
|
18718
|
+
var sbrk = instance.exports.sbrk;
|
|
18719
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18720
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18721
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18722
|
+
var result = fun(sp, vertex_count, vertex_positions_stride);
|
|
18723
|
+
sbrk(sp - sbrk(0));
|
|
18724
|
+
return result;
|
|
18725
|
+
}
|
|
18726
|
+
|
|
18727
|
+
function simplifyPoints(
|
|
18728
|
+
fun,
|
|
18729
|
+
vertex_positions,
|
|
18730
|
+
vertex_count,
|
|
18731
|
+
vertex_positions_stride,
|
|
18732
|
+
vertex_colors,
|
|
18733
|
+
vertex_colors_stride,
|
|
18734
|
+
color_weight,
|
|
18735
|
+
target_vertex_count
|
|
18736
|
+
) {
|
|
18737
|
+
var sbrk = instance.exports.sbrk;
|
|
18738
|
+
var ti = sbrk(target_vertex_count * 4);
|
|
18739
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18740
|
+
var sc = sbrk(vertex_count * vertex_colors_stride);
|
|
18741
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18742
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18743
|
+
if (vertex_colors) {
|
|
18744
|
+
heap.set(bytes(vertex_colors), sc);
|
|
18745
|
+
}
|
|
18746
|
+
var result = fun(ti, sp, vertex_count, vertex_positions_stride, sc, vertex_colors_stride, color_weight, target_vertex_count);
|
|
18747
|
+
// heap may have grown
|
|
18748
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18749
|
+
var target = new Uint32Array(result);
|
|
18750
|
+
bytes(target).set(heap.subarray(ti, ti + result * 4));
|
|
18751
|
+
sbrk(ti - sbrk(0));
|
|
18752
|
+
return target;
|
|
18753
|
+
}
|
|
18754
|
+
|
|
18755
|
+
function simplifySloppy(
|
|
18756
|
+
fun,
|
|
18757
|
+
indices,
|
|
18758
|
+
index_count,
|
|
18759
|
+
vertex_positions,
|
|
18760
|
+
vertex_count,
|
|
18761
|
+
vertex_positions_stride,
|
|
18762
|
+
vertex_lock,
|
|
18763
|
+
target_index_count,
|
|
18764
|
+
target_error
|
|
18765
|
+
) {
|
|
18766
|
+
var sbrk = instance.exports.sbrk;
|
|
18767
|
+
var te = sbrk(4);
|
|
18768
|
+
var ti = sbrk(index_count * 4);
|
|
18769
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18770
|
+
var si = sbrk(index_count * 4);
|
|
18771
|
+
var vl = vertex_lock ? sbrk(vertex_count) : 0;
|
|
18772
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18773
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18774
|
+
heap.set(bytes(indices), si);
|
|
18775
|
+
if (vertex_lock) {
|
|
18776
|
+
heap.set(bytes(vertex_lock), vl);
|
|
18777
|
+
}
|
|
18778
|
+
var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, vl, target_index_count, target_error, te);
|
|
18779
|
+
// heap may have grown
|
|
18780
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18781
|
+
var target = new Uint32Array(result);
|
|
18782
|
+
bytes(target).set(heap.subarray(ti, ti + result * 4));
|
|
18783
|
+
var error = new Float32Array(1);
|
|
18784
|
+
bytes(error).set(heap.subarray(te, te + 4));
|
|
18785
|
+
sbrk(te - sbrk(0));
|
|
18786
|
+
return [target, error[0]];
|
|
18787
|
+
}
|
|
18788
|
+
|
|
18789
|
+
function simplifyPrune(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_error) {
|
|
18790
|
+
var sbrk = instance.exports.sbrk;
|
|
18791
|
+
var ti = sbrk(index_count * 4);
|
|
18792
|
+
var sp = sbrk(vertex_count * vertex_positions_stride);
|
|
18793
|
+
var si = sbrk(index_count * 4);
|
|
18794
|
+
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18795
|
+
heap.set(bytes(vertex_positions), sp);
|
|
18796
|
+
heap.set(bytes(indices), si);
|
|
18797
|
+
var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_error);
|
|
18798
|
+
// heap may have grown
|
|
18799
|
+
heap = new Uint8Array(instance.exports.memory.buffer);
|
|
18800
|
+
var target = new Uint32Array(result);
|
|
18801
|
+
bytes(target).set(heap.subarray(ti, ti + result * 4));
|
|
18802
|
+
sbrk(ti - sbrk(0));
|
|
18803
|
+
return target;
|
|
18804
|
+
}
|
|
18805
|
+
|
|
18806
|
+
var simplifyOptions = {
|
|
18807
|
+
LockBorder: 1,
|
|
18808
|
+
Sparse: 2,
|
|
18809
|
+
ErrorAbsolute: 4,
|
|
18810
|
+
Prune: 8,
|
|
18811
|
+
Regularize: 16,
|
|
18812
|
+
Permissive: 32,
|
|
18813
|
+
_InternalDebug: 1 << 30, // internal, don't use!
|
|
18814
|
+
};
|
|
18815
|
+
|
|
18816
|
+
return {
|
|
18817
|
+
ready: ready,
|
|
18818
|
+
supported: true,
|
|
18819
|
+
|
|
18820
|
+
compactMesh: function (indices) {
|
|
18821
|
+
assert(
|
|
18822
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
18823
|
+
);
|
|
18824
|
+
assert(indices.length % 3 == 0);
|
|
18825
|
+
|
|
18826
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
18827
|
+
return reorder(instance.exports.meshopt_optimizeVertexFetchRemap, indices32, maxindex(indices) + 1);
|
|
18828
|
+
},
|
|
18829
|
+
|
|
18830
|
+
generatePositionRemap: function (vertex_positions, vertex_positions_stride) {
|
|
18831
|
+
assert(vertex_positions instanceof Float32Array);
|
|
18832
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
18833
|
+
assert(vertex_positions_stride >= 3);
|
|
18834
|
+
|
|
18835
|
+
return genremap(
|
|
18836
|
+
instance.exports.meshopt_generatePositionRemap,
|
|
18837
|
+
vertex_positions,
|
|
18838
|
+
vertex_positions.length / vertex_positions_stride,
|
|
18839
|
+
vertex_positions_stride
|
|
18840
|
+
);
|
|
18841
|
+
},
|
|
18842
|
+
|
|
18843
|
+
simplify: function (indices, vertex_positions, vertex_positions_stride, target_index_count, target_error, flags) {
|
|
18844
|
+
assert(
|
|
18845
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
18846
|
+
);
|
|
18847
|
+
assert(indices.length % 3 == 0);
|
|
18848
|
+
assert(vertex_positions instanceof Float32Array);
|
|
18849
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
18850
|
+
assert(vertex_positions_stride >= 3);
|
|
18851
|
+
assert(target_index_count >= 0 && target_index_count <= indices.length);
|
|
18852
|
+
assert(target_index_count % 3 == 0);
|
|
18853
|
+
assert(target_error >= 0);
|
|
18854
|
+
|
|
18855
|
+
var options = 0;
|
|
18856
|
+
for (var i = 0; i < (flags ? flags.length : 0); ++i) {
|
|
18857
|
+
assert(flags[i] in simplifyOptions);
|
|
18858
|
+
options |= simplifyOptions[flags[i]];
|
|
18859
|
+
}
|
|
18860
|
+
|
|
18861
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
18862
|
+
var result = simplify(
|
|
18863
|
+
instance.exports.meshopt_simplify,
|
|
18864
|
+
indices32,
|
|
18865
|
+
indices.length,
|
|
18866
|
+
vertex_positions,
|
|
18867
|
+
vertex_positions.length / vertex_positions_stride,
|
|
18868
|
+
vertex_positions_stride * 4,
|
|
18869
|
+
target_index_count,
|
|
18870
|
+
target_error,
|
|
18871
|
+
options
|
|
18872
|
+
);
|
|
18873
|
+
result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
|
|
18874
|
+
|
|
18875
|
+
return result;
|
|
18876
|
+
},
|
|
18877
|
+
|
|
18878
|
+
simplifyWithAttributes: function (
|
|
18879
|
+
indices,
|
|
18880
|
+
vertex_positions,
|
|
18881
|
+
vertex_positions_stride,
|
|
18882
|
+
vertex_attributes,
|
|
18883
|
+
vertex_attributes_stride,
|
|
18884
|
+
attribute_weights,
|
|
18885
|
+
vertex_lock,
|
|
18886
|
+
target_index_count,
|
|
18887
|
+
target_error,
|
|
18888
|
+
flags
|
|
18889
|
+
) {
|
|
18890
|
+
assert(
|
|
18891
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
18892
|
+
);
|
|
18893
|
+
assert(indices.length % 3 == 0);
|
|
18894
|
+
assert(vertex_positions instanceof Float32Array);
|
|
18895
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
18896
|
+
assert(vertex_positions_stride >= 3);
|
|
18897
|
+
assert(vertex_attributes instanceof Float32Array);
|
|
18898
|
+
assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
|
|
18899
|
+
assert(vertex_attributes_stride >= 0);
|
|
18900
|
+
assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
|
|
18901
|
+
assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
|
|
18902
|
+
assert(target_index_count >= 0 && target_index_count <= indices.length);
|
|
18903
|
+
assert(target_index_count % 3 == 0);
|
|
18904
|
+
assert(target_error >= 0);
|
|
18905
|
+
assert(Array.isArray(attribute_weights));
|
|
18906
|
+
assert(vertex_attributes_stride >= attribute_weights.length);
|
|
18907
|
+
assert(attribute_weights.length <= 32);
|
|
18908
|
+
for (var i = 0; i < attribute_weights.length; ++i) {
|
|
18909
|
+
assert(attribute_weights[i] >= 0);
|
|
18910
|
+
}
|
|
18911
|
+
|
|
18912
|
+
var options = 0;
|
|
18913
|
+
for (var i = 0; i < (flags ? flags.length : 0); ++i) {
|
|
18914
|
+
assert(flags[i] in simplifyOptions);
|
|
18915
|
+
options |= simplifyOptions[flags[i]];
|
|
18916
|
+
}
|
|
18917
|
+
|
|
18918
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
18919
|
+
var result = simplifyAttr(
|
|
18920
|
+
instance.exports.meshopt_simplifyWithAttributes,
|
|
18921
|
+
indices32,
|
|
18922
|
+
indices.length,
|
|
18923
|
+
vertex_positions,
|
|
18924
|
+
vertex_positions.length / vertex_positions_stride,
|
|
18925
|
+
vertex_positions_stride * 4,
|
|
18926
|
+
vertex_attributes,
|
|
18927
|
+
vertex_attributes_stride * 4,
|
|
18928
|
+
new Float32Array(attribute_weights),
|
|
18929
|
+
vertex_lock,
|
|
18930
|
+
target_index_count,
|
|
18931
|
+
target_error,
|
|
18932
|
+
options
|
|
18933
|
+
);
|
|
18934
|
+
result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
|
|
18935
|
+
|
|
18936
|
+
return result;
|
|
18937
|
+
},
|
|
18938
|
+
|
|
18939
|
+
simplifyWithUpdate: function (
|
|
18940
|
+
indices,
|
|
18941
|
+
vertex_positions,
|
|
18942
|
+
vertex_positions_stride,
|
|
18943
|
+
vertex_attributes,
|
|
18944
|
+
vertex_attributes_stride,
|
|
18945
|
+
attribute_weights,
|
|
18946
|
+
vertex_lock,
|
|
18947
|
+
target_index_count,
|
|
18948
|
+
target_error,
|
|
18949
|
+
flags
|
|
18950
|
+
) {
|
|
18951
|
+
assert(
|
|
18952
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
18953
|
+
);
|
|
18954
|
+
assert(indices.length % 3 == 0);
|
|
18955
|
+
assert(vertex_positions instanceof Float32Array);
|
|
18956
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
18957
|
+
assert(vertex_positions_stride >= 3);
|
|
18958
|
+
assert(vertex_attributes instanceof Float32Array);
|
|
18959
|
+
assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
|
|
18960
|
+
assert(vertex_attributes_stride >= 0);
|
|
18961
|
+
assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
|
|
18962
|
+
assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
|
|
18963
|
+
assert(target_index_count >= 0 && target_index_count <= indices.length);
|
|
18964
|
+
assert(target_index_count % 3 == 0);
|
|
18965
|
+
assert(target_error >= 0);
|
|
18966
|
+
assert(Array.isArray(attribute_weights));
|
|
18967
|
+
assert(vertex_attributes_stride >= attribute_weights.length);
|
|
18968
|
+
assert(attribute_weights.length <= 32);
|
|
18969
|
+
for (var i = 0; i < attribute_weights.length; ++i) {
|
|
18970
|
+
assert(attribute_weights[i] >= 0);
|
|
18971
|
+
}
|
|
18972
|
+
|
|
18973
|
+
var options = 0;
|
|
18974
|
+
for (var i = 0; i < (flags ? flags.length : 0); ++i) {
|
|
18975
|
+
assert(flags[i] in simplifyOptions);
|
|
18976
|
+
options |= simplifyOptions[flags[i]];
|
|
18977
|
+
}
|
|
18978
|
+
|
|
18979
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
18980
|
+
var result = simplifyUpdate(
|
|
18981
|
+
instance.exports.meshopt_simplifyWithUpdate,
|
|
18982
|
+
indices32,
|
|
18983
|
+
indices.length,
|
|
18984
|
+
vertex_positions,
|
|
18985
|
+
vertex_positions.length / vertex_positions_stride,
|
|
18986
|
+
vertex_positions_stride * 4,
|
|
18987
|
+
vertex_attributes,
|
|
18988
|
+
vertex_attributes_stride * 4,
|
|
18989
|
+
new Float32Array(attribute_weights),
|
|
18990
|
+
vertex_lock,
|
|
18991
|
+
target_index_count,
|
|
18992
|
+
target_error,
|
|
18993
|
+
options
|
|
18994
|
+
);
|
|
18995
|
+
if (indices !== indices32) {
|
|
18996
|
+
// copy back indices if they were converted to Uint32Array
|
|
18997
|
+
for (var i = 0; i < result[0]; ++i) {
|
|
18998
|
+
indices[i] = indices32[i];
|
|
18999
|
+
}
|
|
19000
|
+
}
|
|
19001
|
+
return result;
|
|
19002
|
+
},
|
|
19003
|
+
|
|
19004
|
+
getScale: function (vertex_positions, vertex_positions_stride) {
|
|
19005
|
+
assert(vertex_positions instanceof Float32Array);
|
|
19006
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
19007
|
+
assert(vertex_positions_stride >= 3);
|
|
19008
|
+
return simplifyScale(
|
|
19009
|
+
instance.exports.meshopt_simplifyScale,
|
|
19010
|
+
vertex_positions,
|
|
19011
|
+
vertex_positions.length / vertex_positions_stride,
|
|
19012
|
+
vertex_positions_stride * 4
|
|
19013
|
+
);
|
|
19014
|
+
},
|
|
19015
|
+
|
|
19016
|
+
simplifyPoints: function (vertex_positions, vertex_positions_stride, target_vertex_count, vertex_colors, vertex_colors_stride, color_weight) {
|
|
19017
|
+
assert(vertex_positions instanceof Float32Array);
|
|
19018
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
19019
|
+
assert(vertex_positions_stride >= 3);
|
|
19020
|
+
assert(target_vertex_count >= 0 && target_vertex_count <= vertex_positions.length / vertex_positions_stride);
|
|
19021
|
+
if (vertex_colors) {
|
|
19022
|
+
assert(vertex_colors instanceof Float32Array);
|
|
19023
|
+
assert(vertex_colors.length % vertex_colors_stride == 0);
|
|
19024
|
+
assert(vertex_colors_stride >= 3);
|
|
19025
|
+
assert(vertex_positions.length / vertex_positions_stride == vertex_colors.length / vertex_colors_stride);
|
|
19026
|
+
return simplifyPoints(
|
|
19027
|
+
instance.exports.meshopt_simplifyPoints,
|
|
19028
|
+
vertex_positions,
|
|
19029
|
+
vertex_positions.length / vertex_positions_stride,
|
|
19030
|
+
vertex_positions_stride * 4,
|
|
19031
|
+
vertex_colors,
|
|
19032
|
+
vertex_colors_stride * 4,
|
|
19033
|
+
color_weight,
|
|
19034
|
+
target_vertex_count
|
|
19035
|
+
);
|
|
19036
|
+
} else {
|
|
19037
|
+
return simplifyPoints(
|
|
19038
|
+
instance.exports.meshopt_simplifyPoints,
|
|
19039
|
+
vertex_positions,
|
|
19040
|
+
vertex_positions.length / vertex_positions_stride,
|
|
19041
|
+
vertex_positions_stride * 4,
|
|
19042
|
+
undefined,
|
|
19043
|
+
0,
|
|
19044
|
+
0,
|
|
19045
|
+
target_vertex_count
|
|
19046
|
+
);
|
|
19047
|
+
}
|
|
19048
|
+
},
|
|
19049
|
+
|
|
19050
|
+
simplifySloppy: function (indices, vertex_positions, vertex_positions_stride, vertex_lock, target_index_count, target_error) {
|
|
19051
|
+
assert(
|
|
19052
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
19053
|
+
);
|
|
19054
|
+
assert(indices.length % 3 == 0);
|
|
19055
|
+
assert(vertex_positions instanceof Float32Array);
|
|
19056
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
19057
|
+
assert(vertex_positions_stride >= 3);
|
|
19058
|
+
assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
|
|
19059
|
+
assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
|
|
19060
|
+
assert(target_index_count >= 0 && target_index_count <= indices.length);
|
|
19061
|
+
assert(target_index_count % 3 == 0);
|
|
19062
|
+
assert(target_error >= 0);
|
|
19063
|
+
|
|
19064
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
19065
|
+
var result = simplifySloppy(
|
|
19066
|
+
instance.exports.meshopt_simplifySloppy,
|
|
19067
|
+
indices32,
|
|
19068
|
+
indices.length,
|
|
19069
|
+
vertex_positions,
|
|
19070
|
+
vertex_positions.length / vertex_positions_stride,
|
|
19071
|
+
vertex_positions_stride * 4,
|
|
19072
|
+
vertex_lock,
|
|
19073
|
+
target_index_count,
|
|
19074
|
+
target_error
|
|
19075
|
+
);
|
|
19076
|
+
result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
|
|
19077
|
+
|
|
19078
|
+
return result;
|
|
19079
|
+
},
|
|
19080
|
+
|
|
19081
|
+
simplifyPrune: function (indices, vertex_positions, vertex_positions_stride, target_error) {
|
|
19082
|
+
assert(
|
|
19083
|
+
indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
|
|
19084
|
+
);
|
|
19085
|
+
assert(indices.length % 3 == 0);
|
|
19086
|
+
assert(vertex_positions instanceof Float32Array);
|
|
19087
|
+
assert(vertex_positions.length % vertex_positions_stride == 0);
|
|
19088
|
+
assert(vertex_positions_stride >= 3);
|
|
19089
|
+
assert(target_error >= 0);
|
|
19090
|
+
|
|
19091
|
+
var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
|
|
19092
|
+
var result = simplifyPrune(
|
|
19093
|
+
instance.exports.meshopt_simplifyPrune,
|
|
19094
|
+
indices32,
|
|
19095
|
+
indices.length,
|
|
19096
|
+
vertex_positions,
|
|
19097
|
+
vertex_positions.length / vertex_positions_stride,
|
|
19098
|
+
vertex_positions_stride * 4,
|
|
19099
|
+
target_error
|
|
19100
|
+
);
|
|
19101
|
+
result = indices instanceof Uint32Array ? result : new indices.constructor(result);
|
|
19102
|
+
|
|
19103
|
+
return result;
|
|
19104
|
+
},
|
|
19105
|
+
};
|
|
19106
|
+
})();
|
|
19107
|
+
|
|
19108
|
+
/**
|
|
19109
|
+
* Build a minimal GLB (glTF 2.0 binary) file containing a single triangle mesh.
|
|
19110
|
+
*
|
|
19111
|
+
* The output contains only positions and triangle indices — no normals,
|
|
19112
|
+
* UVs, or materials — suitable for collision meshes.
|
|
19113
|
+
*
|
|
19114
|
+
* @param positions - Vertex positions (3 floats per vertex)
|
|
19115
|
+
* @param indices - Triangle indices (3 per triangle, unsigned 32-bit)
|
|
19116
|
+
* @returns GLB file as a Uint8Array
|
|
19117
|
+
*/
|
|
19118
|
+
function buildCollisionGlb(positions, indices) {
|
|
19119
|
+
const vertexCount = positions.length / 3;
|
|
19120
|
+
const indexCount = indices.length;
|
|
19121
|
+
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
19122
|
+
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
|
19123
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
19124
|
+
const x = positions[i], y = positions[i + 1], z = positions[i + 2];
|
|
19125
|
+
if (x < minX)
|
|
19126
|
+
minX = x;
|
|
19127
|
+
if (y < minY)
|
|
19128
|
+
minY = y;
|
|
19129
|
+
if (z < minZ)
|
|
19130
|
+
minZ = z;
|
|
19131
|
+
if (x > maxX)
|
|
19132
|
+
maxX = x;
|
|
19133
|
+
if (y > maxY)
|
|
19134
|
+
maxY = y;
|
|
19135
|
+
if (z > maxZ)
|
|
19136
|
+
maxZ = z;
|
|
19137
|
+
}
|
|
19138
|
+
const positionsByteLength = positions.byteLength;
|
|
19139
|
+
const indicesByteLength = indices.byteLength;
|
|
19140
|
+
const totalBinSize = positionsByteLength + indicesByteLength;
|
|
19141
|
+
const gltf = {
|
|
19142
|
+
asset: { version: '2.0', generator: 'splat-transform' },
|
|
19143
|
+
scene: 0,
|
|
19144
|
+
scenes: [{ nodes: [0] }],
|
|
19145
|
+
nodes: [{ mesh: 0 }],
|
|
19146
|
+
meshes: [{
|
|
19147
|
+
primitives: [{
|
|
19148
|
+
attributes: { POSITION: 0 },
|
|
19149
|
+
indices: 1
|
|
19150
|
+
}]
|
|
19151
|
+
}],
|
|
19152
|
+
accessors: [
|
|
19153
|
+
{
|
|
19154
|
+
bufferView: 0,
|
|
19155
|
+
componentType: 5126, // FLOAT
|
|
19156
|
+
count: vertexCount,
|
|
19157
|
+
type: 'VEC3',
|
|
19158
|
+
min: [minX, minY, minZ],
|
|
19159
|
+
max: [maxX, maxY, maxZ]
|
|
19160
|
+
},
|
|
19161
|
+
{
|
|
19162
|
+
bufferView: 1,
|
|
19163
|
+
componentType: 5125, // UNSIGNED_INT
|
|
19164
|
+
count: indexCount,
|
|
19165
|
+
type: 'SCALAR'
|
|
19166
|
+
}
|
|
19167
|
+
],
|
|
19168
|
+
bufferViews: [
|
|
19169
|
+
{
|
|
19170
|
+
buffer: 0,
|
|
19171
|
+
byteOffset: 0,
|
|
19172
|
+
byteLength: positionsByteLength,
|
|
19173
|
+
target: 34962 // ARRAY_BUFFER
|
|
19174
|
+
},
|
|
19175
|
+
{
|
|
19176
|
+
buffer: 0,
|
|
19177
|
+
byteOffset: positionsByteLength,
|
|
19178
|
+
byteLength: indicesByteLength,
|
|
19179
|
+
target: 34963 // ELEMENT_ARRAY_BUFFER
|
|
19180
|
+
}
|
|
19181
|
+
],
|
|
19182
|
+
buffers: [{ byteLength: totalBinSize }]
|
|
19183
|
+
};
|
|
19184
|
+
const jsonString = JSON.stringify(gltf);
|
|
19185
|
+
const jsonEncoder = new TextEncoder();
|
|
19186
|
+
const jsonBytes = jsonEncoder.encode(jsonString);
|
|
19187
|
+
// JSON chunk must be padded to 4-byte alignment with spaces (0x20)
|
|
19188
|
+
const jsonPadding = (4 - (jsonBytes.length % 4)) % 4;
|
|
19189
|
+
const jsonChunkLength = jsonBytes.length + jsonPadding;
|
|
19190
|
+
// BIN chunk must be padded to 4-byte alignment with zeros
|
|
19191
|
+
const binPadding = (4 - (totalBinSize % 4)) % 4;
|
|
19192
|
+
const binChunkLength = totalBinSize + binPadding;
|
|
19193
|
+
// GLB layout: header (12) + JSON chunk header (8) + JSON data + BIN chunk header (8) + BIN data
|
|
19194
|
+
const totalLength = 12 + 8 + jsonChunkLength + 8 + binChunkLength;
|
|
19195
|
+
const buffer = new ArrayBuffer(totalLength);
|
|
19196
|
+
const view = new DataView(buffer);
|
|
19197
|
+
const byteArray = new Uint8Array(buffer);
|
|
19198
|
+
let offset = 0;
|
|
19199
|
+
// GLB header
|
|
19200
|
+
view.setUint32(offset, 0x46546C67, true);
|
|
19201
|
+
offset += 4; // magic: "glTF"
|
|
19202
|
+
view.setUint32(offset, 2, true);
|
|
19203
|
+
offset += 4; // version: 2
|
|
19204
|
+
view.setUint32(offset, totalLength, true);
|
|
19205
|
+
offset += 4; // total length
|
|
19206
|
+
// JSON chunk header
|
|
19207
|
+
view.setUint32(offset, jsonChunkLength, true);
|
|
19208
|
+
offset += 4;
|
|
19209
|
+
view.setUint32(offset, 0x4E4F534A, true);
|
|
19210
|
+
offset += 4; // type: "JSON"
|
|
19211
|
+
// JSON chunk data
|
|
19212
|
+
byteArray.set(jsonBytes, offset);
|
|
19213
|
+
offset += jsonBytes.length;
|
|
19214
|
+
for (let i = 0; i < jsonPadding; i++) {
|
|
19215
|
+
byteArray[offset++] = 0x20;
|
|
19216
|
+
}
|
|
19217
|
+
// BIN chunk header
|
|
19218
|
+
view.setUint32(offset, binChunkLength, true);
|
|
19219
|
+
offset += 4;
|
|
19220
|
+
view.setUint32(offset, 0x004E4942, true);
|
|
19221
|
+
offset += 4; // type: "BIN\0"
|
|
19222
|
+
// BIN chunk data: positions then indices
|
|
19223
|
+
byteArray.set(new Uint8Array(positions.buffer, positions.byteOffset, positionsByteLength), offset);
|
|
19224
|
+
offset += positionsByteLength;
|
|
19225
|
+
byteArray.set(new Uint8Array(indices.buffer, indices.byteOffset, indicesByteLength), offset);
|
|
19226
|
+
return byteArray;
|
|
19227
|
+
}
|
|
19228
|
+
|
|
18380
19229
|
/**
|
|
18381
19230
|
* Compute axis-aligned bounding box half-extents for all Gaussians in a DataTable.
|
|
18382
19231
|
*
|
|
@@ -19242,6 +20091,525 @@ class GpuVoxelization {
|
|
|
19242
20091
|
}
|
|
19243
20092
|
}
|
|
19244
20093
|
|
|
20094
|
+
// ============================================================================
|
|
20095
|
+
// Voxel bit helpers
|
|
20096
|
+
// ============================================================================
|
|
20097
|
+
// Bit layout within a 4x4x4 block: bitIdx = lx + ly*4 + lz*16
|
|
20098
|
+
// lo = bits 0-31 (lz 0-1), hi = bits 32-63 (lz 2-3)
|
|
20099
|
+
/**
|
|
20100
|
+
* Test whether a voxel is occupied within a block's bitmask.
|
|
20101
|
+
*
|
|
20102
|
+
* @param lo - Lower 32 bits of the block mask
|
|
20103
|
+
* @param hi - Upper 32 bits of the block mask
|
|
20104
|
+
* @param lx - Local x coordinate (0-3)
|
|
20105
|
+
* @param ly - Local y coordinate (0-3)
|
|
20106
|
+
* @param lz - Local z coordinate (0-3)
|
|
20107
|
+
* @returns True if the voxel is occupied
|
|
20108
|
+
*/
|
|
20109
|
+
function isVoxelSet(lo, hi, lx, ly, lz) {
|
|
20110
|
+
const bitIdx = lx + ly * 4 + lz * 16;
|
|
20111
|
+
if (bitIdx < 32) {
|
|
20112
|
+
return (lo & (1 << bitIdx)) !== 0;
|
|
20113
|
+
}
|
|
20114
|
+
return (hi & (1 << (bitIdx - 32))) !== 0;
|
|
20115
|
+
}
|
|
20116
|
+
// ============================================================================
|
|
20117
|
+
// Occupancy grid from BlockAccumulator
|
|
20118
|
+
// ============================================================================
|
|
20119
|
+
/**
|
|
20120
|
+
* Build a fast-lookup occupancy structure from a BlockAccumulator.
|
|
20121
|
+
* Returns a function that queries whether a voxel at global coordinates
|
|
20122
|
+
* (vx, vy, vz) is occupied.
|
|
20123
|
+
*
|
|
20124
|
+
* @param accumulator - Block data
|
|
20125
|
+
* @returns Lookup function (vx, vy, vz) => boolean
|
|
20126
|
+
*/
|
|
20127
|
+
function buildOccupancyLookup(accumulator) {
|
|
20128
|
+
// Map from "bx,by,bz" encoded as single number to {lo,hi} or solid flag
|
|
20129
|
+
// Block key = bx + by * stride + bz * stride^2 where stride is large enough
|
|
20130
|
+
const mixed = accumulator.getMixedBlocks();
|
|
20131
|
+
const solid = accumulator.getSolidBlocks();
|
|
20132
|
+
// Use a Map<number, number> where value encodes index into mask arrays.
|
|
20133
|
+
// For solid blocks, store -1 as sentinel.
|
|
20134
|
+
const blockMap = new Map();
|
|
20135
|
+
for (let i = 0; i < mixed.morton.length; i++) {
|
|
20136
|
+
blockMap.set(mixed.morton[i], i);
|
|
20137
|
+
}
|
|
20138
|
+
for (let i = 0; i < solid.length; i++) {
|
|
20139
|
+
blockMap.set(solid[i], -1);
|
|
20140
|
+
}
|
|
20141
|
+
const masks = mixed.masks;
|
|
20142
|
+
return (vx, vy, vz) => {
|
|
20143
|
+
if (vx < 0 || vy < 0 || vz < 0)
|
|
20144
|
+
return false;
|
|
20145
|
+
const bx = vx >> 2;
|
|
20146
|
+
const by = vy >> 2;
|
|
20147
|
+
const bz = vz >> 2;
|
|
20148
|
+
const entry = blockMap.get(xyzToMorton(bx, by, bz));
|
|
20149
|
+
if (entry === undefined)
|
|
20150
|
+
return false;
|
|
20151
|
+
if (entry === -1)
|
|
20152
|
+
return true; // solid block
|
|
20153
|
+
const lo = masks[entry * 2];
|
|
20154
|
+
const hi = masks[entry * 2 + 1];
|
|
20155
|
+
return isVoxelSet(lo, hi, vx & 3, vy & 3, vz & 3);
|
|
20156
|
+
};
|
|
20157
|
+
}
|
|
20158
|
+
// ============================================================================
|
|
20159
|
+
// Marching Cubes
|
|
20160
|
+
// ============================================================================
|
|
20161
|
+
/**
|
|
20162
|
+
* Extract a triangle mesh from a BlockAccumulator using marching cubes.
|
|
20163
|
+
*
|
|
20164
|
+
* Each voxel is treated as a cell in the marching cubes grid. Corner values
|
|
20165
|
+
* are binary (0 = empty, 1 = occupied) with a 0.5 threshold. Vertices are
|
|
20166
|
+
* placed at edge midpoints, producing a mesh that follows voxel boundaries.
|
|
20167
|
+
*
|
|
20168
|
+
* @param accumulator - Voxel block data after filtering
|
|
20169
|
+
* @param gridBounds - Grid bounds aligned to block boundaries
|
|
20170
|
+
* @param voxelResolution - Size of each voxel in world units
|
|
20171
|
+
* @returns Mesh with positions and indices
|
|
20172
|
+
*/
|
|
20173
|
+
function marchingCubes(accumulator, gridBounds, voxelResolution) {
|
|
20174
|
+
const isOccupied = buildOccupancyLookup(accumulator);
|
|
20175
|
+
// Collect all voxel coordinates that need processing.
|
|
20176
|
+
// We need to check every cell where at least one corner differs from
|
|
20177
|
+
// the others, which means we need to check occupied voxels and their
|
|
20178
|
+
// immediate neighbors.
|
|
20179
|
+
const mixed = accumulator.getMixedBlocks();
|
|
20180
|
+
const solid = accumulator.getSolidBlocks();
|
|
20181
|
+
// Collect set of all block coordinates that exist
|
|
20182
|
+
const blockSet = new Set();
|
|
20183
|
+
for (let i = 0; i < mixed.morton.length; i++) {
|
|
20184
|
+
blockSet.add(mixed.morton[i]);
|
|
20185
|
+
}
|
|
20186
|
+
for (let i = 0; i < solid.length; i++) {
|
|
20187
|
+
blockSet.add(solid[i]);
|
|
20188
|
+
}
|
|
20189
|
+
// For each block, we process a 4x4x4 region of marching cubes cells.
|
|
20190
|
+
// Each cell at (vx, vy, vz) has corners at (vx..vx+1, vy..vy+1, vz..vz+1).
|
|
20191
|
+
// We only generate triangles for cells that have mixed corners (not all same).
|
|
20192
|
+
// Vertex deduplication: edge ID -> vertex index
|
|
20193
|
+
// Edge ID encodes the voxel coordinate and edge direction
|
|
20194
|
+
const vertexMap = new Map();
|
|
20195
|
+
const positions = [];
|
|
20196
|
+
const indices = [];
|
|
20197
|
+
const originX = gridBounds.min.x;
|
|
20198
|
+
const originY = gridBounds.min.y;
|
|
20199
|
+
const originZ = gridBounds.min.z;
|
|
20200
|
+
// Compute strides from actual grid dimensions (+3 for the -1 boundary
|
|
20201
|
+
// extension, the far edge +1, and one extra for safety).
|
|
20202
|
+
const strideX = Math.round((gridBounds.max.x - gridBounds.min.x) / voxelResolution) + 3;
|
|
20203
|
+
const strideXY = strideX * (Math.round((gridBounds.max.y - gridBounds.min.y) / voxelResolution) + 3);
|
|
20204
|
+
// Get or create a vertex at the midpoint of an edge.
|
|
20205
|
+
// Edge is identified by the lower corner voxel coordinate and axis (0=x, 1=y, 2=z).
|
|
20206
|
+
const getVertex = (vx, vy, vz, axis) => {
|
|
20207
|
+
// Pack (vx, vy, vz, axis) into a single key. Offset by 1 so that
|
|
20208
|
+
// vx = -1 (from the boundary extension) maps to 0, keeping keys non-negative.
|
|
20209
|
+
const key = ((vx + 1) + (vy + 1) * strideX + (vz + 1) * strideXY) * 3 + axis;
|
|
20210
|
+
let idx = vertexMap.get(key);
|
|
20211
|
+
if (idx !== undefined)
|
|
20212
|
+
return idx;
|
|
20213
|
+
idx = positions.length / 3;
|
|
20214
|
+
let px = originX + vx * voxelResolution;
|
|
20215
|
+
let py = originY + vy * voxelResolution;
|
|
20216
|
+
let pz = originZ + vz * voxelResolution;
|
|
20217
|
+
// Place vertex at edge midpoint (binary field -> always at 0.5)
|
|
20218
|
+
if (axis === 0)
|
|
20219
|
+
px += voxelResolution * 0.5;
|
|
20220
|
+
else if (axis === 1)
|
|
20221
|
+
py += voxelResolution * 0.5;
|
|
20222
|
+
else
|
|
20223
|
+
pz += voxelResolution * 0.5;
|
|
20224
|
+
positions.push(px, py, pz);
|
|
20225
|
+
vertexMap.set(key, idx);
|
|
20226
|
+
return idx;
|
|
20227
|
+
};
|
|
20228
|
+
// Process all blocks and their boundary neighbors
|
|
20229
|
+
const allMortons = [];
|
|
20230
|
+
blockSet.forEach(m => allMortons.push(m));
|
|
20231
|
+
for (let bi = 0; bi < allMortons.length; bi++) {
|
|
20232
|
+
const morton = allMortons[bi];
|
|
20233
|
+
const [bx, by, bz] = mortonToXYZ(morton);
|
|
20234
|
+
// Iterate -1..3 to include the boundary layer in the negative
|
|
20235
|
+
// direction. Cells at lx/ly/lz = -1 straddle the block edge and
|
|
20236
|
+
// are needed to close the surface where no neighboring block exists.
|
|
20237
|
+
for (let lz = -1; lz < 4; lz++) {
|
|
20238
|
+
for (let ly = -1; ly < 4; ly++) {
|
|
20239
|
+
for (let lx = -1; lx < 4; lx++) {
|
|
20240
|
+
const vx = bx * 4 + lx;
|
|
20241
|
+
const vy = by * 4 + ly;
|
|
20242
|
+
const vz = bz * 4 + lz;
|
|
20243
|
+
// Determine which block owns this cell
|
|
20244
|
+
const ownerBx = vx >> 2;
|
|
20245
|
+
const ownerBy = vy >> 2;
|
|
20246
|
+
const ownerBz = vz >> 2;
|
|
20247
|
+
if (ownerBx !== bx || ownerBy !== by || ownerBz !== bz) {
|
|
20248
|
+
// Cell belongs to a different block — skip if that
|
|
20249
|
+
// block exists (it will process the cell itself).
|
|
20250
|
+
// Guard negative coords: xyzToMorton assumes non-negative inputs.
|
|
20251
|
+
if (ownerBx >= 0 && ownerBy >= 0 && ownerBz >= 0 &&
|
|
20252
|
+
blockSet.has(xyzToMorton(ownerBx, ownerBy, ownerBz)))
|
|
20253
|
+
continue;
|
|
20254
|
+
}
|
|
20255
|
+
// Get corner values for this cell (8 corners)
|
|
20256
|
+
// Corners: (vx,vy,vz), (vx+1,vy,vz), (vx+1,vy+1,vz), (vx,vy+1,vz),
|
|
20257
|
+
// (vx,vy,vz+1), (vx+1,vy,vz+1), (vx+1,vy+1,vz+1), (vx,vy+1,vz+1)
|
|
20258
|
+
const c0 = isOccupied(vx, vy, vz) ? 1 : 0;
|
|
20259
|
+
const c1 = isOccupied(vx + 1, vy, vz) ? 1 : 0;
|
|
20260
|
+
const c2 = isOccupied(vx + 1, vy + 1, vz) ? 1 : 0;
|
|
20261
|
+
const c3 = isOccupied(vx, vy + 1, vz) ? 1 : 0;
|
|
20262
|
+
const c4 = isOccupied(vx, vy, vz + 1) ? 1 : 0;
|
|
20263
|
+
const c5 = isOccupied(vx + 1, vy, vz + 1) ? 1 : 0;
|
|
20264
|
+
const c6 = isOccupied(vx + 1, vy + 1, vz + 1) ? 1 : 0;
|
|
20265
|
+
const c7 = isOccupied(vx, vy + 1, vz + 1) ? 1 : 0;
|
|
20266
|
+
const cubeIndex = c0 | (c1 << 1) | (c2 << 2) | (c3 << 3) |
|
|
20267
|
+
(c4 << 4) | (c5 << 5) | (c6 << 6) | (c7 << 7);
|
|
20268
|
+
if (cubeIndex === 0 || cubeIndex === 255)
|
|
20269
|
+
continue;
|
|
20270
|
+
const edges = EDGE_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
|
|
20271
|
+
if (edges === 0)
|
|
20272
|
+
continue;
|
|
20273
|
+
// Compute vertices on active edges
|
|
20274
|
+
// Edge -> vertex mapping using getVertex with (corner voxel coord, axis)
|
|
20275
|
+
const edgeVerts = new Array(12);
|
|
20276
|
+
if (edges & 1)
|
|
20277
|
+
edgeVerts[0] = getVertex(vx, vy, vz, 0); // edge 0: x-axis at (vx, vy, vz)
|
|
20278
|
+
if (edges & 2)
|
|
20279
|
+
edgeVerts[1] = getVertex(vx + 1, vy, vz, 1); // edge 1: y-axis at (vx+1, vy, vz)
|
|
20280
|
+
if (edges & 4)
|
|
20281
|
+
edgeVerts[2] = getVertex(vx, vy + 1, vz, 0); // edge 2: x-axis at (vx, vy+1, vz)
|
|
20282
|
+
if (edges & 8)
|
|
20283
|
+
edgeVerts[3] = getVertex(vx, vy, vz, 1); // edge 3: y-axis at (vx, vy, vz)
|
|
20284
|
+
if (edges & 16)
|
|
20285
|
+
edgeVerts[4] = getVertex(vx, vy, vz + 1, 0); // edge 4: x-axis at (vx, vy, vz+1)
|
|
20286
|
+
if (edges & 32)
|
|
20287
|
+
edgeVerts[5] = getVertex(vx + 1, vy, vz + 1, 1); // edge 5: y-axis at (vx+1, vy, vz+1)
|
|
20288
|
+
if (edges & 64)
|
|
20289
|
+
edgeVerts[6] = getVertex(vx, vy + 1, vz + 1, 0); // edge 6: x-axis at (vx, vy+1, vz+1)
|
|
20290
|
+
if (edges & 128)
|
|
20291
|
+
edgeVerts[7] = getVertex(vx, vy, vz + 1, 1); // edge 7: y-axis at (vx, vy, vz+1)
|
|
20292
|
+
if (edges & 256)
|
|
20293
|
+
edgeVerts[8] = getVertex(vx, vy, vz, 2); // edge 8: z-axis at (vx, vy, vz)
|
|
20294
|
+
if (edges & 512)
|
|
20295
|
+
edgeVerts[9] = getVertex(vx + 1, vy, vz, 2); // edge 9: z-axis at (vx+1, vy, vz)
|
|
20296
|
+
if (edges & 1024)
|
|
20297
|
+
edgeVerts[10] = getVertex(vx + 1, vy + 1, vz, 2); // edge 10: z-axis at (vx+1, vy+1, vz)
|
|
20298
|
+
if (edges & 2048)
|
|
20299
|
+
edgeVerts[11] = getVertex(vx, vy + 1, vz, 2); // edge 11: z-axis at (vx, vy+1, vz)
|
|
20300
|
+
// Emit triangles (reversed winding to face outward)
|
|
20301
|
+
const triRow = TRI_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
|
|
20302
|
+
for (let t = 0; t < triRow.length; t += 3) {
|
|
20303
|
+
indices.push(edgeVerts[triRow[t]], edgeVerts[triRow[t + 2]], edgeVerts[triRow[t + 1]]);
|
|
20304
|
+
}
|
|
20305
|
+
}
|
|
20306
|
+
}
|
|
20307
|
+
}
|
|
20308
|
+
}
|
|
20309
|
+
return {
|
|
20310
|
+
positions: new Float32Array(positions),
|
|
20311
|
+
indices: new Uint32Array(indices)
|
|
20312
|
+
};
|
|
20313
|
+
}
|
|
20314
|
+
// ============================================================================
|
|
20315
|
+
// Marching Cubes Lookup Tables
|
|
20316
|
+
// ============================================================================
|
|
20317
|
+
// Standard tables from Paul Bourke's polygonising a scalar field.
|
|
20318
|
+
// EDGE_TABLE: 256 entries, each a 12-bit mask of which edges are intersected.
|
|
20319
|
+
// TRI_TABLE: 256 entries, each an array of edge indices forming triangles.
|
|
20320
|
+
const EDGE_TABLE = [
|
|
20321
|
+
0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
|
|
20322
|
+
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
|
|
20323
|
+
0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
|
|
20324
|
+
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
|
|
20325
|
+
0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
|
|
20326
|
+
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
|
|
20327
|
+
0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
|
|
20328
|
+
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
|
|
20329
|
+
0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c,
|
|
20330
|
+
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
|
|
20331
|
+
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc,
|
|
20332
|
+
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
|
|
20333
|
+
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c,
|
|
20334
|
+
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
|
|
20335
|
+
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc,
|
|
20336
|
+
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
|
|
20337
|
+
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
|
|
20338
|
+
0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
|
|
20339
|
+
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
|
|
20340
|
+
0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
|
|
20341
|
+
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
|
|
20342
|
+
0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
|
|
20343
|
+
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
|
|
20344
|
+
0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
|
|
20345
|
+
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
|
|
20346
|
+
0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
|
|
20347
|
+
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
|
|
20348
|
+
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
|
|
20349
|
+
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
|
|
20350
|
+
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
|
|
20351
|
+
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
|
|
20352
|
+
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
|
|
20353
|
+
];
|
|
20354
|
+
const TRI_TABLE = [
|
|
20355
|
+
[],
|
|
20356
|
+
[0, 8, 3],
|
|
20357
|
+
[0, 1, 9],
|
|
20358
|
+
[1, 8, 3, 9, 8, 1],
|
|
20359
|
+
[1, 2, 10],
|
|
20360
|
+
[0, 8, 3, 1, 2, 10],
|
|
20361
|
+
[9, 2, 10, 0, 2, 9],
|
|
20362
|
+
[2, 8, 3, 2, 10, 8, 10, 9, 8],
|
|
20363
|
+
[3, 11, 2],
|
|
20364
|
+
[0, 11, 2, 8, 11, 0],
|
|
20365
|
+
[1, 9, 0, 2, 3, 11],
|
|
20366
|
+
[1, 11, 2, 1, 9, 11, 9, 8, 11],
|
|
20367
|
+
[3, 10, 1, 11, 10, 3],
|
|
20368
|
+
[0, 10, 1, 0, 8, 10, 8, 11, 10],
|
|
20369
|
+
[3, 9, 0, 3, 11, 9, 11, 10, 9],
|
|
20370
|
+
[9, 8, 10, 10, 8, 11],
|
|
20371
|
+
[4, 7, 8],
|
|
20372
|
+
[4, 3, 0, 7, 3, 4],
|
|
20373
|
+
[0, 1, 9, 8, 4, 7],
|
|
20374
|
+
[4, 1, 9, 4, 7, 1, 7, 3, 1],
|
|
20375
|
+
[1, 2, 10, 8, 4, 7],
|
|
20376
|
+
[3, 4, 7, 3, 0, 4, 1, 2, 10],
|
|
20377
|
+
[9, 2, 10, 9, 0, 2, 8, 4, 7],
|
|
20378
|
+
[2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4],
|
|
20379
|
+
[8, 4, 7, 3, 11, 2],
|
|
20380
|
+
[11, 4, 7, 11, 2, 4, 2, 0, 4],
|
|
20381
|
+
[9, 0, 1, 8, 4, 7, 2, 3, 11],
|
|
20382
|
+
[4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1],
|
|
20383
|
+
[3, 10, 1, 3, 11, 10, 7, 8, 4],
|
|
20384
|
+
[1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4],
|
|
20385
|
+
[4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3],
|
|
20386
|
+
[4, 7, 11, 4, 11, 9, 9, 11, 10],
|
|
20387
|
+
[9, 5, 4],
|
|
20388
|
+
[9, 5, 4, 0, 8, 3],
|
|
20389
|
+
[0, 5, 4, 1, 5, 0],
|
|
20390
|
+
[8, 5, 4, 8, 3, 5, 3, 1, 5],
|
|
20391
|
+
[1, 2, 10, 9, 5, 4],
|
|
20392
|
+
[3, 0, 8, 1, 2, 10, 4, 9, 5],
|
|
20393
|
+
[5, 2, 10, 5, 4, 2, 4, 0, 2],
|
|
20394
|
+
[2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8],
|
|
20395
|
+
[9, 5, 4, 2, 3, 11],
|
|
20396
|
+
[0, 11, 2, 0, 8, 11, 4, 9, 5],
|
|
20397
|
+
[0, 5, 4, 0, 1, 5, 2, 3, 11],
|
|
20398
|
+
[2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5],
|
|
20399
|
+
[10, 3, 11, 10, 1, 3, 9, 5, 4],
|
|
20400
|
+
[4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10],
|
|
20401
|
+
[5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3],
|
|
20402
|
+
[5, 4, 8, 5, 8, 10, 10, 8, 11],
|
|
20403
|
+
[9, 7, 8, 5, 7, 9],
|
|
20404
|
+
[9, 3, 0, 9, 5, 3, 5, 7, 3],
|
|
20405
|
+
[0, 7, 8, 0, 1, 7, 1, 5, 7],
|
|
20406
|
+
[1, 5, 3, 3, 5, 7],
|
|
20407
|
+
[9, 7, 8, 9, 5, 7, 10, 1, 2],
|
|
20408
|
+
[10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3],
|
|
20409
|
+
[8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2],
|
|
20410
|
+
[2, 10, 5, 2, 5, 3, 3, 5, 7],
|
|
20411
|
+
[7, 9, 5, 7, 8, 9, 3, 11, 2],
|
|
20412
|
+
[9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11],
|
|
20413
|
+
[2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7],
|
|
20414
|
+
[11, 2, 1, 11, 1, 7, 7, 1, 5],
|
|
20415
|
+
[9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11],
|
|
20416
|
+
[5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0],
|
|
20417
|
+
[11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0],
|
|
20418
|
+
[11, 10, 5, 7, 11, 5],
|
|
20419
|
+
[10, 6, 5],
|
|
20420
|
+
[0, 8, 3, 5, 10, 6],
|
|
20421
|
+
[9, 0, 1, 5, 10, 6],
|
|
20422
|
+
[1, 8, 3, 1, 9, 8, 5, 10, 6],
|
|
20423
|
+
[1, 6, 5, 2, 6, 1],
|
|
20424
|
+
[1, 6, 5, 1, 2, 6, 3, 0, 8],
|
|
20425
|
+
[9, 6, 5, 9, 0, 6, 0, 2, 6],
|
|
20426
|
+
[5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8],
|
|
20427
|
+
[2, 3, 11, 10, 6, 5],
|
|
20428
|
+
[11, 0, 8, 11, 2, 0, 10, 6, 5],
|
|
20429
|
+
[0, 1, 9, 2, 3, 11, 5, 10, 6],
|
|
20430
|
+
[5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11],
|
|
20431
|
+
[6, 3, 11, 6, 5, 3, 5, 1, 3],
|
|
20432
|
+
[0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6],
|
|
20433
|
+
[3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9],
|
|
20434
|
+
[6, 5, 9, 6, 9, 11, 11, 9, 8],
|
|
20435
|
+
[5, 10, 6, 4, 7, 8],
|
|
20436
|
+
[4, 3, 0, 4, 7, 3, 6, 5, 10],
|
|
20437
|
+
[1, 9, 0, 5, 10, 6, 8, 4, 7],
|
|
20438
|
+
[10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4],
|
|
20439
|
+
[6, 1, 2, 6, 5, 1, 4, 7, 8],
|
|
20440
|
+
[1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7],
|
|
20441
|
+
[8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6],
|
|
20442
|
+
[7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9],
|
|
20443
|
+
[3, 11, 2, 7, 8, 4, 10, 6, 5],
|
|
20444
|
+
[5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11],
|
|
20445
|
+
[0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6],
|
|
20446
|
+
[9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6],
|
|
20447
|
+
[8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6],
|
|
20448
|
+
[5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11],
|
|
20449
|
+
[0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7],
|
|
20450
|
+
[6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9],
|
|
20451
|
+
[10, 4, 9, 6, 4, 10],
|
|
20452
|
+
[4, 10, 6, 4, 9, 10, 0, 8, 3],
|
|
20453
|
+
[10, 0, 1, 10, 6, 0, 6, 4, 0],
|
|
20454
|
+
[8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10],
|
|
20455
|
+
[1, 4, 9, 1, 2, 4, 2, 6, 4],
|
|
20456
|
+
[3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4],
|
|
20457
|
+
[0, 2, 4, 4, 2, 6],
|
|
20458
|
+
[8, 3, 2, 8, 2, 4, 4, 2, 6],
|
|
20459
|
+
[10, 4, 9, 10, 6, 4, 11, 2, 3],
|
|
20460
|
+
[0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6],
|
|
20461
|
+
[3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10],
|
|
20462
|
+
[6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1],
|
|
20463
|
+
[9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3],
|
|
20464
|
+
[8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1],
|
|
20465
|
+
[3, 11, 6, 3, 6, 0, 0, 6, 4],
|
|
20466
|
+
[6, 4, 8, 11, 6, 8],
|
|
20467
|
+
[7, 10, 6, 7, 8, 10, 8, 9, 10],
|
|
20468
|
+
[0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10],
|
|
20469
|
+
[10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0],
|
|
20470
|
+
[10, 6, 7, 10, 7, 1, 1, 7, 3],
|
|
20471
|
+
[1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7],
|
|
20472
|
+
[2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9],
|
|
20473
|
+
[7, 8, 0, 7, 0, 6, 6, 0, 2],
|
|
20474
|
+
[7, 3, 2, 6, 7, 2],
|
|
20475
|
+
[2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7],
|
|
20476
|
+
[2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7],
|
|
20477
|
+
[1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11],
|
|
20478
|
+
[11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1],
|
|
20479
|
+
[8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6],
|
|
20480
|
+
[0, 9, 1, 11, 6, 7],
|
|
20481
|
+
[7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0],
|
|
20482
|
+
[7, 11, 6],
|
|
20483
|
+
[7, 6, 11],
|
|
20484
|
+
[3, 0, 8, 11, 7, 6],
|
|
20485
|
+
[0, 1, 9, 11, 7, 6],
|
|
20486
|
+
[8, 1, 9, 8, 3, 1, 11, 7, 6],
|
|
20487
|
+
[10, 1, 2, 6, 11, 7],
|
|
20488
|
+
[1, 2, 10, 3, 0, 8, 6, 11, 7],
|
|
20489
|
+
[2, 9, 0, 2, 10, 9, 6, 11, 7],
|
|
20490
|
+
[6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8],
|
|
20491
|
+
[7, 2, 3, 6, 2, 7],
|
|
20492
|
+
[7, 0, 8, 7, 6, 0, 6, 2, 0],
|
|
20493
|
+
[2, 7, 6, 2, 3, 7, 0, 1, 9],
|
|
20494
|
+
[1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6],
|
|
20495
|
+
[10, 7, 6, 10, 1, 7, 1, 3, 7],
|
|
20496
|
+
[10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8],
|
|
20497
|
+
[0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7],
|
|
20498
|
+
[7, 6, 10, 7, 10, 8, 8, 10, 9],
|
|
20499
|
+
[6, 8, 4, 11, 8, 6],
|
|
20500
|
+
[3, 6, 11, 3, 0, 6, 0, 4, 6],
|
|
20501
|
+
[8, 6, 11, 8, 4, 6, 9, 0, 1],
|
|
20502
|
+
[9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6],
|
|
20503
|
+
[6, 8, 4, 6, 11, 8, 2, 10, 1],
|
|
20504
|
+
[1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6],
|
|
20505
|
+
[4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9],
|
|
20506
|
+
[10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3],
|
|
20507
|
+
[8, 2, 3, 8, 4, 2, 4, 6, 2],
|
|
20508
|
+
[0, 4, 2, 4, 6, 2],
|
|
20509
|
+
[1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8],
|
|
20510
|
+
[1, 9, 4, 1, 4, 2, 2, 4, 6],
|
|
20511
|
+
[8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1],
|
|
20512
|
+
[10, 1, 0, 10, 0, 6, 6, 0, 4],
|
|
20513
|
+
[4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3],
|
|
20514
|
+
[10, 9, 4, 6, 10, 4],
|
|
20515
|
+
[4, 9, 5, 7, 6, 11],
|
|
20516
|
+
[0, 8, 3, 4, 9, 5, 11, 7, 6],
|
|
20517
|
+
[5, 0, 1, 5, 4, 0, 7, 6, 11],
|
|
20518
|
+
[11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5],
|
|
20519
|
+
[9, 5, 4, 10, 1, 2, 7, 6, 11],
|
|
20520
|
+
[6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5],
|
|
20521
|
+
[7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2],
|
|
20522
|
+
[3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6],
|
|
20523
|
+
[7, 2, 3, 7, 6, 2, 5, 4, 9],
|
|
20524
|
+
[9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7],
|
|
20525
|
+
[3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0],
|
|
20526
|
+
[6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8],
|
|
20527
|
+
[9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7],
|
|
20528
|
+
[1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4],
|
|
20529
|
+
[4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10],
|
|
20530
|
+
[7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10],
|
|
20531
|
+
[6, 9, 5, 6, 11, 9, 11, 8, 9],
|
|
20532
|
+
[3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5],
|
|
20533
|
+
[0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11],
|
|
20534
|
+
[6, 11, 3, 6, 3, 5, 5, 3, 1],
|
|
20535
|
+
[1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6],
|
|
20536
|
+
[0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10],
|
|
20537
|
+
[11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5],
|
|
20538
|
+
[6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3],
|
|
20539
|
+
[5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2],
|
|
20540
|
+
[9, 5, 6, 9, 6, 0, 0, 6, 2],
|
|
20541
|
+
[1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8],
|
|
20542
|
+
[1, 5, 6, 2, 1, 6],
|
|
20543
|
+
[1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6],
|
|
20544
|
+
[10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0],
|
|
20545
|
+
[0, 3, 8, 5, 6, 10],
|
|
20546
|
+
[10, 5, 6],
|
|
20547
|
+
[11, 5, 10, 7, 5, 11],
|
|
20548
|
+
[11, 5, 10, 11, 7, 5, 8, 3, 0],
|
|
20549
|
+
[5, 11, 7, 5, 10, 11, 1, 9, 0],
|
|
20550
|
+
[10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1],
|
|
20551
|
+
[11, 1, 2, 11, 7, 1, 7, 5, 1],
|
|
20552
|
+
[0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11],
|
|
20553
|
+
[9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7],
|
|
20554
|
+
[7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2],
|
|
20555
|
+
[2, 5, 10, 2, 3, 5, 3, 7, 5],
|
|
20556
|
+
[8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5],
|
|
20557
|
+
[9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2],
|
|
20558
|
+
[9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2],
|
|
20559
|
+
[1, 3, 5, 3, 7, 5],
|
|
20560
|
+
[0, 8, 7, 0, 7, 1, 1, 7, 5],
|
|
20561
|
+
[9, 0, 3, 9, 3, 5, 5, 3, 7],
|
|
20562
|
+
[9, 8, 7, 5, 9, 7],
|
|
20563
|
+
[5, 8, 4, 5, 10, 8, 10, 11, 8],
|
|
20564
|
+
[5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0],
|
|
20565
|
+
[0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5],
|
|
20566
|
+
[10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4],
|
|
20567
|
+
[2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8],
|
|
20568
|
+
[0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11],
|
|
20569
|
+
[0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5],
|
|
20570
|
+
[9, 4, 5, 2, 11, 3],
|
|
20571
|
+
[2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4],
|
|
20572
|
+
[5, 10, 2, 5, 2, 4, 4, 2, 0],
|
|
20573
|
+
[3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9],
|
|
20574
|
+
[5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2],
|
|
20575
|
+
[8, 4, 5, 8, 5, 3, 3, 5, 1],
|
|
20576
|
+
[0, 4, 5, 1, 0, 5],
|
|
20577
|
+
[8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5],
|
|
20578
|
+
[9, 4, 5],
|
|
20579
|
+
[4, 11, 7, 4, 9, 11, 9, 10, 11],
|
|
20580
|
+
[0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11],
|
|
20581
|
+
[1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11],
|
|
20582
|
+
[3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4],
|
|
20583
|
+
[4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2],
|
|
20584
|
+
[9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3],
|
|
20585
|
+
[11, 7, 4, 11, 4, 2, 2, 4, 0],
|
|
20586
|
+
[11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4],
|
|
20587
|
+
[2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9],
|
|
20588
|
+
[9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7],
|
|
20589
|
+
[3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10],
|
|
20590
|
+
[1, 10, 2, 8, 7, 4],
|
|
20591
|
+
[4, 9, 1, 4, 1, 7, 7, 1, 3],
|
|
20592
|
+
[4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1],
|
|
20593
|
+
[4, 0, 3, 7, 4, 3],
|
|
20594
|
+
[4, 8, 7],
|
|
20595
|
+
[9, 10, 8, 10, 11, 8],
|
|
20596
|
+
[3, 0, 9, 3, 9, 11, 11, 9, 10],
|
|
20597
|
+
[0, 1, 10, 0, 10, 8, 8, 10, 11],
|
|
20598
|
+
[3, 1, 10, 11, 3, 10],
|
|
20599
|
+
[1, 2, 11, 1, 11, 9, 9, 11, 8],
|
|
20600
|
+
[3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9],
|
|
20601
|
+
[0, 2, 11, 8, 0, 11],
|
|
20602
|
+
[3, 2, 11],
|
|
20603
|
+
[2, 3, 8, 2, 8, 10, 10, 8, 9],
|
|
20604
|
+
[9, 10, 2, 0, 9, 2],
|
|
20605
|
+
[2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8],
|
|
20606
|
+
[1, 10, 2],
|
|
20607
|
+
[1, 3, 8, 9, 1, 8],
|
|
20608
|
+
[0, 9, 1],
|
|
20609
|
+
[0, 3, 8],
|
|
20610
|
+
[]
|
|
20611
|
+
];
|
|
20612
|
+
|
|
19245
20613
|
// ============================================================================
|
|
19246
20614
|
// Edge mask constants for 4x4x4 voxel blocks
|
|
19247
20615
|
// ============================================================================
|
|
@@ -19511,9 +20879,10 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
|
|
|
19511
20879
|
* Voxelizes Gaussian splat data and writes the result as a sparse voxel octree.
|
|
19512
20880
|
*
|
|
19513
20881
|
* This function performs GPU-accelerated voxelization of Gaussian splat data
|
|
19514
|
-
* and outputs two files:
|
|
20882
|
+
* and outputs two or three files:
|
|
19515
20883
|
* - `filename` (.voxel.json) - JSON metadata including bounds, resolution, and array sizes
|
|
19516
20884
|
* - Corresponding .voxel.bin - Binary octree data (nodes + leafData as Uint32 arrays)
|
|
20885
|
+
* - Corresponding .collision.glb - Triangle mesh extracted via marching cubes (GLB format, optional)
|
|
19517
20886
|
*
|
|
19518
20887
|
* The binary file layout is:
|
|
19519
20888
|
* - Bytes 0 to (nodeCount * 4 - 1): nodes array (Uint32, little-endian)
|
|
@@ -19532,16 +20901,17 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
|
|
|
19532
20901
|
* dataTable: myDataTable,
|
|
19533
20902
|
* voxelResolution: 0.05,
|
|
19534
20903
|
* opacityCutoff: 0.5,
|
|
20904
|
+
* collisionMesh: true,
|
|
19535
20905
|
* createDevice: async () => myGraphicsDevice
|
|
19536
20906
|
* }, fs);
|
|
19537
20907
|
* ```
|
|
19538
20908
|
*/
|
|
19539
20909
|
const writeVoxel = async (options, fs) => {
|
|
19540
|
-
const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice } = options;
|
|
20910
|
+
const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice, collisionMesh = false, meshSimplify = 0.25 } = options;
|
|
19541
20911
|
if (!createDevice) {
|
|
19542
20912
|
throw new Error('writeVoxel requires a createDevice function for GPU voxelization');
|
|
19543
20913
|
}
|
|
19544
|
-
logger.progress.begin(
|
|
20914
|
+
logger.progress.begin(collisionMesh ? 7 : 5);
|
|
19545
20915
|
const extentsResult = computeGaussianExtents(dataTable);
|
|
19546
20916
|
const bounds = extentsResult.sceneBounds;
|
|
19547
20917
|
logger.progress.step('Building BVH');
|
|
@@ -19713,10 +21083,61 @@ const writeVoxel = async (options, fs) => {
|
|
|
19713
21083
|
gpuVoxelization.destroy();
|
|
19714
21084
|
logger.progress.step('Filtering');
|
|
19715
21085
|
accumulator = filterAndFillBlocks(accumulator);
|
|
21086
|
+
let glbBytes = null;
|
|
21087
|
+
if (collisionMesh) {
|
|
21088
|
+
logger.progress.step('Extracting collision mesh');
|
|
21089
|
+
const rawMesh = marchingCubes(accumulator, gridBounds, voxelResolution);
|
|
21090
|
+
logger.log(`collision mesh (raw): ${rawMesh.positions.length / 3} vertices, ${rawMesh.indices.length / 3} triangles`);
|
|
21091
|
+
if (rawMesh.indices.length < 3) {
|
|
21092
|
+
logger.progress.step('Simplifying collision mesh');
|
|
21093
|
+
logger.log('collision mesh: no triangles generated, skipping GLB output');
|
|
21094
|
+
}
|
|
21095
|
+
else {
|
|
21096
|
+
logger.progress.step('Simplifying collision mesh');
|
|
21097
|
+
await MeshoptSimplifier.ready;
|
|
21098
|
+
const clampedSimplify = Number.isFinite(meshSimplify) ? Math.min(1, Math.max(0, meshSimplify)) : 0.25;
|
|
21099
|
+
const targetIndexCount = Math.max(3, Math.min(rawMesh.indices.length, Math.floor(rawMesh.indices.length * clampedSimplify / 3) * 3));
|
|
21100
|
+
const [simplifiedIndices] = MeshoptSimplifier.simplify(rawMesh.indices, rawMesh.positions, 3, targetIndexCount, voxelResolution, ['ErrorAbsolute']);
|
|
21101
|
+
const vertexRemap = new Map();
|
|
21102
|
+
let newVertexCount = 0;
|
|
21103
|
+
for (let i = 0; i < simplifiedIndices.length; i++) {
|
|
21104
|
+
if (!vertexRemap.has(simplifiedIndices[i])) {
|
|
21105
|
+
vertexRemap.set(simplifiedIndices[i], newVertexCount++);
|
|
21106
|
+
}
|
|
21107
|
+
}
|
|
21108
|
+
const compactPositions = new Float32Array(newVertexCount * 3);
|
|
21109
|
+
for (const [oldIdx, newIdx] of vertexRemap) {
|
|
21110
|
+
compactPositions[newIdx * 3] = rawMesh.positions[oldIdx * 3];
|
|
21111
|
+
compactPositions[newIdx * 3 + 1] = rawMesh.positions[oldIdx * 3 + 1];
|
|
21112
|
+
compactPositions[newIdx * 3 + 2] = rawMesh.positions[oldIdx * 3 + 2];
|
|
21113
|
+
}
|
|
21114
|
+
const compactIndices = new Uint32Array(simplifiedIndices.length);
|
|
21115
|
+
for (let i = 0; i < simplifiedIndices.length; i++) {
|
|
21116
|
+
compactIndices[i] = vertexRemap.get(simplifiedIndices[i]);
|
|
21117
|
+
}
|
|
21118
|
+
const reduction = (1 - simplifiedIndices.length / rawMesh.indices.length) * 100;
|
|
21119
|
+
logger.log(`collision mesh (simplified): ${newVertexCount} vertices, ${simplifiedIndices.length / 3} triangles (${reduction.toFixed(0)}% reduction)`);
|
|
21120
|
+
glbBytes = buildCollisionGlb(compactPositions, compactIndices);
|
|
21121
|
+
}
|
|
21122
|
+
}
|
|
21123
|
+
logger.progress.step('Building octree');
|
|
19716
21124
|
const octree = buildSparseOctree(accumulator, gridBounds, bounds, // Original scene bounds
|
|
19717
21125
|
voxelResolution);
|
|
21126
|
+
logger.log(`octree: depth=${octree.treeDepth}, interior=${octree.numInteriorNodes}, mixed=${octree.numMixedLeaves}`);
|
|
19718
21127
|
logger.progress.step('Writing');
|
|
19719
21128
|
await writeOctreeFiles(fs, filename, octree);
|
|
21129
|
+
if (glbBytes) {
|
|
21130
|
+
const glbFilename = filename.replace('.voxel.json', '.collision.glb');
|
|
21131
|
+
logger.log(`writing '${glbFilename}'...`);
|
|
21132
|
+
await writeFile$1(fs, glbFilename, glbBytes);
|
|
21133
|
+
}
|
|
21134
|
+
const totalBytes = (octree.nodes.length + octree.leafData.length) * 4;
|
|
21135
|
+
if (glbBytes) {
|
|
21136
|
+
logger.log(`total size: octree ${(totalBytes / 1024).toFixed(1)} KB, collision mesh ${(glbBytes.length / 1024).toFixed(1)} KB`);
|
|
21137
|
+
}
|
|
21138
|
+
else {
|
|
21139
|
+
logger.log(`total size: ${(totalBytes / 1024).toFixed(1)} KB`);
|
|
21140
|
+
}
|
|
19720
21141
|
};
|
|
19721
21142
|
|
|
19722
21143
|
/**
|
|
@@ -19849,6 +21270,8 @@ const writeFile = async (writeOptions, fs) => {
|
|
|
19849
21270
|
dataTable,
|
|
19850
21271
|
voxelResolution: options.voxelResolution,
|
|
19851
21272
|
opacityCutoff: options.opacityCutoff,
|
|
21273
|
+
collisionMesh: options.collisionMesh,
|
|
21274
|
+
meshSimplify: options.meshSimplify,
|
|
19852
21275
|
createDevice
|
|
19853
21276
|
}, fs);
|
|
19854
21277
|
break;
|
|
@@ -20374,7 +21797,9 @@ const parseArguments = async () => {
|
|
|
20374
21797
|
'lod-chunk-extent': { type: 'string', short: 'X', default: '16' },
|
|
20375
21798
|
unbundled: { type: 'boolean', short: 'U', default: false },
|
|
20376
21799
|
'voxel-resolution': { type: 'string', short: 'R', default: '0.05' },
|
|
20377
|
-
'opacity-cutoff': { type: 'string', short: 'A', default: '0.
|
|
21800
|
+
'opacity-cutoff': { type: 'string', short: 'A', default: '0.1' },
|
|
21801
|
+
'collision-mesh': { type: 'boolean', short: 'K', default: false },
|
|
21802
|
+
'mesh-simplify': { type: 'string', short: 'T', default: '0.25' },
|
|
20378
21803
|
// per-file options
|
|
20379
21804
|
translate: { type: 'string', short: 't', multiple: true },
|
|
20380
21805
|
rotate: { type: 'string', short: 'r', multiple: true },
|
|
@@ -20461,8 +21886,13 @@ const parseArguments = async () => {
|
|
|
20461
21886
|
lodChunkCount: parseInteger(v['lod-chunk-count']),
|
|
20462
21887
|
lodChunkExtent: parseInteger(v['lod-chunk-extent']),
|
|
20463
21888
|
voxelResolution: parseNumber(v['voxel-resolution']),
|
|
20464
|
-
opacityCutoff: parseNumber(v['opacity-cutoff'])
|
|
21889
|
+
opacityCutoff: parseNumber(v['opacity-cutoff']),
|
|
21890
|
+
collisionMesh: v['collision-mesh'],
|
|
21891
|
+
meshSimplify: parseNumber(v['mesh-simplify'])
|
|
20465
21892
|
};
|
|
21893
|
+
if (!Number.isFinite(options.meshSimplify) || options.meshSimplify < 0 || options.meshSimplify > 1) {
|
|
21894
|
+
throw new Error(`Invalid mesh-simplify value: ${options.meshSimplify}. Must be a finite number between 0 and 1.`);
|
|
21895
|
+
}
|
|
20466
21896
|
for (const t of tokens) {
|
|
20467
21897
|
if (t.kind === 'positional') {
|
|
20468
21898
|
files.push({
|
|
@@ -20669,7 +22099,9 @@ GLOBAL OPTIONS
|
|
|
20669
22099
|
-C, --lod-chunk-count <n> Approximate number of Gaussians per LOD chunk in K. Default: 512
|
|
20670
22100
|
-X, --lod-chunk-extent <n> Approximate size of an LOD chunk in world units (m). Default: 16
|
|
20671
22101
|
-R, --voxel-resolution <n> Voxel size in world units for .voxel.json. Default: 0.05
|
|
20672
|
-
-A, --opacity-cutoff <n> Opacity threshold for solid voxels. Default: 0.
|
|
22102
|
+
-A, --opacity-cutoff <n> Opacity threshold for solid voxels. Default: 0.1
|
|
22103
|
+
-K, --collision-mesh Generate collision mesh (.collision.glb) with voxel output
|
|
22104
|
+
-T, --mesh-simplify <n> Ratio of triangles to keep for collision mesh (0-1). Default: 0.25
|
|
20673
22105
|
|
|
20674
22106
|
EXAMPLES
|
|
20675
22107
|
# Scale then translate
|
|
@@ -20687,9 +22119,12 @@ EXAMPLES
|
|
|
20687
22119
|
# Generate LOD with custom chunk size and node split size
|
|
20688
22120
|
splat-transform -O 0,1,2 -C 1024 -X 32 input.lcc output/lod-meta.json
|
|
20689
22121
|
|
|
20690
|
-
# Generate voxel
|
|
22122
|
+
# Generate voxel data
|
|
20691
22123
|
splat-transform input.ply output.voxel.json
|
|
20692
22124
|
|
|
22125
|
+
# Generate voxel data with collision mesh
|
|
22126
|
+
splat-transform -K input.ply output.voxel.json
|
|
22127
|
+
|
|
20693
22128
|
# Generate voxel data with custom resolution and opacity threshold
|
|
20694
22129
|
splat-transform -R 0.1 -A 0.3 input.ply output.voxel.json
|
|
20695
22130
|
|
|
@@ -20720,15 +22155,17 @@ const main = async () => {
|
|
|
20720
22155
|
if (node.stepName) {
|
|
20721
22156
|
console.error(`[${node.step}/${node.totalSteps}] ${node.stepName}`);
|
|
20722
22157
|
}
|
|
22158
|
+
else if (node.step === 0) {
|
|
22159
|
+
start = hrtime();
|
|
22160
|
+
}
|
|
20723
22161
|
else {
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
process.stderr.write(
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
process.stderr.write('#');
|
|
22162
|
+
const displaySteps = 10;
|
|
22163
|
+
const curr = Math.round(displaySteps * node.step / node.totalSteps);
|
|
22164
|
+
const prev = Math.round(displaySteps * (node.step - 1) / node.totalSteps);
|
|
22165
|
+
if (curr > prev)
|
|
22166
|
+
process.stderr.write('#'.repeat(curr - prev));
|
|
22167
|
+
if (node.step === node.totalSteps) {
|
|
22168
|
+
process.stderr.write(` done in ${hrtimeDelta(start, hrtime()).toFixed(3)}s 🎉\n`);
|
|
20732
22169
|
}
|
|
20733
22170
|
}
|
|
20734
22171
|
}
|