@@ -89,6 +89,7 @@ namespace msc {
89
89
90
90
// Yes, code in the following functions handling data coming in from
91
91
// ArrayBuffers IS copying the data. Sigh! According to Alon Zakai:
92
+ //
92
93
// "There isn't a way to let compiled code access a new ArrayBuffer.
93
94
// The compiled code has hardcoded access to the wasm Memory it was
94
95
// instantiated with - all the pointers it can understand are
@@ -366,10 +367,9 @@ interface TranscodeResult {
366
367
TranscodedImage transcodedImage;
367
368
};
368
369
369
- interface BasisTranscoder {
370
- void BasisTranscoder();
371
- static void init();
372
- static long getBytesPerBlock();
370
+ interface BasisUImageTranscoder {
371
+ void BasisUImageTranscoder();
372
+ uint32_t getBytesPerBlock(const TranscodeTarget format);
373
373
bool decode_palettes(uint32_t num_endpoints,
374
374
const ArrayBufferView endpoints,
375
375
uint32_t num_selectors,
@@ -387,6 +387,19 @@ interface BasisTranscoder {
387
387
bool transcodeAlphaToOpaqueFormats = false);
388
388
};
389
389
390
+ interface UastcImageTranscoder {
391
+ void UastcImageTranscoder();
392
+ uint32_t getBytesPerBlock(const TranscodeTarget format);
393
+ TranscodeResult transcode_image(const val& jsTargetFormat,
394
+ uint32_t level,
395
+ const ArrayBufferView jsInImage,
396
+ uint32_t width, uint32_t height,
397
+ uint32_t num_blocks_x,
398
+ uint32_t num_blocks_y,
399
+ bool hasAlpha = false,
400
+ uint32_t transcode_flags = 0);
401
+ };
402
+
390
403
// Some targets may not be available depending on options used when compiling
391
404
// the web assembly.
392
405
enum TranscodeTarget = {
@@ -412,6 +425,12 @@ enum TranscodeTarget = {
412
425
"EAC_R11",
413
426
"EAC_RG11"
414
427
};
428
+
429
+ enum TranscodeFlagBits = {
430
+ "TRANSCODE_ALPHA_DAT_TO_OPAQUE_FORMATS",
431
+ "HIGH_QUALITY"
432
+ };
433
+
415
434
@endcode
416
435
417
436
## How to use
@@ -425,7 +444,8 @@ automatically load msc_basis_transcoder.wasm.
425
444
426
445
### Create an instance of the MSC_TRANSCODER module
427
446
428
- Add this to the .html file to initialize the transcoder and make it available on the main window.
447
+ Add this to the .html file to initialize the transcoder and make it available on the
448
+ main window.
429
449
@code{.unparsed}
430
450
<script src="msc_transcoder_wrapper.js"></script>
431
451
<script type="text/javascript">
@@ -440,19 +460,49 @@ a function with code like the following to be executed.
440
460
441
461
## Somewhere in the loader/transcoder
442
462
443
- Assume a KTX file is fetched via an XMLHttpRequest which deposits the data into a Uint8Array, "buData"...
463
+ Assume a KTX file is fetched via an XMLHttpRequest which deposits the data into
464
+ a Uint8Array, "buData"...
444
465
445
466
@note The names of the data items used in the following code are those
446
467
from the KTX2 specification but the actual data is not specific to that
447
468
container format.
448
469
449
470
@code{.unparsed}
471
+ const {
472
+ InitTranscoderGlobal,
473
+ BasisUImageTranscoder,
474
+ UastcImageTranscoder,
475
+ BasisTranscoderState,
476
+ TranscodeTarget
477
+ } = MSC_TRANSCODER;
478
+
479
+ InitTranscoderGlobal();
480
+
481
+ // Determine from the KTX2 header information in buData if
482
+ // the data format is BasisU or Uastc.
483
+ // supercompressionScheme value == 1, it's BasisU.
484
+ // DFD colorModel == 166, it's UASTC.
485
+
486
+ // Determine appropriate transcode format from available targets,
487
+ // info about the texture, e.g. texture.numComponents, and
488
+ // expected use. Use values from TranscodeTarget.
489
+ var targetFormat = ...
490
+
491
+ if (Uastc) {
492
+ transcodeUastc(targetFormat);
493
+ } else {
494
+ transcodeEtc1s(targetFormat);
495
+ }
496
+ @endcode
497
+
498
+ This is the function for transcoding etc1s.
499
+
500
+ @code{.unparsed}
501
+ transcodeEtc1s(targetFormat) {
450
502
// Locate the supercompression global data and compresssed
451
503
// mip level data within buData.
452
504
453
- const { BasisTranscoder, BasisTranscoderState, TranscodeTarget } = MSC_TRANSCODER;
454
- BasisTranscoder.init();
455
- var transcoder = new BasisTranscoder();
505
+ var bit = new BasisUImageTranscoder();
456
506
457
507
// Find the index of the starts of the endpoints, selectors and tables
458
508
// data within buData...
@@ -463,21 +513,16 @@ container format.
463
513
// within buData. In KTX2 they are in the header of the
464
514
// supercompressionGlobalData.
465
515
466
- var endpoints = new UInt8Array (buData, endpointsStart,
516
+ var endpoints = new Uint8Array (buData, endpointsStart,
467
517
endpointsByteLength);
468
- var selectors = new UINt8Array (buData, selectorsStart,
518
+ var selectors = new Uint8Array (buData, selectorsStart,
469
519
selectorsByteLength);
470
520
471
- transcoder .decodePalettes(numEndpoints, endpoints,
521
+ bit .decodePalettes(numEndpoints, endpoints,
472
522
numSelectors, selectors);
473
523
474
524
var tables = new UInt8Array(buData, tablesStart, tablesByteLength);
475
- transcoder.decodeTables(tables);
476
-
477
- // Determine appropriate transcode format from available targets,
478
- // info about the texture, e.g. texture.numComponents, and
479
- // expected use. Use values from TranscodeTarget.
480
- var targetFormat = ...
525
+ bit.decodeTables(tables);
481
526
482
527
// Determine if the file contains a video sequence...
483
528
var isVideo = ...
@@ -496,14 +541,13 @@ container format.
496
541
var curImageIndex = 0;
497
542
498
543
// Pseudo code ...
499
- foreach level
544
+ foreach level {
500
545
var width = width of image at this level
501
546
var height = height of image at this level
502
547
var bw = 4; // for ETC1S based Basis compressed data.
503
548
var bh = 4; // ditto
504
549
var num_blocks_x = Math.ceil(width / bw);
505
550
var num_blocks_y = Math.ceil(height / bh);
506
- var levelData = location of level within texdata
507
551
foreach image in level {
508
552
// In KTX2 container locate the imageDesc for this image.
509
553
var imageDesc = imageDescs[curImageIndex++];
@@ -518,9 +562,9 @@ container format.
518
562
// Do the same for the alpha slice. Length 0 is okay.
519
563
var alphaSliceStart = levelData + imageDesc[3];
520
564
var alphaSliceByteLength = imageDesc[4];
521
- var alphaSlice = new UINt8Array (buData, alphaSliceStart,
565
+ var alphaSlice = new Uint8Array (buData, alphaSliceStart,
522
566
alphaSliceByteLength);
523
- const {transcodedImage, error} = transcoder .transcodeImage(
567
+ const {transcodedImage, error} = bit .transcodeImage(
524
568
imageDesc[0], // imageFlags,
525
569
rgbSlice,
526
570
alphaSlice,
@@ -541,6 +585,71 @@ container format.
541
585
transcodedImage.delete();
542
586
}
543
587
}
588
+ }
589
+ }
590
+ @endcode
591
+
592
+ This is the function for transcoding Uastc.
593
+
594
+ @code{.unparsed}
595
+ transcodeUastc(targetFormat) {
596
+ var uit = new UastcImageTranscoder();
597
+
598
+ // Determine if the data is supercompressed.
599
+ var zstd = (supercompressionScheme == 2);
600
+
601
+ // Determine if the data has alpha.
602
+ var hasAlpha = (Channel ID of sample in DFD == 1);
603
+
604
+ var dctx;
605
+ if (zstd) {
606
+ // Initialize the zstd decoder. Zstd JS wrapper + wasm is
607
+ // a separate package.
608
+ dctx = ZSTD_createDCtx();
609
+ }
610
+
611
+ // Pseudo code ...
612
+ foreach level {
613
+ // Determine the location in the ArrayBuffer buData of the
614
+ // start of the deflated data for the level.
615
+ var levelData = ...
616
+ if (zstd) {
617
+ // Inflate the level data
618
+ levelData = ZSTD_decompressDCtx(dctx, levelData, ... );
619
+ }
620
+
621
+ var width = width of image at this level
622
+ var height = height of image at this level
623
+ var depth = depth of texture at this level
624
+ var bw = 4; // for UASTC 4x4 block-compressed data.
625
+ var bh = 4; // ditto
626
+ var num_blocks_x = Math.ceil(width / bw);
627
+ var num_blocks_y = Math.ceil(height / bh);
628
+ levelImageCount = number of layers * number of faces * depth;
629
+
630
+ foreach image in level {
631
+ inImage = Uint8Array(levelData, imageStart, imageEnd);
632
+ const {transcodedImage, error} = uit.transcodeImage(
633
+ targetFormat,
634
+ level,
635
+ inImage,
636
+ width, height,
637
+ num_blocks_x,
638
+ num_blocks_y,
639
+ hasAlpha,
640
+ 0);
641
+ if (!error) {
642
+ let imgData = transcodedImage.get_typed_memory_view();
643
+
644
+ // Upload data in imgData to WebGL...
645
+
646
+ // Do not call delete() until data has been uploaded
647
+ // or otherwise copied.
648
+ transcodedImage.delete();
649
+ }
650
+ }
651
+ }
652
+ }
544
653
@endcode
545
654
546
655
*/
@@ -591,6 +700,12 @@ EMSCRIPTEN_BINDINGS(ktx_wrappers)
591
700
#endif
592
701
;
593
702
703
+ enum_<ktx_transcode_flag_bits_e>(" TranscodeFlagBits" )
704
+ .value (" TRANSCODE_ALPHA_DAT_TO_OPAQUE_FORMATS" ,
705
+ KTX_TF_TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS)
706
+ .value (" HIGH_QUALITY" , KTX_TF_HIGH_QUALITY)
707
+ ;
708
+
594
709
function (" InitTranscoderGlobal" , basisu_transcoder_init);
595
710
596
711
class_<msc::BasisUImageTranscoder>(" BasisUImageTranscoder" )
0 commit comments