@luma.gl/engine 9.1.0-alpha.2 → 9.1.0-beta.1

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 (196) hide show
  1. package/dist/animation/key-frames.js +1 -0
  2. package/dist/animation/key-frames.js.map +1 -0
  3. package/dist/animation/timeline.js +1 -0
  4. package/dist/animation/timeline.js.map +1 -0
  5. package/dist/animation-loop/animation-loop-template.js +1 -0
  6. package/dist/animation-loop/animation-loop-template.js.map +1 -0
  7. package/dist/animation-loop/animation-loop.d.ts +2 -0
  8. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-loop.js +24 -6
  10. package/dist/animation-loop/animation-loop.js.map +1 -0
  11. package/dist/animation-loop/animation-props.js +1 -0
  12. package/dist/animation-loop/animation-props.js.map +1 -0
  13. package/dist/animation-loop/make-animation-loop.d.ts +5 -1
  14. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  15. package/dist/animation-loop/make-animation-loop.js +3 -1
  16. package/dist/animation-loop/make-animation-loop.js.map +1 -0
  17. package/dist/animation-loop/request-animation-frame.d.ts +4 -2
  18. package/dist/animation-loop/request-animation-frame.d.ts.map +1 -1
  19. package/dist/animation-loop/request-animation-frame.js +5 -3
  20. package/dist/animation-loop/request-animation-frame.js.map +1 -0
  21. package/dist/application-utils/load-file.d.ts +1 -1
  22. package/dist/application-utils/load-file.d.ts.map +1 -1
  23. package/dist/application-utils/load-file.js +2 -2
  24. package/dist/application-utils/load-file.js.map +1 -0
  25. package/dist/application-utils/random.js +1 -0
  26. package/dist/application-utils/random.js.map +1 -0
  27. package/dist/async-texture/async-texture.d.ts +14 -2
  28. package/dist/async-texture/async-texture.d.ts.map +1 -1
  29. package/dist/async-texture/async-texture.js +40 -3
  30. package/dist/async-texture/async-texture.js.map +1 -0
  31. package/dist/compute/buffer-transform.d.ts +41 -0
  32. package/dist/compute/buffer-transform.d.ts.map +1 -0
  33. package/dist/{transform → compute}/buffer-transform.js +19 -12
  34. package/dist/compute/buffer-transform.js.map +1 -0
  35. package/dist/{computation.d.ts → compute/computation.d.ts} +3 -3
  36. package/dist/compute/computation.d.ts.map +1 -0
  37. package/dist/{computation.js → compute/computation.js} +7 -8
  38. package/dist/compute/computation.js.map +1 -0
  39. package/dist/compute/swap.d.ts +48 -0
  40. package/dist/compute/swap.d.ts.map +1 -0
  41. package/dist/compute/swap.js +91 -0
  42. package/dist/compute/swap.js.map +1 -0
  43. package/dist/{transform → compute}/texture-transform.d.ts +0 -6
  44. package/dist/compute/texture-transform.d.ts.map +1 -0
  45. package/dist/{transform → compute}/texture-transform.js +10 -15
  46. package/dist/compute/texture-transform.js.map +1 -0
  47. package/dist/debug/copy-texture-to-image.js +1 -0
  48. package/dist/debug/copy-texture-to-image.js.map +1 -0
  49. package/dist/debug/debug-framebuffer.js +2 -1
  50. package/dist/debug/debug-framebuffer.js.map +1 -0
  51. package/dist/debug/debug-shader-layout.js +2 -1
  52. package/dist/debug/debug-shader-layout.js.map +1 -0
  53. package/dist/debug/pixel-data-utils.js +1 -0
  54. package/dist/debug/pixel-data-utils.js.map +1 -0
  55. package/dist/dist.dev.js +2952 -5816
  56. package/dist/dist.min.js +422 -91
  57. package/dist/{lib → factories}/pipeline-factory.d.ts +11 -1
  58. package/dist/factories/pipeline-factory.d.ts.map +1 -0
  59. package/dist/factories/pipeline-factory.js +181 -0
  60. package/dist/factories/pipeline-factory.js.map +1 -0
  61. package/dist/{lib → factories}/shader-factory.d.ts +5 -1
  62. package/dist/factories/shader-factory.d.ts.map +1 -0
  63. package/dist/{lib → factories}/shader-factory.js +39 -4
  64. package/dist/factories/shader-factory.js.map +1 -0
  65. package/dist/geometries/cone-geometry.js +1 -0
  66. package/dist/geometries/cone-geometry.js.map +1 -0
  67. package/dist/geometries/cube-geometry.js +1 -0
  68. package/dist/geometries/cube-geometry.js.map +1 -0
  69. package/dist/geometries/cylinder-geometry.js +1 -0
  70. package/dist/geometries/cylinder-geometry.js.map +1 -0
  71. package/dist/geometries/ico-sphere-geometry.js +1 -0
  72. package/dist/geometries/ico-sphere-geometry.js.map +1 -0
  73. package/dist/geometries/plane-geometry.js +1 -0
  74. package/dist/geometries/plane-geometry.js.map +1 -0
  75. package/dist/geometries/sphere-geometry.js +1 -0
  76. package/dist/geometries/sphere-geometry.js.map +1 -0
  77. package/dist/geometries/truncated-cone-geometry.js +1 -0
  78. package/dist/geometries/truncated-cone-geometry.js.map +1 -0
  79. package/dist/geometry/geometry-table.js +1 -0
  80. package/dist/geometry/geometry-table.js.map +1 -0
  81. package/dist/geometry/geometry-utils.js +1 -0
  82. package/dist/geometry/geometry-utils.js.map +1 -0
  83. package/dist/geometry/geometry.js +1 -0
  84. package/dist/geometry/geometry.js.map +1 -0
  85. package/dist/geometry/gpu-geometry.js +1 -0
  86. package/dist/geometry/gpu-geometry.js.map +1 -0
  87. package/dist/geometry/gpu-table.js +1 -0
  88. package/dist/geometry/gpu-table.js.map +1 -0
  89. package/dist/index.cjs +1440 -217
  90. package/dist/index.cjs.map +4 -4
  91. package/dist/index.d.ts +23 -12
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +19 -9
  94. package/dist/index.js.map +1 -0
  95. package/dist/model/model.d.ts +11 -10
  96. package/dist/model/model.d.ts.map +1 -1
  97. package/dist/model/model.js +92 -69
  98. package/dist/model/model.js.map +1 -0
  99. package/dist/model/split-uniforms-and-bindings.d.ts +1 -1
  100. package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -1
  101. package/dist/model/split-uniforms-and-bindings.js +2 -1
  102. package/dist/model/split-uniforms-and-bindings.js.map +1 -0
  103. package/dist/models/billboard-texture-model.d.ts +23 -0
  104. package/dist/models/billboard-texture-model.d.ts.map +1 -0
  105. package/dist/models/billboard-texture-model.js +78 -0
  106. package/dist/models/billboard-texture-model.js.map +1 -0
  107. package/dist/models/billboard-texture-module.d.ts +10 -0
  108. package/dist/models/billboard-texture-module.d.ts.map +1 -0
  109. package/dist/models/billboard-texture-module.js +37 -0
  110. package/dist/models/billboard-texture-module.js.map +1 -0
  111. package/dist/{lib → models}/clip-space.d.ts +3 -1
  112. package/dist/models/clip-space.d.ts.map +1 -0
  113. package/dist/models/clip-space.js +77 -0
  114. package/dist/models/clip-space.js.map +1 -0
  115. package/dist/modules/picking/color-picking.d.ts +28 -0
  116. package/dist/modules/picking/color-picking.d.ts.map +1 -0
  117. package/dist/modules/picking/color-picking.js +177 -0
  118. package/dist/modules/picking/color-picking.js.map +1 -0
  119. package/dist/modules/picking/index-picking.d.ts +32 -0
  120. package/dist/modules/picking/index-picking.d.ts.map +1 -0
  121. package/dist/modules/picking/index-picking.js +148 -0
  122. package/dist/modules/picking/index-picking.js.map +1 -0
  123. package/dist/modules/picking/legacy-picking-manager.d.ts +27 -0
  124. package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -0
  125. package/dist/modules/picking/legacy-picking-manager.js +76 -0
  126. package/dist/modules/picking/legacy-picking-manager.js.map +1 -0
  127. package/dist/modules/picking/picking-manager.d.ts +45 -0
  128. package/dist/modules/picking/picking-manager.d.ts.map +1 -0
  129. package/dist/modules/picking/picking-manager.js +101 -0
  130. package/dist/modules/picking/picking-manager.js.map +1 -0
  131. package/dist/modules/picking/picking-uniforms.d.ts +79 -0
  132. package/dist/modules/picking/picking-uniforms.d.ts.map +1 -0
  133. package/dist/modules/picking/picking-uniforms.js +109 -0
  134. package/dist/modules/picking/picking-uniforms.js.map +1 -0
  135. package/dist/passes/get-fragment-shader.d.ts +12 -0
  136. package/dist/passes/get-fragment-shader.d.ts.map +1 -0
  137. package/dist/passes/get-fragment-shader.js +117 -0
  138. package/dist/passes/get-fragment-shader.js.map +1 -0
  139. package/dist/passes/shader-pass-renderer.d.ts +63 -0
  140. package/dist/passes/shader-pass-renderer.d.ts.map +1 -0
  141. package/dist/passes/shader-pass-renderer.js +197 -0
  142. package/dist/passes/shader-pass-renderer.js.map +1 -0
  143. package/dist/scenegraph/group-node.js +1 -0
  144. package/dist/scenegraph/group-node.js.map +1 -0
  145. package/dist/scenegraph/model-node.js +1 -0
  146. package/dist/scenegraph/model-node.js.map +1 -0
  147. package/dist/scenegraph/scenegraph-node.js +1 -0
  148. package/dist/scenegraph/scenegraph-node.js.map +1 -0
  149. package/dist/shader-inputs.d.ts +8 -19
  150. package/dist/shader-inputs.d.ts.map +1 -1
  151. package/dist/shader-inputs.js +28 -18
  152. package/dist/shader-inputs.js.map +1 -0
  153. package/dist/utils/deep-equal.js +1 -0
  154. package/dist/utils/deep-equal.js.map +1 -0
  155. package/dist/utils/uid.js +1 -0
  156. package/dist/utils/uid.js.map +1 -0
  157. package/package.json +6 -6
  158. package/src/animation-loop/animation-loop.ts +27 -6
  159. package/src/animation-loop/make-animation-loop.ts +8 -3
  160. package/src/animation-loop/request-animation-frame.ts +4 -3
  161. package/src/application-utils/load-file.ts +2 -4
  162. package/src/async-texture/async-texture.ts +48 -10
  163. package/src/{transform → compute}/buffer-transform.ts +30 -14
  164. package/src/{computation.ts → compute/computation.ts} +14 -8
  165. package/src/compute/swap.ts +116 -0
  166. package/src/{transform → compute}/texture-transform.ts +9 -18
  167. package/src/debug/debug-framebuffer.ts +1 -1
  168. package/src/debug/debug-shader-layout.ts +1 -1
  169. package/src/factories/pipeline-factory.ts +222 -0
  170. package/src/{lib → factories}/shader-factory.ts +41 -5
  171. package/src/index.ts +35 -16
  172. package/src/model/model.ts +132 -77
  173. package/src/model/split-uniforms-and-bindings.ts +4 -4
  174. package/src/models/billboard-texture-model.ts +98 -0
  175. package/src/models/billboard-texture-module.ts +49 -0
  176. package/src/models/clip-space.ts +88 -0
  177. package/src/modules/picking/README.md +88 -0
  178. package/src/modules/picking/color-picking.ts +190 -0
  179. package/src/modules/picking/index-picking.ts +156 -0
  180. package/src/modules/picking/legacy-picking-manager.ts +99 -0
  181. package/src/modules/picking/picking-manager.ts +137 -0
  182. package/src/modules/picking/picking-uniforms.ts +179 -0
  183. package/src/passes/get-fragment-shader.ts +129 -0
  184. package/src/passes/shader-pass-renderer.ts +252 -0
  185. package/src/shader-inputs.ts +44 -59
  186. package/dist/computation.d.ts.map +0 -1
  187. package/dist/lib/clip-space.d.ts.map +0 -1
  188. package/dist/lib/clip-space.js +0 -46
  189. package/dist/lib/pipeline-factory.d.ts.map +0 -1
  190. package/dist/lib/pipeline-factory.js +0 -98
  191. package/dist/lib/shader-factory.d.ts.map +0 -1
  192. package/dist/transform/buffer-transform.d.ts +0 -35
  193. package/dist/transform/buffer-transform.d.ts.map +0 -1
  194. package/dist/transform/texture-transform.d.ts.map +0 -1
  195. package/src/lib/clip-space.ts +0 -53
  196. package/src/lib/pipeline-factory.ts +0 -126
