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