@loaders.gl/textures 4.4.0-alpha.16 → 4.4.0-alpha.17

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 (74) hide show
  1. package/README.md +44 -0
  2. package/dist/basis-loader.d.ts +17 -8
  3. package/dist/basis-loader.d.ts.map +1 -1
  4. package/dist/basis-loader.js.map +1 -1
  5. package/dist/basis-worker-node.js +317 -188
  6. package/dist/basis-worker.js +252 -123
  7. package/dist/compressed-texture-worker.js +1035 -326
  8. package/dist/crunch-worker.js +141 -82
  9. package/dist/dist.dev.js +1220 -334
  10. package/dist/dist.min.js +1 -2
  11. package/dist/index.cjs +657 -317
  12. package/dist/index.cjs.map +4 -4
  13. package/dist/index.d.ts +2 -4
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -3
  16. package/dist/index.js.map +1 -1
  17. package/dist/ktx2-basis-writer-worker-node.js +2 -2
  18. package/dist/ktx2-basis-writer-worker.js +2 -2
  19. package/dist/lib/gl-extensions.d.ts +164 -58
  20. package/dist/lib/gl-extensions.d.ts.map +1 -1
  21. package/dist/lib/gl-extensions.js +175 -66
  22. package/dist/lib/gl-extensions.js.map +1 -1
  23. package/dist/lib/parsers/parse-basis.d.ts +16 -1
  24. package/dist/lib/parsers/parse-basis.d.ts.map +1 -1
  25. package/dist/lib/parsers/parse-basis.js +216 -43
  26. package/dist/lib/parsers/parse-basis.js.map +1 -1
  27. package/dist/lib/parsers/parse-crunch.d.ts.map +1 -1
  28. package/dist/lib/parsers/parse-crunch.js +4 -4
  29. package/dist/lib/parsers/parse-crunch.js.map +1 -1
  30. package/dist/lib/parsers/parse-dds.d.ts.map +1 -1
  31. package/dist/lib/parsers/parse-dds.js +7 -7
  32. package/dist/lib/parsers/parse-dds.js.map +1 -1
  33. package/dist/lib/parsers/parse-ktx.d.ts.map +1 -1
  34. package/dist/lib/parsers/parse-ktx.js +7 -0
  35. package/dist/lib/parsers/parse-ktx.js.map +1 -1
  36. package/dist/lib/parsers/parse-pvr.d.ts.map +1 -1
  37. package/dist/lib/parsers/parse-pvr.js +28 -70
  38. package/dist/lib/parsers/parse-pvr.js.map +1 -1
  39. package/dist/lib/utils/detect-supported-texture-formats.d.ts +14 -0
  40. package/dist/lib/utils/detect-supported-texture-formats.d.ts.map +1 -0
  41. package/dist/lib/utils/detect-supported-texture-formats.js +197 -0
  42. package/dist/lib/utils/detect-supported-texture-formats.js.map +1 -0
  43. package/dist/lib/utils/extract-mipmap-images.d.ts +2 -2
  44. package/dist/lib/utils/extract-mipmap-images.d.ts.map +1 -1
  45. package/dist/lib/utils/extract-mipmap-images.js +12 -2
  46. package/dist/lib/utils/extract-mipmap-images.js.map +1 -1
  47. package/dist/lib/utils/ktx-format-helper.d.ts +2 -1
  48. package/dist/lib/utils/ktx-format-helper.d.ts.map +1 -1
  49. package/dist/lib/utils/ktx-format-helper.js +67 -109
  50. package/dist/lib/utils/ktx-format-helper.js.map +1 -1
  51. package/dist/lib/utils/texture-format-map.d.ts +3 -0
  52. package/dist/lib/utils/texture-format-map.d.ts.map +1 -0
  53. package/dist/lib/utils/texture-format-map.js +71 -0
  54. package/dist/lib/utils/texture-format-map.js.map +1 -0
  55. package/dist/lib/utils/version.js +1 -1
  56. package/dist/npy-worker.js +1 -1
  57. package/package.json +6 -6
  58. package/src/basis-loader.ts +21 -8
  59. package/src/index.ts +2 -4
  60. package/src/lib/gl-extensions.ts +186 -81
  61. package/src/lib/parsers/parse-basis.ts +274 -40
  62. package/src/lib/parsers/parse-crunch.ts +13 -6
  63. package/src/lib/parsers/parse-dds.ts +16 -9
  64. package/src/lib/parsers/parse-ktx.ts +12 -2
  65. package/src/lib/parsers/parse-pvr.ts +72 -72
  66. package/src/lib/utils/detect-supported-texture-formats.ts +210 -0
  67. package/src/lib/utils/extract-mipmap-images.ts +15 -4
  68. package/src/lib/utils/ktx-format-helper.ts +124 -111
  69. package/src/lib/utils/texture-format-map.ts +135 -0
  70. package/dist/lib/utils/texture-formats.d.ts +0 -8
  71. package/dist/lib/utils/texture-formats.d.ts.map +0 -1
  72. package/dist/lib/utils/texture-formats.js +0 -51
  73. package/dist/lib/utils/texture-formats.js.map +0 -1
  74. package/src/lib/utils/texture-formats.ts +0 -59
