@luma.gl/engine 9.0.17 → 9.1.0-alpha.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/dist/animation/key-frames.d.ts.map +1 -1
- package/dist/animation/key-frames.js +3 -0
- package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop-template.js +3 -0
- package/dist/animation-loop/animation-loop.d.ts +1 -1
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +5 -4
- package/dist/animation-loop/animation-props.d.ts.map +1 -1
- package/dist/animation-loop/animation-props.js +3 -0
- package/dist/animation-loop/make-animation-loop.js +1 -1
- package/dist/animation-loop/request-animation-frame.d.ts +3 -0
- package/dist/animation-loop/request-animation-frame.d.ts.map +1 -0
- package/dist/animation-loop/request-animation-frame.js +16 -0
- package/dist/application-utils/load-file.d.ts +22 -0
- package/dist/application-utils/load-file.d.ts.map +1 -0
- package/dist/application-utils/load-file.js +42 -0
- package/dist/application-utils/random.d.ts +3 -0
- package/dist/application-utils/random.d.ts.map +1 -0
- package/dist/application-utils/random.js +16 -0
- package/dist/async-texture/async-texture.d.ts +50 -0
- package/dist/async-texture/async-texture.d.ts.map +1 -0
- package/dist/async-texture/async-texture.js +83 -0
- package/dist/computation.d.ts +4 -3
- package/dist/computation.d.ts.map +1 -1
- package/dist/computation.js +14 -6
- package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
- package/dist/debug/copy-texture-to-image.js +4 -1
- package/dist/debug/debug-framebuffer.d.ts.map +1 -1
- package/dist/debug/debug-framebuffer.js +17 -12
- package/dist/debug/pixel-data-utils.d.ts +1 -1
- package/dist/dist.dev.js +728 -555
- package/dist/dist.min.js +57 -41
- package/dist/geometries/cone-geometry.d.ts.map +1 -1
- package/dist/geometries/cone-geometry.js +4 -1
- package/dist/geometries/cube-geometry.d.ts.map +1 -1
- package/dist/geometries/cube-geometry.js +4 -1
- package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
- package/dist/geometries/cylinder-geometry.js +4 -1
- package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +4 -1
- package/dist/geometries/plane-geometry.d.ts.map +1 -1
- package/dist/geometries/plane-geometry.js +4 -1
- package/dist/geometries/sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/sphere-geometry.js +4 -1
- package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
- package/dist/geometries/truncated-cone-geometry.js +4 -1
- package/dist/geometry/geometry-table.d.ts +2 -1
- package/dist/geometry/geometry-table.d.ts.map +1 -1
- package/dist/geometry/geometry-utils.d.ts.map +1 -1
- package/dist/geometry/geometry-utils.js +3 -1
- package/dist/geometry/geometry.d.ts +5 -4
- package/dist/geometry/geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.js +9 -5
- package/dist/geometry/gpu-geometry.d.ts +1 -1
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +18 -6
- package/dist/geometry/gpu-table.js +3 -0
- package/dist/index.cjs +514 -258
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/lib/clip-space.d.ts.map +1 -1
- package/dist/lib/clip-space.js +10 -7
- package/dist/lib/pipeline-factory.d.ts +3 -2
- package/dist/lib/pipeline-factory.d.ts.map +1 -1
- package/dist/lib/pipeline-factory.js +12 -8
- package/dist/lib/shader-factory.d.ts +3 -2
- package/dist/lib/shader-factory.d.ts.map +1 -1
- package/dist/lib/shader-factory.js +11 -4
- package/dist/model/model.d.ts +10 -6
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +64 -8
- package/dist/model/split-uniforms-and-bindings.d.ts +9 -0
- package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -0
- package/dist/model/split-uniforms-and-bindings.js +20 -0
- package/dist/scenegraph/group-node.d.ts +1 -1
- package/dist/scenegraph/group-node.d.ts.map +1 -1
- package/dist/scenegraph/group-node.js +3 -0
- package/dist/scenegraph/model-node.d.ts +2 -2
- package/dist/scenegraph/model-node.d.ts.map +1 -1
- package/dist/scenegraph/model-node.js +6 -3
- package/dist/scenegraph/scenegraph-node.d.ts +5 -6
- package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
- package/dist/scenegraph/scenegraph-node.js +11 -8
- package/dist/shader-inputs.d.ts +21 -8
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +11 -6
- package/dist/transform/buffer-transform.d.ts.map +1 -1
- package/dist/transform/buffer-transform.js +8 -2
- package/dist/transform/texture-transform.d.ts +2 -2
- package/dist/transform/texture-transform.d.ts.map +1 -1
- package/dist/transform/texture-transform.js +1 -0
- package/dist/utils/deep-equal.d.ts +9 -0
- package/dist/utils/deep-equal.d.ts.map +1 -0
- package/dist/utils/deep-equal.js +50 -0
- package/dist/utils/uid.d.ts +7 -0
- package/dist/utils/uid.d.ts.map +1 -0
- package/dist/utils/uid.js +14 -0
- package/package.json +7 -6
- package/src/animation/key-frames.ts +4 -0
- package/src/animation-loop/animation-loop-template.ts +4 -0
- package/src/animation-loop/animation-loop.ts +6 -4
- package/src/animation-loop/animation-props.ts +4 -0
- package/src/animation-loop/make-animation-loop.ts +1 -1
- package/src/animation-loop/request-animation-frame.ts +19 -0
- package/src/application-utils/load-file.ts +51 -0
- package/src/application-utils/random.ts +18 -0
- package/src/async-texture/async-texture.ts +146 -0
- package/src/computation.ts +17 -9
- package/src/debug/copy-texture-to-image.ts +4 -1
- package/src/debug/debug-framebuffer.ts +18 -12
- package/src/debug/pixel-data-utils.ts +1 -1
- package/src/geometries/cone-geometry.ts +5 -1
- package/src/geometries/cube-geometry.ts +5 -1
- package/src/geometries/cylinder-geometry.ts +5 -1
- package/src/geometries/ico-sphere-geometry.ts +5 -1
- package/src/geometries/plane-geometry.ts +5 -1
- package/src/geometries/sphere-geometry.ts +5 -1
- package/src/geometries/truncated-cone-geometry.ts +5 -1
- package/src/geometry/geometry-table.ts +2 -1
- package/src/geometry/geometry-utils.ts +3 -1
- package/src/geometry/geometry.ts +16 -19
- package/src/geometry/gpu-geometry.ts +20 -14
- package/src/geometry/gpu-table.ts +4 -0
- package/src/index.ts +16 -0
- package/src/lib/clip-space.ts +6 -2
- package/src/lib/pipeline-factory.ts +17 -16
- package/src/lib/shader-factory.ts +13 -6
- package/src/model/model.ts +70 -17
- package/src/model/split-uniforms-and-bindings.ts +31 -0
- package/src/scenegraph/group-node.ts +4 -0
- package/src/scenegraph/model-node.ts +9 -5
- package/src/scenegraph/scenegraph-node.ts +17 -13
- package/src/shader-inputs.ts +47 -18
- package/src/transform/buffer-transform.ts +8 -9
- package/src/transform/texture-transform.ts +2 -1
- package/src/utils/deep-equal.ts +51 -0
- package/src/utils/uid.ts +16 -0
|
@@ -1,22 +1,27 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
1
5
|
import {Device, Shader, ShaderProps} from '@luma.gl/core';
|
|
2
6
|
|
|
3
7
|
/** Manages a cached pool of Shaders for reuse. */
|
|
4
8
|
export class ShaderFactory {
|
|
5
9
|
static readonly defaultProps: Required<ShaderProps> = {...Shader.defaultProps};
|
|
6
10
|
|
|
7
|
-
public readonly device: Device;
|
|
8
|
-
|
|
9
|
-
private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
|
|
10
|
-
|
|
11
11
|
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
12
12
|
static getDefaultShaderFactory(device: Device): ShaderFactory {
|
|
13
13
|
device._lumaData.defaultShaderFactory ||= new ShaderFactory(device);
|
|
14
14
|
return device._lumaData.defaultShaderFactory as ShaderFactory;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
public readonly device: Device;
|
|
18
|
+
readonly destroyPolicy: 'unused' | 'never';
|
|
19
|
+
private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
|
|
20
|
+
|
|
17
21
|
/** @internal */
|
|
18
22
|
constructor(device: Device) {
|
|
19
23
|
this.device = device;
|
|
24
|
+
this.destroyPolicy = device.props._factoryDestroyPolicy;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
@@ -43,8 +48,10 @@ export class ShaderFactory {
|
|
|
43
48
|
if (cacheEntry) {
|
|
44
49
|
cacheEntry.useCount--;
|
|
45
50
|
if (cacheEntry.useCount === 0) {
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
if (this.destroyPolicy === 'unused') {
|
|
52
|
+
delete this._cache[key];
|
|
53
|
+
cacheEntry.shader.destroy();
|
|
54
|
+
}
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
}
|
package/src/model/model.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
// A lot of imports, but then Model is where it all comes together...
|
|
6
|
-
import type {TypedArray
|
|
6
|
+
import type {TypedArray} from '@math.gl/types';
|
|
7
|
+
import type {RenderPipelineProps, RenderPipelineParameters} from '@luma.gl/core';
|
|
7
8
|
import type {BufferLayout, Shader, VertexArray, TransformFeedback} from '@luma.gl/core';
|
|
8
9
|
import type {AttributeInfo, Binding, UniformValue, PrimitiveTopology} from '@luma.gl/core';
|
|
9
10
|
import {Device, DeviceFeature, Buffer, Texture, TextureView, Sampler} from '@luma.gl/core';
|
|
10
11
|
import {RenderPipeline, RenderPass, UniformStore} from '@luma.gl/core';
|
|
11
|
-
import {log
|
|
12
|
+
import {log} from '@luma.gl/core';
|
|
12
13
|
import {getTypedArrayFromDataType, getAttributeInfosFromLayouts} from '@luma.gl/core';
|
|
13
14
|
|
|
14
15
|
import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
|
|
@@ -16,16 +17,22 @@ import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
|
|
|
16
17
|
|
|
17
18
|
import type {Geometry} from '../geometry/geometry';
|
|
18
19
|
import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry';
|
|
19
|
-
import {ShaderInputs} from '../shader-inputs';
|
|
20
20
|
import {PipelineFactory} from '../lib/pipeline-factory';
|
|
21
21
|
import {ShaderFactory} from '../lib/shader-factory';
|
|
22
22
|
import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
|
|
23
23
|
import {debugFramebuffer} from '../debug/debug-framebuffer';
|
|
24
|
+
import {deepEqual} from '../utils/deep-equal';
|
|
25
|
+
import {uid} from '../utils/uid';
|
|
26
|
+
import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
|
|
27
|
+
|
|
28
|
+
import {ShaderInputs} from '../shader-inputs';
|
|
29
|
+
// import type {AsyncTextureProps} from '../async-texture/async-texture';
|
|
30
|
+
import {AsyncTexture} from '../async-texture/async-texture';
|
|
24
31
|
|
|
25
32
|
const LOG_DRAW_PRIORITY = 2;
|
|
26
33
|
const LOG_DRAW_TIMEOUT = 10000;
|
|
27
34
|
|
|
28
|
-
export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
|
|
35
|
+
export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
29
36
|
source?: string;
|
|
30
37
|
vs: string | null;
|
|
31
38
|
fs: string | null;
|
|
@@ -39,7 +46,7 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
|
|
|
39
46
|
/** Shader inputs, used to generated uniform buffers and bindings */
|
|
40
47
|
shaderInputs?: ShaderInputs;
|
|
41
48
|
/** Bindings */
|
|
42
|
-
bindings?: Record<string, Binding>;
|
|
49
|
+
bindings?: Record<string, Binding | AsyncTexture>;
|
|
43
50
|
/** Parameters that are built into the pipeline */
|
|
44
51
|
parameters?: RenderPipelineParameters;
|
|
45
52
|
|
|
@@ -92,7 +99,7 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
|
|
|
92
99
|
export class Model {
|
|
93
100
|
static defaultProps: Required<ModelProps> = {
|
|
94
101
|
...RenderPipeline.defaultProps,
|
|
95
|
-
source:
|
|
102
|
+
source: undefined!,
|
|
96
103
|
vs: null,
|
|
97
104
|
fs: null,
|
|
98
105
|
id: 'unnamed',
|
|
@@ -114,7 +121,7 @@ export class Model {
|
|
|
114
121
|
shaderInputs: undefined!,
|
|
115
122
|
pipelineFactory: undefined!,
|
|
116
123
|
shaderFactory: undefined!,
|
|
117
|
-
transformFeedback: undefined
|
|
124
|
+
transformFeedback: undefined!,
|
|
118
125
|
shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(),
|
|
119
126
|
|
|
120
127
|
debugShaders: undefined!,
|
|
@@ -123,8 +130,11 @@ export class Model {
|
|
|
123
130
|
|
|
124
131
|
readonly device: Device;
|
|
125
132
|
readonly id: string;
|
|
133
|
+
// @ts-expect-error assigned in function called from constructor
|
|
126
134
|
readonly source: string;
|
|
135
|
+
// @ts-expect-error assigned in function called from constructor
|
|
127
136
|
readonly vs: string;
|
|
137
|
+
// @ts-expect-error assigned in function called from constructor
|
|
128
138
|
readonly fs: string;
|
|
129
139
|
readonly pipelineFactory: PipelineFactory;
|
|
130
140
|
readonly shaderFactory: ShaderFactory;
|
|
@@ -156,7 +166,7 @@ export class Model {
|
|
|
156
166
|
/** Constant-valued attributes */
|
|
157
167
|
constantAttributes: Record<string, TypedArray> = {};
|
|
158
168
|
/** Bindings (textures, samplers, uniform buffers) */
|
|
159
|
-
bindings: Record<string, Binding> = {};
|
|
169
|
+
bindings: Record<string, Binding | AsyncTexture> = {};
|
|
160
170
|
/** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
|
|
161
171
|
uniforms: Record<string, UniformValue> = {};
|
|
162
172
|
|
|
@@ -174,8 +184,9 @@ export class Model {
|
|
|
174
184
|
pipeline: RenderPipeline;
|
|
175
185
|
|
|
176
186
|
/** ShaderInputs instance */
|
|
187
|
+
// @ts-expect-error Assigned in function called by constructor
|
|
177
188
|
shaderInputs: ShaderInputs;
|
|
178
|
-
|
|
189
|
+
// @ts-expect-error Assigned in function called by constructor
|
|
179
190
|
_uniformStore: UniformStore;
|
|
180
191
|
|
|
181
192
|
_attributeInfos: Record<string, AttributeInfo> = {};
|
|
@@ -209,6 +220,7 @@ export class Model {
|
|
|
209
220
|
|
|
210
221
|
// Extract modules from shader inputs if not supplied
|
|
211
222
|
const modules =
|
|
223
|
+
// @ts-expect-error shaderInputs is assigned in setShaderInputs above.
|
|
212
224
|
(this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
213
225
|
|
|
214
226
|
const isWebGPU = this.device.type === 'webgpu';
|
|
@@ -219,16 +231,17 @@ export class Model {
|
|
|
219
231
|
if (isWebGPU && this.props.source) {
|
|
220
232
|
// WGSL
|
|
221
233
|
this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
|
|
222
|
-
const {source, getUniforms} = this.props.shaderAssembler.
|
|
234
|
+
const {source, getUniforms} = this.props.shaderAssembler.assembleWGSLShader({
|
|
223
235
|
platformInfo,
|
|
224
236
|
...this.props,
|
|
225
237
|
modules
|
|
226
238
|
});
|
|
227
239
|
this.source = source;
|
|
240
|
+
// @ts-expect-error
|
|
228
241
|
this._getModuleUniforms = getUniforms;
|
|
229
242
|
} else {
|
|
230
243
|
// GLSL
|
|
231
|
-
const {vs, fs, getUniforms} = this.props.shaderAssembler.
|
|
244
|
+
const {vs, fs, getUniforms} = this.props.shaderAssembler.assembleGLSLShaderPair({
|
|
232
245
|
platformInfo,
|
|
233
246
|
...this.props,
|
|
234
247
|
modules
|
|
@@ -236,6 +249,7 @@ export class Model {
|
|
|
236
249
|
|
|
237
250
|
this.vs = vs;
|
|
238
251
|
this.fs = fs;
|
|
252
|
+
// @ts-expect-error
|
|
239
253
|
this._getModuleUniforms = getUniforms;
|
|
240
254
|
}
|
|
241
255
|
|
|
@@ -358,7 +372,11 @@ export class Model {
|
|
|
358
372
|
|
|
359
373
|
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
|
|
360
374
|
// Any caching needs to be done inside the pipeline functions
|
|
361
|
-
this
|
|
375
|
+
// TODO this is a busy initialized check for all bindings every frame
|
|
376
|
+
const syncBindings = this._getBindings();
|
|
377
|
+
this.pipeline.setBindings(syncBindings, {
|
|
378
|
+
disableWarnings: this.props.disableWarnings
|
|
379
|
+
});
|
|
362
380
|
if (!isObjectEmpty(this.uniforms)) {
|
|
363
381
|
this.pipeline.setUniformsWebGL(this.uniforms);
|
|
364
382
|
}
|
|
@@ -513,7 +531,7 @@ export class Model {
|
|
|
513
531
|
/**
|
|
514
532
|
* Sets bindings (textures, samplers, uniform buffers)
|
|
515
533
|
*/
|
|
516
|
-
setBindings(bindings: Record<string, Binding>): void {
|
|
534
|
+
setBindings(bindings: Record<string, Binding | AsyncTexture>): void {
|
|
517
535
|
Object.assign(this.bindings, bindings);
|
|
518
536
|
this.setNeedsRedraw('bindings');
|
|
519
537
|
}
|
|
@@ -626,6 +644,21 @@ export class Model {
|
|
|
626
644
|
|
|
627
645
|
// Internal methods
|
|
628
646
|
|
|
647
|
+
/** Get texture / texture view from any async textures */
|
|
648
|
+
_getBindings(): Record<string, Binding> {
|
|
649
|
+
// Extract actual textures from async textures. If not loaded, null
|
|
650
|
+
return Object.entries(this.bindings).reduce<Record<string, Binding>>((acc, [name, binding]) => {
|
|
651
|
+
if (binding instanceof AsyncTexture) {
|
|
652
|
+
if (binding.isReady) {
|
|
653
|
+
acc[name] = binding.texture;
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
acc[name] = binding;
|
|
657
|
+
}
|
|
658
|
+
return acc;
|
|
659
|
+
}, {});
|
|
660
|
+
}
|
|
661
|
+
|
|
629
662
|
/** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
|
|
630
663
|
_getBindingsUpdateTimestamp(): number {
|
|
631
664
|
let timestamp = 0;
|
|
@@ -634,6 +667,11 @@ export class Model {
|
|
|
634
667
|
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
635
668
|
} else if (binding instanceof Buffer || binding instanceof Texture) {
|
|
636
669
|
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
670
|
+
} else if (binding instanceof AsyncTexture) {
|
|
671
|
+
timestamp = binding.texture
|
|
672
|
+
? Math.max(timestamp, binding.texture.updateTimestamp)
|
|
673
|
+
: // The texture will become available in the future
|
|
674
|
+
Infinity;
|
|
637
675
|
} else if (!(binding instanceof Sampler)) {
|
|
638
676
|
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
639
677
|
}
|
|
@@ -713,6 +751,9 @@ export class Model {
|
|
|
713
751
|
bufferLayout: this.bufferLayout,
|
|
714
752
|
topology: this.topology,
|
|
715
753
|
parameters: this.parameters,
|
|
754
|
+
// TODO - why set bindings here when we reset them every frame?
|
|
755
|
+
// Should we expose a BindGroup abstraction?
|
|
756
|
+
bindings: this._getBindings(),
|
|
716
757
|
vs,
|
|
717
758
|
fs
|
|
718
759
|
});
|
|
@@ -788,13 +829,13 @@ export class Model {
|
|
|
788
829
|
_getAttributeDebugTable(): Record<string, Record<string, unknown>> {
|
|
789
830
|
const table: Record<string, Record<string, unknown>> = {};
|
|
790
831
|
for (const [name, attributeInfo] of Object.entries(this._attributeInfos)) {
|
|
832
|
+
const values = this.vertexArray.attributes[attributeInfo.location];
|
|
791
833
|
table[attributeInfo.location] = {
|
|
792
834
|
name,
|
|
793
835
|
type: attributeInfo.shaderType,
|
|
794
|
-
values:
|
|
795
|
-
this.
|
|
796
|
-
|
|
797
|
-
)
|
|
836
|
+
values: values
|
|
837
|
+
? this._getBufferOrConstantValues(values, attributeInfo.bufferDataType)
|
|
838
|
+
: 'null'
|
|
798
839
|
};
|
|
799
840
|
}
|
|
800
841
|
if (this.vertexArray.indexBuffer) {
|
|
@@ -855,3 +896,15 @@ function getAttributeNames(bufferLayout: BufferLayout): string[] {
|
|
|
855
896
|
? bufferLayout.attributes?.map(layout => layout.attribute)
|
|
856
897
|
: [bufferLayout.name];
|
|
857
898
|
}
|
|
899
|
+
|
|
900
|
+
/** Returns true if given object is empty, false otherwise. */
|
|
901
|
+
function isObjectEmpty(obj: object): boolean {
|
|
902
|
+
let isEmpty = true;
|
|
903
|
+
// @ts-ignore key is unused
|
|
904
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
905
|
+
for (const key in obj) {
|
|
906
|
+
isEmpty = false;
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
return isEmpty;
|
|
910
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {UniformValue, Binding} from '@luma.gl/core';
|
|
6
|
+
import {isNumericArray} from '@math.gl/types';
|
|
7
|
+
|
|
8
|
+
export function isUniformValue(value: unknown): value is UniformValue {
|
|
9
|
+
return isNumericArray(value) !== null || typeof value === 'number' || typeof value === 'boolean';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type UniformsAndBindings = {
|
|
13
|
+
bindings: Record<string, Binding>;
|
|
14
|
+
uniforms: Record<string, UniformValue>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function splitUniformsAndBindings(
|
|
18
|
+
uniforms: Record<string, Binding | UniformValue>
|
|
19
|
+
): UniformsAndBindings {
|
|
20
|
+
const result: UniformsAndBindings = {bindings: {}, uniforms: {}};
|
|
21
|
+
Object.keys(uniforms).forEach(name => {
|
|
22
|
+
const uniform = uniforms[name];
|
|
23
|
+
if (isUniformValue(uniform)) {
|
|
24
|
+
result.uniforms[name] = uniform;
|
|
25
|
+
} else {
|
|
26
|
+
result.bindings[name] = uniform;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
1
5
|
import {RenderPass} from '@luma.gl/core';
|
|
2
6
|
import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
|
|
3
7
|
import {Model} from '../model/model';
|
|
@@ -28,10 +32,6 @@ export class ModelNode extends ScenegraphNode {
|
|
|
28
32
|
this.setProps(props);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
override getBounds(): [number[], number[]] | null {
|
|
32
|
-
return this.bounds;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
35
|
override destroy(): void {
|
|
36
36
|
if (this.model) {
|
|
37
37
|
this.model.destroy();
|
|
@@ -42,8 +42,12 @@ export class ModelNode extends ScenegraphNode {
|
|
|
42
42
|
this.managedResources = [];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
override getBounds(): [number[], number[]] | null {
|
|
46
|
+
return this.bounds;
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
// Expose model methods
|
|
46
|
-
draw(renderPass
|
|
50
|
+
draw(renderPass: RenderPass) {
|
|
47
51
|
// Return value indicates if something was actually drawn
|
|
48
52
|
return this.model.draw(renderPass);
|
|
49
53
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Vector3, Matrix4, NumericArray} from '@math.gl/core';
|
|
6
|
+
import {uid} from '../utils/uid';
|
|
3
7
|
|
|
4
8
|
/** Properties for creating a new Scenegraph */
|
|
5
9
|
export type ScenegraphNodeProps = {
|
|
6
10
|
id?: string;
|
|
7
11
|
/** whether to display the object at all */
|
|
8
12
|
display?: boolean;
|
|
9
|
-
matrix?:
|
|
10
|
-
position?:
|
|
11
|
-
rotation?:
|
|
12
|
-
scale?:
|
|
13
|
+
matrix?: NumericArray;
|
|
14
|
+
position?: NumericArray;
|
|
15
|
+
rotation?: NumericArray;
|
|
16
|
+
scale?: NumericArray;
|
|
13
17
|
update?: boolean;
|
|
14
18
|
};
|
|
15
19
|
|
|
@@ -53,19 +57,19 @@ export class ScenegraphNode {
|
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
setPosition(position: any): this {
|
|
56
|
-
assert(position.length === 3, 'setPosition requires vector argument');
|
|
60
|
+
// assert(position.length === 3, 'setPosition requires vector argument');
|
|
57
61
|
this.position = position;
|
|
58
62
|
return this;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
setRotation(rotation: any): this {
|
|
62
|
-
assert(rotation.length === 3, 'setRotation requires vector argument');
|
|
66
|
+
// assert(rotation.length === 3, 'setRotation requires vector argument');
|
|
63
67
|
this.rotation = rotation;
|
|
64
68
|
return this;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
setScale(scale: any): this {
|
|
68
|
-
assert(scale.length === 3, 'setScale requires vector argument');
|
|
72
|
+
// assert(scale.length === 3, 'setScale requires vector argument');
|
|
69
73
|
this.scale = scale;
|
|
70
74
|
return this;
|
|
71
75
|
}
|
|
@@ -140,7 +144,7 @@ export class ScenegraphNode {
|
|
|
140
144
|
} {
|
|
141
145
|
// TODO - solve multiple class problem
|
|
142
146
|
// assert(viewMatrix instanceof Matrix4);
|
|
143
|
-
assert(viewMatrix);
|
|
147
|
+
// assert(viewMatrix);
|
|
144
148
|
modelMatrix = modelMatrix || this.matrix;
|
|
145
149
|
const worldMatrix = new Matrix4(viewMatrix).multiplyRight(modelMatrix);
|
|
146
150
|
const worldInverse = worldMatrix.invert();
|
|
@@ -180,9 +184,9 @@ export class ScenegraphNode {
|
|
|
180
184
|
*/
|
|
181
185
|
|
|
182
186
|
_setScenegraphNodeProps(props: ScenegraphNodeProps): void {
|
|
183
|
-
if ('display' in props) {
|
|
184
|
-
|
|
185
|
-
}
|
|
187
|
+
// if ('display' in props) {
|
|
188
|
+
// this.display = props.display;
|
|
189
|
+
// }
|
|
186
190
|
|
|
187
191
|
if ('position' in props) {
|
|
188
192
|
this.setPosition(props.position);
|
package/src/shader-inputs.ts
CHANGED
|
@@ -2,10 +2,36 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {
|
|
6
|
-
import {log
|
|
5
|
+
import type {UniformValue, Texture, Sampler} from '@luma.gl/core';
|
|
6
|
+
import {log} from '@luma.gl/core';
|
|
7
7
|
// import type {ShaderUniformType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core';
|
|
8
|
-
import {
|
|
8
|
+
import {getShaderModuleDependencies, ShaderModule} from '@luma.gl/shadertools';
|
|
9
|
+
import {splitUniformsAndBindings} from './model/split-uniforms-and-bindings';
|
|
10
|
+
|
|
11
|
+
type BindingValue = Buffer | Texture | Sampler;
|
|
12
|
+
|
|
13
|
+
/** Minimal ShaderModule subset, we don't need shader code etc */
|
|
14
|
+
export type ShaderModuleInputs<
|
|
15
|
+
PropsT extends Record<string, unknown> = Record<string, unknown>,
|
|
16
|
+
UniformsT extends Record<string, UniformValue> = Record<string, UniformValue>,
|
|
17
|
+
BindingsT extends Record<string, BindingValue> = Record<string, BindingValue>
|
|
18
|
+
> = {
|
|
19
|
+
defaultUniforms?: UniformsT;
|
|
20
|
+
getUniforms?: (props?: any, oldProps?: any) => Record<string, BindingValue | UniformValue>;
|
|
21
|
+
|
|
22
|
+
/** Not used. Used to access props type */
|
|
23
|
+
props?: PropsT;
|
|
24
|
+
|
|
25
|
+
bindings?: Record<
|
|
26
|
+
keyof BindingsT,
|
|
27
|
+
{
|
|
28
|
+
location: number;
|
|
29
|
+
type: 'texture' | 'sampler' | 'uniforms';
|
|
30
|
+
}
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
uniformTypes?: any;
|
|
34
|
+
};
|
|
9
35
|
|
|
10
36
|
/**
|
|
11
37
|
* ShaderInputs holds uniform and binding values for one or more shader modules,
|
|
@@ -23,22 +49,24 @@ export class ShaderInputs<
|
|
|
23
49
|
* The map of modules
|
|
24
50
|
* @todo should should this include the resolved dependencies?
|
|
25
51
|
*/
|
|
26
|
-
|
|
52
|
+
// @ts-expect-error Fix typings
|
|
53
|
+
modules: Readonly<{[P in keyof ShaderPropsT]: ShaderModuleInputs<ShaderPropsT[P]>}>;
|
|
27
54
|
|
|
28
55
|
/** Stores the uniform values for each module */
|
|
29
56
|
moduleUniforms: Record<keyof ShaderPropsT, Record<string, UniformValue>>;
|
|
30
57
|
/** Stores the uniform bindings for each module */
|
|
31
|
-
moduleBindings: Record<keyof ShaderPropsT, Record<string,
|
|
58
|
+
moduleBindings: Record<keyof ShaderPropsT, Record<string, Texture | Sampler>>;
|
|
32
59
|
/** Tracks if uniforms have changed */
|
|
33
|
-
moduleUniformsChanged: Record<keyof ShaderPropsT, false | string>;
|
|
60
|
+
// moduleUniformsChanged: Record<keyof ShaderPropsT, false | string>;
|
|
34
61
|
|
|
35
62
|
/**
|
|
36
63
|
* Create a new UniformStore instance
|
|
37
64
|
* @param modules
|
|
38
65
|
*/
|
|
39
|
-
|
|
66
|
+
// @ts-expect-error Fix typings
|
|
67
|
+
constructor(modules: {[P in keyof ShaderPropsT]?: ShaderModuleInputs<ShaderPropsT[P]>}) {
|
|
40
68
|
// Extract modules with dependencies
|
|
41
|
-
const resolvedModules =
|
|
69
|
+
const resolvedModules = getShaderModuleDependencies(
|
|
42
70
|
Object.values(modules).filter(module => module.dependencies)
|
|
43
71
|
);
|
|
44
72
|
for (const resolvedModule of resolvedModules) {
|
|
@@ -49,9 +77,10 @@ export class ShaderInputs<
|
|
|
49
77
|
log.log(1, 'Creating ShaderInputs with modules', Object.keys(modules))();
|
|
50
78
|
|
|
51
79
|
// Store the module definitions and create storage for uniform values and binding values, per module
|
|
52
|
-
|
|
80
|
+
// @ts-expect-error Fix typings
|
|
81
|
+
this.modules = modules;
|
|
53
82
|
this.moduleUniforms = {} as Record<keyof ShaderPropsT, Record<string, UniformValue>>;
|
|
54
|
-
this.moduleBindings = {} as Record<keyof ShaderPropsT, Record<string,
|
|
83
|
+
this.moduleBindings = {} as Record<keyof ShaderPropsT, Record<string, Texture | Sampler>>;
|
|
55
84
|
|
|
56
85
|
// Initialize the modules
|
|
57
86
|
for (const [name, module] of Object.entries(modules)) {
|
|
@@ -72,7 +101,7 @@ export class ShaderInputs<
|
|
|
72
101
|
setProps(props: Partial<{[P in keyof ShaderPropsT]?: Partial<ShaderPropsT[P]>}>): void {
|
|
73
102
|
for (const name of Object.keys(props)) {
|
|
74
103
|
const moduleName = name as keyof ShaderPropsT;
|
|
75
|
-
const moduleProps = props[moduleName];
|
|
104
|
+
const moduleProps = props[moduleName] || {};
|
|
76
105
|
const module = this.modules[moduleName];
|
|
77
106
|
if (!module) {
|
|
78
107
|
// Ignore props for unregistered modules
|
|
@@ -80,10 +109,10 @@ export class ShaderInputs<
|
|
|
80
109
|
continue; // eslint-disable-line no-continue
|
|
81
110
|
}
|
|
82
111
|
|
|
83
|
-
const oldUniforms = this.moduleUniforms[moduleName]
|
|
112
|
+
const oldUniforms = this.moduleUniforms[moduleName];
|
|
84
113
|
const oldBindings = this.moduleBindings[moduleName];
|
|
85
|
-
|
|
86
|
-
|
|
114
|
+
let uniformsAndBindings = module.getUniforms?.(moduleProps, this.moduleUniforms[moduleName]);
|
|
115
|
+
uniformsAndBindings ||= {...this.moduleUniforms[moduleName], ...moduleProps};
|
|
87
116
|
|
|
88
117
|
const {uniforms, bindings} = splitUniformsAndBindings(uniformsAndBindings);
|
|
89
118
|
this.moduleUniforms[moduleName] = {...oldUniforms, ...uniforms};
|
|
@@ -103,7 +132,7 @@ export class ShaderInputs<
|
|
|
103
132
|
* Return the map of modules
|
|
104
133
|
* @todo should should this include the resolved dependencies?
|
|
105
134
|
*/
|
|
106
|
-
getModules():
|
|
135
|
+
getModules(): ShaderModule[] {
|
|
107
136
|
return Object.values(this.modules);
|
|
108
137
|
}
|
|
109
138
|
|
|
@@ -113,8 +142,8 @@ export class ShaderInputs<
|
|
|
113
142
|
}
|
|
114
143
|
|
|
115
144
|
/** Merges all bindings for the shader (from the various modules) */
|
|
116
|
-
getBindings(): Record<string,
|
|
117
|
-
const bindings = {} as Record<string,
|
|
145
|
+
getBindings(): Record<string, Texture | Sampler> {
|
|
146
|
+
const bindings = {} as Record<string, Texture | Sampler>;
|
|
118
147
|
for (const moduleBindings of Object.values(this.moduleBindings)) {
|
|
119
148
|
Object.assign(bindings, moduleBindings);
|
|
120
149
|
}
|
|
@@ -126,7 +155,7 @@ export class ShaderInputs<
|
|
|
126
155
|
for (const [moduleName, module] of Object.entries(this.moduleUniforms)) {
|
|
127
156
|
for (const [key, value] of Object.entries(module)) {
|
|
128
157
|
table[`${moduleName}.${key}`] = {
|
|
129
|
-
type: this.modules[moduleName].uniformTypes?.[key
|
|
158
|
+
type: this.modules[moduleName].uniformTypes?.[key],
|
|
130
159
|
value: String(value)
|
|
131
160
|
};
|
|
132
161
|
}
|
|
@@ -2,14 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
Device,
|
|
7
|
-
Buffer,
|
|
8
|
-
BufferRange,
|
|
9
|
-
TransformFeedback,
|
|
10
|
-
assert,
|
|
11
|
-
RenderPassProps
|
|
12
|
-
} from '@luma.gl/core';
|
|
5
|
+
import {Device, Buffer, BufferRange, TransformFeedback, RenderPassProps} from '@luma.gl/core';
|
|
13
6
|
import {getPassthroughFS} from '@luma.gl/shadertools';
|
|
14
7
|
import {Model} from '../model/model';
|
|
15
8
|
import type {ModelProps} from '../model/model';
|
|
@@ -38,7 +31,9 @@ export class BufferTransform {
|
|
|
38
31
|
}
|
|
39
32
|
|
|
40
33
|
constructor(device: Device, props: BufferTransformProps = Model.defaultProps) {
|
|
41
|
-
|
|
34
|
+
if (!BufferTransform.isSupported(device)) {
|
|
35
|
+
throw new Error('BufferTransform not yet implemented on WebGPU');
|
|
36
|
+
}
|
|
42
37
|
|
|
43
38
|
this.device = device;
|
|
44
39
|
|
|
@@ -51,6 +46,7 @@ export class BufferTransform {
|
|
|
51
46
|
|
|
52
47
|
this.transformFeedback = this.device.createTransformFeedback({
|
|
53
48
|
layout: this.model.pipeline.shaderLayout,
|
|
49
|
+
// @ts-expect-error TODO
|
|
54
50
|
buffers: props.feedbackBuffers
|
|
55
51
|
});
|
|
56
52
|
|
|
@@ -93,6 +89,9 @@ export class BufferTransform {
|
|
|
93
89
|
|
|
94
90
|
readAsync(varyingName: string): Promise<Uint8Array> {
|
|
95
91
|
const result = this.getBuffer(varyingName);
|
|
92
|
+
if (!result) {
|
|
93
|
+
throw new Error('BufferTransform#getBuffer');
|
|
94
|
+
}
|
|
96
95
|
if (result instanceof Buffer) {
|
|
97
96
|
return result.readAsync();
|
|
98
97
|
}
|
|
@@ -111,7 +111,7 @@ export class TextureTransform {
|
|
|
111
111
|
return targetTexture;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
getFramebuffer(): Framebuffer {
|
|
114
|
+
getFramebuffer(): Framebuffer | undefined {
|
|
115
115
|
const currentResources = this.bindings[this.currentIndex];
|
|
116
116
|
return currentResources.framebuffer;
|
|
117
117
|
}
|
|
@@ -134,6 +134,7 @@ export class TextureTransform {
|
|
|
134
134
|
binding = {
|
|
135
135
|
sourceBuffers: {},
|
|
136
136
|
sourceTextures: {},
|
|
137
|
+
// @ts-expect-error
|
|
137
138
|
targetTexture: null
|
|
138
139
|
};
|
|
139
140
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fast partial deep equal for prop.
|
|
7
|
+
*
|
|
8
|
+
* @param a Prop
|
|
9
|
+
* @param b Prop to compare against `a`
|
|
10
|
+
* @param depth Depth to which to recurse in nested Objects/Arrays. Use 0 (default) for shallow comparison, -1 for infinite depth
|
|
11
|
+
*/
|
|
12
|
+
/* eslint-disable complexity */
|
|
13
|
+
export function deepEqual(a: any, b: any, depth: number): boolean {
|
|
14
|
+
if (a === b) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (!depth || !a || !b) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(a)) {
|
|
21
|
+
if (!Array.isArray(b) || a.length !== b.length) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
for (let i = 0; i < a.length; i++) {
|
|
25
|
+
if (!deepEqual(a[i], b[i], depth - 1)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (Array.isArray(b)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (typeof a === 'object' && typeof b === 'object') {
|
|
35
|
+
const aKeys = Object.keys(a);
|
|
36
|
+
const bKeys = Object.keys(b);
|
|
37
|
+
if (aKeys.length !== bKeys.length) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
for (const key of aKeys) {
|
|
41
|
+
if (!b.hasOwnProperty(key)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (!deepEqual(a[key], b[key], depth - 1)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|