@luma.gl/engine 9.0.0-alpha.31 → 9.0.0-alpha.32

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 (48) hide show
  1. package/dist/dist.dev.js +539 -286
  2. package/dist/geometries/truncated-cone-geometry.d.ts +0 -2
  3. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  4. package/dist/geometries/truncated-cone-geometry.js +0 -11
  5. package/dist/geometries/truncated-cone-geometry.js.map +1 -1
  6. package/dist/geometry/geometry.d.ts +6 -7
  7. package/dist/geometry/geometry.d.ts.map +1 -1
  8. package/dist/geometry/geometry.js.map +1 -1
  9. package/dist/geometry/gpu-geometry.d.ts +45 -0
  10. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  11. package/dist/geometry/gpu-geometry.js +123 -0
  12. package/dist/geometry/gpu-geometry.js.map +1 -0
  13. package/dist/geometry/gpu-table.d.ts +1 -0
  14. package/dist/geometry/gpu-table.d.ts.map +1 -0
  15. package/dist/geometry/gpu-table.js +2 -0
  16. package/dist/geometry/gpu-table.js.map +1 -0
  17. package/dist/index.cjs +311 -211
  18. package/dist/lib/pipeline-factory.d.ts +11 -44
  19. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  20. package/dist/lib/pipeline-factory.js +28 -119
  21. package/dist/lib/pipeline-factory.js.map +1 -1
  22. package/dist/model/model-shaders.d.ts +35 -0
  23. package/dist/model/model-shaders.d.ts.map +1 -0
  24. package/dist/model/model-shaders.js +38 -0
  25. package/dist/model/model-shaders.js.map +1 -0
  26. package/dist/model/model-utils.d.ts +1 -1
  27. package/dist/model/model-utils.d.ts.map +1 -1
  28. package/dist/model/model-utils.js +1 -1
  29. package/dist/model/model-utils.js.map +1 -1
  30. package/dist/model/model.d.ts +107 -22
  31. package/dist/model/model.d.ts.map +1 -1
  32. package/dist/model/model.js +144 -93
  33. package/dist/model/model.js.map +1 -1
  34. package/dist.min.js +67 -67
  35. package/package.json +6 -6
  36. package/src/geometries/truncated-cone-geometry.ts +0 -10
  37. package/src/geometry/geometry.ts +7 -7
  38. package/src/geometry/gpu-geometry.ts +159 -0
  39. package/src/geometry/gpu-table.ts +41 -0
  40. package/src/lib/pipeline-factory.ts +43 -164
  41. package/src/model/model-shaders.ts +76 -0
  42. package/src/model/model-utils.ts +2 -2
  43. package/src/model/model.ts +268 -126
  44. package/dist/geometry/primitive-utils.d.ts +0 -1
  45. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  46. package/dist/geometry/primitive-utils.js +0 -2
  47. package/dist/geometry/primitive-utils.js.map +0 -1
  48. package/src/geometry/primitive-utils.ts +0 -30
