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

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 (44) hide show
  1. package/dist/dist.dev.js +583 -294
  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 +25 -11
  7. package/dist/geometry/geometry.d.ts.map +1 -1
  8. package/dist/geometry/geometry.js +1 -2
  9. package/dist/geometry/geometry.js.map +1 -1
  10. package/dist/geometry/gpu-geometry.d.ts +48 -0
  11. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  12. package/dist/geometry/gpu-geometry.js +137 -0
  13. package/dist/geometry/gpu-geometry.js.map +1 -0
  14. package/dist/geometry/gpu-table.d.ts +1 -0
  15. package/dist/geometry/gpu-table.d.ts.map +1 -0
  16. package/dist/geometry/gpu-table.js +2 -0
  17. package/dist/geometry/gpu-table.js.map +1 -0
  18. package/dist/index.cjs +313 -222
  19. package/dist/lib/pipeline-factory.d.ts +11 -44
  20. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  21. package/dist/lib/pipeline-factory.js +28 -119
  22. package/dist/lib/pipeline-factory.js.map +1 -1
  23. package/dist/model/model.d.ts +108 -22
  24. package/dist/model/model.d.ts.map +1 -1
  25. package/dist/model/model.js +148 -92
  26. package/dist/model/model.js.map +1 -1
  27. package/dist.min.js +67 -67
  28. package/package.json +6 -6
  29. package/src/geometries/truncated-cone-geometry.ts +0 -10
  30. package/src/geometry/geometry.ts +26 -23
  31. package/src/geometry/gpu-geometry.ts +158 -0
  32. package/src/geometry/gpu-table.ts +41 -0
  33. package/src/lib/pipeline-factory.ts +43 -164
  34. package/src/model/model.ts +276 -126
  35. package/dist/geometry/primitive-utils.d.ts +0 -1
  36. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  37. package/dist/geometry/primitive-utils.js +0 -2
  38. package/dist/geometry/primitive-utils.js.map +0 -1
  39. package/dist/model/model-utils.d.ts +0 -5
  40. package/dist/model/model-utils.d.ts.map +0 -1
  41. package/dist/model/model-utils.js +0 -40
  42. package/dist/model/model-utils.js.map +0 -1
  43. package/src/geometry/primitive-utils.ts +0 -30
  44. package/src/model/model-utils.ts +0 -125
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,126 @@ ${isVertex ? "" : FRAGMENT_SHADER_PROLOGUE}
3879
3888
  return result;
3880
3889
  }
3881
3890
 
3891
+ // ../shadertools/src/lib/shader-assembly/select-shaders.ts
3892
+ function selectShaders(platformInfo, props) {
3893
+ if (!props.vs) {
3894
+ throw new Error("no vertex shader");
3895
+ }
3896
+ const vs = getShaderSource(platformInfo, props.vs);
3897
+ let fs;
3898
+ if (props.fs) {
3899
+ fs = getShaderSource(platformInfo, props.fs);
3900
+ }
3901
+ return {
3902
+ ...props,
3903
+ vs,
3904
+ fs
3905
+ };
3906
+ }
3907
+ function getShaderSource(platformInfo, shader) {
3908
+ if (typeof shader === "string") {
3909
+ return shader;
3910
+ }
3911
+ switch (platformInfo.type) {
3912
+ case "webgpu":
3913
+ if (shader?.wgsl) {
3914
+ return shader.wgsl;
3915
+ }
3916
+ throw new Error("WebGPU does not support GLSL shaders");
3917
+ default:
3918
+ if (shader?.glsl) {
3919
+ return shader.glsl;
3920
+ }
3921
+ throw new Error("WebGL does not support WGSL shaders");
3922
+ }
3923
+ }
3924
+
3925
+ // ../shadertools/src/lib/shader-assembler.ts
3926
+ var ShaderAssembler = class {
3927
+ /** Default ShaderAssembler instance */
3928
+ /** Hook functions */
3929
+ _hookFunctions = [];
3930
+ /** Shader modules */
3931
+ _defaultModules = [];
3932
+ /**
3933
+ * A default shader assembler instance - the natural place to register default modules and hooks
3934
+ * @returns
3935
+ */
3936
+ static getDefaultShaderAssembler() {
3937
+ ShaderAssembler.defaultShaderAssembler = ShaderAssembler.defaultShaderAssembler || new ShaderAssembler();
3938
+ return ShaderAssembler.defaultShaderAssembler;
3939
+ }
3940
+ /**
3941
+ * Add a default module that does not have to be provided with every call to assembleShaders()
3942
+ */
3943
+ addDefaultModule(module) {
3944
+ if (!this._defaultModules.find((m) => m.name === (typeof module === "string" ? module : module.name))) {
3945
+ this._defaultModules.push(module);
3946
+ }
3947
+ }
3948
+ /**
3949
+ * Remove a default module
3950
+ */
3951
+ removeDefaultModule(module) {
3952
+ const moduleName = typeof module === "string" ? module : module.name;
3953
+ this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
3954
+ }
3955
+ /**
3956
+ * Register a shader hook
3957
+ * @param hook
3958
+ * @param opts
3959
+ */
3960
+ addShaderHook(hook, opts) {
3961
+ if (opts) {
3962
+ hook = Object.assign(opts, {
3963
+ hook
3964
+ });
3965
+ }
3966
+ this._hookFunctions.push(hook);
3967
+ }
3968
+ /**
3969
+ * Assemble a pair of shaders into a single shader program
3970
+ * @param platformInfo
3971
+ * @param props
3972
+ * @returns
3973
+ */
3974
+ assembleShaders(platformInfo, props) {
3975
+ const modules = this._getModuleList(props.modules);
3976
+ const hookFunctions = this._hookFunctions;
3977
+ const options = selectShaders(platformInfo, props);
3978
+ const assembled = assembleShaders(platformInfo, {
3979
+ ...options,
3980
+ modules,
3981
+ hookFunctions
3982
+ });
3983
+ return assembled;
3984
+ }
3985
+ /**
3986
+ * Dedupe and combine with default modules
3987
+ */
3988
+ _getModuleList(appModules = []) {
3989
+ const modules = new Array(this._defaultModules.length + appModules.length);
3990
+ const seen = {};
3991
+ let count = 0;
3992
+ for (let i = 0, len = this._defaultModules.length; i < len; ++i) {
3993
+ const module = this._defaultModules[i];
3994
+ const name2 = module.name;
3995
+ modules[count++] = module;
3996
+ seen[name2] = true;
3997
+ }
3998
+ for (let i = 0, len = appModules.length; i < len; ++i) {
3999
+ const module = appModules[i];
4000
+ const name2 = module.name;
4001
+ if (!seen[name2]) {
4002
+ modules[count++] = module;
4003
+ seen[name2] = true;
4004
+ }
4005
+ }
4006
+ modules.length = count;
4007
+ return modules;
4008
+ }
4009
+ };
4010
+
3882
4011
  // ../shadertools/src/lib/glsl-utils/get-shader-info.ts
