@luma.gl/engine 9.0.0-alpha.3 → 9.0.0-alpha.30

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 (148) hide show
  1. package/LICENSE +2 -1
  2. package/dist/animation/key-frames.d.ts +1 -1
  3. package/dist/animation/key-frames.d.ts.map +1 -1
  4. package/dist/animation/key-frames.js +0 -20
  5. package/dist/animation/key-frames.js.map +1 -1
  6. package/dist/animation/timeline.d.ts +5 -5
  7. package/dist/animation/timeline.d.ts.map +1 -1
  8. package/dist/animation/timeline.js +0 -30
  9. package/dist/animation/timeline.js.map +1 -1
  10. package/dist/{lib → animation-loop}/animation-loop.d.ts +28 -29
  11. package/dist/animation-loop/animation-loop.d.ts.map +1 -0
  12. package/dist/{lib → animation-loop}/animation-loop.js +96 -175
  13. package/dist/animation-loop/animation-loop.js.map +1 -0
  14. package/dist/{lib → animation-loop}/animation-props.d.ts +7 -7
  15. package/dist/animation-loop/animation-props.d.ts.map +1 -0
  16. package/dist/animation-loop/animation-props.js.map +1 -0
  17. package/dist/animation-loop/make-animation-loop.d.ts +6 -0
  18. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
  19. package/dist/animation-loop/make-animation-loop.js +28 -0
  20. package/dist/animation-loop/make-animation-loop.js.map +1 -0
  21. package/dist/animation-loop/render-loop.d.ts +23 -0
  22. package/dist/animation-loop/render-loop.d.ts.map +1 -0
  23. package/dist/animation-loop/render-loop.js +7 -0
  24. package/dist/animation-loop/render-loop.js.map +1 -0
  25. package/dist/dist.dev.js +14887 -0
  26. package/dist/geometries/cone-geometry.d.ts +1 -1
  27. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  28. package/dist/geometries/cone-geometry.js +6 -5
  29. package/dist/geometries/cone-geometry.js.map +1 -1
  30. package/dist/geometries/cube-geometry.d.ts +2 -2
  31. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  32. package/dist/geometries/cube-geometry.js +15 -8
  33. package/dist/geometries/cube-geometry.js.map +1 -1
  34. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  35. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  36. package/dist/geometries/cylinder-geometry.js +6 -5
  37. package/dist/geometries/cylinder-geometry.js.map +1 -1
  38. package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
  39. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  40. package/dist/geometries/ico-sphere-geometry.js +9 -18
  41. package/dist/geometries/ico-sphere-geometry.js.map +1 -1
  42. package/dist/geometries/plane-geometry.d.ts +2 -2
  43. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  44. package/dist/geometries/plane-geometry.js +10 -19
  45. package/dist/geometries/plane-geometry.js.map +1 -1
  46. package/dist/geometries/sphere-geometry.d.ts +2 -2
  47. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  48. package/dist/geometries/sphere-geometry.js +9 -13
  49. package/dist/geometries/sphere-geometry.js.map +1 -1
  50. package/dist/geometries/truncated-cone-geometry.d.ts +2 -2
  51. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  52. package/dist/geometries/truncated-cone-geometry.js +9 -14
  53. package/dist/geometries/truncated-cone-geometry.js.map +1 -1
  54. package/dist/geometry/geometry-table.d.ts +2 -2
  55. package/dist/geometry/geometry-table.d.ts.map +1 -1
  56. package/dist/geometry/geometry-table.js.map +1 -1
  57. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  58. package/dist/geometry/geometry-utils.js +0 -9
  59. package/dist/geometry/geometry-utils.js.map +1 -1
  60. package/dist/geometry/geometry.d.ts +35 -58
  61. package/dist/geometry/geometry.d.ts.map +1 -1
  62. package/dist/geometry/geometry.js +26 -89
  63. package/dist/geometry/geometry.js.map +1 -1
  64. package/dist/geometry/primitive-utils.js.map +1 -1
  65. package/dist/index.cjs +2574 -0
  66. package/dist/index.d.ts +18 -9
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +20 -13
  69. package/dist/index.js.map +1 -1
  70. package/dist/lib/clip-space.d.ts +8 -0
  71. package/dist/lib/clip-space.d.ts.map +1 -1
  72. package/dist/lib/clip-space.js +36 -1
  73. package/dist/lib/clip-space.js.map +1 -1
  74. package/dist/lib/pipeline-factory.d.ts +19 -14
  75. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  76. package/dist/lib/pipeline-factory.js +52 -63
  77. package/dist/lib/pipeline-factory.js.map +1 -1
  78. package/dist/{lib → model}/model-utils.d.ts +2 -2
  79. package/dist/model/model-utils.d.ts.map +1 -0
  80. package/dist/{lib → model}/model-utils.js +3 -8
  81. package/dist/model/model-utils.js.map +1 -0
  82. package/dist/model/model.d.ts +65 -0
  83. package/dist/model/model.d.ts.map +1 -0
  84. package/dist/{lib → model}/model.js +56 -75
  85. package/dist/model/model.js.map +1 -0
  86. package/dist/scenegraph/group-node.d.ts +21 -0
  87. package/dist/scenegraph/group-node.d.ts.map +1 -0
  88. package/dist/scenegraph/group-node.js +95 -0
  89. package/dist/scenegraph/group-node.js.map +1 -0
  90. package/dist/scenegraph/model-node.d.ts +18 -0
  91. package/dist/scenegraph/model-node.d.ts.map +1 -0
  92. package/dist/scenegraph/model-node.js +29 -0
  93. package/dist/scenegraph/model-node.js.map +1 -0
  94. package/dist/scenegraph/scenegraph-node.d.ts +56 -0
  95. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
  96. package/dist/scenegraph/scenegraph-node.js +142 -0
  97. package/dist/scenegraph/scenegraph-node.js.map +1 -0
  98. package/dist/transform/transform.d.ts +98 -0
  99. package/dist/transform/transform.d.ts.map +1 -0
  100. package/dist/transform/transform.js +67 -0
  101. package/dist/transform/transform.js.map +1 -0
  102. package/dist.min.js +314 -0
  103. package/package.json +22 -12
  104. package/src/animation/timeline.ts +2 -2
  105. package/src/{lib → animation-loop}/animation-loop.ts +115 -97
  106. package/src/{lib → animation-loop}/animation-props.ts +6 -5
  107. package/src/animation-loop/make-animation-loop.ts +44 -0
  108. package/src/animation-loop/render-loop.ts +23 -0
  109. package/src/geometries/cone-geometry.ts +1 -1
  110. package/src/geometries/cube-geometry.ts +6 -3
  111. package/src/geometries/cylinder-geometry.ts +2 -2
  112. package/src/geometries/ico-sphere-geometry.ts +7 -6
  113. package/src/geometries/plane-geometry.ts +5 -4
  114. package/src/geometries/sphere-geometry.ts +4 -3
  115. package/src/geometries/truncated-cone-geometry.ts +4 -3
  116. package/src/geometry/geometry-table.ts +1 -1
  117. package/src/geometry/geometry-utils.ts +3 -3
  118. package/src/geometry/geometry.ts +72 -115
  119. package/src/index.ts +28 -12
  120. package/src/lib/clip-space.ts +17 -15
  121. package/src/lib/pipeline-factory.ts +60 -51
  122. package/src/{lib → model}/model-utils.ts +5 -4
  123. package/src/model/model.ts +226 -0
  124. package/src/scenegraph/group-node.ts +103 -0
  125. package/src/scenegraph/model-node.ts +50 -0
  126. package/src/scenegraph/scenegraph-node.ts +204 -0
  127. package/src/transform/transform.ts +246 -0
  128. package/dist/bundle.d.ts +0 -2
  129. package/dist/bundle.d.ts.map +0 -1
  130. package/dist/bundle.js +0 -5
  131. package/dist/bundle.js.map +0 -1
  132. package/dist/lib/animation-loop.d.ts.map +0 -1
  133. package/dist/lib/animation-loop.js.map +0 -1
  134. package/dist/lib/animation-props.d.ts.map +0 -1
  135. package/dist/lib/animation-props.js.map +0 -1
  136. package/dist/lib/model-utils.d.ts.map +0 -1
  137. package/dist/lib/model-utils.js.map +0 -1
  138. package/dist/lib/model.d.ts +0 -41
  139. package/dist/lib/model.d.ts.map +0 -1
  140. package/dist/lib/model.js.map +0 -1
  141. package/dist/lib/render-loop.d.ts +0 -14
  142. package/dist/lib/render-loop.d.ts.map +0 -1
  143. package/dist/lib/render-loop.js +0 -49
  144. package/dist/lib/render-loop.js.map +0 -1
  145. package/src/bundle.ts +0 -4
  146. package/src/lib/model.ts +0 -179
  147. package/src/lib/render-loop.ts +0 -58
  148. /package/dist/{lib → animation-loop}/animation-props.js +0 -0
