1<!-- 2 Simple .basis file transcode tester. 3 Supports numerous texture formats: ETC1, PVRTC1, BC1-BC7, BC6H, ASTC LDR/HDR, and various uncompressed fallbacks. 4 Important note: This sample doesn't support all ASTC/XUASTC LDR block sizes yet, just 4x4. See the "ktx2_encode_test" or "video_test" samples, which do. 5--> 6 7<!doctype html> 8<html> 9<head> 10
10<script src="renderer.js"></script>
10 11
11<script src="../transcoder/build/basis_transcoder.js"></script>
11 12
12<script type="text/javascript"> 13 function log(s) { 14 var div = document.createElement('div'); 15 div.innerHTML = s; 16 document.getElementById('logger').appendChild(div); 17 } 18 19 function logTime(desc, t) { 20 log(t + 'ms ' + desc); 21 } 22 23 function isDef(v) { 24 return typeof v != 'undefined'; 25 } 26 27 function elem(id) { 28 return document.getElementById(id); 29 } 30 31 function loadArrayBuffer(uri, callback) { 32 log('Loading ' + uri + '...'); 33 var xhr = new XMLHttpRequest(); 34 xhr.responseType = "arraybuffer"; 35 xhr.open('GET', uri, true); 36 xhr.onreadystatechange = function (e) { 37 if (xhr.readyState == 4 && xhr.status == 200) { 38 callback(xhr.response); 39 } 40 } 41 xhr.send(null); 42 } 43 44 // ASTC format, from: 45 // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/ 46 COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0; 47 48 // DXT formats, from: 49 // http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ 50 COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; 51 COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; 52 COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; 53 COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; 54 55 // BC6H/BC7 formats, from: 56 // https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_bptc/ 57 COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C; 58 COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT = 0x8E8F; 59 60 // ETC format, from: 61 // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/ 62 COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; 63 64 // PVRTC format, from: 65 // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/ 66 COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00; 67 COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02; 68 69 // Half float RGBA, from: 70 // https://registry.khronos.org/webgl/extensions/OES_texture_half_float/ 71 HALF_FLOAT_OES = 0x8D61; 72 73 // Same as the Module.transcoder_texture_format enum 74 BASIS_FORMAT = { 75 cTFETC1: 0, 76 cTFETC2: 1, 77 cTFBC1: 2, 78 cTFBC3: 3, 79 cTFBC4: 4, 80 cTFBC5: 5, 81 cTFBC7: 6, 82 cTFPVRTC1_4_RGB: 8, 83 cTFPVRTC1_4_RGBA: 9, 84 cTFASTC_4x4: 10, 85 cTFATC_RGB: 11, 86 cTFATC_RGBA_INTERPOLATED_ALPHA: 12, 87 cTFRGBA32: 13, 88 cTFRGB565: 14, 89 cTFBGR565: 15, 90 cTFRGBA4444: 16, 91 cTFFXT1_RGB: 17, 92 cTFPVRTC2_4_RGB: 18, 93 cTFPVRTC2_4_RGBA: 19, 94 cTFETC2_EAC_R11: 20, 95 cTFETC2_EAC_RG11: 21, 96 cTFBC6H: 22, 97 cTFASTC_HDR_4x4_RGBA: 23, 98 cTFRGB_HALF: 24, 99 cTFRGBA_HALF: 25, 100 cTFRGB_9E5: 26, 101 cTFASTC_HDR_6x6_RGBA: 27 102 }; 103 104 BASIS_FORMAT_NAMES = {}; 105 for (var name in BASIS_FORMAT) { 106 BASIS_FORMAT_NAMES[BASIS_FORMAT[name]] = name; 107 } 108 109 DXT_FORMAT_MAP = {}; 110 DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC1] = COMPRESSED_RGB_S3TC_DXT1_EXT; 111 DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC3] = COMPRESSED_RGBA_S3TC_DXT5_EXT; 112 DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC7] = COMPRESSED_RGBA_BPTC_UNORM; 113 114 var astcSupported = false; 115 var etcSupported = false; 116 var dxtSupported = false; 117 var bc7Supported = false; 118 var bc6hSupported = false; 119 var astcHDRSupported = false; 120 var rgbaHalfSupported = false; 121 var halfFloatWebGLFormat = 0; 122 var pvrtcSupported = false; 123 124 var drawMode = 0; 125 var drawScale = 1.0; 126 var linearToSRGBFlag = false; 127 128 var tex, width, height, images, levels, has_alpha, is_hdr, basisTexFormat; 129 var alignedWidth, alignedHeight, format, displayWidth, displayHeight; 130 131 function redraw() { 132 if (!width) 133 return; 134 135 renderer.drawTexture(tex, displayWidth, displayHeight, drawMode, drawScale, linearToSRGBFlag); 136 } 137 138 function dumpBasisFileDesc(basisFile) { 139 var basisFileDesc = basisFile.getFileDesc(); 140 141 log('------'); 142 log('getFileDesc():'); 143 log('version: ' + basisFileDesc.version); 144 log('us per frame: ' + basisFileDesc.usPerFrame); 145 log('total images: ' + basisFileDesc.totalImages); 146 log('userdata0: ' + basisFileDesc.userdata0 + ' userdata1: ' + basisFileDesc.userdata1); 147 log('texFormat: ' + basisFileDesc.texFormat); 148 log('yFlipped: ' + basisFileDesc.yFlipped + ' hasAlphaSlices: ' + basisFileDesc.hasAlphaSlices); 149 150 if (basisFileDesc.texFormat == Module.basis_tex_format.cETC1S.value) { 151 log('numEndpoints: ' + basisFileDesc.numEndpoints); 152 log('endpointPaletteOfs: ' + basisFileDesc.endpointPaletteOfs); 153 log('endpointPaletteLen: ' + basisFileDesc.endpointPaletteLen); 154 log('numSelectors: ' + basisFileDesc.numSelectors); 155 log('selectorPaletteOfs: ' + basisFileDesc.selectorPaletteOfs); 156 log('selectorPaletteLen: ' + basisFileDesc.selectorPaletteLen); 157 log('tablesOfs: ' + basisFileDesc.tablesOfs); 158 log('tablesLen: ' + basisFileDesc.tablesLen); 159 } 160 log('------'); 161 log('getImageDesc() for all images:'); 162 var image_index; 163 for (image_index = 0; image_index < basisFileDesc.totalImages; image_index++) { 164 log('image: ' + image_index); 165 166 var basisImageDesc = basisFile.getImageDesc(image_index); 167 168 log('origWidth: ' + basisImageDesc.origWidth + ' origWidth: ' + basisImageDesc.origHeight); 169 log('numBlocksX: ' + basisImageDesc.numBlocksX + ' origWidth: ' + basisImageDesc.numBlocksY); 170 log('numLevels: ' + basisImageDesc.numLevels); 171 log('alphaFlag: ' + basisImageDesc.alphaFlag + ' iframeFlag: ' + basisImageDesc.iframeFlag); 172 173 log('getImageLevelDesc() for all mipmap levels:'); 174 var level_index; 175 for (level_index = 0; level_index < basisImageDesc.numLevels; level_index++) { 176 var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); 177 178 log('level: ' + level_index + 179 ' rgb_file_offset: ' + basisImageLevelDesc.rgbFileOfs + ' rgb_file_len: ' + basisImageLevelDesc.rgbFileLen); 180 181 if (basisFileDesc.hasAlphaSlices) 182 log('alpha_file_offset: ' + basisImageLevelDesc.alphaFileOfs + ' alpha_file_len: ' + basisImageLevelDesc.alphaFileLen); 183 } 184 } 185 186 log('------'); 187 } 188 189 function dataLoaded(data) { 190 log('Done loading .basis file, decoded header:'); 191 192 const { BasisFile, initializeBasis } = Module; 193 194 drawMode = 0; 195 drawScale = 1.0; 196 linearToSRGBFlag = false;
197 elem('scale-slider').value = 1.0; 198 elem('scale-value').textContent = 1; 199 200 initializeBasis(); 201 202 const startTime = performance.now(); 203 204 const basisFile = new BasisFile(new Uint8Array(data)); 205 206 width = basisFile.getImageWidth(0, 0); 207 height = basisFile.getImageHeight(0, 0); 208 images = basisFile.getNumImages(); 209 levels = basisFile.getNumLevels(0); 210 has_alpha = basisFile.getHasAlpha(); 211 is_hdr = basisFile.isHDR(); 212 basisTexFormat = basisFile.getBasisTexFormat(); 213 214 var srcBlockWidth = basisFile.getBlockWidth(); 215 var srcBlockHeight = basisFile.getBlockHeight(); 216 217 var dstBlockWidth = 4; 218 var dstBlockHeight = 4; 219 220 log('isHDR: ' + is_hdr); 221 222 dumpBasisFileDesc(basisFile); 223 224 if (!width || !height || !images || !levels) { 225 console.warn('Invalid .basis file'); 226 basisFile.close(); 227 basisFile.delete(); 228 return; 229 } 230 231 // Note: If the file is UASTC LDR, the preferred formats are ASTC/BC7. For UASTC HDR, ASTC/BC6H. 232 // If the file is ETC1S and doesn't have alpha, the preferred formats are ETC1 and BC1. For alpha, the preferred formats are ETC2, BC3 or BC7. 233 234 var formatString = 'UNKNOWN'; 235 if (is_hdr) { 236 if (astcHDRSupported) 237 { 238 if (basisTexFormat == Module.basis_tex_format.cUASTC_HDR_4x4.value) 239 { 240 formatString = 'UASTC HDR 4x4'; 241 format = BASIS_FORMAT.cTFASTC_HDR_4x4_RGBA; 242 } 243 else 244 { 245 formatString = 'ASTC HDR 6x6'; 246 format = BASIS_FORMAT.cTFASTC_HDR_6x6_RGBA; 247 248 dstBlockWidth = 6; 249 dstBlockHeight = 6; 250 } 251 } 252 else if (bc6hSupported) { 253 formatString = 'BC6H'; 254 format = BASIS_FORMAT.cTFBC6H; 255 } 256 else if (rgbaHalfSupported) { 257 formatString = 'RGBA_HALF'; 258 format = BASIS_FORMAT.cTFRGBA_HALF; 259 } 260 else { 261 formatString = '32-bit RGBA'; 262 format = BASIS_FORMAT.cTFRGBA_HALF; 263 264 log('Decoding .basis data to 32-bit RGBA'); 265 } 266 } 267 else if (astcSupported) { 268 formatString = 'ASTC'; 269 format = BASIS_FORMAT.cTFASTC_4x4; 270 } 271 else if (bc7Supported) { 272 formatString = 'BC7'; 273 format = BASIS_FORMAT.cTFBC7; 274 } 275 else if (dxtSupported) { 276 if (has_alpha) { 277 formatString = 'BC3'; 278 format = BASIS_FORMAT.cTFBC3; 279 } 280 else { 281 formatString = 'BC1'; 282 format = BASIS_FORMAT.cTFBC1; 283 } 284 } 285 else if (pvrtcSupported) { 286 if (has_alpha) { 287 formatString = 'PVRTC1_RGBA'; 288 format = BASIS_FORMAT.cTFPVRTC1_4_RGBA; 289 } 290 else { 291 formatString = 'PVRTC1_RGB'; 292 format = BASIS_FORMAT.cTFPVRTC1_4_RGB; 293 } 294 295 if ( 296 ((width & (width - 1)) != 0) || ((height & (height - 1)) != 0) 297 ) { 298 log('ERROR: PVRTC1 requires square power of 2 textures'); 299 } 300 if (width != height) { 301 log('ERROR: PVRTC1 requires square power of 2 textures'); 302 } 303 } 304 else if (etcSupported) { 305 formatString = 'ETC1'; 306 format = BASIS_FORMAT.cTFETC1; 307 } 308 else { 309 formatString = 'RGB565'; 310 format = BASIS_FORMAT.cTFRGB565; 311 log('Decoding .basis data to 565'); 312 } 313 314 elem('format').innerText = formatString; 315 316 log('format: ' + format); 317 318 if (!basisFile.startTranscoding()) { 319 log('startTranscoding failed'); 320 console.warn('startTranscoding failed'); 321 basisFile.close(); 322 basisFile.delete(); 323 return; 324 } 325 326 const isUncompressedFormat = Module.formatIsUncompressed(format); 327 328 const bytesPerBlockOrPixel = Module.getBytesPerBlockOrPixel(format); 329 log('isUncompressedFormat: ' + isUncompressedFormat + ' bytesPerBlockOrPixel: ' + bytesPerBlockOrPixel); 330 331 const dstSize = basisFile.getImageTranscodedSizeInBytes(0, 0, format); 332 const dst = new Uint8Array(dstSize); 333 334 // log('getImageTranscodedSizeInBytes() returned ' + dstSize); 335 336 // Use the low or high level transcoding API's. The high level API's require .basis files, while the low-level API's just work off blobs of memory and parameters. 337 if (elem('ContainerIndependentTranscoding').checked) { 338 // Always transcode the first image and the first mipmap level 339 const image_index = 0; 340 const level_index = 0; 341 342 // Get the .basis file description 343 var basisFileDesc = basisFile.getFileDesc(); 344 345 // Get the description of the file's first image (there could be multiple images, for texture arrays or videos) 346 var basisImageDesc = basisFile.getImageDesc(image_index); 347 348 // Get the description of this image's mipmap level 349 var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); 350 351 var status = false;
352 353 // If we're transcoding to ETC1S, use the LowLevelETC1SImageTranscoder class. Otherwise use the transcodeUASTCImage() function. 354 if (basisFileDesc.texFormat == Module.basis_tex_format.cETC1S.value) { 355 // Create an instance of the LowLevelETC1SImageTranscoder class. 356 const etc1s_transcoder = new Module.LowLevelETC1SImageTranscoder(); 357 358 // Create Uint8Array's pointing into the various bits of the .basis file holding the compressed data for the codebooks and the Huffman tables. 359 var selectorPalette = new Uint8Array(data, basisFileDesc.selectorPaletteOfs, basisFileDesc.selectorPaletteLen); 360 var endpointPalette = new Uint8Array(data, basisFileDesc.endpointPaletteOfs, basisFileDesc.endpointPaletteLen); 361 var tables = new Uint8Array(data, basisFileDesc.tablesOfs, basisFileDesc.tablesLen); 362 363 // Create a Uint8Array pointing to the image's compressed data. 364 // If it's an opaque .basis file, there will only be RGB data. For transparant .basis files, each RGB slice will be immediately followed by an alpha slice. 365 // Compressed ETC1S alpha data is guaranteed to immediately follow the RGB data (it's always at odd slices in the .basis file). 366 var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen + basisImageLevelDesc.alphaFileLen); 367 368 // Decompress the palettes. This only has to be done once for each .basis file. 369 var status = etc1s_transcoder.decodePalettes(basisFileDesc.numEndpoints, endpointPalette, basisFileDesc.numSelectors, selectorPalette); 370 if (status) { 371 // Decompress the Huffman tables. This only has to be done once for each .basis file. 372 status = etc1s_transcoder.decodeTables(tables); 373 if (status) { 374 // Now transcode the image using the container independent transcode API. This API does not interpret any .basis file structures - only the compressed ETC1S data. 375 status = etc1s_transcoder.transcodeImage( 376 format, 377 dst, dstSize / bytesPerBlockOrPixel, 378 compData, 379 basisImageDesc.numBlocksX, basisImageDesc.numBlocksY, basisImageDesc.origWidth, basisImageDesc.origHeight, level_index, 380 0, basisImageLevelDesc.rgbFileLen, basisFileDesc.hasAlphaSlices ? basisImageLevelDesc.rgbFileLen : 0, basisImageLevelDesc.alphaFileLen, 381 0, 382 basisFileDesc.hasAlphaSlices, 383 basisFileDesc.isVideo, 384 0, 385 0); 386 387 if (!status) 388 log('transcodeImage() failed'); 389 } 390 else { 391 log('decodeTables() failed'); 392 } 393 } 394 else { 395 log('decodePalettes() failed'); 396 } 397 398 etc1s_transcoder.delete(); 399 400 if (!status) { 401 log('etc1s_transcoder failed'); 402 console.warn('etc1s_transcoder failed'); 403 basisFile.close(); 404 basisFile.delete(); 405 return; 406 } 407 else { 408 log('Successfully called etc1s_transcoder.transcodeImage()'); 409 } 410 } 411 else { 412 // Create a Uint8Array pointing to the image's compressed data. 413 var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen); 414 415 // Transcode the UASTC texture data to the desired output format. 416 status = Module.transcodeUASTCImage( 417 basisTexFormat, 418 format, 419 dst, dstSize / bytesPerBlockOrPixel, 420 compData, 421 basisImageDesc.numBlocksX, basisImageDesc.numBlocksY, basisImageDesc.origWidth, basisImageDesc.origHeight, level_index, 422 0, basisImageLevelDesc.rgbFileLen, 423 0, 424 basisFileDesc.hasAlphaSlices, 425 basisFileDesc.isVideo, 426 0, 427 0, 428 -1, -1); 429 430 if (!status) { 431 log('transcodeUASTCImage() failed'); 432 console.warn('transcodeUASTCImage() failed'); 433 basisFile.close(); 434 basisFile.delete(); 435 return; 436 } 437 else { 438 log('Successfully called transcodeUASTCImage()'); 439 } 440 } 441 } 442 else { 443 // Use the high-level transcode API, which requires a .basis file. 444 if (!basisFile.transcodeImage(dst, 0, 0, format, 0, 0
444)) { 445 log('basisFile.transcodeImage failed'); 446 console.warn('transcodeImage failed'); 447 basisFile.close(); 448 basisFile.delete(); 449 450 return; 451 } 452 } 453 454 const elapsed = performance.now() - startTime; 455 456 basisFile.close(); 457 basisFile.delete(); 458 459 log('width: ' + width); 460 log('height: ' + height); 461 log('images: ' + images); 462 log('first image mipmap levels: ' + levels); 463 log('has_alpha: ' + has_alpha); 464 logTime('transcoding time', elapsed.toFixed(2)); 465 466 alignedWidth = Math.floor((width + dstBlockWidth - 1) / dstBlockWidth) * dstBlockWidth; 467 alignedHeight = Math.floor((height + dstBlockHeight - 1) / dstBlockHeight) * dstBlockHeight; 468 469 displayWidth = alignedWidth; 470 displayHeight = alignedHeight; 471 472 var canvas = elem('canvas'); 473 canvas.width = alignedWidth; 474 canvas.height = alignedHeight; 475 476 // Create the WebGL texture object. 477 if ((format === BASIS_FORMAT.cTFASTC_4x4) || (format === BASIS_FORMAT.cTFASTC_HDR_4x4_RGBA)) { 478 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGBA_ASTC_4x4_KHR); 479 } 480 else if (format === BASIS_FORMAT.cTFASTC_HDR_6x6_RGBA) { 481 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGBA_ASTC_6x6_KHR); 482 } 483 else if ((format === BASIS_FORMAT.cTFBC3) || (format === BASIS_FORMAT.cTFBC1) || (format == BASIS_FORMAT.cTFBC7)) { 484 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, DXT_FORMAT_MAP[format]); 485 } 486 else if (format === BASIS_FORMAT.cTFETC1) { 487 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGB_ETC1_WEBGL); 488 } 489 else if (format === BASIS_FORMAT.cTFPVRTC1_4_RGB) { 490 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGB_PVRTC_4BPPV1_IMG); 491 } 492 else if (format === BASIS_FORMAT.cTFPVRTC1_4_RGBA) { 493 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG); 494 } 495 else if (format === BASIS_FORMAT.cTFBC6H) { 496 tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT); 497 } 498 else if (format == BASIS_FORMAT.cTFRGBA_HALF) { 499 canvas.width = width; 500 canvas.height = height; 501 displayWidth = width; 502 displayHeight = height; 503 504 if (rgbaHalfSupported) { 505 var numHalfs = dstSize / 2; 506 507 // Create uint16 data from the uint8 data. 508 var dstHalfs = new Uint16Array(numHalfs); 509 510 // Convert the array of bytes to an array of uint16's. 511 for (var i = 0; i < numHalfs; i++) 512 dstHalfs[i] = dst[2 * i + 0] | (dst[2 * i + 1] << 8); 513 514 tex = renderer.createHalfRGBATexture(dstHalfs, width, height, halfFloatWebGLFormat); 515 } 516 else { 517 // No HDR texture formats are supported (TODO: 9e5?) Fall back to plain 32bpp RGBA, just to do *something*. (Could also convert to RGBM.) 518 const dstRGBA = new Uint8Array(width * height * 4); 519 520 // Convert the array of half floats to uint8_t's, clamping as needed. 521 var srcOfs = 0, dstOfs = 0; 522 for (var y = 0; y < height; y++) { 523 for (var x = 0; x < width; x++) { 524 for (var c = 0; c < 4; c++) { 525 var h = dst[srcOfs] | (dst[srcOfs + 1] << 8); 526 var f = Module.convertHalfToFloat(h); 527 528 dstRGBA[dstOfs] = Math.min(255, Math.max(0, Math.round(f * 255.0))); 529 530 srcOfs += 2; 531 dstOfs++; 532 } 533 } 534 } 535 536 tex = renderer.createRgbaTexture(dstRGBA, width, height); 537 } 538 } 539 else { 540 canvas.width = width; 541 canvas.height = height; 542 displayWidth = width; 543 displayHeight = height; 544 545 // Create 565 texture. 546 var dstTex = new Uint16Array(width * height); 547 548 // Convert the array of bytes to an array of uint16's. 549 var pix = 0; 550 for (var y = 0; y < height; y++) 551 for (var x = 0; x < width; x++, pix++) 552 dstTex[pix] = dst[2 * pix + 0] | (dst[2 * pix + 1] << 8); 553 554 tex = renderer.createRgb565Texture(dstTex, width, height); 555 } 556 557 // Now draw a quad with the texture. 558 redraw(); 559 } 560 561 function runLoadFile() { 562 elem('logger').innerHTML = ''; 563 loadArrayBuffer(elem('file').value, dataLoaded); 564 } 565 566 function alphaBlend() { drawMode = 0; redraw(); } 567 function viewRGB() { drawMode = 1; redraw(); } 568 function viewAlpha() { drawMode = 2; redraw(); } 569 function linearToSRGB() { linearToSRGBFlag = !linearToSRGBFlag; redraw(); } 570 571 function updateScale(value) { 572 document.getElementById('scale-value').textContent = value; 573 drawScale = value; 574 redraw(); 575 } 576 577 function checkForGPUFormatSupport(gl) { 578 astcSupported = !!gl.getExtension('WEBGL_compressed_texture_astc'); 579 etcSupported = !!gl.getExtension('WEBGL_compressed_texture_etc1'); 580 dxtSupported = !!gl.getExtension('WEBGL_compressed_texture_s3tc'); 581 pvrtcSupported = !!(gl.getExtension('WEBGL_compressed_texture_pvrtc')) || !!(gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc')); 582 bc7Supported = !!gl.getExtension('EXT_texture_compression_bptc'); 583 584 // Check for BC6H support 585 { 586 var ext = gl.getExtension('EXT_texture_compression_bptc'); 587 if (ext) { 588 bc6hSupported = !!ext.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; 589 } 590 } 591 592 // Check for ASTC HDR support 593 { 594 var ext = gl.getExtension('WEBGL_compressed_texture_astc'); 595 596 if (ext) {
597 var supportedProfiles = ext.getSupportedProfiles(); 598 599 var hdrProfiles = supportedProfiles.filter(profile => profile.includes('hdr')); 600 601 if (hdrProfiles.length > 0) { 602 astcHDRSupported = true; 603 } 604 } 605 } 606 607 // Check for half-float texture support. 608 { 609 var ext = gl.getExtension('OES_texture_half_float'); 610 if (ext) { 611 rgbaHalfSupported = true; 612 halfFloatWebGLFormat = ext.HALF_FLOAT_OES; 613 } 614 } 615 616 // HACK HACK - for testing uncompressed 617 //astcSupported = false; 618 //etcSupported = false; 619 //dxtSupported = false; 620 //bc7Supported = false; 621 //pvrtcSupported = false; 622 //bc6hSupported = false; 623 //astcHDRSupported = false; 624 //rgbaHalfSupported = false; 625 626 console.log('astcSupported: ' + astcSupported); 627 console.log('etcSupported: ' + etcSupported); 628 console.log('dxtSupported: ' + dxtSupported); 629 console.log('bc7Supported: ' + bc7Supported); 630 console.log('pvrtcSupported: ' + pvrtcSupported); 631 console.log('bc6hSupported: ' + bc6hSupported); 632 console.log('astcHDRSupported: ' + astcHDRSupported); 633 console.log('rgbaHalfSupported: ' + rgbaHalfSupported); 634 } 635 636 </script>
636 637</head> 638<body> 639 <br> 640 <div style="font-size: 24pt; font-weight: bold"> 641 .basis->GPU Compressed Texture Transcoder Test 642 </div> 643 644 <br>This demo uses the Basis Universal C++ transcoder (compiled to WebAssembly using Emscripten) to transcode a .basis file to <b id='format'>FORMAT</b> 645 <br>Thanks to Evan Parker for providing <a href="https://github.com/toji/webgl-texture-utils">webgl-texture-utils</a> and this test bed. <a href="../index.html">Go back.</a> 646 <br> 647 <br> 648 .basis file: 649 <input id="file" type="text" size=30 value="assets/desk.basis"></input> 650 <input type="button" value="Run!" onclick="runLoadFile()"></input> 651 <br> 652 <br> 653 <input type="button" value="Alpha blend" onclick="alphaBlend()"></input> 654 <input type="button" value="View RGB" onclick="viewRGB()"></input> 655 <input type="button" value="View Alpha" onclick="viewAlpha()"></input> 656 <input type="button" value="LinearToSRGB" onclick="linearToSRGB()"></input> 657 658 <br> 659 660 <label for="scale-slider">Scale:</label> 661 <input type="range" id="scale-slider" min="0" max="16" step=".05" value="1" style="width: 300px;" oninput="updateScale(this.value)"> 662 <span id="scale-value">1</span> 663 664 <br> 665 <br> 666 Use Container Independent Transcoding API's: 667 <input type="checkbox" id="ContainerIndependentTranscoding"> 668 669 <div style="position:absolute; left: 525px; top:130px; font-size: 20pt; font-weight: bold; color: red"> 670 <canvas id='canvas'></canvas> 671 </div> 672 673 <br><br> 674 <div id='logger'></div> 675</body>
676<script> 677 BASIS({ 678 onRuntimeInitialized: () => { 679 var gl = elem('canvas').getContext('webgl'); 680 681 checkForGPUFormatSupport(gl); 682 683 window.renderer = new Renderer(gl); 684 685 elem('file').addEventListener('keydown', function (e) { 686 if (e.keyCode == 13) { 687 runLoadFile(); 688 } 689 }, false); 690 691 runLoadFile(); 692 } 693 }).then(module => window.Module = module); 694</script>
694 695</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.