{"version":3,"file":"KTXLoader.cjs","sources":["../../src/loaders/KTXLoader.js"],"sourcesContent":["import { CompressedTextureLoader } from 'three'\n\n/**\n * for description see https://www.khronos.org/opengles/sdk/tools/KTX/\n * for file layout see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/\n *\n * ported from https://github.com/BabylonJS/Babylon.js/blob/master/src/Tools/babylon.khronosTextureContainer.ts\n */\n\nclass KTXLoader extends CompressedTextureLoader {\n  constructor(manager) {\n    super(manager)\n  }\n\n  parse(buffer, loadMipmaps) {\n    const ktx = new KhronosTextureContainer(buffer, 1)\n\n    return {\n      mipmaps: ktx.mipmaps(loadMipmaps),\n      width: ktx.pixelWidth,\n      height: ktx.pixelHeight,\n      format: ktx.glInternalFormat,\n      isCubemap: ktx.numberOfFaces === 6,\n      mipmapCount: ktx.numberOfMipmapLevels,\n    }\n  }\n}\n\nconst HEADER_LEN = 12 + 13 * 4 // identifier + header elements (not including key value meta-data pairs)\n// load types\nconst COMPRESSED_2D = 0 // uses a gl.compressedTexImage2D()\n//const COMPRESSED_3D = 1; // uses a gl.compressedTexImage3D()\n//const TEX_2D = 2; // uses a gl.texImage2D()\n//const TEX_3D = 3; // uses a gl.texImage3D()\n\nclass KhronosTextureContainer {\n  /**\n   * @param {ArrayBuffer} arrayBuffer- contents of the KTX container file\n   * @param {number} facesExpected- should be either 1 or 6, based whether a cube texture or or\n   * @param {boolean} threeDExpected- provision for indicating that data should be a 3D texture, not implemented\n   * @param {boolean} textureArrayExpected- provision for indicating that data should be a texture array, not implemented\n   */\n  constructor(arrayBuffer, facesExpected /*, threeDExpected, textureArrayExpected */) {\n    this.arrayBuffer = arrayBuffer\n\n    // Test that it is a ktx formatted file, based on the first 12 bytes, character representation is:\n    // '´', 'K', 'T', 'X', ' ', '1', '1', 'ª', '\\r', '\\n', '\\x1A', '\\n'\n    // 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A\n    const identifier = new Uint8Array(this.arrayBuffer, 0, 12)\n    if (\n      identifier[0] !== 0xab ||\n      identifier[1] !== 0x4b ||\n      identifier[2] !== 0x54 ||\n      identifier[3] !== 0x58 ||\n      identifier[4] !== 0x20 ||\n      identifier[5] !== 0x31 ||\n      identifier[6] !== 0x31 ||\n      identifier[7] !== 0xbb ||\n      identifier[8] !== 0x0d ||\n      identifier[9] !== 0x0a ||\n      identifier[10] !== 0x1a ||\n      identifier[11] !== 0x0a\n    ) {\n      console.error('texture missing KTX identifier')\n      return\n    }\n\n    // load the reset of the header in native 32 bit uint\n    const dataSize = Uint32Array.BYTES_PER_ELEMENT\n    const headerDataView = new DataView(this.arrayBuffer, 12, 13 * dataSize)\n    const endianness = headerDataView.getUint32(0, true)\n    const littleEndian = endianness === 0x04030201\n\n    this.glType = headerDataView.getUint32(1 * dataSize, littleEndian) // must be 0 for compressed textures\n    this.glTypeSize = headerDataView.getUint32(2 * dataSize, littleEndian) // must be 1 for compressed textures\n    this.glFormat = headerDataView.getUint32(3 * dataSize, littleEndian) // must be 0 for compressed textures\n    this.glInternalFormat = headerDataView.getUint32(4 * dataSize, littleEndian) // the value of arg passed to gl.compressedTexImage2D(,,x,,,,)\n    this.glBaseInternalFormat = headerDataView.getUint32(5 * dataSize, littleEndian) // specify GL_RGB, GL_RGBA, GL_ALPHA, etc (un-compressed only)\n    this.pixelWidth = headerDataView.getUint32(6 * dataSize, littleEndian) // level 0 value of arg passed to gl.compressedTexImage2D(,,,x,,,)\n    this.pixelHeight = headerDataView.getUint32(7 * dataSize, littleEndian) // level 0 value of arg passed to gl.compressedTexImage2D(,,,,x,,)\n    this.pixelDepth = headerDataView.getUint32(8 * dataSize, littleEndian) // level 0 value of arg passed to gl.compressedTexImage3D(,,,,,x,,)\n    this.numberOfArrayElements = headerDataView.getUint32(9 * dataSize, littleEndian) // used for texture arrays\n    this.numberOfFaces = headerDataView.getUint32(10 * dataSize, littleEndian) // used for cubemap textures, should either be 1 or 6\n    this.numberOfMipmapLevels = headerDataView.getUint32(11 * dataSize, littleEndian) // number of levels; disregard possibility of 0 for compressed textures\n    this.bytesOfKeyValueData = headerDataView.getUint32(12 * dataSize, littleEndian) // the amount of space after the header for meta-data\n\n    // Make sure we have a compressed type.  Not only reduces work, but probably better to let dev know they are not compressing.\n    if (this.glType !== 0) {\n      console.warn('only compressed formats currently supported')\n      return\n    } else {\n      // value of zero is an indication to generate mipmaps @ runtime.  Not usually allowed for compressed, so disregard.\n      this.numberOfMipmapLevels = Math.max(1, this.numberOfMipmapLevels)\n    }\n\n    if (this.pixelHeight === 0 || this.pixelDepth !== 0) {\n      console.warn('only 2D textures currently supported')\n      return\n    }\n\n    if (this.numberOfArrayElements !== 0) {\n      console.warn('texture arrays not currently supported')\n      return\n    }\n\n    if (this.numberOfFaces !== facesExpected) {\n      console.warn('number of faces expected' + facesExpected + ', but found ' + this.numberOfFaces)\n      return\n    }\n\n    // we now have a completely validated file, so could use existence of loadType as success\n    // would need to make this more elaborate & adjust checks above to support more than one load type\n    this.loadType = COMPRESSED_2D\n  }\n\n  mipmaps(loadMipmaps) {\n    const mipmaps = []\n\n    // initialize width & height for level 1\n    let dataOffset = HEADER_LEN + this.bytesOfKeyValueData\n    let width = this.pixelWidth\n    let height = this.pixelHeight\n    const mipmapCount = loadMipmaps ? this.numberOfMipmapLevels : 1\n\n    for (let level = 0; level < mipmapCount; level++) {\n      const imageSize = new Int32Array(this.arrayBuffer, dataOffset, 1)[0] // size per face, since not supporting array cubemaps\n      dataOffset += 4 // size of the image + 4 for the imageSize field\n\n      for (let face = 0; face < this.numberOfFaces; face++) {\n        const byteArray = new Uint8Array(this.arrayBuffer, dataOffset, imageSize)\n\n        mipmaps.push({ data: byteArray, width: width, height: height })\n\n        dataOffset += imageSize\n        dataOffset += 3 - ((imageSize + 3) % 4) // add padding for odd sized image\n      }\n\n      width = Math.max(1.0, width * 0.5)\n      height = Math.max(1.0, height * 0.5)\n    }\n\n    return mipmaps\n  }\n}\n\nexport { KTXLoader }\n"],"names":["CompressedTextureLoader"],"mappings":"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"}