@deck.gl/extensions 9.4.0-beta.1 → 9.4.0-beta.3
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/dist.dev.js +1281 -120
- package/dist/fill-style/fill-style-extension.d.ts +38 -6
- package/dist/fill-style/fill-style-extension.d.ts.map +1 -1
- package/dist/fill-style/fill-style-extension.js +88 -10
- package/dist/fill-style/fill-style-extension.js.map +1 -1
- package/dist/fill-style/procedural-pattern.d.ts +65 -0
- package/dist/fill-style/procedural-pattern.d.ts.map +1 -0
- package/dist/fill-style/procedural-pattern.js +135 -0
- package/dist/fill-style/procedural-pattern.js.map +1 -0
- package/dist/fill-style/shader-module.d.ts +13 -4
- package/dist/fill-style/shader-module.d.ts.map +1 -1
- package/dist/fill-style/shader-module.js +212 -21
- package/dist/fill-style/shader-module.js.map +1 -1
- package/dist/index.cjs +946 -172
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/mask/shader-module.d.ts +1 -0
- package/dist/mask/shader-module.d.ts.map +1 -1
- package/dist/path-style/path-style-extension.d.ts +49 -6
- package/dist/path-style/path-style-extension.d.ts.map +1 -1
- package/dist/path-style/path-style-extension.js +237 -37
- package/dist/path-style/path-style-extension.js.map +1 -1
- package/dist/path-style/shaders.glsl.d.ts +30 -1
- package/dist/path-style/shaders.glsl.d.ts.map +1 -1
- package/dist/path-style/shaders.glsl.js +136 -21
- package/dist/path-style/shaders.glsl.js.map +1 -1
- package/dist/terrain/shader-module.d.ts +1 -0
- package/dist/terrain/shader-module.d.ts.map +1 -1
- package/dist.min.js +377 -98
- package/package.json +6 -6
- package/src/fill-style/fill-style-extension.ts +135 -13
- package/src/fill-style/procedural-pattern.ts +203 -0
- package/src/fill-style/shader-module.ts +233 -23
- package/src/index.ts +10 -1
- package/src/path-style/path-style-extension.ts +350 -44
- package/src/path-style/shaders.glsl.ts +268 -27
package/dist/dist.dev.js
CHANGED
|
@@ -1176,10 +1176,10 @@ void main() {
|
|
|
1176
1176
|
out[2] = a[2] * b;
|
|
1177
1177
|
return out;
|
|
1178
1178
|
}
|
|
1179
|
-
function scaleAndAdd(out, a, b,
|
|
1180
|
-
out[0] = a[0] + b[0] *
|
|
1181
|
-
out[1] = a[1] + b[1] *
|
|
1182
|
-
out[2] = a[2] + b[2] *
|
|
1179
|
+
function scaleAndAdd(out, a, b, scale3) {
|
|
1180
|
+
out[0] = a[0] + b[0] * scale3;
|
|
1181
|
+
out[1] = a[1] + b[1] * scale3;
|
|
1182
|
+
out[2] = a[2] + b[2] * scale3;
|
|
1183
1183
|
return out;
|
|
1184
1184
|
}
|
|
1185
1185
|
function distance(a, b) {
|
|
@@ -1216,13 +1216,13 @@ void main() {
|
|
|
1216
1216
|
const x = a[0];
|
|
1217
1217
|
const y = a[1];
|
|
1218
1218
|
const z = a[2];
|
|
1219
|
-
let
|
|
1220
|
-
if (
|
|
1221
|
-
|
|
1219
|
+
let len3 = x * x + y * y + z * z;
|
|
1220
|
+
if (len3 > 0) {
|
|
1221
|
+
len3 = 1 / Math.sqrt(len3);
|
|
1222
1222
|
}
|
|
1223
|
-
out[0] = a[0] *
|
|
1224
|
-
out[1] = a[1] *
|
|
1225
|
-
out[2] = a[2] *
|
|
1223
|
+
out[0] = a[0] * len3;
|
|
1224
|
+
out[1] = a[1] * len3;
|
|
1225
|
+
out[2] = a[2] * len3;
|
|
1226
1226
|
return out;
|
|
1227
1227
|
}
|
|
1228
1228
|
function dot(a, b) {
|
|
@@ -1283,14 +1283,14 @@ void main() {
|
|
|
1283
1283
|
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
|
|
1284
1284
|
return out;
|
|
1285
1285
|
}
|
|
1286
|
-
function random(out,
|
|
1287
|
-
|
|
1286
|
+
function random(out, scale3) {
|
|
1287
|
+
scale3 = scale3 === void 0 ? 1 : scale3;
|
|
1288
1288
|
const r = RANDOM() * 2 * Math.PI;
|
|
1289
1289
|
const z = RANDOM() * 2 - 1;
|
|
1290
|
-
const zScale = Math.sqrt(1 - z * z) *
|
|
1290
|
+
const zScale = Math.sqrt(1 - z * z) * scale3;
|
|
1291
1291
|
out[0] = Math.cos(r) * zScale;
|
|
1292
1292
|
out[1] = Math.sin(r) * zScale;
|
|
1293
|
-
out[2] = z *
|
|
1293
|
+
out[2] = z * scale3;
|
|
1294
1294
|
return out;
|
|
1295
1295
|
}
|
|
1296
1296
|
function transformMat4(out, a, m) {
|
|
@@ -1449,6 +1449,372 @@ void main() {
|
|
|
1449
1449
|
};
|
|
1450
1450
|
})();
|
|
1451
1451
|
|
|
1452
|
+
// ../../node_modules/@math.gl/core/dist/gl-matrix/vec4.js
|
|
1453
|
+
var vec4_exports = {};
|
|
1454
|
+
__export(vec4_exports, {
|
|
1455
|
+
add: () => add2,
|
|
1456
|
+
ceil: () => ceil2,
|
|
1457
|
+
clone: () => clone2,
|
|
1458
|
+
copy: () => copy2,
|
|
1459
|
+
create: () => create2,
|
|
1460
|
+
cross: () => cross2,
|
|
1461
|
+
dist: () => dist2,
|
|
1462
|
+
distance: () => distance2,
|
|
1463
|
+
div: () => div2,
|
|
1464
|
+
divide: () => divide2,
|
|
1465
|
+
dot: () => dot2,
|
|
1466
|
+
equals: () => equals3,
|
|
1467
|
+
exactEquals: () => exactEquals2,
|
|
1468
|
+
floor: () => floor2,
|
|
1469
|
+
forEach: () => forEach2,
|
|
1470
|
+
fromValues: () => fromValues2,
|
|
1471
|
+
inverse: () => inverse2,
|
|
1472
|
+
len: () => len2,
|
|
1473
|
+
length: () => length2,
|
|
1474
|
+
lerp: () => lerp2,
|
|
1475
|
+
max: () => max2,
|
|
1476
|
+
min: () => min2,
|
|
1477
|
+
mul: () => mul2,
|
|
1478
|
+
multiply: () => multiply2,
|
|
1479
|
+
negate: () => negate2,
|
|
1480
|
+
normalize: () => normalize2,
|
|
1481
|
+
random: () => random2,
|
|
1482
|
+
round: () => round3,
|
|
1483
|
+
scale: () => scale2,
|
|
1484
|
+
scaleAndAdd: () => scaleAndAdd2,
|
|
1485
|
+
set: () => set2,
|
|
1486
|
+
sqrDist: () => sqrDist2,
|
|
1487
|
+
sqrLen: () => sqrLen2,
|
|
1488
|
+
squaredDistance: () => squaredDistance2,
|
|
1489
|
+
squaredLength: () => squaredLength2,
|
|
1490
|
+
str: () => str2,
|
|
1491
|
+
sub: () => sub2,
|
|
1492
|
+
subtract: () => subtract2,
|
|
1493
|
+
transformMat4: () => transformMat42,
|
|
1494
|
+
transformQuat: () => transformQuat2,
|
|
1495
|
+
zero: () => zero2
|
|
1496
|
+
});
|
|
1497
|
+
function create2() {
|
|
1498
|
+
const out = new ARRAY_TYPE(4);
|
|
1499
|
+
if (ARRAY_TYPE != Float32Array) {
|
|
1500
|
+
out[0] = 0;
|
|
1501
|
+
out[1] = 0;
|
|
1502
|
+
out[2] = 0;
|
|
1503
|
+
out[3] = 0;
|
|
1504
|
+
}
|
|
1505
|
+
return out;
|
|
1506
|
+
}
|
|
1507
|
+
function clone2(a) {
|
|
1508
|
+
const out = new ARRAY_TYPE(4);
|
|
1509
|
+
out[0] = a[0];
|
|
1510
|
+
out[1] = a[1];
|
|
1511
|
+
out[2] = a[2];
|
|
1512
|
+
out[3] = a[3];
|
|
1513
|
+
return out;
|
|
1514
|
+
}
|
|
1515
|
+
function fromValues2(x, y, z, w) {
|
|
1516
|
+
const out = new ARRAY_TYPE(4);
|
|
1517
|
+
out[0] = x;
|
|
1518
|
+
out[1] = y;
|
|
1519
|
+
out[2] = z;
|
|
1520
|
+
out[3] = w;
|
|
1521
|
+
return out;
|
|
1522
|
+
}
|
|
1523
|
+
function copy2(out, a) {
|
|
1524
|
+
out[0] = a[0];
|
|
1525
|
+
out[1] = a[1];
|
|
1526
|
+
out[2] = a[2];
|
|
1527
|
+
out[3] = a[3];
|
|
1528
|
+
return out;
|
|
1529
|
+
}
|
|
1530
|
+
function set2(out, x, y, z, w) {
|
|
1531
|
+
out[0] = x;
|
|
1532
|
+
out[1] = y;
|
|
1533
|
+
out[2] = z;
|
|
1534
|
+
out[3] = w;
|
|
1535
|
+
return out;
|
|
1536
|
+
}
|
|
1537
|
+
function add2(out, a, b) {
|
|
1538
|
+
out[0] = a[0] + b[0];
|
|
1539
|
+
out[1] = a[1] + b[1];
|
|
1540
|
+
out[2] = a[2] + b[2];
|
|
1541
|
+
out[3] = a[3] + b[3];
|
|
1542
|
+
return out;
|
|
1543
|
+
}
|
|
1544
|
+
function subtract2(out, a, b) {
|
|
1545
|
+
out[0] = a[0] - b[0];
|
|
1546
|
+
out[1] = a[1] - b[1];
|
|
1547
|
+
out[2] = a[2] - b[2];
|
|
1548
|
+
out[3] = a[3] - b[3];
|
|
1549
|
+
return out;
|
|
1550
|
+
}
|
|
1551
|
+
function multiply2(out, a, b) {
|
|
1552
|
+
out[0] = a[0] * b[0];
|
|
1553
|
+
out[1] = a[1] * b[1];
|
|
1554
|
+
out[2] = a[2] * b[2];
|
|
1555
|
+
out[3] = a[3] * b[3];
|
|
1556
|
+
return out;
|
|
1557
|
+
}
|
|
1558
|
+
function divide2(out, a, b) {
|
|
1559
|
+
out[0] = a[0] / b[0];
|
|
1560
|
+
out[1] = a[1] / b[1];
|
|
1561
|
+
out[2] = a[2] / b[2];
|
|
1562
|
+
out[3] = a[3] / b[3];
|
|
1563
|
+
return out;
|
|
1564
|
+
}
|
|
1565
|
+
function ceil2(out, a) {
|
|
1566
|
+
out[0] = Math.ceil(a[0]);
|
|
1567
|
+
out[1] = Math.ceil(a[1]);
|
|
1568
|
+
out[2] = Math.ceil(a[2]);
|
|
1569
|
+
out[3] = Math.ceil(a[3]);
|
|
1570
|
+
return out;
|
|
1571
|
+
}
|
|
1572
|
+
function floor2(out, a) {
|
|
1573
|
+
out[0] = Math.floor(a[0]);
|
|
1574
|
+
out[1] = Math.floor(a[1]);
|
|
1575
|
+
out[2] = Math.floor(a[2]);
|
|
1576
|
+
out[3] = Math.floor(a[3]);
|
|
1577
|
+
return out;
|
|
1578
|
+
}
|
|
1579
|
+
function min2(out, a, b) {
|
|
1580
|
+
out[0] = Math.min(a[0], b[0]);
|
|
1581
|
+
out[1] = Math.min(a[1], b[1]);
|
|
1582
|
+
out[2] = Math.min(a[2], b[2]);
|
|
1583
|
+
out[3] = Math.min(a[3], b[3]);
|
|
1584
|
+
return out;
|
|
1585
|
+
}
|
|
1586
|
+
function max2(out, a, b) {
|
|
1587
|
+
out[0] = Math.max(a[0], b[0]);
|
|
1588
|
+
out[1] = Math.max(a[1], b[1]);
|
|
1589
|
+
out[2] = Math.max(a[2], b[2]);
|
|
1590
|
+
out[3] = Math.max(a[3], b[3]);
|
|
1591
|
+
return out;
|
|
1592
|
+
}
|
|
1593
|
+
function round3(out, a) {
|
|
1594
|
+
out[0] = round(a[0]);
|
|
1595
|
+
out[1] = round(a[1]);
|
|
1596
|
+
out[2] = round(a[2]);
|
|
1597
|
+
out[3] = round(a[3]);
|
|
1598
|
+
return out;
|
|
1599
|
+
}
|
|
1600
|
+
function scale2(out, a, b) {
|
|
1601
|
+
out[0] = a[0] * b;
|
|
1602
|
+
out[1] = a[1] * b;
|
|
1603
|
+
out[2] = a[2] * b;
|
|
1604
|
+
out[3] = a[3] * b;
|
|
1605
|
+
return out;
|
|
1606
|
+
}
|
|
1607
|
+
function scaleAndAdd2(out, a, b, scale3) {
|
|
1608
|
+
out[0] = a[0] + b[0] * scale3;
|
|
1609
|
+
out[1] = a[1] + b[1] * scale3;
|
|
1610
|
+
out[2] = a[2] + b[2] * scale3;
|
|
1611
|
+
out[3] = a[3] + b[3] * scale3;
|
|
1612
|
+
return out;
|
|
1613
|
+
}
|
|
1614
|
+
function distance2(a, b) {
|
|
1615
|
+
const x = b[0] - a[0];
|
|
1616
|
+
const y = b[1] - a[1];
|
|
1617
|
+
const z = b[2] - a[2];
|
|
1618
|
+
const w = b[3] - a[3];
|
|
1619
|
+
return Math.sqrt(x * x + y * y + z * z + w * w);
|
|
1620
|
+
}
|
|
1621
|
+
function squaredDistance2(a, b) {
|
|
1622
|
+
const x = b[0] - a[0];
|
|
1623
|
+
const y = b[1] - a[1];
|
|
1624
|
+
const z = b[2] - a[2];
|
|
1625
|
+
const w = b[3] - a[3];
|
|
1626
|
+
return x * x + y * y + z * z + w * w;
|
|
1627
|
+
}
|
|
1628
|
+
function length2(a) {
|
|
1629
|
+
const x = a[0];
|
|
1630
|
+
const y = a[1];
|
|
1631
|
+
const z = a[2];
|
|
1632
|
+
const w = a[3];
|
|
1633
|
+
return Math.sqrt(x * x + y * y + z * z + w * w);
|
|
1634
|
+
}
|
|
1635
|
+
function squaredLength2(a) {
|
|
1636
|
+
const x = a[0];
|
|
1637
|
+
const y = a[1];
|
|
1638
|
+
const z = a[2];
|
|
1639
|
+
const w = a[3];
|
|
1640
|
+
return x * x + y * y + z * z + w * w;
|
|
1641
|
+
}
|
|
1642
|
+
function negate2(out, a) {
|
|
1643
|
+
out[0] = -a[0];
|
|
1644
|
+
out[1] = -a[1];
|
|
1645
|
+
out[2] = -a[2];
|
|
1646
|
+
out[3] = -a[3];
|
|
1647
|
+
return out;
|
|
1648
|
+
}
|
|
1649
|
+
function inverse2(out, a) {
|
|
1650
|
+
out[0] = 1 / a[0];
|
|
1651
|
+
out[1] = 1 / a[1];
|
|
1652
|
+
out[2] = 1 / a[2];
|
|
1653
|
+
out[3] = 1 / a[3];
|
|
1654
|
+
return out;
|
|
1655
|
+
}
|
|
1656
|
+
function normalize2(out, a) {
|
|
1657
|
+
const x = a[0];
|
|
1658
|
+
const y = a[1];
|
|
1659
|
+
const z = a[2];
|
|
1660
|
+
const w = a[3];
|
|
1661
|
+
let len3 = x * x + y * y + z * z + w * w;
|
|
1662
|
+
if (len3 > 0) {
|
|
1663
|
+
len3 = 1 / Math.sqrt(len3);
|
|
1664
|
+
}
|
|
1665
|
+
out[0] = x * len3;
|
|
1666
|
+
out[1] = y * len3;
|
|
1667
|
+
out[2] = z * len3;
|
|
1668
|
+
out[3] = w * len3;
|
|
1669
|
+
return out;
|
|
1670
|
+
}
|
|
1671
|
+
function dot2(a, b) {
|
|
1672
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
1673
|
+
}
|
|
1674
|
+
function cross2(out, u, v, w) {
|
|
1675
|
+
const A = v[0] * w[1] - v[1] * w[0];
|
|
1676
|
+
const B = v[0] * w[2] - v[2] * w[0];
|
|
1677
|
+
const C = v[0] * w[3] - v[3] * w[0];
|
|
1678
|
+
const D = v[1] * w[2] - v[2] * w[1];
|
|
1679
|
+
const E = v[1] * w[3] - v[3] * w[1];
|
|
1680
|
+
const F = v[2] * w[3] - v[3] * w[2];
|
|
1681
|
+
const G = u[0];
|
|
1682
|
+
const H = u[1];
|
|
1683
|
+
const I = u[2];
|
|
1684
|
+
const J = u[3];
|
|
1685
|
+
out[0] = H * F - I * E + J * D;
|
|
1686
|
+
out[1] = -(G * F) + I * C - J * B;
|
|
1687
|
+
out[2] = G * E - H * C + J * A;
|
|
1688
|
+
out[3] = -(G * D) + H * B - I * A;
|
|
1689
|
+
return out;
|
|
1690
|
+
}
|
|
1691
|
+
function lerp2(out, a, b, t) {
|
|
1692
|
+
const ax = a[0];
|
|
1693
|
+
const ay = a[1];
|
|
1694
|
+
const az = a[2];
|
|
1695
|
+
const aw = a[3];
|
|
1696
|
+
out[0] = ax + t * (b[0] - ax);
|
|
1697
|
+
out[1] = ay + t * (b[1] - ay);
|
|
1698
|
+
out[2] = az + t * (b[2] - az);
|
|
1699
|
+
out[3] = aw + t * (b[3] - aw);
|
|
1700
|
+
return out;
|
|
1701
|
+
}
|
|
1702
|
+
function random2(out, scale3) {
|
|
1703
|
+
scale3 = scale3 === void 0 ? 1 : scale3;
|
|
1704
|
+
let v1;
|
|
1705
|
+
let v2;
|
|
1706
|
+
let v3;
|
|
1707
|
+
let v4;
|
|
1708
|
+
let s1;
|
|
1709
|
+
let s2;
|
|
1710
|
+
do {
|
|
1711
|
+
v1 = RANDOM() * 2 - 1;
|
|
1712
|
+
v2 = RANDOM() * 2 - 1;
|
|
1713
|
+
s1 = v1 * v1 + v2 * v2;
|
|
1714
|
+
} while (s1 >= 1);
|
|
1715
|
+
do {
|
|
1716
|
+
v3 = RANDOM() * 2 - 1;
|
|
1717
|
+
v4 = RANDOM() * 2 - 1;
|
|
1718
|
+
s2 = v3 * v3 + v4 * v4;
|
|
1719
|
+
} while (s2 >= 1);
|
|
1720
|
+
const d = Math.sqrt((1 - s1) / s2);
|
|
1721
|
+
out[0] = scale3 * v1;
|
|
1722
|
+
out[1] = scale3 * v2;
|
|
1723
|
+
out[2] = scale3 * v3 * d;
|
|
1724
|
+
out[3] = scale3 * v4 * d;
|
|
1725
|
+
return out;
|
|
1726
|
+
}
|
|
1727
|
+
function transformMat42(out, a, m) {
|
|
1728
|
+
const x = a[0];
|
|
1729
|
+
const y = a[1];
|
|
1730
|
+
const z = a[2];
|
|
1731
|
+
const w = a[3];
|
|
1732
|
+
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
|
|
1733
|
+
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
|
|
1734
|
+
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
|
|
1735
|
+
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
|
|
1736
|
+
return out;
|
|
1737
|
+
}
|
|
1738
|
+
function transformQuat2(out, a, q) {
|
|
1739
|
+
const x = a[0];
|
|
1740
|
+
const y = a[1];
|
|
1741
|
+
const z = a[2];
|
|
1742
|
+
const qx = q[0];
|
|
1743
|
+
const qy = q[1];
|
|
1744
|
+
const qz = q[2];
|
|
1745
|
+
const qw = q[3];
|
|
1746
|
+
const ix = qw * x + qy * z - qz * y;
|
|
1747
|
+
const iy = qw * y + qz * x - qx * z;
|
|
1748
|
+
const iz = qw * z + qx * y - qy * x;
|
|
1749
|
+
const iw = -qx * x - qy * y - qz * z;
|
|
1750
|
+
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
|
1751
|
+
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
|
1752
|
+
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
|
1753
|
+
out[3] = a[3];
|
|
1754
|
+
return out;
|
|
1755
|
+
}
|
|
1756
|
+
function zero2(out) {
|
|
1757
|
+
out[0] = 0;
|
|
1758
|
+
out[1] = 0;
|
|
1759
|
+
out[2] = 0;
|
|
1760
|
+
out[3] = 0;
|
|
1761
|
+
return out;
|
|
1762
|
+
}
|
|
1763
|
+
function str2(a) {
|
|
1764
|
+
return `vec4(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]})`;
|
|
1765
|
+
}
|
|
1766
|
+
function exactEquals2(a, b) {
|
|
1767
|
+
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
|
|
1768
|
+
}
|
|
1769
|
+
function equals3(a, b) {
|
|
1770
|
+
const a0 = a[0];
|
|
1771
|
+
const a1 = a[1];
|
|
1772
|
+
const a2 = a[2];
|
|
1773
|
+
const a3 = a[3];
|
|
1774
|
+
const b0 = b[0];
|
|
1775
|
+
const b1 = b[1];
|
|
1776
|
+
const b2 = b[2];
|
|
1777
|
+
const b3 = b[3];
|
|
1778
|
+
return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1, Math.abs(a3), Math.abs(b3));
|
|
1779
|
+
}
|
|
1780
|
+
var sub2 = subtract2;
|
|
1781
|
+
var mul2 = multiply2;
|
|
1782
|
+
var div2 = divide2;
|
|
1783
|
+
var dist2 = distance2;
|
|
1784
|
+
var sqrDist2 = squaredDistance2;
|
|
1785
|
+
var len2 = length2;
|
|
1786
|
+
var sqrLen2 = squaredLength2;
|
|
1787
|
+
var forEach2 = (function() {
|
|
1788
|
+
const vec = create2();
|
|
1789
|
+
return function(a, stride, offset, count, fn, arg) {
|
|
1790
|
+
let i;
|
|
1791
|
+
let l;
|
|
1792
|
+
if (!stride) {
|
|
1793
|
+
stride = 4;
|
|
1794
|
+
}
|
|
1795
|
+
if (!offset) {
|
|
1796
|
+
offset = 0;
|
|
1797
|
+
}
|
|
1798
|
+
if (count) {
|
|
1799
|
+
l = Math.min(count * stride + offset, a.length);
|
|
1800
|
+
} else {
|
|
1801
|
+
l = a.length;
|
|
1802
|
+
}
|
|
1803
|
+
for (i = offset; i < l; i += stride) {
|
|
1804
|
+
vec[0] = a[i];
|
|
1805
|
+
vec[1] = a[i + 1];
|
|
1806
|
+
vec[2] = a[i + 2];
|
|
1807
|
+
vec[3] = a[i + 3];
|
|
1808
|
+
fn(vec, vec, arg);
|
|
1809
|
+
a[i] = vec[0];
|
|
1810
|
+
a[i + 1] = vec[1];
|
|
1811
|
+
a[i + 2] = vec[2];
|
|
1812
|
+
a[i + 3] = vec[3];
|
|
1813
|
+
}
|
|
1814
|
+
return a;
|
|
1815
|
+
};
|
|
1816
|
+
})();
|
|
1817
|
+
|
|
1452
1818
|
// ../../node_modules/@luma.gl/shadertools/dist/modules/math/fp64/fp64-utils.js
|
|
1453
1819
|
function fp64ify(a, out = [], startIndex = 0) {
|
|
1454
1820
|
const hiPart = Math.fround(a);
|
|
@@ -3857,14 +4223,14 @@ vec4 project_position_to_clipspace(
|
|
|
3857
4223
|
var getMemoizedUniforms = (0, import_core5._memoize)(calculateUniforms);
|
|
3858
4224
|
function getUniforms2(opts) {
|
|
3859
4225
|
if (opts && "viewport" in opts) {
|
|
3860
|
-
const { viewProjectionMatrix, scale:
|
|
3861
|
-
return getMemoizedUniforms({ viewProjectionMatrix, scale:
|
|
4226
|
+
const { viewProjectionMatrix, scale: scale3 } = opts.viewport;
|
|
4227
|
+
return getMemoizedUniforms({ viewProjectionMatrix, scale: scale3 });
|
|
3862
4228
|
}
|
|
3863
4229
|
return {};
|
|
3864
4230
|
}
|
|
3865
4231
|
function calculateUniforms({
|
|
3866
4232
|
viewProjectionMatrix,
|
|
3867
|
-
scale:
|
|
4233
|
+
scale: scale3
|
|
3868
4234
|
}) {
|
|
3869
4235
|
const glViewProjectionMatrixFP64 = fp64ifyMatrix42(viewProjectionMatrix);
|
|
3870
4236
|
const viewProjectionMatrix64High = new Float32Array(16);
|
|
@@ -3878,7 +4244,7 @@ vec4 project_position_to_clipspace(
|
|
|
3878
4244
|
}
|
|
3879
4245
|
}
|
|
3880
4246
|
return {
|
|
3881
|
-
scale: fp64ify2(
|
|
4247
|
+
scale: fp64ify2(scale3),
|
|
3882
4248
|
viewProjectionMatrix: [...viewProjectionMatrix64High],
|
|
3883
4249
|
viewProjectionMatrix64Low: [...viewProjectionMatrix64Low]
|
|
3884
4250
|
};
|
|
@@ -3911,27 +4277,121 @@ vec4 project_position_to_clipspace(
|
|
|
3911
4277
|
"vs:#decl": `
|
|
3912
4278
|
in vec2 instanceDashArrays;
|
|
3913
4279
|
#ifdef HIGH_PRECISION_DASH
|
|
3914
|
-
in
|
|
4280
|
+
// [distance from the start of the path, total length of the path], in common space.
|
|
4281
|
+
in vec2 instanceDashOffsets;
|
|
3915
4282
|
#endif
|
|
3916
4283
|
out vec2 vDashArray;
|
|
3917
4284
|
out float vDashOffset;
|
|
4285
|
+
out float vDashPathLength;
|
|
4286
|
+
|
|
4287
|
+
// Also declared in the fragment stage. The vertex stage needs dashAlignMode so that it can
|
|
4288
|
+
// reduce the dash phase modulo the same period the fragment stage will test against, and
|
|
4289
|
+
// dashUnits to scale the dash array into that period's units.
|
|
4290
|
+
layout(std140) uniform pathStyleUniforms {
|
|
4291
|
+
float dashAlignMode;
|
|
4292
|
+
bool dashGapPickable;
|
|
4293
|
+
highp int dashUnits;
|
|
4294
|
+
} pathStyle;
|
|
3918
4295
|
`,
|
|
3919
4296
|
"vs:#main-end": `
|
|
3920
|
-
|
|
4297
|
+
// How many screen pixels one unit of vPathPosition.y covers. The two extrusion branches of
|
|
4298
|
+
// the path layer leave this in different units, and both differences have to be undone here
|
|
4299
|
+
// for a billboarded path to dash like a flat one.
|
|
4300
|
+
//
|
|
4301
|
+
// Flat paths extrude in common space, so \`width\` is in common units and a unit of
|
|
4302
|
+
// vPathPosition.y is width.x * project.scale pixels.
|
|
4303
|
+
//
|
|
4304
|
+
// Billboarded paths extrude in clip space, so \`width\` is already in pixels at this point -
|
|
4305
|
+
// the clip-space conversion happens inside getLineJoinOffset. That conversion also folds in
|
|
4306
|
+
// project.focalDistance, which scales the half-width the segment delta is divided by but not
|
|
4307
|
+
// the delta itself, so a unit of vPathPosition.y ends up focalDistance pixels wider than the
|
|
4308
|
+
// stroke it is supposed to be relative to.
|
|
4309
|
+
float dashWidthPixels = path.billboard
|
|
4310
|
+
? width.x * project.focalDistance
|
|
4311
|
+
: width.x * project.scale;
|
|
4312
|
+
|
|
4313
|
+
// The actual half stroke width on screen, which is what 'widths' is relative to. It differs
|
|
4314
|
+
// from dashWidthPixels by exactly the spurious focalDistance above, so expressing 'widths'
|
|
4315
|
+
// as a ratio of the two corrects the billboard case onto the flat one - getDashArray is
|
|
4316
|
+
// documented relative to the stroke, and flat paths already honor that.
|
|
4317
|
+
float strokeHalfWidthPixels = path.billboard ? width.x : width.x * project.scale;
|
|
4318
|
+
|
|
4319
|
+
// Everything reduces to "how many screen pixels is one dash unit", divided through by the
|
|
4320
|
+
// pixels per unit of vPathPosition.y, so the fragment shader needs no notion of units at all.
|
|
4321
|
+
// Keep the cases in sync with DASH_UNITS in path-style-extension.ts.
|
|
4322
|
+
float dashUnitPixels = strokeHalfWidthPixels;
|
|
4323
|
+
if (pathStyle.dashUnits == 1) {
|
|
4324
|
+
dashUnitPixels = 1.0;
|
|
4325
|
+
} else if (pathStyle.dashUnits == 2) {
|
|
4326
|
+
dashUnitPixels = project_size_to_pixel(1.0);
|
|
4327
|
+
} else if (pathStyle.dashUnits == 3) {
|
|
4328
|
+
dashUnitPixels = project.scale;
|
|
4329
|
+
}
|
|
4330
|
+
vDashArray = instanceDashArrays * (dashUnitPixels / dashWidthPixels);
|
|
4331
|
+
|
|
3921
4332
|
#ifdef HIGH_PRECISION_DASH
|
|
3922
|
-
|
|
4333
|
+
// instanceDashOffsets accumulates common-space distance on the CPU. Convert it to pixels, then
|
|
4334
|
+
// divide by the pixel half-width so both extrusion branches use the same dash coordinate.
|
|
4335
|
+
vec2 dashOffsetAndLength = (instanceDashOffsets * project.scale) / dashWidthPixels;
|
|
4336
|
+
vDashPathLength = dashOffsetAndLength.y;
|
|
4337
|
+
|
|
4338
|
+
// Reduce the phase into the first period here rather than in the fragment shader. On a long
|
|
4339
|
+
// path at high zoom the raw offset reaches into the millions, and adding the much smaller
|
|
4340
|
+
// vPathPosition.y to it in fp32 loses the latter entirely, freezing the pattern mid-segment.
|
|
4341
|
+
// The dash function is periodic, so this discards nothing - but it has to be reduced modulo
|
|
4342
|
+
// whichever period the fragment stage will actually test against, hence dashAlignMode here.
|
|
4343
|
+
float dashUnitLength = vDashArray.x + vDashArray.y;
|
|
4344
|
+
float dashPeriod = pathStyle.dashAlignMode == 0.0
|
|
4345
|
+
? dashUnitLength
|
|
4346
|
+
: vDashPathLength / max(round(vDashPathLength / max(dashUnitLength, 0.0001)), 1.0);
|
|
4347
|
+
vDashOffset = dashPeriod > 0.0 ? mod(dashOffsetAndLength.x, dashPeriod) : 0.0;
|
|
3923
4348
|
#else
|
|
3924
4349
|
vDashOffset = 0.0;
|
|
4350
|
+
vDashPathLength = 0.0;
|
|
3925
4351
|
#endif
|
|
3926
4352
|
`,
|
|
3927
4353
|
"fs:#decl": `
|
|
3928
4354
|
layout(std140) uniform pathStyleUniforms {
|
|
3929
4355
|
float dashAlignMode;
|
|
3930
4356
|
bool dashGapPickable;
|
|
4357
|
+
highp int dashUnits;
|
|
3931
4358
|
} pathStyle;
|
|
3932
4359
|
|
|
3933
4360
|
in vec2 vDashArray;
|
|
3934
4361
|
in float vDashOffset;
|
|
4362
|
+
in float vDashPathLength;
|
|
4363
|
+
|
|
4364
|
+
// Integral of the dash square wave from 0 to position, i.e. how much solid stroke lies before it.
|
|
4365
|
+
float dashPatternIntegral(float position, float solidLength, float unitLength) {
|
|
4366
|
+
return floor(position / unitLength) * solidLength +
|
|
4367
|
+
min(mod(position, unitLength), solidLength);
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
// Fraction of the filter-width interval centered on position that is covered by solid stroke.
|
|
4371
|
+
//
|
|
4372
|
+
// Testing the dash pattern with a single comparison per fragment aliases as soon as one
|
|
4373
|
+
// period approaches one pixel: the stroke breaks into moire or, when the phase happens to
|
|
4374
|
+
// land inside a dash, reads as solid. Integrating the wave over the fragment footprint
|
|
4375
|
+
// instead is the closed form of what a mipmapped dash texture approximates, and it degrades
|
|
4376
|
+
// the way one wants - once a period drops below a pixel the result converges on the duty
|
|
4377
|
+
// cycle solidLength / unitLength, so the stroke fades to a uniformly lighter line.
|
|
4378
|
+
//
|
|
4379
|
+
// position is reduced into the first period first. The integral satisfies
|
|
4380
|
+
// F(position + periodIndex * unitLength) = F(position) + periodIndex * solidLength,
|
|
4381
|
+
// so the same periodIndex cancels out of the
|
|
4382
|
+
// difference below, and keeping the arguments small avoids subtracting two large nearly
|
|
4383
|
+
// equal numbers in fp32 on long paths.
|
|
4384
|
+
float dashPatternCoverage(
|
|
4385
|
+
float position,
|
|
4386
|
+
float solidLength,
|
|
4387
|
+
float unitLength,
|
|
4388
|
+
float filterWidth
|
|
4389
|
+
) {
|
|
4390
|
+
float halfFilter = 0.5 * filterWidth;
|
|
4391
|
+
float reducedPosition = mod(position, unitLength);
|
|
4392
|
+
return (dashPatternIntegral(reducedPosition + halfFilter, solidLength, unitLength) -
|
|
4393
|
+
dashPatternIntegral(reducedPosition - halfFilter, solidLength, unitLength)) / filterWidth;
|
|
4394
|
+
}
|
|
3935
4395
|
`,
|
|
3936
4396
|
// if given position is in the gap part of the dashed line
|
|
3937
4397
|
// dashArray.x: solid stroke length, relative to width
|
|
@@ -3942,41 +4402,130 @@ in float vDashOffset;
|
|
|
3942
4402
|
// 1 - stretch to fit, draw half dash at each end for nicer joints
|
|
3943
4403
|
// o-- ---- ---- ---- --o-- --o-- ---- --o
|
|
3944
4404
|
"fs:#main-start": `
|
|
4405
|
+
float dashCoverage = 1.0;
|
|
4406
|
+
bool shouldDiscardDash = false;
|
|
4407
|
+
bool inRoundedDashGap = false;
|
|
4408
|
+
float roundedDashResolvedCoverage = 1.0;
|
|
4409
|
+
float roundedDashSubPixelBlend = 0.0;
|
|
4410
|
+
float roundedDashDutyCycle = 1.0;
|
|
4411
|
+
|
|
3945
4412
|
float solidLength = vDashArray.x;
|
|
3946
4413
|
float gapLength = vDashArray.y;
|
|
3947
4414
|
float unitLength = solidLength + gapLength;
|
|
3948
4415
|
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
if (unitLength > 0.0) {
|
|
4416
|
+
if (unitLength > 0.0 && gapLength > 0.0) {
|
|
4417
|
+
float offset;
|
|
3952
4418
|
if (pathStyle.dashAlignMode == 0.0) {
|
|
3953
4419
|
offset = vDashOffset;
|
|
3954
4420
|
} else {
|
|
3955
|
-
|
|
4421
|
+
// Justified: stretch the period so a whole number of them spans the run, and start
|
|
4422
|
+
// half a dash in so both ends finish on a joint. Rounding up to at least one period
|
|
4423
|
+
// matters - a run shorter than half a period used to round to zero, which made
|
|
4424
|
+
// unitLength infinite and rendered it solid.
|
|
4425
|
+
#ifdef HIGH_PRECISION_DASH
|
|
4426
|
+
// Justify across the entire path rather than each segment separately, so the gaps stay
|
|
4427
|
+
// even instead of being stretched by a different amount on every segment. vDashOffset
|
|
4428
|
+
// already carries the distance to the start of this segment, reduced modulo this same
|
|
4429
|
+
// period in the vertex shader.
|
|
4430
|
+
unitLength = vDashPathLength / max(round(vDashPathLength / unitLength), 1.0);
|
|
4431
|
+
#else
|
|
4432
|
+
unitLength = vPathLength / max(round(vPathLength / unitLength), 1.0);
|
|
4433
|
+
#endif
|
|
4434
|
+
// A short segment or path can make the fitted period shorter than the requested dash.
|
|
4435
|
+
// Bound the solid interval to that period so coverage and duty cycle remain valid.
|
|
4436
|
+
solidLength = min(solidLength, unitLength);
|
|
3956
4437
|
offset = solidLength / 2.0;
|
|
4438
|
+
#ifdef HIGH_PRECISION_DASH
|
|
4439
|
+
offset += vDashOffset;
|
|
4440
|
+
#endif
|
|
3957
4441
|
}
|
|
3958
4442
|
|
|
3959
|
-
float
|
|
4443
|
+
float alongPath = vPathPosition.y + offset;
|
|
4444
|
+
float unitOffset = mod(alongPath, unitLength);
|
|
4445
|
+
float filterWidth = max(fwidth(alongPath), 0.0001);
|
|
3960
4446
|
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
4447
|
+
// Picking stays a hard in-or-out test. A blended picking colour decodes to the wrong
|
|
4448
|
+
// index, and dashGapPickable is defined in terms of whole gaps rather than coverage.
|
|
4449
|
+
if (bool(picking.isActive)) {
|
|
4450
|
+
bool inGap = unitOffset > solidLength;
|
|
4451
|
+
// Only measure the rounded end-cap distance after the hard interval test has found a
|
|
4452
|
+
// gap. Inside a solid interval the longitudinal distance is negative; taking its
|
|
4453
|
+
// vector length would turn it positive and incorrectly discard the middle of a dash.
|
|
4454
|
+
if (inGap && path.capType > 0.5) {
|
|
4455
|
+
inGap = length(vec2(
|
|
3969
4456
|
min(unitOffset - solidLength, unitLength - unitOffset),
|
|
3970
4457
|
vPathPosition.x
|
|
3971
|
-
));
|
|
3972
|
-
if (distToEnd > 1.0) {
|
|
3973
|
-
if (!(pathStyle.dashGapPickable && bool(picking.isActive))) {
|
|
3974
|
-
discard;
|
|
3975
|
-
}
|
|
3976
|
-
}
|
|
4458
|
+
)) > 1.0;
|
|
3977
4459
|
}
|
|
4460
|
+
if (inGap && !pathStyle.dashGapPickable) {
|
|
4461
|
+
shouldDiscardDash = true;
|
|
4462
|
+
}
|
|
4463
|
+
} else if (path.capType <= 0.5) {
|
|
4464
|
+
dashCoverage = dashPatternCoverage(alongPath, solidLength, unitLength, filterWidth);
|
|
4465
|
+
} else {
|
|
4466
|
+
// Rounded caps: the dash end is an arc, so resolve the 2D distance to the nearer solid
|
|
4467
|
+
// end rather than the 1D position along the path. Only filter fragments in the gap;
|
|
4468
|
+
// PathLayer already antialiases the ordinary sides of the solid stroke.
|
|
4469
|
+
float distanceAlongGap = min(unitOffset - solidLength, unitLength - unitOffset);
|
|
4470
|
+
// Clamp before taking the derivative so the distance stays continuous across the
|
|
4471
|
+
// wrapped period boundary. Evaluate fwidth for every fragment in the quad; derivatives
|
|
4472
|
+
// are undefined inside the non-uniform gap branch below.
|
|
4473
|
+
float distanceToEnd = length(vec2(max(distanceAlongGap, 0.0), vPathPosition.x));
|
|
4474
|
+
float capEdgePixels = (1.0 - distanceToEnd) / max(fwidth(distanceToEnd), 1e-6);
|
|
4475
|
+
if (distanceAlongGap > 0.0) {
|
|
4476
|
+
inRoundedDashGap = true;
|
|
4477
|
+
roundedDashResolvedCoverage = smoothedge(0.0, capEdgePixels);
|
|
4478
|
+
dashCoverage = roundedDashResolvedCoverage;
|
|
4479
|
+
}
|
|
4480
|
+
// That smoothstep resolves one dash end at a time, so it stops meaning anything once a
|
|
4481
|
+
// whole period fits inside the filter footprint. Start fading only at that boundary;
|
|
4482
|
+
// blending resolvable periods would attenuate the solid body of every rounded dash.
|
|
4483
|
+
float subPixelBlend = smoothstep(unitLength, 2.0 * unitLength, filterWidth);
|
|
4484
|
+
roundedDashSubPixelBlend = subPixelBlend;
|
|
4485
|
+
// At sub-pixel scale, preserve the area of the repeated capsule rather than falling
|
|
4486
|
+
// back to the rectangular duty cycle. Each scanline contains the solid body plus the
|
|
4487
|
+
// two circular cap intrusions, capped when neighboring caps overlap across the gap.
|
|
4488
|
+
float boundedSolidLength = min(solidLength, unitLength);
|
|
4489
|
+
float effectiveGap = max(unitLength - boundedSolidLength, 0.0);
|
|
4490
|
+
float capSpan = 2.0 * sqrt(max(1.0 - vPathPosition.x * vPathPosition.x, 0.0));
|
|
4491
|
+
float roundedDutyCycle = clamp(
|
|
4492
|
+
(boundedSolidLength + min(effectiveGap, capSpan)) / unitLength,
|
|
4493
|
+
0.0,
|
|
4494
|
+
1.0
|
|
4495
|
+
);
|
|
4496
|
+
roundedDashDutyCycle = roundedDutyCycle;
|
|
4497
|
+
dashCoverage = mix(dashCoverage, roundedDutyCycle, subPixelBlend);
|
|
3978
4498
|
}
|
|
4499
|
+
|
|
4500
|
+
dashCoverage = clamp(dashCoverage, 0.0, 1.0);
|
|
4501
|
+
// Fully transparent fragments would still write depth and occlude whatever is behind.
|
|
4502
|
+
shouldDiscardDash = shouldDiscardDash || dashCoverage <= 0.0;
|
|
4503
|
+
}
|
|
4504
|
+
`,
|
|
4505
|
+
"fs:#main-end": `
|
|
4506
|
+
// PathLayer computes analytic-edge derivatives in its fragment body. A discard in
|
|
4507
|
+
// #main-start can remove helper invocations and make those derivatives undefined, so all
|
|
4508
|
+
// dash-related termination is deferred until the layer has completed that work.
|
|
4509
|
+
#ifdef ANTIALIASING
|
|
4510
|
+
if (inRoundedDashGap) {
|
|
4511
|
+
// The rounded dash cap and PathLayer silhouette are two geometric constraints on the
|
|
4512
|
+
// same fragment. Intersect their coverage instead of multiplying two edge ramps; at the
|
|
4513
|
+
// cap/body shoulder both ramps are half covered and multiplication would create a dark
|
|
4514
|
+
// quarter-covered notch. Keep the sub-pixel duty cycle separable from the path silhouette.
|
|
4515
|
+
float pathCoverage = smoothedge(0.0, edgePixels);
|
|
4516
|
+
float resolvedCapMultiplier =
|
|
4517
|
+
min(pathCoverage, roundedDashResolvedCoverage) / max(pathCoverage, 1e-6);
|
|
4518
|
+
dashCoverage = mix(
|
|
4519
|
+
resolvedCapMultiplier,
|
|
4520
|
+
roundedDashDutyCycle,
|
|
4521
|
+
roundedDashSubPixelBlend
|
|
4522
|
+
);
|
|
4523
|
+
}
|
|
4524
|
+
#endif
|
|
4525
|
+
if (shouldDiscardDash) {
|
|
4526
|
+
discard;
|
|
3979
4527
|
}
|
|
4528
|
+
fragColor.a *= dashCoverage;
|
|
3980
4529
|
`
|
|
3981
4530
|
}
|
|
3982
4531
|
};
|
|
@@ -4198,13 +4747,42 @@ in float instanceOffsets;
|
|
|
4198
4747
|
vPathPosition.x = (vPathPosition.x + offsetDir) * offsetWidth - offsetDir;
|
|
4199
4748
|
vPathPosition.y *= offsetWidth;
|
|
4200
4749
|
vPathLength *= offsetWidth;
|
|
4750
|
+
#ifdef DASH_ENABLED
|
|
4751
|
+
// DECKGL_FILTER_SIZE above widened the stroke by offsetWidth, so these rescalings restore
|
|
4752
|
+
// units of the original half-width. The dash block merges ahead of this one.
|
|
4753
|
+
if (pathStyle.dashUnits != 0) {
|
|
4754
|
+
// Absolute dash units must not inherit the artificial width used to build offset
|
|
4755
|
+
// geometry. Relative 'widths' units intentionally remain tied to the original stroke.
|
|
4756
|
+
vDashArray *= offsetWidth;
|
|
4757
|
+
}
|
|
4758
|
+
vPathBounds *= offsetWidth;
|
|
4759
|
+
#ifdef HIGH_PRECISION_DASH
|
|
4760
|
+
vDashPathLength *= offsetWidth;
|
|
4761
|
+
// The dash block reduced the CPU path offset modulo a period expressed in widened-width
|
|
4762
|
+
// units. Multiplying that remainder cannot recover the original phase after wrapping, so
|
|
4763
|
+
// redo the reduction with both the restored path offset and restored justified period.
|
|
4764
|
+
float restoredDashUnitLength = vDashArray.x + vDashArray.y;
|
|
4765
|
+
float restoredDashPeriod = pathStyle.dashAlignMode == 0.0
|
|
4766
|
+
? restoredDashUnitLength
|
|
4767
|
+
: vDashPathLength /
|
|
4768
|
+
max(round(vDashPathLength / max(restoredDashUnitLength, 0.0001)), 1.0);
|
|
4769
|
+
vDashOffset = restoredDashPeriod > 0.0
|
|
4770
|
+
? mod(dashOffsetAndLength.x * offsetWidth, restoredDashPeriod)
|
|
4771
|
+
: 0.0;
|
|
4772
|
+
#else
|
|
4773
|
+
vDashOffset *= offsetWidth;
|
|
4774
|
+
#endif
|
|
4775
|
+
#endif
|
|
4201
4776
|
`,
|
|
4202
|
-
"fs:#main-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4777
|
+
"fs:#main-end": `
|
|
4778
|
+
#ifndef ANTIALIASING
|
|
4779
|
+
// With analytic antialiasing, PathLayer evaluates this boundary using the remapped
|
|
4780
|
+
// vPathPosition and retains the complete centered coverage ramp. The hard clip remains for
|
|
4781
|
+
// the original non-AA path.
|
|
4782
|
+
if (abs(vPathPosition.x) > 1.0) {
|
|
4206
4783
|
discard;
|
|
4207
4784
|
}
|
|
4785
|
+
#endif
|
|
4208
4786
|
`
|
|
4209
4787
|
}
|
|
4210
4788
|
};
|
|
@@ -4214,15 +4792,73 @@ in float instanceOffsets;
|
|
|
4214
4792
|
getDashArray: { type: "accessor", value: [0, 0] },
|
|
4215
4793
|
getOffset: { type: "accessor", value: 0 },
|
|
4216
4794
|
dashJustified: false,
|
|
4217
|
-
dashGapPickable: false
|
|
4795
|
+
dashGapPickable: false,
|
|
4796
|
+
dashUnits: "widths"
|
|
4218
4797
|
};
|
|
4798
|
+
var DASH_UNITS = {
|
|
4799
|
+
widths: 0,
|
|
4800
|
+
pixels: 1,
|
|
4801
|
+
meters: 2,
|
|
4802
|
+
common: 3
|
|
4803
|
+
};
|
|
4804
|
+
var PATH_STYLE_ATTRIBUTES = ["instanceDashArrays", "instanceDashOffsets", "instanceOffsets"];
|
|
4805
|
+
function dashMetricsProjectionPropsChanged({
|
|
4806
|
+
props,
|
|
4807
|
+
oldProps
|
|
4808
|
+
}) {
|
|
4809
|
+
return !(0, import_core7._deepEqual)(props.modelMatrix, oldProps.modelMatrix, 2) || props.coordinateSystem !== oldProps.coordinateSystem || !(0, import_core7._deepEqual)(props.coordinateOrigin, oldProps.coordinateOrigin, 1);
|
|
4810
|
+
}
|
|
4811
|
+
function projectRenderedPathPosition(layer, position, projectUniforms) {
|
|
4812
|
+
const viewport = layer.context.viewport;
|
|
4813
|
+
if (!(viewport instanceof import_core7.WebMercatorViewport) || viewport.zoom < 12) {
|
|
4814
|
+
return layer.projectPosition(position, { autoOffset: false });
|
|
4815
|
+
}
|
|
4816
|
+
const positionWorld = vec4_exports.transformMat4(
|
|
4817
|
+
[],
|
|
4818
|
+
[position[0], position[1], position[2] || 0, 1],
|
|
4819
|
+
projectUniforms.modelMatrix
|
|
4820
|
+
);
|
|
4821
|
+
const coordinateSystem = layer.props.coordinateSystem === "default" ? "lnglat" : layer.props.coordinateSystem;
|
|
4822
|
+
if (coordinateSystem === "lnglat") {
|
|
4823
|
+
if (Math.abs(positionWorld[1] - projectUniforms.coordinateOrigin[1]) > 0.25) {
|
|
4824
|
+
let longitude = positionWorld[0];
|
|
4825
|
+
if (projectUniforms.wrapLongitude) {
|
|
4826
|
+
longitude = ((longitude + 180) % 360 + 360) % 360 - 180;
|
|
4827
|
+
}
|
|
4828
|
+
const commonPosition = viewport.projectPosition([longitude, positionWorld[1], 0]);
|
|
4829
|
+
return [
|
|
4830
|
+
commonPosition[0] - projectUniforms.commonOrigin[0],
|
|
4831
|
+
commonPosition[1] - projectUniforms.commonOrigin[1],
|
|
4832
|
+
positionWorld[2] * projectUniforms.commonUnitsPerMeter[2]
|
|
4833
|
+
];
|
|
4834
|
+
}
|
|
4835
|
+
vec3_exports.sub(positionWorld, positionWorld, projectUniforms.coordinateOrigin);
|
|
4836
|
+
} else if (coordinateSystem === "cartesian") {
|
|
4837
|
+
vec3_exports.sub(positionWorld, positionWorld, projectUniforms.coordinateOrigin);
|
|
4838
|
+
}
|
|
4839
|
+
const deltaLatitude = positionWorld[1];
|
|
4840
|
+
const scale3 = vec3_exports.scaleAndAdd(
|
|
4841
|
+
[],
|
|
4842
|
+
projectUniforms.commonUnitsPerWorldUnit,
|
|
4843
|
+
projectUniforms.commonUnitsPerWorldUnit2,
|
|
4844
|
+
deltaLatitude
|
|
4845
|
+
);
|
|
4846
|
+
return vec3_exports.multiply([], positionWorld, scale3);
|
|
4847
|
+
}
|
|
4219
4848
|
var PathStyleExtension = class extends import_core7.LayerExtension {
|
|
4220
4849
|
constructor({
|
|
4221
4850
|
dash = false,
|
|
4222
4851
|
offset = false,
|
|
4852
|
+
dashMode,
|
|
4223
4853
|
highPrecisionDash = false
|
|
4224
4854
|
} = {}) {
|
|
4225
|
-
|
|
4855
|
+
const resolvedDashMode = dashMode ?? (highPrecisionDash ? "path" : "segment");
|
|
4856
|
+
super({
|
|
4857
|
+
dash: dash || highPrecisionDash || dashMode !== void 0,
|
|
4858
|
+
offset,
|
|
4859
|
+
dashMode: resolvedDashMode,
|
|
4860
|
+
highPrecisionDash: resolvedDashMode === "path"
|
|
4861
|
+
});
|
|
4226
4862
|
}
|
|
4227
4863
|
getLayerType(layer) {
|
|
4228
4864
|
if ("pathTesselator" in layer.state) {
|
|
@@ -4237,6 +4873,59 @@ in float instanceOffsets;
|
|
|
4237
4873
|
}
|
|
4238
4874
|
return null;
|
|
4239
4875
|
}
|
|
4876
|
+
synchronizeAttributes(layer) {
|
|
4877
|
+
const attributeManager = layer.getAttributeManager();
|
|
4878
|
+
const layerType = this.getLayerType(layer);
|
|
4879
|
+
if (!attributeManager || !layerType) {
|
|
4880
|
+
return false;
|
|
4881
|
+
}
|
|
4882
|
+
const attributes = attributeManager.getAttributes();
|
|
4883
|
+
const desiredAttributes = /* @__PURE__ */ new Set();
|
|
4884
|
+
if (this.opts.dash) {
|
|
4885
|
+
desiredAttributes.add("instanceDashArrays");
|
|
4886
|
+
}
|
|
4887
|
+
if (layerType === "path" && this.opts.dash && this.opts.dashMode === "path") {
|
|
4888
|
+
desiredAttributes.add("instanceDashOffsets");
|
|
4889
|
+
}
|
|
4890
|
+
if (layerType === "path" && this.opts.offset) {
|
|
4891
|
+
desiredAttributes.add("instanceOffsets");
|
|
4892
|
+
}
|
|
4893
|
+
let topologyChanged = false;
|
|
4894
|
+
for (const attributeName of PATH_STYLE_ATTRIBUTES) {
|
|
4895
|
+
if (attributes[attributeName] && !desiredAttributes.has(attributeName)) {
|
|
4896
|
+
attributeManager.remove([attributeName]);
|
|
4897
|
+
topologyChanged = true;
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
if (desiredAttributes.has("instanceDashArrays") && !attributes.instanceDashArrays) {
|
|
4901
|
+
attributeManager.addInstanced({
|
|
4902
|
+
instanceDashArrays: { size: 2, accessor: "getDashArray" }
|
|
4903
|
+
});
|
|
4904
|
+
topologyChanged = true;
|
|
4905
|
+
}
|
|
4906
|
+
if (desiredAttributes.has("instanceDashOffsets") && !attributes.instanceDashOffsets) {
|
|
4907
|
+
attributeManager.addInstanced({
|
|
4908
|
+
instanceDashOffsets: {
|
|
4909
|
+
// [distance from the start of the path, total length of the path]
|
|
4910
|
+
size: 2,
|
|
4911
|
+
// Recalculate from rendered geometry when getPath changes. A binary getPath buffer
|
|
4912
|
+
// contains positions, not dash metrics, so keep it as an update trigger rather than
|
|
4913
|
+
// binding it directly to this attribute.
|
|
4914
|
+
accessor: ["getPath"],
|
|
4915
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
4916
|
+
update: this.calculateDashMetrics
|
|
4917
|
+
}
|
|
4918
|
+
});
|
|
4919
|
+
topologyChanged = true;
|
|
4920
|
+
}
|
|
4921
|
+
if (desiredAttributes.has("instanceOffsets") && !attributes.instanceOffsets) {
|
|
4922
|
+
attributeManager.addInstanced({
|
|
4923
|
+
instanceOffsets: { size: 1, accessor: "getOffset" }
|
|
4924
|
+
});
|
|
4925
|
+
topologyChanged = true;
|
|
4926
|
+
}
|
|
4927
|
+
return topologyChanged;
|
|
4928
|
+
}
|
|
4240
4929
|
isEnabled(layer) {
|
|
4241
4930
|
return this.getLayerType(layer) !== null;
|
|
4242
4931
|
}
|
|
@@ -4263,57 +4952,54 @@ in float instanceOffsets;
|
|
|
4263
4952
|
const defines = {};
|
|
4264
4953
|
if (extension.opts.dash) {
|
|
4265
4954
|
result = (0, import_core7._mergeShaders)(result, dashShaders);
|
|
4266
|
-
|
|
4955
|
+
defines.DASH_ENABLED = true;
|
|
4956
|
+
if (extension.opts.dashMode === "path") {
|
|
4267
4957
|
defines.HIGH_PRECISION_DASH = true;
|
|
4268
4958
|
}
|
|
4269
4959
|
}
|
|
4270
4960
|
if (extension.opts.offset) {
|
|
4271
4961
|
result = (0, import_core7._mergeShaders)(result, offsetShaders);
|
|
4962
|
+
defines.PATH_STYLE_OFFSET = true;
|
|
4272
4963
|
}
|
|
4273
4964
|
const { inject: inject6 } = result;
|
|
4274
4965
|
const pathStyle = {
|
|
4275
4966
|
name: "pathStyle",
|
|
4276
|
-
inject: inject6
|
|
4277
|
-
uniformTypes: {
|
|
4278
|
-
dashAlignMode: "f32",
|
|
4279
|
-
dashGapPickable: "i32"
|
|
4280
|
-
}
|
|
4967
|
+
inject: inject6
|
|
4281
4968
|
};
|
|
4969
|
+
if (extension.opts.dash) {
|
|
4970
|
+
pathStyle.uniformTypes = {
|
|
4971
|
+
dashAlignMode: "f32",
|
|
4972
|
+
dashGapPickable: "i32",
|
|
4973
|
+
dashUnits: "i32"
|
|
4974
|
+
};
|
|
4975
|
+
}
|
|
4282
4976
|
return {
|
|
4283
4977
|
modules: [pathStyle],
|
|
4284
4978
|
defines
|
|
4285
4979
|
};
|
|
4286
4980
|
}
|
|
4287
4981
|
initializeState(context, extension) {
|
|
4288
|
-
|
|
4289
|
-
const layerType = extension.getLayerType(this);
|
|
4290
|
-
if (!attributeManager || !layerType) {
|
|
4291
|
-
return;
|
|
4292
|
-
}
|
|
4293
|
-
if (extension.opts.dash) {
|
|
4294
|
-
attributeManager.addInstanced({
|
|
4295
|
-
instanceDashArrays: { size: 2, accessor: "getDashArray" },
|
|
4296
|
-
...layerType === "path" && extension.opts.highPrecisionDash ? {
|
|
4297
|
-
instanceDashOffsets: {
|
|
4298
|
-
size: 1,
|
|
4299
|
-
accessor: "getPath",
|
|
4300
|
-
transform: extension.getDashOffsets.bind(this)
|
|
4301
|
-
}
|
|
4302
|
-
} : {}
|
|
4303
|
-
});
|
|
4304
|
-
}
|
|
4305
|
-
if (layerType === "path" && extension.opts.offset) {
|
|
4306
|
-
attributeManager.addInstanced({
|
|
4307
|
-
instanceOffsets: { size: 1, accessor: "getOffset" }
|
|
4308
|
-
});
|
|
4309
|
-
}
|
|
4982
|
+
extension.synchronizeAttributes(this);
|
|
4310
4983
|
}
|
|
4311
4984
|
updateState(params, extension) {
|
|
4312
4985
|
if (!extension.isEnabled(this)) {
|
|
4313
4986
|
return;
|
|
4314
4987
|
}
|
|
4988
|
+
if (params.changeFlags.extensionsChanged) {
|
|
4989
|
+
const topologyChanged = extension.synchronizeAttributes(this);
|
|
4990
|
+
const attributeManager = this.getAttributeManager();
|
|
4991
|
+
if (attributeManager && topologyChanged) {
|
|
4992
|
+
attributeManager.invalidateAll();
|
|
4993
|
+
for (const model of this.getModels()) {
|
|
4994
|
+
model.setBufferLayout(attributeManager.getBufferLayouts(model));
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4315
4998
|
if (extension.opts.dash) {
|
|
4316
4999
|
const layerType = extension.getLayerType(this);
|
|
5000
|
+
if (layerType === "path" && extension.opts.dashMode === "path" && dashMetricsProjectionPropsChanged(params)) {
|
|
5001
|
+
this.getAttributeManager()?.invalidate("instanceDashOffsets");
|
|
5002
|
+
}
|
|
4317
5003
|
if (layerType === "scatterplot" || layerType === "textBackground") {
|
|
4318
5004
|
const pathStyleProps = {
|
|
4319
5005
|
dashGapPickable: Boolean(this.props.dashGapPickable)
|
|
@@ -4322,12 +5008,101 @@ in float instanceOffsets;
|
|
|
4322
5008
|
} else {
|
|
4323
5009
|
const pathStyleProps = {
|
|
4324
5010
|
dashAlignMode: this.props.dashJustified ? 1 : 0,
|
|
4325
|
-
dashGapPickable: Boolean(this.props.dashGapPickable)
|
|
5011
|
+
dashGapPickable: Boolean(this.props.dashGapPickable),
|
|
5012
|
+
dashUnits: DASH_UNITS[this.props.dashUnits ?? "widths"]
|
|
4326
5013
|
};
|
|
4327
5014
|
this.setShaderModuleProps({ pathStyle: pathStyleProps });
|
|
4328
5015
|
}
|
|
4329
5016
|
}
|
|
4330
5017
|
}
|
|
5018
|
+
calculateDashMetrics(attribute, { startRow, endRow }) {
|
|
5019
|
+
const pathTesselator = this.state.pathTesselator;
|
|
5020
|
+
const vertexStarts = pathTesselator?.vertexStarts;
|
|
5021
|
+
const instanceCount = pathTesselator?.instanceCount;
|
|
5022
|
+
const packedPositions = pathTesselator?.get("positions");
|
|
5023
|
+
if (!vertexStarts || instanceCount === void 0 || typeof pathTesselator?.getPathSegmentIndices !== "function") {
|
|
5024
|
+
throw new Error("PathStyleExtension requires PathLayer tessellation data for path dashes.");
|
|
5025
|
+
}
|
|
5026
|
+
const binaryPath = this.props.data?.attributes?.getPath;
|
|
5027
|
+
const binaryValue = ArrayBuffer.isView(binaryPath) ? binaryPath : binaryPath?.value;
|
|
5028
|
+
const hasReadableBinaryPath = ArrayBuffer.isView(binaryValue);
|
|
5029
|
+
const usePackedPositions = packedPositions && (!binaryPath || pathTesselator.normalize || pathTesselator.opts?.isWebGPU);
|
|
5030
|
+
if (binaryPath && !hasReadableBinaryPath || !usePackedPositions && !hasReadableBinaryPath) {
|
|
5031
|
+
throw new Error(
|
|
5032
|
+
"PathStyleExtension cannot calculate whole-path dash metrics from GPU-only getPath data; supply data.attributes.instanceDashOffsets."
|
|
5033
|
+
);
|
|
5034
|
+
}
|
|
5035
|
+
const output = attribute.value;
|
|
5036
|
+
const metricSize = attribute.size;
|
|
5037
|
+
const firstRow = Math.max(0, startRow);
|
|
5038
|
+
const lastRow = Math.min(endRow, vertexStarts.length - 1);
|
|
5039
|
+
let binarySize = 3;
|
|
5040
|
+
let binaryStride = 3;
|
|
5041
|
+
let binaryOffset = 0;
|
|
5042
|
+
if (!usePackedPositions) {
|
|
5043
|
+
const bytesPerElement = binaryValue.BYTES_PER_ELEMENT;
|
|
5044
|
+
binarySize = binaryPath?.size || (this.props.positionFormat === "XY" ? 2 : 3);
|
|
5045
|
+
binaryStride = binaryPath?.stride ? binaryPath.stride / bytesPerElement : binarySize;
|
|
5046
|
+
binaryOffset = binaryPath?.offset ? binaryPath.offset / bytesPerElement : 0;
|
|
5047
|
+
}
|
|
5048
|
+
const sourcePosition = new Array(3);
|
|
5049
|
+
const projectUniforms = import_core7.project.getUniforms({
|
|
5050
|
+
viewport: this.context.viewport,
|
|
5051
|
+
modelMatrix: this.props.modelMatrix,
|
|
5052
|
+
coordinateSystem: this.props.coordinateSystem,
|
|
5053
|
+
coordinateOrigin: this.props.coordinateOrigin,
|
|
5054
|
+
// PathLayer normalizes/cuts wrapped paths on the CPU; its shader never wraps again.
|
|
5055
|
+
autoWrapLongitude: this.wrapLongitude
|
|
5056
|
+
});
|
|
5057
|
+
const readPosition = (vertexIndex) => {
|
|
5058
|
+
if (usePackedPositions) {
|
|
5059
|
+
sourcePosition[0] = packedPositions[vertexIndex * 3];
|
|
5060
|
+
sourcePosition[1] = packedPositions[vertexIndex * 3 + 1];
|
|
5061
|
+
sourcePosition[2] = packedPositions[vertexIndex * 3 + 2];
|
|
5062
|
+
} else {
|
|
5063
|
+
const sourceIndex = binaryOffset + vertexIndex * binaryStride;
|
|
5064
|
+
sourcePosition[0] = binaryValue[sourceIndex];
|
|
5065
|
+
sourcePosition[1] = binaryValue[sourceIndex + 1];
|
|
5066
|
+
sourcePosition[2] = binarySize === 3 ? binaryValue[sourceIndex + 2] : 0;
|
|
5067
|
+
}
|
|
5068
|
+
return sourcePosition;
|
|
5069
|
+
};
|
|
5070
|
+
attribute.startIndices = vertexStarts;
|
|
5071
|
+
for (let row = firstRow; row < lastRow; row++) {
|
|
5072
|
+
const rowStart = vertexStarts[row];
|
|
5073
|
+
const rowEnd = Math.min(vertexStarts[row + 1] ?? instanceCount, instanceCount);
|
|
5074
|
+
output.fill(0, rowStart * metricSize, rowEnd * metricSize);
|
|
5075
|
+
const validSegments = pathTesselator.getPathSegmentIndices(row);
|
|
5076
|
+
let phase = 0;
|
|
5077
|
+
let previousSegment = -2;
|
|
5078
|
+
let previousEnd = null;
|
|
5079
|
+
for (const segmentIndex of validSegments) {
|
|
5080
|
+
const outputIndex = segmentIndex * metricSize;
|
|
5081
|
+
output[outputIndex] = phase;
|
|
5082
|
+
const start = segmentIndex === previousSegment + 1 && previousEnd ? previousEnd : projectRenderedPathPosition(this, readPosition(segmentIndex), projectUniforms);
|
|
5083
|
+
const end = projectRenderedPathPosition(
|
|
5084
|
+
this,
|
|
5085
|
+
readPosition(segmentIndex + 1),
|
|
5086
|
+
projectUniforms
|
|
5087
|
+
);
|
|
5088
|
+
phase += vec3_exports.dist(start, end);
|
|
5089
|
+
previousSegment = segmentIndex;
|
|
5090
|
+
previousEnd = end;
|
|
5091
|
+
}
|
|
5092
|
+
if (metricSize > 1) {
|
|
5093
|
+
for (let vertexIndex = rowStart; vertexIndex < rowEnd; vertexIndex++) {
|
|
5094
|
+
output[vertexIndex * metricSize + 1] = phase;
|
|
5095
|
+
}
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
/**
|
|
5100
|
+
* Calculates the distance from the start of a path to each rendered segment.
|
|
5101
|
+
*
|
|
5102
|
+
* The final entry is zero because PathLayer reserves the final vertex as invalid padding.
|
|
5103
|
+
* This scalar return shape is retained for compatibility; path-mode rendering uses an
|
|
5104
|
+
* internal attribute containing both each segment offset and the total path length.
|
|
5105
|
+
*/
|
|
4331
5106
|
getDashOffsets(path) {
|
|
4332
5107
|
const result = [0];
|
|
4333
5108
|
const positionSize = this.props.positionFormat === "XY" ? 2 : 3;
|
|
@@ -4337,7 +5112,7 @@ in float instanceOffsets;
|
|
|
4337
5112
|
let prevP;
|
|
4338
5113
|
for (let i = 0; i < geometrySize - 1; i++) {
|
|
4339
5114
|
p = isNested ? path[i] : path.slice(i * positionSize, i * positionSize + positionSize);
|
|
4340
|
-
p = this.projectPosition(p);
|
|
5115
|
+
p = this.projectPosition(p, { autoOffset: false });
|
|
4341
5116
|
if (i > 0) {
|
|
4342
5117
|
result[i] = result[i - 1] + vec3_exports.dist(prevP, p);
|
|
4343
5118
|
}
|
|
@@ -4355,12 +5130,26 @@ in float instanceOffsets;
|
|
|
4355
5130
|
|
|
4356
5131
|
// src/fill-style/shader-module.ts
|
|
4357
5132
|
var import_core9 = __toESM(require_core(), 1);
|
|
5133
|
+
var FILL_UV_SCALE = 512 / 4e7;
|
|
5134
|
+
function getPatternUnitScale(sizeUnits, viewport) {
|
|
5135
|
+
switch (sizeUnits) {
|
|
5136
|
+
case "pixels":
|
|
5137
|
+
return 2 ** -Math.round(viewport.zoom);
|
|
5138
|
+
case "common":
|
|
5139
|
+
return 1;
|
|
5140
|
+
default:
|
|
5141
|
+
return FILL_UV_SCALE;
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
4358
5144
|
var uniformBlock3 = (
|
|
4359
5145
|
/* glsl */
|
|
4360
5146
|
`layout(std140) uniform fillUniforms {
|
|
4361
5147
|
vec2 patternTextureSize;
|
|
5148
|
+
float patternUnitScale;
|
|
4362
5149
|
bool patternEnabled;
|
|
4363
5150
|
bool patternMask;
|
|
5151
|
+
bool procedural;
|
|
5152
|
+
bool flipY;
|
|
4364
5153
|
vec2 uvCoordinateOrigin;
|
|
4365
5154
|
vec2 uvCoordinateOrigin64Low;
|
|
4366
5155
|
} fill;
|
|
@@ -4369,13 +5158,20 @@ in float instanceOffsets;
|
|
|
4369
5158
|
var patternVs = (
|
|
4370
5159
|
/* glsl */
|
|
4371
5160
|
`
|
|
5161
|
+
uniform sampler2D fill_patternTexture;
|
|
5162
|
+
|
|
4372
5163
|
in vec4 fillPatternFrames;
|
|
4373
5164
|
in float fillPatternScales;
|
|
4374
5165
|
in vec2 fillPatternOffsets;
|
|
5166
|
+
in vec4 fillPatternBackgroundColors;
|
|
4375
5167
|
|
|
4376
5168
|
out vec2 fill_uv;
|
|
4377
5169
|
out vec4 fill_patternBounds;
|
|
4378
5170
|
out vec4 fill_patternPlacement;
|
|
5171
|
+
out vec4 fill_backgroundColor;
|
|
5172
|
+
out float fill_patternCoordinateScale;
|
|
5173
|
+
flat out vec4 fill_patternParams0;
|
|
5174
|
+
flat out vec4 fill_patternParams1;
|
|
4379
5175
|
`
|
|
4380
5176
|
);
|
|
4381
5177
|
var vs3 = `
|
|
@@ -4389,9 +5185,136 @@ uniform sampler2D fill_patternTexture;
|
|
|
4389
5185
|
|
|
4390
5186
|
in vec4 fill_patternBounds;
|
|
4391
5187
|
in vec4 fill_patternPlacement;
|
|
5188
|
+
in vec4 fill_backgroundColor;
|
|
4392
5189
|
in vec2 fill_uv;
|
|
5190
|
+
in float fill_patternCoordinateScale;
|
|
5191
|
+
flat in vec4 fill_patternParams0;
|
|
5192
|
+
flat in vec4 fill_patternParams1;
|
|
5193
|
+
|
|
5194
|
+
const float FILL_PATTERN_HATCH = 1.0;
|
|
5195
|
+
const float FILL_PATTERN_CROSS_HATCH = 2.0;
|
|
5196
|
+
const float FILL_PATTERN_DOTS = 3.0;
|
|
5197
|
+
|
|
5198
|
+
float fill_getPatternCoordinate(vec2 axis, float period, float offset) {
|
|
5199
|
+
float coordinateScale = max(abs(fill_patternCoordinateScale), 1.0e-20);
|
|
5200
|
+
vec2 coordinateOrigin = fill.uvCoordinateOrigin;
|
|
5201
|
+
vec2 coordinateOffset = fill.uvCoordinateOrigin64Low + fill_uv;
|
|
5202
|
+
float yDirection = fill.flipY ? 1.0 : -1.0;
|
|
5203
|
+
coordinateOrigin.y *= yDirection;
|
|
5204
|
+
coordinateOffset.y *= yDirection;
|
|
5205
|
+
|
|
5206
|
+
// Reduce the high part before adding the local offset to retain precision in large coordinates.
|
|
5207
|
+
float highPart = mod(dot(coordinateOrigin, axis) / coordinateScale, period);
|
|
5208
|
+
float lowPart = dot(coordinateOffset, axis) / coordinateScale;
|
|
5209
|
+
return mod(highPart + lowPart + offset * period, period);
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
vec2 fill_getPatternCoords(
|
|
5213
|
+
vec2 axis0,
|
|
5214
|
+
vec2 axis1,
|
|
5215
|
+
vec2 period,
|
|
5216
|
+
vec2 offset
|
|
5217
|
+
) {
|
|
5218
|
+
return vec2(
|
|
5219
|
+
fill_getPatternCoordinate(axis0, period.x, offset.x),
|
|
5220
|
+
fill_getPatternCoordinate(axis1, period.y, offset.y)
|
|
5221
|
+
);
|
|
5222
|
+
}
|
|
5223
|
+
|
|
5224
|
+
float fill_getScreenSpaceAlpha(float signedDistance) {
|
|
5225
|
+
float distanceDerivative = fwidth(signedDistance);
|
|
5226
|
+
if (distanceDerivative == 0.0) {
|
|
5227
|
+
return signedDistance <= 0.0 ? 1.0 : 0.0;
|
|
5228
|
+
}
|
|
5229
|
+
// Normalize the SDF to screen pixels so the coverage ramp is independent of pattern units.
|
|
5230
|
+
float distanceInPixels = signedDistance / distanceDerivative;
|
|
5231
|
+
return 1.0 - smoothstep(-0.5, 0.5, distanceInPixels);
|
|
5232
|
+
}
|
|
5233
|
+
|
|
5234
|
+
float fill_getLineAlpha(float position, float center, float period, float strokeWidth) {
|
|
5235
|
+
float distanceToLine = abs(mod(position - center + period * 0.5, period) - period * 0.5);
|
|
5236
|
+
return fill_getScreenSpaceAlpha(distanceToLine - strokeWidth * 0.5);
|
|
5237
|
+
}
|
|
4393
5238
|
|
|
4394
|
-
|
|
5239
|
+
float fill_getHatchAlpha(float angle, float strokeWidth, vec2 gaps, bool alternating) {
|
|
5240
|
+
vec2 lineDirection = vec2(cos(angle), sin(angle));
|
|
5241
|
+
vec2 lineNormal = vec2(-lineDirection.y, lineDirection.x);
|
|
5242
|
+
float period = alternating
|
|
5243
|
+
? strokeWidth * 2.0 + gaps.x + gaps.y
|
|
5244
|
+
: strokeWidth + gaps.x;
|
|
5245
|
+
float offset = dot(fill_patternPlacement.xy, lineNormal);
|
|
5246
|
+
float position = fill_getPatternCoordinate(lineNormal, period, offset);
|
|
5247
|
+
float alpha = fill_getLineAlpha(position, 0.0, period, strokeWidth);
|
|
5248
|
+
if (alternating) {
|
|
5249
|
+
alpha = max(
|
|
5250
|
+
alpha,
|
|
5251
|
+
fill_getLineAlpha(position, strokeWidth + gaps.x, period, strokeWidth)
|
|
5252
|
+
);
|
|
5253
|
+
}
|
|
5254
|
+
return alpha;
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
float fill_getDotAlpha(float angle, float skew, float radius, float gap) {
|
|
5258
|
+
vec2 axis0 = vec2(cos(angle), sin(angle));
|
|
5259
|
+
float axis1Angle = angle + 1.5707963267948966 - skew;
|
|
5260
|
+
vec2 axis1 = vec2(cos(axis1Angle), sin(axis1Angle));
|
|
5261
|
+
float determinant = axis0.x * axis1.y - axis0.y * axis1.x;
|
|
5262
|
+
|
|
5263
|
+
// The reciprocal basis maps common coordinates into the skewed dot lattice.
|
|
5264
|
+
vec2 reciprocal0 = vec2(axis1.y, -axis1.x) / determinant;
|
|
5265
|
+
vec2 reciprocal1 = vec2(-axis0.y, axis0.x) / determinant;
|
|
5266
|
+
float period = radius * 2.0 + gap;
|
|
5267
|
+
vec2 latticeCoords = fill_getPatternCoords(
|
|
5268
|
+
reciprocal0,
|
|
5269
|
+
reciprocal1,
|
|
5270
|
+
vec2(period),
|
|
5271
|
+
fill_patternPlacement.xy
|
|
5272
|
+
);
|
|
5273
|
+
vec2 cellOffset = mod(latticeCoords + period * 0.5, period) - period * 0.5;
|
|
5274
|
+
float distanceToDotSquared = 1.0e20;
|
|
5275
|
+
// In a skewed lattice the closest dot is not necessarily in the independently wrapped cell.
|
|
5276
|
+
// Include adjacent cells to keep the repeated distance field continuous at cell boundaries.
|
|
5277
|
+
for (int x = -1; x <= 1; x++) {
|
|
5278
|
+
for (int y = -1; y <= 1; y++) {
|
|
5279
|
+
vec2 neighborOffset = cellOffset + vec2(float(x), float(y)) * period;
|
|
5280
|
+
vec2 dotOffset = axis0 * neighborOffset.x + axis1 * neighborOffset.y;
|
|
5281
|
+
distanceToDotSquared = min(distanceToDotSquared, dot(dotOffset, dotOffset));
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
float distanceToDot = sqrt(distanceToDotSquared);
|
|
5285
|
+
return fill_getScreenSpaceAlpha(distanceToDot - radius);
|
|
5286
|
+
}
|
|
5287
|
+
|
|
5288
|
+
float fill_getProceduralPatternAlpha() {
|
|
5289
|
+
float patternType = fill_patternParams0.x;
|
|
5290
|
+
float size = fill_patternParams0.y;
|
|
5291
|
+
vec2 gaps = fill_patternParams0.zw;
|
|
5292
|
+
vec2 angles = fill_patternParams1.xy;
|
|
5293
|
+
float elementCount = fill_patternParams1.z;
|
|
5294
|
+
|
|
5295
|
+
if (patternType == FILL_PATTERN_HATCH) {
|
|
5296
|
+
return fill_getHatchAlpha(angles.x, size, gaps, elementCount == 2.0);
|
|
5297
|
+
}
|
|
5298
|
+
if (patternType == FILL_PATTERN_CROSS_HATCH) {
|
|
5299
|
+
return max(
|
|
5300
|
+
fill_getHatchAlpha(angles.x, size, gaps, false),
|
|
5301
|
+
fill_getHatchAlpha(angles.y, size, gaps, false)
|
|
5302
|
+
);
|
|
5303
|
+
}
|
|
5304
|
+
if (patternType == FILL_PATTERN_DOTS) {
|
|
5305
|
+
return fill_getDotAlpha(angles.x, angles.y, size, gaps.x);
|
|
5306
|
+
}
|
|
5307
|
+
return 1.0;
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
// Draw the pattern over the background fill (Porter-Duff source-over)
|
|
5311
|
+
vec4 fill_blendOverBackground(vec4 pattern, vec4 background) {
|
|
5312
|
+
if (background.a == 0.0 || layer.opacity == 0.0) return pattern;
|
|
5313
|
+
float patternAlpha = pattern.a / layer.opacity;
|
|
5314
|
+
float blendedAlpha = patternAlpha + background.a * (1.0 - patternAlpha);
|
|
5315
|
+
vec3 blendedRGB = mix(background.rgb, pattern.rgb, patternAlpha / blendedAlpha);
|
|
5316
|
+
return vec4(blendedRGB, blendedAlpha * layer.opacity);
|
|
5317
|
+
}
|
|
4395
5318
|
`
|
|
4396
5319
|
);
|
|
4397
5320
|
var fs3 = `
|
|
@@ -4402,16 +5325,32 @@ ${patternFs}
|
|
|
4402
5325
|
"vs:DECKGL_FILTER_GL_POSITION": (
|
|
4403
5326
|
/* glsl */
|
|
4404
5327
|
`
|
|
4405
|
-
fill_uv = geometry.position.xy;
|
|
4406
|
-
`
|
|
4407
|
-
),
|
|
4408
|
-
"vs:DECKGL_FILTER_COLOR": (
|
|
4409
|
-
/* glsl */
|
|
4410
|
-
`
|
|
4411
5328
|
if (fill.patternEnabled) {
|
|
4412
|
-
fill_patternBounds = fillPatternFrames / vec4(fill.patternTextureSize, fill.patternTextureSize);
|
|
4413
5329
|
fill_patternPlacement.xy = fillPatternOffsets;
|
|
4414
|
-
|
|
5330
|
+
fill_backgroundColor = fillPatternBackgroundColors;
|
|
5331
|
+
if (fill.procedural) {
|
|
5332
|
+
fill_uv = geometry.position.xy;
|
|
5333
|
+
fill_patternCoordinateScale = fill.patternUnitScale * fillPatternScales;
|
|
5334
|
+
int texelIndex = int(fillPatternFrames.x) * 4;
|
|
5335
|
+
fill_patternParams0 = vec4(
|
|
5336
|
+
texelFetch(fill_patternTexture, ivec2(texelIndex, 0), 0).rg,
|
|
5337
|
+
texelFetch(fill_patternTexture, ivec2(texelIndex + 1, 0), 0).rg
|
|
5338
|
+
);
|
|
5339
|
+
fill_patternParams1 = vec4(
|
|
5340
|
+
texelFetch(fill_patternTexture, ivec2(texelIndex + 2, 0), 0).rg,
|
|
5341
|
+
texelFetch(fill_patternTexture, ivec2(texelIndex + 3, 0), 0).rg
|
|
5342
|
+
);
|
|
5343
|
+
} else {
|
|
5344
|
+
fill_patternBounds = fillPatternFrames / vec4(fill.patternTextureSize, fill.patternTextureSize);
|
|
5345
|
+
vec2 patternFrameCommon = fill.patternUnitScale * fillPatternScales * fillPatternFrames.zw;
|
|
5346
|
+
// Reduce the coordinate origin to within one tile before adding the vertex position. The
|
|
5347
|
+
// origin is large in common space, and fp32 cannot carry the sum at full precision.
|
|
5348
|
+
vec2 origin = mod(fill.uvCoordinateOrigin, patternFrameCommon) + fill.uvCoordinateOrigin64Low;
|
|
5349
|
+
fill_uv = (origin + geometry.position.xy) / patternFrameCommon;
|
|
5350
|
+
// Pattern atlases use top-left coordinates, so reverse common-space Y in bottom-left views.
|
|
5351
|
+
fill_uv.y *= fill.flipY ? 1.0 : -1.0;
|
|
5352
|
+
fill_uv += fillPatternOffsets;
|
|
5353
|
+
}
|
|
4415
5354
|
}
|
|
4416
5355
|
`
|
|
4417
5356
|
),
|
|
@@ -4419,17 +5358,25 @@ ${patternFs}
|
|
|
4419
5358
|
/* glsl */
|
|
4420
5359
|
`
|
|
4421
5360
|
if (fill.patternEnabled) {
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
5361
|
+
if (fill.procedural) {
|
|
5362
|
+
color.a *= fill_getProceduralPatternAlpha();
|
|
5363
|
+
} else {
|
|
5364
|
+
vec2 patternUV = fract(fill_uv);
|
|
5365
|
+
vec2 texCoords = fill_patternBounds.xy + fill_patternBounds.zw * patternUV;
|
|
5366
|
+
|
|
5367
|
+
// Tiling is emulated by wrapping the coordinate, so texCoords jumps from the end of the
|
|
5368
|
+
// frame back to its start once per tile, leading to the wrong mip level being selected,
|
|
5369
|
+
// which leads to artifacts at pattern edges. fill_uv is continuous across the primitive,
|
|
5370
|
+
// meaning that the correct mip level is always selected
|
|
5371
|
+
vec4 grad = fill_patternBounds.zwzw * vec4(dFdx(fill_uv), dFdy(fill_uv));
|
|
5372
|
+
vec4 patternColor = textureGrad(fill_patternTexture, texCoords, grad.xy, grad.zw);
|
|
5373
|
+
|
|
5374
|
+
color.a *= patternColor.a;
|
|
5375
|
+
if (!fill.patternMask) {
|
|
5376
|
+
color.rgb = patternColor.rgb;
|
|
5377
|
+
}
|
|
4432
5378
|
}
|
|
5379
|
+
color = fill_blendOverBackground(color, fill_backgroundColor);
|
|
4433
5380
|
}
|
|
4434
5381
|
`
|
|
4435
5382
|
)
|
|
@@ -4445,17 +5392,28 @@ ${patternFs}
|
|
|
4445
5392
|
uniforms.patternTextureSize = [fillPatternTexture.width, fillPatternTexture.height];
|
|
4446
5393
|
}
|
|
4447
5394
|
if ("project" in opts) {
|
|
4448
|
-
const {
|
|
5395
|
+
const {
|
|
5396
|
+
fillPatternMask = true,
|
|
5397
|
+
fillPatternEnabled = true,
|
|
5398
|
+
fillPatternSizeUnits = "meters",
|
|
5399
|
+
fillPatternCommonFrame = null,
|
|
5400
|
+
procedural = false
|
|
5401
|
+
} = opts;
|
|
4449
5402
|
const projectUniforms = import_core9.project.getUniforms(opts.project);
|
|
4450
5403
|
const { commonOrigin: coordinateOriginCommon } = projectUniforms;
|
|
4451
|
-
const
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
5404
|
+
const unitScale = getPatternUnitScale(fillPatternSizeUnits, opts.project.viewport);
|
|
5405
|
+
const origin = [coordinateOriginCommon[0], coordinateOriginCommon[1]];
|
|
5406
|
+
if (fillPatternCommonFrame) {
|
|
5407
|
+
origin[0] %= unitScale * fillPatternCommonFrame[0];
|
|
5408
|
+
origin[1] %= unitScale * fillPatternCommonFrame[1];
|
|
5409
|
+
}
|
|
5410
|
+
uniforms.uvCoordinateOrigin = origin;
|
|
5411
|
+
uniforms.uvCoordinateOrigin64Low = [(0, import_core9.fp64LowPart)(origin[0]), (0, import_core9.fp64LowPart)(origin[1])];
|
|
5412
|
+
uniforms.patternUnitScale = unitScale;
|
|
4457
5413
|
uniforms.patternMask = fillPatternMask;
|
|
4458
5414
|
uniforms.patternEnabled = fillPatternEnabled;
|
|
5415
|
+
uniforms.procedural = procedural;
|
|
5416
|
+
uniforms.flipY = opts.project.viewport?.flipY ?? false;
|
|
4459
5417
|
}
|
|
4460
5418
|
return uniforms;
|
|
4461
5419
|
}
|
|
@@ -4468,31 +5426,172 @@ ${patternFs}
|
|
|
4468
5426
|
getUniforms: getPatternUniforms,
|
|
4469
5427
|
uniformTypes: {
|
|
4470
5428
|
patternTextureSize: "vec2<f32>",
|
|
5429
|
+
patternUnitScale: "f32",
|
|
4471
5430
|
patternEnabled: "i32",
|
|
4472
5431
|
patternMask: "i32",
|
|
5432
|
+
procedural: "i32",
|
|
5433
|
+
flipY: "i32",
|
|
4473
5434
|
uvCoordinateOrigin: "vec2<f32>",
|
|
4474
5435
|
uvCoordinateOrigin64Low: "vec2<f32>"
|
|
4475
5436
|
}
|
|
4476
5437
|
};
|
|
4477
5438
|
|
|
5439
|
+
// src/fill-style/procedural-pattern.ts
|
|
5440
|
+
var PROCEDURAL_PATTERN_TEXTURE_FORMAT = "rg32float";
|
|
5441
|
+
var PROCEDURAL_PATTERN_COMPONENTS_PER_TEXEL = 2;
|
|
5442
|
+
var PROCEDURAL_PATTERN_TEXELS_PER_PATTERN = 4;
|
|
5443
|
+
var PROCEDURAL_PATTERN_TYPES = {
|
|
5444
|
+
none: 0,
|
|
5445
|
+
hatch: 1,
|
|
5446
|
+
crossHatch: 2,
|
|
5447
|
+
dots: 3
|
|
5448
|
+
};
|
|
5449
|
+
var PROCEDURAL_PATTERN_OFFSETS = {
|
|
5450
|
+
type: 0,
|
|
5451
|
+
size: 1,
|
|
5452
|
+
gap0: 2,
|
|
5453
|
+
gap1: 3,
|
|
5454
|
+
angle0: 4,
|
|
5455
|
+
angle1: 5,
|
|
5456
|
+
/** Number of alternating gaps, hatch directions, or dot-grid axes, depending on type. */
|
|
5457
|
+
elementCount: 6
|
|
5458
|
+
};
|
|
5459
|
+
var COMPONENTS_PER_PATTERN = PROCEDURAL_PATTERN_COMPONENTS_PER_TEXEL * PROCEDURAL_PATTERN_TEXELS_PER_PATTERN;
|
|
5460
|
+
var DEGREES_TO_RADIANS2 = Math.PI / 180;
|
|
5461
|
+
var DEFAULT_SIZE = 1;
|
|
5462
|
+
var DEFAULT_GAP = 1;
|
|
5463
|
+
var DEFAULT_HATCH_ANGLE = 0;
|
|
5464
|
+
var DEFAULT_CROSS_HATCH_ANGLES = [45, 135];
|
|
5465
|
+
var DEFAULT_DOT_ANGLE = 0;
|
|
5466
|
+
var DEFAULT_DOT_SKEW = 0;
|
|
5467
|
+
function packProceduralPatterns(mapping) {
|
|
5468
|
+
const entries = Object.entries(mapping);
|
|
5469
|
+
const data = new Float32Array((entries.length + 1) * COMPONENTS_PER_PATTERN);
|
|
5470
|
+
const patternIndices = /* @__PURE__ */ new Map();
|
|
5471
|
+
entries.forEach(([id, config2], entryIndex) => {
|
|
5472
|
+
const patternIndex = entryIndex + 1;
|
|
5473
|
+
const offset = patternIndex * COMPONENTS_PER_PATTERN;
|
|
5474
|
+
patternIndices.set(id, patternIndex);
|
|
5475
|
+
switch (config2.type) {
|
|
5476
|
+
case "hatch": {
|
|
5477
|
+
const gap = config2.gap === void 0 ? DEFAULT_GAP : config2.gap;
|
|
5478
|
+
const strokeWidth = config2.strokeWidth === void 0 ? DEFAULT_SIZE : config2.strokeWidth;
|
|
5479
|
+
const angle2 = config2.angle === void 0 ? DEFAULT_HATCH_ANGLE : config2.angle;
|
|
5480
|
+
if (Array.isArray(gap) && gap.length !== 2) {
|
|
5481
|
+
throw new Error(`${id}.gap must be a number or a two-element array`);
|
|
5482
|
+
}
|
|
5483
|
+
const gaps = Array.isArray(gap) ? gap : [gap, gap];
|
|
5484
|
+
validatePositive(strokeWidth, `${id}.strokeWidth`);
|
|
5485
|
+
validateNonNegative(gaps[0], `${id}.gap[0]`);
|
|
5486
|
+
validateNonNegative(gaps[1], `${id}.gap[1]`);
|
|
5487
|
+
validateAngle(angle2, `${id}.angle`);
|
|
5488
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.type] = PROCEDURAL_PATTERN_TYPES.hatch;
|
|
5489
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.size] = strokeWidth;
|
|
5490
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap0] = gaps[0];
|
|
5491
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap1] = gaps[1];
|
|
5492
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.angle0] = angle2 * DEGREES_TO_RADIANS2;
|
|
5493
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.elementCount] = Array.isArray(gap) ? 2 : 1;
|
|
5494
|
+
break;
|
|
5495
|
+
}
|
|
5496
|
+
case "cross-hatch": {
|
|
5497
|
+
const angles = config2.angles === void 0 ? DEFAULT_CROSS_HATCH_ANGLES : config2.angles;
|
|
5498
|
+
const strokeWidth = config2.strokeWidth === void 0 ? DEFAULT_SIZE : config2.strokeWidth;
|
|
5499
|
+
const gap = config2.gap === void 0 ? DEFAULT_GAP : config2.gap;
|
|
5500
|
+
if (!Array.isArray(angles) || angles.length !== 2) {
|
|
5501
|
+
throw new Error(`${id}.angles must be a two-element array`);
|
|
5502
|
+
}
|
|
5503
|
+
validatePositive(strokeWidth, `${id}.strokeWidth`);
|
|
5504
|
+
validateNonNegative(gap, `${id}.gap`);
|
|
5505
|
+
validateAngle(angles[0], `${id}.angles[0]`);
|
|
5506
|
+
validateAngle(angles[1], `${id}.angles[1]`);
|
|
5507
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.type] = PROCEDURAL_PATTERN_TYPES.crossHatch;
|
|
5508
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.size] = strokeWidth;
|
|
5509
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap0] = gap;
|
|
5510
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap1] = gap;
|
|
5511
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.angle0] = angles[0] * DEGREES_TO_RADIANS2;
|
|
5512
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.angle1] = angles[1] * DEGREES_TO_RADIANS2;
|
|
5513
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.elementCount] = 2;
|
|
5514
|
+
break;
|
|
5515
|
+
}
|
|
5516
|
+
case "dots": {
|
|
5517
|
+
const radius = config2.radius === void 0 ? DEFAULT_SIZE : config2.radius;
|
|
5518
|
+
const gap = config2.gap === void 0 ? DEFAULT_GAP : config2.gap;
|
|
5519
|
+
const angle2 = config2.angle === void 0 ? DEFAULT_DOT_ANGLE : config2.angle;
|
|
5520
|
+
const skew = config2.skew === void 0 ? DEFAULT_DOT_SKEW : config2.skew;
|
|
5521
|
+
validatePositive(radius, `${id}.radius`);
|
|
5522
|
+
validateNonNegative(gap, `${id}.gap`);
|
|
5523
|
+
validateAngle(angle2, `${id}.angle`);
|
|
5524
|
+
validateSkew(skew, `${id}.skew`);
|
|
5525
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.type] = PROCEDURAL_PATTERN_TYPES.dots;
|
|
5526
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.size] = radius;
|
|
5527
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap0] = gap;
|
|
5528
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.gap1] = gap;
|
|
5529
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.angle0] = angle2 * DEGREES_TO_RADIANS2;
|
|
5530
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.angle1] = skew * DEGREES_TO_RADIANS2;
|
|
5531
|
+
data[offset + PROCEDURAL_PATTERN_OFFSETS.elementCount] = 2;
|
|
5532
|
+
break;
|
|
5533
|
+
}
|
|
5534
|
+
default:
|
|
5535
|
+
throw new Error(`${id}.type is not a supported procedural pattern type`);
|
|
5536
|
+
}
|
|
5537
|
+
});
|
|
5538
|
+
return {
|
|
5539
|
+
data,
|
|
5540
|
+
width: data.length / PROCEDURAL_PATTERN_COMPONENTS_PER_TEXEL,
|
|
5541
|
+
height: 1,
|
|
5542
|
+
patternIndices
|
|
5543
|
+
};
|
|
5544
|
+
}
|
|
5545
|
+
function validatePositive(value, name) {
|
|
5546
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
5547
|
+
throw new Error(`${name} must be a finite number greater than 0`);
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
function validateNonNegative(value, name) {
|
|
5551
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
5552
|
+
throw new Error(`${name} must be a finite number greater than or equal to 0`);
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
function validateAngle(value, name) {
|
|
5556
|
+
if (!Number.isFinite(value)) {
|
|
5557
|
+
throw new Error(`${name} must be a finite number`);
|
|
5558
|
+
}
|
|
5559
|
+
}
|
|
5560
|
+
function validateSkew(value, name) {
|
|
5561
|
+
if (!Number.isFinite(value) || value <= -90 || value >= 90) {
|
|
5562
|
+
throw new Error(`${name} must be a finite number greater than -90 and less than 90`);
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
|
|
4478
5566
|
// src/fill-style/fill-style-extension.ts
|
|
5567
|
+
function leastCommonMultiple(a, b) {
|
|
5568
|
+
if (!Number.isInteger(b) || b <= 0) return 0;
|
|
5569
|
+
if (a === 0) return b;
|
|
5570
|
+
let [x, y] = [a, b];
|
|
5571
|
+
while (y > 0) [x, y] = [y, x % y];
|
|
5572
|
+
return a / x * b;
|
|
5573
|
+
}
|
|
4479
5574
|
var defaultProps4 = {
|
|
4480
5575
|
fillPatternEnabled: true,
|
|
4481
5576
|
fillPatternAtlas: {
|
|
4482
5577
|
type: "image",
|
|
4483
5578
|
value: null,
|
|
4484
|
-
async: true
|
|
4485
|
-
parameters: { lodMaxClamp: 0 }
|
|
5579
|
+
async: true
|
|
4486
5580
|
},
|
|
4487
5581
|
fillPatternMapping: { type: "object", value: {}, async: true },
|
|
4488
5582
|
fillPatternMask: true,
|
|
5583
|
+
fillPatternSizeUnits: "meters",
|
|
4489
5584
|
getFillPattern: { type: "accessor", value: (d) => d.pattern },
|
|
4490
5585
|
getFillPatternScale: { type: "accessor", value: 1 },
|
|
4491
|
-
getFillPatternOffset: { type: "accessor", value: [0, 0] }
|
|
5586
|
+
getFillPatternOffset: { type: "accessor", value: [0, 0] },
|
|
5587
|
+
getFillPatternBackgroundColor: { type: "accessor", value: [0, 0, 0, 0] }
|
|
4492
5588
|
};
|
|
4493
5589
|
var FillStyleExtension = class extends import_core10.LayerExtension {
|
|
4494
|
-
constructor({
|
|
4495
|
-
|
|
5590
|
+
constructor({
|
|
5591
|
+
pattern = false,
|
|
5592
|
+
proceduralPattern = false
|
|
5593
|
+
} = {}) {
|
|
5594
|
+
super({ pattern: pattern || proceduralPattern, proceduralPattern });
|
|
4496
5595
|
}
|
|
4497
5596
|
isEnabled(layer) {
|
|
4498
5597
|
return layer.getAttributeManager() !== null && !("pathTesselator" in layer.state);
|
|
@@ -4516,7 +5615,7 @@ ${patternFs}
|
|
|
4516
5615
|
size: 4,
|
|
4517
5616
|
stepMode: "dynamic",
|
|
4518
5617
|
accessor: "getFillPattern",
|
|
4519
|
-
transform: extension.getPatternFrame.bind(this)
|
|
5618
|
+
transform: extension.opts.proceduralPattern ? extension.getProceduralPatternIndex.bind(this) : extension.getPatternFrame.bind(this)
|
|
4520
5619
|
},
|
|
4521
5620
|
fillPatternScales: {
|
|
4522
5621
|
size: 1,
|
|
@@ -4528,6 +5627,13 @@ ${patternFs}
|
|
|
4528
5627
|
size: 2,
|
|
4529
5628
|
stepMode: "dynamic",
|
|
4530
5629
|
accessor: "getFillPatternOffset"
|
|
5630
|
+
},
|
|
5631
|
+
fillPatternBackgroundColors: {
|
|
5632
|
+
size: 4,
|
|
5633
|
+
type: "unorm8",
|
|
5634
|
+
stepMode: "dynamic",
|
|
5635
|
+
accessor: "getFillPatternBackgroundColor",
|
|
5636
|
+
defaultValue: [0, 0, 0, 255]
|
|
4531
5637
|
}
|
|
4532
5638
|
});
|
|
4533
5639
|
}
|
|
@@ -4536,7 +5642,8 @@ ${patternFs}
|
|
|
4536
5642
|
data: new Uint8Array(4),
|
|
4537
5643
|
width: 1,
|
|
4538
5644
|
height: 1
|
|
4539
|
-
})
|
|
5645
|
+
}),
|
|
5646
|
+
...extension.opts.proceduralPattern && extension.createProceduralPatternTexture.call(this, {})
|
|
4540
5647
|
});
|
|
4541
5648
|
}
|
|
4542
5649
|
updateState({ props, oldProps }, extension) {
|
|
@@ -4544,30 +5651,84 @@ ${patternFs}
|
|
|
4544
5651
|
return;
|
|
4545
5652
|
}
|
|
4546
5653
|
if (props.fillPatternMapping && props.fillPatternMapping !== oldProps.fillPatternMapping) {
|
|
5654
|
+
if (extension.opts.proceduralPattern && typeof props.fillPatternMapping !== "string") {
|
|
5655
|
+
const oldTexture = this.state.proceduralPatternTexture;
|
|
5656
|
+
this.setState(
|
|
5657
|
+
extension.createProceduralPatternTexture.call(
|
|
5658
|
+
this,
|
|
5659
|
+
props.fillPatternMapping
|
|
5660
|
+
)
|
|
5661
|
+
);
|
|
5662
|
+
oldTexture?.delete();
|
|
5663
|
+
}
|
|
4547
5664
|
this.getAttributeManager().invalidate("getFillPattern");
|
|
4548
5665
|
}
|
|
5666
|
+
if (props.fillPatternMapping !== oldProps.fillPatternMapping || props.getFillPatternScale !== oldProps.getFillPatternScale) {
|
|
5667
|
+
this.setState({ commonFrame: extension.getCommonFrame(props) });
|
|
5668
|
+
}
|
|
4549
5669
|
}
|
|
4550
5670
|
draw(params, extension) {
|
|
4551
5671
|
if (!extension.isEnabled(this)) {
|
|
4552
5672
|
return;
|
|
4553
5673
|
}
|
|
4554
|
-
const { fillPatternAtlas, fillPatternEnabled, fillPatternMask } = this.props;
|
|
5674
|
+
const { fillPatternAtlas, fillPatternEnabled, fillPatternMask, fillPatternSizeUnits } = this.props;
|
|
4555
5675
|
const fillProps = {
|
|
4556
5676
|
project: params.shaderModuleProps.project,
|
|
4557
5677
|
fillPatternEnabled,
|
|
4558
5678
|
fillPatternMask,
|
|
4559
|
-
|
|
5679
|
+
fillPatternSizeUnits,
|
|
5680
|
+
procedural: extension.opts.proceduralPattern,
|
|
5681
|
+
fillPatternTexture: extension.opts.proceduralPattern ? this.state.proceduralPatternTexture || this.state.emptyTexture : fillPatternAtlas || this.state.emptyTexture,
|
|
5682
|
+
fillPatternCommonFrame: this.state.commonFrame
|
|
4560
5683
|
};
|
|
4561
5684
|
this.setShaderModuleProps({ fill: fillProps });
|
|
4562
5685
|
}
|
|
4563
5686
|
finalizeState() {
|
|
4564
5687
|
const emptyTexture = this.state.emptyTexture;
|
|
4565
5688
|
emptyTexture?.delete();
|
|
5689
|
+
const proceduralPatternTexture = this.state.proceduralPatternTexture;
|
|
5690
|
+
proceduralPatternTexture?.delete();
|
|
4566
5691
|
}
|
|
4567
5692
|
getPatternFrame(name) {
|
|
4568
5693
|
const { fillPatternMapping } = this.getCurrentLayer().props;
|
|
4569
5694
|
const def = fillPatternMapping && fillPatternMapping[name];
|
|
4570
|
-
return def ? [def.x, def.y, def.width, def.height] : [0, 0, 0, 0];
|
|
5695
|
+
return def && "x" in def ? [def.x, def.y, def.width, def.height] : [0, 0, 0, 0];
|
|
5696
|
+
}
|
|
5697
|
+
/**
|
|
5698
|
+
* Returns common frame into which all patterns fit as integer multiples
|
|
5699
|
+
*/
|
|
5700
|
+
getCommonFrame(props) {
|
|
5701
|
+
const { fillPatternMapping, getFillPatternScale: scale3 } = props;
|
|
5702
|
+
if (typeof scale3 !== "number" || !(scale3 > 0) || typeof fillPatternMapping !== "object") {
|
|
5703
|
+
return null;
|
|
5704
|
+
}
|
|
5705
|
+
let width = 0;
|
|
5706
|
+
let height = 0;
|
|
5707
|
+
for (const name in fillPatternMapping) {
|
|
5708
|
+
const frame = fillPatternMapping[name];
|
|
5709
|
+
if (!("width" in frame)) return null;
|
|
5710
|
+
width = leastCommonMultiple(width, frame.width);
|
|
5711
|
+
height = leastCommonMultiple(height, frame.height);
|
|
5712
|
+
if (!width || !height) return null;
|
|
5713
|
+
}
|
|
5714
|
+
return width ? [scale3 * width, scale3 * height] : null;
|
|
5715
|
+
}
|
|
5716
|
+
getProceduralPatternIndex(name) {
|
|
5717
|
+
const patternIndices = this.state.proceduralPatternIndices;
|
|
5718
|
+
return [patternIndices?.get(name) ?? 0, 0, 0, 0];
|
|
5719
|
+
}
|
|
5720
|
+
createProceduralPatternTexture(mapping) {
|
|
5721
|
+
const packedPatterns = packProceduralPatterns(mapping);
|
|
5722
|
+
return {
|
|
5723
|
+
proceduralPatternIndices: packedPatterns.patternIndices,
|
|
5724
|
+
proceduralPatternTexture: this.context.device.createTexture({
|
|
5725
|
+
data: packedPatterns.data,
|
|
5726
|
+
width: packedPatterns.width,
|
|
5727
|
+
height: packedPatterns.height,
|
|
5728
|
+
format: PROCEDURAL_PATTERN_TEXTURE_FORMAT,
|
|
5729
|
+
sampler: { minFilter: "nearest", magFilter: "nearest" }
|
|
5730
|
+
})
|
|
5731
|
+
};
|
|
4571
5732
|
}
|
|
4572
5733
|
};
|
|
4573
5734
|
FillStyleExtension.defaultProps = defaultProps4;
|
|
@@ -5320,12 +6481,12 @@ in vec2 mask_texCoords;
|
|
|
5320
6481
|
if (zoom === void 0) {
|
|
5321
6482
|
width = width - border * 2;
|
|
5322
6483
|
height = height - border * 2;
|
|
5323
|
-
const
|
|
5324
|
-
zoom = Math.min(Math.log2(
|
|
6484
|
+
const scale3 = Math.min(width / (bounds[2] - bounds[0]), height / (bounds[3] - bounds[1]));
|
|
6485
|
+
zoom = Math.min(Math.log2(scale3), 20);
|
|
5325
6486
|
} else if (!width || !height) {
|
|
5326
|
-
const
|
|
5327
|
-
width = Math.round(Math.abs(bounds[2] - bounds[0]) *
|
|
5328
|
-
height = Math.round(Math.abs(bounds[3] - bounds[1]) *
|
|
6487
|
+
const scale3 = 2 ** zoom;
|
|
6488
|
+
width = Math.round(Math.abs(bounds[2] - bounds[0]) * scale3);
|
|
6489
|
+
height = Math.round(Math.abs(bounds[3] - bounds[1]) * scale3);
|
|
5329
6490
|
const maxSize = MAX_VIEWPORT_SIZE - border * 2;
|
|
5330
6491
|
if (width > maxSize || height > maxSize) {
|
|
5331
6492
|
const r = maxSize / Math.max(width, height);
|
|
@@ -6915,9 +8076,9 @@ if ((terrain.mode == TERRAIN_MODE_USE_COVER) || (terrain.mode == TERRAIN_MODE_US
|
|
|
6915
8076
|
}
|
|
6916
8077
|
this.bounds = bounds;
|
|
6917
8078
|
this.lastViewport = viewport;
|
|
6918
|
-
const
|
|
6919
|
-
const pixelWidth = (bounds[2] - bounds[0]) *
|
|
6920
|
-
const pixelHeight = (bounds[3] - bounds[1]) *
|
|
8079
|
+
const scale3 = viewport.scale;
|
|
8080
|
+
const pixelWidth = (bounds[2] - bounds[0]) * scale3;
|
|
8081
|
+
const pixelHeight = (bounds[3] - bounds[1]) * scale3;
|
|
6921
8082
|
const centerMerc = viewport.isGeospatial ? lngLatToMercatorCommon([
|
|
6922
8083
|
viewport.longitude ?? 0,
|
|
6923
8084
|
viewport.latitude ?? 0
|