{"version":3,"file":"CompressedTextureResource.mjs","sources":["../../src/resources/CompressedTextureResource.ts"],"sourcesContent":["import { INTERNAL_FORMAT_TO_BYTES_PER_PIXEL } from '../const';\nimport { BlobResource } from './BlobResource';\n\nimport type { BaseTexture, BufferType, GLTexture, Renderer } from '@pixi/core';\nimport type { INTERNAL_FORMATS } from '../const';\n\n/**\n * Used in parseKTX\n * @ignore\n */\nexport type CompressedLevelBuffer = {\n    levelID: number,\n    levelWidth: number,\n    levelHeight: number,\n    levelBuffer: Uint8Array\n};\n\n/**\n * @ignore\n */\nexport interface ICompressedTextureResourceOptions\n{\n    format: INTERNAL_FORMATS;\n    width: number;\n    height: number;\n    levels?: number;\n    levelBuffers?: CompressedLevelBuffer[];\n}\n\n/**\n * Resource for compressed texture formats, as follows: S3TC/DXTn (& their sRGB formats), ATC, ASTC, ETC 1/2, PVRTC,\n * BPTC (BC6H, BC7).\n *\n * Compressed textures improve performance when rendering is texture-bound. The texture data stays compressed in\n * graphics memory, increasing memory locality and speeding up texture fetches. These formats can also be used to store\n * more detail in the same amount of memory.\n *\n * For most developers, container file formats are a better abstraction instead of directly handling raw texture\n * data. PixiJS provides native support for the following texture file formats\n * (via {@link PIXI.loadBasis}, {@link PIXI.loadKTX}, and {@link PIXI.loadDDS}):\n *\n * **.dds** - the DirectDraw Surface file format stores DXTn (DXT-1,3,5) data or BCn (BC6H, BC7). See {@link PIXI.parseDDS}\n * **.ktx** - the Khronos Texture Container file format supports storing all the supported WebGL compression formats.\n *  See {@link PIXI.parseKTX}.\n * **.basis** - the BASIS supercompressed file format stores texture data in an internal format that is transcoded\n *  to the compression format supported on the device at _runtime_. It also supports transcoding into a uncompressed\n *  format as a fallback; you must install the `@pixi/basis-loader`, `@pixi/basis-transcoder` packages separately to\n *  use these files. See {@link PIXI.BasisParser}.\n *\n * The loaders for the aforementioned formats use `CompressedTextureResource` internally. It is strongly suggested that\n * they be used instead.\n *\n * ## Working directly with CompressedTextureResource\n *\n * Since `CompressedTextureResource` inherits `BlobResource`, you can provide it a URL pointing to a file containing\n * the raw texture data (with no file headers!):\n * @example\n * import { CompressedTextureResource, INTERNAL_FORMATS } from '@pixi/compressed-textures';\n * import { BaseTexture, Texture, ALPHA_MODES } from 'pixi.js';\n *\n * // The resource backing the texture data for your textures.\n * // NOTE: You can also provide a ArrayBufferView instead of a URL. This is used when loading data from a container file\n * //   format such as KTX, DDS, or BASIS.\n * const compressedResource = new CompressedTextureResource('bunny.dxt5', {\n *     format: INTERNAL_FORMATS.COMPRESSED_RGBA_S3TC_DXT5_EXT,\n *     width: 256,\n *     height: 256,\n * });\n *\n * // You can create a base-texture to the cache, so that future `Texture`s can be created using the `Texture.from` API.\n * const baseTexture = new BaseTexture(compressedResource, { pmaMode: ALPHA_MODES.NPM });\n *\n * // Create a Texture to add to the TextureCache\n * const texture = new Texture(baseTexture);\n *\n * // Add baseTexture & texture to the global texture cache\n * BaseTexture.addToCache(baseTexture, 'bunny.dxt5');\n * Texture.addToCache(texture, 'bunny.dxt5');\n * @memberof PIXI\n */\nexport class CompressedTextureResource extends BlobResource\n{\n    /** The compression format */\n    public format: INTERNAL_FORMATS;\n    /**\n     * The number of mipmap levels stored in the resource buffer.\n     * @default 1\n     */\n    public levels: number;\n\n    // Easy access to the WebGL extension providing support for the compression format via ContextSystem\n    private _extension: 's3tc' | 's3tc_sRGB' | 'atc' | 'astc' | 'etc' | 'etc1' | 'pvrtc' | 'bptc';\n    // Buffer views for each mipmap level in the main buffer\n    private _levelBuffers: CompressedLevelBuffer[];\n\n    /**\n     * @param source - the buffer/URL holding the compressed texture data\n     * @param options\n     * @param {PIXI.INTERNAL_FORMATS} options.format - the compression format\n     * @param {number} options.width - the image width in pixels.\n     * @param {number} options.height - the image height in pixels.\n     * @param {number} [options.level=1] - the mipmap levels stored in the compressed texture, including level 0.\n     * @param {number} [options.levelBuffers] - the buffers for each mipmap level. `CompressedTextureResource` can allows you\n     *      to pass `null` for `source`, for cases where each level is stored in non-contiguous memory.\n     */\n    constructor(source: string | BufferType, options: ICompressedTextureResourceOptions)\n    {\n        super(source, options);\n\n        this.format = options.format;\n        this.levels = options.levels || 1;\n\n        this._width = options.width;\n        this._height = options.height;\n\n        this._extension = CompressedTextureResource._formatToExtension(this.format);\n\n        if (options.levelBuffers || this.buffer)\n        {\n            // ViewableBuffer doesn't support byteOffset :-( so allow source to be Uint8Array\n            this._levelBuffers = options.levelBuffers\n                || CompressedTextureResource._createLevelBuffers(\n                    source instanceof Uint8Array ? source : this.buffer.uint8View,\n                    this.format,\n                    this.levels,\n                    4, 4, // PVRTC has 8x4 blocks in 2bpp mode\n                    this.width,\n                    this.height);\n        }\n    }\n\n    /**\n     * @override\n     * @param renderer - A reference to the current renderer\n     * @param _texture - the texture\n     * @param _glTexture - texture instance for this webgl context\n     */\n    upload(renderer: Renderer, _texture: BaseTexture, _glTexture: GLTexture): boolean\n    {\n        const gl = renderer.gl;\n        const extension = renderer.context.extensions[this._extension];\n\n        if (!extension)\n        {\n            throw new Error(`${this._extension} textures are not supported on the current machine`);\n        }\n        if (!this._levelBuffers)\n        {\n            // Do not try to upload data before BlobResource loads, unless the levelBuffers were provided directly!\n            return false;\n        }\n\n        gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4);\n\n        for (let i = 0, j = this.levels; i < j; i++)\n        {\n            const { levelID, levelWidth, levelHeight, levelBuffer } = this._levelBuffers[i];\n\n            gl.compressedTexImage2D(gl.TEXTURE_2D, levelID, this.format, levelWidth, levelHeight, 0, levelBuffer);\n        }\n\n        return true;\n    }\n\n    /** @protected */\n    protected onBlobLoaded(): void\n    {\n        this._levelBuffers = CompressedTextureResource._createLevelBuffers(\n            this.buffer.uint8View,\n            this.format,\n            this.levels,\n            4, 4, // PVRTC has 8x4 blocks in 2bpp mode\n            this.width,\n            this.height);\n    }\n\n    /**\n     * Returns the key (to ContextSystem#extensions) for the WebGL extension supporting the compression format\n     * @private\n     * @param format - the compression format to get the extension for.\n     */\n    private static _formatToExtension(format: INTERNAL_FORMATS):\n    's3tc' | 's3tc_sRGB' | 'atc' |\n    'astc' | 'etc' | 'etc1' | 'pvrtc' | 'bptc'\n    {\n        if (format >= 0x83F0 && format <= 0x83F3)\n        {\n            return 's3tc';\n        }\n        if (format >= 35916 && format <= 35919)\n        {\n            return 's3tc_sRGB';\n        }\n        else if (format >= 0x9270 && format <= 0x9279)\n        {\n            return 'etc';\n        }\n        else if (format >= 0x8C00 && format <= 0x8C03)\n        {\n            return 'pvrtc';\n        }\n        else if (format === 0x8D64)\n        {\n            return 'etc1';\n        }\n        else if (format === 0x8C92 || format === 0x8C93 || format === 0x87EE)\n        {\n            return 'atc';\n        }\n        else if (format >= 0x8E8C && format <= 0x8E8F)\n        {\n            return 'bptc';\n        }\n        else if (format === 0x93B0)\n        {\n            return 'astc';\n        }\n\n        throw new Error(`Invalid (compressed) texture format given: ${format}`);\n    }\n\n    /**\n     * Pre-creates buffer views for each mipmap level\n     * @private\n     * @param buffer -\n     * @param format - compression formats\n     * @param levels - mipmap levels\n     * @param blockWidth -\n     * @param blockHeight -\n     * @param imageWidth - width of the image in pixels\n     * @param imageHeight - height of the image in pixels\n     */\n    private static _createLevelBuffers(\n        buffer: Uint8Array,\n        format: INTERNAL_FORMATS,\n        levels: number,\n        blockWidth: number,\n        blockHeight: number,\n        imageWidth: number,\n        imageHeight: number\n    ): CompressedLevelBuffer[]\n    {\n        // The byte-size of the first level buffer\n        const buffers = new Array<CompressedLevelBuffer>(levels);\n\n        let offset = buffer.byteOffset;\n\n        let levelWidth = imageWidth;\n        let levelHeight = imageHeight;\n        let alignedLevelWidth = (levelWidth + blockWidth - 1) & ~(blockWidth - 1);\n        let alignedLevelHeight = (levelHeight + blockHeight - 1) & ~(blockHeight - 1);\n\n        let levelSize = alignedLevelWidth * alignedLevelHeight * INTERNAL_FORMAT_TO_BYTES_PER_PIXEL[format];\n\n        for (let i = 0; i < levels; i++)\n        {\n            buffers[i] = {\n                levelID: i,\n                levelWidth: levels > 1 ? levelWidth : alignedLevelWidth,\n                levelHeight: levels > 1 ? levelHeight : alignedLevelHeight,\n                levelBuffer: new Uint8Array(buffer.buffer, offset, levelSize)\n            };\n\n            offset += levelSize;\n\n            // Calculate levelBuffer dimensions for next iteration\n            levelWidth = (levelWidth >> 1) || 1;\n            levelHeight = (levelHeight >> 1) || 1;\n            alignedLevelWidth = (levelWidth + blockWidth - 1) & ~(blockWidth - 1);\n            alignedLevelHeight = (levelHeight + blockHeight - 1) & ~(blockHeight - 1);\n            levelSize = alignedLevelWidth * alignedLevelHeight * INTERNAL_FORMAT_TO_BYTES_PER_PIXEL[format];\n        }\n\n        return buffers;\n    }\n}\n"],"names":[],"mappings":"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"}