@tscircuit/cli 0.1.2411 → 0.1.2413

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.
@@ -4417,6 +4417,651 @@ var require_cjs = __commonJS(function(exports) {
4417
4417
  }
4418
4418
  });
4419
4419
 
4420
+ // node_modules/earcut/src/earcut.js
4421
+ function earcut(data, holeIndices, dim = 2) {
4422
+ const hasHoles = holeIndices && holeIndices.length;
4423
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
4424
+ if (steiners.size)
4425
+ steiners.clear();
4426
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
4427
+ const triangles = [];
4428
+ if (!outerNode || outerNode.next === outerNode.prev)
4429
+ return triangles;
4430
+ let minX = 0, minY = 0, invSize = 0;
4431
+ if (hasHoles)
4432
+ outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
4433
+ if (data.length > 80 * dim) {
4434
+ minX = data[0];
4435
+ minY = data[1];
4436
+ let maxX = minX;
4437
+ let maxY = minY;
4438
+ for (let i = dim;i < outerLen; i += dim) {
4439
+ const x = data[i];
4440
+ const y = data[i + 1];
4441
+ if (x < minX)
4442
+ minX = x;
4443
+ if (y < minY)
4444
+ minY = y;
4445
+ if (x > maxX)
4446
+ maxX = x;
4447
+ if (y > maxY)
4448
+ maxY = y;
4449
+ }
4450
+ invSize = Math.max(maxX - minX, maxY - minY);
4451
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
4452
+ }
4453
+ earcutLinked(outerNode, triangles, minX, minY, invSize);
4454
+ return triangles;
4455
+ }
4456
+ function linkedList(data, start, end, dim, clockwise) {
4457
+ let last = null;
4458
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
4459
+ for (let i = start;i < end; i += dim)
4460
+ last = insertNode(i / dim | 0, data[i], data[i + 1], last);
4461
+ } else {
4462
+ for (let i = end - dim;i >= start; i -= dim)
4463
+ last = insertNode(i / dim | 0, data[i], data[i + 1], last);
4464
+ }
4465
+ if (last && equals(last, last.next)) {
4466
+ removeNode(last);
4467
+ last = last.next;
4468
+ }
4469
+ return last;
4470
+ }
4471
+ function filterPoints(start, end = start) {
4472
+ const full = end === start;
4473
+ let p = start, again;
4474
+ do {
4475
+ again = false;
4476
+ if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
4477
+ if (full || p === end)
4478
+ end = p.prev;
4479
+ filteredOut = true;
4480
+ removeNode(p);
4481
+ p = p.prev;
4482
+ again = true;
4483
+ } else if (full || p !== end) {
4484
+ p = p.next;
4485
+ again = !full;
4486
+ }
4487
+ } while (again || p !== end);
4488
+ return end;
4489
+ }
4490
+ function earcutLinked(ear, triangles, minX, minY, invSize) {
4491
+ if (invSize)
4492
+ indexCurve(ear, minX, minY, invSize);
4493
+ let stop = ear, cured = false;
4494
+ while (ear.prev !== ear.next) {
4495
+ const prev = ear.prev;
4496
+ const next = ear.next;
4497
+ if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
4498
+ triangles.push(prev.i, ear.i, next.i);
4499
+ removeNode(ear);
4500
+ ear = next;
4501
+ stop = next;
4502
+ continue;
4503
+ }
4504
+ ear = next;
4505
+ if (ear === stop) {
4506
+ filteredOut = false;
4507
+ ear = filterPoints(ear);
4508
+ if (filteredOut) {
4509
+ stop = ear;
4510
+ continue;
4511
+ }
4512
+ if (!cured) {
4513
+ ear = cureLocalIntersections(ear, triangles);
4514
+ stop = ear;
4515
+ cured = true;
4516
+ continue;
4517
+ }
4518
+ splitEarcut(ear, triangles, minX, minY, invSize);
4519
+ break;
4520
+ }
4521
+ }
4522
+ }
4523
+ function isEar(ear) {
4524
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
4525
+ let p = c.next;
4526
+ while (p !== a) {
4527
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0)
4528
+ return false;
4529
+ p = p.next;
4530
+ }
4531
+ return true;
4532
+ }
4533
+ function isEarHashed(ear, minX, minY, invSize) {
4534
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy), minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
4535
+ let p = ear.prevZ;
4536
+ while (p && p.z >= minZ) {
4537
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== c && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0)
4538
+ return false;
4539
+ p = p.prevZ;
4540
+ }
4541
+ let n = ear.nextZ;
4542
+ while (n && n.z <= maxZ) {
4543
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== c && !(ax === n.x && ay === n.y) && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0)
4544
+ return false;
4545
+ n = n.nextZ;
4546
+ }
4547
+ return true;
4548
+ }
4549
+ function cureLocalIntersections(start, triangles) {
4550
+ let p = start;
4551
+ let cured = false;
4552
+ do {
4553
+ const a = p.prev, b = p.next.next;
4554
+ if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
4555
+ triangles.push(a.i, p.i, b.i);
4556
+ removeNode(p);
4557
+ removeNode(p.next);
4558
+ p = start = b;
4559
+ cured = true;
4560
+ }
4561
+ p = p.next;
4562
+ } while (p !== start);
4563
+ return cured ? filterPoints(p) : p;
4564
+ }
4565
+ function splitEarcut(start, triangles, minX, minY, invSize) {
4566
+ let a = start;
4567
+ do {
4568
+ let b = a.next.next;
4569
+ while (b !== a.prev) {
4570
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
4571
+ let c = splitPolygon(a, b);
4572
+ a = filterPoints(a, a.next);
4573
+ c = filterPoints(c, c.next);
4574
+ earcutLinked(a, triangles, minX, minY, invSize);
4575
+ earcutLinked(c, triangles, minX, minY, invSize);
4576
+ return;
4577
+ }
4578
+ b = b.next;
4579
+ }
4580
+ a = a.next;
4581
+ } while (a !== start);
4582
+ }
4583
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
4584
+ const queue = [];
4585
+ for (let i = 0, len = holeIndices.length;i < len; i++) {
4586
+ const start = holeIndices[i] * dim;
4587
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
4588
+ const list = linkedList(data, start, end, dim, false);
4589
+ if (list === list.next)
4590
+ steiners.add(list);
4591
+ queue.push(getLeftmost(list));
4592
+ }
4593
+ queue.sort(compareXYSlope);
4594
+ buildBlockIndex(data.length / dim, holeIndices.length);
4595
+ indexSegment(outerNode, outerNode);
4596
+ indexActive = true;
4597
+ for (let i = 0;i < queue.length; i++) {
4598
+ outerNode = eliminateHole(queue[i], outerNode);
4599
+ }
4600
+ indexActive = false;
4601
+ return filterPoints(outerNode);
4602
+ }
4603
+ function compareXYSlope(a, b) {
4604
+ return a.x - b.x || a.y - b.y || (a.next.y - a.y) / (a.next.x - a.x) - (b.next.y - b.y) / (b.next.x - b.x);
4605
+ }
4606
+ function eliminateHole(hole, outerNode) {
4607
+ const bridge = findHoleBridge(hole, outerNode);
4608
+ if (!bridge) {
4609
+ return outerNode;
4610
+ }
4611
+ const bridgeReverse = splitPolygon(bridge, hole);
4612
+ const bridge2 = bridgeReverse.next;
4613
+ indexSegment(bridge, bridge2.next);
4614
+ filterPoints(bridgeReverse, bridgeReverse.next);
4615
+ return filterPoints(bridge, bridge.next);
4616
+ }
4617
+ function buildBlockIndex(maxNodes, numHoles) {
4618
+ const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
4619
+ if (blockBBox.length < maxBlocks * 4)
4620
+ blockBBox = new Float64Array(maxBlocks * 4);
4621
+ numBlocks = 0;
4622
+ }
4623
+ function indexSegment(head, stop) {
4624
+ let p = head;
4625
+ do {
4626
+ const b = numBlocks++;
4627
+ blockHead[b] = p;
4628
+ let minX = p.x, minY = p.y, maxX = p.x, maxY = p.y;
4629
+ let k = 0;
4630
+ do {
4631
+ const c = p.next;
4632
+ p.z = b;
4633
+ if (c.x < minX)
4634
+ minX = c.x;
4635
+ if (c.x > maxX)
4636
+ maxX = c.x;
4637
+ if (c.y < minY)
4638
+ minY = c.y;
4639
+ if (c.y > maxY)
4640
+ maxY = c.y;
4641
+ p = c;
4642
+ } while (++k < K && p !== stop);
4643
+ blockStop[b] = p;
4644
+ const g = b * 4;
4645
+ blockBBox[g] = minX;
4646
+ blockBBox[g + 1] = minY;
4647
+ blockBBox[g + 2] = maxX;
4648
+ blockBBox[g + 3] = maxY;
4649
+ } while (p !== stop);
4650
+ }
4651
+ function growBlock(head, tail) {
4652
+ const g = head.z * 4;
4653
+ if (tail.x < blockBBox[g])
4654
+ blockBBox[g] = tail.x;
4655
+ if (tail.y < blockBBox[g + 1])
4656
+ blockBBox[g + 1] = tail.y;
4657
+ if (tail.x > blockBBox[g + 2])
4658
+ blockBBox[g + 2] = tail.x;
4659
+ if (tail.y > blockBBox[g + 3])
4660
+ blockBBox[g + 3] = tail.y;
4661
+ }
4662
+ function liveBlockStop(b) {
4663
+ let stop = blockStop[b];
4664
+ while (stop.prev.next !== stop)
4665
+ stop = stop.next;
4666
+ blockStop[b] = stop;
4667
+ return stop;
4668
+ }
4669
+ function liveBlockHead(b) {
4670
+ let head = blockHead[b];
4671
+ while (head.prev.next !== head)
4672
+ head = head.next;
4673
+ blockHead[b] = head;
4674
+ return head;
4675
+ }
4676
+ function findHoleBridge(hole, outerNode) {
4677
+ let p = outerNode;
4678
+ const hx = hole.x;
4679
+ const hy = hole.y;
4680
+ let qx = -Infinity;
4681
+ let m;
4682
+ if (equals(hole, p))
4683
+ return p;
4684
+ for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
4685
+ if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx)
4686
+ continue;
4687
+ const stop = liveBlockStop(b);
4688
+ p = liveBlockHead(b);
4689
+ do {
4690
+ if (p.prev.next === p) {
4691
+ if (equals(hole, p.next))
4692
+ return p.next;
4693
+ else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
4694
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
4695
+ if (x <= hx && x > qx) {
4696
+ qx = x;
4697
+ m = p.x < p.next.x ? p : p.next;
4698
+ if (x === hx)
4699
+ return m;
4700
+ }
4701
+ }
4702
+ }
4703
+ p = p.next;
4704
+ } while (p !== stop);
4705
+ }
4706
+ if (!m)
4707
+ return null;
4708
+ const mx = m.x;
4709
+ const my = m.y;
4710
+ const tminY = Math.min(hy, my);
4711
+ const tmaxY = Math.max(hy, my);
4712
+ let tanMin = Infinity;
4713
+ for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
4714
+ if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY)
4715
+ continue;
4716
+ const stop = liveBlockStop(b);
4717
+ p = liveBlockHead(b);
4718
+ do {
4719
+ if (p.prev.next === p && hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
4720
+ const tan = Math.abs(hy - p.y) / (hx - p.x);
4721
+ if ((locallyInside(p, hole) || p.y === hy && p.next.y === hy && p.next.x > hx) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
4722
+ m = p;
4723
+ tanMin = tan;
4724
+ }
4725
+ }
4726
+ p = p.next;
4727
+ } while (p !== stop);
4728
+ }
4729
+ return m;
4730
+ }
4731
+ function sectorContainsSector(m, p) {
4732
+ return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
4733
+ }
4734
+ function indexCurve(start, minX, minY, invSize) {
4735
+ let p = start;
4736
+ let n = 0;
4737
+ do {
4738
+ p.z = zOrder(p.x, p.y, minX, minY, invSize);
4739
+ sortArr[n++] = p;
4740
+ p = p.next;
4741
+ } while (p !== start);
4742
+ sortNodes(n);
4743
+ let prev = null;
4744
+ for (let i = 0;i < n; i++) {
4745
+ const node = sortArr[i];
4746
+ node.prevZ = prev;
4747
+ if (prev)
4748
+ prev.nextZ = node;
4749
+ prev = node;
4750
+ }
4751
+ prev.nextZ = null;
4752
+ sortArr.fill(null, 0, n);
4753
+ sortBuf.fill(null, 0, n);
4754
+ }
4755
+ function sortNodes(n) {
4756
+ if (n <= 32) {
4757
+ for (let i = 1;i < n; i++) {
4758
+ const node = sortArr[i], z = node.z;
4759
+ let j = i - 1;
4760
+ while (j >= 0 && sortArr[j].z > z) {
4761
+ sortArr[j + 1] = sortArr[j];
4762
+ j--;
4763
+ }
4764
+ sortArr[j + 1] = node;
4765
+ }
4766
+ return;
4767
+ }
4768
+ if (zArr.length < n) {
4769
+ zArr = new Uint32Array(n);
4770
+ zBuf = new Uint32Array(n);
4771
+ sortBuf = new Array(n);
4772
+ }
4773
+ for (let i = 0;i < n; i++)
4774
+ zArr[i] = sortArr[i].z;
4775
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
4776
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
4777
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
4778
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
4779
+ }
4780
+ function radixPass(n, src, srcZ, dst, dstZ, shift) {
4781
+ counts.fill(0);
4782
+ for (let i = 0;i < n; i++)
4783
+ counts[srcZ[i] >>> shift & 255]++;
4784
+ let sum = 0;
4785
+ for (let b = 0;b < 256; b++) {
4786
+ const c = counts[b];
4787
+ counts[b] = sum;
4788
+ sum += c;
4789
+ }
4790
+ for (let i = 0;i < n; i++) {
4791
+ const z = srcZ[i];
4792
+ const pos = counts[z >>> shift & 255]++;
4793
+ dst[pos] = src[i];
4794
+ dstZ[pos] = z;
4795
+ }
4796
+ }
4797
+ function zOrder(x, y, minX, minY, invSize) {
4798
+ x = (x - minX) * invSize | 0;
4799
+ y = (y - minY) * invSize | 0;
4800
+ x = (x | x << 8) & 16711935;
4801
+ x = (x | x << 4) & 252645135;
4802
+ x = (x | x << 2) & 858993459;
4803
+ x = (x | x << 1) & 1431655765;
4804
+ y = (y | y << 8) & 16711935;
4805
+ y = (y | y << 4) & 252645135;
4806
+ y = (y | y << 2) & 858993459;
4807
+ y = (y | y << 1) & 1431655765;
4808
+ return x | y << 1;
4809
+ }
4810
+ function getLeftmost(start) {
4811
+ let p = start, leftmost = start;
4812
+ do {
4813
+ if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y)
4814
+ leftmost = p;
4815
+ p = p.next;
4816
+ } while (p !== start);
4817
+ return leftmost;
4818
+ }
4819
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
4820
+ return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
4821
+ }
4822
+ function isValidDiagonal(a, b) {
4823
+ const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
4824
+ return a.next.i !== b.i && (zeroLength || locallyInside(a, b) && locallyInside(b, a) && (area(a.prev, a, b.prev) !== 0 || area(a, b.prev, b) !== 0)) && !intersectsPolygon(a, b) && (zeroLength || middleInside(a, b));
4825
+ }
4826
+ function area(p, q, r) {
4827
+ return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
4828
+ }
4829
+ function equals(p1, p2) {
4830
+ return p1.x === p2.x && p1.y === p2.y;
4831
+ }
4832
+ function intersects(p1, q1, p2, q2, includeBoundary = true) {
4833
+ const o1 = area(p1, q1, p2);
4834
+ const o2 = area(p1, q1, q2);
4835
+ const o3 = area(p2, q2, p1);
4836
+ const o4 = area(p2, q2, q1);
4837
+ if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0))
4838
+ return true;
4839
+ if (!includeBoundary)
4840
+ return false;
4841
+ if (o1 === 0 && onSegment(p1, p2, q1))
4842
+ return true;
4843
+ if (o2 === 0 && onSegment(p1, q2, q1))
4844
+ return true;
4845
+ if (o3 === 0 && onSegment(p2, p1, q2))
4846
+ return true;
4847
+ if (o4 === 0 && onSegment(p2, q1, q2))
4848
+ return true;
4849
+ return false;
4850
+ }
4851
+ function onSegment(p, q, r) {
4852
+ return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
4853
+ }
4854
+ function intersectsPolygon(a, b) {
4855
+ const minX = Math.min(a.x, b.x);
4856
+ const maxX = Math.max(a.x, b.x);
4857
+ const minY = Math.min(a.y, b.y);
4858
+ const maxY = Math.max(a.y, b.y);
4859
+ let p = a;
4860
+ do {
4861
+ const n = p.next;
4862
+ if (p.x > maxX && n.x > maxX || p.x < minX && n.x < minX || p.y > maxY && n.y > maxY || p.y < minY && n.y < minY) {
4863
+ p = n;
4864
+ continue;
4865
+ }
4866
+ if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b))
4867
+ return true;
4868
+ p = n;
4869
+ } while (p !== a);
4870
+ return false;
4871
+ }
4872
+ function locallyInside(a, b) {
4873
+ return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
4874
+ }
4875
+ function middleInside(a, b) {
4876
+ let p = a;
4877
+ let inside = false;
4878
+ const px = (a.x + b.x) / 2;
4879
+ const py = (a.y + b.y) / 2;
4880
+ do {
4881
+ const n = p.next;
4882
+ if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
4883
+ inside = !inside;
4884
+ p = n;
4885
+ } while (p !== a);
4886
+ return inside;
4887
+ }
4888
+ function splitPolygon(a, b) {
4889
+ const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
4890
+ a.next = b;
4891
+ b.prev = a;
4892
+ a2.next = an;
4893
+ an.prev = a2;
4894
+ b2.next = a2;
4895
+ a2.prev = b2;
4896
+ bp.next = b2;
4897
+ b2.prev = bp;
4898
+ return b2;
4899
+ }
4900
+ function insertNode(i, x, y, last) {
4901
+ const p = createNode(i, x, y);
4902
+ if (!last) {
4903
+ p.prev = p;
4904
+ p.next = p;
4905
+ } else {
4906
+ p.next = last.next;
4907
+ p.prev = last;
4908
+ last.next.prev = p;
4909
+ last.next = p;
4910
+ }
4911
+ return p;
4912
+ }
4913
+ function removeNode(p) {
4914
+ p.next.prev = p.prev;
4915
+ p.prev.next = p.next;
4916
+ if (p.prevZ)
4917
+ p.prevZ.nextZ = p.nextZ;
4918
+ if (p.nextZ)
4919
+ p.nextZ.prevZ = p.prevZ;
4920
+ if (indexActive)
4921
+ growBlock(p.prev, p.next);
4922
+ }
4923
+ function createNode(i, x, y) {
4924
+ return {
4925
+ i,
4926
+ x,
4927
+ y,
4928
+ prev: null,
4929
+ next: null,
4930
+ z: 0,
4931
+ prevZ: null,
4932
+ nextZ: null
4933
+ };
4934
+ }
4935
+ function signedArea(data, start, end, dim) {
4936
+ let sum = 0;
4937
+ for (let i = start, j = end - dim;i < end; i += dim) {
4938
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
4939
+ j = i;
4940
+ }
4941
+ return sum;
4942
+ }
4943
+ function refine(triangles, coords, dim = 2) {
4944
+ const t = triangles;
4945
+ const n = t.length;
4946
+ if (n < 6)
4947
+ return;
4948
+ ensureScratch(n);
4949
+ gen++;
4950
+ he.fill(-1, 0, n);
4951
+ let i = 0;
4952
+ for (let e = 0;e < n; e++) {
4953
+ const a = t[e], b = t[nextHE(e)];
4954
+ const lo = a < b ? a : b, hi = a < b ? b : a;
4955
+ let h = (Math.imul(lo, 2654435761) ^ Math.imul(hi, 2246822507)) & hMask;
4956
+ while (hStamp[h] === gen) {
4957
+ const s = hTable[h];
4958
+ if (s !== -1) {
4959
+ const sa = t[s], sb = t[nextHE(s)];
4960
+ if (sa === lo && sb === hi || sa === hi && sb === lo) {
4961
+ he[e] = s;
4962
+ he[s] = e;
4963
+ hTable[h] = -1;
4964
+ edgeStamp[s] = 1;
4965
+ edgeStack[i++] = s;
4966
+ break;
4967
+ }
4968
+ }
4969
+ h = h + 1 & hMask;
4970
+ }
4971
+ if (hStamp[h] !== gen) {
4972
+ hTable[h] = e;
4973
+ hStamp[h] = gen;
4974
+ }
4975
+ }
4976
+ while (i > 0) {
4977
+ const a = edgeStack[--i];
4978
+ edgeStamp[a] = 0;
4979
+ const b = he[a];
4980
+ if (b === -1)
4981
+ continue;
4982
+ const a0 = a - a % 3;
4983
+ const b0 = b - b % 3;
4984
+ const ar = a0 + (a + 2) % 3;
4985
+ const al = a0 + (a + 1) % 3;
4986
+ const bl = b0 + (b + 2) % 3;
4987
+ const br = b0 + (b + 1) % 3;
4988
+ const p0 = t[ar], pr = t[a], pl = t[al], p1 = t[bl];
4989
+ const x0 = coords[p0 * dim], y0 = coords[p0 * dim + 1];
4990
+ const xr = coords[pr * dim], yr = coords[pr * dim + 1];
4991
+ const xl = coords[pl * dim], yl = coords[pl * dim + 1];
4992
+ const x1 = coords[p1 * dim], y1 = coords[p1 * dim + 1];
4993
+ if (!inCircle(x0, y0, xr, yr, xl, yl, x1, y1) && orient(x0, y0, xr, yr, x1, y1) > 0 && orient(x0, y0, x1, y1, xl, yl) > 0) {
4994
+ t[a] = p1;
4995
+ t[b] = p0;
4996
+ const hbl = he[bl], har = he[ar];
4997
+ he[a] = hbl;
4998
+ if (hbl !== -1)
4999
+ he[hbl] = a;
5000
+ he[b] = har;
5001
+ if (har !== -1)
5002
+ he[har] = b;
5003
+ he[ar] = bl;
5004
+ he[bl] = ar;
5005
+ if (hbl !== -1 && edgeStamp[a] === 0) {
5006
+ edgeStamp[a] = 1;
5007
+ edgeStack[i++] = a;
5008
+ }
5009
+ if (har !== -1 && edgeStamp[b] === 0) {
5010
+ edgeStamp[b] = 1;
5011
+ edgeStack[i++] = b;
5012
+ }
5013
+ if (he[al] !== -1 && edgeStamp[al] === 0) {
5014
+ edgeStamp[al] = 1;
5015
+ edgeStack[i++] = al;
5016
+ }
5017
+ if (he[br] !== -1 && edgeStamp[br] === 0) {
5018
+ edgeStamp[br] = 1;
5019
+ edgeStack[i++] = br;
5020
+ }
5021
+ }
5022
+ }
5023
+ }
5024
+ function orient(ax, ay, bx, by, cx, cy) {
5025
+ return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
5026
+ }
5027
+ function inCircle(ax, ay, bx, by, cx, cy, px, py) {
5028
+ const dx = ax - px, dy = ay - py, ex = bx - px, ey = by - py, fx = cx - px, fy = cy - py;
5029
+ const ap = dx * dx + dy * dy, bp = ex * ex + ey * ey, cp = fx * fx + fy * fy;
5030
+ const s = ap + bp + cp;
5031
+ return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) <= 0.0000000000001 * s * s;
5032
+ }
5033
+ function nextHE(e) {
5034
+ return e - e % 3 + (e + 1) % 3;
5035
+ }
5036
+ function ensureScratch(n) {
5037
+ if (!edgeStack || edgeStack.length < n)
5038
+ edgeStack = new Int32Array(n);
5039
+ if (!he || he.length < n)
5040
+ he = new Int32Array(n);
5041
+ if (!edgeStamp || edgeStamp.length < n)
5042
+ edgeStamp = new Uint8Array(n);
5043
+ let size = 1;
5044
+ while (size < n * 4)
5045
+ size <<= 1;
5046
+ if (!hTable || hTable.length < size) {
5047
+ hTable = new Int32Array(size);
5048
+ hStamp = new Uint32Array(size);
5049
+ }
5050
+ hMask = size - 1;
5051
+ }
5052
+ var steiners, filteredOut = false, indexActive = false, K = 16, blockBBox, numBlocks = 0, blockHead, blockStop, sortArr, sortBuf, zArr, zBuf, counts, edgeStack, he, hTable, hStamp, edgeStamp, hMask = 0, gen = 0;
5053
+ var init_earcut = __esm(() => {
5054
+ steiners = new Set;
5055
+ blockBBox = new Float64Array(0);
5056
+ blockHead = [];
5057
+ blockStop = [];
5058
+ sortArr = [];
5059
+ sortBuf = [];
5060
+ zArr = new Uint32Array(0);
5061
+ zBuf = new Uint32Array(0);
5062
+ counts = new Uint32Array(256);
5063
+ });
5064
+
4420
5065
  // node_modules/fflate/esm/index.mjs
