@tscircuit/cli 0.1.2411 → 0.1.2412
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/build/build.worker.js +1417 -138
- package/dist/cli/main.js +2 -2
- package/dist/cli/snapshot/snapshot.worker.js +1417 -138
- package/dist/lib/index.js +1340 -1345
- package/package.json +8 -6
- package/types/tscircuit.config.schema.json +8 -0
|
@@ -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 =
|
|
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
|
-
|
|
17587
|
-
|
|
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
|
|
18514
|
+
return import_gl_matrix2.vec3.fromValues(0, -1, 0);
|
|
17611
18515
|
case "x+":
|
|
17612
|
-
return
|
|
18516
|
+
return import_gl_matrix2.vec3.fromValues(1, 0, 0);
|
|
17613
18517
|
case "x-":
|
|
17614
|
-
return
|
|
18518
|
+
return import_gl_matrix2.vec3.fromValues(-1, 0, 0);
|
|
17615
18519
|
case "z+":
|
|
17616
|
-
return
|
|
18520
|
+
return import_gl_matrix2.vec3.fromValues(0, 0, 1);
|
|
17617
18521
|
case "z-":
|
|
17618
|
-
return
|
|
18522
|
+
return import_gl_matrix2.vec3.fromValues(0, 0, -1);
|
|
17619
18523
|
case "y+":
|
|
17620
18524
|
default:
|
|
17621
|
-
return
|
|
18525
|
+
return import_gl_matrix2.vec3.fromValues(0, 1, 0);
|
|
17622
18526
|
}
|
|
17623
18527
|
}
|
|
17624
18528
|
function buildCameraWorldMatrix(eye, forward, up) {
|
|
17625
|
-
const normalizedForward =
|
|
17626
|
-
const right =
|
|
17627
|
-
if (
|
|
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
|
-
|
|
17631
|
-
const correctedUp =
|
|
17632
|
-
if (
|
|
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
|
-
|
|
17636
|
-
return
|
|
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 =
|
|
17640
|
-
if (Math.abs(
|
|
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
|
|
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
|
|
18552
|
+
return import_gl_matrix2.mat4.create();
|
|
17649
18553
|
}
|
|
17650
18554
|
if (rotation.x !== 0) {
|
|
17651
|
-
|
|
18555
|
+
import_gl_matrix2.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
|
|
17652
18556
|
}
|
|
17653
18557
|
if (rotation.y !== 0) {
|
|
17654
|
-
|
|
18558
|
+
import_gl_matrix2.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
|
|
17655
18559
|
}
|
|
17656
18560
|
if (rotation.z !== 0) {
|
|
17657
|
-
|
|
18561
|
+
import_gl_matrix2.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
|
|
17658
18562
|
}
|
|
17659
|
-
const view =
|
|
17660
|
-
|
|
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 =
|
|
17665
|
-
if (
|
|
17666
|
-
return
|
|
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
|
|
18574
|
+
return import_gl_matrix2.mat4.create();
|
|
17671
18575
|
}
|
|
17672
|
-
const view =
|
|
17673
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
17701
|
-
|
|
17702
|
-
return
|
|
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 =
|
|
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 ?
|
|
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 :
|
|
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 =
|
|
17718
|
-
|
|
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:
|
|
18625
|
+
view: view2,
|
|
17721
18626
|
proj: proj2
|
|
17722
18627
|
};
|
|
17723
18628
|
}
|
|
17724
|
-
const eye = camPos ?
|
|
17725
|
-
const target = lookAt ?
|
|
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 =
|
|
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 =
|
|
17759
|
-
|
|
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, {
|
|
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(
|
|
17832
|
-
|
|
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
|
-
|
|
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 =
|
|
18070
|
-
|
|
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 =
|
|
18085
|
-
|
|
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 =
|
|
18214
|
-
|
|
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 =
|
|
18219
|
-
|
|
18220
|
-
const inv_vp =
|
|
18221
|
-
|
|
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 =
|
|
18227
|
-
const far_point =
|
|
18228
|
-
|
|
18229
|
-
|
|
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 =
|
|
18247
|
-
const clip_pt =
|
|
18248
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
19834
|
+
const model = import_gl_matrix13.mat4.create();
|
|
18610
19835
|
const offset = options.offset ?? {};
|
|
18611
|
-
|
|
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 =
|
|
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 =
|
|
18794
|
-
const tmp =
|
|
18795
|
-
|
|
18796
|
-
|
|
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 =
|
|
18841
|
-
|
|
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 =
|
|
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,
|
|
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 =
|
|
19306
|
-
|
|
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 =
|
|
19313
|
-
const c =
|
|
19314
|
-
|
|
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
|
-
|
|
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 :
|
|
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 =
|
|
19444
|
-
|
|
19445
|
-
const normalMat =
|
|
19446
|
-
|
|
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 =
|
|
19474
|
-
const c =
|
|
19475
|
-
|
|
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 =
|
|
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 =
|
|
19492
|
-
const nw =
|
|
19493
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(),
|