Fix issues with compressed texture support

* Get rid of the compression option

  We know if a texture is compressed based on its internalFormat

* Remove level stuff

  I think there was a mis-understanding how how twgl works. If you
  want to set anything other than level 0 you need to directly
  call `setTextureFormArray` directly (or `setTextureFromElement`)

* Fix tests

  The tests needed to check that the extension exists

Note: we need to decide if and how to handle cubemaps.
The code in their currently will fail. Will fix in next PR
This commit is contained in:
Gregg Tavares 2025-07-11 20:12:02 -07:00
parent 3a4c8809fb
commit 8f53aa82a9
4 changed files with 225 additions and 198 deletions

View File

@ -11,7 +11,7 @@ module.exports = {
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2020,
"ecmaVersion": 2023,
},
"plugins": [
"eslint-plugin-html",

View File

@ -386,73 +386,86 @@ function getTextureInternalFormatInfo(internalFormat) {
t[DEPTH24_STENCIL8] = { textureFormat: DEPTH_STENCIL, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [UNSIGNED_INT_24_8], };
t[DEPTH32F_STENCIL8] = { textureFormat: DEPTH_STENCIL, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [FLOAT_32_UNSIGNED_INT_24_8_REV], };
// compressed texture formats
// s3tc:https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc.txt
t[COMPRESSED_RGB_S3TC_DXT1_EXT] = { textureFormat : COMPRESSED_RGB_S3TC_DXT1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT1_EXT] = { textureFormat : COMPRESSED_RGBA_S3TC_DXT1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT3_EXT] = { textureFormat : COMPRESSED_RGBA_S3TC_DXT3_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT5_EXT] = { textureFormat : COMPRESSED_RGBA_S3TC_DXT5_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc_srgb.txt
t[COMPRESSED_SRGB_S3TC_DXT1_EXT] = { textureFormat : COMPRESSED_SRGB_S3TC_DXT1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT] = { textureFormat : COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT] = { textureFormat : COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT] = { textureFormat : COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
t[COMPRESSED_RGB_ETC1_WEBGL] = { textureFormat : COMPRESSED_RGB_ETC1_WEBGL, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_R11_EAC] = { textureFormat : COMPRESSED_R11_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_R11_EAC] = { textureFormat : COMPRESSED_SIGNED_R11_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [BYTE], };
t[COMPRESSED_RG11_EAC] = { textureFormat : COMPRESSED_RG11_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RG11_EAC] = { textureFormat : COMPRESSED_SIGNED_RG11_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [16], type : [SHORT], };
t[COMPRESSED_RGB8_ETC2] = { textureFormat : COMPRESSED_RGB8_ETC2, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ETC2] = { textureFormat : COMPRESSED_SRGB8_ETC2, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2] = { textureFormat : COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2] = { textureFormat: COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, colorRenderable : true, textureFilterable : false, bytesPerElement : [8], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA8_ETC2_EAC] = { textureFormat : COMPRESSED_RGBA8_ETC2_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ETC2_EAC] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, colorRenderable : true, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
t[COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = { textureFormat : COMPRESSED_RGB_PVRTC_4BPPV1_IMG, colorRenderable : false, textureFilterable : false, bytesPerElement : [4], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = { textureFormat : COMPRESSED_RGB_PVRTC_2BPPV1_IMG, colorRenderable : false, textureFilterable : false, bytesPerElement : [2], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = { textureFormat : COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, colorRenderable : false, textureFilterable : false, bytesPerElement : [4], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = { textureFormat : COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, colorRenderable : false, textureFilterable : false, bytesPerElement : [2], type : [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt
t[COMPRESSED_RGBA_ASTC_4x4_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_4x4_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_5x4_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_5x4_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_5x5_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_5x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_6x5_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_6x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_6x6_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_6x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x5_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_8x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x6_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_8x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x8_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_8x8_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x5_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_10x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x6_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_10x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x8_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_10x8_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x10_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_10x10_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_12x10_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_12x10_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_12x12_KHR] = { textureFormat : COMPRESSED_RGBA_ASTC_12x12_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR] = { textureFormat : COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_bptc.txt
t[COMPRESSED_RGBA_BPTC_UNORM_EXT] = { textureFormat : COMPRESSED_RGBA_BPTC_UNORM_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT] = { textureFormat : COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT] = { textureFormat : COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [4], type : [FLOAT], };
t[COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT] = { textureFormat : COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [4], type : [FLOAT], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_rgtc.txt
t[COMPRESSED_RED_RGTC1_EXT] = { textureFormat : COMPRESSED_RED_RGTC1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RED_RGTC1_EXT] = { textureFormat : COMPRESSED_SIGNED_RED_RGTC1_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_RED_GREEN_RGTC2_EXT] = { textureFormat : COMPRESSED_RED_GREEN_RGTC2_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT] = { textureFormat : COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, colorRenderable : false, textureFilterable : false, bytesPerElement : [16], type : [UNSIGNED_BYTE], };
const getCompressedTextureFormats = () => {
const t = {};
// compressed texture formats
// s3tc:https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc.txt
t[COMPRESSED_RGB_S3TC_DXT1_EXT] = { textureFormat: COMPRESSED_RGB_S3TC_DXT1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT1_EXT] = { textureFormat: COMPRESSED_RGBA_S3TC_DXT1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT3_EXT] = { textureFormat: COMPRESSED_RGBA_S3TC_DXT3_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_S3TC_DXT5_EXT] = { textureFormat: COMPRESSED_RGBA_S3TC_DXT5_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc_srgb.txt
t[COMPRESSED_SRGB_S3TC_DXT1_EXT] = { textureFormat: COMPRESSED_SRGB_S3TC_DXT1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT] = { textureFormat: COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT] = { textureFormat: COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT] = { textureFormat: COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
t[COMPRESSED_RGB_ETC1_WEBGL] = { textureFormat: COMPRESSED_RGB_ETC1_WEBGL, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_R11_EAC] = { textureFormat: COMPRESSED_R11_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_R11_EAC] = { textureFormat: COMPRESSED_SIGNED_R11_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [BYTE], };
t[COMPRESSED_RG11_EAC] = { textureFormat: COMPRESSED_RG11_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RG11_EAC] = { textureFormat: COMPRESSED_SIGNED_RG11_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [SHORT], };
t[COMPRESSED_RGB8_ETC2] = { textureFormat: COMPRESSED_RGB8_ETC2, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ETC2] = { textureFormat: COMPRESSED_SRGB8_ETC2, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2] = { textureFormat: COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2] = { textureFormat: COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA8_ETC2_EAC] = { textureFormat: COMPRESSED_RGBA8_ETC2_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ETC2_EAC] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
t[COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = { textureFormat: COMPRESSED_RGB_PVRTC_4BPPV1_IMG, colorRenderable: false, textureFilterable: false, bytesPerElement: [4], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = { textureFormat: COMPRESSED_RGB_PVRTC_2BPPV1_IMG, colorRenderable: false, textureFilterable: false, bytesPerElement: [2], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = { textureFormat: COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, colorRenderable: false, textureFilterable: false, bytesPerElement: [4], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = { textureFormat: COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, colorRenderable: false, textureFilterable: false, bytesPerElement: [2], type: [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt
t[COMPRESSED_RGBA_ASTC_4x4_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_4x4_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_5x4_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_5x4_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_5x5_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_5x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_6x5_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_6x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_6x6_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_6x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x5_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_8x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x6_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_8x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_8x8_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_8x8_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x5_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_10x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x6_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_10x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x8_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_10x8_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_10x10_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_10x10_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_12x10_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_12x10_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGBA_ASTC_12x12_KHR] = { textureFormat: COMPRESSED_RGBA_ASTC_12x12_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR] = { textureFormat: COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_bptc.txt
t[COMPRESSED_RGBA_BPTC_UNORM_EXT] = { textureFormat: COMPRESSED_RGBA_BPTC_UNORM_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT] = { textureFormat: COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT] = { textureFormat: COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [4], type: [FLOAT], };
t[COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT] = { textureFormat: COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [4], type: [FLOAT], };
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_rgtc.txt
t[COMPRESSED_RED_RGTC1_EXT] = { textureFormat: COMPRESSED_RED_RGTC1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RED_RGTC1_EXT] = { textureFormat: COMPRESSED_SIGNED_RED_RGTC1_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_RED_GREEN_RGTC2_EXT] = { textureFormat: COMPRESSED_RED_GREEN_RGTC2_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
t[COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT] = { textureFormat: COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [UNSIGNED_BYTE], };
for (const value of Object.values(t)) {
value.compressed = true;
}
return t;
};
Object.assign(t, getCompressedTextureFormats());
Object.keys(t).forEach(function(internalFormat) {
const info = t[internalFormat];
info.bytesPerElementMap = {};
@ -513,6 +526,18 @@ function getFormatAndTypeForInternalFormat(internalFormat) {
};
}
/**
* @param {number} internalFormat The internal format
* @returns if the internalFormat is a compressed format
*/
function isCompressedInternalFormat(internalFormat) {
const info = getTextureInternalFormatInfo(internalFormat);
if (!info) {
throw "unknown internal format";
}
return !!info.compressed;
}
/**
* Returns true if value is power of 2
* @param {number} value number to check.
@ -741,7 +766,6 @@ function setDefaults(newDefaults) {
* @property {string} [crossOrigin] What to set the crossOrigin property of images when they are downloaded.
* default: undefined. Also see {@link module:twgl.setDefaults}.
*
* @property {boolean} [compressed] If set to `true`, compressedTexImage2D will be used to process the texture. Defaults to `false`.
* @memberOf module:twgl
*/
@ -1650,15 +1674,11 @@ function setTextureFromArray(gl, tex, src, options) {
options = options || defaults.textureOptions;
const target = options.target || TEXTURE_2D;
gl.bindTexture(target, tex);
let width = options.width;
let height = options.height;
let depth = options.depth;
const level = options.level || 0;
const internalFormat = options.internalFormat || options.format || RGBA;
const formatType = getFormatAndTypeForInternalFormat(internalFormat);
const format = options.format || formatType.format;
const type = options.type || getTextureTypeForArrayType(gl, src, formatType.type);
const compressed = options.compressed;
if (!isArrayBuffer(src)) {
const Type = typedArrays.getTypedArrayTypeForGLType(type);
src = new Type(src);
@ -1666,42 +1686,9 @@ function setTextureFromArray(gl, tex, src, options) {
src = new Uint8Array(src.buffer);
}
const bytesPerElement = getBytesPerElementForInternalFormat(internalFormat, type);
const numElements = src.byteLength / bytesPerElement; // TODO: check UNPACK_ALIGNMENT?
if (numElements % 1) {
throw "length wrong size for format: " + utils.glEnumToString(gl, format);
}
if (compressed && !width && !height) {
throw "compressed texture needs to set width and height!";
}
let dimensions;
if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) {
if (!width && !height && !depth) {
const size = Math.cbrt(numElements);
if (size % 1 !== 0) {
throw "can't guess cube size of array of numElements: " + numElements;
}
width = size;
height = size;
depth = size;
} else if (width && (!height || !depth)) {
dimensions = guessDimensions(gl, target, height, depth, numElements / width);
height = dimensions.width;
depth = dimensions.height;
} else if (height && (!width || !depth)) {
dimensions = guessDimensions(gl, target, width, depth, numElements / height);
width = dimensions.width;
depth = dimensions.height;
} else {
dimensions = guessDimensions(gl, target, width, height, numElements / depth);
width = dimensions.width;
height = dimensions.height;
}
} else {
dimensions = guessDimensions(gl, target, width, height, numElements);
width = dimensions.width;
height = dimensions.height;
}
const { bytesPerElement, numElements, width, height, depth } = getTextureDataInfo(target, src, options, internalFormat, format, type);
const compressed = isCompressedInternalFormat(internalFormat);
setSkipStateToDefault(gl);
gl.pixelStorei(UNPACK_ALIGNMENT, options.unpackAlignment || 1);
scopedSetPackState(gl, options, () => {
@ -1712,30 +1699,17 @@ function setTextureFromArray(gl, tex, src, options) {
getCubeFacesWithNdx(gl, options).forEach(f => {
const offset = faceSize * f.ndx;
const data = src.subarray(offset, offset + faceSize);
gl.texImage2D(f.face, level, internalFormat, width, height, 0, format, type, data);
if (compressed) {
gl.compressedTexImage2D(f.face, level, internalFormat, width, height, 0, data);
} else {
gl.texImage2D(f.face, level, internalFormat, width, height, 0, format, type, data);
}
});
} else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) {
gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, src);
} else {
if ( compressed ){
if ( level === 0 ){
gl.compressedTexImage2D(target, level, internalFormat, width, height, 0, src);
} else {
let offset = false;
for (let i = 0; i < level; ++i) {
// Determine how big this level of compressed texture data is in bytes.
const levelSize = textureLevelSize(internalFormat, width, height);
// Get a view of the bytes for this level of DXT data.
const dxtLevel = new Uint8Array(src.buffer, src.byteOffset + offset, levelSize);
// Upload!
gl.compressedTexImage2D(gl.TEXTURE_2D, i, internalFormat, width, height, 0, dxtLevel);
// The next mip level will be half the height and width of this one.
width = width >> 1;
height = height >> 1;
// Advance the offset into the compressed texture data past the current mip level's data.
offset += levelSize;
}
}
if (compressed) {
gl.compressedTexImage2D(target, level, internalFormat, width, height, 0, src);
} else {
gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, src);
}
@ -1749,6 +1723,67 @@ function setTextureFromArray(gl, tex, src, options) {
};
}
function getTextureDataInfo(target, src, options, internalFormat, format, type) {
let width = options.width;
let height = options.height;
let depth = options.depth;
let bytesPerElement = 0;
let numElements = 0;
const compressed = isCompressedInternalFormat(internalFormat);
if (compressed) {
if (!width || !height) {
throw "compressed texture needs to set width and height!";
}
} else {
bytesPerElement = getBytesPerElementForInternalFormat(internalFormat, type);
numElements = src.byteLength / bytesPerElement; // TODO: check UNPACK_ALIGNMENT?
if (numElements % 1) {
throw "length wrong size for format: " + utils.glEnumToString(gl, format);
}
if (compressed && (!width || !height)) {
throw "compressed texture needs to set width and height!";
}
let dimensions;
if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) {
if (!width && !height && !depth) {
const size = Math.cbrt(numElements);
if (size % 1 !== 0) {
throw "can't guess cube size of array of numElements: " + numElements;
}
width = size;
height = size;
depth = size;
} else if (width && (!height || !depth)) {
dimensions = guessDimensions(gl, target, height, depth, numElements / width);
height = dimensions.width;
depth = dimensions.height;
} else if (height && (!width || !depth)) {
dimensions = guessDimensions(gl, target, width, depth, numElements / height);
width = dimensions.width;
depth = dimensions.height;
} else {
dimensions = guessDimensions(gl, target, width, height, numElements / depth);
width = dimensions.width;
height = dimensions.height;
}
} else {
dimensions = guessDimensions(gl, target, width, height, numElements);
width = dimensions.width;
height = dimensions.height;
}
}
return {
bytesPerElement,
numElements,
width,
height,
depth,
};
}
/**
* Sets a texture with no contents of a certain size. In other words calls `gl.texImage2D` with `null`.
* You must set `options.width` and `options.height`.
@ -2111,29 +2146,6 @@ function createTexturesAsync(gl, options) {
});
}
function textureLevelSize(format, width, height) {
switch (format) {
case COMPRESSED_RGB_S3TC_DXT1_EXT:
case COMPRESSED_RGB_ETC1_WEBGL:
return ((width + 3) >> 2) * ((height + 3) >> 2) * 8;
case COMPRESSED_RGBA_S3TC_DXT3_EXT:
case COMPRESSED_RGBA_S3TC_DXT5_EXT:
return ((width + 3) >> 2) * ((height + 3) >> 2) * 16;
case COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
case COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
return Math.floor((Math.max(width, 8) * Math.max(height, 8) * 4 + 7) / 8);
case COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
case COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
return Math.floor((Math.max(width, 16) * Math.max(height, 8) * 2 + 7) / 8);
default:
return 0;
}
}
export {
setDefaults as setTextureDefaults_,

View File

@ -11,7 +11,8 @@ import {
createContext2,
itWebGL,
itWebGL2,
checkColor
checkColor,
setCanvasAndViewportSizeTo1x1
} from '../webgl.js';
function assertPixelFromTexture(gl, texture, expected) {
@ -32,6 +33,25 @@ function createRedGreenURL() {
return ctx.canvas.toDataURL();
}
function create1PixelTextureRenderingProgram(gl) {
const vs = `#version 300 es
void main() {
gl_Position = vec4(0, 0, 0, 1);
gl_PointSize = 1.0;
}
`;
const fs = `#version 300 es
precision highp float;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = texture(u_texture, vec2(0.5));
}
`;
return twgl.createProgram(gl, [vs, fs]);
}
describe('texture tests', () => {
itWebGL(`test y flips correctly`, async() => {
@ -75,60 +95,49 @@ describe('texture tests', () => {
assertNoWebGLError(gl);
});
itWebGL2(`test compressed texture format`, async() => {
itWebGL2(`test compressed texture format EXT_texture_compression_bptc`, ['EXT_texture_compression_bptc'], async() => {
const {gl} = createContext2();
const vs = `#version 300 es
in vec2 position;
in vec2 texcoord;
out vec2 v_texcoord;
void main() {
gl_Position = vec4(position, 0, 1);
v_texcoord = texcoord;
}`;
const fs = `#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = texture(u_texture, v_texcoord);
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const arrays = {
position: [1, 1, 0.0, 1, -1, 0.0, -1, -1, 0.0, -1, 1, 0.0],
texcoord: [1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0],
indices: [0, 1, 3, 1, 2, 3],
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
twgl.addExtensionsToContext(gl);
setCanvasAndViewportSizeTo1x1(gl);
const green = [2, 255, 2, 255];
// KTX2:BASIS_FORMAT.cTFBC7
const internalFormat = gl.COMPRESSED_RGBA_BPTC_UNORM;
const green_4x4 = new Uint8Array([32, 128, 193, 255, 15, 24, 252, 255, 175, 170, 170, 170, 0, 0, 0, 0]);
const width = 4;
const height = 4;
let internalFormat = 0x8E8C; //COMPRESSED_RGBA_BPTC_UNORM
gl.canvas.width = width;
gl.canvas.height = height;
let texture = twgl.createTexture(gl, { src: green_4x4, width, height, internalFormat, compressed: true });
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, { u_texture: texture });
twgl.drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
// eslint-disable-next-line no-unused-vars
const texture = twgl.createTexture(gl, { src: green_4x4, width, height, internalFormat });
assertNoWebGLError(gl);
const prg = create1PixelTextureRenderingProgram(gl);
gl.useProgram(prg);
gl.drawArrays(gl.POINTS, 0, 1);
checkColor(gl, green);
});
itWebGL2(`test compressed texture format WEBGL_compressed_texture_s3tc`, ['WEBGL_compressed_texture_s3tc'], async() => {
const {gl} = createContext2();
twgl.addExtensionsToContext(gl);
setCanvasAndViewportSizeTo1x1(gl);
const red = [255, 0, 0, 255];
// DDS:COMPRESSED_RGB_S3TC_DXT1_EXT
const red_4x4 = new Uint8Array([0, 248, 0, 248, 0, 0, 0, 0, 0, 248, 0, 248, 0, 0, 0, 0, 0, 248, 0, 248, 0, 0, 0, 0]);
internalFormat = 0x83F0; //COMPRESSED_RGB_S3TC_DXT1_EXT
texture = twgl.createTexture(gl, { src: red_4x4, width, height, internalFormat, compressed: true, level:3 });
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, { u_texture: texture });
twgl.drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
const internalFormat = gl.COMPRESSED_RGB_S3TC_DXT1_EXT;
const red_4x4 = new Uint16Array([
0b11111_000000_00000,
0b11111_000000_00000,
0, 0,
]);
const width = 4;
const height = 4;
// eslint-disable-next-line no-unused-vars
const texture = twgl.createTexture(gl, { src: red_4x4, width, height, internalFormat });
assertNoWebGLError(gl);
const prg = create1PixelTextureRenderingProgram(gl);
gl.useProgram(prg);
gl.drawArrays(gl.POINTS, 0, 1);
checkColor(gl, red);
assertNoWebGLError(gl);

View File

@ -34,6 +34,12 @@ export function fnWithCallbackToPromise(fn) {
};
}
export function setCanvasAndViewportSizeTo1x1(gl) {
gl.canvas.width = 1;
gl.canvas.height = 1;
gl.viewport(0, 0, 1, 1);
}
export function createContext() {
const gl = document.createElement('canvas').getContext('webgl');
return { gl };