Files
Foundry-VTT-Docker/resources/app/node_modules/@pixi/compressed-textures/lib/parsers/parseKTX.mjs.map
2025-01-04 00:34:03 +01:00

1 line
18 KiB
Plaintext

{"version":3,"file":"parseKTX.mjs","sources":["../../src/parsers/parseKTX.ts"],"sourcesContent":["import { BufferResource, FORMATS, TYPES } from '@pixi/core';\nimport { INTERNAL_FORMAT_TO_BYTES_PER_PIXEL } from '../const';\nimport { CompressedTextureResource } from '../resources';\n\nimport type { CompressedLevelBuffer } from '../resources';\n\n/**\n * The 12-byte KTX file identifier\n * @see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/#2.1\n * @ignore\n */\nconst FILE_IDENTIFIER = [0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A];\n\n/**\n * The value stored in the \"endianness\" field.\n * @see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/#2.2\n * @ignore\n */\nconst ENDIANNESS = 0x04030201;\n\n/**\n * Byte offsets of the KTX file header fields\n * @ignore\n */\nconst KTX_FIELDS = {\n FILE_IDENTIFIER: 0,\n ENDIANNESS: 12,\n GL_TYPE: 16,\n GL_TYPE_SIZE: 20,\n GL_FORMAT: 24,\n GL_INTERNAL_FORMAT: 28,\n GL_BASE_INTERNAL_FORMAT: 32,\n PIXEL_WIDTH: 36,\n PIXEL_HEIGHT: 40,\n PIXEL_DEPTH: 44,\n NUMBER_OF_ARRAY_ELEMENTS: 48,\n NUMBER_OF_FACES: 52,\n NUMBER_OF_MIPMAP_LEVELS: 56,\n BYTES_OF_KEY_VALUE_DATA: 60\n};\n\n/**\n * Byte size of the file header fields in {@code KTX_FIELDS}\n * @ignore\n */\nconst FILE_HEADER_SIZE = 64;\n\n/**\n * Maps {@link PIXI.TYPES} to the bytes taken per component, excluding those ones that are bit-fields.\n * @ignore\n */\nexport const TYPES_TO_BYTES_PER_COMPONENT: { [id: number]: number } = {\n [TYPES.UNSIGNED_BYTE]: 1,\n [TYPES.UNSIGNED_SHORT]: 2,\n [TYPES.INT]: 4,\n [TYPES.UNSIGNED_INT]: 4,\n [TYPES.FLOAT]: 4,\n [TYPES.HALF_FLOAT]: 8\n};\n\n/**\n * Number of components in each {@link PIXI.FORMATS}\n * @ignore\n */\nexport const FORMATS_TO_COMPONENTS: { [id: number]: number } = {\n [FORMATS.RGBA]: 4,\n [FORMATS.RGB]: 3,\n [FORMATS.RG]: 2,\n [FORMATS.RED]: 1,\n [FORMATS.LUMINANCE]: 1,\n [FORMATS.LUMINANCE_ALPHA]: 2,\n [FORMATS.ALPHA]: 1\n};\n\n/**\n * Number of bytes per pixel in bit-field types in {@link PIXI.TYPES}\n * @ignore\n */\nexport const TYPES_TO_BYTES_PER_PIXEL: { [id: number]: number } = {\n [TYPES.UNSIGNED_SHORT_4_4_4_4]: 2,\n [TYPES.UNSIGNED_SHORT_5_5_5_1]: 2,\n [TYPES.UNSIGNED_SHORT_5_6_5]: 2\n};\n\nexport function parseKTX(url: string, arrayBuffer: ArrayBuffer, loadKeyValueData = false): {\n compressed?: CompressedTextureResource[]\n uncompressed?: { resource: BufferResource, type: TYPES, format: FORMATS }[]\n kvData: Map<string, DataView> | null\n}\n{\n const dataView = new DataView(arrayBuffer);\n\n if (!validate(url, dataView))\n {\n return null;\n }\n\n const littleEndian = dataView.getUint32(KTX_FIELDS.ENDIANNESS, true) === ENDIANNESS;\n const glType = dataView.getUint32(KTX_FIELDS.GL_TYPE, littleEndian);\n // const glTypeSize = dataView.getUint32(KTX_FIELDS.GL_TYPE_SIZE, 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 // Whether the platform architecture is little endian. If littleEndian !== platformLittleEndian, then the\n // file contents must be endian-converted!\n // TODO: Endianness conversion\n // const platformLittleEndian = new Uint8Array((new Uint32Array([ENDIANNESS])).buffer)[0] === 0x01;\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 // TODO: Support splitting array-textures into multiple BaseTextures\n throw new Error('WebGL does not support array textures');\n }\n\n // TODO: 8x4 blocks for 2bpp pvrtc\n const blockWidth = 4;\n const blockHeight = 4;\n\n const alignedWidth = (pixelWidth + 3) & ~3;\n const alignedHeight = (pixelHeight + 3) & ~3;\n const imageBuffers = new Array<CompressedLevelBuffer[]>(numberOfArrayElements);\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 imagePixelByteSize: number;\n\n if (glType !== 0)\n {\n // Uncompressed texture format\n if (TYPES_TO_BYTES_PER_COMPONENT[glType])\n {\n imagePixelByteSize = TYPES_TO_BYTES_PER_COMPONENT[glType] * FORMATS_TO_COMPONENTS[glFormat];\n }\n else\n {\n imagePixelByteSize = TYPES_TO_BYTES_PER_PIXEL[glType];\n }\n }\n else\n {\n imagePixelByteSize = INTERNAL_FORMAT_TO_BYTES_PER_PIXEL[glInternalFormat];\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 const kvData: Map<string, DataView> | null = loadKeyValueData\n ? parseKvData(dataView, bytesOfKeyValueData, littleEndian)\n : null;\n\n const imageByteSize = imagePixels * imagePixelByteSize;\n let mipByteSize = imageByteSize;\n let mipWidth = pixelWidth;\n let mipHeight = pixelHeight;\n let alignedMipWidth = alignedWidth;\n let alignedMipHeight = alignedHeight;\n let imageOffset = FILE_HEADER_SIZE + bytesOfKeyValueData;\n\n for (let mipmapLevel = 0; mipmapLevel < numberOfMipmapLevels; mipmapLevel++)\n {\n const imageSize = dataView.getUint32(imageOffset, littleEndian);\n let elementOffset = imageOffset + 4;\n\n for (let arrayElement = 0; arrayElement < numberOfArrayElements; arrayElement++)\n {\n // TODO: Maybe support 3D textures? :-)\n // for (let zSlice = 0; zSlice < pixelDepth; zSlice)\n\n let mips = imageBuffers[arrayElement];\n\n if (!mips)\n {\n mips = imageBuffers[arrayElement] = new Array(numberOfMipmapLevels);\n }\n\n mips[mipmapLevel] = {\n levelID: mipmapLevel,\n\n // don't align mipWidth when texture not compressed! (glType not zero)\n levelWidth: numberOfMipmapLevels > 1 || glType !== 0 ? mipWidth : alignedMipWidth,\n levelHeight: numberOfMipmapLevels > 1 || glType !== 0 ? mipHeight : alignedMipHeight,\n levelBuffer: new Uint8Array(arrayBuffer, elementOffset, mipByteSize)\n };\n elementOffset += mipByteSize;\n }\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 + blockWidth - 1) & ~(blockWidth - 1);\n alignedMipHeight = (mipHeight + blockHeight - 1) & ~(blockHeight - 1);\n\n // Each mipmap level is 4-times smaller?\n mipByteSize = alignedMipWidth * alignedMipHeight * imagePixelByteSize;\n }\n\n // We use the levelBuffers feature of CompressedTextureResource b/c texture data is image-major, not level-major.\n if (glType !== 0)\n {\n return {\n uncompressed: imageBuffers.map((levelBuffers) =>\n {\n let buffer: Float32Array | Uint32Array | Int32Array | Uint8Array = levelBuffers[0].levelBuffer;\n let convertToInt = false;\n\n if (glType === TYPES.FLOAT)\n {\n buffer = new Float32Array(\n levelBuffers[0].levelBuffer.buffer,\n levelBuffers[0].levelBuffer.byteOffset,\n levelBuffers[0].levelBuffer.byteLength / 4);\n }\n else if (glType === TYPES.UNSIGNED_INT)\n {\n convertToInt = true;\n buffer = new Uint32Array(\n levelBuffers[0].levelBuffer.buffer,\n levelBuffers[0].levelBuffer.byteOffset,\n levelBuffers[0].levelBuffer.byteLength / 4);\n }\n else if (glType === TYPES.INT)\n {\n convertToInt = true;\n buffer = new Int32Array(\n levelBuffers[0].levelBuffer.buffer,\n levelBuffers[0].levelBuffer.byteOffset,\n levelBuffers[0].levelBuffer.byteLength / 4);\n }\n\n return {\n resource: new BufferResource(\n buffer,\n {\n width: levelBuffers[0].levelWidth,\n height: levelBuffers[0].levelHeight,\n }\n ),\n type: glType,\n format: convertToInt ? convertFormatToInteger(glFormat) : glFormat,\n };\n }),\n kvData\n };\n }\n\n return {\n compressed: imageBuffers.map((levelBuffers) => new CompressedTextureResource(null, {\n format: glInternalFormat,\n width: pixelWidth,\n height: pixelHeight,\n levels: numberOfMipmapLevels,\n levelBuffers,\n })),\n kvData\n };\n}\n\n/**\n * Checks whether the arrayBuffer contains a valid *.ktx file.\n * @param url\n * @param dataView\n */\nfunction validate(url: string, 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 < FILE_IDENTIFIER.length; i++)\n {\n if (dataView.getUint8(i) !== FILE_IDENTIFIER[i])\n {\n if (process.env.DEBUG)\n {\n console.error(`${url} is not a valid *.ktx file!`);\n }\n\n return false;\n }\n }\n\n return true;\n}\n\nfunction convertFormatToInteger(format: FORMATS)\n{\n switch (format)\n {\n case FORMATS.RGBA: return FORMATS.RGBA_INTEGER;\n case FORMATS.RGB: return FORMATS.RGB_INTEGER;\n case FORMATS.RG: return FORMATS.RG_INTEGER;\n case FORMATS.RED: return FORMATS.RED_INTEGER;\n default: return format;\n }\n}\n\nfunction parseKvData(dataView: DataView, bytesOfKeyValueData: number, littleEndian: boolean): Map<string, DataView>\n{\n const kvData = new Map<string, DataView>();\n let bytesIntoKeyValueData = 0;\n\n while (bytesIntoKeyValueData < bytesOfKeyValueData)\n {\n const keyAndValueByteSize = dataView.getUint32(FILE_HEADER_SIZE + bytesIntoKeyValueData, littleEndian);\n const keyAndValueByteOffset = FILE_HEADER_SIZE + bytesIntoKeyValueData + 4;\n const valuePadding = 3 - ((keyAndValueByteSize + 3) % 4);\n\n // Bounds check\n if (keyAndValueByteSize === 0 || keyAndValueByteSize > bytesOfKeyValueData - bytesIntoKeyValueData)\n {\n console.error('KTXLoader: keyAndValueByteSize out of bounds');\n break;\n }\n\n // Note: keyNulByte can't be 0 otherwise the key is an empty string.\n let keyNulByte = 0;\n\n for (; keyNulByte < keyAndValueByteSize; keyNulByte++)\n {\n if (dataView.getUint8(keyAndValueByteOffset + keyNulByte) === 0x00)\n {\n break;\n }\n }\n\n if (keyNulByte === -1)\n {\n console.error('KTXLoader: Failed to find null byte terminating kvData key');\n break;\n }\n\n const key = new TextDecoder().decode(\n new Uint8Array(dataView.buffer, keyAndValueByteOffset, keyNulByte)\n );\n const value = new DataView(\n dataView.buffer,\n keyAndValueByteOffset + keyNulByte + 1,\n keyAndValueByteSize - keyNulByte - 1,\n );\n\n kvData.set(key, value);\n\n // 4 = the keyAndValueByteSize field itself\n // keyAndValueByteSize = the bytes taken by the key and value\n // valuePadding = extra padding to align with 4 bytes\n bytesIntoKeyValueData += 4 + keyAndValueByteSize + valuePadding;\n }\n\n return kvData;\n}\n"],"names":[],"mappings":"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"}