4421
5066
  import { createRequire as createRequire2 } from "module";
4422
5067
  function deflateSync(data, opts) {
@@ -17555,6 +18200,7 @@ __export(exports_dist, {
17555
18200
  createEdgeDrawCall: () => createEdgeDrawCall,
17556
18201
  createGrid: () => createGrid,
17557
18202
  createInfiniteGrid: () => createInfiniteGrid,
18203
+ createOutlineSection: () => createOutlineSection,
17558
18204
  createSceneFromGLTF: () => createSceneFromGLTF,
17559
18205
  createUint8Bitmap: () => createUint8Bitmap,
17560
18206
  decodeImageFromBuffer: () => decodeImageFromBuffer,
@@ -17576,15 +18222,273 @@ import {
17576
18222
  glyphLineAlphabet,
17577
18223
  textMetrics
17578
18224
  } from "@tscircuit/alphabet";
18225
+ function findSectionLoops(input) {
18226
+ const { positions, axis, offset, epsilon = 0.00001 } = input;
18227
+ const k = axis === "x" ? 0 : axis === "y" ? 1 : 2;
18228
+ let minimum = Infinity, maximum = -Infinity;
18229
+ for (let i = k;i < positions.length; i += 3) {
18230
+ minimum = Math.min(minimum, positions[i]);
18231
+ maximum = Math.max(maximum, positions[i]);
18232
+ }
18233
+ if (offset <= minimum + epsilon || offset >= maximum - epsilon)
18234
+ return { loops: [], openChains: 0 };
18235
+ const u = (k + 1) % 3;
18236
+ const v = (k + 2) % 3;
18237
+ const points = /* @__PURE__ */ new Map;
18238
+ const adjacency = /* @__PURE__ */ new Map;
18239
+ const edges = /* @__PURE__ */ new Set;
18240
+ const key = (p) => `${Math.round(p[0] / epsilon)},${Math.round(p[1] / epsilon)}`;
18241
+ for (let i = 0;i < positions.length; i += 9) {
18242
+ const hits = [];
18243
+ const distances = [0, 1, 2].map((j) => positions[i + j * 3 + k] - offset);
18244
+ const onPlane = distances.filter((d) => Math.abs(d) <= epsilon).length;
18245
+ if (onPlane === 3)
18246
+ continue;
18247
+ if (!(distances.some((d) => d > epsilon) && distances.some((d) => d < -epsilon)) && !(onPlane === 2 && distances.some((d) => d < -epsilon)))
18248
+ continue;
18249
+ for (let j = 0;j < 3; j++) {
18250
+ const a2 = i + j * 3;
18251
+ const b2 = i + (j + 1) % 3 * 3;
18252
+ const da = distances[j];
18253
+ const db = distances[(j + 1) % 3];
18254
+ if (Math.abs(da) <= epsilon)
18255
+ hits.push([positions[a2 + u], positions[a2 + v]]);
18256
+ else if (da > 0 !== db > 0 && Math.abs(db) > epsilon) {
18257
+ const t = da / (da - db);
18258
+ hits.push([
18259
+ positions[a2 + u] + t * (positions[b2 + u] - positions[a2 + u]),
18260
+ positions[a2 + v] + t * (positions[b2 + v] - positions[a2 + v])
18261
+ ]);
18262
+ }
18263
+ }
18264
+ const unique = [...new Map(hits.map((p) => [key(p), p])).values()];
18265
+ if (unique.length !== 2)
18266
+ continue;
18267
+ const [a, b] = unique.map(key);
18268
+ if (a === b)
18269
+ continue;
18270
+ const edge2 = a < b ? `${a}|${b}` : `${b}|${a}`;
18271
+ if (edges.has(edge2))
18272
+ continue;
18273
+ edges.add(edge2);
18274
+ points.set(a, unique[0]);
18275
+ points.set(b, unique[1]);
18276
+ if (!adjacency.has(a))
18277
+ adjacency.set(a, /* @__PURE__ */ new Set);
18278
+ if (!adjacency.has(b))
18279
+ adjacency.set(b, /* @__PURE__ */ new Set);
18280
+ adjacency.get(a).add(b);
18281
+ adjacency.get(b).add(a);
18282
+ }
18283
+ const loops = [];
18284
+ let openChains = 0;
18285
+ while (edges.size) {
18286
+ const first = edges.values().next().value;
18287
+ const [start, next] = first.split("|");
18288
+ const path = [start];
18289
+ let previous = start;
18290
+ let current = next;
18291
+ const remove = (a, b) => {
18292
+ edges.delete(a < b ? `${a}|${b}` : `${b}|${a}`);
18293
+ adjacency.get(a)?.delete(b);
18294
+ adjacency.get(b)?.delete(a);
18295
+ };
18296
+ remove(start, next);
18297
+ while (current !== start) {
18298
+ path.push(current);
18299
+ const candidates = [...adjacency.get(current) ?? []];
18300
+ if (!candidates.length)
18301
+ break;
18302
+ const p = points.get(previous);
18303
+ const c = points.get(current);
18304
+ candidates.sort((a, b) => {
18305
+ const score = (s) => {
18306
+ const n = points.get(s);
18307
+ return ((c[0] - p[0]) * (n[0] - c[0]) + (c[1] - p[1]) * (n[1] - c[1])) / (Math.hypot(n[0] - c[0], n[1] - c[1]) || 1);
18308
+ };
18309
+ return score(b) - score(a);
18310
+ });
18311
+ const chosen = candidates[0];
18312
+ remove(current, chosen);
18313
+ previous = current;
18314
+ current = chosen;
18315
+ }
18316
+ if (current === start && path.length >= 3)
18317
+ loops.push(path.map((p) => points.get(p)));
18318
+ else
18319
+ openChains++;
18320
+ }
18321
+ return { loops, openChains };
18322
+ }
18323
+ function contains(p, polygon) {
18324
+ let inside = false;
18325
+ for (let i = 0, j = polygon.length - 1;i < polygon.length; j = i++) {
18326
+ const a = polygon[i], b = polygon[j];
18327
+ if (a[1] > p[1] !== b[1] > p[1] && p[0] < (b[0] - a[0]) * (p[1] - a[1]) / (b[1] - a[1]) + a[0])
18328
+ inside = !inside;
18329
+ }
18330
+ return inside;
18331
+ }
18332
+ function createOutlineSection(drawCalls, spec) {
18333
+ const k = spec.axis === "x" ? 0 : spec.axis === "y" ? 1 : 2;
18334
+ const u = (k + 1) % 3, v = (k + 2) % 3;
18335
+ const spacing = spec.hatchSpacing ?? 1;
18336
+ if (!["x", "y", "z"].includes(spec.axis) || !Number.isFinite(spec.offset) || !["less", "greater"].includes(spec.keepSide) || !Number.isFinite(spacing) || spacing <= 0)
18337
+ throw new Error("Invalid outline section plane or hatch spacing");
18338
+ const output = [];
18339
+ let openChains = 0;
18340
+ const texture = createUint8Bitmap(128, 128);
18341
+ for (let y = 0;y < 128; y++)
18342
+ for (let x = 0;x < 128; x++) {
18343
+ const c = (x + 127 - y) % 16 < 2 ? 0 : 255;
18344
+ texture.data.set([c, c, c, 255], (y * 128 + x) * 4);
18345
+ }
18346
+ const sign = spec.keepSide === "less" ? 1 : -1;
18347
+ for (const dc of drawCalls) {
18348
+ const points = [];
18349
+ for (let i = 0;i < dc.positions.length; i += 3)
18350
+ points.push(Array.from(import_gl_matrix.vec3.transformMat4(import_gl_matrix.vec3.create(), dc.positions.subarray(i, i + 3), dc.model)));
18351
+ const indices = dc.indices ?? Uint32Array.from(points, (_, i) => i);
18352
+ const clipped = [], triangles = [];
18353
+ const distance = (p) => sign * (p[k] - spec.offset);
18354
+ const intersection = (a, b) => {
18355
+ const t = distance(a) / (distance(a) - distance(b));
18356
+ return a.map((n, j) => n + t * (b[j] - n));
18357
+ };
18358
+ if (dc.mode === 1) {
18359
+ for (let i = 0;i + 1 < indices.length; i += 2) {
18360
+ let a = points[indices[i]], b = points[indices[i + 1]];
18361
+ if (distance(a) > 0 && distance(b) > 0)
18362
+ continue;
18363
+ if (distance(a) > 0)
18364
+ a = intersection(a, b);
18365
+ else if (distance(b) > 0)
18366
+ b = intersection(a, b);
18367
+ clipped.push(...a, ...b);
18368
+ }
18369
+ output.push({
18370
+ ...dc,
18371
+ positions: new Float32Array(clipped),
18372
+ indices: null,
18373
+ model: import_gl_matrix.mat4.create()
18374
+ });
18375
+ continue;
18376
+ }
18377
+ if (dc.mode != null && dc.mode !== 4)
18378
+ continue;
18379
+ for (let i = 0;i + 2 < indices.length; i += 3) {
18380
+ const triangle = [
18381
+ points[indices[i]],
18382
+ points[indices[i + 1]],
18383
+ points[indices[i + 2]]
18384
+ ];
18385
+ triangles.push(...triangle.flat());
18386
+ const polygon = [];
18387
+ for (let j = 0;j < 3; j++) {
18388
+ const a = triangle[j], b = triangle[(j + 1) % 3];
18389
+ if (distance(a) <= 0)
18390
+ polygon.push(a);
18391
+ if (distance(a) < 0 && distance(b) > 0 || distance(a) > 0 && distance(b) < 0)
18392
+ polygon.push(intersection(a, b));
18393
+ }
18394
+ for (let j = 1;j + 1 < polygon.length; j++)
18395
+ clipped.push(...polygon[0], ...polygon[j], ...polygon[j + 1]);
18396
+ }
18397
+ const white = {
18398
+ baseColorFactor: [1, 1, 1, 1],
18399
+ baseColorTexture: null
18400
+ };
18401
+ const mesh = {
18402
+ ...dc,
18403
+ positions: new Float32Array(clipped),
18404
+ indices: null,
18405
+ model: import_gl_matrix.mat4.create(),
18406
+ normals: null,
18407
+ colors: null,
18408
+ uvs: null,
18409
+ material: white
18410
+ };
18411
+ output.push(mesh);
18412
+ const extent = Math.max(...[0, 1, 2].map((axis) => {
18413
+ let min = Infinity, max = -Infinity;
18414
+ for (const p of points) {
18415
+ min = Math.min(min, p[axis]);
18416
+ max = Math.max(max, p[axis]);
18417
+ }
18418
+ return max - min;
18419
+ }));
18420
+ const result = findSectionLoops({
18421
+ positions: new Float32Array(triangles),
18422
+ axis: spec.axis,
18423
+ offset: spec.offset,
18424
+ epsilon: Math.max(extent * 0.0000001, 0.000000001)
18425
+ });
18426
+ openChains += result.openChains;
18427
+ const rings = result.loops.map((points2) => ({
18428
+ points: points2,
18429
+ area: Math.abs(points2.reduce((a, p, i) => {
18430
+ const q = points2[(i + 1) % points2.length];
18431
+ return a + p[0] * q[1] - q[0] * p[1];
18432
+ }, 0)),
18433
+ parent: -1,
18434
+ depth: 0
18435
+ })).sort((a, b) => b.area - a.area);
18436
+ rings.forEach((ring, i) => {
18437
+ for (let j = 0;j < i; j++)
18438
+ if (contains(ring.points[0], rings[j].points))
18439
+ ring.parent = j;
18440
+ ring.depth = ring.parent < 0 ? 0 : rings[ring.parent].depth + 1;
18441
+ });
18442
+ const cap = [], uv = [];
18443
+ rings.forEach((ring, i) => {
18444
+ if (ring.depth % 2)
18445
+ return;
18446
+ const holes = rings.filter((r) => r.parent === i && r.depth % 2);
18447
+ const flat = [...ring.points], starts = [];
18448
+ for (const hole of holes) {
18449
+ starts.push(flat.length);
18450
+ flat.push(...hole.points);
18451
+ }
18452
+ const faces = earcut(flat.flat(), starts, 2);
18453
+ for (let j = 0;j < faces.length; j += 3) {
18454
+ const ids = faces.slice(j, j + 3);
18455
+ const a = flat[ids[0]], b = flat[ids[1]], c = flat[ids[2]];
18456
+ if (((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) * sign < 0)
18457
+ ids.reverse();
18458
+ for (const id of ids) {
18459
+ const p = flat[id], xyz = [0, 0, 0];
18460
+ xyz[k] = spec.offset;
18461
+ xyz[u] = p[0];
18462
+ xyz[v] = p[1];
18463
+ cap.push(...xyz);
18464
+ uv.push(p[0] / (spacing * 8 * Math.SQRT2), p[1] / (spacing * 8 * Math.SQRT2));
18465
+ }
18466
+ }
18467
+ });
18468
+ if (cap.length)
18469
+ output.push({
18470
+ ...mesh,
18471
+ outlineSectionCap: true,
18472
+ positions: new Float32Array(cap),
18473
+ uvs: new Float32Array(uv),
18474
+ material: {
18475
+ ...white,
18476
+ baseColorTexture: texture,
18477
+ baseColorTextureWrap: "repeat"
18478
+ }
18479
+ });
18480
+ }
18481
+ return { drawCalls: output, openChains };
18482
+ }
17579
18483
  function computeWorldAABB(drawCalls) {
17580
18484
  const min = [Infinity, Infinity, Infinity];
17581
18485
  const max = [-Infinity, -Infinity, -Infinity];
17582
- const tmp = import_gl_matrix2.vec4.create();
18486
+ const tmp = import_gl_matrix3.vec4.create();
17583
18487
  for (const dc of drawCalls) {
17584
18488
  const { positions, model } = dc;
17585
18489
  for (let i = 0;i < positions.length; i += 3) {
17586
- import_gl_matrix2.vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
17587
- import_gl_matrix2.vec4.transformMat4(tmp, tmp, model);
18490
+ import_gl_matrix3.vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
18491
+ import_gl_matrix3.vec4.transformMat4(tmp, tmp, model);
17588
18492
  const x = tmp[0];
17589
18493
  const y = tmp[1];
17590
18494
  const z = tmp[2];
@@ -17607,75 +18511,75 @@ function computeWorldAABB(drawCalls) {
17607
18511
  function getWorldUpVector(up) {
17608
18512
  switch (up) {
17609
18513
  case "y-":
17610
- return import_gl_matrix.vec3.fromValues(0, -1, 0);
18514
+ return import_gl_matrix2.vec3.fromValues(0, -1, 0);
17611
18515
  case "x+":
17612
- return import_gl_matrix.vec3.fromValues(1, 0, 0);
18516
+ return import_gl_matrix2.vec3.fromValues(1, 0, 0);
17613
18517
  case "x-":
17614
- return import_gl_matrix.vec3.fromValues(-1, 0, 0);
18518
+ return import_gl_matrix2.vec3.fromValues(-1, 0, 0);
17615
18519
  case "z+":
17616
- return import_gl_matrix.vec3.fromValues(0, 0, 1);
18520
+ return import_gl_matrix2.vec3.fromValues(0, 0, 1);
17617
18521
  case "z-":
17618
- return import_gl_matrix.vec3.fromValues(0, 0, -1);
18522
+ return import_gl_matrix2.vec3.fromValues(0, 0, -1);
17619
18523
  case "y+":
17620
18524
  default:
17621
- return import_gl_matrix.vec3.fromValues(0, 1, 0);
18525
+ return import_gl_matrix2.vec3.fromValues(0, 1, 0);
17622
18526
  }
17623
18527
  }
17624
18528
  function buildCameraWorldMatrix(eye, forward, up) {
17625
- const normalizedForward = import_gl_matrix.vec3.normalize(import_gl_matrix.vec3.create(), forward);
17626
- const right = import_gl_matrix.vec3.cross(import_gl_matrix.vec3.create(), normalizedForward, up);
17627
- if (import_gl_matrix.vec3.squaredLength(right) === 0) {
18529
+ const normalizedForward = import_gl_matrix2.vec3.normalize(import_gl_matrix2.vec3.create(), forward);
18530
+ const right = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), normalizedForward, up);
18531
+ if (import_gl_matrix2.vec3.squaredLength(right) === 0) {
17628
18532
  return null;
17629
18533
  }
17630
- import_gl_matrix.vec3.normalize(right, right);
17631
- const correctedUp = import_gl_matrix.vec3.cross(import_gl_matrix.vec3.create(), right, normalizedForward);
17632
- if (import_gl_matrix.vec3.squaredLength(correctedUp) === 0) {
18534
+ import_gl_matrix2.vec3.normalize(right, right);
18535
+ const correctedUp = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), right, normalizedForward);
18536
+ if (import_gl_matrix2.vec3.squaredLength(correctedUp) === 0) {
17633
18537
  return null;
17634
18538
  }
17635
- import_gl_matrix.vec3.normalize(correctedUp, correctedUp);
17636
- return import_gl_matrix.mat4.fromValues(right[0], right[1], right[2], 0, correctedUp[0], correctedUp[1], correctedUp[2], 0, -normalizedForward[0], -normalizedForward[1], -normalizedForward[2], 0, eye[0], eye[1], eye[2], 1);
18539
+ import_gl_matrix2.vec3.normalize(correctedUp, correctedUp);
18540
+ return import_gl_matrix2.mat4.fromValues(right[0], right[1], right[2], 0, correctedUp[0], correctedUp[1], correctedUp[2], 0, -normalizedForward[0], -normalizedForward[1], -normalizedForward[2], 0, eye[0], eye[1], eye[2], 1);
17637
18541
  }
17638
18542
  function getDefaultForwardForUp(up) {
17639
- const zForward = import_gl_matrix.vec3.fromValues(0, 0, -1);
17640
- if (Math.abs(import_gl_matrix.vec3.dot(up, zForward)) < 0.999) {
18543
+ const zForward = import_gl_matrix2.vec3.fromValues(0, 0, -1);
18544
+ if (Math.abs(import_gl_matrix2.vec3.dot(up, zForward)) < 0.999) {
17641
18545
  return zForward;
17642
18546
  }
17643
- return import_gl_matrix.vec3.fromValues(1, 0, 0);
18547
+ return import_gl_matrix2.vec3.fromValues(1, 0, 0);
17644
18548
  }
17645
18549
  function buildViewFromRotation(eye, up, rotation) {
17646
18550
  const cameraWorld = buildCameraWorldMatrix(eye, getDefaultForwardForUp(up), up);
17647
18551
  if (!cameraWorld) {
17648
- return import_gl_matrix.mat4.create();
18552
+ return import_gl_matrix2.mat4.create();
17649
18553
  }
17650
18554
  if (rotation.x !== 0) {
17651
- import_gl_matrix.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
18555
+ import_gl_matrix2.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
17652
18556
  }
17653
18557
  if (rotation.y !== 0) {
17654
- import_gl_matrix.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
18558
+ import_gl_matrix2.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
17655
18559
  }
17656
18560
  if (rotation.z !== 0) {
17657
- import_gl_matrix.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
18561
+ import_gl_matrix2.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
17658
18562
  }
17659
- const view = import_gl_matrix.mat4.create();
17660
- import_gl_matrix.mat4.invert(view, cameraWorld);
18563
+ const view = import_gl_matrix2.mat4.create();
18564
+ import_gl_matrix2.mat4.invert(view, cameraWorld);
17661
18565
  return view;
17662
18566
  }
17663
18567
  function buildViewFromLookAt(eye, center, up) {
17664
- const forward = import_gl_matrix.vec3.subtract(import_gl_matrix.vec3.create(), center, eye);
17665
- if (import_gl_matrix.vec3.squaredLength(forward) === 0) {
17666
- return import_gl_matrix.mat4.create();
18568
+ const forward = import_gl_matrix2.vec3.subtract(import_gl_matrix2.vec3.create(), center, eye);
18569
+ if (import_gl_matrix2.vec3.squaredLength(forward) === 0) {
18570
+ return import_gl_matrix2.mat4.create();
17667
18571
  }
17668
18572
  const cameraWorld = buildCameraWorldMatrix(eye, forward, up);
17669
18573
  if (!cameraWorld) {
17670
- return import_gl_matrix.mat4.create();
18574
+ return import_gl_matrix2.mat4.create();
17671
18575
  }
17672
- const view = import_gl_matrix.mat4.create();
17673
- import_gl_matrix.mat4.invert(view, cameraWorld);
18576
+ const view = import_gl_matrix2.mat4.create();
18577
+ import_gl_matrix2.mat4.invert(view, cameraWorld);
17674
18578
  return view;
17675
18579
  }
17676
18580
  function getAutoDistance(drawCalls, fovDeg) {
17677
18581
  const aabb = computeWorldAABB(drawCalls);
17678
- const diag = import_gl_matrix.vec3.distance(import_gl_matrix.vec3.fromValues(aabb.min[0], aabb.min[1], aabb.min[2]), import_gl_matrix.vec3.fromValues(aabb.max[0], aabb.max[1], aabb.max[2]));
18582
+ const diag = import_gl_matrix2.vec3.distance(import_gl_matrix2.vec3.fromValues(aabb.min[0], aabb.min[1], aabb.min[2]), import_gl_matrix2.vec3.fromValues(aabb.max[0], aabb.max[1], aabb.max[2]));
17679
18583
  const radius = diag * 0.5;
17680
18584
  const fov = toRad(fovDeg);
17681
18585
  return radius / Math.tan(fov * 0.5) + radius * 0.5;
@@ -17689,7 +18593,7 @@ function getAABBCornerDistances(aabb, eye) {
17689
18593
  for (const x of xs) {
17690
18594
  for (const y of ys) {
17691
18595
  for (const z of zs) {
17692
- const distance = import_gl_matrix.vec3.distance(eye, import_gl_matrix.vec3.fromValues(x, y, z));
18596
+ const distance = import_gl_matrix2.vec3.distance(eye, import_gl_matrix2.vec3.fromValues(x, y, z));
17693
18597
  farthest = Math.max(farthest, distance);
17694
18598
  }
17695
18599
  }
@@ -17697,40 +18601,56 @@ function getAABBCornerDistances(aabb, eye) {
17697
18601
  return { nearest, farthest };
17698
18602
  }
17699
18603
  function getCameraForwardFromView(view) {
17700
- const cameraWorld = import_gl_matrix.mat4.create();
17701
- import_gl_matrix.mat4.invert(cameraWorld, view);
17702
- return import_gl_matrix.vec3.fromValues(-cameraWorld[8], -cameraWorld[9], -cameraWorld[10]);
18604
+ const cameraWorld = import_gl_matrix2.mat4.create();
18605
+ import_gl_matrix2.mat4.invert(cameraWorld, view);
18606
+ return import_gl_matrix2.vec3.fromValues(-cameraWorld[8], -cameraWorld[9], -cameraWorld[10]);
17703
18607
  }
17704
- function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null) {
18608
+ function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null, projection = "perspective", orthographicHeight = null) {
17705
18609
  const aspect = width / height;
17706
18610
  const worldUp = getWorldUpVector(up);
17707
18611
  const aabb = computeWorldAABB(drawCalls);
17708
- const center = import_gl_matrix.vec3.fromValues(0.5 * (aabb.min[0] + aabb.max[0]), 0.5 * (aabb.min[1] + aabb.max[1]), 0.5 * (aabb.min[2] + aabb.max[2]));
18612
+ const center = import_gl_matrix2.vec3.fromValues(0.5 * (aabb.min[0] + aabb.max[0]), 0.5 * (aabb.min[1] + aabb.max[1]), 0.5 * (aabb.min[2] + aabb.max[2]));
17709
18613
  const autoDistance = getAutoDistance(drawCalls, fovDeg);
17710
18614
  if (cameraRotation) {
17711
- const provisionalEye = camPos ? import_gl_matrix.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix.vec3.clone(center);
18615
+ const provisionalEye = camPos ? import_gl_matrix2.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix2.vec3.clone(center);
17712
18616
  const provisionalView = buildViewFromRotation(provisionalEye, worldUp, cameraRotation);
17713
- const eye2 = camPos ? provisionalEye : import_gl_matrix.vec3.scaleAndAdd(import_gl_matrix.vec3.create(), center, getCameraForwardFromView(provisionalView), -autoDistance);
18617
+ const eye2 = camPos ? provisionalEye : import_gl_matrix2.vec3.scaleAndAdd(import_gl_matrix2.vec3.create(), center, getCameraForwardFromView(provisionalView), -autoDistance);
17714
18618
  const { nearest: nearest2, farthest: farthest2 } = getAABBCornerDistances(aabb, eye2);
17715
18619
  const near2 = Math.max(0.01, nearest2 * 0.5);
17716
18620
  const far2 = Math.max(1000, farthest2 * 1.1);
17717
- const proj2 = import_gl_matrix.mat4.create();
17718
- import_gl_matrix.mat4.perspective(proj2, toRad(fovDeg), aspect, near2, far2);
18621
+ const proj2 = import_gl_matrix2.mat4.create();
18622
+ const view2 = buildViewFromRotation(eye2, worldUp, cameraRotation);
18623
+ setProjection(proj2, view2, aabb, projection, orthographicHeight, fovDeg, aspect, near2, far2);
17719
18624
  return {
17720
- view: buildViewFromRotation(eye2, worldUp, cameraRotation),
18625
+ view: view2,
17721
18626
  proj: proj2
17722
18627
  };
17723
18628
  }
17724
- const eye = camPos ? import_gl_matrix.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix.vec3.fromValues(center[0] + autoDistance, center[1] + autoDistance * 0.3, center[2] + autoDistance);
17725
- const target = lookAt ? import_gl_matrix.vec3.fromValues(lookAt[0], lookAt[1], lookAt[2]) : center;
18629
+ const eye = camPos ? import_gl_matrix2.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix2.vec3.fromValues(center[0] + autoDistance, center[1] + autoDistance * 0.3, center[2] + autoDistance);
18630
+ const target = lookAt ? import_gl_matrix2.vec3.fromValues(lookAt[0], lookAt[1], lookAt[2]) : center;
17726
18631
  const { nearest, farthest } = getAABBCornerDistances(aabb, eye);
17727
18632
  const near = Math.max(0.01, nearest * 0.5);
17728
18633
  const far = Math.max(1000, farthest * 1.1);
17729
- const proj = import_gl_matrix.mat4.create();
17730
- import_gl_matrix.mat4.perspective(proj, toRad(fovDeg), aspect, near, far);
18634
+ const proj = import_gl_matrix2.mat4.create();
17731
18635
  const view = buildViewFromLookAt(eye, target, worldUp);
18636
+ setProjection(proj, view, aabb, projection, orthographicHeight, fovDeg, aspect, near, far);
17732
18637
  return { view, proj };
17733
18638
  }
18639
+ function setProjection(proj, view, aabb, projection, height, fov, aspect, near, far) {
18640
+ if (projection === "perspective") {
18641
+ import_gl_matrix2.mat4.perspective(proj, toRad(fov), aspect, near, far);
18642
+ return;
18643
+ }
18644
+ let halfHeight = 0;
18645
+ for (const x of [aabb.min[0], aabb.max[0]])
18646
+ for (const y of [aabb.min[1], aabb.max[1]])
18647
+ for (const z of [aabb.min[2], aabb.max[2]]) {
18648
+ const p = import_gl_matrix2.vec3.transformMat4(import_gl_matrix2.vec3.create(), [x, y, z], view);
18649
+ halfHeight = Math.max(halfHeight, Math.abs(p[1]), Math.abs(p[0]) / aspect);
18650
+ }
18651
+ halfHeight = height != null && Number.isFinite(height) && height > 0 ? height / 2 : Math.max(halfHeight * 1.1, 0.001);
18652
+ import_gl_matrix2.mat4.ortho(proj, -halfHeight * aspect, halfHeight * aspect, -halfHeight, halfHeight, near, far);
18653
+ }
17734
18654
  function createGrid(options = {}) {
17735
18655
  const size = options.size ?? 10;
17736
18656
  const sizeX = typeof size === "number" ? size : size[0];
@@ -17755,8 +18675,8 @@ function createGrid(options = {}) {
17755
18675
  positions.push(halfSizeX, 0, pZ);
17756
18676
  indices.push(vertexIndex++, vertexIndex++);
17757
18677
  }
17758
- const model = import_gl_matrix3.mat4.create();
17759
- import_gl_matrix3.mat4.fromTranslation(model, [offset.x, offset.y, offset.z]);
18678
+ const model = import_gl_matrix4.mat4.create();
18679
+ import_gl_matrix4.mat4.fromTranslation(model, [offset.x, offset.y, offset.z]);
17760
18680
  return {
17761
18681
  positions: new Float32Array(positions),
17762
18682
  indices: new Uint32Array(indices),
@@ -17788,7 +18708,7 @@ function triangleNormal(positions, i0, i1, i2) {
17788
18708
  return null;
17789
18709
  return [nx / length, ny / length, nz / length];
17790
18710
  }
17791
- function addEdge(edges, positions, i0, i1, normal) {
18711
+ function addEdge(edges, positions, i0, i1, thirdVertex, normal, facing) {
17792
18712
  const key0 = positionKey(positions, i0);
17793
18713
  const key1 = positionKey(positions, i1);
17794
18714
  const isForward = key0 < key1;
@@ -17798,8 +18718,15 @@ function addEdge(edges, positions, i0, i1, normal) {
17798
18718
  if (existing) {
17799
18719
  if (normal)
17800
18720
  existing.normals.push(normal);
18721
+ existing.adjacentVertices.push(thirdVertex);
18722
+ existing.facings.push(facing);
17801
18723
  } else {
17802
- edges.set(key, { indices, normals: normal ? [normal] : [] });
18724
+ edges.set(key, {
18725
+ indices,
18726
+ normals: normal ? [normal] : [],
18727
+ adjacentVertices: [thirdVertex],
18728
+ facings: [facing]
18729
+ });
17803
18730
  }
17804
18731
  }
17805
18732
  function hasCrease(normals, minimumDot) {
@@ -17816,29 +18743,42 @@ function hasCrease(normals, minimumDot) {
17816
18743
  }
17817
18744
  return false;
17818
18745
  }
17819
- function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES) {
18746
+ function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES, camera) {
17820
18747
  if (mesh.mode != null && mesh.mode !== 4)
17821
18748
  return null;
17822
18749
  const vertexCount = Math.floor(mesh.positions.length / 3);
17823
18750
  const triangleIndices = mesh.indices ?? Uint32Array.from({ length: vertexCount }, (_, i) => i);
17824
18751
  if (triangleIndices.length < 3)
17825
18752
  return null;
18753
+ let normalPositions = mesh.positions;
18754
+ if (camera) {
18755
+ const modelView = import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), camera.view, mesh.model);
18756
+ normalPositions = new Float32Array(mesh.positions.length);
18757
+ for (let i = 0;i < vertexCount; i++) {
18758
+ const point = import_gl_matrix5.vec3.transformMat4(import_gl_matrix5.vec3.create(), mesh.positions.subarray(i * 3, i * 3 + 3), modelView);
18759
+ normalPositions.set(point, i * 3);
18760
+ }
18761
+ }
17826
18762
  const edges = /* @__PURE__ */ new Map;
17827
18763
  for (let i = 0;i + 2 < triangleIndices.length; i += 3) {
17828
18764
  const i0 = triangleIndices[i];
17829
18765
  const i1 = triangleIndices[i + 1];
17830
18766
  const i2 = triangleIndices[i + 2];
17831
- const normal = triangleNormal(mesh.positions, i0, i1, i2);
17832
- addEdge(edges, mesh.positions, i0, i1, normal);
17833
- addEdge(edges, mesh.positions, i1, i2, normal);
17834
- addEdge(edges, mesh.positions, i2, i0, normal);
18767
+ const normal = triangleNormal(normalPositions, i0, i1, i2);
18768
+ const facing = !normal ? 0 : camera?.projection === "perspective" ? -(normal[0] * normalPositions[i0 * 3] + normal[1] * normalPositions[i0 * 3 + 1] + normal[2] * normalPositions[i0 * 3 + 2]) : normal[2];
18769
+ addEdge(edges, mesh.positions, i0, i1, i2, normal, facing);
18770
+ addEdge(edges, mesh.positions, i1, i2, i0, normal, facing);
18771
+ addEdge(edges, mesh.positions, i2, i0, i1, normal, facing);
17835
18772
  }
17836
18773
  const minimumDot = Math.cos(creaseAngleDegrees * Math.PI / 180);
17837
18774
  const edgeIndices = [];
18775
+ const edgeAdjacentVertices = [];
17838
18776
  for (const edge2 of edges.values()) {
17839
- if (!hasCrease(edge2.normals, minimumDot))
18777
+ const silhouette = camera && edge2.facings.some((n) => n > 0.0000001) && edge2.facings.some((n) => n <= 0.0000001);
18778
+ if (!hasCrease(edge2.normals, minimumDot) && !silhouette)
17840
18779
  continue;
17841
18780
  edgeIndices.push(edge2.indices[0], edge2.indices[1]);
18781
+ edgeAdjacentVertices.push(edge2.adjacentVertices);
17842
18782
  }
17843
18783
  if (edgeIndices.length === 0)
17844
18784
  return null;
@@ -17853,7 +18793,8 @@ function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGR
17853
18793
  baseColorTexture: null,
17854
18794
  alphaMode: "BLEND"
17855
18795
  },
17856
- mode: 1
18796
+ mode: 1,
18797
+ edgeAdjacentVertices
17857
18798
  };
17858
18799
  }
17859
18800
  function downsampleBitmap(source, targetWidth, targetHeight, imageFactory) {
@@ -18060,14 +19001,102 @@ function clipMeshToNearPlane(mesh, mvp) {
18060
19001
  indices: new Uint32Array(indices)
18061
19002
  };
18062
19003
  }
19004
+ function clipLine(start, end, marginX, marginY) {
19005
+ if (![...start, ...end].every(Number.isFinite))
19006
+ return null;
19007
+ const distances = (p) => [
19008
+ p[3] * (1 + marginX) + p[0],
19009
+ p[3] * (1 + marginX) - p[0],
19010
+ p[3] * (1 + marginY) + p[1],
19011
+ p[3] * (1 + marginY) - p[1],
19012
+ p[3] + p[2],
19013
+ p[3] - p[2]
19014
+ ];
19015
+ const a = distances(start);
19016
+ const b = distances(end);
19017
+ let from = 0;
19018
+ let to = 1;
19019
+ for (let plane = 0;plane < 6; plane++) {
19020
+ if (a[plane] < 0 && b[plane] < 0)
19021
+ return null;
19022
+ if (a[plane] < 0 !== b[plane] < 0) {
19023
+ const t = a[plane] / (a[plane] - b[plane]);
19024
+ if (a[plane] < 0)
19025
+ from = Math.max(from, t);
19026
+ else
19027
+ to = Math.min(to, t);
19028
+ }
19029
+ }
19030
+ if (from > to)
19031
+ return null;
19032
+ return [from, to].map((t) => Array.from(start, (value, axis) => value + t * (end[axis] - value)));
19033
+ }
19034
+ function rasterizeWideLine(start, end, width, height, strokeWidth, dashed, dashLength, fragment) {
19035
+ const radius = strokeWidth / 2;
19036
+ const padding = radius + 0.5;
19037
+ const clipped = clipLine(start, end, 2 * padding / Math.max(1, width - 1), 2 * padding / Math.max(1, height - 1));
19038
+ if (!clipped)
19039
+ return;
19040
+ const project = (p) => [
19041
+ (p[0] / p[3] * 0.5 + 0.5) * (width - 1),
19042
+ (0.5 - p[1] / p[3] * 0.5) * (height - 1),
19043
+ Math.max(0, Math.min(1, p[2] / p[3] * 0.5 + 0.5))
19044
+ ];
19045
+ const a = project(clipped[0]);
19046
+ const b = project(clipped[1]);
19047
+ if (![...a, ...b].every(Number.isFinite))
19048
+ return;
19049
+ const [x0, y0, z0] = a;
19050
+ const [x1, y1, z1] = b;
19051
+ const dx = x1 - x0;
19052
+ const dy = y1 - y0;
19053
+ const lengthSquared = dx * dx + dy * dy;
19054
+ const length = Math.sqrt(lengthSquared);
19055
+ const original = start[3] > 0 ? project(start) : a;
19056
+ const phase = Math.hypot(x0 - original[0], y0 - original[1]);
19057
+ const drawPixel = (x, y) => {
19058
+ const t = lengthSquared === 0 ? 0 : Math.max(0, Math.min(1, ((x - x0) * dx + (y - y0) * dy) / lengthSquared));
19059
+ if (dashed && Math.floor((phase + t * length) / dashLength) % 2 === 1)
19060
+ return;
19061
+ const distance = Math.hypot(x - (x0 + t * dx), y - (y0 + t * dy));
19062
+ const coverage = Math.min(1, padding - distance);
19063
+ if (coverage > 0)
19064
+ fragment(x, y, z0 + t * (z1 - z0), coverage);
19065
+ };
19066
+ if (Math.abs(dx) >= Math.abs(dy)) {
19067
+ const band = length === 0 ? padding : padding * length / Math.abs(dx);
19068
+ const first = Math.max(0, Math.ceil(Math.min(x0, x1) - padding));
19069
+ const last = Math.min(width - 1, Math.floor(Math.max(x0, x1) + padding));
19070
+ for (let x = first;x <= last; x++) {
19071
+ const t = dx === 0 ? 0 : Math.max(0, Math.min(1, (x - x0) / dx));
19072
+ const centerY = y0 + t * dy;
19073
+ const top = Math.max(0, Math.ceil(centerY - band));
19074
+ const bottom = Math.min(height - 1, Math.floor(centerY + band));
19075
+ for (let y = top;y <= bottom; y++)
19076
+ drawPixel(x, y);
19077
+ }
19078
+ } else {
19079
+ const band = padding * length / Math.abs(dy);
19080
+ const first = Math.max(0, Math.ceil(Math.min(y0, y1) - padding));
19081
+ const last = Math.min(height - 1, Math.floor(Math.max(y0, y1) + padding));
19082
+ for (let y = first;y <= last; y++) {
19083
+ const t = Math.max(0, Math.min(1, (y - y0) / dy));
19084
+ const centerX = x0 + t * dx;
19085
+ const left = Math.max(0, Math.ceil(centerX - band));
19086
+ const right = Math.min(width - 1, Math.floor(centerX + band));
19087
+ for (let x = left;x <= right; x++)
19088
+ drawPixel(x, y);
19089
+ }
19090
+ }
19091
+ }
18063
19092
  function edge(a, b, p) {
18064
19093
  return (p[0] - a[0]) * (b[1] - a[1]) - (p[1] - a[1]) * (b[0] - a[0]);
18065
19094
  }
18066
19095
  function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPointColor, debugLabelColor) {
18067
19096
  if (debugPoints.length === 0)
18068
19097
  return;
18069
- const viewProj = import_gl_matrix4.mat4.create();
18070
- import_gl_matrix4.mat4.multiply(viewProj, camera.proj, camera.view);
19098
+ const viewProj = import_gl_matrix6.mat4.create();
19099
+ import_gl_matrix6.mat4.multiply(viewProj, camera.proj, camera.view);
18071
19100
  const markerColor = toColorRGBA(debugPointColor, DEFAULT_MARKER_COLOR);
18072
19101
  const textColor = toColorRGBA(debugLabelColor, DEFAULT_TEXT_COLOR);
18073
19102
  const labelScale = typeof debugFontSize === "number" && Number.isFinite(debugFontSize) ? Math.max(1, Math.round(debugFontSize)) : Math.max(12, Math.round(Math.min(renderer.width, renderer.height) * 0.028));
@@ -18081,8 +19110,8 @@ function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPoin
18081
19110
  }
18082
19111
  }
18083
19112
  function projectWorldToScreen(position, viewProj, renderer) {
18084
- const clip = import_gl_matrix4.vec4.fromValues(position.x, position.y, position.z, 1);
18085
- import_gl_matrix4.vec4.transformMat4(clip, clip, viewProj);
19113
+ const clip = import_gl_matrix6.vec4.fromValues(position.x, position.y, position.z, 1);
19114
+ import_gl_matrix6.vec4.transformMat4(clip, clip, viewProj);
18086
19115
  if (!Number.isFinite(clip[3]) || clip[3] <= 0)
18087
19116
  return null;
18088
19117
  const invW = 1 / clip[3];
@@ -18210,23 +19239,23 @@ function drawInfiniteGrid(software_renderer, params) {
18210
19239
  const camera = params.camera;
18211
19240
  const view = camera.view;
18212
19241
  const proj = camera.proj;
18213
- const inv_view = import_gl_matrix6.mat4.create();
18214
- import_gl_matrix6.mat4.invert(inv_view, view);
19242
+ const inv_view = import_gl_matrix8.mat4.create();
19243
+ import_gl_matrix8.mat4.invert(inv_view, view);
18215
19244
  const cam_pos_x = inv_view[12];
18216
19245
  const cam_pos_y = inv_view[13];
18217
19246
  const cam_pos_z = inv_view[14];
18218
- const vp = import_gl_matrix6.mat4.create();
18219
- import_gl_matrix6.mat4.multiply(vp, proj, view);
18220
- const inv_vp = import_gl_matrix6.mat4.create();
18221
- import_gl_matrix6.mat4.invert(inv_vp, vp);
19247
+ const vp = import_gl_matrix8.mat4.create();
19248
+ import_gl_matrix8.mat4.multiply(vp, proj, view);
19249
+ const inv_vp = import_gl_matrix8.mat4.create();
19250
+ import_gl_matrix8.mat4.invert(inv_vp, vp);
18222
19251
  for (let y = 0;y < software_renderer.height; y++) {
18223
19252
  for (let x = 0;x < software_renderer.width; x++) {
18224
19253
  const ndc_x = x / (software_renderer.width - 1) * 2 - 1;
18225
19254
  const ndc_y = 1 - y / (software_renderer.height - 1) * 2;
18226
- const near_point = import_gl_matrix6.vec4.fromValues(ndc_x, ndc_y, -1, 1);
18227
- const far_point = import_gl_matrix6.vec4.fromValues(ndc_x, ndc_y, 1, 1);
18228
- import_gl_matrix6.vec4.transformMat4(near_point, near_point, inv_vp);
18229
- import_gl_matrix6.vec4.transformMat4(far_point, far_point, inv_vp);
19255
+ const near_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, -1, 1);
19256
+ const far_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, 1, 1);
19257
+ import_gl_matrix8.vec4.transformMat4(near_point, near_point, inv_vp);
19258
+ import_gl_matrix8.vec4.transformMat4(far_point, far_point, inv_vp);
18230
19259
  near_point[0] /= near_point[3];
18231
19260
  near_point[1] /= near_point[3];
18232
19261
  near_point[2] /= near_point[3];
@@ -18243,9 +19272,9 @@ function drawInfiniteGrid(software_renderer, params) {
18243
19272
  continue;
18244
19273
  const world_x = near_point[0] + t * ray_dir_x;
18245
19274
  const world_z = near_point[2] + t * ray_dir_z;
18246
- const world_pt = import_gl_matrix6.vec4.fromValues(world_x, grid_y, world_z, 1);
18247
- const clip_pt = import_gl_matrix6.vec4.create();
18248
- import_gl_matrix6.vec4.transformMat4(clip_pt, world_pt, vp);
19275
+ const world_pt = import_gl_matrix8.vec4.fromValues(world_x, grid_y, world_z, 1);
19276
+ const clip_pt = import_gl_matrix8.vec4.create();
19277
+ import_gl_matrix8.vec4.transformMat4(clip_pt, world_pt, vp);
18249
19278
  const ndc_z = clip_pt[2] / clip_pt[3];
18250
19279
  const depth_01 = ndc_z * 0.5 + 0.5;
18251
19280
  const di = y * software_renderer.width + x;
@@ -18331,17 +19360,36 @@ function resolveCameraRotation(cameraRotation) {
18331
19360
  }
18332
19361
  function resolveRenderOptions(options = {}) {
18333
19362
  const supersampling = typeof options.supersampling === "number" && Number.isFinite(options.supersampling) ? Math.max(1, Math.floor(options.supersampling)) : DEFAULT_RENDER_OPTIONS.supersampling;
19363
+ const outline = options.renderStyle === "outline";
18334
19364
  return {
18335
19365
  ...DEFAULT_RENDER_OPTIONS,
18336
19366
  ...options,
19367
+ renderStyle: outline ? "outline" : "shaded",
19368
+ projection: options.projection === "orthographic" || outline && options.projection !== "perspective" ? "orthographic" : "perspective",
19369
+ orthographicHeight: typeof options.orthographicHeight === "number" && Number.isFinite(options.orthographicHeight) && options.orthographicHeight > 0 ? options.orthographicHeight : null,
19370
+ ...outline ? {
19371
+ realistic: false,
19372
+ ambient: 1,
19373
+ gamma: false,
19374
+ cull: false,
19375
+ backgroundColor: options.backgroundColor ?? "#ffffff"
19376
+ } : {},
18337
19377
  supersampling,
18338
19378
  lightDir: options.lightDir != null ? options.lightDir : DEFAULT_RENDER_OPTIONS.lightDir,
18339
19379
  camPos: options.camPos !== undefined ? options.camPos : DEFAULT_RENDER_OPTIONS.camPos,
18340
19380
  lookAt: options.lookAt !== undefined ? options.lookAt : DEFAULT_RENDER_OPTIONS.lookAt,
18341
19381
  up: resolveCameraUp(options.up),
18342
- cameraRotation: resolveCameraRotation(options.cameraRotation)
19382
+ cameraRotation: resolveCameraRotation(options.cameraRotation),
19383
+ showEdges: options.showEdges ?? outline,
19384
+ showHiddenEdges: typeof options.showHiddenEdges === "boolean" ? options.showHiddenEdges : outline ? false : null,
19385
+ edgeWidth: resolveWidth(options.edgeWidth),
19386
+ lineWidth: resolveWidth(options.lineWidth),
19387
+ hiddenEdgeOpacity: typeof options.hiddenEdgeOpacity === "number" && Number.isFinite(options.hiddenEdgeOpacity) ? Math.max(0, Math.min(1, options.hiddenEdgeOpacity)) : DEFAULT_RENDER_OPTIONS.hiddenEdgeOpacity
18343
19388
  };
18344
19389
  }
19390
+ function resolveWidth(width) {
19391
+ return typeof width === "number" && Number.isFinite(width) && width > 0 ? width : 1;
19392
+ }
18345
19393
  function dotNormal(normal, direction) {
18346
19394
  return normal[0] * direction[0] + normal[1] * direction[1] + normal[2] * direction[2];
18347
19395
  }
@@ -18365,7 +19413,7 @@ function basis(n) {
18365
19413
  ]
18366
19414
  ];
18367
19415
  }
18368
- function orient(x, y, z, n, t, b) {
19416
+ function orient2(x, y, z, n, t, b) {
18369
19417
  return [
18370
19418
  t[0] * x + b[0] * y + n[0] * z,
18371
19419
  t[1] * x + b[1] * y + n[1] * z,
@@ -18407,14 +19455,14 @@ function getTables() {
18407
19455
  ];
18408
19456
  const [t, b] = basis(n), index = y * W + x;
18409
19457
  for (const s of diffuseSamples) {
18410
- const l = orient(...s, n, t, b);
19458
+ const l = orient2(...s, n, t, b);
18411
19459
  for (let j = 0;j < lobes.length; j++)
18412
19460
  diffuse[j][index] += Math.exp(lobes[j].sharpness * (dot(l, lobes[j].direction) - 1)) / SAMPLES;
18413
19461
  }
18414
19462
  for (let r = 0;r < ROUGHNESSES.length; r++) {
18415
19463
  let weight = 0;
18416
19464
  for (const s of halfSamples[r]) {
18417
- const h = orient(...s, n, t, b), nh = dot(n, h);
19465
+ const h = orient2(...s, n, t, b), nh = dot(n, h);
18418
19466
  const l = [
18419
19467
  2 * nh * h[0] - n[0],
18420
19468
  2 * nh * h[1] - n[1],
@@ -18455,11 +19503,150 @@ function getTables() {
18455
19503
  cachedTables = { diffuse, specular, brdf };
18456
19504
  return cachedTables;
18457
19505
  }
19506
+ function createExplosionLineDrawCall(line) {
19507
+ if (line.points.length < 2 || line.points.some((point) => point.length !== 3 || !point.every(Number.isFinite))) {
19508
+ throw new Error("Explosion lines need at least two finite XYZ points");
19509
+ }
19510
+ const color = line.color ?? [0.08, 0.2, 0.35];
19511
+ if (color.length !== 3 || color.some((channel) => !Number.isFinite(channel) || channel < 0 || channel > 1)) {
19512
+ throw new Error("Explosion line colors must be linear RGB values from 0 to 1");
19513
+ }
19514
+ const indices = [];
19515
+ for (let vertex = 1;vertex < line.points.length; vertex++) {
19516
+ indices.push(vertex - 1, vertex);
19517
+ }
19518
+ return {
19519
+ positions: new Float32Array(line.points.flatMap((point) => [...point])),
19520
+ indices: new Uint32Array(indices),
19521
+ normals: null,
19522
+ uvs: null,
19523
+ model: import_gl_matrix11.mat4.create(),
19524
+ material: { baseColorFactor: [...color, 1], baseColorTexture: null },
19525
+ mode: 1
19526
+ };
19527
+ }
19528
+ function clipExplosionLineDrawCall(drawCall, camera) {
19529
+ const viewProjection = import_gl_matrix11.mat4.multiply(import_gl_matrix11.mat4.create(), camera.proj, camera.view);
19530
+ const positions = [];
19531
+ const indices = [];
19532
+ const distances = (point) => [
19533
+ point[3] + point[0],
19534
+ point[3] - point[0],
19535
+ point[3] + point[1],
19536
+ point[3] - point[1],
19537
+ point[3] + point[2],
19538
+ point[3] - point[2]
19539
+ ];
19540
+ for (let segment = 0;segment < drawCall.indices.length; segment += 2) {
19541
+ const startIndex = drawCall.indices[segment] * 3;
19542
+ const endIndex = drawCall.indices[segment + 1] * 3;
19543
+ const start = import_gl_matrix11.vec4.fromValues(drawCall.positions[startIndex], drawCall.positions[startIndex + 1], drawCall.positions[startIndex + 2], 1);
19544
+ const end = import_gl_matrix11.vec4.fromValues(drawCall.positions[endIndex], drawCall.positions[endIndex + 1], drawCall.positions[endIndex + 2], 1);
19545
+ const startDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), start, viewProjection));
19546
+ const endDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), end, viewProjection));
19547
+ let from = 0;
19548
+ let to = 1;
19549
+ for (let plane = 0;plane < 6; plane++) {
19550
+ const a = startDistances[plane];
19551
+ const b = endDistances[plane];
19552
+ if (a < 0 && b < 0) {
19553
+ to = -1;
19554
+ break;
19555
+ }
19556
+ if (a < 0 !== b < 0) {
19557
+ const intersection = a / (a - b);
19558
+ if (a < 0)
19559
+ from = Math.max(from, intersection);
19560
+ else
19561
+ to = Math.min(to, intersection);
19562
+ }
19563
+ }
19564
+ if (from > to)
19565
+ continue;
19566
+ const vertex = positions.length / 3;
19567
+ for (const progress of [from, to]) {
19568
+ for (let axis = 0;axis < 3; axis++) {
19569
+ positions.push(start[axis] + progress * (end[axis] - start[axis]));
19570
+ }
19571
+ }
19572
+ indices.push(vertex, vertex + 1);
19573
+ }
19574
+ return {
19575
+ ...drawCall,
19576
+ positions: new Float32Array(positions),
19577
+ indices: new Uint32Array(indices)
19578
+ };
19579
+ }
19580
+ function createExplosionArrowDrawCall(drawCall, camera, width, height, supersampling) {
19581
+ if (width <= 1 || height <= 1)
19582
+ return null;
19583
+ const points = drawCall.positions;
19584
+ const end = points.length - 3;
19585
+ let start = end - 3;
19586
+ while (start >= 0 && points[start] === points[end] && points[start + 1] === points[end + 1] && points[start + 2] === points[end + 2]) {
19587
+ start -= 3;
19588
+ }
19589
+ if (start < 0)
19590
+ return null;
19591
+ const viewProjection = import_gl_matrix12.mat4.multiply(import_gl_matrix12.mat4.create(), camera.proj, camera.view);
19592
+ const tip = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(points[end], points[end + 1], points[end + 2], 1), viewProjection);
19593
+ if (!Array.from(tip).every(Number.isFinite) || tip[3] <= 0 || Math.abs(tip[0]) > tip[3] || Math.abs(tip[1]) > tip[3] || Math.abs(tip[2]) > tip[3]) {
19594
+ return null;
19595
+ }
19596
+ const clipped = clipExplosionLineDrawCall({
19597
+ ...drawCall,
19598
+ positions: new Float32Array([
19599
+ points[start],
19600
+ points[start + 1],
19601
+ points[start + 2],
19602
+ points[end],
19603
+ points[end + 1],
19604
+ points[end + 2]
19605
+ ]),
19606
+ indices: new Uint32Array([0, 1])
19607
+ }, camera);
19608
+ if (!clipped.indices?.length)
19609
+ return null;
19610
+ const tail = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(clipped.positions[0], clipped.positions[1], clipped.positions[2], 1), viewProjection);
19611
+ if (tail[3] <= 0)
19612
+ return null;
19613
+ const dx = (tip[0] / tip[3] - tail[0] / tail[3]) * (width - 1) / 2;
19614
+ const dy = (tip[1] / tip[3] - tail[1] / tail[3]) * (height - 1) / 2;
19615
+ const length = Math.hypot(dx, dy);
19616
+ if (!Number.isFinite(length) || length < 0.001)
19617
+ return null;
19618
+ const arrowLength = Math.min(10 * supersampling, length / 2);
19619
+ const ux = dx / length;
19620
+ const uy = dy / length;
19621
+ const inverse = import_gl_matrix12.mat4.invert(import_gl_matrix12.mat4.create(), viewProjection);
19622
+ if (!inverse)
19623
+ return null;
19624
+ const positions = [points[end], points[end + 1], points[end + 2]];
19625
+ for (const side of [-1, 1]) {
19626
+ const offsetX = -ux * arrowLength - side * uy * arrowLength * 0.45;
19627
+ const offsetY = -uy * arrowLength + side * ux * arrowLength * 0.45;
19628
+ const wing = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(tip[0] / tip[3] + 2 * offsetX / (width - 1), tip[1] / tip[3] + 2 * offsetY / (height - 1), tip[2] / tip[3], 1), inverse);
19629
+ if (!Array.from(wing).every(Number.isFinite) || wing[3] === 0)
19630
+ return null;
19631
+ positions.push(wing[0] / wing[3], wing[1] / wing[3], wing[2] / wing[3]);
19632
+ }
19633
+ return {
19634
+ ...drawCall,
19635
+ positions: new Float32Array(positions),
19636
+ indices: new Uint32Array([0, 1, 0, 2])
19637
+ };
19638
+ }
18458
19639
  function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint8Bitmap) {
18459
19640
  const options = resolveRenderOptions(optionsInput);
19641
+ if (options.section) {
19642
+ if (options.renderStyle !== "outline")
19643
+ throw new Error("section requires renderStyle: outline");
19644
+ drawCalls = createOutlineSection(drawCalls, options.section).drawCalls;
19645
+ }
18460
19646
  const renderWidth = options.width * options.supersampling;
18461
19647
  const renderHeight = options.height * options.supersampling;
18462
- const camera = buildCamera(drawCalls, renderWidth, renderHeight, options.fov, options.camPos ?? null, options.lookAt ?? null, options.up, options.cameraRotation ?? null);
19648
+ const explosionDrawCalls = (options.explosionLines ?? []).map(createExplosionLineDrawCall);
19649
+ const camera = buildCamera([...drawCalls, ...explosionDrawCalls], renderWidth, renderHeight, options.fov, options.camPos ?? null, options.lookAt ?? null, options.up, options.cameraRotation ?? null, options.projection, options.orthographicHeight);
18463
19650
  const renderer = new SoftwareRenderer(renderWidth, renderHeight, imageFactory, options.realistic);
18464
19651
  let rgb = null;
18465
19652
  if (options.backgroundColor) {
@@ -18480,7 +19667,17 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
18480
19667
  } else {
18481
19668
  renderer.clear([0, 0, 0, 0]);
18482
19669
  }
18483
- const allDrawCalls = [...drawCalls];
19670
+ const allDrawCalls = options.renderStyle === "outline" ? drawCalls.map((dc) => dc.mode === 1 || dc.outlineSectionCap ? dc : {
19671
+ ...dc,
19672
+ normals: null,
19673
+ colors: null,
19674
+ uvs: null,
19675
+ material: {
19676
+ baseColorFactor: [1, 1, 1, 1],
19677
+ baseColorTexture: null,
19678
+ alphaMode: "OPAQUE"
19679
+ }
19680
+ }) : [...drawCalls];
18484
19681
  let infiniteGridOptions = null;
18485
19682
  if (options.grid) {
18486
19683
  const userGridOptions = typeof options.grid === "boolean" ? {} : options.grid;
@@ -18531,7 +19728,9 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
18531
19728
  for (let i = 0;i < dcs.length; i++) {
18532
19729
  const dc = dcs[i];
18533
19730
  if (dc.mode === 1) {
18534
- renderer.drawLines(dc, camera, options.gamma);
19731
+ renderer.drawLines(dc, camera, options.gamma, {
19732
+ width: options.lineWidth * options.supersampling
19733
+ });
18535
19734
  } else {
18536
19735
  renderer.drawMesh(dc, camera, { dir: options.lightDir, ambient: options.ambient }, dc.material, options.cull, options.gamma, studio, opaque && winners ? { winners, triangleOffset: triangleOffsets[i], depthOnly: false } : undefined);
18537
19736
  }
@@ -18558,24 +19757,50 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
18558
19757
  renderGroup(blendDraws);
18559
19758
  renderer.denoise(options.gamma);
18560
19759
  for (const dc of drawCalls) {
18561
- if (!dc.showHiddenEdges)
19760
+ const showHiddenEdges = options.showHiddenEdges ?? dc.showHiddenEdges;
19761
+ if (!options.showEdges && !showHiddenEdges)
18562
19762
  continue;
18563
- const edgeDrawCall = createEdgeDrawCall(dc);
19763
+ const edgeDrawCall = createEdgeDrawCall(dc, 30, options.renderStyle === "outline" ? { view: camera.view, projection: options.projection } : undefined);
18564
19764
  if (!edgeDrawCall)
18565
19765
  continue;
18566
19766
  renderer.drawLines(edgeDrawCall, camera, options.gamma, {
18567
19767
  depthCompare: "less-equal",
18568
19768
  depthWrite: false,
18569
- depthBias: 0.0001
19769
+ depthBias: 0.0001,
19770
+ width: options.edgeWidth * options.supersampling
18570
19771
  });
19772
+ if (!showHiddenEdges)
19773
+ continue;
18571
19774
  renderer.drawLines(edgeDrawCall, camera, options.gamma, {
18572
19775
  depthCompare: "greater",
18573
19776
  depthWrite: false,
18574
19777
  depthBias: 0.0001,
18575
19778
  dashed: true,
18576
19779
  dashLength: 4 * options.supersampling,
18577
- opacity: 0.35
19780
+ opacity: options.hiddenEdgeOpacity,
19781
+ width: options.edgeWidth * options.supersampling
19782
+ });
19783
+ }
19784
+ for (const [index, drawCall] of explosionDrawCalls.entries()) {
19785
+ renderer.drawLines(clipExplosionLineDrawCall(drawCall, camera), camera, options.gamma, {
19786
+ depthCompare: "less-equal",
19787
+ depthWrite: false,
19788
+ depthBias: 0.0001,
19789
+ dashed: options.explosionLines[index].dashed ?? true,
19790
+ dashLength: 4 * options.supersampling,
19791
+ width: options.lineWidth * options.supersampling
18578
19792
  });
19793
+ if (options.explosionLines[index].arrow) {
19794
+ const arrow = createExplosionArrowDrawCall(drawCall, camera, renderWidth, renderHeight, options.supersampling);
19795
+ if (arrow) {
19796
+ renderer.drawLines(clipExplosionLineDrawCall(arrow, camera), camera, options.gamma, {
19797
+ depthCompare: "less-equal",
19798
+ depthWrite: false,
19799
+ depthBias: 0.0001,
19800
+ width: options.lineWidth * options.supersampling
19801
+ });
19802
+ }
19803
+ }
18579
19804
  }
18580
19805
  if (options.debugPoints?.length) {
18581
19806
  drawDebugPoints(renderer, camera, options.debugPoints, options.debugFontSize, options.debugPointColor, options.debugLabelColor);
@@ -18606,9 +19831,9 @@ function createInfiniteGrid(options = {}) {
18606
19831
  size
18607
19832
  ]);
18608
19833
  const indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
18609
- const model = import_gl_matrix9.mat4.create();
19834
+ const model = import_gl_matrix13.mat4.create();
18610
19835
  const offset = options.offset ?? {};
18611
- import_gl_matrix9.mat4.fromTranslation(model, [offset.x ?? 0, offset.y ?? 0, offset.z ?? 0]);
19836
+ import_gl_matrix13.mat4.fromTranslation(model, [offset.x ?? 0, offset.y ?? 0, offset.z ?? 0]);
18612
19837
  return {
18613
19838
  positions,
18614
19839
  indices,
@@ -18782,7 +20007,7 @@ function readIndices(ctx, accessorIndex) {
18782
20007
  }
18783
20008
  function nodeLocalMatrix(node) {
18784
20009
  if (node.matrix) {
18785
- const m2 = import_gl_matrix10.mat4.create();
20010
+ const m2 = import_gl_matrix14.mat4.create();
18786
20011
  for (let i = 0;i < 16; i++)
18787
20012
  m2[i] = node.matrix[i];
18788
20013
  return m2;
@@ -18790,10 +20015,10 @@ function nodeLocalMatrix(node) {
18790
20015
  const translation = node.translation || [0, 0, 0];
18791
20016
  const rotation = node.rotation || [0, 0, 0, 1];
18792
20017
  const scale = node.scale || [1, 1, 1];
18793
- const m = import_gl_matrix10.mat4.create();
18794
- const tmp = import_gl_matrix10.mat4.create();
18795
- import_gl_matrix10.mat4.fromRotationTranslationScale(tmp, rotation, translation, scale);
18796
- import_gl_matrix10.mat4.copy(m, tmp);
20018
+ const m = import_gl_matrix14.mat4.create();
20019
+ const tmp = import_gl_matrix14.mat4.create();
20020
+ import_gl_matrix14.mat4.fromRotationTranslationScale(tmp, rotation, translation, scale);
20021
+ import_gl_matrix14.mat4.copy(m, tmp);
18797
20022
  return m;
18798
20023
  }
18799
20024
  function getMaterial(gltf, textures, images, materialIndex) {
@@ -18837,8 +20062,8 @@ function createSceneFromGLTF(gltf, resources) {
18837
20062
  if (!node)
18838
20063
  return;
18839
20064
  const local = nodeLocalMatrix(node);
18840
- const world = import_gl_matrix10.mat4.create();
18841
- import_gl_matrix10.mat4.multiply(world, parentMatrix, local);
20065
+ const world = import_gl_matrix14.mat4.create();
20066
+ import_gl_matrix14.mat4.multiply(world, parentMatrix, local);
18842
20067
  if (Number.isInteger(node.mesh)) {
18843
20068
  const mesh = meshes[node.mesh];
18844
20069
  if (mesh) {
@@ -18874,7 +20099,7 @@ function createSceneFromGLTF(gltf, resources) {
18874
20099
  traverse(childIndex, world);
18875
20100
  }
18876
20101
  }
18877
- const identity = import_gl_matrix10.mat4.create();
20102
+ const identity = import_gl_matrix14.mat4.create();
18878
20103
  for (const rootIndex of scene.nodes || []) {
18879
20104
  traverse(rootIndex, identity);
18880
20105
  }
@@ -19160,11 +20385,11 @@ async function renderGLTFToPNGFromGLB(glb, options = {}) {
19160
20385
  function renderSceneFromGLTF(scene, options, imageFactory) {
19161
20386
  return renderDrawCalls(scene.drawCalls, options, imageFactory);
19162
20387
  }
19163
- var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, import_gl_matrix5, import_gl_matrix6, import_gl_matrix7, import_gl_matrix8, import_gl_matrix9, import_gl_matrix10, toRad = (degrees) => degrees * Math.PI / 180, DEFAULT_CREASE_ANGLE_DEGREES = 30, createUint8Bitmap = (width, height) => ({
20388
+ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, import_gl_matrix5, import_gl_matrix6, import_gl_matrix7, import_gl_matrix8, import_gl_matrix9, import_gl_matrix10, import_gl_matrix11, import_gl_matrix12, import_gl_matrix13, import_gl_matrix14, createUint8Bitmap = (width, height) => ({
19164
20389
  width,
19165
20390
  height,
19166
20391
  data: new Uint8ClampedArray(width * height * 4)
19167
- }), DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, clamp = (value, min, max) => Math.max(min, Math.min(max, value)), GeometryDenoiser = class {
20392
+ }), toRad = (degrees) => degrees * Math.PI / 180, DEFAULT_CREASE_ANGLE_DEGREES = 30, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, clamp = (value, min, max) => Math.max(min, Math.min(max, value)), GeometryDenoiser = class {
19168
20393
  constructor(width, height) {
19169
20394
  this.width = width;
19170
20395
  this.height = height;
@@ -19302,16 +20527,18 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19302
20527
  return;
19303
20528
  const view = camera.view;
19304
20529
  const proj = camera.proj;
19305
- const mvp = import_gl_matrix5.mat4.create();
19306
- import_gl_matrix5.mat4.multiply(mvp, proj, import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), view, model));
20530
+ const mvp = import_gl_matrix7.mat4.create();
20531
+ import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
19307
20532
  const vertexCount = positions.length / 3 | 0;
19308
20533
  const vScreen = new Array(vertexCount);
19309
20534
  const vInvW = new Float32Array(vertexCount);
19310
20535
  const vNDCz = new Float32Array(vertexCount);
20536
+ const clipVertices = [];
19311
20537
  for (let i = 0;i < vertexCount; i++) {
19312
- const p = import_gl_matrix5.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
19313
- const c = import_gl_matrix5.vec4.create();
19314
- import_gl_matrix5.vec4.transformMat4(c, p, mvp);
20538
+ const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
20539
+ const c = import_gl_matrix7.vec4.create();
20540
+ import_gl_matrix7.vec4.transformMat4(c, p, mvp);
20541
+ clipVertices.push(c);
19315
20542
  const invW = 1 / c[3];
19316
20543
  vInvW[i] = invW;
19317
20544
  if (!isFinite(invW)) {
@@ -19346,9 +20573,58 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19346
20573
  const depthWrite = options.depthWrite ?? true;
19347
20574
  const depthBias = options.depthBias ?? 0;
19348
20575
  const dashLength = Math.max(1, options.dashLength ?? 4);
20576
+ const strokeWidth = typeof options.width === "number" && Number.isFinite(options.width) && options.width > 0 ? options.width : 1;
20577
+ const drawFragment = (xi, yi, z, coverage = 1) => {
20578
+ if (z < 0 || z > 1)
20579
+ return;
20580
+ const di = yi * this.width + xi;
20581
+ const currentDepth = this.depth[di];
20582
+ const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
20583
+ if (!passesDepth)
20584
+ return;
20585
+ if (depthWrite)
20586
+ this.depth[di] = z;
20587
+ const pixelIndex = di * 4;
20588
+ const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
20589
+ const alpha = sourceAlpha * coverage;
20590
+ const oneMinusSourceAlpha = 1 - alpha;
20591
+ const outAlpha = alpha + destinationAlpha * oneMinusSourceAlpha;
20592
+ const blend = (channel, offset) => outAlpha === 0 ? 0 : (channel * alpha + this.buffer[pixelIndex + offset] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
20593
+ this.setPixel(xi, yi, blend(r255, 0), blend(g255, 1), blend(b255, 2), outAlpha * 255);
20594
+ };
19349
20595
  for (let i = 0;i < indices.length; i += 2) {
19350
20596
  const i0 = indices[i + 0];
19351
20597
  const i1 = indices[i + 1];
20598
+ if (strokeWidth !== 1) {
20599
+ const sourceFaces = (mesh.edgeAdjacentVertices?.[i / 2] ?? []).flatMap((third) => {
20600
+ if (clipVertices[i0][3] <= 0 || clipVertices[i1][3] <= 0 || clipVertices[third][3] <= 0)
20601
+ return [];
20602
+ const a2 = vScreen[i0];
20603
+ const b2 = vScreen[i1];
20604
+ const c = vScreen[third];
20605
+ const area = edge(a2, b2, c);
20606
+ if (!Number.isFinite(area) || area === 0)
20607
+ return [];
20608
+ return [{ a: a2, b: b2, c, inverseArea: 1 / area, third }];
20609
+ });
20610
+ rasterizeWideLine(clipVertices[i0], clipVertices[i1], this.width, this.height, strokeWidth, options.dashed ?? false, dashLength, sourceFaces.length === 0 ? drawFragment : (x2, y2, z2, coverage) => {
20611
+ let surfaceDepth = Infinity;
20612
+ const sample = [x2 + 0.5, y2 + 0.5];
20613
+ for (const face of sourceFaces) {
20614
+ const l0 = edge(face.b, face.c, sample) * face.inverseArea;
20615
+ const l1 = edge(face.c, face.a, sample) * face.inverseArea;
20616
+ const l2 = 1 - l0 - l1;
20617
+ if (l0 < -0.000001 || l1 < -0.000001 || l2 < -0.000001)
20618
+ continue;
20619
+ const depth = (l0 * vNDCz[i0] + l1 * vNDCz[i1] + l2 * vNDCz[face.third]) * 0.5 + 0.5;
20620
+ if (depth >= 0 && depth <= 1) {
20621
+ surfaceDepth = Math.min(surfaceDepth, depth);
20622
+ }
20623
+ }
20624
+ drawFragment(x2, y2, surfaceDepth === Infinity ? z2 : surfaceDepth, coverage);
20625
+ });
20626
+ continue;
20627
+ }
19352
20628
  const v0s = vScreen[i0];
19353
20629
  const v1s = vScreen[i1];
19354
20630
  const z0_ndc = vNDCz[i0];
@@ -19384,21 +20660,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19384
20660
  const xi = Math.round(x);
19385
20661
  const yi = Math.round(y);
19386
20662
  if (xi >= 0 && xi < this.width && yi >= 0 && yi < this.height && z >= 0 && z <= 1) {
19387
- const di = yi * this.width + xi;
19388
- const currentDepth = this.depth[di];
19389
- const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
19390
- if (passesDepth) {
19391
- if (depthWrite)
19392
- this.depth[di] = z;
19393
- const pixelIndex = di * 4;
19394
- const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
19395
- const oneMinusSourceAlpha = 1 - sourceAlpha;
19396
- const outAlpha = sourceAlpha + destinationAlpha * oneMinusSourceAlpha;
19397
- const outR = outAlpha === 0 ? 0 : (r255 * sourceAlpha + this.buffer[pixelIndex + 0] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
19398
- const outG = outAlpha === 0 ? 0 : (g255 * sourceAlpha + this.buffer[pixelIndex + 1] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
19399
- const outB = outAlpha === 0 ? 0 : (b255 * sourceAlpha + this.buffer[pixelIndex + 2] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
19400
- this.setPixel(xi, yi, outR, outG, outB, outAlpha * 255);
19401
- }
20663
+ drawFragment(xi, yi, z);
19402
20664
  }
19403
20665
  x += xinc;
19404
20666
  y += yinc;
@@ -19437,13 +20699,13 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19437
20699
  const materialId = this.denoiser?.materialId(material) ?? 0;
19438
20700
  const lightDir = light.dir ?? DEFAULT_LIGHT_DIR;
19439
20701
  const ambient = clamp(light.ambient ?? DEFAULT_RENDER_OPTIONS.ambient, 0, 1);
19440
- const L = studio ? null : import_gl_matrix5.vec3.normalize(import_gl_matrix5.vec3.create(), import_gl_matrix5.vec3.fromValues(lightDir[0], lightDir[1], lightDir[2]));
20702
+ const L = studio ? null : import_gl_matrix7.vec3.normalize(import_gl_matrix7.vec3.create(), import_gl_matrix7.vec3.fromValues(lightDir[0], lightDir[1], lightDir[2]));
19441
20703
  const view = camera.view;
19442
20704
  const proj = camera.proj;
19443
- const mvp = import_gl_matrix5.mat4.create();
19444
- import_gl_matrix5.mat4.multiply(mvp, proj, import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), view, model));
19445
- const normalMat = import_gl_matrix5.mat3.create();
19446
- import_gl_matrix5.mat3.normalFromMat4(normalMat, model);
20705
+ const mvp = import_gl_matrix7.mat4.create();
20706
+ import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
20707
+ const normalMat = import_gl_matrix7.mat3.create();
20708
+ import_gl_matrix7.mat3.normalFromMat4(normalMat, model);
19447
20709
  let vertexCount = positions.length / 3 | 0;
19448
20710
  let idx = indices ?? (() => {
19449
20711
  const a = new Uint32Array(vertexCount);
@@ -19470,11 +20732,11 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19470
20732
  const vWorldP = studio && !depthOnly ? new Array(vertexCount) : null;
19471
20733
  const vColor = new Array(depthOnly ? 0 : vertexCount);
19472
20734
  for (let i = 0;i < vertexCount; i++) {
19473
- const p = import_gl_matrix5.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
19474
- const c = import_gl_matrix5.vec4.create();
19475
- import_gl_matrix5.vec4.transformMat4(c, p, mvp);
20735
+ const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
20736
+ const c = import_gl_matrix7.vec4.create();
20737
+ import_gl_matrix7.vec4.transformMat4(c, p, mvp);
19476
20738
  if (vWorldP) {
19477
- const world = import_gl_matrix5.vec4.transformMat4(import_gl_matrix5.vec4.create(), p, model);
20739
+ const world = import_gl_matrix7.vec4.transformMat4(import_gl_matrix7.vec4.create(), p, model);
19478
20740
  vWorldP[i] = [world[0], world[1], world[2]];
19479
20741
  }
19480
20742
  const invW = 1 / c[3];
@@ -19488,9 +20750,9 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19488
20750
  vNDCz[i] = ndcZ;
19489
20751
  if (depthOnly)
19490
20752
  continue;
19491
- const n = import_gl_matrix5.vec3.fromValues(useNormals[i * 3 + 0], useNormals[i * 3 + 1], useNormals[i * 3 + 2]);
19492
- const nw = import_gl_matrix5.vec3.create();
19493
- import_gl_matrix5.vec3.transformMat3(nw, n, normalMat);
20753
+ const n = import_gl_matrix7.vec3.fromValues(useNormals[i * 3 + 0], useNormals[i * 3 + 1], useNormals[i * 3 + 2]);
20754
+ const nw = import_gl_matrix7.vec3.create();
20755
+ import_gl_matrix7.vec3.transformMat3(nw, n, normalMat);
19494
20756
  vWorldN[i] = [nw[0], nw[1], nw[2]];
19495
20757
  if (colors && colors.length >= (i + 1) * 3) {
19496
20758
  vColor[i] = [colors[i * 3 + 0], colors[i * 3 + 1], colors[i * 3 + 2]];
@@ -19577,7 +20839,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19577
20839
  ];
19578
20840
  if (uv && material.baseColorTexture) {
19579
20841
  const uvp = this.perspInterp(uv, invW, [l0, l1, l2]);
19580
- const texel = this.sampleTextureNearest(material.baseColorTexture, uvp[0], uvp[1]);
20842
+ const texel = this.sampleTextureNearest(material.baseColorTexture, material.baseColorTextureWrap === "repeat" ? uvp[0] - Math.floor(uvp[0]) : uvp[0], material.baseColorTextureWrap === "repeat" ? uvp[1] - Math.floor(uvp[1]) : uvp[1]);
19581
20843
  baseColor = mulColor(baseColor, [
19582
20844
  srgbDecodeToLinear01(texel[0]),
19583
20845
  srgbDecodeToLinear01(texel[1]),
@@ -19702,7 +20964,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
19702
20964
  const count = dc.indices?.length ?? dc.positions.length / 3;
19703
20965
  const worldVertices = [];
19704
20966
  for (let i = 0;i < dc.positions.length; i += 3) {
19705
- const p = import_gl_matrix8.vec3.transformMat4(import_gl_matrix8.vec3.create(), [dc.positions[i], dc.positions[i + 1], dc.positions[i + 2]], dc.model);
20967
+ const p = import_gl_matrix10.vec3.transformMat4(import_gl_matrix10.vec3.create(), [dc.positions[i], dc.positions[i + 1], dc.positions[i + 2]], dc.model);
19706
20968
  worldVertices.push([p[0], p[1], p[2]]);
19707
20969
  }
19708
20970
  const vertex = (index) => worldVertices[dc.indices?.[index] ?? index];
@@ -20024,7 +21286,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
20024
21286
  }
20025
21287
  constructor(drawCalls, camera) {
20026
21288
  this.occlusion = new RayOcclusion(drawCalls);
20027
- const world = import_gl_matrix7.mat4.invert(import_gl_matrix7.mat4.create(), camera.view);
21289
+ const world = import_gl_matrix9.mat4.invert(import_gl_matrix9.mat4.create(), camera.view);
20028
21290
  if (!world)
20029
21291
  throw new Error("Realistic rendering requires an invertible camera view.");
20030
21292
  this.eye = [world[12], world[13], world[14]];
@@ -20032,7 +21294,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
20032
21294
  const [t, b] = basis(l.direction);
20033
21295
  return Array.from({ length: SHADOW_SAMPLES }, (_, i) => {
20034
21296
  const u = (i + 0.5) / SHADOW_SAMPLES, cos = 1 + Math.log(1 - u) / l.sharpness, sin = Math.sqrt(Math.max(0, 1 - cos * cos)), phi = 2 * Math.PI * radicalInverse(i);
20035
- const direction = orient(sin * Math.cos(phi), sin * Math.sin(phi), cos, l.direction, t, b);
21297
+ const direction = orient2(sin * Math.cos(phi), sin * Math.sin(phi), cos, l.direction, t, b);
20036
21298
  const parallel = dot(direction, l.direction);
20037
21299
  return {
20038
21300
  parallel: l.direction.map((v) => v * parallel),
@@ -20155,7 +21417,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
20155
21417
  const [t, b] = basis(n);
20156
21418
  let blocked = 0;
20157
21419
  for (let i = 0;metal < 1 && i < DIFFUSE_SAMPLES; i++) {
20158
- const phi = i * 2 * Math.PI / DIFFUSE_SAMPLES + phase, l = orient(0.7 * Math.cos(phi), 0.7 * Math.sin(phi), Math.sqrt(0.51), n, t, b);
21420
+ const phi = i * 2 * Math.PI / DIFFUSE_SAMPLES + phase, l = orient2(0.7 * Math.cos(phi), 0.7 * Math.sin(phi), Math.sqrt(0.51), n, t, b);
20159
21421
  const hit = this.occlusion.trace(origin, l);
20160
21422
  if (hit) {
20161
21423
  blocked++;
@@ -20178,7 +21440,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
20178
21440
  this.reflectionSamples.set(rough, samples);
20179
21441
  }
20180
21442
  for (const [sx, sy, nh] of samples) {
20181
- const h = orient(sx * cosPhase - sy * sinPhase, sx * sinPhase + sy * cosPhase, nh, reflected, rt, rb);
21443
+ const h = orient2(sx * cosPhase - sy * sinPhase, sx * sinPhase + sy * cosPhase, nh, reflected, rt, rb);
20182
21444
  const l = [
20183
21445
  2 * nh * h[0] - reflected[0],
20184
21446
  2 * nh * h[1] - reflected[1],
@@ -20202,6 +21464,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
20202
21464
  }
20203
21465
  }, COMPONENT_INFO, NUM_COMPONENTS, MAGIC = 1179937895, JSON_CHUNK_TYPE = 1313821514, BIN_CHUNK_TYPE = 5130562;
20204
21466
  var init_dist = __esm(() => {
21467
+ init_earcut();
20205
21468
  init_lib();
20206
21469
  init_lib();
20207
21470
  import_gl_matrix = __toESM(require_cjs(), 1);
@@ -20214,8 +21477,16 @@ var init_dist = __esm(() => {
20214
21477
  import_gl_matrix8 = __toESM(require_cjs(), 1);
20215
21478
  import_gl_matrix9 = __toESM(require_cjs(), 1);
20216
21479
  import_gl_matrix10 = __toESM(require_cjs(), 1);
21480
+ import_gl_matrix11 = __toESM(require_cjs(), 1);
21481
+ import_gl_matrix12 = __toESM(require_cjs(), 1);
21482
+ import_gl_matrix13 = __toESM(require_cjs(), 1);
21483
+ import_gl_matrix14 = __toESM(require_cjs(), 1);
20217
21484
  DEFAULT_LIGHT_DIR = [-0.4, -0.9, -0.2];
20218
21485
  DEFAULT_RENDER_OPTIONS = {
21486
+ renderStyle: "shaded",
21487
+ section: null,
21488
+ projection: "perspective",
21489
+ orthographicHeight: null,
20219
21490
  realistic: false,
20220
21491
  width: 800,
20221
21492
  height: 600,
@@ -20234,7 +21505,13 @@ var init_dist = __esm(() => {
20234
21505
  debugPoints: null,
20235
21506
  debugFontSize: null,
20236
21507
  debugPointColor: null,
20237
- debugLabelColor: null
21508
+ debugLabelColor: null,
21509
+ explosionLines: null,
21510
+ showEdges: false,
21511
+ showHiddenEdges: null,
21512
+ edgeWidth: 1,
21513
+ lineWidth: 1,
21514
+ hiddenEdgeOpacity: 0.35
20238
21515
  };
20239
21516
  DEFAULT_MARKER_COLOR = [
20240
21517
  255,
@@ -25845,6 +27122,8 @@ var projectConfigSchema = z.object({
25845
27122
  kicadLibrary: z.boolean().optional(),
25846
27123
  kicadPcm: z.boolean().optional(),
25847
27124
  previewImages: z.boolean().optional(),
27125
+ drawings: z.boolean().optional(),
27126
+ drawing: z.string().optional(),
25848
27127
  glbs: z.boolean().optional(),
25849
27128
  step: z.boolean().optional(),
25850
27129
  workerTimeoutMs: z.number().int().positive().optional(),