@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/dist/index.cjs CHANGED
@@ -745,6 +745,16 @@ class Progress {
745
745
  if (!quiet)
746
746
  impl.onProgress(this.currentNode);
747
747
  }
748
+ /**
749
+ * Cancel the current progress node, popping it from the stack without
750
+ * completing remaining steps. Use this before early exits (e.g. break)
751
+ * to keep the progress stack balanced.
752
+ */
753
+ cancel() {
754
+ if (!this.currentNode)
755
+ return;
756
+ this.currentNode = this.currentNode.parent;
757
+ }
748
758
  /**
749
759
  * Advance to the next step. Auto-increments the step counter.
750
760
  * Auto-ends when all steps are complete.
@@ -932,33 +942,74 @@ const sortMortonOrder = (dataTable, indices) => {
932
942
  generate(indices);
933
943
  };
934
944
 
945
+ const nthElement = (arr, lo, hi, k, values) => {
946
+ while (lo < hi) {
947
+ const mid = (lo + hi) >> 1;
948
+ const va = values[arr[lo]], vb = values[arr[mid]], vc = values[arr[hi]];
949
+ let pivotIdx;
950
+ if ((vb - va) * (vc - vb) >= 0)
951
+ pivotIdx = mid;
952
+ else if ((va - vb) * (vc - va) >= 0)
953
+ pivotIdx = lo;
954
+ else
955
+ pivotIdx = hi;
956
+ const pivotVal = values[arr[pivotIdx]];
957
+ let tmp = arr[pivotIdx];
958
+ arr[pivotIdx] = arr[hi];
959
+ arr[hi] = tmp;
960
+ let store = lo;
961
+ for (let i = lo; i < hi; i++) {
962
+ if (values[arr[i]] < pivotVal) {
963
+ tmp = arr[i];
964
+ arr[i] = arr[store];
965
+ arr[store] = tmp;
966
+ store++;
967
+ }
968
+ }
969
+ tmp = arr[store];
970
+ arr[store] = arr[hi];
971
+ arr[hi] = tmp;
972
+ if (store === k)
973
+ return;
974
+ else if (store < k)
975
+ lo = store + 1;
976
+ else
977
+ hi = store - 1;
978
+ }
979
+ };
935
980
  class KdTree {
936
981
  centroids;
937
982
  root;
983
+ colData;
938
984
  constructor(centroids) {
939
- const build = (indices, depth) => {
940
- const { centroids } = this;
941
- const values = centroids.columns[depth % centroids.numColumns].data;
942
- indices.sort((a, b) => values[a] - values[b]);
943
- if (indices.length === 1) {
944
- return {
945
- index: indices[0],
946
- count: 1
947
- };
948
- }
949
- else if (indices.length === 2) {
985
+ const numCols = centroids.numColumns;
986
+ const colData = centroids.columns.map(c => c.data);
987
+ const indices = new Uint32Array(centroids.numRows);
988
+ for (let i = 0; i < indices.length; ++i) {
989
+ indices[i] = i;
990
+ }
991
+ const build = (lo, hi, depth) => {
992
+ const count = hi - lo + 1;
993
+ if (count === 1) {
994
+ return { index: indices[lo], count: 1 };
995
+ }
996
+ const values = colData[depth % numCols];
997
+ if (count === 2) {
998
+ if (values[indices[lo]] > values[indices[hi]]) {
999
+ const tmp = indices[lo];
1000
+ indices[lo] = indices[hi];
1001
+ indices[hi] = tmp;
1002
+ }
950
1003
  return {
951
- index: indices[0],
1004
+ index: indices[lo],
952
1005
  count: 2,
953
- right: {
954
- index: indices[1],
955
- count: 1
956
- }
1006
+ right: { index: indices[hi], count: 1 }
957
1007
  };
958
1008
  }
959
- const mid = indices.length >> 1;
960
- const left = build(indices.subarray(0, mid), depth + 1);
961
- const right = build(indices.subarray(mid + 1), depth + 1);
1009
+ const mid = lo + (count >> 1);
1010
+ nthElement(indices, lo, hi, mid, values);
1011
+ const left = build(lo, mid - 1, depth + 1);
1012
+ const right = build(mid + 1, hi, depth + 1);
962
1013
  return {
963
1014
  index: indices[mid],
964
1015
  count: 1 + left.count + right.count,
@@ -966,48 +1017,39 @@ class KdTree {
966
1017
  right
967
1018
  };
968
1019
  };
969
- const indices = new Uint32Array(centroids.numRows);
970
- for (let i = 0; i < indices.length; ++i) {
971
- indices[i] = i;
972
- }
973
1020
  this.centroids = centroids;
974
- this.root = build(indices, 0);
1021
+ this.colData = colData;
1022
+ this.root = build(0, indices.length - 1, 0);
975
1023
  }
976
1024
  findNearest(point, filterFunc) {
977
- const { centroids } = this;
978
- const { numColumns } = centroids;
979
- const calcDistance = (index) => {
980
- let l = 0;
981
- for (let i = 0; i < numColumns; ++i) {
982
- const v = centroids.columns[i].data[index] - point[i];
983
- l += v * v;
984
- }
985
- return l;
986
- };
1025
+ const colData = this.colData;
1026
+ const numCols = colData.length;
987
1027
  let mind = Infinity;
988
1028
  let mini = -1;
989
1029
  let cnt = 0;
990
- const recurse = (node, depth) => {
991
- const axis = depth % numColumns;
992
- const distance = point[axis] - centroids.columns[axis].data[node.index];
1030
+ const recurse = (node, axis) => {
1031
+ const distance = point[axis] - colData[axis][node.index];
993
1032
  const next = (distance > 0) ? node.right : node.left;
1033
+ const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
994
1034
  cnt++;
995
1035
  if (next) {
996
- recurse(next, depth + 1);
1036
+ recurse(next, nextAxis);
997
1037
  }
998
- // check index
999
1038
  if (!filterFunc || filterFunc(node.index)) {
1000
- const thisd = calcDistance(node.index);
1039
+ let thisd = 0;
1040
+ for (let c = 0; c < numCols; c++) {
1041
+ const v = colData[c][node.index] - point[c];
1042
+ thisd += v * v;
1043
+ }
1001
1044
  if (thisd < mind) {
1002
1045
  mind = thisd;
1003
1046
  mini = node.index;
1004
1047
  }
1005
1048
  }
1006
- // check the other side
1007
1049
  if (distance * distance < mind) {
1008
1050
  const other = next === node.right ? node.left : node.right;
1009
1051
  if (other) {
1010
- recurse(other, depth + 1);
1052
+ recurse(other, nextAxis);
1011
1053
  }
1012
1054
  }
1013
1055
  };
@@ -1019,16 +1061,8 @@ class KdTree {
1019
1061
  return { indices: new Int32Array(0), distances: new Float32Array(0) };
1020
1062
  }
1021
1063
  k = Math.min(k, this.centroids.numRows);
1022
- const { centroids } = this;
1023
- const { numColumns } = centroids;
1024
- const calcDistance = (index) => {
1025
- let l = 0;
1026
- for (let i = 0; i < numColumns; ++i) {
1027
- const v = centroids.columns[i].data[index] - point[i];
1028
- l += v * v;
1029
- }
1030
- return l;
1031
- };
1064
+ const colData = this.colData;
1065
+ const numCols = colData.length;
1032
1066
  // Bounded max-heap: stores (distance, index) pairs sorted so the
1033
1067
  // farthest element is at position 0, enabling O(1) pruning bound.
1034
1068
  const heapDist = new Float32Array(k).fill(Infinity);
@@ -1036,14 +1070,12 @@ class KdTree {
1036
1070
  let heapSize = 0;
1037
1071
  const heapPush = (dist, idx) => {
1038
1072
  if (heapSize < k) {
1039
- // Heap not full yet -- insert via sift-up
1040
1073
  let pos = heapSize++;
1041
1074
  heapDist[pos] = dist;
1042
1075
  heapIdx[pos] = idx;
1043
1076
  while (pos > 0) {
1044
1077
  const parent = (pos - 1) >> 1;
1045
1078
  if (heapDist[parent] < heapDist[pos]) {
1046
- // swap
1047
1079
  const td = heapDist[parent];
1048
1080
  heapDist[parent] = heapDist[pos];
1049
1081
  heapDist[pos] = td;
@@ -1058,7 +1090,6 @@ class KdTree {
1058
1090
  }
1059
1091
  }
1060
1092
  else if (dist < heapDist[0]) {
1061
- // Replace root (farthest) and sift-down
1062
1093
  heapDist[0] = dist;
1063
1094
  heapIdx[0] = idx;
1064
1095
  let pos = 0;
@@ -1082,22 +1113,26 @@ class KdTree {
1082
1113
  }
1083
1114
  }
1084
1115
  };
1085
- const recurse = (node, depth) => {
1086
- const axis = depth % numColumns;
1087
- const distance = point[axis] - centroids.columns[axis].data[node.index];
1116
+ const recurse = (node, axis) => {
1117
+ const distance = point[axis] - colData[axis][node.index];
1088
1118
  const next = (distance > 0) ? node.right : node.left;
1119
+ const nextAxis = axis + 1 < numCols ? axis + 1 : 0;
1089
1120
  if (next) {
1090
- recurse(next, depth + 1);
1121
+ recurse(next, nextAxis);
1091
1122
  }
1092
1123
  if (!filterFunc || filterFunc(node.index)) {
1093
- const thisd = calcDistance(node.index);
1124
+ let thisd = 0;
1125
+ for (let c = 0; c < numCols; c++) {
1126
+ const v = colData[c][node.index] - point[c];
1127
+ thisd += v * v;
1128
+ }
1094
1129
  heapPush(thisd, node.index);
1095
1130
  }
1096
1131
  const bound = heapSize < k ? Infinity : heapDist[0];
1097
1132
  if (distance * distance < bound) {
1098
1133
  const other = next === node.right ? node.left : node.right;
1099
1134
  if (other) {
1100
- recurse(other, depth + 1);
1135
+ recurse(other, nextAxis);
1101
1136
  }
1102
1137
  }
1103
1138
  };
@@ -1132,6 +1167,54 @@ const OPACITY_PRUNE_THRESHOLD = 0.1;
1132
1167
  const KNN_K = 16;
1133
1168
  const MC_SAMPLES = 1;
1134
1169
  const EPS_COV = 1e-8;
1170
+ const PROGRESS_TICKS = 100;
1171
+ // Radix sort edge indices by their Float32 costs.
1172
+ // Converts floats to sortable uint32 keys (preserving order), then does
1173
+ // 4-pass LSD radix sort with 8-bit radix. Returns the number of valid
1174
+ // (finite-cost) edges written to `out`.
1175
+ const radixSortIndicesByFloat = (out, count, keys) => {
1176
+ const keyBits = new Uint32Array(keys.buffer, keys.byteOffset, keys.length);
1177
+ const sortKeys = new Uint32Array(count);
1178
+ let validCount = 0;
1179
+ for (let i = 0; i < count; i++) {
1180
+ const bits = keyBits[i];
1181
+ if ((bits & 0x7F800000) === 0x7F800000)
1182
+ continue;
1183
+ sortKeys[validCount] = (bits & 0x80000000) ? ~bits >>> 0 : (bits | 0x80000000) >>> 0;
1184
+ out[validCount] = i;
1185
+ validCount++;
1186
+ }
1187
+ if (validCount <= 1)
1188
+ return validCount;
1189
+ const n = validCount;
1190
+ const temp = new Uint32Array(n);
1191
+ const tempKeys = new Uint32Array(n);
1192
+ const counts = new Uint32Array(256);
1193
+ for (let pass = 0; pass < 4; pass++) {
1194
+ const shift = pass << 3;
1195
+ const srcIdx = (pass & 1) ? temp : out;
1196
+ const dstIdx = (pass & 1) ? out : temp;
1197
+ const srcK = (pass & 1) ? tempKeys : sortKeys;
1198
+ const dstK = (pass & 1) ? sortKeys : tempKeys;
1199
+ counts.fill(0);
1200
+ for (let i = 0; i < n; i++) {
1201
+ counts[(srcK[i] >>> shift) & 0xFF]++;
1202
+ }
1203
+ let sum = 0;
1204
+ for (let b = 0; b < 256; b++) {
1205
+ const c = counts[b];
1206
+ counts[b] = sum;
1207
+ sum += c;
1208
+ }
1209
+ for (let i = 0; i < n; i++) {
1210
+ const bucket = (srcK[i] >>> shift) & 0xFF;
1211
+ const pos = counts[bucket]++;
1212
+ dstIdx[pos] = srcIdx[i];
1213
+ dstK[pos] = srcK[i];
1214
+ }
1215
+ }
1216
+ return validCount;
1217
+ };
1135
1218
  // ---------- sigmoid / logit ----------
1136
1219
  const sigmoid$1 = (x) => 1 / (1 + Math.exp(-x));
1137
1220
  const logit = (p) => {
@@ -1619,7 +1702,6 @@ const simplifyGaussians = (dataTable, targetCount) => {
1619
1702
  let current;
1620
1703
  if (keptIndices.length < N && keptIndices.length > targetCount) {
1621
1704
  current = dataTable.permuteRows(keptIndices);
1622
- logger.debug(`opacity pruning: ${N} -> ${current.numRows} splats (threshold=${pruneThreshold.toFixed(4)})`);
1623
1705
  }
1624
1706
  else {
1625
1707
  current = dataTable;
@@ -1630,7 +1712,8 @@ const simplifyGaussians = (dataTable, targetCount) => {
1630
1712
  while (current.numRows > targetCount) {
1631
1713
  const n = current.numRows;
1632
1714
  const kEff = Math.min(Math.max(1, KNN_K), Math.max(1, n - 1));
1633
- logger.debug(`merging iteration: ${n} -> ${targetCount} splats`);
1715
+ logger.progress.begin(5);
1716
+ logger.progress.step('Building KD-tree');
1634
1717
  const cx = current.getColumnByName('x').data;
1635
1718
  const cy = current.getColumnByName('y').data;
1636
1719
  const cz = current.getColumnByName('z').data;
@@ -1643,16 +1726,21 @@ const simplifyGaussians = (dataTable, targetCount) => {
1643
1726
  const cr2 = current.getColumnByName('rot_2').data;
1644
1727
  const cr3 = current.getColumnByName('rot_3').data;
1645
1728
  const cache = buildPerSplatCache(n, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3);
1646
- // Build KNN graph
1647
1729
  const posTable = new DataTable([
1648
1730
  new Column('x', cx instanceof Float32Array ? cx : new Float32Array(cx)),
1649
1731
  new Column('y', cy instanceof Float32Array ? cy : new Float32Array(cy)),
1650
1732
  new Column('z', cz instanceof Float32Array ? cz : new Float32Array(cz))
1651
1733
  ]);
1652
1734
  const kdTree = new KdTree(posTable);
1653
- const edgeSet = new Set();
1654
- const edges = [];
1735
+ logger.progress.step('Finding nearest neighbors');
1736
+ let edgeCapacity = Math.ceil(n * kEff / 2);
1737
+ let edgeU = new Uint32Array(edgeCapacity);
1738
+ let edgeV = new Uint32Array(edgeCapacity);
1739
+ let edgeCount = 0;
1655
1740
  const queryPoint = new Float32Array(3);
1741
+ const knnInterval = Math.max(1, Math.ceil(n / PROGRESS_TICKS));
1742
+ const knnTicks = Math.ceil(n / knnInterval);
1743
+ logger.progress.begin(knnTicks);
1656
1744
  for (let i = 0; i < n; i++) {
1657
1745
  queryPoint[0] = cx[i];
1658
1746
  queryPoint[1] = cy[i];
@@ -1660,46 +1748,58 @@ const simplifyGaussians = (dataTable, targetCount) => {
1660
1748
  const knn = kdTree.findKNearest(queryPoint, kEff + 1);
1661
1749
  for (let ki = 0; ki < knn.indices.length; ki++) {
1662
1750
  const j = knn.indices[ki];
1663
- if (j === i || j < 0)
1751
+ if (j <= i)
1664
1752
  continue;
1665
- const u = Math.min(i, j);
1666
- const v = Math.max(i, j);
1667
- const key = `${u},${v}`;
1668
- if (!edgeSet.has(key)) {
1669
- edgeSet.add(key);
1670
- edges.push([u, v]);
1753
+ if (edgeCount === edgeCapacity) {
1754
+ edgeCapacity *= 2;
1755
+ const newU = new Uint32Array(edgeCapacity);
1756
+ const newV = new Uint32Array(edgeCapacity);
1757
+ newU.set(edgeU);
1758
+ newV.set(edgeV);
1759
+ edgeU = newU;
1760
+ edgeV = newV;
1671
1761
  }
1762
+ edgeU[edgeCount] = i;
1763
+ edgeV[edgeCount] = j;
1764
+ edgeCount++;
1672
1765
  }
1766
+ if ((i + 1) % knnInterval === 0)
1767
+ logger.progress.step();
1673
1768
  }
1674
- if (edges.length === 0)
1769
+ if (n % knnInterval !== 0)
1770
+ logger.progress.step();
1771
+ if (edgeCount === 0) {
1772
+ logger.progress.cancel();
1675
1773
  break;
1676
- // Compute edge costs
1774
+ }
1775
+ logger.progress.step('Computing edge costs');
1677
1776
  const appData = [];
1678
1777
  for (let ai = 0; ai < allAppearanceCols.length; ai++) {
1679
1778
  const col = current.getColumnByName(allAppearanceCols[ai]);
1680
1779
  if (col)
1681
1780
  appData.push(col.data);
1682
1781
  }
1683
- const costs = new Float32Array(edges.length);
1684
- for (let e = 0; e < edges.length; e++) {
1685
- costs[e] = computeEdgeCost(edges[e][0], edges[e][1], cx, cy, cz, cache, Z, appData, appData.length);
1686
- }
1687
- // Greedy disjoint pair selection
1688
- const valid = [];
1689
- for (let i = 0; i < edges.length; i++) {
1690
- if (Number.isFinite(costs[i]))
1691
- valid.push(i);
1692
- }
1693
- valid.sort((a, b) => {
1694
- const d = costs[a] - costs[b];
1695
- return d !== 0 ? d : a - b;
1696
- });
1697
1782
  const mergesNeeded = n - targetCount;
1783
+ const costs = new Float32Array(edgeCount);
1784
+ const costInterval = Math.max(1, Math.ceil(edgeCount / PROGRESS_TICKS));
1785
+ const costTicks = Math.ceil(edgeCount / costInterval);
1786
+ logger.progress.begin(costTicks);
1787
+ for (let e = 0; e < edgeCount; e++) {
1788
+ costs[e] = computeEdgeCost(edgeU[e], edgeV[e], cx, cy, cz, cache, Z, appData, appData.length);
1789
+ if ((e + 1) % costInterval === 0)
1790
+ logger.progress.step();
1791
+ }
1792
+ if (edgeCount % costInterval !== 0)
1793
+ logger.progress.step();
1794
+ logger.progress.step('Merging splats');
1795
+ // Sort and greedy disjoint pair selection
1796
+ const sorted = new Uint32Array(edgeCount);
1797
+ const validCount = radixSortIndicesByFloat(sorted, edgeCount, costs);
1698
1798
  const used = new Uint8Array(n);
1699
1799
  const pairs = [];
1700
- for (let t = 0; t < valid.length; t++) {
1701
- const e = valid[t];
1702
- const u = edges[e][0], v = edges[e][1];
1800
+ for (let t = 0; t < validCount; t++) {
1801
+ const e = sorted[t];
1802
+ const u = edgeU[e], v = edgeV[e];
1703
1803
  if (used[u] || used[v])
1704
1804
  continue;
1705
1805
  used[u] = 1;
@@ -1708,9 +1808,10 @@ const simplifyGaussians = (dataTable, targetCount) => {
1708
1808
  if (pairs.length >= mergesNeeded)
1709
1809
  break;
1710
1810
  }
1711
- if (pairs.length === 0)
1811
+ if (pairs.length === 0) {
1812
+ logger.progress.cancel();
1712
1813
  break;
1713
- logger.debug(`selected ${pairs.length} merge pairs from ${edges.length} edges`);
1814
+ }
1714
1815
  // Mark which indices are consumed by merging
1715
1816
  const usedSet = new Uint8Array(n);
1716
1817
  for (let p = 0; p < pairs.length; p++) {
@@ -1738,7 +1839,7 @@ const simplifyGaussians = (dataTable, targetCount) => {
1738
1839
  newTable.columns[c].data[dst] = cols[c].data[src];
1739
1840
  }
1740
1841
  }
1741
- // Merge pairs -- cache column refs and handled set once
1842
+ // Merge pairs
1742
1843
  const mergeOut = {
1743
1844
  mu: new Float64Array(3),
1744
1845
  sc: new Float64Array(3),
@@ -1766,6 +1867,9 @@ const simplifyGaussians = (dataTable, targetCount) => {
1766
1867
  .filter(col => !handledCols.has(col.name))
1767
1868
  .map(col => ({ src: col, dst: newTable.getColumnByName(col.name) }))
1768
1869
  .filter(pair => pair.dst);
1870
+ const mergeInterval = Math.max(1, Math.ceil(pairs.length / PROGRESS_TICKS));
1871
+ const mergeTicks = Math.ceil(pairs.length / mergeInterval);
1872
+ logger.progress.begin(mergeTicks);
1769
1873
  for (let p = 0; p < pairs.length; p++, dst++) {
1770
1874
  const pi = pairs[p][0], pj = pairs[p][1];
1771
1875
  momentMatch(pi, pj, cx, cy, cz, cop, cs0, cs1, cs2, cr0, cr1, cr2, cr3, mergeOut, appData, appData.length);
@@ -1788,7 +1892,12 @@ const simplifyGaussians = (dataTable, targetCount) => {
1788
1892
  for (let u = 0; u < unhandledColPairs.length; u++) {
1789
1893
  unhandledColPairs[u].dst.data[dst] = unhandledColPairs[u].src.data[dominant];
1790
1894
  }
1895
+ if ((p + 1) % mergeInterval === 0)
1896
+ logger.progress.step();
1791
1897
  }
1898
+ if (pairs.length % mergeInterval !== 0)
1899
+ logger.progress.step();
1900
+ logger.progress.step('Finalizing');
1792
1901
  current = newTable;
1793
1902
  }
1794
1903
  return current;
@@ -5616,7 +5725,7 @@ class CompressedChunk {
5616
5725
  }
5617
5726
  }
5618
5727
 
5619
- var version = "1.9.0";
5728
+ var version = "1.9.2";
5620
5729
 
5621
5730
  const generatedByString = `Generated by splat-transform ${version}`;
5622
5731
  const chunkProps = [
@@ -7663,6 +7772,746 @@ const writePly = async (options, fs) => {
7663
7772
  await writer.close();
7664
7773
  };
7665
7774
 
7775
+ // This file is part of meshoptimizer library and is distributed under the terms of MIT License.
7776
+ // Copyright (C) 2016-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
7777
+ var MeshoptSimplifier = (function () {
7778
+ // Built with clang version 19.1.5-wasi-sdk
7779
+ // Built from meshoptimizer 1.0
7780
+ var wasm =
7781
+ '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
7782
+
7783
+ var wasmpack = new Uint8Array([
7784
+ 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,
7785
+ 24, 23, 146, 148, 18, 14, 22, 45, 70, 69, 56, 114, 101, 21, 25, 63, 75, 136, 108, 28, 118, 29, 73, 115,
7786
+ ]);
7787
+
7788
+ if (typeof WebAssembly !== 'object') {
7789
+ return {
7790
+ supported: false,
7791
+ };
7792
+ }
7793
+
7794
+ var instance;
7795
+
7796
+ var ready = WebAssembly.instantiate(unpack(wasm), {}).then(function (result) {
7797
+ instance = result.instance;
7798
+ instance.exports.__wasm_call_ctors();
7799
+ });
7800
+
7801
+ function unpack(data) {
7802
+ var result = new Uint8Array(data.length);
7803
+ for (var i = 0; i < data.length; ++i) {
7804
+ var ch = data.charCodeAt(i);
7805
+ result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4;
7806
+ }
7807
+ var write = 0;
7808
+ for (var i = 0; i < data.length; ++i) {
7809
+ result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i];
7810
+ }
7811
+ return result.buffer.slice(0, write);
7812
+ }
7813
+
7814
+ function assert(cond) {
7815
+ if (!cond) {
7816
+ throw new Error('Assertion failed');
7817
+ }
7818
+ }
7819
+
7820
+ function bytes(view) {
7821
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
7822
+ }
7823
+
7824
+ function genremap(fun, positions, vertices, stride) {
7825
+ var sbrk = instance.exports.sbrk;
7826
+ var rp = sbrk(vertices * 4);
7827
+ var sp = sbrk(vertices * stride * 4);
7828
+ var heap = new Uint8Array(instance.exports.memory.buffer);
7829
+ heap.set(bytes(positions), sp);
7830
+ fun(rp, sp, vertices, stride * 4);
7831
+ // heap may have grown
7832
+ heap = new Uint8Array(instance.exports.memory.buffer);
7833
+ var remap = new Uint32Array(vertices);
7834
+ new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
7835
+ sbrk(rp - sbrk(0));
7836
+ return remap;
7837
+ }
7838
+
7839
+ function reorder(fun, indices, vertices) {
7840
+ var sbrk = instance.exports.sbrk;
7841
+ var ip = sbrk(indices.length * 4);
7842
+ var rp = sbrk(vertices * 4);
7843
+ var heap = new Uint8Array(instance.exports.memory.buffer);
7844
+ var indices8 = bytes(indices);
7845
+ heap.set(indices8, ip);
7846
+ var unique = fun(rp, ip, indices.length, vertices);
7847
+ // heap may have grown
7848
+ heap = new Uint8Array(instance.exports.memory.buffer);
7849
+ var remap = new Uint32Array(vertices);
7850
+ new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4));
7851
+ indices8.set(heap.subarray(ip, ip + indices.length * 4));
7852
+ sbrk(ip - sbrk(0));
7853
+
7854
+ for (var i = 0; i < indices.length; ++i) indices[i] = remap[indices[i]];
7855
+
7856
+ return [remap, unique];
7857
+ }
7858
+
7859
+ function maxindex(source) {
7860
+ var result = 0;
7861
+ for (var i = 0; i < source.length; ++i) {
7862
+ var index = source[i];
7863
+ result = result < index ? index : result;
7864
+ }
7865
+ return result;
7866
+ }
7867
+
7868
+ function simplify(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, options) {
7869
+ var sbrk = instance.exports.sbrk;
7870
+ var te = sbrk(4);
7871
+ var ti = sbrk(index_count * 4);
7872
+ var sp = sbrk(vertex_count * vertex_positions_stride);
7873
+ var si = sbrk(index_count * 4);
7874
+ var heap = new Uint8Array(instance.exports.memory.buffer);
7875
+ heap.set(bytes(vertex_positions), sp);
7876
+ heap.set(bytes(indices), si);
7877
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_index_count, target_error, options, te);
7878
+ // heap may have grown
7879
+ heap = new Uint8Array(instance.exports.memory.buffer);
7880
+ var target = new Uint32Array(result);
7881
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
7882
+ var error = new Float32Array(1);
7883
+ bytes(error).set(heap.subarray(te, te + 4));
7884
+ sbrk(te - sbrk(0));
7885
+ return [target, error[0]];
7886
+ }
7887
+
7888
+ function simplifyAttr(
7889
+ fun,
7890
+ indices,
7891
+ index_count,
7892
+ vertex_positions,
7893
+ vertex_count,
7894
+ vertex_positions_stride,
7895
+ vertex_attributes,
7896
+ vertex_attributes_stride,
7897
+ attribute_weights,
7898
+ vertex_lock,
7899
+ target_index_count,
7900
+ target_error,
7901
+ options
7902
+ ) {
7903
+ var sbrk = instance.exports.sbrk;
7904
+ var te = sbrk(4);
7905
+ var ti = sbrk(index_count * 4);
7906
+ var sp = sbrk(vertex_count * vertex_positions_stride);
7907
+ var sa = sbrk(vertex_count * vertex_attributes_stride);
7908
+ var sw = sbrk(attribute_weights.length * 4);
7909
+ var si = sbrk(index_count * 4);
7910
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
7911
+ var heap = new Uint8Array(instance.exports.memory.buffer);
7912
+ heap.set(bytes(vertex_positions), sp);
7913
+ heap.set(bytes(vertex_attributes), sa);
7914
+ heap.set(bytes(attribute_weights), sw);
7915
+ heap.set(bytes(indices), si);
7916
+ if (vertex_lock) {
7917
+ heap.set(bytes(vertex_lock), vl);
7918
+ }
7919
+ var result = fun(
7920
+ ti,
7921
+ si,
7922
+ index_count,
7923
+ sp,
7924
+ vertex_count,
7925
+ vertex_positions_stride,
7926
+ sa,
7927
+ vertex_attributes_stride,
7928
+ sw,
7929
+ attribute_weights.length,
7930
+ vl,
7931
+ target_index_count,
7932
+ target_error,
7933
+ options,
7934
+ te
7935
+ );
7936
+ // heap may have grown
7937
+ heap = new Uint8Array(instance.exports.memory.buffer);
7938
+ var target = new Uint32Array(result);
7939
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
7940
+ var error = new Float32Array(1);
7941
+ bytes(error).set(heap.subarray(te, te + 4));
7942
+ sbrk(te - sbrk(0));
7943
+ return [target, error[0]];
7944
+ }
7945
+
7946
+ function simplifyUpdate(
7947
+ fun,
7948
+ indices,
7949
+ index_count,
7950
+ vertex_positions,
7951
+ vertex_count,
7952
+ vertex_positions_stride,
7953
+ vertex_attributes,
7954
+ vertex_attributes_stride,
7955
+ attribute_weights,
7956
+ vertex_lock,
7957
+ target_index_count,
7958
+ target_error,
7959
+ options
7960
+ ) {
7961
+ var sbrk = instance.exports.sbrk;
7962
+ var te = sbrk(4);
7963
+ var sp = sbrk(vertex_count * vertex_positions_stride);
7964
+ var sa = sbrk(vertex_count * vertex_attributes_stride);
7965
+ var sw = sbrk(attribute_weights.length * 4);
7966
+ var si = sbrk(index_count * 4);
7967
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
7968
+ var heap = new Uint8Array(instance.exports.memory.buffer);
7969
+ heap.set(bytes(vertex_positions), sp);
7970
+ heap.set(bytes(vertex_attributes), sa);
7971
+ heap.set(bytes(attribute_weights), sw);
7972
+ heap.set(bytes(indices), si);
7973
+ if (vertex_lock) {
7974
+ heap.set(bytes(vertex_lock), vl);
7975
+ }
7976
+ var result = fun(
7977
+ si,
7978
+ index_count,
7979
+ sp,
7980
+ vertex_count,
7981
+ vertex_positions_stride,
7982
+ sa,
7983
+ vertex_attributes_stride,
7984
+ sw,
7985
+ attribute_weights.length,
7986
+ vl,
7987
+ target_index_count,
7988
+ target_error,
7989
+ options,
7990
+ te
7991
+ );
7992
+ // heap may have grown
7993
+ heap = new Uint8Array(instance.exports.memory.buffer);
7994
+ bytes(indices).set(heap.subarray(si, si + result * 4));
7995
+ bytes(vertex_positions).set(heap.subarray(sp, sp + vertex_count * vertex_positions_stride));
7996
+ bytes(vertex_attributes).set(heap.subarray(sa, sa + vertex_count * vertex_attributes_stride));
7997
+ var error = new Float32Array(1);
7998
+ bytes(error).set(heap.subarray(te, te + 4));
7999
+ sbrk(te - sbrk(0));
8000
+ return [result, error[0]];
8001
+ }
8002
+
8003
+ function simplifyScale(fun, vertex_positions, vertex_count, vertex_positions_stride) {
8004
+ var sbrk = instance.exports.sbrk;
8005
+ var sp = sbrk(vertex_count * vertex_positions_stride);
8006
+ var heap = new Uint8Array(instance.exports.memory.buffer);
8007
+ heap.set(bytes(vertex_positions), sp);
8008
+ var result = fun(sp, vertex_count, vertex_positions_stride);
8009
+ sbrk(sp - sbrk(0));
8010
+ return result;
8011
+ }
8012
+
8013
+ function simplifyPoints(
8014
+ fun,
8015
+ vertex_positions,
8016
+ vertex_count,
8017
+ vertex_positions_stride,
8018
+ vertex_colors,
8019
+ vertex_colors_stride,
8020
+ color_weight,
8021
+ target_vertex_count
8022
+ ) {
8023
+ var sbrk = instance.exports.sbrk;
8024
+ var ti = sbrk(target_vertex_count * 4);
8025
+ var sp = sbrk(vertex_count * vertex_positions_stride);
8026
+ var sc = sbrk(vertex_count * vertex_colors_stride);
8027
+ var heap = new Uint8Array(instance.exports.memory.buffer);
8028
+ heap.set(bytes(vertex_positions), sp);
8029
+ if (vertex_colors) {
8030
+ heap.set(bytes(vertex_colors), sc);
8031
+ }
8032
+ var result = fun(ti, sp, vertex_count, vertex_positions_stride, sc, vertex_colors_stride, color_weight, target_vertex_count);
8033
+ // heap may have grown
8034
+ heap = new Uint8Array(instance.exports.memory.buffer);
8035
+ var target = new Uint32Array(result);
8036
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
8037
+ sbrk(ti - sbrk(0));
8038
+ return target;
8039
+ }
8040
+
8041
+ function simplifySloppy(
8042
+ fun,
8043
+ indices,
8044
+ index_count,
8045
+ vertex_positions,
8046
+ vertex_count,
8047
+ vertex_positions_stride,
8048
+ vertex_lock,
8049
+ target_index_count,
8050
+ target_error
8051
+ ) {
8052
+ var sbrk = instance.exports.sbrk;
8053
+ var te = sbrk(4);
8054
+ var ti = sbrk(index_count * 4);
8055
+ var sp = sbrk(vertex_count * vertex_positions_stride);
8056
+ var si = sbrk(index_count * 4);
8057
+ var vl = vertex_lock ? sbrk(vertex_count) : 0;
8058
+ var heap = new Uint8Array(instance.exports.memory.buffer);
8059
+ heap.set(bytes(vertex_positions), sp);
8060
+ heap.set(bytes(indices), si);
8061
+ if (vertex_lock) {
8062
+ heap.set(bytes(vertex_lock), vl);
8063
+ }
8064
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, vl, target_index_count, target_error, te);
8065
+ // heap may have grown
8066
+ heap = new Uint8Array(instance.exports.memory.buffer);
8067
+ var target = new Uint32Array(result);
8068
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
8069
+ var error = new Float32Array(1);
8070
+ bytes(error).set(heap.subarray(te, te + 4));
8071
+ sbrk(te - sbrk(0));
8072
+ return [target, error[0]];
8073
+ }
8074
+
8075
+ function simplifyPrune(fun, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_error) {
8076
+ var sbrk = instance.exports.sbrk;
8077
+ var ti = sbrk(index_count * 4);
8078
+ var sp = sbrk(vertex_count * vertex_positions_stride);
8079
+ var si = sbrk(index_count * 4);
8080
+ var heap = new Uint8Array(instance.exports.memory.buffer);
8081
+ heap.set(bytes(vertex_positions), sp);
8082
+ heap.set(bytes(indices), si);
8083
+ var result = fun(ti, si, index_count, sp, vertex_count, vertex_positions_stride, target_error);
8084
+ // heap may have grown
8085
+ heap = new Uint8Array(instance.exports.memory.buffer);
8086
+ var target = new Uint32Array(result);
8087
+ bytes(target).set(heap.subarray(ti, ti + result * 4));
8088
+ sbrk(ti - sbrk(0));
8089
+ return target;
8090
+ }
8091
+
8092
+ var simplifyOptions = {
8093
+ LockBorder: 1,
8094
+ Sparse: 2,
8095
+ ErrorAbsolute: 4,
8096
+ Prune: 8,
8097
+ Regularize: 16,
8098
+ Permissive: 32,
8099
+ _InternalDebug: 1 << 30, // internal, don't use!
8100
+ };
8101
+
8102
+ return {
8103
+ ready: ready,
8104
+ supported: true,
8105
+
8106
+ compactMesh: function (indices) {
8107
+ assert(
8108
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8109
+ );
8110
+ assert(indices.length % 3 == 0);
8111
+
8112
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8113
+ return reorder(instance.exports.meshopt_optimizeVertexFetchRemap, indices32, maxindex(indices) + 1);
8114
+ },
8115
+
8116
+ generatePositionRemap: function (vertex_positions, vertex_positions_stride) {
8117
+ assert(vertex_positions instanceof Float32Array);
8118
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8119
+ assert(vertex_positions_stride >= 3);
8120
+
8121
+ return genremap(
8122
+ instance.exports.meshopt_generatePositionRemap,
8123
+ vertex_positions,
8124
+ vertex_positions.length / vertex_positions_stride,
8125
+ vertex_positions_stride
8126
+ );
8127
+ },
8128
+
8129
+ simplify: function (indices, vertex_positions, vertex_positions_stride, target_index_count, target_error, flags) {
8130
+ assert(
8131
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8132
+ );
8133
+ assert(indices.length % 3 == 0);
8134
+ assert(vertex_positions instanceof Float32Array);
8135
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8136
+ assert(vertex_positions_stride >= 3);
8137
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
8138
+ assert(target_index_count % 3 == 0);
8139
+ assert(target_error >= 0);
8140
+
8141
+ var options = 0;
8142
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
8143
+ assert(flags[i] in simplifyOptions);
8144
+ options |= simplifyOptions[flags[i]];
8145
+ }
8146
+
8147
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8148
+ var result = simplify(
8149
+ instance.exports.meshopt_simplify,
8150
+ indices32,
8151
+ indices.length,
8152
+ vertex_positions,
8153
+ vertex_positions.length / vertex_positions_stride,
8154
+ vertex_positions_stride * 4,
8155
+ target_index_count,
8156
+ target_error,
8157
+ options
8158
+ );
8159
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
8160
+
8161
+ return result;
8162
+ },
8163
+
8164
+ simplifyWithAttributes: function (
8165
+ indices,
8166
+ vertex_positions,
8167
+ vertex_positions_stride,
8168
+ vertex_attributes,
8169
+ vertex_attributes_stride,
8170
+ attribute_weights,
8171
+ vertex_lock,
8172
+ target_index_count,
8173
+ target_error,
8174
+ flags
8175
+ ) {
8176
+ assert(
8177
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8178
+ );
8179
+ assert(indices.length % 3 == 0);
8180
+ assert(vertex_positions instanceof Float32Array);
8181
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8182
+ assert(vertex_positions_stride >= 3);
8183
+ assert(vertex_attributes instanceof Float32Array);
8184
+ assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
8185
+ assert(vertex_attributes_stride >= 0);
8186
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
8187
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
8188
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
8189
+ assert(target_index_count % 3 == 0);
8190
+ assert(target_error >= 0);
8191
+ assert(Array.isArray(attribute_weights));
8192
+ assert(vertex_attributes_stride >= attribute_weights.length);
8193
+ assert(attribute_weights.length <= 32);
8194
+ for (var i = 0; i < attribute_weights.length; ++i) {
8195
+ assert(attribute_weights[i] >= 0);
8196
+ }
8197
+
8198
+ var options = 0;
8199
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
8200
+ assert(flags[i] in simplifyOptions);
8201
+ options |= simplifyOptions[flags[i]];
8202
+ }
8203
+
8204
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8205
+ var result = simplifyAttr(
8206
+ instance.exports.meshopt_simplifyWithAttributes,
8207
+ indices32,
8208
+ indices.length,
8209
+ vertex_positions,
8210
+ vertex_positions.length / vertex_positions_stride,
8211
+ vertex_positions_stride * 4,
8212
+ vertex_attributes,
8213
+ vertex_attributes_stride * 4,
8214
+ new Float32Array(attribute_weights),
8215
+ vertex_lock,
8216
+ target_index_count,
8217
+ target_error,
8218
+ options
8219
+ );
8220
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
8221
+
8222
+ return result;
8223
+ },
8224
+
8225
+ simplifyWithUpdate: function (
8226
+ indices,
8227
+ vertex_positions,
8228
+ vertex_positions_stride,
8229
+ vertex_attributes,
8230
+ vertex_attributes_stride,
8231
+ attribute_weights,
8232
+ vertex_lock,
8233
+ target_index_count,
8234
+ target_error,
8235
+ flags
8236
+ ) {
8237
+ assert(
8238
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8239
+ );
8240
+ assert(indices.length % 3 == 0);
8241
+ assert(vertex_positions instanceof Float32Array);
8242
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8243
+ assert(vertex_positions_stride >= 3);
8244
+ assert(vertex_attributes instanceof Float32Array);
8245
+ assert(vertex_attributes.length == vertex_attributes_stride * (vertex_positions.length / vertex_positions_stride));
8246
+ assert(vertex_attributes_stride >= 0);
8247
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
8248
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
8249
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
8250
+ assert(target_index_count % 3 == 0);
8251
+ assert(target_error >= 0);
8252
+ assert(Array.isArray(attribute_weights));
8253
+ assert(vertex_attributes_stride >= attribute_weights.length);
8254
+ assert(attribute_weights.length <= 32);
8255
+ for (var i = 0; i < attribute_weights.length; ++i) {
8256
+ assert(attribute_weights[i] >= 0);
8257
+ }
8258
+
8259
+ var options = 0;
8260
+ for (var i = 0; i < (flags ? flags.length : 0); ++i) {
8261
+ assert(flags[i] in simplifyOptions);
8262
+ options |= simplifyOptions[flags[i]];
8263
+ }
8264
+
8265
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8266
+ var result = simplifyUpdate(
8267
+ instance.exports.meshopt_simplifyWithUpdate,
8268
+ indices32,
8269
+ indices.length,
8270
+ vertex_positions,
8271
+ vertex_positions.length / vertex_positions_stride,
8272
+ vertex_positions_stride * 4,
8273
+ vertex_attributes,
8274
+ vertex_attributes_stride * 4,
8275
+ new Float32Array(attribute_weights),
8276
+ vertex_lock,
8277
+ target_index_count,
8278
+ target_error,
8279
+ options
8280
+ );
8281
+ if (indices !== indices32) {
8282
+ // copy back indices if they were converted to Uint32Array
8283
+ for (var i = 0; i < result[0]; ++i) {
8284
+ indices[i] = indices32[i];
8285
+ }
8286
+ }
8287
+ return result;
8288
+ },
8289
+
8290
+ getScale: function (vertex_positions, vertex_positions_stride) {
8291
+ assert(vertex_positions instanceof Float32Array);
8292
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8293
+ assert(vertex_positions_stride >= 3);
8294
+ return simplifyScale(
8295
+ instance.exports.meshopt_simplifyScale,
8296
+ vertex_positions,
8297
+ vertex_positions.length / vertex_positions_stride,
8298
+ vertex_positions_stride * 4
8299
+ );
8300
+ },
8301
+
8302
+ simplifyPoints: function (vertex_positions, vertex_positions_stride, target_vertex_count, vertex_colors, vertex_colors_stride, color_weight) {
8303
+ assert(vertex_positions instanceof Float32Array);
8304
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8305
+ assert(vertex_positions_stride >= 3);
8306
+ assert(target_vertex_count >= 0 && target_vertex_count <= vertex_positions.length / vertex_positions_stride);
8307
+ if (vertex_colors) {
8308
+ assert(vertex_colors instanceof Float32Array);
8309
+ assert(vertex_colors.length % vertex_colors_stride == 0);
8310
+ assert(vertex_colors_stride >= 3);
8311
+ assert(vertex_positions.length / vertex_positions_stride == vertex_colors.length / vertex_colors_stride);
8312
+ return simplifyPoints(
8313
+ instance.exports.meshopt_simplifyPoints,
8314
+ vertex_positions,
8315
+ vertex_positions.length / vertex_positions_stride,
8316
+ vertex_positions_stride * 4,
8317
+ vertex_colors,
8318
+ vertex_colors_stride * 4,
8319
+ color_weight,
8320
+ target_vertex_count
8321
+ );
8322
+ } else {
8323
+ return simplifyPoints(
8324
+ instance.exports.meshopt_simplifyPoints,
8325
+ vertex_positions,
8326
+ vertex_positions.length / vertex_positions_stride,
8327
+ vertex_positions_stride * 4,
8328
+ undefined,
8329
+ 0,
8330
+ 0,
8331
+ target_vertex_count
8332
+ );
8333
+ }
8334
+ },
8335
+
8336
+ simplifySloppy: function (indices, vertex_positions, vertex_positions_stride, vertex_lock, target_index_count, target_error) {
8337
+ assert(
8338
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8339
+ );
8340
+ assert(indices.length % 3 == 0);
8341
+ assert(vertex_positions instanceof Float32Array);
8342
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8343
+ assert(vertex_positions_stride >= 3);
8344
+ assert(vertex_lock == null || vertex_lock instanceof Uint8Array);
8345
+ assert(vertex_lock == null || vertex_lock.length == vertex_positions.length / vertex_positions_stride);
8346
+ assert(target_index_count >= 0 && target_index_count <= indices.length);
8347
+ assert(target_index_count % 3 == 0);
8348
+ assert(target_error >= 0);
8349
+
8350
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8351
+ var result = simplifySloppy(
8352
+ instance.exports.meshopt_simplifySloppy,
8353
+ indices32,
8354
+ indices.length,
8355
+ vertex_positions,
8356
+ vertex_positions.length / vertex_positions_stride,
8357
+ vertex_positions_stride * 4,
8358
+ vertex_lock,
8359
+ target_index_count,
8360
+ target_error
8361
+ );
8362
+ result[0] = indices instanceof Uint32Array ? result[0] : new indices.constructor(result[0]);
8363
+
8364
+ return result;
8365
+ },
8366
+
8367
+ simplifyPrune: function (indices, vertex_positions, vertex_positions_stride, target_error) {
8368
+ assert(
8369
+ indices instanceof Uint32Array || indices instanceof Int32Array || indices instanceof Uint16Array || indices instanceof Int16Array
8370
+ );
8371
+ assert(indices.length % 3 == 0);
8372
+ assert(vertex_positions instanceof Float32Array);
8373
+ assert(vertex_positions.length % vertex_positions_stride == 0);
8374
+ assert(vertex_positions_stride >= 3);
8375
+ assert(target_error >= 0);
8376
+
8377
+ var indices32 = indices.BYTES_PER_ELEMENT == 4 ? indices : new Uint32Array(indices);
8378
+ var result = simplifyPrune(
8379
+ instance.exports.meshopt_simplifyPrune,
8380
+ indices32,
8381
+ indices.length,
8382
+ vertex_positions,
8383
+ vertex_positions.length / vertex_positions_stride,
8384
+ vertex_positions_stride * 4,
8385
+ target_error
8386
+ );
8387
+ result = indices instanceof Uint32Array ? result : new indices.constructor(result);
8388
+
8389
+ return result;
8390
+ },
8391
+ };
8392
+ })();
8393
+
8394
+ /**
8395
+ * Build a minimal GLB (glTF 2.0 binary) file containing a single triangle mesh.
8396
+ *
8397
+ * The output contains only positions and triangle indices — no normals,
8398
+ * UVs, or materials — suitable for collision meshes.
8399
+ *
8400
+ * @param positions - Vertex positions (3 floats per vertex)
8401
+ * @param indices - Triangle indices (3 per triangle, unsigned 32-bit)
8402
+ * @returns GLB file as a Uint8Array
8403
+ */
8404
+ function buildCollisionGlb(positions, indices) {
8405
+ const vertexCount = positions.length / 3;
8406
+ const indexCount = indices.length;
8407
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
8408
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
8409
+ for (let i = 0; i < positions.length; i += 3) {
8410
+ const x = positions[i], y = positions[i + 1], z = positions[i + 2];
8411
+ if (x < minX)
8412
+ minX = x;
8413
+ if (y < minY)
8414
+ minY = y;
8415
+ if (z < minZ)
8416
+ minZ = z;
8417
+ if (x > maxX)
8418
+ maxX = x;
8419
+ if (y > maxY)
8420
+ maxY = y;
8421
+ if (z > maxZ)
8422
+ maxZ = z;
8423
+ }
8424
+ const positionsByteLength = positions.byteLength;
8425
+ const indicesByteLength = indices.byteLength;
8426
+ const totalBinSize = positionsByteLength + indicesByteLength;
8427
+ const gltf = {
8428
+ asset: { version: '2.0', generator: 'splat-transform' },
8429
+ scene: 0,
8430
+ scenes: [{ nodes: [0] }],
8431
+ nodes: [{ mesh: 0 }],
8432
+ meshes: [{
8433
+ primitives: [{
8434
+ attributes: { POSITION: 0 },
8435
+ indices: 1
8436
+ }]
8437
+ }],
8438
+ accessors: [
8439
+ {
8440
+ bufferView: 0,
8441
+ componentType: 5126, // FLOAT
8442
+ count: vertexCount,
8443
+ type: 'VEC3',
8444
+ min: [minX, minY, minZ],
8445
+ max: [maxX, maxY, maxZ]
8446
+ },
8447
+ {
8448
+ bufferView: 1,
8449
+ componentType: 5125, // UNSIGNED_INT
8450
+ count: indexCount,
8451
+ type: 'SCALAR'
8452
+ }
8453
+ ],
8454
+ bufferViews: [
8455
+ {
8456
+ buffer: 0,
8457
+ byteOffset: 0,
8458
+ byteLength: positionsByteLength,
8459
+ target: 34962 // ARRAY_BUFFER
8460
+ },
8461
+ {
8462
+ buffer: 0,
8463
+ byteOffset: positionsByteLength,
8464
+ byteLength: indicesByteLength,
8465
+ target: 34963 // ELEMENT_ARRAY_BUFFER
8466
+ }
8467
+ ],
8468
+ buffers: [{ byteLength: totalBinSize }]
8469
+ };
8470
+ const jsonString = JSON.stringify(gltf);
8471
+ const jsonEncoder = new TextEncoder();
8472
+ const jsonBytes = jsonEncoder.encode(jsonString);
8473
+ // JSON chunk must be padded to 4-byte alignment with spaces (0x20)
8474
+ const jsonPadding = (4 - (jsonBytes.length % 4)) % 4;
8475
+ const jsonChunkLength = jsonBytes.length + jsonPadding;
8476
+ // BIN chunk must be padded to 4-byte alignment with zeros
8477
+ const binPadding = (4 - (totalBinSize % 4)) % 4;
8478
+ const binChunkLength = totalBinSize + binPadding;
8479
+ // GLB layout: header (12) + JSON chunk header (8) + JSON data + BIN chunk header (8) + BIN data
8480
+ const totalLength = 12 + 8 + jsonChunkLength + 8 + binChunkLength;
8481
+ const buffer = new ArrayBuffer(totalLength);
8482
+ const view = new DataView(buffer);
8483
+ const byteArray = new Uint8Array(buffer);
8484
+ let offset = 0;
8485
+ // GLB header
8486
+ view.setUint32(offset, 0x46546C67, true);
8487
+ offset += 4; // magic: "glTF"
8488
+ view.setUint32(offset, 2, true);
8489
+ offset += 4; // version: 2
8490
+ view.setUint32(offset, totalLength, true);
8491
+ offset += 4; // total length
8492
+ // JSON chunk header
8493
+ view.setUint32(offset, jsonChunkLength, true);
8494
+ offset += 4;
8495
+ view.setUint32(offset, 0x4E4F534A, true);
8496
+ offset += 4; // type: "JSON"
8497
+ // JSON chunk data
8498
+ byteArray.set(jsonBytes, offset);
8499
+ offset += jsonBytes.length;
8500
+ for (let i = 0; i < jsonPadding; i++) {
8501
+ byteArray[offset++] = 0x20;
8502
+ }
8503
+ // BIN chunk header
8504
+ view.setUint32(offset, binChunkLength, true);
8505
+ offset += 4;
8506
+ view.setUint32(offset, 0x004E4942, true);
8507
+ offset += 4; // type: "BIN\0"
8508
+ // BIN chunk data: positions then indices
8509
+ byteArray.set(new Uint8Array(positions.buffer, positions.byteOffset, positionsByteLength), offset);
8510
+ offset += positionsByteLength;
8511
+ byteArray.set(new Uint8Array(indices.buffer, indices.byteOffset, indicesByteLength), offset);
8512
+ return byteArray;
8513
+ }
8514
+
7666
8515
  /**
7667
8516
  * Compute axis-aligned bounding box half-extents for all Gaussians in a DataTable.
7668
8517
  *
@@ -8528,6 +9377,525 @@ class GpuVoxelization {
8528
9377
  }
8529
9378
  }
8530
9379
 
9380
+ // ============================================================================
9381
+ // Voxel bit helpers
9382
+ // ============================================================================
9383
+ // Bit layout within a 4x4x4 block: bitIdx = lx + ly*4 + lz*16
9384
+ // lo = bits 0-31 (lz 0-1), hi = bits 32-63 (lz 2-3)
9385
+ /**
9386
+ * Test whether a voxel is occupied within a block's bitmask.
9387
+ *
9388
+ * @param lo - Lower 32 bits of the block mask
9389
+ * @param hi - Upper 32 bits of the block mask
9390
+ * @param lx - Local x coordinate (0-3)
9391
+ * @param ly - Local y coordinate (0-3)
9392
+ * @param lz - Local z coordinate (0-3)
9393
+ * @returns True if the voxel is occupied
9394
+ */
9395
+ function isVoxelSet(lo, hi, lx, ly, lz) {
9396
+ const bitIdx = lx + ly * 4 + lz * 16;
9397
+ if (bitIdx < 32) {
9398
+ return (lo & (1 << bitIdx)) !== 0;
9399
+ }
9400
+ return (hi & (1 << (bitIdx - 32))) !== 0;
9401
+ }
9402
+ // ============================================================================
9403
+ // Occupancy grid from BlockAccumulator
9404
+ // ============================================================================
9405
+ /**
9406
+ * Build a fast-lookup occupancy structure from a BlockAccumulator.
9407
+ * Returns a function that queries whether a voxel at global coordinates
9408
+ * (vx, vy, vz) is occupied.
9409
+ *
9410
+ * @param accumulator - Block data
9411
+ * @returns Lookup function (vx, vy, vz) => boolean
9412
+ */
9413
+ function buildOccupancyLookup(accumulator) {
9414
+ // Map from "bx,by,bz" encoded as single number to {lo,hi} or solid flag
9415
+ // Block key = bx + by * stride + bz * stride^2 where stride is large enough
9416
+ const mixed = accumulator.getMixedBlocks();
9417
+ const solid = accumulator.getSolidBlocks();
9418
+ // Use a Map<number, number> where value encodes index into mask arrays.
9419
+ // For solid blocks, store -1 as sentinel.
9420
+ const blockMap = new Map();
9421
+ for (let i = 0; i < mixed.morton.length; i++) {
9422
+ blockMap.set(mixed.morton[i], i);
9423
+ }
9424
+ for (let i = 0; i < solid.length; i++) {
9425
+ blockMap.set(solid[i], -1);
9426
+ }
9427
+ const masks = mixed.masks;
9428
+ return (vx, vy, vz) => {
9429
+ if (vx < 0 || vy < 0 || vz < 0)
9430
+ return false;
9431
+ const bx = vx >> 2;
9432
+ const by = vy >> 2;
9433
+ const bz = vz >> 2;
9434
+ const entry = blockMap.get(xyzToMorton(bx, by, bz));
9435
+ if (entry === undefined)
9436
+ return false;
9437
+ if (entry === -1)
9438
+ return true; // solid block
9439
+ const lo = masks[entry * 2];
9440
+ const hi = masks[entry * 2 + 1];
9441
+ return isVoxelSet(lo, hi, vx & 3, vy & 3, vz & 3);
9442
+ };
9443
+ }
9444
+ // ============================================================================
9445
+ // Marching Cubes
9446
+ // ============================================================================
9447
+ /**
9448
+ * Extract a triangle mesh from a BlockAccumulator using marching cubes.
9449
+ *
9450
+ * Each voxel is treated as a cell in the marching cubes grid. Corner values
9451
+ * are binary (0 = empty, 1 = occupied) with a 0.5 threshold. Vertices are
9452
+ * placed at edge midpoints, producing a mesh that follows voxel boundaries.
9453
+ *
9454
+ * @param accumulator - Voxel block data after filtering
9455
+ * @param gridBounds - Grid bounds aligned to block boundaries
9456
+ * @param voxelResolution - Size of each voxel in world units
9457
+ * @returns Mesh with positions and indices
9458
+ */
9459
+ function marchingCubes(accumulator, gridBounds, voxelResolution) {
9460
+ const isOccupied = buildOccupancyLookup(accumulator);
9461
+ // Collect all voxel coordinates that need processing.
9462
+ // We need to check every cell where at least one corner differs from
9463
+ // the others, which means we need to check occupied voxels and their
9464
+ // immediate neighbors.
9465
+ const mixed = accumulator.getMixedBlocks();
9466
+ const solid = accumulator.getSolidBlocks();
9467
+ // Collect set of all block coordinates that exist
9468
+ const blockSet = new Set();
9469
+ for (let i = 0; i < mixed.morton.length; i++) {
9470
+ blockSet.add(mixed.morton[i]);
9471
+ }
9472
+ for (let i = 0; i < solid.length; i++) {
9473
+ blockSet.add(solid[i]);
9474
+ }
9475
+ // For each block, we process a 4x4x4 region of marching cubes cells.
9476
+ // Each cell at (vx, vy, vz) has corners at (vx..vx+1, vy..vy+1, vz..vz+1).
9477
+ // We only generate triangles for cells that have mixed corners (not all same).
9478
+ // Vertex deduplication: edge ID -> vertex index
9479
+ // Edge ID encodes the voxel coordinate and edge direction
9480
+ const vertexMap = new Map();
9481
+ const positions = [];
9482
+ const indices = [];
9483
+ const originX = gridBounds.min.x;
9484
+ const originY = gridBounds.min.y;
9485
+ const originZ = gridBounds.min.z;
9486
+ // Compute strides from actual grid dimensions (+3 for the -1 boundary
9487
+ // extension, the far edge +1, and one extra for safety).
9488
+ const strideX = Math.round((gridBounds.max.x - gridBounds.min.x) / voxelResolution) + 3;
9489
+ const strideXY = strideX * (Math.round((gridBounds.max.y - gridBounds.min.y) / voxelResolution) + 3);
9490
+ // Get or create a vertex at the midpoint of an edge.
9491
+ // Edge is identified by the lower corner voxel coordinate and axis (0=x, 1=y, 2=z).
9492
+ const getVertex = (vx, vy, vz, axis) => {
9493
+ // Pack (vx, vy, vz, axis) into a single key. Offset by 1 so that
9494
+ // vx = -1 (from the boundary extension) maps to 0, keeping keys non-negative.
9495
+ const key = ((vx + 1) + (vy + 1) * strideX + (vz + 1) * strideXY) * 3 + axis;
9496
+ let idx = vertexMap.get(key);
9497
+ if (idx !== undefined)
9498
+ return idx;
9499
+ idx = positions.length / 3;
9500
+ let px = originX + vx * voxelResolution;
9501
+ let py = originY + vy * voxelResolution;
9502
+ let pz = originZ + vz * voxelResolution;
9503
+ // Place vertex at edge midpoint (binary field -> always at 0.5)
9504
+ if (axis === 0)
9505
+ px += voxelResolution * 0.5;
9506
+ else if (axis === 1)
9507
+ py += voxelResolution * 0.5;
9508
+ else
9509
+ pz += voxelResolution * 0.5;
9510
+ positions.push(px, py, pz);
9511
+ vertexMap.set(key, idx);
9512
+ return idx;
9513
+ };
9514
+ // Process all blocks and their boundary neighbors
9515
+ const allMortons = [];
9516
+ blockSet.forEach(m => allMortons.push(m));
9517
+ for (let bi = 0; bi < allMortons.length; bi++) {
9518
+ const morton = allMortons[bi];
9519
+ const [bx, by, bz] = mortonToXYZ(morton);
9520
+ // Iterate -1..3 to include the boundary layer in the negative
9521
+ // direction. Cells at lx/ly/lz = -1 straddle the block edge and
9522
+ // are needed to close the surface where no neighboring block exists.
9523
+ for (let lz = -1; lz < 4; lz++) {
9524
+ for (let ly = -1; ly < 4; ly++) {
9525
+ for (let lx = -1; lx < 4; lx++) {
9526
+ const vx = bx * 4 + lx;
9527
+ const vy = by * 4 + ly;
9528
+ const vz = bz * 4 + lz;
9529
+ // Determine which block owns this cell
9530
+ const ownerBx = vx >> 2;
9531
+ const ownerBy = vy >> 2;
9532
+ const ownerBz = vz >> 2;
9533
+ if (ownerBx !== bx || ownerBy !== by || ownerBz !== bz) {
9534
+ // Cell belongs to a different block — skip if that
9535
+ // block exists (it will process the cell itself).
9536
+ // Guard negative coords: xyzToMorton assumes non-negative inputs.
9537
+ if (ownerBx >= 0 && ownerBy >= 0 && ownerBz >= 0 &&
9538
+ blockSet.has(xyzToMorton(ownerBx, ownerBy, ownerBz)))
9539
+ continue;
9540
+ }
9541
+ // Get corner values for this cell (8 corners)
9542
+ // Corners: (vx,vy,vz), (vx+1,vy,vz), (vx+1,vy+1,vz), (vx,vy+1,vz),
9543
+ // (vx,vy,vz+1), (vx+1,vy,vz+1), (vx+1,vy+1,vz+1), (vx,vy+1,vz+1)
9544
+ const c0 = isOccupied(vx, vy, vz) ? 1 : 0;
9545
+ const c1 = isOccupied(vx + 1, vy, vz) ? 1 : 0;
9546
+ const c2 = isOccupied(vx + 1, vy + 1, vz) ? 1 : 0;
9547
+ const c3 = isOccupied(vx, vy + 1, vz) ? 1 : 0;
9548
+ const c4 = isOccupied(vx, vy, vz + 1) ? 1 : 0;
9549
+ const c5 = isOccupied(vx + 1, vy, vz + 1) ? 1 : 0;
9550
+ const c6 = isOccupied(vx + 1, vy + 1, vz + 1) ? 1 : 0;
9551
+ const c7 = isOccupied(vx, vy + 1, vz + 1) ? 1 : 0;
9552
+ const cubeIndex = c0 | (c1 << 1) | (c2 << 2) | (c3 << 3) |
9553
+ (c4 << 4) | (c5 << 5) | (c6 << 6) | (c7 << 7);
9554
+ if (cubeIndex === 0 || cubeIndex === 255)
9555
+ continue;
9556
+ const edges = EDGE_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
9557
+ if (edges === 0)
9558
+ continue;
9559
+ // Compute vertices on active edges
9560
+ // Edge -> vertex mapping using getVertex with (corner voxel coord, axis)
9561
+ const edgeVerts = new Array(12);
9562
+ if (edges & 1)
9563
+ edgeVerts[0] = getVertex(vx, vy, vz, 0); // edge 0: x-axis at (vx, vy, vz)
9564
+ if (edges & 2)
9565
+ edgeVerts[1] = getVertex(vx + 1, vy, vz, 1); // edge 1: y-axis at (vx+1, vy, vz)
9566
+ if (edges & 4)
9567
+ edgeVerts[2] = getVertex(vx, vy + 1, vz, 0); // edge 2: x-axis at (vx, vy+1, vz)
9568
+ if (edges & 8)
9569
+ edgeVerts[3] = getVertex(vx, vy, vz, 1); // edge 3: y-axis at (vx, vy, vz)
9570
+ if (edges & 16)
9571
+ edgeVerts[4] = getVertex(vx, vy, vz + 1, 0); // edge 4: x-axis at (vx, vy, vz+1)
9572
+ if (edges & 32)
9573
+ edgeVerts[5] = getVertex(vx + 1, vy, vz + 1, 1); // edge 5: y-axis at (vx+1, vy, vz+1)
9574
+ if (edges & 64)
9575
+ edgeVerts[6] = getVertex(vx, vy + 1, vz + 1, 0); // edge 6: x-axis at (vx, vy+1, vz+1)
9576
+ if (edges & 128)
9577
+ edgeVerts[7] = getVertex(vx, vy, vz + 1, 1); // edge 7: y-axis at (vx, vy, vz+1)
9578
+ if (edges & 256)
9579
+ edgeVerts[8] = getVertex(vx, vy, vz, 2); // edge 8: z-axis at (vx, vy, vz)
9580
+ if (edges & 512)
9581
+ edgeVerts[9] = getVertex(vx + 1, vy, vz, 2); // edge 9: z-axis at (vx+1, vy, vz)
9582
+ if (edges & 1024)
9583
+ edgeVerts[10] = getVertex(vx + 1, vy + 1, vz, 2); // edge 10: z-axis at (vx+1, vy+1, vz)
9584
+ if (edges & 2048)
9585
+ edgeVerts[11] = getVertex(vx, vy + 1, vz, 2); // edge 11: z-axis at (vx, vy+1, vz)
9586
+ // Emit triangles (reversed winding to face outward)
9587
+ const triRow = TRI_TABLE[cubeIndex]; // eslint-disable-line no-use-before-define
9588
+ for (let t = 0; t < triRow.length; t += 3) {
9589
+ indices.push(edgeVerts[triRow[t]], edgeVerts[triRow[t + 2]], edgeVerts[triRow[t + 1]]);
9590
+ }
9591
+ }
9592
+ }
9593
+ }
9594
+ }
9595
+ return {
9596
+ positions: new Float32Array(positions),
9597
+ indices: new Uint32Array(indices)
9598
+ };
9599
+ }
9600
+ // ============================================================================
9601
+ // Marching Cubes Lookup Tables
9602
+ // ============================================================================
9603
+ // Standard tables from Paul Bourke's polygonising a scalar field.
9604
+ // EDGE_TABLE: 256 entries, each a 12-bit mask of which edges are intersected.
9605
+ // TRI_TABLE: 256 entries, each an array of edge indices forming triangles.
9606
+ const EDGE_TABLE = [
9607
+ 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
9608
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
9609
+ 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
9610
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
9611
+ 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
9612
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
9613
+ 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
9614
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
9615
+ 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c,
9616
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
9617
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc,
9618
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
9619
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c,
9620
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
9621
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc,
9622
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
9623
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
9624
+ 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
9625
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
9626
+ 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
9627
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
9628
+ 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
9629
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
9630
+ 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
9631
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
9632
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
9633
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
9634
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
9635
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
9636
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
9637
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
9638
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
9639
+ ];
9640
+ const TRI_TABLE = [
9641
+ [],
9642
+ [0, 8, 3],
9643
+ [0, 1, 9],
9644
+ [1, 8, 3, 9, 8, 1],
9645
+ [1, 2, 10],
9646
+ [0, 8, 3, 1, 2, 10],
9647
+ [9, 2, 10, 0, 2, 9],
9648
+ [2, 8, 3, 2, 10, 8, 10, 9, 8],
9649
+ [3, 11, 2],
9650
+ [0, 11, 2, 8, 11, 0],
9651
+ [1, 9, 0, 2, 3, 11],
9652
+ [1, 11, 2, 1, 9, 11, 9, 8, 11],
9653
+ [3, 10, 1, 11, 10, 3],
9654
+ [0, 10, 1, 0, 8, 10, 8, 11, 10],
9655
+ [3, 9, 0, 3, 11, 9, 11, 10, 9],
9656
+ [9, 8, 10, 10, 8, 11],
9657
+ [4, 7, 8],
9658
+ [4, 3, 0, 7, 3, 4],
9659
+ [0, 1, 9, 8, 4, 7],
9660
+ [4, 1, 9, 4, 7, 1, 7, 3, 1],
9661
+ [1, 2, 10, 8, 4, 7],
9662
+ [3, 4, 7, 3, 0, 4, 1, 2, 10],
9663
+ [9, 2, 10, 9, 0, 2, 8, 4, 7],
9664
+ [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4],
9665
+ [8, 4, 7, 3, 11, 2],
9666
+ [11, 4, 7, 11, 2, 4, 2, 0, 4],
9667
+ [9, 0, 1, 8, 4, 7, 2, 3, 11],
9668
+ [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1],
9669
+ [3, 10, 1, 3, 11, 10, 7, 8, 4],
9670
+ [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4],
9671
+ [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3],
9672
+ [4, 7, 11, 4, 11, 9, 9, 11, 10],
9673
+ [9, 5, 4],
9674
+ [9, 5, 4, 0, 8, 3],
9675
+ [0, 5, 4, 1, 5, 0],
9676
+ [8, 5, 4, 8, 3, 5, 3, 1, 5],
9677
+ [1, 2, 10, 9, 5, 4],
9678
+ [3, 0, 8, 1, 2, 10, 4, 9, 5],
9679
+ [5, 2, 10, 5, 4, 2, 4, 0, 2],
9680
+ [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8],
9681
+ [9, 5, 4, 2, 3, 11],
9682
+ [0, 11, 2, 0, 8, 11, 4, 9, 5],
9683
+ [0, 5, 4, 0, 1, 5, 2, 3, 11],
9684
+ [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5],
9685
+ [10, 3, 11, 10, 1, 3, 9, 5, 4],
9686
+ [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10],
9687
+ [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3],
9688
+ [5, 4, 8, 5, 8, 10, 10, 8, 11],
9689
+ [9, 7, 8, 5, 7, 9],
9690
+ [9, 3, 0, 9, 5, 3, 5, 7, 3],
9691
+ [0, 7, 8, 0, 1, 7, 1, 5, 7],
9692
+ [1, 5, 3, 3, 5, 7],
9693
+ [9, 7, 8, 9, 5, 7, 10, 1, 2],
9694
+ [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3],
9695
+ [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2],
9696
+ [2, 10, 5, 2, 5, 3, 3, 5, 7],
9697
+ [7, 9, 5, 7, 8, 9, 3, 11, 2],
9698
+ [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11],
9699
+ [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7],
9700
+ [11, 2, 1, 11, 1, 7, 7, 1, 5],
9701
+ [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11],
9702
+ [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0],
9703
+ [11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0],
9704
+ [11, 10, 5, 7, 11, 5],
9705
+ [10, 6, 5],
9706
+ [0, 8, 3, 5, 10, 6],
9707
+ [9, 0, 1, 5, 10, 6],
9708
+ [1, 8, 3, 1, 9, 8, 5, 10, 6],
9709
+ [1, 6, 5, 2, 6, 1],
9710
+ [1, 6, 5, 1, 2, 6, 3, 0, 8],
9711
+ [9, 6, 5, 9, 0, 6, 0, 2, 6],
9712
+ [5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8],
9713
+ [2, 3, 11, 10, 6, 5],
9714
+ [11, 0, 8, 11, 2, 0, 10, 6, 5],
9715
+ [0, 1, 9, 2, 3, 11, 5, 10, 6],
9716
+ [5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11],
9717
+ [6, 3, 11, 6, 5, 3, 5, 1, 3],
9718
+ [0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6],
9719
+ [3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9],
9720
+ [6, 5, 9, 6, 9, 11, 11, 9, 8],
9721
+ [5, 10, 6, 4, 7, 8],
9722
+ [4, 3, 0, 4, 7, 3, 6, 5, 10],
9723
+ [1, 9, 0, 5, 10, 6, 8, 4, 7],
9724
+ [10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4],
9725
+ [6, 1, 2, 6, 5, 1, 4, 7, 8],
9726
+ [1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7],
9727
+ [8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6],
9728
+ [7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9],
9729
+ [3, 11, 2, 7, 8, 4, 10, 6, 5],
9730
+ [5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11],
9731
+ [0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6],
9732
+ [9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6],
9733
+ [8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6],
9734
+ [5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11],
9735
+ [0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7],
9736
+ [6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9],
9737
+ [10, 4, 9, 6, 4, 10],
9738
+ [4, 10, 6, 4, 9, 10, 0, 8, 3],
9739
+ [10, 0, 1, 10, 6, 0, 6, 4, 0],
9740
+ [8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10],
9741
+ [1, 4, 9, 1, 2, 4, 2, 6, 4],
9742
+ [3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4],
9743
+ [0, 2, 4, 4, 2, 6],
9744
+ [8, 3, 2, 8, 2, 4, 4, 2, 6],
9745
+ [10, 4, 9, 10, 6, 4, 11, 2, 3],
9746
+ [0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6],
9747
+ [3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10],
9748
+ [6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1],
9749
+ [9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3],
9750
+ [8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1],
9751
+ [3, 11, 6, 3, 6, 0, 0, 6, 4],
9752
+ [6, 4, 8, 11, 6, 8],
9753
+ [7, 10, 6, 7, 8, 10, 8, 9, 10],
9754
+ [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10],
9755
+ [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0],
9756
+ [10, 6, 7, 10, 7, 1, 1, 7, 3],
9757
+ [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7],
9758
+ [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9],
9759
+ [7, 8, 0, 7, 0, 6, 6, 0, 2],
9760
+ [7, 3, 2, 6, 7, 2],
9761
+ [2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7],
9762
+ [2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7],
9763
+ [1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11],
9764
+ [11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1],
9765
+ [8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6],
9766
+ [0, 9, 1, 11, 6, 7],
9767
+ [7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0],
9768
+ [7, 11, 6],
9769
+ [7, 6, 11],
9770
+ [3, 0, 8, 11, 7, 6],
9771
+ [0, 1, 9, 11, 7, 6],
9772
+ [8, 1, 9, 8, 3, 1, 11, 7, 6],
9773
+ [10, 1, 2, 6, 11, 7],
9774
+ [1, 2, 10, 3, 0, 8, 6, 11, 7],
9775
+ [2, 9, 0, 2, 10, 9, 6, 11, 7],
9776
+ [6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8],
9777
+ [7, 2, 3, 6, 2, 7],
9778
+ [7, 0, 8, 7, 6, 0, 6, 2, 0],
9779
+ [2, 7, 6, 2, 3, 7, 0, 1, 9],
9780
+ [1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6],
9781
+ [10, 7, 6, 10, 1, 7, 1, 3, 7],
9782
+ [10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8],
9783
+ [0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7],
9784
+ [7, 6, 10, 7, 10, 8, 8, 10, 9],
9785
+ [6, 8, 4, 11, 8, 6],
9786
+ [3, 6, 11, 3, 0, 6, 0, 4, 6],
9787
+ [8, 6, 11, 8, 4, 6, 9, 0, 1],
9788
+ [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6],
9789
+ [6, 8, 4, 6, 11, 8, 2, 10, 1],
9790
+ [1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6],
9791
+ [4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9],
9792
+ [10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3],
9793
+ [8, 2, 3, 8, 4, 2, 4, 6, 2],
9794
+ [0, 4, 2, 4, 6, 2],
9795
+ [1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8],
9796
+ [1, 9, 4, 1, 4, 2, 2, 4, 6],
9797
+ [8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1],
9798
+ [10, 1, 0, 10, 0, 6, 6, 0, 4],
9799
+ [4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3],
9800
+ [10, 9, 4, 6, 10, 4],
9801
+ [4, 9, 5, 7, 6, 11],
9802
+ [0, 8, 3, 4, 9, 5, 11, 7, 6],
9803
+ [5, 0, 1, 5, 4, 0, 7, 6, 11],
9804
+ [11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5],
9805
+ [9, 5, 4, 10, 1, 2, 7, 6, 11],
9806
+ [6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5],
9807
+ [7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2],
9808
+ [3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6],
9809
+ [7, 2, 3, 7, 6, 2, 5, 4, 9],
9810
+ [9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7],
9811
+ [3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0],
9812
+ [6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8],
9813
+ [9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7],
9814
+ [1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4],
9815
+ [4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10],
9816
+ [7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10],
9817
+ [6, 9, 5, 6, 11, 9, 11, 8, 9],
9818
+ [3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5],
9819
+ [0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11],
9820
+ [6, 11, 3, 6, 3, 5, 5, 3, 1],
9821
+ [1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6],
9822
+ [0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10],
9823
+ [11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5],
9824
+ [6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3],
9825
+ [5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2],
9826
+ [9, 5, 6, 9, 6, 0, 0, 6, 2],
9827
+ [1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8],
9828
+ [1, 5, 6, 2, 1, 6],
9829
+ [1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6],
9830
+ [10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0],
9831
+ [0, 3, 8, 5, 6, 10],
9832
+ [10, 5, 6],
9833
+ [11, 5, 10, 7, 5, 11],
9834
+ [11, 5, 10, 11, 7, 5, 8, 3, 0],
9835
+ [5, 11, 7, 5, 10, 11, 1, 9, 0],
9836
+ [10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1],
9837
+ [11, 1, 2, 11, 7, 1, 7, 5, 1],
9838
+ [0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11],
9839
+ [9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7],
9840
+ [7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2],
9841
+ [2, 5, 10, 2, 3, 5, 3, 7, 5],
9842
+ [8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5],
9843
+ [9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2],
9844
+ [9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2],
9845
+ [1, 3, 5, 3, 7, 5],
9846
+ [0, 8, 7, 0, 7, 1, 1, 7, 5],
9847
+ [9, 0, 3, 9, 3, 5, 5, 3, 7],
9848
+ [9, 8, 7, 5, 9, 7],
9849
+ [5, 8, 4, 5, 10, 8, 10, 11, 8],
9850
+ [5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0],
9851
+ [0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5],
9852
+ [10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4],
9853
+ [2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8],
9854
+ [0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11],
9855
+ [0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5],
9856
+ [9, 4, 5, 2, 11, 3],
9857
+ [2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4],
9858
+ [5, 10, 2, 5, 2, 4, 4, 2, 0],
9859
+ [3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9],
9860
+ [5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2],
9861
+ [8, 4, 5, 8, 5, 3, 3, 5, 1],
9862
+ [0, 4, 5, 1, 0, 5],
9863
+ [8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5],
9864
+ [9, 4, 5],
9865
+ [4, 11, 7, 4, 9, 11, 9, 10, 11],
9866
+ [0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11],
9867
+ [1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11],
9868
+ [3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4],
9869
+ [4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2],
9870
+ [9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3],
9871
+ [11, 7, 4, 11, 4, 2, 2, 4, 0],
9872
+ [11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4],
9873
+ [2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9],
9874
+ [9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7],
9875
+ [3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10],
9876
+ [1, 10, 2, 8, 7, 4],
9877
+ [4, 9, 1, 4, 1, 7, 7, 1, 3],
9878
+ [4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1],
9879
+ [4, 0, 3, 7, 4, 3],
9880
+ [4, 8, 7],
9881
+ [9, 10, 8, 10, 11, 8],
9882
+ [3, 0, 9, 3, 9, 11, 11, 9, 10],
9883
+ [0, 1, 10, 0, 10, 8, 8, 10, 11],
9884
+ [3, 1, 10, 11, 3, 10],
9885
+ [1, 2, 11, 1, 11, 9, 9, 11, 8],
9886
+ [3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9],
9887
+ [0, 2, 11, 8, 0, 11],
9888
+ [3, 2, 11],
9889
+ [2, 3, 8, 2, 8, 10, 10, 8, 9],
9890
+ [9, 10, 2, 0, 9, 2],
9891
+ [2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8],
9892
+ [1, 10, 2],
9893
+ [1, 3, 8, 9, 1, 8],
9894
+ [0, 9, 1],
9895
+ [0, 3, 8],
9896
+ []
9897
+ ];
9898
+
8531
9899
  // ============================================================================