@@ -2,11 +2,28 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ /* eslint-disable camelcase */
5
6
  /* eslint-disable indent */
6
- import type {TextureLevel} from '@loaders.gl/schema';
7
+ import type {GLTextureFormat, TextureFormat, TextureLevel} from '@loaders.gl/schema';
7
8
  import {loadBasisEncoderModule, loadBasisTranscoderModule} from './basis-module-loader';
8
- import {GL_EXTENSIONS_CONSTANTS} from '../gl-extensions';
9
- import {getSupportedGPUTextureFormats} from '../utils/texture-formats';
9
+ import {
10
+ GL_COMPRESSED_RED_GREEN_RGTC2_EXT,
11
+ GL_COMPRESSED_RED_RGTC1_EXT,
12
+ GL_COMPRESSED_RGB_ATC_WEBGL,
13
+ GL_COMPRESSED_RGB_ETC1_WEBGL,
14
+ GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
15
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
16
+ GL_COMPRESSED_RGBA8_ETC2_EAC,
17
+ GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
18
+ GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL,
19
+ GL_COMPRESSED_RGBA_BPTC_UNORM_EXT,
20
+ GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
21
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
22
+ GL_RGB565,
23
+ GL_RGBA4,
24
+ GL_RGBA8
25
+ } from '../gl-extensions';
26
+ import {detectSupportedTextureFormats} from '../utils/detect-supported-texture-formats';
10
27
  import {isKTX} from './parse-ktx';
11
28
 
12
29
  // TODO - circular type import
@@ -34,58 +51,125 @@ export type BasisFormat =
34
51
  type BasisOutputOptions = {
35
52
  basisFormat: number;
36
53
  compressed: boolean;
37
- format?: number;
54
+ format?: GLTextureFormat;
55
+ textureFormat?: TextureFormat;
38
56
  };
39
57
 
