{"version":3,"file":"parseKTX.mjs","sources":["../../../src/compressed-textures/ktx/parseKTX.ts"],"sourcesContent":["import { KTX } from '../ktx2/const';\n\nimport type { TEXTURE_FORMATS } from '../../rendering/renderers/shared/texture/const';\nimport type { TextureSourceOptions } from '../../rendering/renderers/shared/texture/sources/TextureSource';\n\n/**\n * @param arrayBuffer\n * @param supportedFormats\n * @internal\n */\nexport function parseKTX(arrayBuffer: ArrayBuffer, supportedFormats: TEXTURE_FORMATS[]): TextureSourceOptions<Uint8Array[]>\n{\n    const dataView = new DataView(arrayBuffer);\n\n    if (!validate(dataView))\n    {\n        throw new Error('Invalid KTX identifier in header');\n    }\n\n    const {\n        littleEndian,\n        glType,\n        glFormat,\n        glInternalFormat,\n        pixelWidth,\n        pixelHeight,\n        numberOfMipmapLevels,\n        offset,\n    } = parseKTXHeader(dataView);\n\n    const textureFormat = KTX.INTERNAL_FORMAT_TO_TEXTURE_FORMATS[glInternalFormat];\n\n    if (!textureFormat)\n    {\n        throw new Error(`Unknown texture format ${glInternalFormat}`);\n    }\n    if (!supportedFormats.includes(textureFormat))\n    {\n        throw new Error(`Unsupported texture format: ${textureFormat}, supportedFormats: ${supportedFormats}`);\n    }\n\n    const imagePixelByteSize = getImagePixelByteSize(glType, glFormat, glInternalFormat);\n\n    const imageBuffers = getImageBuffers(dataView, glType, imagePixelByteSize, pixelWidth, pixelHeight, offset,\n        numberOfMipmapLevels, littleEndian);\n\n    return {\n        format: textureFormat,\n        width: pixelWidth,\n        height: pixelHeight,\n        resource: imageBuffers,\n        alphaMode: 'no-premultiply-alpha'\n    };\n}\n\nfunction getImageBuffers(dataView: DataView, glType: number, imagePixelByteSize: number, pixelWidth: number,\n    pixelHeight: number, offset: number, numberOfMipmapLevels: number, littleEndian: boolean)\n{\n    const alignedWidth = (pixelWidth + 3) & ~3;\n    const alignedHeight = (pixelHeight + 3) & ~3;\n    let imagePixels = pixelWidth * pixelHeight;\n\n    if (glType === 0)\n    {\n        // Align to 16 pixels (4x4 blocks)\n        imagePixels = alignedWidth * alignedHeight;\n    }\n\n    let mipByteSize = imagePixels * imagePixelByteSize;\n    let mipWidth = pixelWidth;\n    let mipHeight = pixelHeight;\n    let alignedMipWidth = alignedWidth;\n    let alignedMipHeight = alignedHeight;\n    let imageOffset = offset;\n\n    const imageBuffers = new Array<Uint8Array>(numberOfMipmapLevels);\n\n    for (let mipmapLevel = 0; mipmapLevel < numberOfMipmapLevels; mipmapLevel++)\n    {\n        const imageSize = dataView.getUint32(imageOffset, littleEndian);\n        let elementOffset = imageOffset + 4;\n\n        imageBuffers[mipmapLevel] = new Uint8Array(dataView.buffer, elementOffset, mipByteSize);\n\n        elementOffset += mipByteSize;\n\n        // HINT: Aligns to 4-byte boundary after jumping imageSize (in lieu of mipPadding)\n        imageOffset += imageSize + 4;// (+4 to jump the imageSize field itself)\n        imageOffset = imageOffset % 4 !== 0 ? imageOffset + 4 - (imageOffset % 4) : imageOffset;\n\n        // Calculate mipWidth, mipHeight for _next_ iteration\n        mipWidth = (mipWidth >> 1) || 1;\n        mipHeight = (mipHeight >> 1) || 1;\n        alignedMipWidth = (mipWidth + 4 - 1) & ~(4 - 1);\n        alignedMipHeight = (mipHeight + 4 - 1) & ~(4 - 1);\n\n        // Each mipmap level is 4-times smaller?\n        mipByteSize = alignedMipWidth * alignedMipHeight * imagePixelByteSize;\n    }\n\n    return imageBuffers;\n}\n\nfunction getImagePixelByteSize(glType: number, glFormat: number, glInternalFormat: number)\n{\n    let imagePixelByteSize = KTX.INTERNAL_FORMAT_TO_BYTES_PER_PIXEL[glInternalFormat];\n\n    if (glType !== 0)\n    {\n        // Uncompressed texture format\n        if (KTX.TYPES_TO_BYTES_PER_COMPONENT[glType])\n        {\n            imagePixelByteSize = KTX.TYPES_TO_BYTES_PER_COMPONENT[glType] * KTX.FORMATS_TO_COMPONENTS[glFormat];\n        }\n        else\n        {\n            imagePixelByteSize = KTX.TYPES_TO_BYTES_PER_PIXEL[glType];\n        }\n    }\n\n    if (imagePixelByteSize === undefined)\n    {\n        throw new Error('Unable to resolve the pixel format stored in the *.ktx file!');\n    }\n\n    return imagePixelByteSize;\n}\n\nfunction parseKTXHeader(dataView: DataView)\n{\n    const littleEndian = dataView.getUint32(KTX.FIELDS.ENDIANNESS, true) === KTX.ENDIANNESS;\n    const glType = dataView.getUint32(KTX.FIELDS.GL_TYPE, littleEndian);\n    const glFormat = dataView.getUint32(KTX.FIELDS.GL_FORMAT, littleEndian);\n    const glInternalFormat = dataView.getUint32(KTX.FIELDS.GL_INTERNAL_FORMAT, littleEndian);\n    const pixelWidth = dataView.getUint32(KTX.FIELDS.PIXEL_WIDTH, littleEndian);\n    const pixelHeight = dataView.getUint32(KTX.FIELDS.PIXEL_HEIGHT, littleEndian) || 1;// \"pixelHeight = 0\" -> \"1\"\n    const pixelDepth = dataView.getUint32(KTX.FIELDS.PIXEL_DEPTH, littleEndian) || 1;// ^^\n    const numberOfArrayElements = dataView.getUint32(KTX.FIELDS.NUMBER_OF_ARRAY_ELEMENTS, littleEndian) || 1;// ^^\n    const numberOfFaces = dataView.getUint32(KTX.FIELDS.NUMBER_OF_FACES, littleEndian);\n    const numberOfMipmapLevels = dataView.getUint32(KTX.FIELDS.NUMBER_OF_MIPMAP_LEVELS, littleEndian);\n    const bytesOfKeyValueData = dataView.getUint32(KTX.FIELDS.BYTES_OF_KEY_VALUE_DATA, littleEndian);\n\n    if (pixelHeight === 0 || pixelDepth !== 1)\n    {\n        throw new Error('Only 2D textures are supported');\n    }\n    if (numberOfFaces !== 1)\n    {\n        throw new Error('CubeTextures are not supported by KTXLoader yet!');\n    }\n    if (numberOfArrayElements !== 1)\n    {\n        throw new Error('WebGL does not support array textures');\n    }\n\n    return {\n        littleEndian,\n        glType,\n        glFormat,\n        glInternalFormat,\n        pixelWidth,\n        pixelHeight,\n        numberOfMipmapLevels,\n        offset: KTX.FILE_HEADER_SIZE + bytesOfKeyValueData\n    };\n}\n\n/**\n * Checks whether the arrayBuffer contains a valid *.ktx file.\n * @param dataView\n */\nfunction validate(dataView: DataView): boolean\n{\n    // NOTE: Do not optimize this into 3 32-bit integer comparison because the endianness\n    // of the data is not specified.\n    for (let i = 0; i < KTX.FILE_IDENTIFIER.length; i++)\n    {\n        if (dataView.getUint8(i) !== KTX.FILE_IDENTIFIER[i])\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n"],"names":[],"mappings":"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"}