8532
9900
  // Edge mask constants for 4x4x4 voxel blocks
8533
9901
  // ============================================================================
@@ -8797,9 +10165,10 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
8797
10165
  * Voxelizes Gaussian splat data and writes the result as a sparse voxel octree.
8798
10166
  *
8799
10167
  * This function performs GPU-accelerated voxelization of Gaussian splat data
8800
- * and outputs two files:
10168
+ * and outputs two or three files:
8801
10169
  * - `filename` (.voxel.json) - JSON metadata including bounds, resolution, and array sizes
8802
10170
  * - Corresponding .voxel.bin - Binary octree data (nodes + leafData as Uint32 arrays)
10171
+ * - Corresponding .collision.glb - Triangle mesh extracted via marching cubes (GLB format, optional)
8803
10172
  *
8804
10173
  * The binary file layout is:
8805
10174
  * - Bytes 0 to (nodeCount * 4 - 1): nodes array (Uint32, little-endian)
@@ -8818,16 +10187,17 @@ const writeOctreeFiles = async (fs, jsonFilename, octree) => {
8818
10187
  * dataTable: myDataTable,
8819
10188
  * voxelResolution: 0.05,
8820
10189
  * opacityCutoff: 0.5,
10190
+ * collisionMesh: true,
8821
10191
  * createDevice: async () => myGraphicsDevice
8822
10192
  * }, fs);