@@ -1,34 +1,35 @@
1
- import type {RenderPipelineProps, RenderPipelineParameters} from '@luma.gl/api';
2
- import {Device, RenderPipeline, ComputePipeline} from '@luma.gl/api/';
1
+ import type {RenderPipelineParameters, PrimitiveTopology, ShaderLayout} from '@luma.gl/core';
2
+ import {Device, RenderPipeline} from '@luma.gl/core';
3
3
  import type { ShaderModule } from '@luma.gl/shadertools';
4
4
  import {assembleShaders} from '@luma.gl/shadertools';
5
5
 
6
6
  export type GetRenderPipelineOptions = {
7
- vs: string,
8
- fs: string,
9
- topology;
7
+ vs: string;
8
+ fs: string | null;
9
+ topology: PrimitiveTopology;
10
+ layout?: ShaderLayout | null;
10
11
  parameters?: RenderPipelineParameters;
11
12
 
12
13
  modules?: ShaderModule[];
13
- defines?: Record<string, string>,
14
- inject?: Record<string, string>,
14
+ defines?: Record<string, string | number | boolean>;
15
+ inject?: Record<string, string>;
15
16
  transpileToGLSL100?: boolean;
16
17
 
17
- varyings?: string[],
18
+ varyings?: string[];
18
19
  bufferMode?: number,
19
20
  };
