@adatechnology/game-vehicles 0.4.4 → 0.4.6

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.
@@ -580,12 +580,12 @@ var GameVehicles = (() => {
580
580
  return triangles;
581
581
  }
582
582
  };
583
- function linkedList(data, start, end, dim, clockwise) {
583
+ function linkedList(data, start2, end, dim, clockwise) {
584
584
  let i, last;
585
- if (clockwise === signedArea(data, start, end, dim) > 0) {
586
- for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
585
+ if (clockwise === signedArea(data, start2, end, dim) > 0) {
586
+ for (i = start2; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
587
587
  } else {
588
- for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
588
+ for (i = end - dim; i >= start2; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
589
589
  }
590
590
  if (last && equals(last, last.next)) {
591
591
  removeNode(last);
@@ -593,10 +593,10 @@ var GameVehicles = (() => {
593
593
  }
594
594
  return last;
595
595
  }
596
- function filterPoints(start, end) {
597
- if (!start) return start;
598
- if (!end) end = start;
599
- let p = start, again;
596
+ function filterPoints(start2, end) {
597
+ if (!start2) return start2;
598
+ if (!end) end = start2;
599
+ let p = start2, again;
600
600
  do {
601
601
  again = false;
602
602
  if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
@@ -675,8 +675,8 @@ var GameVehicles = (() => {
675
675
  }
676
676
  return true;
677
677
  }
678
- function cureLocalIntersections(start, triangles, dim) {
679
- let p = start;
678
+ function cureLocalIntersections(start2, triangles, dim) {
679
+ let p = start2;
680
680
  do {
681
681
  const a = p.prev, b = p.next.next;
682
682
  if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
@@ -685,14 +685,14 @@ var GameVehicles = (() => {
685
685
  triangles.push(b.i / dim | 0);
686
686
  removeNode(p);
687
687
  removeNode(p.next);
688
- p = start = b;
688
+ p = start2 = b;
689
689
  }
690
690
  p = p.next;
691
- } while (p !== start);
691
+ } while (p !== start2);
692
692
  return filterPoints(p);
693
693
  }
694
- function splitEarcut(start, triangles, dim, minX, minY, invSize) {
695
- let a = start;
694
+ function splitEarcut(start2, triangles, dim, minX, minY, invSize) {
695
+ let a = start2;
696
696
  do {
697
697
  let b = a.next.next;
698
698
  while (b !== a.prev) {
@@ -707,15 +707,15 @@ var GameVehicles = (() => {
707
707
  b = b.next;
708
708
  }
709
709
  a = a.next;
710
- } while (a !== start);
710
+ } while (a !== start2);
711
711
  }
712
712
  function eliminateHoles(data, holeIndices, outerNode, dim) {
713
713
  const queue = [];
714
- let i, len, start, end, list2;
714
+ let i, len, start2, end, list2;
715
715
  for (i = 0, len = holeIndices.length; i < len; i++) {
716
- start = holeIndices[i] * dim;
716
+ start2 = holeIndices[i] * dim;
717
717
  end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
718
- list2 = linkedList(data, start, end, dim, false);
718
+ list2 = linkedList(data, start2, end, dim, false);
719
719
  if (list2 === list2.next) list2.steiner = true;
720
720
  queue.push(getLeftmost(list2));
721
721
  }
@@ -770,14 +770,14 @@ var GameVehicles = (() => {
770
770
  function sectorContainsSector(m, p) {
771
771
  return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
772
772
  }
773
- function indexCurve(start, minX, minY, invSize) {
774
- let p = start;
773
+ function indexCurve(start2, minX, minY, invSize) {
774
+ let p = start2;
775
775
  do {
776
776
  if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
777
777
  p.prevZ = p.prev;
778
778
  p.nextZ = p.next;
779
779
  p = p.next;
780
- } while (p !== start);
780
+ } while (p !== start2);
781
781
  p.prevZ.nextZ = null;
782
782
  p.prevZ = null;
783
783
  sortLinked(p);
@@ -834,12 +834,12 @@ var GameVehicles = (() => {
834
834
  y = (y | y << 1) & 1431655765;
835
835
  return x | y << 1;
836
836
  }
837
- function getLeftmost(start) {
838
- let p = start, leftmost = start;
837
+ function getLeftmost(start2) {
838
+ let p = start2, leftmost = start2;
839
839
  do {
840
840
  if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
841
841
  p = p.next;
842
- } while (p !== start);
842
+ } while (p !== start2);
843
843
  return leftmost;
844
844
  }
845
845
  function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
@@ -938,9 +938,9 @@ var GameVehicles = (() => {
938
938
  this.nextZ = null;
939
939
  this.steiner = false;
940
940
  }
941
- function signedArea(data, start, end, dim) {
941
+ function signedArea(data, start2, end, dim) {
942
942
  let sum = 0;
943
- for (let i = start, j = end - dim; i < end; i += dim) {
943
+ for (let i = start2, j = end - dim; i < end; i += dim) {
944
944
  sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
945
945
  j = i;
946
946
  }
@@ -1197,7 +1197,7 @@ var GameVehicles = (() => {
1197
1197
  const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)];
1198
1198
  for (const k of [0, 1, 3, 1, 2, 3]) addUV(...uvs[k]);
1199
1199
  };
1200
- let start = verticesArray.length / 3;
1200
+ let start2 = verticesArray.length / 3;
1201
1201
  if (bevelEnabled) {
1202
1202
  let offset = 0;
1203
1203
  for (let i = 0; i < flen; i++) {
@@ -1220,8 +1220,8 @@ var GameVehicles = (() => {
1220
1220
  f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps);
1221
1221
  }
1222
1222
  }
1223
- groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 0 });
1224
- start = verticesArray.length / 3;
1223
+ groups.push({ start: start2, count: verticesArray.length / 3 - start2, materialIndex: 0 });
1224
+ start2 = verticesArray.length / 3;
1225
1225
  const sidewalls = (ring2, layeroffset2) => {
1226
1226
  let i = ring2.length;
1227
1227
  while (--i >= 0) {
@@ -1242,7 +1242,7 @@ var GameVehicles = (() => {
1242
1242
  sidewalls(ahole, layeroffset);
1243
1243
  layeroffset += ahole.length;
1244
1244
  }
1245
- groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 1 });
1245
+ groups.push({ start: start2, count: verticesArray.length / 3 - start2, materialIndex: 1 });
1246
1246
  const positions = new Float32Array(verticesArray);
1247
1247
  return { type: "ExtrudeGeometry", parameters, positions, normals: computeVertexNormals(positions), uvs: new Float32Array(uvArray), groups };
1248
1248
  }
@@ -1518,8 +1518,8 @@ var GameVehicles = (() => {
1518
1518
  var shims = /* @__PURE__ */ new WeakSet();
1519
1519
  function shapeGeometries(THREE, options = {}) {
1520
1520
  if (shims.has(THREE)) return THREE;
1521
- const cache = options.cache !== false;
1522
- const key = cache ? "cache" : "nocache";
1521
+ const cache2 = options.cache !== false;
1522
+ const key = cache2 ? "cache" : "nocache";
1523
1523
  let byKey = namespaces.get(THREE);
1524
1524
  if (!byKey) {
1525
1525
  byKey = /* @__PURE__ */ new Map();
@@ -1528,7 +1528,7 @@ var GameVehicles = (() => {
1528
1528
  const existing = byKey.get(key);
1529
1529
  if (existing) return existing;
1530
1530
  const made = (p) => toGeometry(THREE, p);
1531
- const viaCache = (node, direct) => cache ? buildPrimitive(node) : direct();
1531
+ const viaCache = (node, direct) => cache2 ? buildPrimitive(node) : direct();
1532
1532
  const defined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1533
1533
  const constructors = {
1534
1534
  BoxGeometry: (width, height, depth, ws = 1, hs = 1, ds = 1) => made(viaCache({ kind: "box", size: [width ?? 1, height ?? 1, depth ?? 1], segments: [ws, hs, ds] }, () => box(width, height, depth, ws, hs, ds))),
@@ -2224,7 +2224,7 @@ var GameVehicles = (() => {
2224
2224
  const I = kit._;
2225
2225
  const document2 = kit.document;
2226
2226
  const RUST = new THREE.Color("#5e3220");
2227
- const cache = {};
2227
+ const cache2 = {};
2228
2228
  let envTex = null;
2229
2229
  function studioEnvironment() {
2230
2230
  if (envTex) return envTex;
@@ -2269,7 +2269,7 @@ var GameVehicles = (() => {
2269
2269
  const key = "s" + c.getHexString() + JSON.stringify(o, function(k, v) {
2270
2270
  return v && v.isColor ? "#" + v.getHexString() : v && v.isTexture ? v.uuid : v;
2271
2271
  });
2272
- if (!cache[key]) {
2272
+ if (!cache2[key]) {
2273
2273
  const o2 = Object.assign({}, o);
2274
2274
  delete o2.noEnv;
2275
2275
  const mt = new THREE.MeshStandardMaterial(Object.assign({ color: c, roughness: 0.8, metalness: 0, flatShading: false }, o2));
@@ -2277,9 +2277,9 @@ var GameVehicles = (() => {
2277
2277
  mt.envMap = studioEnvironment();
2278
2278
  if (o.envMapIntensity == null) mt.envMapIntensity = 0.55 + (mt.metalness - 0.6) * 1.6;
2279
2279
  }
2280
- cache[key] = mt;
2280
+ cache2[key] = mt;
2281
2281
  }
2282
- return cache[key];
2282
+ return cache2[key];
2283
2283
  }
2284
2284
  function makeFlatMaterial(color2, o) {
2285
2285
  return makeMaterial(color2, Object.assign({ flatShading: true, roughness: 0.92 }, o || {}));
@@ -2394,7 +2394,131 @@ var GameVehicles = (() => {
2394
2394
  return t;
2395
2395
  }
2396
2396
  kit.textTexture = textTexture;
2397
- Object.assign(I, { RUST, cache, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE, toColor, MATERIALS, paintColor, texCache, textTexture });
2397
+ Object.assign(I, { RUST, cache: cache2, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE, toColor, MATERIALS, paintColor, texCache, textTexture });
2398
+ }
2399
+
2400
+ // src/tri-index.ts
2401
+ var TRI_BLOCK = 32;
2402
+ var cache = /* @__PURE__ */ new WeakMap();
2403
+ function trianglesOf(geo) {
2404
+ return Math.floor((geo.index ? geo.index.count : geo.attributes.position.count) / 3);
2405
+ }
2406
+ function supports(geo) {
2407
+ const pos = geo.attributes && geo.attributes.position;
2408
+ return !!pos && !pos.isInterleavedBufferAttribute && pos.itemSize === 3;
2409
+ }
2410
+ function isCurrent(geo, ti) {
2411
+ const pos = geo.attributes.position;
2412
+ return ti.position === pos && ti.positionVersion === pos.version && ti.index === (geo.index || null) && ti.indexVersion === (geo.index ? geo.index.version : 0) && ti.triangles === trianglesOf(geo);
2413
+ }
2414
+ function blockCount(triangles) {
2415
+ return Math.ceil(triangles / TRI_BLOCK);
2416
+ }
2417
+ function boxBlock(ti, block) {
2418
+ const B = ti.boxes;
2419
+ const t0 = block * TRI_BLOCK;
2420
+ const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
2421
+ const o = block * 6;
2422
+ for (let k = 0; k < 3; k++) {
2423
+ ti.blocks[o + k] = Infinity;
2424
+ ti.blocks[o + 3 + k] = -Infinity;
2425
+ }
2426
+ for (let t = t0; t < t1; t++) {
2427
+ const j = t * 6;
2428
+ for (let k = 0; k < 3; k++) {
2429
+ if (B[j + k] < ti.blocks[o + k]) ti.blocks[o + k] = B[j + k];
2430
+ if (B[j + 3 + k] > ti.blocks[o + 3 + k]) ti.blocks[o + 3 + k] = B[j + 3 + k];
2431
+ }
2432
+ }
2433
+ }
2434
+ function boxTriangle(geo, ti, t) {
2435
+ const P = geo.attributes.position.array;
2436
+ const ix = geo.index ? geo.index.array : null;
2437
+ const a = (ix ? ix[t * 3] : t * 3) * 3;
2438
+ const b = (ix ? ix[t * 3 + 1] : t * 3 + 1) * 3;
2439
+ const c = (ix ? ix[t * 3 + 2] : t * 3 + 2) * 3;
2440
+ const j = t * 6;
2441
+ for (let k = 0; k < 3; k++) {
2442
+ ti.boxes[j + k] = Math.min(P[a + k], P[b + k], P[c + k]);
2443
+ ti.boxes[j + 3 + k] = Math.max(P[a + k], P[b + k], P[c + k]);
2444
+ }
2445
+ }
2446
+ function advance(geo, ti, deadline) {
2447
+ const total = blockCount(ti.triangles);
2448
+ while (ti.builtBlocks < total) {
2449
+ const block = ti.builtBlocks;
2450
+ const t1 = Math.min(ti.triangles, (block + 1) * TRI_BLOCK);
2451
+ for (let t = block * TRI_BLOCK; t < t1; t++) boxTriangle(geo, ti, t);
2452
+ boxBlock(ti, block);
2453
+ ti.builtBlocks++;
2454
+ if (deadline !== Infinity && performance.now() >= deadline) break;
2455
+ }
2456
+ return ti.builtBlocks === total;
2457
+ }
2458
+ function start(geo) {
2459
+ const pos = geo.attributes.position;
2460
+ const triangles = trianglesOf(geo);
2461
+ const ti = {
2462
+ position: pos,
2463
+ positionVersion: pos.version,
2464
+ index: geo.index || null,
2465
+ indexVersion: geo.index ? geo.index.version : 0,
2466
+ triangles,
2467
+ boxes: new Float64Array(triangles * 6),
2468
+ blocks: new Float64Array(blockCount(triangles) * 6),
2469
+ builtBlocks: 0
2470
+ };
2471
+ cache.set(geo, ti);
2472
+ return ti;
2473
+ }
2474
+ function triIndexOf(geo) {
2475
+ if (!supports(geo)) return void 0;
2476
+ let ti = cache.get(geo);
2477
+ if (!ti || !isCurrent(geo, ti)) ti = start(geo);
2478
+ advance(geo, ti, Infinity);
2479
+ return ti;
2480
+ }
2481
+ function warmTriIndex(geo, deadline) {
2482
+ if (!supports(geo)) return true;
2483
+ let ti = cache.get(geo);
2484
+ if (!ti || !isCurrent(geo, ti)) ti = start(geo);
2485
+ return advance(geo, ti, deadline);
2486
+ }
2487
+ function storeTriIndex(geo, boxes) {
2488
+ const ti = start(geo);
2489
+ ti.boxes = boxes;
2490
+ const total = blockCount(ti.triangles);
2491
+ for (let b = 0; b < total; b++) boxBlock(ti, b);
2492
+ ti.builtBlocks = total;
2493
+ }
2494
+ function liveTriIndex(geo) {
2495
+ if (geo.index || !supports(geo)) return void 0;
2496
+ const ti = cache.get(geo);
2497
+ return ti && isCurrent(geo, ti) && ti.builtBlocks === blockCount(ti.triangles) ? ti : void 0;
2498
+ }
2499
+ function touchTriIndex(geo, ti, vertices) {
2500
+ if (ti.positionVersion + 1 !== geo.attributes.position.version) return;
2501
+ const blocks = /* @__PURE__ */ new Set();
2502
+ for (const v of vertices) {
2503
+ const t = Math.floor(v / 3);
2504
+ if (t >= ti.triangles) continue;
2505
+ boxTriangle(geo, ti, t);
2506
+ blocks.add(Math.floor(t / TRI_BLOCK));
2507
+ }
2508
+ blocks.forEach((b) => boxBlock(ti, b));
2509
+ ti.positionVersion = geo.attributes.position.version;
2510
+ }
2511
+ function boundsFromIndex(geo) {
2512
+ if (geo.index || !supports(geo)) return void 0;
2513
+ const ti = cache.get(geo);
2514
+ if (!ti || !isCurrent(geo, ti) || ti.builtBlocks !== blockCount(ti.triangles) || !ti.triangles || geo.attributes.position.count !== ti.triangles * 3) return void 0;
2515
+ const box2 = new Float64Array([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
2516
+ for (let b = 0, n = blockCount(ti.triangles); b < n; b++)
2517
+ for (let k = 0; k < 3; k++) {
2518
+ box2[k] = Math.min(box2[k], ti.blocks[b * 6 + k]);
2519
+ box2[3 + k] = Math.max(box2[3 + k], ti.blocks[b * 6 + 3 + k]);
2520
+ }
2521
+ return { box: box2, version: ti.positionVersion };
2398
2522
  }
2399
2523
 
2400
2524
  // src/geometry.ts
@@ -2491,7 +2615,8 @@ var GameVehicles = (() => {
2491
2615
  g.userData.crease = true;
2492
2616
  return g;
2493
2617
  }
2494
- function crease(geo, deg) {
2618
+ const latestCrease = /* @__PURE__ */ new WeakMap();
2619
+ function creaseTask(geo, deg) {
2495
2620
  if (geo.index) {
2496
2621
  const ni = geo.toNonIndexed();
2497
2622
  Object.keys(ni.attributes).forEach(function(k) {
@@ -2499,30 +2624,22 @@ var GameVehicles = (() => {
2499
2624
  });
2500
2625
  geo.setIndex(null);
2501
2626
  }
2502
- const p = geo.attributes.position;
2503
- const n = p.count;
2627
+ const P = geo.attributes.position.array;
2628
+ const n = geo.attributes.position.count;
2504
2629
  const faces = n / 3;
2505
2630
  const FN = new Float64Array(faces * 3);
2506
- const map = /* @__PURE__ */ new Map();
2507
- const RANGE = 65536;
2508
- function key(i) {
2509
- const x = Math.round(p.getX(i) * 2e3);
2510
- const y = Math.round(p.getY(i) * 2e3);
2511
- const z = Math.round(p.getZ(i) * 2e3);
2512
- if (Math.abs(x) < RANGE && Math.abs(y) < RANGE && Math.abs(z) < RANGE) return ((x + RANGE) * 131072 + (y + RANGE)) * 131072 + (z + RANGE);
2513
- return x + "," + y + "," + z;
2514
- }
2515
- const keys = new Array(n);
2631
+ const out = new Float32Array(n * 3);
2516
2632
  for (let f = 0; f < faces; f++) {
2517
- const ax = p.getX(3 * f);
2518
- const ay = p.getY(3 * f);
2519
- const az = p.getZ(3 * f);
2520
- const bx = p.getX(3 * f + 1);
2521
- const by = p.getY(3 * f + 1);
2522
- const bz = p.getZ(3 * f + 1);
2523
- const cx = p.getX(3 * f + 2);
2524
- const cy = p.getY(3 * f + 2);
2525
- const cz = p.getZ(3 * f + 2);
2633
+ const o = 9 * f;
2634
+ const ax = P[o];
2635
+ const ay = P[o + 1];
2636
+ const az = P[o + 2];
2637
+ const bx = P[o + 3];
2638
+ const by = P[o + 4];
2639
+ const bz = P[o + 5];
2640
+ const cx = P[o + 6];
2641
+ const cy = P[o + 7];
2642
+ const cz = P[o + 8];
2526
2643
  const e1x = cx - bx;
2527
2644
  const e1y = cy - by;
2528
2645
  const e1z = cz - bz;
@@ -2542,41 +2659,109 @@ var GameVehicles = (() => {
2542
2659
  FN[3 * f + 1] = ny;
2543
2660
  FN[3 * f + 2] = nz;
2544
2661
  for (let k = 0; k < 3; k++) {
2545
- const kk = key(3 * f + k);
2546
- keys[3 * f + k] = kk;
2547
- const list2 = map.get(kk);
2548
- if (list2) list2.push(f);
2549
- else map.set(kk, [f]);
2662
+ out[9 * f + 3 * k] = nx;
2663
+ out[9 * f + 3 * k + 1] = ny;
2664
+ out[9 * f + 3 * k + 2] = nz;
2665
+ }
2666
+ }
2667
+ const normal = new THREE.BufferAttribute(out, 3);
2668
+ geo.setAttribute("normal", normal);
2669
+ const token = {};
2670
+ latestCrease.set(geo, token);
2671
+ let size = 16;
2672
+ while (size < n * 2) size *= 2;
2673
+ const mask = size - 1;
2674
+ const slot = new Int32Array(size).fill(-1);
2675
+ const gx = new Int32Array(n);
2676
+ const gy = new Int32Array(n);
2677
+ const gz = new Int32Array(n);
2678
+ const groupOf = new Int32Array(n);
2679
+ let groups = 0;
2680
+ let start2;
2681
+ let members;
2682
+ const cs = Math.cos(deg * PI / 180);
2683
+ let phase = 0;
2684
+ let at = 0;
2685
+ function hashSlice(deadline) {
2686
+ for (; at < n; at++) {
2687
+ if ((at & 1023) === 0 && performance.now() > deadline) return false;
2688
+ const x = Math.round(P[3 * at] * 2e3) | 0;
2689
+ const y = Math.round(P[3 * at + 1] * 2e3) | 0;
2690
+ const z = Math.round(P[3 * at + 2] * 2e3) | 0;
2691
+ let h = (Math.imul(x, 73856093) ^ Math.imul(y, 19349663) ^ Math.imul(z, 83492791)) & mask;
2692
+ let g = slot[h];
2693
+ while (g >= 0 && (gx[g] !== x || gy[g] !== y || gz[g] !== z)) {
2694
+ h = h + 1 & mask;
2695
+ g = slot[h];
2696
+ }
2697
+ if (g < 0) {
2698
+ g = groups++;
2699
+ slot[h] = g;
2700
+ gx[g] = x;
2701
+ gy[g] = y;
2702
+ gz[g] = z;
2703
+ }
2704
+ groupOf[at] = g;
2550
2705
  }
2706
+ return true;
2551
2707
  }
2552
- const cs = Math.cos(deg * PI / 180);
2553
- const out = new Float32Array(n * 3);
2554
- for (let i = 0; i < n; i++) {
2555
- const fi = (i / 3 | 0) * 3;
2556
- const list2 = map.get(keys[i]);
2557
- let sx = 0;
2558
- let sy = 0;
2559
- let sz = 0;
2560
- for (let j = 0; j < list2.length; j++) {
2561
- const g = list2[j] * 3;
2562
- if (FN[g] * FN[fi] + FN[g + 1] * FN[fi + 1] + FN[g + 2] * FN[fi + 2] >= cs) {
2563
- sx += FN[g];
2564
- sy += FN[g + 1];
2565
- sz += FN[g + 2];
2708
+ function gather() {
2709
+ start2 = new Int32Array(groups + 1);
2710
+ for (let i = 0; i < n; i++) start2[groupOf[i] + 1]++;
2711
+ for (let g = 0; g < groups; g++) start2[g + 1] += start2[g];
2712
+ const fill = start2.slice(0, groups);
2713
+ members = new Int32Array(n);
2714
+ for (let i = 0; i < n; i++) members[fill[groupOf[i]]++] = i / 3 | 0;
2715
+ }
2716
+ function smoothSlice(deadline) {
2717
+ for (; at < n; at++) {
2718
+ if ((at & 1023) === 0 && performance.now() > deadline) return false;
2719
+ const fi = (at / 3 | 0) * 3;
2720
+ const g = groupOf[at];
2721
+ let sx = 0;
2722
+ let sy = 0;
2723
+ let sz = 0;
2724
+ for (let j = start2[g], end = start2[g + 1]; j < end; j++) {
2725
+ const o = members[j] * 3;
2726
+ if (FN[o] * FN[fi] + FN[o + 1] * FN[fi + 1] + FN[o + 2] * FN[fi + 2] >= cs) {
2727
+ sx += FN[o];
2728
+ sy += FN[o + 1];
2729
+ sz += FN[o + 2];
2730
+ }
2731
+ }
2732
+ if (sx * sx + sy * sy + sz * sz < 1e-20) {
2733
+ sx = FN[fi];
2734
+ sy = FN[fi + 1];
2735
+ sz = FN[fi + 2];
2566
2736
  }
2737
+ const inv = 1 / (Math.sqrt(sx * sx + sy * sy + sz * sz) || 1);
2738
+ out[3 * at] = sx * inv;
2739
+ out[3 * at + 1] = sy * inv;
2740
+ out[3 * at + 2] = sz * inv;
2567
2741
  }
2568
- if (sx * sx + sy * sy + sz * sz < 1e-20) {
2569
- sx = FN[fi];
2570
- sy = FN[fi + 1];
2571
- sz = FN[fi + 2];
2742
+ return true;
2743
+ }
2744
+ function step(deadline) {
2745
+ if (latestCrease.get(geo) !== token) return true;
2746
+ if (phase === 0) {
2747
+ if (!hashSlice(deadline)) return false;
2748
+ gather();
2749
+ phase = 1;
2750
+ at = 0;
2751
+ }
2752
+ if (phase === 1) {
2753
+ const done = smoothSlice(deadline);
2754
+ if (deadline !== Infinity) normal.needsUpdate = true;
2755
+ if (!done) return false;
2756
+ phase = 2;
2757
+ geo.userData.crease = true;
2572
2758
  }
2573
- const inv = 1 / (Math.sqrt(sx * sx + sy * sy + sz * sz) || 1);
2574
- out[3 * i] = sx * inv;
2575
- out[3 * i + 1] = sy * inv;
2576
- out[3 * i + 2] = sz * inv;
2759
+ return true;
2577
2760
  }
2578
- geo.setAttribute("normal", new THREE.BufferAttribute(out, 3));
2579
- geo.userData.crease = true;
2761
+ return { geo, step };
2762
+ }
2763
+ function crease(geo, deg) {
2764
+ creaseTask(geo, deg).step(Infinity);
2580
2765
  return geo;
2581
2766
  }
2582
2767
  function pathShape(items) {
@@ -2723,28 +2908,28 @@ var GameVehicles = (() => {
2723
2908
  return g;
2724
2909
  }
2725
2910
  function cutGeometry(geo, tests) {
2726
- const src = geo.index ? geo.toNonIndexed() : geo;
2911
+ const idx = geo.index ? geo.index.array : null;
2727
2912
  const names = ["position"].concat(
2728
2913
  ["color", "uv"].filter(function(n2) {
2729
- return !!src.attributes[n2];
2914
+ return !!geo.attributes[n2];
2730
2915
  })
2731
2916
  );
2732
2917
  const sizes = names.map(function(n2) {
2733
- return src.attributes[n2].itemSize;
2918
+ return geo.attributes[n2].itemSize;
2734
2919
  });
2735
2920
  const arrs = names.map(function(n2) {
2736
- return src.attributes[n2].array;
2921
+ return geo.attributes[n2].array;
2737
2922
  });
2738
- const nv = src.attributes.position.count;
2739
- let tris = [];
2740
- for (let f = 0; f < nv; f += 3) {
2923
+ const nv = idx ? idx.length : geo.attributes.position.count;
2924
+ function readTri(f) {
2741
2925
  const t = [];
2742
2926
  for (let k = 0; k < 3; k++) {
2927
+ const vi = idx ? idx[f + k] : f + k;
2743
2928
  const v = [];
2744
- for (let a = 0; a < names.length; a++) for (let q = 0; q < sizes[a]; q++) v.push(arrs[a][(f + k) * sizes[a] + q]);
2929
+ for (let a = 0; a < names.length; a++) for (let q = 0; q < sizes[a]; q++) v.push(arrs[a][vi * sizes[a] + q]);
2745
2930
  t.push(v);
2746
2931
  }
2747
- tris.push(t);
2932
+ return t;
2748
2933
  }
2749
2934
  const cut = {};
2750
2935
  const n = new V3();
@@ -2770,60 +2955,177 @@ var GameVehicles = (() => {
2770
2955
  function fan(poly, arr) {
2771
2956
  for (let i = 1; i < poly.length - 1; i++) arr.push([poly[0], poly[i], poly[i + 1]]);
2772
2957
  }
2773
- tests.forEach(function(T) {
2774
- const next = [];
2958
+ function testTri(T, t, next, rem) {
2959
+ const A = t[0];
2960
+ const B = t[1];
2961
+ const C = t[2];
2962
+ e1.set(B[0] - A[0], B[1] - A[1], B[2] - A[2]);
2963
+ e2.set(C[0] - A[0], C[1] - A[1], C[2] - A[2]);
2964
+ n.crossVectors(e1, e2);
2965
+ const len = n.length();
2966
+ if (len < 1e-12) {
2967
+ next.push(t);
2968
+ return;
2969
+ }
2970
+ n.multiplyScalar(1 / len);
2971
+ ce.set((A[0] + B[0] + C[0]) / 3, (A[1] + B[1] + C[1]) / 3, (A[2] + B[2] + C[2]) / 3);
2972
+ if (T.sel && !T.sel(n, ce)) {
2973
+ next.push(t);
2974
+ return;
2975
+ }
2976
+ const d = [T.sdf(A[0], A[1], A[2]), T.sdf(B[0], B[1], B[2]), T.sdf(C[0], C[1], C[2])];
2977
+ const ins = (d[0] < 0 ? 1 : 0) + (d[1] < 0 ? 1 : 0) + (d[2] < 0 ? 1 : 0);
2978
+ if (ins === 0) next.push(t);
2979
+ else if (ins === 3) {
2980
+ if (rem) rem.push(t);
2981
+ } else {
2982
+ fan(clip(t, d, 1), next);
2983
+ if (rem) fan(clip(t, d, -1), rem);
2984
+ }
2985
+ }
2986
+ const segments = [];
2987
+ let total = 0;
2988
+ const ti = tests.length === 1 && tests[0].bounds ? triIndexOf(geo) : void 0;
2989
+ if (ti) {
2990
+ const T = tests[0];
2991
+ const lo = T.bounds.lo;
2992
+ const hi = T.bounds.hi;
2775
2993
  const rem = T.tag ? cut[T.tag] = cut[T.tag] || [] : null;
2776
- tris.forEach(function(t) {
2777
- const A = t[0];
2778
- const B = t[1];
2779
- const C = t[2];
2780
- e1.set(B[0] - A[0], B[1] - A[1], B[2] - A[2]);
2781
- e2.set(C[0] - A[0], C[1] - A[1], C[2] - A[2]);
2782
- n.crossVectors(e1, e2);
2783
- const len = n.length();
2784
- if (len < 1e-12) {
2785
- next.push(t);
2786
- return;
2787
- }
2788
- n.multiplyScalar(1 / len);
2789
- ce.set((A[0] + B[0] + C[0]) / 3, (A[1] + B[1] + C[1]) / 3, (A[2] + B[2] + C[2]) / 3);
2790
- if (T.sel && !T.sel(n, ce)) {
2791
- next.push(t);
2792
- return;
2994
+ const boxes = ti.boxes;
2995
+ const blocks = ti.blocks;
2996
+ let runFrom = -1;
2997
+ const closeRun = function(end) {
2998
+ if (runFrom < 0) return;
2999
+ segments.push([runFrom, end]);
3000
+ total += end - runFrom;
3001
+ runFrom = -1;
3002
+ };
3003
+ for (let blk = 0, t0 = 0; t0 < ti.triangles; blk++, t0 += TRI_BLOCK) {
3004
+ const j = blk * 6;
3005
+ if (blocks[j + 3] < lo[0] || blocks[j] > hi[0] || blocks[j + 4] < lo[1] || blocks[j + 1] > hi[1] || blocks[j + 5] < lo[2] || blocks[j + 2] > hi[2]) {
3006
+ if (runFrom < 0) runFrom = t0;
3007
+ continue;
2793
3008
  }
2794
- const d = [T.sdf(A[0], A[1], A[2]), T.sdf(B[0], B[1], B[2]), T.sdf(C[0], C[1], C[2])];
2795
- const ins = (d[0] < 0 ? 1 : 0) + (d[1] < 0 ? 1 : 0) + (d[2] < 0 ? 1 : 0);
2796
- if (ins === 0) next.push(t);
2797
- else if (ins === 3) {
2798
- if (rem) rem.push(t);
2799
- } else {
2800
- fan(clip(t, d, 1), next);
2801
- if (rem) fan(clip(t, d, -1), rem);
3009
+ const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
3010
+ for (let t = t0; t < t1; t++) {
3011
+ const q = t * 6;
3012
+ if (boxes[q + 3] < lo[0] || boxes[q] > hi[0] || boxes[q + 4] < lo[1] || boxes[q + 1] > hi[1] || boxes[q + 5] < lo[2] || boxes[q + 2] > hi[2]) {
3013
+ if (runFrom < 0) runFrom = t;
3014
+ continue;
3015
+ }
3016
+ closeRun(t);
3017
+ const next = [];
3018
+ testTri(T, readTri(t * 3), next, rem);
3019
+ if (next.length) {
3020
+ segments.push(next);
3021
+ total += next.length;
3022
+ }
2802
3023
  }
3024
+ }
3025
+ closeRun(ti.triangles);
3026
+ } else {
3027
+ let tris = [];
3028
+ for (let f = 0; f < nv; f += 3) tris.push(readTri(f));
3029
+ tests.forEach(function(T) {
3030
+ const next = [];
3031
+ const rem = T.tag ? cut[T.tag] = cut[T.tag] || [] : null;
3032
+ tris.forEach(function(t) {
3033
+ testTri(T, t, next, rem);
3034
+ });
3035
+ tris = next;
2803
3036
  });
2804
- tris = next;
2805
- });
2806
- function build(list2) {
3037
+ segments.push(tris);
3038
+ total = tris.length;
3039
+ }
3040
+ function fill(segs, count, boxesOut2) {
2807
3041
  const g = new THREE.BufferGeometry();
2808
- let off = 0;
2809
- names.forEach(function(nm, a) {
2810
- const arr = new Float32Array(list2.length * 3 * sizes[a]);
2811
- let w = 0;
2812
- list2.forEach(function(t) {
2813
- for (let k = 0; k < 3; k++) for (let q = 0; q < sizes[a]; q++) arr[w++] = t[k][off + q];
3042
+ const dst = names.map(function(_nm, a) {
3043
+ return new Float32Array(count * 3 * sizes[a]);
3044
+ });
3045
+ const w = names.map(function() {
3046
+ return 0;
3047
+ });
3048
+ let wb = 0;
3049
+ segs.forEach(function(seg) {
3050
+ if (typeof seg[0] === "number") {
3051
+ for (let a = 0; a < names.length; a++) {
3052
+ const size = sizes[a];
3053
+ if (!idx) {
3054
+ dst[a].set(arrs[a].subarray(seg[0] * 3 * size, seg[1] * 3 * size), w[a]);
3055
+ w[a] += (seg[1] - seg[0]) * 3 * size;
3056
+ continue;
3057
+ }
3058
+ for (let f = seg[0] * 3; f < seg[1] * 3; f++) for (let q = 0; q < size; q++) dst[a][w[a]++] = arrs[a][idx[f] * size + q];
3059
+ }
3060
+ if (boxesOut2 && ti) {
3061
+ boxesOut2.set(ti.boxes.subarray(seg[0] * 6, seg[1] * 6), wb);
3062
+ wb += (seg[1] - seg[0]) * 6;
3063
+ }
3064
+ return;
3065
+ }
3066
+ seg.forEach(function(t) {
3067
+ if (boxesOut2) {
3068
+ for (let k = 0; k < 3; k++) {
3069
+ boxesOut2[wb + k] = Math.fround(Math.min(t[0][k], t[1][k], t[2][k]));
3070
+ boxesOut2[wb + 3 + k] = Math.fround(Math.max(t[0][k], t[1][k], t[2][k]));
3071
+ }
3072
+ wb += 6;
3073
+ }
3074
+ let off = 0;
3075
+ for (let a = 0; a < names.length; a++) {
3076
+ for (let k = 0; k < 3; k++) for (let q = 0; q < sizes[a]; q++) dst[a][w[a]++] = t[k][off + q];
3077
+ off += sizes[a];
3078
+ }
2814
3079
  });
2815
- g.setAttribute(nm, new THREE.BufferAttribute(arr, sizes[a]));
2816
- off += sizes[a];
3080
+ });
3081
+ names.forEach(function(nm, a) {
3082
+ g.setAttribute(nm, new THREE.BufferAttribute(dst[a], sizes[a]));
2817
3083
  });
2818
3084
  g.userData.crease = true;
2819
3085
  return g;
2820
3086
  }
2821
- const out = { geo: build(tris), cut: {} };
3087
+ const boxesOut = ti ? new Float64Array(total * 6) : void 0;
3088
+ const out = { geo: fill(segments, total, boxesOut), cut: {}, tasks: {} };
3089
+ if (boxesOut) storeTriIndex(out.geo, boxesOut);
2822
3090
  Object.keys(cut).forEach(function(k) {
2823
- out.cut[k] = crease(build(cut[k]), 42);
3091
+ const piece = fill([cut[k]], cut[k].length);
3092
+ const mode = tests.find(function(T) {
3093
+ return T.tag === k;
3094
+ }).pieces;
3095
+ if (mode === "none") out.cut[k] = piece;
3096
+ else if (mode === "later") {
3097
+ out.cut[k] = piece;
3098
+ out.tasks[k] = creaseTask(piece, 42);
3099
+ } else out.cut[k] = crease(piece, 42);
2824
3100
  });
2825
3101
  return out;
2826
3102
  }
3103
+ function refreshBounds(geo) {
3104
+ const found = boundsFromIndex(geo);
3105
+ if (!found) {
3106
+ geo.computeBoundingSphere();
3107
+ geo.computeBoundingBox();
3108
+ return;
3109
+ }
3110
+ if (geo.boundingBox && geo.boundingSphere && boundsDone.get(geo) === found.version) return;
3111
+ const b = found.box;
3112
+ if (!geo.boundingBox) geo.boundingBox = new THREE.Box3();
3113
+ geo.boundingBox.min.set(b[0], b[1], b[2]);
3114
+ geo.boundingBox.max.set(b[3], b[4], b[5]);
3115
+ if (!geo.boundingSphere) geo.boundingSphere = new THREE.Sphere();
3116
+ const center = geo.boundingBox.getCenter(geo.boundingSphere.center);
3117
+ const P = geo.attributes.position.array;
3118
+ let maxRadiusSq = 0;
3119
+ for (let i = 0; i < P.length; i += 3) {
3120
+ const dx = center.x - P[i];
3121
+ const dy = center.y - P[i + 1];
3122
+ const dz = center.z - P[i + 2];
3123
+ maxRadiusSq = Math.max(maxRadiusSq, dx * dx + dy * dy + dz * dz);
3124
+ }
3125
+ geo.boundingSphere.radius = Math.sqrt(maxRadiusSq);
3126
+ boundsDone.set(geo, found.version);
3127
+ }
3128
+ const boundsDone = /* @__PURE__ */ new WeakMap();
2827
3129
  function mergeGeometries(list2) {
2828
3130
  const pos = [];
2829
3131
  const nor = [];
@@ -2954,7 +3256,7 @@ var GameVehicles = (() => {
2954
3256
  }
2955
3257
  };
2956
3258
  };
2957
- Object.assign(I, { roundedBoxGeometry, taper, subdivide, crease, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject });
3259
+ Object.assign(I, { roundedBoxGeometry, taper, subdivide, crease, creaseTask, refreshBounds, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject });
2958
3260
  }
2959
3261
 
2960
3262
  // ../game-contracts/dist/index.js
@@ -8335,6 +8637,8 @@ var GameVehicles = (() => {
8335
8637
  const pos = g && g.attributes && g.attributes.position;
8336
8638
  return o.raycast === THREE.Mesh.prototype.raycast && !o.isSkinnedMesh && !Array.isArray(o.material) && pos && !pos.isInterleavedBufferAttribute && pos.itemSize === 3 && !g.groups.length && !(g.morphAttributes && g.morphAttributes.position) && (g.index ? g.index.count : pos.count) / 3 >= PROXY_MIN_TRIANGLES;
8337
8639
  }
8640
+ let _keep = new Uint32Array(0);
8641
+ let _box = new Float32Array(0);
8338
8642
  function proxyIn(o, Mw, R) {
8339
8643
  _pm.copy(o.matrixWorld).invert().multiply(Mw);
8340
8644
  const lo = [Infinity, Infinity, Infinity];
@@ -8347,39 +8651,48 @@ var GameVehicles = (() => {
8347
8651
  }
8348
8652
  }
8349
8653
  const g = o.geometry;
8350
- const P = g.attributes.position.array;
8654
+ const ti = triIndexOf(g);
8655
+ if (!ti) return null;
8351
8656
  const ix = g.index ? g.index.array : null;
8352
- const n = ix ? ix.length : P.length / 3;
8353
- const keep = new Uint32Array(n - n % 3);
8657
+ const boxes = ti.boxes;
8658
+ const blocks = ti.blocks;
8659
+ if (_keep.length < ti.triangles * 3) {
8660
+ _keep = new Uint32Array(ti.triangles * 3);
8661
+ _box = new Float32Array(ti.triangles * 6);
8662
+ }
8663
+ const keep = _keep;
8664
+ const box2 = _box;
8354
8665
  let nk = 0;
8355
- for (let t = 0; t + 2 < n; t += 3) {
8356
- const a = (ix ? ix[t] : t) * 3;
8357
- const b = (ix ? ix[t + 1] : t + 1) * 3;
8358
- const d = (ix ? ix[t + 2] : t + 2) * 3;
8359
- let out = false;
8360
- for (let k = 0; k < 3 && !out; k++) {
8361
- const u = P[a + k];
8362
- const v = P[b + k];
8363
- const w = P[d + k];
8364
- out = Math.max(u, v, w) < lo[k] || Math.min(u, v, w) > hi[k];
8365
- }
8366
- if (!out) {
8367
- keep[nk++] = ix ? ix[t] : t;
8368
- keep[nk++] = ix ? ix[t + 1] : t + 1;
8369
- keep[nk++] = ix ? ix[t + 2] : t + 2;
8666
+ let nt = 0;
8667
+ for (let blk = 0, t0 = 0; t0 < ti.triangles; blk++, t0 += TRI_BLOCK) {
8668
+ const j = blk * 6;
8669
+ if (blocks[j + 3] < lo[0] || blocks[j] > hi[0] || blocks[j + 4] < lo[1] || blocks[j + 1] > hi[1] || blocks[j + 5] < lo[2] || blocks[j + 2] > hi[2]) continue;
8670
+ const t1 = Math.min(ti.triangles, t0 + TRI_BLOCK);
8671
+ for (let t = t0; t < t1; t++) {
8672
+ const q = t * 6;
8673
+ if (boxes[q + 3] < lo[0] || boxes[q] > hi[0] || boxes[q + 4] < lo[1] || boxes[q + 1] > hi[1] || boxes[q + 5] < lo[2] || boxes[q + 2] > hi[2]) continue;
8674
+ keep[nk++] = ix ? ix[t * 3] : t * 3;
8675
+ keep[nk++] = ix ? ix[t * 3 + 1] : t * 3 + 1;
8676
+ keep[nk++] = ix ? ix[t * 3 + 2] : t * 3 + 2;
8677
+ for (let k = 0; k < 6; k++) box2[nt * 6 + k] = boxes[q + k];
8678
+ nt++;
8370
8679
  }
8371
8680
  }
8372
8681
  if (!nk) return null;
8373
8682
  const kept = keep.slice(0, nk);
8374
- const box2 = new Float32Array(kept.length / 3 * 6);
8375
- for (let t = 0, j = 0; t < kept.length; t += 3, j += 6) {
8376
- const a = kept[t] * 3;
8377
- const b = kept[t + 1] * 3;
8378
- const d = kept[t + 2] * 3;
8683
+ const keptBox = box2.slice(0, nt * 6);
8684
+ const keptBlocks = new Float32Array(Math.ceil(nt / TRI_BLOCK) * 6);
8685
+ for (let blk = 0; blk * TRI_BLOCK < nt; blk++) {
8686
+ const b = blk * 6;
8379
8687
  for (let k = 0; k < 3; k++) {
8380
- box2[j + k] = Math.min(P[a + k], P[b + k], P[d + k]);
8381
- box2[j + 3 + k] = Math.max(P[a + k], P[b + k], P[d + k]);
8688
+ keptBlocks[b + k] = Infinity;
8689
+ keptBlocks[b + 3 + k] = -Infinity;
8382
8690
  }
8691
+ for (let t = blk * TRI_BLOCK, t1 = Math.min(nt, t + TRI_BLOCK); t < t1; t++)
8692
+ for (let k = 0; k < 3; k++) {
8693
+ if (keptBox[t * 6 + k] < keptBlocks[b + k]) keptBlocks[b + k] = keptBox[t * 6 + k];
8694
+ if (keptBox[t * 6 + 3 + k] > keptBlocks[b + 3 + k]) keptBlocks[b + 3 + k] = keptBox[t * 6 + 3 + k];
8695
+ }
8383
8696
  }
8384
8697
  const pg = new THREE.BufferGeometry();
8385
8698
  pg.setAttribute("position", g.attributes.position);
@@ -8390,7 +8703,8 @@ var GameVehicles = (() => {
8390
8703
  proxy.layers.mask = o.layers.mask;
8391
8704
  proxy.proxyOf = o;
8392
8705
  proxy.kept = kept;
8393
- proxy.keptBox = box2;
8706
+ proxy.keptBox = keptBox;
8707
+ proxy.keptBlocks = keptBlocks;
8394
8708
  return proxy;
8395
8709
  }
8396
8710
  function narrowTo(rc, proxy) {
@@ -8410,13 +8724,21 @@ var GameVehicles = (() => {
8410
8724
  const hi2 = Math.max(z0, _pv.z) + 1e-4;
8411
8725
  const K = proxy.kept;
8412
8726
  const X = proxy.keptBox;
8727
+ const KB = proxy.keptBlocks;
8728
+ const nt = K.length / 3;
8413
8729
  const dst = proxy.geometry.index.array;
8414
8730
  let m = 0;
8415
- for (let t = 0, j = 0; t < K.length; t += 3, j += 6) {
8416
- if (X[j + 3] < lo0 || X[j] > hi0 || X[j + 4] < lo1 || X[j + 1] > hi1 || X[j + 5] < lo2 || X[j + 2] > hi2) continue;
8417
- dst[m++] = K[t];
8418
- dst[m++] = K[t + 1];
8419
- dst[m++] = K[t + 2];
8731
+ for (let blk = 0, t0 = 0; t0 < nt; blk++, t0 += TRI_BLOCK) {
8732
+ const b = blk * 6;
8733
+ if (KB[b + 3] < lo0 || KB[b] > hi0 || KB[b + 4] < lo1 || KB[b + 1] > hi1 || KB[b + 5] < lo2 || KB[b + 2] > hi2) continue;
8734
+ const t1 = Math.min(nt, t0 + TRI_BLOCK);
8735
+ for (let t = t0; t < t1; t++) {
8736
+ const j = t * 6;
8737
+ if (X[j + 3] < lo0 || X[j] > hi0 || X[j + 4] < lo1 || X[j + 1] > hi1 || X[j + 5] < lo2 || X[j + 2] > hi2) continue;
8738
+ dst[m++] = K[t * 3];
8739
+ dst[m++] = K[t * 3 + 1];
8740
+ dst[m++] = K[t * 3 + 2];
8741
+ }
8420
8742
  }
8421
8743
  proxy.geometry.setDrawRange(0, m);
8422
8744
  }
@@ -8834,6 +9156,8 @@ var GameVehicles = (() => {
8834
9156
  irel.copy(rel).invert();
8835
9157
  const pos = g.attributes.position;
8836
9158
  let changed = false;
9159
+ const liveIndex = liveTriIndex(g);
9160
+ const movedVertices = [];
8837
9161
  const near = boxInFrame(B, irel, v);
8838
9162
  for (let i = 0; i < pos.count; i++) {
8839
9163
  v.fromBufferAttribute(pos, i);
@@ -8845,6 +9169,7 @@ var GameVehicles = (() => {
8845
9169
  if (opt.extra) opt.extra(v, f);
8846
9170
  v.applyMatrix4(irel);
8847
9171
  pos.setXYZ(i, v.x, v.y, v.z);
9172
+ movedVertices.push(i);
8848
9173
  changed = true;
8849
9174
  }
8850
9175
  if (opt.extraAll) {
@@ -8853,12 +9178,14 @@ var GameVehicles = (() => {
8853
9178
  if (opt.extraAll(v)) {
8854
9179
  v.applyMatrix4(irel);
8855
9180
  pos.setXYZ(j, v.x, v.y, v.z);
9181
+ movedVertices.push(j);
8856
9182
  changed = true;
8857
9183
  }
8858
9184
  }
8859
9185
  }
8860
9186
  if (changed) {
8861
9187
  pos.needsUpdate = true;
9188
+ if (liveIndex) touchTriIndex(g, liveIndex, movedVertices);
8862
9189
  dirty.add(msh);
8863
9190
  }
8864
9191
  if (changed || boundsDue) {
@@ -8889,6 +9216,26 @@ var GameVehicles = (() => {
8889
9216
  });
8890
9217
  return { field, moved, ax, a, cu, cv, hu, hv, outer };
8891
9218
  }
9219
+ function panelBoundsIn(rel, rect, B, a, ax) {
9220
+ const det = rel.determinant();
9221
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return void 0;
9222
+ const back = rel.clone().invert();
9223
+ const lo = [Infinity, Infinity, Infinity];
9224
+ const hi = [-Infinity, -Infinity, -Infinity];
9225
+ const q = new V3();
9226
+ for (let i = 0; i < 8; i++) {
9227
+ q.setComponent(ax[0], i & 1 ? rect[1] : rect[0]);
9228
+ q.setComponent(ax[1], i & 2 ? rect[3] : rect[2]);
9229
+ q.setComponent(a, i & 4 ? I.boxHi(B, a) : I.boxLo(B, a));
9230
+ q.applyMatrix4(back);
9231
+ for (let k = 0; k < 3; k++) {
9232
+ lo[k] = Math.min(lo[k], q.getComponent(k));
9233
+ hi[k] = Math.max(hi[k], q.getComponent(k));
9234
+ }
9235
+ }
9236
+ const pad = 1e-3;
9237
+ return { lo: lo.map((x) => x - pad), hi: hi.map((x) => x + pad) };
9238
+ }
8892
9239
  function cutPanel(c, z, rect, keep, dirty, o) {
8893
9240
  o = o || {};
8894
9241
  const B = z.box;
@@ -8921,6 +9268,7 @@ var GameVehicles = (() => {
8921
9268
  }
8922
9269
  const test = {
8923
9270
  tag: "part",
9271
+ pieces: keep ? o.pieceTasks ? "later" : "crease" : "none",
8924
9272
  sel: o.anyN || z.cutAll ? null : function(n) {
8925
9273
  nv.copy(n).applyMatrix3(nm).normalize();
8926
9274
  return nv.dot(outN) > 0.3;
@@ -8939,13 +9287,12 @@ var GameVehicles = (() => {
8939
9287
  return q;
8940
9288
  }
8941
9289
  };
8942
- const r = cutGeometry(g, [test]);
9290
+ const r = cutGeometry(g, [{ ...test, bounds: panelBoundsIn(rel, rect, B, a, ax) }]);
8943
9291
  const cg = r.cut.part;
8944
9292
  if (!cg || !cg.attributes.position.count) return;
8945
9293
  g.dispose();
8946
9294
  msh.geometry = r.geo;
8947
- r.geo.computeBoundingSphere();
8948
- r.geo.computeBoundingBox();
9295
+ I.refreshBounds(r.geo);
8949
9296
  dirty.add(msh);
8950
9297
  if (!keep) {
8951
9298
  cg.dispose();
@@ -8958,6 +9305,7 @@ var GameVehicles = (() => {
8958
9305
  rel.decompose(pm.position, pm.quaternion, pm.scale);
8959
9306
  c.vehicle.add(pm);
8960
9307
  pm.updateMatrixWorld(true);
9308
+ if (o.pieceTasks) o.pieceTasks.set(pm, r.tasks.part);
8961
9309
  pieces.push({ mesh: pm, cut: true });
8962
9310
  });
8963
9311
  return pieces;
@@ -12594,7 +12942,15 @@ var GameVehicles = (() => {
12594
12942
  __publicField(this, "gone", /* @__PURE__ */ new Set());
12595
12943
  /** Shows or hides the plate and the recess of a door or lid by its state (see `showWhenOpen`). */
12596
12944
  __publicField(this, "syncPlates", /* @__PURE__ */ new Map());
12945
+ /** Doors and lids whose own skin was cut from the body and hung on the hinge (true), or that had none to take and keep the plate (false). */
12946
+ __publicField(this, "skins", /* @__PURE__ */ new Map());
12597
12947
  __publicField(this, "lightsOn", true);
12948
+ /** Heavy body meshes whose triangle index is still to build (null once done). */
12949
+ __publicField(this, "warming");
12950
+ /** A panel was torn off since the last `pump`: that frame already paid for the cut, the smoothing starts on the next one. */
12951
+ __publicField(this, "tornThisFrame", false);
12952
+ /** Normal smoothing still running, by mesh: a mesh cut again gets a new task and the old one is dropped. */
12953
+ __publicField(this, "smoothing", /* @__PURE__ */ new Map());
12598
12954
  __publicField(this, "hood");
12599
12955
  this.kit = kit;
12600
12956
  this.c = c;
@@ -12604,6 +12960,8 @@ var GameVehicles = (() => {
12604
12960
  for (const p of model.parts) this.byId.set(p.id, p);
12605
12961
  c.root.updateMatrixWorld(true);
12606
12962
  this.hood = this.nameHood();
12963
+ this.warming = c.deform.filter((msh) => msh.geometry && msh.geometry.attributes.position && msh.geometry.attributes.position.count >= 1500);
12964
+ if (!this.warming.length) this.warming = null;
12607
12965
  for (const p of model.parts) {
12608
12966
  if (p.role === "door" || p.role === "lid") this.makePlate(p);
12609
12967
  else if (p.role === "mirror" && !this.mirrorObjects(p).length) this.makeMirror(p);
@@ -12739,11 +13097,21 @@ var GameVehicles = (() => {
12739
13097
  * keeps the shape of its model instead of flat panels over its curved sides. Follows the hinge's rotation, whoever turns it (the clips of a host, `detach`).
12740
13098
  */
12741
13099
  showWhenOpen(id, piv, panel, recess) {
13100
+ let busy = false;
12742
13101
  const sync = () => {
13102
+ if (busy) return;
12743
13103
  const r = piv.rotation;
12744
13104
  const open = Math.abs(r.x) + Math.abs(r.y) + Math.abs(r.z) > 1e-3 || this.gone.has(id) || piv.parent !== this.c.vehicle;
12745
- panel.visible = open;
12746
- recess.visible = open;
13105
+ if (open && !this.gone.has(id) && piv.parent === this.c.vehicle && !this.skins.has(id)) {
13106
+ busy = true;
13107
+ try {
13108
+ this.skins.set(id, this.takeSkin(id, piv));
13109
+ } finally {
13110
+ busy = false;
13111
+ }
13112
+ }
13113
+ panel.visible = open && !this.skins.get(id);
13114
+ recess.visible = open && !this.skins.get(id);
12747
13115
  };
12748
13116
  const euler = piv.rotation;
12749
13117
  const quaternion = piv.quaternion;
@@ -12760,6 +13128,58 @@ var GameVehicles = (() => {
12760
13128
  this.syncPlates.set(id, sync);
12761
13129
  sync();
12762
13130
  }
13131
+ /**
13132
+ * Cuts the skin of a door or lid zone out of the body (as the damage's hanging door does) and hangs it, with the thin parts on it (trim, handle) and, for a door, the side
13133
+ * window over it, on the hinge. Done with the hinge closed, so every piece keeps its place; answers whether there was skin to take.
13134
+ */
13135
+ takeSkin(id, piv) {
13136
+ const p = this.byId.get(id);
13137
+ const z = p && this.zone(p);
13138
+ if (!p || !z) return false;
13139
+ const I = this.I;
13140
+ const B = z.box;
13141
+ const q = piv.quaternion.clone();
13142
+ piv.quaternion.identity();
13143
+ this.c.root.updateMatrixWorld(true);
13144
+ const inv = I.worldInverseOf(this.c);
13145
+ let objs = [];
13146
+ try {
13147
+ if (p.role === "door") {
13148
+ const dirty = /* @__PURE__ */ new Set();
13149
+ const rect = [B.x0 + 0.03, B.x1 - 0.03, B.y0 + Math.min(0.08, (B.y1 - B.y0) * 0.1), B.y1 - 0.02];
13150
+ const pcs = I.cutPanel(this.c, z, rect, true, dirty).map((x) => x.mesh).filter((m) => !!m);
13151
+ this.mend(dirty);
13152
+ if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv), ...I.windowsOver(this.c, z, inv)];
13153
+ } else {
13154
+ const pcs = this.cutZone(z);
13155
+ if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv)];
13156
+ }
13157
+ } catch {
13158
+ objs = [];
13159
+ }
13160
+ const deform = this.c.deform ?? [];
13161
+ for (const o of objs) {
13162
+ if (!o.parent || o === piv) continue;
13163
+ piv.attach(o);
13164
+ o.traverse((x) => {
13165
+ x.userData.noFollow = true;
13166
+ });
13167
+ const di = deform.indexOf(o);
13168
+ if (di >= 0) deform.splice(di, 1);
13169
+ }
13170
+ piv.quaternion.copy(q);
13171
+ this.c.root.updateMatrixWorld(true);
13172
+ return objs.length > 0;
13173
+ }
13174
+ mend(dirty) {
13175
+ dirty.forEach((msh) => {
13176
+ const g = msh.geometry;
13177
+ if (g.userData.crease || !g.index) this.I.crease(g, 42);
13178
+ else g.computeVertexNormals();
13179
+ g.computeBoundingSphere();
13180
+ g.computeBoundingBox();
13181
+ });
13182
+ }
12763
13183
  makeMirror(p) {
12764
13184
  const [cx, cy, cz] = p.box.center;
12765
13185
  const s = cz < 0 ? -1 : 1;
@@ -12897,6 +13317,31 @@ var GameVehicles = (() => {
12897
13317
  this.I.flattenTire(w, Math.min(0.5, 0.12 + 0.38 * melt));
12898
13318
  }
12899
13319
  }
13320
+ /** Smooths the normals of a cut mesh a slice per frame (see `pump`); until then it draws with flat face normals. */
13321
+ smoothLater(msh) {
13322
+ this.smoothing.set(msh, this.I.creaseTask(msh.geometry, 42));
13323
+ this.tornThisFrame = true;
13324
+ }
13325
+ /** Spends at most `budgetMs` finishing the pending normal smoothing. Call once per frame. */
13326
+ pump(budgetMs = 2.5) {
13327
+ if (this.tornThisFrame) {
13328
+ this.tornThisFrame = false;
13329
+ return;
13330
+ }
13331
+ if (!this.smoothing.size && !this.warming) return;
13332
+ const deadline = performance.now() + budgetMs;
13333
+ for (const [msh, task] of this.smoothing) {
13334
+ if (msh.geometry !== task.geo || task.step(deadline)) this.smoothing.delete(msh);
13335
+ if (performance.now() >= deadline) return;
13336
+ }
13337
+ this.warmIndexes(deadline);
13338
+ }
13339
+ /** Measures the triangles of the heavy body meshes once, a slice per frame, so the first panel torn off finds them ready (see `triIndexOf`). */
13340
+ warmIndexes(deadline) {
13341
+ if (!this.warming) return;
13342
+ this.warming = this.warming.filter((msh) => !warmTriIndex(msh.geometry, deadline));
13343
+ if (!this.warming.length) this.warming = null;
13344
+ }
12900
13345
  /** Moves the panel of a lost zone out of the body (the kit's torn-off look). */
12901
13346
  tearOff(p) {
12902
13347
  const z = this.zone(p);
@@ -12909,10 +13354,9 @@ var GameVehicles = (() => {
12909
13354
  }
12910
13355
  dirty.forEach((msh) => {
12911
13356
  const g = msh.geometry;
12912
- if (g.userData.crease || !g.index) this.I.crease(g, 42);
13357
+ if (g.userData.crease || !g.index) this.smoothLater(msh);
12913
13358
  else g.computeVertexNormals();
12914
- g.computeBoundingSphere();
12915
- g.computeBoundingBox();
13359
+ this.I.refreshBounds(g);
12916
13360
  });
12917
13361
  this.gone.add(p.id);
12918
13362
  }
@@ -13055,17 +13499,19 @@ var GameVehicles = (() => {
13055
13499
  const mg = Math.min(0.05, (u1 - u0) * 0.08, (v1 - v0) * 0.08);
13056
13500
  const dirty = /* @__PURE__ */ new Set();
13057
13501
  let pcs = [];
13502
+ const pieceTasks = /* @__PURE__ */ new Map();
13058
13503
  try {
13059
- pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty);
13504
+ pcs = I.cutPanel(this.c, z, [u0 + mg, u1 - mg, v0 + mg, v1 - mg], true, dirty, { pieceTasks });
13060
13505
  } catch {
13061
13506
  pcs = [];
13062
13507
  }
13508
+ pieceTasks.forEach((task, mesh2) => this.smoothing.set(mesh2, task));
13509
+ this.tornThisFrame = true;
13063
13510
  dirty.forEach((msh) => {
13064
13511
  const g = msh.geometry;
13065
- if (g.userData.crease || !g.index) I.crease(g, 42);
13512
+ if (g.userData.crease || !g.index) this.smoothLater(msh);
13066
13513
  else g.computeVertexNormals();
13067
- g.computeBoundingSphere();
13068
- g.computeBoundingBox();
13514
+ I.refreshBounds(g);
13069
13515
  });
13070
13516
  return pcs.map((q) => q.mesh).filter((m) => !!m);
13071
13517
  }
@@ -13844,7 +14290,7 @@ var GameVehicles = (() => {
13844
14290
  specCache = { name: options.name ?? c.spec.name ?? c.key, parts, joints, tags: ["vehicle", kindOf(c)] };
13845
14291
  return specCache;
13846
14292
  };
13847
- const state = () => {
14293
+ const buildState = () => {
13848
14294
  const parts = model.parts.map((d) => {
13849
14295
  const p = ps.get(d.id);
13850
14296
  const marked = p.dents.length > 0 || p.holes.length > 0 || p.cracks.length > 0;
@@ -13881,7 +14327,15 @@ var GameVehicles = (() => {
13881
14327
  }));
13882
14328
  return { id, name: options.name ?? c.spec.name ?? c.key, position: [0, 0, 0], rotation: [0, 0, 0, 1], parts, joints, groups: groupsCache.map((g) => [...g]), destroyed: parts.every((p) => p.status === "broken" || p.status === "melted" || p.status === "ashes") };
13883
14329
  };
14330
+ let stateCache;
14331
+ const state = () => stateCache ?? (stateCache = buildState());
14332
+ const isSimulating = () => {
14333
+ if (leaks.size > 0) return true;
14334
+ for (const p of ps.values()) if (!p.lost && (p.burning || p.temp > AMBIENT)) return true;
14335
+ return false;
14336
+ };
13884
14337
  const hit = (h) => {
14338
+ stateCache = void 0;
13885
14339
  const out = [];
13886
14340
  const hh = h.space === "local" ? { ...h, space: "world", point: toWorld(h.point) } : h;
13887
14341
  if (hh.space === "local" || !hh.point) return out;
@@ -13908,6 +14362,8 @@ var GameVehicles = (() => {
13908
14362
  clock += dt;
13909
14363
  const out = queue;
13910
14364
  queue = [];
14365
+ const wasSimulating = isSimulating();
14366
+ const handledBefore = (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0);
13911
14367
  const hood = c.hood;
13912
14368
  if (hood) {
13913
14369
  const sign2 = hood.sign || 1;
@@ -13928,12 +14384,15 @@ var GameVehicles = (() => {
13928
14384
  afterBlast(out);
13929
14385
  afterRoll(out);
13930
14386
  applyEffects();
14387
+ vis?.pump();
14388
+ if (wasSimulating || out.length > 0 || handledBefore !== (blastHandled ? 1 : 0) + (rollHandled ? 2 : 0)) stateCache = void 0;
13931
14389
  return out;
13932
14390
  };
13933
14391
  const disassemble = (jointId, tool, dt) => {
13934
14392
  const j = js.find((x) => x.def.id === jointId);
13935
14393
  if (!j || !j.def.tools.includes(tool)) return -1;
13936
14394
  if (j.open) return 1;
14395
+ stateCache = void 0;
13937
14396
  j.progress = Math.min(1, j.progress + dt / j.def.seconds);
13938
14397
  const step = Math.floor(j.progress * 4) / 4;
13939
14398
  if (step > j.reported && j.progress < 1) {
@@ -13949,6 +14408,7 @@ var GameVehicles = (() => {
13949
14408
  return j.progress;
13950
14409
  };
13951
14410
  const extinguish = (partId) => {
14411
+ stateCache = void 0;
13952
14412
  for (const p of ps.values()) {
13953
14413
  if (partId && p.def.id !== partId) continue;
13954
14414
  if (p.burning) {
@@ -13962,6 +14422,7 @@ var GameVehicles = (() => {
13962
14422
  }
13963
14423
  };
13964
14424
  const reset = () => {
14425
+ stateCache = void 0;
13965
14426
  const old = c;
13966
14427
  const parent = old.root.parent;
13967
14428
  const next = kit.build(old.key, old.state, old.scenario != null ? { scenario: old.scenario } : void 0);
@@ -13979,6 +14440,7 @@ var GameVehicles = (() => {
13979
14440
  setup();
13980
14441
  };
13981
14442
  const rollover = (side2 = 1) => {
14443
+ stateCache = void 0;
13982
14444
  if (kit.roll(c, side2)) rolled = true;
13983
14445
  void rolled;
13984
14446
  };