40
- const OutputFormat: Record<string, BasisOutputOptions> = {
58
+ export const BASIS_FORMAT_TO_OUTPUT_OPTIONS: Record<BasisFormat, BasisOutputOptions> = {
41
59
  etc1: {
42
60
  basisFormat: 0,
43
61
  compressed: true,
44
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_ETC1_WEBGL
62
+ format: GL_COMPRESSED_RGB_ETC1_WEBGL,
63
+ textureFormat: 'etc1-rbg-unorm-webgl'
64
+ },
65
+ etc2: {
66
+ basisFormat: 1,
67
+ compressed: true,
68
+ format: GL_COMPRESSED_RGBA8_ETC2_EAC,
69
+ textureFormat: 'etc2-rgba8unorm'
45
70
  },
46
- etc2: {basisFormat: 1, compressed: true},
47
71
  bc1: {
48
72
  basisFormat: 2,
49
73
  compressed: true,
50
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT
74
+ format: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
75
+ textureFormat: 'bc1-rgb-unorm-webgl'
51
76
  },
52
77
  bc3: {
53
78
  basisFormat: 3,
54
79
  compressed: true,
55
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT
80
+ format: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
81
+ textureFormat: 'bc3-rgba-unorm'
82
+ },
83
+ bc4: {
84
+ basisFormat: 4,
85
+ compressed: true,
86
+ format: GL_COMPRESSED_RED_RGTC1_EXT,
87
+ textureFormat: 'bc4-r-unorm'
88
+ },
89
+ bc5: {
90
+ basisFormat: 5,
91
+ compressed: true,
92
+ format: GL_COMPRESSED_RED_GREEN_RGTC2_EXT,
93
+ textureFormat: 'bc5-rg-unorm'
94
+ },
95
+ 'bc7-m6-opaque-only': {
96
+ basisFormat: 6,
97
+ compressed: true,
98
+ format: GL_COMPRESSED_RGBA_BPTC_UNORM_EXT,
99
+ textureFormat: 'bc7-rgba-unorm'
100
+ },
101
+ 'bc7-m5': {
102
+ basisFormat: 7,
103
+ compressed: true,
104
+ format: GL_COMPRESSED_RGBA_BPTC_UNORM_EXT,
105
+ textureFormat: 'bc7-rgba-unorm'
56
106
  },
57
- bc4: {basisFormat: 4, compressed: true},
58
- bc5: {basisFormat: 5, compressed: true},
59
- 'bc7-m6-opaque-only': {basisFormat: 6, compressed: true},
60
- 'bc7-m5': {basisFormat: 7, compressed: true},
61
107
  'pvrtc1-4-rgb': {
62
108
  basisFormat: 8,
63
109
  compressed: true,
64
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_PVRTC_4BPPV1_IMG
110
+ format: GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
111
+ textureFormat: 'pvrtc-rgb4unorm-webgl'
65
112
  },
66
113
  'pvrtc1-4-rgba': {
67
114
  basisFormat: 9,
68
115
  compressed: true,
69
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
116
+ format: GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
117
+ textureFormat: 'pvrtc-rgba4unorm-webgl'
70
118
  },
71
119
  'astc-4x4': {
72
120
  basisFormat: 10,
73
121
  compressed: true,
74
- format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_4X4_KHR
122
+ format: GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
123
+ textureFormat: 'astc-4x4-unorm'
124
+ },
125
+ 'atc-rgb': {
126
+ basisFormat: 11,
127
+ compressed: true,
128
+ format: GL_COMPRESSED_RGB_ATC_WEBGL,
129
+ textureFormat: 'atc-rgb-unorm-webgl'
130
+ },
131
+ 'atc-rgba-interpolated-alpha': {
132
+ basisFormat: 12,
133
+ compressed: true,
134
+ format: GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL,
135
+ textureFormat: 'atc-rgbai-unorm-webgl'
136
+ },
137
+ rgba32: {
138
+ basisFormat: 13,
139
+ compressed: false,
140
+ format: GL_RGBA8,
141
+ textureFormat: 'rgba8unorm'
142
+ },
143
+ rgb565: {
144
+ basisFormat: 14,
145
+ compressed: false,
146
+ format: GL_RGB565,
147
+ textureFormat: 'rgb565unorm-webgl'
75
148
  },
76
- 'atc-rgb': {basisFormat: 11, compressed: true},
77
- 'atc-rgba-interpolated-alpha': {basisFormat: 12, compressed: true},
78
- rgba32: {basisFormat: 13, compressed: false},
79
- rgb565: {basisFormat: 14, compressed: false},
80
- bgr565: {basisFormat: 15, compressed: false},
81
- rgba4444: {basisFormat: 16, compressed: false}
149
+ bgr565: {
150
+ basisFormat: 15,
151
+ compressed: false,
152
+ format: GL_RGB565,
153
+ textureFormat: 'rgb565unorm-webgl'
154
+ },
155
+ rgba4444: {
156
+ basisFormat: 16,
157
+ compressed: false,
158
+ format: GL_RGBA4,
159
+ textureFormat: 'rgba4unorm-webgl'
160
+ }
82
161
  };
83
162
 
163
+ export const BASIS_FORMATS = Object.freeze(
164
+ Object.keys(BASIS_FORMAT_TO_OUTPUT_OPTIONS) as BasisFormat[]
165
+ );
166
+
84
167
  export type ParseBasisOptions = {
85
168
  format: 'auto' | BasisFormat | {alpha: BasisFormat; noAlpha: BasisFormat};
86
169
  libraryPath?: string;
87
170
  containerFormat: 'auto' | 'ktx2' | 'basis';
88
171
  module: 'transcoder' | 'encoder';
172
+ supportedTextureFormats?: TextureFormat[];
89
173
  };
90
174
 
91
175
  /**
@@ -185,7 +269,7 @@ function transcodeImage(
185
269
  const hasAlpha = basisFile.getHasAlpha(/* imageIndex, levelIndex */);
