@luma.gl/engine 9.0.0-alpha.25 → 9.0.0-alpha.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dist.dev.js CHANGED
@@ -1369,9 +1369,9 @@ var __exports__ = (() => {
1369
1369
  };
1370
1370
  if ((props.usage || 0) & Buffer2.INDEX && !props.indexType) {
1371
1371
  if (props.data instanceof Uint32Array) {
1372
- props.indexType = "uint32";
1372
+ newProps.indexType = "uint32";
1373
1373
  } else if (props.data instanceof Uint16Array) {
1374
- props.indexType = "uint16";
1374
+ newProps.indexType = "uint16";
1375
1375
  }
1376
1376
  }
1377
1377
  return newProps;
@@ -1581,7 +1581,7 @@ var __exports__ = (() => {
1581
1581
  * Use devicePixelRatio to set canvas width and height
1582
1582
  * @note this is a raw port of luma.gl v8 code. Might be worth a review
1583
1583
  */
1584
- setDevicePixelRatio(devicePixelRatio2, options = {}) {
1584
+ setDevicePixelRatio(devicePixelRatio, options = {}) {
1585
1585
  if (!this.htmlCanvas) {
1586
1586
  return;
1587
1587
  }
@@ -1589,13 +1589,13 @@ var __exports__ = (() => {
1589
1589
  let clientHeight = "height" in options ? options.height : this.htmlCanvas.clientHeight;
1590
1590
  if (!clientWidth || !clientHeight) {
1591
1591
  log.log(1, "Canvas clientWidth/clientHeight is 0")();
1592
- devicePixelRatio2 = 1;
1592
+ devicePixelRatio = 1;
1593
1593
  clientWidth = this.htmlCanvas.width || 1;
1594
1594
  clientHeight = this.htmlCanvas.height || 1;
1595
1595
  }
1596
1596
  const cachedSize = this._canvasSizeInfo;
1597
- if (cachedSize.clientWidth !== clientWidth || cachedSize.clientHeight !== clientHeight || cachedSize.devicePixelRatio !== devicePixelRatio2) {
1598
- let clampedPixelRatio = devicePixelRatio2;
1597
+ if (cachedSize.clientWidth !== clientWidth || cachedSize.clientHeight !== clientHeight || cachedSize.devicePixelRatio !== devicePixelRatio) {
1598
+ let clampedPixelRatio = devicePixelRatio;
1599
1599
  const canvasWidth = Math.floor(clientWidth * clampedPixelRatio);
1600
1600
  const canvasHeight = Math.floor(clientHeight * clampedPixelRatio);
1601
1601
  this.htmlCanvas.width = canvasWidth;
@@ -1609,7 +1609,7 @@ var __exports__ = (() => {
1609
1609
  }
1610
1610
  this._canvasSizeInfo.clientWidth = clientWidth;
1611
1611
  this._canvasSizeInfo.clientHeight = clientHeight;
1612
- this._canvasSizeInfo.devicePixelRatio = devicePixelRatio2;
1612
+ this._canvasSizeInfo.devicePixelRatio = devicePixelRatio;
1613
1613
  }
1614
1614
  }
1615
1615
  // PRIVATE
@@ -2028,6 +2028,7 @@ var __exports__ = (() => {
2028
2028
  };
2029
2029
  /** Set attributes (stored on pipeline and set before each call) */
2030
2030
  /** Set attributes (stored on pipeline and set before each call) */
2031
+ /** Set constant attributes (WebGL only) */
2031
2032
  /** Set bindings (stored on pipeline and set before each call) */
2032
2033
  /** Uniforms (only supported on WebGL devices. Reset before each call to enable pipeline sharing) */
2033
2034
  /** Draw call */
@@ -2042,7 +2043,11 @@ var __exports__ = (() => {
2042
2043
  constructor(device, props) {
2043
2044
  super(device, props, _RenderPass.defaultProps);
2044
2045
  }
2045
- /** A small set of parameters can be changed between every draw call (viewport, scissorRect, blendColor, stencilReference) */
2046
+ /** Call when rendering is done in this pass. */
2047
+ /**
2048
+ * A small set of parameters can be changed between every draw call
2049
+ * (viewport, scissorRect, blendColor, stencilReference)
2050
+ */
2046
2051
  // writeTimestamp(querySet: GPUQuerySet, queryIndex: number): void;
2047
2052
  // beginOcclusionQuery(queryIndex: number): void;
2048
2053
  // endOcclusionQuery(): void;
@@ -2429,6 +2434,43 @@ var __exports__ = (() => {
2429
2434
  });
2430
2435
  }
2431
2436
 
2437
+ // ../api/src/lib/utils/array-utils-flat.ts
2438
+ var arrayBuffer;
2439
+ function getScratchArrayBuffer(byteLength) {
2440
+ if (!arrayBuffer || arrayBuffer.byteLength < byteLength) {
2441
+ arrayBuffer = new ArrayBuffer(byteLength);
2442
+ }
2443
+ return arrayBuffer;
2444
+ }
2445
+ function getScratchArray(Type, length) {
2446
+ const scratchArrayBuffer = getScratchArrayBuffer(Type.BYTES_PER_ELEMENT * length);
2447
+ return new Type(scratchArrayBuffer, 0, length);
2448
+ }
2449
+ function fillArray(options) {
2450
+ const {
2451
+ target,
2452
+ source,
2453
+ start = 0,
2454
+ count = 1
2455
+ } = options;
2456
+ const length = source.length;
2457
+ const total = count * length;
2458
+ let copied = 0;
2459
+ for (let i = start; copied < length; copied++) {
2460
+ target[i++] = source[copied];
2461
+ }
2462
+ while (copied < total) {
2463
+ if (copied < total - copied) {
2464
+ target.copyWithin(start + copied, start, start + copied);
2465
+ copied *= 2;
2466
+ } else {
2467
+ target.copyWithin(start + copied, start, start + total - copied);
2468
+ copied = total;
2469
+ }
2470
+ }
2471
+ return options.target;
2472
+ }
2473
+
2432
2474
  // ../api/src/lib/request-animation-frame.ts
2433
2475
  function requestAnimationFrame(callback) {
2434
2476
  return typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame(callback) : setTimeout(callback, 1e3 / 60);
@@ -5830,6 +5872,7 @@ void main() {
5830
5872
  };
5831
5873
  var Model = class {
5832
5874
  fs = null;
5875
+ userData = {};
5833
5876
  constructor(device, props) {
5834
5877
  this.props = {
5835
5878
  ...DEFAULT_MODEL_PROPS,
@@ -5838,6 +5881,7 @@ void main() {
5838
5881
  props = this.props;
5839
5882
  this.id = this.props.id;
5840
5883
  this.device = device;
5884
+ Object.assign(this.userData, this.props.userData);
5841
5885
  if (!props.vs) {
5842
5886
  throw new Error("no vertex shader");
5843
5887
  }
@@ -5910,10 +5954,49 @@ void main() {
5910
5954
  this.pipeline.setIndexBuffer(indices);
5911
5955
  return this;
5912
5956
  }
5913
- setAttributes(attributes) {
5914
- this.pipeline.setAttributes(attributes);
5915
- Object.assign(this.props.attributes, attributes);
5916
- return this;
5957
+ // Temporary hack to support deck.gl's dependency on luma.gl v8 Model attribute API.
5958
+ _splitAttributes(attributes, filterBuffers) {
5959
+ const bufferAttributes = {};
5960
+ const constantAttributes = {};
5961
+ const indices = attributes.indices;
5962
+ delete attributes.indices;
5963
+ for (const name in attributes) {
5964
+ let attribute = attributes[name];
5965
+ if (attribute instanceof Buffer2) {
5966
+ bufferAttributes[name] = attribute;
5967
+ continue;
5968
+ }
5969
+ if (attribute.getValue) {
5970
+ attribute = attribute.getValue();
5971
+ console.warn(`attribute ${name}: getValue() will be removed`);
5972
+ }
5973
+ if (ArrayBuffer.isView(attribute) && !attribute) {
5974
+ constantAttributes[name] = attribute;
5975
+ continue;
5976
+ }
5977
+ if (filterBuffers && attribute[name]._buffer) {
5978
+ buffer[name] = attribute[name]._buffer;
5979
+ }
5980
+ }
5981
+ return {
5982
+ bufferAttributes,
5983
+ constantAttributes,
5984
+ indices
5985
+ };
5986
+ }
5987
+ setAttributes(attributes, filterBuffers) {
5988
+ const {
5989
+ bufferAttributes,
5990
+ constantAttributes,
5991
+ indices
5992
+ } = this._splitAttributes(attributes, filterBuffers);
5993
+ if (indices) {
5994
+ this.setIndexBuffer(indices);
5995
+ console.warn("luma.gl: indices should not be part of attributes");
5996
+ }
5997
+ this.pipeline.setAttributes(bufferAttributes);
5998
+ this.pipeline.setConstantAttributes(constantAttributes);
5999
+ Object.assign(this.props.attributes, bufferAttributes, constantAttributes);
5917
6000
  }
5918
6001
  /** Set the bindings */
5919
6002
  setBindings(bindings) {
@@ -6756,13 +6839,13 @@ void main() {
6756
6839
  attrib.enabled = false;
6757
6840
  return original.disableVertexAttribArray.apply(this, arguments);
6758
6841
  };
6759
- gl.bindBuffer = function bindBuffer2(target, buffer) {
6842
+ gl.bindBuffer = function bindBuffer2(target, buffer2) {
6760
6843
  switch (target) {
6761
6844
  case gl.ARRAY_BUFFER:
6762
- self.currentArrayBuffer = buffer;
6845
+ self.currentArrayBuffer = buffer2;
6763
6846
  break;
6764
6847
  case gl.ELEMENT_ARRAY_BUFFER:
6765
- self.currentVertexArrayObject.elementArrayBuffer = buffer;
6848
+ self.currentVertexArrayObject.elementArrayBuffer = buffer2;
6766
6849
  break;
6767
6850
  default:
6768
6851
  }
@@ -7601,7 +7684,7 @@ void main() {
7601
7684
  return null;
7602
7685
  }
7603
7686
  },
7604
- bindBuffer: (update, target, buffer) => {
7687
+ bindBuffer: (update, target, buffer2) => {
7605
7688
  const pname = {
7606
7689
  [GL.ARRAY_BUFFER]: [GL.ARRAY_BUFFER_BINDING],
7607
7690
  [GL.COPY_READ_BUFFER]: [GL.COPY_READ_BUFFER_BINDING],
@@ -7611,7 +7694,7 @@ void main() {
7611
7694
  }[target];
7612
7695
  if (pname) {
7613
7696
  return update({
7614
- [pname]: buffer
7697
+ [pname]: buffer2
7615
7698
  });
7616
7699
  }
7617
7700
  return {
@@ -10981,6 +11064,7 @@ void main(void) {}`;
10981
11064
  */
10982
11065
  resize(options) {
10983
11066
  if (this.canvas) {
11067
+ const devicePixelRatio = this.getDevicePixelRatio(options?.useDevicePixels);
10984
11068
  this.setDevicePixelRatio(devicePixelRatio, options);
10985
11069
  return;
10986
11070
  }
@@ -12376,8 +12460,25 @@ ${formattedLog}`)();
12376
12460
  get [Symbol.toStringTag]() {
12377
12461
  return "BaseVertexArrayObject";
12378
12462
  }
12463
+ /** Buffer constant */
12464
+ buffer = null;
12465
+ bufferValue = null;
12466
+ static isConstantAttributeZeroSupported(device) {
12467
+ return device.info.type === "webgl2" || getBrowser() === "Chrome";
12468
+ }
12469
+ // Create a VertexArray
12379
12470
  constructor(device, props) {
12380
- super(device, props, {});
12471
+ super(device, props, {
12472
+ ...Resource.defaultProps,
12473
+ constantAttributeZero: false
12474
+ });
12475
+ Object.seal(this);
12476
+ }
12477
+ destroy() {
12478
+ super.destroy();
12479
+ if (this.buffer) {
12480
+ this.buffer?.destroy();
12481
+ }
12381
12482
  }
12382
12483
  _createHandle() {
12383
12484
  return this.gl2.createVertexArray();
@@ -12389,6 +12490,20 @@ ${formattedLog}`)();
12389
12490
  _bindHandle(handle) {
12390
12491
  this.gl2.bindVertexArray(handle);
12391
12492
  }
12493
+ /**
12494
+ * Enabling an attribute location makes it reference the currently bound buffer
12495
+ * Disabling an attribute location makes it reference the global constant value
12496
+ * TODO - handle single values for size 1 attributes?
12497
+ * TODO - convert classic arrays based on known type?
12498
+ */
12499
+ enable(location, enable2 = true) {
12500
+ const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === "Chrome";
12501
+ const canDisableAttribute = canDisableAttributeZero || location !== 0;
12502
+ if (enable2 || canDisableAttribute) {
12503
+ location = Number(location);
12504
+ this.bind(() => enable2 ? this.gl.enableVertexAttribArray(location) : this.gl.disableVertexAttribArray(location));
12505
+ }
12506
+ }
12392
12507
  // Set (bind) an elements buffer, for indexed rendering.
12393
12508
  // Must be a Buffer bound to GL.ELEMENT_ARRAY_BUFFER. Constants not supported
12394
12509
  setElementBuffer(elementBuffer = null, opts = {}) {
@@ -12396,12 +12511,12 @@ ${formattedLog}`)();
12396
12511
  this.bind(() => {
12397
12512
  this.gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, elementBuffer ? elementBuffer.handle : null);
12398
12513
  });
12399
- return this;
12400
12514
  }
12401
12515
  /** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
12402
- setBuffer(location, buffer, accessor) {
12403
- if (buffer.target === GL.ELEMENT_ARRAY_BUFFER) {
12404
- return this.setElementBuffer(buffer, accessor);
12516
+ setBuffer(location, buffer2, accessor) {
12517
+ if (buffer2.target === GL.ELEMENT_ARRAY_BUFFER) {
12518
+ this.setElementBuffer(buffer2, accessor);
12519
+ return;
12405
12520
  }
12406
12521
  const {
12407
12522
  size,
@@ -12418,7 +12533,7 @@ ${formattedLog}`)();
12418
12533
  } = this;
12419
12534
  location = Number(location);
12420
12535
  this.bind(() => {
12421
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer.handle);
12536
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer2.handle);
12422
12537
  if (integer) {
12423
12538
  this.device.assertWebGL2();
12424
12539
  gl2.vertexAttribIPointer(location, size, type, stride, offset);
@@ -12428,24 +12543,106 @@ ${formattedLog}`)();
12428
12543
  gl.enableVertexAttribArray(location);
12429
12544
  gl2.vertexAttribDivisor(location, divisor || 0);
12430
12545
  });
12431
- return this;
12432
12546
  }
12433
12547
  /**
12434
- * Enabling an attribute location makes it reference the currently bound buffer
12435
- * Disabling an attribute location makes it reference the global constant value
12436
- * TODO - handle single values for size 1 attributes?
12437
- * TODO - convert classic arrays based on known type?
12548
+ * Set an attribute to a constant value
12549
+ * @param device
12550
+ * @param location
12551
+ * @param array
12552
+ *
12553
+ * @note Constants are stored globally on the WebGL context, not the VAO
12554
+ * so they need to be updated before every render
12555
+ * @todo - use known type (in configuration or passed in) to allow non-typed arrays?
12556
+ * @todo - remember/cache values to avoid setting them unnecessarily?
12438
12557
  */
12439
- enable(location, enable2 = true) {
12440
- const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === "Chrome";
12441
- const canDisableAttribute = canDisableAttributeZero || location !== 0;
12442
- if (enable2 || canDisableAttribute) {
12443
- location = Number(location);
12444
- this.bind(() => enable2 ? this.gl.enableVertexAttribArray(location) : this.gl.disableVertexAttribArray(location));
12558
+ setConstant(location, array) {
12559
+ switch (array.constructor) {
12560
+ case Float32Array:
12561
+ setConstantFloatArray(this.device, location, array);
12562
+ break;
12563
+ case Int32Array:
12564
+ setConstantIntArray(this.device, location, array);
12565
+ break;
12566
+ case Uint32Array:
12567
+ setConstantUintArray(this.device, location, array);
12568
+ break;
12569
+ default:
12570
+ assert2(false);
12445
12571
  }
12446
- return this;
12572
+ }
12573
+ /**
12574
+ * Provide a means to create a buffer that is equivalent to a constant.
12575
+ * NOTE: Desktop OpenGL cannot disable attribute 0.
12576
+ * https://stackoverflow.com/questions/20305231/webgl-warning-attribute-0-is-disabled-
12577
+ * this-has-significant-performance-penalty
12578
+ */
12579
+ getConstantBuffer(elementCount, value) {
12580
+ const constantValue = normalizeConstantArrayValue(value);
12581
+ const byteLength = constantValue.byteLength * elementCount;
12582
+ const length = constantValue.length * elementCount;
12583
+ let updateNeeded = !this.buffer;
12584
+ this.buffer = this.buffer || this.device.createBuffer({
12585
+ byteLength
12586
+ });
12587
+ updateNeeded = updateNeeded || this.buffer.reallocate(byteLength);
12588
+ updateNeeded = updateNeeded || !compareConstantArrayValues(constantValue, this.bufferValue);
12589
+ if (updateNeeded) {
12590
+ const typedArray = getScratchArray(value.constructor, length);
12591
+ fillArray({
12592
+ target: typedArray,
12593
+ source: constantValue,
12594
+ start: 0,
12595
+ count: length
12596
+ });
12597
+ this.buffer.subData(typedArray);
12598
+ this.bufferValue = value;
12599
+ }
12600
+ return this.buffer;
12447
12601
  }
12448
12602
  };
12603
+ function setConstantFloatArray(device, location, array) {
12604
+ switch (array.length) {
12605
+ case 1:
12606
+ device.gl.vertexAttrib1fv(location, array);
12607
+ break;
12608
+ case 2:
12609
+ device.gl.vertexAttrib2fv(location, array);
12610
+ break;
12611
+ case 3:
12612
+ device.gl.vertexAttrib3fv(location, array);
12613
+ break;
12614
+ case 4:
12615
+ device.gl.vertexAttrib4fv(location, array);
12616
+ break;
12617
+ default:
12618
+ assert2(false);
12619
+ }
12620
+ }
12621
+ function setConstantIntArray(device, location, array) {
12622
+ device.assertWebGL2();
12623
+ device.gl2?.vertexAttribI4iv(location, array);
12624
+ }
12625
+ function setConstantUintArray(device, location, array) {
12626
+ device.assertWebGL2();
12627
+ device.gl2?.vertexAttribI4uiv(location, array);
12628
+ }
12629
+ function normalizeConstantArrayValue(arrayValue) {
12630
+ if (Array.isArray(arrayValue)) {
12631
+ return new Float32Array(arrayValue);
12632
+ }
12633
+ return arrayValue;
12634
+ }
12635
+ function compareConstantArrayValues(v1, v2) {
12636
+ if (!v1 || !v2 || v1.length !== v2.length || v1.constructor !== v2.constructor) {
12637
+ return false;
12638
+ }
12639
+ for (let i = 0; i < v1.length; ++i) {
12640
+ if (v1[i] !== v2[i]) {
12641
+ return false;
12642
+ }
12643
+ }
12644
+ return true;
12645
+ }
12449
12646
 
12450
12647
  // ../webgl/src/adapter/resources/webgl-render-pipeline.ts
12451
12648
  var LOG_PROGRAM_PERF_PRIORITY = 4;
@@ -12495,11 +12692,11 @@ ${formattedLog}`)();
12495
12692
  }
12496
12693
  /** @todo needed for portable model */
12497
12694
  setAttributes(attributes) {
12498
- for (const [name, buffer] of Object.entries(attributes)) {
12499
- const webglBuffer = cast(buffer);
12695
+ for (const [name, buffer2] of Object.entries(attributes)) {
12696
+ const webglBuffer = cast(buffer2);
12500
12697
  const attribute = getAttributeLayout(this.layout, name);
12501
12698
  if (!attribute) {
12502
- log.warn(`Ignoring buffer supplied for unknown attribute "${name}" in pipeline "${this.id}" (buffer "${buffer.id}")`)();
12699
+ log.warn(`Ignoring buffer supplied for unknown attribute "${name}" in pipeline "${this.id}" (buffer "${buffer2.id}")`)();
12503
12700
  continue;
12504
12701
  }
12505
12702
  const decoded = decodeVertexFormat(attribute.format);
@@ -12523,7 +12720,26 @@ ${formattedLog}`)();
12523
12720
  });
12524
12721
  }
12525
12722
  }
12526
- /** @todo needed for portable model */
12723
+ /**
12724
+ * Constant attributes are only supported in WebGL, not in WebGPU
12725
+ * Any attribute that is disabled in the current vertex array object
12726
+ * is read from the context's global constant value for that attribute location.
12727
+ * @param attributes
12728
+ */
12729
+ setConstantAttributes(attributes) {
12730
+ for (const [name, value] of Object.entries(attributes)) {
12731
+ const attribute = getAttributeLayout(this.layout, name);
12732
+ if (!attribute) {
12733
+ log.warn(`Ignoring constant value supplied for unknown attribute "${name}" in pipeline "${this.id}"`)();
12734
+ continue;
12735
+ }
12736
+ this.vertexArrayObject.setConstant(attribute.location, value);
12737
+ }
12738
+ }
12739
+ /**
12740
+ * Bindings include: textures, samplers and uniform buffers
12741
+ * @todo needed for portable model
12742
+ */
12527
12743
  setBindings(bindings) {
12528
12744
  for (const [name, value] of Object.entries(bindings)) {
12529
12745
  const binding = this.layout.bindings.find((binding2) => binding2.name === name);