@luma.gl/engine 9.0.17 → 9.1.0-alpha.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 (139) hide show
  1. package/dist/animation/key-frames.d.ts.map +1 -1
  2. package/dist/animation/key-frames.js +3 -0
  3. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
  4. package/dist/animation-loop/animation-loop-template.js +3 -0
  5. package/dist/animation-loop/animation-loop.d.ts +1 -1
  6. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  7. package/dist/animation-loop/animation-loop.js +5 -4
  8. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-props.js +3 -0
  10. package/dist/animation-loop/make-animation-loop.js +1 -1
  11. package/dist/animation-loop/request-animation-frame.d.ts +3 -0
  12. package/dist/animation-loop/request-animation-frame.d.ts.map +1 -0
  13. package/dist/animation-loop/request-animation-frame.js +16 -0
  14. package/dist/application-utils/load-file.d.ts +22 -0
  15. package/dist/application-utils/load-file.d.ts.map +1 -0
  16. package/dist/application-utils/load-file.js +42 -0
  17. package/dist/application-utils/random.d.ts +3 -0
  18. package/dist/application-utils/random.d.ts.map +1 -0
  19. package/dist/application-utils/random.js +16 -0
  20. package/dist/async-texture/async-texture.d.ts +50 -0
  21. package/dist/async-texture/async-texture.d.ts.map +1 -0
  22. package/dist/async-texture/async-texture.js +83 -0
  23. package/dist/computation.d.ts +4 -3
  24. package/dist/computation.d.ts.map +1 -1
  25. package/dist/computation.js +14 -6
  26. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  27. package/dist/debug/copy-texture-to-image.js +4 -1
  28. package/dist/debug/debug-framebuffer.d.ts.map +1 -1
  29. package/dist/debug/debug-framebuffer.js +17 -12
  30. package/dist/debug/pixel-data-utils.d.ts +1 -1
  31. package/dist/dist.dev.js +728 -555
  32. package/dist/dist.min.js +57 -41
  33. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  34. package/dist/geometries/cone-geometry.js +4 -1
  35. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  36. package/dist/geometries/cube-geometry.js +4 -1
  37. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  38. package/dist/geometries/cylinder-geometry.js +4 -1
  39. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  40. package/dist/geometries/ico-sphere-geometry.js +4 -1
  41. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  42. package/dist/geometries/plane-geometry.js +4 -1
  43. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  44. package/dist/geometries/sphere-geometry.js +4 -1
  45. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  46. package/dist/geometries/truncated-cone-geometry.js +4 -1
  47. package/dist/geometry/geometry-table.d.ts +2 -1
  48. package/dist/geometry/geometry-table.d.ts.map +1 -1
  49. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  50. package/dist/geometry/geometry-utils.js +3 -1
  51. package/dist/geometry/geometry.d.ts +5 -4
  52. package/dist/geometry/geometry.d.ts.map +1 -1
  53. package/dist/geometry/geometry.js +9 -5
  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 +18 -6
  57. package/dist/geometry/gpu-table.js +3 -0
  58. package/dist/index.cjs +514 -258
  59. package/dist/index.cjs.map +4 -4
  60. package/dist/index.d.ts +6 -0
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +8 -1
  63. package/dist/lib/clip-space.d.ts.map +1 -1
  64. package/dist/lib/clip-space.js +10 -7
  65. package/dist/lib/pipeline-factory.d.ts +3 -2
  66. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  67. package/dist/lib/pipeline-factory.js +12 -8
  68. package/dist/lib/shader-factory.d.ts +3 -2
  69. package/dist/lib/shader-factory.d.ts.map +1 -1
  70. package/dist/lib/shader-factory.js +11 -4
  71. package/dist/model/model.d.ts +10 -6
  72. package/dist/model/model.d.ts.map +1 -1
  73. package/dist/model/model.js +64 -8
  74. package/dist/model/split-uniforms-and-bindings.d.ts +9 -0
  75. package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -0
  76. package/dist/model/split-uniforms-and-bindings.js +20 -0
  77. package/dist/scenegraph/group-node.d.ts +1 -1
  78. package/dist/scenegraph/group-node.d.ts.map +1 -1
  79. package/dist/scenegraph/group-node.js +3 -0
  80. package/dist/scenegraph/model-node.d.ts +2 -2
  81. package/dist/scenegraph/model-node.d.ts.map +1 -1
  82. package/dist/scenegraph/model-node.js +6 -3
  83. package/dist/scenegraph/scenegraph-node.d.ts +5 -6
  84. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
  85. package/dist/scenegraph/scenegraph-node.js +11 -8
  86. package/dist/shader-inputs.d.ts +21 -8
  87. package/dist/shader-inputs.d.ts.map +1 -1
  88. package/dist/shader-inputs.js +11 -6
  89. package/dist/transform/buffer-transform.d.ts.map +1 -1
  90. package/dist/transform/buffer-transform.js +8 -2
  91. package/dist/transform/texture-transform.d.ts +2 -2
  92. package/dist/transform/texture-transform.d.ts.map +1 -1
  93. package/dist/transform/texture-transform.js +1 -0
  94. package/dist/utils/deep-equal.d.ts +9 -0
  95. package/dist/utils/deep-equal.d.ts.map +1 -0
  96. package/dist/utils/deep-equal.js +50 -0
  97. package/dist/utils/uid.d.ts +7 -0
  98. package/dist/utils/uid.d.ts.map +1 -0
  99. package/dist/utils/uid.js +14 -0
  100. package/package.json +7 -6
  101. package/src/animation/key-frames.ts +4 -0
  102. package/src/animation-loop/animation-loop-template.ts +4 -0
  103. package/src/animation-loop/animation-loop.ts +6 -4
  104. package/src/animation-loop/animation-props.ts +4 -0
  105. package/src/animation-loop/make-animation-loop.ts +1 -1
  106. package/src/animation-loop/request-animation-frame.ts +19 -0
  107. package/src/application-utils/load-file.ts +51 -0
  108. package/src/application-utils/random.ts +18 -0
  109. package/src/async-texture/async-texture.ts +146 -0
  110. package/src/computation.ts +17 -9
  111. package/src/debug/copy-texture-to-image.ts +4 -1
  112. package/src/debug/debug-framebuffer.ts +18 -12
  113. package/src/debug/pixel-data-utils.ts +1 -1
  114. package/src/geometries/cone-geometry.ts +5 -1
  115. package/src/geometries/cube-geometry.ts +5 -1
  116. package/src/geometries/cylinder-geometry.ts +5 -1
  117. package/src/geometries/ico-sphere-geometry.ts +5 -1
  118. package/src/geometries/plane-geometry.ts +5 -1
  119. package/src/geometries/sphere-geometry.ts +5 -1
  120. package/src/geometries/truncated-cone-geometry.ts +5 -1
  121. package/src/geometry/geometry-table.ts +2 -1
  122. package/src/geometry/geometry-utils.ts +3 -1
  123. package/src/geometry/geometry.ts +16 -19
  124. package/src/geometry/gpu-geometry.ts +20 -14
  125. package/src/geometry/gpu-table.ts +4 -0
  126. package/src/index.ts +16 -0
  127. package/src/lib/clip-space.ts +6 -2
  128. package/src/lib/pipeline-factory.ts +17 -16
  129. package/src/lib/shader-factory.ts +13 -6
  130. package/src/model/model.ts +70 -17
  131. package/src/model/split-uniforms-and-bindings.ts +31 -0
  132. package/src/scenegraph/group-node.ts +4 -0
  133. package/src/scenegraph/model-node.ts +9 -5
  134. package/src/scenegraph/scenegraph-node.ts +17 -13
  135. package/src/shader-inputs.ts +47 -18
  136. package/src/transform/buffer-transform.ts +8 -9
  137. package/src/transform/texture-transform.ts +2 -1
  138. package/src/utils/deep-equal.ts +51 -0
  139. package/src/utils/uid.ts +16 -0