186
270
 
187
271
  // Check options for output format etc
188
- const {compressed, format, basisFormat} = getBasisOptions(options, hasAlpha);
272
+ const {compressed, format, basisFormat, textureFormat} = getBasisOptions(options, hasAlpha);
189
273
 
190
274
  const decodedSize = basisFile.getImageTranscodedSizeInBytes(imageIndex, levelIndex, basisFormat);
191
275
  const decodedData = new Uint8Array(decodedSize);
@@ -196,11 +280,13 @@ function transcodeImage(
196
280
 
197
281
  return {
198
282
  // standard loaders.gl image category payload
283
+ shape: 'texture-level',
199
284
  width,
200
285
  height,
201
286
  data: decodedData,
202
287
  compressed,
203
- format,
288
+ ...(format !== undefined ? {format} : {}),
289
+ ...(textureFormat !== undefined ? {textureFormat} : {}),
204
290
 
205
291
  // Additional fields
206
292
  // Add levelSize field.
@@ -251,7 +337,7 @@ function transcodeKTX2Image(
251
337
  const {alphaFlag, height, width} = ktx2File.getImageLevelInfo(levelIndex, 0, 0);
252
338
 
253
339
  // Check options for output format etc
254
- const {compressed, format, basisFormat} = getBasisOptions(options, alphaFlag);
340
+ const {compressed, format, basisFormat, textureFormat} = getBasisOptions(options, alphaFlag);
255
341
 
256
342
  const decodedSize = ktx2File.getImageTranscodedSizeInBytes(
257
343
  levelIndex,
@@ -278,15 +364,17 @@ function transcodeKTX2Image(
278
364
 
279
365
  return {
280
366
  // standard loaders.gl image category payload
367
+ shape: 'texture-level',
281
368
  width,
282
369
  height,
283
370
  data: decodedData,
284
371
  compressed,
372
+ ...(format !== undefined ? {format} : {}),
373
+ ...(textureFormat !== undefined ? {textureFormat} : {}),
285
374
 
286
375
  // Additional fields
287
376
  levelSize: decodedSize,
288
- hasAlpha: alphaFlag,
289
- format
377
+ hasAlpha: alphaFlag
290
378
  };
291
379
  }
292
380
 
@@ -297,16 +385,21 @@ function transcodeKTX2Image(
297
385
  * @returns BasisFormat data
298
386
  */
299
387
  function getBasisOptions(options: BasisLoaderOptions, hasAlpha: boolean): BasisOutputOptions {
300
- // TODO - any
301
- let format: any = options.basis?.format;
388
+ let format = options.basis?.format || 'auto';
302
389
  if (format === 'auto') {
303
- format = selectSupportedBasisFormat();
390
+ format = options.basis?.supportedTextureFormats
391
+ ? selectSupportedBasisFormat(options.basis.supportedTextureFormats)
392
+ : selectSupportedBasisFormat();
304
393
  }
305
394
  if (typeof format === 'object') {
306
395
  format = hasAlpha ? format.alpha : format.noAlpha;
307
396
  }
308
- format = format.toLowerCase();
309
- return OutputFormat[format];
397
+ const normalizedFormat = format.toLowerCase() as BasisFormat;
398
+ const basisOutputOptions = BASIS_FORMAT_TO_OUTPUT_OPTIONS[normalizedFormat];
399
+ if (!basisOutputOptions) {
400
+ throw new Error(`Unknown Basis format ${format}`);
401
+ }
402
+ return basisOutputOptions;
310
403
  }
311
404
 
312
405
  /**
@@ -318,24 +411,165 @@ export function selectSupportedBasisFormat():
318
411
  | {
319
412
  alpha: BasisFormat;
320
413
  noAlpha: BasisFormat;
321
- } {
322
- const supportedFormats = getSupportedGPUTextureFormats();
323
- if (supportedFormats.has('astc')) {
414
+ };
415
+ export function selectSupportedBasisFormat(supportedTextureFormats?: Iterable<TextureFormat>):
416
+ | BasisFormat
417
+ | {
418
+ alpha: BasisFormat;
419
+ noAlpha: BasisFormat;
420
+ };
421
+ export function selectSupportedBasisFormat(
422
+ supportedTextureFormats: Iterable<TextureFormat> = detectSupportedTextureFormats()
423
+ ): BasisFormat | {alpha: BasisFormat; noAlpha: BasisFormat} {
424
+ const textureFormats = new Set(supportedTextureFormats);
425
+
426
+ if (hasSupportedTextureFormat(textureFormats, ['astc-4x4-unorm', 'astc-4x4-unorm-srgb'])) {
324
427
  return 'astc-4x4';
325
- } else if (supportedFormats.has('dxt')) {
428
+ } else if (hasSupportedTextureFormat(textureFormats, ['bc7-rgba-unorm', 'bc7-rgba-unorm-srgb'])) {
429
+ return {
430
+ alpha: 'bc7-m5',
431
+ noAlpha: 'bc7-m6-opaque-only'
432
+ };
433
+ } else if (
434
+ hasSupportedTextureFormat(textureFormats, [
435
+ 'bc1-rgb-unorm-webgl',
436
+ 'bc1-rgb-unorm-srgb-webgl',
437
+ 'bc1-rgba-unorm',
438
+ 'bc1-rgba-unorm-srgb',
439
+ 'bc2-rgba-unorm',
440
+ 'bc2-rgba-unorm-srgb',
441
+ 'bc3-rgba-unorm',
442
+ 'bc3-rgba-unorm-srgb'
443
+ ])
444
+ ) {
326
445
  return {
327
446
  alpha: 'bc3',
328
447
  noAlpha: 'bc1'
329
448
  };
330
- } else if (supportedFormats.has('pvrtc')) {
449
+ } else if (
450
+ hasSupportedTextureFormat(textureFormats, [
451
+ 'pvrtc-rgb4unorm-webgl',
452
+ 'pvrtc-rgba4unorm-webgl',
453
+ 'pvrtc-rbg2unorm-webgl',
454
+ 'pvrtc-rgba2unorm-webgl'
455
+ ])
456
+ ) {
331
457
  return {
332
458
  alpha: 'pvrtc1-4-rgba',
333
459
  noAlpha: 'pvrtc1-4-rgb'
334
460
  };
335
- } else if (supportedFormats.has('etc1')) {
336
- return 'etc1';
337
- } else if (supportedFormats.has('etc2')) {
461
+ } else if (
462
+ hasSupportedTextureFormat(textureFormats, [
463
+ 'etc2-rgb8unorm',
464
+ 'etc2-rgb8unorm-srgb',
465
+ 'etc2-rgb8a1unorm',
466
+ 'etc2-rgb8a1unorm-srgb',
467
+ 'etc2-rgba8unorm',
468
+ 'etc2-rgba8unorm-srgb',
469
+ 'eac-r11unorm',
470
+ 'eac-r11snorm',
471
+ 'eac-rg11unorm',
472
+ 'eac-rg11snorm'
473
+ ])
474
+ ) {
338
475
  return 'etc2';
476
+ } else if (textureFormats.has('etc1-rbg-unorm-webgl')) {
477
+ return 'etc1';
478
+ } else if (
479
+ hasSupportedTextureFormat(textureFormats, [
480
+ 'atc-rgb-unorm-webgl',
481
+ 'atc-rgba-unorm-webgl',
482
+ 'atc-rgbai-unorm-webgl'
483
+ ])
484
+ ) {
485
+ return {
486
+ alpha: 'atc-rgba-interpolated-alpha',
487
+ noAlpha: 'atc-rgb'
488
+ };
339
489
  }
340
490
  return 'rgb565';
341
491
  }
492
+
493
+ export function getSupportedBasisFormats(
494
+ supportedTextureFormats: Iterable<TextureFormat> = detectSupportedTextureFormats()
495
+ ): BasisFormat[] {
496
+ const textureFormats = new Set(supportedTextureFormats);
497
+ const basisFormats: BasisFormat[] = [];
498
+
499
+ if (hasSupportedTextureFormat(textureFormats, ['astc-4x4-unorm', 'astc-4x4-unorm-srgb'])) {
500
+ basisFormats.push('astc-4x4');
501
+ }
502
+ if (
503
+ hasSupportedTextureFormat(textureFormats, [
504
+ 'bc1-rgb-unorm-webgl',
505
+ 'bc1-rgb-unorm-srgb-webgl',
506
+ 'bc1-rgba-unorm',
507
+ 'bc1-rgba-unorm-srgb',
508
+ 'bc2-rgba-unorm',
509
+ 'bc2-rgba-unorm-srgb',
510
+ 'bc3-rgba-unorm',
511
+ 'bc3-rgba-unorm-srgb'
512
+ ])
513
+ ) {
514
+ basisFormats.push('bc1', 'bc3');
515
+ }
516
+ if (hasSupportedTextureFormat(textureFormats, ['bc4-r-unorm', 'bc4-r-snorm'])) {
517
+ basisFormats.push('bc4');
518
+ }
519
+ if (hasSupportedTextureFormat(textureFormats, ['bc5-rg-unorm', 'bc5-rg-snorm'])) {
520
+ basisFormats.push('bc5');
521
+ }
522
+ if (hasSupportedTextureFormat(textureFormats, ['bc7-rgba-unorm', 'bc7-rgba-unorm-srgb'])) {
523
+ basisFormats.push('bc7-m5', 'bc7-m6-opaque-only');
524
+ }
525
+ if (
526
+ hasSupportedTextureFormat(textureFormats, [
527
+ 'pvrtc-rgb4unorm-webgl',
528
+ 'pvrtc-rgba4unorm-webgl',
529
+ 'pvrtc-rbg2unorm-webgl',
530
+ 'pvrtc-rgba2unorm-webgl'
531
+ ])
532
+ ) {
533
+ basisFormats.push('pvrtc1-4-rgb', 'pvrtc1-4-rgba');
534
+ }
535
+ if (
536
+ hasSupportedTextureFormat(textureFormats, [
537
+ 'etc2-rgb8unorm',
538
+ 'etc2-rgb8unorm-srgb',
539
+ 'etc2-rgb8a1unorm',
540
+ 'etc2-rgb8a1unorm-srgb',
541
+ 'etc2-rgba8unorm',
542
+ 'etc2-rgba8unorm-srgb',
543
+ 'eac-r11unorm',
544
+ 'eac-r11snorm',
545
+ 'eac-rg11unorm',
546
+ 'eac-rg11snorm'
547
+ ])
548
+ ) {
549
+ basisFormats.push('etc2');
550
+ }
551
+ if (textureFormats.has('etc1-rbg-unorm-webgl')) {
552
+ basisFormats.push('etc1');
553
+ }
554
+ if (
555
+ hasSupportedTextureFormat(textureFormats, [
556
+ 'atc-rgb-unorm-webgl',
557
+ 'atc-rgba-unorm-webgl',
558
+ 'atc-rgbai-unorm-webgl'
559
+ ])
560
+ ) {
561
+ basisFormats.push('atc-rgb', 'atc-rgba-interpolated-alpha');
562
+ }
563
+
564
+ basisFormats.push('rgba32', 'rgb565', 'bgr565', 'rgba4444');
565
+ return basisFormats;
566
+ }
567
+
568
+ function hasSupportedTextureFormat(
569
+ supportedTextureFormats: Set<TextureFormat>,
570
+ candidateTextureFormats: TextureFormat[]
571
+ ): boolean {
572
+ return candidateTextureFormats.some((textureFormat) =>
573
+ supportedTextureFormats.has(textureFormat)
574
+ );
575
+ }
@@ -2,12 +2,16 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {TextureLevel} from '@loaders.gl/schema';
5
+ import type {GLTextureFormat, TextureLevel} from '@loaders.gl/schema';
6
6
  import {loadCrunchModule} from './crunch-module-loader';
7
- import {GL_EXTENSIONS_CONSTANTS} from '../gl-extensions';
8
7
  import {assert} from '@loaders.gl/loader-utils';
9
8
  import {getDxt1LevelSize, getDxtXLevelSize} from './parse-dds';
10
9
  import {extractMipmapImages} from '../utils/extract-mipmap-images';
10
+ import {
11
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
12
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
13
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
14
+ } from '../gl-extensions';
11
15
 
12
16
  // Taken from crnlib.h
13
17
  const CRN_FORMAT = {
@@ -22,17 +26,20 @@ const CRN_FORMAT = {
22
26
  };
23
27
 
24
28
  /** Mapping of Crunch formats to DXT formats. */
25
- const DXT_FORMAT_MAP = {
29
+ const DXT_FORMAT_MAP: Record<
30
+ number,
31
+ {pixelFormat: GLTextureFormat; sizeFunction: (width: number, height: number) => number}
32
+ > = {
26
33
  [CRN_FORMAT.cCRNFmtDXT1]: {
27
- pixelFormat: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT,
34
+ pixelFormat: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
28
35
  sizeFunction: getDxt1LevelSize
29
36
  },
30
37
  [CRN_FORMAT.cCRNFmtDXT3]: {
31
- pixelFormat: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT3_EXT,
38
+ pixelFormat: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
32
39
  sizeFunction: getDxtXLevelSize
33
40
  },
34
41
  [CRN_FORMAT.cCRNFmtDXT5]: {
35
- pixelFormat: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT,
42
+ pixelFormat: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
36
43
  sizeFunction: getDxtXLevelSize
37
44
  }
38
45
  };
@@ -2,9 +2,16 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {TextureLevel} from '@loaders.gl/schema';
5
+ import type {GLTextureFormat, TextureLevel} from '@loaders.gl/schema';
6
6
  import {assert} from '@loaders.gl/loader-utils';
7
- import {GL_EXTENSIONS_CONSTANTS} from '../gl-extensions';
7
+ import {
8
+ GL_COMPRESSED_RGB_ATC_WEBGL,
9
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
10
+ GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
11
+ GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL,
12
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
13
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
14
+ } from '../gl-extensions';
8
15
  import {extractMipmapImages} from '../utils/extract-mipmap-images';
9
16
 
10
17
  const DDS_CONSTANTS = {
@@ -22,13 +29,13 @@ const DDS_CONSTANTS = {
22
29
  DDPF_FOURCC: 0x4
23
30
  };
24
31
 
25
- const DDS_PIXEL_FORMATS: Record<string, number> = {
26
- DXT1: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT,
27
- DXT3: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT3_EXT,
28
- DXT5: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT,
29
- 'ATC ': GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_ATC_WEBGL,
30
- ATCA: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
31
- ATCI: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
32
+ const DDS_PIXEL_FORMATS: Record<string, GLTextureFormat> = {
33
+ DXT1: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
34
+ DXT3: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
35
+ DXT5: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
36
+ 'ATC ': GL_COMPRESSED_RGB_ATC_WEBGL,
37
+ ATCA: GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
38
+ ATCI: GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
32
39
  };
33
40
 
34
41
  const getATCLevelSize = getDxt1LevelSize;
@@ -2,7 +2,8 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {TextureLevel} from '@loaders.gl/schema';
5
+ import type {GLTextureFormat, TextureLevel} from '@loaders.gl/schema';
6
+ import {log} from '@loaders.gl/loader-utils';
6
7
  import {read} from 'ktx-parse';
7
8
  import {extractMipmapImages} from '../utils/extract-mipmap-images';
8
9
  import {mapVkFormatToWebGL} from '../utils/ktx-format-helper';
@@ -40,7 +41,16 @@ export function parseKTX(arrayBuffer: ArrayBuffer): TextureLevel[] {
40
41
  const mipMapLevels = Math.max(1, ktx.levels.length);
41
42
  const width = ktx.pixelWidth;
42
43
  const height = ktx.pixelHeight;
43
- const internalFormat = mapVkFormatToWebGL(ktx.vkFormat);
44
+ const internalFormat: GLTextureFormat | undefined = mapVkFormatToWebGL(ktx.vkFormat);
45
+
46
+ if (internalFormat === undefined) {
47
+ // TODO: Basis-backed and otherwise unknown-format KTX2 files should preserve the
48
+ // legacy CompressedTextureLoader behavior for now. Do not fail here or add implicit
49
+ // transcoding in this parser path; just return levels without `format` metadata.
50
+ log.warn(
51
+ `KTX2 container vkFormat ${ktx.vkFormat} does not map to a known WebGL format; returning texture levels without format metadata.`
52
+ )();
53
+ }
44
54
 
45
55
  return extractMipmapImages(ktx.levels, {
46
56
  mipMapLevels,