three-stdlib 2.29.7 → 2.29.9
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/loaders/RGBELoader.cjs +50 -60
- package/loaders/RGBELoader.cjs.map +1 -1
- package/loaders/RGBELoader.js +50 -60
- package/loaders/RGBELoader.js.map +1 -1
- package/loaders/SVGLoader.cjs +158 -50
- package/loaders/SVGLoader.cjs.map +1 -1
- package/loaders/SVGLoader.js +158 -50
- package/loaders/SVGLoader.js.map +1 -1
- package/package.json +1 -1
package/loaders/SVGLoader.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { Loader, FileLoader, Matrix3, Vector2, Vector3, ShapeUtils, Box2, Shape, Path, BufferGeometry, Float32BufferAttribute, ShapePath } from "three";
|
2
|
+
const COLOR_SPACE_SVG = "srgb";
|
2
3
|
class SVGLoader extends Loader {
|
3
4
|
constructor(manager) {
|
4
5
|
super(manager);
|
@@ -35,10 +36,11 @@ class SVGLoader extends Loader {
|
|
35
36
|
if (node.nodeType !== 1)
|
36
37
|
return;
|
37
38
|
const transform = getNodeTransform(node);
|
38
|
-
let
|
39
|
+
let isDefsNode = false;
|
39
40
|
let path = null;
|
40
41
|
switch (node.nodeName) {
|
41
42
|
case "svg":
|
43
|
+
style = parseStyle(node, style);
|
42
44
|
break;
|
43
45
|
case "style":
|
44
46
|
parseCSSStylesheet(node);
|
@@ -76,14 +78,12 @@ class SVGLoader extends Loader {
|
|
76
78
|
path = parseLineNode(node);
|
77
79
|
break;
|
78
80
|
case "defs":
|
79
|
-
|
80
|
-
break;
|
81
|
-
case "mask":
|
82
|
-
traverseChildNodes = false;
|
81
|
+
isDefsNode = true;
|
83
82
|
break;
|
84
83
|
case "use":
|
85
84
|
style = parseStyle(node, style);
|
86
|
-
const
|
85
|
+
const href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "";
|
86
|
+
const usedNodeId = href.substring(1);
|
87
87
|
const usedNode = node.viewportElement.getElementById(usedNodeId);
|
88
88
|
if (usedNode) {
|
89
89
|
parseNode(usedNode, style);
|
@@ -94,17 +94,19 @@ class SVGLoader extends Loader {
|
|
94
94
|
}
|
95
95
|
if (path) {
|
96
96
|
if (style.fill !== void 0 && style.fill !== "none") {
|
97
|
-
path.color.setStyle(style.fill);
|
97
|
+
path.color.setStyle(style.fill, COLOR_SPACE_SVG);
|
98
98
|
}
|
99
99
|
transformPath(path, currentTransform);
|
100
100
|
paths.push(path);
|
101
101
|
path.userData = { node, style };
|
102
102
|
}
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
const childNodes = node.childNodes;
|
104
|
+
for (let i = 0; i < childNodes.length; i++) {
|
105
|
+
const node2 = childNodes[i];
|
106
|
+
if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs") {
|
107
|
+
continue;
|
107
108
|
}
|
109
|
+
parseNode(node2, style);
|
108
110
|
}
|
109
111
|
if (transform) {
|
110
112
|
transformStack.pop();
|
@@ -123,11 +125,13 @@ class SVGLoader extends Loader {
|
|
123
125
|
let isFirstPoint = true;
|
124
126
|
let doSetFirstPoint = false;
|
125
127
|
const d = node.getAttribute("d");
|
128
|
+
if (d === "" || d === "none")
|
129
|
+
return null;
|
126
130
|
const commands = d.match(/[a-df-z][^a-df-z]*/gi);
|
127
131
|
for (let i = 0, l = commands.length; i < l; i++) {
|
128
132
|
const command = commands[i];
|
129
133
|
const type = command.charAt(0);
|
130
|
-
const data2 = command.
|
134
|
+
const data2 = command.slice(1).trim();
|
131
135
|
if (isFirstPoint === true) {
|
132
136
|
doSetFirstPoint = true;
|
133
137
|
isFirstPoint = false;
|
@@ -440,7 +444,8 @@ class SVGLoader extends Loader {
|
|
440
444
|
continue;
|
441
445
|
const selectorList = stylesheet.selectorText.split(/,/gm).filter(Boolean).map((i2) => i2.trim());
|
442
446
|
for (let j = 0; j < selectorList.length; j++) {
|
443
|
-
|
447
|
+
const definitions = Object.fromEntries(Object.entries(stylesheet.style).filter(([, v]) => v !== ""));
|
448
|
+
stylesheets[selectorList[j]] = Object.assign(stylesheets[selectorList[j]] || {}, definitions);
|
444
449
|
}
|
445
450
|
}
|
446
451
|
}
|
@@ -528,7 +533,7 @@ class SVGLoader extends Loader {
|
|
528
533
|
}
|
529
534
|
index++;
|
530
535
|
}
|
531
|
-
const regex = /(
|
536
|
+
const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
532
537
|
const path = new ShapePath();
|
533
538
|
let index = 0;
|
534
539
|
node.getAttribute("points").replace(regex, iterator);
|
@@ -546,7 +551,7 @@ class SVGLoader extends Loader {
|
|
546
551
|
}
|
547
552
|
index++;
|
548
553
|
}
|
549
|
-
const regex = /(
|
554
|
+
const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
550
555
|
const path = new ShapePath();
|
551
556
|
let index = 0;
|
552
557
|
node.getAttribute("points").replace(regex, iterator);
|
@@ -598,13 +603,12 @@ class SVGLoader extends Loader {
|
|
598
603
|
stylesheetStyles = Object.assign(stylesheetStyles, stylesheets["#" + node.getAttribute("id")]);
|
599
604
|
}
|
600
605
|
function addStyle(svgName, jsName, adjustFunction) {
|
601
|
-
if (adjustFunction === void 0)
|
606
|
+
if (adjustFunction === void 0)
|
602
607
|
adjustFunction = function copy(v) {
|
603
608
|
if (v.startsWith("url"))
|
604
609
|
console.warn("SVGLoader: url access in attributes is not implemented.");
|
605
610
|
return v;
|
606
611
|
};
|
607
|
-
}
|
608
612
|
if (node.hasAttribute(svgName))
|
609
613
|
style[jsName] = adjustFunction(node.getAttribute(svgName));
|
610
614
|
if (stylesheetStyles[svgName])
|
@@ -869,14 +873,14 @@ class SVGLoader extends Loader {
|
|
869
873
|
const openParPos = transformText.indexOf("(");
|
870
874
|
const closeParPos = transformText.length;
|
871
875
|
if (openParPos > 0 && openParPos < closeParPos) {
|
872
|
-
const transformType = transformText.
|
873
|
-
const array = parseFloats(transformText.
|
876
|
+
const transformType = transformText.slice(0, openParPos);
|
877
|
+
const array = parseFloats(transformText.slice(openParPos + 1));
|
874
878
|
currentTransform2.identity();
|
875
879
|
switch (transformType) {
|
876
880
|
case "translate":
|
877
881
|
if (array.length >= 1) {
|
878
882
|
const tx = array[0];
|
879
|
-
let ty =
|
883
|
+
let ty = 0;
|
880
884
|
if (array.length >= 2) {
|
881
885
|
ty = array[1];
|
882
886
|
}
|
@@ -888,15 +892,15 @@ class SVGLoader extends Loader {
|
|
888
892
|
let angle = 0;
|
889
893
|
let cx = 0;
|
890
894
|
let cy = 0;
|
891
|
-
angle =
|
895
|
+
angle = array[0] * Math.PI / 180;
|
892
896
|
if (array.length >= 3) {
|
893
897
|
cx = array[1];
|
894
898
|
cy = array[2];
|
895
899
|
}
|
896
|
-
tempTransform1.
|
897
|
-
tempTransform2.
|
900
|
+
tempTransform1.makeTranslation(-cx, -cy);
|
901
|
+
tempTransform2.makeRotation(angle);
|
898
902
|
tempTransform3.multiplyMatrices(tempTransform2, tempTransform1);
|
899
|
-
tempTransform1.
|
903
|
+
tempTransform1.makeTranslation(cx, cy);
|
900
904
|
currentTransform2.multiplyMatrices(tempTransform1, tempTransform3);
|
901
905
|
}
|
902
906
|
break;
|
@@ -937,7 +941,55 @@ class SVGLoader extends Loader {
|
|
937
941
|
tempV3.set(v2.x, v2.y, 1).applyMatrix3(m);
|
938
942
|
v2.set(tempV3.x, tempV3.y);
|
939
943
|
}
|
940
|
-
|
944
|
+
function transfEllipseGeneric(curve) {
|
945
|
+
const a = curve.xRadius;
|
946
|
+
const b = curve.yRadius;
|
947
|
+
const cosTheta = Math.cos(curve.aRotation);
|
948
|
+
const sinTheta = Math.sin(curve.aRotation);
|
949
|
+
const v1 = new Vector3(a * cosTheta, a * sinTheta, 0);
|
950
|
+
const v2 = new Vector3(-b * sinTheta, b * cosTheta, 0);
|
951
|
+
const f1 = v1.applyMatrix3(m);
|
952
|
+
const f2 = v2.applyMatrix3(m);
|
953
|
+
const mF = tempTransform0.set(f1.x, f2.x, 0, f1.y, f2.y, 0, 0, 0, 1);
|
954
|
+
const mFInv = tempTransform1.copy(mF).invert();
|
955
|
+
const mFInvT = tempTransform2.copy(mFInv).transpose();
|
956
|
+
const mQ = mFInvT.multiply(mFInv);
|
957
|
+
const mQe = mQ.elements;
|
958
|
+
const ed = eigenDecomposition(mQe[0], mQe[1], mQe[4]);
|
959
|
+
const rt1sqrt = Math.sqrt(ed.rt1);
|
960
|
+
const rt2sqrt = Math.sqrt(ed.rt2);
|
961
|
+
curve.xRadius = 1 / rt1sqrt;
|
962
|
+
curve.yRadius = 1 / rt2sqrt;
|
963
|
+
curve.aRotation = Math.atan2(ed.sn, ed.cs);
|
964
|
+
const isFullEllipse = (curve.aEndAngle - curve.aStartAngle) % (2 * Math.PI) < Number.EPSILON;
|
965
|
+
if (!isFullEllipse) {
|
966
|
+
const mDsqrt = tempTransform1.set(rt1sqrt, 0, 0, 0, rt2sqrt, 0, 0, 0, 1);
|
967
|
+
const mRT = tempTransform2.set(ed.cs, ed.sn, 0, -ed.sn, ed.cs, 0, 0, 0, 1);
|
968
|
+
const mDRF = mDsqrt.multiply(mRT).multiply(mF);
|
969
|
+
const transformAngle = (phi) => {
|
970
|
+
const { x: cosR, y: sinR } = new Vector3(Math.cos(phi), Math.sin(phi), 0).applyMatrix3(mDRF);
|
971
|
+
return Math.atan2(sinR, cosR);
|
972
|
+
};
|
973
|
+
curve.aStartAngle = transformAngle(curve.aStartAngle);
|
974
|
+
curve.aEndAngle = transformAngle(curve.aEndAngle);
|
975
|
+
if (isTransformFlipped(m)) {
|
976
|
+
curve.aClockwise = !curve.aClockwise;
|
977
|
+
}
|
978
|
+
}
|
979
|
+
}
|
980
|
+
function transfEllipseNoSkew(curve) {
|
981
|
+
const sx = getTransformScaleX(m);
|
982
|
+
const sy = getTransformScaleY(m);
|
983
|
+
curve.xRadius *= sx;
|
984
|
+
curve.yRadius *= sy;
|
985
|
+
const theta = sx > Number.EPSILON ? Math.atan2(m.elements[1], m.elements[0]) : Math.atan2(-m.elements[3], m.elements[4]);
|
986
|
+
curve.aRotation += theta;
|
987
|
+
if (isTransformFlipped(m)) {
|
988
|
+
curve.aStartAngle *= -1;
|
989
|
+
curve.aEndAngle *= -1;
|
990
|
+
curve.aClockwise = !curve.aClockwise;
|
991
|
+
}
|
992
|
+
}
|
941
993
|
const subPaths = path.subPaths;
|
942
994
|
for (let i = 0, n = subPaths.length; i < n; i++) {
|
943
995
|
const subPath = subPaths[i];
|
@@ -957,21 +1009,31 @@ class SVGLoader extends Loader {
|
|
957
1009
|
transfVec2(curve.v1);
|
958
1010
|
transfVec2(curve.v2);
|
959
1011
|
} else if (curve.isEllipseCurve) {
|
960
|
-
if (isRotated) {
|
961
|
-
console.warn("SVGLoader: Elliptic arc or ellipse rotation or skewing is not implemented.");
|
962
|
-
}
|
963
1012
|
tempV2.set(curve.aX, curve.aY);
|
964
1013
|
transfVec2(tempV2);
|
965
1014
|
curve.aX = tempV2.x;
|
966
1015
|
curve.aY = tempV2.y;
|
967
|
-
|
968
|
-
|
1016
|
+
if (isTransformSkewed(m)) {
|
1017
|
+
transfEllipseGeneric(curve);
|
1018
|
+
} else {
|
1019
|
+
transfEllipseNoSkew(curve);
|
1020
|
+
}
|
969
1021
|
}
|
970
1022
|
}
|
971
1023
|
}
|
972
1024
|
}
|
973
|
-
function
|
974
|
-
|
1025
|
+
function isTransformFlipped(m) {
|
1026
|
+
const te = m.elements;
|
1027
|
+
return te[0] * te[4] - te[1] * te[3] < 0;
|
1028
|
+
}
|
1029
|
+
function isTransformSkewed(m) {
|
1030
|
+
const te = m.elements;
|
1031
|
+
const basisDot = te[0] * te[3] + te[1] * te[4];
|
1032
|
+
if (basisDot === 0)
|
1033
|
+
return false;
|
1034
|
+
const sx = getTransformScaleX(m);
|
1035
|
+
const sy = getTransformScaleY(m);
|
1036
|
+
return Math.abs(basisDot / (sx * sy)) > Number.EPSILON;
|
975
1037
|
}
|
976
1038
|
function getTransformScaleX(m) {
|
977
1039
|
const te = m.elements;
|
@@ -981,6 +1043,45 @@ class SVGLoader extends Loader {
|
|
981
1043
|
const te = m.elements;
|
982
1044
|
return Math.sqrt(te[3] * te[3] + te[4] * te[4]);
|
983
1045
|
}
|
1046
|
+
function eigenDecomposition(A, B, C) {
|
1047
|
+
let rt1, rt2, cs, sn, t;
|
1048
|
+
const sm = A + C;
|
1049
|
+
const df = A - C;
|
1050
|
+
const rt = Math.sqrt(df * df + 4 * B * B);
|
1051
|
+
if (sm > 0) {
|
1052
|
+
rt1 = 0.5 * (sm + rt);
|
1053
|
+
t = 1 / rt1;
|
1054
|
+
rt2 = A * t * C - B * t * B;
|
1055
|
+
} else if (sm < 0) {
|
1056
|
+
rt2 = 0.5 * (sm - rt);
|
1057
|
+
} else {
|
1058
|
+
rt1 = 0.5 * rt;
|
1059
|
+
rt2 = -0.5 * rt;
|
1060
|
+
}
|
1061
|
+
if (df > 0) {
|
1062
|
+
cs = df + rt;
|
1063
|
+
} else {
|
1064
|
+
cs = df - rt;
|
1065
|
+
}
|
1066
|
+
if (Math.abs(cs) > 2 * Math.abs(B)) {
|
1067
|
+
t = -2 * B / cs;
|
1068
|
+
sn = 1 / Math.sqrt(1 + t * t);
|
1069
|
+
cs = t * sn;
|
1070
|
+
} else if (Math.abs(B) === 0) {
|
1071
|
+
cs = 1;
|
1072
|
+
sn = 0;
|
1073
|
+
} else {
|
1074
|
+
t = -0.5 * cs / B;
|
1075
|
+
cs = 1 / Math.sqrt(1 + t * t);
|
1076
|
+
sn = t * cs;
|
1077
|
+
}
|
1078
|
+
if (df > 0) {
|
1079
|
+
t = cs;
|
1080
|
+
cs = -sn;
|
1081
|
+
sn = t;
|
1082
|
+
}
|
1083
|
+
return { rt1, rt2, cs, sn };
|
1084
|
+
}
|
984
1085
|
const paths = [];
|
985
1086
|
const stylesheets = {};
|
986
1087
|
const transformStack = [];
|
@@ -1180,13 +1281,13 @@ class SVGLoader extends Loader {
|
|
1180
1281
|
let isHoleFor = null;
|
1181
1282
|
let lastCWValue = null;
|
1182
1283
|
for (let i2 = 0; i2 < stack.length; i2++) {
|
1183
|
-
const
|
1284
|
+
const identifier = stack[i2];
|
1184
1285
|
if (isHole) {
|
1185
|
-
lastCWValue = allPaths[
|
1286
|
+
lastCWValue = allPaths[identifier].isCW;
|
1186
1287
|
isHole = false;
|
1187
|
-
isHoleFor =
|
1188
|
-
} else if (lastCWValue !== allPaths[
|
1189
|
-
lastCWValue = allPaths[
|
1288
|
+
isHoleFor = identifier;
|
1289
|
+
} else if (lastCWValue !== allPaths[identifier].isCW) {
|
1290
|
+
lastCWValue = allPaths[identifier].isCW;
|
1190
1291
|
isHole = true;
|
1191
1292
|
}
|
1192
1293
|
}
|
@@ -1195,7 +1296,6 @@ class SVGLoader extends Loader {
|
|
1195
1296
|
console.warn('fill-rule: "' + _fillRule + '" is currently not implemented.');
|
1196
1297
|
}
|
1197
1298
|
}
|
1198
|
-
let identifier = 0;
|
1199
1299
|
let scanlineMinX = BIGNUMBER;
|
1200
1300
|
let scanlineMaxX = -BIGNUMBER;
|
1201
1301
|
let simplePaths = shapePath.subPaths.map((p) => {
|
@@ -1229,13 +1329,22 @@ class SVGLoader extends Loader {
|
|
1229
1329
|
curves: p.curves,
|
1230
1330
|
points,
|
1231
1331
|
isCW: ShapeUtils.isClockWise(points),
|
1232
|
-
identifier:
|
1332
|
+
identifier: -1,
|
1233
1333
|
boundingBox: new Box2(new Vector2(minX, minY), new Vector2(maxX, maxY))
|
1234
1334
|
};
|
1235
1335
|
});
|
1236
1336
|
simplePaths = simplePaths.filter((sp) => sp.points.length > 1);
|
1337
|
+
for (let identifier = 0; identifier < simplePaths.length; identifier++) {
|
1338
|
+
simplePaths[identifier].identifier = identifier;
|
1339
|
+
}
|
1237
1340
|
const isAHole = simplePaths.map(
|
1238
|
-
(p) => isHoleTo(
|
1341
|
+
(p) => isHoleTo(
|
1342
|
+
p,
|
1343
|
+
simplePaths,
|
1344
|
+
scanlineMinX,
|
1345
|
+
scanlineMaxX,
|
1346
|
+
shapePath.userData ? shapePath.userData.style.fillRule : void 0
|
1347
|
+
)
|
1239
1348
|
);
|
1240
1349
|
const shapesToReturn = [];
|
1241
1350
|
simplePaths.forEach((p) => {
|
@@ -1331,9 +1440,8 @@ class SVGLoader extends Loader {
|
|
1331
1440
|
if (iPoint === numPoints - 1) {
|
1332
1441
|
if (isClosed) {
|
1333
1442
|
nextPoint = points[1];
|
1334
|
-
} else
|
1443
|
+
} else
|
1335
1444
|
nextPoint = void 0;
|
1336
|
-
}
|
1337
1445
|
} else {
|
1338
1446
|
nextPoint = points[iPoint + 1];
|
1339
1447
|
}
|
@@ -1359,7 +1467,7 @@ class SVGLoader extends Loader {
|
|
1359
1467
|
tempV2_3.subVectors(nextPoint, currentPoint);
|
1360
1468
|
tempV2_3.normalize();
|
1361
1469
|
const dot = Math.abs(normal1.dot(tempV2_3));
|
1362
|
-
if (dot
|
1470
|
+
if (dot > Number.EPSILON) {
|
1363
1471
|
const miterSide = strokeWidth2 / dot;
|
1364
1472
|
tempV2_3.multiplyScalar(-miterSide);
|
1365
1473
|
tempV2_4.subVectors(currentPoint, previousPoint);
|
@@ -1569,8 +1677,8 @@ class SVGLoader extends Loader {
|
|
1569
1677
|
addVertex(lastPointL, u0, 0);
|
1570
1678
|
addVertex(currentPointL, u1, 0);
|
1571
1679
|
addVertex(lastPointR, u0, 1);
|
1572
|
-
addVertex(currentPointL, u1,
|
1573
|
-
addVertex(currentPointR, u1,
|
1680
|
+
addVertex(currentPointL, u1, 0);
|
1681
|
+
addVertex(currentPointR, u1, 1);
|
1574
1682
|
}
|
1575
1683
|
function makeSegmentWithBevelJoin(joinIsOnLeftSide2, innerSideModified2, u) {
|
1576
1684
|
if (innerSideModified2) {
|
@@ -1592,8 +1700,8 @@ class SVGLoader extends Loader {
|
|
1592
1700
|
addVertex(innerPoint, u1, 0);
|
1593
1701
|
addVertex(currentPointR, u1, 1);
|
1594
1702
|
addVertex(currentPointR, u, 1);
|
1595
|
-
addVertex(
|
1596
|
-
addVertex(
|
1703
|
+
addVertex(innerPoint, u, 0);
|
1704
|
+
addVertex(nextPointR, u, 1);
|
1597
1705
|
}
|
1598
1706
|
} else {
|
1599
1707
|
if (joinIsOnLeftSide2) {
|
@@ -1659,7 +1767,7 @@ class SVGLoader extends Loader {
|
|
1659
1767
|
tempV2_4.toArray(vertices, 3 * 3);
|
1660
1768
|
} else {
|
1661
1769
|
tempV2_3.toArray(vertices, 1 * 3);
|
1662
|
-
tempV2_3.toArray(vertices, 3 * 3);
|
1770
|
+
uvs[3 * 2 + 1] === 1 ? tempV2_4.toArray(vertices, 3 * 3) : tempV2_3.toArray(vertices, 3 * 3);
|
1663
1771
|
tempV2_4.toArray(vertices, 0 * 3);
|
1664
1772
|
}
|
1665
1773
|
} else {
|
@@ -1673,8 +1781,8 @@ class SVGLoader extends Loader {
|
|
1673
1781
|
tempV2_4.toArray(vertices, vl - 2 * 3);
|
1674
1782
|
tempV2_4.toArray(vertices, vl - 4 * 3);
|
1675
1783
|
} else {
|
1676
|
-
|
1677
|
-
|
1784
|
+
tempV2_4.toArray(vertices, vl - 2 * 3);
|
1785
|
+
tempV2_3.toArray(vertices, vl - 1 * 3);
|
1678
1786
|
tempV2_4.toArray(vertices, vl - 4 * 3);
|
1679
1787
|
}
|
1680
1788
|
}
|