@luma.gl/engine 9.1.9 → 9.2.0-alpha.2

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 (102) hide show
  1. package/README.md +5 -0
  2. package/dist/animation-loop/animation-loop.d.ts +12 -12
  3. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  4. package/dist/animation-loop/animation-loop.js +26 -62
  5. package/dist/animation-loop/animation-loop.js.map +1 -1
  6. package/dist/animation-loop/animation-props.d.ts +3 -4
  7. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  8. package/dist/animation-loop/make-animation-loop.d.ts +4 -1
  9. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  10. package/dist/animation-loop/make-animation-loop.js +39 -7
  11. package/dist/animation-loop/make-animation-loop.js.map +1 -1
  12. package/dist/async-texture/async-texture.d.ts +106 -2
  13. package/dist/async-texture/async-texture.d.ts.map +1 -1
  14. package/dist/async-texture/async-texture.js +281 -13
  15. package/dist/async-texture/async-texture.js.map +1 -1
  16. package/dist/compute/computation.d.ts +1 -1
  17. package/dist/compute/computation.d.ts.map +1 -1
  18. package/dist/compute/computation.js +2 -2
  19. package/dist/compute/computation.js.map +1 -1
  20. package/dist/compute/swap.d.ts.map +1 -1
  21. package/dist/compute/swap.js +6 -2
  22. package/dist/compute/swap.js.map +1 -1
  23. package/dist/compute/texture-transform.d.ts.map +1 -1
  24. package/dist/compute/texture-transform.js +4 -2
  25. package/dist/compute/texture-transform.js.map +1 -1
  26. package/dist/debug/copy-texture-to-image.d.ts +23 -1
  27. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  28. package/dist/debug/copy-texture-to-image.js +37 -1
  29. package/dist/debug/copy-texture-to-image.js.map +1 -1
  30. package/dist/dist.dev.js +566 -232
  31. package/dist/dist.min.js +26 -26
  32. package/dist/factories/pipeline-factory.d.ts +11 -1
  33. package/dist/factories/pipeline-factory.d.ts.map +1 -1
  34. package/dist/factories/pipeline-factory.js +107 -25
  35. package/dist/factories/pipeline-factory.js.map +1 -1
  36. package/dist/factories/shader-factory.d.ts +5 -1
  37. package/dist/factories/shader-factory.d.ts.map +1 -1
  38. package/dist/factories/shader-factory.js +40 -6
  39. package/dist/factories/shader-factory.js.map +1 -1
  40. package/dist/geometries/cube-geometry.d.ts +3 -3
  41. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  42. package/dist/geometry/geometry.d.ts.map +1 -1
  43. package/dist/geometry/geometry.js +3 -2
  44. package/dist/geometry/geometry.js.map +1 -1
  45. package/dist/index.cjs +581 -251
  46. package/dist/index.cjs.map +4 -4
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/model/model.d.ts +4 -25
  51. package/dist/model/model.d.ts.map +1 -1
  52. package/dist/model/model.js +26 -71
  53. package/dist/model/model.js.map +1 -1
  54. package/dist/models/billboard-texture-model.d.ts.map +1 -1
  55. package/dist/models/billboard-texture-model.js +6 -4
  56. package/dist/models/billboard-texture-model.js.map +1 -1
  57. package/dist/modules/picking/legacy-picking-manager.d.ts +1 -1
  58. package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -1
  59. package/dist/modules/picking/legacy-picking-manager.js +1 -1
  60. package/dist/modules/picking/legacy-picking-manager.js.map +1 -1
  61. package/dist/modules/picking/picking-manager.d.ts +2 -2
  62. package/dist/modules/picking/picking-manager.d.ts.map +1 -1
  63. package/dist/modules/picking/picking-manager.js +2 -2
  64. package/dist/modules/picking/picking-manager.js.map +1 -1
  65. package/dist/passes/get-fragment-shader.js +2 -2
  66. package/dist/passes/shader-pass-renderer.d.ts +4 -4
  67. package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
  68. package/dist/passes/shader-pass-renderer.js +15 -5
  69. package/dist/passes/shader-pass-renderer.js.map +1 -1
  70. package/dist/shader-inputs.js +1 -1
  71. package/dist/shader-inputs.js.map +1 -1
  72. package/dist/utils/buffer-layout-helper.d.ts +12 -0
  73. package/dist/utils/buffer-layout-helper.d.ts.map +1 -0
  74. package/dist/utils/buffer-layout-helper.js +41 -0
  75. package/dist/utils/buffer-layout-helper.js.map +1 -0
  76. package/dist/utils/buffer-layout-order.d.ts +3 -0
  77. package/dist/utils/buffer-layout-order.d.ts.map +1 -0
  78. package/dist/utils/buffer-layout-order.js +16 -0
  79. package/dist/utils/buffer-layout-order.js.map +1 -0
  80. package/package.json +4 -4
  81. package/src/animation-loop/animation-loop.ts +31 -71
  82. package/src/animation-loop/animation-props.ts +3 -5
  83. package/src/animation-loop/make-animation-loop.ts +41 -9
  84. package/src/async-texture/async-texture.ts +386 -23
  85. package/src/async-texture/texture-setters.ts.disabled +296 -0
  86. package/src/compute/computation.ts +3 -3
  87. package/src/compute/swap.ts +7 -2
  88. package/src/compute/texture-transform.ts +4 -2
  89. package/src/debug/copy-texture-to-image.ts +52 -2
  90. package/src/factories/pipeline-factory.ts +122 -26
  91. package/src/factories/shader-factory.ts +43 -7
  92. package/src/geometry/geometry.ts +3 -2
  93. package/src/index.ts +12 -0
  94. package/src/model/model.ts +31 -86
  95. package/src/models/billboard-texture-model.ts +6 -4
  96. package/src/modules/picking/legacy-picking-manager.ts +2 -2
  97. package/src/modules/picking/picking-manager.ts +3 -3
  98. package/src/passes/get-fragment-shader.ts +2 -2
  99. package/src/passes/shader-pass-renderer.ts +18 -8
  100. package/src/shader-inputs.ts +1 -1
  101. package/src/utils/buffer-layout-helper.ts +51 -0
  102. package/src/utils/buffer-layout-order.ts +26 -0