20
21
 
21
22
  export type GetComputePipelineOptions = {
22
- cs: string,
23
- parameters?: RenderPipelineParameters;
23
+ cs: string;
24
+ parameters?: RenderPipelineParameters;
24
25
 
25
26
  modules?: ShaderModule[];
26
- defines?: Record<string, string>,
27
- inject?: Record<string, string>,
27
+ defines?: Record<string, string>;
28
+ inject?: Record<string, string>;
28
29
  transpileToGLSL100?: boolean;
29
30
 
30
- varyings?: string[],
31
- bufferMode?: number,
31
+ varyings?: string[];
32
+ bufferMode?: number;
32
33
  };
33
34
 
34
35
  const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
@@ -38,6 +39,7 @@ const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
38
39
  defines: {},
39
40
  inject: {},
40
41
  transpileToGLSL100: false,
42
+ layout: null,
41
43
 
42
44
  varyings: [],
43
45
  bufferMode: 0x8c8d, // // varyings/bufferMode for xform feedback, 0x8c8d: SEPARATE_ATTRIBS
@@ -45,8 +47,10 @@ const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
45
47
  parameters: {}
46
48
  };
47
49
 
50
+ type GetUniformsFunc = (props?: Record<string, any>) => Record<string, any>;
51
+
48
52
  /** Efficiently create shared pipelines with varying parameters */