@@ -1,22 +1,27 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
1
5
  import {Device, Shader, ShaderProps} from '@luma.gl/core';
2
6
 
3
7
  /** Manages a cached pool of Shaders for reuse. */
4
8
  export class ShaderFactory {
5
9
  static readonly defaultProps: Required<ShaderProps> = {...Shader.defaultProps};
6
10
 
7
- public readonly device: Device;
8
-
9
- private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
10
-
11
11
  /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
12
12
  static getDefaultShaderFactory(device: Device): ShaderFactory {
13
13
  device._lumaData.defaultShaderFactory ||= new ShaderFactory(device);
14
14
  return device._lumaData.defaultShaderFactory as ShaderFactory;
15
15
  }
16
16
 
17
+ public readonly device: Device;
18
+ readonly destroyPolicy: 'unused' | 'never';
19
+ private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
20
+
17
21
  /** @internal */
18
22
  constructor(device: Device) {
19
23
  this.device = device;
24
+ this.destroyPolicy = device.props._factoryDestroyPolicy;
20
25
  }
21
26
 
22
27
  /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
@@ -43,8 +48,10 @@ export class ShaderFactory {
43
48
  if (cacheEntry) {
44
49
  cacheEntry.useCount--;
45
50
  if (cacheEntry.useCount === 0) {
46
- delete this._cache[key];
47
- cacheEntry.shader.destroy();
51
+ if (this.destroyPolicy === 'unused') {
52
+ delete this._cache[key];
53
+ cacheEntry.shader.destroy();
54
+ }
48
55
  }
49
56
  }
50
57
  }
@@ -3,12 +3,13 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  // A lot of imports, but then Model is where it all comes together...
6
- import type {TypedArray, RenderPipelineProps, RenderPipelineParameters} from '@luma.gl/core';
6
+ import type {TypedArray} from '@math.gl/types';
7
+ import type {RenderPipelineProps, RenderPipelineParameters} from '@luma.gl/core';
7
8
  import type {BufferLayout, Shader, VertexArray, TransformFeedback} from '@luma.gl/core';
8
9
  import type {AttributeInfo, Binding, UniformValue, PrimitiveTopology} from '@luma.gl/core';
9
10
  import {Device, DeviceFeature, Buffer, Texture, TextureView, Sampler} from '@luma.gl/core';
10
11
  import {RenderPipeline, RenderPass, UniformStore} from '@luma.gl/core';
11
- import {log, uid, deepEqual, isObjectEmpty, splitUniformsAndBindings} from '@luma.gl/core';
12
+ import {log} from '@luma.gl/core';
12
13
  import {getTypedArrayFromDataType, getAttributeInfosFromLayouts} from '@luma.gl/core';
13
14
 
14
15
  import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
@@ -16,16 +17,22 @@ import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
16
17
 
17
18
  import type {Geometry} from '../geometry/geometry';
18
19
  import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry';
19
- import {ShaderInputs} from '../shader-inputs';
20
20
  import {PipelineFactory} from '../lib/pipeline-factory';
21
21
  import {ShaderFactory} from '../lib/shader-factory';
22
22
  import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
23
23
  import {debugFramebuffer} from '../debug/debug-framebuffer';
24
+ import {deepEqual} from '../utils/deep-equal';
25
+ import {uid} from '../utils/uid';
26
+ import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
27
+
28
+ import {ShaderInputs} from '../shader-inputs';
29
+ // import type {AsyncTextureProps} from '../async-texture/async-texture';
30
+ import {AsyncTexture} from '../async-texture/async-texture';
24
31
 
25
32
  const LOG_DRAW_PRIORITY = 2;
26
33
  const LOG_DRAW_TIMEOUT = 10000;
27
34
 
28
- export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
35
+ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
29
36
  source?: string;
30
37
  vs: string | null;
31
38
  fs: string | null;
@@ -39,7 +46,7 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
39
46
  /** Shader inputs, used to generated uniform buffers and bindings */
40
47
  shaderInputs?: ShaderInputs;
41
48
  /** Bindings */
42
- bindings?: Record<string, Binding>;
49
+ bindings?: Record<string, Binding | AsyncTexture>;
43
50
  /** Parameters that are built into the pipeline */
44
51
  parameters?: RenderPipelineParameters;
45
52
 
@@ -92,7 +99,7 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
92
99
  export class Model {
93
100
  static defaultProps: Required<ModelProps> = {
94
101
  ...RenderPipeline.defaultProps,
95
- source: null,
102
+ source: undefined!,
96
103
  vs: null,
97
104
  fs: null,
98
105
  id: 'unnamed',
@@ -114,7 +121,7 @@ export class Model {
114
121
  shaderInputs: undefined!,
115
122
  pipelineFactory: undefined!,
116
123
  shaderFactory: undefined!,
117
- transformFeedback: undefined,
124
+ transformFeedback: undefined!,
118
125
  shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(),
119
126
 
120
127
  debugShaders: undefined!,
@@ -123,8 +130,11 @@ export class Model {
123
130
 
124
131
  readonly device: Device;
125
132
  readonly id: string;
133
+ // @ts-expect-error assigned in function called from constructor
126
134
  readonly source: string;
135
+ // @ts-expect-error assigned in function called from constructor
127
136
  readonly vs: string;
137
+ // @ts-expect-error assigned in function called from constructor
128
138
  readonly fs: string;
129
139
  readonly pipelineFactory: PipelineFactory;
130
140
  readonly shaderFactory: ShaderFactory;
@@ -156,7 +166,7 @@ export class Model {
156
166
  /** Constant-valued attributes */
157
167
  constantAttributes: Record<string, TypedArray> = {};
158
168
  /** Bindings (textures, samplers, uniform buffers) */
159
- bindings: Record<string, Binding> = {};
169
+ bindings: Record<string, Binding | AsyncTexture> = {};
160
170
  /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
161
171
  uniforms: Record<string, UniformValue> = {};
162
172
 
@@ -174,8 +184,9 @@ export class Model {
174
184
  pipeline: RenderPipeline;
175
185
 
176
186
  /** ShaderInputs instance */
187
+ // @ts-expect-error Assigned in function called by constructor
177
188
  shaderInputs: ShaderInputs;
178
-
189
+ // @ts-expect-error Assigned in function called by constructor
179
190
  _uniformStore: UniformStore;
180
191
 
181
192
  _attributeInfos: Record<string, AttributeInfo> = {};
@@ -209,6 +220,7 @@ export class Model {
209
220
 
210
221
  // Extract modules from shader inputs if not supplied
211
222
  const modules =
223
+ // @ts-expect-error shaderInputs is assigned in setShaderInputs above.
212
224
  (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
213
225
 
214
226
  const isWebGPU = this.device.type === 'webgpu';
@@ -219,16 +231,17 @@ export class Model {
219
231
  if (isWebGPU && this.props.source) {
220
232
  // WGSL
221
233
  this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
222
- const {source, getUniforms} = this.props.shaderAssembler.assembleShader({
234
+ const {source, getUniforms} = this.props.shaderAssembler.assembleWGSLShader({
223
235
  platformInfo,
224
236
  ...this.props,
225
237
  modules
226
238
  });
227
239
  this.source = source;
240
+ // @ts-expect-error
228
241
  this._getModuleUniforms = getUniforms;
229
242
  } else {
230
243
  // GLSL
231
- const {vs, fs, getUniforms} = this.props.shaderAssembler.assembleShaderPair({
244
+ const {vs, fs, getUniforms} = this.props.shaderAssembler.assembleGLSLShaderPair({
232
245
  platformInfo,
233
246
  ...this.props,
234
247
  modules
@@ -236,6 +249,7 @@ export class Model {
236
249
 
237
250
  this.vs = vs;
238
251
  this.fs = fs;
252
+ // @ts-expect-error
239
253
  this._getModuleUniforms = getUniforms;
240
254
  }
241
255
 
@@ -358,7 +372,11 @@ export class Model {
358
372
 
359
373
  // Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
360
374
  // Any caching needs to be done inside the pipeline functions
361
- this.pipeline.setBindings(this.bindings, {disableWarnings: this.props.disableWarnings});
375
+ // TODO this is a busy initialized check for all bindings every frame
376
+ const syncBindings = this._getBindings();
377
+ this.pipeline.setBindings(syncBindings, {
378
+ disableWarnings: this.props.disableWarnings
379
+ });
362
380
  if (!isObjectEmpty(this.uniforms)) {
363
381
  this.pipeline.setUniformsWebGL(this.uniforms);
364
382
  }
@@ -513,7 +531,7 @@ export class Model {
513
531
  /**
514
532
  * Sets bindings (textures, samplers, uniform buffers)
515
533
  */
516
- setBindings(bindings: Record<string, Binding>): void {
534
+ setBindings(bindings: Record<string, Binding | AsyncTexture>): void {
517
535
  Object.assign(this.bindings, bindings);
518
536
  this.setNeedsRedraw('bindings');
519
537
  }
@@ -626,6 +644,21 @@ export class Model {
626
644
 
627
645
  // Internal methods
628
646
 
647
+ /** Get texture / texture view from any async textures */
648
+ _getBindings(): Record<string, Binding> {
649
+ // Extract actual textures from async textures. If not loaded, null
650
+ return Object.entries(this.bindings).reduce<Record<string, Binding>>((acc, [name, binding]) => {
651
+ if (binding instanceof AsyncTexture) {
652
+ if (binding.isReady) {
653
+ acc[name] = binding.texture;
654
+ }
655
+ } else {
656
+ acc[name] = binding;
657
+ }
658
+ return acc;
659
+ }, {});
660
+ }
661
+
629
662
  /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
630
663
  _getBindingsUpdateTimestamp(): number {
631
664
  let timestamp = 0;
@@ -634,6 +667,11 @@ export class Model {
634
667
  timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
635
668
  } else if (binding instanceof Buffer || binding instanceof Texture) {
636
669
  timestamp = Math.max(timestamp, binding.updateTimestamp);
670
+ } else if (binding instanceof AsyncTexture) {
671
+ timestamp = binding.texture
672
+ ? Math.max(timestamp, binding.texture.updateTimestamp)
673
+ : // The texture will become available in the future
674
+ Infinity;
637
675
  } else if (!(binding instanceof Sampler)) {
638
676
  timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
639
677
  }
@@ -713,6 +751,9 @@ export class Model {
713
751
  bufferLayout: this.bufferLayout,
714
752
  topology: this.topology,
715
753
  parameters: this.parameters,
754
+ // TODO - why set bindings here when we reset them every frame?
755
+ // Should we expose a BindGroup abstraction?
756
+ bindings: this._getBindings(),
716
757
  vs,
717
758
  fs
718
759
  });
@@ -788,13 +829,13 @@ export class Model {
788
829
  _getAttributeDebugTable(): Record<string, Record<string, unknown>> {
789
830
  const table: Record<string, Record<string, unknown>> = {};
790
831
  for (const [name, attributeInfo] of Object.entries(this._attributeInfos)) {
832
+ const values = this.vertexArray.attributes[attributeInfo.location];
791
833
  table[attributeInfo.location] = {
792
834
  name,
793
835
  type: attributeInfo.shaderType,
794
- values: this._getBufferOrConstantValues(
795
- this.vertexArray.attributes[attributeInfo.location],
796
- attributeInfo.bufferDataType
797
- )
836
+ values: values
837
+ ? this._getBufferOrConstantValues(values, attributeInfo.bufferDataType)
838
+ : 'null'
798
839
  };
799
840
  }
800
841
  if (this.vertexArray.indexBuffer) {
@@ -855,3 +896,15 @@ function getAttributeNames(bufferLayout: BufferLayout): string[] {
855
896
  ? bufferLayout.attributes?.map(layout => layout.attribute)
856
897
  : [bufferLayout.name];
857
898
  }
899
+
900
+ /** Returns true if given object is empty, false otherwise. */
901
+ function isObjectEmpty(obj: object): boolean {
902
+ let isEmpty = true;
903
+ // @ts-ignore key is unused
904
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
905
+ for (const key in obj) {
906
+ isEmpty = false;
907
+ break;
908
+ }
909
+ return isEmpty;
910
+ }
@@ -0,0 +1,31 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {UniformValue, Binding} from '@luma.gl/core';
6
+ import {isNumericArray} from '@math.gl/types';
7
+
8
+ export function isUniformValue(value: unknown): value is UniformValue {
9
+ return isNumericArray(value) !== null || typeof value === 'number' || typeof value === 'boolean';
10
+ }
11
+
12
+ type UniformsAndBindings = {
13
+ bindings: Record<string, Binding>;
14
+ uniforms: Record<string, UniformValue>;
15
+ };
16
+
17
+ export function splitUniformsAndBindings(
18
+ uniforms: Record<string, Binding | UniformValue>
19
+ ): UniformsAndBindings {
20
+ const result: UniformsAndBindings = {bindings: {}, uniforms: {}};
21
+ Object.keys(uniforms).forEach(name => {
22
+ const uniform = uniforms[name];
23
+ if (isUniformValue(uniform)) {
24
+ result.uniforms[name] = uniform;
25
+ } else {
26
+ result.bindings[name] = uniform;
27
+ }
28
+ });
29
+
30
+ return result;
31
+ }
@@ -1,3 +1,7 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
1
5
  import {Matrix4, Vector3} from '@math.gl/core';
2
6
  import {log} from '@luma.gl/core';
3
7
  import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
@@ -1,3 +1,7 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
1
5
  import {RenderPass} from '@luma.gl/core';
2
6
  import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
3
7
  import {Model} from '../model/model';
@@ -28,10 +32,6 @@ export class ModelNode extends ScenegraphNode {
28
32
  this.setProps(props);
29
33
  }
30
34
 
31
- override getBounds(): [number[], number[]] | null {
32
- return this.bounds;
33
- }
34
-
35
35
  override destroy(): void {
36
36
  if (this.model) {
37
37
  this.model.destroy();
@@ -42,8 +42,12 @@ export class ModelNode extends ScenegraphNode {
42
42
  this.managedResources = [];
43
43
  }
44
44
 
45
+ override getBounds(): [number[], number[]] | null {
46
+ return this.bounds;
47
+ }
48
+
45
49
  // Expose model methods
46
- draw(renderPass?: RenderPass) {
50
+ draw(renderPass: RenderPass) {
47
51
  // Return value indicates if something was actually drawn
48
52
  return this.model.draw(renderPass);
49
53
  }
@@ -1,15 +1,19 @@
1
- import {assert, uid, NumberArray} from '@luma.gl/core';
2
- import {Vector3, Matrix4} from '@math.gl/core';
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Vector3, Matrix4, NumericArray} from '@math.gl/core';
6
+ import {uid} from '../utils/uid';
3
7
 
4
8
  /** Properties for creating a new Scenegraph */
5
9
  export type ScenegraphNodeProps = {
6
10
  id?: string;
7
11
  /** whether to display the object at all */
8
12
  display?: boolean;
9
- matrix?: NumberArray;
10
- position?: NumberArray;
11
- rotation?: NumberArray;
12
- scale?: NumberArray;
13
+ matrix?: NumericArray;
14
+ position?: NumericArray;
15
+ rotation?: NumericArray;
16
+ scale?: NumericArray;
13
17
  update?: boolean;
14
18
  };
15
19
 
@@ -53,19 +57,19 @@ export class ScenegraphNode {
53
57
  }
54
58
 
55
59
  setPosition(position: any): this {
56
- assert(position.length === 3, 'setPosition requires vector argument');
60
+ // assert(position.length === 3, 'setPosition requires vector argument');
57
61
  this.position = position;
58
62
  return this;
59
63
  }
60
64
 
61
65
  setRotation(rotation: any): this {
62
- assert(rotation.length === 3, 'setRotation requires vector argument');
66
+ // assert(rotation.length === 3, 'setRotation requires vector argument');
63
67
  this.rotation = rotation;
64
68
  return this;
65
69
  }
66
70
 
67
71
  setScale(scale: any): this {
68
- assert(scale.length === 3, 'setScale requires vector argument');
72
+ // assert(scale.length === 3, 'setScale requires vector argument');
69
73
  this.scale = scale;
70
74
  return this;
71
75
  }
@@ -140,7 +144,7 @@ export class ScenegraphNode {
140
144
  } {
141
145
  // TODO - solve multiple class problem
142
146
  // assert(viewMatrix instanceof Matrix4);
143
- assert(viewMatrix);
147
+ // assert(viewMatrix);
144
148
  modelMatrix = modelMatrix || this.matrix;
145
149
  const worldMatrix = new Matrix4(viewMatrix).multiplyRight(modelMatrix);
146
150
  const worldInverse = worldMatrix.invert();
@@ -180,9 +184,9 @@ export class ScenegraphNode {
180
184
  */
181
185
 
182
186
  _setScenegraphNodeProps(props: ScenegraphNodeProps): void {
183
- if ('display' in props) {
184
- this.display = props.display;
185
- }
187
+ // if ('display' in props) {
188
+ // this.display = props.display;
189
+ // }
186
190
 
187
191
  if ('position' in props) {
188
192
  this.setPosition(props.position);
@@ -2,10 +2,36 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {Binding, UniformValue} from '@luma.gl/core';
6
- import {log, splitUniformsAndBindings} from '@luma.gl/core';
5
+ import type {UniformValue, Texture, Sampler} from '@luma.gl/core';
6
+ import {log} from '@luma.gl/core';
7
7
  // import type {ShaderUniformType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core';
8
- import {_resolveModules, ShaderModule, ShaderModuleInstance} from '@luma.gl/shadertools';
8
+ import {getShaderModuleDependencies, ShaderModule} from '@luma.gl/shadertools';
9
+ import {splitUniformsAndBindings} from './model/split-uniforms-and-bindings';
10
+
11
+ type BindingValue = Buffer | Texture | Sampler;
12
+
13
+ /** Minimal ShaderModule subset, we don't need shader code etc */
14
+ export type ShaderModuleInputs<
15
+ PropsT extends Record<string, unknown> = Record<string, unknown>,
16
+ UniformsT extends Record<string, UniformValue> = Record<string, UniformValue>,
17
+ BindingsT extends Record<string, BindingValue> = Record<string, BindingValue>
18
+ > = {
19
+ defaultUniforms?: UniformsT;
20
+ getUniforms?: (props?: any, oldProps?: any) => Record<string, BindingValue | UniformValue>;
21
+
22
+ /** Not used. Used to access props type */
23
+ props?: PropsT;
24
+
25
+ bindings?: Record<
26
+ keyof BindingsT,
27
+ {
28
+ location: number;
29
+ type: 'texture' | 'sampler' | 'uniforms';
30
+ }
31
+ >;
32
+
33
+ uniformTypes?: any;
34
+ };
9
35
 
10
36
  /**
11
37
  * ShaderInputs holds uniform and binding values for one or more shader modules,
@@ -23,22 +49,24 @@ export class ShaderInputs<
23
49
  * The map of modules
24
50
  * @todo should should this include the resolved dependencies?
25
51
  */
26
- modules: Readonly<{[P in keyof ShaderPropsT]: ShaderModule<ShaderPropsT[P]>}>;
52
+ // @ts-expect-error Fix typings
53
+ modules: Readonly<{[P in keyof ShaderPropsT]: ShaderModuleInputs<ShaderPropsT[P]>}>;
27
54
 
28
55
  /** Stores the uniform values for each module */
29
56
  moduleUniforms: Record<keyof ShaderPropsT, Record<string, UniformValue>>;
30
57
  /** Stores the uniform bindings for each module */
31
- moduleBindings: Record<keyof ShaderPropsT, Record<string, Binding>>;
58
+ moduleBindings: Record<keyof ShaderPropsT, Record<string, Texture | Sampler>>;
32
59
  /** Tracks if uniforms have changed */
33
- moduleUniformsChanged: Record<keyof ShaderPropsT, false | string>;
60
+ // moduleUniformsChanged: Record<keyof ShaderPropsT, false | string>;
34
61
 
35
62
  /**
36
63
  * Create a new UniformStore instance
37
64
  * @param modules
38
65
  */
39
- constructor(modules: {[P in keyof ShaderPropsT]?: ShaderModule<ShaderPropsT[P], any>}) {
66
+ // @ts-expect-error Fix typings
67
+ constructor(modules: {[P in keyof ShaderPropsT]?: ShaderModuleInputs<ShaderPropsT[P]>}) {
40
68
  // Extract modules with dependencies
41
- const resolvedModules = _resolveModules(
69
+ const resolvedModules = getShaderModuleDependencies(
42
70
  Object.values(modules).filter(module => module.dependencies)
43
71
  );
44
72
  for (const resolvedModule of resolvedModules) {
@@ -49,9 +77,10 @@ export class ShaderInputs<
49
77
  log.log(1, 'Creating ShaderInputs with modules', Object.keys(modules))();
50
78
 
51
79
  // Store the module definitions and create storage for uniform values and binding values, per module
52
- this.modules = modules as {[P in keyof ShaderPropsT]: ShaderModule<ShaderPropsT[P]>};
80
+ // @ts-expect-error Fix typings
81
+ this.modules = modules;
53
82
  this.moduleUniforms = {} as Record<keyof ShaderPropsT, Record<string, UniformValue>>;
54
- this.moduleBindings = {} as Record<keyof ShaderPropsT, Record<string, Binding>>;
83
+ this.moduleBindings = {} as Record<keyof ShaderPropsT, Record<string, Texture | Sampler>>;
55
84
 
56
85
  // Initialize the modules
57
86
  for (const [name, module] of Object.entries(modules)) {
@@ -72,7 +101,7 @@ export class ShaderInputs<
72
101
  setProps(props: Partial<{[P in keyof ShaderPropsT]?: Partial<ShaderPropsT[P]>}>): void {
73
102
  for (const name of Object.keys(props)) {
74
103
  const moduleName = name as keyof ShaderPropsT;
75
- const moduleProps = props[moduleName];
104
+ const moduleProps = props[moduleName] || {};
76
105
  const module = this.modules[moduleName];
77
106
  if (!module) {
78
107
  // Ignore props for unregistered modules
@@ -80,10 +109,10 @@ export class ShaderInputs<
80
109
  continue; // eslint-disable-line no-continue
81
110
  }
82
111
 
83
- const oldUniforms = this.moduleUniforms[moduleName] as (typeof module)['uniforms'];
112
+ const oldUniforms = this.moduleUniforms[moduleName];
84
113
  const oldBindings = this.moduleBindings[moduleName];
85
- const uniformsAndBindings =
86
- module.getUniforms?.(moduleProps, oldUniforms) || (moduleProps as any);
114
+ let uniformsAndBindings = module.getUniforms?.(moduleProps, this.moduleUniforms[moduleName]);
115
+ uniformsAndBindings ||= {...this.moduleUniforms[moduleName], ...moduleProps};
87
116
 
88
117
  const {uniforms, bindings} = splitUniformsAndBindings(uniformsAndBindings);
89
118
  this.moduleUniforms[moduleName] = {...oldUniforms, ...uniforms};
@@ -103,7 +132,7 @@ export class ShaderInputs<
103
132
  * Return the map of modules
104
133
  * @todo should should this include the resolved dependencies?
105
134
  */
106
- getModules(): ShaderModuleInstance[] {
135
+ getModules(): ShaderModule[] {
107
136
  return Object.values(this.modules);
108
137
  }
109
138
 
@@ -113,8 +142,8 @@ export class ShaderInputs<
113
142
  }
114
143
 
115
144
  /** Merges all bindings for the shader (from the various modules) */
116
- getBindings(): Record<string, Binding> {
117
- const bindings = {} as Record<string, Binding>;
145
+ getBindings(): Record<string, Texture | Sampler> {
146
+ const bindings = {} as Record<string, Texture | Sampler>;
118
147
  for (const moduleBindings of Object.values(this.moduleBindings)) {
119
148
  Object.assign(bindings, moduleBindings);
120
149
  }
@@ -126,7 +155,7 @@ export class ShaderInputs<
126
155
  for (const [moduleName, module] of Object.entries(this.moduleUniforms)) {
127
156
  for (const [key, value] of Object.entries(module)) {
128
157
  table[`${moduleName}.${key}`] = {
129
- type: this.modules[moduleName].uniformTypes?.[key as keyof ShaderPropsT],
158
+ type: this.modules[moduleName].uniformTypes?.[key],
130
159
  value: String(value)
131
160
  };
132
161
  }
@@ -2,14 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {
6
- Device,
7
- Buffer,
8
- BufferRange,
9
- TransformFeedback,
10
- assert,
11
- RenderPassProps
12
- } from '@luma.gl/core';
5
+ import {Device, Buffer, BufferRange, TransformFeedback, RenderPassProps} from '@luma.gl/core';
13
6
  import {getPassthroughFS} from '@luma.gl/shadertools';
14
7
  import {Model} from '../model/model';
15
8
  import type {ModelProps} from '../model/model';
@@ -38,7 +31,9 @@ export class BufferTransform {
38
31
  }
39
32
 
40
33
  constructor(device: Device, props: BufferTransformProps = Model.defaultProps) {
41
- assert(BufferTransform.isSupported(device), 'BufferTransform not yet implemented on WebGPU');
34
+ if (!BufferTransform.isSupported(device)) {
35
+ throw new Error('BufferTransform not yet implemented on WebGPU');
36
+ }
42
37
 
43
38
  this.device = device;
44
39
 
@@ -51,6 +46,7 @@ export class BufferTransform {
51
46
 
52
47
  this.transformFeedback = this.device.createTransformFeedback({
53
48
  layout: this.model.pipeline.shaderLayout,
49
+ // @ts-expect-error TODO
54
50
  buffers: props.feedbackBuffers
55
51
  });
56
52
 
@@ -93,6 +89,9 @@ export class BufferTransform {
93
89
 
94
90
  readAsync(varyingName: string): Promise<Uint8Array> {
95
91
  const result = this.getBuffer(varyingName);
92
+ if (!result) {
93
+ throw new Error('BufferTransform#getBuffer');
94
+ }
96
95
  if (result instanceof Buffer) {
97
96
  return result.readAsync();
98
97
  }
@@ -111,7 +111,7 @@ export class TextureTransform {
111
111
  return targetTexture;
112
112
  }
113
113
 
114
- getFramebuffer(): Framebuffer {
114
+ getFramebuffer(): Framebuffer | undefined {
115
115
  const currentResources = this.bindings[this.currentIndex];
116
116
  return currentResources.framebuffer;
117
117
  }
@@ -134,6 +134,7 @@ export class TextureTransform {
134
134
  binding = {
135
135
  sourceBuffers: {},
136
136
  sourceTextures: {},
137
+ // @ts-expect-error
137
138
  targetTexture: null
138
139
  };
139
140
  }
@@ -0,0 +1,51 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /**
6
+ * Fast partial deep equal for prop.
7
+ *
8
+ * @param a Prop
9
+ * @param b Prop to compare against `a`
10
+ * @param depth Depth to which to recurse in nested Objects/Arrays. Use 0 (default) for shallow comparison, -1 for infinite depth
11
+ */
12
+ /* eslint-disable complexity */
13
+ export function deepEqual(a: any, b: any, depth: number): boolean {
14
+ if (a === b) {
15
+ return true;
16
+ }
17
+ if (!depth || !a || !b) {
18
+ return false;
19
+ }
20
+ if (Array.isArray(a)) {
21
+ if (!Array.isArray(b) || a.length !== b.length) {
22
+ return false;
23
+ }
24
+ for (let i = 0; i < a.length; i++) {
25
+ if (!deepEqual(a[i], b[i], depth - 1)) {
26
+ return false;
27
+ }
28
+ }
29
+ return true;
30
+ }
31
+ if (Array.isArray(b)) {
32
+ return false;
33
+ }
34
+ if (typeof a === 'object' && typeof b === 'object') {
35
+ const aKeys = Object.keys(a);
36
+ const bKeys = Object.keys(b);
37
+ if (aKeys.length !== bKeys.length) {
38
+ return false;
39
+ }
40
+ for (const key of aKeys) {
41
+ if (!b.hasOwnProperty(key)) {
42
+ return false;
43
+ }
44
+ if (!deepEqual(a[key], b[key], depth - 1)) {
45
+ return false;
46
+ }
47
+ }
48
+ return true;
49
+ }
50
+ return false;
51
+ }