@@ -2,24 +2,20 @@
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
4
  import type {
5
- Texture,
6
5
  TextureProps,
7
- Sampler,
6
+ SamplerProps,
8
7
  TextureView,
9
8
  Device,
10
- Texture1DData,
11
- Texture2DData,
12
- Texture3DData,
13
- TextureArrayData,
14
- TextureCubeData,
15
- TextureCubeArrayData
9
+ TypedArray,
10
+ TextureFormat,
11
+ ExternalImage
16
12
  } from '@luma.gl/core';
17
13
 
14
+ import {Texture, Sampler, log} from '@luma.gl/core';
15
+
18
16
  import {loadImageBitmap} from '../application-utils/load-file';
19
17
  import {uid} from '../utils/uid';
20
18
 
21
- export type AsyncTextureProps = Omit<TextureProps, 'data'> & AsyncTextureDataProps;
22
-
23
19
  type AsyncTextureDataProps =
24
20
  | AsyncTexture1DProps
25
21
  | AsyncTexture2DProps
@@ -44,9 +40,73 @@ type AsyncTextureCubeArrayProps = {
44
40
  data: Promise<TextureCubeArrayData> | TextureCubeArrayData | null;
45
41
  };
46
42
 
47
- type TextureData = TextureProps['data'];
48
43
  type AsyncTextureData = AsyncTextureProps['data'];
49
44
 