49
- export default class PipelineFactory {
53
+ export class PipelineFactory {
50
54
  readonly device: Device;
51
55
 
52
56
  stateHash: number = 0; // Used to change hashing if hooks are modified
@@ -56,7 +60,7 @@ export default class PipelineFactory {
56
60
 
57
61
  private readonly _pipelineCache: Record<string, RenderPipeline> = {};
58
62
 
59
- private readonly _getUniforms: Record<string, any> = {};
63
+ private readonly _getUniforms: Record<string, GetUniformsFunc> = {};
60
64
  private readonly _hookFunctions: any[] = [];
61
65
  private _defaultModules: any[] = [];
62
66
  // private readonly _registeredModules = {}; // TODO: Remove? This isn't used anywhere in luma.gl
@@ -72,20 +76,20 @@ export default class PipelineFactory {
72
76
  this.device = device;
73
77
  }
74
78
 
75
- // addDefaultModule(module: ShaderModule): void {
76
- // if (!this._defaultModules.find((m) => m.name === (typeof module === 'string' ? module : module.name))) {
77
- // this._defaultModules.push(module);
78
- // }
79
- // this.stateHash++;
80
- // }
79
+ addDefaultModule(module: ShaderModule): void {
80
+ if (!this._defaultModules.find((m) => m.name === (typeof module === 'string' ? module : module.name))) {
81
+ this._defaultModules.push(module);
82
+ }
83
+ this.stateHash++;
84
+ }
81
85
 
82
- // removeDefaultModule(module: ShaderModule): void {
83
- // const moduleName = typeof module === 'string' ? module : module.name;
84
- // this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
85
- // this.stateHash++;
86
- // }
86
+ removeDefaultModule(module: ShaderModule): void {
87
+ const moduleName = typeof module === 'string' ? module : module.name;
88
+ this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
89
+ this.stateHash++;
90
+ }
87
91
 
88
- addShaderHook(hook, opts?): void {
92
+ addShaderHook(hook: string, opts?: any): void {
89
93
  if (opts) {
90
94
  hook = Object.assign(opts, {hook});
91
95
  }
@@ -94,8 +98,8 @@ export default class PipelineFactory {
94
98
  }
95
99
 
96
100
  createRenderPipeline(options: GetRenderPipelineOptions): {
97
- renderPipeline: RenderPipeline;
98
- getUniforms: (props: Record<string, Record<string, any>>) => Record<string, any>;
101
+ pipeline: RenderPipeline;
102
+ getUniforms: GetUniformsFunc;
99
103
  } {
100
104
  const props: Required<GetRenderPipelineOptions> = {...DEFAULT_RENDER_PIPELINE_OPTIONS, ...options};
101
105
 
@@ -104,17 +108,17 @@ export default class PipelineFactory {
104
108
  const hash = this._hashRenderPipeline({...props, modules});
105
109
 
106
110
  if (!this._pipelineCache[hash]) {
107
- const {renderPipeline, getUniforms} = this._createRenderPipeline({...props, modules});
108
- renderPipeline.hash = hash;
109
- this._pipelineCache[hash] = renderPipeline;
110
- this._getUniforms[hash] = getUniforms || ((x: Record<string, Record<string, any>>) => {});
111
+ const {pipeline, getUniforms} = this._createRenderPipeline({...props, modules});
112
+ pipeline.hash = hash;
113
+ this._pipelineCache[hash] = pipeline;
114
+ this._getUniforms[hash] = getUniforms || ((x?: unknown) => ({}));
111
115
  this._useCounts[hash] = 0;
112
116
  }
113
117
 
114
118
  this._useCounts[hash]++;
115
119
 
116
120
  return {
117
- renderPipeline: this._pipelineCache[hash],
121
+ pipeline: this._pipelineCache[hash],
118
122
  getUniforms: this._getUniforms[hash]
119
123
  };
120
124
  }
@@ -137,50 +141,55 @@ export default class PipelineFactory {
137
141
  // PRIVATE
138
142
 
139
143
  _createRenderPipeline(props: GetRenderPipelineOptions): {
140
- renderPipeline: RenderPipeline,
141
- getUniforms: (props: Record<string, Record<string, any>>) => Record<string, any>
144
+ pipeline: RenderPipeline,
145
+ getUniforms: GetUniformsFunc
142
146
  } {
143
147
  const platformInfo = {
144
148
  gpu: this.device.info.gpu,
145
149
  features: this.device.features
146
150
  };
147
151
 
148
- const assembled = assembleShaders(platformInfo, {...props, hookFunctions: this._hookFunctions});
152
+ if (!props.fs) {
153
+ throw new Error('fs');
154
+ }
155
+
156
+ const assembled = assembleShaders(platformInfo, {...props, fs: props.fs, hookFunctions: this._hookFunctions});
149
157
 
150
- const renderPipeline = this.device.createRenderPipeline({
158
+ const pipeline = this.device.createRenderPipeline({
151
159
  ...props,
152
160
  vs: this.device.createShader({stage: 'vertex', source: assembled.vs}),
153
- fs: assembled.fs && this.device.createShader({stage: 'fragment', source: assembled.fs}),
161
+ fs: assembled.fs ? this.device.createShader({stage: 'fragment', source: assembled.fs}) : null,
154
162
  });
155
163
 
156
- return {renderPipeline, getUniforms: assembled.getUniforms};
164
+ return {pipeline, getUniforms: assembled.getUniforms};
157
165
  }
158
166
 
159
167
  /** Calculate a hash based on all the inputs for a render pipeline */
160
168
  _hashRenderPipeline(props: GetRenderPipelineOptions): string {
169
+ const {modules = [], varyings = [], defines = {}, inject = {}, parameters = {}} = props;
161
170
  const vsHash = this._getHash(props.vs);
162
- const fsHash = this._getHash(props.fs);
171
+ const fsHash = props.fs ? this._getHash(props.fs) : 0;
163
172
 
164
- const moduleHashes = props.modules.map((m) => this._getHash(typeof m === 'string' ? m : m.name)).sort();
165
- const varyingHashes = props.varyings.map((v) => this._getHash(v));
173
+ const moduleHashes = modules.map((m) => this._getHash(typeof m === 'string' ? m : m.name)).sort();
174
+ const varyingHashes = varyings.map((v) => this._getHash(v));
166
175
 
167
- const defineKeys = Object.keys(props.defines).sort();
168
- const injectKeys = Object.keys(props.inject).sort();
169
- const defineHashes = [];
170
- const injectHashes = [];
176
+ const defineKeys = Object.keys(defines).sort();
177
+ const injectKeys = Object.keys(inject).sort();
178
+ const defineHashes: number[] = [];
179
+ const injectHashes: number[] = [];
171
180
 
172
181
  for (const key of defineKeys) {
173
182
  defineHashes.push(this._getHash(key));
174
- defineHashes.push(this._getHash(props.defines[key]));
183
+ defineHashes.push(this._getHash(String(defines[key])));
175
184
  }
176
185
 
177
186
  for (const key of injectKeys) {
178
187
  injectHashes.push(this._getHash(key));
179
- injectHashes.push(this._getHash(props.inject[key]));
188
+ injectHashes.push(this._getHash(inject[key]));
180
189
  }
181
190
 
182
191
  // TODO - hash parameters!
183
- const parameterHash = JSON.stringify(props.parameters);
192
+ const parameterHash = JSON.stringify(parameters);
184
193
 
185
194
  return `${vsHash}/${fsHash}D${defineHashes.join('/')}M${moduleHashes.join(
186
195
  '/'
@@ -1,5 +1,5 @@
1
- import {Device, Buffer, assert} from '@luma.gl/api';
2
- import type Geometry from '../geometry/geometry';
1
+ import {Device, Buffer, assert} from '@luma.gl/core';
2
+ import type {Geometry} from '../geometry/geometry';
3
3
 
4
4
  // Support for mapping new geometries with glTF attribute names to "classic" luma.gl shader names
5
5
  const GLTF_TO_LUMA_ATTRIBUTE_MAP = {
@@ -72,10 +72,10 @@ export function getAttributeBuffersFromGeometry(device: Device, geometry: Geomet
72
72
 
73
73
  for (const [name, attribute] of Object.entries(geometry.attributes)) {
74
74
  const remappedName = mapAttributeName(name);
75
- if (attribute.constant) {
75
+ if (attribute?.constant) {
76
76
  throw new Error('constant attributes not supported');
77
77
  } else {
78
- const typedArray = attribute.value;
78
+ const typedArray = attribute?.value;
79
79
  buffers[remappedName] = device.createBuffer({data: typedArray, id: `${remappedName}-buffer`});
80
80
  }
81
81
  }
@@ -84,6 +84,7 @@ export function getAttributeBuffersFromGeometry(device: Device, geometry: Geomet
84
84
  }
85
85
 
86
86
  function mapAttributeName(name: string): string {
87
+ // @ts-ignore-error
87
88
  return GLTF_TO_LUMA_ATTRIBUTE_MAP[name] || name;
88
89
  }
89
90
 
@@ -0,0 +1,226 @@
1
+ // luma.gl, MIT license
2
+
3
+ import {
4
+ Device,
5
+ Buffer,
6
+ RenderPipelineProps,
7
+ RenderPass,
8
+ Binding,
9
+ PrimitiveTopology,
10
+ log
11
+ } from '@luma.gl/core';
12
+ import {RenderPipeline} from '@luma.gl/core';
13
+ import type {ShaderModule} from '@luma.gl/shadertools';
14
+ import type {Geometry} from '../geometry/geometry';
15
+ import {getAttributeBuffersFromGeometry, getIndexBufferFromGeometry} from './model-utils';
16
+ import {PipelineFactory} from '../lib/pipeline-factory';
17
+ import {TypedArray} from '@math.gl/core';
18
+
19
+ /** @todo import type */
20
+ type UniformValue = unknown;
21
+
22
+ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
23
+ // Model also accepts a string
24
+ vs?: {glsl?: string; wgsl?: string} | string | null;
25
+ fs?: {glsl?: string; wgsl?: string} | string | null;
26
+ defines?: Record<string, string | number | boolean>;
27
+ modules?: ShaderModule[];
28
+ moduleSettings?: Record<string, Record<string, any>>;
29
+ geometry?: Geometry | null;
30
+ /** deprecated pipeline factory to use to create renderpipelines */
31
+ pipelineFactory?: PipelineFactory;
32
+ };
33
+
34
+ const DEFAULT_MODEL_PROPS: Required<ModelProps> = {
35
+ ...RenderPipeline._DEFAULT_PROPS,
36
+ vs: null,
37
+ fs: null,
38
+ id: 'unnamed',
39
+ handle: undefined,
40
+ userData: {},
41
+ defines: {},
42
+ modules: [],
43
+ moduleSettings: {},
44
+ geometry: null,
45
+ pipelineFactory: undefined
46
+ };
47
+
48
+ /** v9 API */
49
+ export class Model {
50
+ readonly device: Device;
51
+ readonly id: string;
52
+ readonly vs: string;
53
+ readonly fs: string | null = null;
54
+ readonly topology: PrimitiveTopology;
55
+ readonly pipelineFactory: PipelineFactory;
56
+ /** The underlying GPU "program". @note May be recreated if parameters change */
57
+ pipeline: RenderPipeline;
58
+ userData: {[key: string]: any} = {};
59
+
60
+ // readonly props: Required<ModelProps>;
61
+
62
+ /** Vertex count */
63
+ vertexCount: number;
64
+ /** instance count */
65
+ instanceCount: number = 0;
66
+ /** Buffer-valued attributes */
67
+ bufferAttributes: Record<string, Buffer> = {};
68
+ /** Constant-valued attributes */
69
+ constantAttributes: Record<string, TypedArray> = {};
70
+ /** Bindings (textures, samplers, uniform buffers) */
71
+ bindings: Record<string, Binding> = {};
72
+ /** Uniforms */
73
+ uniforms: Record<string, UniformValue> = {};
74
+
75
+ private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
76
+
77
+ constructor(device: Device, props: ModelProps) {
78
+ props = {...DEFAULT_MODEL_PROPS, ...props};
79
+ this.id = props.id;
80
+ this.device = device;
81
+
82
+ Object.assign(this.userData, props.userData);
83
+
84
+ // Create the pipeline
85
+ if (!props.vs) {
86
+ throw new Error('no vertex shader');
87
+ }
88
+ this.vs = getShaderSource(this.device, props.vs);
89
+ if (props.fs) {
90
+ this.fs = getShaderSource(this.device, props.fs);
91
+ }
92
+
93
+ this.vertexCount = props.vertexCount;
94
+ this.instanceCount = props.instanceCount;
95
+ this.topology = props.topology;
96
+
97
+ if (props.geometry) {
98
+ this.vertexCount = props.geometry.vertexCount;
99
+ this.topology = props.geometry.topology || 'triangle-list';
100
+ }
101
+
102
+ this.pipelineFactory =
103
+ props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
104
+ const {pipeline, getUniforms} = this.pipelineFactory.createRenderPipeline({
105
+ ...props,
106
+ vs: this.vs,
107
+ fs: this.fs,
108
+ topology: this.topology,
109
+ defines: props.defines,
110
+ parameters: props.parameters,
111
+ layout: props.layout
112
+ });
113
+
114
+ this.pipeline = pipeline;
115
+ this._getModuleUniforms = getUniforms;
116
+
117
+ if (props.geometry) {
118
+ this._setGeometry(props.geometry);
119
+ }
120
+
121
+ this.setUniforms(this._getModuleUniforms()); // Get all default module uniforms
122
+
123
+ // Props can update any of the above, so call setProps last.
124
+ this.setProps(props);
125
+ }
126
+
127
+ destroy(): void {
128
+ this.pipelineFactory.release(this.pipeline);
129
+ }
130
+
131
+ draw(renderPass: RenderPass): void {
132
+ this.pipeline.draw({
133
+ renderPass,
134
+ vertexCount: this.vertexCount,
135
+ instanceCount: this.instanceCount
136
+ });
137
+ }
138
+
139
+ setProps(props: ModelProps): void {
140
+ if (props.indices) {
141
+ this.setIndexBuffer(props.indices);
142
+ }
143
+ if (props.attributes) {
144
+ this.setAttributes(props.attributes);
145
+ }
146
+ if (props.bindings) {
147
+ this.setBindings(props.bindings);
148
+ }
149
+ if (props.uniforms) {
150
+ this.setUniforms(props.uniforms);
151
+ }
152
+ if (props.moduleSettings) {
153
+ this.updateModuleSettings(props.moduleSettings);
154
+ }
155
+ }
156
+
157
+ updateModuleSettings(props: Record<string, any>): void {
158
+ const uniforms = this._getModuleUniforms(props);
159
+ this.setUniforms(uniforms);
160
+ }
161
+
162
+ setIndexBuffer(indices: Buffer): void {
163
+ this.pipeline.setIndexBuffer(indices);
164
+ // this._indices = indices;
165
+ }
166
+
167
+ setAttributes(bufferAttributes: Record<string, Buffer>): void {
168
+ if (bufferAttributes.indices) {
169
+ log.warn(`Model:${this.id} setAttributes() - indices should be set using setIndexBuffer()`);
170
+ }
171
+
172
+ this.pipeline.setAttributes(bufferAttributes);
173
+ Object.assign(this.bufferAttributes, bufferAttributes);
174
+ }
175
+
176
+ setConstantAttributes(constantAttributes: Record<string, TypedArray>): void {
177
+ // TODO - this doesn't work under WebGPU, we'll need to create buffers or inject uniforms
178
+ this.pipeline.setConstantAttributes(constantAttributes);
179
+ Object.assign(this.constantAttributes, constantAttributes);
180
+ }
181
+
182
+ /** Set the bindings */
183
+ setBindings(bindings: Record<string, Binding>): void {
184
+ this.pipeline.setBindings(bindings);
185
+ Object.assign(this.bindings, bindings);
186
+ }
187
+
188
+ setUniforms(uniforms: Record<string, any>): void {
189
+ this.pipeline.setUniforms(uniforms);
190
+ Object.assign(this.uniforms, uniforms);
191
+ }
192
+
193
+ _setGeometry(geometry: Geometry): void {
194
+ // this._deleteGeometryBuffers();
195
+
196
+ const geometryBuffers = getAttributeBuffersFromGeometry(this.device, geometry);
197
+ this.setAttributes(geometryBuffers);
198
+
199
+ const indexBuffer = getIndexBufferFromGeometry(this.device, geometry);
200
+ if (indexBuffer) {
201
+ this.setIndexBuffer(indexBuffer);
202
+ }
203
+ }
204
+ }
205
+
206
+ /** Create a shader from the different overloads */
207
+ function getShaderSource(device: Device, shader: string | {glsl?: string; wgsl?: string}): string {
208
+ // TODO - detect WGSL/GLSL and throw an error if not supported
209
+ if (typeof shader === 'string') {
210
+ return shader;
211
+ }
212
+
213
+ switch (device.info.type) {
214
+ case 'webgpu':
215
+ if (shader?.wgsl) {
216
+ return shader.wgsl;
217
+ }
218
+ throw new Error('WebGPU does not support GLSL shaders');
219
+
220
+ default:
221
+ if (shader?.glsl) {
222
+ return shader.glsl;
223
+ }
224
+ throw new Error('WebGL does not support WGSL shaders');
225
+ }
226
+ }
@@ -0,0 +1,103 @@
1
+ import {Matrix4, Vector3} from '@math.gl/core';
2
+ import {log} from '@luma.gl/core';
3
+ import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
4
+
5
+ export type GroupNodeProps = ScenegraphNodeProps & {
6
+ children?: ScenegraphNode[];
7
+ }
8
+
9
+ export class GroupNode extends ScenegraphNode {
10
+ children: ScenegraphNode[];
11
+
12
+ constructor(children: ScenegraphNode[]);
13
+ constructor(props?: GroupNodeProps);
14
+
15
+ constructor(props: ScenegraphNode[] | GroupNodeProps = {}) {
16
+ props = Array.isArray(props) ? {children: props} : props;
17
+ const {children = []} = props;
18
+ log.assert(
19
+ children.every((child) => child instanceof ScenegraphNode),
20
+ 'every child must an instance of ScenegraphNode'
21
+ );
22
+ super(props);
23
+ this.children = children;
24
+ }
25
+
26
+ override getBounds(): [number[], number[]] | null {
27
+ const result: [number[], number[]] = [[Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]];
28
+
29
+ this.traverse((node, {worldMatrix}) => {
30
+ const bounds = node.getBounds();
31
+ if (!bounds) {
32
+ return;
33
+ }
34
+ const [min, max] = bounds;
35
+ const center = new Vector3(min).add(max).divide([2, 2, 2]);
36
+ worldMatrix.transformAsPoint(center, center);
37
+ const halfSize = new Vector3(max).subtract(min).divide([2, 2, 2]);
38
+ worldMatrix.transformAsVector(halfSize, halfSize);
39
+
40
+ for (let v = 0; v < 8; v++) {
41
+ // Test all 8 corners of the box
42
+ const position = new Vector3(
43
+ v & 0b001 ? -1 : 1,
44
+ v & 0b010 ? -1 : 1,
45
+ v & 0b100 ? -1 : 1
46
+ ).multiply(halfSize).add(center);
47
+
48
+ for (let i = 0; i < 3; i++) {
49
+ result[0][i] = Math.min(result[0][i], position[i]);
50
+ result[1][i] = Math.max(result[1][i], position[i]);
51
+ }
52
+ }
53
+ });
54
+ if (!Number.isFinite(result[0][0])) {
55
+ return null;
56
+ }
57
+ return result;
58
+ }
59
+
60
+ override destroy(): void {
61
+ this.children.forEach((child) => child.destroy());
62
+ this.removeAll();
63
+ super.destroy();
64
+ }
65
+
66
+ // Unpacks arrays and nested arrays of children
67
+ add(...children: (ScenegraphNode | ScenegraphNode[])[]): this {
68
+ for (const child of children) {
69
+ if (Array.isArray(child)) {
70
+ this.add(...child);
71
+ } else {
72
+ this.children.push(child);
73
+ }
74
+ }
75
+ return this;
76
+ }
77
+
78
+ remove(child: ScenegraphNode): this {
79
+ const children = this.children;
80
+ const indexOf = children.indexOf(child);
81
+ if (indexOf > -1) {
82
+ children.splice(indexOf, 1);
83
+ }
84
+ return this;
85
+ }
86
+
87
+ removeAll(): this {
88
+ this.children = [];
89
+ return this;
90
+ }
91
+
92
+ traverse(visitor: (node: ScenegraphNode, context: {worldMatrix: Matrix4}) => void, {worldMatrix = new Matrix4()} = {}) {
93
+ const modelMatrix = new Matrix4(worldMatrix).multiplyRight(this.matrix);
94
+
95
+ for (const child of this.children) {
96
+ if (child instanceof GroupNode) {
97
+ child.traverse(visitor, {worldMatrix: modelMatrix});
98
+ } else {
99
+ visitor(child, {worldMatrix: modelMatrix});
100
+ }
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,50 @@
1
+ import {RenderPass} from '@luma.gl/core';
2
+ import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
3
+ import {Model} from '../model/model';
4
+
5
+ export type ModelNodeProps = ScenegraphNodeProps & {
6
+ model: Model;
7
+ managedResources?: any[];
8
+ bounds?: [number[], number[]];
9
+ }
10
+
11
+ export class ModelNode extends ScenegraphNode {
12
+ readonly model: Model;
13
+ bounds: [number[], number[]] | null = null;
14
+ managedResources: any[];
15
+
16
+ // TODO - is this used? override callbacks to make sure we call them with this
17
+ // onBeforeRender = null;
18
+ // onAfterRender = null;
19
+ // AfterRender = null;
20
+
21
+ constructor(props: ModelNodeProps) {
22
+ super(props);
23
+
24
+ // Create new Model or used supplied Model
25
+ this.model = props.model;
26
+ this.managedResources = props.managedResources || [];
27
+ this.bounds = props.bounds || null;
28
+ this.setProps(props);
29
+ }
30
+
31
+ override getBounds(): [number[], number[]] | null {
32
+ return this.bounds;
33
+ }
34
+
35
+ override destroy(): void {
36
+ if (this.model) {
37
+ this.model.destroy();
38
+ // @ts-expect-error
39
+ this.model = null;
40
+ }
41
+ this.managedResources.forEach((resource) => resource.destroy());
42
+ this.managedResources = [];
43
+ }
44
+
45
+ // Expose model methods
46
+ draw(renderPass?: RenderPass) {
47
+ // Return value indicates if something was actually drawn
48
+ return this.model.draw(renderPass);
49
+ }
50
+ }