package/dist/dist.dev.js CHANGED
@@ -1181,6 +1181,8 @@ var __exports__ = (() => {
1181
1181
  get [Symbol.toStringTag]() {
1182
1182
  return "Buffer";
1183
1183
  }
1184
+ /** The usage with which this buffer was created */
1185
+ /** For index buffers, whether indices are 16 or 32 bit */
1184
1186
  /** Length of buffer in bytes */
1185
1187
  constructor(device, props) {
1186
1188
  const deducedProps = {
@@ -1194,6 +1196,8 @@ var __exports__ = (() => {
1194
1196
  }
1195
1197
  }
1196
1198
  super(device, deducedProps, _Buffer.defaultProps);
1199
+ this.usage = props.usage || 0;
1200
+ this.indexType = deducedProps.indexType;
1197
1201
  }
1198
1202
  write(data, byteOffset) {
1199
1203
  throw new Error("not implemented");
@@ -2016,7 +2020,11 @@ var __exports__ = (() => {
2016
2020
  /** Set attributes (stored on pipeline and set before each call) */
2017
2021
  /** Set constant attributes (WebGL only) */
2018
2022
  /** Set bindings (stored on pipeline and set before each call) */
2019
- /** Uniforms (only supported on WebGL devices. Reset before each call to enable pipeline sharing) */
2023
+ /** Uniforms
2024
+ * @deprecated Only supported on WebGL devices.
2025
+ * @note textures, samplers and uniform buffers should be set via `setBindings()`, these are not considered uniforms.
2026
+ * @note In WebGL uniforms have a performance penalty, they are reset before each call to enable pipeline sharing.
2027
+ */
2020
2028
  /** Draw call */
2021
2029
  };
2022
2030
  var RenderPipeline = _RenderPipeline;
@@ -2648,6 +2656,47 @@ var __exports__ = (() => {
2648
2656
  return options.target;
2649
2657
  }
2650
2658
 
2659
+ // ../core/src/lib/utils/deep-equal.ts
2660
+ function deepEqual(a, b, depth) {
2661
+ if (a === b) {
2662
+ return true;
2663
+ }
2664
+ if (!depth || !a || !b) {
2665
+ return false;
2666
+ }
2667
+ if (Array.isArray(a)) {
2668
+ if (!Array.isArray(b) || a.length !== b.length) {
2669
+ return false;
2670
+ }
2671
+ for (let i = 0; i < a.length; i++) {
2672
+ if (!deepEqual(a[i], b[i], depth - 1)) {
2673
+ return false;
2674
+ }
2675
+ }
2676
+ return true;
2677
+ }
2678
+ if (Array.isArray(b)) {
2679
+ return false;
2680
+ }
2681
+ if (typeof a === "object" && typeof b === "object") {
2682
+ const aKeys = Object.keys(a);
2683
+ const bKeys = Object.keys(b);
2684
+ if (aKeys.length !== bKeys.length) {
2685
+ return false;
2686
+ }
2687
+ for (const key of aKeys) {
2688
+ if (!b.hasOwnProperty(key)) {
2689
+ return false;
2690
+ }
2691
+ if (!deepEqual(a[key], b[key], depth - 1)) {
2692
+ return false;
2693
+ }
2694
+ }
2695
+ return true;
2696
+ }
2697
+ return false;
2698
+ }
2699
+
2651
2700
  // ../core/src/lib/request-animation-frame.ts
2652
2701
  function requestAnimationFrame(callback) {
2653
2702
  return typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame(callback) : setTimeout(callback, 1e3 / 60);
@@ -3064,46 +3113,6 @@ var __exports__ = (() => {
3064
3113
  return animationLoop;
3065
3114
  }
3066
3115
 
3067
- // src/model/model-utils.ts
3068
- var GLTF_TO_LUMA_ATTRIBUTE_MAP = {
3069
- POSITION: "positions",
3070
- NORMAL: "normals",
3071
- COLOR_0: "colors",
3072
- TEXCOORD_0: "texCoords",
3073
- TEXCOORD_1: "texCoords1",
3074
- TEXCOORD_2: "texCoords2"
3075
- };
3076
- function getIndexBufferFromGeometry(device, geometry) {
3077
- if (!geometry.indices) {
3078
- return void 0;
3079
- }
3080
- const data = geometry.indices.value || geometry.indices;
3081
- assert2(data instanceof Uint16Array || data instanceof Uint32Array, 'attribute array for "indices" must be of integer type');
3082
- return device.createBuffer({
3083
- usage: Buffer2.INDEX,
3084
- data
3085
- });
3086
- }
3087
- function getAttributeBuffersFromGeometry(device, geometry) {
3088
- const buffers = {};
3089
- for (const [name2, attribute] of Object.entries(geometry.attributes)) {
3090
- const remappedName = mapAttributeName(name2);
3091
- if (attribute?.constant) {
3092
- throw new Error("constant attributes not supported");
3093
- } else {
3094
- const typedArray = attribute?.value;
3095
- buffers[remappedName] = device.createBuffer({
3096
- data: typedArray,
3097
- id: `${remappedName}-buffer`
3098
- });
3099
- }
3100
- }
3101
- return buffers;
3102
- }
3103
- function mapAttributeName(name2) {
3104
- return GLTF_TO_LUMA_ATTRIBUTE_MAP[name2] || name2;
3105
- }
3106
-
3107
3116
  // ../shadertools/src/lib/glsl-utils/highlight.ts
3108
3117
  var glsl2 = (x) => `${x}`;
3109
3118
 
@@ -3326,7 +3335,7 @@ ${moduleSource}// END MODULE_${this.name}
3326
3335
  return result;
3327
3336
  }
3328
3337
 
3329
- // ../shadertools/src/lib/shader-assembler/resolve-modules.ts
3338
+ // ../shadertools/src/lib/shader-assembly/resolve-modules.ts
3330
3339
  function resolveModules(modules) {
3331
3340
  const instances = ShaderModuleInstance.instantiateModules(modules);
3332
3341
  return getShaderDependencies(instances);
@@ -3370,7 +3379,7 @@ ${moduleSource}// END MODULE_${this.name}
3370
3379
  }
3371
3380
  }
3372
3381
 
3373
- // ../shadertools/src/lib/shader-assembler/platform-defines.ts
3382
+ // ../shadertools/src/lib/shader-assembly/platform-defines.ts
3374
3383
  function getPlatformShaderDefines(platformInfo) {
3375
3384
  switch (platformInfo?.gpu.toLowerCase()) {
3376
3385
  case "apple":
@@ -3505,7 +3514,7 @@ ${moduleSource}// END MODULE_${this.name}
3505
3514
  #endif
3506
3515
  `;
3507
3516
 
3508
- // ../shadertools/src/lib/shader-assembler/inject-shader.ts
3517
+ // ../shadertools/src/lib/shader-assembly/inject-shader.ts
3509
3518
  var MODULE_INJECTORS = {
3510
3519
  vs: MODULE_INJECTORS_VS,
3511
3520
  fs: MODULE_INJECTORS_FS
@@ -3647,7 +3656,7 @@ ${match}`).replace(new RegExp(`\\b${ES100_FRAGMENT_OUTPUT_NAME}\\b`, "g"), outpu
3647
3656
  return new RegExp(`\\b${qualifier}[ \\t]+(\\w+[ \\t]+\\w+(\\[\\w+\\])?;)`, "g");
3648
3657
  }
3649
3658
 
3650
- // ../shadertools/src/lib/shader-assembler/assemble-shaders.ts
3659
+ // ../shadertools/src/lib/shader-assembly/assemble-shaders.ts
3651
3660
  var INJECT_SHADER_DECLARATIONS = `
3652
3661
 
3653
3662
  ${DECLARATION_INJECT_MARKER}
@@ -3879,6 +3888,91 @@ ${isVertex ? "" : FRAGMENT_SHADER_PROLOGUE}
3879
3888
  return result;
3880
3889
  }
3881
3890
 
3891
+ // ../shadertools/src/lib/shader-assembler.ts
3892
+ var ShaderAssembler = class {
3893
+ /** Default ShaderAssembler instance */
3894
+ /** Hook functions */
3895
+ _hookFunctions = [];
3896
+ /** Shader modules */
3897
+ _defaultModules = [];
3898
+ /**
3899
+ * A default shader assembler instance - the natural place to register default modules and hooks
3900
+ * @returns
3901
+ */
3902
+ static getDefaultShaderAssembler() {
3903
+ ShaderAssembler.defaultShaderAssembler = ShaderAssembler.defaultShaderAssembler || new ShaderAssembler();
3904
+ return ShaderAssembler.defaultShaderAssembler;
3905
+ }
3906
+ /**
3907
+ * Add a default module that does not have to be provided with every call to assembleShaders()
3908
+ */
3909
+ addDefaultModule(module) {
3910
+ if (!this._defaultModules.find((m) => m.name === (typeof module === "string" ? module : module.name))) {
3911
+ this._defaultModules.push(module);
3912
+ }
3913
+ }
3914
+ /**
3915
+ * Remove a default module
3916
+ */
3917
+ removeDefaultModule(module) {
3918
+ const moduleName = typeof module === "string" ? module : module.name;
3919
+ this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
3920
+ }
3921
+ /**
3922
+ * Register a shader hook
3923
+ * @param hook
3924
+ * @param opts
3925
+ */
3926
+ addShaderHook(hook, opts) {
3927
+ if (opts) {
3928
+ hook = Object.assign(opts, {
3929
+ hook
3930
+ });
3931
+ }
3932
+ this._hookFunctions.push(hook);
3933
+ }
3934
+ /**
3935
+ * Assemble a pair of shaders into a single shader program
3936
+ * @param platformInfo
3937
+ * @param props
3938
+ * @returns
3939
+ */
3940
+ assembleShaders(platformInfo, props) {
3941
+ const modules = this._getModuleList(props.modules);
3942
+ const hookFunctions = this._hookFunctions;
3943
+ const assembled = assembleShaders(platformInfo, {
3944
+ ...props,
3945
+ modules,
3946
+ hookFunctions
3947
+ });
3948
+ return assembled;
3949
+ }
3950
+ /**
3951
+ * Dedupe and combine with default modules
3952
+ */
3953
+ _getModuleList(appModules = []) {
3954
+ const modules = new Array(this._defaultModules.length + appModules.length);
3955
+ const seen = {};
3956
+ let count = 0;
3957
+ for (let i = 0, len = this._defaultModules.length; i < len; ++i) {
3958
+ const module = this._defaultModules[i];
3959
+ const name2 = module.name;
3960
+ modules[count++] = module;
3961
+ seen[name2] = true;
3962
+ }
3963
+ for (let i = 0, len = appModules.length; i < len; ++i) {
3964
+ const module = appModules[i];
3965
+ const name2 = module.name;
3966
+ if (!seen[name2]) {
3967
+ modules[count++] = module;
3968
+ seen[name2] = true;
3969
+ }
3970
+ }
3971
+ modules.length = count;
3972
+ return modules;
3973
+ }
3974
+ };
3975
+
3882
3976
  // ../shadertools/src/lib/glsl-utils/get-shader-info.ts
3883
3977
  function getShaderInfo(source, defaultName) {
3884
3978
  return {
@@ -5850,87 +5944,151 @@ void main() {
5850
5944
  return result;
5851
5945
  }
5852
5946
 
5853
- // src/lib/pipeline-factory.ts
5854
- var DEFAULT_RENDER_PIPELINE_OPTIONS = {
5855
- vs: "",
5856
- fs: "",
5857
- modules: [],
5858
- defines: {},
5859
- inject: {},
5860
- transpileToGLSL100: false,
5861
- shaderLayout: null,
5862
- varyings: [],
5863
- bufferMode: 35981,
5864
- // // varyings/bufferMode for xform feedback, 0x8c8d: SEPARATE_ATTRIBS
5865
- topology: "triangle-list",
5866
- parameters: {}
5947
+ // src/geometry/gpu-geometry.ts
5948
+ var GPUGeometry = class {
5949
+ userData = {};
5950
+ /** Determines how vertices are read from the 'vertex' attributes */
5951
+ bufferLayout = [];
5952
+ constructor(props) {
5953
+ this.id = props.id || uid("geometry");
5954
+ this.topology = props.topology;
5955
+ this.indices = props.indices || null;
5956
+ this.attributes = props.attributes;
5957
+ this.vertexCount = props.vertexCount || this._calculateVertexCount(this.attributes.positions);
5958
+ this.bufferLayout = props.bufferLayout || [];
5959
+ if (!this.bufferLayout.find((layout) => layout.name === "positions")) {
5960
+ this.bufferLayout.push({
5961
+ name: "positions",
5962
+ format: "float32x3"
5963
+ });
5964
+ }
5965
+ if (!this.bufferLayout.find((layout) => layout.name === "normals")) {
5966
+ this.bufferLayout.push({
5967
+ name: "normals",
5968
+ format: "float32x3"
5969
+ });
5970
+ }
5971
+ if (!this.bufferLayout.find((layout) => layout.name === "texCoords")) {
5972
+ this.bufferLayout.push({
5973
+ name: "texCoords",
5974
+ format: "float32x2"
5975
+ });
5976
+ }
5977
+ if (!this.bufferLayout.find((layout) => layout.name === "colors")) {
5978
+ this.bufferLayout.push({
5979
+ name: "colors",
5980
+ format: "float32x3"
5981
+ });
5982
+ }
5983
+ if (this.indices) {
5984
+ assert2(this.indices.usage === Buffer2.INDEX);
5985
+ }
5986
+ }
5987
+ destroy() {
5988
+ this.indices.destroy();
5989
+ this.attributes.positions.destroy();
5990
+ this.attributes.normals.destroy();
5991
+ this.attributes.texCoords.destroy();
5992
+ this.attributes.colors?.destroy();
5993
+ }
5994
+ getVertexCount() {
5995
+ return this.vertexCount;
5996
+ }
5997
+ getAttributes() {
5998
+ return this.attributes;
5999
+ }
6000
+ getIndexes() {
6001
+ return this.indices;
6002
+ }
6003
+ _calculateVertexCount(positions) {
6004
+ const vertexCount = positions.byteLength / 12;
6005
+ return vertexCount;
6006
+ }
5867
6007
  };
5868
- var PipelineFactory = class {
5869
- stateHash = 0;
5870
- // Used to change hashing if hooks are modified
6008
+ function makeGPUGeometry(device, geometry) {
6009
+ if (geometry instanceof GPUGeometry) {
6010
+ return geometry;
6011
+ }
6012
+ const indices = getIndexBufferFromGeometry(device, geometry);
6013
+ const attributes = getAttributeBuffersFromGeometry(device, geometry);
6014
+ return new GPUGeometry({
6015
+ topology: geometry.topology,
6016
+ vertexCount: geometry.vertexCount,
6017
+ indices,
6018
+ attributes
6019
+ });
6020
+ }
6021
+ function getIndexBufferFromGeometry(device, geometry) {
6022
+ if (!geometry.indices) {
6023
+ return void 0;
6024
+ }
6025
+ const data = geometry.indices.value || geometry.indices;
6026
+ assert2(data instanceof Uint16Array || data instanceof Uint32Array, 'attribute array for "indices" must be of integer type');
6027
+ return device.createBuffer({
6028
+ usage: Buffer2.INDEX,
6029
+ data
6030
+ });
6031
+ }
6032
+ function getAttributeBuffersFromGeometry(device, geometry) {
6033
+ const positions = geometry.attributes.positions || geometry.attributes.POSITION;
6034
+ const normals = geometry.attributes.normals || geometry.attributes.NORMAL;
6035
+ const texCoords = geometry.attributes.texCoords || geometry.attributes.TEXCOORD_0;
6036
+ const buffers = {
6037
+ positions: device.createBuffer({
6038
+ data: positions.value,
6039
+ id: "positions-buffer"
6040
+ }),
6041
+ normals: device.createBuffer({
6042
+ data: normals.value,
6043
+ id: "normals-buffer"
6044
+ }),
6045
+ texCoords: device.createBuffer({
6046
+ data: texCoords.value,
6047
+ id: "texCoords-buffer"
6048
+ })
6049
+ };
6050
+ return buffers;
6051
+ }
6052
+
6053
+ // src/lib/pipeline-factory.ts
6054
+ var _PipelineFactory = class {
5871
6055
  _hashCounter = 0;
5872
6056
  _hashes = {};
5873
6057
  _useCounts = {};
5874
6058
  _pipelineCache = {};
5875
- _getUniforms = {};
5876
- _hookFunctions = [];
5877
- _defaultModules = [];
5878
- // private readonly _registeredModules = {}; // TODO: Remove? This isn't used anywhere in luma.gl
5879
6059
  static getDefaultPipelineFactory(device) {
5880
- device.defaultPipelineFactory = device.defaultPipelineFactory || new PipelineFactory(device);
5881
- return device.defaultPipelineFactory;
6060
+ device._lumaData.defaultPipelineFactory = device._lumaData.defaultPipelineFactory || new _PipelineFactory(device);
6061
+ return device._lumaData.defaultPipelineFactory;
5882
6062
  }
5883
6063
  constructor(device) {
5884
6064
  this.device = device;
5885
6065
  }
5886
- addDefaultModule(module) {
5887
- if (!this._defaultModules.find((m) => m.name === (typeof module === "string" ? module : module.name))) {
5888
- this._defaultModules.push(module);
5889
- }
5890
- this.stateHash++;
5891
- }
5892
- removeDefaultModule(module) {
5893
- const moduleName = typeof module === "string" ? module : module.name;
5894
- this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
5895
- this.stateHash++;
5896
- }
5897
- addShaderHook(hook, opts) {
5898
- if (opts) {
5899
- hook = Object.assign(opts, {
5900
- hook
5901
- });
5902
- }
5903
- this._hookFunctions.push(hook);
5904
- this.stateHash++;
5905
- }
5906
6066
  createRenderPipeline(options) {
5907
6067
  const props = {
5908
- ...DEFAULT_RENDER_PIPELINE_OPTIONS,
6068
+ ..._PipelineFactory.defaultProps,
5909
6069
  ...options
5910
6070
  };
5911
- const modules = this._getModuleList(props.modules);
5912
6071
  const hash = this._hashRenderPipeline({
5913
- ...props,
5914
- modules
6072
+ ...props
5915
6073
  });
5916
6074
  if (!this._pipelineCache[hash]) {
5917
- const {
5918
- pipeline,
5919
- getUniforms
5920
- } = this._createRenderPipeline({
6075
+ const pipeline = this.device.createRenderPipeline({
5921
6076
  ...props,
5922
- modules
6077
+ vs: this.device.createShader({
6078
+ stage: "vertex",
6079
+ source: props.vs
6080
+ }),
6081
+ fs: props.fs ? this.device.createShader({
6082
+ stage: "fragment",
6083
+ source: props.fs
6084
+ }) : null
5923
6085
  });
5924
6086
  pipeline.hash = hash;
5925
6087
  this._pipelineCache[hash] = pipeline;
5926
- this._getUniforms[hash] = getUniforms || ((x) => ({}));
5927
6088
  this._useCounts[hash] = 0;
5928
6089
  }
5929
6090
  this._useCounts[hash]++;
5930
- return {
5931
- pipeline: this._pipelineCache[hash],
5932
- getUniforms: this._getUniforms[hash]
5933
- };
6091
+ return this._pipelineCache[hash];
5934
6092
  }
5935
6093
  release(pipeline) {
5936
6094
  const hash = pipeline.hash;
@@ -5938,70 +6096,35 @@ void main() {
5938
6096
  if (this._useCounts[hash] === 0) {
5939
6097
  this._pipelineCache[hash].destroy();
5940
6098
  delete this._pipelineCache[hash];
5941
- delete this._getUniforms[hash];
5942
6099
  delete this._useCounts[hash];
5943
6100
  }
5944
6101
  }
5945
- getUniforms(pipeline) {
5946
- return this._getUniforms[pipeline.hash] || null;
5947
- }
5948
6102
  // PRIVATE
5949
6103
  _createRenderPipeline(props) {
5950
- const platformInfo = {
5951
- gpu: this.device.info.gpu,
5952
- features: this.device.features
5953
- };
5954
6104
  if (!props.fs) {
5955
6105
  throw new Error("fs");
5956
6106
  }
5957
- const assembled = assembleShaders(platformInfo, {
5958
- ...props,
5959
- fs: props.fs,
5960
- hookFunctions: this._hookFunctions
5961
- });
5962
6107
  const pipeline = this.device.createRenderPipeline({
5963
6108
  ...props,
5964
6109
  vs: this.device.createShader({
5965
6110
  stage: "vertex",
5966
- source: assembled.vs
6111
+ source: props.vs
5967
6112
  }),
5968
- fs: assembled.fs ? this.device.createShader({
6113
+ fs: props.fs ? this.device.createShader({
5969
6114
  stage: "fragment",
5970
- source: assembled.fs
6115
+ source: props.fs
5971
6116
  }) : null
5972
6117
  });
5973
- return {
5974
- pipeline,
5975
- getUniforms: assembled.getUniforms
5976
- };
6118
+ return pipeline;
5977
6119
  }
5978
6120
  /** Calculate a hash based on all the inputs for a render pipeline */
5979
6121
  _hashRenderPipeline(props) {
5980
- const {
5981
- modules = [],
5982
- varyings = [],
5983
- defines = {},
5984
- inject = {},
5985
- parameters = {}
5986
- } = props;
5987
6122
  const vsHash = this._getHash(props.vs);
5988
6123
  const fsHash = props.fs ? this._getHash(props.fs) : 0;
5989
- const moduleHashes = modules.map((m) => this._getHash(typeof m === "string" ? m : m.name)).sort();
5990
- const varyingHashes = varyings.map((v) => this._getHash(v));
5991
- const defineKeys = Object.keys(defines).sort();
5992
- const injectKeys = Object.keys(inject).sort();
5993
- const defineHashes = [];
5994
- const injectHashes = [];
5995
- for (const key of defineKeys) {
5996
- defineHashes.push(this._getHash(key));
5997
- defineHashes.push(this._getHash(String(defines[key])));
5998
- }
5999
- for (const key of injectKeys) {
6000
- injectHashes.push(this._getHash(key));
6001
- injectHashes.push(this._getHash(inject[key]));
6002
- }
6003
- const parameterHash = JSON.stringify(parameters);
6004
- return `${vsHash}/${fsHash}D${defineHashes.join("/")}M${moduleHashes.join("/")}I${injectHashes.join("/")}V${varyingHashes.join("/")}H${this.stateHash}B${props.bufferMode}${props.transpileToGLSL100 ? "T" : ""}P${parameterHash}`;
6124
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
6125
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
6126
+ const varyingHash = "-";
6127
+ return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}}`;
6005
6128
  }
6006
6129
  _getHash(key) {
6007
6130
  if (this._hashes[key] === void 0) {
@@ -6009,116 +6132,110 @@ void main() {
6009
6132
  }
6010
6133
  return this._hashes[key];
6011
6134
  }
6012
- // Dedupe and combine with default modules
6013
- _getModuleList(appModules = []) {
6014
- const modules = new Array(this._defaultModules.length + appModules.length);
6015
- const seen = {};
6016
- let count = 0;
6017
- for (let i = 0, len = this._defaultModules.length; i < len; ++i) {
6018
- const module = this._defaultModules[i];
6019
- const name2 = module.name;
6020
- modules[count++] = module;
6021
- seen[name2] = true;
6022
- }
6023
- for (let i = 0, len = appModules.length; i < len; ++i) {
6024
- const module = appModules[i];
6025
- const name2 = module.name;
6026
- if (!seen[name2]) {
6027
- modules[count++] = module;
6028
- seen[name2] = true;
6135
+ };
6136
+ var PipelineFactory = _PipelineFactory;
6137
+ __publicField(PipelineFactory, "defaultProps", {
6138
+ ...RenderPipeline.defaultProps,
6139
+ vs: void 0,
6140
+ fs: void 0
6141
+ });
6142
+
6143
+ // src/model/model-shaders.ts
6144
+ function buildShaders(device, props) {
6145
+ if (!props.vs) {
6146
+ throw new Error("no vertex shader");
6147
+ }
6148
+ const vs = getShaderSource(device, props.vs);
6149
+ let fs;
6150
+ if (props.fs) {
6151
+ fs = getShaderSource(device, props.fs);
6152
+ }
6153
+ const platformInfo = {
6154
+ type: device.info.type,
6155
+ gpu: device.info.gpu,
6156
+ features: device.features
6157
+ };
6158
+ return props.shaderAssembler.assembleShaders(platformInfo, {
6159
+ ...props,
6160
+ fs,
6161
+ vs
6162
+ });
6163
+ }
6164
+ function getShaderSource(device, shader) {
6165
+ if (typeof shader === "string") {
6166
+ return shader;
6167
+ }
6168
+ switch (device.info.type) {
6169
+ case "webgpu":
6170
+ if (shader?.wgsl) {
6171
+ return shader.wgsl;
6029
6172
  }
6030
- }
6031
- modules.length = count;
6032
- return modules;
6173
+ throw new Error("WebGPU does not support GLSL shaders");
6174
+ default:
6175
+ if (shader?.glsl) {
6176
+ return shader.glsl;
6177
+ }
6178
+ throw new Error("WebGL does not support WGSL shaders");
6033
6179
  }
6034
- };
6180
+ }
6035
6181
 
6036
6182
  // src/model/model.ts
6037
- var DEFAULT_MODEL_PROPS = {
6038
- ...RenderPipeline.defaultProps,
6039
- vs: null,
6040
- fs: null,
6041
- id: "unnamed",
6042
- handle: void 0,
6043
- userData: {},
6044
- defines: {},
6045
- modules: [],
6046
- moduleSettings: {},
6047
- geometry: null,
6048
- pipelineFactory: void 0,
6049
- vertexCount: 0,
6050
- instanceCount: 0
6051
- };
6052
- var Model = class {
6053
- fs = null;
6054
- /** The underlying GPU "program". @note May be recreated if parameters change */
6183
+ var _Model = class {
6055
6184
  userData = {};
6056
- // readonly props: Required<ModelProps>;
6185
+ // Fixed properties (change can trigger pipeline rebuild)
6186
+ /** The render pipeline GPU parameters, depth testing etc */
6187
+ /** The primitive topology */
6188
+ /** Buffer layout */
6189
+ // Dynamic properties
6057
6190
  /** Vertex count */
6058
6191
  /** instance count */
6059
6192
  instanceCount = 0;
6193
+ /** Index buffer */
6194
+ indices = null;
6060
6195
  /** Buffer-valued attributes */
6061
6196
  bufferAttributes = {};
6062
6197
  /** Constant-valued attributes */
6063
6198
  constantAttributes = {};
6064
6199
  /** Bindings (textures, samplers, uniform buffers) */
6065
6200
  bindings = {};
6066
- /** Uniforms */
6201
+ /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
6067
6202
  uniforms = {};
6203
+ /** The underlying GPU "program". @note May be recreated if parameters change */
6204
+ _pipelineNeedsUpdate = "newly created";
6068
6205
  constructor(device, props) {
6069
- props = {
6070
- ...DEFAULT_MODEL_PROPS,
6206
+ this.props = {
6207
+ ..._Model.defaultProps,
6071
6208
  ...props
6072
6209
  };
6073
- this.id = props.id;
6210
+ props = this.props;
6211
+ this.id = props.id || uid("model");
6074
6212
  this.device = device;
6075
6213
  Object.assign(this.userData, props.userData);
6076
- if (!props.vs) {
6077
- throw new Error("no vertex shader");
6078
- }
6079
- this.vs = getShaderSource(this.device, props.vs);
6080
- if (props.fs) {
6081
- this.fs = getShaderSource(this.device, props.fs);
6082
- }
6083
- this.vertexCount = props.vertexCount;
6084
- this.instanceCount = props.instanceCount;
6085
- this.topology = props.topology;
6086
- if (props.geometry) {
6087
- this.vertexCount = props.geometry.vertexCount;
6088
- this.topology = props.geometry.topology || "triangle-list";
6089
- }
6090
- this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
6091
6214
  const {
6092
- pipeline,
6215
+ vs,
6216
+ fs,
6093
6217
  getUniforms
6094
- } = this.pipelineFactory.createRenderPipeline({
6095
- ...props,
6096
- vs: this.vs,
6097
- fs: this.fs,
6098
- topology: this.topology,
6099
- defines: props.defines,
6100
- parameters: props.parameters,
6101
- shaderLayout: props.shaderLayout
6102
- });
6103
- this.pipeline = pipeline;
6218
+ } = buildShaders(device, this.props);
6219
+ this.vs = vs;
6220
+ this.fs = fs;
6104
6221
  this._getModuleUniforms = getUniforms;
6105
- if (props.geometry) {
6106
- this._setGeometry(props.geometry);
6222
+ this.vertexCount = this.props.vertexCount;
6223
+ this.instanceCount = this.props.instanceCount;
6224
+ this.topology = this.props.topology;
6225
+ this.bufferLayout = this.props.bufferLayout;
6226
+ this.parameters = this.props.parameters;
6227
+ const gpuGeometry = props.geometry && makeGPUGeometry(device, props.geometry);
6228
+ if (gpuGeometry) {
6229
+ this.setGeometry(gpuGeometry);
6230
+ }
6231
+ this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
6232
+ this.pipeline = this._updatePipeline();
6233
+ if (props.vertexCount) {
6234
+ this.setVertexCount(props.vertexCount);
6235
+ }
6236
+ if (props.instanceCount) {
6237
+ this.setInstanceCount(props.instanceCount);
6107
6238
  }
6108
- this.setUniforms(this._getModuleUniforms());
6109
- this.setProps(props);
6110
- }
6111
- destroy() {
6112
- this.pipelineFactory.release(this.pipeline);
6113
- }
6114
- draw(renderPass) {
6115
- this.pipeline.draw({
6116
- renderPass,
6117
- vertexCount: this.vertexCount,
6118
- instanceCount: this.instanceCount
6119
- });
6120
- }
6121
- setProps(props) {
6122
6239
  if (props.indices) {
6123
6240
  this.setIndexBuffer(props.indices);
6124
6241
  }
@@ -6134,59 +6251,195 @@ void main() {
6134
6251
  if (props.moduleSettings) {
6135
6252
  this.updateModuleSettings(props.moduleSettings);
6136
6253
  }
6254
+ this.setUniforms(this._getModuleUniforms());
6255
+ Object.seal(this);
6137
6256
  }
6138
- updateModuleSettings(props) {
6257
+ destroy() {
6258
+ this.pipelineFactory.release(this.pipeline);
6259
+ }
6260
+ // Draw call
6261
+ draw(renderPass) {
6262
+ this.pipeline = this._updatePipeline();
6263
+ this.pipeline.setIndexBuffer(this.indices);
6264
+ this.pipeline.setAttributes(this.bufferAttributes);
6265
+ this.pipeline.setConstantAttributes(this.constantAttributes);
6266
+ this.pipeline.setBindings(this.bindings);
6267
+ this.pipeline.setUniforms(this.uniforms);
6268
+ this.pipeline.draw({
6269
+ renderPass,
6270
+ vertexCount: this.vertexCount,
6271
+ instanceCount: this.instanceCount
6272
+ });
6273
+ }
6274
+ // Update fixed fields (can trigger pipeline rebuild)
6275
+ /**
6276
+ * Updates the optional geometry
6277
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
6278
+ */
6279
+ setGeometry(geometry) {
6280
+ this.setTopology(geometry.topology || "triangle-list");
6281
+ this.bufferLayout = mergeBufferLayouts(this.bufferLayout, geometry.bufferLayout);
6282
+ this.vertexCount = geometry.vertexCount;
6283
+ this.setAttributes(geometry.attributes);
6284
+ this.setIndexBuffer(geometry.indices);
6285
+ }
6286
+ /**
6287
+ * Updates the primitive topology ('triangle-list', 'triangle-strip' etc).
6288
+ * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
6289
+ */
6290
+ setTopology(topology) {
6291
+ if (topology !== this.topology) {
6292
+ this.topology = topology;
6293
+ if (this.device.info.type === "webgpu") {
6294
+ this._setPipelineNeedsUpdate("topology");
6295
+ }
6296
+ }
6297
+ }
6298
+ /**
6299
+ * Updates the buffer layout.
6300
+ * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
6301
+ */
6302
+ setBufferLayout(bufferLayout) {
6303
+ if (bufferLayout !== this.bufferLayout) {
6304
+ this.bufferLayout = bufferLayout;
6305
+ if (this.device.info.type === "webgpu") {
6306
+ this._setPipelineNeedsUpdate("bufferLayout");
6307
+ }
6308
+ }
6309
+ }
6310
+ /**
6311
+ * Set GPU parameters.
6312
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch.
6313
+ * @param parameters
6314
+ */
6315
+ setParameters(parameters) {
6316
+ if (!deepEqual(parameters, this.parameters, 2)) {
6317
+ this.parameters = parameters;
6318
+ if (this.device.info.type === "webgpu") {
6319
+ this._setPipelineNeedsUpdate("parameters");
6320
+ }
6321
+ }
6322
+ }
6323
+ // Update dynamic fields
6324
+ /**
6325
+ * Updates the vertex count (used in draw calls)
6326
+ * @note Any attributes with stepMode=vertex need to be at least this big
6327
+ */
6328
+ setVertexCount(vertexCount) {
6329
+ this.vertexCount = vertexCount;
6330
+ }
6331
+ /**
6332
+ * Updates the instance count (used in draw calls)
6333
+ * @note Any attributes with stepMode=instance need to be at least this big
6334
+ */
6335
+ setInstanceCount(instanceCount) {
6336
+ this.instanceCount = instanceCount;
6337
+ }
6338
+ /**
6339
+ * Updates shader module settings (which results in uniforms being set)
6340
+ */
6341
+ setShaderModuleProps(props) {
6139
6342
  const uniforms = this._getModuleUniforms(props);
6140
- this.setUniforms(uniforms);
6343
+ Object.assign(this.uniforms, uniforms);
6141
6344
  }
6345
+ /**
6346
+ * @deprecated Updates shader module settings (which results in uniforms being set)
6347
+ */
6348
+ updateModuleSettings(props) {
6349
+ this.setShaderModuleProps(props);
6350
+ }
6351
+ /**
6352
+ * Sets the index buffer
6353
+ * @todo - how to unset it if we change geometry?
6354
+ */
6142
6355
  setIndexBuffer(indices) {
6143
- this.pipeline.setIndexBuffer(indices);
6356
+ this.indices = indices;
6144
6357
  }
6358
+ /**
6359
+ * Sets attributes (buffers)
6360
+ * @note Overrides any attributes previously set with the same name
6361
+ */
6145
6362
  setAttributes(bufferAttributes) {
6146
6363
  if (bufferAttributes.indices) {
6147
6364
  log.warn(`Model:${this.id} setAttributes() - indices should be set using setIndexBuffer()`);
6148
6365
  }
6149
- this.pipeline.setAttributes(bufferAttributes);
6150
6366
  Object.assign(this.bufferAttributes, bufferAttributes);
6151
6367
  }
6368
+ /**
6369
+ * Sets constant attributes
6370
+ * @note Overrides any attributes previously set with the same name
6371
+ * @param constantAttributes
6372
+ */
6152
6373
  setConstantAttributes(constantAttributes) {
6153
- this.pipeline.setConstantAttributes(constantAttributes);
6154
6374
  Object.assign(this.constantAttributes, constantAttributes);
6155
6375
  }
6156
- /** Set the bindings */
6376
+ /**
6377
+ * Sets bindings (textures, samplers, uniform buffers)
6378
+ */
6157
6379
  setBindings(bindings) {
6158
- this.pipeline.setBindings(bindings);
6159
6380
  Object.assign(this.bindings, bindings);
6160
6381
  }
6382
+ /**
6383
+ * Sets individual uniforms
6384
+ * @deprecated WebGL only, use uniform buffers for portability
6385
+ * @param uniforms
6386
+ * @returns self for chaining
6387
+ */
6161
6388
  setUniforms(uniforms) {
6162
6389
  this.pipeline.setUniforms(uniforms);
6163
6390
  Object.assign(this.uniforms, uniforms);
6164
6391
  }
6165
- _setGeometry(geometry) {
6166
- const geometryBuffers = getAttributeBuffersFromGeometry(this.device, geometry);
6167
- this.setAttributes(geometryBuffers);
6168
- const indexBuffer = getIndexBufferFromGeometry(this.device, geometry);
6169
- if (indexBuffer) {
6170
- this.setIndexBuffer(indexBuffer);
6392
+ _setPipelineNeedsUpdate(reason) {
6393
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
6394
+ }
6395
+ _updatePipeline() {
6396
+ if (this._pipelineNeedsUpdate) {
6397
+ log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
6398
+ this._pipelineNeedsUpdate = false;
6399
+ this.pipeline = this.device.createRenderPipeline({
6400
+ ...this.props,
6401
+ bufferLayout: this.bufferLayout,
6402
+ topology: this.topology,
6403
+ parameters: this.parameters,
6404
+ vs: this.device.createShader({
6405
+ stage: "vertex",
6406
+ source: this.vs
6407
+ }),
6408
+ fs: this.fs ? this.device.createShader({
6409
+ stage: "fragment",
6410
+ source: this.fs
6411
+ }) : null
6412
+ });
6171
6413
  }
6414
+ return this.pipeline;
6172
6415
  }
6173
6416
  };
6174
- function getShaderSource(device, shader) {
6175
- if (typeof shader === "string") {
6176
- return shader;
6177
- }
6178
- switch (device.info.type) {
6179
- case "webgpu":
6180
- if (shader?.wgsl) {
6181
- return shader.wgsl;
6182
- }
6183
- throw new Error("WebGPU does not support GLSL shaders");
6184
- default:
6185
- if (shader?.glsl) {
6186
- return shader.glsl;
6187
- }
6188
- throw new Error("WebGL does not support WGSL shaders");
6417
+ var Model = _Model;
6418
+ __publicField(Model, "defaultProps", {
6419
+ ...RenderPipeline.defaultProps,
6420
+ vs: null,
6421
+ fs: null,
6422
+ id: "unnamed",
6423
+ handle: void 0,
6424
+ userData: {},
6425
+ defines: {},
6426
+ modules: [],
6427
+ moduleSettings: {},
6428
+ geometry: null,
6429
+ pipelineFactory: void 0,
6430
+ shaderAssembler: ShaderAssembler.getDefaultShaderAssembler()
6431
+ });
6432
+ function mergeBufferLayouts(layouts1, layouts2) {
6433
+ const layouts = [...layouts1];
6434
+ for (const attribute of layouts2) {
6435
+ const index = layouts.findIndex((attribute2) => attribute2.name === attribute.name);
6436
+ if (index < 0) {
6437
+ layouts.push(attribute);
6438
+ } else {
6439
+ layouts[index] = attribute;
6440
+ }
6189
6441
  }
6442
+ return layouts;
6190
6443
  }
6191
6444
 
6192
6445
  // ../constants/src/constants-enum.ts
@@ -12488,34 +12741,34 @@ ${formattedLog}`)();
12488
12741
  // ../webgl/src/adapter/helpers/set-uniform.ts
12489
12742
  function setUniform(gl, location, type, value) {
12490
12743
  const gl2 = gl;
12491
- if (typeof value === "number") {
12492
- switch (type) {
12493
- case GL.SAMPLER_2D:
12494
- case GL.SAMPLER_CUBE:
12495
- case GL.SAMPLER_3D:
12496
- case GL.SAMPLER_2D_SHADOW:
12497
- case GL.SAMPLER_2D_ARRAY:
12498
- case GL.SAMPLER_2D_ARRAY_SHADOW:
12499
- case GL.SAMPLER_CUBE_SHADOW:
12500
- case GL.INT_SAMPLER_2D:
12501
- case GL.INT_SAMPLER_3D:
12502
- case GL.INT_SAMPLER_CUBE:
12503
- case GL.INT_SAMPLER_2D_ARRAY:
12504
- case GL.UNSIGNED_INT_SAMPLER_2D:
12505
- case GL.UNSIGNED_INT_SAMPLER_3D:
12506
- case GL.UNSIGNED_INT_SAMPLER_CUBE:
12507
- case GL.UNSIGNED_INT_SAMPLER_2D_ARRAY:
12508
- return gl.uniform1i(location, value);
12509
- }
12510
- }
12511
- if (value === true) {
12512
- value = 1;
12513
- }
12514
- if (value === false) {
12515
- value = 0;
12516
- }
12517
- const arrayValue = typeof value === "number" ? [value] : value;
12744
+ let uniformValue = value;
12745
+ if (uniformValue === true) {
12746
+ uniformValue = 1;
12747
+ }
12748
+ if (uniformValue === false) {
12749
+ uniformValue = 0;
12750
+ }
12751
+ const arrayValue = typeof uniformValue === "number" ? [uniformValue] : uniformValue;
12518
12752
  switch (type) {
12753
+ case GL.SAMPLER_2D:
12754
+ case GL.SAMPLER_CUBE:
12755
+ case GL.SAMPLER_3D:
12756
+ case GL.SAMPLER_2D_SHADOW:
12757
+ case GL.SAMPLER_2D_ARRAY:
12758
+ case GL.SAMPLER_2D_ARRAY_SHADOW:
12759
+ case GL.SAMPLER_CUBE_SHADOW:
12760
+ case GL.INT_SAMPLER_2D:
12761
+ case GL.INT_SAMPLER_3D:
12762
+ case GL.INT_SAMPLER_CUBE:
12763
+ case GL.INT_SAMPLER_2D_ARRAY:
12764
+ case GL.UNSIGNED_INT_SAMPLER_2D:
12765
+ case GL.UNSIGNED_INT_SAMPLER_3D:
12766
+ case GL.UNSIGNED_INT_SAMPLER_CUBE:
12767
+ case GL.UNSIGNED_INT_SAMPLER_2D_ARRAY:
12768
+ if (typeof value !== "number") {
12769
+ throw new Error("samplers must be set to integers");
12770
+ }
12771
+ return gl.uniform1i(location, value);
12519
12772
  case GL.FLOAT:
12520
12773
  return gl.uniform1fv(location, arrayValue);
12521
12774
  case GL.FLOAT_VEC2: