@luma.gl/engine 9.0.0-beta.4 → 9.0.0-beta.6

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 (149) hide show
  1. package/dist/animation/key-frames.js +54 -54
  2. package/dist/animation/timeline.d.ts.map +1 -1
  3. package/dist/animation/timeline.js +95 -100
  4. package/dist/animation-loop/animation-loop-template.d.ts +1 -1
  5. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
  6. package/dist/animation-loop/animation-loop-template.js +19 -5
  7. package/dist/animation-loop/animation-loop.d.ts +2 -2
  8. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-loop.js +433 -356
  10. package/dist/animation-loop/animation-props.d.ts +2 -2
  11. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  12. package/dist/animation-loop/animation-props.js +0 -1
  13. package/dist/animation-loop/make-animation-loop.d.ts +2 -2
  14. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  15. package/dist/animation-loop/make-animation-loop.js +28 -24
  16. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  17. package/dist/debug/copy-texture-to-image.js +41 -42
  18. package/dist/debug/debug-framebuffer.d.ts.map +1 -1
  19. package/dist/debug/debug-framebuffer.js +43 -40
  20. package/dist/debug/debug-shader-layout.js +24 -25
  21. package/dist/debug/pixel-data-utils.d.ts.map +1 -1
  22. package/dist/debug/pixel-data-utils.js +34 -36
  23. package/dist/dist.dev.js +3873 -8643
  24. package/dist/geometries/cone-geometry.d.ts +1 -1
  25. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  26. package/dist/geometries/cone-geometry.js +11 -17
  27. package/dist/geometries/cube-geometry.d.ts +1 -1
  28. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  29. package/dist/geometries/cube-geometry.js +190 -61
  30. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  31. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  32. package/dist/geometries/cylinder-geometry.js +9 -14
  33. package/dist/geometries/ico-sphere-geometry.d.ts +1 -1
  34. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  35. package/dist/geometries/ico-sphere-geometry.js +141 -160
  36. package/dist/geometries/plane-geometry.d.ts +1 -1
  37. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  38. package/dist/geometries/plane-geometry.js +92 -110
  39. package/dist/geometries/sphere-geometry.d.ts +1 -1
  40. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  41. package/dist/geometries/sphere-geometry.js +76 -95
  42. package/dist/geometries/truncated-cone-geometry.d.ts +1 -1
  43. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  44. package/dist/geometries/truncated-cone-geometry.js +99 -117
  45. package/dist/geometry/geometry-table.d.ts.map +1 -1
  46. package/dist/geometry/geometry-table.js +3 -1
  47. package/dist/geometry/geometry-utils.js +35 -32
  48. package/dist/geometry/geometry.d.ts.map +1 -1
  49. package/dist/geometry/geometry.js +80 -71
  50. package/dist/geometry/gpu-geometry.d.ts +1 -1
  51. package/dist/geometry/gpu-geometry.d.ts.map +1 -1
  52. package/dist/geometry/gpu-geometry.js +80 -99
  53. package/dist/geometry/gpu-table.js +41 -1
  54. package/dist/index.cjs +241 -206
  55. package/dist/index.cjs.map +7 -0
  56. package/dist/index.d.ts +41 -40
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +5 -1
  59. package/dist/lib/clip-space.d.ts +1 -1
  60. package/dist/lib/clip-space.d.ts.map +1 -1
  61. package/dist/lib/clip-space.js +23 -28
  62. package/dist/lib/pipeline-factory.d.ts +1 -5
  63. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  64. package/dist/lib/pipeline-factory.js +64 -68
  65. package/dist/lib/shader-factory.d.ts +17 -0
  66. package/dist/lib/shader-factory.d.ts.map +1 -0
  67. package/dist/lib/shader-factory.js +44 -0
  68. package/dist/model/model.d.ts +22 -10
  69. package/dist/model/model.d.ts.map +1 -1
  70. package/dist/model/model.js +562 -410
  71. package/dist/scenegraph/group-node.d.ts +1 -1
  72. package/dist/scenegraph/group-node.d.ts.map +1 -1
  73. package/dist/scenegraph/group-node.js +73 -83
  74. package/dist/scenegraph/model-node.d.ts +2 -2
  75. package/dist/scenegraph/model-node.d.ts.map +1 -1
  76. package/dist/scenegraph/model-node.js +31 -24
  77. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
  78. package/dist/scenegraph/scenegraph-node.js +136 -124
  79. package/dist/shader-inputs.d.ts.map +1 -1
  80. package/dist/shader-inputs.js +99 -58
  81. package/dist/transform/buffer-transform.d.ts +1 -1
  82. package/dist/transform/buffer-transform.d.ts.map +1 -1
  83. package/dist/transform/buffer-transform.js +65 -57
  84. package/dist/transform/texture-transform.d.ts +1 -1
  85. package/dist/transform/texture-transform.d.ts.map +1 -1
  86. package/dist/transform/texture-transform.js +109 -114
  87. package/dist.min.js +2 -272
  88. package/package.json +10 -9
  89. package/src/animation/timeline.ts +20 -20
  90. package/src/animation-loop/animation-loop-template.ts +10 -8
  91. package/src/animation-loop/animation-loop.ts +20 -10
  92. package/src/animation-loop/animation-props.ts +1 -1
  93. package/src/animation-loop/make-animation-loop.ts +17 -8
  94. package/src/debug/copy-texture-to-image.ts +8 -6
  95. package/src/debug/debug-framebuffer.ts +16 -3
  96. package/src/debug/debug-shader-layout.ts +1 -1
  97. package/src/debug/pixel-data-utils.ts +3 -6
  98. package/src/geometries/cube-geometry.ts +17 -13
  99. package/src/geometries/ico-sphere-geometry.ts +1 -1
  100. package/src/geometries/plane-geometry.ts +1 -1
  101. package/src/geometries/sphere-geometry.ts +1 -1
  102. package/src/geometries/truncated-cone-geometry.ts +2 -1
  103. package/src/geometry/geometry-table.ts +9 -6
  104. package/src/geometry/geometry-utils.ts +1 -1
  105. package/src/geometry/geometry.ts +9 -6
  106. package/src/geometry/gpu-geometry.ts +14 -6
  107. package/src/index.ts +1 -0
  108. package/src/lib/clip-space.ts +14 -18
  109. package/src/lib/pipeline-factory.ts +12 -22
  110. package/src/lib/shader-factory.ts +55 -0
  111. package/src/model/model.ts +74 -42
  112. package/src/scenegraph/group-node.ts +14 -10
  113. package/src/scenegraph/model-node.ts +2 -2
  114. package/src/scenegraph/scenegraph-node.ts +2 -2
  115. package/src/shader-inputs.ts +19 -12
  116. package/src/transform/buffer-transform.ts +16 -8
  117. package/src/transform/texture-transform.ts +14 -15
  118. package/dist/animation/key-frames.js.map +0 -1
  119. package/dist/animation/timeline.js.map +0 -1
  120. package/dist/animation-loop/animation-loop-template.js.map +0 -1
  121. package/dist/animation-loop/animation-loop.js.map +0 -1
  122. package/dist/animation-loop/animation-props.js.map +0 -1
  123. package/dist/animation-loop/make-animation-loop.js.map +0 -1
  124. package/dist/debug/copy-texture-to-image.js.map +0 -1
  125. package/dist/debug/debug-framebuffer.js.map +0 -1
  126. package/dist/debug/debug-shader-layout.js.map +0 -1
  127. package/dist/debug/pixel-data-utils.js.map +0 -1
  128. package/dist/geometries/cone-geometry.js.map +0 -1
  129. package/dist/geometries/cube-geometry.js.map +0 -1
  130. package/dist/geometries/cylinder-geometry.js.map +0 -1
  131. package/dist/geometries/ico-sphere-geometry.js.map +0 -1
  132. package/dist/geometries/plane-geometry.js.map +0 -1
  133. package/dist/geometries/sphere-geometry.js.map +0 -1
  134. package/dist/geometries/truncated-cone-geometry.js.map +0 -1
  135. package/dist/geometry/geometry-table.js.map +0 -1
  136. package/dist/geometry/geometry-utils.js.map +0 -1
  137. package/dist/geometry/geometry.js.map +0 -1
  138. package/dist/geometry/gpu-geometry.js.map +0 -1
  139. package/dist/geometry/gpu-table.js.map +0 -1
  140. package/dist/index.js.map +0 -1
  141. package/dist/lib/clip-space.js.map +0 -1
  142. package/dist/lib/pipeline-factory.js.map +0 -1
  143. package/dist/model/model.js.map +0 -1
  144. package/dist/scenegraph/group-node.js.map +0 -1
  145. package/dist/scenegraph/model-node.js.map +0 -1
  146. package/dist/scenegraph/scenegraph-node.js.map +0 -1
  147. package/dist/shader-inputs.js.map +0 -1
  148. package/dist/transform/buffer-transform.js.map +0 -1
  149. package/dist/transform/texture-transform.js.map +0 -1