45
+ /** Names of cube texture faces */
46
+ export type TextureCubeFace = '+X' | '-X' | '+Y' | '-Y' | '+Z' | '-Z';
47
+ export const TextureCubeFaces: TextureCubeFace[] = ['+X', '-X', '+Y', '-Y', '+Z', '-Z'];
48
+ // prettier-ignore
49
+ export const TextureCubeFaceMap = {'+X': 0, '-X': 1, '+Y': 2, '-Y': 3, '+Z': 4, '-Z': 5};
50
+
51
+ /**
52
+ * One mip level
53
+ * Basic data structure is similar to `ImageData`
54
+ * additional optional fields can describe compressed texture data.
55
+ */
56
+ export type TextureImageData = {
57
+ /** WebGPU style format string. Defaults to 'rgba8unorm' */
58
+ format?: TextureFormat;
59
+ data: TypedArray;
60
+ width: number;
61
+ height: number;
62
+
63
+ compressed?: boolean;
64
+ byteLength?: number;
65
+ hasAlpha?: boolean;
66
+ };
67
+
68
+ export type TextureLevelSource = TextureImageData | ExternalImage;
69
+
70
+ /** Texture data can be one or more mip levels */
71
+ export type TextureData = TextureImageData | ExternalImage | (TextureImageData | ExternalImage)[];
72
+
73
+ /** @todo - define what data type is supported for 1D textures */
74
+ export type Texture1DData = TypedArray | TextureImageData;
75
+
76
+ /** Texture data can be one or more mip levels */
77
+ export type Texture2DData =
78
+ | TypedArray
79
+ | TextureImageData
80
+ | ExternalImage
81
+ | (TextureImageData | ExternalImage)[];
82
+
83
+ /** 6 face textures */
84
+ export type TextureCubeData = Record<TextureCubeFace, TextureData>;
85
+
86
+ /** Array of textures */
87
+ export type Texture3DData = TextureData[];
88
+
89
+ /** Array of textures */
90
+ export type TextureArrayData = TextureData[];
91
+
92
+ /** Array of 6 face textures */
93
+ export type TextureCubeArrayData = Record<TextureCubeFace, TextureData>[];
94
+
95
+ export const CubeFaces: TextureCubeFace[] = ['+X', '-X', '+Y', '-Y', '+Z', '-Z'];
96
+
97
+ /** Properties for an async texture */
98
+ export type AsyncTextureProps = Omit<TextureProps, 'data' | 'mipLevels' | 'width' | 'height'> &
99
+ AsyncTextureDataProps & {
100
+ /** Generate mipmaps after creating textures and setting data */
101
+ mipmaps?: boolean;
102
+ /** nipLevels can be set to 'auto' to generate max number of mipLevels */
103
+ mipLevels?: number | 'auto';
104
+ /** Width - can be auto-calculated when initializing from ExternalImage */
105
+ width?: number;
106
+ /** Height - can be auto-calculated when initializing from ExternalImage */
107
+ height?: number;
108
+ };
109
+
50
110
  /**
51
111
  * It is very convenient to be able to initialize textures with promises
52
112
  * This can add considerable complexity to the Texture class, and doesn't
@@ -56,6 +116,7 @@ type AsyncTextureData = AsyncTextureProps['data'];
56
116
  export class AsyncTexture {
57
117
  readonly device: Device;
58
118
  readonly id: string;
119
+ props: Required<Omit<AsyncTextureProps, 'data'>>;
59
120
 
60
121
  // TODO - should we type these as possibly `null`? It will make usage harder?
61
122
  // @ts-expect-error
@@ -82,12 +143,21 @@ export class AsyncTexture {
82
143
 
83
144
  constructor(device: Device, props: AsyncTextureProps) {
84
145
  this.device = device;
85
- this.id = props.id || uid('async-texture');
86
- // this.id = typeof props?.data === 'string' ? props.data.slice(-20) : uid('async-texture');
87
146
 
147
+ // TODO - if we support URL strings as data...
148
+ const id = uid('async-texture'); // typeof props?.data === 'string' ? props.data.slice(-20) : uid('async-texture');
149
+ this.props = {...AsyncTexture.defaultProps, id, ...props};
150
+ this.id = this.props.id;
151
+
152
+ props = {...props};
88
153
  // Signature: new AsyncTexture(device, {data: url})
89
154
  if (typeof props?.data === 'string' && props.dimension === '2d') {
90
- props = {...props, data: loadImageBitmap(props.data)};
155
+ props.data = loadImageBitmap(props.data);
156
+ }
157
+
158
+ // If mipmaps are requested, we need to allocate space for them
159
+ if (props.mipmaps) {
160
+ props.mipLevels = 'auto';
91
161
  }
92
162
 
93
163
  this.ready = new Promise<void>((resolve, reject) => {
@@ -102,13 +172,11 @@ export class AsyncTexture {
102
172
  }
103
173
 
104
174
  async initAsync(props: AsyncTextureProps): Promise<void> {
175
+ let resolveReady;
176
+ let rejectReady;
177
+
105
178
  const asyncData: AsyncTextureData = props.data;
106
- let data: TextureData;
107
- try {
108
- data = await awaitAllPromises(asyncData);
109
- } catch (error) {
110
- this.rejectReady(error as Error);
111
- }
179
+ const data: TextureData = await awaitAllPromises(asyncData).then(resolveReady, rejectReady);
112
180
 
113
181
  // Check that we haven't been destroyed while waiting for texture data to load
114
182
  if (this.destroyed) {
@@ -116,14 +184,57 @@ export class AsyncTexture {
116
184
  }
117
185
 
118
186
  // Now we can actually create the texture
119
- // @ts-expect-error Discriminated union
120
- const syncProps: TextureProps = {...props, data};
187
+
188
+ // Auto-deduce width and height if not supplied
189
+ const size =
190
+ this.props.width && this.props.height
191
+ ? {width: this.props.width, height: this.props.height}
192
+ : this.getTextureDataSize(data);
193
+ if (!size) {
194
+ throw new Error('Texture size could not be determined');
195
+ }
196
+ const syncProps: TextureProps = {...size, ...props, data: undefined, mipLevels: 1};
197
+
198
+ // Auto-calculate the number of mip levels as a convenience
199
+ // TODO - Should we clamp to 1-getMipLevelCount?
200
+ const maxMips = this.device.getMipLevelCount(syncProps.width, syncProps.height);
201
+ syncProps.mipLevels =
202
+ this.props.mipLevels === 'auto' ? maxMips : Math.min(maxMips, this.props.mipLevels);
121
203
 
122
204
  this.texture = this.device.createTexture(syncProps);
123
205
  this.sampler = this.texture.sampler;
124
206
  this.view = this.texture.view;
125
207
  this.isReady = true;
126
- this.resolveReady();
208
+
209
+ if (props.data) {
210
+ switch (this.props.dimension) {
211
+ case '1d':
212
+ this._setTexture1DData(this.texture, data as Texture1DData);
213
+ break;
214
+ case '2d':
215
+ this._setTexture2DData(data);
216
+ break;
217
+ case '3d':
218
+ this._setTexture3DData(this.texture, data as Texture3DData);
219
+ break;
220
+ case '2d-array':
221
+ this._setTextureArrayData(this.texture, data as TextureArrayData);
222
+ break;
223
+ case 'cube':
224
+ this._setTextureCubeData(this.texture, data as unknown as TextureCubeData);
225
+ break;
226
+ case 'cube-array':
227
+ this._setTextureCubeArrayData(this.texture, data as unknown as TextureCubeArrayData);
228
+ break;
229
+ }
230
+ }
231
+
232
+ // Do we need to generate mipmaps?
233
+ if (this.props.mipmaps) {
234
+ this.generateMipmaps();
235
+ }
236
+
237
+ log.info(1, `${this} loaded`);
127
238
  }
128
239
 
129
240
  destroy(): void {
@@ -135,10 +246,24 @@ export class AsyncTexture {
135
246
  this.destroyed = true;
136
247
  }
137
248
 
249
+ generateMipmaps(): void {
250
+ // if (this.device.type === 'webgl') {
251
+ this.texture.generateMipmapsWebGL();
252
+ // }
253
+ }
254
+
255
+ /** Set sampler or create and set new Sampler from SamplerProps */
256
+ setSampler(sampler: Sampler | SamplerProps = {}): void {
257
+ this.texture.setSampler(
258
+ sampler instanceof Sampler ? sampler : this.device.createSampler(sampler)
259
+ );
260
+ }
261
+
138
262
  /**
139
263
  * Textures are immutable and cannot be resized after creation,
140
264
  * but we can create a similar texture with the same parameters but a new size.
141
265
  * @note Does not copy contents of the texture
266
+ * @note Mipmaps may need to be regenerated after resizing / setting new data
142
267
  * @todo Abort pending promise and create a texture with the new size?
143
268
  */