8823
10193
  * ```
8824
10194
  */
8825
10195
  const writeVoxel = async (options, fs) => {
8826
- const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice } = options;
10196
+ const { filename, dataTable, voxelResolution = 0.05, opacityCutoff = 0.5, createDevice, collisionMesh = false, meshSimplify = 0.25 } = options;
8827
10197
  if (!createDevice) {
8828
10198
  throw new Error('writeVoxel requires a createDevice function for GPU voxelization');
8829
10199
  }
8830
- logger.progress.begin(4);
10200
+ logger.progress.begin(collisionMesh ? 7 : 5);
8831
10201
  const extentsResult = computeGaussianExtents(dataTable);
8832
10202
  const bounds = extentsResult.sceneBounds;
8833
10203
  logger.progress.step('Building BVH');
@@ -8999,10 +10369,61 @@ const writeVoxel = async (options, fs) => {
8999
10369
  gpuVoxelization.destroy();
9000
10370
  logger.progress.step('Filtering');
9001
10371
  accumulator = filterAndFillBlocks(accumulator);
10372
+ let glbBytes = null;
10373
+ if (collisionMesh) {
10374
+ logger.progress.step('Extracting collision mesh');
10375
+ const rawMesh = marchingCubes(accumulator, gridBounds, voxelResolution);
10376
+ logger.log(`collision mesh (raw): ${rawMesh.positions.length / 3} vertices, ${rawMesh.indices.length / 3} triangles`);
10377
+ if (rawMesh.indices.length < 3) {
10378
+ logger.progress.step('Simplifying collision mesh');
10379
+ logger.log('collision mesh: no triangles generated, skipping GLB output');
10380
+ }
10381
+ else {
10382
+ logger.progress.step('Simplifying collision mesh');
10383
+ await MeshoptSimplifier.ready;
10384
+ const clampedSimplify = Number.isFinite(meshSimplify) ? Math.min(1, Math.max(0, meshSimplify)) : 0.25;
10385
+ const targetIndexCount = Math.max(3, Math.min(rawMesh.indices.length, Math.floor(rawMesh.indices.length * clampedSimplify / 3) * 3));
10386
+ const [simplifiedIndices] = MeshoptSimplifier.simplify(rawMesh.indices, rawMesh.positions, 3, targetIndexCount, voxelResolution, ['ErrorAbsolute']);
10387
+ const vertexRemap = new Map();
10388
+ let newVertexCount = 0;
10389
+ for (let i = 0; i < simplifiedIndices.length; i++) {
10390
+ if (!vertexRemap.has(simplifiedIndices[i])) {
10391
+ vertexRemap.set(simplifiedIndices[i], newVertexCount++);
10392
+ }
10393
+ }
10394
+ const compactPositions = new Float32Array(newVertexCount * 3);
10395
+ for (const [oldIdx, newIdx] of vertexRemap) {
10396
+ compactPositions[newIdx * 3] = rawMesh.positions[oldIdx * 3];
10397
+ compactPositions[newIdx * 3 + 1] = rawMesh.positions[oldIdx * 3 + 1];
10398
+ compactPositions[newIdx * 3 + 2] = rawMesh.positions[oldIdx * 3 + 2];
10399
+ }
10400
+ const compactIndices = new Uint32Array(simplifiedIndices.length);
10401
+ for (let i = 0; i < simplifiedIndices.length; i++) {
10402
+ compactIndices[i] = vertexRemap.get(simplifiedIndices[i]);
10403
+ }
10404
+ const reduction = (1 - simplifiedIndices.length / rawMesh.indices.length) * 100;
10405
+ logger.log(`collision mesh (simplified): ${newVertexCount} vertices, ${simplifiedIndices.length / 3} triangles (${reduction.toFixed(0)}% reduction)`);
10406
+ glbBytes = buildCollisionGlb(compactPositions, compactIndices);
10407
+ }
10408
+ }
10409
+ logger.progress.step('Building octree');
9002
10410
  const octree = buildSparseOctree(accumulator, gridBounds, bounds, // Original scene bounds
9003
10411
  voxelResolution);
10412
+ logger.log(`octree: depth=${octree.treeDepth}, interior=${octree.numInteriorNodes}, mixed=${octree.numMixedLeaves}`);
9004
10413
  logger.progress.step('Writing');
9005
10414
  await writeOctreeFiles(fs, filename, octree);
10415
+ if (glbBytes) {
10416
+ const glbFilename = filename.replace('.voxel.json', '.collision.glb');
10417
+ logger.log(`writing '${glbFilename}'...`);
10418
+ await writeFile$1(fs, glbFilename, glbBytes);
10419
+ }
10420
+ const totalBytes = (octree.nodes.length + octree.leafData.length) * 4;
10421
+ if (glbBytes) {
10422
+ logger.log(`total size: octree ${(totalBytes / 1024).toFixed(1)} KB, collision mesh ${(glbBytes.length / 1024).toFixed(1)} KB`);
10423
+ }
10424
+ else {
10425
+ logger.log(`total size: ${(totalBytes / 1024).toFixed(1)} KB`);
10426
+ }
9006
10427
  };
9007
10428
 
9008
10429
  /**
@@ -9135,6 +10556,8 @@ const writeFile = async (writeOptions, fs) => {
9135
10556
  dataTable,
9136
10557
  voxelResolution: options.voxelResolution,
9137
10558
  opacityCutoff: options.opacityCutoff,
10559
+ collisionMesh: options.collisionMesh,
10560
+ meshSimplify: options.meshSimplify,
9138
10561
  createDevice
9139
10562
  }, fs);
9140
10563
  break;
@@ -9403,6 +10826,7 @@ exports.computeSummary = computeSummary;
9403
10826
  exports.getInputFormat = getInputFormat;
9404
10827
  exports.getOutputFormat = getOutputFormat;
9405
10828
  exports.logger = logger;
10829
+ exports.marchingCubes = marchingCubes;
9406
10830
  exports.processDataTable = processDataTable;
9407
10831
  exports.readFile = readFile;
9408
10832
  exports.readKsplat = readKsplat;