@@ -4,31 +4,51 @@
4
4
 
5
5
  // A lot of imports, but then Model is where it all comes together...
6
6
  import type {TypedArray} from '@math.gl/types';
7
- import type {RenderPipelineProps, RenderPipelineParameters} from '@luma.gl/core';
8
- import type {BufferLayout, Shader, VertexArray, TransformFeedback} from '@luma.gl/core';
9
- import type {AttributeInfo, Binding, UniformValue, PrimitiveTopology} from '@luma.gl/core';
10
- import {Device, DeviceFeature, Buffer, Texture, TextureView, Sampler} from '@luma.gl/core';
11
- import {RenderPipeline, RenderPass, UniformStore} from '@luma.gl/core';
12
- import {log} from '@luma.gl/core';
13
- import {getTypedArrayFromDataType, getAttributeInfosFromLayouts} from '@luma.gl/core';
7
+ import type {
8
+ RenderPipelineProps,
9
+ RenderPipelineParameters,
10
+ BufferLayout,
11
+ Shader,
12
+ VertexArray,
13
+ TransformFeedback,
14
+ AttributeInfo,
15
+ Binding,
16
+ UniformValue,
17
+ PrimitiveTopology
18
+ } from '@luma.gl/core';
19
+ import {
20
+ Device,
21
+ DeviceFeature,
22
+ Buffer,
23
+ Texture,
24
+ TextureView,
25
+ Sampler,
26
+ RenderPipeline,
27
+ RenderPass,
28
+ UniformStore,
29
+ log,
30
+ getTypedArrayFromDataType,
31
+ getAttributeInfosFromLayouts,
32
+ _BufferLayoutHelper
33
+ } from '@luma.gl/core';
14
34
 
