Buckets:
| import { CompressedTextureLoader } from "three"; | |
| class KTXLoader extends CompressedTextureLoader { | |
| constructor(manager) { | |
| super(manager); | |
| } | |
| parse(buffer, loadMipmaps) { | |
| const ktx = new KhronosTextureContainer(buffer, 1); | |
| return { | |
| mipmaps: ktx.mipmaps(loadMipmaps), | |
| width: ktx.pixelWidth, | |
| height: ktx.pixelHeight, | |
| format: ktx.glInternalFormat, | |
| isCubemap: ktx.numberOfFaces === 6, | |
| mipmapCount: ktx.numberOfMipmapLevels | |
| }; | |
| } | |
| } | |
| const HEADER_LEN = 12 + 13 * 4; | |
| const COMPRESSED_2D = 0; | |
| class KhronosTextureContainer { | |
| /** | |
| * @param {ArrayBuffer} arrayBuffer- contents of the KTX container file | |
| * @param {number} facesExpected- should be either 1 or 6, based whether a cube texture or or | |
| * @param {boolean} threeDExpected- provision for indicating that data should be a 3D texture, not implemented | |
| * @param {boolean} textureArrayExpected- provision for indicating that data should be a texture array, not implemented | |
| */ | |
| constructor(arrayBuffer, facesExpected) { | |
| this.arrayBuffer = arrayBuffer; | |
| const identifier = new Uint8Array(this.arrayBuffer, 0, 12); | |
| if (identifier[0] !== 171 || identifier[1] !== 75 || identifier[2] !== 84 || identifier[3] !== 88 || identifier[4] !== 32 || identifier[5] !== 49 || identifier[6] !== 49 || identifier[7] !== 187 || identifier[8] !== 13 || identifier[9] !== 10 || identifier[10] !== 26 || identifier[11] !== 10) { | |
| console.error("texture missing KTX identifier"); | |
| return; | |
| } | |
| const dataSize = Uint32Array.BYTES_PER_ELEMENT; | |
| const headerDataView = new DataView(this.arrayBuffer, 12, 13 * dataSize); | |
| const endianness = headerDataView.getUint32(0, true); | |
| const littleEndian = endianness === 67305985; | |
| this.glType = headerDataView.getUint32(1 * dataSize, littleEndian); | |
| this.glTypeSize = headerDataView.getUint32(2 * dataSize, littleEndian); | |
| this.glFormat = headerDataView.getUint32(3 * dataSize, littleEndian); | |
| this.glInternalFormat = headerDataView.getUint32(4 * dataSize, littleEndian); | |
| this.glBaseInternalFormat = headerDataView.getUint32(5 * dataSize, littleEndian); | |
| this.pixelWidth = headerDataView.getUint32(6 * dataSize, littleEndian); | |
| this.pixelHeight = headerDataView.getUint32(7 * dataSize, littleEndian); | |
| this.pixelDepth = headerDataView.getUint32(8 * dataSize, littleEndian); | |
| this.numberOfArrayElements = headerDataView.getUint32(9 * dataSize, littleEndian); | |
| this.numberOfFaces = headerDataView.getUint32(10 * dataSize, littleEndian); | |
| this.numberOfMipmapLevels = headerDataView.getUint32(11 * dataSize, littleEndian); | |
| this.bytesOfKeyValueData = headerDataView.getUint32(12 * dataSize, littleEndian); | |
| if (this.glType !== 0) { | |
| console.warn("only compressed formats currently supported"); | |
| return; | |
| } else { | |
| this.numberOfMipmapLevels = Math.max(1, this.numberOfMipmapLevels); | |
| } | |
| if (this.pixelHeight === 0 || this.pixelDepth !== 0) { | |
| console.warn("only 2D textures currently supported"); | |
| return; | |
| } | |
| if (this.numberOfArrayElements !== 0) { | |
| console.warn("texture arrays not currently supported"); | |
| return; | |
| } | |
| if (this.numberOfFaces !== facesExpected) { | |
| console.warn("number of faces expected" + facesExpected + ", but found " + this.numberOfFaces); | |
| return; | |
| } | |
| this.loadType = COMPRESSED_2D; | |
| } | |
| mipmaps(loadMipmaps) { | |
| const mipmaps = []; | |
| let dataOffset = HEADER_LEN + this.bytesOfKeyValueData; | |
| let width = this.pixelWidth; | |
| let height = this.pixelHeight; | |
| const mipmapCount = loadMipmaps ? this.numberOfMipmapLevels : 1; | |
| for (let level = 0; level < mipmapCount; level++) { | |
| const imageSize = new Int32Array(this.arrayBuffer, dataOffset, 1)[0]; | |
| dataOffset += 4; | |
| for (let face = 0; face < this.numberOfFaces; face++) { | |
| const byteArray = new Uint8Array(this.arrayBuffer, dataOffset, imageSize); | |
| mipmaps.push({ data: byteArray, width, height }); | |
| dataOffset += imageSize; | |
| dataOffset += 3 - (imageSize + 3) % 4; | |
| } | |
| width = Math.max(1, width * 0.5); | |
| height = Math.max(1, height * 0.5); | |
| } | |
| return mipmaps; | |
| } | |
| } | |
| export { | |
| KTXLoader | |
| }; | |
| //# sourceMappingURL=KTXLoader.js.map | |
Xet Storage Details
- Size:
- 4.25 kB
- Xet hash:
- c104f6f4afd5f32b210099528ed4ed3038dfcfa5479b534c9e582a37908e657d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.