@luma.gl/engine 9.2.6 → 9.3.0-alpha.4
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/animation-loop/animation-loop.d.ts +3 -1
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +10 -4
- package/dist/animation-loop/animation-loop.js.map +1 -1
- package/dist/compute/computation.d.ts.map +1 -1
- package/dist/compute/computation.js +3 -2
- package/dist/compute/computation.js.map +1 -1
- package/dist/compute/swap.d.ts +2 -0
- package/dist/compute/swap.d.ts.map +1 -1
- package/dist/compute/swap.js +10 -5
- package/dist/compute/swap.js.map +1 -1
- package/dist/dist.dev.js +1251 -574
- package/dist/dist.min.js +216 -48
- package/dist/dynamic-texture/dynamic-texture.d.ts +95 -0
- package/dist/dynamic-texture/dynamic-texture.d.ts.map +1 -0
- package/dist/dynamic-texture/dynamic-texture.js +389 -0
- package/dist/dynamic-texture/dynamic-texture.js.map +1 -0
- package/dist/dynamic-texture/mipmaps.d.ts +6 -0
- package/dist/dynamic-texture/mipmaps.d.ts.map +1 -0
- package/dist/dynamic-texture/mipmaps.js +441 -0
- package/dist/dynamic-texture/mipmaps.js.map +1 -0
- package/dist/dynamic-texture/texture-data.d.ts +137 -0
- package/dist/dynamic-texture/texture-data.d.ts.map +1 -0
- package/dist/dynamic-texture/texture-data.js +183 -0
- package/dist/dynamic-texture/texture-data.js.map +1 -0
- package/dist/factories/pipeline-factory.d.ts.map +1 -1
- package/dist/factories/pipeline-factory.js +3 -3
- package/dist/factories/pipeline-factory.js.map +1 -1
- package/dist/factories/shader-factory.d.ts.map +1 -1
- package/dist/factories/shader-factory.js +3 -2
- package/dist/factories/shader-factory.js.map +1 -1
- package/dist/index.cjs +1243 -583
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/model/model.d.ts +31 -10
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +34 -14
- package/dist/model/model.js.map +1 -1
- package/dist/models/billboard-texture-model.d.ts +8 -5
- package/dist/models/billboard-texture-model.d.ts.map +1 -1
- package/dist/models/billboard-texture-model.js +70 -18
- package/dist/models/billboard-texture-model.js.map +1 -1
- package/dist/passes/get-fragment-shader.js +15 -11
- package/dist/passes/get-fragment-shader.js.map +1 -1
- package/dist/passes/shader-pass-renderer.d.ts +5 -5
- package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
- package/dist/passes/shader-pass-renderer.js +13 -12
- package/dist/passes/shader-pass-renderer.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/buffer-layout-order.d.ts.map +1 -1
- package/dist/utils/buffer-layout-order.js +12 -2
- package/dist/utils/buffer-layout-order.js.map +1 -1
- package/package.json +6 -6
- package/src/animation-loop/animation-loop.ts +11 -4
- package/src/compute/computation.ts +3 -2
- package/src/compute/swap.ts +13 -7
- package/src/dynamic-texture/dynamic-texture.ts +499 -0
- package/src/dynamic-texture/mipmaps.ts +517 -0
- package/src/dynamic-texture/texture-data.ts +301 -0
- package/src/factories/pipeline-factory.ts +4 -3
- package/src/factories/shader-factory.ts +4 -2
- package/src/index.ts +9 -4
- package/src/model/model.ts +37 -18
- package/src/models/billboard-texture-model.ts +81 -22
- package/src/passes/get-fragment-shader.ts +15 -11
- package/src/passes/shader-pass-renderer.ts +22 -16
- package/src/types.ts +11 -0
- package/src/utils/buffer-layout-order.ts +18 -2
- package/dist/async-texture/async-texture.d.ts +0 -166
- package/dist/async-texture/async-texture.d.ts.map +0 -1
- package/dist/async-texture/async-texture.js +0 -386
- package/dist/async-texture/async-texture.js.map +0 -1
- package/src/async-texture/async-texture.ts +0 -551
- /package/src/{async-texture/texture-setters.ts.disabled → dynamic-texture/texture-data.ts.disabled} +0 -0
package/dist/dist.dev.js
CHANGED
|
@@ -70,6 +70,7 @@ var __exports__ = (() => {
|
|
|
70
70
|
ConeGeometry: () => ConeGeometry,
|
|
71
71
|
CubeGeometry: () => CubeGeometry,
|
|
72
72
|
CylinderGeometry: () => CylinderGeometry,
|
|
73
|
+
DynamicTexture: () => DynamicTexture,
|
|
73
74
|
GPUGeometry: () => GPUGeometry,
|
|
74
75
|
Geometry: () => Geometry,
|
|
75
76
|
GroupNode: () => GroupNode,
|
|
@@ -492,7 +493,7 @@ var __exports__ = (() => {
|
|
|
492
493
|
gpuTime;
|
|
493
494
|
frameRate;
|
|
494
495
|
display;
|
|
495
|
-
|
|
496
|
+
_needsRedraw = "initialized";
|
|
496
497
|
_initialized = false;
|
|
497
498
|
_running = false;
|
|
498
499
|
_animationFrameId = null;
|
|
@@ -534,9 +535,15 @@ var __exports__ = (() => {
|
|
|
534
535
|
}
|
|
535
536
|
/** Flags this animation loop as needing redraw */
|
|
536
537
|
setNeedsRedraw(reason) {
|
|
537
|
-
this.
|
|
538
|
+
this._needsRedraw = this._needsRedraw || reason;
|
|
538
539
|
return this;
|
|
539
540
|
}
|
|
541
|
+
/** Query redraw status. Clears the flag. */
|
|
542
|
+
needsRedraw() {
|
|
543
|
+
const reason = this._needsRedraw;
|
|
544
|
+
this._needsRedraw = false;
|
|
545
|
+
return reason;
|
|
546
|
+
}
|
|
540
547
|
setProps(props) {
|
|
541
548
|
if ("autoResizeViewport" in props) {
|
|
542
549
|
this.props.autoResizeViewport = props.autoResizeViewport || false;
|
|
@@ -678,7 +685,7 @@ var __exports__ = (() => {
|
|
|
678
685
|
this.device?.submit();
|
|
679
686
|
}
|
|
680
687
|
_clearNeedsRedraw() {
|
|
681
|
-
this.
|
|
688
|
+
this._needsRedraw = false;
|
|
682
689
|
}
|
|
683
690
|
_setupFrame() {
|
|
684
691
|
this._resizeViewport();
|
|
@@ -736,7 +743,7 @@ var __exports__ = (() => {
|
|
|
736
743
|
this.animationProps.width = width;
|
|
737
744
|
this.animationProps.height = height;
|
|
738
745
|
this.animationProps.aspect = aspect;
|
|
739
|
-
this.animationProps.needsRedraw = this.
|
|
746
|
+
this.animationProps.needsRedraw = this._needsRedraw;
|
|
740
747
|
this.animationProps.engineTime = Date.now() - this.animationProps.startTime;
|
|
741
748
|
if (this.timeline) {
|
|
742
749
|
this.timeline.update(this.animationProps.engineTime);
|
|
@@ -892,8 +899,8 @@ var __exports__ = (() => {
|
|
|
892
899
|
}
|
|
893
900
|
|
|
894
901
|
// src/model/model.ts
|
|
895
|
-
var
|
|
896
|
-
var
|
|
902
|
+
var import_core12 = __toESM(require_core(), 1);
|
|
903
|
+
var import_shadertools3 = __toESM(require_shadertools(), 1);
|
|
897
904
|
|
|
898
905
|
// src/geometry/gpu-geometry.ts
|
|
899
906
|
var import_core3 = __toESM(require_core(), 1);
|
|
@@ -1007,8 +1014,9 @@ var __exports__ = (() => {
|
|
|
1007
1014
|
var _PipelineFactory = class {
|
|
1008
1015
|
/** Get the singleton default pipeline factory for the specified device */
|
|
1009
1016
|
static getDefaultPipelineFactory(device) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1017
|
+
const moduleData = device.getModuleData("@luma.gl/engine");
|
|
1018
|
+
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
1019
|
+
return moduleData.defaultPipelineFactory;
|
|
1012
1020
|
}
|
|
1013
1021
|
device;
|
|
1014
1022
|
cachingEnabled;
|
|
@@ -1177,8 +1185,9 @@ var __exports__ = (() => {
|
|
|
1177
1185
|
var _ShaderFactory = class {
|
|
1178
1186
|
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
1179
1187
|
static getDefaultShaderFactory(device) {
|
|
1180
|
-
device.
|
|
1181
|
-
|
|
1188
|
+
const moduleData = device.getModuleData("@luma.gl/engine");
|
|
1189
|
+
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
1190
|
+
return moduleData.defaultShaderFactory;
|
|
1182
1191
|
}
|
|
1183
1192
|
device;
|
|
1184
1193
|
cachingEnabled;
|
|
@@ -1399,6 +1408,16 @@ var __exports__ = (() => {
|
|
|
1399
1408
|
};
|
|
1400
1409
|
|
|
1401
1410
|
// src/utils/buffer-layout-order.ts
|
|
1411
|
+
function getMinLocation(attributeNames, shaderLayoutMap) {
|
|
1412
|
+
let minLocation = Infinity;
|
|
1413
|
+
for (const name of attributeNames) {
|
|
1414
|
+
const location = shaderLayoutMap[name];
|
|
1415
|
+
if (location !== void 0) {
|
|
1416
|
+
minLocation = Math.min(minLocation, location);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
return minLocation;
|
|
1420
|
+
}
|
|
1402
1421
|
function sortedBufferLayoutByShaderSourceLocations(shaderLayout, bufferLayout) {
|
|
1403
1422
|
const shaderLayoutMap = Object.fromEntries(
|
|
1404
1423
|
shaderLayout.attributes.map((attr) => [attr.name, attr.location])
|
|
@@ -1407,8 +1426,8 @@ var __exports__ = (() => {
|
|
|
1407
1426
|
sortedLayout.sort((a, b) => {
|
|
1408
1427
|
const attributeNamesA = a.attributes ? a.attributes.map((attr) => attr.attribute) : [a.name];
|
|
1409
1428
|
const attributeNamesB = b.attributes ? b.attributes.map((attr) => attr.attribute) : [b.name];
|
|
1410
|
-
const minLocationA =
|
|
1411
|
-
const minLocationB =
|
|
1429
|
+
const minLocationA = getMinLocation(attributeNamesA, shaderLayoutMap);
|
|
1430
|
+
const minLocationB = getMinLocation(attributeNamesB, shaderLayoutMap);
|
|
1412
1431
|
return minLocationA - minLocationB;
|
|
1413
1432
|
});
|
|
1414
1433
|
return sortedLayout;
|
|
@@ -1554,49 +1573,810 @@ var __exports__ = (() => {
|
|
|
1554
1573
|
}
|
|
1555
1574
|
};
|
|
1556
1575
|
|
|
1557
|
-
// src/
|
|
1558
|
-
var
|
|
1576
|
+
// src/dynamic-texture/dynamic-texture.ts
|
|
1577
|
+
var import_core11 = __toESM(require_core(), 1);
|
|
1559
1578
|
|
|
1560
|
-
// src/
|
|
1561
|
-
var
|
|
1562
|
-
|
|
1563
|
-
|
|
1579
|
+
// src/dynamic-texture/texture-data.ts
|
|
1580
|
+
var import_core8 = __toESM(require_core(), 1);
|
|
1581
|
+
var TEXTURE_CUBE_FACE_MAP = { "+X": 0, "-X": 1, "+Y": 2, "-Y": 3, "+Z": 4, "-Z": 5 };
|
|
1582
|
+
function getFirstMipLevel(layer) {
|
|
1583
|
+
if (!layer)
|
|
1584
|
+
return null;
|
|
1585
|
+
return Array.isArray(layer) ? layer[0] ?? null : layer;
|
|
1564
1586
|
}
|
|
1565
|
-
|
|
1566
|
-
const
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1587
|
+
function getTextureSizeFromData(props) {
|
|
1588
|
+
const { dimension, data } = props;
|
|
1589
|
+
if (!data) {
|
|
1590
|
+
return null;
|
|
1591
|
+
}
|
|
1592
|
+
switch (dimension) {
|
|
1593
|
+
case "1d": {
|
|
1594
|
+
const mipLevel = getFirstMipLevel(data);
|
|
1595
|
+
if (!mipLevel)
|
|
1596
|
+
return null;
|
|
1597
|
+
const { width } = getTextureMipLevelSize(mipLevel);
|
|
1598
|
+
return { width, height: 1 };
|
|
1599
|
+
}
|
|
1600
|
+
case "2d": {
|
|
1601
|
+
const mipLevel = getFirstMipLevel(data);
|
|
1602
|
+
return mipLevel ? getTextureMipLevelSize(mipLevel) : null;
|
|
1603
|
+
}
|
|
1604
|
+
case "3d":
|
|
1605
|
+
case "2d-array": {
|
|
1606
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
1607
|
+
return null;
|
|
1608
|
+
const mipLevel = getFirstMipLevel(data[0]);
|
|
1609
|
+
return mipLevel ? getTextureMipLevelSize(mipLevel) : null;
|
|
1610
|
+
}
|
|
1611
|
+
case "cube": {
|
|
1612
|
+
const face = Object.keys(data)[0] ?? null;
|
|
1613
|
+
if (!face)
|
|
1614
|
+
return null;
|
|
1615
|
+
const faceData = data[face];
|
|
1616
|
+
const mipLevel = getFirstMipLevel(faceData);
|
|
1617
|
+
return mipLevel ? getTextureMipLevelSize(mipLevel) : null;
|
|
1618
|
+
}
|
|
1619
|
+
case "cube-array": {
|
|
1620
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
1621
|
+
return null;
|
|
1622
|
+
const firstCube = data[0];
|
|
1623
|
+
const face = Object.keys(firstCube)[0] ?? null;
|
|
1624
|
+
if (!face)
|
|
1625
|
+
return null;
|
|
1626
|
+
const mipLevel = getFirstMipLevel(firstCube[face]);
|
|
1627
|
+
return mipLevel ? getTextureMipLevelSize(mipLevel) : null;
|
|
1628
|
+
}
|
|
1629
|
+
default:
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1571
1632
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1633
|
+
function getTextureMipLevelSize(data) {
|
|
1634
|
+
if ((0, import_core8.isExternalImage)(data)) {
|
|
1635
|
+
return (0, import_core8.getExternalImageSize)(data);
|
|
1636
|
+
}
|
|
1637
|
+
if (typeof data === "object" && "width" in data && "height" in data) {
|
|
1638
|
+
return { width: data.width, height: data.height };
|
|
1639
|
+
}
|
|
1640
|
+
throw new Error("Unsupported mip-level data");
|
|
1641
|
+
}
|
|
1642
|
+
function isTextureImageData(data) {
|
|
1643
|
+
return typeof data === "object" && data !== null && "data" in data && "width" in data && "height" in data;
|
|
1644
|
+
}
|
|
1645
|
+
function getCubeFaceIndex(face) {
|
|
1646
|
+
const idx = TEXTURE_CUBE_FACE_MAP[face];
|
|
1647
|
+
if (idx === void 0)
|
|
1648
|
+
throw new Error(`Invalid cube face: ${face}`);
|
|
1649
|
+
return idx;
|
|
1650
|
+
}
|
|
1651
|
+
function getCubeArrayFaceIndex(cubeIndex, face) {
|
|
1652
|
+
return 6 * cubeIndex + getCubeFaceIndex(face);
|
|
1653
|
+
}
|
|
1654
|
+
function getTexture1DSubresources(data) {
|
|
1655
|
+
throw new Error("setTexture1DData not supported in WebGL.");
|
|
1656
|
+
}
|
|
1657
|
+
function _normalizeTexture2DData(data) {
|
|
1658
|
+
return Array.isArray(data) ? data : [data];
|
|
1659
|
+
}
|
|
1660
|
+
function getTexture2DSubresources(slice, lodData) {
|
|
1661
|
+
const lodArray = _normalizeTexture2DData(lodData);
|
|
1662
|
+
const z = slice;
|
|
1663
|
+
const subresources = [];
|
|
1664
|
+
for (let mipLevel = 0; mipLevel < lodArray.length; mipLevel++) {
|
|
1665
|
+
const imageData = lodArray[mipLevel];
|
|
1666
|
+
if ((0, import_core8.isExternalImage)(imageData)) {
|
|
1667
|
+
subresources.push({
|
|
1668
|
+
type: "external-image",
|
|
1669
|
+
image: imageData,
|
|
1670
|
+
z,
|
|
1671
|
+
mipLevel
|
|
1672
|
+
});
|
|
1673
|
+
} else if (isTextureImageData(imageData)) {
|
|
1674
|
+
subresources.push({
|
|
1675
|
+
type: "texture-data",
|
|
1676
|
+
data: imageData,
|
|
1677
|
+
z,
|
|
1678
|
+
mipLevel
|
|
1679
|
+
});
|
|
1680
|
+
} else {
|
|
1681
|
+
throw new Error("Unsupported 2D mip-level payload");
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return subresources;
|
|
1685
|
+
}
|
|
1686
|
+
function getTexture3DSubresources(data) {
|
|
1687
|
+
const subresources = [];
|
|
1688
|
+
for (let depth = 0; depth < data.length; depth++) {
|
|
1689
|
+
subresources.push(...getTexture2DSubresources(depth, data[depth]));
|
|
1690
|
+
}
|
|
1691
|
+
return subresources;
|
|
1692
|
+
}
|
|
1693
|
+
function getTextureArraySubresources(data) {
|
|
1694
|
+
const subresources = [];
|
|
1695
|
+
for (let layer = 0; layer < data.length; layer++) {
|
|
1696
|
+
subresources.push(...getTexture2DSubresources(layer, data[layer]));
|
|
1697
|
+
}
|
|
1698
|
+
return subresources;
|
|
1699
|
+
}
|
|
1700
|
+
function getTextureCubeSubresources(data) {
|
|
1701
|
+
const subresources = [];
|
|
1702
|
+
for (const [face, faceData] of Object.entries(data)) {
|
|
1703
|
+
const faceDepth = getCubeFaceIndex(face);
|
|
1704
|
+
subresources.push(...getTexture2DSubresources(faceDepth, faceData));
|
|
1705
|
+
}
|
|
1706
|
+
return subresources;
|
|
1707
|
+
}
|
|
1708
|
+
function getTextureCubeArraySubresources(data) {
|
|
1709
|
+
const subresources = [];
|
|
1710
|
+
data.forEach((cubeData, cubeIndex) => {
|
|
1711
|
+
for (const [face, faceData] of Object.entries(cubeData)) {
|
|
1712
|
+
const faceDepth = getCubeArrayFaceIndex(cubeIndex, face);
|
|
1713
|
+
subresources.push(...getTexture2DSubresources(faceDepth, faceData));
|
|
1714
|
+
}
|
|
1715
|
+
});
|
|
1716
|
+
return subresources;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
// src/dynamic-texture/mipmaps.ts
|
|
1720
|
+
var import_core10 = __toESM(require_core(), 1);
|
|
1721
|
+
|
|
1722
|
+
// src/compute/computation.ts
|
|
1723
|
+
var import_core9 = __toESM(require_core(), 1);
|
|
1724
|
+
var import_shadertools2 = __toESM(require_shadertools(), 1);
|
|
1725
|
+
var LOG_DRAW_PRIORITY = 2;
|
|
1726
|
+
var LOG_DRAW_TIMEOUT = 1e4;
|
|
1727
|
+
var _Computation = class {
|
|
1728
|
+
device;
|
|
1729
|
+
id;
|
|
1730
|
+
pipelineFactory;
|
|
1731
|
+
shaderFactory;
|
|
1732
|
+
userData = {};
|
|
1733
|
+
/** Bindings (textures, samplers, uniform buffers) */
|
|
1734
|
+
bindings = {};
|
|
1735
|
+
/** The underlying GPU pipeline. */
|
|
1736
|
+
pipeline;
|
|
1737
|
+
/** Assembled compute shader source */
|
|
1738
|
+
source;
|
|
1739
|
+
/** the underlying compiled compute shader */
|
|
1740
|
+
// @ts-ignore Set in function called from constructor
|
|
1741
|
+
shader;
|
|
1742
|
+
/** ShaderInputs instance */
|
|
1743
|
+
shaderInputs;
|
|
1744
|
+
// @ts-ignore Set in function called from constructor
|
|
1745
|
+
_uniformStore;
|
|
1746
|
+
_pipelineNeedsUpdate = "newly created";
|
|
1747
|
+
_getModuleUniforms;
|
|
1748
|
+
props;
|
|
1749
|
+
_destroyed = false;
|
|
1750
|
+
constructor(device, props) {
|
|
1751
|
+
if (device.type !== "webgpu") {
|
|
1752
|
+
throw new Error("Computation is only supported in WebGPU");
|
|
1753
|
+
}
|
|
1754
|
+
this.props = { ..._Computation.defaultProps, ...props };
|
|
1755
|
+
props = this.props;
|
|
1756
|
+
this.id = props.id || uid("model");
|
|
1757
|
+
this.device = device;
|
|
1758
|
+
Object.assign(this.userData, props.userData);
|
|
1759
|
+
const moduleMap = Object.fromEntries(
|
|
1760
|
+
this.props.modules?.map((module) => [module.name, module]) || []
|
|
1761
|
+
);
|
|
1762
|
+
this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
|
|
1763
|
+
this.setShaderInputs(this.shaderInputs);
|
|
1764
|
+
this.props.shaderLayout ||= device.getShaderLayout(this.props.source);
|
|
1765
|
+
const platformInfo = getPlatformInfo(device);
|
|
1766
|
+
const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
1767
|
+
this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
1768
|
+
this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
|
|
1769
|
+
const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
|
|
1770
|
+
platformInfo,
|
|
1771
|
+
...this.props,
|
|
1772
|
+
modules
|
|
1773
|
+
});
|
|
1774
|
+
this.source = source3;
|
|
1775
|
+
this._getModuleUniforms = getUniforms2;
|
|
1776
|
+
this.pipeline = this._updatePipeline();
|
|
1777
|
+
if (props.bindings) {
|
|
1778
|
+
this.setBindings(props.bindings);
|
|
1779
|
+
}
|
|
1780
|
+
Object.seal(this);
|
|
1781
|
+
}
|
|
1782
|
+
destroy() {
|
|
1783
|
+
if (this._destroyed)
|
|
1784
|
+
return;
|
|
1785
|
+
this.pipelineFactory.release(this.pipeline);
|
|
1786
|
+
this.shaderFactory.release(this.shader);
|
|
1787
|
+
this._uniformStore.destroy();
|
|
1788
|
+
this._destroyed = true;
|
|
1789
|
+
}
|
|
1790
|
+
// Draw call
|
|
1791
|
+
predraw() {
|
|
1792
|
+
this.updateShaderInputs();
|
|
1793
|
+
}
|
|
1794
|
+
dispatch(computePass, x, y, z) {
|
|
1574
1795
|
try {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1796
|
+
this._logDrawCallStart();
|
|
1797
|
+
this.pipeline = this._updatePipeline();
|
|
1798
|
+
this.pipeline.setBindings(this.bindings);
|
|
1799
|
+
computePass.setPipeline(this.pipeline);
|
|
1800
|
+
computePass.setBindings([]);
|
|
1801
|
+
computePass.dispatch(x, y, z);
|
|
1802
|
+
} finally {
|
|
1803
|
+
this._logDrawCallEnd();
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
// Update fixed fields (can trigger pipeline rebuild)
|
|
1807
|
+
// Update dynamic fields
|
|
1808
|
+
/**
|
|
1809
|
+
* Updates the vertex count (used in draw calls)
|
|
1810
|
+
* @note Any attributes with stepMode=vertex need to be at least this big
|
|
1811
|
+
*/
|
|
1812
|
+
setVertexCount(vertexCount) {
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Updates the instance count (used in draw calls)
|
|
1816
|
+
* @note Any attributes with stepMode=instance need to be at least this big
|
|
1817
|
+
*/
|
|
1818
|
+
setInstanceCount(instanceCount) {
|
|
1819
|
+
}
|
|
1820
|
+
setShaderInputs(shaderInputs) {
|
|
1821
|
+
this.shaderInputs = shaderInputs;
|
|
1822
|
+
this._uniformStore = new import_core9.UniformStore(this.shaderInputs.modules);
|
|
1823
|
+
for (const moduleName of Object.keys(this.shaderInputs.modules)) {
|
|
1824
|
+
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
1825
|
+
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Updates shader module settings (which results in uniforms being set)
|
|
1830
|
+
*/
|
|
1831
|
+
setShaderModuleProps(props) {
|
|
1832
|
+
const uniforms = this._getModuleUniforms(props);
|
|
1833
|
+
const keys = Object.keys(uniforms).filter((k) => {
|
|
1834
|
+
const uniform = uniforms[k];
|
|
1835
|
+
return !isNumericArray(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
|
|
1836
|
+
});
|
|
1837
|
+
const bindings = {};
|
|
1838
|
+
for (const k of keys) {
|
|
1839
|
+
bindings[k] = uniforms[k];
|
|
1840
|
+
delete uniforms[k];
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
updateShaderInputs() {
|
|
1844
|
+
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Sets bindings (textures, samplers, uniform buffers)
|
|
1848
|
+
*/
|
|
1849
|
+
setBindings(bindings) {
|
|
1850
|
+
Object.assign(this.bindings, bindings);
|
|
1851
|
+
}
|
|
1852
|
+
_setPipelineNeedsUpdate(reason) {
|
|
1853
|
+
this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
|
|
1854
|
+
}
|
|
1855
|
+
_updatePipeline() {
|
|
1856
|
+
if (this._pipelineNeedsUpdate) {
|
|
1857
|
+
let prevShader = null;
|
|
1858
|
+
if (this.pipeline) {
|
|
1859
|
+
import_core9.log.log(
|
|
1860
|
+
1,
|
|
1861
|
+
`Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
|
|
1862
|
+
)();
|
|
1863
|
+
prevShader = this.shader;
|
|
1864
|
+
}
|
|
1865
|
+
this._pipelineNeedsUpdate = false;
|
|
1866
|
+
this.shader = this.shaderFactory.createShader({
|
|
1867
|
+
id: `${this.id}-fragment`,
|
|
1868
|
+
stage: "compute",
|
|
1869
|
+
source: this.source,
|
|
1870
|
+
debugShaders: this.props.debugShaders
|
|
1871
|
+
});
|
|
1872
|
+
this.pipeline = this.pipelineFactory.createComputePipeline({
|
|
1873
|
+
...this.props,
|
|
1874
|
+
shader: this.shader
|
|
1875
|
+
});
|
|
1876
|
+
if (prevShader) {
|
|
1877
|
+
this.shaderFactory.release(prevShader);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return this.pipeline;
|
|
1881
|
+
}
|
|
1882
|
+
/** Throttle draw call logging */
|
|
1883
|
+
_lastLogTime = 0;
|
|
1884
|
+
_logOpen = false;
|
|
1885
|
+
_logDrawCallStart() {
|
|
1886
|
+
const logDrawTimeout = import_core9.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
|
|
1887
|
+
if (import_core9.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
this._lastLogTime = Date.now();
|
|
1891
|
+
this._logOpen = true;
|
|
1892
|
+
import_core9.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core9.log.level <= 2 })();
|
|
1893
|
+
}
|
|
1894
|
+
_logDrawCallEnd() {
|
|
1895
|
+
if (this._logOpen) {
|
|
1896
|
+
const uniformTable = this.shaderInputs.getDebugTable();
|
|
1897
|
+
import_core9.log.table(LOG_DRAW_PRIORITY, uniformTable)();
|
|
1898
|
+
import_core9.log.groupEnd(LOG_DRAW_PRIORITY)();
|
|
1899
|
+
this._logOpen = false;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
_drawCount = 0;
|
|
1903
|
+
// TODO - fix typing of luma data types
|
|
1904
|
+
_getBufferOrConstantValues(attribute, dataType) {
|
|
1905
|
+
const TypedArrayConstructor = (0, import_core9.getTypedArrayConstructor)(dataType);
|
|
1906
|
+
const typedArray = attribute instanceof import_core9.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
1907
|
+
return typedArray.toString();
|
|
1908
|
+
}
|
|
1909
|
+
};
|
|
1910
|
+
var Computation = _Computation;
|
|
1911
|
+
__publicField(Computation, "defaultProps", {
|
|
1912
|
+
...import_core9.ComputePipeline.defaultProps,
|
|
1913
|
+
id: "unnamed",
|
|
1914
|
+
handle: void 0,
|
|
1915
|
+
userData: {},
|
|
1916
|
+
source: "",
|
|
1917
|
+
modules: [],
|
|
1918
|
+
defines: {},
|
|
1919
|
+
bindings: void 0,
|
|
1920
|
+
shaderInputs: void 0,
|
|
1921
|
+
pipelineFactory: void 0,
|
|
1922
|
+
shaderFactory: void 0,
|
|
1923
|
+
shaderAssembler: import_shadertools2.ShaderAssembler.getDefaultShaderAssembler(),
|
|
1924
|
+
debugShaders: void 0
|
|
1925
|
+
});
|
|
1926
|
+
function getPlatformInfo(device) {
|
|
1927
|
+
return {
|
|
1928
|
+
type: device.type,
|
|
1929
|
+
shaderLanguage: device.info.shadingLanguage,
|
|
1930
|
+
shaderLanguageVersion: device.info.shadingLanguageVersion,
|
|
1931
|
+
gpu: device.info.gpu,
|
|
1932
|
+
// HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
|
|
1933
|
+
features: device.features
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
// src/dynamic-texture/mipmaps.ts
|
|
1938
|
+
var RENDER_DIMENSIONS = [
|
|
1939
|
+
"2d",
|
|
1940
|
+
"2d-array",
|
|
1941
|
+
"cube",
|
|
1942
|
+
"cube-array"
|
|
1943
|
+
];
|
|
1944
|
+
var WORKGROUP_SIZE = {
|
|
1945
|
+
x: 4,
|
|
1946
|
+
y: 4,
|
|
1947
|
+
z: 4
|
|
1948
|
+
};
|
|
1949
|
+
function generateMipmap(device, texture) {
|
|
1950
|
+
if (texture.mipLevels <= 1) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (device.type !== "webgpu") {
|
|
1954
|
+
throw new Error(
|
|
1955
|
+
`Cannot generate mipmaps on device type "${device.type}". Use generateMipmapsWebGL for WebGL devices.`
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
if (texture.dimension === "3d") {
|
|
1959
|
+
generateMipmaps3D(device, texture);
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
if (RENDER_DIMENSIONS.includes(texture.dimension)) {
|
|
1963
|
+
generateMipmapsRender(device, texture);
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
throw new Error(
|
|
1967
|
+
`Cannot generate mipmaps for texture dimension "${texture.dimension}" with WebGPU.`
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
function generateMipmapsRender(device, texture) {
|
|
1971
|
+
validateFormatCapabilities(device, texture, ["render", "filter"], "render");
|
|
1972
|
+
const colorAttachmentFormat = getColorAttachmentFormat(
|
|
1973
|
+
texture.format,
|
|
1974
|
+
"render",
|
|
1975
|
+
texture.dimension
|
|
1976
|
+
);
|
|
1977
|
+
const viewDimension = texture.dimension;
|
|
1978
|
+
const shader = getRenderMipmapWGSL(viewDimension);
|
|
1979
|
+
const sampler = device.createSampler({ minFilter: "linear", magFilter: "linear" });
|
|
1980
|
+
const uniformValues = new Uint32Array(1);
|
|
1981
|
+
const uniformsBuffer = device.createBuffer({
|
|
1982
|
+
byteLength: 16,
|
|
1983
|
+
usage: import_core10.Buffer.UNIFORM | import_core10.Buffer.COPY_DST
|
|
1984
|
+
});
|
|
1985
|
+
const model = new Model(device, {
|
|
1986
|
+
source: shader,
|
|
1987
|
+
colorAttachmentFormats: [colorAttachmentFormat],
|
|
1988
|
+
topology: "triangle-list",
|
|
1989
|
+
vertexCount: 3,
|
|
1990
|
+
shaderLayout: {
|
|
1991
|
+
attributes: [],
|
|
1992
|
+
bindings: [
|
|
1993
|
+
{ type: "sampler", name: "sourceSampler", group: 0, location: 0 },
|
|
1994
|
+
{
|
|
1995
|
+
type: "texture",
|
|
1996
|
+
name: "sourceTexture",
|
|
1997
|
+
group: 0,
|
|
1998
|
+
location: 1,
|
|
1999
|
+
viewDimension,
|
|
2000
|
+
sampleType: "float"
|
|
2001
|
+
},
|
|
2002
|
+
{ type: "uniform", name: "uniforms", group: 0, location: 2 }
|
|
2003
|
+
]
|
|
2004
|
+
},
|
|
2005
|
+
bindings: {
|
|
2006
|
+
sourceSampler: sampler,
|
|
2007
|
+
sourceTexture: texture,
|
|
2008
|
+
uniforms: uniformsBuffer
|
|
1582
2009
|
}
|
|
1583
2010
|
});
|
|
2011
|
+
let sourceWidth = texture.width;
|
|
2012
|
+
let sourceHeight = texture.height;
|
|
2013
|
+
const layerCount = texture.dimension === "2d" ? 1 : texture.depth;
|
|
2014
|
+
try {
|
|
2015
|
+
for (let baseMipLevel = 1; baseMipLevel < texture.mipLevels; ++baseMipLevel) {
|
|
2016
|
+
validateFormatCapabilities(device, texture, ["render", "filter"], "render");
|
|
2017
|
+
const sourceMipLevel = baseMipLevel - 1;
|
|
2018
|
+
const destinationWidth = Math.max(1, sourceWidth >> 1);
|
|
2019
|
+
const destinationHeight = Math.max(1, sourceHeight >> 1);
|
|
2020
|
+
const sourceView = texture.createView({
|
|
2021
|
+
dimension: viewDimension,
|
|
2022
|
+
baseMipLevel: sourceMipLevel,
|
|
2023
|
+
mipLevelCount: 1,
|
|
2024
|
+
baseArrayLayer: 0,
|
|
2025
|
+
arrayLayerCount: texture.depth
|
|
2026
|
+
});
|
|
2027
|
+
model.setBindings({ sourceTexture: sourceView });
|
|
2028
|
+
for (let baseArrayLayer = 0; baseArrayLayer < layerCount; ++baseArrayLayer) {
|
|
2029
|
+
uniformValues[0] = baseArrayLayer;
|
|
2030
|
+
uniformsBuffer.write(uniformValues);
|
|
2031
|
+
const destinationView = texture.createView({
|
|
2032
|
+
dimension: "2d",
|
|
2033
|
+
baseMipLevel,
|
|
2034
|
+
mipLevelCount: 1,
|
|
2035
|
+
baseArrayLayer,
|
|
2036
|
+
arrayLayerCount: 1
|
|
2037
|
+
});
|
|
2038
|
+
const framebuffer = device.createFramebuffer({
|
|
2039
|
+
colorAttachments: [destinationView]
|
|
2040
|
+
});
|
|
2041
|
+
const renderPass = device.beginRenderPass({
|
|
2042
|
+
id: `mipmap-generation:${texture.format}:${baseMipLevel}:${baseArrayLayer}`,
|
|
2043
|
+
framebuffer
|
|
2044
|
+
});
|
|
2045
|
+
renderPass.setParameters({
|
|
2046
|
+
viewport: [0, 0, destinationWidth, destinationHeight, 0, 1],
|
|
2047
|
+
scissorRect: [0, 0, destinationWidth, destinationHeight]
|
|
2048
|
+
});
|
|
2049
|
+
model.draw(renderPass);
|
|
2050
|
+
renderPass.end();
|
|
2051
|
+
device.submit();
|
|
2052
|
+
destinationView.destroy();
|
|
2053
|
+
framebuffer.destroy();
|
|
2054
|
+
}
|
|
2055
|
+
sourceView.destroy();
|
|
2056
|
+
sourceWidth = destinationWidth;
|
|
2057
|
+
sourceHeight = destinationHeight;
|
|
2058
|
+
}
|
|
2059
|
+
} finally {
|
|
2060
|
+
model.destroy();
|
|
2061
|
+
sampler.destroy();
|
|
2062
|
+
uniformsBuffer.destroy();
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
function getColorAttachmentFormat(format, path, dimension) {
|
|
2066
|
+
if (import_core10.textureFormatDecoder.isColor(format)) {
|
|
2067
|
+
return format;
|
|
2068
|
+
}
|
|
2069
|
+
throw new Error(
|
|
2070
|
+
`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Only color textures can be used for this operation. Required capabilities: color. Actual capabilities: color=false.`
|
|
2071
|
+
);
|
|
2072
|
+
}
|
|
2073
|
+
function generateMipmaps3D(device, texture) {
|
|
2074
|
+
validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
|
|
2075
|
+
const format = getColorAttachmentFormat(texture.format, "compute", texture.dimension);
|
|
2076
|
+
const shaderSource = get3DComputeMipmapWGSL(format);
|
|
2077
|
+
const uniformsBuffer = device.createBuffer({
|
|
2078
|
+
byteLength: 32,
|
|
2079
|
+
usage: import_core10.Buffer.UNIFORM | import_core10.Buffer.COPY_DST
|
|
2080
|
+
});
|
|
2081
|
+
const uniformValues = new Uint32Array(8);
|
|
2082
|
+
let sourceWidth = texture.width;
|
|
2083
|
+
let sourceHeight = texture.height;
|
|
2084
|
+
let sourceDepth = texture.depth;
|
|
2085
|
+
try {
|
|
2086
|
+
for (let destinationMipLevel = 1; destinationMipLevel < texture.mipLevels; ++destinationMipLevel) {
|
|
2087
|
+
validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
|
|
2088
|
+
const destinationWidth = Math.max(1, sourceWidth >> 1);
|
|
2089
|
+
const destinationHeight = Math.max(1, sourceHeight >> 1);
|
|
2090
|
+
const destinationDepth = Math.max(1, sourceDepth >> 1);
|
|
2091
|
+
uniformValues[0] = sourceWidth;
|
|
2092
|
+
uniformValues[1] = sourceHeight;
|
|
2093
|
+
uniformValues[2] = sourceDepth;
|
|
2094
|
+
uniformValues[3] = destinationWidth;
|
|
2095
|
+
uniformValues[4] = destinationHeight;
|
|
2096
|
+
uniformValues[5] = destinationDepth;
|
|
2097
|
+
uniformValues[6] = 0;
|
|
2098
|
+
uniformsBuffer.write(uniformValues);
|
|
2099
|
+
const sourceView = texture.createView({
|
|
2100
|
+
dimension: "3d",
|
|
2101
|
+
baseMipLevel: destinationMipLevel - 1,
|
|
2102
|
+
mipLevelCount: 1,
|
|
2103
|
+
baseArrayLayer: 0,
|
|
2104
|
+
arrayLayerCount: 1
|
|
2105
|
+
});
|
|
2106
|
+
const destinationView = texture.createView({
|
|
2107
|
+
dimension: "3d",
|
|
2108
|
+
baseMipLevel: destinationMipLevel,
|
|
2109
|
+
mipLevelCount: 1,
|
|
2110
|
+
baseArrayLayer: 0,
|
|
2111
|
+
arrayLayerCount: 1
|
|
2112
|
+
});
|
|
2113
|
+
const computation = new Computation(device, {
|
|
2114
|
+
source: shaderSource,
|
|
2115
|
+
shaderLayout: {
|
|
2116
|
+
bindings: [
|
|
2117
|
+
{
|
|
2118
|
+
type: "texture",
|
|
2119
|
+
name: "sourceTexture",
|
|
2120
|
+
group: 0,
|
|
2121
|
+
location: 0,
|
|
2122
|
+
viewDimension: "3d",
|
|
2123
|
+
sampleType: "float"
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
type: "storage",
|
|
2127
|
+
name: "destinationTexture",
|
|
2128
|
+
group: 0,
|
|
2129
|
+
location: 1,
|
|
2130
|
+
format,
|
|
2131
|
+
viewDimension: "3d",
|
|
2132
|
+
access: "write-only"
|
|
2133
|
+
},
|
|
2134
|
+
{ type: "uniform", name: "uniforms", group: 0, location: 2 }
|
|
2135
|
+
]
|
|
2136
|
+
},
|
|
2137
|
+
bindings: {
|
|
2138
|
+
sourceTexture: sourceView,
|
|
2139
|
+
destinationTexture: destinationView,
|
|
2140
|
+
uniforms: uniformsBuffer
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
const workgroupsX = Math.ceil(destinationWidth / WORKGROUP_SIZE.x);
|
|
2144
|
+
const workgroupsY = Math.ceil(destinationHeight / WORKGROUP_SIZE.y);
|
|
2145
|
+
const workgroupsZ = Math.ceil(destinationDepth / WORKGROUP_SIZE.z);
|
|
2146
|
+
const computePass = device.beginComputePass({});
|
|
2147
|
+
computation.dispatch(computePass, workgroupsX, workgroupsY, workgroupsZ);
|
|
2148
|
+
computePass.end();
|
|
2149
|
+
device.submit();
|
|
2150
|
+
computation.destroy();
|
|
2151
|
+
sourceView.destroy();
|
|
2152
|
+
destinationView.destroy();
|
|
2153
|
+
sourceWidth = destinationWidth;
|
|
2154
|
+
sourceHeight = destinationHeight;
|
|
2155
|
+
sourceDepth = destinationDepth;
|
|
2156
|
+
}
|
|
2157
|
+
} finally {
|
|
2158
|
+
uniformsBuffer.destroy();
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
function validateFormatCapabilities(device, texture, requiredCapabilities, path) {
|
|
2162
|
+
const { format, dimension } = texture;
|
|
2163
|
+
const capabilities = device.getTextureFormatCapabilities(format);
|
|
2164
|
+
const missingCapabilities = requiredCapabilities.filter((capability) => !capabilities[capability]);
|
|
2165
|
+
if (missingCapabilities.length > 0) {
|
|
2166
|
+
const required = requiredCapabilities.join(" + ");
|
|
2167
|
+
const actual = requiredCapabilities.map((capability) => `${capability}=${capabilities[capability]}`).join(", ");
|
|
2168
|
+
throw new Error(
|
|
2169
|
+
`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Required capabilities: ${required}. Actual capabilities: ${actual}.`
|
|
2170
|
+
);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
function getSourceTextureType(dimension) {
|
|
2174
|
+
switch (dimension) {
|
|
2175
|
+
case "2d":
|
|
2176
|
+
return "texture_2d<f32>";
|
|
2177
|
+
case "2d-array":
|
|
2178
|
+
return "texture_2d_array<f32>";
|
|
2179
|
+
case "cube":
|
|
2180
|
+
return "texture_cube<f32>";
|
|
2181
|
+
case "cube-array":
|
|
2182
|
+
return "texture_cube_array<f32>";
|
|
2183
|
+
default:
|
|
2184
|
+
throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
function getRenderMipmapWGSL(dimension) {
|
|
2188
|
+
const sourceSnippet = getRenderMipmapSampleSnippet(dimension);
|
|
2189
|
+
return `
|
|
2190
|
+
struct MipmapUniforms {
|
|
2191
|
+
sourceLayer: u32,
|
|
2192
|
+
};
|
|
2193
|
+
|
|
2194
|
+
fn _touchUniform(uniforms: MipmapUniforms) {
|
|
2195
|
+
let unusedSourceLayer = uniforms.sourceLayer;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
const faceMat = array(
|
|
2199
|
+
mat3x3f(
|
|
2200
|
+
0.0, 0.0, -2.0,
|
|
2201
|
+
0.0, -2.0, 0.0,
|
|
2202
|
+
1.0, 1.0, 1.0
|
|
2203
|
+
), // pos-x
|
|
2204
|
+
mat3x3f(
|
|
2205
|
+
0.0, 0.0, 2.0,
|
|
2206
|
+
0.0, -2.0, 0.0,
|
|
2207
|
+
-1.0, 1.0, -1.0
|
|
2208
|
+
), // neg-x
|
|
2209
|
+
mat3x3f(
|
|
2210
|
+
2.0, 0.0, 0.0,
|
|
2211
|
+
0.0, 0.0, 2.0,
|
|
2212
|
+
-1.0, 1.0, -1.0
|
|
2213
|
+
), // pos-y
|
|
2214
|
+
mat3x3f(
|
|
2215
|
+
2.0, 0.0, 0.0,
|
|
2216
|
+
0.0, 0.0, -2.0,
|
|
2217
|
+
-1.0, -1.0, 1.0
|
|
2218
|
+
), // neg-y
|
|
2219
|
+
mat3x3f(
|
|
2220
|
+
2.0, 0.0, 0.0,
|
|
2221
|
+
0.0, -2.0, 0.0,
|
|
2222
|
+
-1.0, 1.0, 1.0
|
|
2223
|
+
), // pos-z
|
|
2224
|
+
mat3x3f(
|
|
2225
|
+
-2.0, 0.0, 0.0,
|
|
2226
|
+
0.0, -2.0, 0.0,
|
|
2227
|
+
1.0, 1.0, -1.0
|
|
2228
|
+
) // neg-z
|
|
2229
|
+
);
|
|
2230
|
+
|
|
2231
|
+
struct FragmentInputs {
|
|
2232
|
+
@builtin(position) position: vec4f,
|
|
2233
|
+
@location(0) texcoord: vec2f
|
|
2234
|
+
};
|
|
2235
|
+
|
|
2236
|
+
struct VertexOutput {
|
|
2237
|
+
@builtin(position) position: vec4f,
|
|
2238
|
+
@location(0) texcoord: vec2f
|
|
2239
|
+
};
|
|
2240
|
+
|
|
2241
|
+
@group(0) @binding(0) var sourceSampler: sampler;
|
|
2242
|
+
@group(0) @binding(1) var sourceTexture: ${getSourceTextureType(dimension)};
|
|
2243
|
+
@group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
|
|
2244
|
+
|
|
2245
|
+
@vertex
|
|
2246
|
+
fn vertexMain(
|
|
2247
|
+
@builtin(vertex_index) vertexIndex: u32
|
|
2248
|
+
) -> VertexOutput {
|
|
2249
|
+
const positions = array(
|
|
2250
|
+
vec2f(-1.0, -1.0),
|
|
2251
|
+
vec2f(-1.0, 3.0),
|
|
2252
|
+
vec2f( 3.0, -1.0)
|
|
2253
|
+
);
|
|
2254
|
+
|
|
2255
|
+
let xy = positions[vertexIndex];
|
|
2256
|
+
return VertexOutput(
|
|
2257
|
+
vec4f(xy, 0.0, 1.0),
|
|
2258
|
+
xy * vec2f(0.5, -0.5) + vec2f(0.5)
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
@fragment
|
|
2263
|
+
fn fragmentMain(fsInput: VertexOutput) -> @location(0) vec4f {
|
|
2264
|
+
_touchUniform(uniforms);
|
|
2265
|
+
return ${sourceSnippet};
|
|
2266
|
+
}
|
|
2267
|
+
`;
|
|
2268
|
+
}
|
|
2269
|
+
function getRenderMipmapSampleSnippet(dimension) {
|
|
2270
|
+
const layer = "uniforms.sourceLayer";
|
|
2271
|
+
switch (dimension) {
|
|
2272
|
+
case "2d":
|
|
2273
|
+
return "textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, 0.0)";
|
|
2274
|
+
case "2d-array":
|
|
2275
|
+
return `textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, i32(${layer}), 0.0)`;
|
|
2276
|
+
case "cube":
|
|
2277
|
+
return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer})] * vec3f(fract(fsInput.texcoord), 1.0), 0.0)`;
|
|
2278
|
+
case "cube-array":
|
|
2279
|
+
return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer} % 6u)] * vec3f(fract(fsInput.texcoord), 1.0), i32(${layer} / 6u), 0.0)`;
|
|
2280
|
+
default:
|
|
2281
|
+
throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
function get3DComputeMipmapWGSL(format) {
|
|
2285
|
+
return `
|
|
2286
|
+
struct MipmapUniforms {
|
|
2287
|
+
sourceWidth: u32,
|
|
2288
|
+
sourceHeight: u32,
|
|
2289
|
+
sourceDepth: u32,
|
|
2290
|
+
destinationWidth: u32,
|
|
2291
|
+
destinationHeight: u32,
|
|
2292
|
+
destinationDepth: u32,
|
|
2293
|
+
padding: u32,
|
|
2294
|
+
};
|
|
2295
|
+
|
|
2296
|
+
@group(0) @binding(0) var sourceTexture: texture_3d<f32>;
|
|
2297
|
+
@group(0) @binding(1) var destinationTexture: texture_storage_3d<${format}, write>;
|
|
2298
|
+
@group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
|
|
2299
|
+
|
|
2300
|
+
@compute @workgroup_size(${WORKGROUP_SIZE.x}, ${WORKGROUP_SIZE.y}, ${WORKGROUP_SIZE.z})
|
|
2301
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
2302
|
+
if (
|
|
2303
|
+
id.x >= uniforms.destinationWidth ||
|
|
2304
|
+
id.y >= uniforms.destinationHeight ||
|
|
2305
|
+
id.z >= uniforms.destinationDepth
|
|
2306
|
+
) {
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
let sourceBase = id * 2u;
|
|
2311
|
+
let sourceX0 = min(sourceBase.x, uniforms.sourceWidth - 1u);
|
|
2312
|
+
let sourceY0 = min(sourceBase.y, uniforms.sourceHeight - 1u);
|
|
2313
|
+
let sourceZ0 = min(sourceBase.z, uniforms.sourceDepth - 1u);
|
|
2314
|
+
|
|
2315
|
+
let sourceX1 = min(sourceBase.x + 1u, uniforms.sourceWidth - 1u);
|
|
2316
|
+
let sourceY1 = min(sourceBase.y + 1u, uniforms.sourceHeight - 1u);
|
|
2317
|
+
let sourceZ1 = min(sourceBase.z + 1u, uniforms.sourceDepth - 1u);
|
|
2318
|
+
|
|
2319
|
+
var sum = textureLoad(
|
|
2320
|
+
sourceTexture,
|
|
2321
|
+
vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ0)),
|
|
2322
|
+
0
|
|
2323
|
+
);
|
|
2324
|
+
sum += textureLoad(
|
|
2325
|
+
sourceTexture,
|
|
2326
|
+
vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ0)),
|
|
2327
|
+
0
|
|
2328
|
+
);
|
|
2329
|
+
sum += textureLoad(
|
|
2330
|
+
sourceTexture,
|
|
2331
|
+
vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ0)),
|
|
2332
|
+
0
|
|
2333
|
+
);
|
|
2334
|
+
sum += textureLoad(
|
|
2335
|
+
sourceTexture,
|
|
2336
|
+
vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ0)),
|
|
2337
|
+
0
|
|
2338
|
+
);
|
|
2339
|
+
sum += textureLoad(
|
|
2340
|
+
sourceTexture,
|
|
2341
|
+
vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ1)),
|
|
2342
|
+
0
|
|
2343
|
+
);
|
|
2344
|
+
sum += textureLoad(
|
|
2345
|
+
sourceTexture,
|
|
2346
|
+
vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ1)),
|
|
2347
|
+
0
|
|
2348
|
+
);
|
|
2349
|
+
sum += textureLoad(
|
|
2350
|
+
sourceTexture,
|
|
2351
|
+
vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ1)),
|
|
2352
|
+
0
|
|
2353
|
+
);
|
|
2354
|
+
sum += textureLoad(
|
|
2355
|
+
sourceTexture,
|
|
2356
|
+
vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ1)),
|
|
2357
|
+
0
|
|
2358
|
+
);
|
|
2359
|
+
|
|
2360
|
+
textureStore(
|
|
2361
|
+
destinationTexture,
|
|
2362
|
+
vec3<i32>(i32(id.x), i32(id.y), i32(id.z)),
|
|
2363
|
+
vec4<f32>(sum.xyz / 8.0, sum.w / 8.0)
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
`;
|
|
1584
2367
|
}
|
|
1585
2368
|
|
|
1586
|
-
// src/
|
|
1587
|
-
var
|
|
1588
|
-
var CubeFaces = ["+X", "-X", "+Y", "-Y", "+Z", "-Z"];
|
|
1589
|
-
var _AsyncTexture = class {
|
|
2369
|
+
// src/dynamic-texture/dynamic-texture.ts
|
|
2370
|
+
var _DynamicTexture = class {
|
|
1590
2371
|
device;
|
|
1591
2372
|
id;
|
|
2373
|
+
/** Props with defaults resolved (except `data` which is processed separately) */
|
|
1592
2374
|
props;
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
// @ts-expect-error
|
|
1599
|
-
view;
|
|
2375
|
+
/** Created resources */
|
|
2376
|
+
_texture = null;
|
|
2377
|
+
_sampler = null;
|
|
2378
|
+
_view = null;
|
|
2379
|
+
/** Ready when GPU texture has been created and data (if any) uploaded */
|
|
1600
2380
|
ready;
|
|
1601
2381
|
isReady = false;
|
|
1602
2382
|
destroyed = false;
|
|
@@ -1604,274 +2384,290 @@ var __exports__ = (() => {
|
|
|
1604
2384
|
};
|
|
1605
2385
|
rejectReady = () => {
|
|
1606
2386
|
};
|
|
2387
|
+
get texture() {
|
|
2388
|
+
if (!this._texture)
|
|
2389
|
+
throw new Error("Texture not initialized yet");
|
|
2390
|
+
return this._texture;
|
|
2391
|
+
}
|
|
2392
|
+
get sampler() {
|
|
2393
|
+
if (!this._sampler)
|
|
2394
|
+
throw new Error("Sampler not initialized yet");
|
|
2395
|
+
return this._sampler;
|
|
2396
|
+
}
|
|
2397
|
+
get view() {
|
|
2398
|
+
if (!this._view)
|
|
2399
|
+
throw new Error("View not initialized yet");
|
|
2400
|
+
return this._view;
|
|
2401
|
+
}
|
|
1607
2402
|
get [Symbol.toStringTag]() {
|
|
1608
|
-
return "
|
|
2403
|
+
return "DynamicTexture";
|
|
1609
2404
|
}
|
|
1610
2405
|
toString() {
|
|
1611
|
-
return `
|
|
2406
|
+
return `DynamicTexture:"${this.id}":${this.texture.width}x${this.texture.height}px:(${this.isReady ? "ready" : "loading..."})`;
|
|
1612
2407
|
}
|
|
1613
2408
|
constructor(device, props) {
|
|
1614
2409
|
this.device = device;
|
|
1615
|
-
const id = uid("
|
|
1616
|
-
|
|
2410
|
+
const id = uid("dynamic-texture");
|
|
2411
|
+
const originalPropsWithAsyncData = props;
|
|
2412
|
+
this.props = { ..._DynamicTexture.defaultProps, id, ...props, data: null };
|
|
1617
2413
|
this.id = this.props.id;
|
|
1618
|
-
props = { ...props };
|
|
1619
|
-
if (typeof props?.data === "string" && props.dimension === "2d") {
|
|
1620
|
-
props.data = loadImageBitmap(props.data);
|
|
1621
|
-
}
|
|
1622
|
-
if (props.mipmaps) {
|
|
1623
|
-
props.mipLevels = "auto";
|
|
1624
|
-
}
|
|
1625
2414
|
this.ready = new Promise((resolve, reject) => {
|
|
1626
|
-
this.resolveReady =
|
|
1627
|
-
this.isReady = true;
|
|
1628
|
-
resolve();
|
|
1629
|
-
};
|
|
2415
|
+
this.resolveReady = resolve;
|
|
1630
2416
|
this.rejectReady = reject;
|
|
1631
2417
|
});
|
|
1632
|
-
this.initAsync(
|
|
2418
|
+
this.initAsync(originalPropsWithAsyncData);
|
|
1633
2419
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
this.
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
this.view = this.texture.view;
|
|
1653
|
-
if (props.data) {
|
|
1654
|
-
switch (this.props.dimension) {
|
|
1655
|
-
case "1d":
|
|
1656
|
-
this._setTexture1DData(this.texture, data);
|
|
1657
|
-
break;
|
|
1658
|
-
case "2d":
|
|
1659
|
-
this._setTexture2DData(data);
|
|
1660
|
-
break;
|
|
1661
|
-
case "3d":
|
|
1662
|
-
this._setTexture3DData(this.texture, data);
|
|
1663
|
-
break;
|
|
1664
|
-
case "2d-array":
|
|
1665
|
-
this._setTextureArrayData(this.texture, data);
|
|
1666
|
-
break;
|
|
1667
|
-
case "cube":
|
|
1668
|
-
this._setTextureCubeData(this.texture, data);
|
|
1669
|
-
break;
|
|
1670
|
-
case "cube-array":
|
|
1671
|
-
this._setTextureCubeArrayData(this.texture, data);
|
|
1672
|
-
break;
|
|
2420
|
+
/** @note Fire and forget; caller can await `ready` */
|
|
2421
|
+
async initAsync(originalPropsWithAsyncData) {
|
|
2422
|
+
try {
|
|
2423
|
+
const propsWithSyncData = await this._loadAllData(originalPropsWithAsyncData);
|
|
2424
|
+
this._checkNotDestroyed();
|
|
2425
|
+
const deduceSize = () => {
|
|
2426
|
+
if (this.props.width && this.props.height) {
|
|
2427
|
+
return { width: this.props.width, height: this.props.height };
|
|
2428
|
+
}
|
|
2429
|
+
const size2 = getTextureSizeFromData(propsWithSyncData);
|
|
2430
|
+
if (size2) {
|
|
2431
|
+
return size2;
|
|
2432
|
+
}
|
|
2433
|
+
return { width: this.props.width || 1, height: this.props.height || 1 };
|
|
2434
|
+
};
|
|
2435
|
+
const size = deduceSize();
|
|
2436
|
+
if (!size || size.width <= 0 || size.height <= 0) {
|
|
2437
|
+
throw new Error(`${this} size could not be determined or was zero`);
|
|
1673
2438
|
}
|
|
2439
|
+
const baseTextureProps = {
|
|
2440
|
+
...this.props,
|
|
2441
|
+
...size,
|
|
2442
|
+
mipLevels: 1,
|
|
2443
|
+
// temporary; updated below
|
|
2444
|
+
data: void 0
|
|
2445
|
+
};
|
|
2446
|
+
if (this.device.type === "webgpu" && this.props.mipmaps) {
|
|
2447
|
+
const requiredUsage = this.props.dimension === "3d" ? import_core11.Texture.SAMPLE | import_core11.Texture.STORAGE | import_core11.Texture.COPY_DST | import_core11.Texture.COPY_SRC : import_core11.Texture.SAMPLE | import_core11.Texture.RENDER | import_core11.Texture.COPY_DST | import_core11.Texture.COPY_SRC;
|
|
2448
|
+
baseTextureProps.usage |= requiredUsage;
|
|
2449
|
+
}
|
|
2450
|
+
const maxMips = this.device.getMipLevelCount(baseTextureProps.width, baseTextureProps.height);
|
|
2451
|
+
const desired = this.props.mipLevels === "auto" ? maxMips : Math.max(1, Math.min(maxMips, this.props.mipLevels ?? 1));
|
|
2452
|
+
const finalTextureProps = { ...baseTextureProps, mipLevels: desired };
|
|
2453
|
+
this._texture = this.device.createTexture(finalTextureProps);
|
|
2454
|
+
this._sampler = this.texture.sampler;
|
|
2455
|
+
this._view = this.texture.view;
|
|
2456
|
+
if (propsWithSyncData.data) {
|
|
2457
|
+
switch (propsWithSyncData.dimension) {
|
|
2458
|
+
case "1d":
|
|
2459
|
+
this.setTexture1DData(propsWithSyncData.data);
|
|
2460
|
+
break;
|
|
2461
|
+
case "2d":
|
|
2462
|
+
this.setTexture2DData(propsWithSyncData.data);
|
|
2463
|
+
break;
|
|
2464
|
+
case "3d":
|
|
2465
|
+
this.setTexture3DData(propsWithSyncData.data);
|
|
2466
|
+
break;
|
|
2467
|
+
case "2d-array":
|
|
2468
|
+
this.setTextureArrayData(propsWithSyncData.data);
|
|
2469
|
+
break;
|
|
2470
|
+
case "cube":
|
|
2471
|
+
this.setTextureCubeData(propsWithSyncData.data);
|
|
2472
|
+
break;
|
|
2473
|
+
case "cube-array":
|
|
2474
|
+
this.setTextureCubeArrayData(propsWithSyncData.data);
|
|
2475
|
+
break;
|
|
2476
|
+
default: {
|
|
2477
|
+
throw new Error(`Unhandled dimension ${propsWithSyncData.dimension}`);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
if (this.props.mipmaps) {
|
|
2482
|
+
this.generateMipmaps();
|
|
2483
|
+
}
|
|
2484
|
+
this.isReady = true;
|
|
2485
|
+
this.resolveReady(this.texture);
|
|
2486
|
+
import_core11.log.info(0, `${this} created`)();
|
|
2487
|
+
} catch (e) {
|
|
2488
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
2489
|
+
this.rejectReady(err);
|
|
2490
|
+
throw err;
|
|
1674
2491
|
}
|
|
1675
|
-
if (this.props.mipmaps) {
|
|
1676
|
-
this.generateMipmaps();
|
|
1677
|
-
}
|
|
1678
|
-
import_core8.log.info(1, `${this} loaded`);
|
|
1679
|
-
this.resolveReady();
|
|
1680
2492
|
}
|
|
1681
2493
|
destroy() {
|
|
1682
|
-
if (this.
|
|
1683
|
-
this.
|
|
1684
|
-
this.
|
|
2494
|
+
if (this._texture) {
|
|
2495
|
+
this._texture.destroy();
|
|
2496
|
+
this._texture = null;
|
|
2497
|
+
this._sampler = null;
|
|
2498
|
+
this._view = null;
|
|
1685
2499
|
}
|
|
1686
2500
|
this.destroyed = true;
|
|
1687
2501
|
}
|
|
1688
2502
|
generateMipmaps() {
|
|
1689
|
-
this.
|
|
2503
|
+
if (this.device.type === "webgl") {
|
|
2504
|
+
this.texture.generateMipmapsWebGL();
|
|
2505
|
+
} else if (this.device.type === "webgpu") {
|
|
2506
|
+
generateMipmap(this.device, this.texture);
|
|
2507
|
+
} else {
|
|
2508
|
+
import_core11.log.warn(`${this} mipmaps not supported on ${this.device.type}`);
|
|
2509
|
+
}
|
|
1690
2510
|
}
|
|
1691
|
-
/** Set sampler or create
|
|
2511
|
+
/** Set sampler or create one from props */
|
|
1692
2512
|
setSampler(sampler = {}) {
|
|
1693
|
-
this.
|
|
1694
|
-
|
|
1695
|
-
);
|
|
2513
|
+
this._checkReady();
|
|
2514
|
+
const s = sampler instanceof import_core11.Sampler ? sampler : this.device.createSampler(sampler);
|
|
2515
|
+
this.texture.setSampler(s);
|
|
2516
|
+
this._sampler = s;
|
|
1696
2517
|
}
|
|
1697
2518
|
/**
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1700
|
-
* @note Does not copy contents of the texture
|
|
1701
|
-
* @note Mipmaps may need to be regenerated after resizing / setting new data
|
|
1702
|
-
* @todo Abort pending promise and create a texture with the new size?
|
|
2519
|
+
* Resize by cloning the underlying immutable texture.
|
|
2520
|
+
* Does not copy contents; caller may need to re-upload and/or regenerate mips.
|
|
1703
2521
|
*/
|
|
1704
2522
|
resize(size) {
|
|
1705
|
-
|
|
1706
|
-
throw new Error("Cannot resize texture before it is ready");
|
|
1707
|
-
}
|
|
2523
|
+
this._checkReady();
|
|
1708
2524
|
if (size.width === this.texture.width && size.height === this.texture.height) {
|
|
1709
2525
|
return false;
|
|
1710
2526
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
2527
|
+
const prev = this.texture;
|
|
2528
|
+
this._texture = prev.clone(size);
|
|
2529
|
+
this._sampler = this.texture.sampler;
|
|
2530
|
+
this._view = this.texture.view;
|
|
2531
|
+
prev.destroy();
|
|
2532
|
+
import_core11.log.info(`${this} resized`);
|
|
1716
2533
|
return true;
|
|
1717
2534
|
}
|
|
1718
|
-
/**
|
|
1719
|
-
|
|
1720
|
-
const
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2535
|
+
/** Convert cube face label to texture slice index. Index can be used with `setTexture2DData()`. */
|
|
2536
|
+
getCubeFaceIndex(face) {
|
|
2537
|
+
const index = TEXTURE_CUBE_FACE_MAP[face];
|
|
2538
|
+
if (index === void 0)
|
|
2539
|
+
throw new Error(`Invalid cube face: ${face}`);
|
|
2540
|
+
return index;
|
|
2541
|
+
}
|
|
2542
|
+
/** Convert cube face label to texture slice index. Index can be used with `setTexture2DData()`. */
|
|
2543
|
+
getCubeArrayFaceIndex(cubeIndex, face) {
|
|
2544
|
+
return 6 * cubeIndex + this.getCubeFaceIndex(face);
|
|
2545
|
+
}
|
|
2546
|
+
/** @note experimental: Set multiple mip levels (1D) */
|
|
2547
|
+
setTexture1DData(data) {
|
|
2548
|
+
this._checkReady();
|
|
2549
|
+
if (this.texture.props.dimension !== "1d") {
|
|
2550
|
+
throw new Error(`${this} is not 1d`);
|
|
2551
|
+
}
|
|
2552
|
+
const subresources = getTexture1DSubresources(data);
|
|
2553
|
+
this._setTextureSubresources(subresources);
|
|
2554
|
+
}
|
|
2555
|
+
/** @note experimental: Set multiple mip levels (2D), optionally at `z`, slice (depth/array level) index */
|
|
2556
|
+
setTexture2DData(lodData, z = 0) {
|
|
2557
|
+
this._checkReady();
|
|
2558
|
+
if (this.texture.props.dimension !== "2d") {
|
|
2559
|
+
throw new Error(`${this} is not 2d`);
|
|
2560
|
+
}
|
|
2561
|
+
const subresources = getTexture2DSubresources(z, lodData);
|
|
2562
|
+
this._setTextureSubresources(subresources);
|
|
2563
|
+
}
|
|
2564
|
+
/** 3D: multiple depth slices, each may carry multiple mip levels */
|
|
2565
|
+
setTexture3DData(data) {
|
|
2566
|
+
if (this.texture.props.dimension !== "3d") {
|
|
2567
|
+
throw new Error(`${this} is not 3d`);
|
|
2568
|
+
}
|
|
2569
|
+
const subresources = getTexture3DSubresources(data);
|
|
2570
|
+
this._setTextureSubresources(subresources);
|
|
2571
|
+
}
|
|
2572
|
+
/** 2D array: multiple layers, each may carry multiple mip levels */
|
|
2573
|
+
setTextureArrayData(data) {
|
|
2574
|
+
if (this.texture.props.dimension !== "2d-array") {
|
|
2575
|
+
throw new Error(`${this} is not 2d-array`);
|
|
2576
|
+
}
|
|
2577
|
+
const subresources = getTextureArraySubresources(data);
|
|
2578
|
+
this._setTextureSubresources(subresources);
|
|
2579
|
+
}
|
|
2580
|
+
/** Cube: 6 faces, each may carry multiple mip levels */
|
|
2581
|
+
setTextureCubeData(data) {
|
|
2582
|
+
if (this.texture.props.dimension !== "cube") {
|
|
2583
|
+
throw new Error(`${this} is not cube`);
|
|
2584
|
+
}
|
|
2585
|
+
const subresources = getTextureCubeSubresources(data);
|
|
2586
|
+
this._setTextureSubresources(subresources);
|
|
2587
|
+
}
|
|
2588
|
+
/** Cube array: multiple cubes (faces×layers), each face may carry multiple mips */
|
|
2589
|
+
setTextureCubeArrayData(data) {
|
|
2590
|
+
if (this.texture.props.dimension !== "cube-array") {
|
|
2591
|
+
throw new Error(`${this} is not cube-array`);
|
|
2592
|
+
}
|
|
2593
|
+
const subresources = getTextureCubeArraySubresources(data);
|
|
2594
|
+
this._setTextureSubresources(subresources);
|
|
2595
|
+
}
|
|
2596
|
+
/** Sets multiple mip levels on different `z` slices (depth/array index) */
|
|
2597
|
+
_setTextureSubresources(subresources) {
|
|
2598
|
+
for (const subresource of subresources) {
|
|
2599
|
+
const { z, mipLevel } = subresource;
|
|
2600
|
+
switch (subresource.type) {
|
|
2601
|
+
case "external-image":
|
|
2602
|
+
const { image, flipY } = subresource;
|
|
2603
|
+
this.texture.copyExternalImage({ image, z, mipLevel, flipY });
|
|
2604
|
+
break;
|
|
2605
|
+
case "texture-data":
|
|
2606
|
+
const { data } = subresource;
|
|
2607
|
+
this.texture.writeData(getAlignedUploadData(this.texture, data), {
|
|
2608
|
+
x: 0,
|
|
2609
|
+
y: 0,
|
|
2610
|
+
z,
|
|
2611
|
+
width: data.width,
|
|
2612
|
+
height: data.height,
|
|
2613
|
+
depthOrArrayLayers: 1,
|
|
2614
|
+
mipLevel
|
|
2615
|
+
});
|
|
2616
|
+
break;
|
|
2617
|
+
default:
|
|
2618
|
+
throw new Error("Unsupported 2D mip-level payload");
|
|
1785
2619
|
}
|
|
1786
2620
|
}
|
|
1787
2621
|
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
throw new Error(this.id);
|
|
1795
|
-
}
|
|
1796
|
-
for (let depth = 0; depth < data.length; depth++) {
|
|
1797
|
-
this._setTexture2DData(data[depth], depth);
|
|
1798
|
-
}
|
|
2622
|
+
// ------------------ helpers ------------------
|
|
2623
|
+
/** Recursively resolve all promises in data structures */
|
|
2624
|
+
async _loadAllData(props) {
|
|
2625
|
+
const syncData = await awaitAllPromises(props.data);
|
|
2626
|
+
const dimension = props.dimension ?? "2d";
|
|
2627
|
+
return { dimension, data: syncData ?? null };
|
|
1799
2628
|
}
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
* @param data
|
|
1804
|
-
* @param index
|
|
1805
|
-
*/
|
|
1806
|
-
_setTextureCubeData(texture, data) {
|
|
1807
|
-
if (this.texture?.props.dimension !== "cube") {
|
|
1808
|
-
throw new Error(this.id);
|
|
1809
|
-
}
|
|
1810
|
-
for (const [face, faceData] of Object.entries(data)) {
|
|
1811
|
-
const faceDepth = CubeFaces.indexOf(face);
|
|
1812
|
-
this._setTexture2DData(faceData, faceDepth);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
/**
|
|
1816
|
-
* Experimental: Sets texture array data, multiple levels, multiple depth slices
|
|
1817
|
-
* @param data
|
|
1818
|
-
*/
|
|
1819
|
-
_setTextureArrayData(texture, data) {
|
|
1820
|
-
if (this.texture?.props.dimension !== "2d-array") {
|
|
1821
|
-
throw new Error(this.id);
|
|
1822
|
-
}
|
|
1823
|
-
for (let depth = 0; depth < data.length; depth++) {
|
|
1824
|
-
this._setTexture2DData(data[depth], depth);
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
/**
|
|
1828
|
-
* Experimental: Sets texture cube array, multiple faces, multiple levels, multiple mip levels
|
|
1829
|
-
* @param data
|
|
1830
|
-
*/
|
|
1831
|
-
_setTextureCubeArrayData(texture, data) {
|
|
1832
|
-
throw new Error("setTextureCubeArrayData not supported in WebGL2.");
|
|
1833
|
-
}
|
|
1834
|
-
/** Experimental */
|
|
1835
|
-
_setTextureCubeFaceData(texture, lodData, face, depth = 0) {
|
|
1836
|
-
if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
|
|
1837
|
-
import_core8.log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
2629
|
+
_checkNotDestroyed() {
|
|
2630
|
+
if (this.destroyed) {
|
|
2631
|
+
import_core11.log.warn(`${this} already destroyed`);
|
|
1838
2632
|
}
|
|
1839
|
-
const faceDepth = TextureCubeFaces.indexOf(face);
|
|
1840
|
-
this._setTexture2DData(lodData, faceDepth);
|
|
1841
2633
|
}
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
* @param options
|
|
1846
|
-
* @returns array of TextureImageData / ExternalImages
|
|
1847
|
-
*/
|
|
1848
|
-
_normalizeTextureData(data) {
|
|
1849
|
-
const options = this.texture;
|
|
1850
|
-
let mipLevelArray;
|
|
1851
|
-
if (ArrayBuffer.isView(data)) {
|
|
1852
|
-
mipLevelArray = [
|
|
1853
|
-
{
|
|
1854
|
-
// ts-expect-error does data really need to be Uint8ClampedArray?
|
|
1855
|
-
data,
|
|
1856
|
-
width: options.width,
|
|
1857
|
-
height: options.height
|
|
1858
|
-
// depth: options.depth
|
|
1859
|
-
}
|
|
1860
|
-
];
|
|
1861
|
-
} else if (!Array.isArray(data)) {
|
|
1862
|
-
mipLevelArray = [data];
|
|
1863
|
-
} else {
|
|
1864
|
-
mipLevelArray = data;
|
|
2634
|
+
_checkReady() {
|
|
2635
|
+
if (!this.isReady) {
|
|
2636
|
+
import_core11.log.warn(`${this} Cannot perform this operation before ready`);
|
|
1865
2637
|
}
|
|
1866
|
-
return mipLevelArray;
|
|
1867
2638
|
}
|
|
1868
2639
|
};
|
|
1869
|
-
var
|
|
1870
|
-
__publicField(
|
|
1871
|
-
...
|
|
2640
|
+
var DynamicTexture = _DynamicTexture;
|
|
2641
|
+
__publicField(DynamicTexture, "defaultProps", {
|
|
2642
|
+
...import_core11.Texture.defaultProps,
|
|
2643
|
+
dimension: "2d",
|
|
1872
2644
|
data: null,
|
|
1873
2645
|
mipmaps: false
|
|
1874
2646
|
});
|
|
2647
|
+
function getAlignedUploadData(texture, data) {
|
|
2648
|
+
const { width, height, data: uploadData } = data;
|
|
2649
|
+
const { bytesPerPixel } = texture.device.getTextureFormatInfo(texture.format);
|
|
2650
|
+
const bytesPerRow = width * bytesPerPixel;
|
|
2651
|
+
const alignedBytesPerRow = Math.ceil(bytesPerRow / texture.byteAlignment) * texture.byteAlignment;
|
|
2652
|
+
if (alignedBytesPerRow === bytesPerRow) {
|
|
2653
|
+
return uploadData;
|
|
2654
|
+
}
|
|
2655
|
+
const sourceBytes = new Uint8Array(
|
|
2656
|
+
uploadData.buffer,
|
|
2657
|
+
uploadData.byteOffset,
|
|
2658
|
+
uploadData.byteLength
|
|
2659
|
+
);
|
|
2660
|
+
const paddedBytes = new Uint8Array(alignedBytesPerRow * height);
|
|
2661
|
+
for (let row = 0; row < height; row++) {
|
|
2662
|
+
const sourceOffset = row * bytesPerRow;
|
|
2663
|
+
const destinationOffset = row * alignedBytesPerRow;
|
|
2664
|
+
paddedBytes.set(
|
|
2665
|
+
sourceBytes.subarray(sourceOffset, sourceOffset + bytesPerRow),
|
|
2666
|
+
destinationOffset
|
|
2667
|
+
);
|
|
2668
|
+
}
|
|
2669
|
+
return paddedBytes;
|
|
2670
|
+
}
|
|
1875
2671
|
async function awaitAllPromises(x) {
|
|
1876
2672
|
x = await x;
|
|
1877
2673
|
if (Array.isArray(x)) {
|
|
@@ -1891,19 +2687,27 @@ var __exports__ = (() => {
|
|
|
1891
2687
|
}
|
|
1892
2688
|
|
|
1893
2689
|
// src/model/model.ts
|
|
1894
|
-
var
|
|
1895
|
-
var
|
|
2690
|
+
var LOG_DRAW_PRIORITY2 = 2;
|
|
2691
|
+
var LOG_DRAW_TIMEOUT2 = 1e4;
|
|
1896
2692
|
var _Model = class {
|
|
2693
|
+
/** Device that created this model */
|
|
1897
2694
|
device;
|
|
2695
|
+
/** Application provided identifier */
|
|
1898
2696
|
id;
|
|
2697
|
+
/** WGSL shader source when using unified shader */
|
|
1899
2698
|
// @ts-expect-error assigned in function called from constructor
|
|
1900
2699
|
source;
|
|
2700
|
+
/** GLSL vertex shader source */
|
|
1901
2701
|
// @ts-expect-error assigned in function called from constructor
|
|
1902
2702
|
vs;
|
|
2703
|
+
/** GLSL fragment shader source */
|
|
1903
2704
|
// @ts-expect-error assigned in function called from constructor
|
|
1904
2705
|
fs;
|
|
2706
|
+
/** Factory used to create render pipelines */
|
|
1905
2707
|
pipelineFactory;
|
|
2708
|
+
/** Factory used to create shaders */
|
|
1906
2709
|
shaderFactory;
|
|
2710
|
+
/** User-supplied per-model data */
|
|
1907
2711
|
userData = {};
|
|
1908
2712
|
// Fixed properties (change can trigger pipeline rebuild)
|
|
1909
2713
|
/** The render pipeline GPU parameters, depth testing etc */
|
|
@@ -1967,7 +2771,7 @@ var __exports__ = (() => {
|
|
|
1967
2771
|
);
|
|
1968
2772
|
const shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap, { disableWarnings: this.props.disableWarnings });
|
|
1969
2773
|
this.setShaderInputs(shaderInputs);
|
|
1970
|
-
const platformInfo =
|
|
2774
|
+
const platformInfo = getPlatformInfo2(device);
|
|
1971
2775
|
const modules = (
|
|
1972
2776
|
// @ts-ignore shaderInputs is assigned in setShaderInputs above.
|
|
1973
2777
|
(this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || []
|
|
@@ -1981,7 +2785,7 @@ var __exports__ = (() => {
|
|
|
1981
2785
|
});
|
|
1982
2786
|
this.source = source3;
|
|
1983
2787
|
this._getModuleUniforms = getUniforms2;
|
|
1984
|
-
this.props.shaderLayout ||=
|
|
2788
|
+
this.props.shaderLayout ||= device.getShaderLayout(this.source);
|
|
1985
2789
|
} else {
|
|
1986
2790
|
const { vs: vs3, fs: fs3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleGLSLShaderPair({
|
|
1987
2791
|
platformInfo,
|
|
@@ -2034,7 +2838,6 @@ var __exports__ = (() => {
|
|
|
2034
2838
|
if (props.transformFeedback) {
|
|
2035
2839
|
this.transformFeedback = props.transformFeedback;
|
|
2036
2840
|
}
|
|
2037
|
-
Object.seal(this);
|
|
2038
2841
|
}
|
|
2039
2842
|
destroy() {
|
|
2040
2843
|
if (!this._destroyed) {
|
|
@@ -2062,14 +2865,20 @@ var __exports__ = (() => {
|
|
|
2062
2865
|
setNeedsRedraw(reason) {
|
|
2063
2866
|
this._needsRedraw ||= reason;
|
|
2064
2867
|
}
|
|
2868
|
+
/** Update uniforms and pipeline state prior to drawing. */
|
|
2065
2869
|
predraw() {
|
|
2066
2870
|
this.updateShaderInputs();
|
|
2067
2871
|
this.pipeline = this._updatePipeline();
|
|
2068
2872
|
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Issue one draw call.
|
|
2875
|
+
* @param renderPass - render pass to draw into
|
|
2876
|
+
* @returns `true` if the draw call was executed, `false` if resources were not ready.
|
|
2877
|
+
*/
|
|
2069
2878
|
draw(renderPass) {
|
|
2070
2879
|
const loadingBinding = this._areBindingsLoading();
|
|
2071
2880
|
if (loadingBinding) {
|
|
2072
|
-
|
|
2881
|
+
import_core12.log.info(LOG_DRAW_PRIORITY2, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
|
|
2073
2882
|
return false;
|
|
2074
2883
|
}
|
|
2075
2884
|
try {
|
|
@@ -2199,7 +3008,7 @@ var __exports__ = (() => {
|
|
|
2199
3008
|
/** Set the shader inputs */
|
|
2200
3009
|
setShaderInputs(shaderInputs) {
|
|
2201
3010
|
this.shaderInputs = shaderInputs;
|
|
2202
|
-
this._uniformStore = new
|
|
3011
|
+
this._uniformStore = new import_core12.UniformStore(this.shaderInputs.modules);
|
|
2203
3012
|
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
2204
3013
|
if (shaderModuleHasUniforms(module)) {
|
|
2205
3014
|
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
@@ -2243,7 +3052,7 @@ var __exports__ = (() => {
|
|
|
2243
3052
|
setAttributes(buffers, options) {
|
|
2244
3053
|
const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
|
|
2245
3054
|
if (buffers["indices"]) {
|
|
2246
|
-
|
|
3055
|
+
import_core12.log.warn(
|
|
2247
3056
|
`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
|
|
2248
3057
|
)();
|
|
2249
3058
|
}
|
|
@@ -2256,7 +3065,7 @@ var __exports__ = (() => {
|
|
|
2256
3065
|
const bufferLayout = bufferLayoutHelper.getBufferLayout(bufferName);
|
|
2257
3066
|
if (!bufferLayout) {
|
|
2258
3067
|
if (!disableWarnings) {
|
|
2259
|
-
|
|
3068
|
+
import_core12.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
|
|
2260
3069
|
}
|
|
2261
3070
|
continue;
|
|
2262
3071
|
}
|
|
@@ -2271,7 +3080,7 @@ var __exports__ = (() => {
|
|
|
2271
3080
|
}
|
|
2272
3081
|
}
|
|
2273
3082
|
if (!set && !disableWarnings) {
|
|
2274
|
-
|
|
3083
|
+
import_core12.log.warn(
|
|
2275
3084
|
`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`
|
|
2276
3085
|
)();
|
|
2277
3086
|
}
|
|
@@ -2292,7 +3101,7 @@ var __exports__ = (() => {
|
|
|
2292
3101
|
if (attributeInfo) {
|
|
2293
3102
|
this.vertexArray.setConstantWebGL(attributeInfo.location, value);
|
|
2294
3103
|
} else if (!(options?.disableWarnings ?? this.props.disableWarnings)) {
|
|
2295
|
-
|
|
3104
|
+
import_core12.log.warn(
|
|
2296
3105
|
`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`
|
|
2297
3106
|
)();
|
|
2298
3107
|
}
|
|
@@ -2303,7 +3112,7 @@ var __exports__ = (() => {
|
|
|
2303
3112
|
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
|
|
2304
3113
|
_areBindingsLoading() {
|
|
2305
3114
|
for (const binding of Object.values(this.bindings)) {
|
|
2306
|
-
if (binding instanceof
|
|
3115
|
+
if (binding instanceof DynamicTexture && !binding.isReady) {
|
|
2307
3116
|
return binding.id;
|
|
2308
3117
|
}
|
|
2309
3118
|
}
|
|
@@ -2313,7 +3122,7 @@ var __exports__ = (() => {
|
|
|
2313
3122
|
_getBindings() {
|
|
2314
3123
|
const validBindings = {};
|
|
2315
3124
|
for (const [name, binding] of Object.entries(this.bindings)) {
|
|
2316
|
-
if (binding instanceof
|
|
3125
|
+
if (binding instanceof DynamicTexture) {
|
|
2317
3126
|
if (binding.isReady) {
|
|
2318
3127
|
validBindings[name] = binding.texture;
|
|
2319
3128
|
}
|
|
@@ -2327,16 +3136,16 @@ var __exports__ = (() => {
|
|
|
2327
3136
|
_getBindingsUpdateTimestamp() {
|
|
2328
3137
|
let timestamp = 0;
|
|
2329
3138
|
for (const binding of Object.values(this.bindings)) {
|
|
2330
|
-
if (binding instanceof
|
|
3139
|
+
if (binding instanceof import_core12.TextureView) {
|
|
2331
3140
|
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
2332
|
-
} else if (binding instanceof
|
|
3141
|
+
} else if (binding instanceof import_core12.Buffer || binding instanceof import_core12.Texture) {
|
|
2333
3142
|
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
2334
|
-
} else if (binding instanceof
|
|
3143
|
+
} else if (binding instanceof DynamicTexture) {
|
|
2335
3144
|
timestamp = binding.texture ? Math.max(timestamp, binding.texture.updateTimestamp) : (
|
|
2336
3145
|
// The texture will become available in the future
|
|
2337
3146
|
Infinity
|
|
2338
3147
|
);
|
|
2339
|
-
} else if (!(binding instanceof
|
|
3148
|
+
} else if (!(binding instanceof import_core12.Sampler)) {
|
|
2340
3149
|
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
2341
3150
|
}
|
|
2342
3151
|
}
|
|
@@ -2371,7 +3180,7 @@ var __exports__ = (() => {
|
|
|
2371
3180
|
let prevShaderVs = null;
|
|
2372
3181
|
let prevShaderFs = null;
|
|
2373
3182
|
if (this.pipeline) {
|
|
2374
|
-
|
|
3183
|
+
import_core12.log.log(
|
|
2375
3184
|
1,
|
|
2376
3185
|
`Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
|
|
2377
3186
|
)();
|
|
@@ -2407,7 +3216,7 @@ var __exports__ = (() => {
|
|
|
2407
3216
|
vs: vs3,
|
|
2408
3217
|
fs: fs3
|
|
2409
3218
|
});
|
|
2410
|
-
this._attributeInfos = (0,
|
|
3219
|
+
this._attributeInfos = (0, import_core12.getAttributeInfosFromLayouts)(
|
|
2411
3220
|
this.pipeline.shaderLayout,
|
|
2412
3221
|
this.bufferLayout
|
|
2413
3222
|
);
|
|
@@ -2422,24 +3231,24 @@ var __exports__ = (() => {
|
|
|
2422
3231
|
_lastLogTime = 0;
|
|
2423
3232
|
_logOpen = false;
|
|
2424
3233
|
_logDrawCallStart() {
|
|
2425
|
-
const logDrawTimeout =
|
|
2426
|
-
if (
|
|
3234
|
+
const logDrawTimeout = import_core12.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2;
|
|
3235
|
+
if (import_core12.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
|
|
2427
3236
|
return;
|
|
2428
3237
|
}
|
|
2429
3238
|
this._lastLogTime = Date.now();
|
|
2430
3239
|
this._logOpen = true;
|
|
2431
|
-
|
|
3240
|
+
import_core12.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core12.log.level <= 2 })();
|
|
2432
3241
|
}
|
|
2433
3242
|
_logDrawCallEnd() {
|
|
2434
3243
|
if (this._logOpen) {
|
|
2435
3244
|
const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
|
|
2436
|
-
|
|
3245
|
+
import_core12.log.table(LOG_DRAW_PRIORITY2, shaderLayoutTable)();
|
|
2437
3246
|
const uniformTable = this.shaderInputs.getDebugTable();
|
|
2438
|
-
|
|
3247
|
+
import_core12.log.table(LOG_DRAW_PRIORITY2, uniformTable)();
|
|
2439
3248
|
const attributeTable = this._getAttributeDebugTable();
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
3249
|
+
import_core12.log.table(LOG_DRAW_PRIORITY2, this._attributeInfos)();
|
|
3250
|
+
import_core12.log.table(LOG_DRAW_PRIORITY2, attributeTable)();
|
|
3251
|
+
import_core12.log.groupEnd(LOG_DRAW_PRIORITY2)();
|
|
2443
3252
|
this._logOpen = false;
|
|
2444
3253
|
}
|
|
2445
3254
|
}
|
|
@@ -2478,14 +3287,14 @@ var __exports__ = (() => {
|
|
|
2478
3287
|
}
|
|
2479
3288
|
// TODO - fix typing of luma data types
|
|
2480
3289
|
_getBufferOrConstantValues(attribute, dataType) {
|
|
2481
|
-
const TypedArrayConstructor = (0,
|
|
2482
|
-
const typedArray = attribute instanceof
|
|
3290
|
+
const TypedArrayConstructor = (0, import_core12.getTypedArrayConstructor)(dataType);
|
|
3291
|
+
const typedArray = attribute instanceof import_core12.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
2483
3292
|
return typedArray.toString();
|
|
2484
3293
|
}
|
|
2485
3294
|
};
|
|
2486
3295
|
var Model = _Model;
|
|
2487
3296
|
__publicField(Model, "defaultProps", {
|
|
2488
|
-
...
|
|
3297
|
+
...import_core12.RenderPipeline.defaultProps,
|
|
2489
3298
|
source: void 0,
|
|
2490
3299
|
vs: null,
|
|
2491
3300
|
fs: null,
|
|
@@ -2506,14 +3315,14 @@ var __exports__ = (() => {
|
|
|
2506
3315
|
pipelineFactory: void 0,
|
|
2507
3316
|
shaderFactory: void 0,
|
|
2508
3317
|
transformFeedback: void 0,
|
|
2509
|
-
shaderAssembler:
|
|
3318
|
+
shaderAssembler: import_shadertools3.ShaderAssembler.getDefaultShaderAssembler(),
|
|
2510
3319
|
debugShaders: void 0,
|
|
2511
3320
|
disableWarnings: void 0
|
|
2512
3321
|
});
|
|
2513
3322
|
function shaderModuleHasUniforms(module) {
|
|
2514
3323
|
return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
|
|
2515
3324
|
}
|
|
2516
|
-
function
|
|
3325
|
+
function getPlatformInfo2(device) {
|
|
2517
3326
|
return {
|
|
2518
3327
|
type: device.type,
|
|
2519
3328
|
shaderLanguage: device.info.shadingLanguage,
|
|
@@ -2531,8 +3340,8 @@ var __exports__ = (() => {
|
|
|
2531
3340
|
}
|
|
2532
3341
|
|
|
2533
3342
|
// src/compute/buffer-transform.ts
|
|
2534
|
-
var
|
|
2535
|
-
var
|
|
3343
|
+
var import_core13 = __toESM(require_core(), 1);
|
|
3344
|
+
var import_shadertools4 = __toESM(require_shadertools(), 1);
|
|
2536
3345
|
var _BufferTransform = class {
|
|
2537
3346
|
device;
|
|
2538
3347
|
model;
|
|
@@ -2547,7 +3356,7 @@ var __exports__ = (() => {
|
|
|
2547
3356
|
this.device = device;
|
|
2548
3357
|
this.model = new Model(this.device, {
|
|
2549
3358
|
id: props.id || "buffer-transform-model",
|
|
2550
|
-
fs: props.fs || (0,
|
|
3359
|
+
fs: props.fs || (0, import_shadertools4.getPassthroughFS)(),
|
|
2551
3360
|
topology: props.topology || "point-list",
|
|
2552
3361
|
varyings: props.outputs || props.varyings,
|
|
2553
3362
|
...props
|
|
@@ -2593,7 +3402,7 @@ var __exports__ = (() => {
|
|
|
2593
3402
|
if (!result) {
|
|
2594
3403
|
throw new Error("BufferTransform#getBuffer");
|
|
2595
3404
|
}
|
|
2596
|
-
if (result instanceof
|
|
3405
|
+
if (result instanceof import_core13.Buffer) {
|
|
2597
3406
|
return result.readAsync();
|
|
2598
3407
|
}
|
|
2599
3408
|
const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result;
|
|
@@ -2608,7 +3417,7 @@ var __exports__ = (() => {
|
|
|
2608
3417
|
});
|
|
2609
3418
|
|
|
2610
3419
|
// src/compute/texture-transform.ts
|
|
2611
|
-
var
|
|
3420
|
+
var import_shadertools5 = __toESM(require_shadertools(), 1);
|
|
2612
3421
|
var FS_OUTPUT_VARIABLE = "transform_output";
|
|
2613
3422
|
var TextureTransform = class {
|
|
2614
3423
|
device;
|
|
@@ -2631,7 +3440,7 @@ var __exports__ = (() => {
|
|
|
2631
3440
|
});
|
|
2632
3441
|
this.model = new Model(this.device, {
|
|
2633
3442
|
id: props.id || uid("texture-transform-model"),
|
|
2634
|
-
fs: props.fs || (0,
|
|
3443
|
+
fs: props.fs || (0, import_shadertools5.getPassthroughFS)({
|
|
2635
3444
|
input: props.targetTextureVarying,
|
|
2636
3445
|
inputChannels: props.targetTextureChannels,
|
|
2637
3446
|
output: FS_OUTPUT_VARIABLE
|
|
@@ -2871,22 +3680,31 @@ ${props.source}` };
|
|
|
2871
3680
|
};
|
|
2872
3681
|
|
|
2873
3682
|
// src/models/billboard-texture-model.ts
|
|
3683
|
+
var backgroundModule = {
|
|
3684
|
+
name: "background",
|
|
3685
|
+
uniformTypes: {
|
|
3686
|
+
scale: "vec2<f32>"
|
|
3687
|
+
}
|
|
3688
|
+
};
|
|
2874
3689
|
var BACKGROUND_FS_WGSL = (
|
|
2875
3690
|
/* wgsl */
|
|
2876
3691
|
`@group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
|
|
2877
3692
|
@group(0) @binding(1) var backgroundTextureSampler: sampler;
|
|
3693
|
+
struct backgroundUniforms {
|
|
3694
|
+
scale: vec2<f32>,
|
|
3695
|
+
};
|
|
3696
|
+
@group(0) @binding(2) var<uniform> background: backgroundUniforms;
|
|
2878
3697
|
|
|
2879
3698
|
fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
}
|
|
3699
|
+
let scale: vec2<f32> = background.scale;
|
|
3700
|
+
var position: vec2<f32> = (coordinates - vec2<f32>(0.5, 0.5)) / scale + vec2<f32>(0.5, 0.5);
|
|
3701
|
+
return position;
|
|
3702
|
+
}
|
|
2885
3703
|
|
|
2886
3704
|
@fragment
|
|
2887
3705
|
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
|
|
2888
|
-
|
|
2889
|
-
|
|
3706
|
+
let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
|
|
3707
|
+
return textureSample(backgroundTexture, backgroundTextureSampler, position);
|
|
2890
3708
|
}
|
|
2891
3709
|
`
|
|
2892
3710
|
);
|
|
@@ -2896,27 +3714,33 @@ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
|
|
|
2896
3714
|
precision highp float;
|
|
2897
3715
|
|
|
2898
3716
|
uniform sampler2D backgroundTexture;
|
|
3717
|
+
|
|
3718
|
+
uniform backgroundUniforms {
|
|
3719
|
+
vec2 scale;
|
|
3720
|
+
} background;
|
|
3721
|
+
|
|
3722
|
+
in vec2 coordinate;
|
|
2899
3723
|
out vec4 fragColor;
|
|
2900
3724
|
|
|
2901
|
-
vec2 billboardTexture_getTextureUV() {
|
|
2902
|
-
|
|
2903
|
-
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
|
|
2904
|
-
vec2 position = gl_FragCoord.xy / texSize;
|
|
3725
|
+
vec2 billboardTexture_getTextureUV(vec2 coord) {
|
|
3726
|
+
vec2 position = (coord - 0.5) / background.scale + 0.5;
|
|
2905
3727
|
return position;
|
|
2906
3728
|
}
|
|
2907
3729
|
|
|
2908
3730
|
void main(void) {
|
|
2909
|
-
vec2 position = billboardTexture_getTextureUV();
|
|
3731
|
+
vec2 position = billboardTexture_getTextureUV(coordinate);
|
|
2910
3732
|
fragColor = texture(backgroundTexture, position);
|
|
2911
3733
|
}
|
|
2912
3734
|
`
|
|
2913
3735
|
);
|
|
2914
3736
|
var BackgroundTextureModel = class extends ClipSpace {
|
|
3737
|
+
backgroundTexture = null;
|
|
2915
3738
|
constructor(device, props) {
|
|
2916
3739
|
super(device, {
|
|
2917
3740
|
id: props.id || "background-texture-model",
|
|
2918
3741
|
source: BACKGROUND_FS_WGSL,
|
|
2919
3742
|
fs: BACKGROUND_FS,
|
|
3743
|
+
modules: [backgroundModule],
|
|
2920
3744
|
parameters: {
|
|
2921
3745
|
depthWriteEnabled: false,
|
|
2922
3746
|
...props.blend ? {
|
|
@@ -2933,17 +3757,47 @@ void main(void) {
|
|
|
2933
3757
|
if (!props.backgroundTexture) {
|
|
2934
3758
|
throw new Error("BackgroundTextureModel requires a backgroundTexture prop");
|
|
2935
3759
|
}
|
|
2936
|
-
this.
|
|
3760
|
+
this.setProps(props);
|
|
2937
3761
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3762
|
+
/** Update the background texture */
|
|
3763
|
+
setProps(props) {
|
|
3764
|
+
const { backgroundTexture } = props;
|
|
3765
|
+
if (backgroundTexture) {
|
|
3766
|
+
this.setBindings({ backgroundTexture });
|
|
3767
|
+
if (backgroundTexture.isReady) {
|
|
3768
|
+
const texture = backgroundTexture instanceof DynamicTexture ? backgroundTexture.texture : backgroundTexture;
|
|
3769
|
+
this.backgroundTexture = texture;
|
|
3770
|
+
this.updateScale(texture);
|
|
3771
|
+
} else {
|
|
3772
|
+
backgroundTexture.ready.then((texture) => {
|
|
3773
|
+
this.backgroundTexture = texture;
|
|
3774
|
+
this.updateScale(texture);
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
2942
3778
|
}
|
|
2943
3779
|
predraw() {
|
|
2944
|
-
this.shaderInputs.setProps({});
|
|
2945
3780
|
super.predraw();
|
|
2946
3781
|
}
|
|
3782
|
+
updateScale(texture) {
|
|
3783
|
+
if (!texture) {
|
|
3784
|
+
this.shaderInputs.setProps({ background: { scale: [1, 1] } });
|
|
3785
|
+
return;
|
|
3786
|
+
}
|
|
3787
|
+
const [screenWidth, screenHeight] = this.device.getCanvasContext().getDrawingBufferSize();
|
|
3788
|
+
const textureWidth = texture.width;
|
|
3789
|
+
const textureHeight = texture.height;
|
|
3790
|
+
const screenAspect = screenWidth / screenHeight;
|
|
3791
|
+
const textureAspect = textureWidth / textureHeight;
|
|
3792
|
+
let scaleX = 1;
|
|
3793
|
+
let scaleY = 1;
|
|
3794
|
+
if (screenAspect > textureAspect) {
|
|
3795
|
+
scaleY = screenAspect / textureAspect;
|
|
3796
|
+
} else {
|
|
3797
|
+
scaleX = textureAspect / screenAspect;
|
|
3798
|
+
}
|
|
3799
|
+
this.shaderInputs.setProps({ background: { scale: [scaleX, scaleY] } });
|
|
3800
|
+
}
|
|
2947
3801
|
};
|
|
2948
3802
|
|
|
2949
3803
|
// ../../node_modules/@math.gl/core/dist/lib/common.js
|
|
@@ -5125,13 +5979,13 @@ void main(void) {
|
|
|
5125
5979
|
};
|
|
5126
5980
|
|
|
5127
5981
|
// src/scenegraph/group-node.ts
|
|
5128
|
-
var
|
|
5982
|
+
var import_core16 = __toESM(require_core(), 1);
|
|
5129
5983
|
var GroupNode = class extends ScenegraphNode {
|
|
5130
5984
|
children;
|
|
5131
5985
|
constructor(props = {}) {
|
|
5132
5986
|
props = Array.isArray(props) ? { children: props } : props;
|
|
5133
5987
|
const { children = [] } = props;
|
|
5134
|
-
|
|
5988
|
+
import_core16.log.assert(
|
|
5135
5989
|
children.every((child) => child instanceof ScenegraphNode),
|
|
5136
5990
|
"every child must an instance of ScenegraphNode"
|
|
5137
5991
|
);
|
|
@@ -6345,17 +7199,45 @@ void main(void) {
|
|
|
6345
7199
|
return n - Math.floor(n);
|
|
6346
7200
|
}
|
|
6347
7201
|
|
|
7202
|
+
// src/application-utils/load-file.ts
|
|
7203
|
+
var pathPrefix = "";
|
|
7204
|
+
function setPathPrefix(prefix) {
|
|
7205
|
+
pathPrefix = prefix;
|
|
7206
|
+
}
|
|
7207
|
+
async function loadImageBitmap(url, opts) {
|
|
7208
|
+
const image = new Image();
|
|
7209
|
+
image.crossOrigin = opts?.crossOrigin || "anonymous";
|
|
7210
|
+
image.src = url.startsWith("http") ? url : pathPrefix + url;
|
|
7211
|
+
await image.decode();
|
|
7212
|
+
return opts ? await createImageBitmap(image, opts) : await createImageBitmap(image);
|
|
7213
|
+
}
|
|
7214
|
+
async function loadImage(url, opts) {
|
|
7215
|
+
return await new Promise((resolve, reject) => {
|
|
7216
|
+
try {
|
|
7217
|
+
const image = new Image();
|
|
7218
|
+
image.onload = () => resolve(image);
|
|
7219
|
+
image.onerror = () => reject(new Error(`Could not load image ${url}.`));
|
|
7220
|
+
image.crossOrigin = opts?.crossOrigin || "anonymous";
|
|
7221
|
+
image.src = url.startsWith("http") ? url : pathPrefix + url;
|
|
7222
|
+
} catch (error) {
|
|
7223
|
+
reject(error);
|
|
7224
|
+
}
|
|
7225
|
+
});
|
|
7226
|
+
}
|
|
7227
|
+
|
|
6348
7228
|
// src/passes/shader-pass-renderer.ts
|
|
6349
|
-
var
|
|
7229
|
+
var import_shadertools6 = __toESM(require_shadertools(), 1);
|
|
6350
7230
|
|
|
6351
7231
|
// src/compute/swap.ts
|
|
6352
|
-
var
|
|
7232
|
+
var import_core18 = __toESM(require_core(), 1);
|
|
6353
7233
|
var Swap = class {
|
|
7234
|
+
id;
|
|
6354
7235
|
/** The current resource - usually the source for renders or computations */
|
|
6355
7236
|
current;
|
|
6356
7237
|
/** The next resource - usually the target/destination for transforms / computations */
|
|
6357
7238
|
next;
|
|
6358
7239
|
constructor(props) {
|
|
7240
|
+
this.id = props.id || "swap";
|
|
6359
7241
|
this.current = props.current;
|
|
6360
7242
|
this.next = props.next;
|
|
6361
7243
|
}
|
|
@@ -6374,21 +7256,24 @@ void main(void) {
|
|
|
6374
7256
|
var SwapFramebuffers = class extends Swap {
|
|
6375
7257
|
constructor(device, props) {
|
|
6376
7258
|
props = { ...props };
|
|
7259
|
+
const { width = 1, height = 1 } = props;
|
|
6377
7260
|
let colorAttachments = props.colorAttachments?.map(
|
|
6378
7261
|
(colorAttachment) => typeof colorAttachment !== "string" ? colorAttachment : device.createTexture({
|
|
7262
|
+
id: `${props.id}-texture-0`,
|
|
6379
7263
|
format: colorAttachment,
|
|
6380
|
-
usage:
|
|
6381
|
-
width
|
|
6382
|
-
height
|
|
7264
|
+
usage: import_core18.Texture.SAMPLE | import_core18.Texture.RENDER | import_core18.Texture.COPY_SRC | import_core18.Texture.COPY_DST,
|
|
7265
|
+
width,
|
|
7266
|
+
height
|
|
6383
7267
|
})
|
|
6384
7268
|
);
|
|
6385
7269
|
const current = device.createFramebuffer({ ...props, colorAttachments });
|
|
6386
7270
|
colorAttachments = props.colorAttachments?.map(
|
|
6387
7271
|
(colorAttachment) => typeof colorAttachment !== "string" ? colorAttachment : device.createTexture({
|
|
7272
|
+
id: `${props.id}-texture-1`,
|
|
6388
7273
|
format: colorAttachment,
|
|
6389
|
-
usage:
|
|
6390
|
-
width
|
|
6391
|
-
height
|
|
7274
|
+
usage: import_core18.Texture.SAMPLE | import_core18.Texture.RENDER | import_core18.Texture.COPY_SRC | import_core18.Texture.COPY_DST,
|
|
7275
|
+
width,
|
|
7276
|
+
height
|
|
6392
7277
|
})
|
|
6393
7278
|
);
|
|
6394
7279
|
const next = device.createFramebuffer({ ...props, colorAttachments });
|
|
@@ -6453,19 +7338,23 @@ void main(void) {
|
|
|
6453
7338
|
`// Binding 0:1 is reserved for shader passes
|
|
6454
7339
|
// @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
|
|
6455
7340
|
@group(0) @binding(1) var texture: texture_2d<f32>;
|
|
6456
|
-
@group(0) @binding(2) var
|
|
7341
|
+
@group(0) @binding(2) var textureSampler: sampler;
|
|
6457
7342
|
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
7343
|
+
// This needs to be aligned with
|
|
7344
|
+
// struct FragmentInputs {
|
|
7345
|
+
// @location(0) fragUV: vec2f,
|
|
7346
|
+
// @location(1) fragPosition: vec4f,
|
|
7347
|
+
// @location(2) fragCoordinate: vec4f
|
|
7348
|
+
// };
|
|
6463
7349
|
|
|
6464
7350
|
@fragment
|
|
6465
7351
|
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
|
|
6466
|
-
let
|
|
6467
|
-
|
|
6468
|
-
|
|
7352
|
+
let fragUV = inputs.uv;
|
|
7353
|
+
let fragCoordinate = inputs.coordinate;
|
|
7354
|
+
let texSize = vec2f(textureDimensions(texture, 0));
|
|
7355
|
+
|
|
7356
|
+
var fragColor = textureSample(texture, textureSampler, fragUV);
|
|
7357
|
+
fragColor = ${func}(fragColor, texSize, fragCoordinate);
|
|
6469
7358
|
return fragColor;
|
|
6470
7359
|
}
|
|
6471
7360
|
`
|
|
@@ -6487,9 +7376,9 @@ struct FragmentInputs = {
|
|
|
6487
7376
|
|
|
6488
7377
|
@fragment
|
|
6489
7378
|
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
|
|
6490
|
-
let texSize = textureDimensions(texture, 0);
|
|
7379
|
+
let texSize = vec2f(textureDimensions(texture, 0));
|
|
6491
7380
|
var fragColor = textureSample(texture, sampler, fragUV);
|
|
6492
|
-
fragColor = ${func}(
|
|
7381
|
+
fragColor = ${func}(fragColor, texSize, texCoord);
|
|
6493
7382
|
return fragColor;
|
|
6494
7383
|
}
|
|
6495
7384
|
`
|
|
@@ -6554,7 +7443,7 @@ void main() {
|
|
|
6554
7443
|
textureModel;
|
|
6555
7444
|
constructor(device, props) {
|
|
6556
7445
|
this.device = device;
|
|
6557
|
-
props.shaderPasses.map((shaderPass) => (0,
|
|
7446
|
+
props.shaderPasses.map((shaderPass) => (0, import_shadertools6.initializeShaderModule)(shaderPass));
|
|
6558
7447
|
const modules = props.shaderPasses.reduce(
|
|
6559
7448
|
(object, shaderPass) => ({ ...object, [shaderPass.name]: shaderPass }),
|
|
6560
7449
|
{}
|
|
@@ -6588,12 +7477,10 @@ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
|
|
|
6588
7477
|
|
|
6589
7478
|
uniform sampler2D sourceTexture;
|
|
6590
7479
|
in vec2 uv;
|
|
6591
|
-
in vec2 coordinate;
|
|
6592
7480
|
out vec4 fragColor;
|
|
6593
7481
|
|
|
6594
7482
|
void main() {
|
|
6595
|
-
|
|
6596
|
-
fragColor = texture(sourceTexture, coordinate);
|
|
7483
|
+
fragColor = texture(sourceTexture, uv);
|
|
6597
7484
|
}
|
|
6598
7485
|
`
|
|
6599
7486
|
)
|
|
@@ -6607,9 +7494,11 @@ void main() {
|
|
|
6607
7494
|
}
|
|
6608
7495
|
this.swapFramebuffers.destroy();
|
|
6609
7496
|
this.clipSpace.destroy();
|
|
7497
|
+
this.textureModel.destroy();
|
|
6610
7498
|
}
|
|
6611
|
-
resize(
|
|
6612
|
-
this.
|
|
7499
|
+
resize(size) {
|
|
7500
|
+
size ||= this.device.getCanvasContext().getDrawingBufferSize();
|
|
7501
|
+
this.swapFramebuffers.resize({ width: size[0], height: size[1] });
|
|
6613
7502
|
}
|
|
6614
7503
|
renderToScreen(options) {
|
|
6615
7504
|
const outputTexture = this.renderToTexture(options);
|
|
@@ -6620,7 +7509,7 @@ void main() {
|
|
|
6620
7509
|
const renderPass = this.device.beginRenderPass({
|
|
6621
7510
|
id: "shader-pass-renderer-to-screen",
|
|
6622
7511
|
framebuffer,
|
|
6623
|
-
clearColor: [
|
|
7512
|
+
// clearColor: [1, 1, 0, 1],
|
|
6624
7513
|
clearDepth: 1
|
|
6625
7514
|
});
|
|
6626
7515
|
this.clipSpace.setBindings({ sourceTexture: outputTexture });
|
|
@@ -6636,14 +7525,14 @@ void main() {
|
|
|
6636
7525
|
if (!sourceTexture.isReady) {
|
|
6637
7526
|
return null;
|
|
6638
7527
|
}
|
|
6639
|
-
this.
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
});
|
|
7528
|
+
if (this.passRenderers.length === 0) {
|
|
7529
|
+
return sourceTexture.texture;
|
|
7530
|
+
}
|
|
7531
|
+
this.textureModel.setProps({ backgroundTexture: sourceTexture });
|
|
6643
7532
|
const clearTexturePass = this.device.beginRenderPass({
|
|
6644
7533
|
id: "shader-pass-renderer-clear-texture",
|
|
6645
7534
|
framebuffer: this.swapFramebuffers.current,
|
|
6646
|
-
clearColor: [
|
|
7535
|
+
clearColor: [1, 0, 0, 1]
|
|
6647
7536
|
});
|
|
6648
7537
|
this.textureModel.draw(clearTexturePass);
|
|
6649
7538
|
clearTexturePass.end();
|
|
@@ -6729,221 +7618,6 @@ void main() {
|
|
|
6729
7618
|
}
|
|
6730
7619
|
};
|
|
6731
7620
|
|
|
6732
|
-
// src/compute/computation.ts
|
|
6733
|
-
var import_core16 = __toESM(require_core(), 1);
|
|
6734
|
-
var import_shadertools6 = __toESM(require_shadertools(), 1);
|
|
6735
|
-
var LOG_DRAW_PRIORITY2 = 2;
|
|
6736
|
-
var LOG_DRAW_TIMEOUT2 = 1e4;
|
|
6737
|
-
var _Computation = class {
|
|
6738
|
-
device;
|
|
6739
|
-
id;
|
|
6740
|
-
pipelineFactory;
|
|
6741
|
-
shaderFactory;
|
|
6742
|
-
userData = {};
|
|
6743
|
-
/** Bindings (textures, samplers, uniform buffers) */
|
|
6744
|
-
bindings = {};
|
|
6745
|
-
/** The underlying GPU pipeline. */
|
|
6746
|
-
pipeline;
|
|
6747
|
-
/** Assembled compute shader source */
|
|
6748
|
-
source;
|
|
6749
|
-
/** the underlying compiled compute shader */
|
|
6750
|
-
// @ts-ignore Set in function called from constructor
|
|
6751
|
-
shader;
|
|
6752
|
-
/** ShaderInputs instance */
|
|
6753
|
-
shaderInputs;
|
|
6754
|
-
// @ts-ignore Set in function called from constructor
|
|
6755
|
-
_uniformStore;
|
|
6756
|
-
_pipelineNeedsUpdate = "newly created";
|
|
6757
|
-
_getModuleUniforms;
|
|
6758
|
-
props;
|
|
6759
|
-
_destroyed = false;
|
|
6760
|
-
constructor(device, props) {
|
|
6761
|
-
if (device.type !== "webgpu") {
|
|
6762
|
-
throw new Error("Computation is only supported in WebGPU");
|
|
6763
|
-
}
|
|
6764
|
-
this.props = { ..._Computation.defaultProps, ...props };
|
|
6765
|
-
props = this.props;
|
|
6766
|
-
this.id = props.id || uid("model");
|
|
6767
|
-
this.device = device;
|
|
6768
|
-
Object.assign(this.userData, props.userData);
|
|
6769
|
-
const moduleMap = Object.fromEntries(
|
|
6770
|
-
this.props.modules?.map((module) => [module.name, module]) || []
|
|
6771
|
-
);
|
|
6772
|
-
this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
|
|
6773
|
-
this.setShaderInputs(this.shaderInputs);
|
|
6774
|
-
this.props.shaderLayout ||= (0, import_shadertools6.getShaderLayoutFromWGSL)(this.props.source);
|
|
6775
|
-
const platformInfo = getPlatformInfo2(device);
|
|
6776
|
-
const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
6777
|
-
this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
6778
|
-
this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
|
|
6779
|
-
const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
|
|
6780
|
-
platformInfo,
|
|
6781
|
-
...this.props,
|
|
6782
|
-
modules
|
|
6783
|
-
});
|
|
6784
|
-
this.source = source3;
|
|
6785
|
-
this._getModuleUniforms = getUniforms2;
|
|
6786
|
-
this.pipeline = this._updatePipeline();
|
|
6787
|
-
if (props.bindings) {
|
|
6788
|
-
this.setBindings(props.bindings);
|
|
6789
|
-
}
|
|
6790
|
-
Object.seal(this);
|
|
6791
|
-
}
|
|
6792
|
-
destroy() {
|
|
6793
|
-
if (this._destroyed)
|
|
6794
|
-
return;
|
|
6795
|
-
this.pipelineFactory.release(this.pipeline);
|
|
6796
|
-
this.shaderFactory.release(this.shader);
|
|
6797
|
-
this._uniformStore.destroy();
|
|
6798
|
-
this._destroyed = true;
|
|
6799
|
-
}
|
|
6800
|
-
// Draw call
|
|
6801
|
-
predraw() {
|
|
6802
|
-
this.updateShaderInputs();
|
|
6803
|
-
}
|
|
6804
|
-
dispatch(computePass, x, y, z) {
|
|
6805
|
-
try {
|
|
6806
|
-
this._logDrawCallStart();
|
|
6807
|
-
this.pipeline = this._updatePipeline();
|
|
6808
|
-
this.pipeline.setBindings(this.bindings);
|
|
6809
|
-
computePass.setPipeline(this.pipeline);
|
|
6810
|
-
computePass.setBindings([]);
|
|
6811
|
-
computePass.dispatch(x, y, z);
|
|
6812
|
-
} finally {
|
|
6813
|
-
this._logDrawCallEnd();
|
|
6814
|
-
}
|
|
6815
|
-
}
|
|
6816
|
-
// Update fixed fields (can trigger pipeline rebuild)
|
|
6817
|
-
// Update dynamic fields
|
|
6818
|
-
/**
|
|
6819
|
-
* Updates the vertex count (used in draw calls)
|
|
6820
|
-
* @note Any attributes with stepMode=vertex need to be at least this big
|
|
6821
|
-
*/
|
|
6822
|
-
setVertexCount(vertexCount) {
|
|
6823
|
-
}
|
|
6824
|
-
/**
|
|
6825
|
-
* Updates the instance count (used in draw calls)
|
|
6826
|
-
* @note Any attributes with stepMode=instance need to be at least this big
|
|
6827
|
-
*/
|
|
6828
|
-
setInstanceCount(instanceCount) {
|
|
6829
|
-
}
|
|
6830
|
-
setShaderInputs(shaderInputs) {
|
|
6831
|
-
this.shaderInputs = shaderInputs;
|
|
6832
|
-
this._uniformStore = new import_core16.UniformStore(this.shaderInputs.modules);
|
|
6833
|
-
for (const moduleName of Object.keys(this.shaderInputs.modules)) {
|
|
6834
|
-
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
6835
|
-
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
6836
|
-
}
|
|
6837
|
-
}
|
|
6838
|
-
/**
|
|
6839
|
-
* Updates shader module settings (which results in uniforms being set)
|
|
6840
|
-
*/
|
|
6841
|
-
setShaderModuleProps(props) {
|
|
6842
|
-
const uniforms = this._getModuleUniforms(props);
|
|
6843
|
-
const keys = Object.keys(uniforms).filter((k) => {
|
|
6844
|
-
const uniform = uniforms[k];
|
|
6845
|
-
return !isNumericArray(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
|
|
6846
|
-
});
|
|
6847
|
-
const bindings = {};
|
|
6848
|
-
for (const k of keys) {
|
|
6849
|
-
bindings[k] = uniforms[k];
|
|
6850
|
-
delete uniforms[k];
|
|
6851
|
-
}
|
|
6852
|
-
}
|
|
6853
|
-
updateShaderInputs() {
|
|
6854
|
-
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
6855
|
-
}
|
|
6856
|
-
/**
|
|
6857
|
-
* Sets bindings (textures, samplers, uniform buffers)
|
|
6858
|
-
*/
|
|
6859
|
-
setBindings(bindings) {
|
|
6860
|
-
Object.assign(this.bindings, bindings);
|
|
6861
|
-
}
|
|
6862
|
-
_setPipelineNeedsUpdate(reason) {
|
|
6863
|
-
this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
|
|
6864
|
-
}
|
|
6865
|
-
_updatePipeline() {
|
|
6866
|
-
if (this._pipelineNeedsUpdate) {
|
|
6867
|
-
let prevShader = null;
|
|
6868
|
-
if (this.pipeline) {
|
|
6869
|
-
import_core16.log.log(
|
|
6870
|
-
1,
|
|
6871
|
-
`Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
|
|
6872
|
-
)();
|
|
6873
|
-
prevShader = this.shader;
|
|
6874
|
-
}
|
|
6875
|
-
this._pipelineNeedsUpdate = false;
|
|
6876
|
-
this.shader = this.shaderFactory.createShader({
|
|
6877
|
-
id: `${this.id}-fragment`,
|
|
6878
|
-
stage: "compute",
|
|
6879
|
-
source: this.source,
|
|
6880
|
-
debugShaders: this.props.debugShaders
|
|
6881
|
-
});
|
|
6882
|
-
this.pipeline = this.pipelineFactory.createComputePipeline({
|
|
6883
|
-
...this.props,
|
|
6884
|
-
shader: this.shader
|
|
6885
|
-
});
|
|
6886
|
-
if (prevShader) {
|
|
6887
|
-
this.shaderFactory.release(prevShader);
|
|
6888
|
-
}
|
|
6889
|
-
}
|
|
6890
|
-
return this.pipeline;
|
|
6891
|
-
}
|
|
6892
|
-
/** Throttle draw call logging */
|
|
6893
|
-
_lastLogTime = 0;
|
|
6894
|
-
_logOpen = false;
|
|
6895
|
-
_logDrawCallStart() {
|
|
6896
|
-
const logDrawTimeout = import_core16.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2;
|
|
6897
|
-
if (import_core16.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
|
|
6898
|
-
return;
|
|
6899
|
-
}
|
|
6900
|
-
this._lastLogTime = Date.now();
|
|
6901
|
-
this._logOpen = true;
|
|
6902
|
-
import_core16.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core16.log.level <= 2 })();
|
|
6903
|
-
}
|
|
6904
|
-
_logDrawCallEnd() {
|
|
6905
|
-
if (this._logOpen) {
|
|
6906
|
-
const uniformTable = this.shaderInputs.getDebugTable();
|
|
6907
|
-
import_core16.log.table(LOG_DRAW_PRIORITY2, uniformTable)();
|
|
6908
|
-
import_core16.log.groupEnd(LOG_DRAW_PRIORITY2)();
|
|
6909
|
-
this._logOpen = false;
|
|
6910
|
-
}
|
|
6911
|
-
}
|
|
6912
|
-
_drawCount = 0;
|
|
6913
|
-
// TODO - fix typing of luma data types
|
|
6914
|
-
_getBufferOrConstantValues(attribute, dataType) {
|
|
6915
|
-
const TypedArrayConstructor = (0, import_core16.getTypedArrayConstructor)(dataType);
|
|
6916
|
-
const typedArray = attribute instanceof import_core16.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
6917
|
-
return typedArray.toString();
|
|
6918
|
-
}
|
|
6919
|
-
};
|
|
6920
|
-
var Computation = _Computation;
|
|
6921
|
-
__publicField(Computation, "defaultProps", {
|
|
6922
|
-
...import_core16.ComputePipeline.defaultProps,
|
|
6923
|
-
id: "unnamed",
|
|
6924
|
-
handle: void 0,
|
|
6925
|
-
userData: {},
|
|
6926
|
-
source: "",
|
|
6927
|
-
modules: [],
|
|
6928
|
-
defines: {},
|
|
6929
|
-
bindings: void 0,
|
|
6930
|
-
shaderInputs: void 0,
|
|
6931
|
-
pipelineFactory: void 0,
|
|
6932
|
-
shaderFactory: void 0,
|
|
6933
|
-
shaderAssembler: import_shadertools6.ShaderAssembler.getDefaultShaderAssembler(),
|
|
6934
|
-
debugShaders: void 0
|
|
6935
|
-
});
|
|
6936
|
-
function getPlatformInfo2(device) {
|
|
6937
|
-
return {
|
|
6938
|
-
type: device.type,
|
|
6939
|
-
shaderLanguage: device.info.shadingLanguage,
|
|
6940
|
-
shaderLanguageVersion: device.info.shadingLanguageVersion,
|
|
6941
|
-
gpu: device.info.gpu,
|
|
6942
|
-
// HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
|
|
6943
|
-
features: device.features
|
|
6944
|
-
};
|
|
6945
|
-
}
|
|
6946
|
-
|
|
6947
7621
|
// src/modules/picking/picking-uniforms.ts
|
|
6948
7622
|
var DEFAULT_HIGHLIGHT_COLOR = [0, 1, 1, 1];
|
|
6949
7623
|
var INVALID_INDEX = -1;
|
|
@@ -7480,6 +8154,9 @@ vec4 picking_filterColor(vec4 color) {
|
|
|
7480
8154
|
return [pickX, pickY];
|
|
7481
8155
|
}
|
|
7482
8156
|
};
|
|
8157
|
+
|
|
8158
|
+
// src/index.ts
|
|
8159
|
+
var AsyncTexture = DynamicTexture;
|
|
7483
8160
|
return __toCommonJS(bundle_exports);
|
|
7484
8161
|
})();
|
|
7485
8162
|
return __exports__;
|