@@ -1,440 +1,592 @@
1
- import { Buffer, RenderPipeline, UniformStore, getTypedArrayFromDataType } from '@luma.gl/core';
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ import { Buffer, RenderPipeline, UniformStore } from '@luma.gl/core';
2
5
  import { log, uid, deepEqual, splitUniformsAndBindings, isNumberArray } from '@luma.gl/core';
3
- import { getAttributeInfosFromLayouts } from '@luma.gl/core';
6
+ import { getTypedArrayFromDataType, getAttributeInfosFromLayouts } from '@luma.gl/core';
4
7
  import { ShaderAssembler, getShaderLayoutFromWGSL } from '@luma.gl/shadertools';
5
8
  import { ShaderInputs } from "../shader-inputs.js";
6
9
  import { makeGPUGeometry } from "../geometry/gpu-geometry.js";
7
10
  import { PipelineFactory } from "../lib/pipeline-factory.js";
11
+ import { ShaderFactory } from "../lib/shader-factory.js";
8
12
  import { getDebugTableForShaderLayout } from "../debug/debug-shader-layout.js";
9
13
  import { debugFramebuffer } from "../debug/debug-framebuffer.js";
10
14
  const LOG_DRAW_PRIORITY = 2;
11
15
  const LOG_DRAW_TIMEOUT = 10000;
