@luma.gl/engine 9.0.0-beta.1 → 9.0.0-beta.10

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.
Files changed (154) hide show
  1. package/dist/animation/key-frames.js +54 -54
  2. package/dist/animation/timeline.d.ts.map +1 -1
  3. package/dist/animation/timeline.js +95 -100
  4. package/dist/animation-loop/animation-loop-template.d.ts +1 -1
  5. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
  6. package/dist/animation-loop/animation-loop-template.js +19 -5
  7. package/dist/animation-loop/animation-loop.d.ts +2 -2
  8. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-loop.js +433 -356
  10. package/dist/animation-loop/animation-props.d.ts +2 -2
  11. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  12. package/dist/animation-loop/animation-props.js +0 -1
  13. package/dist/animation-loop/make-animation-loop.d.ts +2 -2
  14. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  15. package/dist/animation-loop/make-animation-loop.js +28 -24
  16. package/dist/computation.d.ts +95 -0
  17. package/dist/computation.d.ts.map +1 -0
  18. package/dist/computation.js +248 -0
  19. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  20. package/dist/debug/copy-texture-to-image.js +39 -42
  21. package/dist/debug/debug-framebuffer.d.ts.map +1 -1
  22. package/dist/debug/debug-framebuffer.js +43 -40
  23. package/dist/debug/debug-shader-layout.js +24 -25
  24. package/dist/debug/pixel-data-utils.d.ts.map +1 -1
  25. package/dist/debug/pixel-data-utils.js +34 -36
  26. package/dist/dist.dev.js +2538 -3027
  27. package/dist/dist.min.js +102 -0
  28. package/dist/geometries/cone-geometry.d.ts +1 -1
  29. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  30. package/dist/geometries/cone-geometry.js +11 -17
  31. package/dist/geometries/cube-geometry.d.ts +1 -1
  32. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  33. package/dist/geometries/cube-geometry.js +190 -61
  34. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  35. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  36. package/dist/geometries/cylinder-geometry.js +9 -14
  37. package/dist/geometries/ico-sphere-geometry.d.ts +1 -1
  38. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  39. package/dist/geometries/ico-sphere-geometry.js +141 -160
  40. package/dist/geometries/plane-geometry.d.ts +1 -1
  41. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  42. package/dist/geometries/plane-geometry.js +92 -110
  43. package/dist/geometries/sphere-geometry.d.ts +1 -1
  44. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  45. package/dist/geometries/sphere-geometry.js +76 -95
  46. package/dist/geometries/truncated-cone-geometry.d.ts +1 -1
  47. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  48. package/dist/geometries/truncated-cone-geometry.js +99 -117
  49. package/dist/geometry/geometry-table.d.ts.map +1 -1
  50. package/dist/geometry/geometry-table.js +3 -1
  51. package/dist/geometry/geometry-utils.js +35 -32
  52. package/dist/geometry/geometry.d.ts.map +1 -1
  53. package/dist/geometry/geometry.js +80 -71
  54. package/dist/geometry/gpu-geometry.d.ts +1 -1
  55. package/dist/geometry/gpu-geometry.d.ts.map +1 -1
  56. package/dist/geometry/gpu-geometry.js +79 -99
  57. package/dist/geometry/gpu-table.js +41 -1
  58. package/dist/index.cjs +725 -409
  59. package/dist/index.cjs.map +7 -0
  60. package/dist/index.d.ts +43 -40
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +6 -1
  63. package/dist/lib/clip-space.d.ts +2 -2
  64. package/dist/lib/clip-space.d.ts.map +1 -1
  65. package/dist/lib/clip-space.js +28 -34
  66. package/dist/lib/pipeline-factory.d.ts +13 -14
  67. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  68. package/dist/lib/pipeline-factory.js +86 -85
  69. package/dist/lib/shader-factory.d.ts +17 -0
  70. package/dist/lib/shader-factory.d.ts.map +1 -0
  71. package/dist/lib/shader-factory.js +46 -0
  72. package/dist/model/model.d.ts +59 -46
  73. package/dist/model/model.d.ts.map +1 -1
  74. package/dist/model/model.js +635 -411
  75. package/dist/scenegraph/group-node.d.ts +1 -1
  76. package/dist/scenegraph/group-node.d.ts.map +1 -1
  77. package/dist/scenegraph/group-node.js +73 -83
  78. package/dist/scenegraph/model-node.d.ts +3 -3
  79. package/dist/scenegraph/model-node.d.ts.map +1 -1
  80. package/dist/scenegraph/model-node.js +31 -24
  81. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
  82. package/dist/scenegraph/scenegraph-node.js +136 -124
  83. package/dist/shader-inputs.d.ts.map +1 -1
  84. package/dist/shader-inputs.js +99 -58
  85. package/dist/transform/buffer-transform.d.ts +1 -1
  86. package/dist/transform/buffer-transform.d.ts.map +1 -1
  87. package/dist/transform/buffer-transform.js +65 -57
  88. package/dist/transform/texture-transform.d.ts +1 -1
  89. package/dist/transform/texture-transform.d.ts.map +1 -1
  90. package/dist/transform/texture-transform.js +109 -114
  91. package/dist.min.js +3 -271
  92. package/package.json +10 -9
  93. package/src/animation/timeline.ts +20 -20
  94. package/src/animation-loop/animation-loop-template.ts +10 -8
  95. package/src/animation-loop/animation-loop.ts +20 -10
  96. package/src/animation-loop/animation-props.ts +1 -1
  97. package/src/animation-loop/make-animation-loop.ts +17 -8
  98. package/src/computation.ts +346 -0
  99. package/src/debug/copy-texture-to-image.ts +9 -11
  100. package/src/debug/debug-framebuffer.ts +16 -3
  101. package/src/debug/debug-shader-layout.ts +1 -1
  102. package/src/debug/pixel-data-utils.ts +3 -6
  103. package/src/geometries/cube-geometry.ts +17 -13
  104. package/src/geometries/ico-sphere-geometry.ts +1 -1
  105. package/src/geometries/plane-geometry.ts +1 -1
  106. package/src/geometries/sphere-geometry.ts +1 -1
  107. package/src/geometries/truncated-cone-geometry.ts +2 -1
  108. package/src/geometry/geometry-table.ts +9 -6
  109. package/src/geometry/geometry-utils.ts +16 -0
  110. package/src/geometry/geometry.ts +9 -6
  111. package/src/geometry/gpu-geometry.ts +18 -11
  112. package/src/index.ts +4 -1
  113. package/src/lib/clip-space.ts +16 -19
  114. package/src/lib/pipeline-factory.ts +71 -64
  115. package/src/lib/shader-factory.ts +57 -0
  116. package/src/model/model.ts +255 -146
  117. package/src/scenegraph/group-node.ts +14 -10
  118. package/src/scenegraph/model-node.ts +2 -2
  119. package/src/scenegraph/scenegraph-node.ts +2 -2
  120. package/src/shader-inputs.ts +19 -12
  121. package/src/transform/buffer-transform.ts +16 -8
  122. package/src/transform/texture-transform.ts +14 -15
  123. package/dist/animation/key-frames.js.map +0 -1
  124. package/dist/animation/timeline.js.map +0 -1
  125. package/dist/animation-loop/animation-loop-template.js.map +0 -1
  126. package/dist/animation-loop/animation-loop.js.map +0 -1
  127. package/dist/animation-loop/animation-props.js.map +0 -1
  128. package/dist/animation-loop/make-animation-loop.js.map +0 -1
  129. package/dist/debug/copy-texture-to-image.js.map +0 -1
  130. package/dist/debug/debug-framebuffer.js.map +0 -1
  131. package/dist/debug/debug-shader-layout.js.map +0 -1
  132. package/dist/debug/pixel-data-utils.js.map +0 -1
  133. package/dist/geometries/cone-geometry.js.map +0 -1
  134. package/dist/geometries/cube-geometry.js.map +0 -1
  135. package/dist/geometries/cylinder-geometry.js.map +0 -1
  136. package/dist/geometries/ico-sphere-geometry.js.map +0 -1
  137. package/dist/geometries/plane-geometry.js.map +0 -1
  138. package/dist/geometries/sphere-geometry.js.map +0 -1
  139. package/dist/geometries/truncated-cone-geometry.js.map +0 -1
  140. package/dist/geometry/geometry-table.js.map +0 -1
  141. package/dist/geometry/geometry-utils.js.map +0 -1
  142. package/dist/geometry/geometry.js.map +0 -1
  143. package/dist/geometry/gpu-geometry.js.map +0 -1
  144. package/dist/geometry/gpu-table.js.map +0 -1
  145. package/dist/index.js.map +0 -1
  146. package/dist/lib/clip-space.js.map +0 -1
  147. package/dist/lib/pipeline-factory.js.map +0 -1
  148. package/dist/model/model.js.map +0 -1
  149. package/dist/scenegraph/group-node.js.map +0 -1
  150. package/dist/scenegraph/model-node.js.map +0 -1
  151. package/dist/scenegraph/scenegraph-node.js.map +0 -1
  152. package/dist/shader-inputs.js.map +0 -1
  153. package/dist/transform/buffer-transform.js.map +0 -1
  154. package/dist/transform/texture-transform.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -22,13 +22,14 @@ var __publicField = (obj, key, value) => {
22
22
  return value;
23
23
  };
24
24
 