144
269
  resize(size: {width: number; height: number}): boolean {
@@ -155,9 +280,247 @@ export class AsyncTexture {
155
280
  this.texture = texture.clone(size);
156
281
  texture.destroy();
157
282
  }
283
+
158
284
  return true;
159
285
  }
286
+
287
+ /** Check if texture data is a typed array */
288
+ isTextureLevelData(data: TextureData): data is TextureImageData {
289
+ const typedArray = (data as TextureImageData)?.data;
290
+ return ArrayBuffer.isView(typedArray);
291
+ }
292
+
293
+ /** Get the size of the texture described by the provided TextureData */
294
+ getTextureDataSize(
295
+ data: TextureData | TextureCubeData | TextureArrayData | TextureCubeArrayData | TypedArray
296
+ ): {width: number; height: number} | null {
297
+ if (!data) {
298
+ return null;
299
+ }
300
+ if (ArrayBuffer.isView(data)) {
301
+ return null;
302
+ }
303
+ // Recurse into arrays (array of miplevels)
304
+ if (Array.isArray(data)) {
305
+ return this.getTextureDataSize(data[0]);
306
+ }
307
+ if (this.device.isExternalImage(data)) {
308
+ return this.device.getExternalImageSize(data);
309
+ }
310
+ if (data && typeof data === 'object' && data.constructor === Object) {
311
+ const textureDataArray = Object.values(data);
312
+ const untypedData = textureDataArray[0];
313
+ return {width: untypedData.width, height: untypedData.height};
314
+ }
315
+ throw new Error('texture size deduction failed');
316
+ }
317
+
318
+ /** Convert luma.gl cubemap face constants to depth index */
319
+ getCubeFaceDepth(face: TextureCubeFace): number {
320
+ // prettier-ignore
321
+ switch (face) {
322
+ case '+X': return 0;
323
+ case '-X': return 1;
324
+ case '+Y': return 2;
325
+ case '-Y': return 3;
326
+ case '+Z': return 4;
327
+ case '-Z': return 5;
328
+ default: throw new Error(face);
329
+ }
330
+ }
331
+
332
+ // EXPERIMENTAL
333
+
334
+ setTextureData(data: TextureData) {}
335
+
336
+ /** Experimental: Set multiple mip levels */
337
+ _setTexture1DData(texture: Texture, data: Texture1DData): void {
338
+ throw new Error('setTexture1DData not supported in WebGL.');
339
+ }
340
+
341
+ /** Experimental: Set multiple mip levels */
342
+ _setTexture2DData(lodData: Texture2DData, depth = 0): void {
343
+ if (!this.texture) {
344
+ throw new Error('Texture not initialized');
345
+ }
346
+
347
+ const lodArray = this._normalizeTextureData(lodData);
348
+
349
+ // If the user provides multiple LODs, then automatic mipmap
350
+ // generation generateMipmap() should be disabled to avoid overwriting them.
351
+ if (lodArray.length > 1 && this.props.mipmaps !== false) {
352
+ log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
353
+ }
354
+
355
+ for (let mipLevel = 0; mipLevel < lodArray.length; mipLevel++) {
356
+ const imageData = lodArray[mipLevel];
357
+ if (this.device.isExternalImage(imageData)) {
358
+ this.texture.copyExternalImage({image: imageData, depth, mipLevel, flipY: true});
359
+ } else {
360
+ this.texture.copyImageData({data: imageData.data /* , depth */, mipLevel});
361
+ }
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Experimental: Sets 3D texture data: multiple depth slices, multiple mip levels
367
+ * @param data
368
+ */
369
+ _setTexture3DData(texture: Texture, data: Texture3DData): void {
370
+ if (this.texture?.props.dimension !== '3d') {
371
+ throw new Error(this.id);
372
+ }
373
+ for (let depth = 0; depth < data.length; depth++) {
374
+ this._setTexture2DData(data[depth], depth);
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Experimental: Set Cube texture data, multiple faces, multiple mip levels
380
+ * @todo - could support TextureCubeArray with depth
381
+ * @param data
382
+ * @param index
383
+ */
384
+ _setTextureCubeData(texture: Texture, data: TextureCubeData): void {
385
+ if (this.texture?.props.dimension !== 'cube') {
386
+ throw new Error(this.id);
387
+ }
388
+ for (const [face, faceData] of Object.entries(data)) {
389
+ const faceDepth = CubeFaces.indexOf(face as TextureCubeFace);
390
+ this._setTexture2DData(faceData, faceDepth);
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Experimental: Sets texture array data, multiple levels, multiple depth slices
396
+ * @param data
397
+ */
398
+ _setTextureArrayData(texture: Texture, data: TextureArrayData): void {
399
+ if (this.texture?.props.dimension !== '2d-array') {
400
+ throw new Error(this.id);
401
+ }
402
+ for (let depth = 0; depth < data.length; depth++) {
403
+ this._setTexture2DData(data[depth], depth);
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Experimental: Sets texture cube array, multiple faces, multiple levels, multiple mip levels
409
+ * @param data
410
+ */
411
+ _setTextureCubeArrayData(texture: Texture, data: TextureCubeArrayData): void {
412
+ throw new Error('setTextureCubeArrayData not supported in WebGL2.');
413
+ }
414
+
415
+ /** Experimental */
416
+ _setTextureCubeFaceData(
417
+ texture: Texture,
418
+ lodData: Texture2DData,
419
+ face: TextureCubeFace,
420
+ depth: number = 0
421
+ ): void {
422
+ // assert(this.props.dimension === 'cube');
423
+
424
+ // If the user provides multiple LODs, then automatic mipmap
425
+ // generation generateMipmap() should be disabled to avoid overwriting them.
426
+ if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
427
+ log.warn(`${this.id} has mipmap and multiple LODs.`)();
428
+ }
429
+
430
+ const faceDepth = TextureCubeFaces.indexOf(face);
431
+ this._setTexture2DData(lodData, faceDepth);
432
+ }
433
+
434
+ /**
435
+ * Normalize TextureData to an array of TextureImageData / ExternalImages
436
+ * @param data
437
+ * @param options
438
+ * @returns array of TextureImageData / ExternalImages
439
+ */
440
+ _normalizeTextureData(data: Texture2DData): (TextureImageData | ExternalImage)[] {
441
+ const options: {width: number; height: number; depth: number} = this.texture;
442
+ let mipLevelArray: (TextureImageData | ExternalImage)[];
443
+ if (ArrayBuffer.isView(data)) {
444
+ mipLevelArray = [
445
+ {
446
+ // ts-expect-error does data really need to be Uint8ClampedArray?
447
+ data,
448
+ width: options.width,
449
+ height: options.height
450
+ // depth: options.depth
451
+ }
452
+ ];
453
+ } else if (!Array.isArray(data)) {
454
+ mipLevelArray = [data];
455
+ } else {
456
+ mipLevelArray = data;
457
+ }
458
+ return mipLevelArray;
459
+ }
460
+
461
+ static defaultProps: Required<AsyncTextureProps> = {
462
+ ...Texture.defaultProps,
463
+ data: null,
464
+ mipmaps: false
465
+ };
466
+ }
467
+
468
+ // TODO - Remove when texture refactor is complete
469
+
470
+ /*
471
+ setCubeMapData(options: {
472
+ width: number;
473
+ height: number;
474
+ data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
475
+ format?: any;
476
+ type?: any;
477
+ /** @deprecated Use .data *
478
+ pixels: any;
479
+ }): void {
480
+ const {gl} = this;
481
+
482
+ const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
483
+
484
+ // pixel data (imageDataMap) is an Object from Face to Image or Promise.
485
+ // For example:
486
+ // {
487
+ // GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
488
+ // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
489
+ // ... }
490
+ // To provide multiple level-of-details (LODs) this can be Face to Array
491
+ // of Image or Promise, like this
492
+ // {
493
+ // GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
494
+ // GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
495
+ // ... }
496
+
497
+ const imageDataMap = this._getImageDataMap(pixels || data);
498
+
499
+ const resolvedFaces = WEBGLTexture.FACES.map(face => {
500
+ const facePixels = imageDataMap[face];
501
+ return Array.isArray(facePixels) ? facePixels : [facePixels];
502
+ });
503
+ this.bind();
504
+
505
+ WEBGLTexture.FACES.forEach((face, index) => {
506
+ if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
507
+ // If the user provides multiple LODs, then automatic mipmap
508
+ // generation generateMipmaps() should be disabled to avoid overwritting them.
509
+ log.warn(`${this.id} has mipmap and multiple LODs.`)();
510
+ }
511
+ resolvedFaces[index].forEach((image, lodLevel) => {
512
+ // TODO: adjust width & height for LOD!
513
+ if (width && height) {
514
+ gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
515
+ } else {
516
+ gl.texImage2D(face, lodLevel, format, format, type, image);
517
+ }
518
+ });
519
+ });
520
+
521
+ this.unbind();
160
522
  }
523
+ */
161
524
 
162
525
  // HELPERS
163
526