15
35
  import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
16
36
  import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
17
37
 
18
38
  import type {Geometry} from '../geometry/geometry';
19
39
  import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry';
20
- import {PipelineFactory} from '../lib/pipeline-factory';
21
- import {ShaderFactory} from '../lib/shader-factory';
40
+ import {PipelineFactory} from '../factories/pipeline-factory';
41
+ import {ShaderFactory} from '../factories/shader-factory';
22
42
  import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
23
43
  import {debugFramebuffer} from '../debug/debug-framebuffer';
24
44
  import {deepEqual} from '../utils/deep-equal';
25
45
  import {uid} from '../utils/uid';
26
- import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
27
-
28
46
  import {ShaderInputs} from '../shader-inputs';
29
47
  // import type {AsyncTextureProps} from '../async-texture/async-texture';
30
48
  import {AsyncTexture} from '../async-texture/async-texture';
31
49
 
50
+ import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
51
+
32
52
  const LOG_DRAW_PRIORITY = 2;
33
53
  const LOG_DRAW_TIMEOUT = 10000;
34
54
 
@@ -201,6 +221,14 @@ export class Model {
201
221
  /** "Time" of last draw. Monotonically increasing timestamp */
202
222
  _lastDrawTimestamp: number = -1;
203
223
 
224
+ get [Symbol.toStringTag](): string {
225
+ return 'Model';
226
+ }
227
+
228
+ toString(): string {
229
+ return `Model(${this.id})`;
230
+ }
231
+
204
232
  constructor(device: Device, props: ModelProps) {
205
233
  this.props = {...Model.defaultProps, ...props};
206
234
  props = this.props;
@@ -275,7 +303,8 @@ export class Model {
275
303
  this.pipeline = this._updatePipeline();
276
304
 
277
305
  this.vertexArray = device.createVertexArray({
278
- renderPipeline: this.pipeline
306
+ shaderLayout: this.pipeline.shaderLayout,
307
+ bufferLayout: this.pipeline.bufferLayout
279
308
  });
280
309
 
281
310
  // Now we can apply geometry attributes
@@ -307,11 +336,11 @@ export class Model {
307
336
  this.setBindings(props.bindings);
308
337
  }
309
338
  if (props.uniforms) {
310
- this.setUniforms(props.uniforms);
339
+ this.setUniformsWebGL(props.uniforms);
311
340
  }
312
341
  if (props.moduleSettings) {
313
342
  // log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
314
- this.updateModuleSettings(props.moduleSettings);
343
+ this.updateModuleSettingsWebGL(props.moduleSettings);
315
344
  }
316
345
  if (props.transformFeedback) {
317
346
  this.transformFeedback = props.transformFeedback;
@@ -322,16 +351,19 @@ export class Model {
322
351
  }
323
352
 
324
353
  destroy(): void {
325
- if (this._destroyed) return;
326
- this.pipelineFactory.release(this.pipeline);
327
- this.shaderFactory.release(this.pipeline.vs);
328
- if (this.pipeline.fs) {
329
- this.shaderFactory.release(this.pipeline.fs);
330
- }
331
- this._uniformStore.destroy();
332
- // TODO - mark resource as managed and destroyIfManaged() ?
333
- this._gpuGeometry?.destroy();
334
- this._destroyed = true;
354
+ if (!this._destroyed) {
355
+ // Release pipeline before we destroy the shaders used by the pipeline
356
+ this.pipelineFactory.release(this.pipeline);
357
+ // Release the shaders
358
+ this.shaderFactory.release(this.pipeline.vs);
359
+ if (this.pipeline.fs) {
360
+ this.shaderFactory.release(this.pipeline.fs);
361
+ }
362
+ this._uniformStore.destroy();
363
+ // TODO - mark resource as managed and destroyIfManaged() ?
364
+ this._gpuGeometry?.destroy();
365
+ this._destroyed = true;
366
+ }
335
367
  }
336
368
 
337
369
  // Draw call
@@ -352,7 +384,7 @@ export class Model {
352
384
  this._needsRedraw ||= reason;
353
385
  }
354
386
 
355
- predraw() {
387
+ predraw(): void {
356
388
  // Update uniform buffers if needed
357
389
  this.updateShaderInputs();
358
390
  // Check if the pipeline is invalidated
@@ -360,10 +392,22 @@ export class Model {
360
392
  }
361
393
 
362
394
  draw(renderPass: RenderPass): boolean {
363
- this.predraw();
395
+ const loadingBinding = this._areBindingsLoading();
396
+ if (loadingBinding) {
397
+ log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
398
+ return false;
399
+ }
400
+
401
+ try {
402
+ renderPass.pushDebugGroup(`${this}.predraw(${renderPass})`);
403
+ this.predraw();
404
+ } finally {
405
+ renderPass.popDebugGroup();
406
+ }
364
407
 
365
408
  let drawSuccess: boolean;
366
409
  try {
410
+ renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
367
411
  this._logDrawCallStart();
368
412
 
369
413
  // Update the pipeline if invalidated
@@ -374,6 +418,7 @@ export class Model {
374
418
  // Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
375
419
  // Any caching needs to be done inside the pipeline functions
376
420
  // TODO this is a busy initialized check for all bindings every frame
421
+
377
422
  const syncBindings = this._getBindings();
378
423
  this.pipeline.setBindings(syncBindings, {
379
424
  disableWarnings: this.props.disableWarnings
@@ -402,6 +447,7 @@ export class Model {
402
447
  topology: this.topology
403
448
  });
404
449
  } finally {
450
+ renderPass.popDebugGroup();
405
451
  this._logDrawCallEnd();
406
452
  }
407
453
  this._logFramebuffer(renderPass);
@@ -428,7 +474,11 @@ export class Model {
428
474
  const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
429
475
  if (gpuGeometry) {
430
476
  this.setTopology(gpuGeometry.topology || 'triangle-list');
431
- this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout);
477
+ const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
478
+ this.bufferLayout = bufferLayoutHelper.mergeBufferLayouts(
479
+ gpuGeometry.bufferLayout,
480
+ this.bufferLayout
481
+ );
432
482
  if (this.vertexArray) {
433
483
  this._setGeometryAttributes(gpuGeometry);
434
484
  }
@@ -452,8 +502,9 @@ export class Model {
452
502
  * @note Triggers a pipeline rebuild / pipeline cache fetch
453
503
  */
454
504
  setBufferLayout(bufferLayout: BufferLayout[]): void {
505
+ const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
455
506
  this.bufferLayout = this._gpuGeometry
456
- ? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
507
+ ? bufferLayoutHelper.mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
457
508
  : bufferLayout;
458
509
  this._setPipelineNeedsUpdate('bufferLayout');
459
510
 
@@ -463,7 +514,8 @@ export class Model {
463
514
  // vertex array needs to be updated if we update buffer layout,
464
515
  // but not if we update parameters
465
516
  this.vertexArray = this.device.createVertexArray({
466
- renderPipeline: this.pipeline
517
+ shaderLayout: this.pipeline.shaderLayout,
518
+ bufferLayout: this.pipeline.bufferLayout
467
519
  });
468
520
 
469
521
  // Reapply geometry attributes to the new vertex array
@@ -513,10 +565,12 @@ export class Model {
513
565
  setShaderInputs(shaderInputs: ShaderInputs): void {
514
566
  this.shaderInputs = shaderInputs;
515
567
  this._uniformStore = new UniformStore(this.shaderInputs.modules);
516
- // Create uniform buffer bindings for all modules
517
- for (const moduleName of Object.keys(this.shaderInputs.modules)) {
518
- const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
519
- this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
568
+ // Create uniform buffer bindings for all modules that actually have uniforms
569
+ for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
570
+ if (shaderModuleHasUniforms(module)) {
571
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
572
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
573
+ }
520
574
  }
521
575
  this.setNeedsRedraw('shaderInputs');
522
576
  }
@@ -524,6 +578,7 @@ export class Model {
524
578
  /** Update uniform buffers from the model's shader inputs */
525
579
  updateShaderInputs(): void {
526
580
  this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
581
+ this.setBindings(this.shaderInputs.getBindingValues());
527
582
  // TODO - this is already tracked through buffer/texture update times?
528
583
  this.setNeedsRedraw('shaderInputs');
529
584
  }
@@ -558,22 +613,27 @@ export class Model {
558
613
  * @note Overrides any attributes previously set with the same name
559
614
  */
560
615
  setAttributes(buffers: Record<string, Buffer>, options?: {disableWarnings?: boolean}): void {
616
+ const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
561
617
  if (buffers.indices) {
562
618
  log.warn(
563
619
  `Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
564
620
  )();
565
621
  }
622
+
623
+ const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
624
+
625
+ // Check if all buffers have a layout
566
626
  for (const [bufferName, buffer] of Object.entries(buffers)) {
567
- const bufferLayout = this.bufferLayout.find(layout =>
568
- getAttributeNames(layout).includes(bufferName)
569
- );
627
+ const bufferLayout = bufferLayoutHelper.getBufferLayout(bufferName);
570
628
  if (!bufferLayout) {
571
- log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
629
+ if (!disableWarnings) {
630
+ log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
631
+ }
572
632
  continue; // eslint-disable-line no-continue
573
633
  }
574
634
 
575
635
  // For an interleaved attribute we may need to set multiple attributes
576
- const attributeNames = getAttributeNames(bufferLayout);
636
+ const attributeNames = bufferLayoutHelper.getAttributeNamesForBuffer(bufferLayout);
577
637
  let set = false;
578
638
  for (const attributeName of attributeNames) {
579
639
  const attributeInfo = this._attributeInfos[attributeName];
@@ -582,7 +642,7 @@ export class Model {
582
642
  set = true;
583
643
  }
584
644
  }
585
- if (!set && !(options?.disableWarnings ?? this.props.disableWarnings)) {
645
+ if (!set && !disableWarnings) {
586
646
  log.warn(
587
647
  `Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`
588
648
  )();
@@ -623,7 +683,7 @@ export class Model {
623
683
  * @deprecated WebGL only, use uniform buffers for portability
624
684
  * @param uniforms
625
685
  */
626
- setUniforms(uniforms: Record<string, UniformValue>): void {
686
+ setUniformsWebGL(uniforms: Record<string, UniformValue>): void {
627
687
  if (!isObjectEmpty(uniforms)) {
628
688
  this.pipeline.setUniformsWebGL(uniforms);
629
689
  Object.assign(this.uniforms, uniforms);
@@ -634,7 +694,7 @@ export class Model {
634
694
  /**
635
695
  * @deprecated Updates shader module settings (which results in uniforms being set)
636
696
  */
637
- updateModuleSettings(props: Record<string, any>): void {
697
+ updateModuleSettingsWebGL(props: Record<string, any>): void {
638
698
  // log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
639
699
  const {bindings, uniforms} = splitUniformsAndBindings(this._getModuleUniforms(props));
640
700
  Object.assign(this.bindings, bindings);
@@ -644,19 +704,32 @@ export class Model {
644
704
 
645
705
  // Internal methods
646
706
 
647
- /** Get texture / texture view from any async textures */
707
+ /** Check that bindings are loaded. Returns id of first binding that is still loading. */
708
+ _areBindingsLoading(): string | false {
709
+ for (const binding of Object.values(this.bindings)) {
710
+ if (binding instanceof AsyncTexture && !binding.isReady) {
711
+ return binding.id;
712
+ }
713
+ }
714
+ return false;
715
+ }
716
+
717
+ /** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
648
718
  _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]) => {
719
+ const validBindings: Record<string, Binding> = {};
720
+
721
+ for (const [name, binding] of Object.entries(this.bindings)) {
651
722
  if (binding instanceof AsyncTexture) {
723
+ // Check that async textures are loaded
652
724
  if (binding.isReady) {
653
- acc[name] = binding.texture;
725
+ validBindings[name] = binding.texture;
654
726
  }
655
727
  } else {
656
- acc[name] = binding;
728
+ validBindings[name] = binding;
657
729
  }
658
- return acc;
659
- }, {});
730
+ }
731
+
732
+ return validBindings;
660
733
  }
661
734
 
662
735
  /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
@@ -731,7 +804,7 @@ export class Model {
731
804
  id: `${this.id}-vertex`,
732
805
  stage: 'vertex',
733
806
  source: this.source || this.vs,
734
- debug: this.props.debugShaders
807
+ debugShaders: this.props.debugShaders
735
808
  });
736
809
 
737
810
  let fs: Shader | null = null;
@@ -742,7 +815,7 @@ export class Model {
742
815
  id: `${this.id}-fragment`,
743
816
  stage: 'fragment',
744
817
  source: this.source || this.fs,
745
- debug: this.props.debugShaders
818
+ debugShaders: this.props.debugShaders
746
819
  });
747
820
  }
748
821
 
@@ -812,10 +885,11 @@ export class Model {
812
885
 
813
886
  protected _drawCount = 0;
814
887
  _logFramebuffer(renderPass: RenderPass): void {
815
- const debugFramebuffers = log.get('framebuffer');
888
+ const debugFramebuffers = this.device.props.debugFramebuffers;
816
889
  this._drawCount++;
817
890
  // Update first 3 frames and then every 60 frames
818
- if (!debugFramebuffers || (this._drawCount++ > 3 && this._drawCount % 60)) {
891
+ if (!debugFramebuffers) {
892
+ // } || (this._drawCount++ > 3 && this._drawCount % 60)) {
819
893
  return;
820
894
  }
821
895
  // TODO - display framebuffer output in debug window
@@ -862,22 +936,12 @@ export class Model {
862
936
  }
863
937
  }
864
938
 
865
- // HELPERS
866
-
867
- /** TODO - move to core, document add tests */
868
- function mergeBufferLayouts(layouts1: BufferLayout[], layouts2: BufferLayout[]): BufferLayout[] {
869
- const layouts = [...layouts1];
870
- for (const attribute of layouts2) {
871
- const index = layouts.findIndex(attribute2 => attribute2.name === attribute.name);
872
- if (index < 0) {
873
- layouts.push(attribute);
874
- } else {
875
- layouts[index] = attribute;
876
- }
877
- }
878
- return layouts;
939
+ function shaderModuleHasUniforms(module: ShaderModule): boolean {
940
+ return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
879
941
  }
880
942
 
943
+ // HELPERS
944
+
881
945
  /** Create a shadertools platform info from the Device */
882
946
  export function getPlatformInfo(device: Device): PlatformInfo {
883
947
  return {
@@ -890,21 +954,12 @@ export function getPlatformInfo(device: Device): PlatformInfo {
890
954
  };
891
955
  }
892
956
 
893
- /** Get attribute names from a BufferLayout */
894
- function getAttributeNames(bufferLayout: BufferLayout): string[] {
895
- return bufferLayout.attributes
896
- ? bufferLayout.attributes?.map(layout => layout.attribute)
897
- : [bufferLayout.name];
898
- }
899
-
900
957
  /** Returns true if given object is empty, false otherwise. */
901
958
  function isObjectEmpty(obj: object): boolean {
902
- let isEmpty = true;
903
959
  // @ts-ignore key is unused
904
960
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
905
961
  for (const key in obj) {
906
- isEmpty = false;
907
- break;
962
+ return false;
908
963
  }
909
- return isEmpty;
964
+ return true;
910
965
  }
@@ -5,8 +5,8 @@
5
5
  import type {UniformValue, Binding} from '@luma.gl/core';
6
6
  import {isNumericArray} from '@math.gl/types';
7
7
 
8
- export function isUniformValue(value: unknown): boolean {
9
- return isNumericArray(value) !== null || typeof value === 'number' || typeof value === 'boolean';
8
+ export function isUniformValue(value: unknown): value is UniformValue {
9
+ return isNumericArray(value) || typeof value === 'number' || typeof value === 'boolean';
10
10
  }
11
11
 
12
12
  type UniformsAndBindings = {
@@ -21,9 +21,9 @@ export function splitUniformsAndBindings(
21
21
  Object.keys(uniforms).forEach(name => {
22
22
  const uniform = uniforms[name];
23
23
  if (isUniformValue(uniform)) {
24
- result.uniforms[name] = uniform as UniformValue;
24
+ result.uniforms[name] = uniform;
25
25
  } else {
26
- result.bindings[name] = uniform as Binding;
26
+ result.bindings[name] = uniform;
27
27
  }
28
28
  });
29
29
 
@@ -0,0 +1,98 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Device, Texture} from '@luma.gl/core';
6
+ import {AsyncTexture} from '../async-texture/async-texture';
7
+ import {ClipSpace} from './clip-space';
8
+
9
+ const BACKGROUND_FS_WGSL = /* wgsl */ `\
10
+ @group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
11
+ @group(0) @binding(1) var backgroundTextureSampler: sampler;
12
+
13
+ fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
14
+ let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0) * 2;
15
+ let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
16
+ var position: vec2<f32> = coordinates.xy / texSize;
17
+ return position;
18
+ }
19
+
20
+ @fragment
21
+ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
22
+ let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
23
+ return textureSample(backgroundTexture, backgroundTextureSampler, position);
24
+ }
25
+ `;
26
+
27
+ const BACKGROUND_FS = /* glsl */ `\
28
+ #version 300 es
29
+ precision highp float;
30
+
31
+ uniform sampler2D backgroundTexture;
32
+ out vec4 fragColor;
33
+
34
+ vec2 billboardTexture_getTextureUV() {
35
+ ivec2 iTexSize = textureDimensions(backgroundTexture, 0) * 2;
36
+ vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
37
+ vec2 position = gl_FragCoord.xy / texSize;
38
+ return position;
39
+ }
40
+
41
+ void main(void) {
42
+ vec2 position = billboardTexture_getTextureUV();
43
+ fragColor = texture(backgroundTexture, position);
44
+ }
45
+ `;
46
+
47
+ /**
48
+ * Props for a Model that renders a bitmap into the "background", i.e covering the screen
49
+ */
50
+ export type BackgroundTextureModelProps = {
51
+ /** id of this model */
52
+ id?: string;
53
+ /** The texture to render */
54
+ backgroundTexture: Texture | AsyncTexture;
55
+ /** If true, the texture is rendered into transparent areas of the screen only, i.e blended in where background alpha is small */
56
+ blend?: boolean;
57
+ };
58
+
59
+ /**
60
+ * Model that renders a bitmap into the "background", i.e covering the screen
61
+ */
62
+ export class BackgroundTextureModel extends ClipSpace {
63
+ constructor(device: Device, props: BackgroundTextureModelProps) {
64
+ super(device, {
65
+ id: props.id || 'background-texture-model',
66
+ source: BACKGROUND_FS_WGSL,
67
+ fs: BACKGROUND_FS,
68
+ parameters: {
69
+ depthWriteEnabled: false,
70
+ depthCompare: 'always',
71
+ ...(props.blend
72
+ ? {
73
+ blend: true,
74
+ blendColorOperation: 'add',
75
+ blendAlphaOperation: 'add',
76
+ blendColorSrcFactor: 'one',
77
+ blendColorDstFactor: 'one-minus-src-color',
78
+ blendAlphaSrcFactor: 'one',
79
+ blendAlphaDstFactor: 'one-minus-src-alpha'
80
+ }
81
+ : {})
82
+ }
83
+ });
84
+
85
+ this.setTexture(props.backgroundTexture);
86
+ }
87
+
88
+ setTexture(backgroundTexture: Texture | AsyncTexture): void {
89
+ this.setBindings({
90
+ backgroundTexture
91
+ });
92
+ }
93
+
94
+ override predraw(): void {
95
+ this.shaderInputs.setProps({});
96
+ super.predraw();
97
+ }
98
+ }
@@ -0,0 +1,49 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {ShaderModule} from '@luma.gl/shadertools';
6
+
7
+ const BACKGROUND_FS = /* glsl */ `\
8
+ #version 300 es
9
+
10
+ uniform billboardTextureUniforms {
11
+ vec2 topLeft;
12
+ vec2 bottomRight;
13
+ } billboardTexture;
14
+
15
+ precision highp float;
16
+ uniform sampler2D backgroundTexture;
17
+ out vec4 fragColor;
18
+
19
+ vec2 billboardTexture_getTextureUV() {
20
+ ivec2 iTexSize = textureSize(backgroundTexture, 0) * 2;
21
+ vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
22
+ vec2 position = gl_FragCoord.xy / texSize;
23
+ return position;
24
+ }
25
+
26
+ void main(void) {
27
+ vec2 position = billboardTexture_getTextureUV();
28
+ fragColor = texture(backgroundTexture, position);
29
+ }
30
+ `;
31
+
32
+ type BillboardTextureProps = {
33
+ aspect: number;
34
+ };
35
+
36
+ type BillboardTextureUniforms = {
37
+ topLeft: [number, number];
38
+ bottomRight: [number, number];
39
+ };
40
+
41
+ export const billboardTexture = {
42
+ name: 'billboardTexture',
43
+ fs: BACKGROUND_FS,
44
+ dependencies: [],
45
+ uniformTypes: {
46
+ topLeft: 'vec2<f32>',
47
+ bottomRight: 'vec2<f32>'
48
+ }
49
+ } as const satisfies ShaderModule<BillboardTextureProps, BillboardTextureUniforms>;
@@ -0,0 +1,88 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // ClipSpace
6
+ import {Device} from '@luma.gl/core';
7
+ import {Model, ModelProps} from '../model/model';
8
+ import {Geometry} from '../geometry/geometry';
9
+ import {uid} from '../utils/uid';
10
+
11
+ const CLIPSPACE_VERTEX_SHADER_WGSL = /* wgsl */ `\
12
+ struct VertexInputs {
13
+ @location(0) clipSpacePosition: vec2<f32>,
14
+ @location(1) texCoord: vec2<f32>,
15
+ @location(2) coordinate: vec2<f32>
16
+ }
17
+
18
+ struct FragmentInputs {
19
+ @builtin(position) Position : vec4<f32>,
20
+ @location(0) position : vec2<f32>,
21
+ @location(1) coordinate : vec2<f32>,
22
+ @location(2) uv : vec2<f32>
23
+ };
24
+
25
+ @vertex
26
+ fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
27
+ var outputs: FragmentInputs;
28
+ outputs.Position = vec4(inputs.clipSpacePosition, 0., 1.);
29
+ outputs.position = inputs.clipSpacePosition;
30
+ outputs.coordinate = inputs.coordinate;
31
+ outputs.uv = inputs.texCoord;
32
+ return outputs;
33
+ }
34
+ `;
35
+
36
+ const CLIPSPACE_VERTEX_SHADER = /* glsl */ `\
37
+ #version 300 es
38
+ in vec2 clipSpacePosition;
39
+ in vec2 texCoord;
40
+ in vec2 coordinate;
41
+
42
+ out vec2 position;
43
+ out vec2 coordinate;
44
+ out vec2 uv;
45
+
46
+ void main(void) {
47
+ gl_Position = vec4(clipSpacePosition, 0., 1.);
48
+ position = clipSpacePosition;
49
+ coordinate = coordinate;
50
+ uv = texCoord;
51
+ }
52
+ `;
53
+
54
+ /* eslint-disable indent, no-multi-spaces */
55
+ const POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
56
+
57
+ /** Props for ClipSpace */
58
+ export type ClipSpaceProps = Omit<ModelProps, 'vs' | 'vertexCount' | 'geometry'>;
59
+
60
+ /**
61
+ * A flat geometry that covers the "visible area" that the GPU renders.
62
+ */
63
+ export class ClipSpace extends Model {
64
+ constructor(device: Device, props: ClipSpaceProps) {
65
+ const TEX_COORDS = POSITIONS.map(coord => (coord === -1 ? 0 : coord));
66
+
67
+ // For WGSL we need to append the supplied fragment shader to the default vertex shader source
68
+ if (props.source) {
69
+ props = {...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\n${props.source}`};
70
+ }
71
+
72
+ super(device, {
73
+ id: props.id || uid('clip-space'),
74
+ ...props,
75
+ vs: CLIPSPACE_VERTEX_SHADER,
76
+ vertexCount: 4,
77
+ geometry: new Geometry({
78
+ topology: 'triangle-strip',
79
+ vertexCount: 4,
80
+ attributes: {
81
+ clipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
82
+ texCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
83
+ coordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
84
+ }
85
+ })
86
+ });
87
+ }
88
+ }