3883
4012
  function getShaderInfo(source, defaultName) {
3884
4013
  return {
@@ -5850,87 +5979,176 @@ void main() {
5850
5979
  return result;
5851
5980
  }
5852
5981
 
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: {}
5982
+ // src/geometry/gpu-geometry.ts
5983
+ var GPUGeometry = class {
5984
+ userData = {};
5985
+ /** Determines how vertices are read from the 'vertex' attributes */
5986
+ bufferLayout = [];
5987
+ constructor(props) {
5988
+ this.id = props.id || uid("geometry");
5989
+ this.topology = props.topology;
5990
+ this.indices = props.indices || null;
5991
+ this.attributes = props.attributes;
5992
+ this.vertexCount = props.vertexCount;
5993
+ this.bufferLayout = props.bufferLayout || [];
5994
+ if (!this.bufferLayout.find((layout) => layout.name === "positions")) {
5995
+ this.bufferLayout.push({
5996
+ name: "positions",
5997
+ format: "float32x3"
5998
+ });
5999
+ }
6000
+ if (this.attributes.normals && !this.bufferLayout.find((layout) => layout.name === "normals")) {
6001
+ this.bufferLayout.push({
6002
+ name: "normals",
6003
+ format: "float32x3"
6004
+ });
6005
+ }
6006
+ if (this.attributes.texCoords && !this.bufferLayout.find((layout) => layout.name === "texCoords")) {
6007
+ this.bufferLayout.push({
6008
+ name: "texCoords",
6009
+ format: "float32x2"
6010
+ });
6011
+ }
6012
+ if (this.attributes.colors && !this.bufferLayout.find((layout) => layout.name === "colors")) {
6013
+ this.bufferLayout.push({
6014
+ name: "colors",
6015
+ format: "float32x3"
6016
+ });
6017
+ }
6018
+ if (this.indices) {
6019
+ assert2(this.indices.usage === Buffer2.INDEX);
6020
+ }
6021
+ }
6022
+ destroy() {
6023
+ this.indices.destroy();
6024
+ this.attributes.positions.destroy();
6025
+ this.attributes.normals.destroy();
6026
+ this.attributes.texCoords.destroy();
6027
+ this.attributes.colors?.destroy();
6028
+ }
6029
+ getVertexCount() {
6030
+ return this.vertexCount;
6031
+ }
6032
+ getAttributes() {
6033
+ return this.attributes;
6034
+ }
6035
+ getIndexes() {
6036
+ return this.indices;
6037
+ }
6038
+ _calculateVertexCount(positions) {
6039
+ const vertexCount = positions.byteLength / 12;
6040
+ return vertexCount;
6041
+ }
5867
6042
  };
5868
- var PipelineFactory = class {
5869
- stateHash = 0;
5870
- // Used to change hashing if hooks are modified
6043
+ function makeGPUGeometry(device, geometry) {
6044
+ if (geometry instanceof GPUGeometry) {
6045
+ return geometry;
6046
+ }
6047
+ const indices = getIndexBufferFromGeometry(device, geometry);
6048
+ const {
6049
+ attributes,
6050
+ bufferLayout
6051
+ } = getAttributeBuffersFromGeometry(device, geometry);
6052
+ return new GPUGeometry({
6053
+ topology: geometry.topology || "triangle-list",
6054
+ bufferLayout,
6055
+ vertexCount: geometry.vertexCount,
6056
+ indices,
6057
+ attributes
6058
+ });
6059
+ }
6060
+ function getIndexBufferFromGeometry(device, geometry) {
6061
+ if (!geometry.indices) {
6062
+ return void 0;
6063
+ }
6064
+ const data = geometry.indices.value;
6065
+ assert2(data instanceof Uint16Array || data instanceof Uint32Array, 'attribute array for "indices" must be of integer type');
6066
+ return device.createBuffer({
6067
+ usage: Buffer2.INDEX,
6068
+ data
6069
+ });
6070
+ }
6071
+ function getAttributeBuffersFromGeometry(device, geometry) {
6072
+ const positions = geometry.attributes.positions || geometry.attributes.POSITION;
6073
+ const normals = geometry.attributes.normals || geometry.attributes.NORMAL;
6074
+ const texCoords = geometry.attributes.texCoords || geometry.attributes.TEXCOORD_0;
6075
+ const attributes = {
6076
+ positions: device.createBuffer({
6077
+ data: positions.value,
6078
+ id: "positions-buffer"
6079
+ })
6080
+ };
6081
+ const bufferLayout = [{
6082
+ name: "positions",
6083
+ format: `float32x${positions.size}`
6084
+ }];
6085
+ if (normals) {
6086
+ attributes.normals = device.createBuffer({
6087
+ data: normals.value,
6088
+ id: "normals-buffer"
6089
+ });
6090
+ bufferLayout.push({
6091
+ name: "normals",
6092
+ format: `float32x${normals.size}`
6093
+ });
6094
+ }
6095
+ if (texCoords) {
6096
+ attributes.texCoords = device.createBuffer({
6097
+ data: texCoords.value,
6098
+ id: "texCoords-buffer"
6099
+ });
6100
+ bufferLayout.push({
6101
+ name: "texCoords",
6102
+ format: `float32x${texCoords.size}`
6103
+ });
6104
+ }
6105
+ const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
6106
+ return {
6107
+ attributes,
6108
+ bufferLayout,
6109
+ vertexCount
6110
+ };
6111
+ }
6112
+
6113
+ // src/lib/pipeline-factory.ts
6114
+ var _PipelineFactory = class {
5871
6115
  _hashCounter = 0;
5872
6116
  _hashes = {};
5873
6117
  _useCounts = {};
5874
6118
  _pipelineCache = {};
5875
- _getUniforms = {};
5876
- _hookFunctions = [];
5877
- _defaultModules = [];
5878
- // private readonly _registeredModules = {}; // TODO: Remove? This isn't used anywhere in luma.gl
5879
6119
  static getDefaultPipelineFactory(device) {
5880
- device.defaultPipelineFactory = device.defaultPipelineFactory || new PipelineFactory(device);
5881
- return device.defaultPipelineFactory;
6120
+ device._lumaData.defaultPipelineFactory = device._lumaData.defaultPipelineFactory || new _PipelineFactory(device);
6121
+ return device._lumaData.defaultPipelineFactory;
5882
6122
  }
5883
6123
  constructor(device) {
5884
6124
  this.device = device;
5885
6125
  }
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
6126
  createRenderPipeline(options) {
5907
6127
  const props = {
5908
- ...DEFAULT_RENDER_PIPELINE_OPTIONS,
6128
+ ..._PipelineFactory.defaultProps,
5909
6129
  ...options
5910
6130
  };
5911
- const modules = this._getModuleList(props.modules);
5912
6131
  const hash = this._hashRenderPipeline({
5913
- ...props,
5914
- modules
6132
+ ...props
5915
6133
  });
5916
6134
  if (!this._pipelineCache[hash]) {
5917
- const {
5918
- pipeline,
5919
- getUniforms
5920
- } = this._createRenderPipeline({
6135
+ const pipeline = this.device.createRenderPipeline({
5921
6136
  ...props,
5922
- modules
6137
+ vs: this.device.createShader({
6138
+ stage: "vertex",
6139
+ source: props.vs
6140
+ }),
6141
+ fs: props.fs ? this.device.createShader({
6142
+ stage: "fragment",
6143
+ source: props.fs
6144
+ }) : null
5923
6145
  });
5924
6146
  pipeline.hash = hash;
5925
6147
  this._pipelineCache[hash] = pipeline;
5926
- this._getUniforms[hash] = getUniforms || ((x) => ({}));
5927
6148
  this._useCounts[hash] = 0;
5928
6149
  }
5929
6150
  this._useCounts[hash]++;
5930
- return {
5931
- pipeline: this._pipelineCache[hash],
5932
- getUniforms: this._getUniforms[hash]
5933
- };
6151
+ return this._pipelineCache[hash];
5934
6152
  }
5935
6153
  release(pipeline) {
5936
6154
  const hash = pipeline.hash;
@@ -5938,70 +6156,35 @@ void main() {
5938
6156
  if (this._useCounts[hash] === 0) {
5939
6157
  this._pipelineCache[hash].destroy();
5940
6158
  delete this._pipelineCache[hash];
5941
- delete this._getUniforms[hash];
5942
6159
  delete this._useCounts[hash];
5943
6160
  }
5944
6161
  }
5945
- getUniforms(pipeline) {
5946
- return this._getUniforms[pipeline.hash] || null;
5947
- }
5948
6162
  // PRIVATE
5949
6163
  _createRenderPipeline(props) {
5950
- const platformInfo = {
5951
- gpu: this.device.info.gpu,
5952
- features: this.device.features
5953
- };
5954
6164
  if (!props.fs) {
5955
6165
  throw new Error("fs");
5956
6166
  }
5957
- const assembled = assembleShaders(platformInfo, {
5958
- ...props,
5959
- fs: props.fs,
5960
- hookFunctions: this._hookFunctions
5961
- });
5962
6167
  const pipeline = this.device.createRenderPipeline({
5963
6168
  ...props,
5964
6169
  vs: this.device.createShader({
5965
6170
  stage: "vertex",
5966
- source: assembled.vs
6171
+ source: props.vs
5967
6172
  }),
5968
- fs: assembled.fs ? this.device.createShader({
6173
+ fs: props.fs ? this.device.createShader({
5969
6174
  stage: "fragment",
5970
- source: assembled.fs
6175
+ source: props.fs
5971
6176
  }) : null
5972
6177
  });
5973
- return {
5974
- pipeline,
5975
- getUniforms: assembled.getUniforms
5976
- };
6178
+ return pipeline;
5977
6179
  }
5978
6180
  /** Calculate a hash based on all the inputs for a render pipeline */
5979
6181
  _hashRenderPipeline(props) {
5980
- const {
5981
- modules = [],
5982
- varyings = [],
5983
- defines = {},
5984
- inject = {},
5985
- parameters = {}
5986
- } = props;
5987
6182
  const vsHash = this._getHash(props.vs);
5988
6183
  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}`;
6184
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
6185
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
6186
+ const varyingHash = "-";
6187
+ return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}}`;
6005
6188
  }
6006
6189
  _getHash(key) {
6007
6190
  if (this._hashes[key] === void 0) {
@@ -6009,116 +6192,76 @@ void main() {
6009
6192
  }
6010
6193
  return this._hashes[key];
6011
6194
  }
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;
6029
- }
6030
- }
6031
- modules.length = count;
6032
- return modules;
6033
- }
6034
6195
  };
6196
+ var PipelineFactory = _PipelineFactory;
6197
+ __publicField(PipelineFactory, "defaultProps", {
6198
+ ...RenderPipeline.defaultProps,
6199
+ vs: void 0,
6200
+ fs: void 0
6201
+ });
6035
6202
 
6036
6203
  // 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 */
6204
+ var _Model = class {
6055
6205
  userData = {};
6056
- // readonly props: Required<ModelProps>;
6206
+ // Fixed properties (change can trigger pipeline rebuild)
6207
+ /** The render pipeline GPU parameters, depth testing etc */
6208
+ /** The primitive topology */
6209
+ /** Buffer layout */
6210
+ // Dynamic properties
6057
6211
  /** Vertex count */
6058
6212
  /** instance count */
6059
6213
  instanceCount = 0;
6214
+ /** Index buffer */
6215
+ indices = null;
6060
6216
  /** Buffer-valued attributes */
6061
6217
  bufferAttributes = {};
6062
6218
  /** Constant-valued attributes */
6063
6219
  constantAttributes = {};
6064
6220
  /** Bindings (textures, samplers, uniform buffers) */
6065
6221
  bindings = {};
6066
- /** Uniforms */
6222
+ /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
6067
6223
  uniforms = {};
6224
+ /** The underlying GPU "program". @note May be recreated if parameters change */
6225
+ _pipelineNeedsUpdate = "newly created";
6068
6226
  constructor(device, props) {
6069
- props = {
6070
- ...DEFAULT_MODEL_PROPS,
6227
+ this.props = {
6228
+ ..._Model.defaultProps,
6071
6229
  ...props
6072
6230
  };
6073
- this.id = props.id;
6231
+ props = this.props;
6232
+ this.id = props.id || uid("model");
6074
6233
  this.device = device;
6075
6234
  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);
6235
+ const platformInfo = {
6236
+ type: device.info.type,
6237
+ shaderLanguage: device.info.shadingLanguages[0],
6238
+ gpu: device.info.gpu,
6239
+ features: device.features
6240
+ };
6091
6241
  const {
6092
- pipeline,
6242
+ vs,
6243
+ fs,
6093
6244
  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;
6245
+ } = this.props.shaderAssembler.assembleShaders(platformInfo, this.props);
6246
+ this.vs = vs;
6247
+ this.fs = fs;
6104
6248
  this._getModuleUniforms = getUniforms;
6249
+ this.vertexCount = this.props.vertexCount;
6250
+ this.instanceCount = this.props.instanceCount;
6251
+ this.topology = this.props.topology;
6252
+ this.bufferLayout = this.props.bufferLayout;
6253
+ this.parameters = this.props.parameters;
6105
6254
  if (props.geometry) {
6106
- this._setGeometry(props.geometry);
6255
+ this.setGeometry(props.geometry);
6256
+ }
6257
+ this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
6258
+ this.pipeline = this._updatePipeline();
6259
+ if (props.vertexCount) {
6260
+ this.setVertexCount(props.vertexCount);
6261
+ }
6262
+ if (props.instanceCount) {
6263
+ this.setInstanceCount(props.instanceCount);
6107
6264
  }
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
6265
  if (props.indices) {
6123
6266
  this.setIndexBuffer(props.indices);
6124
6267
  }
@@ -6134,59 +6277,197 @@ void main() {
6134
6277
  if (props.moduleSettings) {
6135
6278
  this.updateModuleSettings(props.moduleSettings);
6136
6279
  }
6280
+ this.setUniforms(this._getModuleUniforms());
6281
+ Object.seal(this);
6137
6282
  }
6138
- updateModuleSettings(props) {
6283
+ destroy() {
6284
+ this.pipelineFactory.release(this.pipeline);
6285
+ }
6286
+ // Draw call
6287
+ draw(renderPass) {
6288
+ this.pipeline = this._updatePipeline();
6289
+ this.pipeline.setIndexBuffer(this.indices);
6290
+ this.pipeline.setAttributes(this.bufferAttributes);
6291
+ this.pipeline.setConstantAttributes(this.constantAttributes);
6292
+ this.pipeline.setBindings(this.bindings);
6293
+ this.pipeline.setUniforms(this.uniforms);
6294
+ this.pipeline.draw({
6295
+ renderPass,
6296
+ vertexCount: this.vertexCount,
6297
+ instanceCount: this.instanceCount
6298
+ });
6299
+ }
6300
+ // Update fixed fields (can trigger pipeline rebuild)
6301
+ /**
6302
+ * Updates the optional geometry
6303
+ * Geometry, sets several attributes, indices, and also vertex count and topology
6304
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
6305
+ */
6306
+ setGeometry(geometry) {
6307
+ const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
6308
+ this.setTopology(gpuGeometry.topology || "triangle-list");
6309
+ this.bufferLayout = mergeBufferLayouts(this.bufferLayout, gpuGeometry.bufferLayout);
6310
+ this.vertexCount = gpuGeometry.vertexCount;
6311
+ this.setAttributes(gpuGeometry.attributes);
6312
+ this.setIndexBuffer(gpuGeometry.indices);
6313
+ }
6314
+ /**
6315
+ * Updates the primitive topology ('triangle-list', 'triangle-strip' etc).
6316
+ * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
6317
+ */
6318
+ setTopology(topology) {
6319
+ if (topology !== this.topology) {
6320
+ this.topology = topology;
6321
+ if (this.device.info.type === "webgpu") {
6322
+ this._setPipelineNeedsUpdate("topology");
6323
+ }
6324
+ }
6325
+ }
6326
+ /**
6327
+ * Updates the buffer layout.
6328
+ * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
6329
+ */
6330
+ setBufferLayout(bufferLayout) {
6331
+ if (bufferLayout !== this.bufferLayout) {
6332
+ this.bufferLayout = bufferLayout;
6333
+ if (this.device.info.type === "webgpu") {
6334
+ this._setPipelineNeedsUpdate("bufferLayout");
6335
+ }
6336
+ }
6337
+ }
6338
+ /**
6339
+ * Set GPU parameters.
6340
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch.
6341
+ * @param parameters
6342
+ */
6343
+ setParameters(parameters) {
6344
+ if (!deepEqual(parameters, this.parameters, 2)) {
6345
+ this.parameters = parameters;
6346
+ if (this.device.info.type === "webgpu") {
6347
+ this._setPipelineNeedsUpdate("parameters");
6348
+ }
6349
+ }
6350
+ }
6351
+ // Update dynamic fields
6352
+ /**
6353
+ * Updates the vertex count (used in draw calls)
6354
+ * @note Any attributes with stepMode=vertex need to be at least this big
6355
+ */
6356
+ setVertexCount(vertexCount) {
6357
+ this.vertexCount = vertexCount;
6358
+ }
6359
+ /**
6360
+ * Updates the instance count (used in draw calls)
6361
+ * @note Any attributes with stepMode=instance need to be at least this big
6362
+ */
6363
+ setInstanceCount(instanceCount) {
6364
+ this.instanceCount = instanceCount;
6365
+ }
6366
+ /**
6367
+ * Updates shader module settings (which results in uniforms being set)
6368
+ */
6369
+ setShaderModuleProps(props) {
6139
6370
  const uniforms = this._getModuleUniforms(props);
6140
- this.setUniforms(uniforms);
6371
+ Object.assign(this.uniforms, uniforms);
6372
+ }
6373
+ /**
6374
+ * @deprecated Updates shader module settings (which results in uniforms being set)
6375
+ */
6376
+ updateModuleSettings(props) {
6377
+ this.setShaderModuleProps(props);
6141
6378
  }
6379
+ /**
6380
+ * Sets the index buffer
6381
+ * @todo - how to unset it if we change geometry?
6382
+ */
6142
6383
  setIndexBuffer(indices) {
6143
- this.pipeline.setIndexBuffer(indices);
6384
+ this.indices = indices;
6144
6385
  }
6386
+ /**
6387
+ * Sets attributes (buffers)
6388
+ * @note Overrides any attributes previously set with the same name
6389
+ */
6145
6390
  setAttributes(bufferAttributes) {
6146
6391
  if (bufferAttributes.indices) {
6147
6392
  log.warn(`Model:${this.id} setAttributes() - indices should be set using setIndexBuffer()`);
6148
6393
  }
6149
- this.pipeline.setAttributes(bufferAttributes);
6150
6394
  Object.assign(this.bufferAttributes, bufferAttributes);
6151
6395
  }
6396
+ /**
6397
+ * Sets constant attributes
6398
+ * @note Overrides any attributes previously set with the same name
6399
+ * @param constantAttributes
6400
+ */
6152
6401
  setConstantAttributes(constantAttributes) {
6153
- this.pipeline.setConstantAttributes(constantAttributes);
6154
6402
  Object.assign(this.constantAttributes, constantAttributes);
6155
6403
  }
6156
- /** Set the bindings */
6404
+ /**
6405
+ * Sets bindings (textures, samplers, uniform buffers)
6406
+ */
6157
6407
  setBindings(bindings) {
6158
- this.pipeline.setBindings(bindings);
6159
6408
  Object.assign(this.bindings, bindings);
6160
6409
  }
6410
+ /**
6411
+ * Sets individual uniforms
6412
+ * @deprecated WebGL only, use uniform buffers for portability
6413
+ * @param uniforms
6414
+ * @returns self for chaining
6415
+ */
6161
6416
  setUniforms(uniforms) {
6162
6417
  this.pipeline.setUniforms(uniforms);
6163
6418
  Object.assign(this.uniforms, uniforms);
6164
6419
  }
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);
6420
+ _setPipelineNeedsUpdate(reason) {
6421
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
6422
+ }
6423
+ _updatePipeline() {
6424
+ if (this._pipelineNeedsUpdate) {
6425
+ log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
6426
+ this._pipelineNeedsUpdate = false;
6427
+ this.pipeline = this.device.createRenderPipeline({
6428
+ ...this.props,
6429
+ bufferLayout: this.bufferLayout,
6430
+ topology: this.topology,
6431
+ parameters: this.parameters,
6432
+ vs: this.device.createShader({
6433
+ stage: "vertex",
6434
+ source: this.vs
6435
+ }),
6436
+ fs: this.fs ? this.device.createShader({
6437
+ stage: "fragment",
6438
+ source: this.fs
6439
+ }) : null
6440
+ });
6171
6441
  }
6442
+ return this.pipeline;
6172
6443
  }
6173
6444
  };
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");
6445
+ var Model = _Model;
6446
+ __publicField(Model, "defaultProps", {
6447
+ ...RenderPipeline.defaultProps,
6448
+ vs: null,
6449
+ fs: null,
6450
+ id: "unnamed",
6451
+ handle: void 0,
6452
+ userData: {},
6453
+ defines: {},
6454
+ modules: [],
6455
+ moduleSettings: {},
6456
+ geometry: null,
6457
+ pipelineFactory: void 0,
6458
+ shaderAssembler: ShaderAssembler.getDefaultShaderAssembler()
6459
+ });
6460
+ function mergeBufferLayouts(layouts1, layouts2) {
6461
+ const layouts = [...layouts1];
6462
+ for (const attribute of layouts2) {
6463
+ const index = layouts.findIndex((attribute2) => attribute2.name === attribute.name);
6464
+ if (index < 0) {
6465
+ layouts.push(attribute);
6466
+ } else {
6467
+ layouts[index] = attribute;
6468
+ }
6189
6469
  }
6470
+ return layouts;
6190
6471
  }
6191
6472
 
6192
6473
  // ../constants/src/constants-enum.ts
@@ -12488,34 +12769,34 @@ ${formattedLog}`)();
12488
12769
  // ../webgl/src/adapter/helpers/set-uniform.ts
12489
12770
  function setUniform(gl, location, type, value) {
12490
12771
  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;
12772
+ let uniformValue = value;
12773
+ if (uniformValue === true) {
12774
+ uniformValue = 1;
12775
+ }
12776
+ if (uniformValue === false) {
12777
+ uniformValue = 0;
12778
+ }
12779
+ const arrayValue = typeof uniformValue === "number" ? [uniformValue] : uniformValue;
12518
12780
  switch (type) {
12781
+ case GL.SAMPLER_2D:
12782
+ case GL.SAMPLER_CUBE:
12783
+ case GL.SAMPLER_3D:
12784
+ case GL.SAMPLER_2D_SHADOW:
12785
+ case GL.SAMPLER_2D_ARRAY:
12786
+ case GL.SAMPLER_2D_ARRAY_SHADOW:
12787
+ case GL.SAMPLER_CUBE_SHADOW:
12788
+ case GL.INT_SAMPLER_2D:
12789
+ case GL.INT_SAMPLER_3D:
12790
+ case GL.INT_SAMPLER_CUBE:
12791
+ case GL.INT_SAMPLER_2D_ARRAY:
12792
+ case GL.UNSIGNED_INT_SAMPLER_2D:
12793
+ case GL.UNSIGNED_INT_SAMPLER_3D:
12794
+ case GL.UNSIGNED_INT_SAMPLER_CUBE:
12795
+ case GL.UNSIGNED_INT_SAMPLER_2D_ARRAY:
12796
+ if (typeof value !== "number") {
12797
+ throw new Error("samplers must be set to integers");
12798
+ }
12799
+ return gl.uniform1i(location, value);
12519
12800
  case GL.FLOAT:
12520
12801
  return gl.uniform1fv(location, arrayValue);
12521
12802
  case GL.FLOAT_VEC2:
@@ -13826,7 +14107,10 @@ ${formattedLog}`)();
13826
14107
  getVertexCount() {
13827
14108
  return this.vertexCount;
13828
14109
  }
13829
- // Return an object with all attributes plus indices added as a field.
14110
+ /**
14111
+ * Return an object with all attributes plus indices added as a field.
14112
+ * TODO Geometry types are a mess
14113
+ */
13830
14114
  getAttributes() {
13831
14115
  return this.indices ? {
13832
14116
  indices: this.indices,
@@ -13837,11 +14121,17 @@ ${formattedLog}`)();
13837
14121
  _print(attributeName) {
13838
14122
  return `Geometry ${this.id} attribute ${attributeName}`;
13839
14123
  }
13840
- // GeometryAttribute
13841
- // value: typed array
13842
- // type: indices, vertices, uvs
13843
- // size: elements per vertex
13844
- // target: WebGL buffer type (string or constant)
14124
+ /**
14125
+ * GeometryAttribute
14126
+ * value: typed array
14127
+ * type: indices, vertices, uvs
14128
+ * size: elements per vertex
14129
+ * target: WebGL buffer type (string or constant)
14130
+ *
14131
+ * @param attributes
14132
+ * @param indices
14133
+ * @returns
14134
+ */
13845
14135
  _setAttributes(attributes, indices) {
13846
14136
  return this;
13847
14137
  }
@@ -13850,8 +14140,7 @@ ${formattedLog}`)();
13850
14140
  return indices.value.length;
13851
14141
  }
13852
14142
  let vertexCount = Infinity;
13853
- for (const attributeName in attributes) {
13854
- const attribute = attributes[attributeName];
14143
+ for (const attribute of Object.values(attributes)) {
13855
14144
  const {
13856
14145
  value,
13857
14146
  size,