25
- // src/index.ts
26
- var src_exports = {};
27
- __export(src_exports, {
25
+ // dist/index.js
26
+ var dist_exports = {};
27
+ __export(dist_exports, {
28
28
  AnimationLoop: () => AnimationLoop,
29
29
  AnimationLoopTemplate: () => AnimationLoopTemplate,
30
30
  BufferTransform: () => BufferTransform,
31
31
  ClipSpace: () => ClipSpace,
32
+ Computation: () => Computation,
32
33
  ConeGeometry: () => ConeGeometry,
33
34
  CubeGeometry: () => CubeGeometry,
34
35
  CylinderGeometry: () => CylinderGeometry,
@@ -42,6 +43,7 @@ __export(src_exports, {
42
43
  PipelineFactory: () => PipelineFactory,
43
44
  PlaneGeometry: () => PlaneGeometry,
44
45
  ScenegraphNode: () => ScenegraphNode,
46
+ ShaderFactory: () => ShaderFactory,
45
47
  SphereGeometry: () => SphereGeometry,
46
48
  TextureTransform: () => TextureTransform,
47
49
  Timeline: () => Timeline,
@@ -49,9 +51,9 @@ __export(src_exports, {
49
51
  _ShaderInputs: () => ShaderInputs,
50
52
  makeAnimationLoop: () => makeAnimationLoop
51
53
  });
52
- module.exports = __toCommonJS(src_exports);
54
+ module.exports = __toCommonJS(dist_exports);
53
55
 
54
- // src/animation/timeline.ts
56
+ // dist/animation/timeline.js
55
57
  var channelHandles = 1;
56
58
  var animationHandles = 1;
57
59
  var Timeline = class {
@@ -156,7 +158,7 @@ var Timeline = class {
156
158
  }
157
159
  };
158
160
 
159
- // src/animation/key-frames.ts
161
+ // dist/animation/key-frames.js
160
162
  var KeyFrames = class {
161
163
  startIndex = -1;
162
164
  endIndex = -1;
@@ -213,7 +215,7 @@ var KeyFrames = class {
213
215
  }
214
216
  };
215
217
 
216
- // src/animation-loop/animation-loop-template.ts
218
+ // dist/animation-loop/animation-loop-template.js
217
219
  var AnimationLoopTemplate = class {
218
220
  constructor(animationProps) {
219
221
  }
@@ -222,7 +224,7 @@ var AnimationLoopTemplate = class {
222
224
  }
223
225
  };
224
226
 
225
- // src/animation-loop/animation-loop.ts
227
+ // dist/animation-loop/animation-loop.js
226
228
  var import_core = require("@luma.gl/core");
227
229
  var import_core2 = require("@luma.gl/core");
228
230
  var import_stats = require("@probe.gl/stats");
@@ -564,7 +566,14 @@ var AnimationLoop = class {
564
566
  /** Default viewport setup */
565
567
  _resizeViewport() {
566
568
  if (this.props.autoResizeViewport && this.device.gl) {
567
- this.device.gl.viewport(0, 0, this.device.gl.drawingBufferWidth, this.device.gl.drawingBufferHeight);
569
+ this.device.gl.viewport(
570
+ 0,
571
+ 0,
572
+ // @ts-expect-error Expose canvasContext
573
+ this.device.gl.drawingBufferWidth,
574
+ // @ts-expect-error Expose canvasContext
575
+ this.device.gl.drawingBufferHeight
576
+ );
568
577
  }
569
578
  }
570
579
  /**
@@ -602,7 +611,7 @@ var AnimationLoop = class {
602
611
  }
603
612
  };
604
613
 
605
- // src/animation-loop/make-animation-loop.ts
614
+ // dist/animation-loop/make-animation-loop.js
606
615
  var import_core3 = require("@luma.gl/core");
607
616
  function makeAnimationLoop(AnimationLoopTemplateCtor, props) {
608
617
  let renderLoop = null;
@@ -623,18 +632,110 @@ function makeAnimationLoop(AnimationLoopTemplateCtor, props) {
623
632
  return animationLoop;
624
633
  }
625
634
 
626
- // src/model/model.ts
627
- var import_core7 = require("@luma.gl/core");
635
+ // dist/model/model.js
628
636
  var import_core8 = require("@luma.gl/core");
629
637
  var import_core9 = require("@luma.gl/core");
638
+ var import_core10 = require("@luma.gl/core");
639
+ var import_core11 = require("@luma.gl/core");
630
640
  var import_shadertools2 = require("@luma.gl/shadertools");
631
641
 
632
- // src/shader-inputs.ts
642
+ // dist/geometry/gpu-geometry.js
633
643
  var import_core4 = require("@luma.gl/core");
644
+ var GPUGeometry = class {
645
+ id;
646
+ userData = {};
647
+ /** Determines how vertices are read from the 'vertex' attributes */
648
+ topology;
649
+ bufferLayout = [];
650
+ vertexCount;
651
+ indices;
652
+ attributes;
653
+ constructor(props) {
654
+ this.id = props.id || (0, import_core4.uid)("geometry");
655
+ this.topology = props.topology;
656
+ this.indices = props.indices || null;
657
+ this.attributes = props.attributes;
658
+ this.vertexCount = props.vertexCount;
659
+ this.bufferLayout = props.bufferLayout || [];
660
+ if (this.indices) {
661
+ (0, import_core4.assert)(this.indices.usage === import_core4.Buffer.INDEX);
662
+ }
663
+ }
664
+ destroy() {
665
+ var _a;
666
+ (_a = this.indices) == null ? void 0 : _a.destroy();
667
+ for (const attribute of Object.values(this.attributes)) {
668
+ attribute.destroy();
669
+ }
670
+ }
671
+ getVertexCount() {
672
+ return this.vertexCount;
673
+ }
674
+ getAttributes() {
675
+ return this.attributes;
676
+ }
677
+ getIndexes() {
678
+ return this.indices;
679
+ }
680
+ _calculateVertexCount(positions) {
681
+ const vertexCount = positions.byteLength / 12;
682
+ return vertexCount;
683
+ }
684
+ };
685
+ function makeGPUGeometry(device, geometry) {
686
+ if (geometry instanceof GPUGeometry) {
687
+ return geometry;
688
+ }
689
+ const indices = getIndexBufferFromGeometry(device, geometry);
690
+ const { attributes, bufferLayout } = getAttributeBuffersFromGeometry(device, geometry);
691
+ return new GPUGeometry({
692
+ topology: geometry.topology || "triangle-list",
693
+ bufferLayout,
694
+ vertexCount: geometry.vertexCount,
695
+ indices,
696
+ attributes
697
+ });
698
+ }
699
+ function getIndexBufferFromGeometry(device, geometry) {
700
+ if (!geometry.indices) {
701
+ return void 0;
702
+ }
703
+ const data = geometry.indices.value;
704
+ return device.createBuffer({ usage: import_core4.Buffer.INDEX, data });
705
+ }
706
+ function getAttributeBuffersFromGeometry(device, geometry) {
707
+ const bufferLayout = [];
708
+ const attributes = {};
709
+ for (const [attributeName, attribute] of Object.entries(geometry.attributes)) {
710
+ let name = attributeName;
711
+ switch (attributeName) {
712
+ case "POSITION":
713
+ name = "positions";
714
+ break;
715
+ case "NORMAL":
716
+ name = "normals";
717
+ break;
718
+ case "TEXCOORD_0":
719
+ name = "texCoords";
720
+ break;
721
+ case "COLOR_0":
722
+ name = "colors";
723
+ break;
724
+ }
725
+ attributes[name] = device.createBuffer({ data: attribute.value, id: `${attributeName}-buffer` });
726
+ const { value, size, normalized } = attribute;
727
+ bufferLayout.push({ name, format: (0, import_core4.getVertexFormatFromAttribute)(value, size, normalized) });
728
+ }
729
+ const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
730
+ return { attributes, bufferLayout, vertexCount };
731
+ }
732
+
733
+ // dist/shader-inputs.js
734
+ var import_core5 = require("@luma.gl/core");
634
735
  var import_shadertools = require("@luma.gl/shadertools");
635
736
  var ShaderInputs = class {
636
- /**
637
- * The map of modules
737
+ /**
738
+ * The map of modules
638
739
  * @todo should should this include the resolved dependencies?
639
740
  */
640
741
  modules;
@@ -650,7 +751,7 @@ var ShaderInputs = class {
650
751
  */
651
752
  constructor(modules) {
652
753
  const allModules = (0, import_shadertools._resolveModules)(Object.values(modules));
653
- import_core4.log.log(1, "Creating ShaderInputs with modules", allModules.map((m) => m.name))();
754
+ import_core5.log.log(1, "Creating ShaderInputs with modules", allModules.map((m) => m.name))();
654
755
  this.modules = modules;
655
756
  this.moduleUniforms = {};
656
757
  this.moduleBindings = {};
@@ -673,7 +774,7 @@ var ShaderInputs = class {
673
774
  const moduleProps = props[moduleName];
674
775
  const module2 = this.modules[moduleName];
675
776
  if (!module2) {
676
- import_core4.log.warn(`Module ${name} not found`)();
777
+ import_core5.log.warn(`Module ${name} not found`)();
677
778
  continue;
678
779
  }
679
780
  const oldUniforms = this.moduleUniforms[moduleName];
@@ -685,8 +786,8 @@ var ShaderInputs = class {
685
786
  // getUniformBlocks(): Record<string, Texture | Sampler> {
686
787
  // return this.moduleUniforms;
687
788
  // }
688
- /**
689
- * Return the map of modules
789
+ /**
790
+ * Return the map of modules
690
791
  * @todo should should this include the resolved dependencies?
691
792
  */
692
793
  getModules() {
@@ -719,106 +820,15 @@ var ShaderInputs = class {
719
820
  }
720
821
  };
721
822
 
722
- // src/geometry/gpu-geometry.ts
723
- var import_core5 = require("@luma.gl/core");
724
- var GPUGeometry = class {
725
- id;
726
- userData = {};
727
- /** Determines how vertices are read from the 'vertex' attributes */
728
- topology;
729
- bufferLayout = [];
730
- vertexCount;
731
- indices;
732
- attributes;
733
- constructor(props) {
734
- this.id = props.id || (0, import_core5.uid)("geometry");
735
- this.topology = props.topology;
736
- this.indices = props.indices || null;
737
- this.attributes = props.attributes;
738
- this.vertexCount = props.vertexCount;
739
- this.bufferLayout = props.bufferLayout || [];
740
- if (this.indices) {
741
- (0, import_core5.assert)(this.indices.usage === import_core5.Buffer.INDEX);
742
- }
743
- }
744
- destroy() {
745
- var _a;
746
- this.indices.destroy();
747
- this.attributes.positions.destroy();
748
- this.attributes.normals.destroy();
749
- this.attributes.texCoords.destroy();
750
- (_a = this.attributes.colors) == null ? void 0 : _a.destroy();
751
- }
752
- getVertexCount() {
753
- return this.vertexCount;
754
- }
755
- getAttributes() {
756
- return this.attributes;
757
- }
758
- getIndexes() {
759
- return this.indices;
760
- }
761
- _calculateVertexCount(positions) {
762
- const vertexCount = positions.byteLength / 12;
763
- return vertexCount;
764
- }
765
- };
766
- function makeGPUGeometry(device, geometry) {
767
- if (geometry instanceof GPUGeometry) {
768
- return geometry;
769
- }
770
- const indices = getIndexBufferFromGeometry(device, geometry);
771
- const { attributes, bufferLayout } = getAttributeBuffersFromGeometry(device, geometry);
772
- return new GPUGeometry({
773
- topology: geometry.topology || "triangle-list",
774
- bufferLayout,
775
- vertexCount: geometry.vertexCount,
776
- indices,
777
- attributes
778
- });
779
- }
780
- function getIndexBufferFromGeometry(device, geometry) {
781
- if (!geometry.indices) {
782
- return void 0;
783
- }
784
- const data = geometry.indices.value;
785
- return device.createBuffer({ usage: import_core5.Buffer.INDEX, data });
786
- }
787
- function getAttributeBuffersFromGeometry(device, geometry) {
788
- const bufferLayout = [];
789
- const attributes = {};
790
- for (const [attributeName, attribute] of Object.entries(geometry.attributes)) {
791
- let name = attributeName;
792
- switch (attributeName) {
793
- case "POSITION":
794
- name = "positions";
795
- break;
796
- case "NORMAL":
797
- name = "normals";
798
- break;
799
- case "TEXCOORD_0":
800
- name = "texCoords";
801
- break;
802
- case "COLOR_0":
803
- name = "colors";
804
- break;
805
- }
806
- attributes[name] = device.createBuffer({ data: attribute.value, id: `${attributeName}-buffer` });
807
- const { value, size, normalized } = attribute;
808
- bufferLayout.push({ name, format: (0, import_core5.getVertexFormatFromAttribute)(value, size, normalized) });
809
- }
810
- const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
811
- return { attributes, bufferLayout, vertexCount };
812
- }
813
-
814
- // src/lib/pipeline-factory.ts
823
+ // dist/lib/pipeline-factory.js
815
824
  var import_core6 = require("@luma.gl/core");
816
825
  var _PipelineFactory = class {
817
826
  device;
818
827
  _hashCounter = 0;
819
828
  _hashes = {};
820
- _useCounts = {};
821
- _pipelineCache = {};
829
+ _renderPipelineCache = {};
830
+ _computePipelineCache = {};
831
+ /** Get the singleton default pipeline factory for the specified device */
822
832
  static getDefaultPipelineFactory(device) {
823
833
  device._lumaData.defaultPipelineFactory = device._lumaData.defaultPipelineFactory || new _PipelineFactory(device);
824
834
  return device._lumaData.defaultPipelineFactory;
@@ -826,55 +836,59 @@ var _PipelineFactory = class {
826
836
  constructor(device) {
827
837
  this.device = device;
828
838
  }
829
- createRenderPipeline(options) {
830
- const props = { ..._PipelineFactory.defaultProps, ...options };
831
- const hash = this._hashRenderPipeline({ ...props });
832
- if (!this._pipelineCache[hash]) {
839
+ /** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
840
+ createRenderPipeline(props) {
841
+ const allProps = { ...import_core6.RenderPipeline.defaultProps, ...props };
842
+ const hash = this._hashRenderPipeline(allProps);
843
+ if (!this._renderPipelineCache[hash]) {
833
844
  const pipeline = this.device.createRenderPipeline({
834
- ...props,
835
- vs: this.device.createShader({ stage: "vertex", source: props.vs }),
836
- fs: props.fs ? this.device.createShader({ stage: "fragment", source: props.fs }) : null
845
+ ...allProps,
846
+ id: allProps.id ? `${allProps.id}-cached` : void 0
847
+ });
848
+ pipeline.hash = hash;
849
+ this._renderPipelineCache[hash] = { pipeline, useCount: 0 };
850
+ }
851
+ this._renderPipelineCache[hash].useCount++;
852
+ return this._renderPipelineCache[hash].pipeline;
853
+ }
854
+ createComputePipeline(props) {
855
+ const allProps = { ...import_core6.ComputePipeline.defaultProps, ...props };
856
+ const hash = this._hashComputePipeline(allProps);
857
+ if (!this._computePipelineCache[hash]) {
858
+ const pipeline = this.device.createComputePipeline({
859
+ ...allProps,
860
+ id: allProps.id ? `${allProps.id}-cached` : void 0
837
861
  });
838
862
  pipeline.hash = hash;
839
- this._pipelineCache[hash] = pipeline;
840
- this._useCounts[hash] = 0;
863
+ this._computePipelineCache[hash] = { pipeline, useCount: 0 };
841
864
  }
842
- this._useCounts[hash]++;
843
- return this._pipelineCache[hash];
865
+ this._computePipelineCache[hash].useCount++;
866
+ return this._computePipelineCache[hash].pipeline;
844
867
  }
845
868
  release(pipeline) {
846
869
  const hash = pipeline.hash;
847
- this._useCounts[hash]--;
848
- if (this._useCounts[hash] === 0) {
849
- this._pipelineCache[hash].destroy();
850
- delete this._pipelineCache[hash];
851
- delete this._useCounts[hash];
870
+ const cache = pipeline instanceof import_core6.ComputePipeline ? this._computePipelineCache : this._renderPipelineCache;
871
+ cache[hash].useCount--;
872
+ if (cache[hash].useCount === 0) {
873
+ cache[hash].pipeline.destroy();
874
+ delete cache[hash];
852
875
  }
853
876
  }
854
877
  // PRIVATE
855
- _createRenderPipeline(props) {
856
- if (!props.fs) {
857
- throw new Error("fs");
858
- }
859
- const pipeline = this.device.createRenderPipeline({
860
- ...props,
861
- vs: this.device.createShader({ stage: "vertex", source: props.vs }),
862
- fs: props.fs ? this.device.createShader({ stage: "fragment", source: props.fs }) : null
863
- });
864
- return pipeline;
878
+ _hashComputePipeline(props) {
879
+ const shaderHash = this._getHash(props.shader.source);
880
+ return `${shaderHash}`;
865
881
  }
866
882
  /** Calculate a hash based on all the inputs for a render pipeline */
867
883
  _hashRenderPipeline(props) {
868
- const vsHash = this._getHash(props.vs);
869
- const fsHash = props.fs ? this._getHash(props.fs) : 0;
884
+ const vsHash = this._getHash(props.vs.source);
885
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
870
886
  const varyingHash = "-";
871
- switch (this.device.info.type) {
872
- case "webgpu":
873
- const parameterHash = this._getHash(JSON.stringify(props.parameters));
874
- const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
875
- return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}}`;
887
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
888
+ switch (this.device.type) {
876
889
  default:
877
- return `${vsHash}/${fsHash}V${varyingHash}`;
890
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
891
+ return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
878
892
  }
879
893
  }
880
894
  _getHash(key) {
@@ -885,13 +899,57 @@ var _PipelineFactory = class {
885
899
  }
886
900
  };
887
901
  var PipelineFactory = _PipelineFactory;
888
- __publicField(PipelineFactory, "defaultProps", {
889
- ...import_core6.RenderPipeline.defaultProps,
890
- vs: void 0,
891
- fs: void 0
892
- });
902
+ __publicField(PipelineFactory, "defaultProps", { ...import_core6.RenderPipeline.defaultProps });
903
+
904
+ // dist/lib/shader-factory.js
905
+ var import_core7 = require("@luma.gl/core");
906
+ var _ShaderFactory = class {
907
+ device;
908
+ _cache = {};
909
+ /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
910
+ static getDefaultShaderFactory(device) {
911
+ device._lumaData.defaultShaderFactory ||= new _ShaderFactory(device);
912
+ return device._lumaData.defaultShaderFactory;
913
+ }
914
+ /** @internal */
915
+ constructor(device) {
916
+ this.device = device;
917
+ }
918
+ /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
919
+ createShader(props) {
920
+ const key = this._hashShader(props);
921
+ let cacheEntry = this._cache[key];
922
+ if (!cacheEntry) {
923
+ const shader = this.device.createShader({
924
+ ...props,
925
+ id: props.id ? `${props.id}-cached` : void 0
926
+ });
927
+ this._cache[key] = cacheEntry = { shader, useCount: 0 };
928
+ }
929
+ cacheEntry.useCount++;
930
+ return cacheEntry.shader;
931
+ }
932
+ /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
933
+ release(shader) {
934
+ const key = this._hashShader(shader);
935
+ const cacheEntry = this._cache[key];
936
+ if (cacheEntry) {
937
+ cacheEntry.useCount--;
938
+ if (cacheEntry.useCount === 0) {
939
+ delete this._cache[key];
940
+ cacheEntry.shader.destroy();
941
+ }
942
+ }
943
+ }
944
+ // PRIVATE
945
+ _hashShader(value) {
946
+ return `${value.stage}:${value.source}`;
947
+ }
948
+ };
949
+ var ShaderFactory = _ShaderFactory;
950
+ __publicField(ShaderFactory, "defaultProps", { ...import_core7.Shader.defaultProps });
893
951
 
894
- // src/debug/debug-shader-layout.ts
952
+ // dist/debug/debug-shader-layout.js
895
953
  function getDebugTableForShaderLayout(layout, name) {
896
954
  var _a;
897
955
  const table = {};
@@ -912,7 +970,7 @@ function getDebugTableForShaderLayout(layout, name) {
912
970
  return table;
913
971
  }
914
972
 
915
- // src/debug/debug-framebuffer.ts
973
+ // dist/debug/debug-framebuffer.js
916
974
  var canvas = null;
917
975
  var ctx = null;
918
976
  function debugFramebuffer(fbo, { id, minimap, opaque, top = "0", left = "0", rgbaScale = 1 }) {
@@ -947,15 +1005,17 @@ function debugFramebuffer(fbo, { id, minimap, opaque, top = "0", left = "0", rgb
947
1005
  ctx.putImageData(imageData, 0, 0);
948
1006
  }
949
1007
 
950
- // src/model/model.ts
1008
+ // dist/model/model.js
951
1009
  var LOG_DRAW_PRIORITY = 2;
952
1010
  var LOG_DRAW_TIMEOUT = 1e4;
953
1011
  var _Model = class {
954
1012
  device;
955
1013
  id;
1014
+ source;
956
1015
  vs;
957
1016
  fs;
958
1017
  pipelineFactory;
1018
+ shaderFactory;
959
1019
  userData = {};
960
1020
  // Fixed properties (change can trigger pipeline rebuild)
961
1021
  /** The render pipeline GPU parameters, depth testing etc */
@@ -992,52 +1052,56 @@ var _Model = class {
992
1052
  /** ShaderInputs instance */
993
1053
  shaderInputs;
994
1054
  _uniformStore;
995
- _pipelineNeedsUpdate = "newly created";
996
1055
  _attributeInfos = {};
997
1056
  _gpuGeometry = null;
998
1057
  _getModuleUniforms;
999
1058
  props;
1059
+ _pipelineNeedsUpdate = "newly created";
1060
+ _needsRedraw = "initializing";
1061
+ _destroyed = false;
1062
+ /** "Time" of last draw. Monotonically increasing timestamp */
1063
+ _lastDrawTimestamp = -1;
1000
1064
  constructor(device, props) {
1001
1065
  var _a, _b, _c;
1002
1066
  this.props = { ..._Model.defaultProps, ...props };
1003
1067
  props = this.props;
1004
- this.id = props.id || (0, import_core8.uid)("model");
1068
+ this.id = props.id || (0, import_core10.uid)("model");
1005
1069
  this.device = device;
1006
1070
  Object.assign(this.userData, props.userData);
1007
- const moduleMap = Object.fromEntries(
1008
- ((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []
1009
- );
1071
+ const moduleMap = Object.fromEntries(((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []);
1010
1072
  this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
1011
- const isWebGPU = this.device.info.type === "webgpu";
1012
- if (this.props.source) {
1013
- if (isWebGPU) {
1014
- this.props.shaderLayout ||= (0, import_shadertools2.getShaderLayoutFromWGSL)(this.props.source);
1015
- }
1016
- this.props.fs = this.props.source;
1017
- this.props.vs = this.props.source;
1018
- }
1019
- if (isWebGPU && typeof this.props.vs !== "string") {
1020
- this.props.shaderLayout ||= (0, import_shadertools2.getShaderLayoutFromWGSL)(this.props.vs.wgsl);
1021
- }
1022
1073
  const platformInfo = getPlatformInfo(device);
1023
1074
  const modules = (((_b = this.props.modules) == null ? void 0 : _b.length) > 0 ? this.props.modules : (_c = this.shaderInputs) == null ? void 0 : _c.getModules()) || [];
1024
- const { vs, fs, getUniforms } = this.props.shaderAssembler.assembleShaders({
1025
- platformInfo,
1026
- ...this.props,
1027
- modules
1028
- });
1029
- this.vs = vs;
1030
- this.fs = fs;
1031
- this._getModuleUniforms = getUniforms;
1075
+ const isWebGPU = this.device.type === "webgpu";
1076
+ if (isWebGPU && this.props.source) {
1077
+ this.props.shaderLayout ||= (0, import_shadertools2.getShaderLayoutFromWGSL)(this.props.source);
1078
+ const { source, getUniforms } = this.props.shaderAssembler.assembleShader({
1079
+ platformInfo,
1080
+ ...this.props,
1081
+ modules
1082
+ });
1083
+ this.source = source;
1084
+ this._getModuleUniforms = getUniforms;
1085
+ } else {
1086
+ const { vs, fs, getUniforms } = this.props.shaderAssembler.assembleShaderPair({
1087
+ platformInfo,
1088
+ ...this.props,
1089
+ modules
1090
+ });
1091
+ this.vs = vs;
1092
+ this.fs = fs;
1093
+ this._getModuleUniforms = getUniforms;
1094
+ }
1032
1095
  this.vertexCount = this.props.vertexCount;
1033
1096
  this.instanceCount = this.props.instanceCount;
1034
1097
  this.topology = this.props.topology;
1035
1098
  this.bufferLayout = this.props.bufferLayout;
1036
1099
  this.parameters = this.props.parameters;
1037
1100
  if (props.geometry) {
1038
- this._gpuGeometry = this.setGeometry(props.geometry);
1101
+ this.setGeometry(props.geometry);
1039
1102
  }
1040
1103
  this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
1104
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
1041
1105
  this.pipeline = this._updatePipeline();
1042
1106
  this.vertexArray = device.createVertexArray({
1043
1107
  renderPipeline: this.pipeline
@@ -1058,7 +1122,9 @@ var _Model = class {
1058
1122
  this.setIndexBuffer(props.indexBuffer);
1059
1123
  }
1060
1124
  if (props.attributes) {
1061
- this.setAttributes(props.attributes);
1125
+ this.setAttributes(props.attributes, {
1126
+ ignoreUnknownAttributes: props.ignoreUnknownAttributes
1127
+ });
1062
1128
  }
1063
1129
  if (props.constantAttributes) {
1064
1130
  this.setConstantAttributes(props.constantAttributes);
@@ -1070,7 +1136,7 @@ var _Model = class {
1070
1136
  this.setUniforms(props.uniforms);
1071
1137
  }
1072
1138
  if (props.moduleSettings) {
1073
- import_core8.log.warn("Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()")();
1139
+ import_core10.log.warn("Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()")();
1074
1140
  this.updateModuleSettings(props.moduleSettings);
1075
1141
  }
1076
1142
  if (props.transformFeedback) {
@@ -1079,31 +1145,67 @@ var _Model = class {
1079
1145
  Object.seal(this);
1080
1146
  }
1081
1147
  destroy() {
1148
+ var _a;
1149
+ if (this._destroyed)
1150
+ return;
1082
1151
  this.pipelineFactory.release(this.pipeline);
1152
+ this.shaderFactory.release(this.pipeline.vs);
1153
+ if (this.pipeline.fs) {
1154
+ this.shaderFactory.release(this.pipeline.fs);
1155
+ }
1083
1156
  this._uniformStore.destroy();
1157
+ (_a = this._gpuGeometry) == null ? void 0 : _a.destroy();
1158
+ this._destroyed = true;
1084
1159
  }
1085
1160
  // Draw call
1161
+ /** Query redraw status. Clears the status. */
1162
+ needsRedraw() {
1163
+ if (this._getBindingsUpdateTimestamp() > this._lastDrawTimestamp) {
1164
+ this.setNeedsRedraw("contents of bound textures or buffers updated");
1165
+ }
1166
+ const needsRedraw = this._needsRedraw;
1167
+ this._needsRedraw = false;
1168
+ return needsRedraw;
1169
+ }
1170
+ /** Mark the model as needing a redraw */
1171
+ setNeedsRedraw(reason) {
1172
+ this._needsRedraw ||= reason;
1173
+ }
1086
1174
  predraw() {
1087
1175
  this.updateShaderInputs();
1176
+ this.pipeline = this._updatePipeline();
1088
1177
  }
1089
1178
  draw(renderPass) {
1090
1179
  this.predraw();
1180
+ let drawSuccess;
1091
1181
  try {
1092
1182
  this._logDrawCallStart();
1093
1183
  this.pipeline = this._updatePipeline();
1094
1184
  this.pipeline.setBindings(this.bindings);
1095
- this.pipeline.setUniforms(this.uniforms);
1096
- this.pipeline.draw({
1185
+ if (!(0, import_core10.isObjectEmpty)(this.uniforms)) {
1186
+ this.pipeline.setUniformsWebGL(this.uniforms);
1187
+ }
1188
+ const { indexBuffer } = this.vertexArray;
1189
+ const indexCount = indexBuffer ? indexBuffer.byteLength / (indexBuffer.indexType === "uint32" ? 4 : 2) : void 0;
1190
+ drawSuccess = this.pipeline.draw({
1097
1191
  renderPass,
1098
1192
  vertexArray: this.vertexArray,
1099
1193
  vertexCount: this.vertexCount,
1100
1194
  instanceCount: this.instanceCount,
1195
+ indexCount,
1101
1196
  transformFeedback: this.transformFeedback
1102
1197
  });
1103
1198
  } finally {
1104
1199
  this._logDrawCallEnd();
1105
1200
  }
1106
1201
  this._logFramebuffer(renderPass);
1202
+ if (drawSuccess) {
1203
+ this._lastDrawTimestamp = this.device.timestamp;
1204
+ this._needsRedraw = false;
1205
+ } else {
1206
+ this._needsRedraw = "waiting for resource initialization";
1207
+ }
1208
+ return drawSuccess;
1107
1209
  }
1108
1210
  // Update fixed fields (can trigger pipeline rebuild)
1109
1211
  /**
@@ -1112,30 +1214,17 @@ var _Model = class {
1112
1214
  * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
1113
1215
  */
1114
1216
  setGeometry(geometry) {
1217
+ var _a;
1218
+ (_a = this._gpuGeometry) == null ? void 0 : _a.destroy();
1115
1219
  const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
1116
- this.setTopology(gpuGeometry.topology || "triangle-list");
1117
- this.bufferLayout = mergeBufferLayouts(this.bufferLayout, gpuGeometry.bufferLayout);
1118
- if (this.vertexArray) {
1119
- this._setGeometryAttributes(gpuGeometry);
1120
- }
1121
- return gpuGeometry;
1122
- }
1123
- /**
1124
- * Updates the optional geometry attributes
1125
- * Geometry, sets several attributes, indexBuffer, and also vertex count
1126
- * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
1127
- */
1128
- _setGeometryAttributes(gpuGeometry) {
1129
- const attributes = { ...gpuGeometry.attributes };
1130
- for (const [attributeName] of Object.entries(attributes)) {
1131
- if (!this.pipeline.shaderLayout.attributes.find((layout) => layout.name === attributeName) && attributeName !== "positions") {
1132
- delete attributes[attributeName];
1220
+ if (gpuGeometry) {
1221
+ this.setTopology(gpuGeometry.topology || "triangle-list");
1222
+ this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout);
1223
+ if (this.vertexArray) {
1224
+ this._setGeometryAttributes(gpuGeometry);
1133
1225
  }
1134
1226
  }
1135
- this.vertexCount = gpuGeometry.vertexCount;
1136
- this.setIndexBuffer(gpuGeometry.indices);
1137
- this.setAttributes(gpuGeometry.attributes, "ignore-unknown");
1138
- this.setAttributes(attributes);
1227
+ this._gpuGeometry = gpuGeometry;
1139
1228
  }
1140
1229
  /**
1141
1230
  * Updates the primitive topology ('triangle-list', 'triangle-strip' etc).
@@ -1149,7 +1238,7 @@ var _Model = class {
1149
1238
  }
1150
1239
  /**
1151
1240
  * Updates the buffer layout.
1152
- * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
1241
+ * @note Triggers a pipeline rebuild / pipeline cache fetch
1153
1242
  */
1154
1243
  setBufferLayout(bufferLayout) {
1155
1244
  this.bufferLayout = this._gpuGeometry ? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout) : bufferLayout;
@@ -1168,7 +1257,7 @@ var _Model = class {
1168
1257
  * @param parameters
1169
1258
  */
1170
1259
  setParameters(parameters) {
1171
- if (!(0, import_core8.deepEqual)(parameters, this.parameters, 2)) {
1260
+ if (!(0, import_core10.deepEqual)(parameters, this.parameters, 2)) {
1172
1261
  this.parameters = parameters;
1173
1262
  this._setPipelineNeedsUpdate("parameters");
1174
1263
  }
@@ -1180,6 +1269,7 @@ var _Model = class {
1180
1269
  */
1181
1270
  setVertexCount(vertexCount) {
1182
1271
  this.vertexCount = vertexCount;
1272
+ this.setNeedsRedraw("vertexCount");
1183
1273
  }
1184
1274
  /**
1185
1275
  * Updates the instance count (used in draw calls)
@@ -1187,57 +1277,34 @@ var _Model = class {
1187
1277
  */
1188
1278
  setInstanceCount(instanceCount) {
1189
1279
  this.instanceCount = instanceCount;
1280
+ this.setNeedsRedraw("instanceCount");
1190
1281
  }
1191
1282
  setShaderInputs(shaderInputs) {
1192
1283
  this.shaderInputs = shaderInputs;
1193
- this._uniformStore = new import_core7.UniformStore(this.shaderInputs.modules);
1284
+ this._uniformStore = new import_core9.UniformStore(this.shaderInputs.modules);
1194
1285
  for (const moduleName of Object.keys(this.shaderInputs.modules)) {
1195
1286
  const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
1196
1287
  this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
1197
1288
  }
1198
- }
1199
- /**
1200
- * Updates shader module settings (which results in uniforms being set)
1201
- */
1202
- setShaderModuleProps(props) {
1203
- const uniforms = this._getModuleUniforms(props);
1204
- const keys = Object.keys(uniforms).filter((k) => {
1205
- const uniform = uniforms[k];
1206
- return !(0, import_core8.isNumberArray)(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
1207
- });
1208
- const bindings = {};
1209
- for (const k of keys) {
1210
- bindings[k] = uniforms[k];
1211
- delete uniforms[k];
1212
- }
1289
+ this.setNeedsRedraw("shaderInputs");
1213
1290
  }
1214
1291
  updateShaderInputs() {
1215
1292
  this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
1216
- }
1217
- /**
1218
- * @deprecated Updates shader module settings (which results in uniforms being set)
1219
- */
1220
- updateModuleSettings(props) {
1221
- import_core8.log.warn("Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()")();
1222
- const { bindings, uniforms } = (0, import_core8.splitUniformsAndBindings)(this._getModuleUniforms(props));
1223
- Object.assign(this.bindings, bindings);
1224
- Object.assign(this.uniforms, uniforms);
1293
+ this.setNeedsRedraw("shaderInputs");
1225
1294
  }
1226
1295
  /**
1227
1296
  * Sets bindings (textures, samplers, uniform buffers)
1228
1297
  */
1229
1298
  setBindings(bindings) {
1230
1299
  Object.assign(this.bindings, bindings);
1300
+ this.setNeedsRedraw("bindings");
1231
1301
  }
1232
1302
  /**
1233
- * Sets individual uniforms
1234
- * @deprecated WebGL only, use uniform buffers for portability
1235
- * @param uniforms
1236
- * @returns self for chaining
1303
+ * Updates optional transform feedback. WebGL only.
1237
1304
  */
1238
- setUniforms(uniforms) {
1239
- this.pipeline.setUniforms(uniforms);
1240
- Object.assign(this.uniforms, uniforms);
1305
+ setTransformFeedback(transformFeedback) {
1306
+ this.transformFeedback = transformFeedback;
1307
+ this.setNeedsRedraw("transformFeedback");
1241
1308
  }
1242
1309
  /**
1243
1310
  * Sets the index buffer
@@ -1245,27 +1312,20 @@ var _Model = class {
1245
1312
  */
1246
1313
  setIndexBuffer(indexBuffer) {
1247
1314
  this.vertexArray.setIndexBuffer(indexBuffer);
1248
- }
1249
- /**
1250
- * Updates optional transform feedback. WebGL 2 only.
1251
- */
1252
- setTransformFeedback(transformFeedback) {
1253
- this.transformFeedback = transformFeedback;
1315
+ this.setNeedsRedraw("indexBuffer");
1254
1316
  }
1255
1317
  /**
1256
1318
  * Sets attributes (buffers)
1257
1319
  * @note Overrides any attributes previously set with the same name
1258
1320
  */
1259
- setAttributes(buffers, _option) {
1321
+ setAttributes(buffers, options) {
1260
1322
  if (buffers.indices) {
1261
- import_core8.log.warn(
1262
- `Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
1263
- )();
1323
+ import_core10.log.warn(`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`)();
1264
1324
  }
1265
1325
  for (const [bufferName, buffer] of Object.entries(buffers)) {
1266
1326
  const bufferLayout = this.bufferLayout.find((layout) => getAttributeNames(layout).includes(bufferName));
1267
1327
  if (!bufferLayout) {
1268
- import_core8.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
1328
+ import_core10.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
1269
1329
  continue;
1270
1330
  }
1271
1331
  const attributeNames = getAttributeNames(bufferLayout);
@@ -1277,12 +1337,11 @@ var _Model = class {
1277
1337
  set = true;
1278
1338
  }
1279
1339
  }
1280
- if (!set && _option !== "ignore-unknown") {
1281
- import_core8.log.warn(
1282
- `Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`
1283
- )();
1340
+ if (!set && ((options == null ? void 0 : options.ignoreUnknownAttributes) || this.props.ignoreUnknownAttributes)) {
1341
+ import_core10.log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
1284
1342
  }
1285
1343
  }
1344
+ this.setNeedsRedraw("attributes");
1286
1345
  }
1287
1346
  /**
1288
1347
  * Sets constant attributes
@@ -1296,37 +1355,103 @@ var _Model = class {
1296
1355
  for (const [attributeName, value] of Object.entries(attributes)) {
1297
1356
  const attributeInfo = this._attributeInfos[attributeName];
1298
1357
  if (attributeInfo) {
1299
- this.vertexArray.setConstant(attributeInfo.location, value);
1358
+ this.vertexArray.setConstantWebGL(attributeInfo.location, value);
1300
1359
  } else {
1301
- import_core8.log.warn(
1302
- `Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`
1303
- )();
1360
+ import_core10.log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
1361
+ }
1362
+ }
1363
+ this.setNeedsRedraw("constants");
1364
+ }
1365
+ // DEPRECATED METHODS
1366
+ /**
1367
+ * Sets individual uniforms
1368
+ * @deprecated WebGL only, use uniform buffers for portability
1369
+ * @param uniforms
1370
+ */
1371
+ setUniforms(uniforms) {
1372
+ if (!(0, import_core10.isObjectEmpty)(uniforms)) {
1373
+ this.pipeline.setUniformsWebGL(uniforms);
1374
+ Object.assign(this.uniforms, uniforms);
1375
+ }
1376
+ this.setNeedsRedraw("uniforms");
1377
+ }
1378
+ /**
1379
+ * @deprecated Updates shader module settings (which results in uniforms being set)
1380
+ */
1381
+ updateModuleSettings(props) {
1382
+ import_core10.log.warn("Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()")();
1383
+ const { bindings, uniforms } = (0, import_core10.splitUniformsAndBindings)(this._getModuleUniforms(props));
1384
+ Object.assign(this.bindings, bindings);
1385
+ Object.assign(this.uniforms, uniforms);
1386
+ this.setNeedsRedraw("moduleSettings");
1387
+ }
1388
+ // Internal methods
1389
+ /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
1390
+ _getBindingsUpdateTimestamp() {
1391
+ let timestamp = 0;
1392
+ for (const binding of Object.values(this.bindings)) {
1393
+ if (binding instanceof import_core8.TextureView) {
1394
+ timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
1395
+ } else if (binding instanceof import_core8.Buffer || binding instanceof import_core8.Texture) {
1396
+ timestamp = Math.max(timestamp, binding.updateTimestamp);
1397
+ } else if (!(binding instanceof import_core8.Sampler)) {
1398
+ timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
1399
+ }
1400
+ }
1401
+ return timestamp;
1402
+ }
1403
+ /**
1404
+ * Updates the optional geometry attributes
1405
+ * Geometry, sets several attributes, indexBuffer, and also vertex count
1406
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
1407
+ */
1408
+ _setGeometryAttributes(gpuGeometry) {
1409
+ const attributes = { ...gpuGeometry.attributes };
1410
+ for (const [attributeName] of Object.entries(attributes)) {
1411
+ if (!this.pipeline.shaderLayout.attributes.find((layout) => layout.name === attributeName) && attributeName !== "positions") {
1412
+ delete attributes[attributeName];
1304
1413
  }
1305
1414
  }
1415
+ this.vertexCount = gpuGeometry.vertexCount;
1416
+ this.setIndexBuffer(gpuGeometry.indices);
1417
+ this.setAttributes(gpuGeometry.attributes, { ignoreUnknownAttributes: true });
1418
+ this.setAttributes(attributes, { ignoreUnknownAttributes: this.props.ignoreUnknownAttributes });
1419
+ this.setNeedsRedraw("geometry attributes");
1306
1420
  }
1421
+ /** Mark pipeline as needing update */
1307
1422
  _setPipelineNeedsUpdate(reason) {
1308
- this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
1423
+ this._pipelineNeedsUpdate ||= reason;
1424
+ this.setNeedsRedraw(reason);
1309
1425
  }
1426
+ /** Update pipeline if needed */
1310
1427
  _updatePipeline() {
1311
1428
  if (this._pipelineNeedsUpdate) {
1429
+ let prevShaderVs = null;
1430
+ let prevShaderFs = null;
1312
1431
  if (this.pipeline) {
1313
- import_core8.log.log(
1314
- 1,
1315
- `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
1316
- )();
1432
+ import_core10.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
1433
+ prevShaderVs = this.pipeline.vs;
1434
+ prevShaderFs = this.pipeline.fs;
1317
1435
  }
1318
1436
  this._pipelineNeedsUpdate = false;
1319
- const vs = this.device.createShader({
1437
+ const vs = this.shaderFactory.createShader({
1320
1438
  id: `${this.id}-vertex`,
1321
1439
  stage: "vertex",
1322
- source: this.vs
1440
+ source: this.source || this.vs,
1441
+ debug: this.props.debugShaders
1323
1442
  });
1324
- const fs = this.fs ? this.device.createShader({
1325
- id: `${this.id}-fragment`,
1326
- stage: "fragment",
1327
- source: this.fs
1328
- }) : null;
1329
- this.pipeline = this.device.createRenderPipeline({
1443
+ let fs = null;
1444
+ if (this.source) {
1445
+ fs = vs;
1446
+ } else if (this.fs) {
1447
+ fs = this.shaderFactory.createShader({
1448
+ id: `${this.id}-fragment`,
1449
+ stage: "fragment",
1450
+ source: this.source || this.fs,
1451
+ debug: this.props.debugShaders
1452
+ });
1453
+ }
1454
+ this.pipeline = this.pipelineFactory.createRenderPipeline({
1330
1455
  ...this.props,
1331
1456
  bufferLayout: this.bufferLayout,
1332
1457
  topology: this.topology,
@@ -1334,10 +1459,11 @@ var _Model = class {
1334
1459
  vs,
1335
1460
  fs
1336
1461
  });
1337
- this._attributeInfos = (0, import_core9.getAttributeInfosFromLayouts)(
1338
- this.pipeline.shaderLayout,
1339
- this.bufferLayout
1340
- );
1462
+ this._attributeInfos = (0, import_core11.getAttributeInfosFromLayouts)(this.pipeline.shaderLayout, this.bufferLayout);
1463
+ if (prevShaderVs)
1464
+ this.shaderFactory.release(prevShaderVs);
1465
+ if (prevShaderFs)
1466
+ this.shaderFactory.release(prevShaderFs);
1341
1467
  }
1342
1468
  return this.pipeline;
1343
1469
  }
@@ -1345,33 +1471,33 @@ var _Model = class {
1345
1471
  _lastLogTime = 0;
1346
1472
  _logOpen = false;
1347
1473
  _logDrawCallStart() {
1348
- const logDrawTimeout = import_core8.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
1349
- if (import_core8.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
1474
+ const logDrawTimeout = import_core10.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
1475
+ if (import_core10.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
1350
1476
  return;
1351
1477
  }
1352
1478
  this._lastLogTime = Date.now();
1353
1479
  this._logOpen = true;
1354
- import_core8.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core8.log.level <= 2 })();
1480
+ import_core10.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core10.log.level <= 2 })();
1355
1481
  }
1356
1482
  _logDrawCallEnd() {
1357
1483
  if (this._logOpen) {
1358
1484
  const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
1359
- import_core8.log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
1485
+ import_core10.log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
1360
1486
  const uniformTable = this.shaderInputs.getDebugTable();
1361
1487
  for (const [name, value] of Object.entries(this.uniforms)) {
1362
1488
  uniformTable[name] = { value };
1363
1489
  }
1364
- import_core8.log.table(LOG_DRAW_PRIORITY, uniformTable)();
1490
+ import_core10.log.table(LOG_DRAW_PRIORITY, uniformTable)();
1365
1491
  const attributeTable = this._getAttributeDebugTable();
1366
- import_core8.log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
1367
- import_core8.log.table(LOG_DRAW_PRIORITY, attributeTable)();
1368
- import_core8.log.groupEnd(LOG_DRAW_PRIORITY)();
1492
+ import_core10.log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
1493
+ import_core10.log.table(LOG_DRAW_PRIORITY, attributeTable)();
1494
+ import_core10.log.groupEnd(LOG_DRAW_PRIORITY)();
1369
1495
  this._logOpen = false;
1370
1496
  }
1371
1497
  }
1372
1498
  _drawCount = 0;
1373
1499
  _logFramebuffer(renderPass) {
1374
- const debugFramebuffers = import_core8.log.get("framebuffer");
1500
+ const debugFramebuffers = import_core10.log.get("framebuffer");
1375
1501
  this._drawCount++;
1376
1502
  if (!debugFramebuffers || this._drawCount++ > 3 && this._drawCount % 60) {
1377
1503
  return;
@@ -1387,10 +1513,7 @@ var _Model = class {
1387
1513
  table[attributeInfo.location] = {
1388
1514
  name,
1389
1515
  type: attributeInfo.shaderType,
1390
- values: this._getBufferOrConstantValues(
1391
- this.vertexArray.attributes[attributeInfo.location],
1392
- attributeInfo.bufferDataType
1393
- )
1516
+ values: this._getBufferOrConstantValues(this.vertexArray.attributes[attributeInfo.location], attributeInfo.bufferDataType)
1394
1517
  };
1395
1518
  }
1396
1519
  if (this.vertexArray.indexBuffer) {
@@ -1406,14 +1529,14 @@ var _Model = class {
1406
1529
  }
1407
1530
  // TODO - fix typing of luma data types
1408
1531
  _getBufferOrConstantValues(attribute, dataType) {
1409
- const TypedArrayConstructor = (0, import_core7.getTypedArrayFromDataType)(dataType);
1410
- const typedArray = attribute instanceof import_core7.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
1532
+ const TypedArrayConstructor = (0, import_core11.getTypedArrayFromDataType)(dataType);
1533
+ const typedArray = attribute instanceof import_core8.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
1411
1534
  return typedArray.toString();
1412
1535
  }
1413
1536
  };
1414
1537
  var Model = _Model;
1415
1538
  __publicField(Model, "defaultProps", {
1416
- ...import_core7.RenderPipeline.defaultProps,
1539
+ ...import_core9.RenderPipeline.defaultProps,
1417
1540
  source: null,
1418
1541
  vs: null,
1419
1542
  fs: null,
@@ -1430,8 +1553,11 @@ __publicField(Model, "defaultProps", {
1430
1553
  varyings: [],
1431
1554
  shaderInputs: void 0,
1432
1555
  pipelineFactory: void 0,
1556
+ shaderFactory: void 0,
1433
1557
  transformFeedback: void 0,
1434
- shaderAssembler: import_shadertools2.ShaderAssembler.getDefaultShaderAssembler()
1558
+ shaderAssembler: import_shadertools2.ShaderAssembler.getDefaultShaderAssembler(),
1559
+ debugShaders: void 0,
1560
+ ignoreUnknownAttributes: void 0
1435
1561
  });
1436
1562
  function mergeBufferLayouts(layouts1, layouts2) {
1437
1563
  const layouts = [...layouts1];
@@ -1447,10 +1573,11 @@ function mergeBufferLayouts(layouts1, layouts2) {
1447
1573
  }
1448
1574
  function getPlatformInfo(device) {
1449
1575
  return {
1450
- type: device.info.type,
1576
+ type: device.type,
1451
1577
  shaderLanguage: device.info.shadingLanguage,
1452
1578
  shaderLanguageVersion: device.info.shadingLanguageVersion,
1453
1579
  gpu: device.info.gpu,
1580
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
1454
1581
  features: device.features
1455
1582
  };
1456
1583
  }
@@ -1459,8 +1586,8 @@ function getAttributeNames(bufferLayout) {
1459
1586
  return bufferLayout.attributes ? (_a = bufferLayout.attributes) == null ? void 0 : _a.map((layout) => layout.attribute) : [bufferLayout.name];
1460
1587
  }
1461
1588
 
1462
- // src/transform/buffer-transform.ts
1463
- var import_core10 = require("@luma.gl/core");
1589
+ // dist/transform/buffer-transform.js
1590
+ var import_core12 = require("@luma.gl/core");
1464
1591
  var import_shadertools3 = require("@luma.gl/shadertools");
1465
1592
  var BufferTransform = class {
1466
1593
  device;
@@ -1468,14 +1595,15 @@ var BufferTransform = class {
1468
1595
  transformFeedback;
1469
1596
  /** @deprecated Use device feature test. */
1470
1597
  static isSupported(device) {
1471
- return device.features.has("transform-feedback-webgl2");
1598
+ var _a;
1599
+ return ((_a = device == null ? void 0 : device.info) == null ? void 0 : _a.type) === "webgl";
1472
1600
  }
1473
1601
  constructor(device, props = Model.defaultProps) {
1474
- (0, import_core10.assert)(device.features.has("transform-feedback-webgl2"), "Device must support transform feedback");
1602
+ (0, import_core12.assert)(BufferTransform.isSupported(device), "BufferTransform not yet implemented on WebGPU");
1475
1603
  this.device = device;
1476
1604
  this.model = new Model(this.device, {
1477
1605
  id: props.id || "buffer-transform-model",
1478
- fs: props.fs || (0, import_shadertools3.getPassthroughFS)({ version: 300 }),
1606
+ fs: props.fs || (0, import_shadertools3.getPassthroughFS)(),
1479
1607
  topology: props.topology || "point-list",
1480
1608
  ...props
1481
1609
  });
@@ -1512,7 +1640,7 @@ var BufferTransform = class {
1512
1640
  }
1513
1641
  readAsync(varyingName) {
1514
1642
  const result = this.getBuffer(varyingName);
1515
- if (result instanceof import_core10.Buffer) {
1643
+ if (result instanceof import_core12.Buffer) {
1516
1644
  return result.readAsync();
1517
1645
  }
1518
1646
  const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result;
@@ -1520,7 +1648,7 @@ var BufferTransform = class {
1520
1648
  }
1521
1649
  };
1522
1650
 
1523
- // src/transform/texture-transform.ts
1651
+ // dist/transform/texture-transform.js
1524
1652
  var import_shadertools4 = require("@luma.gl/shadertools");
1525
1653
  var FS_OUTPUT_VARIABLE = "transform_output";
1526
1654
  var TextureTransform = class {
@@ -1545,7 +1673,6 @@ var TextureTransform = class {
1545
1673
  this.model = new Model(this.device, {
1546
1674
  id: props.id || "texture-transform-model",
1547
1675
  fs: props.fs || (0, import_shadertools4.getPassthroughFS)({
1548
- version: 300,
1549
1676
  input: props.targetTextureVarying,
1550
1677
  inputChannels: props.targetTextureChannels,
1551
1678
  output: FS_OUTPUT_VARIABLE
@@ -1628,11 +1755,11 @@ var TextureTransform = class {
1628
1755
  }
1629
1756
  };
1630
1757
 
1631
- // src/lib/clip-space.ts
1632
- var import_core12 = require("@luma.gl/core");
1758
+ // dist/lib/clip-space.js
1759
+ var import_core14 = require("@luma.gl/core");
1633
1760
 
1634
- // src/geometry/geometry.ts
1635
- var import_core11 = require("@luma.gl/core");
1761
+ // dist/geometry/geometry.js
1762
+ var import_core13 = require("@luma.gl/core");
1636
1763
  var Geometry = class {
1637
1764
  id;
1638
1765
  /** Determines how vertices are read from the 'vertex' attributes */
@@ -1643,7 +1770,7 @@ var Geometry = class {
1643
1770
  userData = {};
1644
1771
  constructor(props) {
1645
1772
  const { attributes = {}, indices = null, vertexCount = null } = props;
1646
- this.id = props.id || (0, import_core11.uid)("geometry");
1773
+ this.id = props.id || (0, import_core13.uid)("geometry");
1647
1774
  this.topology = props.topology;
1648
1775
  if (indices) {
1649
1776
  this.indices = ArrayBuffer.isView(indices) ? { value: indices, size: 1 } : indices;
@@ -1651,15 +1778,12 @@ var Geometry = class {
1651
1778
  this.attributes = {};
1652
1779
  for (const [attributeName, attributeValue] of Object.entries(attributes)) {
1653
1780
  const attribute = ArrayBuffer.isView(attributeValue) ? { value: attributeValue } : attributeValue;
1654
- (0, import_core11.assert)(
1655
- ArrayBuffer.isView(attribute.value),
1656
- `${this._print(attributeName)}: must be typed array or object with value as typed array`
1657
- );
1781
+ (0, import_core13.assert)(ArrayBuffer.isView(attribute.value), `${this._print(attributeName)}: must be typed array or object with value as typed array`);
1658
1782
  if ((attributeName === "POSITION" || attributeName === "positions") && !attribute.size) {
1659
1783
  attribute.size = 3;
1660
1784
  }
1661
1785
  if (attributeName === "indices") {
1662
- (0, import_core11.assert)(!this.indices);
1786
+ (0, import_core13.assert)(!this.indices);
1663
1787
  this.indices = attribute;
1664
1788
  } else {
1665
1789
  this.attributes[attributeName] = attribute;
@@ -1674,7 +1798,7 @@ var Geometry = class {
1674
1798
  getVertexCount() {
1675
1799
  return this.vertexCount;
1676
1800
  }
1677
- /**
1801
+ /**
1678
1802
  * Return an object with all attributes plus indices added as a field.
1679
1803
  * TODO Geometry types are a mess
1680
1804
  */
@@ -1691,10 +1815,10 @@ var Geometry = class {
1691
1815
  * type: indices, vertices, uvs
1692
1816
  * size: elements per vertex
1693
1817
  * target: WebGL buffer type (string or constant)
1694
- *
1695
- * @param attributes
1696
- * @param indices
1697
- * @returns
1818
+ *
1819
+ * @param attributes
1820
+ * @param indices
1821
+ * @returns
1698
1822
  */
1699
1823
  _setAttributes(attributes, indices) {
1700
1824
  return this;
@@ -1710,67 +1834,62 @@ var Geometry = class {
1710
1834
  vertexCount = Math.min(vertexCount, value.length / size);
1711
1835
  }
1712
1836
  }
1713
- (0, import_core11.assert)(Number.isFinite(vertexCount));
1837
+ (0, import_core13.assert)(Number.isFinite(vertexCount));
1714
1838
  return vertexCount;
1715
1839
  }
1716
1840
  };
1717
1841
 
1718
- // src/lib/clip-space.ts
1719
- var CLIPSPACE_VERTEX_SHADER = import_core12.glsl`\
1842
+ // dist/lib/clip-space.js
1843
+ var CLIPSPACE_VERTEX_SHADER = `#version 300 es
1720
1844
  in vec2 aClipSpacePosition;
1721
1845
  in vec2 aTexCoord;
1722
1846
  in vec2 aCoordinate;
1723
-
1724
1847
  out vec2 position;
1725
1848
  out vec2 coordinate;
1726
1849
  out vec2 uv;
1727
-
1728
1850
  void main(void) {
1729
- gl_Position = vec4(aClipSpacePosition, 0., 1.);
1730
- position = aClipSpacePosition;
1731
- coordinate = aCoordinate;
1732
- uv = aTexCoord;
1851
+ gl_Position = vec4(aClipSpacePosition, 0., 1.);
1852
+ position = aClipSpacePosition;
1853
+ coordinate = aCoordinate;
1854
+ uv = aTexCoord;
1733
1855
  }
1734
1856
  `;
1735
1857
  var POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
1736
1858
  var ClipSpace = class extends Model {
1737
1859
  constructor(device, opts) {
1738
1860
  const TEX_COORDS = POSITIONS.map((coord) => coord === -1 ? 0 : coord);
1739
- super(
1740
- device,
1741
- {
1742
- ...opts,
1743
- vs: CLIPSPACE_VERTEX_SHADER,
1861
+ super(device, {
1862
+ ...opts,
1863
+ vs: CLIPSPACE_VERTEX_SHADER,
1864
+ vertexCount: 4,
1865
+ geometry: new Geometry({
1866
+ topology: "triangle-strip",
1744
1867
  vertexCount: 4,
1745
- geometry: new Geometry({
1746
- topology: "triangle-strip",
1747
- vertexCount: 4,
1748
- attributes: {
1749
- aClipSpacePosition: { size: 2, value: new Float32Array(POSITIONS) },
1750
- aTexCoord: { size: 2, value: new Float32Array(TEX_COORDS) },
1751
- aCoordinate: { size: 2, value: new Float32Array(TEX_COORDS) }
1752
- }
1753
- })
1754
- }
1755
- );
1868
+ attributes: {
1869
+ aClipSpacePosition: { size: 2, value: new Float32Array(POSITIONS) },
1870
+ aTexCoord: { size: 2, value: new Float32Array(TEX_COORDS) },
1871
+ aCoordinate: { size: 2, value: new Float32Array(TEX_COORDS) }
1872
+ }
1873
+ })
1874
+ });
1756
1875
  }
1757
1876
  };
1758
1877
 
1759
- // src/scenegraph/scenegraph-node.ts
1760
- var import_core13 = require("@luma.gl/core");
1761
- var import_core14 = require("@math.gl/core");
1878
+ // dist/scenegraph/scenegraph-node.js
1879
+ var import_core15 = require("@luma.gl/core");
1880
+ var import_core16 = require("@math.gl/core");
1762
1881
  var ScenegraphNode = class {
1763
1882
  id;
1764
- matrix = new import_core14.Matrix4();
1883
+ matrix = new import_core16.Matrix4();
1765
1884
  display = true;
1766
- position = new import_core14.Vector3();
1767
- rotation = new import_core14.Vector3();
1768
- scale = new import_core14.Vector3(1, 1, 1);
1885
+ position = new import_core16.Vector3();
1886
+ rotation = new import_core16.Vector3();
1887
+ scale = new import_core16.Vector3(1, 1, 1);
1769
1888
  userData = {};
1770
1889
  props = {};
1771
1890
  constructor(props = {}) {
1772
1891
  const { id } = props;
1773
- this.id = id || (0, import_core13.uid)(this.constructor.name);
1892
+ this.id = id || (0, import_core15.uid)(this.constructor.name);
1774
1893
  this._setScenegraphNodeProps(props);
1775
1894
  }
1776
1895
  getBounds() {
@@ -1790,17 +1909,17 @@ var ScenegraphNode = class {
1790
1909
  return `{type: ScenegraphNode, id: ${this.id})}`;
1791
1910
  }
1792
1911
  setPosition(position) {
1793
- (0, import_core13.assert)(position.length === 3, "setPosition requires vector argument");
1912
+ (0, import_core15.assert)(position.length === 3, "setPosition requires vector argument");
1794
1913
  this.position = position;
1795
1914
  return this;
1796
1915
  }
1797
1916
  setRotation(rotation) {
1798
- (0, import_core13.assert)(rotation.length === 3, "setRotation requires vector argument");
1917
+ (0, import_core15.assert)(rotation.length === 3, "setRotation requires vector argument");
1799
1918
  this.rotation = rotation;
1800
1919
  return this;
1801
1920
  }
1802
1921
  setScale(scale) {
1803
- (0, import_core13.assert)(scale.length === 3, "setScale requires vector argument");
1922
+ (0, import_core15.assert)(scale.length === 3, "setScale requires vector argument");
1804
1923
  this.scale = scale;
1805
1924
  return this;
1806
1925
  }
@@ -1852,9 +1971,9 @@ var ScenegraphNode = class {
1852
1971
  return this;
1853
1972
  }
1854
1973
  getCoordinateUniforms(viewMatrix, modelMatrix) {
1855
- (0, import_core13.assert)(viewMatrix);
1974
+ (0, import_core15.assert)(viewMatrix);
1856
1975
  modelMatrix = modelMatrix || this.matrix;
1857
- const worldMatrix = new import_core14.Matrix4(viewMatrix).multiplyRight(modelMatrix);
1976
+ const worldMatrix = new import_core16.Matrix4(viewMatrix).multiplyRight(modelMatrix);
1858
1977
  const worldInverse = worldMatrix.invert();
1859
1978
  const worldInverseTranspose = worldInverse.transpose();
1860
1979
  return {
@@ -1908,39 +2027,35 @@ var ScenegraphNode = class {
1908
2027
  }
1909
2028
  };
1910
2029
 
1911
- // src/scenegraph/group-node.ts
1912
- var import_core15 = require("@math.gl/core");
1913
- var import_core16 = require("@luma.gl/core");
2030
+ // dist/scenegraph/group-node.js
2031
+ var import_core17 = require("@math.gl/core");
2032
+ var import_core18 = require("@luma.gl/core");
1914
2033
  var GroupNode = class extends ScenegraphNode {
1915
2034
  children;
1916
2035
  constructor(props = {}) {
1917
2036
  props = Array.isArray(props) ? { children: props } : props;
1918
2037
  const { children = [] } = props;
1919
- import_core16.log.assert(
1920
- children.every((child) => child instanceof ScenegraphNode),
1921
- "every child must an instance of ScenegraphNode"
1922
- );
2038
+ import_core18.log.assert(children.every((child) => child instanceof ScenegraphNode), "every child must an instance of ScenegraphNode");
1923
2039
  super(props);
1924
2040
  this.children = children;
1925
2041
  }
1926
2042
  getBounds() {
1927
- const result = [[Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]];
2043
+ const result = [
2044
+ [Infinity, Infinity, Infinity],
2045
+ [-Infinity, -Infinity, -Infinity]
2046
+ ];
1928
2047
  this.traverse((node, { worldMatrix }) => {
1929
2048
  const bounds = node.getBounds();
1930
2049
  if (!bounds) {
1931
2050
  return;
1932
2051
  }
1933
2052
  const [min, max] = bounds;
1934
- const center = new import_core15.Vector3(min).add(max).divide([2, 2, 2]);
2053
+ const center = new import_core17.Vector3(min).add(max).divide([2, 2, 2]);
1935
2054
  worldMatrix.transformAsPoint(center, center);
1936
- const halfSize = new import_core15.Vector3(max).subtract(min).divide([2, 2, 2]);
2055
+ const halfSize = new import_core17.Vector3(max).subtract(min).divide([2, 2, 2]);
1937
2056
  worldMatrix.transformAsVector(halfSize, halfSize);
1938
2057
  for (let v = 0; v < 8; v++) {
1939
- const position = new import_core15.Vector3(
1940
- v & 1 ? -1 : 1,
1941
- v & 2 ? -1 : 1,
1942
- v & 4 ? -1 : 1
1943
- ).multiply(halfSize).add(center);
2058
+ const position = new import_core17.Vector3(v & 1 ? -1 : 1, v & 2 ? -1 : 1, v & 4 ? -1 : 1).multiply(halfSize).add(center);
1944
2059
  for (let i = 0; i < 3; i++) {
1945
2060
  result[0][i] = Math.min(result[0][i], position[i]);
1946
2061
  result[1][i] = Math.max(result[1][i], position[i]);
@@ -1980,8 +2095,8 @@ var GroupNode = class extends ScenegraphNode {
1980
2095
  this.children = [];
1981
2096
  return this;
1982
2097
  }
1983
- traverse(visitor, { worldMatrix = new import_core15.Matrix4() } = {}) {
1984
- const modelMatrix = new import_core15.Matrix4(worldMatrix).multiplyRight(this.matrix);
2098
+ traverse(visitor, { worldMatrix = new import_core17.Matrix4() } = {}) {
2099
+ const modelMatrix = new import_core17.Matrix4(worldMatrix).multiplyRight(this.matrix);
1985
2100
  for (const child of this.children) {
1986
2101
  if (child instanceof GroupNode) {
1987
2102
  child.traverse(visitor, { worldMatrix: modelMatrix });
@@ -1992,7 +2107,7 @@ var GroupNode = class extends ScenegraphNode {
1992
2107
  }
1993
2108
  };
1994
2109
 
1995
- // src/scenegraph/model-node.ts
2110
+ // dist/scenegraph/model-node.js
1996
2111
  var ModelNode = class extends ScenegraphNode {
1997
2112
  model;
1998
2113
  bounds = null;
@@ -2025,11 +2140,11 @@ var ModelNode = class extends ScenegraphNode {
2025
2140
  }
2026
2141
  };
2027
2142
 
2028
- // src/geometries/cone-geometry.ts
2029
- var import_core18 = require("@luma.gl/core");
2143
+ // dist/geometries/cone-geometry.js
2144
+ var import_core20 = require("@luma.gl/core");
2030
2145
 
2031
- // src/geometries/truncated-cone-geometry.ts
2032
- var import_core17 = require("@luma.gl/core");
2146
+ // dist/geometries/truncated-cone-geometry.js
2147
+ var import_core19 = require("@luma.gl/core");
2033
2148
  var INDEX_OFFSETS = {
2034
2149
  x: [2, 0, 1],
2035
2150
  y: [0, 1, 2],
@@ -2037,7 +2152,7 @@ var INDEX_OFFSETS = {
2037
2152
  };
2038
2153
  var TruncatedConeGeometry = class extends Geometry {
2039
2154
  constructor(props = {}) {
2040
- const { id = (0, import_core17.uid)("truncated-code-geometry") } = props;
2155
+ const { id = (0, import_core19.uid)("truncated-code-geometry") } = props;
2041
2156
  const { indices, attributes } = tesselateTruncatedCone(props);
2042
2157
  super({
2043
2158
  ...props,
@@ -2054,16 +2169,7 @@ var TruncatedConeGeometry = class extends Geometry {
2054
2169
  }
2055
2170
  };
2056
2171
  function tesselateTruncatedCone(props = {}) {
2057
- const {
2058
- bottomRadius = 0,
2059
- topRadius = 0,
2060
- height = 1,
2061
- nradial = 10,
2062
- nvertical = 10,
2063
- verticalAxis = "y",
2064
- topCap = false,
2065
- bottomCap = false
2066
- } = props;
2172
+ const { bottomRadius = 0, topRadius = 0, height = 1, nradial = 10, nvertical = 10, verticalAxis = "y", topCap = false, bottomCap = false } = props;
2067
2173
  const extra = (topCap ? 2 : 0) + (bottomCap ? 2 : 0);
2068
2174
  const numVertices = (nradial + 1) * (nvertical + 1 + extra);
2069
2175
  const slant = Math.atan2(bottomRadius - topRadius, height);
@@ -2138,10 +2244,10 @@ function tesselateTruncatedCone(props = {}) {
2138
2244
  };
2139
2245
  }
2140
2246
 
2141
- // src/geometries/cone-geometry.ts
2247
+ // dist/geometries/cone-geometry.js
2142
2248
  var ConeGeometry = class extends TruncatedConeGeometry {
2143
2249
  constructor(props = {}) {
2144
- const { id = (0, import_core18.uid)("cone-geometry"), radius = 1, cap = true } = props;
2250
+ const { id = (0, import_core20.uid)("cone-geometry"), radius = 1, cap = true } = props;
2145
2251
  super({
2146
2252
  ...props,
2147
2253
  id,
@@ -2153,11 +2259,11 @@ var ConeGeometry = class extends TruncatedConeGeometry {
2153
2259
  }
2154
2260
  };
2155
2261
 
2156
- // src/geometries/cube-geometry.ts
2157
- var import_core19 = require("@luma.gl/core");
2262
+ // dist/geometries/cube-geometry.js
2263
+ var import_core21 = require("@luma.gl/core");
2158
2264
  var CubeGeometry = class extends Geometry {
2159
2265
  constructor(props = {}) {
2160
- const { id = (0, import_core19.uid)("cube-geometry"), indices = true } = props;
2266
+ const { id = (0, import_core21.uid)("cube-geometry"), indices = true } = props;
2161
2267
  super(indices ? {
2162
2268
  ...props,
2163
2269
  id,
@@ -2763,11 +2869,11 @@ var NON_INDEXED_ATTRIBUTES = {
2763
2869
  COLOR_0: { size: 3, value: CUBE_NON_INDEXED_COLORS }
2764
2870
  };
2765
2871
 
2766
- // src/geometries/cylinder-geometry.ts
2767
- var import_core20 = require("@luma.gl/core");
2872
+ // dist/geometries/cylinder-geometry.js
2873
+ var import_core22 = require("@luma.gl/core");
2768
2874
  var CylinderGeometry = class extends TruncatedConeGeometry {
2769
2875
  constructor(props = {}) {
2770
- const { id = (0, import_core20.uid)("cylinder-geometry"), radius = 1 } = props;
2876
+ const { id = (0, import_core22.uid)("cylinder-geometry"), radius = 1 } = props;
2771
2877
  super({
2772
2878
  ...props,
2773
2879
  id,
@@ -2777,14 +2883,14 @@ var CylinderGeometry = class extends TruncatedConeGeometry {
2777
2883
  }
2778
2884
  };
2779
2885
 
2780
- // src/geometries/ico-sphere-geometry.ts
2781
- var import_core21 = require("@luma.gl/core");
2782
- var import_core22 = require("@math.gl/core");
2886
+ // dist/geometries/ico-sphere-geometry.js
2887
+ var import_core23 = require("@luma.gl/core");
2888
+ var import_core24 = require("@math.gl/core");
2783
2889
  var ICO_POSITIONS = [-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, -1, 0, 1, 0, 0];
2784
2890
  var ICO_INDICES = [3, 4, 5, 3, 5, 1, 3, 1, 0, 3, 0, 4, 4, 0, 2, 4, 2, 5, 2, 0, 1, 5, 2, 1];
2785
2891
  var IcoSphereGeometry = class extends Geometry {
2786
2892
  constructor(props = {}) {
2787
- const { id = (0, import_core21.uid)("ico-sphere-geometry") } = props;
2893
+ const { id = (0, import_core23.uid)("ico-sphere-geometry") } = props;
2788
2894
  const { indices, attributes } = tesselateIcosaHedron(props);
2789
2895
  super({
2790
2896
  ...props,
@@ -2877,7 +2983,7 @@ function tesselateIcosaHedron(props) {
2877
2983
  const u3 = 1 - phi3 / PI2;
2878
2984
  const vec1 = [x3 - x2, y3 - y2, z3 - z2];
2879
2985
  const vec2 = [x1 - x2, y1 - y2, z1 - z2];
2880
- const normal = new import_core22.Vector3(vec1).cross(vec2).normalize();
2986
+ const normal = new import_core24.Vector3(vec1).cross(vec2).normalize();
2881
2987
  let newIndex;
2882
2988
  if ((u1 === 0 || u2 === 0 || u3 === 0) && (u1 === 0 || u1 > 0.5) && (u2 === 0 || u2 > 0.5) && (u3 === 0 || u3 > 0.5)) {
2883
2989
  positions.push(positions[in1 + 0], positions[in1 + 1], positions[in1 + 2]);
@@ -2925,10 +3031,10 @@ function tesselateIcosaHedron(props) {
2925
3031
  };
2926
3032
  }
2927
3033
 
2928
- // src/geometries/plane-geometry.ts
2929
- var import_core23 = require("@luma.gl/core");
3034
+ // dist/geometries/plane-geometry.js
3035
+ var import_core25 = require("@luma.gl/core");
2930
3036
 
2931
- // src/geometry/geometry-utils.ts
3037
+ // dist/geometry/geometry-utils.js
2932
3038
  function unpackIndexedGeometry(geometry) {
2933
3039
  const { indices, attributes } = geometry;
2934
3040
  if (!indices) {
@@ -2956,10 +3062,10 @@ function unpackIndexedGeometry(geometry) {
2956
3062
  };
2957
3063
  }
2958
3064
 
2959
- // src/geometries/plane-geometry.ts
3065
+ // dist/geometries/plane-geometry.js
2960
3066
  var PlaneGeometry = class extends Geometry {
2961
3067
  constructor(props = {}) {
2962
- const { id = (0, import_core23.uid)("plane-geometry") } = props;
3068
+ const { id = (0, import_core25.uid)("plane-geometry") } = props;
2963
3069
  const { indices, attributes } = tesselatePlane(props);
2964
3070
  super({
2965
3071
  ...props,
@@ -3048,11 +3154,11 @@ function tesselatePlane(props) {
3048
3154
  return unpack ? unpackIndexedGeometry(geometry) : geometry;
3049
3155
  }
3050
3156
 
3051
- // src/geometries/sphere-geometry.ts
3052
- var import_core24 = require("@luma.gl/core");
3157
+ // dist/geometries/sphere-geometry.js
3158
+ var import_core26 = require("@luma.gl/core");
3053
3159
  var SphereGeometry = class extends Geometry {
3054
3160
  constructor(props = {}) {
3055
- const { id = (0, import_core24.uid)("sphere-geometry") } = props;
3161
+ const { id = (0, import_core26.uid)("sphere-geometry") } = props;
3056
3162
  const { indices, attributes } = tesselateSphere(props);
3057
3163
  super({
3058
3164
  ...props,
@@ -3126,3 +3232,213 @@ function tesselateSphere(props) {
3126
3232
  }
3127
3233
  };
3128
3234
  }
3235
+
3236
+ // dist/computation.js
3237
+ var import_core27 = require("@luma.gl/core");
3238
+ var import_core28 = require("@luma.gl/core");
3239
+ var import_core29 = require("@luma.gl/core");
3240
+ var import_shadertools5 = require("@luma.gl/shadertools");
3241
+ var LOG_DRAW_PRIORITY2 = 2;
3242
+ var LOG_DRAW_TIMEOUT2 = 1e4;
3243
+ var _Computation = class {
3244
+ device;
3245
+ id;
3246
+ pipelineFactory;
3247
+ shaderFactory;
3248
+ userData = {};
3249
+ /** Bindings (textures, samplers, uniform buffers) */
3250
+ bindings = {};
3251
+ /** The underlying GPU "program". @note May be recreated if parameters change */
3252
+ pipeline;
3253
+ /** the underlying compiled compute shader */
3254
+ shader;
3255
+ source;
3256
+ /** ShaderInputs instance */
3257
+ shaderInputs;
3258
+ _uniformStore;
3259
+ _pipelineNeedsUpdate = "newly created";
3260
+ _getModuleUniforms;
3261
+ props;
3262
+ _destroyed = false;
3263
+ constructor(device, props) {
3264
+ var _a, _b, _c;
3265
+ if (device.type !== "webgpu") {
3266
+ throw new Error("Computation is only supported in WebGPU");
3267
+ }
3268
+ this.props = { ..._Computation.defaultProps, ...props };
3269
+ props = this.props;
3270
+ this.id = props.id || (0, import_core28.uid)("model");
3271
+ this.device = device;
3272
+ Object.assign(this.userData, props.userData);
3273
+ const moduleMap = Object.fromEntries(((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []);
3274
+ this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
3275
+ this.props.shaderLayout ||= (0, import_shadertools5.getShaderLayoutFromWGSL)(this.props.source);
3276
+ const platformInfo = getPlatformInfo2(device);
3277
+ const modules = (((_b = this.props.modules) == null ? void 0 : _b.length) > 0 ? this.props.modules : (_c = this.shaderInputs) == null ? void 0 : _c.getModules()) || [];
3278
+ this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
3279
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
3280
+ const { source, getUniforms } = this.props.shaderAssembler.assembleShader({
3281
+ platformInfo,
3282
+ ...this.props,
3283
+ modules
3284
+ });
3285
+ this.source = source;
3286
+ this._getModuleUniforms = getUniforms;
3287
+ this.pipeline = this._updatePipeline();
3288
+ if (props.bindings) {
3289
+ this.setBindings(props.bindings);
3290
+ }
3291
+ Object.seal(this);
3292
+ }
3293
+ destroy() {
3294
+ if (this._destroyed)
3295
+ return;
3296
+ this.pipelineFactory.release(this.pipeline);
3297
+ this.shaderFactory.release(this.shader);
3298
+ this._uniformStore.destroy();
3299
+ this._destroyed = true;
3300
+ }
3301
+ // Draw call
3302
+ predraw() {
3303
+ this.updateShaderInputs();
3304
+ }
3305
+ dispatch(computePass, x, y, z) {
3306
+ try {
3307
+ this._logDrawCallStart();
3308
+ this.pipeline = this._updatePipeline();
3309
+ this.pipeline.setBindings(this.bindings);
3310
+ computePass.setPipeline(this.pipeline);
3311
+ computePass.setBindings([]);
3312
+ computePass.dispatch(x, y, z);
3313
+ } finally {
3314
+ this._logDrawCallEnd();
3315
+ }
3316
+ }
3317
+ // Update fixed fields (can trigger pipeline rebuild)
3318
+ // Update dynamic fields
3319
+ /**
3320
+ * Updates the vertex count (used in draw calls)
3321
+ * @note Any attributes with stepMode=vertex need to be at least this big
3322
+ */
3323
+ setVertexCount(vertexCount) {
3324
+ }
3325
+ /**
3326
+ * Updates the instance count (used in draw calls)
3327
+ * @note Any attributes with stepMode=instance need to be at least this big
3328
+ */
3329
+ setInstanceCount(instanceCount) {
3330
+ }
3331
+ setShaderInputs(shaderInputs) {
3332
+ this.shaderInputs = shaderInputs;
3333
+ this._uniformStore = new import_core27.UniformStore(this.shaderInputs.modules);
3334
+ for (const moduleName of Object.keys(this.shaderInputs.modules)) {
3335
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
3336
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
3337
+ }
3338
+ }
3339
+ /**
3340
+ * Updates shader module settings (which results in uniforms being set)
3341
+ */
3342
+ setShaderModuleProps(props) {
3343
+ const uniforms = this._getModuleUniforms(props);
3344
+ const keys = Object.keys(uniforms).filter((k) => {
3345
+ const uniform = uniforms[k];
3346
+ return !(0, import_core28.isNumberArray)(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
3347
+ });
3348
+ const bindings = {};
3349
+ for (const k of keys) {
3350
+ bindings[k] = uniforms[k];
3351
+ delete uniforms[k];
3352
+ }
3353
+ }
3354
+ updateShaderInputs() {
3355
+ this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
3356
+ }
3357
+ /**
3358
+ * Sets bindings (textures, samplers, uniform buffers)
3359
+ */
3360
+ setBindings(bindings) {
3361
+ Object.assign(this.bindings, bindings);
3362
+ }
3363
+ _setPipelineNeedsUpdate(reason) {
3364
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
3365
+ }
3366
+ _updatePipeline() {
3367
+ if (this._pipelineNeedsUpdate) {
3368
+ let prevShader = null;
3369
+ if (this.pipeline) {
3370
+ import_core28.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
3371
+ prevShader = this.shader;
3372
+ }
3373
+ this._pipelineNeedsUpdate = false;
3374
+ this.shader = this.shaderFactory.createShader({
3375
+ id: `${this.id}-fragment`,
3376
+ stage: "compute",
3377
+ source: this.source,
3378
+ debug: this.props.debugShaders
3379
+ });
3380
+ this.pipeline = this.pipelineFactory.createComputePipeline({
3381
+ ...this.props,
3382
+ shader: this.shader
3383
+ });
3384
+ if (prevShader) {
3385
+ this.shaderFactory.release(prevShader);
3386
+ }
3387
+ }
3388
+ return this.pipeline;
3389
+ }
3390
+ /** Throttle draw call logging */
3391
+ _lastLogTime = 0;
3392
+ _logOpen = false;
3393
+ _logDrawCallStart() {
3394
+ const logDrawTimeout = import_core28.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2;
3395
+ if (import_core28.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
3396
+ return;
3397
+ }
3398
+ this._lastLogTime = Date.now();
3399
+ this._logOpen = true;
3400
+ import_core28.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core28.log.level <= 2 })();
3401
+ }
3402
+ _logDrawCallEnd() {
3403
+ if (this._logOpen) {
3404
+ const uniformTable = this.shaderInputs.getDebugTable();
3405
+ import_core28.log.table(LOG_DRAW_PRIORITY2, uniformTable)();
3406
+ import_core28.log.groupEnd(LOG_DRAW_PRIORITY2)();
3407
+ this._logOpen = false;
3408
+ }
3409
+ }
3410
+ _drawCount = 0;
3411
+ // TODO - fix typing of luma data types
3412
+ _getBufferOrConstantValues(attribute, dataType) {
3413
+ const TypedArrayConstructor = (0, import_core29.getTypedArrayFromDataType)(dataType);
3414
+ const typedArray = attribute instanceof import_core27.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
3415
+ return typedArray.toString();
3416
+ }
3417
+ };
3418
+ var Computation = _Computation;
3419
+ __publicField(Computation, "defaultProps", {
3420
+ ...import_core27.ComputePipeline.defaultProps,
3421
+ id: "unnamed",
3422
+ handle: void 0,
3423
+ userData: {},
3424
+ source: "",
3425
+ modules: [],
3426
+ defines: {},
3427
+ bindings: void 0,
3428
+ shaderInputs: void 0,
3429
+ pipelineFactory: void 0,
3430
+ shaderFactory: void 0,
3431
+ shaderAssembler: import_shadertools5.ShaderAssembler.getDefaultShaderAssembler(),
3432
+ debugShaders: void 0
3433
+ });
3434
+ function getPlatformInfo2(device) {
3435
+ return {
3436
+ type: device.type,
3437
+ shaderLanguage: device.info.shadingLanguage,
3438
+ shaderLanguageVersion: device.info.shadingLanguageVersion,
3439
+ gpu: device.info.gpu,
3440
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
3441
+ features: device.features
3442
+ };
3443
+ }
3444
+ //# sourceMappingURL=index.cjs.map