diff --git a/src/textures.js b/src/textures.js index ec438357..63d3a5b1 100644 --- a/src/textures.js +++ b/src/textures.js @@ -216,6 +216,74 @@ const RED_INTEGER = 0x8D94; const RGB_INTEGER = 0x8D98; const RGBA_INTEGER = 0x8D99; +/* Compressed Texture Formats */ +// s3tc +const COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; +const COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; +const COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; +const COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; +// s3tc_srgb +const COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C; +const COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D; +const COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E; +const COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F; +// etc +const COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; +const COMPRESSED_R11_EAC = 0x9270; +const COMPRESSED_SIGNED_R11_EAC = 0x9271; +const COMPRESSED_RG11_EAC = 0x9272; +const COMPRESSED_SIGNED_RG11_EAC = 0x9273; +const COMPRESSED_RGB8_ETC2 = 0x9274; +const COMPRESSED_SRGB8_ETC2 = 0x9275; +const COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276; +const COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277; +const COMPRESSED_RGBA8_ETC2_EAC = 0x9278; +const COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279; +// pvrtc +const COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00; +const COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01; +const COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02; +const COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03; +// astc +const COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0; +const COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1; +const COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2; +const COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3; +const COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4; +const COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5; +const COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6; +const COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7; +const COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8; +const COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9; +const COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA; +const COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB; +const COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC; +const COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD; +const COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0; +const COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1; +const COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2; +const COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3; +const COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4; +const COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5; +const COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6; +const COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7; +const COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8; +const COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9; +const COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA; +const COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB; +const COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC; +const COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD; +// bptc +const COMPRESSED_RGBA_BPTC_UNORM_EXT = 0x8E8C; +const COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT = 0x8E8D; +const COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT = 0x8E8E; +const COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT = 0x8E8F; +// rgtc +const COMPRESSED_RED_RGTC1_EXT = 0x8DBB; +const COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC; +const COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD; +const COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE; + const formatInfo = {}; { // NOTE: this is named `numColorComponents` vs `numComponents` so we can let Uglify mangle @@ -318,6 +386,73 @@ 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], }; Object.keys(t).forEach(function(internalFormat) { const info = t[internalFormat]; info.bytesPerElementMap = {}; @@ -606,6 +741,7 @@ 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 */ @@ -1522,6 +1658,7 @@ function setTextureFromArray(gl, tex, src, options) { 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); @@ -1534,6 +1671,9 @@ function setTextureFromArray(gl, tex, src, options) { 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) { @@ -1577,7 +1717,28 @@ function setTextureFromArray(gl, tex, src, options) { } else if (target === TEXTURE_3D || target === TEXTURE_2D_ARRAY) { gl.texImage3D(target, level, internalFormat, width, height, depth, 0, format, type, src); } else { - gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, src); + 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; + } + } + } else { + gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, src); + } } }); return { @@ -1950,6 +2111,29 @@ 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_, diff --git a/src/twgl.js b/src/twgl.js index 95674c5e..86de94ca 100644 --- a/src/twgl.js +++ b/src/twgl.js @@ -204,6 +204,8 @@ const supportedExtensions = [ 'EXT_frag_depth', 'EXT_sRGB', 'EXT_shader_texture_lod', + 'EXT_texture_compression_bptc', + 'EXT_texture_compression_rgtc', 'EXT_texture_filter_anisotropic', 'OES_element_index_uint', 'OES_standard_derivatives', @@ -215,6 +217,7 @@ const supportedExtensions = [ 'WEBGL_color_buffer_float', 'WEBGL_compressed_texture_atc', 'WEBGL_compressed_texture_etc1', + 'WEBGL_compressed_texture_etc', 'WEBGL_compressed_texture_pvrtc', 'WEBGL_compressed_texture_s3tc', 'WEBGL_compressed_texture_s3tc_srgb', diff --git a/test/tests/texture-tests.js b/test/tests/texture-tests.js index 4e790bd8..0262ade9 100644 --- a/test/tests/texture-tests.js +++ b/test/tests/texture-tests.js @@ -8,7 +8,10 @@ import {describe} from '../mocha-support.js'; import { assertNoWebGLError, createContext, + createContext2, itWebGL, + itWebGL2, + checkColor } from '../webgl.js'; function assertPixelFromTexture(gl, texture, expected) { @@ -72,4 +75,63 @@ describe('texture tests', () => { assertNoWebGLError(gl); }); + itWebGL2(`test compressed texture format`, 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); + const green = [2, 255, 2, 255]; + // KTX2:BASIS_FORMAT.cTFBC7 + 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); + checkColor(gl, green); + + 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); + checkColor(gl, red); + + assertNoWebGLError(gl); + }); + }); \ No newline at end of file