@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
|
@@ -6839,6 +6839,651 @@ var require_cjs = __commonJS(function(exports) {
|
|
|
6839
6839
|
}
|
|
6840
6840
|
});
|
|
6841
6841
|
|
|
6842
|
+
// node_modules/earcut/src/earcut.js
|
|
6843
|
+
function earcut(data, holeIndices, dim = 2) {
|
|
6844
|
+
const hasHoles = holeIndices && holeIndices.length;
|
|
6845
|
+
const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
6846
|
+
if (steiners.size)
|
|
6847
|
+
steiners.clear();
|
|
6848
|
+
let outerNode = linkedList(data, 0, outerLen, dim, true);
|
|
6849
|
+
const triangles = [];
|
|
6850
|
+
if (!outerNode || outerNode.next === outerNode.prev)
|
|
6851
|
+
return triangles;
|
|
6852
|
+
let minX = 0, minY = 0, invSize = 0;
|
|
6853
|
+
if (hasHoles)
|
|
6854
|
+
outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
|
|
6855
|
+
if (data.length > 80 * dim) {
|
|
6856
|
+
minX = data[0];
|
|
6857
|
+
minY = data[1];
|
|
6858
|
+
let maxX = minX;
|
|
6859
|
+
let maxY = minY;
|
|
6860
|
+
for (let i = dim;i < outerLen; i += dim) {
|
|
6861
|
+
const x = data[i];
|
|
6862
|
+
const y = data[i + 1];
|
|
6863
|
+
if (x < minX)
|
|
6864
|
+
minX = x;
|
|
6865
|
+
if (y < minY)
|
|
6866
|
+
minY = y;
|
|
6867
|
+
if (x > maxX)
|
|
6868
|
+
maxX = x;
|
|
6869
|
+
if (y > maxY)
|
|
6870
|
+
maxY = y;
|
|
6871
|
+
}
|
|
6872
|
+
invSize = Math.max(maxX - minX, maxY - minY);
|
|
6873
|
+
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
|
6874
|
+
}
|
|
6875
|
+
earcutLinked(outerNode, triangles, minX, minY, invSize);
|
|
6876
|
+
return triangles;
|
|
6877
|
+
}
|
|
6878
|
+
function linkedList(data, start, end, dim, clockwise) {
|
|
6879
|
+
let last = null;
|
|
6880
|
+
if (clockwise === signedArea(data, start, end, dim) > 0) {
|
|
6881
|
+
for (let i = start;i < end; i += dim)
|
|
6882
|
+
last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
6883
|
+
} else {
|
|
6884
|
+
for (let i = end - dim;i >= start; i -= dim)
|
|
6885
|
+
last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
6886
|
+
}
|
|
6887
|
+
if (last && equals(last, last.next)) {
|
|
6888
|
+
removeNode(last);
|
|
6889
|
+
last = last.next;
|
|
6890
|
+
}
|
|
6891
|
+
return last;
|
|
6892
|
+
}
|
|
6893
|
+
function filterPoints(start, end = start) {
|
|
6894
|
+
const full = end === start;
|
|
6895
|
+
let p = start, again;
|
|
6896
|
+
do {
|
|
6897
|
+
again = false;
|
|
6898
|
+
if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
|
|
6899
|
+
if (full || p === end)
|
|
6900
|
+
end = p.prev;
|
|
6901
|
+
filteredOut = true;
|
|
6902
|
+
removeNode(p);
|
|
6903
|
+
p = p.prev;
|
|
6904
|
+
again = true;
|
|
6905
|
+
} else if (full || p !== end) {
|
|
6906
|
+
p = p.next;
|
|
6907
|
+
again = !full;
|
|
6908
|
+
}
|
|
6909
|
+
} while (again || p !== end);
|
|
6910
|
+
return end;
|
|
6911
|
+
}
|
|
6912
|
+
function earcutLinked(ear, triangles, minX, minY, invSize) {
|
|
6913
|
+
if (invSize)
|
|
6914
|
+
indexCurve(ear, minX, minY, invSize);
|
|
6915
|
+
let stop = ear, cured = false;
|
|
6916
|
+
while (ear.prev !== ear.next) {
|
|
6917
|
+
const prev = ear.prev;
|
|
6918
|
+
const next = ear.next;
|
|
6919
|
+
if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
|
|
6920
|
+
triangles.push(prev.i, ear.i, next.i);
|
|
6921
|
+
removeNode(ear);
|
|
6922
|
+
ear = next;
|
|
6923
|
+
stop = next;
|
|
6924
|
+
continue;
|
|
6925
|
+
}
|
|
6926
|
+
ear = next;
|
|
6927
|
+
if (ear === stop) {
|
|
6928
|
+
filteredOut = false;
|
|
6929
|
+
ear = filterPoints(ear);
|
|
6930
|
+
if (filteredOut) {
|
|
6931
|
+
stop = ear;
|
|
6932
|
+
continue;
|
|
6933
|
+
}
|
|
6934
|
+
if (!cured) {
|
|
6935
|
+
ear = cureLocalIntersections(ear, triangles);
|
|
6936
|
+
stop = ear;
|
|
6937
|
+
cured = true;
|
|
6938
|
+
continue;
|
|
6939
|
+
}
|
|
6940
|
+
splitEarcut(ear, triangles, minX, minY, invSize);
|
|
6941
|
+
break;
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
}
|
|
6945
|
+
function isEar(ear) {
|
|
6946
|
+
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);
|
|
6947
|
+
let p = c.next;
|
|
6948
|
+
while (p !== a) {
|
|
6949
|
+
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)
|
|
6950
|
+
return false;
|
|
6951
|
+
p = p.next;
|
|
6952
|
+
}
|
|
6953
|
+
return true;
|
|
6954
|
+
}
|
|
6955
|
+
function isEarHashed(ear, minX, minY, invSize) {
|
|
6956
|
+
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);
|
|
6957
|
+
let p = ear.prevZ;
|
|
6958
|
+
while (p && p.z >= minZ) {
|
|
6959
|
+
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)
|
|
6960
|
+
return false;
|
|
6961
|
+
p = p.prevZ;
|
|
6962
|
+
}
|
|
6963
|
+
let n = ear.nextZ;
|
|
6964
|
+
while (n && n.z <= maxZ) {
|
|
6965
|
+
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)
|
|
6966
|
+
return false;
|
|
6967
|
+
n = n.nextZ;
|
|
6968
|
+
}
|
|
6969
|
+
return true;
|
|
6970
|
+
}
|
|
6971
|
+
function cureLocalIntersections(start, triangles) {
|
|
6972
|
+
let p = start;
|
|
6973
|
+
let cured = false;
|
|
6974
|
+
do {
|
|
6975
|
+
const a = p.prev, b = p.next.next;
|
|
6976
|
+
if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
|
|
6977
|
+
triangles.push(a.i, p.i, b.i);
|
|
6978
|
+
removeNode(p);
|
|
6979
|
+
removeNode(p.next);
|
|
6980
|
+
p = start = b;
|
|
6981
|
+
cured = true;
|
|
6982
|
+
}
|
|
6983
|
+
p = p.next;
|
|
6984
|
+
} while (p !== start);
|
|
6985
|
+
return cured ? filterPoints(p) : p;
|
|
6986
|
+
}
|
|
6987
|
+
function splitEarcut(start, triangles, minX, minY, invSize) {
|
|
6988
|
+
let a = start;
|
|
6989
|
+
do {
|
|
6990
|
+
let b = a.next.next;
|
|
6991
|
+
while (b !== a.prev) {
|
|
6992
|
+
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
6993
|
+
let c = splitPolygon(a, b);
|
|
6994
|
+
a = filterPoints(a, a.next);
|
|
6995
|
+
c = filterPoints(c, c.next);
|
|
6996
|
+
earcutLinked(a, triangles, minX, minY, invSize);
|
|
6997
|
+
earcutLinked(c, triangles, minX, minY, invSize);
|
|
6998
|
+
return;
|
|
6999
|
+
}
|
|
7000
|
+
b = b.next;
|
|
7001
|
+
}
|
|
7002
|
+
a = a.next;
|
|
7003
|
+
} while (a !== start);
|
|
7004
|
+
}
|
|
7005
|
+
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
7006
|
+
const queue = [];
|
|
7007
|
+
for (let i = 0, len = holeIndices.length;i < len; i++) {
|
|
7008
|
+
const start = holeIndices[i] * dim;
|
|
7009
|
+
const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
7010
|
+
const list = linkedList(data, start, end, dim, false);
|
|
7011
|
+
if (list === list.next)
|
|
7012
|
+
steiners.add(list);
|
|
7013
|
+
queue.push(getLeftmost(list));
|
|
7014
|
+
}
|
|
7015
|
+
queue.sort(compareXYSlope);
|
|
7016
|
+
buildBlockIndex(data.length / dim, holeIndices.length);
|
|
7017
|
+
indexSegment(outerNode, outerNode);
|
|
7018
|
+
indexActive = true;
|
|
7019
|
+
for (let i = 0;i < queue.length; i++) {
|
|
7020
|
+
outerNode = eliminateHole(queue[i], outerNode);
|
|
7021
|
+
}
|
|
7022
|
+
indexActive = false;
|
|
7023
|
+
return filterPoints(outerNode);
|
|
7024
|
+
}
|
|
7025
|
+
function compareXYSlope(a, b) {
|
|
7026
|
+
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);
|
|
7027
|
+
}
|
|
7028
|
+
function eliminateHole(hole, outerNode) {
|
|
7029
|
+
const bridge = findHoleBridge(hole, outerNode);
|
|
7030
|
+
if (!bridge) {
|
|
7031
|
+
return outerNode;
|
|
7032
|
+
}
|
|
7033
|
+
const bridgeReverse = splitPolygon(bridge, hole);
|
|
7034
|
+
const bridge2 = bridgeReverse.next;
|
|
7035
|
+
indexSegment(bridge, bridge2.next);
|
|
7036
|
+
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
7037
|
+
return filterPoints(bridge, bridge.next);
|
|
7038
|
+
}
|
|
7039
|
+
function buildBlockIndex(maxNodes, numHoles) {
|
|
7040
|
+
const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
|
|
7041
|
+
if (blockBBox.length < maxBlocks * 4)
|
|
7042
|
+
blockBBox = new Float64Array(maxBlocks * 4);
|
|
7043
|
+
numBlocks = 0;
|
|
7044
|
+
}
|
|
7045
|
+
function indexSegment(head, stop) {
|
|
7046
|
+
let p = head;
|
|
7047
|
+
do {
|
|
7048
|
+
const b = numBlocks++;
|
|
7049
|
+
blockHead[b] = p;
|
|
7050
|
+
let minX = p.x, minY = p.y, maxX = p.x, maxY = p.y;
|
|
7051
|
+
let k = 0;
|
|
7052
|
+
do {
|
|
7053
|
+
const c = p.next;
|
|
7054
|
+
p.z = b;
|
|
7055
|
+
if (c.x < minX)
|
|
7056
|
+
minX = c.x;
|
|
7057
|
+
if (c.x > maxX)
|
|
7058
|
+
maxX = c.x;
|
|
7059
|
+
if (c.y < minY)
|
|
7060
|
+
minY = c.y;
|
|
7061
|
+
if (c.y > maxY)
|
|
7062
|
+
maxY = c.y;
|
|
7063
|
+
p = c;
|
|
7064
|
+
} while (++k < K && p !== stop);
|
|
7065
|
+
blockStop[b] = p;
|
|
7066
|
+
const g = b * 4;
|
|
7067
|
+
blockBBox[g] = minX;
|
|
7068
|
+
blockBBox[g + 1] = minY;
|
|
7069
|
+
blockBBox[g + 2] = maxX;
|
|
7070
|
+
blockBBox[g + 3] = maxY;
|
|
7071
|
+
} while (p !== stop);
|
|
7072
|
+
}
|
|
7073
|
+
function growBlock(head, tail) {
|
|
7074
|
+
const g = head.z * 4;
|
|
7075
|
+
if (tail.x < blockBBox[g])
|
|
7076
|
+
blockBBox[g] = tail.x;
|
|
7077
|
+
if (tail.y < blockBBox[g + 1])
|
|
7078
|
+
blockBBox[g + 1] = tail.y;
|
|
7079
|
+
if (tail.x > blockBBox[g + 2])
|
|
7080
|
+
blockBBox[g + 2] = tail.x;
|
|
7081
|
+
if (tail.y > blockBBox[g + 3])
|
|
7082
|
+
blockBBox[g + 3] = tail.y;
|
|
7083
|
+
}
|
|
7084
|
+
function liveBlockStop(b) {
|
|
7085
|
+
let stop = blockStop[b];
|
|
7086
|
+
while (stop.prev.next !== stop)
|
|
7087
|
+
stop = stop.next;
|
|
7088
|
+
blockStop[b] = stop;
|
|
7089
|
+
return stop;
|
|
7090
|
+
}
|
|
7091
|
+
function liveBlockHead(b) {
|
|
7092
|
+
let head = blockHead[b];
|
|
7093
|
+
while (head.prev.next !== head)
|
|
7094
|
+
head = head.next;
|
|
7095
|
+
blockHead[b] = head;
|
|
7096
|
+
return head;
|
|
7097
|
+
}
|
|
7098
|
+
function findHoleBridge(hole, outerNode) {
|
|
7099
|
+
let p = outerNode;
|
|
7100
|
+
const hx = hole.x;
|
|
7101
|
+
const hy = hole.y;
|
|
7102
|
+
let qx = -Infinity;
|
|
7103
|
+
let m;
|
|
7104
|
+
if (equals(hole, p))
|
|
7105
|
+
return p;
|
|
7106
|
+
for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
|
|
7107
|
+
if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx)
|
|
7108
|
+
continue;
|
|
7109
|
+
const stop = liveBlockStop(b);
|
|
7110
|
+
p = liveBlockHead(b);
|
|
7111
|
+
do {
|
|
7112
|
+
if (p.prev.next === p) {
|
|
7113
|
+
if (equals(hole, p.next))
|
|
7114
|
+
return p.next;
|
|
7115
|
+
else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
|
|
7116
|
+
const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
|
|
7117
|
+
if (x <= hx && x > qx) {
|
|
7118
|
+
qx = x;
|
|
7119
|
+
m = p.x < p.next.x ? p : p.next;
|
|
7120
|
+
if (x === hx)
|
|
7121
|
+
return m;
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
p = p.next;
|
|
7126
|
+
} while (p !== stop);
|
|
7127
|
+
}
|
|
7128
|
+
if (!m)
|
|
7129
|
+
return null;
|
|
7130
|
+
const mx = m.x;
|
|
7131
|
+
const my = m.y;
|
|
7132
|
+
const tminY = Math.min(hy, my);
|
|
7133
|
+
const tmaxY = Math.max(hy, my);
|
|
7134
|
+
let tanMin = Infinity;
|
|
7135
|
+
for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
|
|
7136
|
+
if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY)
|
|
7137
|
+
continue;
|
|
7138
|
+
const stop = liveBlockStop(b);
|
|
7139
|
+
p = liveBlockHead(b);
|
|
7140
|
+
do {
|
|
7141
|
+
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)) {
|
|
7142
|
+
const tan = Math.abs(hy - p.y) / (hx - p.x);
|
|
7143
|
+
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)))) {
|
|
7144
|
+
m = p;
|
|
7145
|
+
tanMin = tan;
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7148
|
+
p = p.next;
|
|
7149
|
+
} while (p !== stop);
|
|
7150
|
+
}
|
|
7151
|
+
return m;
|
|
7152
|
+
}
|
|
7153
|
+
function sectorContainsSector(m, p) {
|
|
7154
|
+
return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
|
|
7155
|
+
}
|
|
7156
|
+
function indexCurve(start, minX, minY, invSize) {
|
|
7157
|
+
let p = start;
|
|
7158
|
+
let n = 0;
|
|
7159
|
+
do {
|
|
7160
|
+
p.z = zOrder(p.x, p.y, minX, minY, invSize);
|
|
7161
|
+
sortArr[n++] = p;
|
|
7162
|
+
p = p.next;
|
|
7163
|
+
} while (p !== start);
|
|
7164
|
+
sortNodes(n);
|
|
7165
|
+
let prev = null;
|
|
7166
|
+
for (let i = 0;i < n; i++) {
|
|
7167
|
+
const node = sortArr[i];
|
|
7168
|
+
node.prevZ = prev;
|
|
7169
|
+
if (prev)
|
|
7170
|
+
prev.nextZ = node;
|
|
7171
|
+
prev = node;
|
|
7172
|
+
}
|
|
7173
|
+
prev.nextZ = null;
|
|
7174
|
+
sortArr.fill(null, 0, n);
|
|
7175
|
+
sortBuf.fill(null, 0, n);
|
|
7176
|
+
}
|
|
7177
|
+
function sortNodes(n) {
|
|
7178
|
+
if (n <= 32) {
|
|
7179
|
+
for (let i = 1;i < n; i++) {
|
|
7180
|
+
const node = sortArr[i], z = node.z;
|
|
7181
|
+
let j = i - 1;
|
|
7182
|
+
while (j >= 0 && sortArr[j].z > z) {
|
|
7183
|
+
sortArr[j + 1] = sortArr[j];
|
|
7184
|
+
j--;
|
|
7185
|
+
}
|
|
7186
|
+
sortArr[j + 1] = node;
|
|
7187
|
+
}
|
|
7188
|
+
return;
|
|
7189
|
+
}
|
|
7190
|
+
if (zArr.length < n) {
|
|
7191
|
+
zArr = new Uint32Array(n);
|
|
7192
|
+
zBuf = new Uint32Array(n);
|
|
7193
|
+
sortBuf = new Array(n);
|
|
7194
|
+
}
|
|
7195
|
+
for (let i = 0;i < n; i++)
|
|
7196
|
+
zArr[i] = sortArr[i].z;
|
|
7197
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
|
|
7198
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
|
|
7199
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
|
|
7200
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
|
|
7201
|
+
}
|
|
7202
|
+
function radixPass(n, src, srcZ, dst, dstZ, shift) {
|
|
7203
|
+
counts.fill(0);
|
|
7204
|
+
for (let i = 0;i < n; i++)
|
|
7205
|
+
counts[srcZ[i] >>> shift & 255]++;
|
|
7206
|
+
let sum = 0;
|
|
7207
|
+
for (let b = 0;b < 256; b++) {
|
|
7208
|
+
const c = counts[b];
|
|
7209
|
+
counts[b] = sum;
|
|
7210
|
+
sum += c;
|
|
7211
|
+
}
|
|
7212
|
+
for (let i = 0;i < n; i++) {
|
|
7213
|
+
const z = srcZ[i];
|
|
7214
|
+
const pos = counts[z >>> shift & 255]++;
|
|
7215
|
+
dst[pos] = src[i];
|
|
7216
|
+
dstZ[pos] = z;
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
function zOrder(x, y, minX, minY, invSize) {
|
|
7220
|
+
x = (x - minX) * invSize | 0;
|
|
7221
|
+
y = (y - minY) * invSize | 0;
|
|
7222
|
+
x = (x | x << 8) & 16711935;
|
|
7223
|
+
x = (x | x << 4) & 252645135;
|
|
7224
|
+
x = (x | x << 2) & 858993459;
|
|
7225
|
+
x = (x | x << 1) & 1431655765;
|
|
7226
|
+
y = (y | y << 8) & 16711935;
|
|
7227
|
+
y = (y | y << 4) & 252645135;
|
|
7228
|
+
y = (y | y << 2) & 858993459;
|
|
7229
|
+
y = (y | y << 1) & 1431655765;
|
|
7230
|
+
return x | y << 1;
|
|
7231
|
+
}
|
|
7232
|
+
function getLeftmost(start) {
|
|
7233
|
+
let p = start, leftmost = start;
|
|
7234
|
+
do {
|
|
7235
|
+
if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y)
|
|
7236
|
+
leftmost = p;
|
|
7237
|
+
p = p.next;
|
|
7238
|
+
} while (p !== start);
|
|
7239
|
+
return leftmost;
|
|
7240
|
+
}
|
|
7241
|
+
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
7242
|
+
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);
|
|
7243
|
+
}
|
|
7244
|
+
function isValidDiagonal(a, b) {
|
|
7245
|
+
const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
|
|
7246
|
+
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));
|
|
7247
|
+
}
|
|
7248
|
+
function area(p, q, r) {
|
|
7249
|
+
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
7250
|
+
}
|
|
7251
|
+
function equals(p1, p2) {
|
|
7252
|
+
return p1.x === p2.x && p1.y === p2.y;
|
|
7253
|
+
}
|
|
7254
|
+
function intersects(p1, q1, p2, q2, includeBoundary = true) {
|
|
7255
|
+
const o1 = area(p1, q1, p2);
|
|
7256
|
+
const o2 = area(p1, q1, q2);
|
|
7257
|
+
const o3 = area(p2, q2, p1);
|
|
7258
|
+
const o4 = area(p2, q2, q1);
|
|
7259
|
+
if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0))
|
|
7260
|
+
return true;
|
|
7261
|
+
if (!includeBoundary)
|
|
7262
|
+
return false;
|
|
7263
|
+
if (o1 === 0 && onSegment(p1, p2, q1))
|
|
7264
|
+
return true;
|
|
7265
|
+
if (o2 === 0 && onSegment(p1, q2, q1))
|
|
7266
|
+
return true;
|
|
7267
|
+
if (o3 === 0 && onSegment(p2, p1, q2))
|
|
7268
|
+
return true;
|
|
7269
|
+
if (o4 === 0 && onSegment(p2, q1, q2))
|
|
7270
|
+
return true;
|
|
7271
|
+
return false;
|
|
7272
|
+
}
|
|
7273
|
+
function onSegment(p, q, r) {
|
|
7274
|
+
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);
|
|
7275
|
+
}
|
|
7276
|
+
function intersectsPolygon(a, b) {
|
|
7277
|
+
const minX = Math.min(a.x, b.x);
|
|
7278
|
+
const maxX = Math.max(a.x, b.x);
|
|
7279
|
+
const minY = Math.min(a.y, b.y);
|
|
7280
|
+
const maxY = Math.max(a.y, b.y);
|
|
7281
|
+
let p = a;
|
|
7282
|
+
do {
|
|
7283
|
+
const n = p.next;
|
|
7284
|
+
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) {
|
|
7285
|
+
p = n;
|
|
7286
|
+
continue;
|
|
7287
|
+
}
|
|
7288
|
+
if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b))
|
|
7289
|
+
return true;
|
|
7290
|
+
p = n;
|
|
7291
|
+
} while (p !== a);
|
|
7292
|
+
return false;
|
|
7293
|
+
}
|
|
7294
|
+
function locallyInside(a, b) {
|
|
7295
|
+
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;
|
|
7296
|
+
}
|
|
7297
|
+
function middleInside(a, b) {
|
|
7298
|
+
let p = a;
|
|
7299
|
+
let inside = false;
|
|
7300
|
+
const px = (a.x + b.x) / 2;
|
|
7301
|
+
const py = (a.y + b.y) / 2;
|
|
7302
|
+
do {
|
|
7303
|
+
const n = p.next;
|
|
7304
|
+
if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
|
|
7305
|
+
inside = !inside;
|
|
7306
|
+
p = n;
|
|
7307
|
+
} while (p !== a);
|
|
7308
|
+
return inside;
|
|
7309
|
+
}
|
|
7310
|
+
function splitPolygon(a, b) {
|
|
7311
|
+
const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
|
|
7312
|
+
a.next = b;
|
|
7313
|
+
b.prev = a;
|
|
7314
|
+
a2.next = an;
|
|
7315
|
+
an.prev = a2;
|
|
7316
|
+
b2.next = a2;
|
|
7317
|
+
a2.prev = b2;
|
|
7318
|
+
bp.next = b2;
|
|
7319
|
+
b2.prev = bp;
|
|
7320
|
+
return b2;
|
|
7321
|
+
}
|
|
7322
|
+
function insertNode(i, x, y, last) {
|
|
7323
|
+
const p = createNode(i, x, y);
|
|
7324
|
+
if (!last) {
|
|
7325
|
+
p.prev = p;
|
|
7326
|
+
p.next = p;
|
|
7327
|
+
} else {
|
|
7328
|
+
p.next = last.next;
|
|
7329
|
+
p.prev = last;
|
|
7330
|
+
last.next.prev = p;
|
|
7331
|
+
last.next = p;
|
|
7332
|
+
}
|
|
7333
|
+
return p;
|
|
7334
|
+
}
|
|
7335
|
+
function removeNode(p) {
|
|
7336
|
+
p.next.prev = p.prev;
|
|
7337
|
+
p.prev.next = p.next;
|
|
7338
|
+
if (p.prevZ)
|
|
7339
|
+
p.prevZ.nextZ = p.nextZ;
|
|
7340
|
+
if (p.nextZ)
|
|
7341
|
+
p.nextZ.prevZ = p.prevZ;
|
|
7342
|
+
if (indexActive)
|
|
7343
|
+
growBlock(p.prev, p.next);
|
|
7344
|
+
}
|
|
7345
|
+
function createNode(i, x, y) {
|
|
7346
|
+
return {
|
|
7347
|
+
i,
|
|
7348
|
+
x,
|
|
7349
|
+
y,
|
|
7350
|
+
prev: null,
|
|
7351
|
+
next: null,
|
|
7352
|
+
z: 0,
|
|
7353
|
+
prevZ: null,
|
|
7354
|
+
nextZ: null
|
|
7355
|
+
};
|
|
7356
|
+
}
|
|
7357
|
+
function signedArea(data, start, end, dim) {
|
|
7358
|
+
let sum = 0;
|
|
7359
|
+
for (let i = start, j = end - dim;i < end; i += dim) {
|
|
7360
|
+
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
7361
|
+
j = i;
|
|
7362
|
+
}
|
|
7363
|
+
return sum;
|
|
7364
|
+
}
|
|
7365
|
+
function refine(triangles, coords, dim = 2) {
|
|
7366
|
+
const t = triangles;
|
|
7367
|
+
const n = t.length;
|
|
7368
|
+
if (n < 6)
|
|
7369
|
+
return;
|
|
7370
|
+
ensureScratch(n);
|
|
7371
|
+
gen++;
|
|
7372
|
+
he.fill(-1, 0, n);
|
|
7373
|
+
let i = 0;
|
|
7374
|
+
for (let e = 0;e < n; e++) {
|
|
7375
|
+
const a = t[e], b = t[nextHE(e)];
|
|
7376
|
+
const lo = a < b ? a : b, hi = a < b ? b : a;
|
|
7377
|
+
let h = (Math.imul(lo, 2654435761) ^ Math.imul(hi, 2246822507)) & hMask;
|
|
7378
|
+
while (hStamp[h] === gen) {
|
|
7379
|
+
const s = hTable[h];
|
|
7380
|
+
if (s !== -1) {
|
|
7381
|
+
const sa = t[s], sb = t[nextHE(s)];
|
|
7382
|
+
if (sa === lo && sb === hi || sa === hi && sb === lo) {
|
|
7383
|
+
he[e] = s;
|
|
7384
|
+
he[s] = e;
|
|
7385
|
+
hTable[h] = -1;
|
|
7386
|
+
edgeStamp[s] = 1;
|
|
7387
|
+
edgeStack[i++] = s;
|
|
7388
|
+
break;
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7391
|
+
h = h + 1 & hMask;
|
|
7392
|
+
}
|
|
7393
|
+
if (hStamp[h] !== gen) {
|
|
7394
|
+
hTable[h] = e;
|
|
7395
|
+
hStamp[h] = gen;
|
|
7396
|
+
}
|
|
7397
|
+
}
|
|
7398
|
+
while (i > 0) {
|
|
7399
|
+
const a = edgeStack[--i];
|
|
7400
|
+
edgeStamp[a] = 0;
|
|
7401
|
+
const b = he[a];
|
|
7402
|
+
if (b === -1)
|
|
7403
|
+
continue;
|
|
7404
|
+
const a0 = a - a % 3;
|
|
7405
|
+
const b0 = b - b % 3;
|
|
7406
|
+
const ar = a0 + (a + 2) % 3;
|
|
7407
|
+
const al = a0 + (a + 1) % 3;
|
|
7408
|
+
const bl = b0 + (b + 2) % 3;
|
|
7409
|
+
const br = b0 + (b + 1) % 3;
|
|
7410
|
+
const p0 = t[ar], pr = t[a], pl = t[al], p1 = t[bl];
|
|
7411
|
+
const x0 = coords[p0 * dim], y0 = coords[p0 * dim + 1];
|
|
7412
|
+
const xr = coords[pr * dim], yr = coords[pr * dim + 1];
|
|
7413
|
+
const xl = coords[pl * dim], yl = coords[pl * dim + 1];
|
|
7414
|
+
const x1 = coords[p1 * dim], y1 = coords[p1 * dim + 1];
|
|
7415
|
+
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) {
|
|
7416
|
+
t[a] = p1;
|
|
7417
|
+
t[b] = p0;
|
|
7418
|
+
const hbl = he[bl], har = he[ar];
|
|
7419
|
+
he[a] = hbl;
|
|
7420
|
+
if (hbl !== -1)
|
|
7421
|
+
he[hbl] = a;
|
|
7422
|
+
he[b] = har;
|
|
7423
|
+
if (har !== -1)
|
|
7424
|
+
he[har] = b;
|
|
7425
|
+
he[ar] = bl;
|
|
7426
|
+
he[bl] = ar;
|
|
7427
|
+
if (hbl !== -1 && edgeStamp[a] === 0) {
|
|
7428
|
+
edgeStamp[a] = 1;
|
|
7429
|
+
edgeStack[i++] = a;
|
|
7430
|
+
}
|
|
7431
|
+
if (har !== -1 && edgeStamp[b] === 0) {
|
|
7432
|
+
edgeStamp[b] = 1;
|
|
7433
|
+
edgeStack[i++] = b;
|
|
7434
|
+
}
|
|
7435
|
+
if (he[al] !== -1 && edgeStamp[al] === 0) {
|
|
7436
|
+
edgeStamp[al] = 1;
|
|
7437
|
+
edgeStack[i++] = al;
|
|
7438
|
+
}
|
|
7439
|
+
if (he[br] !== -1 && edgeStamp[br] === 0) {
|
|
7440
|
+
edgeStamp[br] = 1;
|
|
7441
|
+
edgeStack[i++] = br;
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
}
|
|
7446
|
+
function orient(ax, ay, bx, by, cx, cy) {
|
|
7447
|
+
return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
|
|
7448
|
+
}
|
|
7449
|
+
function inCircle(ax, ay, bx, by, cx, cy, px, py) {
|
|
7450
|
+
const dx = ax - px, dy = ay - py, ex = bx - px, ey = by - py, fx = cx - px, fy = cy - py;
|
|
7451
|
+
const ap = dx * dx + dy * dy, bp = ex * ex + ey * ey, cp = fx * fx + fy * fy;
|
|
7452
|
+
const s = ap + bp + cp;
|
|
7453
|
+
return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) <= 0.0000000000001 * s * s;
|
|
7454
|
+
}
|
|
7455
|
+
function nextHE(e) {
|
|
7456
|
+
return e - e % 3 + (e + 1) % 3;
|
|
7457
|
+
}
|
|
7458
|
+
function ensureScratch(n) {
|
|
7459
|
+
if (!edgeStack || edgeStack.length < n)
|
|
7460
|
+
edgeStack = new Int32Array(n);
|
|
7461
|
+
if (!he || he.length < n)
|
|
7462
|
+
he = new Int32Array(n);
|
|
7463
|
+
if (!edgeStamp || edgeStamp.length < n)
|
|
7464
|
+
edgeStamp = new Uint8Array(n);
|
|
7465
|
+
let size = 1;
|
|
7466
|
+
while (size < n * 4)
|
|
7467
|
+
size <<= 1;
|
|
7468
|
+
if (!hTable || hTable.length < size) {
|
|
7469
|
+
hTable = new Int32Array(size);
|
|
7470
|
+
hStamp = new Uint32Array(size);
|
|
7471
|
+
}
|
|
7472
|
+
hMask = size - 1;
|
|
7473
|
+
}
|
|
7474
|
+
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;
|
|
7475
|
+
var init_earcut = __esm(() => {
|
|
7476
|
+
steiners = new Set;
|
|
7477
|
+
blockBBox = new Float64Array(0);
|
|
7478
|
+
blockHead = [];
|
|
7479
|
+
blockStop = [];
|
|
7480
|
+
sortArr = [];
|
|
7481
|
+
sortBuf = [];
|
|
7482
|
+
zArr = new Uint32Array(0);
|
|
7483
|
+
zBuf = new Uint32Array(0);
|
|
7484
|
+
counts = new Uint32Array(256);
|
|
7485
|
+
});
|
|
7486
|
+
|
|
6842
7487
|
// node_modules/fflate/esm/index.mjs
|
|
6843
7488
|
import { createRequire as createRequire3 } from "module";
|
|
6844
7489
|
function deflateSync(data, opts) {
|
|
@@ -19977,6 +20622,7 @@ __export(exports_dist, {
|
|
|
19977
20622
|
createEdgeDrawCall: () => createEdgeDrawCall,
|
|
19978
20623
|
createGrid: () => createGrid,
|
|
19979
20624
|
createInfiniteGrid: () => createInfiniteGrid,
|
|
20625
|
+
createOutlineSection: () => createOutlineSection,
|
|
19980
20626
|
createSceneFromGLTF: () => createSceneFromGLTF,
|
|
19981
20627
|
createUint8Bitmap: () => createUint8Bitmap,
|
|
19982
20628
|
decodeImageFromBuffer: () => decodeImageFromBuffer,
|
|
@@ -19998,15 +20644,273 @@ import {
|
|
|
19998
20644
|
glyphLineAlphabet,
|
|
19999
20645
|
textMetrics
|
|
20000
20646
|
} from "@tscircuit/alphabet";
|
|
20647
|
+
function findSectionLoops(input) {
|
|
20648
|
+
const { positions, axis, offset, epsilon = 0.00001 } = input;
|
|
20649
|
+
const k = axis === "x" ? 0 : axis === "y" ? 1 : 2;
|
|
20650
|
+
let minimum = Infinity, maximum = -Infinity;
|
|
20651
|
+
for (let i = k;i < positions.length; i += 3) {
|
|
20652
|
+
minimum = Math.min(minimum, positions[i]);
|
|
20653
|
+
maximum = Math.max(maximum, positions[i]);
|
|
20654
|
+
}
|
|
20655
|
+
if (offset <= minimum + epsilon || offset >= maximum - epsilon)
|
|
20656
|
+
return { loops: [], openChains: 0 };
|
|
20657
|
+
const u = (k + 1) % 3;
|
|
20658
|
+
const v = (k + 2) % 3;
|
|
20659
|
+
const points = /* @__PURE__ */ new Map;
|
|
20660
|
+
const adjacency = /* @__PURE__ */ new Map;
|
|
20661
|
+
const edges = /* @__PURE__ */ new Set;
|
|
20662
|
+
const key = (p) => `${Math.round(p[0] / epsilon)},${Math.round(p[1] / epsilon)}`;
|
|
20663
|
+
for (let i = 0;i < positions.length; i += 9) {
|
|
20664
|
+
const hits = [];
|
|
20665
|
+
const distances = [0, 1, 2].map((j) => positions[i + j * 3 + k] - offset);
|
|
20666
|
+
const onPlane = distances.filter((d) => Math.abs(d) <= epsilon).length;
|
|
20667
|
+
if (onPlane === 3)
|
|
20668
|
+
continue;
|
|
20669
|
+
if (!(distances.some((d) => d > epsilon) && distances.some((d) => d < -epsilon)) && !(onPlane === 2 && distances.some((d) => d < -epsilon)))
|
|
20670
|
+
continue;
|
|
20671
|
+
for (let j = 0;j < 3; j++) {
|
|
20672
|
+
const a2 = i + j * 3;
|
|
20673
|
+
const b2 = i + (j + 1) % 3 * 3;
|
|
20674
|
+
const da = distances[j];
|
|
20675
|
+
const db = distances[(j + 1) % 3];
|
|
20676
|
+
if (Math.abs(da) <= epsilon)
|
|
20677
|
+
hits.push([positions[a2 + u], positions[a2 + v]]);
|
|
20678
|
+
else if (da > 0 !== db > 0 && Math.abs(db) > epsilon) {
|
|
20679
|
+
const t = da / (da - db);
|
|
20680
|
+
hits.push([
|
|
20681
|
+
positions[a2 + u] + t * (positions[b2 + u] - positions[a2 + u]),
|
|
20682
|
+
positions[a2 + v] + t * (positions[b2 + v] - positions[a2 + v])
|
|
20683
|
+
]);
|
|
20684
|
+
}
|
|
20685
|
+
}
|
|
20686
|
+
const unique = [...new Map(hits.map((p) => [key(p), p])).values()];
|
|
20687
|
+
if (unique.length !== 2)
|
|
20688
|
+
continue;
|
|
20689
|
+
const [a, b] = unique.map(key);
|
|
20690
|
+
if (a === b)
|
|
20691
|
+
continue;
|
|
20692
|
+
const edge2 = a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
20693
|
+
if (edges.has(edge2))
|
|
20694
|
+
continue;
|
|
20695
|
+
edges.add(edge2);
|
|
20696
|
+
points.set(a, unique[0]);
|
|
20697
|
+
points.set(b, unique[1]);
|
|
20698
|
+
if (!adjacency.has(a))
|
|
20699
|
+
adjacency.set(a, /* @__PURE__ */ new Set);
|
|
20700
|
+
if (!adjacency.has(b))
|
|
20701
|
+
adjacency.set(b, /* @__PURE__ */ new Set);
|
|
20702
|
+
adjacency.get(a).add(b);
|
|
20703
|
+
adjacency.get(b).add(a);
|
|
20704
|
+
}
|
|
20705
|
+
const loops = [];
|
|
20706
|
+
let openChains = 0;
|
|
20707
|
+
while (edges.size) {
|
|
20708
|
+
const first = edges.values().next().value;
|
|
20709
|
+
const [start, next] = first.split("|");
|
|
20710
|
+
const path = [start];
|
|
20711
|
+
let previous = start;
|
|
20712
|
+
let current = next;
|
|
20713
|
+
const remove = (a, b) => {
|
|
20714
|
+
edges.delete(a < b ? `${a}|${b}` : `${b}|${a}`);
|
|
20715
|
+
adjacency.get(a)?.delete(b);
|
|
20716
|
+
adjacency.get(b)?.delete(a);
|
|
20717
|
+
};
|
|
20718
|
+
remove(start, next);
|
|
20719
|
+
while (current !== start) {
|
|
20720
|
+
path.push(current);
|
|
20721
|
+
const candidates = [...adjacency.get(current) ?? []];
|
|
20722
|
+
if (!candidates.length)
|
|
20723
|
+
break;
|
|
20724
|
+
const p = points.get(previous);
|
|
20725
|
+
const c = points.get(current);
|
|
20726
|
+
candidates.sort((a, b) => {
|
|
20727
|
+
const score = (s) => {
|
|
20728
|
+
const n = points.get(s);
|
|
20729
|
+
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);
|
|
20730
|
+
};
|
|
20731
|
+
return score(b) - score(a);
|
|
20732
|
+
});
|
|
20733
|
+
const chosen = candidates[0];
|
|
20734
|
+
remove(current, chosen);
|
|
20735
|
+
previous = current;
|
|
20736
|
+
current = chosen;
|
|
20737
|
+
}
|
|
20738
|
+
if (current === start && path.length >= 3)
|
|
20739
|
+
loops.push(path.map((p) => points.get(p)));
|
|
20740
|
+
else
|
|
20741
|
+
openChains++;
|
|
20742
|
+
}
|
|
20743
|
+
return { loops, openChains };
|
|
20744
|
+
}
|
|
20745
|
+
function contains(p, polygon) {
|
|
20746
|
+
let inside = false;
|
|
20747
|
+
for (let i = 0, j = polygon.length - 1;i < polygon.length; j = i++) {
|
|
20748
|
+
const a = polygon[i], b = polygon[j];
|
|
20749
|
+
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])
|
|
20750
|
+
inside = !inside;
|
|
20751
|
+
}
|
|
20752
|
+
return inside;
|
|
20753
|
+
}
|
|
20754
|
+
function createOutlineSection(drawCalls, spec) {
|
|
20755
|
+
const k = spec.axis === "x" ? 0 : spec.axis === "y" ? 1 : 2;
|
|
20756
|
+
const u = (k + 1) % 3, v = (k + 2) % 3;
|
|
20757
|
+
const spacing = spec.hatchSpacing ?? 1;
|
|
20758
|
+
if (!["x", "y", "z"].includes(spec.axis) || !Number.isFinite(spec.offset) || !["less", "greater"].includes(spec.keepSide) || !Number.isFinite(spacing) || spacing <= 0)
|
|
20759
|
+
throw new Error("Invalid outline section plane or hatch spacing");
|
|
20760
|
+
const output = [];
|
|
20761
|
+
let openChains = 0;
|
|
20762
|
+
const texture = createUint8Bitmap(128, 128);
|
|
20763
|
+
for (let y = 0;y < 128; y++)
|
|
20764
|
+
for (let x = 0;x < 128; x++) {
|
|
20765
|
+
const c = (x + 127 - y) % 16 < 2 ? 0 : 255;
|
|
20766
|
+
texture.data.set([c, c, c, 255], (y * 128 + x) * 4);
|
|
20767
|
+
}
|
|
20768
|
+
const sign = spec.keepSide === "less" ? 1 : -1;
|
|
20769
|
+
for (const dc of drawCalls) {
|
|
20770
|
+
const points = [];
|
|
20771
|
+
for (let i = 0;i < dc.positions.length; i += 3)
|
|
20772
|
+
points.push(Array.from(import_gl_matrix.vec3.transformMat4(import_gl_matrix.vec3.create(), dc.positions.subarray(i, i + 3), dc.model)));
|
|
20773
|
+
const indices = dc.indices ?? Uint32Array.from(points, (_, i) => i);
|
|
20774
|
+
const clipped = [], triangles = [];
|
|
20775
|
+
const distance = (p) => sign * (p[k] - spec.offset);
|
|
20776
|
+
const intersection = (a, b) => {
|
|
20777
|
+
const t = distance(a) / (distance(a) - distance(b));
|
|
20778
|
+
return a.map((n, j) => n + t * (b[j] - n));
|
|
20779
|
+
};
|
|
20780
|
+
if (dc.mode === 1) {
|
|
20781
|
+
for (let i = 0;i + 1 < indices.length; i += 2) {
|
|
20782
|
+
let a = points[indices[i]], b = points[indices[i + 1]];
|
|
20783
|
+
if (distance(a) > 0 && distance(b) > 0)
|
|
20784
|
+
continue;
|
|
20785
|
+
if (distance(a) > 0)
|
|
20786
|
+
a = intersection(a, b);
|
|
20787
|
+
else if (distance(b) > 0)
|
|
20788
|
+
b = intersection(a, b);
|
|
20789
|
+
clipped.push(...a, ...b);
|
|
20790
|
+
}
|
|
20791
|
+
output.push({
|
|
20792
|
+
...dc,
|
|
20793
|
+
positions: new Float32Array(clipped),
|
|
20794
|
+
indices: null,
|
|
20795
|
+
model: import_gl_matrix.mat4.create()
|
|
20796
|
+
});
|
|
20797
|
+
continue;
|
|
20798
|
+
}
|
|
20799
|
+
if (dc.mode != null && dc.mode !== 4)
|
|
20800
|
+
continue;
|
|
20801
|
+
for (let i = 0;i + 2 < indices.length; i += 3) {
|
|
20802
|
+
const triangle = [
|
|
20803
|
+
points[indices[i]],
|
|
20804
|
+
points[indices[i + 1]],
|
|
20805
|
+
points[indices[i + 2]]
|
|
20806
|
+
];
|
|
20807
|
+
triangles.push(...triangle.flat());
|
|
20808
|
+
const polygon = [];
|
|
20809
|
+
for (let j = 0;j < 3; j++) {
|
|
20810
|
+
const a = triangle[j], b = triangle[(j + 1) % 3];
|
|
20811
|
+
if (distance(a) <= 0)
|
|
20812
|
+
polygon.push(a);
|
|
20813
|
+
if (distance(a) < 0 && distance(b) > 0 || distance(a) > 0 && distance(b) < 0)
|
|
20814
|
+
polygon.push(intersection(a, b));
|
|
20815
|
+
}
|
|
20816
|
+
for (let j = 1;j + 1 < polygon.length; j++)
|
|
20817
|
+
clipped.push(...polygon[0], ...polygon[j], ...polygon[j + 1]);
|
|
20818
|
+
}
|
|
20819
|
+
const white = {
|
|
20820
|
+
baseColorFactor: [1, 1, 1, 1],
|
|
20821
|
+
baseColorTexture: null
|
|
20822
|
+
};
|
|
20823
|
+
const mesh = {
|
|
20824
|
+
...dc,
|
|
20825
|
+
positions: new Float32Array(clipped),
|
|
20826
|
+
indices: null,
|
|
20827
|
+
model: import_gl_matrix.mat4.create(),
|
|
20828
|
+
normals: null,
|
|
20829
|
+
colors: null,
|
|
20830
|
+
uvs: null,
|
|
20831
|
+
material: white
|
|
20832
|
+
};
|
|
20833
|
+
output.push(mesh);
|
|
20834
|
+
const extent = Math.max(...[0, 1, 2].map((axis) => {
|
|
20835
|
+
let min = Infinity, max = -Infinity;
|
|
20836
|
+
for (const p of points) {
|
|
20837
|
+
min = Math.min(min, p[axis]);
|
|
20838
|
+
max = Math.max(max, p[axis]);
|
|
20839
|
+
}
|
|
20840
|
+
return max - min;
|
|
20841
|
+
}));
|
|
20842
|
+
const result = findSectionLoops({
|
|
20843
|
+
positions: new Float32Array(triangles),
|
|
20844
|
+
axis: spec.axis,
|
|
20845
|
+
offset: spec.offset,
|
|
20846
|
+
epsilon: Math.max(extent * 0.0000001, 0.000000001)
|
|
20847
|
+
});
|
|
20848
|
+
openChains += result.openChains;
|
|
20849
|
+
const rings = result.loops.map((points2) => ({
|
|
20850
|
+
points: points2,
|
|
20851
|
+
area: Math.abs(points2.reduce((a, p, i) => {
|
|
20852
|
+
const q = points2[(i + 1) % points2.length];
|
|
20853
|
+
return a + p[0] * q[1] - q[0] * p[1];
|
|
20854
|
+
}, 0)),
|
|
20855
|
+
parent: -1,
|
|
20856
|
+
depth: 0
|
|
20857
|
+
})).sort((a, b) => b.area - a.area);
|
|
20858
|
+
rings.forEach((ring, i) => {
|
|
20859
|
+
for (let j = 0;j < i; j++)
|
|
20860
|
+
if (contains(ring.points[0], rings[j].points))
|
|
20861
|
+
ring.parent = j;
|
|
20862
|
+
ring.depth = ring.parent < 0 ? 0 : rings[ring.parent].depth + 1;
|
|
20863
|
+
});
|
|
20864
|
+
const cap = [], uv = [];
|
|
20865
|
+
rings.forEach((ring, i) => {
|
|
20866
|
+
if (ring.depth % 2)
|
|
20867
|
+
return;
|
|
20868
|
+
const holes = rings.filter((r) => r.parent === i && r.depth % 2);
|
|
20869
|
+
const flat = [...ring.points], starts = [];
|
|
20870
|
+
for (const hole of holes) {
|
|
20871
|
+
starts.push(flat.length);
|
|
20872
|
+
flat.push(...hole.points);
|
|
20873
|
+
}
|
|
20874
|
+
const faces = earcut(flat.flat(), starts, 2);
|
|
20875
|
+
for (let j = 0;j < faces.length; j += 3) {
|
|
20876
|
+
const ids = faces.slice(j, j + 3);
|
|
20877
|
+
const a = flat[ids[0]], b = flat[ids[1]], c = flat[ids[2]];
|
|
20878
|
+
if (((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) * sign < 0)
|
|
20879
|
+
ids.reverse();
|
|
20880
|
+
for (const id of ids) {
|
|
20881
|
+
const p = flat[id], xyz = [0, 0, 0];
|
|
20882
|
+
xyz[k] = spec.offset;
|
|
20883
|
+
xyz[u] = p[0];
|
|
20884
|
+
xyz[v] = p[1];
|
|
20885
|
+
cap.push(...xyz);
|
|
20886
|
+
uv.push(p[0] / (spacing * 8 * Math.SQRT2), p[1] / (spacing * 8 * Math.SQRT2));
|
|
20887
|
+
}
|
|
20888
|
+
}
|
|
20889
|
+
});
|
|
20890
|
+
if (cap.length)
|
|
20891
|
+
output.push({
|
|
20892
|
+
...mesh,
|
|
20893
|
+
outlineSectionCap: true,
|
|
20894
|
+
positions: new Float32Array(cap),
|
|
20895
|
+
uvs: new Float32Array(uv),
|
|
20896
|
+
material: {
|
|
20897
|
+
...white,
|
|
20898
|
+
baseColorTexture: texture,
|
|
20899
|
+
baseColorTextureWrap: "repeat"
|
|
20900
|
+
}
|
|
20901
|
+
});
|
|
20902
|
+
}
|
|
20903
|
+
return { drawCalls: output, openChains };
|
|
20904
|
+
}
|
|
20001
20905
|
function computeWorldAABB(drawCalls) {
|
|
20002
20906
|
const min = [Infinity, Infinity, Infinity];
|
|
20003
20907
|
const max = [-Infinity, -Infinity, -Infinity];
|
|
20004
|
-
const tmp =
|
|
20908
|
+
const tmp = import_gl_matrix3.vec4.create();
|
|
20005
20909
|
for (const dc of drawCalls) {
|
|
20006
20910
|
const { positions, model } = dc;
|
|
20007
20911
|
for (let i = 0;i < positions.length; i += 3) {
|
|
20008
|
-
|
|
20009
|
-
|
|
20912
|
+
import_gl_matrix3.vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
|
|
20913
|
+
import_gl_matrix3.vec4.transformMat4(tmp, tmp, model);
|
|
20010
20914
|
const x = tmp[0];
|
|
20011
20915
|
const y = tmp[1];
|
|
20012
20916
|
const z = tmp[2];
|
|
@@ -20029,75 +20933,75 @@ function computeWorldAABB(drawCalls) {
|
|
|
20029
20933
|
function getWorldUpVector(up) {
|
|
20030
20934
|
switch (up) {
|
|
20031
20935
|
case "y-":
|
|
20032
|
-
return
|
|
20936
|
+
return import_gl_matrix2.vec3.fromValues(0, -1, 0);
|
|
20033
20937
|
case "x+":
|
|
20034
|
-
return
|
|
20938
|
+
return import_gl_matrix2.vec3.fromValues(1, 0, 0);
|
|
20035
20939
|
case "x-":
|
|
20036
|
-
return
|
|
20940
|
+
return import_gl_matrix2.vec3.fromValues(-1, 0, 0);
|
|
20037
20941
|
case "z+":
|
|
20038
|
-
return
|
|
20942
|
+
return import_gl_matrix2.vec3.fromValues(0, 0, 1);
|
|
20039
20943
|
case "z-":
|
|
20040
|
-
return
|
|
20944
|
+
return import_gl_matrix2.vec3.fromValues(0, 0, -1);
|
|
20041
20945
|
case "y+":
|
|
20042
20946
|
default:
|
|
20043
|
-
return
|
|
20947
|
+
return import_gl_matrix2.vec3.fromValues(0, 1, 0);
|
|
20044
20948
|
}
|
|
20045
20949
|
}
|
|
20046
20950
|
function buildCameraWorldMatrix(eye, forward, up) {
|
|
20047
|
-
const normalizedForward =
|
|
20048
|
-
const right =
|
|
20049
|
-
if (
|
|
20951
|
+
const normalizedForward = import_gl_matrix2.vec3.normalize(import_gl_matrix2.vec3.create(), forward);
|
|
20952
|
+
const right = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), normalizedForward, up);
|
|
20953
|
+
if (import_gl_matrix2.vec3.squaredLength(right) === 0) {
|
|
20050
20954
|
return null;
|
|
20051
20955
|
}
|
|
20052
|
-
|
|
20053
|
-
const correctedUp =
|
|
20054
|
-
if (
|
|
20956
|
+
import_gl_matrix2.vec3.normalize(right, right);
|
|
20957
|
+
const correctedUp = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), right, normalizedForward);
|
|
20958
|
+
if (import_gl_matrix2.vec3.squaredLength(correctedUp) === 0) {
|
|
20055
20959
|
return null;
|
|
20056
20960
|
}
|
|
20057
|
-
|
|
20058
|
-
return
|
|
20961
|
+
import_gl_matrix2.vec3.normalize(correctedUp, correctedUp);
|
|
20962
|
+
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);
|
|
20059
20963
|
}
|
|
20060
20964
|
function getDefaultForwardForUp(up) {
|
|
20061
|
-
const zForward =
|
|
20062
|
-
if (Math.abs(
|
|
20965
|
+
const zForward = import_gl_matrix2.vec3.fromValues(0, 0, -1);
|
|
20966
|
+
if (Math.abs(import_gl_matrix2.vec3.dot(up, zForward)) < 0.999) {
|
|
20063
20967
|
return zForward;
|
|
20064
20968
|
}
|
|
20065
|
-
return
|
|
20969
|
+
return import_gl_matrix2.vec3.fromValues(1, 0, 0);
|
|
20066
20970
|
}
|
|
20067
20971
|
function buildViewFromRotation(eye, up, rotation) {
|
|
20068
20972
|
const cameraWorld = buildCameraWorldMatrix(eye, getDefaultForwardForUp(up), up);
|
|
20069
20973
|
if (!cameraWorld) {
|
|
20070
|
-
return
|
|
20974
|
+
return import_gl_matrix2.mat4.create();
|
|
20071
20975
|
}
|
|
20072
20976
|
if (rotation.x !== 0) {
|
|
20073
|
-
|
|
20977
|
+
import_gl_matrix2.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
|
|
20074
20978
|
}
|
|
20075
20979
|
if (rotation.y !== 0) {
|
|
20076
|
-
|
|
20980
|
+
import_gl_matrix2.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
|
|
20077
20981
|
}
|
|
20078
20982
|
if (rotation.z !== 0) {
|
|
20079
|
-
|
|
20983
|
+
import_gl_matrix2.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
|
|
20080
20984
|
}
|
|
20081
|
-
const view =
|
|
20082
|
-
|
|
20985
|
+
const view = import_gl_matrix2.mat4.create();
|
|
20986
|
+
import_gl_matrix2.mat4.invert(view, cameraWorld);
|
|
20083
20987
|
return view;
|
|
20084
20988
|
}
|
|
20085
20989
|
function buildViewFromLookAt(eye, center, up) {
|
|
20086
|
-
const forward =
|
|
20087
|
-
if (
|
|
20088
|
-
return
|
|
20990
|
+
const forward = import_gl_matrix2.vec3.subtract(import_gl_matrix2.vec3.create(), center, eye);
|
|
20991
|
+
if (import_gl_matrix2.vec3.squaredLength(forward) === 0) {
|
|
20992
|
+
return import_gl_matrix2.mat4.create();
|
|
20089
20993
|
}
|
|
20090
20994
|
const cameraWorld = buildCameraWorldMatrix(eye, forward, up);
|
|
20091
20995
|
if (!cameraWorld) {
|
|
20092
|
-
return
|
|
20996
|
+
return import_gl_matrix2.mat4.create();
|
|
20093
20997
|
}
|
|
20094
|
-
const view =
|
|
20095
|
-
|
|
20998
|
+
const view = import_gl_matrix2.mat4.create();
|
|
20999
|
+
import_gl_matrix2.mat4.invert(view, cameraWorld);
|
|
20096
21000
|
return view;
|
|
20097
21001
|
}
|
|
20098
21002
|
function getAutoDistance(drawCalls, fovDeg) {
|
|
20099
21003
|
const aabb = computeWorldAABB(drawCalls);
|
|
20100
|
-
const diag =
|
|
21004
|
+
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]));
|
|
20101
21005
|
const radius = diag * 0.5;
|
|
20102
21006
|
const fov = toRad(fovDeg);
|
|
20103
21007
|
return radius / Math.tan(fov * 0.5) + radius * 0.5;
|
|
@@ -20111,7 +21015,7 @@ function getAABBCornerDistances(aabb, eye) {
|
|
|
20111
21015
|
for (const x of xs) {
|
|
20112
21016
|
for (const y of ys) {
|
|
20113
21017
|
for (const z of zs) {
|
|
20114
|
-
const distance =
|
|
21018
|
+
const distance = import_gl_matrix2.vec3.distance(eye, import_gl_matrix2.vec3.fromValues(x, y, z));
|
|
20115
21019
|
farthest = Math.max(farthest, distance);
|
|
20116
21020
|
}
|
|
20117
21021
|
}
|
|
@@ -20119,40 +21023,56 @@ function getAABBCornerDistances(aabb, eye) {
|
|
|
20119
21023
|
return { nearest, farthest };
|
|
20120
21024
|
}
|
|
20121
21025
|
function getCameraForwardFromView(view) {
|
|
20122
|
-
const cameraWorld =
|
|
20123
|
-
|
|
20124
|
-
return
|
|
21026
|
+
const cameraWorld = import_gl_matrix2.mat4.create();
|
|
21027
|
+
import_gl_matrix2.mat4.invert(cameraWorld, view);
|
|
21028
|
+
return import_gl_matrix2.vec3.fromValues(-cameraWorld[8], -cameraWorld[9], -cameraWorld[10]);
|
|
20125
21029
|
}
|
|
20126
|
-
function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null) {
|
|
21030
|
+
function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null, projection = "perspective", orthographicHeight = null) {
|
|
20127
21031
|
const aspect = width / height;
|
|
20128
21032
|
const worldUp = getWorldUpVector(up);
|
|
20129
21033
|
const aabb = computeWorldAABB(drawCalls);
|
|
20130
|
-
const center =
|
|
21034
|
+
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]));
|
|
20131
21035
|
const autoDistance = getAutoDistance(drawCalls, fovDeg);
|
|
20132
21036
|
if (cameraRotation) {
|
|
20133
|
-
const provisionalEye = camPos ?
|
|
21037
|
+
const provisionalEye = camPos ? import_gl_matrix2.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix2.vec3.clone(center);
|
|
20134
21038
|
const provisionalView = buildViewFromRotation(provisionalEye, worldUp, cameraRotation);
|
|
20135
|
-
const eye2 = camPos ? provisionalEye :
|
|
21039
|
+
const eye2 = camPos ? provisionalEye : import_gl_matrix2.vec3.scaleAndAdd(import_gl_matrix2.vec3.create(), center, getCameraForwardFromView(provisionalView), -autoDistance);
|
|
20136
21040
|
const { nearest: nearest2, farthest: farthest2 } = getAABBCornerDistances(aabb, eye2);
|
|
20137
21041
|
const near2 = Math.max(0.01, nearest2 * 0.5);
|
|
20138
21042
|
const far2 = Math.max(1000, farthest2 * 1.1);
|
|
20139
|
-
const proj2 =
|
|
20140
|
-
|
|
21043
|
+
const proj2 = import_gl_matrix2.mat4.create();
|
|
21044
|
+
const view2 = buildViewFromRotation(eye2, worldUp, cameraRotation);
|
|
21045
|
+
setProjection(proj2, view2, aabb, projection, orthographicHeight, fovDeg, aspect, near2, far2);
|
|
20141
21046
|
return {
|
|
20142
|
-
view:
|
|
21047
|
+
view: view2,
|
|
20143
21048
|
proj: proj2
|
|
20144
21049
|
};
|
|
20145
21050
|
}
|
|
20146
|
-
const eye = camPos ?
|
|
20147
|
-
const target = lookAt ?
|
|
21051
|
+
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);
|
|
21052
|
+
const target = lookAt ? import_gl_matrix2.vec3.fromValues(lookAt[0], lookAt[1], lookAt[2]) : center;
|
|
20148
21053
|
const { nearest, farthest } = getAABBCornerDistances(aabb, eye);
|
|
20149
21054
|
const near = Math.max(0.01, nearest * 0.5);
|
|
20150
21055
|
const far = Math.max(1000, farthest * 1.1);
|
|
20151
|
-
const proj =
|
|
20152
|
-
import_gl_matrix.mat4.perspective(proj, toRad(fovDeg), aspect, near, far);
|
|
21056
|
+
const proj = import_gl_matrix2.mat4.create();
|
|
20153
21057
|
const view = buildViewFromLookAt(eye, target, worldUp);
|
|
21058
|
+
setProjection(proj, view, aabb, projection, orthographicHeight, fovDeg, aspect, near, far);
|
|
20154
21059
|
return { view, proj };
|
|
20155
21060
|
}
|
|
21061
|
+
function setProjection(proj, view, aabb, projection, height, fov, aspect, near, far) {
|
|
21062
|
+
if (projection === "perspective") {
|
|
21063
|
+
import_gl_matrix2.mat4.perspective(proj, toRad(fov), aspect, near, far);
|
|
21064
|
+
return;
|
|
21065
|
+
}
|
|
21066
|
+
let halfHeight = 0;
|
|
21067
|
+
for (const x of [aabb.min[0], aabb.max[0]])
|
|
21068
|
+
for (const y of [aabb.min[1], aabb.max[1]])
|
|
21069
|
+
for (const z of [aabb.min[2], aabb.max[2]]) {
|
|
21070
|
+
const p = import_gl_matrix2.vec3.transformMat4(import_gl_matrix2.vec3.create(), [x, y, z], view);
|
|
21071
|
+
halfHeight = Math.max(halfHeight, Math.abs(p[1]), Math.abs(p[0]) / aspect);
|
|
21072
|
+
}
|
|
21073
|
+
halfHeight = height != null && Number.isFinite(height) && height > 0 ? height / 2 : Math.max(halfHeight * 1.1, 0.001);
|
|
21074
|
+
import_gl_matrix2.mat4.ortho(proj, -halfHeight * aspect, halfHeight * aspect, -halfHeight, halfHeight, near, far);
|
|
21075
|
+
}
|
|
20156
21076
|
function createGrid(options = {}) {
|
|
20157
21077
|
const size = options.size ?? 10;
|
|
20158
21078
|
const sizeX = typeof size === "number" ? size : size[0];
|
|
@@ -20177,8 +21097,8 @@ function createGrid(options = {}) {
|
|
|
20177
21097
|
positions.push(halfSizeX, 0, pZ);
|
|
20178
21098
|
indices.push(vertexIndex++, vertexIndex++);
|
|
20179
21099
|
}
|
|
20180
|
-
const model =
|
|
20181
|
-
|
|
21100
|
+
const model = import_gl_matrix4.mat4.create();
|
|
21101
|
+
import_gl_matrix4.mat4.fromTranslation(model, [offset.x, offset.y, offset.z]);
|
|
20182
21102
|
return {
|
|
20183
21103
|
positions: new Float32Array(positions),
|
|
20184
21104
|
indices: new Uint32Array(indices),
|
|
@@ -20210,7 +21130,7 @@ function triangleNormal(positions, i0, i1, i2) {
|
|
|
20210
21130
|
return null;
|
|
20211
21131
|
return [nx / length, ny / length, nz / length];
|
|
20212
21132
|
}
|
|
20213
|
-
function addEdge(edges, positions, i0, i1, normal) {
|
|
21133
|
+
function addEdge(edges, positions, i0, i1, thirdVertex, normal, facing) {
|
|
20214
21134
|
const key0 = positionKey(positions, i0);
|
|
20215
21135
|
const key1 = positionKey(positions, i1);
|
|
20216
21136
|
const isForward = key0 < key1;
|
|
@@ -20220,8 +21140,15 @@ function addEdge(edges, positions, i0, i1, normal) {
|
|
|
20220
21140
|
if (existing) {
|
|
20221
21141
|
if (normal)
|
|
20222
21142
|
existing.normals.push(normal);
|
|
21143
|
+
existing.adjacentVertices.push(thirdVertex);
|
|
21144
|
+
existing.facings.push(facing);
|
|
20223
21145
|
} else {
|
|
20224
|
-
edges.set(key, {
|
|
21146
|
+
edges.set(key, {
|
|
21147
|
+
indices,
|
|
21148
|
+
normals: normal ? [normal] : [],
|
|
21149
|
+
adjacentVertices: [thirdVertex],
|
|
21150
|
+
facings: [facing]
|
|
21151
|
+
});
|
|
20225
21152
|
}
|
|
20226
21153
|
}
|
|
20227
21154
|
function hasCrease(normals, minimumDot) {
|
|
@@ -20238,29 +21165,42 @@ function hasCrease(normals, minimumDot) {
|
|
|
20238
21165
|
}
|
|
20239
21166
|
return false;
|
|
20240
21167
|
}
|
|
20241
|
-
function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES) {
|
|
21168
|
+
function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES, camera) {
|
|
20242
21169
|
if (mesh.mode != null && mesh.mode !== 4)
|
|
20243
21170
|
return null;
|
|
20244
21171
|
const vertexCount = Math.floor(mesh.positions.length / 3);
|
|
20245
21172
|
const triangleIndices = mesh.indices ?? Uint32Array.from({ length: vertexCount }, (_, i) => i);
|
|
20246
21173
|
if (triangleIndices.length < 3)
|
|
20247
21174
|
return null;
|
|
21175
|
+
let normalPositions = mesh.positions;
|
|
21176
|
+
if (camera) {
|
|
21177
|
+
const modelView = import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), camera.view, mesh.model);
|
|
21178
|
+
normalPositions = new Float32Array(mesh.positions.length);
|
|
21179
|
+
for (let i = 0;i < vertexCount; i++) {
|
|
21180
|
+
const point = import_gl_matrix5.vec3.transformMat4(import_gl_matrix5.vec3.create(), mesh.positions.subarray(i * 3, i * 3 + 3), modelView);
|
|
21181
|
+
normalPositions.set(point, i * 3);
|
|
21182
|
+
}
|
|
21183
|
+
}
|
|
20248
21184
|
const edges = /* @__PURE__ */ new Map;
|
|
20249
21185
|
for (let i = 0;i + 2 < triangleIndices.length; i += 3) {
|
|
20250
21186
|
const i0 = triangleIndices[i];
|
|
20251
21187
|
const i1 = triangleIndices[i + 1];
|
|
20252
21188
|
const i2 = triangleIndices[i + 2];
|
|
20253
|
-
const normal = triangleNormal(
|
|
20254
|
-
|
|
20255
|
-
addEdge(edges, mesh.positions, i1, i2, normal);
|
|
20256
|
-
addEdge(edges, mesh.positions, i2, i0, normal);
|
|
21189
|
+
const normal = triangleNormal(normalPositions, i0, i1, i2);
|
|
21190
|
+
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];
|
|
21191
|
+
addEdge(edges, mesh.positions, i0, i1, i2, normal, facing);
|
|
21192
|
+
addEdge(edges, mesh.positions, i1, i2, i0, normal, facing);
|
|
21193
|
+
addEdge(edges, mesh.positions, i2, i0, i1, normal, facing);
|
|
20257
21194
|
}
|
|
20258
21195
|
const minimumDot = Math.cos(creaseAngleDegrees * Math.PI / 180);
|
|
20259
21196
|
const edgeIndices = [];
|
|
21197
|
+
const edgeAdjacentVertices = [];
|
|
20260
21198
|
for (const edge2 of edges.values()) {
|
|
20261
|
-
|
|
21199
|
+
const silhouette = camera && edge2.facings.some((n) => n > 0.0000001) && edge2.facings.some((n) => n <= 0.0000001);
|
|
21200
|
+
if (!hasCrease(edge2.normals, minimumDot) && !silhouette)
|
|
20262
21201
|
continue;
|
|
20263
21202
|
edgeIndices.push(edge2.indices[0], edge2.indices[1]);
|
|
21203
|
+
edgeAdjacentVertices.push(edge2.adjacentVertices);
|
|
20264
21204
|
}
|
|
20265
21205
|
if (edgeIndices.length === 0)
|
|
20266
21206
|
return null;
|
|
@@ -20275,7 +21215,8 @@ function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGR
|
|
|
20275
21215
|
baseColorTexture: null,
|
|
20276
21216
|
alphaMode: "BLEND"
|
|
20277
21217
|
},
|
|
20278
|
-
mode: 1
|
|
21218
|
+
mode: 1,
|
|
21219
|
+
edgeAdjacentVertices
|
|
20279
21220
|
};
|
|
20280
21221
|
}
|
|
20281
21222
|
function downsampleBitmap(source, targetWidth, targetHeight, imageFactory) {
|
|
@@ -20482,14 +21423,102 @@ function clipMeshToNearPlane(mesh, mvp) {
|
|
|
20482
21423
|
indices: new Uint32Array(indices)
|
|
20483
21424
|
};
|
|
20484
21425
|
}
|
|
21426
|
+
function clipLine(start, end, marginX, marginY) {
|
|
21427
|
+
if (![...start, ...end].every(Number.isFinite))
|
|
21428
|
+
return null;
|
|
21429
|
+
const distances = (p) => [
|
|
21430
|
+
p[3] * (1 + marginX) + p[0],
|
|
21431
|
+
p[3] * (1 + marginX) - p[0],
|
|
21432
|
+
p[3] * (1 + marginY) + p[1],
|
|
21433
|
+
p[3] * (1 + marginY) - p[1],
|
|
21434
|
+
p[3] + p[2],
|
|
21435
|
+
p[3] - p[2]
|
|
21436
|
+
];
|
|
21437
|
+
const a = distances(start);
|
|
21438
|
+
const b = distances(end);
|
|
21439
|
+
let from = 0;
|
|
21440
|
+
let to = 1;
|
|
21441
|
+
for (let plane = 0;plane < 6; plane++) {
|
|
21442
|
+
if (a[plane] < 0 && b[plane] < 0)
|
|
21443
|
+
return null;
|
|
21444
|
+
if (a[plane] < 0 !== b[plane] < 0) {
|
|
21445
|
+
const t = a[plane] / (a[plane] - b[plane]);
|
|
21446
|
+
if (a[plane] < 0)
|
|
21447
|
+
from = Math.max(from, t);
|
|
21448
|
+
else
|
|
21449
|
+
to = Math.min(to, t);
|
|
21450
|
+
}
|
|
21451
|
+
}
|
|
21452
|
+
if (from > to)
|
|
21453
|
+
return null;
|
|
21454
|
+
return [from, to].map((t) => Array.from(start, (value, axis) => value + t * (end[axis] - value)));
|
|
21455
|
+
}
|
|
21456
|
+
function rasterizeWideLine(start, end, width, height, strokeWidth, dashed, dashLength, fragment) {
|
|
21457
|
+
const radius = strokeWidth / 2;
|
|
21458
|
+
const padding = radius + 0.5;
|
|
21459
|
+
const clipped = clipLine(start, end, 2 * padding / Math.max(1, width - 1), 2 * padding / Math.max(1, height - 1));
|
|
21460
|
+
if (!clipped)
|
|
21461
|
+
return;
|
|
21462
|
+
const project = (p) => [
|
|
21463
|
+
(p[0] / p[3] * 0.5 + 0.5) * (width - 1),
|
|
21464
|
+
(0.5 - p[1] / p[3] * 0.5) * (height - 1),
|
|
21465
|
+
Math.max(0, Math.min(1, p[2] / p[3] * 0.5 + 0.5))
|
|
21466
|
+
];
|
|
21467
|
+
const a = project(clipped[0]);
|
|
21468
|
+
const b = project(clipped[1]);
|
|
21469
|
+
if (![...a, ...b].every(Number.isFinite))
|
|
21470
|
+
return;
|
|
21471
|
+
const [x0, y0, z0] = a;
|
|
21472
|
+
const [x1, y1, z1] = b;
|
|
21473
|
+
const dx = x1 - x0;
|
|
21474
|
+
const dy = y1 - y0;
|
|
21475
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
21476
|
+
const length = Math.sqrt(lengthSquared);
|
|
21477
|
+
const original = start[3] > 0 ? project(start) : a;
|
|
21478
|
+
const phase = Math.hypot(x0 - original[0], y0 - original[1]);
|
|
21479
|
+
const drawPixel = (x, y) => {
|
|
21480
|
+
const t = lengthSquared === 0 ? 0 : Math.max(0, Math.min(1, ((x - x0) * dx + (y - y0) * dy) / lengthSquared));
|
|
21481
|
+
if (dashed && Math.floor((phase + t * length) / dashLength) % 2 === 1)
|
|
21482
|
+
return;
|
|
21483
|
+
const distance = Math.hypot(x - (x0 + t * dx), y - (y0 + t * dy));
|
|
21484
|
+
const coverage = Math.min(1, padding - distance);
|
|
21485
|
+
if (coverage > 0)
|
|
21486
|
+
fragment(x, y, z0 + t * (z1 - z0), coverage);
|
|
21487
|
+
};
|
|
21488
|
+
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
21489
|
+
const band = length === 0 ? padding : padding * length / Math.abs(dx);
|
|
21490
|
+
const first = Math.max(0, Math.ceil(Math.min(x0, x1) - padding));
|
|
21491
|
+
const last = Math.min(width - 1, Math.floor(Math.max(x0, x1) + padding));
|
|
21492
|
+
for (let x = first;x <= last; x++) {
|
|
21493
|
+
const t = dx === 0 ? 0 : Math.max(0, Math.min(1, (x - x0) / dx));
|
|
21494
|
+
const centerY = y0 + t * dy;
|
|
21495
|
+
const top = Math.max(0, Math.ceil(centerY - band));
|
|
21496
|
+
const bottom = Math.min(height - 1, Math.floor(centerY + band));
|
|
21497
|
+
for (let y = top;y <= bottom; y++)
|
|
21498
|
+
drawPixel(x, y);
|
|
21499
|
+
}
|
|
21500
|
+
} else {
|
|
21501
|
+
const band = padding * length / Math.abs(dy);
|
|
21502
|
+
const first = Math.max(0, Math.ceil(Math.min(y0, y1) - padding));
|
|
21503
|
+
const last = Math.min(height - 1, Math.floor(Math.max(y0, y1) + padding));
|
|
21504
|
+
for (let y = first;y <= last; y++) {
|
|
21505
|
+
const t = Math.max(0, Math.min(1, (y - y0) / dy));
|
|
21506
|
+
const centerX = x0 + t * dx;
|
|
21507
|
+
const left = Math.max(0, Math.ceil(centerX - band));
|
|
21508
|
+
const right = Math.min(width - 1, Math.floor(centerX + band));
|
|
21509
|
+
for (let x = left;x <= right; x++)
|
|
21510
|
+
drawPixel(x, y);
|
|
21511
|
+
}
|
|
21512
|
+
}
|
|
21513
|
+
}
|
|
20485
21514
|
function edge(a, b, p) {
|
|
20486
21515
|
return (p[0] - a[0]) * (b[1] - a[1]) - (p[1] - a[1]) * (b[0] - a[0]);
|
|
20487
21516
|
}
|
|
20488
21517
|
function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPointColor, debugLabelColor) {
|
|
20489
21518
|
if (debugPoints.length === 0)
|
|
20490
21519
|
return;
|
|
20491
|
-
const viewProj =
|
|
20492
|
-
|
|
21520
|
+
const viewProj = import_gl_matrix6.mat4.create();
|
|
21521
|
+
import_gl_matrix6.mat4.multiply(viewProj, camera.proj, camera.view);
|
|
20493
21522
|
const markerColor = toColorRGBA(debugPointColor, DEFAULT_MARKER_COLOR);
|
|
20494
21523
|
const textColor = toColorRGBA(debugLabelColor, DEFAULT_TEXT_COLOR);
|
|
20495
21524
|
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));
|
|
@@ -20503,8 +21532,8 @@ function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPoin
|
|
|
20503
21532
|
}
|
|
20504
21533
|
}
|
|
20505
21534
|
function projectWorldToScreen(position, viewProj, renderer) {
|
|
20506
|
-
const clip =
|
|
20507
|
-
|
|
21535
|
+
const clip = import_gl_matrix6.vec4.fromValues(position.x, position.y, position.z, 1);
|
|
21536
|
+
import_gl_matrix6.vec4.transformMat4(clip, clip, viewProj);
|
|
20508
21537
|
if (!Number.isFinite(clip[3]) || clip[3] <= 0)
|
|
20509
21538
|
return null;
|
|
20510
21539
|
const invW = 1 / clip[3];
|
|
@@ -20632,23 +21661,23 @@ function drawInfiniteGrid(software_renderer, params) {
|
|
|
20632
21661
|
const camera = params.camera;
|
|
20633
21662
|
const view = camera.view;
|
|
20634
21663
|
const proj = camera.proj;
|
|
20635
|
-
const inv_view =
|
|
20636
|
-
|
|
21664
|
+
const inv_view = import_gl_matrix8.mat4.create();
|
|
21665
|
+
import_gl_matrix8.mat4.invert(inv_view, view);
|
|
20637
21666
|
const cam_pos_x = inv_view[12];
|
|
20638
21667
|
const cam_pos_y = inv_view[13];
|
|
20639
21668
|
const cam_pos_z = inv_view[14];
|
|
20640
|
-
const vp =
|
|
20641
|
-
|
|
20642
|
-
const inv_vp =
|
|
20643
|
-
|
|
21669
|
+
const vp = import_gl_matrix8.mat4.create();
|
|
21670
|
+
import_gl_matrix8.mat4.multiply(vp, proj, view);
|
|
21671
|
+
const inv_vp = import_gl_matrix8.mat4.create();
|
|
21672
|
+
import_gl_matrix8.mat4.invert(inv_vp, vp);
|
|
20644
21673
|
for (let y = 0;y < software_renderer.height; y++) {
|
|
20645
21674
|
for (let x = 0;x < software_renderer.width; x++) {
|
|
20646
21675
|
const ndc_x = x / (software_renderer.width - 1) * 2 - 1;
|
|
20647
21676
|
const ndc_y = 1 - y / (software_renderer.height - 1) * 2;
|
|
20648
|
-
const near_point =
|
|
20649
|
-
const far_point =
|
|
20650
|
-
|
|
20651
|
-
|
|
21677
|
+
const near_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, -1, 1);
|
|
21678
|
+
const far_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, 1, 1);
|
|
21679
|
+
import_gl_matrix8.vec4.transformMat4(near_point, near_point, inv_vp);
|
|
21680
|
+
import_gl_matrix8.vec4.transformMat4(far_point, far_point, inv_vp);
|
|
20652
21681
|
near_point[0] /= near_point[3];
|
|
20653
21682
|
near_point[1] /= near_point[3];
|
|
20654
21683
|
near_point[2] /= near_point[3];
|
|
@@ -20665,9 +21694,9 @@ function drawInfiniteGrid(software_renderer, params) {
|
|
|
20665
21694
|
continue;
|
|
20666
21695
|
const world_x = near_point[0] + t * ray_dir_x;
|
|
20667
21696
|
const world_z = near_point[2] + t * ray_dir_z;
|
|
20668
|
-
const world_pt =
|
|
20669
|
-
const clip_pt =
|
|
20670
|
-
|
|
21697
|
+
const world_pt = import_gl_matrix8.vec4.fromValues(world_x, grid_y, world_z, 1);
|
|
21698
|
+
const clip_pt = import_gl_matrix8.vec4.create();
|
|
21699
|
+
import_gl_matrix8.vec4.transformMat4(clip_pt, world_pt, vp);
|
|
20671
21700
|
const ndc_z = clip_pt[2] / clip_pt[3];
|
|
20672
21701
|
const depth_01 = ndc_z * 0.5 + 0.5;
|
|
20673
21702
|
const di = y * software_renderer.width + x;
|
|
@@ -20753,17 +21782,36 @@ function resolveCameraRotation(cameraRotation) {
|
|
|
20753
21782
|
}
|
|
20754
21783
|
function resolveRenderOptions(options = {}) {
|
|
20755
21784
|
const supersampling = typeof options.supersampling === "number" && Number.isFinite(options.supersampling) ? Math.max(1, Math.floor(options.supersampling)) : DEFAULT_RENDER_OPTIONS.supersampling;
|
|
21785
|
+
const outline = options.renderStyle === "outline";
|
|
20756
21786
|
return {
|
|
20757
21787
|
...DEFAULT_RENDER_OPTIONS,
|
|
20758
21788
|
...options,
|
|
21789
|
+
renderStyle: outline ? "outline" : "shaded",
|
|
21790
|
+
projection: options.projection === "orthographic" || outline && options.projection !== "perspective" ? "orthographic" : "perspective",
|
|
21791
|
+
orthographicHeight: typeof options.orthographicHeight === "number" && Number.isFinite(options.orthographicHeight) && options.orthographicHeight > 0 ? options.orthographicHeight : null,
|
|
21792
|
+
...outline ? {
|
|
21793
|
+
realistic: false,
|
|
21794
|
+
ambient: 1,
|
|
21795
|
+
gamma: false,
|
|
21796
|
+
cull: false,
|
|
21797
|
+
backgroundColor: options.backgroundColor ?? "#ffffff"
|
|
21798
|
+
} : {},
|
|
20759
21799
|
supersampling,
|
|
20760
21800
|
lightDir: options.lightDir != null ? options.lightDir : DEFAULT_RENDER_OPTIONS.lightDir,
|
|
20761
21801
|
camPos: options.camPos !== undefined ? options.camPos : DEFAULT_RENDER_OPTIONS.camPos,
|
|
20762
21802
|
lookAt: options.lookAt !== undefined ? options.lookAt : DEFAULT_RENDER_OPTIONS.lookAt,
|
|
20763
21803
|
up: resolveCameraUp(options.up),
|
|
20764
|
-
cameraRotation: resolveCameraRotation(options.cameraRotation)
|
|
21804
|
+
cameraRotation: resolveCameraRotation(options.cameraRotation),
|
|
21805
|
+
showEdges: options.showEdges ?? outline,
|
|
21806
|
+
showHiddenEdges: typeof options.showHiddenEdges === "boolean" ? options.showHiddenEdges : outline ? false : null,
|
|
21807
|
+
edgeWidth: resolveWidth(options.edgeWidth),
|
|
21808
|
+
lineWidth: resolveWidth(options.lineWidth),
|
|
21809
|
+
hiddenEdgeOpacity: typeof options.hiddenEdgeOpacity === "number" && Number.isFinite(options.hiddenEdgeOpacity) ? Math.max(0, Math.min(1, options.hiddenEdgeOpacity)) : DEFAULT_RENDER_OPTIONS.hiddenEdgeOpacity
|
|
20765
21810
|
};
|
|
20766
21811
|
}
|
|
21812
|
+
function resolveWidth(width) {
|
|
21813
|
+
return typeof width === "number" && Number.isFinite(width) && width > 0 ? width : 1;
|
|
21814
|
+
}
|
|
20767
21815
|
function dotNormal(normal, direction) {
|
|
20768
21816
|
return normal[0] * direction[0] + normal[1] * direction[1] + normal[2] * direction[2];
|
|
20769
21817
|
}
|
|
@@ -20787,7 +21835,7 @@ function basis(n) {
|
|
|
20787
21835
|
]
|
|
20788
21836
|
];
|
|
20789
21837
|
}
|
|
20790
|
-
function
|
|
21838
|
+
function orient2(x, y, z, n, t, b) {
|
|
20791
21839
|
return [
|
|
20792
21840
|
t[0] * x + b[0] * y + n[0] * z,
|
|
20793
21841
|
t[1] * x + b[1] * y + n[1] * z,
|
|
@@ -20829,14 +21877,14 @@ function getTables() {
|
|
|
20829
21877
|
];
|
|
20830
21878
|
const [t, b] = basis(n), index = y * W + x;
|
|
20831
21879
|
for (const s of diffuseSamples) {
|
|
20832
|
-
const l =
|
|
21880
|
+
const l = orient2(...s, n, t, b);
|
|
20833
21881
|
for (let j = 0;j < lobes.length; j++)
|
|
20834
21882
|
diffuse[j][index] += Math.exp(lobes[j].sharpness * (dot(l, lobes[j].direction) - 1)) / SAMPLES;
|
|
20835
21883
|
}
|
|
20836
21884
|
for (let r = 0;r < ROUGHNESSES.length; r++) {
|
|
20837
21885
|
let weight = 0;
|
|
20838
21886
|
for (const s of halfSamples[r]) {
|
|
20839
|
-
const h =
|
|
21887
|
+
const h = orient2(...s, n, t, b), nh = dot(n, h);
|
|
20840
21888
|
const l = [
|
|
20841
21889
|
2 * nh * h[0] - n[0],
|
|
20842
21890
|
2 * nh * h[1] - n[1],
|
|
@@ -20877,11 +21925,150 @@ function getTables() {
|
|
|
20877
21925
|
cachedTables = { diffuse, specular, brdf };
|
|
20878
21926
|
return cachedTables;
|
|
20879
21927
|
}
|
|
21928
|
+
function createExplosionLineDrawCall(line) {
|
|
21929
|
+
if (line.points.length < 2 || line.points.some((point) => point.length !== 3 || !point.every(Number.isFinite))) {
|
|
21930
|
+
throw new Error("Explosion lines need at least two finite XYZ points");
|
|
21931
|
+
}
|
|
21932
|
+
const color = line.color ?? [0.08, 0.2, 0.35];
|
|
21933
|
+
if (color.length !== 3 || color.some((channel) => !Number.isFinite(channel) || channel < 0 || channel > 1)) {
|
|
21934
|
+
throw new Error("Explosion line colors must be linear RGB values from 0 to 1");
|
|
21935
|
+
}
|
|
21936
|
+
const indices = [];
|
|
21937
|
+
for (let vertex = 1;vertex < line.points.length; vertex++) {
|
|
21938
|
+
indices.push(vertex - 1, vertex);
|
|
21939
|
+
}
|
|
21940
|
+
return {
|
|
21941
|
+
positions: new Float32Array(line.points.flatMap((point) => [...point])),
|
|
21942
|
+
indices: new Uint32Array(indices),
|
|
21943
|
+
normals: null,
|
|
21944
|
+
uvs: null,
|
|
21945
|
+
model: import_gl_matrix11.mat4.create(),
|
|
21946
|
+
material: { baseColorFactor: [...color, 1], baseColorTexture: null },
|
|
21947
|
+
mode: 1
|
|
21948
|
+
};
|
|
21949
|
+
}
|
|
21950
|
+
function clipExplosionLineDrawCall(drawCall, camera) {
|
|
21951
|
+
const viewProjection = import_gl_matrix11.mat4.multiply(import_gl_matrix11.mat4.create(), camera.proj, camera.view);
|
|
21952
|
+
const positions = [];
|
|
21953
|
+
const indices = [];
|
|
21954
|
+
const distances = (point) => [
|
|
21955
|
+
point[3] + point[0],
|
|
21956
|
+
point[3] - point[0],
|
|
21957
|
+
point[3] + point[1],
|
|
21958
|
+
point[3] - point[1],
|
|
21959
|
+
point[3] + point[2],
|
|
21960
|
+
point[3] - point[2]
|
|
21961
|
+
];
|
|
21962
|
+
for (let segment = 0;segment < drawCall.indices.length; segment += 2) {
|
|
21963
|
+
const startIndex = drawCall.indices[segment] * 3;
|
|
21964
|
+
const endIndex = drawCall.indices[segment + 1] * 3;
|
|
21965
|
+
const start = import_gl_matrix11.vec4.fromValues(drawCall.positions[startIndex], drawCall.positions[startIndex + 1], drawCall.positions[startIndex + 2], 1);
|
|
21966
|
+
const end = import_gl_matrix11.vec4.fromValues(drawCall.positions[endIndex], drawCall.positions[endIndex + 1], drawCall.positions[endIndex + 2], 1);
|
|
21967
|
+
const startDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), start, viewProjection));
|
|
21968
|
+
const endDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), end, viewProjection));
|
|
21969
|
+
let from = 0;
|
|
21970
|
+
let to = 1;
|
|
21971
|
+
for (let plane = 0;plane < 6; plane++) {
|
|
21972
|
+
const a = startDistances[plane];
|
|
21973
|
+
const b = endDistances[plane];
|
|
21974
|
+
if (a < 0 && b < 0) {
|
|
21975
|
+
to = -1;
|
|
21976
|
+
break;
|
|
21977
|
+
}
|
|
21978
|
+
if (a < 0 !== b < 0) {
|
|
21979
|
+
const intersection = a / (a - b);
|
|
21980
|
+
if (a < 0)
|
|
21981
|
+
from = Math.max(from, intersection);
|
|
21982
|
+
else
|
|
21983
|
+
to = Math.min(to, intersection);
|
|
21984
|
+
}
|
|
21985
|
+
}
|
|
21986
|
+
if (from > to)
|
|
21987
|
+
continue;
|
|
21988
|
+
const vertex = positions.length / 3;
|
|
21989
|
+
for (const progress of [from, to]) {
|
|
21990
|
+
for (let axis = 0;axis < 3; axis++) {
|
|
21991
|
+
positions.push(start[axis] + progress * (end[axis] - start[axis]));
|
|
21992
|
+
}
|
|
21993
|
+
}
|
|
21994
|
+
indices.push(vertex, vertex + 1);
|
|
21995
|
+
}
|
|
21996
|
+
return {
|
|
21997
|
+
...drawCall,
|
|
21998
|
+
positions: new Float32Array(positions),
|
|
21999
|
+
indices: new Uint32Array(indices)
|
|
22000
|
+
};
|
|
22001
|
+
}
|
|
22002
|
+
function createExplosionArrowDrawCall(drawCall, camera, width, height, supersampling) {
|
|
22003
|
+
if (width <= 1 || height <= 1)
|
|
22004
|
+
return null;
|
|
22005
|
+
const points = drawCall.positions;
|
|
22006
|
+
const end = points.length - 3;
|
|
22007
|
+
let start = end - 3;
|
|
22008
|
+
while (start >= 0 && points[start] === points[end] && points[start + 1] === points[end + 1] && points[start + 2] === points[end + 2]) {
|
|
22009
|
+
start -= 3;
|
|
22010
|
+
}
|
|
22011
|
+
if (start < 0)
|
|
22012
|
+
return null;
|
|
22013
|
+
const viewProjection = import_gl_matrix12.mat4.multiply(import_gl_matrix12.mat4.create(), camera.proj, camera.view);
|
|
22014
|
+
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);
|
|
22015
|
+
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]) {
|
|
22016
|
+
return null;
|
|
22017
|
+
}
|
|
22018
|
+
const clipped = clipExplosionLineDrawCall({
|
|
22019
|
+
...drawCall,
|
|
22020
|
+
positions: new Float32Array([
|
|
22021
|
+
points[start],
|
|
22022
|
+
points[start + 1],
|
|
22023
|
+
points[start + 2],
|
|
22024
|
+
points[end],
|
|
22025
|
+
points[end + 1],
|
|
22026
|
+
points[end + 2]
|
|
22027
|
+
]),
|
|
22028
|
+
indices: new Uint32Array([0, 1])
|
|
22029
|
+
}, camera);
|
|
22030
|
+
if (!clipped.indices?.length)
|
|
22031
|
+
return null;
|
|
22032
|
+
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);
|
|
22033
|
+
if (tail[3] <= 0)
|
|
22034
|
+
return null;
|
|
22035
|
+
const dx = (tip[0] / tip[3] - tail[0] / tail[3]) * (width - 1) / 2;
|
|
22036
|
+
const dy = (tip[1] / tip[3] - tail[1] / tail[3]) * (height - 1) / 2;
|
|
22037
|
+
const length = Math.hypot(dx, dy);
|
|
22038
|
+
if (!Number.isFinite(length) || length < 0.001)
|
|
22039
|
+
return null;
|
|
22040
|
+
const arrowLength = Math.min(10 * supersampling, length / 2);
|
|
22041
|
+
const ux = dx / length;
|
|
22042
|
+
const uy = dy / length;
|
|
22043
|
+
const inverse = import_gl_matrix12.mat4.invert(import_gl_matrix12.mat4.create(), viewProjection);
|
|
22044
|
+
if (!inverse)
|
|
22045
|
+
return null;
|
|
22046
|
+
const positions = [points[end], points[end + 1], points[end + 2]];
|
|
22047
|
+
for (const side of [-1, 1]) {
|
|
22048
|
+
const offsetX = -ux * arrowLength - side * uy * arrowLength * 0.45;
|
|
22049
|
+
const offsetY = -uy * arrowLength + side * ux * arrowLength * 0.45;
|
|
22050
|
+
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);
|
|
22051
|
+
if (!Array.from(wing).every(Number.isFinite) || wing[3] === 0)
|
|
22052
|
+
return null;
|
|
22053
|
+
positions.push(wing[0] / wing[3], wing[1] / wing[3], wing[2] / wing[3]);
|
|
22054
|
+
}
|
|
22055
|
+
return {
|
|
22056
|
+
...drawCall,
|
|
22057
|
+
positions: new Float32Array(positions),
|
|
22058
|
+
indices: new Uint32Array([0, 1, 0, 2])
|
|
22059
|
+
};
|
|
22060
|
+
}
|
|
20880
22061
|
function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint8Bitmap) {
|
|
20881
22062
|
const options = resolveRenderOptions(optionsInput);
|
|
22063
|
+
if (options.section) {
|
|
22064
|
+
if (options.renderStyle !== "outline")
|
|
22065
|
+
throw new Error("section requires renderStyle: outline");
|
|
22066
|
+
drawCalls = createOutlineSection(drawCalls, options.section).drawCalls;
|
|
22067
|
+
}
|
|
20882
22068
|
const renderWidth = options.width * options.supersampling;
|
|
20883
22069
|
const renderHeight = options.height * options.supersampling;
|
|
20884
|
-
const
|
|
22070
|
+
const explosionDrawCalls = (options.explosionLines ?? []).map(createExplosionLineDrawCall);
|
|
22071
|
+
const camera = buildCamera([...drawCalls, ...explosionDrawCalls], renderWidth, renderHeight, options.fov, options.camPos ?? null, options.lookAt ?? null, options.up, options.cameraRotation ?? null, options.projection, options.orthographicHeight);
|
|
20885
22072
|
const renderer = new SoftwareRenderer(renderWidth, renderHeight, imageFactory, options.realistic);
|
|
20886
22073
|
let rgb = null;
|
|
20887
22074
|
if (options.backgroundColor) {
|
|
@@ -20902,7 +22089,17 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
|
|
|
20902
22089
|
} else {
|
|
20903
22090
|
renderer.clear([0, 0, 0, 0]);
|
|
20904
22091
|
}
|
|
20905
|
-
const allDrawCalls =
|
|
22092
|
+
const allDrawCalls = options.renderStyle === "outline" ? drawCalls.map((dc) => dc.mode === 1 || dc.outlineSectionCap ? dc : {
|
|
22093
|
+
...dc,
|
|
22094
|
+
normals: null,
|
|
22095
|
+
colors: null,
|
|
22096
|
+
uvs: null,
|
|
22097
|
+
material: {
|
|
22098
|
+
baseColorFactor: [1, 1, 1, 1],
|
|
22099
|
+
baseColorTexture: null,
|
|
22100
|
+
alphaMode: "OPAQUE"
|
|
22101
|
+
}
|
|
22102
|
+
}) : [...drawCalls];
|
|
20906
22103
|
let infiniteGridOptions = null;
|
|
20907
22104
|
if (options.grid) {
|
|
20908
22105
|
const userGridOptions = typeof options.grid === "boolean" ? {} : options.grid;
|
|
@@ -20953,7 +22150,9 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
|
|
|
20953
22150
|
for (let i = 0;i < dcs.length; i++) {
|
|
20954
22151
|
const dc = dcs[i];
|
|
20955
22152
|
if (dc.mode === 1) {
|
|
20956
|
-
renderer.drawLines(dc, camera, options.gamma
|
|
22153
|
+
renderer.drawLines(dc, camera, options.gamma, {
|
|
22154
|
+
width: options.lineWidth * options.supersampling
|
|
22155
|
+
});
|
|
20957
22156
|
} else {
|
|
20958
22157
|
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);
|
|
20959
22158
|
}
|
|
@@ -20980,24 +22179,50 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
|
|
|
20980
22179
|
renderGroup(blendDraws);
|
|
20981
22180
|
renderer.denoise(options.gamma);
|
|
20982
22181
|
for (const dc of drawCalls) {
|
|
20983
|
-
|
|
22182
|
+
const showHiddenEdges = options.showHiddenEdges ?? dc.showHiddenEdges;
|
|
22183
|
+
if (!options.showEdges && !showHiddenEdges)
|
|
20984
22184
|
continue;
|
|
20985
|
-
const edgeDrawCall = createEdgeDrawCall(dc);
|
|
22185
|
+
const edgeDrawCall = createEdgeDrawCall(dc, 30, options.renderStyle === "outline" ? { view: camera.view, projection: options.projection } : undefined);
|
|
20986
22186
|
if (!edgeDrawCall)
|
|
20987
22187
|
continue;
|
|
20988
22188
|
renderer.drawLines(edgeDrawCall, camera, options.gamma, {
|
|
20989
22189
|
depthCompare: "less-equal",
|
|
20990
22190
|
depthWrite: false,
|
|
20991
|
-
depthBias: 0.0001
|
|
22191
|
+
depthBias: 0.0001,
|
|
22192
|
+
width: options.edgeWidth * options.supersampling
|
|
20992
22193
|
});
|
|
22194
|
+
if (!showHiddenEdges)
|
|
22195
|
+
continue;
|
|
20993
22196
|
renderer.drawLines(edgeDrawCall, camera, options.gamma, {
|
|
20994
22197
|
depthCompare: "greater",
|
|
20995
22198
|
depthWrite: false,
|
|
20996
22199
|
depthBias: 0.0001,
|
|
20997
22200
|
dashed: true,
|
|
20998
22201
|
dashLength: 4 * options.supersampling,
|
|
20999
|
-
opacity:
|
|
22202
|
+
opacity: options.hiddenEdgeOpacity,
|
|
22203
|
+
width: options.edgeWidth * options.supersampling
|
|
22204
|
+
});
|
|
22205
|
+
}
|
|
22206
|
+
for (const [index, drawCall] of explosionDrawCalls.entries()) {
|
|
22207
|
+
renderer.drawLines(clipExplosionLineDrawCall(drawCall, camera), camera, options.gamma, {
|
|
22208
|
+
depthCompare: "less-equal",
|
|
22209
|
+
depthWrite: false,
|
|
22210
|
+
depthBias: 0.0001,
|
|
22211
|
+
dashed: options.explosionLines[index].dashed ?? true,
|
|
22212
|
+
dashLength: 4 * options.supersampling,
|
|
22213
|
+
width: options.lineWidth * options.supersampling
|
|
21000
22214
|
});
|
|
22215
|
+
if (options.explosionLines[index].arrow) {
|
|
22216
|
+
const arrow = createExplosionArrowDrawCall(drawCall, camera, renderWidth, renderHeight, options.supersampling);
|
|
22217
|
+
if (arrow) {
|
|
22218
|
+
renderer.drawLines(clipExplosionLineDrawCall(arrow, camera), camera, options.gamma, {
|
|
22219
|
+
depthCompare: "less-equal",
|
|
22220
|
+
depthWrite: false,
|
|
22221
|
+
depthBias: 0.0001,
|
|
22222
|
+
width: options.lineWidth * options.supersampling
|
|
22223
|
+
});
|
|
22224
|
+
}
|
|
22225
|
+
}
|
|
21001
22226
|
}
|
|
21002
22227
|
if (options.debugPoints?.length) {
|
|
21003
22228
|
drawDebugPoints(renderer, camera, options.debugPoints, options.debugFontSize, options.debugPointColor, options.debugLabelColor);
|
|
@@ -21028,9 +22253,9 @@ function createInfiniteGrid(options = {}) {
|
|
|
21028
22253
|
size
|
|
21029
22254
|
]);
|
|
21030
22255
|
const indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
|
|
21031
|
-
const model =
|
|
22256
|
+
const model = import_gl_matrix13.mat4.create();
|
|
21032
22257
|
const offset = options.offset ?? {};
|
|
21033
|
-
|
|
22258
|
+
import_gl_matrix13.mat4.fromTranslation(model, [offset.x ?? 0, offset.y ?? 0, offset.z ?? 0]);
|
|
21034
22259
|
return {
|
|
21035
22260
|
positions,
|
|
21036
22261
|
indices,
|
|
@@ -21204,7 +22429,7 @@ function readIndices(ctx, accessorIndex) {
|
|
|
21204
22429
|
}
|
|
21205
22430
|
function nodeLocalMatrix(node) {
|
|
21206
22431
|
if (node.matrix) {
|
|
21207
|
-
const m2 =
|
|
22432
|
+
const m2 = import_gl_matrix14.mat4.create();
|
|
21208
22433
|
for (let i = 0;i < 16; i++)
|
|
21209
22434
|
m2[i] = node.matrix[i];
|
|
21210
22435
|
return m2;
|
|
@@ -21212,10 +22437,10 @@ function nodeLocalMatrix(node) {
|
|
|
21212
22437
|
const translation = node.translation || [0, 0, 0];
|
|
21213
22438
|
const rotation = node.rotation || [0, 0, 0, 1];
|
|
21214
22439
|
const scale = node.scale || [1, 1, 1];
|
|
21215
|
-
const m =
|
|
21216
|
-
const tmp =
|
|
21217
|
-
|
|
21218
|
-
|
|
22440
|
+
const m = import_gl_matrix14.mat4.create();
|
|
22441
|
+
const tmp = import_gl_matrix14.mat4.create();
|
|
22442
|
+
import_gl_matrix14.mat4.fromRotationTranslationScale(tmp, rotation, translation, scale);
|
|
22443
|
+
import_gl_matrix14.mat4.copy(m, tmp);
|
|
21219
22444
|
return m;
|
|
21220
22445
|
}
|
|
21221
22446
|
function getMaterial(gltf, textures, images, materialIndex) {
|
|
@@ -21259,8 +22484,8 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
21259
22484
|
if (!node)
|
|
21260
22485
|
return;
|
|
21261
22486
|
const local = nodeLocalMatrix(node);
|
|
21262
|
-
const world =
|
|
21263
|
-
|
|
22487
|
+
const world = import_gl_matrix14.mat4.create();
|
|
22488
|
+
import_gl_matrix14.mat4.multiply(world, parentMatrix, local);
|
|
21264
22489
|
if (Number.isInteger(node.mesh)) {
|
|
21265
22490
|
const mesh = meshes[node.mesh];
|
|
21266
22491
|
if (mesh) {
|
|
@@ -21296,7 +22521,7 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
21296
22521
|
traverse(childIndex, world);
|
|
21297
22522
|
}
|
|
21298
22523
|
}
|
|
21299
|
-
const identity =
|
|
22524
|
+
const identity = import_gl_matrix14.mat4.create();
|
|
21300
22525
|
for (const rootIndex of scene.nodes || []) {
|
|
21301
22526
|
traverse(rootIndex, identity);
|
|
21302
22527
|
}
|
|
@@ -21582,11 +22807,11 @@ async function renderGLTFToPNGFromGLB(glb, options = {}) {
|
|
|
21582
22807
|
function renderSceneFromGLTF(scene, options, imageFactory) {
|
|
21583
22808
|
return renderDrawCalls(scene.drawCalls, options, imageFactory);
|
|
21584
22809
|
}
|
|
21585
|
-
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,
|
|
22810
|
+
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) => ({
|
|
21586
22811
|
width,
|
|
21587
22812
|
height,
|
|
21588
22813
|
data: new Uint8ClampedArray(width * height * 4)
|
|
21589
|
-
}), DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, clamp = (value, min, max) => Math.max(min, Math.min(max, value)), GeometryDenoiser = class {
|
|
22814
|
+
}), 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 {
|
|
21590
22815
|
constructor(width, height) {
|
|
21591
22816
|
this.width = width;
|
|
21592
22817
|
this.height = height;
|
|
@@ -21724,16 +22949,18 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21724
22949
|
return;
|
|
21725
22950
|
const view = camera.view;
|
|
21726
22951
|
const proj = camera.proj;
|
|
21727
|
-
const mvp =
|
|
21728
|
-
|
|
22952
|
+
const mvp = import_gl_matrix7.mat4.create();
|
|
22953
|
+
import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
|
|
21729
22954
|
const vertexCount = positions.length / 3 | 0;
|
|
21730
22955
|
const vScreen = new Array(vertexCount);
|
|
21731
22956
|
const vInvW = new Float32Array(vertexCount);
|
|
21732
22957
|
const vNDCz = new Float32Array(vertexCount);
|
|
22958
|
+
const clipVertices = [];
|
|
21733
22959
|
for (let i = 0;i < vertexCount; i++) {
|
|
21734
|
-
const p =
|
|
21735
|
-
const c =
|
|
21736
|
-
|
|
22960
|
+
const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
|
|
22961
|
+
const c = import_gl_matrix7.vec4.create();
|
|
22962
|
+
import_gl_matrix7.vec4.transformMat4(c, p, mvp);
|
|
22963
|
+
clipVertices.push(c);
|
|
21737
22964
|
const invW = 1 / c[3];
|
|
21738
22965
|
vInvW[i] = invW;
|
|
21739
22966
|
if (!isFinite(invW)) {
|
|
@@ -21768,9 +22995,58 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21768
22995
|
const depthWrite = options.depthWrite ?? true;
|
|
21769
22996
|
const depthBias = options.depthBias ?? 0;
|
|
21770
22997
|
const dashLength = Math.max(1, options.dashLength ?? 4);
|
|
22998
|
+
const strokeWidth = typeof options.width === "number" && Number.isFinite(options.width) && options.width > 0 ? options.width : 1;
|
|
22999
|
+
const drawFragment = (xi, yi, z, coverage = 1) => {
|
|
23000
|
+
if (z < 0 || z > 1)
|
|
23001
|
+
return;
|
|
23002
|
+
const di = yi * this.width + xi;
|
|
23003
|
+
const currentDepth = this.depth[di];
|
|
23004
|
+
const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
|
|
23005
|
+
if (!passesDepth)
|
|
23006
|
+
return;
|
|
23007
|
+
if (depthWrite)
|
|
23008
|
+
this.depth[di] = z;
|
|
23009
|
+
const pixelIndex = di * 4;
|
|
23010
|
+
const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
|
|
23011
|
+
const alpha = sourceAlpha * coverage;
|
|
23012
|
+
const oneMinusSourceAlpha = 1 - alpha;
|
|
23013
|
+
const outAlpha = alpha + destinationAlpha * oneMinusSourceAlpha;
|
|
23014
|
+
const blend = (channel, offset) => outAlpha === 0 ? 0 : (channel * alpha + this.buffer[pixelIndex + offset] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
|
|
23015
|
+
this.setPixel(xi, yi, blend(r255, 0), blend(g255, 1), blend(b255, 2), outAlpha * 255);
|
|
23016
|
+
};
|
|
21771
23017
|
for (let i = 0;i < indices.length; i += 2) {
|
|
21772
23018
|
const i0 = indices[i + 0];
|
|
21773
23019
|
const i1 = indices[i + 1];
|
|
23020
|
+
if (strokeWidth !== 1) {
|
|
23021
|
+
const sourceFaces = (mesh.edgeAdjacentVertices?.[i / 2] ?? []).flatMap((third) => {
|
|
23022
|
+
if (clipVertices[i0][3] <= 0 || clipVertices[i1][3] <= 0 || clipVertices[third][3] <= 0)
|
|
23023
|
+
return [];
|
|
23024
|
+
const a2 = vScreen[i0];
|
|
23025
|
+
const b2 = vScreen[i1];
|
|
23026
|
+
const c = vScreen[third];
|
|
23027
|
+
const area = edge(a2, b2, c);
|
|
23028
|
+
if (!Number.isFinite(area) || area === 0)
|
|
23029
|
+
return [];
|
|
23030
|
+
return [{ a: a2, b: b2, c, inverseArea: 1 / area, third }];
|
|
23031
|
+
});
|
|
23032
|
+
rasterizeWideLine(clipVertices[i0], clipVertices[i1], this.width, this.height, strokeWidth, options.dashed ?? false, dashLength, sourceFaces.length === 0 ? drawFragment : (x2, y2, z2, coverage) => {
|
|
23033
|
+
let surfaceDepth = Infinity;
|
|
23034
|
+
const sample = [x2 + 0.5, y2 + 0.5];
|
|
23035
|
+
for (const face of sourceFaces) {
|
|
23036
|
+
const l0 = edge(face.b, face.c, sample) * face.inverseArea;
|
|
23037
|
+
const l1 = edge(face.c, face.a, sample) * face.inverseArea;
|
|
23038
|
+
const l2 = 1 - l0 - l1;
|
|
23039
|
+
if (l0 < -0.000001 || l1 < -0.000001 || l2 < -0.000001)
|
|
23040
|
+
continue;
|
|
23041
|
+
const depth = (l0 * vNDCz[i0] + l1 * vNDCz[i1] + l2 * vNDCz[face.third]) * 0.5 + 0.5;
|
|
23042
|
+
if (depth >= 0 && depth <= 1) {
|
|
23043
|
+
surfaceDepth = Math.min(surfaceDepth, depth);
|
|
23044
|
+
}
|
|
23045
|
+
}
|
|
23046
|
+
drawFragment(x2, y2, surfaceDepth === Infinity ? z2 : surfaceDepth, coverage);
|
|
23047
|
+
});
|
|
23048
|
+
continue;
|
|
23049
|
+
}
|
|
21774
23050
|
const v0s = vScreen[i0];
|
|
21775
23051
|
const v1s = vScreen[i1];
|
|
21776
23052
|
const z0_ndc = vNDCz[i0];
|
|
@@ -21806,21 +23082,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21806
23082
|
const xi = Math.round(x);
|
|
21807
23083
|
const yi = Math.round(y);
|
|
21808
23084
|
if (xi >= 0 && xi < this.width && yi >= 0 && yi < this.height && z >= 0 && z <= 1) {
|
|
21809
|
-
|
|
21810
|
-
const currentDepth = this.depth[di];
|
|
21811
|
-
const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
|
|
21812
|
-
if (passesDepth) {
|
|
21813
|
-
if (depthWrite)
|
|
21814
|
-
this.depth[di] = z;
|
|
21815
|
-
const pixelIndex = di * 4;
|
|
21816
|
-
const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
|
|
21817
|
-
const oneMinusSourceAlpha = 1 - sourceAlpha;
|
|
21818
|
-
const outAlpha = sourceAlpha + destinationAlpha * oneMinusSourceAlpha;
|
|
21819
|
-
const outR = outAlpha === 0 ? 0 : (r255 * sourceAlpha + this.buffer[pixelIndex + 0] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
|
|
21820
|
-
const outG = outAlpha === 0 ? 0 : (g255 * sourceAlpha + this.buffer[pixelIndex + 1] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
|
|
21821
|
-
const outB = outAlpha === 0 ? 0 : (b255 * sourceAlpha + this.buffer[pixelIndex + 2] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
|
|
21822
|
-
this.setPixel(xi, yi, outR, outG, outB, outAlpha * 255);
|
|
21823
|
-
}
|
|
23085
|
+
drawFragment(xi, yi, z);
|
|
21824
23086
|
}
|
|
21825
23087
|
x += xinc;
|
|
21826
23088
|
y += yinc;
|
|
@@ -21859,13 +23121,13 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21859
23121
|
const materialId = this.denoiser?.materialId(material) ?? 0;
|
|
21860
23122
|
const lightDir = light.dir ?? DEFAULT_LIGHT_DIR;
|
|
21861
23123
|
const ambient = clamp(light.ambient ?? DEFAULT_RENDER_OPTIONS.ambient, 0, 1);
|
|
21862
|
-
const L = studio ? null :
|
|
23124
|
+
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]));
|
|
21863
23125
|
const view = camera.view;
|
|
21864
23126
|
const proj = camera.proj;
|
|
21865
|
-
const mvp =
|
|
21866
|
-
|
|
21867
|
-
const normalMat =
|
|
21868
|
-
|
|
23127
|
+
const mvp = import_gl_matrix7.mat4.create();
|
|
23128
|
+
import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
|
|
23129
|
+
const normalMat = import_gl_matrix7.mat3.create();
|
|
23130
|
+
import_gl_matrix7.mat3.normalFromMat4(normalMat, model);
|
|
21869
23131
|
let vertexCount = positions.length / 3 | 0;
|
|
21870
23132
|
let idx = indices ?? (() => {
|
|
21871
23133
|
const a = new Uint32Array(vertexCount);
|
|
@@ -21892,11 +23154,11 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21892
23154
|
const vWorldP = studio && !depthOnly ? new Array(vertexCount) : null;
|
|
21893
23155
|
const vColor = new Array(depthOnly ? 0 : vertexCount);
|
|
21894
23156
|
for (let i = 0;i < vertexCount; i++) {
|
|
21895
|
-
const p =
|
|
21896
|
-
const c =
|
|
21897
|
-
|
|
23157
|
+
const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
|
|
23158
|
+
const c = import_gl_matrix7.vec4.create();
|
|
23159
|
+
import_gl_matrix7.vec4.transformMat4(c, p, mvp);
|
|
21898
23160
|
if (vWorldP) {
|
|
21899
|
-
const world =
|
|
23161
|
+
const world = import_gl_matrix7.vec4.transformMat4(import_gl_matrix7.vec4.create(), p, model);
|
|
21900
23162
|
vWorldP[i] = [world[0], world[1], world[2]];
|
|
21901
23163
|
}
|
|
21902
23164
|
const invW = 1 / c[3];
|
|
@@ -21910,9 +23172,9 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21910
23172
|
vNDCz[i] = ndcZ;
|
|
21911
23173
|
if (depthOnly)
|
|
21912
23174
|
continue;
|
|
21913
|
-
const n =
|
|
21914
|
-
const nw =
|
|
21915
|
-
|
|
23175
|
+
const n = import_gl_matrix7.vec3.fromValues(useNormals[i * 3 + 0], useNormals[i * 3 + 1], useNormals[i * 3 + 2]);
|
|
23176
|
+
const nw = import_gl_matrix7.vec3.create();
|
|
23177
|
+
import_gl_matrix7.vec3.transformMat3(nw, n, normalMat);
|
|
21916
23178
|
vWorldN[i] = [nw[0], nw[1], nw[2]];
|
|
21917
23179
|
if (colors && colors.length >= (i + 1) * 3) {
|
|
21918
23180
|
vColor[i] = [colors[i * 3 + 0], colors[i * 3 + 1], colors[i * 3 + 2]];
|
|
@@ -21999,7 +23261,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
21999
23261
|
];
|
|
22000
23262
|
if (uv && material.baseColorTexture) {
|
|
22001
23263
|
const uvp = this.perspInterp(uv, invW, [l0, l1, l2]);
|
|
22002
|
-
const texel = this.sampleTextureNearest(material.baseColorTexture, uvp[0], uvp[1]);
|
|
23264
|
+
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]);
|
|
22003
23265
|
baseColor = mulColor(baseColor, [
|
|
22004
23266
|
srgbDecodeToLinear01(texel[0]),
|
|
22005
23267
|
srgbDecodeToLinear01(texel[1]),
|
|
@@ -22124,7 +23386,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22124
23386
|
const count = dc.indices?.length ?? dc.positions.length / 3;
|
|
22125
23387
|
const worldVertices = [];
|
|
22126
23388
|
for (let i = 0;i < dc.positions.length; i += 3) {
|
|
22127
|
-
const p =
|
|
23389
|
+
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);
|
|
22128
23390
|
worldVertices.push([p[0], p[1], p[2]]);
|
|
22129
23391
|
}
|
|
22130
23392
|
const vertex = (index) => worldVertices[dc.indices?.[index] ?? index];
|
|
@@ -22446,7 +23708,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22446
23708
|
}
|
|
22447
23709
|
constructor(drawCalls, camera) {
|
|
22448
23710
|
this.occlusion = new RayOcclusion(drawCalls);
|
|
22449
|
-
const world =
|
|
23711
|
+
const world = import_gl_matrix9.mat4.invert(import_gl_matrix9.mat4.create(), camera.view);
|
|
22450
23712
|
if (!world)
|
|
22451
23713
|
throw new Error("Realistic rendering requires an invertible camera view.");
|
|
22452
23714
|
this.eye = [world[12], world[13], world[14]];
|
|
@@ -22454,7 +23716,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22454
23716
|
const [t, b] = basis(l.direction);
|
|
22455
23717
|
return Array.from({ length: SHADOW_SAMPLES }, (_, i) => {
|
|
22456
23718
|
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);
|
|
22457
|
-
const direction =
|
|
23719
|
+
const direction = orient2(sin * Math.cos(phi), sin * Math.sin(phi), cos, l.direction, t, b);
|
|
22458
23720
|
const parallel = dot(direction, l.direction);
|
|
22459
23721
|
return {
|
|
22460
23722
|
parallel: l.direction.map((v) => v * parallel),
|
|
@@ -22577,7 +23839,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22577
23839
|
const [t, b] = basis(n);
|
|
22578
23840
|
let blocked = 0;
|
|
22579
23841
|
for (let i = 0;metal < 1 && i < DIFFUSE_SAMPLES; i++) {
|
|
22580
|
-
const phi = i * 2 * Math.PI / DIFFUSE_SAMPLES + phase, l =
|
|
23842
|
+
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);
|
|
22581
23843
|
const hit = this.occlusion.trace(origin, l);
|
|
22582
23844
|
if (hit) {
|
|
22583
23845
|
blocked++;
|
|
@@ -22600,7 +23862,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22600
23862
|
this.reflectionSamples.set(rough, samples);
|
|
22601
23863
|
}
|
|
22602
23864
|
for (const [sx, sy, nh] of samples) {
|
|
22603
|
-
const h =
|
|
23865
|
+
const h = orient2(sx * cosPhase - sy * sinPhase, sx * sinPhase + sy * cosPhase, nh, reflected, rt, rb);
|
|
22604
23866
|
const l = [
|
|
22605
23867
|
2 * nh * h[0] - reflected[0],
|
|
22606
23868
|
2 * nh * h[1] - reflected[1],
|
|
@@ -22624,6 +23886,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
|
|
|
22624
23886
|
}
|
|
22625
23887
|
}, COMPONENT_INFO, NUM_COMPONENTS, MAGIC = 1179937895, JSON_CHUNK_TYPE = 1313821514, BIN_CHUNK_TYPE = 5130562;
|
|
22626
23888
|
var init_dist = __esm(() => {
|
|
23889
|
+
init_earcut();
|
|
22627
23890
|
init_lib();
|
|
22628
23891
|
init_lib();
|
|
22629
23892
|
import_gl_matrix = __toESM(require_cjs(), 1);
|
|
@@ -22636,8 +23899,16 @@ var init_dist = __esm(() => {
|
|
|
22636
23899
|
import_gl_matrix8 = __toESM(require_cjs(), 1);
|
|
22637
23900
|
import_gl_matrix9 = __toESM(require_cjs(), 1);
|
|
22638
23901
|
import_gl_matrix10 = __toESM(require_cjs(), 1);
|
|
23902
|
+
import_gl_matrix11 = __toESM(require_cjs(), 1);
|
|
23903
|
+
import_gl_matrix12 = __toESM(require_cjs(), 1);
|
|
23904
|
+
import_gl_matrix13 = __toESM(require_cjs(), 1);
|
|
23905
|
+
import_gl_matrix14 = __toESM(require_cjs(), 1);
|
|
22639
23906
|
DEFAULT_LIGHT_DIR = [-0.4, -0.9, -0.2];
|
|
22640
23907
|
DEFAULT_RENDER_OPTIONS = {
|
|
23908
|
+
renderStyle: "shaded",
|
|
23909
|
+
section: null,
|
|
23910
|
+
projection: "perspective",
|
|
23911
|
+
orthographicHeight: null,
|
|
22641
23912
|
realistic: false,
|
|
22642
23913
|
width: 800,
|
|
22643
23914
|
height: 600,
|
|
@@ -22656,7 +23927,13 @@ var init_dist = __esm(() => {
|
|
|
22656
23927
|
debugPoints: null,
|
|
22657
23928
|
debugFontSize: null,
|
|
22658
23929
|
debugPointColor: null,
|
|
22659
|
-
debugLabelColor: null
|
|
23930
|
+
debugLabelColor: null,
|
|
23931
|
+
explosionLines: null,
|
|
23932
|
+
showEdges: false,
|
|
23933
|
+
showHiddenEdges: null,
|
|
23934
|
+
edgeWidth: 1,
|
|
23935
|
+
lineWidth: 1,
|
|
23936
|
+
hiddenEdgeOpacity: 0.35
|
|
22660
23937
|
};
|
|
22661
23938
|
DEFAULT_MARKER_COLOR = [
|
|
22662
23939
|
255,
|
|
@@ -31961,6 +33238,8 @@ var projectConfigSchema = z.object({
|
|
|
31961
33238
|
kicadLibrary: z.boolean().optional(),
|
|
31962
33239
|
kicadPcm: z.boolean().optional(),
|
|
31963
33240
|
previewImages: z.boolean().optional(),
|
|
33241
|
+
drawings: z.boolean().optional(),
|
|
33242
|
+
drawing: z.string().optional(),
|
|
31964
33243
|
glbs: z.boolean().optional(),
|
|
31965
33244
|
step: z.boolean().optional(),
|
|
31966
33245
|
workerTimeoutMs: z.number().int().positive().optional(),
|