16
+ /**
17
+ * v9 Model API
18
+ * A model
19
+ * - automatically reuses pipelines (programs) when possible
20
+ * - automatically rebuilds pipelines if necessary to accommodate changed settings
21
+ * shadertools integration
22
+ * - accepts modules and performs shader transpilation
23
+ */
12
24
  export class Model {
13
- constructor(device, props) {
14
- var _this$props$modules, _this$props$modules2, _this$shaderInputs;
15
- this.device = void 0;
16
- this.id = void 0;
17
- this.vs = void 0;
18
- this.fs = void 0;
19
- this.pipelineFactory = void 0;
20
- this.userData = {};
21
- this.parameters = void 0;
22
- this.topology = void 0;
23
- this.bufferLayout = void 0;
24
- this.vertexCount = void 0;
25
- this.instanceCount = 0;
26
- this.indexBuffer = null;
27
- this.bufferAttributes = {};
28
- this.constantAttributes = {};
29
- this.bindings = {};
30
- this.uniforms = {};
31
- this.vertexArray = void 0;
32
- this.transformFeedback = null;
33
- this.pipeline = void 0;
34
- this.shaderInputs = void 0;
35
- this._uniformStore = void 0;
36
- this._pipelineNeedsUpdate = 'newly created';
37
- this._attributeInfos = {};
38
- this._gpuGeometry = null;
39
- this._getModuleUniforms = void 0;
40
- this.props = void 0;
41
- this._lastLogTime = 0;
42
- this._logOpen = false;
43
- this._drawCount = 0;
44
- this.props = {
45
- ...Model.defaultProps,
46
- ...props
25
+ static defaultProps = {
26
+ ...RenderPipeline.defaultProps,
27
+ source: null,
28
+ vs: null,
29
+ fs: null,
30
+ id: 'unnamed',
31
+ handle: undefined,
32
+ userData: {},
33
+ defines: {},
34
+ modules: [],
35
+ moduleSettings: undefined,
36
+ geometry: null,
37
+ indexBuffer: null,
38
+ attributes: {},
39
+ constantAttributes: {},
40
+ varyings: [],
41
+ shaderInputs: undefined,
42
+ pipelineFactory: undefined,
43
+ shaderFactory: undefined,
44
+ transformFeedback: undefined,
45
+ shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(),
46
+ debugShaders: undefined,
47
+ ignoreUnknownAttributes: undefined
47
48
  };
48
- props = this.props;
49
- this.id = props.id || uid('model');
50
- this.device = device;
51
- Object.assign(this.userData, props.userData);
52
- const moduleMap = Object.fromEntries(((_this$props$modules = this.props.modules) === null || _this$props$modules === void 0 ? void 0 : _this$props$modules.map(module => [module.name, module])) || []);
53
- this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
54
- const isWebGPU = this.device.info.type === 'webgpu';
55
- if (this.props.source) {
56
- if (isWebGPU) {
57
- var _this$props;
58
- (_this$props = this.props).shaderLayout || (_this$props.shaderLayout = getShaderLayoutFromWGSL(this.props.source));
59
- }
60
- this.props.fs = this.props.source;
61
- this.props.vs = this.props.source;
62
- }
63
- if (isWebGPU && typeof this.props.vs !== 'string') {
64
- var _this$props2;
65
- (_this$props2 = this.props).shaderLayout || (_this$props2.shaderLayout = getShaderLayoutFromWGSL(this.props.vs.wgsl));
66
- }
67
- const platformInfo = getPlatformInfo(device);
68
- const modules = (((_this$props$modules2 = this.props.modules) === null || _this$props$modules2 === void 0 ? void 0 : _this$props$modules2.length) > 0 ? this.props.modules : (_this$shaderInputs = this.shaderInputs) === null || _this$shaderInputs === void 0 ? void 0 : _this$shaderInputs.getModules()) || [];
69
- const {
70
- vs,
71
- fs,
72
- getUniforms
73
- } = this.props.shaderAssembler.assembleShaders({
74
- platformInfo,
75
- ...this.props,
76
- modules
77
- });
78
- this.vs = vs;
79
- this.fs = fs;
80
- this._getModuleUniforms = getUniforms;
81
- this.vertexCount = this.props.vertexCount;
82
- this.instanceCount = this.props.instanceCount;
83
- this.topology = this.props.topology;
84
- this.bufferLayout = this.props.bufferLayout;
85
- this.parameters = this.props.parameters;
86
- if (props.geometry) {
87
- this._gpuGeometry = this.setGeometry(props.geometry);
88
- }
89
- this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
90
- this.pipeline = this._updatePipeline();
91
- this.vertexArray = device.createVertexArray({
92
- renderPipeline: this.pipeline
93
- });
94
- if (this._gpuGeometry) {
95
- this._setGeometryAttributes(this._gpuGeometry);
96
- }
97
- if (props.vertexCount) {
98
- this.setVertexCount(props.vertexCount);
99
- }
100
- if (props.instanceCount) {
101
- this.setInstanceCount(props.instanceCount);
102
- }
103
- if (props.indices) {
104
- throw new Error('Model.props.indices removed. Use props.indexBuffer');
105
- }
106
- if (props.indexBuffer) {
107
- this.setIndexBuffer(props.indexBuffer);
108
- }
109
- if (props.attributes) {
110
- this.setAttributes(props.attributes);
111
- }
112
- if (props.constantAttributes) {
113
- this.setConstantAttributes(props.constantAttributes);
114
- }
115
- if (props.bindings) {
116
- this.setBindings(props.bindings);
117
- }
118
- if (props.uniforms) {
119
- this.setUniforms(props.uniforms);
120
- }
121
- if (props.moduleSettings) {
122
- log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
123
- this.updateModuleSettings(props.moduleSettings);
124
- }
125
- if (props.transformFeedback) {
126
- this.transformFeedback = props.transformFeedback;
127
- }
128
- Object.seal(this);
129
- }
130
- destroy() {
131
- this.pipelineFactory.release(this.pipeline);
132
- this._uniformStore.destroy();
133
- }
134
- predraw() {
135
- this.updateShaderInputs();
136
- }
137
- draw(renderPass) {
138
- this.predraw();
139
- try {
140
- this._logDrawCallStart();
141
- this.pipeline = this._updatePipeline();
142
- this.pipeline.setBindings(this.bindings);
143
- this.pipeline.setUniforms(this.uniforms);
144
- const {
145
- indexBuffer
146
- } = this.vertexArray;
147
- const indexCount = indexBuffer ? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2) : undefined;
148
- this.pipeline.draw({
149
- renderPass,
150
- vertexArray: this.vertexArray,
151
- vertexCount: this.vertexCount,
152
- instanceCount: this.instanceCount,
153
- indexCount,
154
- transformFeedback: this.transformFeedback
155
- });
156
- } finally {
157
- this._logDrawCallEnd();
158
- }
159
- this._logFramebuffer(renderPass);
160
- }
161
- setGeometry(geometry) {
162
- const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
163
- this.setTopology(gpuGeometry.topology || 'triangle-list');
164
- this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout);
165
- if (this.vertexArray) {
166
- this._setGeometryAttributes(gpuGeometry);
167
- }
168
- return gpuGeometry;
169
- }
170
- _setGeometryAttributes(gpuGeometry) {
171
- const attributes = {
172
- ...gpuGeometry.attributes
173
- };
174
- for (const [attributeName] of Object.entries(attributes)) {
175
- if (!this.pipeline.shaderLayout.attributes.find(layout => layout.name === attributeName) && attributeName !== 'positions') {
176
- delete attributes[attributeName];
177
- }
178
- }
179
- this.vertexCount = gpuGeometry.vertexCount;
180
- this.setIndexBuffer(gpuGeometry.indices);
181
- this.setAttributes(gpuGeometry.attributes, 'ignore-unknown');
182
- this.setAttributes(attributes);
183
- }
184
- setTopology(topology) {
185
- if (topology !== this.topology) {
186
- this.topology = topology;
187
- this._setPipelineNeedsUpdate('topology');
188
- }
189
- }
190
- setBufferLayout(bufferLayout) {
191
- this.bufferLayout = this._gpuGeometry ? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout) : bufferLayout;
192
- this._setPipelineNeedsUpdate('bufferLayout');
193
- this.pipeline = this._updatePipeline();
194
- this.vertexArray = this.device.createVertexArray({
195
- renderPipeline: this.pipeline
196
- });
197
- if (this._gpuGeometry) {
198
- this._setGeometryAttributes(this._gpuGeometry);
199
- }
200
- }
201
- setParameters(parameters) {
202
- if (!deepEqual(parameters, this.parameters, 2)) {
203
- this.parameters = parameters;
204
- this._setPipelineNeedsUpdate('parameters');
205
- }
206
- }
207
- setVertexCount(vertexCount) {
208
- this.vertexCount = vertexCount;
209
- }
210
- setInstanceCount(instanceCount) {
211
- this.instanceCount = instanceCount;
212
- }
213
- setShaderInputs(shaderInputs) {
214
- this.shaderInputs = shaderInputs;
215
- this._uniformStore = new UniformStore(this.shaderInputs.modules);
216
- for (const moduleName of Object.keys(this.shaderInputs.modules)) {
217
- const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
218
- this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
219
- }
220
- }
221
- setShaderModuleProps(props) {
222
- const uniforms = this._getModuleUniforms(props);
223
- const keys = Object.keys(uniforms).filter(k => {
224
- const uniform = uniforms[k];
225
- return !isNumberArray(uniform) && typeof uniform !== 'number' && typeof uniform !== 'boolean';
226
- });
227
- const bindings = {};
228
- for (const k of keys) {
229
- bindings[k] = uniforms[k];
230
- delete uniforms[k];
49
+ device;
50
+ id;
51
+ vs;
52
+ fs;
53
+ pipelineFactory;
54
+ shaderFactory;
55
+ userData = {};
56
+ // Fixed properties (change can trigger pipeline rebuild)
57
+ /** The render pipeline GPU parameters, depth testing etc */
58
+ parameters;
59
+ /** The primitive topology */
60
+ topology;
61
+ /** Buffer layout */
62
+ bufferLayout;
63
+ // Dynamic properties
64
+ /** Vertex count */
65
+ vertexCount;
66
+ /** instance count */
67
+ instanceCount = 0;
68
+ /** Index buffer */
69
+ indexBuffer = null;
70
+ /** Buffer-valued attributes */
71
+ bufferAttributes = {};
72
+ /** Constant-valued attributes */
73
+ constantAttributes = {};
74
+ /** Bindings (textures, samplers, uniform buffers) */
75
+ bindings = {};
76
+ /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
77
+ uniforms = {};
78
+ /**
79
+ * VertexArray
80
+ * @note not implemented: if bufferLayout is updated, vertex array has to be rebuilt!
81
+ * @todo - allow application to define multiple vertex arrays?
82
+ * */
83
+ vertexArray;
84
+ /** TransformFeedback, WebGL 2 only. */
85
+ transformFeedback = null;
86
+ /** The underlying GPU "program". @note May be recreated if parameters change */
87
+ pipeline;
88
+ /** ShaderInputs instance */
89
+ shaderInputs;
90
+ _uniformStore;
91
+ _pipelineNeedsUpdate = 'newly created';
92
+ _attributeInfos = {};
93
+ _gpuGeometry = null;
94
+ _getModuleUniforms;
95
+ props;
96
+ _destroyed = false;
97
+ constructor(device, props) {
98
+ this.props = { ...Model.defaultProps, ...props };
99
+ props = this.props;
100
+ this.id = props.id || uid('model');
101
+ this.device = device;
102
+ Object.assign(this.userData, props.userData);
103
+ // Setup shader module inputs
104
+ const moduleMap = Object.fromEntries(this.props.modules?.map(module => [module.name, module]) || []);
105
+ this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
106
+ const isWebGPU = this.device.info.type === 'webgpu';
107
+ // TODO - hack to support unified WGSL shader
108
+ // TODO - this is wrong, compile a single shader
109
+ if (this.props.source) {
110
+ if (isWebGPU) {
111
+ this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
112
+ }
113
+ this.props.fs = this.props.source;
114
+ this.props.vs = this.props.source;
115
+ }
116
+ // Support WGSL shader layout introspection
117
+ if (isWebGPU && typeof this.props.vs !== 'string') {
118
+ this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.vs.wgsl);
119
+ }
120
+ // Setup shader assembler
121
+ const platformInfo = getPlatformInfo(device);
122
+ // Extract modules from shader inputs if not supplied
123
+ const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
124
+ const { vs, fs, getUniforms } = this.props.shaderAssembler.assembleShaders({
125
+ platformInfo,
126
+ ...this.props,
127
+ modules
128
+ });
129
+ this.vs = vs;
130
+ this.fs = fs;
131
+ this._getModuleUniforms = getUniforms;
132
+ this.vertexCount = this.props.vertexCount;
133
+ this.instanceCount = this.props.instanceCount;
134
+ this.topology = this.props.topology;
135
+ this.bufferLayout = this.props.bufferLayout;
136
+ this.parameters = this.props.parameters;
137
+ // Geometry, if provided, sets topology and vertex cound
138
+ if (props.geometry) {
139
+ this._gpuGeometry = this.setGeometry(props.geometry);
140
+ }
141
+ this.pipelineFactory =
142
+ props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
143
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
144
+ // Create the pipeline
145
+ // @note order is important
146
+ this.pipeline = this._updatePipeline();
147
+ this.vertexArray = device.createVertexArray({
148
+ renderPipeline: this.pipeline
149
+ });
150
+ // Now we can apply geometry attributes
151
+ if (this._gpuGeometry) {
152
+ this._setGeometryAttributes(this._gpuGeometry);
153
+ }
154
+ // Apply any dynamic settings that will not trigger pipeline change
155
+ if (props.vertexCount) {
156
+ this.setVertexCount(props.vertexCount);
157
+ }
158
+ if (props.instanceCount) {
159
+ this.setInstanceCount(props.instanceCount);
160
+ }
161
+ // @ts-expect-error
162
+ if (props.indices) {
163
+ throw new Error('Model.props.indices removed. Use props.indexBuffer');
164
+ }
165
+ if (props.indexBuffer) {
166
+ this.setIndexBuffer(props.indexBuffer);
167
+ }
168
+ if (props.attributes) {
169
+ this.setAttributes(props.attributes, {
170
+ ignoreUnknownAttributes: props.ignoreUnknownAttributes
171
+ });
172
+ }
173
+ if (props.constantAttributes) {
174
+ this.setConstantAttributes(props.constantAttributes);
175
+ }
176
+ if (props.bindings) {
177
+ this.setBindings(props.bindings);
178
+ }
179
+ if (props.uniforms) {
180
+ this.setUniforms(props.uniforms);
181
+ }
182
+ if (props.moduleSettings) {
183
+ log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
184
+ this.updateModuleSettings(props.moduleSettings);
185
+ }
186
+ if (props.transformFeedback) {
187
+ this.transformFeedback = props.transformFeedback;
188
+ }
189
+ // Catch any access to non-standard props
190
+ Object.seal(this);
191
+ }
192
+ destroy() {
193
+ if (this._destroyed)
194
+ return;
195
+ this.pipelineFactory.release(this.pipeline);
196
+ this.shaderFactory.release(this.pipeline.vs);
197
+ this.shaderFactory.release(this.pipeline.fs);
198
+ this._uniformStore.destroy();
199
+ this._destroyed = true;
200
+ }
201
+ // Draw call
202
+ predraw() {
203
+ // Update uniform buffers if needed
204
+ this.updateShaderInputs();
205
+ }
206
+ draw(renderPass) {
207
+ this.predraw();
208
+ try {
209
+ this._logDrawCallStart();
210
+ // Check if the pipeline is invalidated
211
+ // TODO - this is likely the worst place to do this from performance perspective. Perhaps add a predraw()?
212
+ this.pipeline = this._updatePipeline();
213
+ // Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
214
+ // Any caching needs to be done inside the pipeline functions
215
+ this.pipeline.setBindings(this.bindings);
216
+ this.pipeline.setUniformsWebGL(this.uniforms);
217
+ const { indexBuffer } = this.vertexArray;
218
+ const indexCount = indexBuffer
219
+ ? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2)
220
+ : undefined;
221
+ this.pipeline.draw({
222
+ renderPass,
223
+ vertexArray: this.vertexArray,
224
+ vertexCount: this.vertexCount,
225
+ instanceCount: this.instanceCount,
226
+ indexCount,
227
+ transformFeedback: this.transformFeedback
228
+ });
229
+ }
230
+ finally {
231
+ this._logDrawCallEnd();
232
+ }
233
+ this._logFramebuffer(renderPass);
234
+ }
235
+ // Update fixed fields (can trigger pipeline rebuild)
236
+ /**
237
+ * Updates the optional geometry
238
+ * Geometry, set topology and bufferLayout
239
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
240
+ */
241
+ setGeometry(geometry) {
242
+ const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
243
+ this.setTopology(gpuGeometry.topology || 'triangle-list');
244
+ this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout);
245
+ if (this.vertexArray) {
246
+ this._setGeometryAttributes(gpuGeometry);
247
+ }
248
+ return gpuGeometry;
249
+ }
250
+ /**
251
+ * Updates the optional geometry attributes
252
+ * Geometry, sets several attributes, indexBuffer, and also vertex count
253
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU
254
+ */
255
+ _setGeometryAttributes(gpuGeometry) {
256
+ // Filter geometry attribute so that we don't issue warnings for unused attributes
257
+ const attributes = { ...gpuGeometry.attributes };
258
+ for (const [attributeName] of Object.entries(attributes)) {
259
+ if (!this.pipeline.shaderLayout.attributes.find(layout => layout.name === attributeName) &&
260
+ attributeName !== 'positions') {
261
+ delete attributes[attributeName];
262
+ }
263
+ }
264
+ // TODO - delete previous geometry?
265
+ this.vertexCount = gpuGeometry.vertexCount;
266
+ this.setIndexBuffer(gpuGeometry.indices);
267
+ this.setAttributes(gpuGeometry.attributes, { ignoreUnknownAttributes: true });
268
+ this.setAttributes(attributes, { ignoreUnknownAttributes: this.props.ignoreUnknownAttributes });
269
+ }
270
+ /**
271
+ * Updates the primitive topology ('triangle-list', 'triangle-strip' etc).
272
+ * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU
273
+ */
274
+ setTopology(topology) {
275
+ if (topology !== this.topology) {
276
+ this.topology = topology;
277
+ this._setPipelineNeedsUpdate('topology');
278
+ }
231
279
  }
232
- }
233
- updateShaderInputs() {
234
- this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
235
- }
236
- updateModuleSettings(props) {
237
- log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
238
- const {
239
- bindings,
240
- uniforms
241
- } = splitUniformsAndBindings(this._getModuleUniforms(props));
242
- Object.assign(this.bindings, bindings);
243
- Object.assign(this.uniforms, uniforms);
244
- }
245
- setBindings(bindings) {
246
- Object.assign(this.bindings, bindings);
247
- }
248
- setUniforms(uniforms) {
249
- this.pipeline.setUniforms(uniforms);
250
- Object.assign(this.uniforms, uniforms);
251
- }
252
- setIndexBuffer(indexBuffer) {
253
- this.vertexArray.setIndexBuffer(indexBuffer);
254
- }
255
- setTransformFeedback(transformFeedback) {
256
- this.transformFeedback = transformFeedback;
257
- }
258
- setAttributes(buffers, _option) {
259
- if (buffers.indices) {
260
- log.warn(`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`)();
280
+ /**
281
+ * Updates the buffer layout.
282
+ * @note Triggers a pipeline rebuild / pipeline cache fetch
283
+ */
284
+ setBufferLayout(bufferLayout) {
285
+ this.bufferLayout = this._gpuGeometry
286
+ ? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
287
+ : bufferLayout;
288
+ this._setPipelineNeedsUpdate('bufferLayout');
289
+ // Recreate the pipeline
290
+ this.pipeline = this._updatePipeline();
291
+ // vertex array needs to be updated if we update buffer layout,
292
+ // but not if we update parameters
293
+ this.vertexArray = this.device.createVertexArray({
294
+ renderPipeline: this.pipeline
295
+ });
296
+ // Reapply geometry attributes to the new vertex array
297
+ if (this._gpuGeometry) {
298
+ this._setGeometryAttributes(this._gpuGeometry);
299
+ }
261
300
  }
262
- for (const [bufferName, buffer] of Object.entries(buffers)) {
263
- const bufferLayout = this.bufferLayout.find(layout => getAttributeNames(layout).includes(bufferName));
264
- if (!bufferLayout) {
265
- log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
266
- continue;
267
- }
268
- const attributeNames = getAttributeNames(bufferLayout);
269
- let set = false;
270
- for (const attributeName of attributeNames) {
271
- const attributeInfo = this._attributeInfos[attributeName];
272
- if (attributeInfo) {
273
- this.vertexArray.setBuffer(attributeInfo.location, buffer);
274
- set = true;
275
- }
276
- }
277
- if (!set && _option !== 'ignore-unknown') {
278
- log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
279
- }
301
+ /**
302
+ * Set GPU parameters.
303
+ * @note Can trigger a pipeline rebuild / pipeline cache fetch.
304
+ * @param parameters
305
+ */
306
+ setParameters(parameters) {
307
+ if (!deepEqual(parameters, this.parameters, 2)) {
308
+ this.parameters = parameters;
309
+ this._setPipelineNeedsUpdate('parameters');
310
+ }
280
311
  }
281
- }
282
- setConstantAttributes(attributes) {
283
- for (const [attributeName, value] of Object.entries(attributes)) {
284
- const attributeInfo = this._attributeInfos[attributeName];
285
- if (attributeInfo) {
286
- this.vertexArray.setConstant(attributeInfo.location, value);
287
- } else {
288
- log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
289
- }
312
+ // Update dynamic fields
313
+ /**
314
+ * Updates the vertex count (used in draw calls)
315
+ * @note Any attributes with stepMode=vertex need to be at least this big
316
+ */
317
+ setVertexCount(vertexCount) {
318
+ this.vertexCount = vertexCount;
319
+ }
320
+ /**
321
+ * Updates the instance count (used in draw calls)
322
+ * @note Any attributes with stepMode=instance need to be at least this big
323
+ */
324
+ setInstanceCount(instanceCount) {
325
+ this.instanceCount = instanceCount;
326
+ }
327
+ setShaderInputs(shaderInputs) {
328
+ this.shaderInputs = shaderInputs;
329
+ this._uniformStore = new UniformStore(this.shaderInputs.modules);
330
+ // Create uniform buffer bindings for all modules
331
+ for (const moduleName of Object.keys(this.shaderInputs.modules)) {
332
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
333
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
334
+ }
290
335
  }
291
- }
292
- _setPipelineNeedsUpdate(reason) {
293
- this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
294
- }
295
- _updatePipeline() {
296
- if (this._pipelineNeedsUpdate) {
297
- if (this.pipeline) {
298
- log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
299
- }
300
- this._pipelineNeedsUpdate = false;
301
- const vs = this.device.createShader({
302
- id: `${this.id}-vertex`,
303
- stage: 'vertex',
304
- source: this.vs
305
- });
306
- const fs = this.fs ? this.device.createShader({
307
- id: `${this.id}-fragment`,
308
- stage: 'fragment',
309
- source: this.fs
310
- }) : null;
311
- this.pipeline = this.device.createRenderPipeline({
312
- ...this.props,
313
- bufferLayout: this.bufferLayout,
314
- topology: this.topology,
315
- parameters: this.parameters,
316
- vs,
317
- fs
318
- });
319
- this._attributeInfos = getAttributeInfosFromLayouts(this.pipeline.shaderLayout, this.bufferLayout);
336
+ /**
337
+ * Updates shader module settings (which results in uniforms being set)
338
+ */
339
+ setShaderModuleProps(props) {
340
+ const uniforms = this._getModuleUniforms(props);
341
+ // Extract textures & framebuffers set by the modules
342
+ // TODO better way to extract bindings
343
+ const keys = Object.keys(uniforms).filter(k => {
344
+ const uniform = uniforms[k];
345
+ return !isNumberArray(uniform) && typeof uniform !== 'number' && typeof uniform !== 'boolean';
346
+ });
347
+ const bindings = {};
348
+ for (const k of keys) {
349
+ bindings[k] = uniforms[k];
350
+ delete uniforms[k];
351
+ }
320
352
  }
321
- return this.pipeline;
322
- }
323
- _logDrawCallStart() {
324
- const logDrawTimeout = log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
325
- if (log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
326
- return;
353
+ updateShaderInputs() {
354
+ this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
355
+ }
356
+ /**
357
+ * @deprecated Updates shader module settings (which results in uniforms being set)
358
+ */
359
+ updateModuleSettings(props) {
360
+ log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
361
+ const { bindings, uniforms } = splitUniformsAndBindings(this._getModuleUniforms(props));
362
+ Object.assign(this.bindings, bindings);
363
+ Object.assign(this.uniforms, uniforms);
364
+ }
365
+ /**
366
+ * Sets bindings (textures, samplers, uniform buffers)
367
+ */
368
+ setBindings(bindings) {
369
+ Object.assign(this.bindings, bindings);
370
+ }
371
+ /**
372
+ * Sets individual uniforms
373
+ * @deprecated WebGL only, use uniform buffers for portability
374
+ * @param uniforms
375
+ * @returns self for chaining
376
+ */
377
+ setUniforms(uniforms) {
378
+ this.pipeline.setUniformsWebGL(uniforms);
379
+ Object.assign(this.uniforms, uniforms);
380
+ }
381
+ /**
382
+ * Sets the index buffer
383
+ * @todo - how to unset it if we change geometry?
384
+ */
385
+ setIndexBuffer(indexBuffer) {
386
+ this.vertexArray.setIndexBuffer(indexBuffer);
387
+ }
388
+ /**
389
+ * Updates optional transform feedback. WebGL only.
390
+ */
391
+ setTransformFeedback(transformFeedback) {
392
+ this.transformFeedback = transformFeedback;
393
+ }
394
+ /**
395
+ * Sets attributes (buffers)
396
+ * @note Overrides any attributes previously set with the same name
397
+ */
398
+ setAttributes(buffers, options) {
399
+ if (buffers.indices) {
400
+ log.warn(`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`)();
401
+ }
402
+ for (const [bufferName, buffer] of Object.entries(buffers)) {
403
+ const bufferLayout = this.bufferLayout.find(layout => getAttributeNames(layout).includes(bufferName));
404
+ if (!bufferLayout) {
405
+ log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
406
+ continue; // eslint-disable-line no-continue
407
+ }
408
+ // For an interleaved attribute we may need to set multiple attributes
409
+ const attributeNames = getAttributeNames(bufferLayout);
410
+ let set = false;
411
+ for (const attributeName of attributeNames) {
412
+ const attributeInfo = this._attributeInfos[attributeName];
413
+ if (attributeInfo) {
414
+ this.vertexArray.setBuffer(attributeInfo.location, buffer);
415
+ set = true;
416
+ }
417
+ }
418
+ if (!set && (options?.ignoreUnknownAttributes || this.props.ignoreUnknownAttributes)) {
419
+ log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
420
+ }
421
+ }
327
422
  }
328
- this._lastLogTime = Date.now();
329
- this._logOpen = true;
330
- log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, {
331
- collapsed: log.level <= 2
332
- })();
333
- }
334
- _logDrawCallEnd() {
335
- if (this._logOpen) {
336
- const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
337
- log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
338
- const uniformTable = this.shaderInputs.getDebugTable();
339
- for (const [name, value] of Object.entries(this.uniforms)) {
340
- uniformTable[name] = {
341
- value
342
- };
343
- }
344
- log.table(LOG_DRAW_PRIORITY, uniformTable)();
345
- const attributeTable = this._getAttributeDebugTable();
346
- log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
347
- log.table(LOG_DRAW_PRIORITY, attributeTable)();
348
- log.groupEnd(LOG_DRAW_PRIORITY)();
349
- this._logOpen = false;
423
+ /**
424
+ * Sets constant attributes
425
+ * @note Overrides any attributes previously set with the same name
426
+ * Constant attributes are only supported in WebGL, not in WebGPU
427
+ * Any attribute that is disabled in the current vertex array object
428
+ * is read from the context's global constant value for that attribute location.
429
+ * @param constantAttributes
430
+ */
431
+ setConstantAttributes(attributes) {
432
+ for (const [attributeName, value] of Object.entries(attributes)) {
433
+ const attributeInfo = this._attributeInfos[attributeName];
434
+ if (attributeInfo) {
435
+ this.vertexArray.setConstantWebGL(attributeInfo.location, value);
436
+ }
437
+ else {
438
+ log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
439
+ }
440
+ }
350
441
  }
351
- }
352
- _logFramebuffer(renderPass) {
353
- const debugFramebuffers = log.get('framebuffer');
354
- this._drawCount++;
355
- if (!debugFramebuffers || this._drawCount++ > 3 && this._drawCount % 60) {
356
- return;
442
+ _setPipelineNeedsUpdate(reason) {
443
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
444
+ }
445
+ _updatePipeline() {
446
+ if (this._pipelineNeedsUpdate) {
447
+ let prevShaderVs = null;
448
+ let prevShaderFs = null;
449
+ if (this.pipeline) {
450
+ log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
451
+ prevShaderVs = this.pipeline.vs;
452
+ prevShaderFs = this.pipeline.fs;
453
+ }
454
+ this._pipelineNeedsUpdate = false;
455
+ const vs = this.shaderFactory.createShader({
456
+ id: `${this.id}-vertex`,
457
+ stage: 'vertex',
458
+ source: this.vs,
459
+ debug: this.props.debugShaders
460
+ });
461
+ const fs = this.fs
462
+ ? this.shaderFactory.createShader({
463
+ id: `${this.id}-fragment`,
464
+ stage: 'fragment',
465
+ source: this.fs,
466
+ debug: this.props.debugShaders
467
+ })
468
+ : null;
469
+ this.pipeline = this.pipelineFactory.createRenderPipeline({
470
+ ...this.props,
471
+ bufferLayout: this.bufferLayout,
472
+ topology: this.topology,
473
+ parameters: this.parameters,
474
+ vs,
475
+ fs
476
+ });
477
+ this._attributeInfos = getAttributeInfosFromLayouts(this.pipeline.shaderLayout, this.bufferLayout);
478
+ if (prevShaderVs)
479
+ this.shaderFactory.release(prevShaderVs);
480
+ if (prevShaderFs)
481
+ this.shaderFactory.release(prevShaderFs);
482
+ }
483
+ return this.pipeline;
484
+ }
485
+ /** Throttle draw call logging */
486
+ _lastLogTime = 0;
487
+ _logOpen = false;
488
+ _logDrawCallStart() {
489
+ // IF level is 4 or higher, log every frame.
490
+ const logDrawTimeout = log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
491
+ if (log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
492
+ return;
493
+ }
494
+ this._lastLogTime = Date.now();
495
+ this._logOpen = true;
496
+ log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: log.level <= 2 })();
497
+ }
498
+ _logDrawCallEnd() {
499
+ if (this._logOpen) {
500
+ const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
501
+ // log.table(logLevel, attributeTable)();
502
+ // log.table(logLevel, uniformTable)();
503
+ log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
504
+ const uniformTable = this.shaderInputs.getDebugTable();
505
+ // Add any global uniforms
506
+ for (const [name, value] of Object.entries(this.uniforms)) {
507
+ uniformTable[name] = { value };
508
+ }
509
+ log.table(LOG_DRAW_PRIORITY, uniformTable)();
510
+ const attributeTable = this._getAttributeDebugTable();
511
+ log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
512
+ log.table(LOG_DRAW_PRIORITY, attributeTable)();
513
+ log.groupEnd(LOG_DRAW_PRIORITY)();
514
+ this._logOpen = false;
515
+ }
357
516
  }
358
- const framebuffer = renderPass.props.framebuffer;
359
- if (framebuffer) {
360
- debugFramebuffer(framebuffer, {
361
- id: framebuffer.id,
362
- minimap: true
363
- });
517
+ _drawCount = 0;
518
+ _logFramebuffer(renderPass) {
519
+ const debugFramebuffers = log.get('framebuffer');
520
+ this._drawCount++;
521
+ // Update first 3 frames and then every 60 frames
522
+ if (!debugFramebuffers || (this._drawCount++ > 3 && this._drawCount % 60)) {
523
+ return;
524
+ }
525
+ // TODO - display framebuffer output in debug window
526
+ const framebuffer = renderPass.props.framebuffer;
527
+ if (framebuffer) {
528
+ debugFramebuffer(framebuffer, { id: framebuffer.id, minimap: true });
529
+ // log.image({logLevel: LOG_DRAW_PRIORITY, message: `${framebuffer.id} %c sup?`, image})();
530
+ }
364
531
  }
365
- }
366
- _getAttributeDebugTable() {
367
- const table = {};
368
- for (const [name, attributeInfo] of Object.entries(this._attributeInfos)) {
369
- table[attributeInfo.location] = {
370
- name,
371
- type: attributeInfo.shaderType,
372
- values: this._getBufferOrConstantValues(this.vertexArray.attributes[attributeInfo.location], attributeInfo.bufferDataType)
373
- };
532
+ _getAttributeDebugTable() {
533
+ const table = {};
534
+ for (const [name, attributeInfo] of Object.entries(this._attributeInfos)) {
535
+ table[attributeInfo.location] = {
536
+ name,
537
+ type: attributeInfo.shaderType,
538
+ values: this._getBufferOrConstantValues(this.vertexArray.attributes[attributeInfo.location], attributeInfo.bufferDataType)
539
+ };
540
+ }
541
+ if (this.vertexArray.indexBuffer) {
542
+ const { indexBuffer } = this.vertexArray;
543
+ const values = indexBuffer.indexType === 'uint32'
544
+ ? new Uint32Array(indexBuffer.debugData)
545
+ : new Uint16Array(indexBuffer.debugData);
546
+ table.indices = {
547
+ name: 'indices',
548
+ type: indexBuffer.indexType,
549
+ values: values.toString()
550
+ };
551
+ }
552
+ return table;
374
553
  }
375
- if (this.vertexArray.indexBuffer) {
376
- const {
377
- indexBuffer
378
- } = this.vertexArray;
379
- const values = indexBuffer.indexType === 'uint32' ? new Uint32Array(indexBuffer.debugData) : new Uint16Array(indexBuffer.debugData);
380
- table.indices = {
381
- name: 'indices',
382
- type: indexBuffer.indexType,
383
- values: values.toString()
384
- };
554
+ // TODO - fix typing of luma data types
555
+ _getBufferOrConstantValues(attribute, dataType) {
556
+ const TypedArrayConstructor = getTypedArrayFromDataType(dataType);
557
+ const typedArray = attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
558
+ return typedArray.toString();
385
559
  }
386
- return table;
387
- }
388
- _getBufferOrConstantValues(attribute, dataType) {
389
- const TypedArrayConstructor = getTypedArrayFromDataType(dataType);
390
- const typedArray = attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
391
- return typedArray.toString();
392
- }
393
560
  }
394
- Model.defaultProps = {
395
- ...RenderPipeline.defaultProps,
396
- source: null,
397
- vs: null,
398
- fs: null,
399
- id: 'unnamed',
400
- handle: undefined,
401
- userData: {},
402
- defines: {},
403
- modules: [],
404
- moduleSettings: undefined,
405
- geometry: null,
406
- indexBuffer: null,
407
- attributes: {},
408
- constantAttributes: {},
409
- varyings: [],
410
- shaderInputs: undefined,
411
- pipelineFactory: undefined,
412
- transformFeedback: undefined,
413
- shaderAssembler: ShaderAssembler.getDefaultShaderAssembler()
414
- };
561
+ // HELPERS
562
+ /** TODO - move to core, document add tests */
415
563
  function mergeBufferLayouts(layouts1, layouts2) {
416
- const layouts = [...layouts1];
417
- for (const attribute of layouts2) {
418
- const index = layouts.findIndex(attribute2 => attribute2.name === attribute.name);
419
- if (index < 0) {
420
- layouts.push(attribute);
421
- } else {
422
- layouts[index] = attribute;
564
+ const layouts = [...layouts1];
565
+ for (const attribute of layouts2) {
566
+ const index = layouts.findIndex(attribute2 => attribute2.name === attribute.name);
567
+ if (index < 0) {
568
+ layouts.push(attribute);
569
+ }
570
+ else {
571
+ layouts[index] = attribute;
572
+ }
423
573
  }
424
- }
425
- return layouts;
574
+ return layouts;
426
575
  }
576
+ /** Create a shadertools platform info from the Device */
427
577
  export function getPlatformInfo(device) {
428
- return {
429
- type: device.info.type,
430
- shaderLanguage: device.info.shadingLanguage,
431
- shaderLanguageVersion: device.info.shadingLanguageVersion,
432
- gpu: device.info.gpu,
433
- features: device.features
434
- };
578
+ return {
579
+ type: device.info.type,
580
+ shaderLanguage: device.info.shadingLanguage,
581
+ shaderLanguageVersion: device.info.shadingLanguageVersion,
582
+ gpu: device.info.gpu,
583
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
584
+ features: device.features
585
+ };
435
586
  }
587
+ /** Get attribute names from a BufferLayout */
436
588
  function getAttributeNames(bufferLayout) {
437
- var _bufferLayout$attribu;
438
- return bufferLayout.attributes ? (_bufferLayout$attribu = bufferLayout.attributes) === null || _bufferLayout$attribu === void 0 ? void 0 : _bufferLayout$attribu.map(layout => layout.attribute) : [bufferLayout.name];
589
+ return bufferLayout.attributes
590
+ ? bufferLayout.attributes?.map(layout => layout.attribute)
591
+ : [bufferLayout.name];
439
592
  }
440
- //# sourceMappingURL=model.js.map